webview.io 1.0.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/dist/index.js ADDED
@@ -0,0 +1,511 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
14
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
15
+ if (ar || !(i in from)) {
16
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
17
+ ar[i] = from[i];
18
+ }
19
+ }
20
+ return to.concat(ar || Array.prototype.slice.call(from));
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ function newObject(data) {
24
+ return JSON.parse(JSON.stringify(data));
25
+ }
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
+ // Basic sanitization - remove functions and undefined values
41
+ return JSON.parse(JSON.stringify(payload));
42
+ }
43
+ var ackId = function () {
44
+ var rmin = 100000, rmax = 999999, timestamp = Date.now(), random = Math.floor(Math.random() * (rmax - rmin + 1) + rmin);
45
+ return "".concat(timestamp, "_").concat(random);
46
+ };
47
+ var RESERVED_EVENTS = [
48
+ 'ping',
49
+ 'pong',
50
+ '__heartbeat',
51
+ '__heartbeat_response'
52
+ ];
53
+ var WIO = /** @class */ (function () {
54
+ function WIO(options) {
55
+ if (options === void 0) { options = {}; }
56
+ this.messageQueue = [];
57
+ this.messageRateTracker = [];
58
+ this.reconnectAttempts = 0;
59
+ this.maxReconnectAttempts = 5;
60
+ if (options && typeof options !== 'object')
61
+ throw new Error('Invalid Options');
62
+ this.options = __assign({ debug: false, heartbeatInterval: 30000, connectionTimeout: 10000, maxMessageSize: 1024 * 1024, maxMessagesPerSecond: 100, autoReconnect: true, messageQueueSize: 50 }, options);
63
+ this.Events = {};
64
+ this.peer = { type: 'WEBVIEW', connected: false };
65
+ if (options.type)
66
+ this.peer.type = options.type;
67
+ }
68
+ WIO.prototype.debug = function () {
69
+ var args = [];
70
+ for (var _i = 0; _i < arguments.length; _i++) {
71
+ args[_i] = arguments[_i];
72
+ }
73
+ this.options.debug && console.debug.apply(console, args);
74
+ };
75
+ WIO.prototype.isConnected = function () {
76
+ return !!this.peer.connected && !!this.peer.webViewRef;
77
+ };
78
+ // Enhanced connection health monitoring
79
+ WIO.prototype.startHeartbeat = function () {
80
+ var _this = this;
81
+ if (!this.options.heartbeatInterval)
82
+ return;
83
+ this.heartbeatTimer = setInterval(function () {
84
+ if (_this.isConnected()) {
85
+ var now = Date.now();
86
+ // Check if peer is still responsive
87
+ if (_this.peer.lastHeartbeat
88
+ && (now - _this.peer.lastHeartbeat) > (_this.options.heartbeatInterval * 2)) {
89
+ _this.debug("[".concat(_this.peer.type, "] Heartbeat timeout detected"));
90
+ _this.handleConnectionLoss();
91
+ return;
92
+ }
93
+ // Send heartbeat
94
+ try {
95
+ _this.emit('__heartbeat', { timestamp: now });
96
+ }
97
+ catch (error) {
98
+ _this.debug("[".concat(_this.peer.type, "] Heartbeat send failed:"), error);
99
+ _this.handleConnectionLoss();
100
+ }
101
+ }
102
+ }, this.options.heartbeatInterval);
103
+ };
104
+ WIO.prototype.stopHeartbeat = function () {
105
+ if (!this.heartbeatTimer)
106
+ return;
107
+ clearInterval(this.heartbeatTimer);
108
+ this.heartbeatTimer = undefined;
109
+ };
110
+ // Handle connection loss and potential reconnection
111
+ WIO.prototype.handleConnectionLoss = function () {
112
+ if (!this.peer.connected)
113
+ return;
114
+ this.peer.connected = false;
115
+ this.stopHeartbeat();
116
+ this.fire('disconnect', { reason: 'CONNECTION_LOST' });
117
+ this.options.autoReconnect
118
+ && this.reconnectAttempts < this.maxReconnectAttempts
119
+ && this.attemptReconnection();
120
+ };
121
+ WIO.prototype.attemptReconnection = function () {
122
+ var _this = this;
123
+ if (this.reconnectTimer)
124
+ return;
125
+ this.reconnectAttempts++;
126
+ var delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 30000); // Exponential backoff, max 30s
127
+ this.debug("[".concat(this.peer.type, "] Attempting reconnection ").concat(this.reconnectAttempts, "/").concat(this.maxReconnectAttempts, " in ").concat(delay, "ms"));
128
+ this.fire('reconnecting', { attempt: this.reconnectAttempts, delay: delay });
129
+ this.reconnectTimer = setTimeout(function () {
130
+ _this.reconnectTimer = undefined;
131
+ // Re-initiate connection for WEBVIEW type
132
+ _this.peer.type === 'WEBVIEW'
133
+ && _this.emit('ping');
134
+ // For EMBEDDED type, just wait for incoming connection
135
+ // Set timeout for this reconnection attempt
136
+ setTimeout(function () {
137
+ if (_this.peer.connected)
138
+ return;
139
+ _this.reconnectAttempts < _this.maxReconnectAttempts
140
+ ? _this.attemptReconnection()
141
+ : _this.fire('reconnection_failed', { attempts: _this.reconnectAttempts });
142
+ }, _this.options.connectionTimeout);
143
+ }, delay);
144
+ };
145
+ // Message rate limiting
146
+ WIO.prototype.checkRateLimit = function () {
147
+ if (!this.options.maxMessagesPerSecond)
148
+ return true;
149
+ var now = Date.now(), aSecondAgo = now - 1000;
150
+ // Clean old entries
151
+ this.messageRateTracker = this.messageRateTracker.filter(function (timestamp) { return timestamp > aSecondAgo; });
152
+ // Check if limit exceeded
153
+ if (this.messageRateTracker.length >= this.options.maxMessagesPerSecond) {
154
+ this.fire('error', {
155
+ type: 'RATE_LIMIT_EXCEEDED',
156
+ limit: this.options.maxMessagesPerSecond,
157
+ current: this.messageRateTracker.length
158
+ });
159
+ return false;
160
+ }
161
+ this.messageRateTracker.push(now);
162
+ return true;
163
+ };
164
+ // Queue messages when not connected
165
+ WIO.prototype.queueMessage = function (_event, payload, fn) {
166
+ if (this.messageQueue.length >= this.options.messageQueueSize) {
167
+ // Remove oldest message
168
+ var removed = this.messageQueue.shift();
169
+ this.debug("[".concat(this.peer.type, "] Message queue full, removed oldest message:"), removed === null || removed === void 0 ? void 0 : removed._event);
170
+ }
171
+ this.messageQueue.push({
172
+ _event: _event,
173
+ payload: payload,
174
+ fn: fn,
175
+ timestamp: Date.now()
176
+ });
177
+ this.debug("[".concat(this.peer.type, "] Queued message: ").concat(_event, " (queue size: ").concat(this.messageQueue.length, ")"));
178
+ };
179
+ // Process queued messages when connection is established
180
+ WIO.prototype.processMessageQueue = function () {
181
+ var _this = this;
182
+ if (!this.isConnected() || this.messageQueue.length === 0)
183
+ return;
184
+ this.debug("[".concat(this.peer.type, "] Processing ").concat(this.messageQueue.length, " queued messages"));
185
+ var queue = __spreadArray([], this.messageQueue, true);
186
+ this.messageQueue = [];
187
+ queue.forEach(function (message) {
188
+ try {
189
+ _this.emit(message._event, message.payload, message.fn);
190
+ }
191
+ catch (error) {
192
+ _this.debug("[".concat(_this.peer.type, "] Failed to send queued message:"), error);
193
+ }
194
+ });
195
+ };
196
+ /**
197
+ * Establish a connection with WebView
198
+ */
199
+ WIO.prototype.initiate = function (webViewRef, origin) {
200
+ if (!webViewRef || !origin)
201
+ throw new Error('Invalid Connection initiation arguments');
202
+ if (this.peer.type === 'EMBEDDED')
203
+ throw new Error('Expect EMBEDDED to <listen> and WEBVIEW to <initiate> a connection');
204
+ // Clean up existing resources if any
205
+ this.cleanup();
206
+ this.peer.webViewRef = webViewRef;
207
+ this.peer.origin = origin;
208
+ this.peer.connected = false;
209
+ this.reconnectAttempts = 0;
210
+ this.debug("[".concat(this.peer.type, "] Initiate connection: WebView origin <").concat(origin, ">"));
211
+ this.emit('ping');
212
+ return this;
213
+ };
214
+ /**
215
+ * Listening to connection from the WebView host
216
+ * Note: In React Native context, this is handled by injected JavaScript
217
+ */
218
+ WIO.prototype.listen = function (hostOrigin) {
219
+ this.peer.type = 'EMBEDDED'; // iframe.io-rn connection listener is automatically set as EMBEDDED
220
+ this.peer.connected = false;
221
+ this.reconnectAttempts = 0;
222
+ this.debug("[".concat(this.peer.type, "] Listening to connect").concat(hostOrigin ? ": Host <".concat(hostOrigin, ">") : ''));
223
+ return this;
224
+ };
225
+ /**
226
+ * Handle incoming message from WebView
227
+ * Called by React Native component via onMessage prop
228
+ */
229
+ WIO.prototype.handleMessage = function (event) {
230
+ try {
231
+ var data = JSON.parse(event.nativeEvent.data);
232
+ // Enhanced security: check valid message structure
233
+ if (typeof data !== 'object' || !data.hasOwnProperty('_event'))
234
+ return;
235
+ var _a = data, _event = _a._event, payload = _a.payload, cid = _a.cid, timestamp = _a.timestamp;
236
+ // Handle heartbeat responses
237
+ if (_event === '__heartbeat_response') {
238
+ this.peer.lastHeartbeat = Date.now();
239
+ return;
240
+ }
241
+ // Handle heartbeat requests
242
+ if (_event === '__heartbeat') {
243
+ this.emit('__heartbeat_response', { timestamp: Date.now() });
244
+ this.peer.lastHeartbeat = Date.now();
245
+ return;
246
+ }
247
+ this.debug("[".concat(this.peer.type, "] Message: ").concat(_event), payload || '');
248
+ // Handshake or availability check events
249
+ if (_event == 'pong') {
250
+ // WebView is connected
251
+ this.peer.connected = true;
252
+ this.reconnectAttempts = 0;
253
+ this.peer.lastHeartbeat = Date.now();
254
+ this.startHeartbeat();
255
+ this.fire('connect');
256
+ this.processMessageQueue();
257
+ this.debug("[".concat(this.peer.type, "] connected"));
258
+ return;
259
+ }
260
+ // Fire available event listeners
261
+ this.fire(_event, payload, cid);
262
+ }
263
+ catch (error) {
264
+ this.debug("[".concat(this.peer.type, "] Message handling error:"), error);
265
+ this.fire('error', {
266
+ type: 'MESSAGE_HANDLING_ERROR',
267
+ error: error instanceof Error ? error.message : String(error)
268
+ });
269
+ }
270
+ };
271
+ WIO.prototype.fire = function (_event, payload, cid) {
272
+ var _this = this;
273
+ // Volatile event - check if any listeners exist
274
+ if (!this.Events[_event] && !this.Events[_event + '--@once']) {
275
+ this.debug("[".concat(this.peer.type, "] No <").concat(_event, "> listener defined"));
276
+ return;
277
+ }
278
+ var ackFn = cid
279
+ ? function (error) {
280
+ var args = [];
281
+ for (var _i = 1; _i < arguments.length; _i++) {
282
+ args[_i - 1] = arguments[_i];
283
+ }
284
+ _this.emit("".concat(_event, "--").concat(cid, "--@ack"), { error: error || false, args: args });
285
+ return;
286
+ }
287
+ : undefined;
288
+ var listeners = [];
289
+ if (this.Events[_event + '--@once']) {
290
+ // Once triggable event
291
+ _event += '--@once';
292
+ listeners = this.Events[_event];
293
+ // Delete once event listeners after fired
294
+ delete this.Events[_event];
295
+ }
296
+ else
297
+ listeners = this.Events[_event];
298
+ // Fire listeners with error handling
299
+ listeners.forEach(function (fn) {
300
+ try {
301
+ payload !== undefined ? fn(payload, ackFn) : fn(ackFn);
302
+ }
303
+ catch (error) {
304
+ _this.debug("[".concat(_this.peer.type, "] Listener error for ").concat(_event, ":"), error);
305
+ _this.fire('error', {
306
+ type: 'LISTENER_ERROR',
307
+ event: _event,
308
+ error: error instanceof Error ? error.message : String(error)
309
+ });
310
+ }
311
+ });
312
+ };
313
+ WIO.prototype.emit = function (_event, payload, fn) {
314
+ var _a;
315
+ // Check rate limiting
316
+ if (!this.checkRateLimit())
317
+ return this;
318
+ /**
319
+ * Queue message if not connected: Except for
320
+ * connection-related events
321
+ */
322
+ if (!this.isConnected() && !RESERVED_EVENTS.includes(_event)) {
323
+ this.queueMessage(_event, payload, fn);
324
+ return this;
325
+ }
326
+ if (!this.peer.webViewRef) {
327
+ this.fire('error', { type: 'NO_CONNECTION', event: _event });
328
+ return this;
329
+ }
330
+ if (typeof payload == 'function') {
331
+ fn = payload;
332
+ payload = undefined;
333
+ }
334
+ try {
335
+ // Enhanced security: sanitize and validate payload
336
+ var sanitizedPayload = payload
337
+ ? sanitizePayload(payload, this.options.maxMessageSize)
338
+ : payload;
339
+ // Acknowledge event listener
340
+ var cid = void 0;
341
+ if (typeof fn === 'function') {
342
+ var ackFunction_1 = fn;
343
+ cid = ackId();
344
+ this.once("".concat(_event, "--").concat(cid, "--@ack"), function (_a) {
345
+ var error = _a.error, args = _a.args;
346
+ return ackFunction_1.apply(void 0, __spreadArray([error], args, false));
347
+ });
348
+ }
349
+ var messageData = {
350
+ _event: _event,
351
+ payload: sanitizedPayload,
352
+ cid: cid,
353
+ timestamp: Date.now(),
354
+ size: getMessageSize(sanitizedPayload)
355
+ };
356
+ (_a = this.peer.webViewRef.current) === null || _a === void 0 ? void 0 : _a.postMessage(JSON.stringify(newObject(messageData)));
357
+ }
358
+ catch (error) {
359
+ this.debug("[".concat(this.peer.type, "] Emit error:"), error);
360
+ this.fire('error', {
361
+ type: 'EMIT_ERROR',
362
+ event: _event,
363
+ error: error instanceof Error ? error.message : String(error)
364
+ });
365
+ // Call acknowledgment with error if provided
366
+ typeof fn === 'function'
367
+ && fn(error instanceof Error ? error.message : String(error));
368
+ }
369
+ return this;
370
+ };
371
+ WIO.prototype.on = function (_event, fn) {
372
+ // Add Event listener
373
+ if (!this.Events[_event])
374
+ this.Events[_event] = [];
375
+ this.Events[_event].push(fn);
376
+ this.debug("[".concat(this.peer.type, "] New <").concat(_event, "> listener on"));
377
+ return this;
378
+ };
379
+ WIO.prototype.once = function (_event, fn) {
380
+ // Add Once Event listener
381
+ _event += '--@once';
382
+ if (!this.Events[_event])
383
+ this.Events[_event] = [];
384
+ this.Events[_event].push(fn);
385
+ this.debug("[".concat(this.peer.type, "] New <").concat(_event, " once> listener on"));
386
+ return this;
387
+ };
388
+ WIO.prototype.off = function (_event, fn) {
389
+ // Remove Event listener
390
+ if (fn && this.Events[_event]) {
391
+ // Remove specific listener if provided
392
+ var index = this.Events[_event].indexOf(fn);
393
+ if (index > -1) {
394
+ this.Events[_event].splice(index, 1);
395
+ // Remove event array if empty
396
+ if (this.Events[_event].length === 0)
397
+ delete this.Events[_event];
398
+ }
399
+ }
400
+ // Remove all listeners for event
401
+ else
402
+ delete this.Events[_event];
403
+ typeof fn == 'function' && fn();
404
+ this.debug("[".concat(this.peer.type, "] <").concat(_event, "> listener off"));
405
+ return this;
406
+ };
407
+ WIO.prototype.removeListeners = function (fn) {
408
+ // Clear all event listeners
409
+ this.Events = {};
410
+ typeof fn == 'function' && fn();
411
+ this.debug("[".concat(this.peer.type, "] All listeners removed"));
412
+ return this;
413
+ };
414
+ WIO.prototype.emitAsync = function (_event, payload, timeout) {
415
+ var _this = this;
416
+ if (timeout === void 0) { timeout = 5000; }
417
+ return new Promise(function (resolve, reject) {
418
+ var timeoutId = setTimeout(function () {
419
+ reject(new Error("Event '".concat(_event, "' acknowledgment timeout after ").concat(timeout, "ms")));
420
+ }, timeout);
421
+ try {
422
+ _this.emit(_event, payload, function (error) {
423
+ var args = [];
424
+ for (var _i = 1; _i < arguments.length; _i++) {
425
+ args[_i - 1] = arguments[_i];
426
+ }
427
+ clearTimeout(timeoutId);
428
+ error
429
+ ? reject(new Error(typeof error === 'string' ? error : 'Ack error'))
430
+ : resolve(args.length === 0 ? undefined : args.length === 1 ? args[0] : args);
431
+ });
432
+ }
433
+ catch (error) {
434
+ clearTimeout(timeoutId);
435
+ reject(error);
436
+ }
437
+ });
438
+ };
439
+ WIO.prototype.onceAsync = function (_event) {
440
+ var _this = this;
441
+ return new Promise(function (resolve) { return _this.once(_event, resolve); });
442
+ };
443
+ WIO.prototype.connectAsync = function (timeout) {
444
+ var _this = this;
445
+ return new Promise(function (resolve, reject) {
446
+ if (_this.isConnected())
447
+ return resolve();
448
+ var timeoutId = setTimeout(function () {
449
+ _this.off('connect', connectHandler);
450
+ reject(new Error('Connection timeout'));
451
+ }, timeout || _this.options.connectionTimeout);
452
+ var connectHandler = function () {
453
+ clearTimeout(timeoutId);
454
+ resolve();
455
+ };
456
+ _this.once('connect', connectHandler);
457
+ });
458
+ };
459
+ // Clean up all resources
460
+ WIO.prototype.cleanup = function () {
461
+ this.stopHeartbeat();
462
+ if (this.reconnectTimer) {
463
+ clearTimeout(this.reconnectTimer);
464
+ this.reconnectTimer = undefined;
465
+ }
466
+ };
467
+ WIO.prototype.disconnect = function (fn) {
468
+ // Cleanup on disconnect
469
+ this.cleanup();
470
+ this.peer.connected = false;
471
+ this.peer.webViewRef = undefined;
472
+ this.peer.origin = undefined;
473
+ this.peer.lastHeartbeat = undefined;
474
+ this.messageQueue = [];
475
+ this.messageRateTracker = [];
476
+ this.reconnectAttempts = 0;
477
+ this.removeListeners();
478
+ typeof fn == 'function' && fn();
479
+ this.debug("[".concat(this.peer.type, "] Disconnected"));
480
+ return this;
481
+ };
482
+ // Get connection statistics
483
+ WIO.prototype.getStats = function () {
484
+ return {
485
+ connected: this.isConnected(),
486
+ peerType: this.peer.type,
487
+ origin: this.peer.origin,
488
+ lastHeartbeat: this.peer.lastHeartbeat,
489
+ queuedMessages: this.messageQueue.length,
490
+ reconnectAttempts: this.reconnectAttempts,
491
+ activeListeners: Object.keys(this.Events).length,
492
+ messageRate: this.messageRateTracker.length
493
+ };
494
+ };
495
+ // Clear message queue manually
496
+ WIO.prototype.clearQueue = function () {
497
+ var queueSize = this.messageQueue.length;
498
+ this.messageQueue = [];
499
+ this.debug("[".concat(this.peer.type, "] Cleared ").concat(queueSize, " queued messages"));
500
+ return this;
501
+ };
502
+ /**
503
+ * Get injected JavaScript for WebView
504
+ * Sets up the EMBEDDED side of the bridge
505
+ */
506
+ WIO.prototype.getInjectedJavaScript = function () {
507
+ return "\n (function() {\n const RESERVED_EVENTS = ['ping', 'pong', '__heartbeat', '__heartbeat_response'];\n \n window._wio = {\n type: 'EMBEDDED',\n connected: false,\n Events: {},\n messageQueue: [],\n \n ackId: function(){\n const\n rmin = 100000,\n rmax = 999999,\n timestamp = Date.now(),\n random = Math.floor( Math.random() * ( rmax - rmin + 1 ) + rmin );\n\n return timestamp + '_' + random;\n },\n \n fire: function( _event, payload, cid ){\n if( !this.Events[_event] && !this.Events[_event + '--@once'] ) return;\n \n const ackFn = cid\n ? ( error, ...args ) => {\n this.emit( _event + '--' + cid + '--@ack', { error: error || false, args } );\n }\n : undefined;\n \n let listeners = [];\n if( this.Events[_event + '--@once'] ){\n _event += '--@once';\n listeners = this.Events[_event];\n delete this.Events[_event];\n }\n else listeners = this.Events[_event] || [];\n \n listeners.forEach( fn => {\n try { payload !== undefined ? fn( payload, ackFn ) : fn( ackFn ); }\n catch( error ){ console.error('[EMBEDDED] Listener error:', error); }\n });\n },\n \n emit: function( _event, payload, fn ){\n if( typeof payload === 'function' ){\n fn = payload;\n payload = undefined;\n }\n \n if( !this.connected && !RESERVED_EVENTS.includes(_event) ){\n this.messageQueue.push({ _event, payload, fn, timestamp: Date.now() });\n return;\n }\n \n try {\n let cid;\n if( typeof fn === 'function' ){\n cid = this.ackId();\n this.once( _event + '--' + cid + '--@ack', ({ error, args }) => fn( error, ...args ) );\n }\n \n const messageData = {\n _event,\n payload,\n cid,\n timestamp: Date.now()\n };\n \n window.ReactNativeWebView.postMessage( JSON.stringify( messageData ) );\n }\n catch( error ){\n console.error('[EMBEDDED] Emit error:', error);\n typeof fn === 'function' && fn( String(error) );\n }\n },\n \n on: function( _event, fn ){\n if( !this.Events[_event] ) this.Events[_event] = [];\n this.Events[_event].push( fn );\n },\n \n once: function( _event, fn ){\n _event += '--@once';\n if( !this.Events[_event] ) this.Events[_event] = [];\n this.Events[_event].push( fn );\n },\n \n off: function( _event, fn ){\n if( fn && this.Events[_event] ){\n const index = this.Events[_event].indexOf( fn );\n if( index > -1 ){\n this.Events[_event].splice( index, 1 );\n if( this.Events[_event].length === 0 ) delete this.Events[_event];\n }\n }\n else delete this.Events[_event];\n },\n \n processMessageQueue: function(){\n if( !this.connected || this.messageQueue.length === 0 ) return;\n \n const queue = [...this.messageQueue];\n this.messageQueue = [];\n \n queue.forEach( msg => {\n try { this.emit( msg._event, msg.payload, msg.fn ); }\n catch( error ){ console.error('[EMBEDDED] Queue process error:', error); }\n });\n },\n \n handleMessage: function( data ){\n if( !data || !data._event ) return;\n \n const { _event, payload, cid } = data;\n \n if( _event === '__heartbeat_response' ) return;\n \n if( _event === '__heartbeat' ){\n this.emit('__heartbeat_response', { timestamp: Date.now() });\n return;\n }\n \n if( _event === 'ping' ){\n this.emit('pong');\n this.connected = true;\n this.processMessageQueue();\n return;\n }\n \n this.fire( _event, payload, cid );\n }\n };\n \n // Listen to messages from React Native\n window.addEventListener('message', function( event ){\n try {\n const message = JSON.parse( event.data );\n window._wio.handleMessage( message );\n }\n catch( error ){ console.error('[EMBEDDED] Parse error:', error); }\n });\n \n // Android support\n if( typeof document !== 'undefined' ){\n document.addEventListener('message', function( event ){\n try {\n const message = JSON.parse( event.data );\n window._wio.handleMessage( message );\n }\n catch( error ){ console.error('[EMBEDDED] Parse error:', error); }\n });\n }\n \n true;\n })();\n ";
508
+ };
509
+ return WIO;
510
+ }());
511
+ exports.default = WIO;
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "webview.io",
3
+ "version": "1.0.0",
4
+ "description": "Easy and friendly API to connect and interact between React Native and WebView with enhanced security, reliability, and modern async/await support.",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "private": false,
8
+ "scripts": {
9
+ "compile": "rimraf ./dist && tsc",
10
+ "test": "yarn run compile && yarn run test:types && yarn run test:unit",
11
+ "test:types": "tsd",
12
+ "test:unit": "nyc mocha --require ts-node/register --reporter spec --slow 200 --bail --timeout 10000 test/webview.io.ts",
13
+ "prepack": "yarn run compile"
14
+ },
15
+ "dependencies": {
16
+ "@types/node": "^24.6.0",
17
+ "events": "^3.3.0"
18
+ },
19
+ "peerDependencies": {
20
+ "react": ">=16.8.0",
21
+ "react-native-webview": ">=11.0.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/mocha": "^9.1.0",
25
+ "@types/react": "^18.0.0",
26
+ "expect.js": "^0.3.1",
27
+ "mocha": "^9.2.0",
28
+ "nyc": "^15.1.0",
29
+ "react-native-webview": "^13.16.0",
30
+ "rimraf": "^3.0.2",
31
+ "ts-node": "^10.9.0",
32
+ "tsd": "^0.24.1",
33
+ "typescript": "^4.5.5"
34
+ },
35
+ "files": [
36
+ "dist/",
37
+ "src/",
38
+ "README.md"
39
+ ],
40
+ "directories": {
41
+ "example": "example/",
42
+ "test": "test/"
43
+ },
44
+ "license": "MIT",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git://github.com/fabrice8/webview.io"
48
+ },
49
+ "keywords": [
50
+ "react-native",
51
+ "webview",
52
+ "bridge",
53
+ "communication",
54
+ "realtime",
55
+ "events",
56
+ "mobile",
57
+ "cross-origin",
58
+ "secure",
59
+ "async",
60
+ "promise",
61
+ "react-native-webview",
62
+ "messaging",
63
+ "io"
64
+ ],
65
+ "author": "Fabrice K.E.M",
66
+ "engines": {
67
+ "node": ">=12.0.0"
68
+ }
69
+ }