core-outline 1.1.3 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
3
5
  var React = require('react');
6
+ var uuid = require('uuid');
7
+ var engine_ioClient = require('engine.io-client');
4
8
 
5
9
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
6
10
 
@@ -1028,7 +1032,7 @@ function snapshot(n, options) {
1028
1032
  });
1029
1033
  }
1030
1034
 
1031
- function on(type, fn, target = document) {
1035
+ function on$1(type, fn, target = document) {
1032
1036
  const options = { capture: true, passive: true };
1033
1037
  target.addEventListener(type, fn, options);
1034
1038
  return () => target.removeEventListener(type, fn, options);
@@ -1931,9 +1935,9 @@ function initMoveObserver({ mousemoveCb, sampling, doc, mirror, }) {
1931
1935
  trailing: false,
1932
1936
  });
1933
1937
  const handlers = [
1934
- on('mousemove', updatePosition, doc),
1935
- on('touchmove', updatePosition, doc),
1936
- on('drag', updatePosition, doc),
1938
+ on$1('mousemove', updatePosition, doc),
1939
+ on$1('touchmove', updatePosition, doc),
1940
+ on$1('drag', updatePosition, doc),
1937
1941
  ];
1938
1942
  return () => {
1939
1943
  handlers.forEach((h) => h());
@@ -1976,7 +1980,7 @@ function initMouseInteractionObserver({ mouseInteractionCb, doc, mirror, blockCl
1976
1980
  .forEach((eventKey) => {
1977
1981
  const eventName = eventKey.toLowerCase();
1978
1982
  const handler = getHandler(eventKey);
1979
- handlers.push(on(eventName, handler, doc));
1983
+ handlers.push(on$1(eventName, handler, doc));
1980
1984
  });
1981
1985
  return () => {
1982
1986
  handlers.forEach((h) => h());
@@ -2005,7 +2009,7 @@ function initScrollObserver({ scrollCb, doc, mirror, blockClass, blockSelector,
2005
2009
  });
2006
2010
  }
2007
2011
  }, sampling.scroll || 100);
2008
- return on('scroll', updatePosition, doc);
2012
+ return on$1('scroll', updatePosition, doc);
2009
2013
  }
2010
2014
  function initViewportResizeObserver({ viewportResizeCb, }) {
2011
2015
  let lastH = -1;
@@ -2022,7 +2026,7 @@ function initViewportResizeObserver({ viewportResizeCb, }) {
2022
2026
  lastW = width;
2023
2027
  }
2024
2028
  }, 200);
2025
- return on('resize', updateDimension, window);
2029
+ return on$1('resize', updateDimension, window);
2026
2030
  }
2027
2031
  function wrapEventWithUserTriggeredFlag(v, enable) {
2028
2032
  const value = Object.assign({}, v);
@@ -2090,7 +2094,7 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, ig
2090
2094
  }
2091
2095
  }
2092
2096
  const events = sampling.input === 'last' ? ['change'] : ['input', 'change'];
2093
- const handlers = events.map((eventName) => on(eventName, eventHandler, doc));
2097
+ const handlers = events.map((eventName) => on$1(eventName, eventHandler, doc));
2094
2098
  const currentWindow = doc.defaultView;
2095
2099
  if (!currentWindow) {
2096
2100
  return () => {
@@ -2384,11 +2388,11 @@ function initMediaInteractionObserver({ mediaInteractionCb, blockClass, blockSel
2384
2388
  });
2385
2389
  }, sampling.media || 500);
2386
2390
  const handlers = [
2387
- on('play', handler(0)),
2388
- on('pause', handler(1)),
2389
- on('seeked', handler(2)),
2390
- on('volumechange', handler(3)),
2391
- on('ratechange', handler(4)),
2391
+ on$1('play', handler(0)),
2392
+ on$1('pause', handler(1)),
2393
+ on$1('seeked', handler(2)),
2394
+ on$1('volumechange', handler(3)),
2395
+ on$1('ratechange', handler(4)),
2392
2396
  ];
2393
2397
  return () => {
2394
2398
  handlers.forEach((h) => h());
@@ -2462,7 +2466,7 @@ function initSelectionObserver(param) {
2462
2466
  selectionCb({ ranges });
2463
2467
  };
2464
2468
  updateSelection();
2465
- return on('selectionchange', updateSelection);
2469
+ return on$1('selectionchange', updateSelection);
2466
2470
  }
2467
2471
  function mergeHooks(o, hooks) {
2468
2472
  const { mutationCb, mousemoveCb, mouseInteractionCb, scrollCb, viewportResizeCb, inputCb, mediaInteractionCb, styleSheetRuleCb, styleDeclarationCb, canvasMutationCb, fontCb, selectionCb, } = o;
@@ -2938,9 +2942,9 @@ function __awaiter(thisArg, _arguments, P, generator) {
2938
2942
  */
2939
2943
  var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
2940
2944
  // Use a lookup table to find the index.
2941
- var lookup = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256);
2945
+ var lookup$1 = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256);
2942
2946
  for (var i = 0; i < chars.length; i++) {
2943
- lookup[chars.charCodeAt(i)] = i;
2947
+ lookup$1[chars.charCodeAt(i)] = i;
2944
2948
  }
