react-native-nitro-tracing 0.6.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.
Files changed (233) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +21 -0
  3. package/NitroTracing.podspec +32 -0
  4. package/README.md +75 -0
  5. package/android/CMakeLists.txt +49 -0
  6. package/android/build.gradle +133 -0
  7. package/android/fix-prefab.gradle +51 -0
  8. package/android/gradle.properties +5 -0
  9. package/android/proguard-rules.pro +5 -0
  10. package/android/src/main/AndroidManifest.xml +2 -0
  11. package/android/src/main/cpp/cpp-adapter.cpp +47 -0
  12. package/android/src/main/java/com/margelo/nitro/nitrotracing/HermesSamplingGuard.kt +43 -0
  13. package/android/src/main/java/com/margelo/nitro/nitrotracing/NitroTracingFrameSource.kt +36 -0
  14. package/android/src/main/java/com/margelo/nitro/nitrotracing/NitroTracingPackage.kt +31 -0
  15. package/client.ts +15 -0
  16. package/cpp/HermesSampling.cpp +26 -0
  17. package/cpp/HermesSampling.hpp +10 -0
  18. package/cpp/HybridRecording.cpp +66 -0
  19. package/cpp/HybridRecording.hpp +30 -0
  20. package/cpp/HybridTraceSpan.cpp +10 -0
  21. package/cpp/HybridTraceSpan.hpp +17 -0
  22. package/cpp/HybridTracing.cpp +10 -0
  23. package/cpp/HybridTracing.hpp +10 -0
  24. package/cpp/NativeConversions.cpp +77 -0
  25. package/cpp/NativeConversions.hpp +15 -0
  26. package/cpp/core/NativeSampler.cpp +152 -0
  27. package/cpp/core/NativeSampler.hpp +56 -0
  28. package/cpp/core/Recorder.cpp +218 -0
  29. package/cpp/core/Recorder.hpp +60 -0
  30. package/cpp/core/Retention.cpp +26 -0
  31. package/cpp/core/Retention.hpp +7 -0
  32. package/cpp/core/TraceJson.cpp +214 -0
  33. package/cpp/core/TraceJson.hpp +7 -0
  34. package/cpp/core/TraceTypes.hpp +62 -0
  35. package/expo.ts +2 -0
  36. package/ios/NitroTracingFrameSource.mm +35 -0
  37. package/lib/commonjs/client.cjs +767 -0
  38. package/lib/commonjs/client.cjs.map +7 -0
  39. package/lib/commonjs/expo.cjs +88 -0
  40. package/lib/commonjs/expo.cjs.map +7 -0
  41. package/lib/commonjs/index.cjs +28 -0
  42. package/lib/commonjs/index.cjs.map +7 -0
  43. package/lib/commonjs/performance.cjs +112 -0
  44. package/lib/commonjs/performance.cjs.map +7 -0
  45. package/lib/commonjs/plugins.cjs +477 -0
  46. package/lib/commonjs/plugins.cjs.map +7 -0
  47. package/lib/commonjs/react.cjs +3833 -0
  48. package/lib/commonjs/react.cjs.map +7 -0
  49. package/lib/commonjs/release-profiler.cjs +142 -0
  50. package/lib/commonjs/release-profiler.cjs.map +7 -0
  51. package/lib/commonjs/sentry.cjs +188 -0
  52. package/lib/commonjs/sentry.cjs.map +7 -0
  53. package/lib/module/client.mjs +768 -0
  54. package/lib/module/client.mjs.map +7 -0
  55. package/lib/module/expo.mjs +62 -0
  56. package/lib/module/expo.mjs.map +7 -0
  57. package/lib/module/index.mjs +7 -0
  58. package/lib/module/index.mjs.map +7 -0
  59. package/lib/module/performance.mjs +89 -0
  60. package/lib/module/performance.mjs.map +7 -0
  61. package/lib/module/plugins.mjs +461 -0
  62. package/lib/module/plugins.mjs.map +7 -0
  63. package/lib/module/react.mjs +3851 -0
  64. package/lib/module/react.mjs.map +7 -0
  65. package/lib/module/release-profiler.mjs +137 -0
  66. package/lib/module/release-profiler.mjs.map +7 -0
  67. package/lib/module/sentry.mjs +165 -0
  68. package/lib/module/sentry.mjs.map +7 -0
  69. package/lib/typescript/client.d.ts +4 -0
  70. package/lib/typescript/expo.d.ts +2 -0
  71. package/lib/typescript/performance.d.ts +2 -0
  72. package/lib/typescript/plugins.d.ts +12 -0
  73. package/lib/typescript/react.d.ts +5 -0
  74. package/lib/typescript/release-profiler.d.ts +2 -0
  75. package/lib/typescript/sentry.d.ts +2 -0
  76. package/lib/typescript/src/client/TracingSink.d.ts +10 -0
  77. package/lib/typescript/src/client/createTraceClient.d.ts +82 -0
  78. package/lib/typescript/src/client/playground.d.ts +12 -0
  79. package/lib/typescript/src/expo/ExpoAdapter.d.ts +15 -0
  80. package/lib/typescript/src/expo/index.d.ts +2 -0
  81. package/lib/typescript/src/index.d.ts +6 -0
  82. package/lib/typescript/src/plugins/TracePlugin.d.ts +22 -0
  83. package/lib/typescript/src/plugins/errors.d.ts +15 -0
  84. package/lib/typescript/src/plugins/nativeMetrics.d.ts +13 -0
  85. package/lib/typescript/src/plugins/navigation.d.ts +29 -0
  86. package/lib/typescript/src/plugins/network.d.ts +23 -0
  87. package/lib/typescript/src/plugins/orderSpans.d.ts +3 -0
  88. package/lib/typescript/src/plugins/performance.d.ts +13 -0
  89. package/lib/typescript/src/plugins/releaseProfiler.d.ts +25 -0
  90. package/lib/typescript/src/plugins/runtimeMetrics.d.ts +17 -0
  91. package/lib/typescript/src/plugins/sentry.d.ts +15 -0
  92. package/lib/typescript/src/plugins/startPlugins.d.ts +4 -0
  93. package/lib/typescript/src/react/DetailView.d.ts +11 -0
  94. package/lib/typescript/src/react/ExplorerFilters.d.ts +9 -0
  95. package/lib/typescript/src/react/ExplorerView.d.ts +9 -0
  96. package/lib/typescript/src/react/InspectorControls.d.ts +229 -0
  97. package/lib/typescript/src/react/InspectorHeader.d.ts +8 -0
  98. package/lib/typescript/src/react/InspectorSheet.d.ts +16 -0
  99. package/lib/typescript/src/react/MetricsView.d.ts +7 -0
  100. package/lib/typescript/src/react/SummaryView.d.ts +11 -0
  101. package/lib/typescript/src/react/TimelineView.d.ts +8 -0
  102. package/lib/typescript/src/react/TraceInspector.d.ts +11 -0
  103. package/lib/typescript/src/react/TraceOverlay.d.ts +17 -0
  104. package/lib/typescript/src/react/explorerModel.d.ts +38 -0
  105. package/lib/typescript/src/react/labels.d.ts +203 -0
  106. package/lib/typescript/src/react/native.d.ts +42 -0
  107. package/lib/typescript/src/react/readSnapshot.d.ts +4 -0
  108. package/lib/typescript/src/react/store.d.ts +9 -0
  109. package/lib/typescript/src/react/topics.d.ts +80 -0
  110. package/lib/typescript/src/react/useAppReadyMetric.d.ts +3 -0
  111. package/lib/typescript/src/react/useLiveRecording.d.ts +4 -0
  112. package/lib/typescript/src/react/useTraceViewer.d.ts +140 -0
  113. package/lib/typescript/src/react/viewerModel.d.ts +59 -0
  114. package/lib/typescript/src/specs/Recording.nitro.d.ts +31 -0
  115. package/lib/typescript/src/specs/TraceSpan.nitro.d.ts +14 -0
  116. package/lib/typescript/src/specs/Tracing.nitro.d.ts +17 -0
  117. package/lib/typescript/src/types/CompletedSpanOptions.d.ts +15 -0
  118. package/lib/typescript/src/types/EventContext.d.ts +8 -0
  119. package/lib/typescript/src/types/MarkEvent.d.ts +4 -0
  120. package/lib/typescript/src/types/MarkOptions.d.ts +6 -0
  121. package/lib/typescript/src/types/MetricEvent.d.ts +8 -0
  122. package/lib/typescript/src/types/MetricOptions.d.ts +10 -0
  123. package/lib/typescript/src/types/NativeSamplingOptions.d.ts +7 -0
  124. package/lib/typescript/src/types/ReadOptions.d.ts +7 -0
  125. package/lib/typescript/src/types/RecordingOptions.d.ts +11 -0
  126. package/lib/typescript/src/types/RecordingStats.d.ts +25 -0
  127. package/lib/typescript/src/types/SpanEvent.d.ts +13 -0
  128. package/lib/typescript/src/types/SpanOptions.d.ts +6 -0
  129. package/lib/typescript/src/types/SpanOutcome.d.ts +2 -0
  130. package/lib/typescript/src/types/TraceAttribute.d.ts +7 -0
  131. package/lib/typescript/src/types/TraceAttributes.d.ts +3 -0
  132. package/lib/typescript/src/types/TraceContext.d.ts +10 -0
  133. package/lib/typescript/src/types/TracePage.d.ts +18 -0
  134. package/lib/typescript/src/types.d.ts +17 -0
  135. package/nitro.json +20 -0
  136. package/nitrogen/generated/.gitattributes +1 -0
  137. package/nitrogen/generated/android/NitroTracing+autolinking.cmake +83 -0
  138. package/nitrogen/generated/android/NitroTracing+autolinking.gradle +27 -0
  139. package/nitrogen/generated/android/NitroTracingOnLoad.cpp +49 -0
  140. package/nitrogen/generated/android/NitroTracingOnLoad.hpp +34 -0
  141. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrotracing/NitroTracingOnLoad.kt +35 -0
  142. package/nitrogen/generated/ios/NitroTracing+autolinking.rb +62 -0
  143. package/nitrogen/generated/ios/NitroTracing-Swift-Cxx-Bridge.cpp +17 -0
  144. package/nitrogen/generated/ios/NitroTracing-Swift-Cxx-Bridge.hpp +27 -0
  145. package/nitrogen/generated/ios/NitroTracing-Swift-Cxx-Umbrella.hpp +38 -0
  146. package/nitrogen/generated/ios/NitroTracingAutolinking.mm +35 -0
  147. package/nitrogen/generated/ios/NitroTracingAutolinking.swift +16 -0
  148. package/nitrogen/generated/shared/c++/CompletedSpanOptions.hpp +122 -0
  149. package/nitrogen/generated/shared/c++/HybridRecordingSpec.cpp +31 -0
  150. package/nitrogen/generated/shared/c++/HybridRecordingSpec.hpp +100 -0
  151. package/nitrogen/generated/shared/c++/HybridTraceSpanSpec.cpp +23 -0
  152. package/nitrogen/generated/shared/c++/HybridTraceSpanSpec.hpp +65 -0
  153. package/nitrogen/generated/shared/c++/HybridTracingSpec.cpp +22 -0
  154. package/nitrogen/generated/shared/c++/HybridTracingSpec.hpp +68 -0
  155. package/nitrogen/generated/shared/c++/MarkEvent.hpp +102 -0
  156. package/nitrogen/generated/shared/c++/MarkOptions.hpp +99 -0
  157. package/nitrogen/generated/shared/c++/MetricEvent.hpp +110 -0
  158. package/nitrogen/generated/shared/c++/MetricOptions.hpp +107 -0
  159. package/nitrogen/generated/shared/c++/NativeSamplingOptions.hpp +87 -0
  160. package/nitrogen/generated/shared/c++/ReadOptions.hpp +87 -0
  161. package/nitrogen/generated/shared/c++/RecordingOptions.hpp +95 -0
  162. package/nitrogen/generated/shared/c++/RecordingStats.hpp +123 -0
  163. package/nitrogen/generated/shared/c++/SpanEvent.hpp +121 -0
  164. package/nitrogen/generated/shared/c++/SpanOptions.hpp +99 -0
  165. package/nitrogen/generated/shared/c++/SpanOutcome.hpp +84 -0
  166. package/nitrogen/generated/shared/c++/TraceAttribute.hpp +87 -0
  167. package/nitrogen/generated/shared/c++/TracePage.hpp +111 -0
  168. package/package.json +236 -0
  169. package/performance.ts +2 -0
  170. package/plugins.ts +24 -0
  171. package/react-native.config.js +16 -0
  172. package/react.ts +10 -0
  173. package/release-profiler.ts +6 -0
  174. package/sentry.ts +2 -0
  175. package/src/client/TracingSink.ts +25 -0
  176. package/src/client/createTraceClient.ts +439 -0
  177. package/src/client/playground.ts +143 -0
  178. package/src/expo/ExpoAdapter.ts +71 -0
  179. package/src/expo/index.ts +2 -0
  180. package/src/index.ts +8 -0
  181. package/src/plugins/TracePlugin.ts +22 -0
  182. package/src/plugins/errors.ts +69 -0
  183. package/src/plugins/nativeMetrics.ts +26 -0
  184. package/src/plugins/navigation.ts +111 -0
  185. package/src/plugins/network.ts +178 -0
  186. package/src/plugins/orderSpans.ts +22 -0
  187. package/src/plugins/performance.ts +120 -0
  188. package/src/plugins/releaseProfiler.ts +123 -0
  189. package/src/plugins/runtimeMetrics.ts +131 -0
  190. package/src/plugins/sentry.ts +176 -0
  191. package/src/plugins/startPlugins.ts +58 -0
  192. package/src/react/DetailView.tsx +514 -0
  193. package/src/react/ExplorerFilters.tsx +151 -0
  194. package/src/react/ExplorerView.tsx +243 -0
  195. package/src/react/InspectorControls.tsx +651 -0
  196. package/src/react/InspectorHeader.tsx +171 -0
  197. package/src/react/InspectorSheet.tsx +89 -0
  198. package/src/react/MetricsView.tsx +182 -0
  199. package/src/react/SummaryView.tsx +121 -0
  200. package/src/react/TimelineView.tsx +87 -0
  201. package/src/react/TraceInspector.tsx +196 -0
  202. package/src/react/TraceOverlay.tsx +585 -0
  203. package/src/react/explorerModel.ts +285 -0
  204. package/src/react/labels.ts +234 -0
  205. package/src/react/native.tsx +159 -0
  206. package/src/react/readSnapshot.ts +58 -0
  207. package/src/react/store.ts +31 -0
  208. package/src/react/topics.ts +427 -0
  209. package/src/react/useAppReadyMetric.ts +10 -0
  210. package/src/react/useLiveRecording.ts +43 -0
  211. package/src/react/useTraceViewer.ts +333 -0
  212. package/src/react/viewerModel.ts +172 -0
  213. package/src/specs/Recording.nitro.ts +40 -0
  214. package/src/specs/TraceSpan.nitro.ts +14 -0
  215. package/src/specs/Tracing.nitro.ts +14 -0
  216. package/src/types/CompletedSpanOptions.ts +15 -0
  217. package/src/types/EventContext.ts +8 -0
  218. package/src/types/MarkEvent.ts +3 -0
  219. package/src/types/MarkOptions.ts +6 -0
  220. package/src/types/MetricEvent.ts +8 -0
  221. package/src/types/MetricOptions.ts +10 -0
  222. package/src/types/NativeSamplingOptions.ts +7 -0
  223. package/src/types/ReadOptions.ts +7 -0
  224. package/src/types/RecordingOptions.ts +11 -0
  225. package/src/types/RecordingStats.ts +25 -0
  226. package/src/types/SpanEvent.ts +13 -0
  227. package/src/types/SpanOptions.ts +6 -0
  228. package/src/types/SpanOutcome.ts +2 -0
  229. package/src/types/TraceAttribute.ts +7 -0
  230. package/src/types/TraceAttributes.ts +4 -0
  231. package/src/types/TraceContext.ts +10 -0
  232. package/src/types/TracePage.ts +18 -0
  233. package/src/types.ts +17 -0
