@dynamic-labs/react-native-extension 4.91.5 → 5.0.0-rc.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/android/EmbeddedWebViewController.kt +1 -1
- package/android/dynamic/embeddedwebview/EmbeddedWebViewController.kt +1 -1
- package/android/embeddedwebview/EmbeddedWebViewController.kt +1 -1
- package/android/java/xyz/dynamic/embeddedwebview/EmbeddedWebViewController.kt +1 -1
- package/android/main/java/xyz/dynamic/embeddedwebview/EmbeddedWebViewController.kt +1 -1
- package/android/src/main/java/xyz/dynamic/embeddedwebview/EmbeddedWebViewController.kt +1 -1
- package/android/xyz/dynamic/embeddedwebview/EmbeddedWebViewController.kt +1 -1
- package/index.cjs +27 -4
- package/index.js +27 -4
- package/ios/EmbeddedWebViewController.swift +12 -1
- package/package.json +6 -6
|
@@ -24,7 +24,7 @@ import org.json.JSONObject
|
|
|
24
24
|
import java.util.UUID
|
|
25
25
|
|
|
26
26
|
private const val SCRIPT_HANDLER_NAME = "DynamicEmbeddedWebView"
|
|
27
|
-
private const val NAVIGATION_DECISION_TIMEOUT_MS =
|
|
27
|
+
private const val NAVIGATION_DECISION_TIMEOUT_MS = 5000L
|
|
28
28
|
|
|
29
29
|
// Singleton owning the in-app overlay view that hosts the WebView.
|
|
30
30
|
// Mirrors EmbeddedWebViewController on iOS.
|
|
@@ -24,7 +24,7 @@ import org.json.JSONObject
|
|
|
24
24
|
import java.util.UUID
|
|
25
25
|
|
|
26
26
|
private const val SCRIPT_HANDLER_NAME = "DynamicEmbeddedWebView"
|
|
27
|
-
private const val NAVIGATION_DECISION_TIMEOUT_MS =
|
|
27
|
+
private const val NAVIGATION_DECISION_TIMEOUT_MS = 5000L
|
|
28
28
|
|
|
29
29
|
// Singleton owning the in-app overlay view that hosts the WebView.
|
|
30
30
|
// Mirrors EmbeddedWebViewController on iOS.
|
|
@@ -24,7 +24,7 @@ import org.json.JSONObject
|
|
|
24
24
|
import java.util.UUID
|
|
25
25
|
|
|
26
26
|
private const val SCRIPT_HANDLER_NAME = "DynamicEmbeddedWebView"
|
|
27
|
-
private const val NAVIGATION_DECISION_TIMEOUT_MS =
|
|
27
|
+
private const val NAVIGATION_DECISION_TIMEOUT_MS = 5000L
|
|
28
28
|
|
|
29
29
|
// Singleton owning the in-app overlay view that hosts the WebView.
|
|
30
30
|
// Mirrors EmbeddedWebViewController on iOS.
|
|
@@ -24,7 +24,7 @@ import org.json.JSONObject
|
|
|
24
24
|
import java.util.UUID
|
|
25
25
|
|
|
26
26
|
private const val SCRIPT_HANDLER_NAME = "DynamicEmbeddedWebView"
|
|
27
|
-
private const val NAVIGATION_DECISION_TIMEOUT_MS =
|
|
27
|
+
private const val NAVIGATION_DECISION_TIMEOUT_MS = 5000L
|
|
28
28
|
|
|
29
29
|
// Singleton owning the in-app overlay view that hosts the WebView.
|
|
30
30
|
// Mirrors EmbeddedWebViewController on iOS.
|
|
@@ -24,7 +24,7 @@ import org.json.JSONObject
|
|
|
24
24
|
import java.util.UUID
|
|
25
25
|
|
|
26
26
|
private const val SCRIPT_HANDLER_NAME = "DynamicEmbeddedWebView"
|
|
27
|
-
private const val NAVIGATION_DECISION_TIMEOUT_MS =
|
|
27
|
+
private const val NAVIGATION_DECISION_TIMEOUT_MS = 5000L
|
|
28
28
|
|
|
29
29
|
// Singleton owning the in-app overlay view that hosts the WebView.
|
|
30
30
|
// Mirrors EmbeddedWebViewController on iOS.
|
|
@@ -24,7 +24,7 @@ import org.json.JSONObject
|
|
|
24
24
|
import java.util.UUID
|
|
25
25
|
|
|
26
26
|
private const val SCRIPT_HANDLER_NAME = "DynamicEmbeddedWebView"
|
|
27
|
-
private const val NAVIGATION_DECISION_TIMEOUT_MS =
|
|
27
|
+
private const val NAVIGATION_DECISION_TIMEOUT_MS = 5000L
|
|
28
28
|
|
|
29
29
|
// Singleton owning the in-app overlay view that hosts the WebView.
|
|
30
30
|
// Mirrors EmbeddedWebViewController on iOS.
|
|
@@ -24,7 +24,7 @@ import org.json.JSONObject
|
|
|
24
24
|
import java.util.UUID
|
|
25
25
|
|
|
26
26
|
private const val SCRIPT_HANDLER_NAME = "DynamicEmbeddedWebView"
|
|
27
|
-
private const val NAVIGATION_DECISION_TIMEOUT_MS =
|
|
27
|
+
private const val NAVIGATION_DECISION_TIMEOUT_MS = 5000L
|
|
28
28
|
|
|
29
29
|
// Singleton owning the in-app overlay view that hosts the WebView.
|
|
30
30
|
// Mirrors EmbeddedWebViewController on iOS.
|
package/index.cjs
CHANGED
|
@@ -35,7 +35,7 @@ function _interopNamespace(e) {
|
|
|
35
35
|
return Object.freeze(n);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
var version = "
|
|
38
|
+
var version = "5.0.0-rc.0";
|
|
39
39
|
|
|
40
40
|
function _extends() {
|
|
41
41
|
return _extends = Object.assign ? Object.assign.bind() : function (n) {
|
|
@@ -1002,6 +1002,7 @@ const setupEmbeddedWebView = ({
|
|
|
1002
1002
|
let recoveryTimer = null;
|
|
1003
1003
|
let hasFailed = false;
|
|
1004
1004
|
let hasEmittedSuccessLog = false;
|
|
1005
|
+
let tornDown = false;
|
|
1005
1006
|
const clearLoadingTimer = () => {
|
|
1006
1007
|
if (loadingTimer !== null) {
|
|
1007
1008
|
clearTimeout(loadingTimer);
|
|
@@ -1023,6 +1024,7 @@ const setupEmbeddedWebView = ({
|
|
|
1023
1024
|
hasFailed = true;
|
|
1024
1025
|
clearLoadingTimer();
|
|
1025
1026
|
clearRecoveryTimer();
|
|
1027
|
+
logger.debug(`[EmbeddedWebView] raiseFailure phase=${phase}`);
|
|
1026
1028
|
const meta = phaseTimers.getMeta({
|
|
1027
1029
|
phase
|
|
1028
1030
|
});
|
|
@@ -1064,6 +1066,7 @@ const setupEmbeddedWebView = ({
|
|
|
1064
1066
|
const handleSdkReady = message => {
|
|
1065
1067
|
if (message.origin !== 'webview') return;
|
|
1066
1068
|
if (message.type !== webviewMessages.sdkHasLoadedEventName) return;
|
|
1069
|
+
logger.debug('[EmbeddedWebView] SDK ready signal received');
|
|
1067
1070
|
clearRecoveryTimer();
|
|
1068
1071
|
if (hasEmittedSuccessLog || hasFailed) return;
|
|
1069
1072
|
hasEmittedSuccessLog = true;
|
|
@@ -1099,11 +1102,13 @@ const setupEmbeddedWebView = ({
|
|
|
1099
1102
|
isTopFrame: event.isTopFrame,
|
|
1100
1103
|
url: event.url
|
|
1101
1104
|
}, builtUrl);
|
|
1105
|
+
logger.debug(`[EmbeddedWebView] onShouldStartLoad id=${event.id} url=${event.url} isTopFrame=${event.isTopFrame} allow=${allow}`);
|
|
1102
1106
|
native.respondToShouldStartLoad(event.id, allow).catch(err => {
|
|
1103
1107
|
logger.warn('EmbeddedWebView.respondToShouldStartLoad failed', err);
|
|
1104
1108
|
});
|
|
1105
1109
|
});
|
|
1106
1110
|
const onLoadStartSub = native.addListener('onLoadStart', () => {
|
|
1111
|
+
logger.debug('[EmbeddedWebView] onLoadStart');
|
|
1107
1112
|
phaseTimers.recordEvent('load_start');
|
|
1108
1113
|
// Re-arm both timers on every load_start. A retry from the native
|
|
1109
1114
|
// side (e.g. a redirect, or a reload after a transient failure)
|
|
@@ -1116,10 +1121,12 @@ const setupEmbeddedWebView = ({
|
|
|
1116
1121
|
}, _loadingTimeoutMs);
|
|
1117
1122
|
});
|
|
1118
1123
|
const onLoadSub = native.addListener('onLoad', () => {
|
|
1124
|
+
logger.debug('[EmbeddedWebView] onLoad (response committed)');
|
|
1119
1125
|
phaseTimers.recordEvent('load');
|
|
1120
1126
|
clearLoadingTimer();
|
|
1121
1127
|
});
|
|
1122
1128
|
const onLoadEndSub = native.addListener('onLoadEnd', () => {
|
|
1129
|
+
logger.debug('[EmbeddedWebView] onLoadEnd (page finished)');
|
|
1123
1130
|
phaseTimers.recordEvent('load_end');
|
|
1124
1131
|
clearLoadingTimer();
|
|
1125
1132
|
clearRecoveryTimer();
|
|
@@ -1128,6 +1135,7 @@ const setupEmbeddedWebView = ({
|
|
|
1128
1135
|
}, _recoveryTimeoutMs);
|
|
1129
1136
|
});
|
|
1130
1137
|
const onLoadErrorSub = native.addListener('onLoadError', event => {
|
|
1138
|
+
logger.debug(`[EmbeddedWebView] onLoadError domain=${event.domain} code=${event.code} url=${event.url}`);
|
|
1131
1139
|
phaseTimers.recordEvent('native_error');
|
|
1132
1140
|
logger.warn('EmbeddedWebView load error', event);
|
|
1133
1141
|
raiseFailure('embedded_native_error', {
|
|
@@ -1147,13 +1155,28 @@ const setupEmbeddedWebView = ({
|
|
|
1147
1155
|
// without emitting onLoadError — leaving onLoadStart (and therefore the
|
|
1148
1156
|
// timer) never triggered. The onLoadStart handler clears and re-arms this
|
|
1149
1157
|
// timer when it fires, so behaviour after onLoadStart is unchanged.
|
|
1158
|
+
logger.debug(`[EmbeddedWebView] arming loading timer (${_loadingTimeoutMs}ms) before setUrl`);
|
|
1150
1159
|
loadingTimer = setTimeout(() => {
|
|
1160
|
+
logger.debug('[EmbeddedWebView] loading timer fired — raising html_load failure');
|
|
1151
1161
|
raiseFailure('html_load');
|
|
1152
1162
|
}, _loadingTimeoutMs);
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1163
|
+
// Defer setUrl by one event-loop tick so the JS thread has fully settled
|
|
1164
|
+
// after listener registration. On cold boot the main thread is congested
|
|
1165
|
+
// with bundle evaluation — yielding here gives pending microtasks and
|
|
1166
|
+
// native bridge batches a chance to flush before the native side starts
|
|
1167
|
+
// firing navigation events that require a JS round-trip response.
|
|
1168
|
+
const warmupTimer = setTimeout(() => {
|
|
1169
|
+
var _a;
|
|
1170
|
+
if (tornDown) return;
|
|
1171
|
+
logger.debug(`[EmbeddedWebView] calling setUrl: ${builtUrl.toString()}`);
|
|
1172
|
+
(_a = native.setUrl(builtUrl.toString())) === null || _a === void 0 ? void 0 : _a.catch(err => {
|
|
1173
|
+
logger.warn('EmbeddedWebView.setUrl failed', err);
|
|
1174
|
+
});
|
|
1175
|
+
}, 0);
|
|
1156
1176
|
return () => {
|
|
1177
|
+
logger.debug('[EmbeddedWebView] teardown — removing listeners');
|
|
1178
|
+
tornDown = true;
|
|
1179
|
+
clearTimeout(warmupTimer);
|
|
1157
1180
|
clearLoadingTimer();
|
|
1158
1181
|
clearRecoveryTimer();
|
|
1159
1182
|
removeVisibilityHandler();
|
package/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { createURL, getInitialURL, addEventListener, openURL } from 'expo-linkin
|
|
|
13
13
|
import { openAuthSessionAsync } from 'expo-web-browser';
|
|
14
14
|
import { createPasskey, PasskeyStamper } from '@turnkey/react-native-passkey-stamper';
|
|
15
15
|
|
|
16
|
-
var version = "
|
|
16
|
+
var version = "5.0.0-rc.0";
|
|
17
17
|
|
|
18
18
|
function _extends() {
|
|
19
19
|
return _extends = Object.assign ? Object.assign.bind() : function (n) {
|
|
@@ -980,6 +980,7 @@ const setupEmbeddedWebView = ({
|
|
|
980
980
|
let recoveryTimer = null;
|
|
981
981
|
let hasFailed = false;
|
|
982
982
|
let hasEmittedSuccessLog = false;
|
|
983
|
+
let tornDown = false;
|
|
983
984
|
const clearLoadingTimer = () => {
|
|
984
985
|
if (loadingTimer !== null) {
|
|
985
986
|
clearTimeout(loadingTimer);
|
|
@@ -1001,6 +1002,7 @@ const setupEmbeddedWebView = ({
|
|
|
1001
1002
|
hasFailed = true;
|
|
1002
1003
|
clearLoadingTimer();
|
|
1003
1004
|
clearRecoveryTimer();
|
|
1005
|
+
logger.debug(`[EmbeddedWebView] raiseFailure phase=${phase}`);
|
|
1004
1006
|
const meta = phaseTimers.getMeta({
|
|
1005
1007
|
phase
|
|
1006
1008
|
});
|
|
@@ -1042,6 +1044,7 @@ const setupEmbeddedWebView = ({
|
|
|
1042
1044
|
const handleSdkReady = message => {
|
|
1043
1045
|
if (message.origin !== 'webview') return;
|
|
1044
1046
|
if (message.type !== sdkHasLoadedEventName) return;
|
|
1047
|
+
logger.debug('[EmbeddedWebView] SDK ready signal received');
|
|
1045
1048
|
clearRecoveryTimer();
|
|
1046
1049
|
if (hasEmittedSuccessLog || hasFailed) return;
|
|
1047
1050
|
hasEmittedSuccessLog = true;
|
|
@@ -1077,11 +1080,13 @@ const setupEmbeddedWebView = ({
|
|
|
1077
1080
|
isTopFrame: event.isTopFrame,
|
|
1078
1081
|
url: event.url
|
|
1079
1082
|
}, builtUrl);
|
|
1083
|
+
logger.debug(`[EmbeddedWebView] onShouldStartLoad id=${event.id} url=${event.url} isTopFrame=${event.isTopFrame} allow=${allow}`);
|
|
1080
1084
|
native.respondToShouldStartLoad(event.id, allow).catch(err => {
|
|
1081
1085
|
logger.warn('EmbeddedWebView.respondToShouldStartLoad failed', err);
|
|
1082
1086
|
});
|
|
1083
1087
|
});
|
|
1084
1088
|
const onLoadStartSub = native.addListener('onLoadStart', () => {
|
|
1089
|
+
logger.debug('[EmbeddedWebView] onLoadStart');
|
|
1085
1090
|
phaseTimers.recordEvent('load_start');
|
|
1086
1091
|
// Re-arm both timers on every load_start. A retry from the native
|
|
1087
1092
|
// side (e.g. a redirect, or a reload after a transient failure)
|
|
@@ -1094,10 +1099,12 @@ const setupEmbeddedWebView = ({
|
|
|
1094
1099
|
}, _loadingTimeoutMs);
|
|
1095
1100
|
});
|
|
1096
1101
|
const onLoadSub = native.addListener('onLoad', () => {
|
|
1102
|
+
logger.debug('[EmbeddedWebView] onLoad (response committed)');
|
|
1097
1103
|
phaseTimers.recordEvent('load');
|
|
1098
1104
|
clearLoadingTimer();
|
|
1099
1105
|
});
|
|
1100
1106
|
const onLoadEndSub = native.addListener('onLoadEnd', () => {
|
|
1107
|
+
logger.debug('[EmbeddedWebView] onLoadEnd (page finished)');
|
|
1101
1108
|
phaseTimers.recordEvent('load_end');
|
|
1102
1109
|
clearLoadingTimer();
|
|
1103
1110
|
clearRecoveryTimer();
|
|
@@ -1106,6 +1113,7 @@ const setupEmbeddedWebView = ({
|
|
|
1106
1113
|
}, _recoveryTimeoutMs);
|
|
1107
1114
|
});
|
|
1108
1115
|
const onLoadErrorSub = native.addListener('onLoadError', event => {
|
|
1116
|
+
logger.debug(`[EmbeddedWebView] onLoadError domain=${event.domain} code=${event.code} url=${event.url}`);
|
|
1109
1117
|
phaseTimers.recordEvent('native_error');
|
|
1110
1118
|
logger.warn('EmbeddedWebView load error', event);
|
|
1111
1119
|
raiseFailure('embedded_native_error', {
|
|
@@ -1125,13 +1133,28 @@ const setupEmbeddedWebView = ({
|
|
|
1125
1133
|
// without emitting onLoadError — leaving onLoadStart (and therefore the
|
|
1126
1134
|
// timer) never triggered. The onLoadStart handler clears and re-arms this
|
|
1127
1135
|
// timer when it fires, so behaviour after onLoadStart is unchanged.
|
|
1136
|
+
logger.debug(`[EmbeddedWebView] arming loading timer (${_loadingTimeoutMs}ms) before setUrl`);
|
|
1128
1137
|
loadingTimer = setTimeout(() => {
|
|
1138
|
+
logger.debug('[EmbeddedWebView] loading timer fired — raising html_load failure');
|
|
1129
1139
|
raiseFailure('html_load');
|
|
1130
1140
|
}, _loadingTimeoutMs);
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1141
|
+
// Defer setUrl by one event-loop tick so the JS thread has fully settled
|
|
1142
|
+
// after listener registration. On cold boot the main thread is congested
|
|
1143
|
+
// with bundle evaluation — yielding here gives pending microtasks and
|
|
1144
|
+
// native bridge batches a chance to flush before the native side starts
|
|
1145
|
+
// firing navigation events that require a JS round-trip response.
|
|
1146
|
+
const warmupTimer = setTimeout(() => {
|
|
1147
|
+
var _a;
|
|
1148
|
+
if (tornDown) return;
|
|
1149
|
+
logger.debug(`[EmbeddedWebView] calling setUrl: ${builtUrl.toString()}`);
|
|
1150
|
+
(_a = native.setUrl(builtUrl.toString())) === null || _a === void 0 ? void 0 : _a.catch(err => {
|
|
1151
|
+
logger.warn('EmbeddedWebView.setUrl failed', err);
|
|
1152
|
+
});
|
|
1153
|
+
}, 0);
|
|
1134
1154
|
return () => {
|
|
1155
|
+
logger.debug('[EmbeddedWebView] teardown — removing listeners');
|
|
1156
|
+
tornDown = true;
|
|
1157
|
+
clearTimeout(warmupTimer);
|
|
1135
1158
|
clearLoadingTimer();
|
|
1136
1159
|
clearRecoveryTimer();
|
|
1137
1160
|
removeVisibilityHandler();
|
|
@@ -2,7 +2,7 @@ import UIKit
|
|
|
2
2
|
import WebKit
|
|
3
3
|
|
|
4
4
|
private let scriptHandlerName = "dynamicEmbeddedWebView"
|
|
5
|
-
private let navigationDecisionTimeout: TimeInterval =
|
|
5
|
+
private let navigationDecisionTimeout: TimeInterval = 5.0
|
|
6
6
|
|
|
7
7
|
// Cleartext http is only permitted in debug builds (e.g. Metro at
|
|
8
8
|
// http://localhost:4202). Release builds reject http top-frame and sub-frame
|
|
@@ -366,6 +366,17 @@ extension EmbeddedWebViewController: WKNavigationDelegate {
|
|
|
366
366
|
if let handler = self.pendingNavigationDecisions.removeValue(forKey: id) {
|
|
367
367
|
self.navigationTimers.removeValue(forKey: id)?.invalidate()
|
|
368
368
|
handler(.cancel)
|
|
369
|
+
// Surface an explicit load error so the SDK's error path runs
|
|
370
|
+
// immediately instead of waiting for the 20 s html_load timer.
|
|
371
|
+
// Matches Android's EmbeddedWebViewNavigationTimeout behavior.
|
|
372
|
+
let timeoutMs = Int(navigationDecisionTimeout * 1000)
|
|
373
|
+
self.eventEmitter?("onLoadError", [
|
|
374
|
+
"url": url,
|
|
375
|
+
"code": -1,
|
|
376
|
+
"domain": "EmbeddedWebViewNavigationTimeout",
|
|
377
|
+
"description": "Navigation decision timed out after \(timeoutMs)ms",
|
|
378
|
+
"isProvisional": true,
|
|
379
|
+
])
|
|
369
380
|
}
|
|
370
381
|
}
|
|
371
382
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs/react-native-extension",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-rc.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": "
|
|
22
|
-
"@dynamic-labs/client": "
|
|
23
|
-
"@dynamic-labs/logger": "
|
|
24
|
-
"@dynamic-labs/message-transport": "
|
|
25
|
-
"@dynamic-labs/webview-messages": "
|
|
21
|
+
"@dynamic-labs/assert-package-version": "5.0.0-rc.0",
|
|
22
|
+
"@dynamic-labs/client": "5.0.0-rc.0",
|
|
23
|
+
"@dynamic-labs/logger": "5.0.0-rc.0",
|
|
24
|
+
"@dynamic-labs/message-transport": "5.0.0-rc.0",
|
|
25
|
+
"@dynamic-labs/webview-messages": "5.0.0-rc.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": ">=18.0.0 <20.0.0",
|