@gojek/clickstream-web
Version:
A Modern, Fast, and Lightweight Event Ingestion library for Web
1,504 lines (1,424 loc) • 75.6 kB
JavaScript
'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