iframe.io 1.0.4 → 1.0.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.
Files changed (2) hide show
  1. package/README.md +458 -1
  2. package/package.json +7 -1
package/README.md CHANGED
@@ -1,2 +1,459 @@
1
1
  # iframe.io
2
- Easy and friendly API to connect and interact between content window and its containing iframe
2
+
3
+ Easy and friendly API to connect and interact between content window and its containing iframe with enhanced features like heartbeat monitoring, automatic reconnection, message queuing, and rate limiting.
4
+
5
+ ## Features
6
+
7
+ - 🔄 **Bi-directional Communication** - Seamless messaging between parent window and iframe
8
+ - 💓 **Heartbeat Monitoring** - Automatic connection health checking
9
+ - 🔌 **Auto Reconnection** - Automatic reconnection with exponential backoff
10
+ - 📦 **Message Queuing** - Queue messages when connection is lost
11
+ - 🛡️ **Security** - Origin validation and message sanitization
12
+ - ⚡ **Rate Limiting** - Prevent message flooding
13
+ - 🎯 **Event System** - Robust event-driven architecture
14
+ - ✨ **Promise Support** - Async/await compatible methods
15
+ - 📊 **Connection Stats** - Real-time connection statistics
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install iframe.io
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ### Parent Window (WINDOW type)
26
+
27
+ ```javascript
28
+ import IOF from 'iframe.io'
29
+
30
+ // Create iframe and get reference
31
+ const iframe = document.createElement('iframe')
32
+ iframe.src = 'https://example.com/iframe-content'
33
+ document.body.appendChild(iframe)
34
+
35
+ // Initialize connection
36
+ const iof = new IOF({ type: 'WINDOW', debug: true })
37
+
38
+ iframe.onload = () => {
39
+ // Initiate connection with iframe
40
+ iof.initiate(iframe.contentWindow, 'https://example.com')
41
+
42
+ // Listen for connection
43
+ iof.on('connect', () => {
44
+ console.log('Connected to iframe!')
45
+
46
+ // Send message
47
+ iof.emit('hello', { message: 'Hello from parent!' })
48
+ })
49
+
50
+ // Listen for messages
51
+ iof.on('response', (data) => {
52
+ console.log('Received:', data)
53
+ })
54
+ }
55
+ ```
56
+
57
+ ### Iframe Content (IFRAME type)
58
+
59
+ ```javascript
60
+ import IOF from 'iframe.io'
61
+
62
+ // Create connection listener
63
+ const iof = new IOF({ type: 'IFRAME', debug: true })
64
+
65
+ // Listen for parent connection
66
+ iof.listen('https://parent-domain.com')
67
+
68
+ // Handle connection
69
+ iof.on('connect', () => {
70
+ console.log('Connected to parent!')
71
+ })
72
+
73
+ // Listen for messages
74
+ iof.on('hello', (data, ack) => {
75
+ console.log('Received from parent:', data)
76
+
77
+ // Send response
78
+ iof.emit('response', { message: 'Hello from iframe!' })
79
+
80
+ // Acknowledge receipt (optional)
81
+ if (ack) ack(false, 'Message received')
82
+ })
83
+ ```
84
+
85
+ ## API Reference
86
+
87
+ ### Constructor
88
+
89
+ ```javascript
90
+ new IOF(options?)
91
+ ```
92
+
93
+ #### Options
94
+
95
+ | Option | Type | Default | Description |
96
+ |--------|------|---------|-------------|
97
+ | `type` | `'WINDOW' \| 'IFRAME'` | `'IFRAME'` | Connection type |
98
+ | `debug` | `boolean` | `false` | Enable debug logging |
99
+ | `heartbeatInterval` | `number` | `30000` | Heartbeat interval in ms |
100
+ | `connectionTimeout` | `number` | `10000` | Connection timeout in ms |
101
+ | `maxMessageSize` | `number` | `1048576` | Max message size (1MB) |
102
+ | `maxMessagesPerSecond` | `number` | `100` | Rate limit for messages |
103
+ | `autoReconnect` | `boolean` | `true` | Enable auto reconnection |
104
+ | `messageQueueSize` | `number` | `50` | Max queued messages |
105
+
106
+ ### Connection Methods
107
+
108
+ #### `initiate(contentWindow, iframeOrigin)`
109
+
110
+ Establish connection with an iframe (WINDOW type only).
111
+
112
+ ```javascript
113
+ iof.initiate(iframe.contentWindow, 'https://iframe-origin.com')
114
+ ```
115
+
116
+ **Parameters:**
117
+ - `contentWindow` - The iframe's contentWindow
118
+ - `iframeOrigin` - The iframe's origin URL
119
+
120
+ #### `listen(hostOrigin?)`
121
+
122
+ Listen for connection from parent window (IFRAME type).
123
+
124
+ ```javascript
125
+ iof.listen('https://parent-origin.com') // Optional origin restriction
126
+ ```
127
+
128
+ **Parameters:**
129
+ - `hostOrigin` (optional) - Restrict connections to specific origin
130
+
131
+ #### `disconnect(callback?)`
132
+
133
+ Disconnect and clean up all resources.
134
+
135
+ ```javascript
136
+ iof.disconnect(() => {
137
+ console.log('Disconnected!')
138
+ })
139
+ ```
140
+
141
+ ### Messaging Methods
142
+
143
+ #### `emit(event, payload?, callback?)`
144
+
145
+ Send a message to the peer.
146
+
147
+ ```javascript
148
+ // Simple message
149
+ iof.emit('myEvent', { data: 'hello' })
150
+
151
+ // With acknowledgment
152
+ iof.emit('myEvent', { data: 'hello' }, (error, response) => {
153
+ if (error) {
154
+ console.error('Error:', error)
155
+ } else {
156
+ console.log('Response:', response)
157
+ }
158
+ })
159
+
160
+ // Callback as second parameter
161
+ iof.emit('myEvent', (error, response) => {
162
+ console.log('Response:', response)
163
+ })
164
+ ```
165
+
166
+ #### `on(event, listener)`
167
+
168
+ Add event listener.
169
+
170
+ ```javascript
171
+ iof.on('myEvent', (data, ack) => {
172
+ console.log('Received:', data)
173
+
174
+ // Send acknowledgment (optional)
175
+ if (ack) ack(false, 'Success response')
176
+ })
177
+ ```
178
+
179
+ #### `once(event, listener)`
180
+
181
+ Add one-time event listener.
182
+
183
+ ```javascript
184
+ iof.once('myEvent', (data) => {
185
+ console.log('This will only fire once:', data)
186
+ })
187
+ ```
188
+
189
+ #### `off(event, listener?)`
190
+
191
+ Remove event listener(s).
192
+
193
+ ```javascript
194
+ // Remove specific listener
195
+ iof.off('myEvent', myListener)
196
+
197
+ // Remove all listeners for event
198
+ iof.off('myEvent')
199
+ ```
200
+
201
+ #### `removeListeners(callback?)`
202
+
203
+ Remove all event listeners.
204
+
205
+ ```javascript
206
+ iof.removeListeners(() => {
207
+ console.log('All listeners removed')
208
+ })
209
+ ```
210
+
211
+ ### Async Methods
212
+
213
+ #### `emitAsync(event, payload?)`
214
+
215
+ Send message and return Promise.
216
+
217
+ ```javascript
218
+ try {
219
+ const response = await iof.emitAsync('getData', { id: 123 })
220
+ console.log('Response:', response)
221
+ } catch (error) {
222
+ console.error('Error:', error)
223
+ }
224
+ ```
225
+
226
+ #### `onceAsync(event)`
227
+
228
+ Wait for single event occurrence.
229
+
230
+ ```javascript
231
+ const data = await iof.onceAsync('dataReady')
232
+ console.log('Data received:', data)
233
+ ```
234
+
235
+ #### `connectAsync(timeout?)`
236
+
237
+ Wait for connection to be established.
238
+
239
+ ```javascript
240
+ try {
241
+ await iof.connectAsync(5000) // 5 second timeout
242
+ console.log('Connected!')
243
+ } catch (error) {
244
+ console.error('Connection timeout')
245
+ }
246
+ ```
247
+
248
+ ### Utility Methods
249
+
250
+ #### `isConnected()`
251
+
252
+ Check if connection is active.
253
+
254
+ ```javascript
255
+ if (iof.isConnected()) {
256
+ console.log('Connection is active')
257
+ }
258
+ ```
259
+
260
+ #### `getStats()`
261
+
262
+ Get connection statistics.
263
+
264
+ ```javascript
265
+ const stats = iof.getStats()
266
+ console.log('Stats:', stats)
267
+ /*
268
+ {
269
+ connected: true,
270
+ peerType: 'WINDOW',
271
+ origin: 'https://example.com',
272
+ lastHeartbeat: 1640995200000,
273
+ queuedMessages: 0,
274
+ reconnectAttempts: 0,
275
+ activeListeners: 5,
276
+ messageRate: 10
277
+ }
278
+ */
279
+ ```
280
+
281
+ #### `clearQueue()`
282
+
283
+ Clear queued messages.
284
+
285
+ ```javascript
286
+ iof.clearQueue()
287
+ ```
288
+
289
+ ## Events
290
+
291
+ ### Built-in Events
292
+
293
+ | Event | Description | Data |
294
+ |-------|-------------|------|
295
+ | `connect` | Connection established | - |
296
+ | `disconnect` | Connection lost | `{ reason: string }` |
297
+ | `reconnecting` | Reconnection attempt | `{ attempt: number, delay: number }` |
298
+ | `reconnection_failed` | All reconnection attempts failed | `{ attempts: number }` |
299
+ | `error` | Error occurred | `{ type: string, ...details }` |
300
+
301
+ ### Error Types
302
+
303
+ - `RATE_LIMIT_EXCEEDED` - Message rate limit exceeded
304
+ - `MESSAGE_HANDLING_ERROR` - Error processing received message
305
+ - `EMIT_ERROR` - Error sending message
306
+ - `LISTENER_ERROR` - Error in event listener
307
+ - `INVALID_ORIGIN` - Message from unauthorized origin
308
+ - `ORIGIN_MISMATCH` - Origin doesn't match established connection
309
+ - `NO_CONNECTION` - Attempted to send without connection
310
+
311
+ ## Advanced Usage
312
+
313
+ ### Message Acknowledgments
314
+
315
+ ```javascript
316
+ // Sender
317
+ iof.emit('processData', { data: [...] }, (error, result) => {
318
+ if (error) {
319
+ console.error('Processing failed:', error)
320
+ } else {
321
+ console.log('Processing result:', result)
322
+ }
323
+ })
324
+
325
+ // Receiver
326
+ iof.on('processData', async (data, ack) => {
327
+ try {
328
+ const result = await processData(data.data)
329
+ ack(false, result) // Success: ack(error, ...args)
330
+ } catch (error) {
331
+ ack(error.message) // Error: ack(errorMessage)
332
+ }
333
+ })
334
+ ```
335
+
336
+ ### Connection Monitoring
337
+
338
+ ```javascript
339
+ const iof = new IOF({
340
+ heartbeatInterval: 10000, // 10 seconds
341
+ connectionTimeout: 5000, // 5 seconds
342
+ autoReconnect: true
343
+ })
344
+
345
+ iof.on('disconnect', ({ reason }) => {
346
+ console.log('Connection lost:', reason)
347
+ })
348
+
349
+ iof.on('reconnecting', ({ attempt, delay }) => {
350
+ console.log(`Reconnecting (${attempt}/5) in ${delay}ms`)
351
+ })
352
+
353
+ iof.on('reconnection_failed', ({ attempts }) => {
354
+ console.log(`Failed to reconnect after ${attempts} attempts`)
355
+ })
356
+ ```
357
+
358
+ ### Message Queuing
359
+
360
+ ```javascript
361
+ const iof = new IOF({
362
+ messageQueueSize: 100,
363
+ autoReconnect: true
364
+ })
365
+
366
+ // Messages sent while disconnected are automatically queued
367
+ iof.emit('queuedMessage', { data: 'This will be queued if disconnected' })
368
+
369
+ // Check queue status
370
+ const stats = iof.getStats()
371
+ console.log(`Queued messages: ${stats.queuedMessages}`)
372
+ ```
373
+
374
+ ### Rate Limiting
375
+
376
+ ```javascript
377
+ const iof = new IOF({
378
+ maxMessagesPerSecond: 50,
379
+ maxMessageSize: 512 * 1024 // 512KB
380
+ })
381
+
382
+ iof.on('error', ({ type, limit, current }) => {
383
+ if (type === 'RATE_LIMIT_EXCEEDED') {
384
+ console.log(`Rate limit exceeded: ${current}/${limit} messages per second`)
385
+ }
386
+ })
387
+ ```
388
+
389
+ ### Security Best Practices
390
+
391
+ ```javascript
392
+ // Always specify allowed origins
393
+ iof.listen('https://trusted-parent.com')
394
+
395
+ // Handle security errors
396
+ iof.on('error', ({ type, expected, received }) => {
397
+ if (type === 'INVALID_ORIGIN') {
398
+ console.warn(`Rejected message from ${received}, expected ${expected}`)
399
+ }
400
+ })
401
+
402
+ // Validate message content
403
+ iof.on('userData', (data, ack) => {
404
+ if (!isValidUserData(data)) {
405
+ return ack('Invalid data format')
406
+ }
407
+ // Process valid data...
408
+ })
409
+ ```
410
+
411
+ ## Browser Support
412
+
413
+ - Modern browsers with postMessage API support
414
+ - Chrome 2+
415
+ - Firefox 3+
416
+ - Safari 4+
417
+ - IE 8+
418
+ - Edge (all versions)
419
+
420
+ ## TypeScript Support
421
+
422
+ The library is written in TypeScript and includes full type definitions:
423
+
424
+ ```typescript
425
+ import IOF, { Options, PeerType, AckFunction, Listener } from 'iframe.io'
426
+
427
+ const options: Options = {
428
+ type: 'WINDOW',
429
+ debug: true,
430
+ heartbeatInterval: 15000
431
+ }
432
+
433
+ const iof = new IOF(options)
434
+
435
+ // Type-safe event handling
436
+ iof.on('myEvent', (data: { message: string }, ack?: AckFunction) => {
437
+ console.log(data.message)
438
+ ack?.(false, 'success')
439
+ })
440
+
441
+ // Type-safe async emissions
442
+ const response = await iof.emitAsync<{ query: string }, { result: any }>('search', {
443
+ query: 'typescript'
444
+ })
445
+ ```
446
+
447
+ ## License
448
+
449
+ MIT License - see LICENSE file for details.
450
+
451
+ ## Contributing
452
+
453
+ Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
454
+
455
+ ## Support
456
+
457
+ - Create an issue on GitHub for bug reports
458
+ - Check existing issues for common problems
459
+ - Review the documentation for usage examples
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iframe.io",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
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",
@@ -34,6 +34,12 @@
34
34
  },
35
35
  "keywords": [
36
36
  "realtime",
37
+ "embeddable",
38
+ "widget",
39
+ "components",
40
+ "micro-frontend",
41
+ "Secure",
42
+ "cross-origin",
37
43
  "iframe",
38
44
  "browser",
39
45
  "events",