iframe.io 1.0.6 → 1.2.0
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/README.md +282 -319
- package/dist/index.d.ts +10 -0
- package/dist/index.js +233 -230
- package/package.json +2 -2
- package/src/index.ts +72 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iframe.io",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
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",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"events",
|
|
46
46
|
"io"
|
|
47
47
|
],
|
|
48
|
-
"author": "Fabrice K.M
|
|
48
|
+
"author": "Fabrice K.E.M"
|
|
49
49
|
}
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,16 @@ export type Options = {
|
|
|
12
12
|
maxMessagesPerSecond?: number
|
|
13
13
|
autoReconnect?: boolean
|
|
14
14
|
messageQueueSize?: number
|
|
15
|
+
/**
|
|
16
|
+
* Optional allowlist of incoming application-level events.
|
|
17
|
+
* Reserved internal events (ping/pong/heartbeats) are always allowed.
|
|
18
|
+
*/
|
|
19
|
+
allowedIncomingEvents?: string[]
|
|
20
|
+
/**
|
|
21
|
+
* Optional custom validator for incoming messages.
|
|
22
|
+
* Return false to drop a message; an 'error' event will be emitted.
|
|
23
|
+
*/
|
|
24
|
+
validateIncoming?: ( event: string, payload: any, origin: string ) => boolean
|
|
15
25
|
}
|
|
16
26
|
|
|
17
27
|
export interface RegisteredEvents {
|
|
@@ -68,13 +78,32 @@ function sanitizePayload( payload: any, maxSize: number ): any {
|
|
|
68
78
|
}
|
|
69
79
|
|
|
70
80
|
const ackId = () => {
|
|
81
|
+
// Prefer cryptographically strong randomness when available
|
|
82
|
+
try {
|
|
83
|
+
const globalCrypto = (typeof crypto !== 'undefined'
|
|
84
|
+
? crypto
|
|
85
|
+
: (typeof window !== 'undefined' && (window as any).crypto)
|
|
86
|
+
|| (typeof globalThis !== 'undefined' && (globalThis as any).crypto))
|
|
87
|
+
|
|
88
|
+
if( globalCrypto && typeof globalCrypto.getRandomValues === 'function' ){
|
|
89
|
+
const buffer = new Uint32Array(4)
|
|
90
|
+
globalCrypto.getRandomValues( buffer )
|
|
91
|
+
|
|
92
|
+
const randomPart = Array.from( buffer ).map( n => n.toString( 16 ) ).join('')
|
|
93
|
+
return `${Date.now()}_${randomPart}`
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch{
|
|
97
|
+
// Fall back to Math.random-based implementation below
|
|
98
|
+
}
|
|
99
|
+
|
|
71
100
|
const
|
|
72
101
|
rmin = 100000,
|
|
73
102
|
rmax = 999999,
|
|
74
|
-
|
|
75
|
-
|
|
103
|
+
timestampFallback = Date.now(),
|
|
104
|
+
randomFallback = Math.floor( Math.random() * ( rmax - rmin + 1 ) + rmin )
|
|
76
105
|
|
|
77
|
-
return `${
|
|
106
|
+
return `${timestampFallback}_${randomFallback}`
|
|
78
107
|
}
|
|
79
108
|
|
|
80
109
|
const RESERVED_EVENTS = [
|
|
@@ -89,8 +118,8 @@ export default class IOF {
|
|
|
89
118
|
peer: Peer
|
|
90
119
|
options: Options
|
|
91
120
|
private messageListener?: ( event: MessageEvent ) => void
|
|
92
|
-
private heartbeatTimer?:
|
|
93
|
-
private reconnectTimer?:
|
|
121
|
+
private heartbeatTimer?: number
|
|
122
|
+
private reconnectTimer?: number
|
|
94
123
|
private messageQueue: QueuedMessage[] = []
|
|
95
124
|
private messageRateTracker: number[] = []
|
|
96
125
|
private reconnectAttempts: number = 0
|
|
@@ -312,11 +341,38 @@ export default class IOF {
|
|
|
312
341
|
this.peer.connected = true
|
|
313
342
|
this.reconnectAttempts = 0
|
|
314
343
|
this.peer.lastHeartbeat = Date.now()
|
|
344
|
+
|
|
315
345
|
this.startHeartbeat()
|
|
316
346
|
this.fire('connect')
|
|
317
347
|
this.processMessageQueue()
|
|
348
|
+
this.debug(`[${this.peer.type}] connected`)
|
|
318
349
|
|
|
319
|
-
return
|
|
350
|
+
return
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Optional application-level incoming validation (non-reserved events only)
|
|
354
|
+
if( !RESERVED_EVENTS.includes( _event ) ){
|
|
355
|
+
if( this.options.allowedIncomingEvents
|
|
356
|
+
&& !this.options.allowedIncomingEvents.includes( _event ) ){
|
|
357
|
+
this.fire('error', {
|
|
358
|
+
type: 'DISALLOWED_EVENT',
|
|
359
|
+
direction: 'incoming',
|
|
360
|
+
event: _event,
|
|
361
|
+
origin
|
|
362
|
+
})
|
|
363
|
+
return
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if( this.options.validateIncoming
|
|
367
|
+
&& !this.options.validateIncoming( _event, payload, origin ) ){
|
|
368
|
+
this.fire('error', {
|
|
369
|
+
type: 'INVALID_MESSAGE',
|
|
370
|
+
direction: 'incoming',
|
|
371
|
+
event: _event,
|
|
372
|
+
origin
|
|
373
|
+
})
|
|
374
|
+
return
|
|
375
|
+
}
|
|
320
376
|
}
|
|
321
377
|
|
|
322
378
|
// Fire available event listeners
|
|
@@ -347,6 +403,7 @@ export default class IOF {
|
|
|
347
403
|
this.peer.type = 'IFRAME' // iframe.io connection listener is automatically set as IFRAME
|
|
348
404
|
this.peer.connected = false
|
|
349
405
|
this.reconnectAttempts = 0
|
|
406
|
+
|
|
350
407
|
this.debug(`[${this.peer.type}] Listening to connect${hostOrigin ? `: Host <${hostOrigin}>` : ''}`)
|
|
351
408
|
|
|
352
409
|
// Clean up existing listener if any
|
|
@@ -414,7 +471,8 @@ export default class IOF {
|
|
|
414
471
|
this.fire('connect')
|
|
415
472
|
this.processMessageQueue()
|
|
416
473
|
|
|
417
|
-
|
|
474
|
+
this.debug(`[${this.peer.type}] connected`)
|
|
475
|
+
return
|
|
418
476
|
}
|
|
419
477
|
|
|
420
478
|
// Fire available event listeners
|
|
@@ -437,8 +495,10 @@ export default class IOF {
|
|
|
437
495
|
|
|
438
496
|
fire( _event: string, payload?: MessageData['payload'], cid?: string ){
|
|
439
497
|
// Volatile event - check if any listeners exist
|
|
440
|
-
if( !this.Events[_event] && !this.Events[_event + '--@once'] )
|
|
441
|
-
|
|
498
|
+
if( !this.Events[_event] && !this.Events[_event + '--@once'] ){
|
|
499
|
+
this.debug(`[${this.peer.type}] No <${_event}> listener defined`)
|
|
500
|
+
return
|
|
501
|
+
}
|
|
442
502
|
|
|
443
503
|
const ackFn = cid
|
|
444
504
|
? ( error: boolean | string, ...args: any[] ): void => {
|
|
@@ -590,7 +650,7 @@ export default class IOF {
|
|
|
590
650
|
return new Promise(( resolve, reject ) => {
|
|
591
651
|
const timeoutId = setTimeout(() => {
|
|
592
652
|
reject( new Error(`Event '${_event}' acknowledgment timeout after ${timeout}ms`) )
|
|
593
|
-
}, timeout)
|
|
653
|
+
}, timeout )
|
|
594
654
|
|
|
595
655
|
try {
|
|
596
656
|
this.emit( _event, payload, ( error, ...args ) => {
|
|
@@ -646,7 +706,7 @@ export default class IOF {
|
|
|
646
706
|
}
|
|
647
707
|
|
|
648
708
|
disconnect( fn?: () => void ){
|
|
649
|
-
//
|
|
709
|
+
// Cleanup on disconnect
|
|
650
710
|
this.cleanup()
|
|
651
711
|
|
|
652
712
|
this.peer.connected = false
|
|
@@ -656,6 +716,7 @@ export default class IOF {
|
|
|
656
716
|
this.messageQueue = []
|
|
657
717
|
this.messageRateTracker = []
|
|
658
718
|
this.reconnectAttempts = 0
|
|
719
|
+
|
|
659
720
|
this.removeListeners()
|
|
660
721
|
|
|
661
722
|
typeof fn == 'function' && fn()
|