diff --git a/README.md b/README.md index 352d935..eb7bf98 100644 --- a/README.md +++ b/README.md @@ -281,6 +281,24 @@ import { createCable } from '@anycable/web' export default createCable({protocol: 'actioncable-v1-ext-json'}) ``` +#### Using with Protobuf and Msgpack + +You can use the extended protocol with Protobuf and Msgpack encoders as follows: + +```js +// cable.js +import { createCable } from '@anycable/web' +import { MsgpackEncoder } from '@anycable/msgpack-encoder' + +export default createCable({protocol: 'actioncable-v1-ext-msgpack', encoder: new MsgpackEncoder()}) + +// or for protobuf +import { createCable } from '@anycable/web' +import { ProtobufEncoderV2 } from '@anycable/protobuf-encoder' + +export default createCable({protocol: 'actioncable-v1-ext-protobuf', encoder: new ProtobufEncoderV2()}) +``` + #### Loading initial history on client initialization To catch up messages broadcasted during the initial page load (or client-side application initialization), you can specify the `historyTimestamp` option to retrieve messages after the specified time along with subscription requests. The value must be a UTC timestamp (the number of seconds). For example: diff --git a/package.json b/package.json index 4312d00..2fda7c5 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,12 @@ "test:dev": "NODE_OPTIONS='--experimental-vm-modules' jest", "test": "yarn test:dev --coverage && check-dts", "lint": "eslint . && prettier --check 'packages/**/*.{js,ts}'", - "lint:fix": "eslint . --fix && prettier --check 'packages/**/*.{js,ts}' --write" + "lint:fix": "eslint . --fix && prettier --check 'packages/**/*.{js,ts}' --write", + "protos": "yarn protos:build && yarn protos:fix", + "protos:build": "yarn protos:build:js && yarn protos:build:ts", + "protos:build:js": "pbjs -t static-module --keep-case --force-number -w es6 -o packages/protobuf-encoder/generated/message_pb.js packages/protobuf-encoder/message.proto", + "protos:build:ts": "pbts -o packages/protobuf-encoder/generated/message_pb.d.ts packages/protobuf-encoder/generated/message_pb.js", + "protos:fix": "sed -i '' 's/import \\* as \\$protobuf from \"protobufjs\\/minimal\";/import \\$protobuf from \"protobufjs\\/minimal.js\"\\\n\\$protobuf.util.Long = undefined;\\\n\\$protobuf.configure();/g' packages/protobuf-encoder/generated/message_pb.js" }, "homepage": "https://anycable.io/", "repository": "https://github.com/anycable/anycable-client", diff --git a/packages/core/cable/index.test.ts b/packages/core/cable/index.test.ts index 2a50978..c8e4e82 100644 --- a/packages/core/cable/index.test.ts +++ b/packages/core/cable/index.test.ts @@ -171,6 +171,7 @@ describe('connect/disconnect', () => { let p1 = cable.connect() let p2 = cable.connect() + cable.connected() cable.connected() await p1 diff --git a/packages/core/create-cable/index.d.ts b/packages/core/create-cable/index.d.ts index 7804f99..48e0b48 100644 --- a/packages/core/create-cable/index.d.ts +++ b/packages/core/create-cable/index.d.ts @@ -8,7 +8,10 @@ import { Channel, Message, ChannelParamsMap } from '../channel/index.js' import { Options } from '../action_cable/index.js' import { ExtendedOptions } from '../action_cable_ext/index.js' -export type ExtendedProtocolID = 'actioncable-v1-ext-json' +export type ExtendedProtocolID = + | 'actioncable-v1-ext-json' + | 'actioncable-v1-ext-msgpack' + | 'actioncable-v1-ext-protobuf' export type ProtocolID = | 'actioncable-v1-json' diff --git a/packages/protobuf-encoder/CHANGELOG.md b/packages/protobuf-encoder/CHANGELOG.md index dd8b44f..016acc3 100644 --- a/packages/protobuf-encoder/CHANGELOG.md +++ b/packages/protobuf-encoder/CHANGELOG.md @@ -2,4 +2,8 @@ ## master +- Add `ProtobufEncoderV2` class supporting updated Protobuf schema with Message and Reply types separated. + + This encoder MUST be used with the extended protocol. + [@palkan]: https://github.com/palkan diff --git a/packages/protobuf-encoder/generated/message_pb.d.ts b/packages/protobuf-encoder/generated/message_pb.d.ts index 3b6f9c5..ae6a80e 100644 --- a/packages/protobuf-encoder/generated/message_pb.d.ts +++ b/packages/protobuf-encoder/generated/message_pb.d.ts @@ -1,4 +1,5 @@ -import $protobuf from "protobufjs"; +import * as $protobuf from "protobufjs"; +import Long = require("long"); /** Namespace action_cable. */ export namespace action_cable { @@ -9,7 +10,9 @@ export namespace action_cable { disconnect = 2, ping = 3, confirm_subscription = 4, - reject_subscription = 5 + reject_subscription = 5, + confirm_history = 6, + reject_history = 7 } /** Command enum. */ @@ -17,7 +20,215 @@ export namespace action_cable { unknown_command = 0, subscribe = 1, unsubscribe = 2, - message = 3 + message = 3, + history = 4, + pong = 5 + } + + /** Properties of a StreamHistoryRequest. */ + interface IStreamHistoryRequest { + + /** StreamHistoryRequest epoch */ + epoch?: (string|null); + + /** StreamHistoryRequest offset */ + offset?: (number|null); + } + + /** Represents a StreamHistoryRequest. */ + class StreamHistoryRequest implements IStreamHistoryRequest { + + /** + * Constructs a new StreamHistoryRequest. + * @param [properties] Properties to set + */ + constructor(properties?: action_cable.IStreamHistoryRequest); + + /** StreamHistoryRequest epoch. */ + public epoch: string; + + /** StreamHistoryRequest offset. */ + public offset: number; + + /** + * Creates a new StreamHistoryRequest instance using the specified properties. + * @param [properties] Properties to set + * @returns StreamHistoryRequest instance + */ + public static create(properties?: action_cable.IStreamHistoryRequest): action_cable.StreamHistoryRequest; + + /** + * Encodes the specified StreamHistoryRequest message. Does not implicitly {@link action_cable.StreamHistoryRequest.verify|verify} messages. + * @param message StreamHistoryRequest message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: action_cable.IStreamHistoryRequest, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified StreamHistoryRequest message, length delimited. Does not implicitly {@link action_cable.StreamHistoryRequest.verify|verify} messages. + * @param message StreamHistoryRequest message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: action_cable.IStreamHistoryRequest, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a StreamHistoryRequest message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns StreamHistoryRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): action_cable.StreamHistoryRequest; + + /** + * Decodes a StreamHistoryRequest message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns StreamHistoryRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): action_cable.StreamHistoryRequest; + + /** + * Verifies a StreamHistoryRequest message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a StreamHistoryRequest message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns StreamHistoryRequest + */ + public static fromObject(object: { [k: string]: any }): action_cable.StreamHistoryRequest; + + /** + * Creates a plain object from a StreamHistoryRequest message. Also converts values to other types if specified. + * @param message StreamHistoryRequest + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: action_cable.StreamHistoryRequest, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this StreamHistoryRequest to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + + /** + * Gets the default type url for StreamHistoryRequest + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a HistoryRequest. */ + interface IHistoryRequest { + + /** HistoryRequest since */ + since?: (number|null); + + /** HistoryRequest streams */ + streams?: ({ [k: string]: action_cable.IStreamHistoryRequest }|null); + } + + /** Represents a HistoryRequest. */ + class HistoryRequest implements IHistoryRequest { + + /** + * Constructs a new HistoryRequest. + * @param [properties] Properties to set + */ + constructor(properties?: action_cable.IHistoryRequest); + + /** HistoryRequest since. */ + public since: number; + + /** HistoryRequest streams. */ + public streams: { [k: string]: action_cable.IStreamHistoryRequest }; + + /** + * Creates a new HistoryRequest instance using the specified properties. + * @param [properties] Properties to set + * @returns HistoryRequest instance + */ + public static create(properties?: action_cable.IHistoryRequest): action_cable.HistoryRequest; + + /** + * Encodes the specified HistoryRequest message. Does not implicitly {@link action_cable.HistoryRequest.verify|verify} messages. + * @param message HistoryRequest message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: action_cable.IHistoryRequest, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified HistoryRequest message, length delimited. Does not implicitly {@link action_cable.HistoryRequest.verify|verify} messages. + * @param message HistoryRequest message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: action_cable.IHistoryRequest, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a HistoryRequest message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns HistoryRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): action_cable.HistoryRequest; + + /** + * Decodes a HistoryRequest message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns HistoryRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): action_cable.HistoryRequest; + + /** + * Verifies a HistoryRequest message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a HistoryRequest message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns HistoryRequest + */ + public static fromObject(object: { [k: string]: any }): action_cable.HistoryRequest; + + /** + * Creates a plain object from a HistoryRequest message. Also converts values to other types if specified. + * @param message HistoryRequest + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: action_cable.HistoryRequest, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this HistoryRequest to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + + /** + * Gets the default type url for HistoryRequest + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; } /** Properties of a Message. */ @@ -43,6 +254,9 @@ export namespace action_cable { /** Message reconnect */ reconnect?: (boolean|null); + + /** Message history */ + history?: (action_cable.IHistoryRequest|null); } /** Represents a Message. */ @@ -75,6 +289,9 @@ export namespace action_cable { /** Message reconnect. */ public reconnect: boolean; + /** Message history. */ + public history?: (action_cable.IHistoryRequest|null); + /** * Creates a new Message instance using the specified properties. * @param [properties] Properties to set @@ -144,5 +361,169 @@ export namespace action_cable { * @returns JSON object */ public toJSON(): { [k: string]: any }; + + /** + * Gets the default type url for Message + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a Reply. */ + interface IReply { + + /** Reply type */ + type?: (action_cable.Type|null); + + /** Reply identifier */ + identifier?: (string|null); + + /** Reply message */ + message?: (Uint8Array|null); + + /** Reply reason */ + reason?: (string|null); + + /** Reply reconnect */ + reconnect?: (boolean|null); + + /** Reply stream_id */ + stream_id?: (string|null); + + /** Reply epoch */ + epoch?: (string|null); + + /** Reply offset */ + offset?: (number|null); + + /** Reply sid */ + sid?: (string|null); + + /** Reply restored */ + restored?: (boolean|null); + + /** Reply restored_ids */ + restored_ids?: (string[]|null); + } + + /** Represents a Reply. */ + class Reply implements IReply { + + /** + * Constructs a new Reply. + * @param [properties] Properties to set + */ + constructor(properties?: action_cable.IReply); + + /** Reply type. */ + public type: action_cable.Type; + + /** Reply identifier. */ + public identifier: string; + + /** Reply message. */ + public message: Uint8Array; + + /** Reply reason. */ + public reason: string; + + /** Reply reconnect. */ + public reconnect: boolean; + + /** Reply stream_id. */ + public stream_id: string; + + /** Reply epoch. */ + public epoch: string; + + /** Reply offset. */ + public offset: number; + + /** Reply sid. */ + public sid: string; + + /** Reply restored. */ + public restored: boolean; + + /** Reply restored_ids. */ + public restored_ids: string[]; + + /** + * Creates a new Reply instance using the specified properties. + * @param [properties] Properties to set + * @returns Reply instance + */ + public static create(properties?: action_cable.IReply): action_cable.Reply; + + /** + * Encodes the specified Reply message. Does not implicitly {@link action_cable.Reply.verify|verify} messages. + * @param message Reply message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: action_cable.IReply, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Reply message, length delimited. Does not implicitly {@link action_cable.Reply.verify|verify} messages. + * @param message Reply message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: action_cable.IReply, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Reply message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Reply + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): action_cable.Reply; + + /** + * Decodes a Reply message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Reply + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): action_cable.Reply; + + /** + * Verifies a Reply message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a Reply message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Reply + */ + public static fromObject(object: { [k: string]: any }): action_cable.Reply; + + /** + * Creates a plain object from a Reply message. Also converts values to other types if specified. + * @param message Reply + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: action_cable.Reply, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Reply to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + + /** + * Gets the default type url for Reply + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; } } diff --git a/packages/protobuf-encoder/generated/message_pb.js b/packages/protobuf-encoder/generated/message_pb.js index 72fc450..749a9db 100644 --- a/packages/protobuf-encoder/generated/message_pb.js +++ b/packages/protobuf-encoder/generated/message_pb.js @@ -1,5 +1,7 @@ /*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/ -import $protobuf from "protobufjs/minimal.js"; +import $protobuf from "protobufjs/minimal.js" +$protobuf.util.Long = undefined; +$protobuf.configure(); // Common aliases const $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; @@ -26,6 +28,8 @@ export const action_cable = $root.action_cable = (() => { * @property {number} ping=3 ping value * @property {number} confirm_subscription=4 confirm_subscription value * @property {number} reject_subscription=5 reject_subscription value + * @property {number} confirm_history=6 confirm_history value + * @property {number} reject_history=7 reject_history value */ action_cable.Type = (function() { const valuesById = {}, values = Object.create(valuesById); @@ -35,6 +39,8 @@ export const action_cable = $root.action_cable = (() => { values[valuesById[3] = "ping"] = 3; values[valuesById[4] = "confirm_subscription"] = 4; values[valuesById[5] = "reject_subscription"] = 5; + values[valuesById[6] = "confirm_history"] = 6; + values[valuesById[7] = "reject_history"] = 7; return values; })(); @@ -46,6 +52,8 @@ export const action_cable = $root.action_cable = (() => { * @property {number} subscribe=1 subscribe value * @property {number} unsubscribe=2 unsubscribe value * @property {number} message=3 message value + * @property {number} history=4 history value + * @property {number} pong=5 pong value */ action_cable.Command = (function() { const valuesById = {}, values = Object.create(valuesById); @@ -53,33 +61,1031 @@ export const action_cable = $root.action_cable = (() => { values[valuesById[1] = "subscribe"] = 1; values[valuesById[2] = "unsubscribe"] = 2; values[valuesById[3] = "message"] = 3; + values[valuesById[4] = "history"] = 4; + values[valuesById[5] = "pong"] = 5; return values; })(); + action_cable.StreamHistoryRequest = (function() { + + /** + * Properties of a StreamHistoryRequest. + * @memberof action_cable + * @interface IStreamHistoryRequest + * @property {string|null} [epoch] StreamHistoryRequest epoch + * @property {number|null} [offset] StreamHistoryRequest offset + */ + + /** + * Constructs a new StreamHistoryRequest. + * @memberof action_cable + * @classdesc Represents a StreamHistoryRequest. + * @implements IStreamHistoryRequest + * @constructor + * @param {action_cable.IStreamHistoryRequest=} [properties] Properties to set + */ + function StreamHistoryRequest(properties) { + if (properties) + for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * StreamHistoryRequest epoch. + * @member {string} epoch + * @memberof action_cable.StreamHistoryRequest + * @instance + */ + StreamHistoryRequest.prototype.epoch = ""; + + /** + * StreamHistoryRequest offset. + * @member {number} offset + * @memberof action_cable.StreamHistoryRequest + * @instance + */ + StreamHistoryRequest.prototype.offset = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * Creates a new StreamHistoryRequest instance using the specified properties. + * @function create + * @memberof action_cable.StreamHistoryRequest + * @static + * @param {action_cable.IStreamHistoryRequest=} [properties] Properties to set + * @returns {action_cable.StreamHistoryRequest} StreamHistoryRequest instance + */ + StreamHistoryRequest.create = function create(properties) { + return new StreamHistoryRequest(properties); + }; + + /** + * Encodes the specified StreamHistoryRequest message. Does not implicitly {@link action_cable.StreamHistoryRequest.verify|verify} messages. + * @function encode + * @memberof action_cable.StreamHistoryRequest + * @static + * @param {action_cable.IStreamHistoryRequest} message StreamHistoryRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + StreamHistoryRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.epoch != null && Object.hasOwnProperty.call(message, "epoch")) + writer.uint32(/* id 2, wireType 2 =*/18).string(message.epoch); + if (message.offset != null && Object.hasOwnProperty.call(message, "offset")) + writer.uint32(/* id 3, wireType 0 =*/24).int64(message.offset); + return writer; + }; + + /** + * Encodes the specified StreamHistoryRequest message, length delimited. Does not implicitly {@link action_cable.StreamHistoryRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof action_cable.StreamHistoryRequest + * @static + * @param {action_cable.IStreamHistoryRequest} message StreamHistoryRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + StreamHistoryRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a StreamHistoryRequest message from the specified reader or buffer. + * @function decode + * @memberof action_cable.StreamHistoryRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {action_cable.StreamHistoryRequest} StreamHistoryRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + StreamHistoryRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + let end = length === undefined ? reader.len : reader.pos + length, message = new $root.action_cable.StreamHistoryRequest(); + while (reader.pos < end) { + let tag = reader.uint32(); + switch (tag >>> 3) { + case 2: { + message.epoch = reader.string(); + break; + } + case 3: { + message.offset = reader.int64(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a StreamHistoryRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof action_cable.StreamHistoryRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {action_cable.StreamHistoryRequest} StreamHistoryRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + StreamHistoryRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a StreamHistoryRequest message. + * @function verify + * @memberof action_cable.StreamHistoryRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + StreamHistoryRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.epoch != null && message.hasOwnProperty("epoch")) + if (!$util.isString(message.epoch)) + return "epoch: string expected"; + if (message.offset != null && message.hasOwnProperty("offset")) + if (!$util.isInteger(message.offset) && !(message.offset && $util.isInteger(message.offset.low) && $util.isInteger(message.offset.high))) + return "offset: integer|Long expected"; + return null; + }; + + /** + * Creates a StreamHistoryRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof action_cable.StreamHistoryRequest + * @static + * @param {Object.} object Plain object + * @returns {action_cable.StreamHistoryRequest} StreamHistoryRequest + */ + StreamHistoryRequest.fromObject = function fromObject(object) { + if (object instanceof $root.action_cable.StreamHistoryRequest) + return object; + let message = new $root.action_cable.StreamHistoryRequest(); + if (object.epoch != null) + message.epoch = String(object.epoch); + if (object.offset != null) + if ($util.Long) + (message.offset = $util.Long.fromValue(object.offset)).unsigned = false; + else if (typeof object.offset === "string") + message.offset = parseInt(object.offset, 10); + else if (typeof object.offset === "number") + message.offset = object.offset; + else if (typeof object.offset === "object") + message.offset = new $util.LongBits(object.offset.low >>> 0, object.offset.high >>> 0).toNumber(); + return message; + }; + + /** + * Creates a plain object from a StreamHistoryRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof action_cable.StreamHistoryRequest + * @static + * @param {action_cable.StreamHistoryRequest} message StreamHistoryRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + StreamHistoryRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + let object = {}; + if (options.defaults) { + object.epoch = ""; + if ($util.Long) { + let long = new $util.Long(0, 0, false); + object.offset = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.offset = options.longs === String ? "0" : 0; + } + if (message.epoch != null && message.hasOwnProperty("epoch")) + object.epoch = message.epoch; + if (message.offset != null && message.hasOwnProperty("offset")) + if (typeof message.offset === "number") + object.offset = options.longs === String ? String(message.offset) : message.offset; + else + object.offset = options.longs === String ? $util.Long.prototype.toString.call(message.offset) : options.longs === Number ? new $util.LongBits(message.offset.low >>> 0, message.offset.high >>> 0).toNumber() : message.offset; + return object; + }; + + /** + * Converts this StreamHistoryRequest to JSON. + * @function toJSON + * @memberof action_cable.StreamHistoryRequest + * @instance + * @returns {Object.} JSON object + */ + StreamHistoryRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for StreamHistoryRequest + * @function getTypeUrl + * @memberof action_cable.StreamHistoryRequest + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + StreamHistoryRequest.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/action_cable.StreamHistoryRequest"; + }; + + return StreamHistoryRequest; + })(); + + action_cable.HistoryRequest = (function() { + + /** + * Properties of a HistoryRequest. + * @memberof action_cable + * @interface IHistoryRequest + * @property {number|null} [since] HistoryRequest since + * @property {Object.|null} [streams] HistoryRequest streams + */ + + /** + * Constructs a new HistoryRequest. + * @memberof action_cable + * @classdesc Represents a HistoryRequest. + * @implements IHistoryRequest + * @constructor + * @param {action_cable.IHistoryRequest=} [properties] Properties to set + */ + function HistoryRequest(properties) { + this.streams = {}; + if (properties) + for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * HistoryRequest since. + * @member {number} since + * @memberof action_cable.HistoryRequest + * @instance + */ + HistoryRequest.prototype.since = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * HistoryRequest streams. + * @member {Object.} streams + * @memberof action_cable.HistoryRequest + * @instance + */ + HistoryRequest.prototype.streams = $util.emptyObject; + + /** + * Creates a new HistoryRequest instance using the specified properties. + * @function create + * @memberof action_cable.HistoryRequest + * @static + * @param {action_cable.IHistoryRequest=} [properties] Properties to set + * @returns {action_cable.HistoryRequest} HistoryRequest instance + */ + HistoryRequest.create = function create(properties) { + return new HistoryRequest(properties); + }; + + /** + * Encodes the specified HistoryRequest message. Does not implicitly {@link action_cable.HistoryRequest.verify|verify} messages. + * @function encode + * @memberof action_cable.HistoryRequest + * @static + * @param {action_cable.IHistoryRequest} message HistoryRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + HistoryRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.since != null && Object.hasOwnProperty.call(message, "since")) + writer.uint32(/* id 1, wireType 0 =*/8).int64(message.since); + if (message.streams != null && Object.hasOwnProperty.call(message, "streams")) + for (let keys = Object.keys(message.streams), i = 0; i < keys.length; ++i) { + writer.uint32(/* id 2, wireType 2 =*/18).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]); + $root.action_cable.StreamHistoryRequest.encode(message.streams[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim(); + } + return writer; + }; + + /** + * Encodes the specified HistoryRequest message, length delimited. Does not implicitly {@link action_cable.HistoryRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof action_cable.HistoryRequest + * @static + * @param {action_cable.IHistoryRequest} message HistoryRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + HistoryRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a HistoryRequest message from the specified reader or buffer. + * @function decode + * @memberof action_cable.HistoryRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {action_cable.HistoryRequest} HistoryRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + HistoryRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + let end = length === undefined ? reader.len : reader.pos + length, message = new $root.action_cable.HistoryRequest(), key, value; + while (reader.pos < end) { + let tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.since = reader.int64(); + break; + } + case 2: { + if (message.streams === $util.emptyObject) + message.streams = {}; + let end2 = reader.uint32() + reader.pos; + key = ""; + value = null; + while (reader.pos < end2) { + let tag2 = reader.uint32(); + switch (tag2 >>> 3) { + case 1: + key = reader.string(); + break; + case 2: + value = $root.action_cable.StreamHistoryRequest.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag2 & 7); + break; + } + } + message.streams[key] = value; + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a HistoryRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof action_cable.HistoryRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {action_cable.HistoryRequest} HistoryRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + HistoryRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a HistoryRequest message. + * @function verify + * @memberof action_cable.HistoryRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + HistoryRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.since != null && message.hasOwnProperty("since")) + if (!$util.isInteger(message.since) && !(message.since && $util.isInteger(message.since.low) && $util.isInteger(message.since.high))) + return "since: integer|Long expected"; + if (message.streams != null && message.hasOwnProperty("streams")) { + if (!$util.isObject(message.streams)) + return "streams: object expected"; + let key = Object.keys(message.streams); + for (let i = 0; i < key.length; ++i) { + let error = $root.action_cable.StreamHistoryRequest.verify(message.streams[key[i]]); + if (error) + return "streams." + error; + } + } + return null; + }; + + /** + * Creates a HistoryRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof action_cable.HistoryRequest + * @static + * @param {Object.} object Plain object + * @returns {action_cable.HistoryRequest} HistoryRequest + */ + HistoryRequest.fromObject = function fromObject(object) { + if (object instanceof $root.action_cable.HistoryRequest) + return object; + let message = new $root.action_cable.HistoryRequest(); + if (object.since != null) + if ($util.Long) + (message.since = $util.Long.fromValue(object.since)).unsigned = false; + else if (typeof object.since === "string") + message.since = parseInt(object.since, 10); + else if (typeof object.since === "number") + message.since = object.since; + else if (typeof object.since === "object") + message.since = new $util.LongBits(object.since.low >>> 0, object.since.high >>> 0).toNumber(); + if (object.streams) { + if (typeof object.streams !== "object") + throw TypeError(".action_cable.HistoryRequest.streams: object expected"); + message.streams = {}; + for (let keys = Object.keys(object.streams), i = 0; i < keys.length; ++i) { + if (typeof object.streams[keys[i]] !== "object") + throw TypeError(".action_cable.HistoryRequest.streams: object expected"); + message.streams[keys[i]] = $root.action_cable.StreamHistoryRequest.fromObject(object.streams[keys[i]]); + } + } + return message; + }; + + /** + * Creates a plain object from a HistoryRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof action_cable.HistoryRequest + * @static + * @param {action_cable.HistoryRequest} message HistoryRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + HistoryRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + let object = {}; + if (options.objects || options.defaults) + object.streams = {}; + if (options.defaults) + if ($util.Long) { + let long = new $util.Long(0, 0, false); + object.since = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.since = options.longs === String ? "0" : 0; + if (message.since != null && message.hasOwnProperty("since")) + if (typeof message.since === "number") + object.since = options.longs === String ? String(message.since) : message.since; + else + object.since = options.longs === String ? $util.Long.prototype.toString.call(message.since) : options.longs === Number ? new $util.LongBits(message.since.low >>> 0, message.since.high >>> 0).toNumber() : message.since; + let keys2; + if (message.streams && (keys2 = Object.keys(message.streams)).length) { + object.streams = {}; + for (let j = 0; j < keys2.length; ++j) + object.streams[keys2[j]] = $root.action_cable.StreamHistoryRequest.toObject(message.streams[keys2[j]], options); + } + return object; + }; + + /** + * Converts this HistoryRequest to JSON. + * @function toJSON + * @memberof action_cable.HistoryRequest + * @instance + * @returns {Object.} JSON object + */ + HistoryRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for HistoryRequest + * @function getTypeUrl + * @memberof action_cable.HistoryRequest + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + HistoryRequest.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/action_cable.HistoryRequest"; + }; + + return HistoryRequest; + })(); + action_cable.Message = (function() { /** - * Properties of a Message. + * Properties of a Message. + * @memberof action_cable + * @interface IMessage + * @property {action_cable.Type|null} [type] Message type + * @property {action_cable.Command|null} [command] Message command + * @property {string|null} [identifier] Message identifier + * @property {string|null} [data] Message data + * @property {Uint8Array|null} [message] Message message + * @property {string|null} [reason] Message reason + * @property {boolean|null} [reconnect] Message reconnect + * @property {action_cable.IHistoryRequest|null} [history] Message history + */ + + /** + * Constructs a new Message. + * @memberof action_cable + * @classdesc Represents a Message. + * @implements IMessage + * @constructor + * @param {action_cable.IMessage=} [properties] Properties to set + */ + function Message(properties) { + if (properties) + for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Message type. + * @member {action_cable.Type} type + * @memberof action_cable.Message + * @instance + */ + Message.prototype.type = 0; + + /** + * Message command. + * @member {action_cable.Command} command + * @memberof action_cable.Message + * @instance + */ + Message.prototype.command = 0; + + /** + * Message identifier. + * @member {string} identifier + * @memberof action_cable.Message + * @instance + */ + Message.prototype.identifier = ""; + + /** + * Message data. + * @member {string} data + * @memberof action_cable.Message + * @instance + */ + Message.prototype.data = ""; + + /** + * Message message. + * @member {Uint8Array} message + * @memberof action_cable.Message + * @instance + */ + Message.prototype.message = $util.newBuffer([]); + + /** + * Message reason. + * @member {string} reason + * @memberof action_cable.Message + * @instance + */ + Message.prototype.reason = ""; + + /** + * Message reconnect. + * @member {boolean} reconnect + * @memberof action_cable.Message + * @instance + */ + Message.prototype.reconnect = false; + + /** + * Message history. + * @member {action_cable.IHistoryRequest|null|undefined} history + * @memberof action_cable.Message + * @instance + */ + Message.prototype.history = null; + + /** + * Creates a new Message instance using the specified properties. + * @function create + * @memberof action_cable.Message + * @static + * @param {action_cable.IMessage=} [properties] Properties to set + * @returns {action_cable.Message} Message instance + */ + Message.create = function create(properties) { + return new Message(properties); + }; + + /** + * Encodes the specified Message message. Does not implicitly {@link action_cable.Message.verify|verify} messages. + * @function encode + * @memberof action_cable.Message + * @static + * @param {action_cable.IMessage} message Message message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Message.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.type != null && Object.hasOwnProperty.call(message, "type")) + writer.uint32(/* id 1, wireType 0 =*/8).int32(message.type); + if (message.command != null && Object.hasOwnProperty.call(message, "command")) + writer.uint32(/* id 2, wireType 0 =*/16).int32(message.command); + if (message.identifier != null && Object.hasOwnProperty.call(message, "identifier")) + writer.uint32(/* id 3, wireType 2 =*/26).string(message.identifier); + if (message.data != null && Object.hasOwnProperty.call(message, "data")) + writer.uint32(/* id 4, wireType 2 =*/34).string(message.data); + if (message.message != null && Object.hasOwnProperty.call(message, "message")) + writer.uint32(/* id 5, wireType 2 =*/42).bytes(message.message); + if (message.reason != null && Object.hasOwnProperty.call(message, "reason")) + writer.uint32(/* id 6, wireType 2 =*/50).string(message.reason); + if (message.reconnect != null && Object.hasOwnProperty.call(message, "reconnect")) + writer.uint32(/* id 7, wireType 0 =*/56).bool(message.reconnect); + if (message.history != null && Object.hasOwnProperty.call(message, "history")) + $root.action_cable.HistoryRequest.encode(message.history, writer.uint32(/* id 8, wireType 2 =*/66).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified Message message, length delimited. Does not implicitly {@link action_cable.Message.verify|verify} messages. + * @function encodeDelimited + * @memberof action_cable.Message + * @static + * @param {action_cable.IMessage} message Message message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Message.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Message message from the specified reader or buffer. + * @function decode + * @memberof action_cable.Message + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {action_cable.Message} Message + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Message.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + let end = length === undefined ? reader.len : reader.pos + length, message = new $root.action_cable.Message(); + while (reader.pos < end) { + let tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.type = reader.int32(); + break; + } + case 2: { + message.command = reader.int32(); + break; + } + case 3: { + message.identifier = reader.string(); + break; + } + case 4: { + message.data = reader.string(); + break; + } + case 5: { + message.message = reader.bytes(); + break; + } + case 6: { + message.reason = reader.string(); + break; + } + case 7: { + message.reconnect = reader.bool(); + break; + } + case 8: { + message.history = $root.action_cable.HistoryRequest.decode(reader, reader.uint32()); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Message message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof action_cable.Message + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {action_cable.Message} Message + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Message.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Message message. + * @function verify + * @memberof action_cable.Message + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Message.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.type != null && message.hasOwnProperty("type")) + switch (message.type) { + default: + return "type: enum value expected"; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + break; + } + if (message.command != null && message.hasOwnProperty("command")) + switch (message.command) { + default: + return "command: enum value expected"; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + break; + } + if (message.identifier != null && message.hasOwnProperty("identifier")) + if (!$util.isString(message.identifier)) + return "identifier: string expected"; + if (message.data != null && message.hasOwnProperty("data")) + if (!$util.isString(message.data)) + return "data: string expected"; + if (message.message != null && message.hasOwnProperty("message")) + if (!(message.message && typeof message.message.length === "number" || $util.isString(message.message))) + return "message: buffer expected"; + if (message.reason != null && message.hasOwnProperty("reason")) + if (!$util.isString(message.reason)) + return "reason: string expected"; + if (message.reconnect != null && message.hasOwnProperty("reconnect")) + if (typeof message.reconnect !== "boolean") + return "reconnect: boolean expected"; + if (message.history != null && message.hasOwnProperty("history")) { + let error = $root.action_cable.HistoryRequest.verify(message.history); + if (error) + return "history." + error; + } + return null; + }; + + /** + * Creates a Message message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof action_cable.Message + * @static + * @param {Object.} object Plain object + * @returns {action_cable.Message} Message + */ + Message.fromObject = function fromObject(object) { + if (object instanceof $root.action_cable.Message) + return object; + let message = new $root.action_cable.Message(); + switch (object.type) { + default: + if (typeof object.type === "number") { + message.type = object.type; + break; + } + break; + case "no_type": + case 0: + message.type = 0; + break; + case "welcome": + case 1: + message.type = 1; + break; + case "disconnect": + case 2: + message.type = 2; + break; + case "ping": + case 3: + message.type = 3; + break; + case "confirm_subscription": + case 4: + message.type = 4; + break; + case "reject_subscription": + case 5: + message.type = 5; + break; + case "confirm_history": + case 6: + message.type = 6; + break; + case "reject_history": + case 7: + message.type = 7; + break; + } + switch (object.command) { + default: + if (typeof object.command === "number") { + message.command = object.command; + break; + } + break; + case "unknown_command": + case 0: + message.command = 0; + break; + case "subscribe": + case 1: + message.command = 1; + break; + case "unsubscribe": + case 2: + message.command = 2; + break; + case "message": + case 3: + message.command = 3; + break; + case "history": + case 4: + message.command = 4; + break; + case "pong": + case 5: + message.command = 5; + break; + } + if (object.identifier != null) + message.identifier = String(object.identifier); + if (object.data != null) + message.data = String(object.data); + if (object.message != null) + if (typeof object.message === "string") + $util.base64.decode(object.message, message.message = $util.newBuffer($util.base64.length(object.message)), 0); + else if (object.message.length >= 0) + message.message = object.message; + if (object.reason != null) + message.reason = String(object.reason); + if (object.reconnect != null) + message.reconnect = Boolean(object.reconnect); + if (object.history != null) { + if (typeof object.history !== "object") + throw TypeError(".action_cable.Message.history: object expected"); + message.history = $root.action_cable.HistoryRequest.fromObject(object.history); + } + return message; + }; + + /** + * Creates a plain object from a Message message. Also converts values to other types if specified. + * @function toObject + * @memberof action_cable.Message + * @static + * @param {action_cable.Message} message Message + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Message.toObject = function toObject(message, options) { + if (!options) + options = {}; + let object = {}; + if (options.defaults) { + object.type = options.enums === String ? "no_type" : 0; + object.command = options.enums === String ? "unknown_command" : 0; + object.identifier = ""; + object.data = ""; + if (options.bytes === String) + object.message = ""; + else { + object.message = []; + if (options.bytes !== Array) + object.message = $util.newBuffer(object.message); + } + object.reason = ""; + object.reconnect = false; + object.history = null; + } + if (message.type != null && message.hasOwnProperty("type")) + object.type = options.enums === String ? $root.action_cable.Type[message.type] === undefined ? message.type : $root.action_cable.Type[message.type] : message.type; + if (message.command != null && message.hasOwnProperty("command")) + object.command = options.enums === String ? $root.action_cable.Command[message.command] === undefined ? message.command : $root.action_cable.Command[message.command] : message.command; + if (message.identifier != null && message.hasOwnProperty("identifier")) + object.identifier = message.identifier; + if (message.data != null && message.hasOwnProperty("data")) + object.data = message.data; + if (message.message != null && message.hasOwnProperty("message")) + object.message = options.bytes === String ? $util.base64.encode(message.message, 0, message.message.length) : options.bytes === Array ? Array.prototype.slice.call(message.message) : message.message; + if (message.reason != null && message.hasOwnProperty("reason")) + object.reason = message.reason; + if (message.reconnect != null && message.hasOwnProperty("reconnect")) + object.reconnect = message.reconnect; + if (message.history != null && message.hasOwnProperty("history")) + object.history = $root.action_cable.HistoryRequest.toObject(message.history, options); + return object; + }; + + /** + * Converts this Message to JSON. + * @function toJSON + * @memberof action_cable.Message + * @instance + * @returns {Object.} JSON object + */ + Message.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for Message + * @function getTypeUrl + * @memberof action_cable.Message + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + Message.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/action_cable.Message"; + }; + + return Message; + })(); + + action_cable.Reply = (function() { + + /** + * Properties of a Reply. * @memberof action_cable - * @interface IMessage - * @property {action_cable.Type|null} [type] Message type - * @property {action_cable.Command|null} [command] Message command - * @property {string|null} [identifier] Message identifier - * @property {string|null} [data] Message data - * @property {Uint8Array|null} [message] Message message - * @property {string|null} [reason] Message reason - * @property {boolean|null} [reconnect] Message reconnect + * @interface IReply + * @property {action_cable.Type|null} [type] Reply type + * @property {string|null} [identifier] Reply identifier + * @property {Uint8Array|null} [message] Reply message + * @property {string|null} [reason] Reply reason + * @property {boolean|null} [reconnect] Reply reconnect + * @property {string|null} [stream_id] Reply stream_id + * @property {string|null} [epoch] Reply epoch + * @property {number|null} [offset] Reply offset + * @property {string|null} [sid] Reply sid + * @property {boolean|null} [restored] Reply restored + * @property {Array.|null} [restored_ids] Reply restored_ids */ /** - * Constructs a new Message. + * Constructs a new Reply. * @memberof action_cable - * @classdesc Represents a Message. - * @implements IMessage + * @classdesc Represents a Reply. + * @implements IReply * @constructor - * @param {action_cable.IMessage=} [properties] Properties to set + * @param {action_cable.IReply=} [properties] Properties to set */ - function Message(properties) { + function Reply(properties) { + this.restored_ids = []; if (properties) for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) if (properties[keys[i]] != null) @@ -87,154 +1093,220 @@ export const action_cable = $root.action_cable = (() => { } /** - * Message type. + * Reply type. * @member {action_cable.Type} type - * @memberof action_cable.Message + * @memberof action_cable.Reply * @instance */ - Message.prototype.type = 0; + Reply.prototype.type = 0; /** - * Message command. - * @member {action_cable.Command} command - * @memberof action_cable.Message + * Reply identifier. + * @member {string} identifier + * @memberof action_cable.Reply * @instance */ - Message.prototype.command = 0; + Reply.prototype.identifier = ""; /** - * Message identifier. - * @member {string} identifier - * @memberof action_cable.Message + * Reply message. + * @member {Uint8Array} message + * @memberof action_cable.Reply * @instance */ - Message.prototype.identifier = ""; + Reply.prototype.message = $util.newBuffer([]); /** - * Message data. - * @member {string} data - * @memberof action_cable.Message + * Reply reason. + * @member {string} reason + * @memberof action_cable.Reply * @instance */ - Message.prototype.data = ""; + Reply.prototype.reason = ""; /** - * Message message. - * @member {Uint8Array} message - * @memberof action_cable.Message + * Reply reconnect. + * @member {boolean} reconnect + * @memberof action_cable.Reply * @instance */ - Message.prototype.message = $util.newBuffer([]); + Reply.prototype.reconnect = false; /** - * Message reason. - * @member {string} reason - * @memberof action_cable.Message + * Reply stream_id. + * @member {string} stream_id + * @memberof action_cable.Reply * @instance */ - Message.prototype.reason = ""; + Reply.prototype.stream_id = ""; /** - * Message reconnect. - * @member {boolean} reconnect - * @memberof action_cable.Message + * Reply epoch. + * @member {string} epoch + * @memberof action_cable.Reply * @instance */ - Message.prototype.reconnect = false; + Reply.prototype.epoch = ""; /** - * Creates a new Message instance using the specified properties. + * Reply offset. + * @member {number} offset + * @memberof action_cable.Reply + * @instance + */ + Reply.prototype.offset = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * Reply sid. + * @member {string} sid + * @memberof action_cable.Reply + * @instance + */ + Reply.prototype.sid = ""; + + /** + * Reply restored. + * @member {boolean} restored + * @memberof action_cable.Reply + * @instance + */ + Reply.prototype.restored = false; + + /** + * Reply restored_ids. + * @member {Array.} restored_ids + * @memberof action_cable.Reply + * @instance + */ + Reply.prototype.restored_ids = $util.emptyArray; + + /** + * Creates a new Reply instance using the specified properties. * @function create - * @memberof action_cable.Message + * @memberof action_cable.Reply * @static - * @param {action_cable.IMessage=} [properties] Properties to set - * @returns {action_cable.Message} Message instance + * @param {action_cable.IReply=} [properties] Properties to set + * @returns {action_cable.Reply} Reply instance */ - Message.create = function create(properties) { - return new Message(properties); + Reply.create = function create(properties) { + return new Reply(properties); }; /** - * Encodes the specified Message message. Does not implicitly {@link action_cable.Message.verify|verify} messages. + * Encodes the specified Reply message. Does not implicitly {@link action_cable.Reply.verify|verify} messages. * @function encode - * @memberof action_cable.Message + * @memberof action_cable.Reply * @static - * @param {action_cable.IMessage} message Message message or plain object to encode + * @param {action_cable.IReply} message Reply message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ - Message.encode = function encode(message, writer) { + Reply.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); if (message.type != null && Object.hasOwnProperty.call(message, "type")) writer.uint32(/* id 1, wireType 0 =*/8).int32(message.type); - if (message.command != null && Object.hasOwnProperty.call(message, "command")) - writer.uint32(/* id 2, wireType 0 =*/16).int32(message.command); if (message.identifier != null && Object.hasOwnProperty.call(message, "identifier")) - writer.uint32(/* id 3, wireType 2 =*/26).string(message.identifier); - if (message.data != null && Object.hasOwnProperty.call(message, "data")) - writer.uint32(/* id 4, wireType 2 =*/34).string(message.data); + writer.uint32(/* id 2, wireType 2 =*/18).string(message.identifier); if (message.message != null && Object.hasOwnProperty.call(message, "message")) - writer.uint32(/* id 5, wireType 2 =*/42).bytes(message.message); + writer.uint32(/* id 3, wireType 2 =*/26).bytes(message.message); if (message.reason != null && Object.hasOwnProperty.call(message, "reason")) - writer.uint32(/* id 6, wireType 2 =*/50).string(message.reason); + writer.uint32(/* id 4, wireType 2 =*/34).string(message.reason); if (message.reconnect != null && Object.hasOwnProperty.call(message, "reconnect")) - writer.uint32(/* id 7, wireType 0 =*/56).bool(message.reconnect); + writer.uint32(/* id 5, wireType 0 =*/40).bool(message.reconnect); + if (message.stream_id != null && Object.hasOwnProperty.call(message, "stream_id")) + writer.uint32(/* id 6, wireType 2 =*/50).string(message.stream_id); + if (message.epoch != null && Object.hasOwnProperty.call(message, "epoch")) + writer.uint32(/* id 7, wireType 2 =*/58).string(message.epoch); + if (message.offset != null && Object.hasOwnProperty.call(message, "offset")) + writer.uint32(/* id 8, wireType 0 =*/64).int64(message.offset); + if (message.sid != null && Object.hasOwnProperty.call(message, "sid")) + writer.uint32(/* id 9, wireType 2 =*/74).string(message.sid); + if (message.restored != null && Object.hasOwnProperty.call(message, "restored")) + writer.uint32(/* id 10, wireType 0 =*/80).bool(message.restored); + if (message.restored_ids != null && message.restored_ids.length) + for (let i = 0; i < message.restored_ids.length; ++i) + writer.uint32(/* id 11, wireType 2 =*/90).string(message.restored_ids[i]); return writer; }; /** - * Encodes the specified Message message, length delimited. Does not implicitly {@link action_cable.Message.verify|verify} messages. + * Encodes the specified Reply message, length delimited. Does not implicitly {@link action_cable.Reply.verify|verify} messages. * @function encodeDelimited - * @memberof action_cable.Message + * @memberof action_cable.Reply * @static - * @param {action_cable.IMessage} message Message message or plain object to encode + * @param {action_cable.IReply} message Reply message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ - Message.encodeDelimited = function encodeDelimited(message, writer) { + Reply.encodeDelimited = function encodeDelimited(message, writer) { return this.encode(message, writer).ldelim(); }; /** - * Decodes a Message message from the specified reader or buffer. + * Decodes a Reply message from the specified reader or buffer. * @function decode - * @memberof action_cable.Message + * @memberof action_cable.Reply * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @param {number} [length] Message length if known beforehand - * @returns {action_cable.Message} Message + * @returns {action_cable.Reply} Reply * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ - Message.decode = function decode(reader, length) { + Reply.decode = function decode(reader, length) { if (!(reader instanceof $Reader)) reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.action_cable.Message(); + let end = length === undefined ? reader.len : reader.pos + length, message = new $root.action_cable.Reply(); while (reader.pos < end) { let tag = reader.uint32(); switch (tag >>> 3) { - case 1: - message.type = reader.int32(); - break; - case 2: - message.command = reader.int32(); - break; - case 3: - message.identifier = reader.string(); - break; - case 4: - message.data = reader.string(); - break; - case 5: - message.message = reader.bytes(); - break; - case 6: - message.reason = reader.string(); - break; - case 7: - message.reconnect = reader.bool(); - break; + case 1: { + message.type = reader.int32(); + break; + } + case 2: { + message.identifier = reader.string(); + break; + } + case 3: { + message.message = reader.bytes(); + break; + } + case 4: { + message.reason = reader.string(); + break; + } + case 5: { + message.reconnect = reader.bool(); + break; + } + case 6: { + message.stream_id = reader.string(); + break; + } + case 7: { + message.epoch = reader.string(); + break; + } + case 8: { + message.offset = reader.int64(); + break; + } + case 9: { + message.sid = reader.string(); + break; + } + case 10: { + message.restored = reader.bool(); + break; + } + case 11: { + if (!(message.restored_ids && message.restored_ids.length)) + message.restored_ids = []; + message.restored_ids.push(reader.string()); + break; + } default: reader.skipType(tag & 7); break; @@ -244,30 +1316,30 @@ export const action_cable = $root.action_cable = (() => { }; /** - * Decodes a Message message from the specified reader or buffer, length delimited. + * Decodes a Reply message from the specified reader or buffer, length delimited. * @function decodeDelimited - * @memberof action_cable.Message + * @memberof action_cable.Reply * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {action_cable.Message} Message + * @returns {action_cable.Reply} Reply * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ - Message.decodeDelimited = function decodeDelimited(reader) { + Reply.decodeDelimited = function decodeDelimited(reader) { if (!(reader instanceof $Reader)) reader = new $Reader(reader); return this.decode(reader, reader.uint32()); }; /** - * Verifies a Message message. + * Verifies a Reply message. * @function verify - * @memberof action_cable.Message + * @memberof action_cable.Reply * @static * @param {Object.} message Plain object to verify * @returns {string|null} `null` if valid, otherwise the reason why it is not */ - Message.verify = function verify(message) { + Reply.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; if (message.type != null && message.hasOwnProperty("type")) @@ -280,24 +1352,13 @@ export const action_cable = $root.action_cable = (() => { case 3: case 4: case 5: - break; - } - if (message.command != null && message.hasOwnProperty("command")) - switch (message.command) { - default: - return "command: enum value expected"; - case 0: - case 1: - case 2: - case 3: + case 6: + case 7: break; } if (message.identifier != null && message.hasOwnProperty("identifier")) if (!$util.isString(message.identifier)) return "identifier: string expected"; - if (message.data != null && message.hasOwnProperty("data")) - if (!$util.isString(message.data)) - return "data: string expected"; if (message.message != null && message.hasOwnProperty("message")) if (!(message.message && typeof message.message.length === "number" || $util.isString(message.message))) return "message: buffer expected"; @@ -307,22 +1368,50 @@ export const action_cable = $root.action_cable = (() => { if (message.reconnect != null && message.hasOwnProperty("reconnect")) if (typeof message.reconnect !== "boolean") return "reconnect: boolean expected"; + if (message.stream_id != null && message.hasOwnProperty("stream_id")) + if (!$util.isString(message.stream_id)) + return "stream_id: string expected"; + if (message.epoch != null && message.hasOwnProperty("epoch")) + if (!$util.isString(message.epoch)) + return "epoch: string expected"; + if (message.offset != null && message.hasOwnProperty("offset")) + if (!$util.isInteger(message.offset) && !(message.offset && $util.isInteger(message.offset.low) && $util.isInteger(message.offset.high))) + return "offset: integer|Long expected"; + if (message.sid != null && message.hasOwnProperty("sid")) + if (!$util.isString(message.sid)) + return "sid: string expected"; + if (message.restored != null && message.hasOwnProperty("restored")) + if (typeof message.restored !== "boolean") + return "restored: boolean expected"; + if (message.restored_ids != null && message.hasOwnProperty("restored_ids")) { + if (!Array.isArray(message.restored_ids)) + return "restored_ids: array expected"; + for (let i = 0; i < message.restored_ids.length; ++i) + if (!$util.isString(message.restored_ids[i])) + return "restored_ids: string[] expected"; + } return null; }; /** - * Creates a Message message from a plain object. Also converts values to their respective internal types. + * Creates a Reply message from a plain object. Also converts values to their respective internal types. * @function fromObject - * @memberof action_cable.Message + * @memberof action_cable.Reply * @static * @param {Object.} object Plain object - * @returns {action_cable.Message} Message + * @returns {action_cable.Reply} Reply */ - Message.fromObject = function fromObject(object) { - if (object instanceof $root.action_cable.Message) + Reply.fromObject = function fromObject(object) { + if (object instanceof $root.action_cable.Reply) return object; - let message = new $root.action_cable.Message(); + let message = new $root.action_cable.Reply(); switch (object.type) { + default: + if (typeof object.type === "number") { + message.type = object.type; + break; + } + break; case "no_type": case 0: message.type = 0; @@ -347,59 +1436,71 @@ export const action_cable = $root.action_cable = (() => { case 5: message.type = 5; break; - } - switch (object.command) { - case "unknown_command": - case 0: - message.command = 0; - break; - case "subscribe": - case 1: - message.command = 1; - break; - case "unsubscribe": - case 2: - message.command = 2; + case "confirm_history": + case 6: + message.type = 6; break; - case "message": - case 3: - message.command = 3; + case "reject_history": + case 7: + message.type = 7; break; } if (object.identifier != null) message.identifier = String(object.identifier); - if (object.data != null) - message.data = String(object.data); if (object.message != null) if (typeof object.message === "string") $util.base64.decode(object.message, message.message = $util.newBuffer($util.base64.length(object.message)), 0); - else if (object.message.length) + else if (object.message.length >= 0) message.message = object.message; if (object.reason != null) message.reason = String(object.reason); if (object.reconnect != null) message.reconnect = Boolean(object.reconnect); + if (object.stream_id != null) + message.stream_id = String(object.stream_id); + if (object.epoch != null) + message.epoch = String(object.epoch); + if (object.offset != null) + if ($util.Long) + (message.offset = $util.Long.fromValue(object.offset)).unsigned = false; + else if (typeof object.offset === "string") + message.offset = parseInt(object.offset, 10); + else if (typeof object.offset === "number") + message.offset = object.offset; + else if (typeof object.offset === "object") + message.offset = new $util.LongBits(object.offset.low >>> 0, object.offset.high >>> 0).toNumber(); + if (object.sid != null) + message.sid = String(object.sid); + if (object.restored != null) + message.restored = Boolean(object.restored); + if (object.restored_ids) { + if (!Array.isArray(object.restored_ids)) + throw TypeError(".action_cable.Reply.restored_ids: array expected"); + message.restored_ids = []; + for (let i = 0; i < object.restored_ids.length; ++i) + message.restored_ids[i] = String(object.restored_ids[i]); + } return message; }; /** - * Creates a plain object from a Message message. Also converts values to other types if specified. + * Creates a plain object from a Reply message. Also converts values to other types if specified. * @function toObject - * @memberof action_cable.Message + * @memberof action_cable.Reply * @static - * @param {action_cable.Message} message Message + * @param {action_cable.Reply} message Reply * @param {$protobuf.IConversionOptions} [options] Conversion options * @returns {Object.} Plain object */ - Message.toObject = function toObject(message, options) { + Reply.toObject = function toObject(message, options) { if (!options) options = {}; let object = {}; + if (options.arrays || options.defaults) + object.restored_ids = []; if (options.defaults) { object.type = options.enums === String ? "no_type" : 0; - object.command = options.enums === String ? "unknown_command" : 0; object.identifier = ""; - object.data = ""; if (options.bytes === String) object.message = ""; else { @@ -409,36 +1510,74 @@ export const action_cable = $root.action_cable = (() => { } object.reason = ""; object.reconnect = false; + object.stream_id = ""; + object.epoch = ""; + if ($util.Long) { + let long = new $util.Long(0, 0, false); + object.offset = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.offset = options.longs === String ? "0" : 0; + object.sid = ""; + object.restored = false; } if (message.type != null && message.hasOwnProperty("type")) - object.type = options.enums === String ? $root.action_cable.Type[message.type] : message.type; - if (message.command != null && message.hasOwnProperty("command")) - object.command = options.enums === String ? $root.action_cable.Command[message.command] : message.command; + object.type = options.enums === String ? $root.action_cable.Type[message.type] === undefined ? message.type : $root.action_cable.Type[message.type] : message.type; if (message.identifier != null && message.hasOwnProperty("identifier")) object.identifier = message.identifier; - if (message.data != null && message.hasOwnProperty("data")) - object.data = message.data; if (message.message != null && message.hasOwnProperty("message")) object.message = options.bytes === String ? $util.base64.encode(message.message, 0, message.message.length) : options.bytes === Array ? Array.prototype.slice.call(message.message) : message.message; if (message.reason != null && message.hasOwnProperty("reason")) object.reason = message.reason; if (message.reconnect != null && message.hasOwnProperty("reconnect")) object.reconnect = message.reconnect; + if (message.stream_id != null && message.hasOwnProperty("stream_id")) + object.stream_id = message.stream_id; + if (message.epoch != null && message.hasOwnProperty("epoch")) + object.epoch = message.epoch; + if (message.offset != null && message.hasOwnProperty("offset")) + if (typeof message.offset === "number") + object.offset = options.longs === String ? String(message.offset) : message.offset; + else + object.offset = options.longs === String ? $util.Long.prototype.toString.call(message.offset) : options.longs === Number ? new $util.LongBits(message.offset.low >>> 0, message.offset.high >>> 0).toNumber() : message.offset; + if (message.sid != null && message.hasOwnProperty("sid")) + object.sid = message.sid; + if (message.restored != null && message.hasOwnProperty("restored")) + object.restored = message.restored; + if (message.restored_ids && message.restored_ids.length) { + object.restored_ids = []; + for (let j = 0; j < message.restored_ids.length; ++j) + object.restored_ids[j] = message.restored_ids[j]; + } return object; }; /** - * Converts this Message to JSON. + * Converts this Reply to JSON. * @function toJSON - * @memberof action_cable.Message + * @memberof action_cable.Reply * @instance * @returns {Object.} JSON object */ - Message.prototype.toJSON = function toJSON() { + Reply.prototype.toJSON = function toJSON() { return this.constructor.toObject(this, $protobuf.util.toJSONOptions); }; - return Message; + /** + * Gets the default type url for Reply + * @function getTypeUrl + * @memberof action_cable.Reply + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + Reply.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/action_cable.Reply"; + }; + + return Reply; })(); return action_cable; diff --git a/packages/protobuf-encoder/index.d.ts b/packages/protobuf-encoder/index.d.ts index fc1aa1c..46d6fe6 100644 --- a/packages/protobuf-encoder/index.d.ts +++ b/packages/protobuf-encoder/index.d.ts @@ -1,4 +1,5 @@ import { Encoder } from '@anycable/core' +import { off } from 'process' export interface MessageObject { command?: string @@ -9,6 +10,19 @@ export interface MessageObject { reconnect?: boolean } +export interface ReplyObject { + type?: string + message?: object + identifier?: string + reason?: string + reconnect?: boolean + stream_id?: string + epoch?: string + offset?: number + restored_ids?: string[] + restored?: bool +} + export class EnumWrapper { constructor(values: object) getIdByValue(value: string): number @@ -19,3 +33,5 @@ export class ProtobufEncoder implements Encoder { encode(msg: MessageObject): Uint8Array decode(raw: Uint8Array): MessageObject | void } + +export class ProtobufEncoderV2 extends ProtobufEncoder {} diff --git a/packages/protobuf-encoder/index.js b/packages/protobuf-encoder/index.js index 1d13596..ce3fd4a 100644 --- a/packages/protobuf-encoder/index.js +++ b/packages/protobuf-encoder/index.js @@ -4,6 +4,7 @@ import { action_cable as protos } from './generated/message_pb.js' import { EnumWrapper } from './enum_wrapper.js' const Message = protos.Message +const Reply = protos.Reply const MessageType = new EnumWrapper(protos.Type) const Command = new EnumWrapper(protos.Command) @@ -29,7 +30,7 @@ export class ProtobufEncoder { /* eslint-disable consistent-return */ decode(data) { try { - let decodedMessage = Message.decode(data) + let decodedMessage = this.decodeReply(data) // We can't skip check for presence here, since enums always have // zero value by default in protobuf, even if nothing was passed @@ -43,4 +44,15 @@ export class ProtobufEncoder { return decodedMessage } catch (_e) {} } + + decodeReply(data) { + return Message.decode(data) + } +} + +export class ProtobufEncoderV2 extends ProtobufEncoder { + decodeReply(data) { + let decoded = Reply.decode(data) + return decoded + } } diff --git a/packages/protobuf-encoder/index.test.ts b/packages/protobuf-encoder/index.test.ts index 6bb9686..3f2fff5 100644 --- a/packages/protobuf-encoder/index.test.ts +++ b/packages/protobuf-encoder/index.test.ts @@ -1,117 +1,166 @@ import msgpack from '@ygoe/msgpack' -import { ProtobufEncoder, MessageObject } from './' +import { + ProtobufEncoder, + ProtobufEncoderV2, + MessageObject, + ReplyObject +} from './' import { action_cable as protos } from './generated/message_pb.js' import { TestTransport } from '../core/transport/testing' import { createCable } from '../core/create-cable' import { Channel } from '../core/channel' +import { Cable } from '../core/cable' +import { Encoder } from '../core/encoder' +import exp from 'constants' const Message = protos.Message -const MessageType = protos.Type +const Reply = protos.Reply const Command = protos.Command -const transport = new TestTransport('ws:///') -const encoder = new ProtobufEncoder() - -let cable = createCable({ - transport, - protocol: 'actioncable-v1-protobuf', - encoder -}) - class TestChannel extends Channel<{ id: string }> { static identifier = 'test' } -let subscribeAndSendPromise: Promise -let channel: TestChannel -const payload = { foo: 1, bar: 'baz' } -const action = 'test' -const identifier = JSON.stringify({ channel: 'test', id: '21' }) - -describe('encode', () => { - it('raises error on invalid input', () => { - expect(() => { - // We ignore TypeScript here to pass a property - // with a wrong type in order to break encoding - // @ts-ignore - encoder.encode({ identifier: 1 }) - }).toThrow('identifier: string expected') - }) +describe('ProtobufEncoder', () => { + let encoder: Encoder - describe('enum encoding', () => { - it('sets enum values to 0, if no values provided', () => { - let encoded = encoder.encode({}) - let decoded = Message.decode(encoded) + beforeEach(() => { + encoder = new ProtobufEncoder() + }) - // Zero is default value for enums by Protobuf protocol - expect(decoded.command).toBe(0) - expect(decoded.type).toBe(0) + describe('encode', () => { + it('raises error on invalid input', () => { + expect(() => { + // We ignore TypeScript here to pass a property + // with a wrong type in order to break encoding + // @ts-ignore + encoder.encode({ identifier: 1 }) + }).toThrow('identifier: string expected') }) - it('converts enum values to ids', () => { - let encoded = encoder.encode({ - command: 'message', - // normally `type` and `command` aren't used together, - // here we just want to test everything at once - type: 'no_type' + describe('enum encoding', () => { + it('sets enum values to 0, if no values provided', () => { + let encoded = encoder.encode({}) + let decoded = Message.decode(encoded as Uint8Array) + + // Zero is default value for enums by Protobuf protocol + expect(decoded.command).toBe(0) + expect(decoded.type).toBe(0) }) - let decoded = Message.decode(encoded) + it('converts enum values to ids', () => { + let encoded = encoder.encode({ + command: 'message', + // normally `type` and `command` aren't used together, + // here we just want to test everything at once + type: 'no_type' + }) - expect(decoded.command).toEqual(3) - expect(decoded.type).toEqual(0) + let decoded = Message.decode(encoded as Uint8Array) + + expect(decoded.command).toEqual(3) + expect(decoded.type).toEqual(0) + }) }) - }) - describe('message field encoding', () => { - it('encodes message, using msgpack', () => { - let payload = { foo: 'bar', bar: 123 } - let encoded = encoder.encode({ message: payload }) - let decoded = Message.decode(encoded) + describe('message field encoding', () => { + it('encodes message, using msgpack', () => { + let payload = { foo: 'bar', bar: 123 } + let encoded = encoder.encode({ message: payload }) + let decoded = Message.decode(encoded as Uint8Array) - expect(msgpack.deserialize(decoded.message)).toEqual(payload) + expect(msgpack.deserialize(decoded.message)).toEqual(payload) + }) }) }) -}) -describe('decode', () => { - describe('enum decoding', () => { - it('converts enum ids to string names', () => { - // normally `type` and `command` aren't used together, - // here we just want to test everything at once - let encoded = Message.encode({ command: 3, type: 3 }).finish() - let decoded = encoder.decode(encoded) as MessageObject - - expect(decoded).toBeDefined() - expect(decoded.type).toEqual('ping') - expect(decoded.command).toEqual('message') + describe('decode', () => { + describe('enum decoding', () => { + it('converts enum ids to string names', () => { + // normally `type` and `command` aren't used together, + // here we just want to test everything at once + let encoded = Message.encode({ command: 3, type: 3 }).finish() + let decoded = encoder.decode(encoded) as MessageObject + + expect(decoded).toBeDefined() + expect(decoded.type).toEqual('ping') + expect(decoded.command).toEqual('message') + }) + + it('sets defaults, if no values provided', () => { + let encoded = Message.encode({}).finish() + let decoded = encoder.decode(encoded) as MessageObject + + expect(decoded).toBeDefined() + expect(decoded.type).toEqual('no_type') + expect(decoded.command).toEqual('unknown_command') + }) }) - it('sets defaults, if no values provided', () => { - let encoded = Message.encode({}).finish() - let decoded = encoder.decode(encoded) as MessageObject + describe('message field decoding', () => { + it('decodes message, using msgpack', () => { + let payload = { foo: 'bar', bar: 123 } + let encoded = Message.encode({ + message: msgpack.serialize(payload) + }).finish() + let decoded = encoder.decode(encoded) as MessageObject - expect(decoded).toBeDefined() - expect(decoded.type).toEqual('no_type') - expect(decoded.command).toEqual('unknown_command') + expect(decoded.message).toEqual(payload) + }) }) }) - describe('message field decoding', () => { - it('decodes message, using msgpack', () => { - let payload = { foo: 'bar', bar: 123 } - let encoded = Message.encode({ - message: msgpack.serialize(payload) - }).finish() - let decoded = encoder.decode(encoded) as MessageObject + describe('ProtobufEncoderV2', () => { + beforeEach(() => { + encoder = new ProtobufEncoderV2() + }) - expect(decoded.message).toEqual(payload) + describe('decoding reply', () => { + it('decodes', () => { + let payload = { foo: 'bar', bar: 123 } + let encoded = Reply.encode({ + identifier: 'test_channel', + stream_id: 'stream-123', + restored_ids: ['1'], + epoch: 'AD', + offset: 2023, + message: msgpack.serialize(payload) + }).finish() + let decoded = encoder.decode(encoded) as ReplyObject + + expect(decoded.message).toEqual(payload) + expect(decoded.identifier).toEqual('test_channel') + expect(decoded.stream_id).toEqual('stream-123') + expect(decoded.epoch).toEqual('AD') + expect(decoded.offset).toEqual(2023) + expect(decoded.restored_ids).toEqual(['1']) + }) }) }) }) describe('protobuf message e2e sending', () => { + let transport: TestTransport + let encoder: Encoder + let cable: Cable + let subscribeAndSendPromise: Promise + let channel: TestChannel + const payload = { foo: 1, bar: 'baz' } + const action = 'test' + const identifier = JSON.stringify({ channel: 'test', id: '21' }) + + beforeEach(() => { + transport = new TestTransport('ws:///') + encoder = new ProtobufEncoder() + + cable = createCable({ + transport, + protocol: 'actioncable-v1-ext-protobuf', + encoder + }) + }) + beforeEach(async () => { channel = new TestChannel({ id: '21' }) @@ -145,27 +194,31 @@ describe('protobuf message e2e sending', () => { expect(JSON.parse(decoded.data)).toEqual({ action, ...payload }) }) - it('decodes message properly', done => { + it('decodes message properly', async () => { let messageBody = { text: 'Lorem ipsum', author: 'John' } - channel.on('message', msg => { - try { - expect(msg).toEqual(messageBody) - done() - } catch (err) { - done(err) - } + let messagePromise = new Promise((resolve, reject) => { + channel.on('message', msg => { + try { + expect(msg).toEqual(messageBody) + resolve() + } catch (err) { + reject(err) + } + }) }) - subscribeAndSendPromise.then(() => { - let encodedMessage = encoder.encode({ - identifier, - type: 'no_type', - message: messageBody - }) + await subscribeAndSendPromise - // imitate message from the server - transport.receive(encodedMessage) - }) + let encodedMessage = encoder.encode({ + identifier, + type: 'no_type', + message: messageBody + })! + + // imitate message from the server + transport.receive(encodedMessage) + + await messagePromise }) }) diff --git a/packages/protobuf-encoder/message.proto b/packages/protobuf-encoder/message.proto index 00b7340..daf409d 100644 --- a/packages/protobuf-encoder/message.proto +++ b/packages/protobuf-encoder/message.proto @@ -9,6 +9,8 @@ enum Type { ping = 3; confirm_subscription = 4; reject_subscription = 5; + confirm_history = 6; + reject_history = 7; } enum Command { @@ -16,6 +18,18 @@ enum Command { subscribe = 1; unsubscribe = 2; message = 3; + history = 4; + pong = 5; +} + +message StreamHistoryRequest { + string epoch = 2; + int64 offset = 3; +} + +message HistoryRequest { + int64 since = 1; + map streams = 2; } message Message { @@ -25,9 +39,24 @@ message Message { // Data is a JSON encoded string. // This is by Action Cable protocol design. string data = 4; - // Message has not structure. + // Message has no structure. // We use Msgpack to encode/decode it. bytes message = 5; string reason = 6; bool reconnect = 7; + HistoryRequest history = 8; +} + +message Reply { + Type type = 1; + string identifier = 2; + bytes message = 3; + string reason = 4; + bool reconnect = 5; + string stream_id = 6; + string epoch = 7; + int64 offset = 8; + string sid = 9; + bool restored = 10; + repeated string restored_ids = 11; } diff --git a/packages/protobuf-encoder/package.json b/packages/protobuf-encoder/package.json index a7495f4..d7b03b3 100644 --- a/packages/protobuf-encoder/package.json +++ b/packages/protobuf-encoder/package.json @@ -20,7 +20,10 @@ }, "dependencies": { "@anycable/core": "^0.6.0", - "protobufjs": "^7.2.1", - "@ygoe/msgpack": "^1.0.0" + "@ygoe/msgpack": "^1.0.0", + "protobufjs": "^7.2.1" + }, + "devDependencies": { + "protobufjs-cli": "^1.1.1" } } diff --git a/yarn.lock b/yarn.lock index d8b7e2b..edefb3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -177,6 +177,11 @@ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz" integrity sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg== +"@babel/parser@^7.20.15": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55" + integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ== + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" @@ -608,6 +613,13 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jsdoc/salty@^0.2.1": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@jsdoc/salty/-/salty-0.2.5.tgz#1b2fa5bb8c66485b536d86eee877c263d322f692" + integrity sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw== + dependencies: + lodash "^4.17.21" + "@logux/eslint-config@^48.0.0": version "48.0.0" resolved "https://registry.npmjs.org/@logux/eslint-config/-/eslint-config-48.0.0.tgz" @@ -813,6 +825,24 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/linkify-it@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" + integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA== + +"@types/markdown-it@^12.2.3": + version "12.2.3" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" + integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ== + dependencies: + "@types/linkify-it" "*" + "@types/mdurl" "*" + +"@types/mdurl@*": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + "@types/node-fetch@^2.6.4": version "2.6.4" resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz" @@ -992,6 +1022,11 @@ acorn@^8.1.0, acorn@^8.8.0, acorn@^8.8.1: resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + agent-base@6: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -1171,6 +1206,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -1179,6 +1219,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" @@ -1255,6 +1302,13 @@ caniuse-lite@^1.0.30001449: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz" integrity sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew== +catharsis@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.9.0.tgz#40382a168be0e6da308c277d3a2b3eb40c7d2121" + integrity sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A== + dependencies: + lodash "^4.17.15" + chalk@^2.0.0: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -1510,6 +1564,11 @@ entities@^4.4.0: resolved "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz" integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== +entities@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" + integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" @@ -1601,6 +1660,18 @@ escape-string-regexp@^4.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +escodegen@^1.13.0: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + escodegen@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz" @@ -1790,6 +1861,11 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== +eslint-visitor-keys@^3.4.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz#8c2095440eca8c933bedcadf16fefa44dbe9ba5f" + integrity sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw== + eslint@^8.33.0: version "8.33.0" resolved "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz" @@ -1835,6 +1911,15 @@ eslint@^8.33.0: strip-json-comments "^3.1.0" text-table "^0.2.0" +espree@^9.0.0: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + espree@^9.4.0: version "9.4.1" resolved "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz" @@ -1863,7 +1948,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: +estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -2110,6 +2195,17 @@ glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + globals@^11.1.0: version "11.12.0" resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" @@ -2148,6 +2244,11 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +graceful-fs@^4.1.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" @@ -2912,6 +3013,34 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +js2xmlparser@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-4.0.2.tgz#2a1fdf01e90585ef2ae872a01bc169c6a8d5e60a" + integrity sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA== + dependencies: + xmlcreate "^2.0.4" + +jsdoc@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-4.0.2.tgz#a1273beba964cf433ddf7a70c23fd02c3c60296e" + integrity sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg== + dependencies: + "@babel/parser" "^7.20.15" + "@jsdoc/salty" "^0.2.1" + "@types/markdown-it" "^12.2.3" + bluebird "^3.7.2" + catharsis "^0.9.0" + escape-string-regexp "^2.0.0" + js2xmlparser "^4.0.2" + klaw "^3.0.0" + markdown-it "^12.3.2" + markdown-it-anchor "^8.4.1" + marked "^4.0.10" + mkdirp "^1.0.4" + requizzle "^0.2.3" + strip-json-comments "^3.1.0" + underscore "~1.13.2" + jsdom@^20.0.0: version "20.0.3" resolved "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz" @@ -2986,6 +3115,13 @@ json5@^2.2.2, json5@^2.2.3: resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +klaw@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" + integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== + dependencies: + graceful-fs "^4.1.9" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" @@ -3017,6 +3153,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +linkify-it@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e" + integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ== + dependencies: + uc.micro "^1.0.1" + locate-path@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" @@ -3041,7 +3184,7 @@ lodash.merge@^4.6.2: resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^4.17.21: +lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3084,6 +3227,32 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +markdown-it-anchor@^8.4.1: + version "8.6.7" + resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz#ee6926daf3ad1ed5e4e3968b1740eef1c6399634" + integrity sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA== + +markdown-it@^12.3.2: + version "12.3.2" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.3.2.tgz#bf92ac92283fe983fe4de8ff8abfb5ad72cd0c90" + integrity sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg== + dependencies: + argparse "^2.0.1" + entities "~2.1.0" + linkify-it "^3.0.1" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +marked@^4.0.10: + version "4.3.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" + integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== + +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" @@ -3131,11 +3300,23 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.7" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + ms@2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" @@ -3420,6 +3601,22 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +protobufjs-cli@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz#f531201b1c8c7772066aa822bf9a08318b24a704" + integrity sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA== + dependencies: + chalk "^4.0.0" + escodegen "^1.13.0" + espree "^9.0.0" + estraverse "^5.1.0" + glob "^8.0.0" + jsdoc "^4.0.0" + minimist "^1.2.0" + semver "^7.1.2" + tmp "^0.2.1" + uglify-js "^3.7.7" + protobufjs@^7.2.1: version "7.2.1" resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.1.tgz" @@ -3523,6 +3720,13 @@ requires-port@^1.0.0: resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== +requizzle@^0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.4.tgz#319eb658b28c370f0c20f968fa8ceab98c13d27c" + integrity sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw== + dependencies: + lodash "^4.17.21" + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" @@ -3559,7 +3763,7 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.2: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -3618,6 +3822,13 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.1.2: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -3819,6 +4030,13 @@ text-table@^0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + tmpl@1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" @@ -3947,6 +4165,16 @@ typescript@^4.9.5: resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +uglify-js@^3.7.7: + version "3.17.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" + integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== + unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" @@ -3957,6 +4185,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +underscore@~1.13.2: + version "1.13.6" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441" + integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== + unist-util-stringify-position@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz" @@ -4159,6 +4392,11 @@ xmlchars@^2.2.0: resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xmlcreate@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.4.tgz#0c5ab0f99cdd02a81065fa9cd8f8ae87624889be" + integrity sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"