UNPKG

@gojek/clickstream-web

Version:

A Modern, Fast, and Lightweight Event Ingestion library for Web

1,504 lines (1,424 loc) 75.6 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var $protobuf1 = require('protobufjs/minimal.js'); function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var $protobuf1__namespace = /*#__PURE__*/_interopNamespace($protobuf1); function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } /** * @typedef {object} EventConfig - Event configuration * @property {{instant: string[]}=} classification - event classification * @property {string=} group - product group name */ /** * @typedef {object} BatchConfig - Batch configuration * @property {number=} maxTimeBetweenTwoBatches - Maximum wait time between two batches * @property {number=} maxBatchSize - Maximum size of a batch * @property {string=} dbName - name for indexedDB */ /** * @typedef {object} NetworkConfig - Network configuration * @property {string | URL} url - base url * @property {Headers} headers - request headers * @property {number=} maxRetries - max retries * @property {number=} timeBetweenTwoRetries - time in seconds between two retries * @property {number=} timeToResumeRetries - time in seconds to resume retries */ /** * @typedef {object} Config - Configuration * @property {EventConfig=} event - event configurations * @property {BatchConfig=} batch - batch configurations * @property {NetworkConfig} network - network configurations * @property {object=} crypto - crypto module instance * @property {Boolean=} debug - debug option */ /** @type {Config} } */ const defaultConfig = { event: { classification: { instant: [] }, group: "" }, batch: { // max interval time between two batches, in seconds maxTimeBetweenTwoBatches: 10, // max size of batch, in bytes maxBatchSize: 50000, // name for indexedDB, must be unique per domain dbName: "clickstream_db" }, network: { url: "", headers: new Headers({}), // max number of retries before pausing maxRetries: 5, // gap between two retries (mSec) timeBetweenTwoRetries: 1000, // time after which retry will resume after hitting max retry count threshold (mSec) timeToResumeRetries: 20000 }, crypto: null }; const EVENT_TYPE = { INSTANT: "instant", REALTIME: "realTime" }; const CUSTOM_EVENT = { BATCH_CREATED: "batchCreated", BATCH_FAILED: "batchFailed" }; const TICK_TIME = 1000; const errorCodes = { CLICKSTREAM_ERROR: "clickstreamError", VALIDATION_ERROR: "validationError", DATABASE_ERROR: "databaseError", NETWORK_ERROR: "networkError", TRACKING_ERROR: "trackingError", CLEANUP_ERROR: "cleanupError" }; const errorNames = { CLICKSTREAM_ERROR: "Clickstream Error", VALIDATION_ERROR: "Validation Error", DATABASE_ERROR: "Database Error", NETWORK_ERROR: "Network Error", TRACKING_ERROR: "Tracking Error", CLEANUP_ERROR: "Cleanup Error" }; class ClickstreamError extends Error { constructor(message, options) { super(message, options); this.name = options?.name ?? errorNames.CLICKSTREAM_ERROR; this.code = options?.code ?? errorCodes.CLICKSTREAM_ERROR; } } class ValidationError extends ClickstreamError { constructor(message, options) { super(message, options); this.name = errorNames.VALIDATION_ERROR; this.code = errorCodes.VALIDATION_ERROR; } } class DatabaseError extends ClickstreamError { constructor(message, options) { super(message, options); this.name = errorNames.DATABASE_ERROR; this.code = errorCodes.DATABASE_ERROR; } } class NetworkError extends ClickstreamError { constructor(message, options) { super(message, options); this.name = errorNames.NETWORK_ERROR; this.code = errorCodes.NETWORK_ERROR; } } // @ts-nocheck let $protobuf; if ($protobuf1__namespace.default) { $protobuf = $protobuf1__namespace.default; } // Common aliases const $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; // Exported root namespace const $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); /** * @type {Class} */ $root.EventService = (() => { /** * Constructs a new EventService service. * @exports EventService * @classdesc Represents an EventService * @extends $protobuf.rpc.Service * @constructor * @param {$protobuf.RPCImpl} rpcImpl RPC implementation * @param {boolean} [requestDelimited=false] Whether requests are length-delimited * @param {boolean} [responseDelimited=false] Whether responses are length-delimited */ function EventService(rpcImpl, requestDelimited, responseDelimited) { $protobuf.rpc.Service.call(this, rpcImpl, requestDelimited, responseDelimited); } (EventService.prototype = Object.create($protobuf.rpc.Service.prototype)).constructor = EventService; /** * Creates new EventService service using the specified rpc implementation. * @function create * @memberof EventService * @static * @param {$protobuf.RPCImpl} rpcImpl RPC implementation * @param {boolean} [requestDelimited=false] Whether requests are length-delimited * @param {boolean} [responseDelimited=false] Whether responses are length-delimited * @returns {EventService} RPC service. Useful where requests and/or responses are streamed. */ EventService.create = function create(rpcImpl, requestDelimited, responseDelimited) { return new this(rpcImpl, requestDelimited, responseDelimited); }; /** * Callback as used by {@link EventService#sendEvent}. * @memberof EventService * @typedef SendEventCallback * @type {function} * @param {Error|null} error Error, if any * @param {SendEventResponse} [response] SendEventResponse */ /** * Calls SendEvent. * @function sendEvent * @memberof EventService * @instance * @param {ISendEventRequest} request SendEventRequest message or plain object * @param {EventService.SendEventCallback} callback Node-style callback called with the error, if any, and SendEventResponse * @returns {undefined} * @variation 1 */ Object.defineProperty(EventService.prototype.sendEvent = function sendEvent(request, callback) { return this.rpcCall(sendEvent, $root.SendEventRequest, $root.SendEventResponse, request, callback); }, "name", { value: "SendEvent" }); /** * Calls SendEvent. * @function sendEvent * @memberof EventService * @instance * @param {ISendEventRequest} request SendEventRequest message or plain object * @returns {Promise<SendEventResponse>} Promise * @variation 2 */ return EventService; })(); /** * @type {Class} */ const SendEventRequest = $root.SendEventRequest = (() => { /** * Properties of a SendEventRequest. * @exports ISendEventRequest * @interface ISendEventRequest * @property {string|null} [reqGuid] SendEventRequest reqGuid * @property {ITimestamp|null} [sentTime] SendEventRequest sentTime * @property {Array.<IEvent>|null} [events] SendEventRequest events */ /** * Constructs a new SendEventRequest. * @exports SendEventRequest * @classdesc Represents a SendEventRequest. * @implements ISendEventRequest * @constructor * @param {ISendEventRequest=} [properties] Properties to set */ function SendEventRequest(properties) { this.events = []; 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]]; } /** * SendEventRequest reqGuid. * @member {string} reqGuid * @memberof SendEventRequest * @instance */ SendEventRequest.prototype.reqGuid = ""; /** * SendEventRequest sentTime. * @member {ITimestamp|null|undefined} sentTime * @memberof SendEventRequest * @instance */ SendEventRequest.prototype.sentTime = null; /** * SendEventRequest events. * @member {Array.<IEvent>} events * @memberof SendEventRequest * @instance */ SendEventRequest.prototype.events = $util.emptyArray; /** * Creates a new SendEventRequest instance using the specified properties. * @function create * @memberof SendEventRequest * @static * @param {ISendEventRequest=} [properties] Properties to set * @returns {SendEventRequest} SendEventRequest instance */ SendEventRequest.create = function create(properties) { return new SendEventRequest(properties); }; /** * Encodes the specified SendEventRequest message. Does not implicitly {@link SendEventRequest.verify|verify} messages. * @function encode * @memberof SendEventRequest * @static * @param {ISendEventRequest} message SendEventRequest message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ SendEventRequest.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); if (message.reqGuid != null && Object.hasOwnProperty.call(message, "reqGuid")) writer.uint32( /* id 1, wireType 2 =*/10).string(message.reqGuid); if (message.sentTime != null && Object.hasOwnProperty.call(message, "sentTime")) $root.Timestamp.encode(message.sentTime, writer.uint32( /* id 2, wireType 2 =*/18).fork()).ldelim(); if (message.events != null && message.events.length) for (let i = 0; i < message.events.length; ++i) $root.Event.encode(message.events[i], writer.uint32( /* id 3, wireType 2 =*/26).fork()).ldelim(); return writer; }; /** * Decodes a SendEventRequest message from the specified reader or buffer. * @function decode * @memberof SendEventRequest * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @param {number} [length] Message length if known beforehand * @returns {SendEventRequest} SendEventRequest * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ SendEventRequest.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.SendEventRequest(); while (reader.pos < end) { let tag = reader.uint32(); switch (tag >>> 3) { case 1: { message.reqGuid = reader.string(); break; } case 2: { message.sentTime = $root.Timestamp.decode(reader, reader.uint32()); break; } case 3: { if (!(message.events && message.events.length)) message.events = []; message.events.push($root.Event.decode(reader, reader.uint32())); break; } default: reader.skipType(tag & 7); break; } } return message; }; /** * Verifies a SendEventRequest message. * @function verify * @memberof SendEventRequest * @static * @param {Object.<string,*>} message Plain object to verify * @returns {string|null} `null` if valid, otherwise the reason why it is not */ SendEventRequest.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; if (message.reqGuid != null && message.hasOwnProperty("reqGuid")) if (!$util.isString(message.reqGuid)) return "reqGuid: string expected"; if (message.sentTime != null && message.hasOwnProperty("sentTime")) { let error = $root.Timestamp.verify(message.sentTime); if (error) return "sentTime." + error; } if (message.events != null && message.hasOwnProperty("events")) { if (!Array.isArray(message.events)) return "events: array expected"; for (let i = 0; i < message.events.length; ++i) { let error = $root.Event.verify(message.events[i]); if (error) return "events." + error; } } return null; }; /** * Gets the default type url for SendEventRequest * @function getTypeUrl * @memberof SendEventRequest * @static * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") * @returns {string} The default type url */ SendEventRequest.getTypeUrl = function getTypeUrl(typeUrlPrefix) { if (typeUrlPrefix === undefined) { typeUrlPrefix = "type.googleapis.com"; } return typeUrlPrefix + "/SendEventRequest"; }; return SendEventRequest; })(); /** * @type {Class} */ $root.Timestamp = (() => { /** * Properties of a Timestamp. * @exports ITimestamp * @interface ITimestamp * @property {number|Long|null} [seconds] Timestamp seconds * @property {number|null} [nanos] Timestamp nanos */ /** * Constructs a new Timestamp. * @exports Timestamp * @classdesc Represents a Timestamp. * @implements ITimestamp * @constructor * @param {ITimestamp=} [properties] Properties to set */ function Timestamp(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]]; } /** * Timestamp seconds. * @member {number|Long} seconds * @memberof Timestamp * @instance */ Timestamp.prototype.seconds = $util.Long ? $util.Long.fromBits(0, 0, false) : 0; /** * Timestamp nanos. * @member {number} nanos * @memberof Timestamp * @instance */ Timestamp.prototype.nanos = 0; /** * Creates a new Timestamp instance using the specified properties. * @function create * @memberof Timestamp * @static * @param {ITimestamp=} [properties] Properties to set * @returns {Timestamp} Timestamp instance */ Timestamp.create = function create(properties) { return new Timestamp(properties); }; /** * Encodes the specified Timestamp message. Does not implicitly {@link Timestamp.verify|verify} messages. * @function encode * @memberof Timestamp * @static * @param {ITimestamp} message Timestamp message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ Timestamp.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); if (message.seconds != null && Object.hasOwnProperty.call(message, "seconds")) writer.uint32( /* id 1, wireType 0 =*/8).int64(message.seconds); if (message.nanos != null && Object.hasOwnProperty.call(message, "nanos")) writer.uint32( /* id 2, wireType 0 =*/16).int32(message.nanos); return writer; }; /** * Decodes a Timestamp message from the specified reader or buffer. * @function decode * @memberof Timestamp * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @param {number} [length] Message length if known beforehand * @returns {Timestamp} Timestamp * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ Timestamp.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.Timestamp(); while (reader.pos < end) { let tag = reader.uint32(); switch (tag >>> 3) { case 1: { message.seconds = reader.int64(); break; } case 2: { message.nanos = reader.int32(); break; } default: reader.skipType(tag & 7); break; } } return message; }; /** * Verifies a Timestamp message. * @function verify * @memberof Timestamp * @static * @param {Object.<string,*>} message Plain object to verify * @returns {string|null} `null` if valid, otherwise the reason why it is not */ Timestamp.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; if (message.seconds != null && message.hasOwnProperty("seconds")) if (!$util.isInteger(message.seconds) && !(message.seconds && $util.isInteger(message.seconds.low) && $util.isInteger(message.seconds.high))) return "seconds: integer|Long expected"; if (message.nanos != null && message.hasOwnProperty("nanos")) if (!$util.isInteger(message.nanos)) return "nanos: integer expected"; return null; }; /** * Gets the default type url for Timestamp * @function getTypeUrl * @memberof Timestamp * @static * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") * @returns {string} The default type url */ Timestamp.getTypeUrl = function getTypeUrl(typeUrlPrefix) { if (typeUrlPrefix === undefined) { typeUrlPrefix = "type.googleapis.com"; } return typeUrlPrefix + "/Timestamp"; }; return Timestamp; })(); /** * @type {Class} */ const Event = $root.Event = (() => { /** * Properties of an Event. * @exports IEvent * @interface IEvent * @property {Uint8Array|null} [eventBytes] Event eventBytes * @property {string|null} [type] Event type */ /** * Constructs a new Event. * @exports Event * @classdesc Represents an Event. * @implements IEvent * @constructor * @param {IEvent=} [properties] Properties to set */ function Event(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]]; } /** * Event eventBytes. * @member {Uint8Array} eventBytes * @memberof Event * @instance */ Event.prototype.eventBytes = $util.newBuffer([]); /** * Event type. * @member {string} type * @memberof Event * @instance */ Event.prototype.type = ""; /** * Creates a new Event instance using the specified properties. * @function create * @memberof Event * @static * @param {IEvent=} [properties] Properties to set * @returns {Event} Event instance */ Event.create = function create(properties) { return new Event(properties); }; /** * Encodes the specified Event message. Does not implicitly {@link Event.verify|verify} messages. * @function encode * @memberof Event * @static * @param {IEvent} message Event message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ Event.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); if (message.eventBytes != null && Object.hasOwnProperty.call(message, "eventBytes")) writer.uint32( /* id 1, wireType 2 =*/10).bytes(message.eventBytes); if (message.type != null && Object.hasOwnProperty.call(message, "type")) writer.uint32( /* id 2, wireType 2 =*/18).string(message.type); return writer; }; /** * Decodes an Event message from the specified reader or buffer. * @function decode * @memberof Event * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @param {number} [length] Message length if known beforehand * @returns {Event} Event * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ Event.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.Event(); while (reader.pos < end) { let tag = reader.uint32(); switch (tag >>> 3) { case 1: { message.eventBytes = reader.bytes(); break; } case 2: { message.type = reader.string(); break; } default: reader.skipType(tag & 7); break; } } return message; }; /** * Verifies an Event message. * @function verify * @memberof Event * @static * @param {Object.<string,*>} message Plain object to verify * @returns {string|null} `null` if valid, otherwise the reason why it is not */ Event.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; if (message.eventBytes != null && message.hasOwnProperty("eventBytes")) if (!(message.eventBytes && typeof message.eventBytes.length === "number" || $util.isString(message.eventBytes))) return "eventBytes: buffer expected"; if (message.type != null && message.hasOwnProperty("type")) if (!$util.isString(message.type)) return "type: string expected"; return null; }; /** * Gets the default type url for Event * @function getTypeUrl * @memberof Event * @static * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") * @returns {string} The default type url */ Event.getTypeUrl = function getTypeUrl(typeUrlPrefix) { if (typeUrlPrefix === undefined) { typeUrlPrefix = "type.googleapis.com"; } return typeUrlPrefix + "/Event"; }; return Event; })(); /** * @type Class */ const SendEventResponse = $root.SendEventResponse = (() => { /** * Properties of a SendEventResponse. * @exports ISendEventResponse * @interface ISendEventResponse * @property {Status|null} [status] SendEventResponse status * @property {Code|null} [code] SendEventResponse code * @property {number|Long|null} [sentTime] SendEventResponse sentTime * @property {string|null} [reason] SendEventResponse reason * @property {Object.<string,string>|null} [data] SendEventResponse data */ /** * Constructs a new SendEventResponse. * @exports SendEventResponse * @classdesc Represents a SendEventResponse. * @implements ISendEventResponse * @constructor * @param {ISendEventResponse=} [properties] Properties to set */ function SendEventResponse(properties) { this.data = {}; 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]]; } /** * SendEventResponse status. * @member {Status} status * @memberof SendEventResponse * @instance */ SendEventResponse.prototype.status = 0; /** * SendEventResponse code. * @member {Code} code * @memberof SendEventResponse * @instance */ SendEventResponse.prototype.code = 0; /** * SendEventResponse sentTime. * @member {number|Long} sentTime * @memberof SendEventResponse * @instance */ SendEventResponse.prototype.sentTime = $util.Long ? $util.Long.fromBits(0, 0, false) : 0; /** * SendEventResponse reason. * @member {string} reason * @memberof SendEventResponse * @instance */ SendEventResponse.prototype.reason = ""; /** * SendEventResponse data. * @member {Object.<string,string>} data * @memberof SendEventResponse * @instance */ SendEventResponse.prototype.data = $util.emptyObject; /** * Creates a new SendEventResponse instance using the specified properties. * @function create * @memberof SendEventResponse * @static * @param {ISendEventResponse=} [properties] Properties to set * @returns {SendEventResponse} SendEventResponse instance */ SendEventResponse.create = function create(properties) { return new SendEventResponse(properties); }; /** * Encodes the specified SendEventResponse message. Does not implicitly {@link SendEventResponse.verify|verify} messages. * @function encode * @memberof SendEventResponse * @static * @param {ISendEventResponse} message SendEventResponse message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ SendEventResponse.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); if (message.status != null && Object.hasOwnProperty.call(message, "status")) writer.uint32( /* id 1, wireType 0 =*/8).int32(message.status); if (message.code != null && Object.hasOwnProperty.call(message, "code")) writer.uint32( /* id 2, wireType 0 =*/16).int32(message.code); if (message.sentTime != null && Object.hasOwnProperty.call(message, "sentTime")) writer.uint32( /* id 3, wireType 0 =*/24).int64(message.sentTime); if (message.reason != null && Object.hasOwnProperty.call(message, "reason")) writer.uint32( /* id 4, wireType 2 =*/34).string(message.reason); if (message.data != null && Object.hasOwnProperty.call(message, "data")) for (let keys = Object.keys(message.data), i = 0; i < keys.length; ++i) writer.uint32( /* id 5, wireType 2 =*/42).fork().uint32( /* id 1, wireType 2 =*/10).string(keys[i]).uint32( /* id 2, wireType 2 =*/18).string(message.data[keys[i]]).ldelim(); return writer; }; /** * Decodes a SendEventResponse message from the specified reader or buffer. * @function decode * @memberof SendEventResponse * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @param {number} [length] Message length if known beforehand * @returns {SendEventResponse} SendEventResponse * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ SendEventResponse.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.SendEventResponse(), key, value; while (reader.pos < end) { let tag = reader.uint32(); switch (tag >>> 3) { case 1: { message.status = reader.int32(); break; } case 2: { message.code = reader.int32(); break; } case 3: { message.sentTime = reader.int64(); break; } case 4: { message.reason = reader.string(); break; } case 5: { if (message.data === $util.emptyObject) message.data = {}; let end2 = reader.uint32() + reader.pos; key = ""; value = ""; while (reader.pos < end2) { let tag2 = reader.uint32(); switch (tag2 >>> 3) { case 1: key = reader.string(); break; case 2: value = reader.string(); break; default: reader.skipType(tag2 & 7); break; } } message.data[key] = value; break; } default: reader.skipType(tag & 7); break; } } return message; }; /** * Verifies a SendEventResponse message. * @function verify * @memberof SendEventResponse * @static * @param {Object.<string,*>} message Plain object to verify * @returns {string|null} `null` if valid, otherwise the reason why it is not */ SendEventResponse.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; if (message.status != null && message.hasOwnProperty("status")) switch (message.status) { default: return "status: enum value expected"; case 0: case 1: case 2: break; } if (message.code != null && message.hasOwnProperty("code")) switch (message.code) { default: return "code: enum value expected"; case 0: case 1: case 2: case 3: case 4: case 5: break; } if (message.sentTime != null && message.hasOwnProperty("sentTime")) if (!$util.isInteger(message.sentTime) && !(message.sentTime && $util.isInteger(message.sentTime.low) && $util.isInteger(message.sentTime.high))) return "sentTime: integer|Long expected"; if (message.reason != null && message.hasOwnProperty("reason")) if (!$util.isString(message.reason)) return "reason: string expected"; if (message.data != null && message.hasOwnProperty("data")) { if (!$util.isObject(message.data)) return "data: object expected"; let key = Object.keys(message.data); for (let i = 0; i < key.length; ++i) if (!$util.isString(message.data[key[i]])) return "data: string{k:string} expected"; } return null; }; /** * Gets the default type url for SendEventResponse * @function getTypeUrl * @memberof SendEventResponse * @static * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") * @returns {string} The default type url */ SendEventResponse.getTypeUrl = function getTypeUrl(typeUrlPrefix) { if (typeUrlPrefix === undefined) { typeUrlPrefix = "type.googleapis.com"; } return typeUrlPrefix + "/SendEventResponse"; }; return SendEventResponse; })(); /** * Status enum. * @exports Status * @enum {number} * @property {number} STATUS_UNSPECIFIED=0 STATUS_UNSPECIFIED value * @property {number} STATUS_SUCCESS=1 STATUS_SUCCESS value * @property {number} STATUS_ERROR=2 STATUS_ERROR value */ $root.Status = (() => { const valuesById = {}, values = Object.create(valuesById); values[valuesById[0] = "STATUS_UNSPECIFIED"] = 0; values[valuesById[1] = "STATUS_SUCCESS"] = 1; values[valuesById[2] = "STATUS_ERROR"] = 2; return values; })(); /** * Code enum. * @exports Code * @enum {number} * @property {number} CODE_UNSPECIFIED=0 CODE_UNSPECIFIED value * @property {number} CODE_OK=1 CODE_OK value * @property {number} CODE_BAD_REQUEST=2 CODE_BAD_REQUEST value * @property {number} CODE_INTERNAL_ERROR=3 CODE_INTERNAL_ERROR value * @property {number} CODE_MAX_CONNECTION_LIMIT_REACHED=4 CODE_MAX_CONNECTION_LIMIT_REACHED value * @property {number} CODE_MAX_USER_LIMIT_REACHED=5 CODE_MAX_USER_LIMIT_REACHED value */ $root.Code = (() => { const valuesById = {}, values = Object.create(valuesById); values[valuesById[0] = "CODE_UNSPECIFIED"] = 0; values[valuesById[1] = "CODE_OK"] = 1; values[valuesById[2] = "CODE_BAD_REQUEST"] = 2; values[valuesById[3] = "CODE_INTERNAL_ERROR"] = 3; values[valuesById[4] = "CODE_MAX_CONNECTION_LIMIT_REACHED"] = 4; values[valuesById[5] = "CODE_MAX_USER_LIMIT_REACHED"] = 5; return values; })(); let logging = false; function format(prefix, args) { if (!prefix) return args; return [prefix, ...args]; } const info = function (prefix = "", ...args) { if (!logging) return; console.log(...format(prefix, args)); }; const debug = function (prefix = "", ...args) { if (!logging) return; console.debug(...format(prefix, args)); }; const warn = function (prefix = "", ...args) { if (!logging) return; console.warn(...format(prefix, args)); }; const error = function (prefix = "", ...args) { console.error(...format(prefix, args)); }; const logger = { info, debug, warn, error, get logging() { return logging; }, set logging(value) { logging = Boolean(value); } }; /** * Returns a promise that resolves with the content of a blob as an ArrayBuffer * * @param {Blob} blob blob content * @returns {Promise} */ const readAsBuffer = async blob => { if (blob.arrayBuffer) { return blob.arrayBuffer(); } return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => { // https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readyState if (reader.readyState === 2) { resolve(reader.result); } }; reader.onerror = err => reject(err); reader.readAsArrayBuffer(blob); }); }; const logPrefix$4 = "Network:"; /** * Gives timestamp object as google timestamp format * @returns timestamp object containing seconds */ const getTimestamp = () => { const date = new Date(); const seconds = Math.floor(date.getTime() / 1000); return { seconds }; }; var _config$2 = /*#__PURE__*/new WeakMap(); var _store$3 = /*#__PURE__*/new WeakMap(); var _eventBus$2 = /*#__PURE__*/new WeakMap(); var _id$2 = /*#__PURE__*/new WeakMap(); var _retryCount = /*#__PURE__*/new WeakMap(); var _resetRetryTimeout = /*#__PURE__*/new WeakMap(); var _createRequest = /*#__PURE__*/new WeakSet(); var _retry = /*#__PURE__*/new WeakSet(); var _makeRequest = /*#__PURE__*/new WeakSet(); class Transport { constructor({ config, eventBus, store, id }) { _classPrivateMethodInitSpec(this, _makeRequest); _classPrivateMethodInitSpec(this, _retry); _classPrivateMethodInitSpec(this, _createRequest); _classPrivateFieldInitSpec(this, _config$2, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _store$3, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _eventBus$2, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _id$2, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _retryCount, { writable: true, value: 0 }); _classPrivateFieldInitSpec(this, _resetRetryTimeout, { writable: true, value: void 0 }); _classPrivateFieldSet(this, _config$2, config); _classPrivateFieldSet(this, _eventBus$2, eventBus); _classPrivateFieldSet(this, _store$3, store); _classPrivateFieldSet(this, _retryCount, 0); _classPrivateFieldSet(this, _resetRetryTimeout, undefined); _classPrivateFieldSet(this, _id$2, id); } /** * Send data over network to clickstream BE * * @param batch batch to send */ async send( /** @type {import("./store.js").Event[]} */batch, { retry = false } = {}) { const request = _classPrivateMethodGet(this, _createRequest, _createRequest2).call(this, batch); _classPrivateMethodGet(this, _makeRequest, _makeRequest2).call(this, request, { retry }); } } function _createRequest2(batch) { const reqGuid = _classPrivateFieldGet(this, _id$2).uuidv4(); const { seconds } = getTimestamp(); logger.info(logPrefix$4, "generated reqGuid", reqGuid); logger.info(logPrefix$4, "generated timestamp(seconds)", seconds); // update QoS1 events in store const realTimeBatch = batch.filter(event => { return event.eventType === EVENT_TYPE.REALTIME; }); if (realTimeBatch.length && _classPrivateFieldGet(this, _store$3).isOpen) { _classPrivateFieldGet(this, _store$3).update(realTimeBatch, "reqGuid", reqGuid); logger.info(logPrefix$4, "updated reqGuid for all events in store"); } const encodedBatch = batch.map(payload => { const { data, type } = payload; return Event.create({ eventBytes: data, type }); }); const request = SendEventRequest.create({ reqGuid, sentTime: { seconds }, events: [...encodedBatch] }); logger.debug(logPrefix$4, "network request", request); return { reqGuid, body: SendEventRequest.encode(request).finish() }; } function _retry2(request) { const { maxRetries, timeBetweenTwoRetries, timeToResumeRetries } = _classPrivateFieldGet(this, _config$2); if (_classPrivateFieldGet(this, _retryCount) < maxRetries) { if (_classPrivateFieldGet(this, _resetRetryTimeout)) { window.clearTimeout(_classPrivateFieldGet(this, _resetRetryTimeout)); _classPrivateFieldSet(this, _resetRetryTimeout, undefined); } _classPrivateFieldSet(this, _retryCount, _classPrivateFieldGet(this, _retryCount) + 1); logger.debug(logPrefix$4, "retry", _classPrivateFieldGet(this, _retryCount)); window.setTimeout(() => { _classPrivateFieldGet(this, _eventBus$2).emit(CUSTOM_EVENT.BATCH_FAILED, { reqGuid: request.reqGuid }); }, timeBetweenTwoRetries); } else if (_classPrivateFieldGet(this, _retryCount) === maxRetries) { if (_classPrivateFieldGet(this, _resetRetryTimeout) === undefined) { logger.debug(logPrefix$4, "waiting for", timeToResumeRetries); _classPrivateFieldSet(this, _resetRetryTimeout, window.setTimeout(() => { _classPrivateFieldSet(this, _retryCount, 0); _classPrivateMethodGet(this, _retry, _retry2).call(this, request); }, timeToResumeRetries)); } } } async function _makeRequest2(request, { retry }) { const headers = new Headers(_classPrivateFieldGet(this, _config$2).headers); headers.append("Content-Type", "application/proto"); try { const response = await fetch(_classPrivateFieldGet(this, _config$2).url, { method: "POST", headers, body: request.body }); if (!response.ok) { logger.error(logPrefix$4, new NetworkError(`Network request to raccoon failed with status code ${response.status}`)); if (retry) _classPrivateMethodGet(this, _retry, _retry2).call(this, request); return; } logger.info(logPrefix$4, "received response from raccoon "); if (_classPrivateFieldGet(this, _store$3).isOpen()) { const blob = await response.blob(); const buffer = await readAsBuffer(blob); const uInt = new Uint8Array(buffer); const res = SendEventResponse.decode(uInt); logger.debug(logPrefix$4, "response data from Raccoon", res, JSON.stringify(res, undefined, 2)); const events = await _classPrivateFieldGet(this, _store$3).readByReqGuid(res.data["req_guid"]); _classPrivateFieldGet(this, _store$3).remove(events); logger.debug("remove events from store with reqGuid", res.data["req_guid"]); } } catch (err) { logger.error(logPrefix$4, new NetworkError(err.message, { cause: err })); if (retry) _classPrivateMethodGet(this, _retry, _retry2).call(this, request); } } const logPrefix$3 = "Processor:"; var _config$1 = /*#__PURE__*/new WeakMap(); var _store$2 = /*#__PURE__*/new WeakMap(); var _id$1 = /*#__PURE__*/new WeakMap(); var _isRealTimeEventsSupported$1 = /*#__PURE__*/new WeakMap(); var _type = /*#__PURE__*/new WeakSet(); var _createEvent = /*#__PURE__*/new WeakSet(); class Processor { constructor({ config, store, id, isRealTimeEventsSupported }) { _classPrivateMethodInitSpec(this, _createEvent); _classPrivateMethodInitSpec(this, _type); _classPrivateFieldInitSpec(this, _config$1, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _store$2, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _id$1, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _isRealTimeEventsSupported$1, { writable: true, value: void 0 }); _classPrivateFieldSet(this, _config$1, config); _classPrivateFieldSet(this, _store$2, store); _classPrivateFieldSet(this, _id$1, id); _classPrivateFieldSet(this, _isRealTimeEventsSupported$1, isRealTimeEventsSupported); } /** * Processes an event * * @param proto - event proto * @returns type and event */ process( /** @type {object} */proto) { const type = _classPrivateMethodGet(this, _type, _type2).call(this, proto); const event = _classPrivateMethodGet(this, _createEvent, _createEvent2).call(this, proto, type); return { type, event }; } } function _type2(proto) { if (!_classPrivateFieldGet(this, _isRealTimeEventsSupported$1)) { logger.info(logPrefix$3, `treating "${proto.eventName}" event as QoS0 as QoS1 events are not supported`); return EVENT_TYPE.INSTANT; } // if the storage is not available, event is treated as instant event if (!_classPrivateFieldGet(this, _store$2).isOpen()) { logger.info(logPrefix$3, `treating "${proto.eventName}" event as QoS0 as indexedDB is not supported`); return EVENT_TYPE.INSTANT; } if (_classPrivateFieldGet(this, _config$1)?.classification?.instant?.includes(proto.eventName)) { logger.info(logPrefix$3, `"${proto.eventName}" event is classified as QoS0 as per configuration`); return EVENT_TYPE.INSTANT; } logger.info(logPrefix$3, `"${proto.eventName}" event is considered as QoS1 by default configuration`); return EVENT_TYPE.REALTIME; } function _createEvent2(payload, eventType) { const PayloadConstructor = payload.constructor; const encodedEvent = PayloadConstructor.encode(payload).finish(); try { if (PayloadConstructor.decode) { const decodedEvent = PayloadConstructor.decode(encodedEvent); logger.debug(logPrefix$3, "decoded event payload", decodedEvent); } } catch (err) { logger.debug(logPrefix$3, "event decoding failed", err); } const typeUrlSplit = PayloadConstructor.getTypeUrl("").split("."); const typeUrl = typeUrlSplit[typeUrlSplit.length - 1].toLowerCase(); const type = _classPrivateFieldGet(this, _config$1).group ? `${_classPrivateFieldGet(this, _config$1).group}-${typeUrl}` : typeUrl; logger.info(logPrefix$3, "topic name is set to", type); /** @type {import("./store.js").Event} */ const event = { data: encodedEvent, eventType, type }; if (eventType === EVENT_TYPE.REALTIME) { event.eventGuid = _classPrivateFieldGet(this, _id$1).uuidv4(); event.reqGuid = ""; } logger.info(logPrefix$3, "created a new event"); logger.debug(logPrefix$3, "new event data", event); return event; } const logPrefix$2 = "Scheduler:"; var _intervalId = /*#__PURE__*/new WeakMap(); var _waitTime = /*#__PURE__*/new WeakMap(); var _batching = /*#__PURE__*/new WeakMap(); var _config = /*#__PURE__*/new WeakMap(); var _eventBus$1 = /*#__PURE__*/new WeakMap(); var _store$1 = /*#__PURE__*/new WeakMap(); var _batch = /*#__PURE__*/new WeakMap(); var _lastBatch = /*#__PURE__*/new WeakMap(); var _flush = /*#__PURE__*/new WeakSet(); var _clearInterval = /*#__PURE__*/new WeakSet(); var _emit = /*#__PURE__*/new WeakSet(); var _listeners$1 = /*#__PURE__*/new WeakSet(); var _removeListeners = /*#__PURE__*/new WeakSet(); var _batchSize = /*#__PURE__*/new WeakSet(); var _splitBySize = /*#__PURE__*/new WeakSet(); var _getRealTimeEvents = /*#__PURE__*/new WeakSet(); var _fill = /*#__PURE__*/new WeakSet(); var _run = /*#__PURE__*/new WeakSet(); class Scheduler { /** @type { number | NodeJS.Timer | undefined } */ constructor({ config, eventBus, store }) { _classPrivateMethodInitSpec(this, _run); _classPrivateMethodInitSpec(this, _fill); _classPrivateMethodInitSpec(this, _getRealTimeEvents); _classPrivateMethodInitSpec(this, _splitBySize); _classPrivateMethodInitSpec(this, _batchSize); _classPrivateMethodInitSpec(this, _removeListeners); _classPrivateMethodInitSpec(this, _listeners$1); _classPrivateMethodInitSpec(this, _emit); _classPrivateMethodInitSpec(this, _clearInterval); _classPrivateMethodInitSpec(this, _flush); _classPrivateFieldInitSpec(this, _intervalId, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _waitTime, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _batching, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _config, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _eventBus$1, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _store$1, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _batch, { writable: true, value: void 0 }); _classPrivateFieldInitSpec(this, _lastBatch, { writable: true, value: void 0 }); _classPrivateFieldSet(this, _config, config); _classPrivateFieldSet(this, _eventBus$1, eventBus); _classPrivateFieldSet(this, _store$1, store); _classPrivateFieldSet(this, _intervalId, undefined); _classPrivateFieldSet(this, _waitTime, 0); _classPrivateFieldSet(this, _batching, false); _classPrivateFieldSet(this, _batch, []); _classPrivateFieldSet(this, _lastBatch, []); } /** * Return if the scheduler is running or not */ isRunning() { return _classPrivateFieldGet(this, _batching); } /** * Start the scheduler */ start() { _classPrivateFieldSet(this, _batching, true); _classPrivateMethodGet(this, _run, _run2).call(this); _classPrivateMethodGet(this, _listeners$1, _listeners2$1).call(this); } /** * Stop the scheduler */ stop() { _classPrivateMethodGet(this, _clearInterval, _clearInterval2).call(this); _classPrivateFieldSet(this, _waitTime, 0); _classPrivateFieldSet(this, _batching, false); } /** * Pause the scheduler */ pause() { _classPrivateFieldSet(this, _batching, false); } /** * Resume the scheduler */ resume() { _classPrivateFieldSet(this, _batching, true); } async free() { try { this.stop(); logger.info(logPrefix$2, "scheduler is stopped"); logger.info(logPrefix$2, "flushing all events"); if (_classPrivateFieldGet(this, _store$1).isOpen()) { await _classPrivateMethodGet(this, _flush, _flush2).call(this); } _classPrivateMethodGet(this, _removeListeners, _removeListeners2).call(this); } catch (err) { return Promise.reject(err); } } /** * Flushes all the events in store */ } async function _flush2() { let events = await _classPrivateFieldGet(this, _store$1).read(); // filter out existing events in batch and last batch events = events.filter(event => { return ![..._classPrivateFieldGet(this, _batch), ..._classPrivateFieldGet(this, _lastBatch)].some(data => { return data.eventGuid === event.eventGuid; }); }); logger.debug(logPrefix$2, "flushed events", events); _classPrivateFieldGet(this, _batch).push(...events); _classPrivateMethodGet(this, _emit, _emit2).call(this); } function _clearInterval2() { if (_classPrivateFieldGet(this, _intervalId) !== undefined) { clearInterval(_classPrivateFieldGet(this, _intervalId)); _classPrivateFieldSet(this, _intervalId, undefined); } } function _emit2() { if (_classPrivateFieldGet(this, _batch).length) { _classPrivateFieldGet(this, _eventBus$1).emit(CUSTOM_EVENT.BATCH_CREATED, { batch: _classPrivateFieldGet(this, _batch) }); } _classPrivateFieldSet(this, _waitTime, 0); _classPrivateFieldSet(this, _lastBatch, _classPrivateFieldGet(this, _batch)); _classPrivateFieldSet(this, _batch, []); } function _listeners2$1() { _classPrivateFieldGet(this, _eventBus$1)?.on(CUSTOM_EVENT.BATCH_FAILED, async e => { logger.debug(logPrefix$2, "batch failed with reqGuid", e.detail.reqGuid); const events = await _classPrivateFieldGet(this, _store$1).readByReqGuid(e.detail.reqGuid); _classPrivateFieldGet(this, _eventBus$1).emit(CUSTOM_EVENT.BATCH_CREATED, { batch: events }); }); logger.info(logPrefix$2, 'added "BATCH_FAILED" listener'); } function _removeListeners2() { _classPrivateFieldGet(this, _eventBus$1)?.remove(CUSTOM_EVENT.BATCH_FAILED); logger.info(logPrefix$2, 'removed "BATCH_FAILED" listener'); } function _batchSize2(batch) { return batch.reduce((prev, curr) => { return prev + new Blob(curr?.data).size; }, 0); } function _splitBySize2(events) { const unitSize = _classPrivateMethodGet(this, _batchSize, _batchSize2).call(this, [events[0]]); const batchSize = _classPrivateMethodGet(this, _batchSize, _batchSize2).call(this, _classPrivateFieldGet(this, _batch)); const remSize = _classPrivateFieldGet(this, _config).maxBatchSize - batchSize; logger.debug(logPrefix$2, "current batch size", batchSize); logger.debug(logPrefix$2, "max batch size", _classPrivateFieldGet(this, _config).maxBatchSize); logger.debug(logPrefi