@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.
Files changed (153) hide show
  1. package/FTMobileReactNativeSDK.podspec +7 -5
  2. package/android/build.gradle +10 -3
  3. package/android/src/main/java/com/ft/sdk/reactnative/FTLogImpl.java +10 -2
  4. package/android/src/main/java/com/ft/sdk/reactnative/FTMobileImpl.java +45 -10
  5. package/android/src/main/java/com/ft/sdk/reactnative/FTRUMImpl.java +131 -6
  6. package/android/src/main/java/com/ft/sdk/reactnative/FTTraceImpl.java +10 -3
  7. package/android/src/main/java/com/ft/sdk/reactnative/JsLongTaskMonitor.java +281 -0
  8. package/android/src/main/java/com/ft/sdk/reactnative/ViewTiming.java +17 -0
  9. package/android/src/main/java/com/ft/sdk/reactnative/VisitorIdConfigMapper.java +50 -0
  10. package/android/src/main/java/com/ft/sdk/reactnative/utils/ReactNativeUtils.java +5 -12
  11. package/android/src/newarch/java/com/ft/sdk/reactnative/FTMobileModule.java +14 -5
  12. package/android/src/newarch/java/com/ft/sdk/reactnative/FTRUMModule.java +44 -1
  13. package/android/src/newarch/java/com/ft/sdk/reactnative/FTTraceModule.java +14 -0
  14. package/android/src/oldarch/java/com/ft/sdk/reactnative/FTMobileModule.java +7 -2
  15. package/android/src/oldarch/java/com/ft/sdk/reactnative/FTRUMModule.java +39 -1
  16. package/android/src/oldarch/java/com/ft/sdk/reactnative/FTTraceModule.java +12 -0
  17. package/android/src/rnpost70/java/com/ft/sdk/reactnative/ReactJsThreadExecutor.java +21 -0
  18. package/android/src/rnpre70/java/com/ft/sdk/reactnative/ReactJsThreadExecutor.java +37 -0
  19. package/android/src/test/java/com/ft/sdk/reactnative/FTMobileImplTest.java +53 -0
  20. package/android/src/test/java/com/ft/sdk/reactnative/FTRUMModuleTest.java +117 -0
  21. package/android/src/test/java/com/ft/sdk/reactnative/JsLongTaskMonitorTest.java +446 -0
  22. package/android/src/test/java/com/ft/sdk/reactnative/utils/ReactNativeUtilsTest.java +33 -0
  23. package/ios/FTJSLongTaskMonitor.h +51 -0
  24. package/ios/FTJSLongTaskMonitor.m +250 -0
  25. package/ios/FTMobileReactNative.mm +54 -18
  26. package/ios/FTReactNativeLog.mm +9 -5
  27. package/ios/FTReactNativeRUM.mm +196 -31
  28. package/ios/FTReactNativeResource.h +4 -0
  29. package/ios/FTReactNativeResource.m +64 -0
  30. package/ios/FTReactNativeTrace.mm +59 -14
  31. package/ios/FTReactNativeUtils.m +10 -15
  32. package/ios/FTReactNativeViewTiming.h +18 -0
  33. package/ios/FTReactNativeWebSocket.h +10 -0
  34. package/ios/FTReactNativeWebSocket.mm +201 -0
  35. package/ios/FTWebSocketMetadataStore.h +25 -0
  36. package/ios/FTWebSocketMetadataStore.m +622 -0
  37. package/ios/FTWebSocketResourceData.h +20 -0
  38. package/ios/FTWebSocketResourceData.m +106 -0
  39. package/lib/commonjs/ft_logger.js +3 -1
  40. package/lib/commonjs/ft_logger.js.map +1 -1
  41. package/lib/commonjs/ft_mobile_agent.js +47 -4
  42. package/lib/commonjs/ft_mobile_agent.js.map +1 -1
  43. package/lib/commonjs/ft_rum.js +65 -5
  44. package/lib/commonjs/ft_rum.js.map +1 -1
  45. package/lib/commonjs/ft_tracing.js +14 -4
  46. package/lib/commonjs/ft_tracing.js.map +1 -1
  47. package/lib/commonjs/index.js +21 -0
  48. package/lib/commonjs/index.js.map +1 -1
  49. package/lib/commonjs/rum/FTBabelInteractionTracking.js +72 -0
  50. package/lib/commonjs/rum/FTBabelInteractionTracking.js.map +1 -0
  51. package/lib/commonjs/rum/FTBabelUtils.js +87 -0
  52. package/lib/commonjs/rum/FTBabelUtils.js.map +1 -0
  53. package/lib/commonjs/rum/FTRumActionTracking.js +10 -39
  54. package/lib/commonjs/rum/FTRumActionTracking.js.map +1 -1
  55. package/lib/commonjs/rum/FTRumActionTrackingContext.js +50 -0
  56. package/lib/commonjs/rum/FTRumActionTrackingContext.js.map +1 -0
  57. package/lib/commonjs/rum/FTRumViewTracking.js +147 -0
  58. package/lib/commonjs/rum/FTRumViewTracking.js.map +1 -0
  59. package/lib/commonjs/rum/FTRumWebSocketNative.js +73 -0
  60. package/lib/commonjs/rum/FTRumWebSocketNative.js.map +1 -0
  61. package/lib/commonjs/rum/FTRumWebSocketTiming.js +73 -0
  62. package/lib/commonjs/rum/FTRumWebSocketTiming.js.map +1 -0
  63. package/lib/commonjs/rum/FTRumWebSocketTracking.js +506 -0
  64. package/lib/commonjs/rum/FTRumWebSocketTracking.js.map +1 -0
  65. package/lib/commonjs/rum/longTasksUtils.js +25 -0
  66. package/lib/commonjs/rum/longTasksUtils.js.map +1 -0
  67. package/lib/commonjs/specs/NativeFTMobileReactNative.js.map +1 -1
  68. package/lib/commonjs/specs/NativeFTReactNativeRUM.js.map +1 -1
  69. package/lib/commonjs/specs/NativeFTReactNativeTrace.js.map +1 -1
  70. package/lib/commonjs/specs/NativeFTReactNativeWebSocket.js +11 -0
  71. package/lib/commonjs/specs/NativeFTReactNativeWebSocket.js.map +1 -0
  72. package/lib/commonjs/version.js +1 -1
  73. package/lib/commonjs/version.js.map +1 -1
  74. package/lib/commonjs/visitorIdConfig.js +37 -0
  75. package/lib/commonjs/visitorIdConfig.js.map +1 -0
  76. package/lib/module/ft_logger.js +3 -1
  77. package/lib/module/ft_logger.js.map +1 -1
  78. package/lib/module/ft_mobile_agent.js +47 -4
  79. package/lib/module/ft_mobile_agent.js.map +1 -1
  80. package/lib/module/ft_rum.js +65 -5
  81. package/lib/module/ft_rum.js.map +1 -1
  82. package/lib/module/ft_tracing.js +14 -2
  83. package/lib/module/ft_tracing.js.map +1 -1
  84. package/lib/module/index.js +4 -1
  85. package/lib/module/index.js.map +1 -1
  86. package/lib/module/rum/FTBabelInteractionTracking.js +66 -0
  87. package/lib/module/rum/FTBabelInteractionTracking.js.map +1 -0
  88. package/lib/module/rum/FTBabelUtils.js +80 -0
  89. package/lib/module/rum/FTBabelUtils.js.map +1 -0
  90. package/lib/module/rum/FTRumActionTracking.js +10 -39
  91. package/lib/module/rum/FTRumActionTracking.js.map +1 -1
  92. package/lib/module/rum/FTRumActionTrackingContext.js +43 -0
  93. package/lib/module/rum/FTRumActionTrackingContext.js.map +1 -0
  94. package/lib/module/rum/FTRumViewTracking.js +140 -0
  95. package/lib/module/rum/FTRumViewTracking.js.map +1 -0
  96. package/lib/module/rum/FTRumWebSocketNative.js +62 -0
  97. package/lib/module/rum/FTRumWebSocketNative.js.map +1 -0
  98. package/lib/module/rum/FTRumWebSocketTiming.js +67 -0
  99. package/lib/module/rum/FTRumWebSocketTiming.js.map +1 -0
  100. package/lib/module/rum/FTRumWebSocketTracking.js +499 -0
  101. package/lib/module/rum/FTRumWebSocketTracking.js.map +1 -0
  102. package/lib/module/rum/longTasksUtils.js +18 -0
  103. package/lib/module/rum/longTasksUtils.js.map +1 -0
  104. package/lib/module/specs/NativeFTMobileReactNative.js.map +1 -1
  105. package/lib/module/specs/NativeFTReactNativeRUM.js.map +1 -1
  106. package/lib/module/specs/NativeFTReactNativeTrace.js.map +1 -1
  107. package/lib/module/specs/NativeFTReactNativeWebSocket.js +8 -0
  108. package/lib/module/specs/NativeFTReactNativeWebSocket.js.map +1 -0
  109. package/lib/module/version.js +1 -1
  110. package/lib/module/version.js.map +1 -1
  111. package/lib/module/visitorIdConfig.js +31 -0
  112. package/lib/module/visitorIdConfig.js.map +1 -0
  113. package/lib/typescript/ft_logger.d.ts +11 -1
  114. package/lib/typescript/ft_mobile_agent.d.ts +28 -0
  115. package/lib/typescript/ft_rum.d.ts +42 -5
  116. package/lib/typescript/ft_tracing.d.ts +9 -1
  117. package/lib/typescript/index.d.ts +5 -1
  118. package/lib/typescript/rum/FTBabelInteractionTracking.d.ts +30 -0
  119. package/lib/typescript/rum/FTBabelUtils.d.ts +1 -0
  120. package/lib/typescript/rum/FTRumActionTracking.d.ts +0 -2
  121. package/lib/typescript/rum/FTRumActionTrackingContext.d.ts +11 -0
  122. package/lib/typescript/rum/FTRumViewTracking.d.ts +32 -0
  123. package/lib/typescript/rum/FTRumWebSocketNative.d.ts +22 -0
  124. package/lib/typescript/rum/FTRumWebSocketTiming.d.ts +7 -0
  125. package/lib/typescript/rum/FTRumWebSocketTracking.d.ts +54 -0
  126. package/lib/typescript/rum/longTasksUtils.d.ts +8 -0
  127. package/lib/typescript/specs/NativeFTMobileReactNative.d.ts +15 -0
  128. package/lib/typescript/specs/NativeFTReactNativeRUM.d.ts +11 -1
  129. package/lib/typescript/specs/NativeFTReactNativeTrace.d.ts +12 -0
  130. package/lib/typescript/specs/NativeFTReactNativeWebSocket.d.ts +13 -0
  131. package/lib/typescript/version.d.ts +1 -1
  132. package/lib/typescript/visitorIdConfig.d.ts +11 -0
  133. package/package.json +6 -4
  134. package/src/ft_logger.tsx +11 -1
  135. package/src/ft_mobile_agent.tsx +79 -7
  136. package/src/ft_rum.tsx +111 -7
  137. package/src/ft_tracing.tsx +24 -2
  138. package/src/index.tsx +8 -0
  139. package/src/rum/FTBabelInteractionTracking.ts +124 -0
  140. package/src/rum/FTBabelUtils.tsx +99 -0
  141. package/src/rum/FTRumActionTracking.tsx +14 -43
  142. package/src/rum/FTRumActionTrackingContext.ts +68 -0
  143. package/src/rum/FTRumViewTracking.ts +179 -0
  144. package/src/rum/FTRumWebSocketNative.ts +107 -0
  145. package/src/rum/FTRumWebSocketTiming.ts +82 -0
  146. package/src/rum/FTRumWebSocketTracking.ts +722 -0
  147. package/src/rum/longTasksUtils.ts +17 -0
  148. package/src/specs/NativeFTMobileReactNative.ts +18 -0
  149. package/src/specs/NativeFTReactNativeRUM.ts +19 -1
  150. package/src/specs/NativeFTReactNativeTrace.ts +12 -0
  151. package/src/specs/NativeFTReactNativeWebSocket.ts +33 -0
  152. package/src/version.ts +1 -1
  153. package/src/visitorIdConfig.ts +123 -0
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.resolveActionTrackingContext = resolveActionTrackingContext;
7
+ exports.resolveActionTrackingContextFromTarget = resolveActionTrackingContextFromTarget;
8
+ const FT_ENABLE_TRACK = 'ft-enable-track';
9
+ const FT_EXTRA_PROPERTY = 'ft-extra-property';
10
+ function findFiberTarget(handlerArgs) {
11
+ for (const handlerArg of handlerArgs) {
12
+ if (handlerArg && typeof handlerArg === 'object' && '_targetInst' in handlerArg) {
13
+ return handlerArg._targetInst || null;
14
+ }
15
+ }
16
+ return null;
17
+ }
18
+ function findFiberProperty(targetNode, propertyName) {
19
+ let currentNode = targetNode;
20
+ while (currentNode) {
21
+ const props = currentNode.memoizedProps;
22
+ if (props && props[propertyName]) {
23
+ return props[propertyName];
24
+ }
25
+ currentNode = currentNode.return || null;
26
+ }
27
+ return undefined;
28
+ }
29
+ function resolveActionTrackingContextFromTarget(targetNode) {
30
+ const enableTrack = findFiberProperty(targetNode, FT_ENABLE_TRACK);
31
+ const extraProperty = findFiberProperty(targetNode, FT_EXTRA_PROPERTY);
32
+ const context = {
33
+ enabled: enableTrack === undefined || enableTrack === 'true'
34
+ };
35
+ if (extraProperty !== undefined) {
36
+ try {
37
+ const parsedProperty = JSON.parse(String(extraProperty));
38
+ if (parsedProperty && typeof parsedProperty === 'object') {
39
+ context.property = parsedProperty;
40
+ }
41
+ } catch (error) {
42
+ console.warn(`Error parsing JSON string ${extraProperty}:`, error);
43
+ }
44
+ }
45
+ return context;
46
+ }
47
+ function resolveActionTrackingContext(handlerArgs) {
48
+ return resolveActionTrackingContextFromTarget(findFiberTarget(handlerArgs));
49
+ }
50
+ //# sourceMappingURL=FTRumActionTrackingContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["FT_ENABLE_TRACK","FT_EXTRA_PROPERTY","findFiberTarget","handlerArgs","handlerArg","_targetInst","findFiberProperty","targetNode","propertyName","currentNode","props","memoizedProps","return","undefined","resolveActionTrackingContextFromTarget","enableTrack","extraProperty","context","enabled","parsedProperty","JSON","parse","String","property","error","console","warn","resolveActionTrackingContext"],"sources":["FTRumActionTrackingContext.ts"],"sourcesContent":["const FT_ENABLE_TRACK = 'ft-enable-track';\nconst FT_EXTRA_PROPERTY = 'ft-extra-property';\n\nexport type FTRumActionTrackingContext = {\n enabled: boolean;\n property?: object;\n};\n\ntype FiberNode = {\n memoizedProps?: Record<string, unknown>;\n return?: FiberNode | null;\n};\n\nfunction findFiberTarget(handlerArgs: unknown[]): FiberNode | null {\n for (const handlerArg of handlerArgs) {\n if (\n handlerArg &&\n typeof handlerArg === 'object' &&\n '_targetInst' in handlerArg\n ) {\n return (handlerArg as { _targetInst?: FiberNode })._targetInst || null;\n }\n }\n return null;\n}\n\nfunction findFiberProperty(\n targetNode: FiberNode | null,\n propertyName: string\n): unknown {\n let currentNode = targetNode;\n while (currentNode) {\n const props = currentNode.memoizedProps;\n if (props && props[propertyName]) {\n return props[propertyName];\n }\n currentNode = currentNode.return || null;\n }\n return undefined;\n}\n\nexport function resolveActionTrackingContextFromTarget(\n targetNode: FiberNode | null\n): FTRumActionTrackingContext {\n const enableTrack = findFiberProperty(targetNode, FT_ENABLE_TRACK);\n const extraProperty = findFiberProperty(targetNode, FT_EXTRA_PROPERTY);\n const context: FTRumActionTrackingContext = {\n enabled: enableTrack === undefined || enableTrack === 'true',\n };\n\n if (extraProperty !== undefined) {\n try {\n const parsedProperty = JSON.parse(String(extraProperty));\n if (parsedProperty && typeof parsedProperty === 'object') {\n context.property = parsedProperty as object;\n }\n } catch (error) {\n console.warn(`Error parsing JSON string ${extraProperty}:`, error);\n }\n }\n return context;\n}\n\nexport function resolveActionTrackingContext(\n handlerArgs: unknown[]\n): FTRumActionTrackingContext {\n return resolveActionTrackingContextFromTarget(findFiberTarget(handlerArgs));\n}\n"],"mappings":";;;;;;;AAAA,MAAMA,eAAe,GAAG,iBAAiB;AACzC,MAAMC,iBAAiB,GAAG,mBAAmB;AAY7C,SAASC,eAAeA,CAACC,WAAsB,EAAoB;EACjE,KAAK,MAAMC,UAAU,IAAID,WAAW,EAAE;IACpC,IACEC,UAAU,IACV,OAAOA,UAAU,KAAK,QAAQ,IAC9B,aAAa,IAAIA,UAAU,EAC3B;MACA,OAAQA,UAAU,CAAiCC,WAAW,IAAI,IAAI;IACxE;EACF;EACA,OAAO,IAAI;AACb;AAEA,SAASC,iBAAiBA,CACxBC,UAA4B,EAC5BC,YAAoB,EACX;EACT,IAAIC,WAAW,GAAGF,UAAU;EAC5B,OAAOE,WAAW,EAAE;IAClB,MAAMC,KAAK,GAAGD,WAAW,CAACE,aAAa;IACvC,IAAID,KAAK,IAAIA,KAAK,CAACF,YAAY,CAAC,EAAE;MAChC,OAAOE,KAAK,CAACF,YAAY,CAAC;IAC5B;IACAC,WAAW,GAAGA,WAAW,CAACG,MAAM,IAAI,IAAI;EAC1C;EACA,OAAOC,SAAS;AAClB;AAEO,SAASC,sCAAsCA,CACpDP,UAA4B,EACA;EAC5B,MAAMQ,WAAW,GAAGT,iBAAiB,CAACC,UAAU,EAAEP,eAAe,CAAC;EAClE,MAAMgB,aAAa,GAAGV,iBAAiB,CAACC,UAAU,EAAEN,iBAAiB,CAAC;EACtE,MAAMgB,OAAmC,GAAG;IAC1CC,OAAO,EAAEH,WAAW,KAAKF,SAAS,IAAIE,WAAW,KAAK;EACxD,CAAC;EAED,IAAIC,aAAa,KAAKH,SAAS,EAAE;IAC/B,IAAI;MACF,MAAMM,cAAc,GAAGC,IAAI,CAACC,KAAK,CAACC,MAAM,CAACN,aAAa,CAAC,CAAC;MACxD,IAAIG,cAAc,IAAI,OAAOA,cAAc,KAAK,QAAQ,EAAE;QACxDF,OAAO,CAACM,QAAQ,GAAGJ,cAAwB;MAC7C;IACF,CAAC,CAAC,OAAOK,KAAK,EAAE;MACdC,OAAO,CAACC,IAAI,CAAC,6BAA6BV,aAAa,GAAG,EAAEQ,KAAK,CAAC;IACpE;EACF;EACA,OAAOP,OAAO;AAChB;AAEO,SAASU,4BAA4BA,CAC1CxB,WAAsB,EACM;EAC5B,OAAOW,sCAAsC,CAACZ,eAAe,CAACC,WAAW,CAAC,CAAC;AAC7E","ignoreList":[]}
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.FTRumViewTracking = void 0;
7
+ var _reactNative = require("react-native");
8
+ var _ft_rum = require("../ft_rum");
9
+ var _ft_mobile_agent = require("../ft_mobile_agent");
10
+ 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; }
11
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
12
+ 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); }
13
+ const MAX_PENDING_LOAD_MS = 15 * 60 * 1000;
14
+
15
+ /** Shared lifecycle coordinator for navigation adapters. Use one per navigator. */
16
+ class FTRumViewTracking {
17
+ constructor(onBackground) {
18
+ this.onBackground = onBackground;
19
+ _defineProperty(this, "current", void 0);
20
+ _defineProperty(this, "active", void 0);
21
+ _defineProperty(this, "generation", 0);
22
+ _defineProperty(this, "lifecycle", 0);
23
+ _defineProperty(this, "state", null);
24
+ _defineProperty(this, "subscription", void 0);
25
+ _defineProperty(this, "loading", new Map());
26
+ _defineProperty(this, "onAppState", state => {
27
+ if (state === this.state) return;
28
+ this.state = state;
29
+ if (state === 'background') {
30
+ var _this$onBackground;
31
+ // Native closes Automatic Views at its own history boundary. No JS stop.
32
+ this.active = undefined;
33
+ this.loading.clear();
34
+ (_this$onBackground = this.onBackground) === null || _this$onBackground === void 0 || _this$onBackground.call(this);
35
+ } else if (state === 'active' && this.current) {
36
+ this.show(this.current);
37
+ }
38
+ });
39
+ }
40
+ start() {
41
+ if (this.subscription) return;
42
+ this.state = _reactNative.AppState.currentState;
43
+ const lifecycle = ++this.lifecycle;
44
+ const listener = state => {
45
+ if (lifecycle === this.lifecycle) this.onAppState(state);
46
+ };
47
+ const subscription = _reactNative.AppState.addEventListener('change', listener);
48
+ // RN < 0.65 uses removeEventListener instead of returning a subscription.
49
+ const legacyAppState = _reactNative.AppState;
50
+ this.subscription = subscription || {
51
+ remove: () => {
52
+ var _legacyAppState$remov;
53
+ return (_legacyAppState$remov = legacyAppState.removeEventListener) === null || _legacyAppState$remov === void 0 ? void 0 : _legacyAppState$remov.call(legacyAppState, 'change', listener);
54
+ }
55
+ };
56
+ }
57
+
58
+ /** Capture both clocks at the loading boundary, before any async work. */
59
+ beginLoad(key) {
60
+ this.start();
61
+ this.pruneLoading();
62
+ if (this.state === 'background' || this.loading.has(key)) return;
63
+ if (typeof performance === 'undefined' || typeof performance.now !== 'function') return;
64
+ // Only the latest transition can supply loading for this navigator.
65
+ this.loading.clear();
66
+ this.loading.set(key, {
67
+ monotonicMs: performance.now(),
68
+ epochMs: Date.now()
69
+ });
70
+ }
71
+
72
+ /** Remember a transitioning route so foreground recovery uses the current page. */
73
+ setCurrent(route) {
74
+ this.start();
75
+ this.current = {
76
+ key: route.key,
77
+ name: route.name
78
+ };
79
+ }
80
+ show(route, loadingKey = route.key) {
81
+ var _this$active;
82
+ this.setCurrent(route);
83
+ this.pruneLoading();
84
+ const loading = this.loading.get(loadingKey);
85
+ this.loading.clear();
86
+ if (this.state !== 'active') return undefined;
87
+ if (((_this$active = this.active) === null || _this$active === void 0 ? void 0 : _this$active.key) === route.key) return this.active.generation;
88
+ this.active = {
89
+ key: route.key,
90
+ generation: ++this.generation
91
+ };
92
+ if (loading) {
93
+ const durationNs = Math.floor((performance.now() - loading.monotonicMs) * 1000000);
94
+ if (Number.isFinite(durationNs) && durationNs > 0) {
95
+ this.report(this.nativeRUM.onCreateViewWithLoadStart(route.name, durationNs, Number.isFinite(loading.epochMs) ? loading.epochMs : 0));
96
+ }
97
+ }
98
+ // Enqueue these calls together. Waiting for a Promise here could start a stale
99
+ // page after background/route changes; native consumes loading before start.
100
+ this.report(this.nativeRUM.startViewWithTrackingType(route.name, _ft_mobile_agent.bridgeContextManager.mergeWithLocalPropertiesSync(), 1 // Automatic is an internal framework bridge detail.
101
+ ));
102
+ return this.active.generation;
103
+ }
104
+
105
+ /** Apply a completed interval only to the appearance that started it. */
106
+ updateLoadingTime(key, generation, durationNs) {
107
+ if (this.state !== 'active' || !this.active || this.active.key !== key || this.active.generation !== generation || !Number.isSafeInteger(durationNs) || durationNs <= 0) return;
108
+ // Enqueue immediately; never let a Promise continuation update another View.
109
+ this.report(_ft_rum.FTReactNativeRUM.updateViewLoadingTime(durationNs));
110
+ }
111
+
112
+ /** Only the appearance that owns the active generation may close it. */
113
+ hide(key, generation) {
114
+ if (this.state !== 'active') return;
115
+ if (!this.active || this.active.key !== key || this.active.generation !== generation) return;
116
+ this.active = undefined;
117
+ this.current = undefined;
118
+ this.report(_ft_rum.FTReactNativeRUM.stopView());
119
+ }
120
+ stop() {
121
+ var _this$subscription;
122
+ ++this.lifecycle;
123
+ (_this$subscription = this.subscription) === null || _this$subscription === void 0 || _this$subscription.remove();
124
+ this.subscription = undefined;
125
+ if (this.active && this.state === 'active') this.report(_ft_rum.FTReactNativeRUM.stopView());
126
+ this.active = undefined;
127
+ this.current = undefined;
128
+ this.loading.clear();
129
+ // Never reuse generation values: callbacks from a previous subscription can arrive late.
130
+ }
131
+ pruneLoading() {
132
+ const now = typeof performance !== 'undefined' && typeof performance.now === 'function' ? performance.now() : NaN;
133
+ for (const [key, load] of this.loading) {
134
+ const age = now - load.monotonicMs;
135
+ if (!Number.isFinite(age) || age < 0 || age >= MAX_PENDING_LOAD_MS) this.loading.delete(key);
136
+ }
137
+ }
138
+ get nativeRUM() {
139
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
140
+ return require('../specs/NativeFTReactNativeRUM').default;
141
+ }
142
+ report(result) {
143
+ result.catch(error => console.warn('[TrueWatch] Automatic View tracking failed', error));
144
+ }
145
+ }
146
+ exports.FTRumViewTracking = FTRumViewTracking;
147
+ //# sourceMappingURL=FTRumViewTracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","_ft_rum","_ft_mobile_agent","_defineProperty","e","r","t","_toPropertyKey","Object","defineProperty","value","enumerable","configurable","writable","i","_toPrimitive","Symbol","toPrimitive","call","TypeError","String","Number","MAX_PENDING_LOAD_MS","FTRumViewTracking","constructor","onBackground","Map","state","_this$onBackground","active","undefined","loading","clear","current","show","start","subscription","AppState","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","isFinite","report","nativeRUM","onCreateViewWithLoadStart","startViewWithTrackingType","bridgeContextManager","mergeWithLocalPropertiesSync","updateLoadingTime","isSafeInteger","FTReactNativeRUM","updateViewLoadingTime","hide","stopView","stop","_this$subscription","NaN","load","age","delete","default","result","catch","error","console","warn","exports"],"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,73 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.NativeWebSocketSession = void 0;
7
+ exports.clearNativeWebSocketSessions = clearNativeWebSocketSessions;
8
+ exports.startNativeWebSocketSession = startNativeWebSocketSession;
9
+ exports.webSocketNativeID = webSocketNativeID;
10
+ var _NativeFTReactNativeWebSocket = _interopRequireDefault(require("../specs/NativeFTReactNativeWebSocket"));
11
+ var _ft_mobile_agent = require("../ft_mobile_agent");
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ 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; }
14
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
15
+ 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); }
16
+ function ignoreBridgeFailure(call) {
17
+ try {
18
+ void Promise.resolve(call()).catch(() => {});
19
+ } catch {
20
+ /* Setup/cleanup replies must not interrupt JS capture. */
21
+ }
22
+ }
23
+ class NativeWebSocketSession {
24
+ constructor(session) {
25
+ this.session = session;
26
+ _defineProperty(this, "stopped", false);
27
+ _defineProperty(this, "sequence", 0);
28
+ // Enqueue setup before start/stop/add on the same native module queue.
29
+ // Its reply never gates JS capture or selects a different reporting route.
30
+ ignoreBridgeFailure(() => _NativeFTReactNativeWebSocket.default.startCapture(session));
31
+ }
32
+ startResource(key, socketID, url) {
33
+ const property = _ft_mobile_agent.bridgeContextManager.mergeWithLocalPropertiesSync();
34
+ return _NativeFTReactNativeWebSocket.default.startResource(key, socketID !== null && socketID !== void 0 ? socketID : -1, url, this.session, ++this.sequence, property);
35
+ }
36
+ stopResource(key, event) {
37
+ const property = _ft_mobile_agent.bridgeContextManager.mergeWithLocalPropertiesSync();
38
+ return _NativeFTReactNativeWebSocket.default.stopResource(key, event, this.session, property);
39
+ }
40
+ addResource(key, content, metrics) {
41
+ return _NativeFTReactNativeWebSocket.default.addResource(key, content, metrics, this.session);
42
+ }
43
+ release(key) {
44
+ ignoreBridgeFailure(() => _NativeFTReactNativeWebSocket.default === null || _NativeFTReactNativeWebSocket.default === void 0 ? void 0 : _NativeFTReactNativeWebSocket.default.releaseResource(key, this.session));
45
+ }
46
+ stop() {
47
+ if (this.stopped) return;
48
+ this.stopped = true;
49
+ // Existing handshakes still finish through their originally selected route.
50
+ ignoreBridgeFailure(() => _NativeFTReactNativeWebSocket.default === null || _NativeFTReactNativeWebSocket.default === void 0 ? void 0 : _NativeFTReactNativeWebSocket.default.stopCapture(this.session));
51
+ }
52
+ }
53
+ exports.NativeWebSocketSession = NativeWebSocketSession;
54
+ function startNativeWebSocketSession(createKey) {
55
+ try {
56
+ if (typeof (_NativeFTReactNativeWebSocket.default === null || _NativeFTReactNativeWebSocket.default === void 0 ? void 0 : _NativeFTReactNativeWebSocket.default.startCapture) === 'function' && typeof _NativeFTReactNativeWebSocket.default.stopCapture === 'function' && typeof _NativeFTReactNativeWebSocket.default.clear === 'function' && typeof _NativeFTReactNativeWebSocket.default.startResource === 'function' && typeof _NativeFTReactNativeWebSocket.default.stopResource === 'function' && typeof _NativeFTReactNativeWebSocket.default.addResource === 'function' && typeof _NativeFTReactNativeWebSocket.default.releaseResource === 'function') return new NativeWebSocketSession(createKey());
57
+ } catch {
58
+ /* Old native binaries keep the JS fallback. */
59
+ }
60
+ return undefined;
61
+ }
62
+ function clearNativeWebSocketSessions() {
63
+ ignoreBridgeFailure(() => _NativeFTReactNativeWebSocket.default === null || _NativeFTReactNativeWebSocket.default === void 0 ? void 0 : _NativeFTReactNativeWebSocket.default.clear());
64
+ }
65
+ function webSocketNativeID(socket) {
66
+ try {
67
+ const id = socket === null || socket === void 0 ? void 0 : socket._socketId;
68
+ return typeof id === 'number' && Number.isSafeInteger(id) && id >= 0 ? id : undefined;
69
+ } catch {
70
+ return undefined;
71
+ }
72
+ }
73
+ //# sourceMappingURL=FTRumWebSocketNative.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_NativeFTReactNativeWebSocket","_interopRequireDefault","require","_ft_mobile_agent","e","__esModule","default","_defineProperty","r","t","_toPropertyKey","Object","defineProperty","value","enumerable","configurable","writable","i","_toPrimitive","Symbol","toPrimitive","call","TypeError","String","Number","ignoreBridgeFailure","Promise","resolve","catch","NativeWebSocketSession","constructor","session","NativeWebSocket","startCapture","startResource","key","socketID","url","property","bridgeContextManager","mergeWithLocalPropertiesSync","sequence","stopResource","event","addResource","content","metrics","release","releaseResource","stop","stopped","stopCapture","exports","startNativeWebSocketSession","createKey","clear","undefined","clearNativeWebSocketSessions","webSocketNativeID","socket","id","_socketId","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":";;;;;;;;;AAAA,IAAAA,6BAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,gBAAA,GAAAD,OAAA;AAA0D,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAAA,SAAAG,gBAAAH,CAAA,EAAAI,CAAA,EAAAC,CAAA,YAAAD,CAAA,GAAAE,cAAA,CAAAF,CAAA,MAAAJ,CAAA,GAAAO,MAAA,CAAAC,cAAA,CAAAR,CAAA,EAAAI,CAAA,IAAAK,KAAA,EAAAJ,CAAA,EAAAK,UAAA,MAAAC,YAAA,MAAAC,QAAA,UAAAZ,CAAA,CAAAI,CAAA,IAAAC,CAAA,EAAAL,CAAA;AAAA,SAAAM,eAAAD,CAAA,QAAAQ,CAAA,GAAAC,YAAA,CAAAT,CAAA,uCAAAQ,CAAA,GAAAA,CAAA,GAAAA,CAAA;AAAA,SAAAC,aAAAT,CAAA,EAAAD,CAAA,2BAAAC,CAAA,KAAAA,CAAA,SAAAA,CAAA,MAAAL,CAAA,GAAAK,CAAA,CAAAU,MAAA,CAAAC,WAAA,kBAAAhB,CAAA,QAAAa,CAAA,GAAAb,CAAA,CAAAiB,IAAA,CAAAZ,CAAA,EAAAD,CAAA,uCAAAS,CAAA,SAAAA,CAAA,YAAAK,SAAA,yEAAAd,CAAA,GAAAe,MAAA,GAAAC,MAAA,EAAAf,CAAA;AAW1D,SAASgB,mBAAmBA,CAACJ,IAAmB,EAAQ;EACtD,IAAI;IACF,KAAKK,OAAO,CAACC,OAAO,CAACN,IAAI,CAAC,CAAC,CAAC,CAACO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;EAC9C,CAAC,CAAC,MAAM;IACN;EAAA;AAEJ;AAEO,MAAMC,sBAAsB,CAAC;EAIlCC,WAAWA,CAAkBC,OAAe,EAAE;IAAA,KAAjBA,OAAe,GAAfA,OAAe;IAAAxB,eAAA,kBAH1B,KAAK;IAAAA,eAAA,mBACJ,CAAC;IAGlB;IACA;IACAkB,mBAAmB,CAAC,MAAMO,qCAAe,CAAEC,YAAY,CAACF,OAAO,CAAC,CAAC;EACnE;EAEAG,aAAaA,CACXC,GAAW,EACXC,QAA4B,EAC5BC,GAAW,EACI;IACf,MAAMC,QAAQ,GAAGC,qCAAoB,CAACC,4BAA4B,CAAC,CAAC;IACpE,OAAOR,qCAAe,CAAEE,aAAa,CACnCC,GAAG,EACHC,QAAQ,aAARA,QAAQ,cAARA,QAAQ,GAAI,CAAC,CAAC,EACdC,GAAG,EACH,IAAI,CAACN,OAAO,EACZ,EAAE,IAAI,CAACU,QAAQ,EACfH,QACF,CAAC;EACH;EAEAI,YAAYA,CAACP,GAAW,EAAEQ,KAAa,EAAiB;IACtD,MAAML,QAAQ,GAAGC,qCAAoB,CAACC,4BAA4B,CAAC,CAAC;IACpE,OAAOR,qCAAe,CAAEU,YAAY,CAACP,GAAG,EAAEQ,KAAK,EAAE,IAAI,CAACZ,OAAO,EAAEO,QAAQ,CAAC;EAC1E;EAEAM,WAAWA,CACTT,GAAW,EACXU,OAAgC,EAChCC,OAAwC,EACzB;IACf,OAAOd,qCAAe,CAAEY,WAAW,CAACT,GAAG,EAAEU,OAAO,EAAEC,OAAO,EAAE,IAAI,CAACf,OAAO,CAAC;EAC1E;EAEAgB,OAAOA,CAACZ,GAAW,EAAQ;IACzBV,mBAAmB,CAAC,MAClBO,qCAAe,aAAfA,qCAAe,uBAAfA,qCAAe,CAAEgB,eAAe,CAACb,GAAG,EAAE,IAAI,CAACJ,OAAO,CACpD,CAAC;EACH;EAEAkB,IAAIA,CAAA,EAAS;IACX,IAAI,IAAI,CAACC,OAAO,EAAE;IAClB,IAAI,CAACA,OAAO,GAAG,IAAI;IACnB;IACAzB,mBAAmB,CAAC,MAAMO,qCAAe,aAAfA,qCAAe,uBAAfA,qCAAe,CAAEmB,WAAW,CAAC,IAAI,CAACpB,OAAO,CAAC,CAAC;EACvE;AACF;AAACqB,OAAA,CAAAvB,sBAAA,GAAAA,sBAAA;AAEM,SAASwB,2BAA2BA,CACzCC,SAAuB,EACa;EACpC,IAAI;IACF,IACE,QAAOtB,qCAAe,aAAfA,qCAAe,uBAAfA,qCAAe,CAAEC,YAAY,MAAK,UAAU,IACnD,OAAOD,qCAAe,CAACmB,WAAW,KAAK,UAAU,IACjD,OAAOnB,qCAAe,CAACuB,KAAK,KAAK,UAAU,IAC3C,OAAOvB,qCAAe,CAACE,aAAa,KAAK,UAAU,IACnD,OAAOF,qCAAe,CAACU,YAAY,KAAK,UAAU,IAClD,OAAOV,qCAAe,CAACY,WAAW,KAAK,UAAU,IACjD,OAAOZ,qCAAe,CAACgB,eAAe,KAAK,UAAU,EAErD,OAAO,IAAInB,sBAAsB,CAACyB,SAAS,CAAC,CAAC,CAAC;EAClD,CAAC,CAAC,MAAM;IACN;EAAA;EAEF,OAAOE,SAAS;AAClB;AAEO,SAASC,4BAA4BA,CAAA,EAAS;EACnDhC,mBAAmB,CAAC,MAAMO,qCAAe,aAAfA,qCAAe,uBAAfA,qCAAe,CAAEuB,KAAK,CAAC,CAAC,CAAC;AACrD;AAEO,SAASG,iBAAiBA,CAACC,MAAe,EAAsB;EACrE,IAAI;IACF,MAAMC,EAAE,GAAID,MAAM,aAANA,MAAM,uBAANA,MAAM,CAA8BE,SAAS;IACzD,OAAO,OAAOD,EAAE,KAAK,QAAQ,IAAIpC,MAAM,CAACsC,aAAa,CAACF,EAAE,CAAC,IAAIA,EAAE,IAAI,CAAC,GAChEA,EAAE,GACFJ,SAAS;EACf,CAAC,CAAC,MAAM;IACN,OAAOA,SAAS;EAClB;AACF","ignoreList":[]}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.startWebSocketTiming = startWebSocketTiming;
7
+ /** Measures only the JS-observed opening handshake; bridge delays are excluded. */
8
+ function startWebSocketTiming() {
9
+ const wallStart = readWallTime();
10
+ let monotonicNow;
11
+ let monotonicStart;
12
+ try {
13
+ const clock = globalThis.performance;
14
+ if (typeof (clock === null || clock === void 0 ? void 0 : clock.now) === 'function') {
15
+ monotonicNow = () => clock.now();
16
+ monotonicStart = monotonicNow();
17
+ }
18
+ } catch {
19
+ // Older runtimes and other instrumentation may not provide this clock.
20
+ }
21
+ return () => {
22
+ let durationMs;
23
+ try {
24
+ if (monotonicNow && Number.isFinite(monotonicStart)) {
25
+ const elapsed = monotonicNow() - monotonicStart;
26
+ if (Number.isFinite(elapsed) && elapsed >= 0) {
27
+ durationMs = elapsed;
28
+ }
29
+ }
30
+ } catch {
31
+ // Fall back to wall time if the monotonic clock becomes unavailable.
32
+ }
33
+ if (durationMs === undefined && wallStart !== undefined) {
34
+ const wallEnd = readWallTime();
35
+ if (wallEnd !== undefined && wallEnd >= wallStart) {
36
+ durationMs = wallEnd - wallStart;
37
+ }
38
+ }
39
+ if (durationMs === undefined) {
40
+ return undefined;
41
+ }
42
+ // Resource metrics use nanoseconds. Do not send an invalid bridge number.
43
+ const durationNs = Math.round(durationMs * 1e6);
44
+ if (!Number.isSafeInteger(durationNs)) return undefined;
45
+ const metrics = {
46
+ duration: durationNs
47
+ };
48
+ if (wallStart !== undefined && Number.isSafeInteger(wallStart) && wallStart > 0) {
49
+ // Add the monotonic elapsed interval to the start epoch, not Date.now()
50
+ // at completion. Split milliseconds/remainder to avoid epoch-ns doubles.
51
+ const endMs = wallStart + Math.floor(durationNs / 1e6);
52
+ const start = `${wallStart}000000`;
53
+ const end = `${endMs}${String(durationNs % 1e6).padStart(6, '0')}`;
54
+ if (Number.isSafeInteger(endMs) && fitsInt64(start) && fitsInt64(end)) {
55
+ metrics.fetchStartNsTimeInterval = start;
56
+ metrics.fetchEndNsTimeInterval = end;
57
+ }
58
+ }
59
+ return metrics;
60
+ };
61
+ }
62
+ function fitsInt64(value) {
63
+ return value.length < 19 || value.length === 19 && value <= '9223372036854775807';
64
+ }
65
+ function readWallTime() {
66
+ try {
67
+ const time = Date.now();
68
+ return Number.isFinite(time) ? time : undefined;
69
+ } catch {
70
+ return undefined;
71
+ }
72
+ }
73
+ //# 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;AACO,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":[]}