@dynamic-labs/react-native-extension 4.72.0 → 4.76.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/index.cjs CHANGED
@@ -34,7 +34,7 @@ function _interopNamespace(e) {
34
34
  return Object.freeze(n);
35
35
  }
36
36
 
37
- var version = "4.72.0";
37
+ var version = "4.76.0";
38
38
 
39
39
  function _extends() {
40
40
  return _extends = Object.assign ? Object.assign.bind() : function (n) {
@@ -90,7 +90,14 @@ const useMessageTransportWebViewBridge = (core, webViewRef) => {
90
90
  const sendMessageToWebView = message => {
91
91
  var _a;
92
92
  if (!webViewRef.current) {
93
- logger.debug('WebView ref not found');
93
+ logger.instrument('WebView ref not found — dropping message', {
94
+ environmentId: core.environmentId,
95
+ hostSdkSessionId: core.hostSdkSessionId,
96
+ key: 'webview.message_dropped',
97
+ messageOrigin: message.origin,
98
+ messageType: message.type,
99
+ time: 0
100
+ });
94
101
  return;
95
102
  }
96
103
  /**
@@ -152,6 +159,7 @@ const styles = reactNative.StyleSheet.create({
152
159
 
153
160
  const CLEAR_STATE_PARAM = 'clear-state';
154
161
  const ENVIRONMENT_ID_PARAM = 'environmentId';
162
+ const WEBVIEW_START_TIME_PARAM = 'webviewStartTime';
155
163
 
156
164
  const setClearStateToUrl = webViewUrl => {
157
165
  const newWebViewUrl = new URL(webViewUrl);
@@ -188,7 +196,13 @@ const useWebViewRecoveryTimeout = ({
188
196
  return;
189
197
  }
190
198
  if (hasClearStateInUrl(webViewUrl)) {
191
- logger.debug('timeout recovery: disabled because webview already cleared its state', webViewUrl.toString());
199
+ logger.instrument('Webview failed to load after clearing its state', {
200
+ environmentId: core.environmentId,
201
+ hostSdkSessionId: core.hostSdkSessionId,
202
+ key: 'webview.failed_to_load_after_clear_state',
203
+ time: 0,
204
+ webviewUrl: webViewUrl.toString()
205
+ });
192
206
  onFailedToLoadAfterClearStateRef.current();
193
207
  return;
194
208
  }
@@ -198,14 +212,26 @@ const useWebViewRecoveryTimeout = ({
198
212
  }
199
213
  timeoutRef.current = setTimeout(() => {
200
214
  if (!core.messageTransport.isBlocked()) {
201
- logger.debug('timeout recovery: skip the timeout because the webview did load');
215
+ logger.instrument('Webview recovery skipped because the webview did load', {
216
+ environmentId: core.environmentId,
217
+ hostSdkSessionId: core.hostSdkSessionId,
218
+ key: 'webview.recovery_skipped',
219
+ time: 0,
220
+ webviewUrl: webViewUrl.toString()
221
+ });
202
222
  return;
203
223
  }
204
224
  core.messageTransport.block();
205
225
  // Increase the retry
206
226
  setWebViewUrl(webViewUrl => {
207
227
  const newWebViewUrl = setClearStateToUrl(webViewUrl);
208
- logger.debug('timeout recovery: reloading webview to clear its state', newWebViewUrl.toString());
228
+ logger.instrument('timeout recovery: reloading webview to clear its state', {
229
+ environmentId: core.environmentId,
230
+ hostSdkSessionId: core.hostSdkSessionId,
231
+ key: 'webview.recovery_by_clear_state',
232
+ time: 0,
233
+ webviewUrl: webViewUrl.toString()
234
+ });
209
235
  return newWebViewUrl;
210
236
  });
211
237
  }, recoveryTimeout);
@@ -257,6 +283,11 @@ const assignEnvironmentIdToUrl = (url, environmentId) => {
257
283
  return _url;
258
284
  };
259
285
 
286
+ const assignStartTimeToUrl = url => {
287
+ url.searchParams.set(WEBVIEW_START_TIME_PARAM, Date.now().toString());
288
+ return url;
289
+ };
290
+
260
291
  const waasOrigins = ['https://app.dynamic-preprod.xyz', 'https://app.dynamicauth.com'];
261
292
  const turnkeyOrigins = ['https://recovery.turnkey.com', 'https://export.turnkey.com'];
262
293
  const WebView = ({
@@ -271,8 +302,7 @@ const WebView = ({
271
302
  const {
272
303
  visible
273
304
  } = useWebViewVisibility(core);
274
- const [webViewUrl, setWebViewUrl] = react.useState(assignEnvironmentIdToUrl(initialWebViewUrl, core.environmentId));
275
- const webViewKey = react.useMemo(() => webViewUrl.toString(), [webViewUrl]);
305
+ const [webViewUrl, setWebViewUrl] = react.useState(() => assignStartTimeToUrl(assignEnvironmentIdToUrl(initialWebViewUrl, core.environmentId)));
276
306
  const {
277
307
  onMessageHandler
278
308
  } = useMessageTransportWebViewBridge(core, webViewRef);
@@ -286,7 +316,7 @@ const WebView = ({
286
316
  },
287
317
  // eslint-disable-next-line react-hooks/exhaustive-deps -- we only care about the unmount callback
288
318
  []);
289
- const blockAndReloadWebView = react.useCallback(() => {
319
+ const blockAndReloadWebView = react.useCallback(reason => {
290
320
  /**
291
321
  * Should not reload the webview if it is already blocked
292
322
  * and loading a new page
@@ -303,14 +333,22 @@ const WebView = ({
303
333
  * the webview is reloading
304
334
  */
305
335
  core.messageTransport.block();
306
- // Increase the retry
307
336
  setWebViewUrl(webViewUrl => {
308
337
  const newWebViewUrl = increaseRetryToUrl(webViewUrl);
309
- logger.debug('Reloading webview', newWebViewUrl.toString());
338
+ logger.instrument('Reloading webview', {
339
+ environmentId: core.environmentId,
340
+ hostSdkSessionId: core.hostSdkSessionId,
341
+ key: 'webview.reloading',
342
+ newWebViewUrl,
343
+ reason,
344
+ time: 0,
345
+ webviewUrl: webViewUrl.toString()
346
+ });
310
347
  return newWebViewUrl;
311
348
  });
312
349
  }, [core]);
313
- react.useEffect(() => core.messageTransport.recoveryManager.onRecoveryRequested(blockAndReloadWebView), [core, blockAndReloadWebView]);
350
+ const blockAndReloadWebViewOsKill = react.useCallback(() => blockAndReloadWebView('os_kill'), [blockAndReloadWebView]);
351
+ react.useEffect(() => core.messageTransport.recoveryManager.onRecoveryRequested(() => blockAndReloadWebView('recovery')), [core, blockAndReloadWebView]);
314
352
  const setWebViewLoadError = react.useCallback(() => {
315
353
  // Error was already thrown, do not throw again
316
354
  if (core.initialization.error instanceof WebViewFailedToLoadError) return;
@@ -355,8 +393,8 @@ const WebView = ({
355
393
  onLoad: onLoad,
356
394
  hideKeyboardAccessoryView: true,
357
395
  webviewDebuggingEnabled: _webviewDebuggingEnabled,
358
- onContentProcessDidTerminate: blockAndReloadWebView,
359
- onRenderProcessGone: blockAndReloadWebView,
396
+ onContentProcessDidTerminate: blockAndReloadWebViewOsKill,
397
+ onRenderProcessGone: blockAndReloadWebViewOsKill,
360
398
  onError: onWebViewLoadError,
361
399
  setSupportMultipleWindows: false,
362
400
  onShouldStartLoadWithRequest: request => {
@@ -377,7 +415,7 @@ const WebView = ({
377
415
  }
378
416
  return false;
379
417
  }
380
- }, webViewKey);
418
+ });
381
419
  };
382
420
  const getUrl = url => {
383
421
  try {
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { assertPackageVersion } from '@dynamic-labs/assert-package-version';
2
2
  import { StyleSheet, Platform } from 'react-native';
3
- import { useEffect, useRef, useState, useCallback, useMemo } from 'react';
3
+ import { useEffect, useRef, useState, useCallback } from 'react';
4
4
  import { WebView as WebView$1 } from 'react-native-webview';
5
5
  import { Logger } from '@dynamic-labs/logger';
6
6
  import { messageTransportDataJsonReviver, parseMessageTransportData, messageTransportDataJsonReplacer, createRequestChannel } from '@dynamic-labs/message-transport';
@@ -12,7 +12,7 @@ import { getItemAsync, deleteItemAsync, setItemAsync } from 'expo-secure-store';
12
12
  import { createPasskey, PasskeyStamper } from '@turnkey/react-native-passkey-stamper';
13
13
  import { requireNativeModule } from 'expo-modules-core';
14
14
 
15
- var version = "4.72.0";
15
+ var version = "4.76.0";
16
16
 
17
17
  function _extends() {
18
18
  return _extends = Object.assign ? Object.assign.bind() : function (n) {
@@ -68,7 +68,14 @@ const useMessageTransportWebViewBridge = (core, webViewRef) => {
68
68
  const sendMessageToWebView = message => {
69
69
  var _a;
70
70
  if (!webViewRef.current) {
71
- logger.debug('WebView ref not found');
71
+ logger.instrument('WebView ref not found — dropping message', {
72
+ environmentId: core.environmentId,
73
+ hostSdkSessionId: core.hostSdkSessionId,
74
+ key: 'webview.message_dropped',
75
+ messageOrigin: message.origin,
76
+ messageType: message.type,
77
+ time: 0
78
+ });
72
79
  return;
73
80
  }
74
81
  /**
@@ -130,6 +137,7 @@ const styles = StyleSheet.create({
130
137
 
131
138
  const CLEAR_STATE_PARAM = 'clear-state';
132
139
  const ENVIRONMENT_ID_PARAM = 'environmentId';
140
+ const WEBVIEW_START_TIME_PARAM = 'webviewStartTime';
133
141
 
134
142
  const setClearStateToUrl = webViewUrl => {
135
143
  const newWebViewUrl = new URL(webViewUrl);
@@ -166,7 +174,13 @@ const useWebViewRecoveryTimeout = ({
166
174
  return;
167
175
  }
168
176
  if (hasClearStateInUrl(webViewUrl)) {
169
- logger.debug('timeout recovery: disabled because webview already cleared its state', webViewUrl.toString());
177
+ logger.instrument('Webview failed to load after clearing its state', {
178
+ environmentId: core.environmentId,
179
+ hostSdkSessionId: core.hostSdkSessionId,
180
+ key: 'webview.failed_to_load_after_clear_state',
181
+ time: 0,
182
+ webviewUrl: webViewUrl.toString()
183
+ });
170
184
  onFailedToLoadAfterClearStateRef.current();
171
185
  return;
172
186
  }
@@ -176,14 +190,26 @@ const useWebViewRecoveryTimeout = ({
176
190
  }
177
191
  timeoutRef.current = setTimeout(() => {
178
192
  if (!core.messageTransport.isBlocked()) {
179
- logger.debug('timeout recovery: skip the timeout because the webview did load');
193
+ logger.instrument('Webview recovery skipped because the webview did load', {
194
+ environmentId: core.environmentId,
195
+ hostSdkSessionId: core.hostSdkSessionId,
196
+ key: 'webview.recovery_skipped',
197
+ time: 0,
198
+ webviewUrl: webViewUrl.toString()
199
+ });
180
200
  return;
181
201
  }
182
202
  core.messageTransport.block();
183
203
  // Increase the retry
184
204
  setWebViewUrl(webViewUrl => {
185
205
  const newWebViewUrl = setClearStateToUrl(webViewUrl);
186
- logger.debug('timeout recovery: reloading webview to clear its state', newWebViewUrl.toString());
206
+ logger.instrument('timeout recovery: reloading webview to clear its state', {
207
+ environmentId: core.environmentId,
208
+ hostSdkSessionId: core.hostSdkSessionId,
209
+ key: 'webview.recovery_by_clear_state',
210
+ time: 0,
211
+ webviewUrl: webViewUrl.toString()
212
+ });
187
213
  return newWebViewUrl;
188
214
  });
189
215
  }, recoveryTimeout);
@@ -235,6 +261,11 @@ const assignEnvironmentIdToUrl = (url, environmentId) => {
235
261
  return _url;
236
262
  };
237
263
 
264
+ const assignStartTimeToUrl = url => {
265
+ url.searchParams.set(WEBVIEW_START_TIME_PARAM, Date.now().toString());
266
+ return url;
267
+ };
268
+
238
269
  const waasOrigins = ['https://app.dynamic-preprod.xyz', 'https://app.dynamicauth.com'];
239
270
  const turnkeyOrigins = ['https://recovery.turnkey.com', 'https://export.turnkey.com'];
240
271
  const WebView = ({
@@ -249,8 +280,7 @@ const WebView = ({
249
280
  const {
250
281
  visible
251
282
  } = useWebViewVisibility(core);
252
- const [webViewUrl, setWebViewUrl] = useState(assignEnvironmentIdToUrl(initialWebViewUrl, core.environmentId));
253
- const webViewKey = useMemo(() => webViewUrl.toString(), [webViewUrl]);
283
+ const [webViewUrl, setWebViewUrl] = useState(() => assignStartTimeToUrl(assignEnvironmentIdToUrl(initialWebViewUrl, core.environmentId)));
254
284
  const {
255
285
  onMessageHandler
256
286
  } = useMessageTransportWebViewBridge(core, webViewRef);
@@ -264,7 +294,7 @@ const WebView = ({
264
294
  },
265
295
  // eslint-disable-next-line react-hooks/exhaustive-deps -- we only care about the unmount callback
266
296
  []);
267
- const blockAndReloadWebView = useCallback(() => {
297
+ const blockAndReloadWebView = useCallback(reason => {
268
298
  /**
269
299
  * Should not reload the webview if it is already blocked
270
300
  * and loading a new page
@@ -281,14 +311,22 @@ const WebView = ({
281
311
  * the webview is reloading
282
312
  */
283
313
  core.messageTransport.block();
284
- // Increase the retry
285
314
  setWebViewUrl(webViewUrl => {
286
315
  const newWebViewUrl = increaseRetryToUrl(webViewUrl);
287
- logger.debug('Reloading webview', newWebViewUrl.toString());
316
+ logger.instrument('Reloading webview', {
317
+ environmentId: core.environmentId,
318
+ hostSdkSessionId: core.hostSdkSessionId,
319
+ key: 'webview.reloading',
320
+ newWebViewUrl,
321
+ reason,
322
+ time: 0,
323
+ webviewUrl: webViewUrl.toString()
324
+ });
288
325
  return newWebViewUrl;
289
326
  });
290
327
  }, [core]);
291
- useEffect(() => core.messageTransport.recoveryManager.onRecoveryRequested(blockAndReloadWebView), [core, blockAndReloadWebView]);
328
+ const blockAndReloadWebViewOsKill = useCallback(() => blockAndReloadWebView('os_kill'), [blockAndReloadWebView]);
329
+ useEffect(() => core.messageTransport.recoveryManager.onRecoveryRequested(() => blockAndReloadWebView('recovery')), [core, blockAndReloadWebView]);
292
330
  const setWebViewLoadError = useCallback(() => {
293
331
  // Error was already thrown, do not throw again
294
332
  if (core.initialization.error instanceof WebViewFailedToLoadError) return;
@@ -333,8 +371,8 @@ const WebView = ({
333
371
  onLoad: onLoad,
334
372
  hideKeyboardAccessoryView: true,
335
373
  webviewDebuggingEnabled: _webviewDebuggingEnabled,
336
- onContentProcessDidTerminate: blockAndReloadWebView,
337
- onRenderProcessGone: blockAndReloadWebView,
374
+ onContentProcessDidTerminate: blockAndReloadWebViewOsKill,
375
+ onRenderProcessGone: blockAndReloadWebViewOsKill,
338
376
  onError: onWebViewLoadError,
339
377
  setSupportMultipleWindows: false,
340
378
  onShouldStartLoadWithRequest: request => {
@@ -355,7 +393,7 @@ const WebView = ({
355
393
  }
356
394
  return false;
357
395
  }
358
- }, webViewKey);
396
+ });
359
397
  };
360
398
  const getUrl = url => {
361
399
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/react-native-extension",
3
- "version": "4.72.0",
3
+ "version": "4.76.0",
4
4
  "main": "./index.cjs",
5
5
  "module": "./index.js",
6
6
  "types": "./src/index.d.ts",
@@ -18,11 +18,11 @@
18
18
  "@turnkey/react-native-passkey-stamper": "1.2.7",
19
19
  "@react-native-documents/picker": "^11.0.0",
20
20
  "react-native-fs": ">=2.20.0",
21
- "@dynamic-labs/assert-package-version": "4.72.0",
22
- "@dynamic-labs/client": "4.72.0",
23
- "@dynamic-labs/logger": "4.72.0",
24
- "@dynamic-labs/message-transport": "4.72.0",
25
- "@dynamic-labs/webview-messages": "4.72.0"
21
+ "@dynamic-labs/assert-package-version": "4.76.0",
22
+ "@dynamic-labs/client": "4.76.0",
23
+ "@dynamic-labs/logger": "4.76.0",
24
+ "@dynamic-labs/message-transport": "4.76.0",
25
+ "@dynamic-labs/webview-messages": "4.76.0"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "react": ">=18.0.0 <20.0.0",
@@ -1,2 +1,3 @@
1
1
  export declare const CLEAR_STATE_PARAM = "clear-state";
2
2
  export declare const ENVIRONMENT_ID_PARAM = "environmentId";
3
+ export declare const WEBVIEW_START_TIME_PARAM = "webviewStartTime";
@@ -0,0 +1 @@
1
+ export declare const assignStartTimeToUrl: (url: URL) => URL;
@@ -0,0 +1 @@
1
+ export { assignStartTimeToUrl } from './assignStartTimeToUrl';