iframe.io 1.0.3 → 1.0.4

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
@@ -23,17 +23,42 @@ Object.defineProperty(exports, "__esModule", { value: true });
23
23
  function newObject(data) {
24
24
  return JSON.parse(JSON.stringify(data));
25
25
  }
26
- var callbackId = function () {
27
- var rmin = 10, rmax = 9999;
28
- return Date.now() + String(Math.floor(Math.random() * (rmax - rmin + 1) + (rmin + 1)));
26
+ function getMessageSize(data) {
27
+ try {
28
+ return JSON.stringify(data).length;
29
+ }
30
+ catch (_a) {
31
+ return 0;
32
+ }
33
+ }
34
+ function sanitizePayload(payload, maxSize) {
35
+ if (!payload)
36
+ return payload;
37
+ var size = getMessageSize(payload);
38
+ if (size > maxSize) {
39
+ throw new Error("Message size ".concat(size, " exceeds limit ").concat(maxSize));
40
+ }
41
+ // Basic sanitization - remove functions and undefined values
42
+ return JSON.parse(JSON.stringify(payload));
43
+ }
44
+ var ackId = function () {
45
+ var rmin = 100000, rmax = 999999;
46
+ var timestamp = Date.now();
47
+ var random = Math.floor(Math.random() * (rmax - rmin + 1) + rmin);
48
+ return "".concat(timestamp, "_").concat(random);
29
49
  };
30
50
  var IOF = /** @class */ (function () {
31
51
  function IOF(options) {
52
+ if (options === void 0) { options = {}; }
53
+ this.messageQueue = [];
54
+ this.messageRateTracker = [];
55
+ this.reconnectAttempts = 0;
56
+ this.maxReconnectAttempts = 5;
32
57
  if (options && typeof options !== 'object')
33
58
  throw new Error('Invalid Options');
34
- this.options = options;
59
+ this.options = __assign({ debug: false, heartbeatInterval: 30000, connectionTimeout: 10000, maxMessageSize: 1024 * 1024, maxMessagesPerSecond: 100, autoReconnect: true, messageQueueSize: 50 }, options);
35
60
  this.Events = {};
36
- this.peer = { type: 'IFRAME' };
61
+ this.peer = { type: 'IFRAME', connected: false };
37
62
  if (options.type)
38
63
  this.peer.type = options.type.toUpperCase();
39
64
  }
@@ -42,92 +67,286 @@ var IOF = /** @class */ (function () {
42
67
  for (var _i = 0; _i < arguments.length; _i++) {
43
68
  args[_i] = arguments[_i];
44
69
  }
45
- console.debug.apply(console, args);
70
+ this.options.debug && console.debug.apply(console, args);
71
+ };
72
+ IOF.prototype.isConnected = function () {
73
+ return !!this.peer.connected && !!this.peer.source;
74
+ };
75
+ // Enhanced connection health monitoring
76
+ IOF.prototype.startHeartbeat = function () {
77
+ var _this = this;
78
+ if (!this.options.heartbeatInterval)
79
+ return;
80
+ this.heartbeatTimer = setInterval(function () {
81
+ if (_this.isConnected()) {
82
+ var now = Date.now();
83
+ // Check if peer is still responsive
84
+ if (_this.peer.lastHeartbeat && (now - _this.peer.lastHeartbeat) > (_this.options.heartbeatInterval * 2)) {
85
+ _this.debug("[".concat(_this.peer.type, "] Heartbeat timeout detected"));
86
+ _this.handleConnectionLoss();
87
+ return;
88
+ }
89
+ // Send heartbeat
90
+ try {
91
+ _this.emit('__heartbeat', { timestamp: now });
92
+ }
93
+ catch (error) {
94
+ _this.debug("[".concat(_this.peer.type, "] Heartbeat send failed:"), error);
95
+ _this.handleConnectionLoss();
96
+ }
97
+ }
98
+ }, this.options.heartbeatInterval);
99
+ };
100
+ IOF.prototype.stopHeartbeat = function () {
101
+ if (!this.heartbeatTimer)
102
+ return;
103
+ clearInterval(this.heartbeatTimer);
104
+ this.heartbeatTimer = undefined;
105
+ };
106
+ // Handle connection loss and potential reconnection
107
+ IOF.prototype.handleConnectionLoss = function () {
108
+ if (!this.peer.connected)
109
+ return;
110
+ this.peer.connected = false;
111
+ this.stopHeartbeat();
112
+ this.fire('disconnect', { reason: 'CONNECTION_LOST' });
113
+ this.options.autoReconnect
114
+ && this.reconnectAttempts < this.maxReconnectAttempts
115
+ && this.attemptReconnection();
116
+ };
117
+ IOF.prototype.attemptReconnection = function () {
118
+ var _this = this;
119
+ if (this.reconnectTimer)
120
+ return;
121
+ this.reconnectAttempts++;
122
+ var delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 30000); // Exponential backoff, max 30s
123
+ this.debug("[".concat(this.peer.type, "] Attempting reconnection ").concat(this.reconnectAttempts, "/").concat(this.maxReconnectAttempts, " in ").concat(delay, "ms"));
124
+ this.fire('reconnecting', { attempt: this.reconnectAttempts, delay: delay });
125
+ this.reconnectTimer = setTimeout(function () {
126
+ _this.reconnectTimer = undefined;
127
+ // Re-initiate connection for WINDOW type
128
+ _this.peer.type === 'WINDOW'
129
+ && _this.peer.source
130
+ && _this.peer.origin
131
+ && _this.emit('ping');
132
+ // For IFRAME type, just wait for incoming connection
133
+ // Set timeout for this reconnection attempt
134
+ setTimeout(function () {
135
+ if (!_this.peer.connected) {
136
+ _this.reconnectAttempts < _this.maxReconnectAttempts
137
+ ? _this.attemptReconnection()
138
+ : _this.fire('reconnection_failed', { attempts: _this.reconnectAttempts });
139
+ }
140
+ }, _this.options.connectionTimeout);
141
+ }, delay);
142
+ };
143
+ // Message rate limiting
144
+ IOF.prototype.checkRateLimit = function () {
145
+ if (!this.options.maxMessagesPerSecond)
146
+ return true;
147
+ var now = Date.now(), aSecondAgo = now - 1000;
148
+ // Clean old entries
149
+ this.messageRateTracker = this.messageRateTracker.filter(function (timestamp) { return timestamp > aSecondAgo; });
150
+ // Check if limit exceeded
151
+ if (this.messageRateTracker.length >= this.options.maxMessagesPerSecond) {
152
+ this.fire('error', {
153
+ type: 'RATE_LIMIT_EXCEEDED',
154
+ limit: this.options.maxMessagesPerSecond,
155
+ current: this.messageRateTracker.length
156
+ });
157
+ return false;
158
+ }
159
+ this.messageRateTracker.push(now);
160
+ return true;
161
+ };
162
+ // Queue messages when not connected
163
+ IOF.prototype.queueMessage = function (_event, payload, fn) {
164
+ if (this.messageQueue.length >= this.options.messageQueueSize) {
165
+ // Remove oldest message
166
+ var removed = this.messageQueue.shift();
167
+ this.debug("[".concat(this.peer.type, "] Message queue full, removed oldest message:"), removed === null || removed === void 0 ? void 0 : removed._event);
168
+ }
169
+ this.messageQueue.push({
170
+ _event: _event,
171
+ payload: payload,
172
+ fn: fn,
173
+ timestamp: Date.now()
174
+ });
175
+ this.debug("[".concat(this.peer.type, "] Queued message: ").concat(_event, " (queue size: ").concat(this.messageQueue.length, ")"));
176
+ };
177
+ // Process queued messages when connection is established
178
+ IOF.prototype.processMessageQueue = function () {
179
+ var _this = this;
180
+ if (!this.isConnected() || this.messageQueue.length === 0)
181
+ return;
182
+ this.debug("[".concat(this.peer.type, "] Processing ").concat(this.messageQueue.length, " queued messages"));
183
+ var queue = __spreadArray([], this.messageQueue, true);
184
+ this.messageQueue = [];
185
+ queue.forEach(function (message) {
186
+ try {
187
+ _this.emit(message._event, message.payload, message.fn);
188
+ }
189
+ catch (error) {
190
+ _this.debug("[".concat(_this.peer.type, "] Failed to send queued message:"), error);
191
+ }
192
+ });
46
193
  };
194
+ /**
195
+ * Establish a connection with an iframe containing
196
+ * in the current window
197
+ */
47
198
  IOF.prototype.initiate = function (contentWindow, iframeOrigin) {
48
199
  var _this = this;
49
- // Establish a connection with an iframe containing in the current window
50
200
  if (!contentWindow || !iframeOrigin)
51
201
  throw new Error('Invalid Connection initiation arguments');
52
202
  if (this.peer.type === 'IFRAME')
53
203
  throw new Error('Expect IFRAME to <listen> and WINDOW to <initiate> a connection');
204
+ // Clean up existing listener if any
205
+ this.cleanup();
54
206
  this.peer.source = contentWindow;
55
207
  this.peer.origin = iframeOrigin;
56
- window.addEventListener('message', function (_a) {
208
+ this.peer.connected = false;
209
+ this.reconnectAttempts = 0;
210
+ this.messageListener = function (_a) {
57
211
  var origin = _a.origin, data = _a.data, source = _a.source;
58
- // Check valid message
59
- if (origin !== _this.peer.origin
60
- || !source
61
- || typeof data !== 'object'
62
- || !data.hasOwnProperty('_event'))
63
- return;
64
- var _b = data, _event = _b._event, payload = _b.payload, cid = _b.cid;
65
- _this.debug("[".concat(_this.peer.type, "] Message: ").concat(_event), payload || '');
66
- // Handshake or availability check events
67
- if (_event == 'pong') {
68
- // Content Window is connected to iframe
69
- _this.fire('connect');
70
- return _this.debug("[".concat(_this.peer.type, "] connected"));
212
+ try {
213
+ // Enhanced security: check valid message structure
214
+ if (origin !== _this.peer.origin
215
+ || !source
216
+ || typeof data !== 'object'
217
+ || !data.hasOwnProperty('_event'))
218
+ return;
219
+ var _b = data, _event = _b._event, payload = _b.payload, cid = _b.cid, timestamp = _b.timestamp;
220
+ // Handle heartbeat responses
221
+ if (_event === '__heartbeat_response') {
222
+ _this.peer.lastHeartbeat = Date.now();
223
+ return;
224
+ }
225
+ // Handle heartbeat requests
226
+ if (_event === '__heartbeat') {
227
+ _this.emit('__heartbeat_response', { timestamp: Date.now() });
228
+ _this.peer.lastHeartbeat = Date.now();
229
+ return;
230
+ }
231
+ _this.debug("[".concat(_this.peer.type, "] Message: ").concat(_event), payload || '');
232
+ // Handshake or availability check events
233
+ if (_event == 'pong') {
234
+ // Content Window is connected to iframe
235
+ _this.peer.connected = true;
236
+ _this.reconnectAttempts = 0;
237
+ _this.peer.lastHeartbeat = Date.now();
238
+ _this.startHeartbeat();
239
+ _this.fire('connect');
240
+ _this.processMessageQueue();
241
+ return _this.debug("[".concat(_this.peer.type, "] connected"));
242
+ }
243
+ // Fire available event listeners
244
+ _this.fire(_event, payload, cid);
71
245
  }
72
- // Fire available event listeners
73
- _this.fire(_event, payload, cid);
74
- }, false);
246
+ catch (error) {
247
+ _this.debug("[".concat(_this.peer.type, "] Message handling error:"), error);
248
+ _this.fire('error', {
249
+ type: 'MESSAGE_HANDLING_ERROR',
250
+ error: error instanceof Error ? error.message : String(error),
251
+ origin: origin
252
+ });
253
+ }
254
+ };
255
+ window.addEventListener('message', this.messageListener, false);
75
256
  this.debug("[".concat(this.peer.type, "] Initiate connection: IFrame origin <").concat(iframeOrigin, ">"));
76
257
  this.emit('ping');
77
258
  return this;
78
259
  };
260
+ /**
261
+ * Listening to connection from the content window
262
+ */
79
263
  IOF.prototype.listen = function (hostOrigin) {
80
- // Listening to connection from the content window
81
264
  var _this = this;
82
265
  this.peer.type = 'IFRAME'; // iframe.io connection listener is automatically set as IFRAME
266
+ this.peer.connected = false;
267
+ this.reconnectAttempts = 0;
83
268
  this.debug("[".concat(this.peer.type, "] Listening to connect").concat(hostOrigin ? ": Host <".concat(hostOrigin, ">") : ''));
84
- window.addEventListener('message', function (_a) {
269
+ // Clean up existing listener if any
270
+ this.cleanup();
271
+ this.messageListener = function (_a) {
85
272
  var origin = _a.origin, data = _a.data, source = _a.source;
86
- // Check host origin where event must only come from.
87
- if (hostOrigin && hostOrigin !== origin)
88
- throw new Error('Invalid Event Origin');
89
- // Check valid message
90
- if (!source
91
- || typeof data !== 'object'
92
- || !data.hasOwnProperty('_event'))
93
- return;
94
- // Define peer source window and origin
95
- if (!_this.peer.source) {
96
- _this.peer = __assign(__assign({}, _this.peer), { source: source, origin: origin });
97
- _this.debug("[".concat(_this.peer.type, "] Connect to ").concat(origin));
273
+ try {
274
+ // Enhanced security: check host origin where event must only come from
275
+ if (hostOrigin && hostOrigin !== origin) {
276
+ _this.fire('error', { type: 'INVALID_ORIGIN', expected: hostOrigin, received: origin });
277
+ return;
278
+ }
279
+ // Enhanced security: check valid message structure
280
+ if (!source
281
+ || typeof data !== 'object'
282
+ || !data.hasOwnProperty('_event'))
283
+ return;
284
+ // Define peer source window and origin
285
+ if (!_this.peer.source) {
286
+ _this.peer = __assign(__assign({}, _this.peer), { source: source, origin: origin });
287
+ _this.debug("[".concat(_this.peer.type, "] Connect to ").concat(origin));
288
+ }
289
+ // Origin different from handshaked source origin
290
+ else if (origin !== _this.peer.origin) {
291
+ _this.fire('error', { type: 'ORIGIN_MISMATCH', expected: _this.peer.origin, received: origin });
292
+ return;
293
+ }
294
+ var _event = data._event, payload = data.payload, cid = data.cid, timestamp = data.timestamp;
295
+ // Handle heartbeat responses
296
+ if (_event === '__heartbeat_response') {
297
+ _this.peer.lastHeartbeat = Date.now();
298
+ return;
299
+ }
300
+ // Handle heartbeat requests
301
+ if (_event === '__heartbeat') {
302
+ _this.emit('__heartbeat_response', { timestamp: Date.now() });
303
+ _this.peer.lastHeartbeat = Date.now();
304
+ return;
305
+ }
306
+ _this.debug("[".concat(_this.peer.type, "] Message: ").concat(_event), payload || '');
307
+ // Handshake or availability check events
308
+ if (_event == 'ping') {
309
+ _this.emit('pong');
310
+ // Iframe is connected to content window
311
+ _this.peer.connected = true;
312
+ _this.reconnectAttempts = 0;
313
+ _this.peer.lastHeartbeat = Date.now();
314
+ _this.startHeartbeat();
315
+ _this.fire('connect');
316
+ _this.processMessageQueue();
317
+ return _this.debug("[".concat(_this.peer.type, "] connected"));
318
+ }
319
+ // Fire available event listeners
320
+ _this.fire(_event, payload, cid);
98
321
  }
99
- // Origin different from handshaked source origin
100
- else if (origin !== _this.peer.origin)
101
- throw new Error('Invalid Origin');
102
- var _event = data._event, payload = data.payload, cid = data.cid;
103
- _this.debug("[".concat(_this.peer.type, "] Message: ").concat(_event), payload || '');
104
- // Handshake or availability check events
105
- if (_event == 'ping') {
106
- _this.emit('pong');
107
- // Iframe is connected to content window
108
- _this.fire('connect');
109
- return _this.debug("[".concat(_this.peer.type, "] connected"));
322
+ catch (error) {
323
+ _this.debug("[".concat(_this.peer.type, "] Message handling error:"), error);
324
+ _this.fire('error', {
325
+ type: 'MESSAGE_HANDLING_ERROR',
326
+ error: error instanceof Error ? error.message : String(error),
327
+ origin: origin
328
+ });
110
329
  }
111
- // Fire available event listeners
112
- _this.fire(_event, payload, cid);
113
- }, false);
330
+ };
331
+ window.addEventListener('message', this.messageListener, false);
114
332
  return this;
115
333
  };
116
334
  IOF.prototype.fire = function (_event, payload, cid) {
117
335
  var _this = this;
118
- // Volatile event
336
+ // Volatile event - check if any listeners exist
119
337
  if (!this.Events[_event]
120
338
  && !this.Events[_event + '--@once'])
121
339
  return this.debug("[".concat(this.peer.type, "] No <").concat(_event, "> listener defined"));
122
- var callbackFn = cid ?
123
- function (error) {
340
+ var ackFn = cid
341
+ ? function (error) {
124
342
  var args = [];
125
343
  for (var _i = 1; _i < arguments.length; _i++) {
126
344
  args[_i - 1] = arguments[_i];
127
345
  }
128
- _this.emit("".concat(_event, "--").concat(cid, "--@callback"), { error: error || false, args: args });
346
+ _this.emit("".concat(_event, "--").concat(cid, "--@ack"), { error: error || false, args: args });
129
347
  return;
130
- } : undefined;
348
+ }
349
+ : undefined;
131
350
  var listeners = [];
132
351
  if (this.Events[_event + '--@once']) {
133
352
  // Once triggable event
@@ -138,27 +357,72 @@ var IOF = /** @class */ (function () {
138
357
  }
139
358
  else
140
359
  listeners = this.Events[_event];
141
- // Fire listeners
142
- listeners.map(function (fn) { return payload !== undefined ? fn(payload, callbackFn) : fn(callbackFn); });
360
+ // Fire listeners with error handling
361
+ listeners.forEach(function (fn) {
362
+ try {
363
+ payload !== undefined ? fn(payload, ackFn) : fn(ackFn);
364
+ }
365
+ catch (error) {
366
+ _this.debug("[".concat(_this.peer.type, "] Listener error for ").concat(_event, ":"), error);
367
+ _this.fire('error', {
368
+ type: 'LISTENER_ERROR',
369
+ event: _event,
370
+ error: error instanceof Error ? error.message : String(error)
371
+ });
372
+ }
373
+ });
143
374
  };
144
375
  IOF.prototype.emit = function (_event, payload, fn) {
145
- if (!this.peer.source)
146
- throw new Error('No Connection initiated');
376
+ // Check rate limiting
377
+ if (!this.checkRateLimit())
378
+ return this;
379
+ // Queue message if not connected (except for connection-related events)
380
+ if (!this.isConnected() && !['ping', 'pong', '__heartbeat', '__heartbeat_response'].includes(_event)) {
381
+ this.queueMessage(_event, payload, fn);
382
+ return this;
383
+ }
384
+ if (!this.peer.source) {
385
+ this.fire('error', { type: 'NO_CONNECTION', event: _event });
386
+ return this;
387
+ }
147
388
  if (typeof payload == 'function') {
148
389
  fn = payload;
149
390
  payload = undefined;
150
391
  }
151
- // Acknowledge/callback event listener
152
- var cid;
153
- if (typeof fn === 'function') {
154
- var callbackFunction_1 = fn;
155
- cid = callbackId();
156
- this.once("".concat(_event, "--").concat(cid, "--@callback"), function (_a) {
157
- var error = _a.error, args = _a.args;
158
- return callbackFunction_1.apply(void 0, __spreadArray([error], args, false));
392
+ try {
393
+ // Enhanced security: sanitize and validate payload
394
+ var sanitizedPayload = payload ? sanitizePayload(payload, this.options.maxMessageSize) : payload;
395
+ // Acknowledge event listener
396
+ var cid = void 0;
397
+ if (typeof fn === 'function') {
398
+ var ackFunction_1 = fn;
399
+ cid = ackId();
400
+ this.once("".concat(_event, "--").concat(cid, "--@ack"), function (_a) {
401
+ var error = _a.error, args = _a.args;
402
+ return ackFunction_1.apply(void 0, __spreadArray([error], args, false));
403
+ });
404
+ }
405
+ var messageData = {
406
+ _event: _event,
407
+ payload: sanitizedPayload,
408
+ cid: cid,
409
+ timestamp: Date.now(),
410
+ size: getMessageSize(sanitizedPayload)
411
+ };
412
+ this.peer.source.postMessage(newObject(messageData), this.peer.origin);
413
+ }
414
+ catch (error) {
415
+ this.debug("[".concat(this.peer.type, "] Emit error:"), error);
416
+ this.fire('error', {
417
+ type: 'EMIT_ERROR',
418
+ event: _event,
419
+ error: error instanceof Error ? error.message : String(error)
159
420
  });
421
+ // Call acknowledgment with error if provided
422
+ if (typeof fn === 'function') {
423
+ fn(error instanceof Error ? error.message : String(error));
424
+ }
160
425
  }
161
- this.peer.source.postMessage(newObject({ _event: _event, payload: payload, cid: cid }), this.peer.origin);
162
426
  return this;
163
427
  };
164
428
  IOF.prototype.on = function (_event, fn) {
@@ -180,7 +444,19 @@ var IOF = /** @class */ (function () {
180
444
  };
181
445
  IOF.prototype.off = function (_event, fn) {
182
446
  // Remove Event listener
183
- delete this.Events[_event];
447
+ if (fn && this.Events[_event]) {
448
+ // Remove specific listener if provided
449
+ var index = this.Events[_event].indexOf(fn);
450
+ if (index > -1) {
451
+ this.Events[_event].splice(index, 1);
452
+ // Remove event array if empty
453
+ if (this.Events[_event].length === 0)
454
+ delete this.Events[_event];
455
+ }
456
+ }
457
+ // Remove all listeners for event
458
+ else
459
+ delete this.Events[_event];
184
460
  typeof fn == 'function' && fn();
185
461
  this.debug("[".concat(this.peer.type, "] <").concat(_event, "> listener off"));
186
462
  return this;
@@ -192,6 +468,93 @@ var IOF = /** @class */ (function () {
192
468
  this.debug("[".concat(this.peer.type, "] All listeners removed"));
193
469
  return this;
194
470
  };
471
+ IOF.prototype.emitAsync = function (_event, payload) {
472
+ var _this = this;
473
+ return new Promise(function (resolve, reject) {
474
+ try {
475
+ _this.emit(_event, payload, function (error) {
476
+ var args = [];
477
+ for (var _i = 1; _i < arguments.length; _i++) {
478
+ args[_i - 1] = arguments[_i];
479
+ }
480
+ error
481
+ ? reject(new Error(typeof error === 'string' ? error : 'Ack error'))
482
+ : resolve(args.length === 0 ? undefined : args.length === 1 ? args[0] : args);
483
+ });
484
+ }
485
+ catch (error) {
486
+ reject(error);
487
+ }
488
+ });
489
+ };
490
+ IOF.prototype.onceAsync = function (_event) {
491
+ var _this = this;
492
+ return new Promise(function (resolve) { return _this.once(_event, resolve); });
493
+ };
494
+ IOF.prototype.connectAsync = function (timeout) {
495
+ var _this = this;
496
+ if (timeout === void 0) { timeout = 5000; }
497
+ return new Promise(function (resolve, reject) {
498
+ if (_this.isConnected())
499
+ return resolve();
500
+ var timeoutId = setTimeout(function () {
501
+ _this.off('connect', connectHandler);
502
+ reject(new Error('Connection timeout'));
503
+ }, timeout);
504
+ var connectHandler = function () {
505
+ clearTimeout(timeoutId);
506
+ resolve();
507
+ };
508
+ _this.once('connect', connectHandler);
509
+ });
510
+ };
511
+ // Clean up all resources
512
+ IOF.prototype.cleanup = function () {
513
+ if (this.messageListener) {
514
+ window.removeEventListener('message', this.messageListener);
515
+ this.messageListener = undefined;
516
+ }
517
+ this.stopHeartbeat();
518
+ if (this.reconnectTimer) {
519
+ clearTimeout(this.reconnectTimer);
520
+ this.reconnectTimer = undefined;
521
+ }
522
+ };
523
+ IOF.prototype.disconnect = function (fn) {
524
+ // Clean disconnect method
525
+ this.cleanup();
526
+ this.peer.connected = false;
527
+ this.peer.source = undefined;
528
+ this.peer.origin = undefined;
529
+ this.peer.lastHeartbeat = undefined;
530
+ this.messageQueue = [];
531
+ this.messageRateTracker = [];
532
+ this.reconnectAttempts = 0;
533
+ this.removeListeners();
534
+ typeof fn == 'function' && fn();
535
+ this.debug("[".concat(this.peer.type, "] Disconnected"));
536
+ return this;
537
+ };
538
+ // Get connection statistics
539
+ IOF.prototype.getStats = function () {
540
+ return {
541
+ connected: this.isConnected(),
542
+ peerType: this.peer.type,
543
+ origin: this.peer.origin,
544
+ lastHeartbeat: this.peer.lastHeartbeat,
545
+ queuedMessages: this.messageQueue.length,
546
+ reconnectAttempts: this.reconnectAttempts,
547
+ activeListeners: Object.keys(this.Events).length,
548
+ messageRate: this.messageRateTracker.length
549
+ };
550
+ };
551
+ // Clear message queue manually
552
+ IOF.prototype.clearQueue = function () {
553
+ var queueSize = this.messageQueue.length;
554
+ this.messageQueue = [];
555
+ this.debug("[".concat(this.peer.type, "] Cleared ").concat(queueSize, " queued messages"));
556
+ return this;
557
+ };
195
558
  return IOF;
196
559
  }());
197
560
  exports.default = IOF;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iframe.io",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Easy and friendly API to connect and interact between content window and its containing iframe",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",