@@ -0,0 +1,137 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __esm = (fn, res, err) => function __init() {
6
+ if (err) throw err[0];
7
+ try {
8
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
9
+ } catch (e) {
10
+ throw err = [e], e;
11
+ }
12
+ };
13
+ var __export = (target, all) => {
14
+ for (var name in all)
15
+ __defProp(target, name, { get: all[name], enumerable: true });
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") {
19
+ for (let key of __getOwnPropNames(from))
20
+ if (!__hasOwnProp.call(to, key) && key !== except)
21
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
+ }
23
+ return to;
24
+ };
25
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
26
+
27
+ // src/index.ts
28
+ var src_exports = {};
29
+ __export(src_exports, {
30
+ Tracing: () => Tracing
31
+ });
32
+ import { NitroModules } from "react-native-nitro-modules";
33
+ var Tracing;
34
+ var init_src = __esm({
35
+ "src/index.ts"() {
36
+ "use strict";
37
+ Tracing = NitroModules.createHybridObject("Tracing");
38
+ }
39
+ });
40
+
41
+ // src/plugins/releaseProfiler.ts
42
+ var owner;
43
+ var stopHermesSampler = () => {
44
+ try {
45
+ const { Tracing: Tracing2 } = (init_src(), __toCommonJS(src_exports));
46
+ Tracing2.disableHermesSampling();
47
+ } catch {
48
+ }
49
+ };
50
+ function createReleaseProfilerPlugin(api, options = {}) {
51
+ const identity = {};
52
+ let context;
53
+ let active = false;
54
+ let span;
55
+ let path;
56
+ let stopping;
57
+ const plugin = {
58
+ id: "release-profiler",
59
+ start(next) {
60
+ if (context)
61
+ throw new Error("Release profiler plugin is already attached");
62
+ context = next;
63
+ return {
64
+ async stop() {
65
+ try {
66
+ if (active) await plugin.stopProfiling();
67
+ } finally {
68
+ context = void 0;
69
+ }
70
+ }
71
+ };
72
+ },
73
+ startProfiling() {
74
+ if (!context)
75
+ throw new Error("Attach release-profiler plugin before profiling");
76
+ if (owner) throw new Error("A release profiler session is already active");
77
+ if (api.startProfiling() === false)
78
+ throw new Error("Hermes sampling profiler is unavailable in this build");
79
+ owner = identity;
80
+ active = true;
81
+ path = void 0;
82
+ try {
83
+ span = context.recording.startSpan({
84
+ name: "hermes.profile",
85
+ correlationId: "",
86
+ attributes: [{ key: "source", value: "release-profiler" }]
87
+ });
88
+ } catch (error) {
89
+ context.reportError(error);
90
+ }
91
+ },
92
+ stopProfiling() {
93
+ if (stopping) return stopping;
94
+ if (!active)
95
+ return Promise.reject(
96
+ new Error("No release profiler session is active")
97
+ );
98
+ stopping = Promise.resolve().then(async () => {
99
+ try {
100
+ path = await api.stopProfiling(false);
101
+ span?.end("success");
102
+ try {
103
+ context?.recording.mark({
104
+ name: "hermes.profile.saved",
105
+ correlationId: "",
106
+ attributes: [
107
+ { key: "source", value: "release-profiler" },
108
+ { key: "path", value: path.slice(0, 512) }
109
+ ]
110
+ });
111
+ } catch (error) {
112
+ context?.reportError(error);
113
+ }
114
+ return path;
115
+ } catch (error) {
116
+ span?.end("error");
117
+ throw error;
118
+ } finally {
119
+ ;
120
+ (options.stopSampler ?? stopHermesSampler)();
121
+ active = false;
122
+ if (owner === identity) owner = void 0;
123
+ span = void 0;
124
+ stopping = void 0;
125
+ }
126
+ });
127
+ return stopping;
128
+ },
129
+ isProfiling: () => active,
130
+ getProfilePath: () => path
131
+ };
132
+ return plugin;
133
+ }
134
+ export {
135
+ createReleaseProfilerPlugin
136
+ };
137
+ //# sourceMappingURL=release-profiler.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.ts", "../../src/plugins/releaseProfiler.ts"],
4
+ "sourcesContent": ["import { NitroModules } from 'react-native-nitro-modules'\nimport type { Tracing as TracingFactory } from './specs/Tracing.nitro'\n/** Native recording factory. See Recording for ownership and cleanup. */\nexport const Tracing =\n NitroModules.createHybridObject<TracingFactory>('Tracing')\nexport type { Recording } from './specs/Recording.nitro'\nexport type { TraceSpan } from './specs/TraceSpan.nitro'\nexport type * from './types'\n", "import type { TraceSpan } from '../specs/TraceSpan.nitro'\nimport type { PluginContext, TracePlugin } from './TracePlugin'\n/** Injected optional react-native-release-profiler module; never imported by core. */\nexport interface ReleaseProfilerApi {\n /** Start the process-wide Hermes sampler; false means unavailable. */\n startProfiling(): boolean | void\n /** Stop and save a local profile artifact. */\n stopProfiling(saveToDownloads?: boolean): Promise<string>\n}\n/** Manually controlled profiler integration. Sampling never starts on plugin setup. */\nexport interface ReleaseProfilerPlugin extends TracePlugin {\n /** Start one session owned by this plugin. */\n startProfiling(): void\n /** Finish profiling and return the artifact's local path. */\n stopProfiling(): Promise<string>\n /** Whether this plugin owns an active or stopping profile. */\n isProfiling(): boolean\n /** Last successful artifact; not sent to remote exporters. */\n getProfilePath(): string | undefined\n}\n// Hermes profiling is process-wide, so two plugin instances must not compete.\nlet owner: object | undefined\n/** Stops Hermes sampling for real; on RN 0.85 Android the profiler's own stop restarts it. */\nconst stopHermesSampler = () => {\n try {\n const { Tracing } = require('../index') as typeof import('../index')\n Tracing.disableHermesSampling()\n } catch {\n // No native module (tests, non-native hosts): nothing is sampling.\n }\n}\nexport interface ReleaseProfilerOptions {\n /** Runs after every stop. Defaults to Tracing.disableHermesSampling(). */\n stopSampler?: () => void\n}\n/** Attach manual Hermes profile controls to a recording. */\nexport function createReleaseProfilerPlugin(\n api: ReleaseProfilerApi,\n options: ReleaseProfilerOptions = {}\n): ReleaseProfilerPlugin {\n const identity = {}\n let context: PluginContext | undefined\n let active = false\n let span: TraceSpan | undefined\n let path: string | undefined\n let stopping: Promise<string> | undefined\n const plugin: ReleaseProfilerPlugin = {\n id: 'release-profiler',\n start(next) {\n if (context)\n throw new Error('Release profiler plugin is already attached')\n context = next\n return {\n async stop() {\n try {\n if (active) await plugin.stopProfiling()\n } finally {\n context = undefined\n }\n },\n }\n },\n startProfiling() {\n if (!context)\n throw new Error('Attach release-profiler plugin before profiling')\n if (owner) throw new Error('A release profiler session is already active')\n if (api.startProfiling() === false)\n throw new Error('Hermes sampling profiler is unavailable in this build')\n owner = identity\n active = true\n path = undefined\n try {\n span = context.recording.startSpan({\n name: 'hermes.profile',\n correlationId: '',\n attributes: [{ key: 'source', value: 'release-profiler' }],\n })\n } catch (error) {\n context.reportError(error)\n }\n },\n stopProfiling() {\n if (stopping) return stopping\n if (!active)\n return Promise.reject(\n new Error('No release profiler session is active')\n )\n stopping = Promise.resolve().then(async () => {\n try {\n path = await api.stopProfiling(false)\n span?.end('success')\n // Lets a Perfetto export point at the .cpuprofile covering the span above.\n try {\n context?.recording.mark({\n name: 'hermes.profile.saved',\n correlationId: '',\n attributes: [\n { key: 'source', value: 'release-profiler' },\n { key: 'path', value: path.slice(0, 512) },\n ],\n })\n } catch (error) {\n context?.reportError(error)\n }\n return path\n } catch (error) {\n span?.end('error')\n throw error\n } finally {\n ;(options.stopSampler ?? stopHermesSampler)()\n active = false\n if (owner === identity) owner = undefined\n span = undefined\n stopping = undefined\n }\n })\n return stopping\n },\n isProfiling: () => active,\n getProfilePath: () => path,\n }\n return plugin\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,oBAAoB;AAA7B,IAGa;AAHb;AAAA;AAAA;AAGO,IAAM,UACX,aAAa,mBAAmC,SAAS;AAAA;AAAA;;;ACiB3D,IAAI;AAEJ,IAAM,oBAAoB,MAAM;AAC9B,MAAI;AACF,UAAM,EAAE,SAAAA,SAAQ,IAAI;AACpB,IAAAA,SAAQ,sBAAsB;AAAA,EAChC,QAAQ;AAAA,EAER;AACF;AAMO,SAAS,4BACd,KACA,UAAkC,CAAC,GACZ;AACvB,QAAM,WAAW,CAAC;AAClB,MAAI;AACJ,MAAI,SAAS;AACb,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,QAAM,SAAgC;AAAA,IACpC,IAAI;AAAA,IACJ,MAAM,MAAM;AACV,UAAI;AACF,cAAM,IAAI,MAAM,6CAA6C;AAC/D,gBAAU;AACV,aAAO;AAAA,QACL,MAAM,OAAO;AACX,cAAI;AACF,gBAAI,OAAQ,OAAM,OAAO,cAAc;AAAA,UACzC,UAAE;AACA,sBAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,iBAAiB;AACf,UAAI,CAAC;AACH,cAAM,IAAI,MAAM,iDAAiD;AACnE,UAAI,MAAO,OAAM,IAAI,MAAM,8CAA8C;AACzE,UAAI,IAAI,eAAe,MAAM;AAC3B,cAAM,IAAI,MAAM,uDAAuD;AACzE,cAAQ;AACR,eAAS;AACT,aAAO;AACP,UAAI;AACF,eAAO,QAAQ,UAAU,UAAU;AAAA,UACjC,MAAM;AAAA,UACN,eAAe;AAAA,UACf,YAAY,CAAC,EAAE,KAAK,UAAU,OAAO,mBAAmB,CAAC;AAAA,QAC3D,CAAC;AAAA,MACH,SAAS,OAAO;AACd,gBAAQ,YAAY,KAAK;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,gBAAgB;AACd,UAAI,SAAU,QAAO;AACrB,UAAI,CAAC;AACH,eAAO,QAAQ;AAAA,UACb,IAAI,MAAM,uCAAuC;AAAA,QACnD;AACF,iBAAW,QAAQ,QAAQ,EAAE,KAAK,YAAY;AAC5C,YAAI;AACF,iBAAO,MAAM,IAAI,cAAc,KAAK;AACpC,gBAAM,IAAI,SAAS;AAEnB,cAAI;AACF,qBAAS,UAAU,KAAK;AAAA,cACtB,MAAM;AAAA,cACN,eAAe;AAAA,cACf,YAAY;AAAA,gBACV,EAAE,KAAK,UAAU,OAAO,mBAAmB;AAAA,gBAC3C,EAAE,KAAK,QAAQ,OAAO,KAAK,MAAM,GAAG,GAAG,EAAE;AAAA,cAC3C;AAAA,YACF,CAAC;AAAA,UACH,SAAS,OAAO;AACd,qBAAS,YAAY,KAAK;AAAA,UAC5B;AACA,iBAAO;AAAA,QACT,SAAS,OAAO;AACd,gBAAM,IAAI,OAAO;AACjB,gBAAM;AAAA,QACR,UAAE;AACA;AAAC,WAAC,QAAQ,eAAe,mBAAmB;AAC5C,mBAAS;AACT,cAAI,UAAU,SAAU,SAAQ;AAChC,iBAAO;AACP,qBAAW;AAAA,QACb;AAAA,MACF,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,aAAa,MAAM;AAAA,IACnB,gBAAgB,MAAM;AAAA,EACxB;AACA,SAAO;AACT;",
6
+ "names": ["Tracing"]
7
+ }
@@ -0,0 +1,165 @@
1
+ // src/plugins/orderSpans.ts
2
+ function orderSpans(spans) {
3
+ const byId = new Map(spans.map((span) => [span.spanId, span]));
4
+ const children = /* @__PURE__ */ new Map();
5
+ const ordered = [];
6
+ for (const span of byId.values()) {
7
+ if (!span.parentSpanId || !byId.has(span.parentSpanId)) ordered.push(span);
8
+ else {
9
+ const siblings = children.get(span.parentSpanId);
10
+ if (siblings) siblings.push(span);
11
+ else children.set(span.parentSpanId, [span]);
12
+ }
13
+ }
14
+ for (let index = 0; index < ordered.length; index++) {
15
+ const descendants = children.get(ordered[index].spanId);
16
+ if (descendants) for (const child of descendants) ordered.push(child);
17
+ }
18
+ if (ordered.length !== byId.size)
19
+ throw new Error("Cannot export cyclic span parents");
20
+ return ordered;
21
+ }
22
+
23
+ // src/plugins/sentry.ts
24
+ function createSentryPlugin(options) {
25
+ return {
26
+ id: "sentry",
27
+ start({ recording, reportError }) {
28
+ const { sentry } = options;
29
+ const stats = recording.getStats();
30
+ const anchor = stats.startedAtUnixMs;
31
+ const client = sentry.getClient();
32
+ if (options.captureSpans && !client)
33
+ throw new Error("Initialize Sentry before enabling local capture");
34
+ const recordMeasurements = (data, start, anchorMs) => {
35
+ const end = (data.timestamp ?? data.start_timestamp) * 1e3 - anchorMs;
36
+ const metric = (name, value, unit) => {
37
+ if (typeof value !== "number" || !Number.isFinite(value)) return;
38
+ recording.recordMetric({
39
+ name,
40
+ value,
41
+ unit,
42
+ timestampMs: Math.max(0, end),
43
+ correlationId: data.trace_id,
44
+ attributes: [
45
+ { key: "source", value: "sentry" },
46
+ {
47
+ key: "span",
48
+ value: (data.description || data.op || "").slice(0, 256)
49
+ }
50
+ ]
51
+ });
52
+ };
53
+ metric("ui.frames.total", data.data?.["frames.total"], "count");
54
+ metric("ui.frames.slow", data.data?.["frames.slow"], "count");
55
+ metric("ui.frames.frozen", data.data?.["frames.frozen"], "count");
56
+ if (data.op === "app.start.cold" || data.op === "app.start.warm")
57
+ metric(data.op, end - start, "ms");
58
+ };
59
+ const unsubscribe = options.captureSpans ? client.on("spanEnd", (span) => {
60
+ try {
61
+ const data = sentry.spanToJSON(span);
62
+ if (data.data?.["nitro.exported"] || data.timestamp === void 0)
63
+ return;
64
+ const start = data.start_timestamp * 1e3 - anchor;
65
+ if (start < 0) return;
66
+ recording.recordSpan({
67
+ name: (data.description || data.op || "sentry.span").slice(
68
+ 0,
69
+ 128
70
+ ),
71
+ correlationId: data.trace_id,
72
+ timestampMs: start,
73
+ sourceSpanId: `sentry:${data.trace_id}:${data.span_id}`,
74
+ sourceParentSpanId: data.parent_span_id ? `sentry:${data.trace_id}:${data.parent_span_id}` : void 0,
75
+ durationMs: Math.max(
76
+ 0,
77
+ (data.timestamp - data.start_timestamp) * 1e3
78
+ ),
79
+ outcome: data.status && data.status !== "ok" ? "error" : "success",
80
+ attributes: [
81
+ { key: "source", value: "sentry" },
82
+ { key: "sentry.span_id", value: data.span_id },
83
+ {
84
+ key: "sentry.parent_span_id",
85
+ value: data.parent_span_id || ""
86
+ }
87
+ ]
88
+ });
89
+ recordMeasurements(data, start, anchor);
90
+ } catch (error) {
91
+ reportError(error);
92
+ }
93
+ }) : void 0;
94
+ return {
95
+ stop() {
96
+ unsubscribe?.();
97
+ },
98
+ async flush() {
99
+ if (options.exportSpans !== true) return;
100
+ if (!sentry.getClient())
101
+ throw new Error("Initialize Sentry before exporting traces");
102
+ const spans = [];
103
+ let cursor = 0;
104
+ while (true) {
105
+ const page = await recording.readEvents({
106
+ afterSequence: cursor,
107
+ limit: 1e3
108
+ });
109
+ spans.push(
110
+ ...page.spans.filter(
111
+ (s) => !s.attributes.some(
112
+ (a) => a.key === "source" && a.value === "sentry"
113
+ )
114
+ )
115
+ );
116
+ if (page.nextSequence === cursor) break;
117
+ cursor = page.nextSequence;
118
+ }
119
+ const ordered = orderSpans(spans);
120
+ const handles = /* @__PURE__ */ new Map();
121
+ const keys = new Set(options.exportedAttributeKeys ?? []);
122
+ for (let index = 0; index < ordered.length; index++) {
123
+ if (index > 0 && index % 250 === 0)
124
+ await new Promise((resolve) => setTimeout(resolve, 0));
125
+ const span = ordered[index];
126
+ const id = span.spanId;
127
+ const parentSpan = handles.get(span.parentSpanId);
128
+ const exported = sentry.startInactiveSpan({
129
+ name: span.name,
130
+ op: "nitro.trace",
131
+ startTime: (anchor + span.timestampMs) / 1e3,
132
+ parentSpan: parentSpan ?? null,
133
+ forceTransaction: !parentSpan,
134
+ attributes: {
135
+ ...Object.fromEntries(
136
+ span.attributes.filter((a) => keys.has(a.key)).map((a) => [a.key, a.value])
137
+ ),
138
+ "nitro.exported": true,
139
+ "nitro.span_id": id,
140
+ "nitro.parent_missing": Boolean(
141
+ span.parentSpanId && !parentSpan
142
+ ),
143
+ "nitro.outcome": span.outcome
144
+ }
145
+ });
146
+ exported.setStatus(
147
+ span.outcome === "success" ? { code: 1 } : { code: 2, message: span.outcome }
148
+ );
149
+ handles.set(id, exported);
150
+ }
151
+ for (let index = ordered.length - 1; index >= 0; index--) {
152
+ const span = ordered[index];
153
+ handles.get(span.spanId).end((anchor + span.timestampMs + span.durationMs) / 1e3);
154
+ if (index > 0 && index % 250 === 0)
155
+ await new Promise((resolve) => setTimeout(resolve, 0));
156
+ }
157
+ }
158
+ };
159
+ }
160
+ };
161
+ }
162
+ export {
163
+ createSentryPlugin
164
+ };
165
+ //# sourceMappingURL=sentry.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/plugins/orderSpans.ts", "../../src/plugins/sentry.ts"],
4
+ "sourcesContent": ["import type { SpanEvent } from '../types'\n/** Parent-first order in O(n), including parents delivered after their children. */\nexport function orderSpans(spans: readonly SpanEvent[]): SpanEvent[] {\n const byId = new Map(spans.map((span) => [span.spanId, span]))\n const children = new Map<string, SpanEvent[]>()\n const ordered: SpanEvent[] = []\n for (const span of byId.values()) {\n if (!span.parentSpanId || !byId.has(span.parentSpanId)) ordered.push(span)\n else {\n const siblings = children.get(span.parentSpanId)\n if (siblings) siblings.push(span)\n else children.set(span.parentSpanId, [span])\n }\n }\n for (let index = 0; index < ordered.length; index++) {\n const descendants = children.get(ordered[index]!.spanId)\n if (descendants) for (const child of descendants) ordered.push(child)\n }\n if (ordered.length !== byId.size)\n throw new Error('Cannot export cyclic span parents')\n return ordered\n}\n", "import type * as Sentry from '@sentry/react-native'\nimport type { SpanEvent } from '../types'\nimport type { TracePlugin } from './TracePlugin'\nimport { orderSpans } from './orderSpans'\n/** Optional Sentry capabilities; SDK initialization and consent remain app-owned. */\nexport interface SentryPluginOptions {\n /** Inject an installed SDK. This module has no runtime SDK dependency. */\n sentry: Pick<typeof Sentry, 'getClient' | 'spanToJSON' | 'startInactiveSpan'>\n /** Capture observable SDK spans locally. Defaults to false; sampling applies. */\n captureSpans?: boolean\n /** Explicitly opt into sending retained span names/timing/status to Sentry on stop. Defaults to false. */\n exportSpans?: boolean\n /** Only these sanitized custom attribute keys may leave the device. Defaults to none. */\n exportedAttributeKeys?: readonly string[]\n}\n/** Optional SDK measurements and opt-in export; neither direction is enabled implicitly. */\nexport function createSentryPlugin(options: SentryPluginOptions): TracePlugin {\n return {\n id: 'sentry',\n start({ recording, reportError }) {\n const { sentry } = options\n const stats = recording.getStats()\n const anchor = stats.startedAtUnixMs\n const client = sentry.getClient()\n if (options.captureSpans && !client)\n throw new Error('Initialize Sentry before enabling local capture')\n /** Sentry as the measurement layer: its frame and app-start data use the native metric names. */\n const recordMeasurements = (\n data: ReturnType<typeof sentry.spanToJSON>,\n start: number,\n anchorMs: number\n ) => {\n const end = (data.timestamp ?? data.start_timestamp) * 1000 - anchorMs\n const metric = (name: string, value: unknown, unit: string) => {\n if (typeof value !== 'number' || !Number.isFinite(value)) return\n recording.recordMetric({\n name,\n value,\n unit,\n timestampMs: Math.max(0, end),\n correlationId: data.trace_id,\n attributes: [\n { key: 'source', value: 'sentry' },\n {\n key: 'span',\n value: (data.description || data.op || '').slice(0, 256),\n },\n ],\n })\n }\n // Set by Sentry's nativeFrames integration on spans it measured.\n metric('ui.frames.total', data.data?.['frames.total'], 'count')\n metric('ui.frames.slow', data.data?.['frames.slow'], 'count')\n metric('ui.frames.frozen', data.data?.['frames.frozen'], 'count')\n // appStart integration spans: app.start.cold / app.start.warm.\n if (data.op === 'app.start.cold' || data.op === 'app.start.warm')\n metric(data.op, end - start, 'ms')\n }\n const unsubscribe = options.captureSpans\n ? client!.on('spanEnd', (span) => {\n try {\n const data = sentry.spanToJSON(span)\n if (data.data?.['nitro.exported'] || data.timestamp === undefined)\n return\n const start = data.start_timestamp * 1000 - anchor\n if (start < 0) return\n recording.recordSpan({\n name: (data.description || data.op || 'sentry.span').slice(\n 0,\n 128\n ),\n correlationId: data.trace_id,\n timestampMs: start,\n sourceSpanId: `sentry:${data.trace_id}:${data.span_id}`,\n sourceParentSpanId: data.parent_span_id\n ? `sentry:${data.trace_id}:${data.parent_span_id}`\n : undefined,\n durationMs: Math.max(\n 0,\n (data.timestamp - data.start_timestamp) * 1000\n ),\n outcome:\n data.status && data.status !== 'ok' ? 'error' : 'success',\n attributes: [\n { key: 'source', value: 'sentry' },\n { key: 'sentry.span_id', value: data.span_id },\n {\n key: 'sentry.parent_span_id',\n value: data.parent_span_id || '',\n },\n ],\n })\n recordMeasurements(data, start, anchor)\n } catch (error) {\n reportError(error)\n }\n })\n : undefined\n return {\n stop() {\n unsubscribe?.()\n },\n async flush() {\n if (options.exportSpans !== true) return\n if (!sentry.getClient())\n throw new Error('Initialize Sentry before exporting traces')\n const spans: SpanEvent[] = []\n let cursor = 0\n while (true) {\n const page = await recording.readEvents({\n afterSequence: cursor,\n limit: 1000,\n })\n spans.push(\n ...page.spans.filter(\n (s) =>\n !s.attributes.some(\n (a) => a.key === 'source' && a.value === 'sentry'\n )\n )\n )\n if (page.nextSequence === cursor) break\n cursor = page.nextSequence\n }\n const ordered = orderSpans(spans)\n const handles = new Map<\n string,\n ReturnType<typeof sentry.startInactiveSpan>\n >()\n const keys = new Set(options.exportedAttributeKeys ?? [])\n for (let index = 0; index < ordered.length; index++) {\n if (index > 0 && index % 250 === 0)\n await new Promise<void>((resolve) => setTimeout(resolve, 0))\n const span = ordered[index]!\n const id = span.spanId\n const parentSpan = handles.get(span.parentSpanId)\n const exported = sentry.startInactiveSpan({\n name: span.name,\n op: 'nitro.trace',\n startTime: (anchor + span.timestampMs) / 1000,\n parentSpan: parentSpan ?? null,\n forceTransaction: !parentSpan,\n attributes: {\n ...Object.fromEntries(\n span.attributes\n .filter((a) => keys.has(a.key))\n .map((a) => [a.key, a.value])\n ),\n 'nitro.exported': true,\n 'nitro.span_id': id,\n 'nitro.parent_missing': Boolean(\n span.parentSpanId && !parentSpan\n ),\n 'nitro.outcome': span.outcome,\n },\n })\n exported.setStatus(\n span.outcome === 'success'\n ? { code: 1 }\n : { code: 2, message: span.outcome }\n )\n handles.set(id, exported)\n }\n for (let index = ordered.length - 1; index >= 0; index--) {\n const span = ordered[index]!\n handles\n .get(span.spanId)!\n .end((anchor + span.timestampMs + span.durationMs) / 1000)\n if (index > 0 && index % 250 === 0)\n await new Promise<void>((resolve) => setTimeout(resolve, 0))\n }\n },\n }\n },\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,4 @@
1
+ export { createTraceClient } from './src/client/createTraceClient';
2
+ export type { TraceClient, TraceClientOptions, TraceClientSnapshot, ClientAttributes, TraceFormat, } from './src/client/createTraceClient';
3
+ export type { PlaygroundReport, PlaygroundCheckId, } from './src/client/playground';
4
+ export type { TracingEntry, TracingSink } from './src/client/TracingSink';
@@ -0,0 +1,2 @@
1
+ export { createExpoTraceSharing, registerTraceDevMenu } from './src/expo';
2
+ export type { ExpoSharingOptions } from './src/expo';
@@ -0,0 +1,2 @@
1
+ export { createPerformancePlugin } from './src/plugins/performance';
2
+ export type { PerformancePluginOptions } from './src/plugins/performance';
@@ -0,0 +1,12 @@
1
+ export { startPlugins } from './src/plugins/startPlugins';
2
+ export type { TracePlugin, PluginContext, PluginHandle, } from './src/plugins/TracePlugin';
3
+ export { createRuntimeMetricsPlugin } from './src/plugins/runtimeMetrics';
4
+ export type { RuntimeMetricsOptions } from './src/plugins/runtimeMetrics';
5
+ export { createNavigationPlugin, createScreenTracker, } from './src/plugins/navigation';
6
+ export type { NavigationRefLike, NavigationPluginOptions, } from './src/plugins/navigation';
7
+ export { createNetworkPlugin, urlTemplate } from './src/plugins/network';
8
+ export type { NetworkPluginOptions } from './src/plugins/network';
9
+ export { createErrorsPlugin } from './src/plugins/errors';
10
+ export type { ErrorsPluginOptions, ErrorUtilsLike } from './src/plugins/errors';
11
+ export { createNativeMetricsPlugin } from './src/plugins/nativeMetrics';
12
+ export type { NativeMetricsOptions } from './src/plugins/nativeMetrics';
@@ -0,0 +1,5 @@
1
+ export { TraceInspector } from './src/react/TraceInspector';
2
+ export { TraceOverlay } from './src/react/TraceOverlay';
3
+ export { defaultLabels } from './src/react/labels';
4
+ export type { InspectorLabels, InspectorTranslator, InspectorLabelKey, } from './src/react/labels';
5
+ export { useAppReadyMetric } from './src/react/useAppReadyMetric';
@@ -0,0 +1,2 @@
1
+ export { createReleaseProfilerPlugin } from './src/plugins/releaseProfiler';
2
+ export type { ReleaseProfilerApi, ReleaseProfilerOptions, ReleaseProfilerPlugin, } from './src/plugins/releaseProfiler';
@@ -0,0 +1,2 @@
1
+ export { createSentryPlugin } from './src/plugins/sentry';
2
+ export type { SentryPluginOptions } from './src/plugins/sentry';
@@ -0,0 +1,10 @@
1
+ /** Optional compatibility output for app logs and breadcrumbs, separate from native retention. */
2
+ export interface TracingEntry {
3
+ name: string;
4
+ entryType: string;
5
+ durationMs: number;
6
+ value?: number | string;
7
+ attributes?: Record<string, unknown>;
8
+ }
9
+ export type TracingSink = (line: string, entry: TracingEntry) => void;
10
+ export declare function formatTracingEntry(entry: TracingEntry): string;
@@ -0,0 +1,82 @@
1
+ import { type RuntimeMetricsOptions } from '../plugins/runtimeMetrics';
2
+ import { type TracingSink } from './TracingSink';
3
+ import type { Recording } from '../specs/Recording.nitro';
4
+ import type { RecordingOptions } from '../types';
5
+ import type { PerformancePluginOptions } from '../plugins/performance';
6
+ import type { TracePlugin } from '../plugins/TracePlugin';
7
+ import type { ReleaseProfilerPlugin } from '../plugins/releaseProfiler';
8
+ import { type PlaygroundReport } from './playground';
9
+ /** `recording`: lossless native schema. `perfetto`: Chrome Trace Events for ui.perfetto.dev. */
10
+ export type TraceFormat = 'recording' | 'perfetto';
11
+ export type ClientAttributes = Record<string, string | number | boolean | undefined>;
12
+ export interface TraceClientOptions {
13
+ /** Optional app log/breadcrumb output; failures never affect measured work. */
14
+ sink?: TracingSink;
15
+ plugins?: TracePlugin[];
16
+ performance?: false | PerformancePluginOptions;
17
+ /** Opt in to foreground JS event-loop and frame-callback metrics. */
18
+ runtimeMetrics?: boolean | RuntimeMetricsOptions;
19
+ onError?: (error: unknown) => void;
20
+ recordingOptions?: Partial<RecordingOptions>;
21
+ /** Serialize and deliver a recording; `format` picks raw recording JSON or Perfetto trace events. */
22
+ share?: (recording: Recording, format: TraceFormat) => Promise<void>;
23
+ shareProfile?: (path: string) => Promise<void>;
24
+ /** Start Hermes sampling with each recording; stopped and saved with it. */
25
+ autoProfile?: boolean;
26
+ /**
27
+ * CPU profile window captured by `flag()` when a profiler is attached and idle.
28
+ * Default 10000 ms; 0 records only the flag mark.
29
+ */
30
+ flagProfileMs?: number;
31
+ profiler?: ReleaseProfilerPlugin;
32
+ }
33
+ export interface TraceClientSnapshot {
34
+ visible: boolean;
35
+ recording: boolean;
36
+ busy: boolean;
37
+ disposed: boolean;
38
+ error?: string;
39
+ profiling: boolean;
40
+ profilePath?: string;
41
+ playground?: PlaygroundReport;
42
+ /** Plugin IDs started for the current recording, so the UI can tell untracked from quiet. */
43
+ collectors?: string[];
44
+ }
45
+ /** Each client exclusively owns its recording and producers. Consumers must dispose it. */
46
+ export declare function createTraceClient(options?: TraceClientOptions): {
47
+ /** Once per client lifetime: elapsed time from client creation to the app-defined ready signal. */
48
+ reportAppReady(): void;
49
+ trace: {
50
+ mark(name: string, attributes?: ClientAttributes): void;
51
+ metric(name: string, value: number | string, attributes?: ClientAttributes): void;
52
+ measure<T>(name: string, fn: () => Promise<T>, attributes?: ClientAttributes): Promise<T>;
53
+ measureSince(name: string, startName: string, id: string, attributes?: ClientAttributes): void;
54
+ clear(id: string): void;
55
+ };
56
+ start: () => Promise<void>;
57
+ stop: () => Promise<void>;
58
+ clear: () => Promise<void>;
59
+ getRecording: () => Recording | undefined;
60
+ getError: () => string | undefined;
61
+ getSnapshot: () => TraceClientSnapshot;
62
+ subscribe(listener: () => void): () => void;
63
+ open(): void;
64
+ close(): void;
65
+ reportError: (error: unknown) => void;
66
+ canShare: boolean;
67
+ canProfile: boolean;
68
+ canShareProfile: boolean;
69
+ export: () => Promise<void>;
70
+ /** Share a snapshot while recording continues, e.g. right after catching a problem. */
71
+ shareTrace: (format?: TraceFormat) => Promise<void>;
72
+ /**
73
+ * Mark the moment a tester saw a problem. With an idle profiler this also captures
74
+ * a bounded Hermes profile, so the flag ships with what the JS thread was doing.
75
+ */
76
+ flag: (note?: string) => void;
77
+ toggleProfile: () => Promise<void>;
78
+ shareProfile: () => Promise<void>;
79
+ playground: () => Promise<void>;
80
+ dispose(): Promise<void>;
81
+ };
82
+ export type TraceClient = ReturnType<typeof createTraceClient>;
@@ -0,0 +1,12 @@
1
+ import type { Recording } from '../specs/Recording.nitro';
2
+ export type PlaygroundCheckId = 'nested' | 'concurrency' | 'cancelled' | 'idempotent' | 'error' | 'metrics';
3
+ export interface PlaygroundReport {
4
+ correlationId: string;
5
+ checks: {
6
+ id: PlaygroundCheckId;
7
+ passed: boolean;
8
+ }[];
9
+ passed: boolean;
10
+ }
11
+ /** Adds a small isolated scenario; never resets or stops the user's recording. */
12
+ export declare const recordPlayground: (current: Recording) => Promise<PlaygroundReport>;
@@ -0,0 +1,15 @@
1
+ import type { TraceClient, TraceFormat } from '../client/createTraceClient';
2
+ import type { Recording } from '../specs/Recording.nitro';
3
+ export interface ExpoSharingOptions {
4
+ dialogTitle?: string;
5
+ }
6
+ /** Native OS file sharing. No remote upload or file-path export to telemetry. */
7
+ export declare function createExpoTraceSharing(options?: ExpoSharingOptions): {
8
+ share(recording: Recording, format?: TraceFormat): Promise<void>;
9
+ shareProfile(path: string): Promise<void>;
10
+ };
11
+ /** Register only in a development build. The consumer owns client disposal. */
12
+ export declare function registerTraceDevMenu(client: TraceClient, options?: {
13
+ name?: string;
14
+ registerDevMenuItems?: typeof import('expo-dev-client').registerDevMenuItems;
15
+ }): Promise<void>;
@@ -0,0 +1,2 @@
1
+ export { createExpoTraceSharing, registerTraceDevMenu } from './ExpoAdapter';
2
+ export type { ExpoSharingOptions } from './ExpoAdapter';
@@ -0,0 +1,6 @@
1
+ import type { Tracing as TracingFactory } from './specs/Tracing.nitro';
2
+ /** Native recording factory. See Recording for ownership and cleanup. */
3
+ export declare const Tracing: TracingFactory;
4
+ export type { Recording } from './specs/Recording.nitro';
5
+ export type { TraceSpan } from './specs/TraceSpan.nitro';
6
+ export type * from './types';
@@ -0,0 +1,22 @@
1
+ import type { Recording } from '../specs/Recording.nitro';
2
+ /** Shared native destination supplied to measurement and export plugins. */
3
+ export interface PluginContext {
4
+ /** Active native recording. */
5
+ recording: Recording;
6
+ /** Surface plugin failures without changing application operations. */
7
+ reportError(error: unknown): void;
8
+ }
9
+ /** Cleanup owned by a started plugin. */
10
+ export interface PluginHandle {
11
+ /** Disconnect observers and finish export before native recording disposal. */
12
+ stop(): void | Promise<void>;
13
+ /** Optional exporter flush after sources stop and native history freezes. */
14
+ flush?(): void | Promise<void>;
15
+ }
16
+ /** Optional measurement source, exporter or profiler integration. */
17
+ export interface TracePlugin {
18
+ /** Unique stable configuration identity. */
19
+ readonly id: string;
20
+ /** Start once per recording; must roll back resources if setup throws. */
21
+ start(context: PluginContext): PluginHandle;
22
+ }
@@ -0,0 +1,15 @@
1
+ import type { TracePlugin } from './TracePlugin';
2
+ type Handler = (error: unknown, isFatal?: boolean) => void;
3
+ export interface ErrorUtilsLike {
4
+ getGlobalHandler(): Handler;
5
+ setGlobalHandler(handler: Handler): void;
6
+ }
7
+ export interface ErrorsPluginOptions {
8
+ /** Defaults to React Native's global ErrorUtils. */
9
+ errorUtils?: ErrorUtilsLike;
10
+ /** Also record console.error calls. Default false; libraries log non-fatal noise there. */
11
+ console?: boolean;
12
+ }
13
+ /** Records uncaught JS errors as `js.error` marks, then calls the previous handler unchanged. */
14
+ export declare function createErrorsPlugin(options?: ErrorsPluginOptions): TracePlugin;
15
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { TracePlugin } from './TracePlugin';
2
+ export interface NativeMetricsOptions {
3
+ /** Metric window; 250–60000 ms. Default 1000. */
4
+ intervalMs?: number;
5
+ /** Main-thread frame metrics (ui.fps, ui.frame_gap.max, ui.frames.slow/frozen). Default true. */
6
+ frames?: boolean;
7
+ }
8
+ /**
9
+ * Native measurement layer: a sampler thread writes process.cpu, process.memory and
10
+ * main-thread frame windows straight into the recording, with no per-frame JS work.
11
+ * Alternative or complement to Sentry's measurements; each metric carries source=native.
12
+ */
13
+ export declare function createNativeMetricsPlugin(options?: NativeMetricsOptions): TracePlugin;
@@ -0,0 +1,29 @@
1
+ import type { TracePlugin } from './TracePlugin';
2
+ /** Structural subset of a React Navigation container ref (expo-router: useNavigationContainerRef()). */
3
+ export interface NavigationRefLike {
4
+ addListener(event: 'state' | 'ready', listener: () => void): () => void;
5
+ getCurrentRoute(): {
6
+ name: string;
7
+ key?: string;
8
+ } | undefined;
9
+ /** React Navigation logs an error when getCurrentRoute() runs before mount. */
10
+ isReady?(): boolean;
11
+ }
12
+ export interface NavigationPluginOptions {
13
+ /** Defaults to requestAnimationFrame. */
14
+ requestFrame?: (callback: () => void) => unknown;
15
+ }
16
+ /**
17
+ * Per focused route: a `navigation.enter` mark, a `screen <name>` visit span (dwell time)
18
+ * and a `navigation.transition` metric from state change to the second frame callback.
19
+ * The transition is a render-opportunity estimate, not content readiness.
20
+ */
21
+ export declare function createNavigationPlugin(ref: NavigationRefLike, options?: NavigationPluginOptions): TracePlugin;
22
+ /** For apps without React Navigation (custom tabs): pass to createNavigationPlugin, call setScreen on change. */
23
+ export declare function createScreenTracker(initial?: string): {
24
+ addListener(_event: "state" | "ready", listener: () => void): () => undefined;
25
+ getCurrentRoute: () => {
26
+ name: string;
27
+ } | undefined;
28
+ setScreen(name: string): void;
29
+ };
@@ -0,0 +1,23 @@
1
+ import type { TracePlugin } from './TracePlugin';
2
+ type Fetch = typeof fetch;
3
+ export interface NetworkPluginOptions {
4
+ /** Defaults to the global XMLHttpRequest, which backs axios and React Native's polyfilled fetch. */
5
+ XMLHttpRequest?: {
6
+ prototype: XMLHttpRequest;
7
+ };
8
+ /** Object whose `fetch` is wrapped. Defaults to globalThis. */
9
+ fetchHost?: {
10
+ fetch?: Fetch;
11
+ };
12
+ /** Skip matching URLs. Defaults to Metro symbolication requests. */
13
+ ignore?: (url: string) => boolean;
14
+ }
15
+ /** Path without origin/query; numeric, UUID and long hex segments become `:id` so requests group. */
16
+ export declare const urlTemplate: (url: string) => string;
17
+ /**
18
+ * Opt-in request timing: method, URL without query, status and duration. Bodies and headers
19
+ * are never read. XMLHttpRequest spans end at loadend; native fetch spans (expo/fetch,
20
+ * nitro-fetch) end when response headers arrive, since reading bodies is left to the app.
21
+ */
22
+ export declare function createNetworkPlugin(options?: NetworkPluginOptions): TracePlugin;
23
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { SpanEvent } from '../types';
2
+ /** Parent-first order in O(n), including parents delivered after their children. */
3
+ export declare function orderSpans(spans: readonly SpanEvent[]): SpanEvent[];