@truewatchtech/react-native-mobile 0.4.2 → 0.4.3
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/FTMobileReactNativeSDK.podspec +7 -5
- package/android/build.gradle +10 -3
- package/android/src/main/java/com/ft/sdk/reactnative/FTLogImpl.java +10 -2
- package/android/src/main/java/com/ft/sdk/reactnative/FTMobileImpl.java +45 -10
- package/android/src/main/java/com/ft/sdk/reactnative/FTRUMImpl.java +131 -6
- package/android/src/main/java/com/ft/sdk/reactnative/FTTraceImpl.java +10 -3
- package/android/src/main/java/com/ft/sdk/reactnative/JsLongTaskMonitor.java +281 -0
- package/android/src/main/java/com/ft/sdk/reactnative/ViewTiming.java +17 -0
- package/android/src/main/java/com/ft/sdk/reactnative/VisitorIdConfigMapper.java +50 -0
- package/android/src/main/java/com/ft/sdk/reactnative/utils/ReactNativeUtils.java +5 -12
- package/android/src/newarch/java/com/ft/sdk/reactnative/FTMobileModule.java +14 -5
- package/android/src/newarch/java/com/ft/sdk/reactnative/FTRUMModule.java +44 -1
- package/android/src/newarch/java/com/ft/sdk/reactnative/FTTraceModule.java +14 -0
- package/android/src/oldarch/java/com/ft/sdk/reactnative/FTMobileModule.java +7 -2
- package/android/src/oldarch/java/com/ft/sdk/reactnative/FTRUMModule.java +39 -1
- package/android/src/oldarch/java/com/ft/sdk/reactnative/FTTraceModule.java +12 -0
- package/android/src/rnpost70/java/com/ft/sdk/reactnative/ReactJsThreadExecutor.java +21 -0
- package/android/src/rnpre70/java/com/ft/sdk/reactnative/ReactJsThreadExecutor.java +37 -0
- package/android/src/test/java/com/ft/sdk/reactnative/FTMobileImplTest.java +53 -0
- package/android/src/test/java/com/ft/sdk/reactnative/FTRUMModuleTest.java +117 -0
- package/android/src/test/java/com/ft/sdk/reactnative/JsLongTaskMonitorTest.java +446 -0
- package/android/src/test/java/com/ft/sdk/reactnative/utils/ReactNativeUtilsTest.java +33 -0
- package/ios/FTJSLongTaskMonitor.h +51 -0
- package/ios/FTJSLongTaskMonitor.m +250 -0
- package/ios/FTMobileReactNative.mm +54 -18
- package/ios/FTReactNativeLog.mm +9 -5
- package/ios/FTReactNativeRUM.mm +196 -31
- package/ios/FTReactNativeResource.h +4 -0
- package/ios/FTReactNativeResource.m +64 -0
- package/ios/FTReactNativeTrace.mm +59 -14
- package/ios/FTReactNativeUtils.m +10 -15
- package/ios/FTReactNativeViewTiming.h +18 -0
- package/ios/FTReactNativeWebSocket.h +10 -0
- package/ios/FTReactNativeWebSocket.mm +201 -0
- package/ios/FTWebSocketMetadataStore.h +25 -0
- package/ios/FTWebSocketMetadataStore.m +622 -0
- package/ios/FTWebSocketResourceData.h +20 -0
- package/ios/FTWebSocketResourceData.m +106 -0
- package/lib/commonjs/ft_logger.js +3 -1
- package/lib/commonjs/ft_logger.js.map +1 -1
- package/lib/commonjs/ft_mobile_agent.js +47 -4
- package/lib/commonjs/ft_mobile_agent.js.map +1 -1
- package/lib/commonjs/ft_rum.js +65 -5
- package/lib/commonjs/ft_rum.js.map +1 -1
- package/lib/commonjs/ft_tracing.js +14 -4
- package/lib/commonjs/ft_tracing.js.map +1 -1
- package/lib/commonjs/index.js +21 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/rum/FTBabelInteractionTracking.js +72 -0
- package/lib/commonjs/rum/FTBabelInteractionTracking.js.map +1 -0
- package/lib/commonjs/rum/FTBabelUtils.js +87 -0
- package/lib/commonjs/rum/FTBabelUtils.js.map +1 -0
- package/lib/commonjs/rum/FTRumActionTracking.js +10 -39
- package/lib/commonjs/rum/FTRumActionTracking.js.map +1 -1
- package/lib/commonjs/rum/FTRumActionTrackingContext.js +50 -0
- package/lib/commonjs/rum/FTRumActionTrackingContext.js.map +1 -0
- package/lib/commonjs/rum/FTRumViewTracking.js +147 -0
- package/lib/commonjs/rum/FTRumViewTracking.js.map +1 -0
- package/lib/commonjs/rum/FTRumWebSocketNative.js +73 -0
- package/lib/commonjs/rum/FTRumWebSocketNative.js.map +1 -0
- package/lib/commonjs/rum/FTRumWebSocketTiming.js +73 -0
- package/lib/commonjs/rum/FTRumWebSocketTiming.js.map +1 -0
- package/lib/commonjs/rum/FTRumWebSocketTracking.js +506 -0
- package/lib/commonjs/rum/FTRumWebSocketTracking.js.map +1 -0
- package/lib/commonjs/rum/longTasksUtils.js +25 -0
- package/lib/commonjs/rum/longTasksUtils.js.map +1 -0
- package/lib/commonjs/specs/NativeFTMobileReactNative.js.map +1 -1
- package/lib/commonjs/specs/NativeFTReactNativeRUM.js.map +1 -1
- package/lib/commonjs/specs/NativeFTReactNativeTrace.js.map +1 -1
- package/lib/commonjs/specs/NativeFTReactNativeWebSocket.js +11 -0
- package/lib/commonjs/specs/NativeFTReactNativeWebSocket.js.map +1 -0
- package/lib/commonjs/version.js +1 -1
- package/lib/commonjs/version.js.map +1 -1
- package/lib/commonjs/visitorIdConfig.js +37 -0
- package/lib/commonjs/visitorIdConfig.js.map +1 -0
- package/lib/module/ft_logger.js +3 -1
- package/lib/module/ft_logger.js.map +1 -1
- package/lib/module/ft_mobile_agent.js +47 -4
- package/lib/module/ft_mobile_agent.js.map +1 -1
- package/lib/module/ft_rum.js +65 -5
- package/lib/module/ft_rum.js.map +1 -1
- package/lib/module/ft_tracing.js +14 -2
- package/lib/module/ft_tracing.js.map +1 -1
- package/lib/module/index.js +4 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/rum/FTBabelInteractionTracking.js +66 -0
- package/lib/module/rum/FTBabelInteractionTracking.js.map +1 -0
- package/lib/module/rum/FTBabelUtils.js +80 -0
- package/lib/module/rum/FTBabelUtils.js.map +1 -0
- package/lib/module/rum/FTRumActionTracking.js +10 -39
- package/lib/module/rum/FTRumActionTracking.js.map +1 -1
- package/lib/module/rum/FTRumActionTrackingContext.js +43 -0
- package/lib/module/rum/FTRumActionTrackingContext.js.map +1 -0
- package/lib/module/rum/FTRumViewTracking.js +140 -0
- package/lib/module/rum/FTRumViewTracking.js.map +1 -0
- package/lib/module/rum/FTRumWebSocketNative.js +62 -0
- package/lib/module/rum/FTRumWebSocketNative.js.map +1 -0
- package/lib/module/rum/FTRumWebSocketTiming.js +67 -0
- package/lib/module/rum/FTRumWebSocketTiming.js.map +1 -0
- package/lib/module/rum/FTRumWebSocketTracking.js +499 -0
- package/lib/module/rum/FTRumWebSocketTracking.js.map +1 -0
- package/lib/module/rum/longTasksUtils.js +18 -0
- package/lib/module/rum/longTasksUtils.js.map +1 -0
- package/lib/module/specs/NativeFTMobileReactNative.js.map +1 -1
- package/lib/module/specs/NativeFTReactNativeRUM.js.map +1 -1
- package/lib/module/specs/NativeFTReactNativeTrace.js.map +1 -1
- package/lib/module/specs/NativeFTReactNativeWebSocket.js +8 -0
- package/lib/module/specs/NativeFTReactNativeWebSocket.js.map +1 -0
- package/lib/module/version.js +1 -1
- package/lib/module/version.js.map +1 -1
- package/lib/module/visitorIdConfig.js +31 -0
- package/lib/module/visitorIdConfig.js.map +1 -0
- package/lib/typescript/ft_logger.d.ts +11 -1
- package/lib/typescript/ft_mobile_agent.d.ts +28 -0
- package/lib/typescript/ft_rum.d.ts +42 -5
- package/lib/typescript/ft_tracing.d.ts +9 -1
- package/lib/typescript/index.d.ts +5 -1
- package/lib/typescript/rum/FTBabelInteractionTracking.d.ts +30 -0
- package/lib/typescript/rum/FTBabelUtils.d.ts +1 -0
- package/lib/typescript/rum/FTRumActionTracking.d.ts +0 -2
- package/lib/typescript/rum/FTRumActionTrackingContext.d.ts +11 -0
- package/lib/typescript/rum/FTRumViewTracking.d.ts +32 -0
- package/lib/typescript/rum/FTRumWebSocketNative.d.ts +22 -0
- package/lib/typescript/rum/FTRumWebSocketTiming.d.ts +7 -0
- package/lib/typescript/rum/FTRumWebSocketTracking.d.ts +54 -0
- package/lib/typescript/rum/longTasksUtils.d.ts +8 -0
- package/lib/typescript/specs/NativeFTMobileReactNative.d.ts +15 -0
- package/lib/typescript/specs/NativeFTReactNativeRUM.d.ts +11 -1
- package/lib/typescript/specs/NativeFTReactNativeTrace.d.ts +12 -0
- package/lib/typescript/specs/NativeFTReactNativeWebSocket.d.ts +13 -0
- package/lib/typescript/version.d.ts +1 -1
- package/lib/typescript/visitorIdConfig.d.ts +11 -0
- package/package.json +6 -4
- package/src/ft_logger.tsx +11 -1
- package/src/ft_mobile_agent.tsx +79 -7
- package/src/ft_rum.tsx +111 -7
- package/src/ft_tracing.tsx +24 -2
- package/src/index.tsx +8 -0
- package/src/rum/FTBabelInteractionTracking.ts +124 -0
- package/src/rum/FTBabelUtils.tsx +99 -0
- package/src/rum/FTRumActionTracking.tsx +14 -43
- package/src/rum/FTRumActionTrackingContext.ts +68 -0
- package/src/rum/FTRumViewTracking.ts +179 -0
- package/src/rum/FTRumWebSocketNative.ts +107 -0
- package/src/rum/FTRumWebSocketTiming.ts +82 -0
- package/src/rum/FTRumWebSocketTracking.ts +722 -0
- package/src/rum/longTasksUtils.ts +17 -0
- package/src/specs/NativeFTMobileReactNative.ts +18 -0
- package/src/specs/NativeFTReactNativeRUM.ts +19 -1
- package/src/specs/NativeFTReactNativeTrace.ts +12 -0
- package/src/specs/NativeFTReactNativeWebSocket.ts +33 -0
- package/src/version.ts +1 -1
- package/src/visitorIdConfig.ts +123 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
2
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
3
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
4
|
+
import { AppState } from 'react-native';
|
|
5
|
+
import { FTReactNativeRUM } from '../ft_rum';
|
|
6
|
+
import { bridgeContextManager } from '../ft_mobile_agent';
|
|
7
|
+
const MAX_PENDING_LOAD_MS = 15 * 60 * 1000;
|
|
8
|
+
|
|
9
|
+
/** Shared lifecycle coordinator for navigation adapters. Use one per navigator. */
|
|
10
|
+
export class FTRumViewTracking {
|
|
11
|
+
constructor(onBackground) {
|
|
12
|
+
this.onBackground = onBackground;
|
|
13
|
+
_defineProperty(this, "current", void 0);
|
|
14
|
+
_defineProperty(this, "active", void 0);
|
|
15
|
+
_defineProperty(this, "generation", 0);
|
|
16
|
+
_defineProperty(this, "lifecycle", 0);
|
|
17
|
+
_defineProperty(this, "state", null);
|
|
18
|
+
_defineProperty(this, "subscription", void 0);
|
|
19
|
+
_defineProperty(this, "loading", new Map());
|
|
20
|
+
_defineProperty(this, "onAppState", state => {
|
|
21
|
+
if (state === this.state) return;
|
|
22
|
+
this.state = state;
|
|
23
|
+
if (state === 'background') {
|
|
24
|
+
var _this$onBackground;
|
|
25
|
+
// Native closes Automatic Views at its own history boundary. No JS stop.
|
|
26
|
+
this.active = undefined;
|
|
27
|
+
this.loading.clear();
|
|
28
|
+
(_this$onBackground = this.onBackground) === null || _this$onBackground === void 0 || _this$onBackground.call(this);
|
|
29
|
+
} else if (state === 'active' && this.current) {
|
|
30
|
+
this.show(this.current);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
start() {
|
|
35
|
+
if (this.subscription) return;
|
|
36
|
+
this.state = AppState.currentState;
|
|
37
|
+
const lifecycle = ++this.lifecycle;
|
|
38
|
+
const listener = state => {
|
|
39
|
+
if (lifecycle === this.lifecycle) this.onAppState(state);
|
|
40
|
+
};
|
|
41
|
+
const subscription = AppState.addEventListener('change', listener);
|
|
42
|
+
// RN < 0.65 uses removeEventListener instead of returning a subscription.
|
|
43
|
+
const legacyAppState = AppState;
|
|
44
|
+
this.subscription = subscription || {
|
|
45
|
+
remove: () => {
|
|
46
|
+
var _legacyAppState$remov;
|
|
47
|
+
return (_legacyAppState$remov = legacyAppState.removeEventListener) === null || _legacyAppState$remov === void 0 ? void 0 : _legacyAppState$remov.call(legacyAppState, 'change', listener);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Capture both clocks at the loading boundary, before any async work. */
|
|
53
|
+
beginLoad(key) {
|
|
54
|
+
this.start();
|
|
55
|
+
this.pruneLoading();
|
|
56
|
+
if (this.state === 'background' || this.loading.has(key)) return;
|
|
57
|
+
if (typeof performance === 'undefined' || typeof performance.now !== 'function') return;
|
|
58
|
+
// Only the latest transition can supply loading for this navigator.
|
|
59
|
+
this.loading.clear();
|
|
60
|
+
this.loading.set(key, {
|
|
61
|
+
monotonicMs: performance.now(),
|
|
62
|
+
epochMs: Date.now()
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Remember a transitioning route so foreground recovery uses the current page. */
|
|
67
|
+
setCurrent(route) {
|
|
68
|
+
this.start();
|
|
69
|
+
this.current = {
|
|
70
|
+
key: route.key,
|
|
71
|
+
name: route.name
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
show(route, loadingKey = route.key) {
|
|
75
|
+
var _this$active;
|
|
76
|
+
this.setCurrent(route);
|
|
77
|
+
this.pruneLoading();
|
|
78
|
+
const loading = this.loading.get(loadingKey);
|
|
79
|
+
this.loading.clear();
|
|
80
|
+
if (this.state !== 'active') return undefined;
|
|
81
|
+
if (((_this$active = this.active) === null || _this$active === void 0 ? void 0 : _this$active.key) === route.key) return this.active.generation;
|
|
82
|
+
this.active = {
|
|
83
|
+
key: route.key,
|
|
84
|
+
generation: ++this.generation
|
|
85
|
+
};
|
|
86
|
+
if (loading) {
|
|
87
|
+
const durationNs = Math.floor((performance.now() - loading.monotonicMs) * 1000000);
|
|
88
|
+
if (Number.isFinite(durationNs) && durationNs > 0) {
|
|
89
|
+
this.report(this.nativeRUM.onCreateViewWithLoadStart(route.name, durationNs, Number.isFinite(loading.epochMs) ? loading.epochMs : 0));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Enqueue these calls together. Waiting for a Promise here could start a stale
|
|
93
|
+
// page after background/route changes; native consumes loading before start.
|
|
94
|
+
this.report(this.nativeRUM.startViewWithTrackingType(route.name, bridgeContextManager.mergeWithLocalPropertiesSync(), 1 // Automatic is an internal framework bridge detail.
|
|
95
|
+
));
|
|
96
|
+
return this.active.generation;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Apply a completed interval only to the appearance that started it. */
|
|
100
|
+
updateLoadingTime(key, generation, durationNs) {
|
|
101
|
+
if (this.state !== 'active' || !this.active || this.active.key !== key || this.active.generation !== generation || !Number.isSafeInteger(durationNs) || durationNs <= 0) return;
|
|
102
|
+
// Enqueue immediately; never let a Promise continuation update another View.
|
|
103
|
+
this.report(FTReactNativeRUM.updateViewLoadingTime(durationNs));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Only the appearance that owns the active generation may close it. */
|
|
107
|
+
hide(key, generation) {
|
|
108
|
+
if (this.state !== 'active') return;
|
|
109
|
+
if (!this.active || this.active.key !== key || this.active.generation !== generation) return;
|
|
110
|
+
this.active = undefined;
|
|
111
|
+
this.current = undefined;
|
|
112
|
+
this.report(FTReactNativeRUM.stopView());
|
|
113
|
+
}
|
|
114
|
+
stop() {
|
|
115
|
+
var _this$subscription;
|
|
116
|
+
++this.lifecycle;
|
|
117
|
+
(_this$subscription = this.subscription) === null || _this$subscription === void 0 || _this$subscription.remove();
|
|
118
|
+
this.subscription = undefined;
|
|
119
|
+
if (this.active && this.state === 'active') this.report(FTReactNativeRUM.stopView());
|
|
120
|
+
this.active = undefined;
|
|
121
|
+
this.current = undefined;
|
|
122
|
+
this.loading.clear();
|
|
123
|
+
// Never reuse generation values: callbacks from a previous subscription can arrive late.
|
|
124
|
+
}
|
|
125
|
+
pruneLoading() {
|
|
126
|
+
const now = typeof performance !== 'undefined' && typeof performance.now === 'function' ? performance.now() : NaN;
|
|
127
|
+
for (const [key, load] of this.loading) {
|
|
128
|
+
const age = now - load.monotonicMs;
|
|
129
|
+
if (!Number.isFinite(age) || age < 0 || age >= MAX_PENDING_LOAD_MS) this.loading.delete(key);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
get nativeRUM() {
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
134
|
+
return require('../specs/NativeFTReactNativeRUM').default;
|
|
135
|
+
}
|
|
136
|
+
report(result) {
|
|
137
|
+
result.catch(error => console.warn('[TrueWatch] Automatic View tracking failed', error));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=FTRumViewTracking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["AppState","FTReactNativeRUM","bridgeContextManager","MAX_PENDING_LOAD_MS","FTRumViewTracking","constructor","onBackground","_defineProperty","Map","state","_this$onBackground","active","undefined","loading","clear","call","current","show","start","subscription","currentState","lifecycle","listener","onAppState","addEventListener","legacyAppState","remove","_legacyAppState$remov","removeEventListener","beginLoad","key","pruneLoading","has","performance","now","set","monotonicMs","epochMs","Date","setCurrent","route","name","loadingKey","_this$active","get","generation","durationNs","Math","floor","Number","isFinite","report","nativeRUM","onCreateViewWithLoadStart","startViewWithTrackingType","mergeWithLocalPropertiesSync","updateLoadingTime","isSafeInteger","updateViewLoadingTime","hide","stopView","stop","_this$subscription","NaN","load","age","delete","require","default","result","catch","error","console","warn"],"sources":["FTRumViewTracking.ts"],"sourcesContent":["import { AppState } from 'react-native';\nimport type { AppStateStatus } from 'react-native';\nimport { FTReactNativeRUM } from '../ft_rum';\nimport { bridgeContextManager } from '../ft_mobile_agent';\nimport type { Spec as NativeRUMSpec } from '../specs/NativeFTReactNativeRUM';\n\ntype Route = { key: string; name: string };\ntype Loading = { monotonicMs: number; epochMs: number };\nconst MAX_PENDING_LOAD_MS = 15 * 60 * 1000;\n\n/** Shared lifecycle coordinator for navigation adapters. Use one per navigator. */\nexport class FTRumViewTracking {\n private current?: Route;\n private active?: { key: string; generation: number };\n private generation = 0;\n private lifecycle = 0;\n private state: AppStateStatus | null = null;\n private subscription?: { remove(): void };\n private loading = new Map<string, Loading>();\n\n constructor(private readonly onBackground?: () => void) {}\n\n start(): void {\n if (this.subscription) return;\n this.state = AppState.currentState;\n const lifecycle = ++this.lifecycle;\n const listener = (state: AppStateStatus): void => {\n if (lifecycle === this.lifecycle) this.onAppState(state);\n };\n const subscription = AppState.addEventListener('change', listener);\n // RN < 0.65 uses removeEventListener instead of returning a subscription.\n const legacyAppState = AppState as typeof AppState & {\n removeEventListener?: (type: string, callback: typeof listener) => void;\n };\n this.subscription = subscription || {\n remove: () => legacyAppState.removeEventListener?.('change', listener),\n };\n }\n\n /** Capture both clocks at the loading boundary, before any async work. */\n beginLoad(key: string): void {\n this.start();\n this.pruneLoading();\n if (this.state === 'background' || this.loading.has(key)) return;\n if (\n typeof performance === 'undefined' ||\n typeof performance.now !== 'function'\n )\n return;\n // Only the latest transition can supply loading for this navigator.\n this.loading.clear();\n this.loading.set(key, {\n monotonicMs: performance.now(),\n epochMs: Date.now(),\n });\n }\n\n /** Remember a transitioning route so foreground recovery uses the current page. */\n setCurrent(route: Route): void {\n this.start();\n this.current = { key: route.key, name: route.name };\n }\n\n show(route: Route, loadingKey: string = route.key): number | undefined {\n this.setCurrent(route);\n this.pruneLoading();\n const loading = this.loading.get(loadingKey);\n this.loading.clear();\n if (this.state !== 'active') return undefined;\n if (this.active?.key === route.key) return this.active.generation;\n this.active = { key: route.key, generation: ++this.generation };\n if (loading) {\n const durationNs = Math.floor(\n (performance.now() - loading.monotonicMs) * 1000000\n );\n if (Number.isFinite(durationNs) && durationNs > 0) {\n this.report(\n this.nativeRUM.onCreateViewWithLoadStart(\n route.name,\n durationNs,\n Number.isFinite(loading.epochMs) ? loading.epochMs : 0\n )\n );\n }\n }\n // Enqueue these calls together. Waiting for a Promise here could start a stale\n // page after background/route changes; native consumes loading before start.\n this.report(\n this.nativeRUM.startViewWithTrackingType(\n route.name,\n bridgeContextManager.mergeWithLocalPropertiesSync(),\n 1 // Automatic is an internal framework bridge detail.\n )\n );\n return this.active.generation;\n }\n\n /** Apply a completed interval only to the appearance that started it. */\n updateLoadingTime(\n key: string,\n generation: number | undefined,\n durationNs: number\n ): void {\n if (\n this.state !== 'active' ||\n !this.active ||\n this.active.key !== key ||\n this.active.generation !== generation ||\n !Number.isSafeInteger(durationNs) ||\n durationNs <= 0\n )\n return;\n // Enqueue immediately; never let a Promise continuation update another View.\n this.report(FTReactNativeRUM.updateViewLoadingTime(durationNs));\n }\n\n /** Only the appearance that owns the active generation may close it. */\n hide(key: string, generation: number | undefined): void {\n if (this.state !== 'active') return;\n if (\n !this.active ||\n this.active.key !== key ||\n this.active.generation !== generation\n )\n return;\n this.active = undefined;\n this.current = undefined;\n this.report(FTReactNativeRUM.stopView());\n }\n\n stop(): void {\n ++this.lifecycle;\n this.subscription?.remove();\n this.subscription = undefined;\n if (this.active && this.state === 'active')\n this.report(FTReactNativeRUM.stopView());\n this.active = undefined;\n this.current = undefined;\n this.loading.clear();\n // Never reuse generation values: callbacks from a previous subscription can arrive late.\n }\n\n private onAppState = (state: AppStateStatus): void => {\n if (state === this.state) return;\n this.state = state;\n if (state === 'background') {\n // Native closes Automatic Views at its own history boundary. No JS stop.\n this.active = undefined;\n this.loading.clear();\n this.onBackground?.();\n } else if (state === 'active' && this.current) {\n this.show(this.current);\n }\n };\n\n private pruneLoading(): void {\n const now =\n typeof performance !== 'undefined' &&\n typeof performance.now === 'function'\n ? performance.now()\n : NaN;\n for (const [key, load] of this.loading) {\n const age = now - load.monotonicMs;\n if (!Number.isFinite(age) || age < 0 || age >= MAX_PENDING_LOAD_MS)\n this.loading.delete(key);\n }\n }\n\n private get nativeRUM(): NativeRUMSpec {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n return require('../specs/NativeFTReactNativeRUM').default;\n }\n\n private report(result: Promise<void>): void {\n result.catch((error) =>\n console.warn('[TrueWatch] Automatic View tracking failed', error)\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
2
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
3
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
4
|
+
import NativeWebSocket from '../specs/NativeFTReactNativeWebSocket';
|
|
5
|
+
import { bridgeContextManager } from '../ft_mobile_agent';
|
|
6
|
+
function ignoreBridgeFailure(call) {
|
|
7
|
+
try {
|
|
8
|
+
void Promise.resolve(call()).catch(() => {});
|
|
9
|
+
} catch {
|
|
10
|
+
/* Setup/cleanup replies must not interrupt JS capture. */
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class NativeWebSocketSession {
|
|
14
|
+
constructor(session) {
|
|
15
|
+
this.session = session;
|
|
16
|
+
_defineProperty(this, "stopped", false);
|
|
17
|
+
_defineProperty(this, "sequence", 0);
|
|
18
|
+
// Enqueue setup before start/stop/add on the same native module queue.
|
|
19
|
+
// Its reply never gates JS capture or selects a different reporting route.
|
|
20
|
+
ignoreBridgeFailure(() => NativeWebSocket.startCapture(session));
|
|
21
|
+
}
|
|
22
|
+
startResource(key, socketID, url) {
|
|
23
|
+
const property = bridgeContextManager.mergeWithLocalPropertiesSync();
|
|
24
|
+
return NativeWebSocket.startResource(key, socketID !== null && socketID !== void 0 ? socketID : -1, url, this.session, ++this.sequence, property);
|
|
25
|
+
}
|
|
26
|
+
stopResource(key, event) {
|
|
27
|
+
const property = bridgeContextManager.mergeWithLocalPropertiesSync();
|
|
28
|
+
return NativeWebSocket.stopResource(key, event, this.session, property);
|
|
29
|
+
}
|
|
30
|
+
addResource(key, content, metrics) {
|
|
31
|
+
return NativeWebSocket.addResource(key, content, metrics, this.session);
|
|
32
|
+
}
|
|
33
|
+
release(key) {
|
|
34
|
+
ignoreBridgeFailure(() => NativeWebSocket === null || NativeWebSocket === void 0 ? void 0 : NativeWebSocket.releaseResource(key, this.session));
|
|
35
|
+
}
|
|
36
|
+
stop() {
|
|
37
|
+
if (this.stopped) return;
|
|
38
|
+
this.stopped = true;
|
|
39
|
+
// Existing handshakes still finish through their originally selected route.
|
|
40
|
+
ignoreBridgeFailure(() => NativeWebSocket === null || NativeWebSocket === void 0 ? void 0 : NativeWebSocket.stopCapture(this.session));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function startNativeWebSocketSession(createKey) {
|
|
44
|
+
try {
|
|
45
|
+
if (typeof (NativeWebSocket === null || NativeWebSocket === void 0 ? void 0 : NativeWebSocket.startCapture) === 'function' && typeof NativeWebSocket.stopCapture === 'function' && typeof NativeWebSocket.clear === 'function' && typeof NativeWebSocket.startResource === 'function' && typeof NativeWebSocket.stopResource === 'function' && typeof NativeWebSocket.addResource === 'function' && typeof NativeWebSocket.releaseResource === 'function') return new NativeWebSocketSession(createKey());
|
|
46
|
+
} catch {
|
|
47
|
+
/* Old native binaries keep the JS fallback. */
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
export function clearNativeWebSocketSessions() {
|
|
52
|
+
ignoreBridgeFailure(() => NativeWebSocket === null || NativeWebSocket === void 0 ? void 0 : NativeWebSocket.clear());
|
|
53
|
+
}
|
|
54
|
+
export function webSocketNativeID(socket) {
|
|
55
|
+
try {
|
|
56
|
+
const id = socket === null || socket === void 0 ? void 0 : socket._socketId;
|
|
57
|
+
return typeof id === 'number' && Number.isSafeInteger(id) && id >= 0 ? id : undefined;
|
|
58
|
+
} catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=FTRumWebSocketNative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeWebSocket","bridgeContextManager","ignoreBridgeFailure","call","Promise","resolve","catch","NativeWebSocketSession","constructor","session","_defineProperty","startCapture","startResource","key","socketID","url","property","mergeWithLocalPropertiesSync","sequence","stopResource","event","addResource","content","metrics","release","releaseResource","stop","stopped","stopCapture","startNativeWebSocketSession","createKey","clear","undefined","clearNativeWebSocketSessions","webSocketNativeID","socket","id","_socketId","Number","isSafeInteger"],"sources":["FTRumWebSocketNative.ts"],"sourcesContent":["import NativeWebSocket from '../specs/NativeFTReactNativeWebSocket';\nimport { bridgeContextManager } from '../ft_mobile_agent';\nimport type { WebSocketTimingMetrics } from './FTRumWebSocketTiming';\n\nexport interface NativeWebSocketResource {\n url: string;\n httpMethod: string;\n requestHeader: Record<string, unknown>;\n webSocketEvent: string;\n errorMessage?: string;\n}\n\nfunction ignoreBridgeFailure(call: () => unknown): void {\n try {\n void Promise.resolve(call()).catch(() => {});\n } catch {\n /* Setup/cleanup replies must not interrupt JS capture. */\n }\n}\n\nexport class NativeWebSocketSession {\n private stopped = false;\n private sequence = 0;\n\n constructor(private readonly session: string) {\n // Enqueue setup before start/stop/add on the same native module queue.\n // Its reply never gates JS capture or selects a different reporting route.\n ignoreBridgeFailure(() => NativeWebSocket!.startCapture(session));\n }\n\n startResource(\n key: string,\n socketID: number | undefined,\n url: string\n ): Promise<void> {\n const property = bridgeContextManager.mergeWithLocalPropertiesSync();\n return NativeWebSocket!.startResource(\n key,\n socketID ?? -1,\n url,\n this.session,\n ++this.sequence,\n property\n );\n }\n\n stopResource(key: string, event: string): Promise<void> {\n const property = bridgeContextManager.mergeWithLocalPropertiesSync();\n return NativeWebSocket!.stopResource(key, event, this.session, property);\n }\n\n addResource(\n key: string,\n content: NativeWebSocketResource,\n metrics: Partial<WebSocketTimingMetrics>\n ): Promise<void> {\n return NativeWebSocket!.addResource(key, content, metrics, this.session);\n }\n\n release(key: string): void {\n ignoreBridgeFailure(() =>\n NativeWebSocket?.releaseResource(key, this.session)\n );\n }\n\n stop(): void {\n if (this.stopped) return;\n this.stopped = true;\n // Existing handshakes still finish through their originally selected route.\n ignoreBridgeFailure(() => NativeWebSocket?.stopCapture(this.session));\n }\n}\n\nexport function startNativeWebSocketSession(\n createKey: () => string\n): NativeWebSocketSession | undefined {\n try {\n if (\n typeof NativeWebSocket?.startCapture === 'function' &&\n typeof NativeWebSocket.stopCapture === 'function' &&\n typeof NativeWebSocket.clear === 'function' &&\n typeof NativeWebSocket.startResource === 'function' &&\n typeof NativeWebSocket.stopResource === 'function' &&\n typeof NativeWebSocket.addResource === 'function' &&\n typeof NativeWebSocket.releaseResource === 'function'\n )\n return new NativeWebSocketSession(createKey());\n } catch {\n /* Old native binaries keep the JS fallback. */\n }\n return undefined;\n}\n\nexport function clearNativeWebSocketSessions(): void {\n ignoreBridgeFailure(() => NativeWebSocket?.clear());\n}\n\nexport function webSocketNativeID(socket: unknown): number | undefined {\n try {\n const id = (socket as { _socketId?: unknown })?._socketId;\n return typeof id === 'number' && Number.isSafeInteger(id) && id >= 0\n ? id\n : undefined;\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** Measures only the JS-observed opening handshake; bridge delays are excluded. */
|
|
2
|
+
export function startWebSocketTiming() {
|
|
3
|
+
const wallStart = readWallTime();
|
|
4
|
+
let monotonicNow;
|
|
5
|
+
let monotonicStart;
|
|
6
|
+
try {
|
|
7
|
+
const clock = globalThis.performance;
|
|
8
|
+
if (typeof (clock === null || clock === void 0 ? void 0 : clock.now) === 'function') {
|
|
9
|
+
monotonicNow = () => clock.now();
|
|
10
|
+
monotonicStart = monotonicNow();
|
|
11
|
+
}
|
|
12
|
+
} catch {
|
|
13
|
+
// Older runtimes and other instrumentation may not provide this clock.
|
|
14
|
+
}
|
|
15
|
+
return () => {
|
|
16
|
+
let durationMs;
|
|
17
|
+
try {
|
|
18
|
+
if (monotonicNow && Number.isFinite(monotonicStart)) {
|
|
19
|
+
const elapsed = monotonicNow() - monotonicStart;
|
|
20
|
+
if (Number.isFinite(elapsed) && elapsed >= 0) {
|
|
21
|
+
durationMs = elapsed;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
// Fall back to wall time if the monotonic clock becomes unavailable.
|
|
26
|
+
}
|
|
27
|
+
if (durationMs === undefined && wallStart !== undefined) {
|
|
28
|
+
const wallEnd = readWallTime();
|
|
29
|
+
if (wallEnd !== undefined && wallEnd >= wallStart) {
|
|
30
|
+
durationMs = wallEnd - wallStart;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (durationMs === undefined) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
// Resource metrics use nanoseconds. Do not send an invalid bridge number.
|
|
37
|
+
const durationNs = Math.round(durationMs * 1e6);
|
|
38
|
+
if (!Number.isSafeInteger(durationNs)) return undefined;
|
|
39
|
+
const metrics = {
|
|
40
|
+
duration: durationNs
|
|
41
|
+
};
|
|
42
|
+
if (wallStart !== undefined && Number.isSafeInteger(wallStart) && wallStart > 0) {
|
|
43
|
+
// Add the monotonic elapsed interval to the start epoch, not Date.now()
|
|
44
|
+
// at completion. Split milliseconds/remainder to avoid epoch-ns doubles.
|
|
45
|
+
const endMs = wallStart + Math.floor(durationNs / 1e6);
|
|
46
|
+
const start = `${wallStart}000000`;
|
|
47
|
+
const end = `${endMs}${String(durationNs % 1e6).padStart(6, '0')}`;
|
|
48
|
+
if (Number.isSafeInteger(endMs) && fitsInt64(start) && fitsInt64(end)) {
|
|
49
|
+
metrics.fetchStartNsTimeInterval = start;
|
|
50
|
+
metrics.fetchEndNsTimeInterval = end;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return metrics;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function fitsInt64(value) {
|
|
57
|
+
return value.length < 19 || value.length === 19 && value <= '9223372036854775807';
|
|
58
|
+
}
|
|
59
|
+
function readWallTime() {
|
|
60
|
+
try {
|
|
61
|
+
const time = Date.now();
|
|
62
|
+
return Number.isFinite(time) ? time : undefined;
|
|
63
|
+
} catch {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=FTRumWebSocketTiming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["startWebSocketTiming","wallStart","readWallTime","monotonicNow","monotonicStart","clock","globalThis","performance","now","durationMs","Number","isFinite","elapsed","undefined","wallEnd","durationNs","Math","round","isSafeInteger","metrics","duration","endMs","floor","start","end","String","padStart","fitsInt64","fetchStartNsTimeInterval","fetchEndNsTimeInterval","value","length","time","Date"],"sources":["FTRumWebSocketTiming.ts"],"sourcesContent":["export interface WebSocketTimingMetrics {\n duration: number;\n // Decimal int64 nanoseconds: epoch nanoseconds exceed JS number precision.\n fetchStartNsTimeInterval?: string;\n fetchEndNsTimeInterval?: string;\n}\n\n/** Measures only the JS-observed opening handshake; bridge delays are excluded. */\nexport function startWebSocketTiming(): () =>\n | WebSocketTimingMetrics\n | undefined {\n const wallStart = readWallTime();\n let monotonicNow: (() => number) | undefined;\n let monotonicStart: number | undefined;\n try {\n const clock = globalThis.performance;\n if (typeof clock?.now === 'function') {\n monotonicNow = () => clock.now();\n monotonicStart = monotonicNow();\n }\n } catch {\n // Older runtimes and other instrumentation may not provide this clock.\n }\n\n return () => {\n let durationMs: number | undefined;\n try {\n if (monotonicNow && Number.isFinite(monotonicStart)) {\n const elapsed = monotonicNow() - (monotonicStart as number);\n if (Number.isFinite(elapsed) && elapsed >= 0) {\n durationMs = elapsed;\n }\n }\n } catch {\n // Fall back to wall time if the monotonic clock becomes unavailable.\n }\n if (durationMs === undefined && wallStart !== undefined) {\n const wallEnd = readWallTime();\n if (wallEnd !== undefined && wallEnd >= wallStart) {\n durationMs = wallEnd - wallStart;\n }\n }\n if (durationMs === undefined) {\n return undefined;\n }\n // Resource metrics use nanoseconds. Do not send an invalid bridge number.\n const durationNs = Math.round(durationMs * 1e6);\n if (!Number.isSafeInteger(durationNs)) return undefined;\n const metrics: WebSocketTimingMetrics = { duration: durationNs };\n if (\n wallStart !== undefined &&\n Number.isSafeInteger(wallStart) &&\n wallStart > 0\n ) {\n // Add the monotonic elapsed interval to the start epoch, not Date.now()\n // at completion. Split milliseconds/remainder to avoid epoch-ns doubles.\n const endMs = wallStart + Math.floor(durationNs / 1e6);\n const start = `${wallStart}000000`;\n const end = `${endMs}${String(durationNs % 1e6).padStart(6, '0')}`;\n if (Number.isSafeInteger(endMs) && fitsInt64(start) && fitsInt64(end)) {\n metrics.fetchStartNsTimeInterval = start;\n metrics.fetchEndNsTimeInterval = end;\n }\n }\n return metrics;\n };\n}\n\nfunction fitsInt64(value: string): boolean {\n return (\n value.length < 19 || (value.length === 19 && value <= '9223372036854775807')\n );\n}\n\nfunction readWallTime(): number | undefined {\n try {\n const time = Date.now();\n return Number.isFinite(time) ? time : undefined;\n } catch {\n return undefined;\n }\n}\n"],"mappings":"AAOA;AACA,OAAO,SAASA,oBAAoBA,CAAA,EAEtB;EACZ,MAAMC,SAAS,GAAGC,YAAY,CAAC,CAAC;EAChC,IAAIC,YAAwC;EAC5C,IAAIC,cAAkC;EACtC,IAAI;IACF,MAAMC,KAAK,GAAGC,UAAU,CAACC,WAAW;IACpC,IAAI,QAAOF,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEG,GAAG,MAAK,UAAU,EAAE;MACpCL,YAAY,GAAGA,CAAA,KAAME,KAAK,CAACG,GAAG,CAAC,CAAC;MAChCJ,cAAc,GAAGD,YAAY,CAAC,CAAC;IACjC;EACF,CAAC,CAAC,MAAM;IACN;EAAA;EAGF,OAAO,MAAM;IACX,IAAIM,UAA8B;IAClC,IAAI;MACF,IAAIN,YAAY,IAAIO,MAAM,CAACC,QAAQ,CAACP,cAAc,CAAC,EAAE;QACnD,MAAMQ,OAAO,GAAGT,YAAY,CAAC,CAAC,GAAIC,cAAyB;QAC3D,IAAIM,MAAM,CAACC,QAAQ,CAACC,OAAO,CAAC,IAAIA,OAAO,IAAI,CAAC,EAAE;UAC5CH,UAAU,GAAGG,OAAO;QACtB;MACF;IACF,CAAC,CAAC,MAAM;MACN;IAAA;IAEF,IAAIH,UAAU,KAAKI,SAAS,IAAIZ,SAAS,KAAKY,SAAS,EAAE;MACvD,MAAMC,OAAO,GAAGZ,YAAY,CAAC,CAAC;MAC9B,IAAIY,OAAO,KAAKD,SAAS,IAAIC,OAAO,IAAIb,SAAS,EAAE;QACjDQ,UAAU,GAAGK,OAAO,GAAGb,SAAS;MAClC;IACF;IACA,IAAIQ,UAAU,KAAKI,SAAS,EAAE;MAC5B,OAAOA,SAAS;IAClB;IACA;IACA,MAAME,UAAU,GAAGC,IAAI,CAACC,KAAK,CAACR,UAAU,GAAG,GAAG,CAAC;IAC/C,IAAI,CAACC,MAAM,CAACQ,aAAa,CAACH,UAAU,CAAC,EAAE,OAAOF,SAAS;IACvD,MAAMM,OAA+B,GAAG;MAAEC,QAAQ,EAAEL;IAAW,CAAC;IAChE,IACEd,SAAS,KAAKY,SAAS,IACvBH,MAAM,CAACQ,aAAa,CAACjB,SAAS,CAAC,IAC/BA,SAAS,GAAG,CAAC,EACb;MACA;MACA;MACA,MAAMoB,KAAK,GAAGpB,SAAS,GAAGe,IAAI,CAACM,KAAK,CAACP,UAAU,GAAG,GAAG,CAAC;MACtD,MAAMQ,KAAK,GAAG,GAAGtB,SAAS,QAAQ;MAClC,MAAMuB,GAAG,GAAG,GAAGH,KAAK,GAAGI,MAAM,CAACV,UAAU,GAAG,GAAG,CAAC,CAACW,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;MAClE,IAAIhB,MAAM,CAACQ,aAAa,CAACG,KAAK,CAAC,IAAIM,SAAS,CAACJ,KAAK,CAAC,IAAII,SAAS,CAACH,GAAG,CAAC,EAAE;QACrEL,OAAO,CAACS,wBAAwB,GAAGL,KAAK;QACxCJ,OAAO,CAACU,sBAAsB,GAAGL,GAAG;MACtC;IACF;IACA,OAAOL,OAAO;EAChB,CAAC;AACH;AAEA,SAASQ,SAASA,CAACG,KAAa,EAAW;EACzC,OACEA,KAAK,CAACC,MAAM,GAAG,EAAE,IAAKD,KAAK,CAACC,MAAM,KAAK,EAAE,IAAID,KAAK,IAAI,qBAAsB;AAEhF;AAEA,SAAS5B,YAAYA,CAAA,EAAuB;EAC1C,IAAI;IACF,MAAM8B,IAAI,GAAGC,IAAI,CAACzB,GAAG,CAAC,CAAC;IACvB,OAAOE,MAAM,CAACC,QAAQ,CAACqB,IAAI,CAAC,GAAGA,IAAI,GAAGnB,SAAS;EACjD,CAAC,CAAC,MAAM;IACN,OAAOA,SAAS;EAClB;AACF","ignoreList":[]}
|