2945
2949
  var encode = function (arraybuffer) {
2946
2950
  var bytes = new Uint8Array(arraybuffer), i, len = bytes.length, base64 = '';
@@ -3783,7 +3787,7 @@ function record(options = {}) {
3783
3787
  };
3784
3788
  try {
3785
3789
  const handlers = [];
3786
- handlers.push(on('DOMContentLoaded', () => {
3790
+ handlers.push(on$1('DOMContentLoaded', () => {
3787
3791
  wrappedEmit(wrapEvent({
3788
3792
  type: EventType.DomContentLoaded,
3789
3793
  data: {},
@@ -3886,7 +3890,7 @@ function record(options = {}) {
3886
3890
  init();
3887
3891
  }
3888
3892
  else {
3889
- handlers.push(on('load', () => {
3893
+ handlers.push(on$1('load', () => {
3890
3894
  wrappedEmit(wrapEvent({
3891
3895
  type: EventType.Load,
3892
3896
  data: {},
@@ -3926,16 +3930,2150 @@ record.takeFullSnapshot = (isCheckout) => {
3926
3930
  };
3927
3931
  record.mirror = mirror;
3928
3932
 
3933
+ /**
3934
+ * URL parser.
3935
+ *
3936
+ * @param uri - url
3937
+ * @param path - the request path of the connection
3938
+ * @param loc - An object meant to mimic window.location.
3939
+ * Defaults to window.location.
3940
+ * @public
3941
+ */
3942
+ function url(uri, path = "", loc) {
3943
+ let obj = uri;
3944
+ // default to window.location
3945
+ loc = loc || (typeof location !== "undefined" && location);
3946
+ if (null == uri)
3947
+ uri = loc.protocol + "//" + loc.host;
3948
+ // relative path support
3949
+ if (typeof uri === "string") {
3950
+ if ("/" === uri.charAt(0)) {
3951
+ if ("/" === uri.charAt(1)) {
3952
+ uri = loc.protocol + uri;
3953
+ }
3954
+ else {
3955
+ uri = loc.host + uri;
3956
+ }
3957
+ }
3958
+ if (!/^(https?|wss?):\/\//.test(uri)) {
3959
+ if ("undefined" !== typeof loc) {
3960
+ uri = loc.protocol + "//" + uri;
3961
+ }
3962
+ else {
3963
+ uri = "https://" + uri;
3964
+ }
3965
+ }
3966
+ // parse
3967
+ obj = engine_ioClient.parse(uri);
3968
+ }
3969
+ // make sure we treat `localhost:80` and `localhost` equally
3970
+ if (!obj.port) {
3971
+ if (/^(http|ws)$/.test(obj.protocol)) {
3972
+ obj.port = "80";
3973
+ }
3974
+ else if (/^(http|ws)s$/.test(obj.protocol)) {
3975
+ obj.port = "443";
3976
+ }
3977
+ }
3978
+ obj.path = obj.path || "/";
3979
+ const ipv6 = obj.host.indexOf(":") !== -1;
3980
+ const host = ipv6 ? "[" + obj.host + "]" : obj.host;
3981
+ // define unique id
3982
+ obj.id = obj.protocol + "://" + host + ":" + obj.port + path;
3983
+ // define href
3984
+ obj.href =
3985
+ obj.protocol +
3986
+ "://" +
3987
+ host +
3988
+ (loc && loc.port === obj.port ? "" : ":" + obj.port);
3989
+ return obj;
3990
+ }
3991
+
3992
+ /**
3993
+ * Initialize a new `Emitter`.
3994
+ *
3995
+ * @api public
3996
+ */
3997
+
3998
+ function Emitter(obj) {
3999
+ if (obj) return mixin(obj);
4000
+ }
4001
+
4002
+ /**
4003
+ * Mixin the emitter properties.
4004
+ *
4005
+ * @param {Object} obj
4006
+ * @return {Object}
4007
+ * @api private
4008
+ */
4009
+
4010
+ function mixin(obj) {
4011
+ for (var key in Emitter.prototype) {
4012
+ obj[key] = Emitter.prototype[key];
4013
+ }
4014
+ return obj;
4015
+ }
4016
+
4017
+ /**
4018
+ * Listen on the given `event` with `fn`.
4019
+ *
4020
+ * @param {String} event
4021
+ * @param {Function} fn
4022
+ * @return {Emitter}
4023
+ * @api public
4024
+ */
4025
+
4026
+ Emitter.prototype.on =
4027
+ Emitter.prototype.addEventListener = function(event, fn){
4028
+ this._callbacks = this._callbacks || {};
4029
+ (this._callbacks['$' + event] = this._callbacks['$' + event] || [])
4030
+ .push(fn);
4031
+ return this;
4032
+ };
4033
+
4034
+ /**
4035
+ * Adds an `event` listener that will be invoked a single
4036
+ * time then automatically removed.
4037
+ *
4038
+ * @param {String} event
4039
+ * @param {Function} fn
4040
+ * @return {Emitter}
4041
+ * @api public
4042
+ */
4043
+
4044
+ Emitter.prototype.once = function(event, fn){
4045
+ function on() {
4046
+ this.off(event, on);
4047
+ fn.apply(this, arguments);
4048
+ }
4049
+
4050
+ on.fn = fn;
4051
+ this.on(event, on);
4052
+ return this;
4053
+ };
4054
+
4055
+ /**
4056
+ * Remove the given callback for `event` or all
4057
+ * registered callbacks.
4058
+ *
4059
+ * @param {String} event
4060
+ * @param {Function} fn
4061
+ * @return {Emitter}
4062
+ * @api public
4063
+ */
4064
+
4065
+ Emitter.prototype.off =
4066
+ Emitter.prototype.removeListener =
4067
+ Emitter.prototype.removeAllListeners =
4068
+ Emitter.prototype.removeEventListener = function(event, fn){
4069
+ this._callbacks = this._callbacks || {};
4070
+
4071
+ // all
4072
+ if (0 == arguments.length) {
4073
+ this._callbacks = {};
4074
+ return this;
4075
+ }
4076
+
4077
+ // specific event
4078
+ var callbacks = this._callbacks['$' + event];
4079
+ if (!callbacks) return this;
4080
+
4081
+ // remove all handlers
4082
+ if (1 == arguments.length) {
4083
+ delete this._callbacks['$' + event];
4084
+ return this;
4085
+ }
4086
+
4087
+ // remove specific handler
4088
+ var cb;
4089
+ for (var i = 0; i < callbacks.length; i++) {
4090
+ cb = callbacks[i];
4091
+ if (cb === fn || cb.fn === fn) {
4092
+ callbacks.splice(i, 1);
4093
+ break;
4094
+ }
4095
+ }
4096
+
4097
+ // Remove event specific arrays for event types that no
4098
+ // one is subscribed for to avoid memory leak.
4099
+ if (callbacks.length === 0) {
4100
+ delete this._callbacks['$' + event];
4101
+ }
4102
+
4103
+ return this;
4104
+ };
4105
+
4106
+ /**
4107
+ * Emit `event` with the given args.
4108
+ *
4109
+ * @param {String} event
4110
+ * @param {Mixed} ...
4111
+ * @return {Emitter}
4112
+ */
4113
+
4114
+ Emitter.prototype.emit = function(event){
4115
+ this._callbacks = this._callbacks || {};
4116
+
4117
+ var args = new Array(arguments.length - 1)
4118
+ , callbacks = this._callbacks['$' + event];
4119
+
4120
+ for (var i = 1; i < arguments.length; i++) {
4121
+ args[i - 1] = arguments[i];
4122
+ }
4123
+
4124
+ if (callbacks) {
4125
+ callbacks = callbacks.slice(0);
4126
+ for (var i = 0, len = callbacks.length; i < len; ++i) {
4127
+ callbacks[i].apply(this, args);
4128
+ }
4129
+ }
4130
+
4131
+ return this;
4132
+ };
4133
+
4134
+ // alias used for reserved events (protected method)
4135
+ Emitter.prototype.emitReserved = Emitter.prototype.emit;
4136
+
4137
+ /**
4138
+ * Return array of callbacks for `event`.
4139
+ *
4140
+ * @param {String} event
4141
+ * @return {Array}
4142
+ * @api public
4143
+ */
4144
+
4145
+ Emitter.prototype.listeners = function(event){
4146
+ this._callbacks = this._callbacks || {};
4147
+ return this._callbacks['$' + event] || [];
4148
+ };
4149
+
4150
+ /**
4151
+ * Check if this emitter has `event` handlers.
4152
+ *
4153
+ * @param {String} event
4154
+ * @return {Boolean}
4155
+ * @api public
4156
+ */
4157
+
4158
+ Emitter.prototype.hasListeners = function(event){
4159
+ return !! this.listeners(event).length;
4160
+ };
4161
+
4162
+ const withNativeArrayBuffer = typeof ArrayBuffer === "function";
4163
+ const isView = (obj) => {
4164
+ return typeof ArrayBuffer.isView === "function"
4165
+ ? ArrayBuffer.isView(obj)
4166
+ : obj.buffer instanceof ArrayBuffer;
4167
+ };
4168
+ const toString = Object.prototype.toString;
4169
+ const withNativeBlob = typeof Blob === "function" ||
4170
+ (typeof Blob !== "undefined" &&
4171
+ toString.call(Blob) === "[object BlobConstructor]");
4172
+ const withNativeFile = typeof File === "function" ||
4173
+ (typeof File !== "undefined" &&
4174
+ toString.call(File) === "[object FileConstructor]");
4175
+ /**
4176
+ * Returns true if obj is a Buffer, an ArrayBuffer, a Blob or a File.
4177
+ *
4178
+ * @private
4179
+ */
4180
+ function isBinary(obj) {
4181
+ return ((withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj))) ||
4182
+ (withNativeBlob && obj instanceof Blob) ||
4183
+ (withNativeFile && obj instanceof File));
4184
+ }
4185
+ function hasBinary(obj, toJSON) {
4186
+ if (!obj || typeof obj !== "object") {
4187
+ return false;
4188
+ }
4189
+ if (Array.isArray(obj)) {
4190
+ for (let i = 0, l = obj.length; i < l; i++) {
4191
+ if (hasBinary(obj[i])) {
4192
+ return true;
4193
+ }
4194
+ }
4195
+ return false;
4196
+ }
4197
+ if (isBinary(obj)) {
4198
+ return true;
4199
+ }
4200
+ if (obj.toJSON &&
4201
+ typeof obj.toJSON === "function" &&
4202
+ arguments.length === 1) {
4203
+ return hasBinary(obj.toJSON(), true);
4204
+ }
4205
+ for (const key in obj) {
4206
+ if (Object.prototype.hasOwnProperty.call(obj, key) && hasBinary(obj[key])) {
4207
+ return true;
4208
+ }
4209
+ }
4210
+ return false;
4211
+ }
4212
+
4213
+ /**
4214
+ * Replaces every Buffer | ArrayBuffer | Blob | File in packet with a numbered placeholder.
4215
+ *
4216
+ * @param {Object} packet - socket.io event packet
4217
+ * @return {Object} with deconstructed packet and list of buffers
4218
+ * @public
4219
+ */
4220
+ function deconstructPacket(packet) {
4221
+ const buffers = [];
4222
+ const packetData = packet.data;
4223
+ const pack = packet;
4224
+ pack.data = _deconstructPacket(packetData, buffers);
4225
+ pack.attachments = buffers.length; // number of binary 'attachments'
4226
+ return { packet: pack, buffers: buffers };
4227
+ }
4228
+ function _deconstructPacket(data, buffers) {
4229
+ if (!data)
4230
+ return data;
4231
+ if (isBinary(data)) {
4232
+ const placeholder = { _placeholder: true, num: buffers.length };
4233
+ buffers.push(data);
4234
+ return placeholder;
4235
+ }
4236
+ else if (Array.isArray(data)) {
4237
+ const newData = new Array(data.length);
4238
+ for (let i = 0; i < data.length; i++) {
4239
+ newData[i] = _deconstructPacket(data[i], buffers);
4240
+ }
4241
+ return newData;
4242
+ }
4243
+ else if (typeof data === "object" && !(data instanceof Date)) {
4244
+ const newData = {};
4245
+ for (const key in data) {
4246
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
4247
+ newData[key] = _deconstructPacket(data[key], buffers);
4248
+ }
4249
+ }
4250
+ return newData;
4251
+ }
4252
+ return data;
4253
+ }
4254
+ /**
4255
+ * Reconstructs a binary packet from its placeholder packet and buffers
4256
+ *
4257
+ * @param {Object} packet - event packet with placeholders
4258
+ * @param {Array} buffers - binary buffers to put in placeholder positions
4259
+ * @return {Object} reconstructed packet
4260
+ * @public
4261
+ */
4262
+ function reconstructPacket(packet, buffers) {
4263
+ packet.data = _reconstructPacket(packet.data, buffers);
4264
+ delete packet.attachments; // no longer useful
4265
+ return packet;
4266
+ }
4267
+ function _reconstructPacket(data, buffers) {
4268
+ if (!data)
4269
+ return data;
4270
+ if (data && data._placeholder === true) {
4271
+ const isIndexValid = typeof data.num === "number" &&
4272
+ data.num >= 0 &&
4273
+ data.num < buffers.length;
4274
+ if (isIndexValid) {
4275
+ return buffers[data.num]; // appropriate buffer (should be natural order anyway)
4276
+ }
4277
+ else {
4278
+ throw new Error("illegal attachments");
4279
+ }
4280
+ }
4281
+ else if (Array.isArray(data)) {
4282
+ for (let i = 0; i < data.length; i++) {
4283
+ data[i] = _reconstructPacket(data[i], buffers);
4284
+ }
4285
+ }
4286
+ else if (typeof data === "object") {
4287
+ for (const key in data) {
4288
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
4289
+ data[key] = _reconstructPacket(data[key], buffers);
4290
+ }
4291
+ }
4292
+ }
4293
+ return data;
4294
+ }
4295
+
4296
+ /**
4297
+ * These strings must not be used as event names, as they have a special meaning.
4298
+ */
4299
+ const RESERVED_EVENTS$1 = [
4300
+ "connect",
4301
+ "connect_error",
4302
+ "disconnect",
4303
+ "disconnecting",
4304
+ "newListener",
4305
+ "removeListener", // used by the Node.js EventEmitter
4306
+ ];
4307
+ /**
4308
+ * Protocol version.
4309
+ *
4310
+ * @public
4311
+ */
4312
+ const protocol = 5;
4313
+ var PacketType;
4314
+ (function (PacketType) {
4315
+ PacketType[PacketType["CONNECT"] = 0] = "CONNECT";
4316
+ PacketType[PacketType["DISCONNECT"] = 1] = "DISCONNECT";
4317
+ PacketType[PacketType["EVENT"] = 2] = "EVENT";
4318
+ PacketType[PacketType["ACK"] = 3] = "ACK";
4319
+ PacketType[PacketType["CONNECT_ERROR"] = 4] = "CONNECT_ERROR";
4320
+ PacketType[PacketType["BINARY_EVENT"] = 5] = "BINARY_EVENT";
4321
+ PacketType[PacketType["BINARY_ACK"] = 6] = "BINARY_ACK";
4322
+ })(PacketType || (PacketType = {}));
4323
+ /**
4324
+ * A socket.io Encoder instance
4325
+ */
4326
+ class Encoder {
4327
+ /**
4328
+ * Encoder constructor
4329
+ *
4330
+ * @param {function} replacer - custom replacer to pass down to JSON.parse
4331
+ */
4332
+ constructor(replacer) {
4333
+ this.replacer = replacer;
4334
+ }
4335
+ /**
4336
+ * Encode a packet as a single string if non-binary, or as a
4337
+ * buffer sequence, depending on packet type.
4338
+ *
4339
+ * @param {Object} obj - packet object
4340
+ */
4341
+ encode(obj) {
4342
+ if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {
4343
+ if (hasBinary(obj)) {
4344
+ return this.encodeAsBinary({
4345
+ type: obj.type === PacketType.EVENT
4346
+ ? PacketType.BINARY_EVENT
4347
+ : PacketType.BINARY_ACK,
4348
+ nsp: obj.nsp,
4349
+ data: obj.data,
4350
+ id: obj.id,
4351
+ });
4352
+ }
4353
+ }
4354
+ return [this.encodeAsString(obj)];
4355
+ }
4356
+ /**
4357
+ * Encode packet as string.
4358
+ */
4359
+ encodeAsString(obj) {
4360
+ // first is type
4361
+ let str = "" + obj.type;
4362
+ // attachments if we have them
4363
+ if (obj.type === PacketType.BINARY_EVENT ||
4364
+ obj.type === PacketType.BINARY_ACK) {
4365
+ str += obj.attachments + "-";
4366
+ }
4367
+ // if we have a namespace other than `/`
4368
+ // we append it followed by a comma `,`
4369
+ if (obj.nsp && "/" !== obj.nsp) {
4370
+ str += obj.nsp + ",";
4371
+ }
4372
+ // immediately followed by the id
4373
+ if (null != obj.id) {
4374
+ str += obj.id;
4375
+ }
4376
+ // json data
4377
+ if (null != obj.data) {
4378
+ str += JSON.stringify(obj.data, this.replacer);
4379
+ }
4380
+ return str;
4381
+ }
4382
+ /**
4383
+ * Encode packet as 'buffer sequence' by removing blobs, and
4384
+ * deconstructing packet into object with placeholders and
4385
+ * a list of buffers.
4386
+ */
4387
+ encodeAsBinary(obj) {
4388
+ const deconstruction = deconstructPacket(obj);
4389
+ const pack = this.encodeAsString(deconstruction.packet);
4390
+ const buffers = deconstruction.buffers;
4391
+ buffers.unshift(pack); // add packet info to beginning of data list
4392
+ return buffers; // write all the buffers
4393
+ }
4394
+ }
4395
+ // see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript
4396
+ function isObject(value) {
4397
+ return Object.prototype.toString.call(value) === "[object Object]";
4398
+ }
4399
+ /**
4400
+ * A socket.io Decoder instance
4401
+ *
4402
+ * @return {Object} decoder
4403
+ */
4404
+ class Decoder extends Emitter {
4405
+ /**
4406
+ * Decoder constructor
4407
+ *
4408
+ * @param {function} reviver - custom reviver to pass down to JSON.stringify
4409
+ */
4410
+ constructor(reviver) {
4411
+ super();
4412
+ this.reviver = reviver;
4413
+ }
4414
+ /**
4415
+ * Decodes an encoded packet string into packet JSON.
4416
+ *
4417
+ * @param {String} obj - encoded packet
4418
+ */
4419
+ add(obj) {
4420
+ let packet;
4421
+ if (typeof obj === "string") {
4422
+ if (this.reconstructor) {
4423
+ throw new Error("got plaintext data when reconstructing a packet");
4424
+ }
4425
+ packet = this.decodeString(obj);
4426
+ const isBinaryEvent = packet.type === PacketType.BINARY_EVENT;
4427
+ if (isBinaryEvent || packet.type === PacketType.BINARY_ACK) {
4428
+ packet.type = isBinaryEvent ? PacketType.EVENT : PacketType.ACK;
4429
+ // binary packet's json
4430
+ this.reconstructor = new BinaryReconstructor(packet);
4431
+ // no attachments, labeled binary but no binary data to follow
4432
+ if (packet.attachments === 0) {
4433
+ super.emitReserved("decoded", packet);
4434
+ }
4435
+ }
4436
+ else {
4437
+ // non-binary full packet
4438
+ super.emitReserved("decoded", packet);
4439
+ }
4440
+ }
4441
+ else if (isBinary(obj) || obj.base64) {
4442
+ // raw binary data
4443
+ if (!this.reconstructor) {
4444
+ throw new Error("got binary data when not reconstructing a packet");
4445
+ }
4446
+ else {
4447
+ packet = this.reconstructor.takeBinaryData(obj);
4448
+ if (packet) {
4449
+ // received final buffer
4450
+ this.reconstructor = null;
4451
+ super.emitReserved("decoded", packet);
4452
+ }
4453
+ }
4454
+ }
4455
+ else {
4456
+ throw new Error("Unknown type: " + obj);
4457
+ }
4458
+ }
4459
+ /**
4460
+ * Decode a packet String (JSON data)
4461
+ *
4462
+ * @param {String} str
4463
+ * @return {Object} packet
4464
+ */
4465
+ decodeString(str) {
4466
+ let i = 0;
4467
+ // look up type
4468
+ const p = {
4469
+ type: Number(str.charAt(0)),
4470
+ };
4471
+ if (PacketType[p.type] === undefined) {
4472
+ throw new Error("unknown packet type " + p.type);
4473
+ }
4474
+ // look up attachments if type binary
4475
+ if (p.type === PacketType.BINARY_EVENT ||
4476
+ p.type === PacketType.BINARY_ACK) {
4477
+ const start = i + 1;
4478
+ while (str.charAt(++i) !== "-" && i != str.length) { }
4479
+ const buf = str.substring(start, i);
4480
+ if (buf != Number(buf) || str.charAt(i) !== "-") {
4481
+ throw new Error("Illegal attachments");
4482
+ }
4483
+ p.attachments = Number(buf);
4484
+ }
4485
+ // look up namespace (if any)
4486
+ if ("/" === str.charAt(i + 1)) {
4487
+ const start = i + 1;
4488
+ while (++i) {
4489
+ const c = str.charAt(i);
4490
+ if ("," === c)
4491
+ break;
4492
+ if (i === str.length)
4493
+ break;
4494
+ }
4495
+ p.nsp = str.substring(start, i);
4496
+ }
4497
+ else {
4498
+ p.nsp = "/";
4499
+ }
4500
+ // look up id
4501
+ const next = str.charAt(i + 1);
4502
+ if ("" !== next && Number(next) == next) {
4503
+ const start = i + 1;
4504
+ while (++i) {
4505
+ const c = str.charAt(i);
4506
+ if (null == c || Number(c) != c) {
4507
+ --i;
4508
+ break;
4509
+ }
4510
+ if (i === str.length)
4511
+ break;
4512
+ }
4513
+ p.id = Number(str.substring(start, i + 1));
4514
+ }
4515
+ // look up json data
4516
+ if (str.charAt(++i)) {
4517
+ const payload = this.tryParse(str.substr(i));
4518
+ if (Decoder.isPayloadValid(p.type, payload)) {
4519
+ p.data = payload;
4520
+ }
4521
+ else {
4522
+ throw new Error("invalid payload");
4523
+ }
4524
+ }
4525
+ return p;
4526
+ }
4527
+ tryParse(str) {
4528
+ try {
4529
+ return JSON.parse(str, this.reviver);
4530
+ }
4531
+ catch (e) {
4532
+ return false;
4533
+ }
4534
+ }
4535
+ static isPayloadValid(type, payload) {
4536
+ switch (type) {
4537
+ case PacketType.CONNECT:
4538
+ return isObject(payload);
4539
+ case PacketType.DISCONNECT:
4540
+ return payload === undefined;
4541
+ case PacketType.CONNECT_ERROR:
4542
+ return typeof payload === "string" || isObject(payload);
4543
+ case PacketType.EVENT:
4544
+ case PacketType.BINARY_EVENT:
4545
+ return (Array.isArray(payload) &&
4546
+ (typeof payload[0] === "number" ||
4547
+ (typeof payload[0] === "string" &&
4548
+ RESERVED_EVENTS$1.indexOf(payload[0]) === -1)));
4549
+ case PacketType.ACK:
4550
+ case PacketType.BINARY_ACK:
4551
+ return Array.isArray(payload);
4552
+ }
4553
+ }
4554
+ /**
4555
+ * Deallocates a parser's resources
4556
+ */
4557
+ destroy() {
4558
+ if (this.reconstructor) {
4559
+ this.reconstructor.finishedReconstruction();
4560
+ this.reconstructor = null;
4561
+ }
4562
+ }
4563
+ }
4564
+ /**
4565
+ * A manager of a binary event's 'buffer sequence'. Should
4566
+ * be constructed whenever a packet of type BINARY_EVENT is
4567
+ * decoded.
4568
+ *
4569
+ * @param {Object} packet
4570
+ * @return {BinaryReconstructor} initialized reconstructor
4571
+ */
4572
+ class BinaryReconstructor {
4573
+ constructor(packet) {
4574
+ this.packet = packet;
4575
+ this.buffers = [];
4576
+ this.reconPack = packet;
4577
+ }
4578
+ /**
4579
+ * Method to be called when binary data received from connection
4580
+ * after a BINARY_EVENT packet.
4581
+ *
4582
+ * @param {Buffer | ArrayBuffer} binData - the raw binary data received
4583
+ * @return {null | Object} returns null if more binary data is expected or
4584
+ * a reconstructed packet object if all buffers have been received.
4585
+ */
4586
+ takeBinaryData(binData) {
4587
+ this.buffers.push(binData);
4588
+ if (this.buffers.length === this.reconPack.attachments) {
4589
+ // done with buffer list
4590
+ const packet = reconstructPacket(this.reconPack, this.buffers);
4591
+ this.finishedReconstruction();
4592
+ return packet;
4593
+ }
4594
+ return null;
4595
+ }
4596
+ /**
4597
+ * Cleans up binary packet reconstruction variables.
4598
+ */
4599
+ finishedReconstruction() {
4600
+ this.reconPack = null;
4601
+ this.buffers = [];
4602
+ }
4603
+ }
4604
+
4605
+ var parser = /*#__PURE__*/Object.freeze({
4606
+ __proto__: null,
4607
+ protocol: protocol,
4608
+ get PacketType () { return PacketType; },
4609
+ Encoder: Encoder,
4610
+ Decoder: Decoder
4611
+ });
4612
+
4613
+ function on(obj, ev, fn) {
4614
+ obj.on(ev, fn);
4615
+ return function subDestroy() {
4616
+ obj.off(ev, fn);
4617
+ };
4618
+ }
4619
+
4620
+ /**
4621
+ * Internal events.
4622
+ * These events can't be emitted by the user.
4623
+ */
4624
+ const RESERVED_EVENTS = Object.freeze({
4625
+ connect: 1,
4626
+ connect_error: 1,
4627
+ disconnect: 1,
4628
+ disconnecting: 1,
4629
+ // EventEmitter reserved events: https://nodejs.org/api/events.html#events_event_newlistener
4630
+ newListener: 1,
4631
+ removeListener: 1,
4632
+ });
4633
+ /**
4634
+ * A Socket is the fundamental class for interacting with the server.
4635
+ *
4636
+ * A Socket belongs to a certain Namespace (by default /) and uses an underlying {@link Manager} to communicate.
4637
+ *
4638
+ * @example
4639
+ * const socket = io();
4640
+ *
4641
+ * socket.on("connect", () => {
4642
+ * console.log("connected");
4643
+ * });
4644
+ *
4645
+ * // send an event to the server
4646
+ * socket.emit("foo", "bar");
4647
+ *
4648
+ * socket.on("foobar", () => {
4649
+ * // an event was received from the server
4650
+ * });
4651
+ *
4652
+ * // upon disconnection
4653
+ * socket.on("disconnect", (reason) => {
4654
+ * console.log(`disconnected due to ${reason}`);
4655
+ * });
4656
+ */
4657
+ class Socket extends Emitter {
4658
+ /**
4659
+ * `Socket` constructor.
4660
+ */
4661
+ constructor(io, nsp, opts) {
4662
+ super();
4663
+ /**
4664
+ * Whether the socket is currently connected to the server.
4665
+ *
4666
+ * @example
4667
+ * const socket = io();
4668
+ *
4669
+ * socket.on("connect", () => {
4670
+ * console.log(socket.connected); // true
4671
+ * });
4672
+ *
4673
+ * socket.on("disconnect", () => {
4674
+ * console.log(socket.connected); // false
4675
+ * });
4676
+ */
4677
+ this.connected = false;
4678
+ /**
4679
+ * Whether the connection state was recovered after a temporary disconnection. In that case, any missed packets will
4680
+ * be transmitted by the server.
4681
+ */
4682
+ this.recovered = false;
4683
+ /**
4684
+ * Buffer for packets received before the CONNECT packet
4685
+ */
4686
+ this.receiveBuffer = [];
4687
+ /**
4688
+ * Buffer for packets that will be sent once the socket is connected
4689
+ */
4690
+ this.sendBuffer = [];
4691
+ /**
4692
+ * The queue of packets to be sent with retry in case of failure.
4693
+ *
4694
+ * Packets are sent one by one, each waiting for the server acknowledgement, in order to guarantee the delivery order.
4695
+ * @private
4696
+ */
4697
+ this._queue = [];
4698
+ /**
4699
+ * A sequence to generate the ID of the {@link QueuedPacket}.
4700
+ * @private
4701
+ */
4702
+ this._queueSeq = 0;
4703
+ this.ids = 0;
4704
+ /**
4705
+ * A map containing acknowledgement handlers.
4706
+ *
4707
+ * The `withError` attribute is used to differentiate handlers that accept an error as first argument:
4708
+ *
4709
+ * - `socket.emit("test", (err, value) => { ... })` with `ackTimeout` option
4710
+ * - `socket.timeout(5000).emit("test", (err, value) => { ... })`
4711
+ * - `const value = await socket.emitWithAck("test")`
4712
+ *
4713
+ * From those that don't:
4714
+ *
4715
+ * - `socket.emit("test", (value) => { ... });`
4716
+ *
4717
+ * In the first case, the handlers will be called with an error when:
4718
+ *
4719
+ * - the timeout is reached
4720
+ * - the socket gets disconnected
4721
+ *
4722
+ * In the second case, the handlers will be simply discarded upon disconnection, since the client will never receive
4723
+ * an acknowledgement from the server.
4724
+ *
4725
+ * @private
4726
+ */
4727
+ this.acks = {};
4728
+ this.flags = {};
4729
+ this.io = io;
4730
+ this.nsp = nsp;
4731
+ if (opts && opts.auth) {
4732
+ this.auth = opts.auth;
4733
+ }
4734
+ this._opts = Object.assign({}, opts);
4735
+ if (this.io._autoConnect)
4736
+ this.open();
4737
+ }
4738
+ /**
4739
+ * Whether the socket is currently disconnected
4740
+ *
4741
+ * @example
4742
+ * const socket = io();
4743
+ *
4744
+ * socket.on("connect", () => {
4745
+ * console.log(socket.disconnected); // false
4746
+ * });
4747
+ *
4748
+ * socket.on("disconnect", () => {
4749
+ * console.log(socket.disconnected); // true
4750
+ * });
4751
+ */
4752
+ get disconnected() {
4753
+ return !this.connected;
4754
+ }
4755
+ /**
4756
+ * Subscribe to open, close and packet events
4757
+ *
4758
+ * @private
4759
+ */
4760
+ subEvents() {
4761
+ if (this.subs)
4762
+ return;
4763
+ const io = this.io;
4764
+ this.subs = [
4765
+ on(io, "open", this.onopen.bind(this)),
4766
+ on(io, "packet", this.onpacket.bind(this)),
4767
+ on(io, "error", this.onerror.bind(this)),
4768
+ on(io, "close", this.onclose.bind(this)),
4769
+ ];
4770
+ }
4771
+ /**
4772
+ * Whether the Socket will try to reconnect when its Manager connects or reconnects.
4773
+ *
4774
+ * @example
4775
+ * const socket = io();
4776
+ *
4777
+ * console.log(socket.active); // true
4778
+ *
4779
+ * socket.on("disconnect", (reason) => {
4780
+ * if (reason === "io server disconnect") {
4781
+ * // the disconnection was initiated by the server, you need to manually reconnect
4782
+ * console.log(socket.active); // false
4783
+ * }
4784
+ * // else the socket will automatically try to reconnect
4785
+ * console.log(socket.active); // true
4786
+ * });
4787
+ */
4788
+ get active() {
4789
+ return !!this.subs;
4790
+ }
4791
+ /**
4792
+ * "Opens" the socket.
4793
+ *
4794
+ * @example
4795
+ * const socket = io({
4796
+ * autoConnect: false
4797
+ * });
4798
+ *
4799
+ * socket.connect();
4800
+ */
4801
+ connect() {
4802
+ if (this.connected)
4803
+ return this;
4804
+ this.subEvents();
4805
+ if (!this.io["_reconnecting"])
4806
+ this.io.open(); // ensure open
4807
+ if ("open" === this.io._readyState)
4808
+ this.onopen();
4809
+ return this;
4810
+ }
4811
+ /**
4812
+ * Alias for {@link connect()}.
4813
+ */
4814
+ open() {
4815
+ return this.connect();
4816
+ }
4817
+ /**
4818
+ * Sends a `message` event.
4819
+ *
4820
+ * This method mimics the WebSocket.send() method.
4821
+ *
4822
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
4823
+ *
4824
+ * @example
4825
+ * socket.send("hello");
4826
+ *
4827
+ * // this is equivalent to
4828
+ * socket.emit("message", "hello");
4829
+ *
4830
+ * @return self
4831
+ */
4832
+ send(...args) {
4833
+ args.unshift("message");
4834
+ this.emit.apply(this, args);
4835
+ return this;
4836
+ }
4837
+ /**
4838
+ * Override `emit`.
4839
+ * If the event is in `events`, it's emitted normally.
4840
+ *
4841
+ * @example
4842
+ * socket.emit("hello", "world");
4843
+ *
4844
+ * // all serializable datastructures are supported (no need to call JSON.stringify)
4845
+ * socket.emit("hello", 1, "2", { 3: ["4"], 5: Uint8Array.from([6]) });
4846
+ *
4847
+ * // with an acknowledgement from the server
4848
+ * socket.emit("hello", "world", (val) => {
4849
+ * // ...
4850
+ * });
4851
+ *
4852
+ * @return self
4853
+ */
4854
+ emit(ev, ...args) {
4855
+ var _a, _b, _c;
4856
+ if (RESERVED_EVENTS.hasOwnProperty(ev)) {
4857
+ throw new Error('"' + ev.toString() + '" is a reserved event name');
4858
+ }
4859
+ args.unshift(ev);
4860
+ if (this._opts.retries && !this.flags.fromQueue && !this.flags.volatile) {
4861
+ this._addToQueue(args);
4862
+ return this;
4863
+ }
4864
+ const packet = {
4865
+ type: PacketType.EVENT,
4866
+ data: args,
4867
+ };
4868
+ packet.options = {};
4869
+ packet.options.compress = this.flags.compress !== false;
4870
+ // event ack callback
4871
+ if ("function" === typeof args[args.length - 1]) {
4872
+ const id = this.ids++;
4873
+ const ack = args.pop();
4874
+ this._registerAckCallback(id, ack);
4875
+ packet.id = id;
4876
+ }
4877
+ const isTransportWritable = (_b = (_a = this.io.engine) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.writable;
4878
+ const isConnected = this.connected && !((_c = this.io.engine) === null || _c === void 0 ? void 0 : _c._hasPingExpired());
4879
+ const discardPacket = this.flags.volatile && !isTransportWritable;
4880
+ if (discardPacket) ;
4881
+ else if (isConnected) {
4882
+ this.notifyOutgoingListeners(packet);
4883
+ this.packet(packet);
4884
+ }
4885
+ else {
4886
+ this.sendBuffer.push(packet);
4887
+ }
4888
+ this.flags = {};
4889
+ return this;
4890
+ }
4891
+ /**
4892
+ * @private
4893
+ */
4894
+ _registerAckCallback(id, ack) {
4895
+ var _a;
4896
+ const timeout = (_a = this.flags.timeout) !== null && _a !== void 0 ? _a : this._opts.ackTimeout;
4897
+ if (timeout === undefined) {
4898
+ this.acks[id] = ack;
4899
+ return;
4900
+ }
4901
+ // @ts-ignore
4902
+ const timer = this.io.setTimeoutFn(() => {
4903
+ delete this.acks[id];
4904
+ for (let i = 0; i < this.sendBuffer.length; i++) {
4905
+ if (this.sendBuffer[i].id === id) {
4906
+ this.sendBuffer.splice(i, 1);
4907
+ }
4908
+ }
4909
+ ack.call(this, new Error("operation has timed out"));
4910
+ }, timeout);
4911
+ const fn = (...args) => {
4912
+ // @ts-ignore
4913
+ this.io.clearTimeoutFn(timer);
4914
+ ack.apply(this, args);
4915
+ };
4916
+ fn.withError = true;
4917
+ this.acks[id] = fn;
4918
+ }
4919
+ /**
4920
+ * Emits an event and waits for an acknowledgement
4921
+ *
4922
+ * @example
4923
+ * // without timeout
4924
+ * const response = await socket.emitWithAck("hello", "world");
4925
+ *
4926
+ * // with a specific timeout
4927
+ * try {
4928
+ * const response = await socket.timeout(1000).emitWithAck("hello", "world");
4929
+ * } catch (err) {
4930
+ * // the server did not acknowledge the event in the given delay
4931
+ * }
4932
+ *
4933
+ * @return a Promise that will be fulfilled when the server acknowledges the event
4934
+ */
4935
+ emitWithAck(ev, ...args) {
4936
+ return new Promise((resolve, reject) => {
4937
+ const fn = (arg1, arg2) => {
4938
+ return arg1 ? reject(arg1) : resolve(arg2);
4939
+ };
4940
+ fn.withError = true;
4941
+ args.push(fn);
4942
+ this.emit(ev, ...args);
4943
+ });
4944
+ }
4945
+ /**
4946
+ * Add the packet to the queue.
4947
+ * @param args
4948
+ * @private
4949
+ */
4950
+ _addToQueue(args) {
4951
+ let ack;
4952
+ if (typeof args[args.length - 1] === "function") {
4953
+ ack = args.pop();
4954
+ }
4955
+ const packet = {
4956
+ id: this._queueSeq++,
4957
+ tryCount: 0,
4958
+ pending: false,
4959
+ args,
4960
+ flags: Object.assign({ fromQueue: true }, this.flags),
4961
+ };
4962
+ args.push((err, ...responseArgs) => {
4963
+ if (packet !== this._queue[0]) {
4964
+ // the packet has already been acknowledged
4965
+ return;
4966
+ }
4967
+ const hasError = err !== null;
4968
+ if (hasError) {
4969
+ if (packet.tryCount > this._opts.retries) {
4970
+ this._queue.shift();
4971
+ if (ack) {
4972
+ ack(err);
4973
+ }
4974
+ }
4975
+ }
4976
+ else {
4977
+ this._queue.shift();
4978
+ if (ack) {
4979
+ ack(null, ...responseArgs);
4980
+ }
4981
+ }
4982
+ packet.pending = false;
4983
+ return this._drainQueue();
4984
+ });
4985
+ this._queue.push(packet);
4986
+ this._drainQueue();
4987
+ }
4988
+ /**
4989
+ * Send the first packet of the queue, and wait for an acknowledgement from the server.
4990
+ * @param force - whether to resend a packet that has not been acknowledged yet
4991
+ *
4992
+ * @private
4993
+ */
4994
+ _drainQueue(force = false) {
4995
+ if (!this.connected || this._queue.length === 0) {
4996
+ return;
4997
+ }
4998
+ const packet = this._queue[0];
4999
+ if (packet.pending && !force) {
5000
+ return;
5001
+ }
5002
+ packet.pending = true;
5003
+ packet.tryCount++;
5004
+ this.flags = packet.flags;
5005
+ this.emit.apply(this, packet.args);
5006
+ }
5007
+ /**
5008
+ * Sends a packet.
5009
+ *
5010
+ * @param packet
5011
+ * @private
5012
+ */
5013
+ packet(packet) {
5014
+ packet.nsp = this.nsp;
5015
+ this.io._packet(packet);
5016
+ }
5017
+ /**
5018
+ * Called upon engine `open`.
5019
+ *
5020
+ * @private
5021
+ */
5022
+ onopen() {
5023
+ if (typeof this.auth == "function") {
5024
+ this.auth((data) => {
5025
+ this._sendConnectPacket(data);
5026
+ });
5027
+ }
5028
+ else {
5029
+ this._sendConnectPacket(this.auth);
5030
+ }
5031
+ }
5032
+ /**
5033
+ * Sends a CONNECT packet to initiate the Socket.IO session.
5034
+ *
5035
+ * @param data
5036
+ * @private
5037
+ */
5038
+ _sendConnectPacket(data) {
5039
+ this.packet({
5040
+ type: PacketType.CONNECT,
5041
+ data: this._pid
5042
+ ? Object.assign({ pid: this._pid, offset: this._lastOffset }, data)
5043
+ : data,
5044
+ });
5045
+ }
5046
+ /**
5047
+ * Called upon engine or manager `error`.
5048
+ *
5049
+ * @param err
5050
+ * @private
5051
+ */
5052
+ onerror(err) {
5053
+ if (!this.connected) {
5054
+ this.emitReserved("connect_error", err);
5055
+ }
5056
+ }
5057
+ /**
5058
+ * Called upon engine `close`.
5059
+ *
5060
+ * @param reason
5061
+ * @param description
5062
+ * @private
5063
+ */
5064
+ onclose(reason, description) {
5065
+ this.connected = false;
5066
+ delete this.id;
5067
+ this.emitReserved("disconnect", reason, description);
5068
+ this._clearAcks();
5069
+ }
5070
+ /**
5071
+ * Clears the acknowledgement handlers upon disconnection, since the client will never receive an acknowledgement from
5072
+ * the server.
5073
+ *
5074
+ * @private
5075
+ */
5076
+ _clearAcks() {
5077
+ Object.keys(this.acks).forEach((id) => {
5078
+ const isBuffered = this.sendBuffer.some((packet) => String(packet.id) === id);
5079
+ if (!isBuffered) {
5080
+ // note: handlers that do not accept an error as first argument are ignored here
5081
+ const ack = this.acks[id];
5082
+ delete this.acks[id];
5083
+ if (ack.withError) {
5084
+ ack.call(this, new Error("socket has been disconnected"));
5085
+ }
5086
+ }
5087
+ });
5088
+ }
5089
+ /**
5090
+ * Called with socket packet.
5091
+ *
5092
+ * @param packet
5093
+ * @private
5094
+ */
5095
+ onpacket(packet) {
5096
+ const sameNamespace = packet.nsp === this.nsp;
5097
+ if (!sameNamespace)
5098
+ return;
5099
+ switch (packet.type) {
5100
+ case PacketType.CONNECT:
5101
+ if (packet.data && packet.data.sid) {
5102
+ this.onconnect(packet.data.sid, packet.data.pid);
5103
+ }
5104
+ else {
5105
+ this.emitReserved("connect_error", new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));
5106
+ }
5107
+ break;
5108
+ case PacketType.EVENT:
5109
+ case PacketType.BINARY_EVENT:
5110
+ this.onevent(packet);
5111
+ break;
5112
+ case PacketType.ACK:
5113
+ case PacketType.BINARY_ACK:
5114
+ this.onack(packet);
5115
+ break;
5116
+ case PacketType.DISCONNECT:
5117
+ this.ondisconnect();
5118
+ break;
5119
+ case PacketType.CONNECT_ERROR:
5120
+ this.destroy();
5121
+ const err = new Error(packet.data.message);
5122
+ // @ts-ignore
5123
+ err.data = packet.data.data;
5124
+ this.emitReserved("connect_error", err);
5125
+ break;
5126
+ }
5127
+ }
5128
+ /**
5129
+ * Called upon a server event.
5130
+ *
5131
+ * @param packet
5132
+ * @private
5133
+ */
5134
+ onevent(packet) {
5135
+ const args = packet.data || [];
5136
+ if (null != packet.id) {
5137
+ args.push(this.ack(packet.id));
5138
+ }
5139
+ if (this.connected) {
5140
+ this.emitEvent(args);
5141
+ }
5142
+ else {
5143
+ this.receiveBuffer.push(Object.freeze(args));
5144
+ }
5145
+ }
5146
+ emitEvent(args) {
5147
+ if (this._anyListeners && this._anyListeners.length) {
5148
+ const listeners = this._anyListeners.slice();
5149
+ for (const listener of listeners) {
5150
+ listener.apply(this, args);
5151
+ }
5152
+ }
5153
+ super.emit.apply(this, args);
5154
+ if (this._pid && args.length && typeof args[args.length - 1] === "string") {
5155
+ this._lastOffset = args[args.length - 1];
5156
+ }
5157
+ }
5158
+ /**
5159
+ * Produces an ack callback to emit with an event.
5160
+ *
5161
+ * @private
5162
+ */
5163
+ ack(id) {
5164
+ const self = this;
5165
+ let sent = false;
5166
+ return function (...args) {
5167
+ // prevent double callbacks
5168
+ if (sent)
5169
+ return;
5170
+ sent = true;
5171
+ self.packet({
5172
+ type: PacketType.ACK,
5173
+ id: id,
5174
+ data: args,
5175
+ });
5176
+ };
5177
+ }
5178
+ /**
5179
+ * Called upon a server acknowledgement.
5180
+ *
5181
+ * @param packet
5182
+ * @private
5183
+ */
5184
+ onack(packet) {
5185
+ const ack = this.acks[packet.id];
5186
+ if (typeof ack !== "function") {
5187
+ return;
5188
+ }
5189
+ delete this.acks[packet.id];
5190
+ // @ts-ignore FIXME ack is incorrectly inferred as 'never'
5191
+ if (ack.withError) {
5192
+ packet.data.unshift(null);
5193
+ }
5194
+ // @ts-ignore
5195
+ ack.apply(this, packet.data);
5196
+ }
5197
+ /**
5198
+ * Called upon server connect.
5199
+ *
5200
+ * @private
5201
+ */
5202
+ onconnect(id, pid) {
5203
+ this.id = id;
5204
+ this.recovered = pid && this._pid === pid;
5205
+ this._pid = pid; // defined only if connection state recovery is enabled
5206
+ this.connected = true;
5207
+ this.emitBuffered();
5208
+ this.emitReserved("connect");
5209
+ this._drainQueue(true);
5210
+ }
5211
+ /**
5212
+ * Emit buffered events (received and emitted).
5213
+ *
5214
+ * @private
5215
+ */
5216
+ emitBuffered() {
5217
+ this.receiveBuffer.forEach((args) => this.emitEvent(args));
5218
+ this.receiveBuffer = [];
5219
+ this.sendBuffer.forEach((packet) => {
5220
+ this.notifyOutgoingListeners(packet);
5221
+ this.packet(packet);
5222
+ });
5223
+ this.sendBuffer = [];
5224
+ }
5225
+ /**
5226
+ * Called upon server disconnect.
5227
+ *
5228
+ * @private
5229
+ */
5230
+ ondisconnect() {
5231
+ this.destroy();
5232
+ this.onclose("io server disconnect");
5233
+ }
5234
+ /**
5235
+ * Called upon forced client/server side disconnections,
5236
+ * this method ensures the manager stops tracking us and
5237
+ * that reconnections don't get triggered for this.
5238
+ *
5239
+ * @private
5240
+ */
5241
+ destroy() {
5242
+ if (this.subs) {
5243
+ // clean subscriptions to avoid reconnections
5244
+ this.subs.forEach((subDestroy) => subDestroy());
5245
+ this.subs = undefined;
5246
+ }
5247
+ this.io["_destroy"](this);
5248
+ }
5249
+ /**
5250
+ * Disconnects the socket manually. In that case, the socket will not try to reconnect.
5251
+ *
5252
+ * If this is the last active Socket instance of the {@link Manager}, the low-level connection will be closed.
5253
+ *
5254
+ * @example
5255
+ * const socket = io();
5256
+ *
5257
+ * socket.on("disconnect", (reason) => {
5258
+ * // console.log(reason); prints "io client disconnect"
5259
+ * });
5260
+ *
5261
+ * socket.disconnect();
5262
+ *
5263
+ * @return self
5264
+ */
5265
+ disconnect() {
5266
+ if (this.connected) {
5267
+ this.packet({ type: PacketType.DISCONNECT });
5268
+ }
5269
+ // remove socket from pool
5270
+ this.destroy();
5271
+ if (this.connected) {
5272
+ // fire events
5273
+ this.onclose("io client disconnect");
5274
+ }
5275
+ return this;
5276
+ }
5277
+ /**
5278
+ * Alias for {@link disconnect()}.
5279
+ *
5280
+ * @return self
5281
+ */
5282
+ close() {
5283
+ return this.disconnect();
5284
+ }
5285
+ /**
5286
+ * Sets the compress flag.
5287
+ *
5288
+ * @example
5289
+ * socket.compress(false).emit("hello");
5290
+ *
5291
+ * @param compress - if `true`, compresses the sending data
5292
+ * @return self
5293
+ */
5294
+ compress(compress) {
5295
+ this.flags.compress = compress;
5296
+ return this;
5297
+ }
5298
+ /**
5299
+ * Sets a modifier for a subsequent event emission that the event message will be dropped when this socket is not
5300
+ * ready to send messages.
5301
+ *
5302
+ * @example
5303
+ * socket.volatile.emit("hello"); // the server may or may not receive it
5304
+ *
5305
+ * @returns self
5306
+ */
5307
+ get volatile() {
5308
+ this.flags.volatile = true;
5309
+ return this;
5310
+ }
5311
+ /**
5312
+ * Sets a modifier for a subsequent event emission that the callback will be called with an error when the
5313
+ * given number of milliseconds have elapsed without an acknowledgement from the server:
5314
+ *
5315
+ * @example
5316
+ * socket.timeout(5000).emit("my-event", (err) => {
5317
+ * if (err) {
5318
+ * // the server did not acknowledge the event in the given delay
5319
+ * }
5320
+ * });
5321
+ *
5322
+ * @returns self
5323
+ */
5324
+ timeout(timeout) {
5325
+ this.flags.timeout = timeout;
5326
+ return this;
5327
+ }
5328
+ /**
5329
+ * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
5330
+ * callback.
5331
+ *
5332
+ * @example
5333
+ * socket.onAny((event, ...args) => {
5334
+ * console.log(`got ${event}`);
5335
+ * });
5336
+ *
5337
+ * @param listener
5338
+ */
5339
+ onAny(listener) {
5340
+ this._anyListeners = this._anyListeners || [];
5341
+ this._anyListeners.push(listener);
5342
+ return this;
5343
+ }
5344
+ /**
5345
+ * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
5346
+ * callback. The listener is added to the beginning of the listeners array.
5347
+ *
5348
+ * @example
5349
+ * socket.prependAny((event, ...args) => {
5350
+ * console.log(`got event ${event}`);
5351
+ * });
5352
+ *
5353
+ * @param listener
5354
+ */
5355
+ prependAny(listener) {
5356
+ this._anyListeners = this._anyListeners || [];
5357
+ this._anyListeners.unshift(listener);
5358
+ return this;
5359
+ }
5360
+ /**
5361
+ * Removes the listener that will be fired when any event is emitted.
5362
+ *
5363
+ * @example
5364
+ * const catchAllListener = (event, ...args) => {
5365
+ * console.log(`got event ${event}`);
5366
+ * }
5367
+ *
5368
+ * socket.onAny(catchAllListener);
5369
+ *
5370
+ * // remove a specific listener
5371
+ * socket.offAny(catchAllListener);
5372
+ *
5373
+ * // or remove all listeners
5374
+ * socket.offAny();
5375
+ *
5376
+ * @param listener
5377
+ */
5378
+ offAny(listener) {
5379
+ if (!this._anyListeners) {
5380
+ return this;
5381
+ }
5382
+ if (listener) {
5383
+ const listeners = this._anyListeners;
5384
+ for (let i = 0; i < listeners.length; i++) {
5385
+ if (listener === listeners[i]) {
5386
+ listeners.splice(i, 1);
5387
+ return this;
5388
+ }
5389
+ }
5390
+ }
5391
+ else {
5392
+ this._anyListeners = [];
5393
+ }
5394
+ return this;
5395
+ }
5396
+ /**
5397
+ * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
5398
+ * e.g. to remove listeners.
5399
+ */
5400
+ listenersAny() {
5401
+ return this._anyListeners || [];
5402
+ }
5403
+ /**
5404
+ * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
5405
+ * callback.
5406
+ *
5407
+ * Note: acknowledgements sent to the server are not included.
5408
+ *
5409
+ * @example
5410
+ * socket.onAnyOutgoing((event, ...args) => {
5411
+ * console.log(`sent event ${event}`);
5412
+ * });
5413
+ *
5414
+ * @param listener
5415
+ */
5416
+ onAnyOutgoing(listener) {
5417
+ this._anyOutgoingListeners = this._anyOutgoingListeners || [];
5418
+ this._anyOutgoingListeners.push(listener);
5419
+ return this;
5420
+ }
5421
+ /**
5422
+ * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
5423
+ * callback. The listener is added to the beginning of the listeners array.
5424
+ *
5425
+ * Note: acknowledgements sent to the server are not included.
5426
+ *
5427
+ * @example
5428
+ * socket.prependAnyOutgoing((event, ...args) => {
5429
+ * console.log(`sent event ${event}`);
5430
+ * });
5431
+ *
5432
+ * @param listener
5433
+ */
5434
+ prependAnyOutgoing(listener) {
5435
+ this._anyOutgoingListeners = this._anyOutgoingListeners || [];
5436
+ this._anyOutgoingListeners.unshift(listener);
5437
+ return this;
5438
+ }
5439
+ /**
5440
+ * Removes the listener that will be fired when any event is emitted.
5441
+ *
5442
+ * @example
5443
+ * const catchAllListener = (event, ...args) => {
5444
+ * console.log(`sent event ${event}`);
5445
+ * }
5446
+ *
5447
+ * socket.onAnyOutgoing(catchAllListener);
5448
+ *
5449
+ * // remove a specific listener
5450
+ * socket.offAnyOutgoing(catchAllListener);
5451
+ *
5452
+ * // or remove all listeners
5453
+ * socket.offAnyOutgoing();
5454
+ *
5455
+ * @param [listener] - the catch-all listener (optional)
5456
+ */
5457
+ offAnyOutgoing(listener) {
5458
+ if (!this._anyOutgoingListeners) {
5459
+ return this;
5460
+ }
5461
+ if (listener) {
5462
+ const listeners = this._anyOutgoingListeners;
5463
+ for (let i = 0; i < listeners.length; i++) {
5464
+ if (listener === listeners[i]) {
5465
+ listeners.splice(i, 1);
5466
+ return this;
5467
+ }
5468
+ }
5469
+ }
5470
+ else {
5471
+ this._anyOutgoingListeners = [];
5472
+ }
5473
+ return this;
5474
+ }
5475
+ /**
5476
+ * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
5477
+ * e.g. to remove listeners.
5478
+ */
5479
+ listenersAnyOutgoing() {
5480
+ return this._anyOutgoingListeners || [];
5481
+ }
5482
+ /**
5483
+ * Notify the listeners for each packet sent
5484
+ *
5485
+ * @param packet
5486
+ *
5487
+ * @private
5488
+ */
5489
+ notifyOutgoingListeners(packet) {
5490
+ if (this._anyOutgoingListeners && this._anyOutgoingListeners.length) {
5491
+ const listeners = this._anyOutgoingListeners.slice();
5492
+ for (const listener of listeners) {
5493
+ listener.apply(this, packet.data);
5494
+ }
5495
+ }
5496
+ }
5497
+ }
5498
+
5499
+ /**
5500
+ * Initialize backoff timer with `opts`.
5501
+ *
5502
+ * - `min` initial timeout in milliseconds [100]
5503
+ * - `max` max timeout [10000]
5504
+ * - `jitter` [0]
5505
+ * - `factor` [2]
5506
+ *
5507
+ * @param {Object} opts
5508
+ * @api public
5509
+ */
5510
+ function Backoff(opts) {
5511
+ opts = opts || {};
5512
+ this.ms = opts.min || 100;
5513
+ this.max = opts.max || 10000;
5514
+ this.factor = opts.factor || 2;
5515
+ this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0;
5516
+ this.attempts = 0;
5517
+ }
5518
+ /**
5519
+ * Return the backoff duration.
5520
+ *
5521
+ * @return {Number}
5522
+ * @api public
5523
+ */
5524
+ Backoff.prototype.duration = function () {
5525
+ var ms = this.ms * Math.pow(this.factor, this.attempts++);
5526
+ if (this.jitter) {
5527
+ var rand = Math.random();
5528
+ var deviation = Math.floor(rand * this.jitter * ms);
5529
+ ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation;
5530
+ }
5531
+ return Math.min(ms, this.max) | 0;
5532
+ };
5533
+ /**
5534
+ * Reset the number of attempts.
5535
+ *
5536
+ * @api public
5537
+ */
5538
+ Backoff.prototype.reset = function () {
5539
+ this.attempts = 0;
5540
+ };
5541
+ /**
5542
+ * Set the minimum duration
5543
+ *
5544
+ * @api public
5545
+ */
5546
+ Backoff.prototype.setMin = function (min) {
5547
+ this.ms = min;
5548
+ };
5549
+ /**
5550
+ * Set the maximum duration
5551
+ *
5552
+ * @api public
5553
+ */
5554
+ Backoff.prototype.setMax = function (max) {
5555
+ this.max = max;
5556
+ };
5557
+ /**
5558
+ * Set the jitter
5559
+ *
5560
+ * @api public
5561
+ */
5562
+ Backoff.prototype.setJitter = function (jitter) {
5563
+ this.jitter = jitter;
5564
+ };
5565
+
5566
+ class Manager extends Emitter {
5567
+ constructor(uri, opts) {
5568
+ var _a;
5569
+ super();
5570
+ this.nsps = {};
5571
+ this.subs = [];
5572
+ if (uri && "object" === typeof uri) {
5573
+ opts = uri;
5574
+ uri = undefined;
5575
+ }
5576
+ opts = opts || {};
5577
+ opts.path = opts.path || "/socket.io";
5578
+ this.opts = opts;
5579
+ engine_ioClient.installTimerFunctions(this, opts);
5580
+ this.reconnection(opts.reconnection !== false);
5581
+ this.reconnectionAttempts(opts.reconnectionAttempts || Infinity);
5582
+ this.reconnectionDelay(opts.reconnectionDelay || 1000);
5583
+ this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000);
5584
+ this.randomizationFactor((_a = opts.randomizationFactor) !== null && _a !== void 0 ? _a : 0.5);
5585
+ this.backoff = new Backoff({
5586
+ min: this.reconnectionDelay(),
5587
+ max: this.reconnectionDelayMax(),
5588
+ jitter: this.randomizationFactor(),
5589
+ });
5590
+ this.timeout(null == opts.timeout ? 20000 : opts.timeout);
5591
+ this._readyState = "closed";
5592
+ this.uri = uri;
5593
+ const _parser = opts.parser || parser;
5594
+ this.encoder = new _parser.Encoder();
5595
+ this.decoder = new _parser.Decoder();
5596
+ this._autoConnect = opts.autoConnect !== false;
5597
+ if (this._autoConnect)
5598
+ this.open();
5599
+ }
5600
+ reconnection(v) {
5601
+ if (!arguments.length)
5602
+ return this._reconnection;
5603
+ this._reconnection = !!v;
5604
+ if (!v) {
5605
+ this.skipReconnect = true;
5606
+ }
5607
+ return this;
5608
+ }
5609
+ reconnectionAttempts(v) {
5610
+ if (v === undefined)
5611
+ return this._reconnectionAttempts;
5612
+ this._reconnectionAttempts = v;
5613
+ return this;
5614
+ }
5615
+ reconnectionDelay(v) {
5616
+ var _a;
5617
+ if (v === undefined)
5618
+ return this._reconnectionDelay;
5619
+ this._reconnectionDelay = v;
5620
+ (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMin(v);
5621
+ return this;
5622
+ }
5623
+ randomizationFactor(v) {
5624
+ var _a;
5625
+ if (v === undefined)
5626
+ return this._randomizationFactor;
5627
+ this._randomizationFactor = v;
5628
+ (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setJitter(v);
5629
+ return this;
5630
+ }
5631
+ reconnectionDelayMax(v) {
5632
+ var _a;
5633
+ if (v === undefined)
5634
+ return this._reconnectionDelayMax;
5635
+ this._reconnectionDelayMax = v;
5636
+ (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMax(v);
5637
+ return this;
5638
+ }
5639
+ timeout(v) {
5640
+ if (!arguments.length)
5641
+ return this._timeout;
5642
+ this._timeout = v;
5643
+ return this;
5644
+ }
5645
+ /**
5646
+ * Starts trying to reconnect if reconnection is enabled and we have not
5647
+ * started reconnecting yet
5648
+ *
5649
+ * @private
5650
+ */
5651
+ maybeReconnectOnOpen() {
5652
+ // Only try to reconnect if it's the first time we're connecting
5653
+ if (!this._reconnecting &&
5654
+ this._reconnection &&
5655
+ this.backoff.attempts === 0) {
5656
+ // keeps reconnection from firing twice for the same reconnection loop
5657
+ this.reconnect();
5658
+ }
5659
+ }
5660
+ /**
5661
+ * Sets the current transport `socket`.
5662
+ *
5663
+ * @param {Function} fn - optional, callback
5664
+ * @return self
5665
+ * @public
5666
+ */
5667
+ open(fn) {
5668
+ if (~this._readyState.indexOf("open"))
5669
+ return this;
5670
+ this.engine = new engine_ioClient.Socket(this.uri, this.opts);
5671
+ const socket = this.engine;
5672
+ const self = this;
5673
+ this._readyState = "opening";
5674
+ this.skipReconnect = false;
5675
+ // emit `open`
5676
+ const openSubDestroy = on(socket, "open", function () {
5677
+ self.onopen();
5678
+ fn && fn();
5679
+ });
5680
+ const onError = (err) => {
5681
+ this.cleanup();
5682
+ this._readyState = "closed";
5683
+ this.emitReserved("error", err);
5684
+ if (fn) {
5685
+ fn(err);
5686
+ }
5687
+ else {
5688
+ // Only do this if there is no fn to handle the error
5689
+ this.maybeReconnectOnOpen();
5690
+ }
5691
+ };
5692
+ // emit `error`
5693
+ const errorSub = on(socket, "error", onError);
5694
+ if (false !== this._timeout) {
5695
+ const timeout = this._timeout;
5696
+ // set timer
5697
+ const timer = this.setTimeoutFn(() => {
5698
+ openSubDestroy();
5699
+ onError(new Error("timeout"));
5700
+ socket.close();
5701
+ }, timeout);
5702
+ if (this.opts.autoUnref) {
5703
+ timer.unref();
5704
+ }
5705
+ this.subs.push(() => {
5706
+ this.clearTimeoutFn(timer);
5707
+ });
5708
+ }
5709
+ this.subs.push(openSubDestroy);
5710
+ this.subs.push(errorSub);
5711
+ return this;
5712
+ }
5713
+ /**
5714
+ * Alias for open()
5715
+ *
5716
+ * @return self
5717
+ * @public
5718
+ */
5719
+ connect(fn) {
5720
+ return this.open(fn);
5721
+ }
5722
+ /**
5723
+ * Called upon transport open.
5724
+ *
5725
+ * @private
5726
+ */
5727
+ onopen() {
5728
+ // clear old subs
5729
+ this.cleanup();
5730
+ // mark as open
5731
+ this._readyState = "open";
5732
+ this.emitReserved("open");
5733
+ // add new subs
5734
+ const socket = this.engine;
5735
+ this.subs.push(on(socket, "ping", this.onping.bind(this)), on(socket, "data", this.ondata.bind(this)), on(socket, "error", this.onerror.bind(this)), on(socket, "close", this.onclose.bind(this)),
5736
+ // @ts-ignore
5737
+ on(this.decoder, "decoded", this.ondecoded.bind(this)));
5738
+ }
5739
+ /**
5740
+ * Called upon a ping.
5741
+ *
5742
+ * @private
5743
+ */
5744
+ onping() {
5745
+ this.emitReserved("ping");
5746
+ }
5747
+ /**
5748
+ * Called with data.
5749
+ *
5750
+ * @private
5751
+ */
5752
+ ondata(data) {
5753
+ try {
5754
+ this.decoder.add(data);
5755
+ }
5756
+ catch (e) {
5757
+ this.onclose("parse error", e);
5758
+ }
5759
+ }
5760
+ /**
5761
+ * Called when parser fully decodes a packet.
5762
+ *
5763
+ * @private
5764
+ */
5765
+ ondecoded(packet) {
5766
+ // the nextTick call prevents an exception in a user-provided event listener from triggering a disconnection due to a "parse error"
5767
+ engine_ioClient.nextTick(() => {
5768
+ this.emitReserved("packet", packet);
5769
+ }, this.setTimeoutFn);
5770
+ }
5771
+ /**
5772
+ * Called upon socket error.
5773
+ *
5774
+ * @private
5775
+ */
5776
+ onerror(err) {
5777
+ this.emitReserved("error", err);
5778
+ }
5779
+ /**
5780
+ * Creates a new socket for the given `nsp`.
5781
+ *
5782
+ * @return {Socket}
5783
+ * @public
5784
+ */
5785
+ socket(nsp, opts) {
5786
+ let socket = this.nsps[nsp];
5787
+ if (!socket) {
5788
+ socket = new Socket(this, nsp, opts);
5789
+ this.nsps[nsp] = socket;
5790
+ }
5791
+ else if (this._autoConnect && !socket.active) {
5792
+ socket.connect();
5793
+ }
5794
+ return socket;
5795
+ }
5796
+ /**
5797
+ * Called upon a socket close.
5798
+ *
5799
+ * @param socket
5800
+ * @private
5801
+ */
5802
+ _destroy(socket) {
5803
+ const nsps = Object.keys(this.nsps);
5804
+ for (const nsp of nsps) {
5805
+ const socket = this.nsps[nsp];
5806
+ if (socket.active) {
5807
+ return;
5808
+ }
5809
+ }
5810
+ this._close();
5811
+ }
5812
+ /**
5813
+ * Writes a packet.
5814
+ *
5815
+ * @param packet
5816
+ * @private
5817
+ */
5818
+ _packet(packet) {
5819
+ const encodedPackets = this.encoder.encode(packet);
5820
+ for (let i = 0; i < encodedPackets.length; i++) {
5821
+ this.engine.write(encodedPackets[i], packet.options);
5822
+ }
5823
+ }
5824
+ /**
5825
+ * Clean up transport subscriptions and packet buffer.
5826
+ *
5827
+ * @private
5828
+ */
5829
+ cleanup() {
5830
+ this.subs.forEach((subDestroy) => subDestroy());
5831
+ this.subs.length = 0;
5832
+ this.decoder.destroy();
5833
+ }
5834
+ /**
5835
+ * Close the current socket.
5836
+ *
5837
+ * @private
5838
+ */
5839
+ _close() {
5840
+ this.skipReconnect = true;
5841
+ this._reconnecting = false;
5842
+ this.onclose("forced close");
5843
+ }
5844
+ /**
5845
+ * Alias for close()
5846
+ *
5847
+ * @private
5848
+ */
5849
+ disconnect() {
5850
+ return this._close();
5851
+ }
5852
+ /**
5853
+ * Called when:
5854
+ *
5855
+ * - the low-level engine is closed
5856
+ * - the parser encountered a badly formatted packet
5857
+ * - all sockets are disconnected
5858
+ *
5859
+ * @private
5860
+ */
5861
+ onclose(reason, description) {
5862
+ var _a;
5863
+ this.cleanup();
5864
+ (_a = this.engine) === null || _a === void 0 ? void 0 : _a.close();
5865
+ this.backoff.reset();
5866
+ this._readyState = "closed";
5867
+ this.emitReserved("close", reason, description);
5868
+ if (this._reconnection && !this.skipReconnect) {
5869
+ this.reconnect();
5870
+ }
5871
+ }
5872
+ /**
5873
+ * Attempt a reconnection.
5874
+ *
5875
+ * @private
5876
+ */
5877
+ reconnect() {
5878
+ if (this._reconnecting || this.skipReconnect)
5879
+ return this;
5880
+ const self = this;
5881
+ if (this.backoff.attempts >= this._reconnectionAttempts) {
5882
+ this.backoff.reset();
5883
+ this.emitReserved("reconnect_failed");
5884
+ this._reconnecting = false;
5885
+ }
5886
+ else {
5887
+ const delay = this.backoff.duration();
5888
+ this._reconnecting = true;
5889
+ const timer = this.setTimeoutFn(() => {
5890
+ if (self.skipReconnect)
5891
+ return;
5892
+ this.emitReserved("reconnect_attempt", self.backoff.attempts);
5893
+ // check again for the case socket closed in above events
5894
+ if (self.skipReconnect)
5895
+ return;
5896
+ self.open((err) => {
5897
+ if (err) {
5898
+ self._reconnecting = false;
5899
+ self.reconnect();
5900
+ this.emitReserved("reconnect_error", err);
5901
+ }
5902
+ else {
5903
+ self.onreconnect();
5904
+ }
5905
+ });
5906
+ }, delay);
5907
+ if (this.opts.autoUnref) {
5908
+ timer.unref();
5909
+ }
5910
+ this.subs.push(() => {
5911
+ this.clearTimeoutFn(timer);
5912
+ });
5913
+ }
5914
+ }
5915
+ /**
5916
+ * Called upon successful reconnect.
5917
+ *
5918
+ * @private
5919
+ */
5920
+ onreconnect() {
5921
+ const attempt = this.backoff.attempts;
5922
+ this._reconnecting = false;
5923
+ this.backoff.reset();
5924
+ this.emitReserved("reconnect", attempt);
5925
+ }
5926
+ }
5927
+
5928
+ /**
5929
+ * Managers cache.
5930
+ */
5931
+ const cache = {};
5932
+ function lookup(uri, opts) {
5933
+ if (typeof uri === "object") {
5934
+ opts = uri;
5935
+ uri = undefined;
5936
+ }
5937
+ opts = opts || {};
5938
+ const parsed = url(uri, opts.path || "/socket.io");
5939
+ const source = parsed.source;
5940
+ const id = parsed.id;
5941
+ const path = parsed.path;
5942
+ const sameNamespace = cache[id] && path in cache[id]["nsps"];
5943
+ const newConnection = opts.forceNew ||
5944
+ opts["force new connection"] ||
5945
+ false === opts.multiplex ||
5946
+ sameNamespace;
5947
+ let io;
5948
+ if (newConnection) {
5949
+ io = new Manager(source, opts);
5950
+ }
5951
+ else {
5952
+ if (!cache[id]) {
5953
+ cache[id] = new Manager(source, opts);
5954
+ }
5955
+ io = cache[id];
5956
+ }
5957
+ if (parsed.query && !opts.query) {
5958
+ opts.query = parsed.queryKey;
5959
+ }
5960
+ return io.socket(parsed.path, opts);
5961
+ }
5962
+ // so that "lookup" can be used both as a function (e.g. `io(...)`) and as a
5963
+ // namespace (e.g. `io.connect(...)`), for backward compatibility
5964
+ Object.assign(lookup, {
5965
+ Manager,
5966
+ Socket,
5967
+ io: lookup,
5968
+ connect: lookup,
5969
+ });
5970
+
5971
+ const socket = lookup('http://localhost:8000');
5972
+
3929
5973
  const CoreOutline = ({
3930
- children
5974
+ children,
5975
+ data_source_id,
5976
+ data_source_secret
3931
5977
  }) => {
3932
5978
  const [events, setEvents] = React.useState([]);
5979
+ const [replayEvents, setReplayEvents] = React.useState([]);
3933
5980
  const recorderActive = React.useRef(false);
3934
5981
  const [currentPage, setCurrentPage] = React.useState(window.location.href);
5982
+ const [location, setLocation] = React.useState({
5983
+ latitude: null,
5984
+ longitude: null
5985
+ });
5986
+ const [browser, setBrowser] = React.useState(getBrowserInfo());
5987
+ const [appToken, setAppToken] = React.useState('');
5988
+ const [sessionId, setSessionId] = React.useState('');
5989
+ async function authorizeApp(data_source_id, data_source_secret) {
5990
+ const requestOptions = {
5991
+ method: 'POST',
5992
+ headers: {
5993
+ 'Content-Type': 'application/json'
5994
+ },
5995
+ body: JSON.stringify({
5996
+ data_source_id: data_source_id,
5997
+ data_source_secret: data_source_secret
5998
+ })
5999
+ };
6000
+ const response = fetch(`http://localhost:4000/data-source/authorize`, requestOptions).then(response => response.json()).then(data => {
6001
+ setAppToken(data.app_token);
6002
+ return data;
6003
+ }).catch(error => {
6004
+ console.error('Error:', error);
6005
+ return error;
6006
+ });
6007
+ return response;
6008
+ }
6009
+ React.useEffect(async () => {
6010
+ await authorizeApp(data_source_id, data_source_secret);
6011
+ setSessionId(uuid.v4());
6012
+ localStorage.setItem('coreOutlineSessionId', sessionId);
6013
+ localStorage.setItem('coreOutlineDataSourceIdId', data_source_id);
6014
+ console.log('Session', sessionId);
6015
+ socket.send({
6016
+ topic: 'session-data',
6017
+ data_source_id: data_source_id,
6018
+ session_id: sessionId,
6019
+ start_date: new Date().toLocaleString(),
6020
+ latitude: location.latitude,
6021
+ longitude: location.longitude,
6022
+ browser: browser,
6023
+ event_id: 'SESSION_START'
6024
+ });
6025
+ return () => {
6026
+ socket.send({
6027
+ topic: 'session-data',
6028
+ data_source_id: data_source_id,
6029
+ session_id: sessionId,
6030
+ start_date: new Date().toLocaleString(),
6031
+ latitude: location.latitude,
6032
+ longitude: location.longitude,
6033
+ browser: browser,
6034
+ event_id: 'SESSION_END'
6035
+ });
6036
+ };
6037
+ }, []);
3935
6038
  React.useEffect(() => {
3936
- console.log(currentPage);
6039
+ const navigationEvent = {
6040
+ type: 4,
6041
+ data: {
6042
+ href: window.location.href,
6043
+ width: 1536,
6044
+ height: 730
6045
+ },
6046
+ timestamp: Date.now()
6047
+ };
6048
+ const startTime = performance.now();
6049
+ const observer = new MutationObserver(() => {
6050
+ const endTime = performance.now();
6051
+ const loadTime = endTime - startTime;
6052
+ navigationEvent.data.loadTime = loadTime;
6053
+ const hours = Math.floor(loadTime / 3600000);
6054
+ const minutes = Math.floor(loadTime % 3600000 / 60000);
6055
+ const seconds = Math.floor(loadTime % 60000 / 1000);
6056
+ navigationEvent.data.loadTimeFormatted = `${hours} hours ${minutes} minutes ${seconds} seconds`;
6057
+ observer.disconnect();
6058
+ });
6059
+ observer.observe(document, {
6060
+ childList: true,
6061
+ subtree: true
6062
+ });
6063
+ setEvents(prevEvents => [...prevEvents, navigationEvent]);
3937
6064
  const handleNavigation = () => {
3938
6065
  setCurrentPage(window.location.href);
6066
+ socket.send({
6067
+ topic: 'session-data',
6068
+ data_source_id: data_source_id,
6069
+ session_id: sessionId,
6070
+ start_date: new Date().toLocaleString(),
6071
+ latitude: location.latitude,
6072
+ longitude: location.longitude,
6073
+ browser: browser,
6074
+ page_name: window.location.href,
6075
+ event_id: 'PAGE_NAVIGATION'
6076
+ });
3939
6077
  saveEvents(events);
3940
6078
  };
3941
6079
  window.addEventListener('popstate', handleNavigation);
@@ -3949,13 +6087,55 @@ const CoreOutline = ({
3949
6087
  window.history.pushState = originalPushState;
3950
6088
  };
3951
6089
  }, [currentPage]);
6090
+ React.useEffect(() => {
6091
+ console.log('Location', location);
6092
+ getLocation();
6093
+ }, []);
6094
+ React.useEffect(() => {
6095
+ let stopFn;
6096
+ if (!recorderActive.current) {
6097
+ stopFn = record({
6098
+ emit(event) {
6099
+ setReplayEvents(prevEvents => [...prevEvents, event]);
6100
+ },
6101
+ maskAllInputs: false,
6102
+ maskTextSelector: null
6103
+ });
6104
+ recorderActive.current = true;
6105
+ }
6106
+ return () => {
6107
+ if (stopFn) {
6108
+ stopFn();
6109
+ saveEvents(events);
6110
+ recorderActive.current = false;
6111
+ }
6112
+ };
6113
+ }, []);
3952
6114
  React.useEffect(() => {
3953
6115
  let stopFn;
3954
6116
  if (!recorderActive.current) {
3955
6117
  stopFn = record({
3956
6118
  emit(event) {
6119
+ console.log('Event:', event);
6120
+ if (event.type == 3 && event.data.type == 2) {
6121
+ return;
6122
+ }
6123
+ if (event.type == 4) {
6124
+ return;
6125
+ }
6126
+ if (event.type == 3 && event.data.source == 0) {
6127
+ return;
6128
+ }
6129
+ if (event.type == 3 && event.data.source == 1) {
6130
+ return;
6131
+ }
6132
+ if (event.type == 3 && event.data.type == 3) {
6133
+ console.log('Contextmenu Event:', event);
6134
+ }
3957
6135
  setEvents(prevEvents => [...prevEvents, event]);
3958
- }
6136
+ },
6137
+ maskAllInputs: false,
6138
+ maskTextSelector: null
3959
6139
  });
3960
6140
  recorderActive.current = true;
3961
6141
  }
@@ -3967,6 +6147,51 @@ const CoreOutline = ({
3967
6147
  }
3968
6148
  };
3969
6149
  }, []);
6150
+ React.useEffect(() => {
6151
+ const handleClick = event => {
6152
+ console.log('Inner text:', event.target.innerText);
6153
+ const clickEvent = {
6154
+ type: EventType.IncrementalSnapshot,
6155
+ data: {
6156
+ source: IncrementalSource.MouseInteraction,
6157
+ type: MouseInteractions.Click,
6158
+ id: event.target.id,
6159
+ x: event.clientX,
6160
+ y: event.clientY
6161
+ },
6162
+ timestamp: Date.now()
6163
+ };
6164
+ const clickedElement = document.elementFromPoint(clickEvent.data.x, clickEvent.data.y);
6165
+ if (clickedElement) {
6166
+ clickEvent.data.metadata = {
6167
+ label: clickedElement.getAttribute('data-label') || clickedElement.innerText || null,
6168
+ value: clickedElement.getAttribute('value') || clickedElement.innerText || null,
6169
+ id: clickedElement.getAttribute('id') || clickedElement.innerText || null,
6170
+ name: clickedElement.getAttribute('name') || clickedElement.innerText || null,
6171
+ class: clickedElement.getAttribute('class') || clickedElement.innerText || null,
6172
+ tag: clickedElement.tagName,
6173
+ html: String(clickedElement.getHTML()),
6174
+ innerText: event.target.innerText
6175
+ };
6176
+ }
6177
+ setEvents(prevEvents => [...prevEvents, clickEvent]);
6178
+ socket.send({
6179
+ topic: 'session-data',
6180
+ data_source_id: data_source_id,
6181
+ session_id: sessionId,
6182
+ start_date: new Date().toLocaleString(),
6183
+ latitude: location.latitude,
6184
+ longitude: location.longitude,
6185
+ browser: browser,
6186
+ event_id: 'ITEM_CLICKED'
6187
+ // item_clicked: event.target,
6188
+ });
6189
+ };
6190
+ document.addEventListener('click', handleClick);
6191
+ return () => {
6192
+ document.removeEventListener('click', handleClick);
6193
+ };
6194
+ }, []);
3970
6195
  function saveEvents(events) {
3971
6196
  const requestOptions = {
3972
6197
  method: 'PUT',
@@ -3975,12 +6200,103 @@ const CoreOutline = ({
3975
6200
  },
3976
6201
  body: JSON.stringify(events)
3977
6202
  };
3978
- fetch('http://localhost:8000/generate-s3-url').then(response => response.json()).then(data => {
6203
+ fetch(`http://localhost:5000/generate-s3-url/${data_source_id}/${sessionId}`).then(response => response.json()).then(data => {
3979
6204
  const uploadURL = data.signed_url;
3980
6205
  return fetch(uploadURL, requestOptions);
3981
6206
  });
3982
6207
  }
3983
- return /*#__PURE__*/React__default["default"].createElement("div", null, children);
6208
+ function saveEventsLocally(type = 'formatted' ) {
6209
+ let blob = '';
6210
+ if (type === 'formatted') {
6211
+ blob = new Blob([JSON.stringify(events, null, 2)], {
6212
+ type: 'application/json'
6213
+ });
6214
+ } else if (type === 'raw') {
6215
+ blob = new Blob([JSON.stringify(replayEvents, null, 2)], {
6216
+ type: 'application/json'
6217
+ });
6218
+ }
6219
+ const url = URL.createObjectURL(blob);
6220
+ const a = document.createElement('a');
6221
+ a.href = url;
6222
+ a.download = `${type}_events.json`;
6223
+ a.click();
6224
+ URL.revokeObjectURL(url);
6225
+ }
6226
+ function getBrowserInfo() {
6227
+ const userAgent = navigator.userAgent;
6228
+ let browserName = 'Unknown';
6229
+ if (userAgent.indexOf('Firefox') > -1) {
6230
+ browserName = 'Firefox';
6231
+ } else if (userAgent.indexOf('Opera') > -1 || userAgent.indexOf('OPR') > -1) {
6232
+ browserName = 'Opera';
6233
+ } else if (userAgent.indexOf('Chrome') > -1) {
6234
+ browserName = 'Chrome';
6235
+ } else if (userAgent.indexOf('Safari') > -1) {
6236
+ browserName = 'Safari';
6237
+ } else if (userAgent.indexOf('MSIE') > -1 || userAgent.indexOf('Trident/') > -1) {
6238
+ browserName = 'Internet Explorer';
6239
+ }
6240
+ return browserName;
6241
+ }
6242
+ function getLocation() {
6243
+ if (navigator.geolocation) {
6244
+ navigator.geolocation.getCurrentPosition(position => {
6245
+ setLocation({
6246
+ latitude: position.coords.latitude,
6247
+ longitude: position.coords.longitude
6248
+ });
6249
+ }, error => {
6250
+ console.error('Error getting location:', error);
6251
+ });
6252
+ } else {
6253
+ console.error('Geolocation is not supported by this browser.');
6254
+ }
6255
+ }
6256
+ return /*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement("button", {
6257
+ onClick: () => {
6258
+ saveEventsLocally('formatted');
6259
+ saveEventsLocally('raw');
6260
+ }
6261
+ }, "Save Events Locally"), children);
6262
+ };
6263
+ const flag_item_clicked = item_id => {
6264
+ const sessionId = localStorage.getItem('coreOutlineSessionId');
6265
+ const dataSourceId = localStorage.getItem('coreOutlineDataSourceIdId');
6266
+ console.log('Session', sessionId);
6267
+ console.log('Data Source', dataSourceId);
6268
+ socket.send({
6269
+ topic: 'session-data',
6270
+ data_source_id: dataSourceId,
6271
+ session_id: sessionId,
6272
+ start_date: new Date().toLocaleString(),
6273
+ event_id: 'PRODUCT_CLICKED',
6274
+ item_clicked: item_id
6275
+ });
6276
+ return {
6277
+ status: 'success',
6278
+ message: 'Item click flagged successfully.'
6279
+ };
6280
+ };
6281
+ const flag_item_purchased = item_id => {
6282
+ const sessionId = localStorage.getItem('coreOutlineSessionId');
6283
+ const dataSourceId = localStorage.getItem('coreOutlineDataSourceIdId');
6284
+ console.log('Session', sessionId);
6285
+ console.log('Data Source', dataSourceId);
6286
+ socket.send({
6287
+ topic: 'session-data',
6288
+ data_source_id: dataSourceId,
6289
+ session_id: sessionId,
6290
+ start_date: new Date().toLocaleString(),
6291
+ event_id: 'PRODUCT_PURCHASED',
6292
+ item_clicked: item_id
6293
+ });
6294
+ return {
6295
+ status: 'success',
6296
+ message: 'Item purchase flagged successfully.'
6297
+ };
3984
6298
  };
3985
6299
 
3986
- module.exports = CoreOutline;
6300
+ exports["default"] = CoreOutline;
6301
+ exports.flag_item_clicked = flag_item_clicked;
6302
+ exports.flag_item_purchased = flag_item_purchased;