webview.io 1.0.4 → 1.0.6
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.d.ts +4 -0
- package/dist/index.js +19 -25
- package/package.json +1 -1
- package/src/index.ts +55 -57
package/dist/index.d.ts
CHANGED
|
@@ -78,6 +78,9 @@ export default class WIO {
|
|
|
78
78
|
initiate(webViewRef: RefObject<WebView>, origin: string): this;
|
|
79
79
|
/**
|
|
80
80
|
* Listening to connection from the WebView host
|
|
81
|
+
*
|
|
82
|
+
* NOTE: This is called manually from page code,
|
|
83
|
+
* not auto-initialized
|
|
81
84
|
*/
|
|
82
85
|
listen(hostOrigin?: string): this;
|
|
83
86
|
/**
|
|
@@ -115,6 +118,7 @@ export default class WIO {
|
|
|
115
118
|
/**
|
|
116
119
|
* Get injected JavaScript for WebView
|
|
117
120
|
* Sets up the EMBEDDED side of the bridge
|
|
121
|
+
* NOTE: Does not auto-initialize - page must call window._wio.listen()
|
|
118
122
|
*/
|
|
119
123
|
getInjectedJavaScript(): string;
|
|
120
124
|
}
|
package/dist/index.js
CHANGED
|
@@ -143,13 +143,9 @@ var WIO = /** @class */ (function () {
|
|
|
143
143
|
_this.connectionAttempts = 0;
|
|
144
144
|
_this.connectionToken = generateToken();
|
|
145
145
|
// Re-initiate connection for WEBVIEW type
|
|
146
|
-
|
|
147
|
-
_this.startConnectionAttempt();
|
|
148
|
-
}
|
|
146
|
+
_this.peer.type === 'WEBVIEW' && _this.startConnectionAttempt();
|
|
149
147
|
// For EMBEDDED type, announce readiness
|
|
150
|
-
|
|
151
|
-
_this.announceEmbeddedReady();
|
|
152
|
-
}
|
|
148
|
+
_this.peer.type === 'EMBEDDED' && _this.announceEmbeddedReady();
|
|
153
149
|
// Set timeout for this reconnection attempt
|
|
154
150
|
setTimeout(function () {
|
|
155
151
|
if (_this.peer.connected)
|
|
@@ -181,9 +177,8 @@ var WIO = /** @class */ (function () {
|
|
|
181
177
|
_this.debug("[".concat(_this.peer.type, "] Connection attempt ").concat(_this.connectionAttempts, "/").concat(_this.options.maxConnectionAttempts));
|
|
182
178
|
_this.emit('ping', { token: _this.connectionToken });
|
|
183
179
|
}
|
|
184
|
-
else
|
|
180
|
+
else
|
|
185
181
|
_this.stopConnectionAttempt();
|
|
186
|
-
}
|
|
187
182
|
}, this.options.connectionPingInterval);
|
|
188
183
|
// Set overall timeout
|
|
189
184
|
this.connectionAttemptTimer = setTimeout(function () {
|
|
@@ -225,16 +220,15 @@ var WIO = /** @class */ (function () {
|
|
|
225
220
|
_this.debug("[".concat(_this.peer.type, "] Ready announcement attempt ").concat(attempts, "/").concat(maxAttempts));
|
|
226
221
|
_this.emit('__embedded_ready');
|
|
227
222
|
}
|
|
228
|
-
else
|
|
223
|
+
else
|
|
229
224
|
_this.stopEmbeddedReadyAnnouncement();
|
|
230
|
-
}
|
|
231
225
|
}, this.options.connectionPingInterval);
|
|
232
226
|
};
|
|
233
227
|
WIO.prototype.stopEmbeddedReadyAnnouncement = function () {
|
|
234
|
-
if (this.embeddedReadyCheckInterval)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
228
|
+
if (!this.embeddedReadyCheckInterval)
|
|
229
|
+
return;
|
|
230
|
+
clearInterval(this.embeddedReadyCheckInterval);
|
|
231
|
+
this.embeddedReadyCheckInterval = undefined;
|
|
238
232
|
};
|
|
239
233
|
// Message rate limiting
|
|
240
234
|
WIO.prototype.checkRateLimit = function () {
|
|
@@ -257,8 +251,8 @@ var WIO = /** @class */ (function () {
|
|
|
257
251
|
};
|
|
258
252
|
// Queue messages when not connected
|
|
259
253
|
WIO.prototype.queueMessage = function (_event, payload, fn) {
|
|
254
|
+
// Remove oldest message
|
|
260
255
|
if (this.messageQueue.length >= this.options.messageQueueSize) {
|
|
261
|
-
// Remove oldest message
|
|
262
256
|
var removed = this.messageQueue.shift();
|
|
263
257
|
this.debug("[".concat(this.peer.type, "] Message queue full, removed oldest message:"), removed === null || removed === void 0 ? void 0 : removed._event);
|
|
264
258
|
}
|
|
@@ -311,6 +305,9 @@ var WIO = /** @class */ (function () {
|
|
|
311
305
|
};
|
|
312
306
|
/**
|
|
313
307
|
* Listening to connection from the WebView host
|
|
308
|
+
*
|
|
309
|
+
* NOTE: This is called manually from page code,
|
|
310
|
+
* not auto-initialized
|
|
314
311
|
*/
|
|
315
312
|
WIO.prototype.listen = function (hostOrigin) {
|
|
316
313
|
var _this = this;
|
|
@@ -320,9 +317,7 @@ var WIO = /** @class */ (function () {
|
|
|
320
317
|
this.reconnectAttempts = 0;
|
|
321
318
|
this.debug("[".concat(this.peer.type, "] Listening to connect").concat(hostOrigin ? ": Host <".concat(hostOrigin, ">") : ''));
|
|
322
319
|
// Start announcing readiness
|
|
323
|
-
setTimeout(function () {
|
|
324
|
-
_this.announceEmbeddedReady();
|
|
325
|
-
}, 100);
|
|
320
|
+
setTimeout(function () { return _this.announceEmbeddedReady(); }, 100);
|
|
326
321
|
return this;
|
|
327
322
|
};
|
|
328
323
|
/**
|
|
@@ -359,9 +354,9 @@ var WIO = /** @class */ (function () {
|
|
|
359
354
|
this.peer.embeddedReady = true;
|
|
360
355
|
this.debug("[".concat(this.peer.type, "] Embedded peer ready"));
|
|
361
356
|
// If we're WEBVIEW and not connected, send ping
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
357
|
+
this.peer.type === 'WEBVIEW'
|
|
358
|
+
&& !this.peer.connected
|
|
359
|
+
&& this.emit('ping', { token: this.connectionToken });
|
|
365
360
|
return;
|
|
366
361
|
}
|
|
367
362
|
// Handle webview ready signal
|
|
@@ -583,9 +578,7 @@ var WIO = /** @class */ (function () {
|
|
|
583
578
|
var _this = this;
|
|
584
579
|
if (timeout === void 0) { timeout = 5000; }
|
|
585
580
|
return new Promise(function (resolve, reject) {
|
|
586
|
-
var timeoutId = setTimeout(function () {
|
|
587
|
-
reject(new Error("Event '".concat(_event, "' acknowledgment timeout after ").concat(timeout, "ms")));
|
|
588
|
-
}, timeout);
|
|
581
|
+
var timeoutId = setTimeout(function () { return reject(new Error("Event '".concat(_event, "' acknowledgment timeout after ").concat(timeout, "ms"))); }, timeout);
|
|
589
582
|
try {
|
|
590
583
|
_this.emit(_event, payload, function (error) {
|
|
591
584
|
var args = [];
|
|
@@ -677,9 +670,10 @@ var WIO = /** @class */ (function () {
|
|
|
677
670
|
/**
|
|
678
671
|
* Get injected JavaScript for WebView
|
|
679
672
|
* Sets up the EMBEDDED side of the bridge
|
|
673
|
+
* NOTE: Does not auto-initialize - page must call window._wio.listen()
|
|
680
674
|
*/
|
|
681
675
|
WIO.prototype.getInjectedJavaScript = function () {
|
|
682
|
-
return "\n (function() {\n try {\n console.log('[EMBEDDED] Initializing WIO bridge...')\n \n const RESERVED_EVENTS = [\n 'ping',\n 'pong',\n '__heartbeat',\n '__heartbeat_response',\n '__embedded_ready',\n '__connection_ack',\n '__webview_ready'\n ]\n \n // Use closure variable to avoid 'this' binding issues\n window._wio = {\n type: 'EMBEDDED',\n connected: false,\n Events: {},\n messageQueue: [],\n connectionToken: null,\n setupComplete: false,\n\n listen: function(){\n console.log('[EMBEDDED] Setting up message listeners...')\n\n // Listen to messages from React Native\n window.addEventListener('message', function( event ){\n try {\n const message = typeof event.data === 'string' ? JSON.parse( event.data ) : event.data\n window._wio.handleMessage( message ) // Use window._wio instead of this\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 = typeof event.data === 'string' ? JSON.parse( event.data ) : event.data\n window._wio.handleMessage( message ) // Use window._wio instead of this\n }\n catch( error ){ console.error('[EMBEDDED] Parse error:', error ) }\n })\n }\n\n window._wio.setupComplete = true // Use window._wio instead of this\n console.log('[EMBEDDED] Setup complete')\n\n return window._wio\n },\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( !window._wio.Events[_event] && !window._wio.Events[_event + '--@once'] ){\n console.log('[EMBEDDED] No listener for:', _event)\n return\n }\n \n const ackFn = cid\n ? ( error, ...args ) => window._wio.emit( _event + '--' + cid + '--@ack', { error: error || false, args } )\n : undefined\n \n let listeners = []\n if( window._wio.Events[_event + '--@once'] ){\n _event += '--@once'\n listeners = window._wio.Events[_event]\n\n delete window._wio.Events[_event]\n }\n else listeners = window._wio.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( !window._wio.connected && !RESERVED_EVENTS.includes(_event) ){\n window._wio.messageQueue.push({ _event, payload, fn, timestamp: Date.now() })\n console.log('[EMBEDDED] Queued message:', _event)\n return\n }\n \n try {\n let cid\n if( typeof fn === 'function' ){\n cid = window._wio.ackId()\n window._wio.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 token: RESERVED_EVENTS.includes(_event) ? window._wio.connectionToken : undefined\n }\n \n if( typeof window.ReactNativeWebView !== 'undefined' )\n window.ReactNativeWebView.postMessage( JSON.stringify( messageData ) )\n else console.error('[EMBEDDED] ReactNativeWebView not available')\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( !window._wio.Events[_event] ) window._wio.Events[_event] = []\n window._wio.Events[_event].push( fn )\n\n return window._wio\n },\n \n once: function( _event, fn ){\n _event += '--@once'\n if( !window._wio.Events[_event] ) window._wio.Events[_event] = []\n\n window._wio.Events[_event].push( fn )\n\n return window._wio\n },\n \n off: function( _event, fn ){\n if( fn && window._wio.Events[_event] ){\n const index = window._wio.Events[_event].indexOf( fn )\n if( index > -1 ){\n window._wio.Events[_event].splice( index, 1 )\n if( window._wio.Events[_event].length === 0 ) delete window._wio.Events[_event]\n }\n }\n else delete window._wio.Events[_event]\n\n return window._wio\n },\n \n processMessageQueue: function(){\n if( !window._wio.connected || window._wio.messageQueue.length === 0 ) return\n \n console.log('[EMBEDDED] Processing', window._wio.messageQueue.length, 'queued messages')\n const queue = [ ...window._wio.messageQueue ]\n window._wio.messageQueue = []\n \n queue.forEach( msg => {\n try { window._wio.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, token } = data\n \n console.log('[EMBEDDED] Received:', _event )\n \n // Handle heartbeat response\n if( _event === '__heartbeat_response' )\n return\n \n // Handle heartbeat request\n if( _event === '__heartbeat' ){\n window._wio.emit('__heartbeat_response', { timestamp: Date.now() })\n return\n }\n \n // Handle webview ready signal\n if( _event === '__webview_ready' ){\n console.log('[EMBEDDED] WebView ready signal received')\n return\n }\n \n // Handle ping from WEBVIEW\n if( _event === 'ping' ){\n console.log('[EMBEDDED] Received ping, sending pong')\n window._wio.connectionToken = token\n\n window._wio.emit('pong', { token: window._wio.connectionToken })\n return\n }\n \n // Handle connection acknowledgment\n if( _event === '__connection_ack' ){\n if( token && token !== window._wio.connectionToken ){\n console.error('[EMBEDDED] Invalid connection token in ack')\n return\n }\n \n console.log('[EMBEDDED] Connection established (received ack)')\n\n window._wio.connected = true\n window._wio.processMessageQueue()\n window._wio.fire('connect')\n\n return\n }\n \n // Fire event listeners\n window._wio.fire( _event, payload, cid )\n },\n \n announceReady: function(){\n let attempts = 0\n const maxAttempts = 5\n const interval = 2000\n \n console.log('[EMBEDDED] Starting ready announcements')\n \n const announce = () => {\n if( window._wio.connected ){\n console.log('[EMBEDDED] Connected, stopping announcements')\n return\n }\n \n attempts++\n if( attempts > maxAttempts ){\n console.log('[EMBEDDED] Max announcement attempts reached')\n return\n }\n \n console.log('[EMBEDDED] Announcing ready (attempt', attempts + '/' + maxAttempts + ')')\n window._wio.emit('__embedded_ready')\n \n setTimeout( announce, interval )\n }\n \n announce()\n }\n }\n\n // Initialize\n wio.listen()\n // Start announcing readiness after a short delay\n setTimeout(() => wio.announceReady(), 100)\n \n console.log('[EMBEDDED] WIO bridge initialized successfully')\n }\n catch( error ){\n console.error('[EMBEDDED] Setup failed:', error )\n \n // Create minimal fallback\n window._wio = {\n error: error.toString(),\n emit: function(){ console.error('[EMBEDDED] WIO failed to initialize') },\n on: function(){},\n once: function(){},\n off: function(){}\n }\n }\n\n true\n })()\n ";
|
|
676
|
+
return "\n (function() {\n try {\n console.log('[EMBEDDED] Initializing WIO bridge...')\n \n const RESERVED_EVENTS = [\n 'ping',\n 'pong',\n '__heartbeat',\n '__heartbeat_response',\n '__embedded_ready',\n '__connection_ack',\n '__webview_ready'\n ]\n \n // Use closure variable to avoid 'this' binding issues\n window._wio = {\n type: 'EMBEDDED',\n connected: false,\n Events: {},\n messageQueue: [],\n connectionToken: null,\n setupComplete: false,\n\n listen: function(){\n if( this.setupComplete ){\n console.warn('[EMBEDDED] Already listening')\n return this\n }\n\n console.log('[EMBEDDED] Setting up message listeners...')\n\n // Listen to messages from React Native\n window.addEventListener('message', function( event ){\n try {\n const message = typeof event.data === 'string' ? JSON.parse( event.data ) : 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 = typeof event.data === 'string' ? JSON.parse( event.data ) : event.data\n window._wio.handleMessage( message )\n }\n catch( error ){ console.error('[EMBEDDED] Parse error:', error ) }\n })\n }\n\n this.setupComplete = true\n console.log('[EMBEDDED] Setup complete, starting ready announcements')\n\n // Start announcing readiness\n this.announceReady()\n\n return this\n },\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( !window._wio.Events[_event] && !window._wio.Events[_event + '--@once'] ){\n console.log('[EMBEDDED] No listener for:', _event)\n return\n }\n \n const ackFn = cid\n ? ( error, ...args ) => window._wio.emit( _event + '--' + cid + '--@ack', { error: error || false, args } )\n : undefined\n \n let listeners = []\n if( window._wio.Events[_event + '--@once'] ){\n _event += '--@once'\n listeners = window._wio.Events[_event]\n\n delete window._wio.Events[_event]\n }\n else listeners = window._wio.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( !window._wio.connected && !RESERVED_EVENTS.includes(_event) ){\n window._wio.messageQueue.push({ _event, payload, fn, timestamp: Date.now() })\n console.log('[EMBEDDED] Queued message:', _event)\n return\n }\n \n try {\n let cid\n if( typeof fn === 'function' ){\n cid = window._wio.ackId()\n window._wio.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 token: RESERVED_EVENTS.includes(_event) ? window._wio.connectionToken : undefined\n }\n \n if( typeof window.ReactNativeWebView !== 'undefined' )\n window.ReactNativeWebView.postMessage( JSON.stringify( messageData ) )\n else console.error('[EMBEDDED] ReactNativeWebView not available')\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( !window._wio.Events[_event] ) window._wio.Events[_event] = []\n window._wio.Events[_event].push( fn )\n\n return window._wio\n },\n \n once: function( _event, fn ){\n _event += '--@once'\n if( !window._wio.Events[_event] ) window._wio.Events[_event] = []\n\n window._wio.Events[_event].push( fn )\n\n return window._wio\n },\n \n off: function( _event, fn ){\n if( fn && window._wio.Events[_event] ){\n const index = window._wio.Events[_event].indexOf( fn )\n if( index > -1 ){\n window._wio.Events[_event].splice( index, 1 )\n if( window._wio.Events[_event].length === 0 ) delete window._wio.Events[_event]\n }\n }\n else delete window._wio.Events[_event]\n\n return window._wio\n },\n \n processMessageQueue: function(){\n if( !window._wio.connected || window._wio.messageQueue.length === 0 ) return\n \n console.log('[EMBEDDED] Processing', window._wio.messageQueue.length, 'queued messages')\n const queue = [ ...window._wio.messageQueue ]\n window._wio.messageQueue = []\n \n queue.forEach( msg => {\n try { window._wio.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, token } = data\n \n console.log('[EMBEDDED] Received:', _event )\n \n // Handle heartbeat response\n if( _event === '__heartbeat_response' )\n return\n \n // Handle heartbeat request\n if( _event === '__heartbeat' ){\n window._wio.emit('__heartbeat_response', { timestamp: Date.now() })\n return\n }\n \n // Handle webview ready signal\n if( _event === '__webview_ready' ){\n console.log('[EMBEDDED] WebView ready signal received')\n return\n }\n \n // Handle ping from WEBVIEW\n if( _event === 'ping' ){\n console.log('[EMBEDDED] Received ping, sending pong')\n window._wio.connectionToken = token\n\n window._wio.emit('pong', { token: window._wio.connectionToken })\n return\n }\n \n // Handle connection acknowledgment\n if( _event === '__connection_ack' ){\n if( token && token !== window._wio.connectionToken ){\n console.error('[EMBEDDED] Invalid connection token in ack')\n return\n }\n \n console.log('[EMBEDDED] Connection established (received ack)')\n\n window._wio.connected = true\n window._wio.processMessageQueue()\n window._wio.fire('connect')\n\n return\n }\n \n // Fire event listeners\n window._wio.fire( _event, payload, cid )\n },\n \n announceReady: function(){\n let attempts = 0\n const maxAttempts = 10\n const interval = 1000\n \n console.log('[EMBEDDED] Starting ready announcements')\n \n const announce = () => {\n if( window._wio.connected ){\n console.log('[EMBEDDED] Connected, stopping announcements')\n return\n }\n \n attempts++\n if( attempts > maxAttempts ){\n console.log('[EMBEDDED] Max announcement attempts reached')\n return\n }\n \n console.log('[EMBEDDED] Announcing ready (attempt', attempts + '/' + maxAttempts + ')')\n window._wio.emit('__embedded_ready')\n \n setTimeout( announce, interval )\n }\n \n announce()\n }\n }\n\n console.log('[EMBEDDED] WIO bridge ready. Call window._wio.listen() to connect.')\n }\n catch( error ){\n console.error('[EMBEDDED] Setup failed:', error )\n \n // Create minimal fallback\n window._wio = {\n error: error.toString(),\n listen: function(){ console.error('[EMBEDDED] WIO failed to initialize') },\n emit: function(){ console.error('[EMBEDDED] WIO failed to initialize') },\n on: function(){},\n once: function(){},\n off: function(){}\n }\n }\n\n true\n })()\n ";
|
|
683
677
|
};
|
|
684
678
|
return WIO;
|
|
685
679
|
}());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webview.io",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
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
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
package/src/index.ts
CHANGED
|
@@ -131,8 +131,7 @@ export default class WIO {
|
|
|
131
131
|
this.Events = {}
|
|
132
132
|
this.peer = { type: 'WEBVIEW', connected: false, embeddedReady: false }
|
|
133
133
|
|
|
134
|
-
if( options.type )
|
|
135
|
-
this.peer.type = options.type
|
|
134
|
+
if( options.type ) this.peer.type = options.type
|
|
136
135
|
}
|
|
137
136
|
|
|
138
137
|
debug( ...args: any[] ){
|
|
@@ -211,24 +210,19 @@ export default class WIO {
|
|
|
211
210
|
this.connectionToken = generateToken()
|
|
212
211
|
|
|
213
212
|
// Re-initiate connection for WEBVIEW type
|
|
214
|
-
|
|
215
|
-
this.startConnectionAttempt()
|
|
216
|
-
}
|
|
217
|
-
|
|
213
|
+
this.peer.type === 'WEBVIEW' && this.startConnectionAttempt()
|
|
218
214
|
// For EMBEDDED type, announce readiness
|
|
219
|
-
|
|
220
|
-
this.announceEmbeddedReady()
|
|
221
|
-
}
|
|
215
|
+
this.peer.type === 'EMBEDDED' && this.announceEmbeddedReady()
|
|
222
216
|
|
|
223
217
|
// Set timeout for this reconnection attempt
|
|
224
|
-
setTimeout(() => {
|
|
218
|
+
setTimeout( () => {
|
|
225
219
|
if( this.peer.connected ) return
|
|
226
220
|
|
|
227
221
|
this.reconnectAttempts < this.maxReconnectAttempts
|
|
228
222
|
? this.attemptReconnection()
|
|
229
223
|
: this.fire('reconnection_failed', { attempts: this.reconnectAttempts })
|
|
230
|
-
}, this.options.connectionTimeout!)
|
|
231
|
-
}, delay)
|
|
224
|
+
}, this.options.connectionTimeout! )
|
|
225
|
+
}, delay )
|
|
232
226
|
}
|
|
233
227
|
|
|
234
228
|
// Start connection attempt with timeout and retries
|
|
@@ -257,10 +251,8 @@ export default class WIO {
|
|
|
257
251
|
this.debug(`[${this.peer.type}] Connection attempt ${this.connectionAttempts}/${this.options.maxConnectionAttempts}`)
|
|
258
252
|
this.emit('ping', { token: this.connectionToken })
|
|
259
253
|
}
|
|
260
|
-
else
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
}, this.options.connectionPingInterval!)
|
|
254
|
+
else this.stopConnectionAttempt()
|
|
255
|
+
}, this.options.connectionPingInterval! )
|
|
264
256
|
|
|
265
257
|
// Set overall timeout
|
|
266
258
|
this.connectionAttemptTimer = setTimeout(() => {
|
|
@@ -310,17 +302,15 @@ export default class WIO {
|
|
|
310
302
|
this.debug(`[${this.peer.type}] Ready announcement attempt ${attempts}/${maxAttempts}`)
|
|
311
303
|
this.emit('__embedded_ready')
|
|
312
304
|
}
|
|
313
|
-
else
|
|
314
|
-
this.stopEmbeddedReadyAnnouncement()
|
|
315
|
-
}
|
|
305
|
+
else this.stopEmbeddedReadyAnnouncement()
|
|
316
306
|
}, this.options.connectionPingInterval!)
|
|
317
307
|
}
|
|
318
308
|
|
|
319
309
|
private stopEmbeddedReadyAnnouncement(){
|
|
320
|
-
if( this.embeddedReadyCheckInterval )
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
310
|
+
if( !this.embeddedReadyCheckInterval ) return
|
|
311
|
+
|
|
312
|
+
clearInterval( this.embeddedReadyCheckInterval )
|
|
313
|
+
this.embeddedReadyCheckInterval = undefined
|
|
324
314
|
}
|
|
325
315
|
|
|
326
316
|
// Message rate limiting
|
|
@@ -351,8 +341,8 @@ export default class WIO {
|
|
|
351
341
|
|
|
352
342
|
// Queue messages when not connected
|
|
353
343
|
private queueMessage( _event: string, payload?: any, fn?: AckFunction ){
|
|
344
|
+
// Remove oldest message
|
|
354
345
|
if( this.messageQueue.length >= this.options.messageQueueSize! ){
|
|
355
|
-
// Remove oldest message
|
|
356
346
|
const removed = this.messageQueue.shift()
|
|
357
347
|
this.debug(`[${this.peer.type}] Message queue full, removed oldest message:`, removed?._event)
|
|
358
348
|
}
|
|
@@ -413,6 +403,9 @@ export default class WIO {
|
|
|
413
403
|
|
|
414
404
|
/**
|
|
415
405
|
* Listening to connection from the WebView host
|
|
406
|
+
*
|
|
407
|
+
* NOTE: This is called manually from page code,
|
|
408
|
+
* not auto-initialized
|
|
416
409
|
*/
|
|
417
410
|
listen( hostOrigin?: string ){
|
|
418
411
|
this.peer.type = 'EMBEDDED'
|
|
@@ -423,9 +416,7 @@ export default class WIO {
|
|
|
423
416
|
this.debug(`[${this.peer.type}] Listening to connect${hostOrigin ? `: Host <${hostOrigin}>` : ''}`)
|
|
424
417
|
|
|
425
418
|
// Start announcing readiness
|
|
426
|
-
setTimeout(() =>
|
|
427
|
-
this.announceEmbeddedReady()
|
|
428
|
-
}, 100)
|
|
419
|
+
setTimeout( () => this.announceEmbeddedReady(), 100 )
|
|
429
420
|
|
|
430
421
|
return this
|
|
431
422
|
}
|
|
@@ -436,9 +427,9 @@ export default class WIO {
|
|
|
436
427
|
handleMessage( event: { nativeEvent: { data: string } } ){
|
|
437
428
|
try {
|
|
438
429
|
const data = JSON.parse( event.nativeEvent.data )
|
|
439
|
-
|
|
440
430
|
// Enhanced security: check valid message structure
|
|
441
|
-
if( typeof data !== 'object' || !data.hasOwnProperty('_event') )
|
|
431
|
+
if( typeof data !== 'object' || !data.hasOwnProperty('_event') )
|
|
432
|
+
return
|
|
442
433
|
|
|
443
434
|
const { _event, payload, cid, timestamp, token } = data as MessageData
|
|
444
435
|
|
|
@@ -470,9 +461,10 @@ export default class WIO {
|
|
|
470
461
|
this.debug(`[${this.peer.type}] Embedded peer ready`)
|
|
471
462
|
|
|
472
463
|
// If we're WEBVIEW and not connected, send ping
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
464
|
+
this.peer.type === 'WEBVIEW'
|
|
465
|
+
&& !this.peer.connected
|
|
466
|
+
&& this.emit('ping', { token: this.connectionToken })
|
|
467
|
+
|
|
476
468
|
return
|
|
477
469
|
}
|
|
478
470
|
|
|
@@ -494,6 +486,7 @@ export default class WIO {
|
|
|
494
486
|
// Don't set fully connected yet - wait for ack
|
|
495
487
|
this.debug(`[${this.peer.type}] Received ping, sent pong`)
|
|
496
488
|
}
|
|
489
|
+
|
|
497
490
|
return
|
|
498
491
|
}
|
|
499
492
|
|
|
@@ -522,6 +515,7 @@ export default class WIO {
|
|
|
522
515
|
|
|
523
516
|
this.debug(`[${this.peer.type}] Connected (3-way handshake complete)`)
|
|
524
517
|
}
|
|
518
|
+
|
|
525
519
|
return
|
|
526
520
|
}
|
|
527
521
|
|
|
@@ -546,6 +540,7 @@ export default class WIO {
|
|
|
546
540
|
|
|
547
541
|
this.debug(`[${this.peer.type}] Connected (received ack)`)
|
|
548
542
|
}
|
|
543
|
+
|
|
549
544
|
return
|
|
550
545
|
}
|
|
551
546
|
|
|
@@ -569,11 +564,11 @@ export default class WIO {
|
|
|
569
564
|
}
|
|
570
565
|
|
|
571
566
|
const ackFn = cid
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
567
|
+
? ( error: boolean | string, ...args: any[] ): void => {
|
|
568
|
+
this.emit(`${_event}--${cid}--@ack`, { error: error || false, args })
|
|
569
|
+
return
|
|
570
|
+
}
|
|
571
|
+
: undefined
|
|
577
572
|
let listeners: Listener[] = []
|
|
578
573
|
|
|
579
574
|
if( this.Events[_event + '--@once'] ){
|
|
@@ -717,9 +712,7 @@ export default class WIO {
|
|
|
717
712
|
|
|
718
713
|
emitAsync<T = any, R = any>( _event: string, payload?: T, timeout: number = 5000 ): Promise<R> {
|
|
719
714
|
return new Promise(( resolve, reject ) => {
|
|
720
|
-
const timeoutId = setTimeout(() => {
|
|
721
|
-
reject( new Error(`Event '${_event}' acknowledgment timeout after ${timeout}ms`) )
|
|
722
|
-
}, timeout )
|
|
715
|
+
const timeoutId = setTimeout(() => reject( new Error(`Event '${_event}' acknowledgment timeout after ${timeout}ms`) ), timeout )
|
|
723
716
|
|
|
724
717
|
try {
|
|
725
718
|
this.emit( _event, payload, ( error, ...args ) => {
|
|
@@ -745,17 +738,17 @@ export default class WIO {
|
|
|
745
738
|
return new Promise(( resolve, reject ) => {
|
|
746
739
|
if( this.isConnected() ) return resolve()
|
|
747
740
|
|
|
748
|
-
const timeoutId = setTimeout(() => {
|
|
749
|
-
this.off('connect', connectHandler)
|
|
741
|
+
const timeoutId = setTimeout( () => {
|
|
742
|
+
this.off('connect', connectHandler )
|
|
750
743
|
reject( new Error('Connection timeout') )
|
|
751
|
-
}, timeout || this.options.connectionTimeout)
|
|
744
|
+
}, timeout || this.options.connectionTimeout )
|
|
752
745
|
|
|
753
746
|
const connectHandler = () => {
|
|
754
747
|
clearTimeout( timeoutId )
|
|
755
748
|
resolve()
|
|
756
749
|
}
|
|
757
750
|
|
|
758
|
-
this.once('connect', connectHandler)
|
|
751
|
+
this.once('connect', connectHandler )
|
|
759
752
|
})
|
|
760
753
|
}
|
|
761
754
|
|
|
@@ -822,6 +815,7 @@ export default class WIO {
|
|
|
822
815
|
/**
|
|
823
816
|
* Get injected JavaScript for WebView
|
|
824
817
|
* Sets up the EMBEDDED side of the bridge
|
|
818
|
+
* NOTE: Does not auto-initialize - page must call window._wio.listen()
|
|
825
819
|
*/
|
|
826
820
|
getInjectedJavaScript(): string {
|
|
827
821
|
return `
|
|
@@ -849,13 +843,18 @@ export default class WIO {
|
|
|
849
843
|
setupComplete: false,
|
|
850
844
|
|
|
851
845
|
listen: function(){
|
|
846
|
+
if( this.setupComplete ){
|
|
847
|
+
console.warn('[EMBEDDED] Already listening')
|
|
848
|
+
return this
|
|
849
|
+
}
|
|
850
|
+
|
|
852
851
|
console.log('[EMBEDDED] Setting up message listeners...')
|
|
853
852
|
|
|
854
853
|
// Listen to messages from React Native
|
|
855
854
|
window.addEventListener('message', function( event ){
|
|
856
855
|
try {
|
|
857
856
|
const message = typeof event.data === 'string' ? JSON.parse( event.data ) : event.data
|
|
858
|
-
window._wio.handleMessage( message )
|
|
857
|
+
window._wio.handleMessage( message )
|
|
859
858
|
}
|
|
860
859
|
catch( error ){ console.error('[EMBEDDED] Parse error:', error ) }
|
|
861
860
|
})
|
|
@@ -865,16 +864,19 @@ export default class WIO {
|
|
|
865
864
|
document.addEventListener('message', function( event ){
|
|
866
865
|
try {
|
|
867
866
|
const message = typeof event.data === 'string' ? JSON.parse( event.data ) : event.data
|
|
868
|
-
window._wio.handleMessage( message )
|
|
867
|
+
window._wio.handleMessage( message )
|
|
869
868
|
}
|
|
870
869
|
catch( error ){ console.error('[EMBEDDED] Parse error:', error ) }
|
|
871
870
|
})
|
|
872
871
|
}
|
|
873
872
|
|
|
874
|
-
|
|
875
|
-
console.log('[EMBEDDED] Setup complete')
|
|
873
|
+
this.setupComplete = true
|
|
874
|
+
console.log('[EMBEDDED] Setup complete, starting ready announcements')
|
|
876
875
|
|
|
877
|
-
|
|
876
|
+
// Start announcing readiness
|
|
877
|
+
this.announceReady()
|
|
878
|
+
|
|
879
|
+
return this
|
|
878
880
|
},
|
|
879
881
|
|
|
880
882
|
ackId: function(){
|
|
@@ -1045,8 +1047,8 @@ export default class WIO {
|
|
|
1045
1047
|
|
|
1046
1048
|
announceReady: function(){
|
|
1047
1049
|
let attempts = 0
|
|
1048
|
-
const maxAttempts =
|
|
1049
|
-
const interval =
|
|
1050
|
+
const maxAttempts = 10
|
|
1051
|
+
const interval = 1000
|
|
1050
1052
|
|
|
1051
1053
|
console.log('[EMBEDDED] Starting ready announcements')
|
|
1052
1054
|
|
|
@@ -1072,12 +1074,7 @@ export default class WIO {
|
|
|
1072
1074
|
}
|
|
1073
1075
|
}
|
|
1074
1076
|
|
|
1075
|
-
|
|
1076
|
-
wio.listen()
|
|
1077
|
-
// Start announcing readiness after a short delay
|
|
1078
|
-
setTimeout(() => wio.announceReady(), 100)
|
|
1079
|
-
|
|
1080
|
-
console.log('[EMBEDDED] WIO bridge initialized successfully')
|
|
1077
|
+
console.log('[EMBEDDED] WIO bridge ready. Call window._wio.listen() to connect.')
|
|
1081
1078
|
}
|
|
1082
1079
|
catch( error ){
|
|
1083
1080
|
console.error('[EMBEDDED] Setup failed:', error )
|
|
@@ -1085,6 +1082,7 @@ export default class WIO {
|
|
|
1085
1082
|
// Create minimal fallback
|
|
1086
1083
|
window._wio = {
|
|
1087
1084
|
error: error.toString(),
|
|
1085
|
+
listen: function(){ console.error('[EMBEDDED] WIO failed to initialize') },
|
|
1088
1086
|
emit: function(){ console.error('[EMBEDDED] WIO failed to initialize') },
|
|
1089
1087
|
on: function(){},
|
|
1090
1088
|
once: function(){},
|