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.
- package/CHANGELOG.md +38 -0
- package/LICENSE +21 -0
- package/NitroTracing.podspec +32 -0
- package/README.md +75 -0
- package/android/CMakeLists.txt +49 -0
- package/android/build.gradle +133 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/proguard-rules.pro +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +47 -0
- package/android/src/main/java/com/margelo/nitro/nitrotracing/HermesSamplingGuard.kt +43 -0
- package/android/src/main/java/com/margelo/nitro/nitrotracing/NitroTracingFrameSource.kt +36 -0
- package/android/src/main/java/com/margelo/nitro/nitrotracing/NitroTracingPackage.kt +31 -0
- package/client.ts +15 -0
- package/cpp/HermesSampling.cpp +26 -0
- package/cpp/HermesSampling.hpp +10 -0
- package/cpp/HybridRecording.cpp +66 -0
- package/cpp/HybridRecording.hpp +30 -0
- package/cpp/HybridTraceSpan.cpp +10 -0
- package/cpp/HybridTraceSpan.hpp +17 -0
- package/cpp/HybridTracing.cpp +10 -0
- package/cpp/HybridTracing.hpp +10 -0
- package/cpp/NativeConversions.cpp +77 -0
- package/cpp/NativeConversions.hpp +15 -0
- package/cpp/core/NativeSampler.cpp +152 -0
- package/cpp/core/NativeSampler.hpp +56 -0
- package/cpp/core/Recorder.cpp +218 -0
- package/cpp/core/Recorder.hpp +60 -0
- package/cpp/core/Retention.cpp +26 -0
- package/cpp/core/Retention.hpp +7 -0
- package/cpp/core/TraceJson.cpp +214 -0
- package/cpp/core/TraceJson.hpp +7 -0
- package/cpp/core/TraceTypes.hpp +62 -0
- package/expo.ts +2 -0
- package/ios/NitroTracingFrameSource.mm +35 -0
- package/lib/commonjs/client.cjs +767 -0
- package/lib/commonjs/client.cjs.map +7 -0
- package/lib/commonjs/expo.cjs +88 -0
- package/lib/commonjs/expo.cjs.map +7 -0
- package/lib/commonjs/index.cjs +28 -0
- package/lib/commonjs/index.cjs.map +7 -0
- package/lib/commonjs/performance.cjs +112 -0
- package/lib/commonjs/performance.cjs.map +7 -0
- package/lib/commonjs/plugins.cjs +477 -0
- package/lib/commonjs/plugins.cjs.map +7 -0
- package/lib/commonjs/react.cjs +3833 -0
- package/lib/commonjs/react.cjs.map +7 -0
- package/lib/commonjs/release-profiler.cjs +142 -0
- package/lib/commonjs/release-profiler.cjs.map +7 -0
- package/lib/commonjs/sentry.cjs +188 -0
- package/lib/commonjs/sentry.cjs.map +7 -0
- package/lib/module/client.mjs +768 -0
- package/lib/module/client.mjs.map +7 -0
- package/lib/module/expo.mjs +62 -0
- package/lib/module/expo.mjs.map +7 -0
- package/lib/module/index.mjs +7 -0
- package/lib/module/index.mjs.map +7 -0
- package/lib/module/performance.mjs +89 -0
- package/lib/module/performance.mjs.map +7 -0
- package/lib/module/plugins.mjs +461 -0
- package/lib/module/plugins.mjs.map +7 -0
- package/lib/module/react.mjs +3851 -0
- package/lib/module/react.mjs.map +7 -0
- package/lib/module/release-profiler.mjs +137 -0
- package/lib/module/release-profiler.mjs.map +7 -0
- package/lib/module/sentry.mjs +165 -0
- package/lib/module/sentry.mjs.map +7 -0
- package/lib/typescript/client.d.ts +4 -0
- package/lib/typescript/expo.d.ts +2 -0
- package/lib/typescript/performance.d.ts +2 -0
- package/lib/typescript/plugins.d.ts +12 -0
- package/lib/typescript/react.d.ts +5 -0
- package/lib/typescript/release-profiler.d.ts +2 -0
- package/lib/typescript/sentry.d.ts +2 -0
- package/lib/typescript/src/client/TracingSink.d.ts +10 -0
- package/lib/typescript/src/client/createTraceClient.d.ts +82 -0
- package/lib/typescript/src/client/playground.d.ts +12 -0
- package/lib/typescript/src/expo/ExpoAdapter.d.ts +15 -0
- package/lib/typescript/src/expo/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts +6 -0
- package/lib/typescript/src/plugins/TracePlugin.d.ts +22 -0
- package/lib/typescript/src/plugins/errors.d.ts +15 -0
- package/lib/typescript/src/plugins/nativeMetrics.d.ts +13 -0
- package/lib/typescript/src/plugins/navigation.d.ts +29 -0
- package/lib/typescript/src/plugins/network.d.ts +23 -0
- package/lib/typescript/src/plugins/orderSpans.d.ts +3 -0
- package/lib/typescript/src/plugins/performance.d.ts +13 -0
- package/lib/typescript/src/plugins/releaseProfiler.d.ts +25 -0
- package/lib/typescript/src/plugins/runtimeMetrics.d.ts +17 -0
- package/lib/typescript/src/plugins/sentry.d.ts +15 -0
- package/lib/typescript/src/plugins/startPlugins.d.ts +4 -0
- package/lib/typescript/src/react/DetailView.d.ts +11 -0
- package/lib/typescript/src/react/ExplorerFilters.d.ts +9 -0
- package/lib/typescript/src/react/ExplorerView.d.ts +9 -0
- package/lib/typescript/src/react/InspectorControls.d.ts +229 -0
- package/lib/typescript/src/react/InspectorHeader.d.ts +8 -0
- package/lib/typescript/src/react/InspectorSheet.d.ts +16 -0
- package/lib/typescript/src/react/MetricsView.d.ts +7 -0
- package/lib/typescript/src/react/SummaryView.d.ts +11 -0
- package/lib/typescript/src/react/TimelineView.d.ts +8 -0
- package/lib/typescript/src/react/TraceInspector.d.ts +11 -0
- package/lib/typescript/src/react/TraceOverlay.d.ts +17 -0
- package/lib/typescript/src/react/explorerModel.d.ts +38 -0
- package/lib/typescript/src/react/labels.d.ts +203 -0
- package/lib/typescript/src/react/native.d.ts +42 -0
- package/lib/typescript/src/react/readSnapshot.d.ts +4 -0
- package/lib/typescript/src/react/store.d.ts +9 -0
- package/lib/typescript/src/react/topics.d.ts +80 -0
- package/lib/typescript/src/react/useAppReadyMetric.d.ts +3 -0
- package/lib/typescript/src/react/useLiveRecording.d.ts +4 -0
- package/lib/typescript/src/react/useTraceViewer.d.ts +140 -0
- package/lib/typescript/src/react/viewerModel.d.ts +59 -0
- package/lib/typescript/src/specs/Recording.nitro.d.ts +31 -0
- package/lib/typescript/src/specs/TraceSpan.nitro.d.ts +14 -0
- package/lib/typescript/src/specs/Tracing.nitro.d.ts +17 -0
- package/lib/typescript/src/types/CompletedSpanOptions.d.ts +15 -0
- package/lib/typescript/src/types/EventContext.d.ts +8 -0
- package/lib/typescript/src/types/MarkEvent.d.ts +4 -0
- package/lib/typescript/src/types/MarkOptions.d.ts +6 -0
- package/lib/typescript/src/types/MetricEvent.d.ts +8 -0
- package/lib/typescript/src/types/MetricOptions.d.ts +10 -0
- package/lib/typescript/src/types/NativeSamplingOptions.d.ts +7 -0
- package/lib/typescript/src/types/ReadOptions.d.ts +7 -0
- package/lib/typescript/src/types/RecordingOptions.d.ts +11 -0
- package/lib/typescript/src/types/RecordingStats.d.ts +25 -0
- package/lib/typescript/src/types/SpanEvent.d.ts +13 -0
- package/lib/typescript/src/types/SpanOptions.d.ts +6 -0
- package/lib/typescript/src/types/SpanOutcome.d.ts +2 -0
- package/lib/typescript/src/types/TraceAttribute.d.ts +7 -0
- package/lib/typescript/src/types/TraceAttributes.d.ts +3 -0
- package/lib/typescript/src/types/TraceContext.d.ts +10 -0
- package/lib/typescript/src/types/TracePage.d.ts +18 -0
- package/lib/typescript/src/types.d.ts +17 -0
- package/nitro.json +20 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/NitroTracing+autolinking.cmake +83 -0
- package/nitrogen/generated/android/NitroTracing+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NitroTracingOnLoad.cpp +49 -0
- package/nitrogen/generated/android/NitroTracingOnLoad.hpp +34 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrotracing/NitroTracingOnLoad.kt +35 -0
- package/nitrogen/generated/ios/NitroTracing+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NitroTracing-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/NitroTracing-Swift-Cxx-Bridge.hpp +27 -0
- package/nitrogen/generated/ios/NitroTracing-Swift-Cxx-Umbrella.hpp +38 -0
- package/nitrogen/generated/ios/NitroTracingAutolinking.mm +35 -0
- package/nitrogen/generated/ios/NitroTracingAutolinking.swift +16 -0
- package/nitrogen/generated/shared/c++/CompletedSpanOptions.hpp +122 -0
- package/nitrogen/generated/shared/c++/HybridRecordingSpec.cpp +31 -0
- package/nitrogen/generated/shared/c++/HybridRecordingSpec.hpp +100 -0
- package/nitrogen/generated/shared/c++/HybridTraceSpanSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridTraceSpanSpec.hpp +65 -0
- package/nitrogen/generated/shared/c++/HybridTracingSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridTracingSpec.hpp +68 -0
- package/nitrogen/generated/shared/c++/MarkEvent.hpp +102 -0
- package/nitrogen/generated/shared/c++/MarkOptions.hpp +99 -0
- package/nitrogen/generated/shared/c++/MetricEvent.hpp +110 -0
- package/nitrogen/generated/shared/c++/MetricOptions.hpp +107 -0
- package/nitrogen/generated/shared/c++/NativeSamplingOptions.hpp +87 -0
- package/nitrogen/generated/shared/c++/ReadOptions.hpp +87 -0
- package/nitrogen/generated/shared/c++/RecordingOptions.hpp +95 -0
- package/nitrogen/generated/shared/c++/RecordingStats.hpp +123 -0
- package/nitrogen/generated/shared/c++/SpanEvent.hpp +121 -0
- package/nitrogen/generated/shared/c++/SpanOptions.hpp +99 -0
- package/nitrogen/generated/shared/c++/SpanOutcome.hpp +84 -0
- package/nitrogen/generated/shared/c++/TraceAttribute.hpp +87 -0
- package/nitrogen/generated/shared/c++/TracePage.hpp +111 -0
- package/package.json +236 -0
- package/performance.ts +2 -0
- package/plugins.ts +24 -0
- package/react-native.config.js +16 -0
- package/react.ts +10 -0
- package/release-profiler.ts +6 -0
- package/sentry.ts +2 -0
- package/src/client/TracingSink.ts +25 -0
- package/src/client/createTraceClient.ts +439 -0
- package/src/client/playground.ts +143 -0
- package/src/expo/ExpoAdapter.ts +71 -0
- package/src/expo/index.ts +2 -0
- package/src/index.ts +8 -0
- package/src/plugins/TracePlugin.ts +22 -0
- package/src/plugins/errors.ts +69 -0
- package/src/plugins/nativeMetrics.ts +26 -0
- package/src/plugins/navigation.ts +111 -0
- package/src/plugins/network.ts +178 -0
- package/src/plugins/orderSpans.ts +22 -0
- package/src/plugins/performance.ts +120 -0
- package/src/plugins/releaseProfiler.ts +123 -0
- package/src/plugins/runtimeMetrics.ts +131 -0
- package/src/plugins/sentry.ts +176 -0
- package/src/plugins/startPlugins.ts +58 -0
- package/src/react/DetailView.tsx +514 -0
- package/src/react/ExplorerFilters.tsx +151 -0
- package/src/react/ExplorerView.tsx +243 -0
- package/src/react/InspectorControls.tsx +651 -0
- package/src/react/InspectorHeader.tsx +171 -0
- package/src/react/InspectorSheet.tsx +89 -0
- package/src/react/MetricsView.tsx +182 -0
- package/src/react/SummaryView.tsx +121 -0
- package/src/react/TimelineView.tsx +87 -0
- package/src/react/TraceInspector.tsx +196 -0
- package/src/react/TraceOverlay.tsx +585 -0
- package/src/react/explorerModel.ts +285 -0
- package/src/react/labels.ts +234 -0
- package/src/react/native.tsx +159 -0
- package/src/react/readSnapshot.ts +58 -0
- package/src/react/store.ts +31 -0
- package/src/react/topics.ts +427 -0
- package/src/react/useAppReadyMetric.ts +10 -0
- package/src/react/useLiveRecording.ts +43 -0
- package/src/react/useTraceViewer.ts +333 -0
- package/src/react/viewerModel.ts +172 -0
- package/src/specs/Recording.nitro.ts +40 -0
- package/src/specs/TraceSpan.nitro.ts +14 -0
- package/src/specs/Tracing.nitro.ts +14 -0
- package/src/types/CompletedSpanOptions.ts +15 -0
- package/src/types/EventContext.ts +8 -0
- package/src/types/MarkEvent.ts +3 -0
- package/src/types/MarkOptions.ts +6 -0
- package/src/types/MetricEvent.ts +8 -0
- package/src/types/MetricOptions.ts +10 -0
- package/src/types/NativeSamplingOptions.ts +7 -0
- package/src/types/ReadOptions.ts +7 -0
- package/src/types/RecordingOptions.ts +11 -0
- package/src/types/RecordingStats.ts +25 -0
- package/src/types/SpanEvent.ts +13 -0
- package/src/types/SpanOptions.ts +6 -0
- package/src/types/SpanOutcome.ts +2 -0
- package/src/types/TraceAttribute.ts +7 -0
- package/src/types/TraceAttributes.ts +4 -0
- package/src/types/TraceContext.ts +10 -0
- package/src/types/TracePage.ts +18 -0
- package/src/types.ts +17 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/index.ts", "../../src/plugins/runtimeMetrics.ts", "../../src/client/TracingSink.ts", "../../src/plugins/performance.ts", "../../src/plugins/startPlugins.ts", "../../src/client/playground.ts", "../../src/client/createTraceClient.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 { TracePlugin } from './TracePlugin'\nexport interface RuntimeMetricsOptions {\n /** Reporting interval in ms, minimum 250; default 1000. */\n intervalMs?: number\n /** Observe JS requestAnimationFrame callbacks (not native UI frames). Default true. */\n frames?: boolean\n}\n/** Injectable clock/lifecycle surface for deterministic tests and alternate hosts. */\nexport interface RuntimeMetricsHost {\n now(): number\n isActive(): boolean\n subscribe(listener: (active: boolean) => void): () => void\n requestFrame(callback: () => void): number\n cancelFrame(id: number): void\n}\nconst nativeHost = (): RuntimeMetricsHost => {\n const { AppState } = require('react-native') as typeof import('react-native')\n return {\n now: () => globalThis.performance.now(),\n isActive: () => AppState.currentState === 'active',\n subscribe: (listener) => {\n const subscription = AppState.addEventListener('change', (state) =>\n listener(state === 'active')\n )\n return () => subscription.remove()\n },\n requestFrame: (callback) => requestAnimationFrame(callback),\n cancelFrame: (id) => cancelAnimationFrame(id),\n }\n}\n/** Low-volume foreground JS health samples. No per-frame native calls or UI FPS claims. */\nexport function createRuntimeMetricsPlugin(\n options: RuntimeMetricsOptions = {},\n host?: RuntimeMetricsHost\n): TracePlugin {\n const interval = options.intervalMs ?? 1000\n if (!Number.isFinite(interval) || interval < 250)\n throw new Error('Runtime metrics interval must be at least 250ms')\n return {\n id: 'runtime-metrics',\n start({ recording, reportError }) {\n const api = host ?? nativeHost()\n let stopped = false\n let active = false\n let timer: ReturnType<typeof setTimeout> | undefined\n let frame: number | undefined\n let started = 0\n let previousFrame: number | undefined\n let frames = 0\n let maxGap = 0\n let longGaps = 0\n const reset = () => {\n started = api.now()\n frames = 0\n maxGap = 0\n longGaps = 0\n }\n const emit = (name: string, value: number, unit: string) => {\n try {\n recording.recordMetric({\n name,\n value,\n unit,\n correlationId: '',\n attributes: [\n { key: 'source', value: 'js-runtime' },\n { key: 'scope', value: 'foreground' },\n { key: 'windowMs', value: String(api.now() - started) },\n ],\n })\n } catch (error) {\n reportError(error)\n }\n }\n const onFrame = () => {\n if (stopped || !active) return\n const now = api.now()\n if (previousFrame !== undefined) {\n const gap = Math.max(0, now - previousFrame)\n maxGap = Math.max(maxGap, gap)\n if (gap > 50) longGaps++\n }\n previousFrame = now\n frames++\n frame = api.requestFrame(onFrame)\n }\n const tick = () => {\n if (stopped || !active) return\n const elapsed = api.now() - started\n emit('js.event_loop.delay', Math.max(0, elapsed - interval), 'ms')\n if (options.frames !== false && elapsed > 0) {\n emit(\n 'js.frame_callback.rate',\n (frames * 1000) / elapsed,\n 'callbacks/s'\n )\n if (frames > 1) emit('js.frame_gap.max', maxGap, 'ms')\n emit('js.frame_gap.over_50ms', longGaps, 'count')\n }\n reset()\n timer = setTimeout(tick, interval)\n }\n const suspend = () => {\n clearTimeout(timer)\n if (frame !== undefined) api.cancelFrame(frame)\n frame = undefined\n }\n const change = (next: boolean) => {\n if (stopped || next === active) return\n active = next\n previousFrame = undefined\n suspend()\n reset()\n if (active) {\n timer = setTimeout(tick, interval)\n if (options.frames !== false) frame = api.requestFrame(onFrame)\n }\n }\n const unsubscribe = api.subscribe(change)\n change(api.isActive())\n return {\n stop() {\n stopped = true\n active = false\n suspend()\n unsubscribe()\n },\n }\n },\n }\n}\n", "/** Optional compatibility output for app logs and breadcrumbs, separate from native retention. */\nexport interface TracingEntry {\n name: string\n entryType: string\n durationMs: number\n value?: number | string\n attributes?: Record<string, unknown>\n}\nexport type TracingSink = (line: string, entry: TracingEntry) => void\nexport function formatTracingEntry(entry: TracingEntry): string {\n const attributes = entry.attributes\n const id = attributes?.id\n const suffix = typeof id === 'string' ? ` [${id.slice(-6)}]` : ''\n const details = Object.entries(attributes ?? {})\n .filter(([key, value]) => key !== 'id' && value !== undefined)\n .map(([key, value]) => `${key}=${value}`)\n const detail = details.length ? ` {${details.join(' ')}}` : ''\n const label =\n entry.entryType === 'metric'\n ? `${entry.name}=${entry.value}`\n : entry.entryType === 'measure'\n ? `${entry.name} ${entry.durationMs.toFixed(0)}ms`\n : entry.name\n return `${label}${suffix}${detail}`\n}\n", "import type { TracingEntry } from '../client/TracingSink'\nimport type performance from 'react-native-performance'\nimport type { PerformanceObserver } from 'react-native-performance'\nimport type { TracePlugin } from './TracePlugin'\n/** Default measurement-source dependencies; supports the installed RN performance API. */\nexport interface PerformancePluginOptions {\n /** Same clock used by the supplied observer's entries. */\n performance: typeof performance\n /** PerformanceObserver from react-native-performance. */\n PerformanceObserver: typeof PerformanceObserver\n}\n/** Observe user timing without patching globals, clearing shared buffers or timing network bodies. */\nexport function createPerformancePlugin(\n api: PerformancePluginOptions,\n onEntry?: (entry: TracingEntry) => void\n): TracePlugin {\n return {\n id: 'performance',\n start({ recording, reportError }) {\n const offset = recording.getStats().nowMs - api.performance.now()\n let stopped = false\n const ingest = (\n entries: ReturnType<PerformanceObserver['takeRecords']>\n ) => {\n if (stopped) return\n for (const entry of entries) {\n try {\n const timestampMs = entry.startTime + offset\n if (timestampMs < 0) continue // Previous history is outside this recording.\n const data = entry as typeof entry & {\n value?: unknown\n detail?: { id?: unknown; unit?: unknown }\n }\n onEntry?.({\n name: entry.name,\n entryType: entry.entryType,\n durationMs: entry.duration,\n value:\n typeof data.value === 'string' || typeof data.value === 'number'\n ? data.value\n : undefined,\n attributes: data.detail,\n })\n const context = {\n name: entry.name.slice(0, 128),\n correlationId:\n typeof data.detail?.id === 'string'\n ? data.detail.id.slice(0, 128)\n : '',\n attributes: [\n { key: 'source', value: 'performance' },\n { key: 'source.startTimeMs', value: String(entry.startTime) },\n ],\n }\n if (entry.entryType === 'longtask')\n recording.recordSpan({\n ...context,\n name: 'js.longtask',\n timestampMs,\n durationMs: entry.duration,\n outcome: 'success',\n })\n else if (entry.entryType === 'measure')\n recording.recordSpan({\n ...context,\n timestampMs,\n durationMs: entry.duration,\n outcome: 'success',\n })\n else if (entry.entryType === 'mark')\n recording.mark({ ...context, timestampMs })\n else if (\n entry.entryType === 'metric' &&\n typeof data.value === 'number' &&\n Number.isFinite(data.value)\n )\n recording.recordMetric({\n ...context,\n timestampMs,\n value: data.value,\n unit:\n typeof data.detail?.unit === 'string'\n ? data.detail.unit.slice(0, 32)\n : 'unspecified',\n })\n } catch (error) {\n reportError(error)\n }\n }\n }\n const observer = new api.PerformanceObserver((list) =>\n ingest(list.getEntries())\n )\n // Global RN observers reject unknown types; react-native-performance lacks longtask.\n const supported = (\n api.PerformanceObserver as { supportedEntryTypes?: readonly string[] }\n ).supportedEntryTypes\n const entryTypes = ['mark', 'measure', 'metric', 'longtask'].filter(\n (type) => (supported ? supported.includes(type) : type !== 'longtask')\n )\n try {\n observer.observe({ entryTypes } as never)\n } catch (error) {\n observer.disconnect()\n throw error\n }\n return {\n stop() {\n if (stopped) return\n try {\n ingest(observer.takeRecords())\n } finally {\n stopped = true\n observer.disconnect()\n }\n },\n }\n },\n }\n}\n", "import type { Recording } from '../specs/Recording.nitro'\nimport type { PluginHandle, TracePlugin } from './TracePlugin'\n/** Start optional integrations. Failures are isolated; stop waits for all cleanup. */\nexport function startPlugins(\n recording: Recording,\n plugins: readonly TracePlugin[],\n onError: (error: unknown) => void\n): PluginHandle {\n const handles: PluginHandle[] = []\n const ids = new Set<string>()\n for (const plugin of plugins) {\n if (ids.has(plugin.id))\n throw new Error(`Duplicate tracing plugin: ${plugin.id}`)\n ids.add(plugin.id)\n }\n const reportError = (error: unknown) => {\n try {\n onError(error)\n } catch {\n /* Error reporters cannot break capture. */\n }\n }\n for (const plugin of plugins) {\n try {\n handles.push(plugin.start({ recording, reportError }))\n } catch (error) {\n reportError(error)\n }\n }\n let stopping: Promise<void> | undefined\n return {\n stop() {\n if (!stopping)\n stopping = (async () => {\n for (const handle of [...handles].reverse()) {\n try {\n await handle.stop()\n } catch (error) {\n reportError(error)\n }\n }\n try {\n recording.stop()\n } catch (error) {\n reportError(error)\n }\n for (const handle of handles) {\n try {\n await handle.flush?.()\n } catch (error) {\n reportError(error)\n }\n }\n })()\n return stopping\n },\n }\n}\n", "import type { Recording } from '../specs/Recording.nitro'\nimport type { SpanEvent, MetricEvent } from '../types'\nexport type PlaygroundCheckId =\n 'nested' | 'concurrency' | 'cancelled' | 'idempotent' | 'error' | 'metrics'\nexport interface PlaygroundReport {\n correlationId: string\n checks: { id: PlaygroundCheckId; passed: boolean }[]\n passed: boolean\n}\nconst delay = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(resolve, ms))\n/** Adds a small isolated scenario; never resets or stops the user's recording. */\nexport const recordPlayground = async (\n current: Recording\n): Promise<PlaygroundReport> => {\n const identity = current.startSpan({\n name: 'playground.run',\n correlationId: '',\n attributes: [],\n })\n const correlationId = `playground-${identity.spanId}`\n identity.end('success')\n const root = current.startSpan({\n name: 'playground.pipeline',\n correlationId,\n attributes: [{ key: 'source', value: 'playground' }],\n })\n const start = (name: string) =>\n current.startSpan({\n name,\n correlationId,\n parentSpanId: root.spanId,\n attributes: [],\n })\n try {\n const first = start('playground.concurrent')\n const second = start('playground.concurrent')\n await Promise.all([\n delay(30).then(() => first.end('success')),\n delay(60).then(() => second.end('success')),\n ])\n const cancelled = start('playground.cancelled')\n cancelled.end('cancelled')\n const repeated = start('playground.idempotent')\n repeated.end('success')\n repeated.end('error')\n const failed = start('playground.error')\n failed.end('error')\n for (const value of [20, 45, 80])\n current.recordMetric({\n name: 'playground.throughput',\n correlationId,\n attributes: [],\n value,\n unit: 'byte/second',\n })\n root.end('success')\n const spans: SpanEvent[] = []\n const metrics: MetricEvent[] = []\n let afterSequence = 0\n // Native recordings cap at 100000 events. Retain only this scenario while scanning.\n for (let pageIndex = 0; pageIndex < 100; pageIndex++) {\n const page = await current.readEvents({ afterSequence, limit: 1000 })\n spans.push(\n ...page.spans.filter(\n (event) =>\n event.correlationId === correlationId ||\n event.spanId === root.spanId\n )\n )\n metrics.push(\n ...page.metrics.filter((event) => event.correlationId === correlationId)\n )\n if (\n page.nextSequence <= afterSequence ||\n page.spans.length + page.marks.length + page.metrics.length < 1000\n )\n break\n afterSequence = page.nextSequence\n }\n const concurrent = spans.filter(\n (span) => span.name === 'playground.concurrent'\n )\n const repeatedEvents = spans.filter(\n (span) => span.spanId === repeated.spanId\n )\n const checks: PlaygroundReport['checks'] = [\n {\n id: 'nested',\n passed:\n spans.length === 6 &&\n spans\n .filter((span) => span.spanId !== root.spanId)\n .every((span) => span.parentSpanId === root.spanId),\n },\n {\n id: 'concurrency',\n passed:\n concurrent.length === 2 &&\n concurrent[0].spanId !== concurrent[1].spanId &&\n Math.max(...concurrent.map((span) => span.timestampMs)) <=\n Math.min(\n ...concurrent.map((span) => span.timestampMs + span.durationMs)\n ),\n },\n {\n id: 'cancelled',\n passed: spans.some(\n (span) =>\n span.spanId === cancelled.spanId && span.outcome === 'cancelled'\n ),\n },\n {\n id: 'idempotent',\n passed:\n repeatedEvents.length === 1 &&\n repeatedEvents[0].outcome === 'success',\n },\n {\n id: 'error',\n passed: spans.some(\n (span) => span.spanId === failed.spanId && span.outcome === 'error'\n ),\n },\n {\n id: 'metrics',\n passed:\n metrics.length === 3 &&\n metrics.map((metric) => metric.value).join(',') === '20,45,80',\n },\n ]\n return {\n correlationId,\n checks,\n passed: checks.every((check) => check.passed),\n }\n } catch (error) {\n try {\n root.end('error')\n } catch {}\n throw error\n }\n}\n", "import {\n createRuntimeMetricsPlugin,\n type RuntimeMetricsOptions,\n} from '../plugins/runtimeMetrics'\nimport {\n formatTracingEntry,\n type TracingEntry,\n type TracingSink,\n} from './TracingSink'\nimport type { Recording } from '../specs/Recording.nitro'\nimport type { RecordingOptions } from '../types'\nimport type { PerformancePluginOptions } from '../plugins/performance'\nimport { createPerformancePlugin } from '../plugins/performance'\nimport { startPlugins } from '../plugins/startPlugins'\nimport type { PluginHandle, TracePlugin } from '../plugins/TracePlugin'\nimport type { ReleaseProfilerPlugin } from '../plugins/releaseProfiler'\nimport { recordPlayground, type PlaygroundReport } from './playground'\n\n/** `recording`: lossless native schema. `perfetto`: Chrome Trace Events for ui.perfetto.dev. */\nexport type TraceFormat = 'recording' | 'perfetto'\nexport type ClientAttributes = Record<\n string,\n string | number | boolean | undefined\n>\nexport interface TraceClientOptions {\n /** Optional app log/breadcrumb output; failures never affect measured work. */\n sink?: TracingSink\n plugins?: TracePlugin[]\n performance?: false | PerformancePluginOptions\n /** Opt in to foreground JS event-loop and frame-callback metrics. */\n runtimeMetrics?: boolean | RuntimeMetricsOptions\n onError?: (error: unknown) => void\n recordingOptions?: Partial<RecordingOptions>\n /** Serialize and deliver a recording; `format` picks raw recording JSON or Perfetto trace events. */\n share?: (recording: Recording, format: TraceFormat) => Promise<void>\n shareProfile?: (path: string) => Promise<void>\n /** Start Hermes sampling with each recording; stopped and saved with it. */\n autoProfile?: boolean\n /**\n * CPU profile window captured by `flag()` when a profiler is attached and idle.\n * Default 10000 ms; 0 records only the flag mark.\n */\n flagProfileMs?: number\n profiler?: ReleaseProfilerPlugin\n}\nexport interface TraceClientSnapshot {\n visible: boolean\n recording: boolean\n busy: boolean\n disposed: boolean\n error?: string\n profiling: boolean\n profilePath?: string\n playground?: PlaygroundReport\n /** Plugin IDs started for the current recording, so the UI can tell untracked from quiet. */\n collectors?: string[]\n}\n/** react-native-performance when installed (existing marks live in its buffer), else RN's global Web Performance API. */\nconst defaultPerformanceApi = (): PerformancePluginOptions | undefined => {\n try {\n // Directly inside `try` so Metro treats the optional peer as optional.\n const module =\n require('react-native-performance') as typeof import('react-native-performance')\n return {\n performance: module.default,\n PerformanceObserver: module.PerformanceObserver,\n }\n } catch {\n const global = globalThis as unknown as Partial<PerformancePluginOptions>\n return global.performance && global.PerformanceObserver\n ? (global as PerformancePluginOptions)\n : undefined\n }\n}\n/** Each client exclusively owns its recording and producers. Consumers must dispose it. */\nexport function createTraceClient(options: TraceClientOptions = {}) {\n let recording: Recording | undefined\n let handle: PluginHandle | undefined\n const readinessStartMs = globalThis.performance.now()\n let readyReported = false\n let enabled = false\n let disposed = false\n let pending = 0\n let tail = Promise.resolve()\n let snapshot: TraceClientSnapshot = {\n visible: false,\n recording: false,\n busy: false,\n disposed: false,\n profiling: false,\n }\n const listeners = new Set<() => void>()\n const marks = new Map<\n string,\n { marks: Map<string, number>; emitted: Set<string> }\n >()\n const publish = (next: Partial<TraceClientSnapshot> = {}) => {\n snapshot = {\n ...snapshot,\n recording: enabled,\n disposed,\n busy: pending > 0,\n profiling: options.profiler?.isProfiling() ?? false,\n profilePath: options.profiler?.getProfilePath(),\n ...next,\n }\n for (const listener of listeners) {\n try {\n listener()\n } catch {\n /* Observers cannot interrupt recording ownership. */\n }\n }\n }\n const reportError = (error: unknown) => {\n publish({ error: String(error) })\n try {\n options.onError?.(error)\n } catch {\n /* Diagnostics cannot change measured operations. */\n }\n }\n const safely = <T>(work: () => T): T | undefined => {\n try {\n return work()\n } catch (error) {\n reportError(error)\n return undefined\n }\n }\n const emit = (entry: TracingEntry) => {\n if (options.sink)\n safely(() => options.sink!(formatTracingEntry(entry), entry))\n }\n const enqueue = (work: () => Promise<void>) => {\n if (disposed) return Promise.reject(new Error('Trace client is disposed'))\n pending++\n publish()\n const result = tail.then(async () => {\n try {\n if (disposed) throw new Error('Trace client is disposed')\n await work()\n } finally {\n pending--\n publish()\n }\n })\n tail = result.catch(reportError)\n return result\n }\n const stopCurrent = async () => {\n enabled = false\n try {\n await handle?.stop()\n } finally {\n handle = undefined\n recording?.stop()\n marks.clear()\n publish()\n }\n }\n const startCurrent = async () => {\n await stopCurrent()\n if (disposed) throw new Error('Trace client is disposed')\n recording?.dispose()\n recording = undefined\n const { Tracing } = require('../index') as typeof import('../index')\n recording = Tracing.startRecording({\n // ~1-2 hours of spans for UAT sessions; metric samples use at most half.\n maxEvents: 10000,\n maxBytes: 6 * 1024 * 1024,\n maxActiveSpans: 256,\n spanTimeoutMs: 30 * 60 * 1000,\n ...options.recordingOptions,\n })\n publish({ error: undefined, playground: undefined })\n try {\n const plugins = [...(options.plugins ?? [])]\n const api =\n options.performance === false\n ? undefined\n : (options.performance ?? defaultPerformanceApi())\n if (api)\n plugins.unshift(\n createPerformancePlugin(api, options.sink ? emit : undefined)\n )\n if (options.runtimeMetrics)\n plugins.push(\n createRuntimeMetricsPlugin(\n options.runtimeMetrics === true ? {} : options.runtimeMetrics\n )\n )\n if (options.profiler) plugins.push(options.profiler)\n handle = startPlugins(recording, plugins, reportError)\n publish({ collectors: plugins.map((plugin) => plugin.id) })\n } catch (error) {\n try {\n await stopCurrent()\n } catch (cleanupError) {\n reportError(cleanupError)\n }\n try {\n recording?.dispose()\n } finally {\n recording = undefined\n }\n throw error\n }\n enabled = true\n if (options.autoProfile && options.profiler)\n safely(() => options.profiler!.startProfiling())\n publish()\n }\n const context = (name: string, attributes?: ClientAttributes) => ({\n name,\n correlationId: String(attributes?.id ?? ''),\n attributes: Object.entries(attributes ?? {})\n .filter(([, value]) => value !== undefined)\n .slice(0, 32)\n .map(([key, value]) => ({\n key: key.slice(0, 64),\n value: String(value).slice(0, 512),\n })),\n })\n const trace = {\n mark(name: string, attributes?: ClientAttributes) {\n safely(() => {\n if (!enabled || !recording) return\n recording.mark(context(name, attributes))\n emit({ name, entryType: 'mark', durationMs: 0, attributes })\n if (typeof attributes?.id === 'string') {\n let bucket = marks.get(attributes.id)\n if (!bucket) {\n if (marks.size >= 512) marks.delete(marks.keys().next().value!)\n bucket = { marks: new Map(), emitted: new Set() }\n marks.set(attributes.id, bucket)\n }\n if (bucket.marks.size >= 64 && !bucket.marks.has(name))\n bucket.marks.delete(bucket.marks.keys().next().value!)\n bucket.marks.set(name, recording.getStats().nowMs)\n }\n })\n },\n metric(\n name: string,\n value: number | string,\n attributes?: ClientAttributes\n ) {\n safely(() => {\n if (!enabled || !recording) return\n const numeric = Number(value)\n if (Number.isFinite(numeric))\n recording.recordMetric({\n ...context(name, attributes),\n value: numeric,\n unit: String(attributes?.unit ?? 'count'),\n })\n else recording.mark(context(name, { ...attributes, value }))\n emit({ name, entryType: 'metric', durationMs: 0, value, attributes })\n })\n },\n async measure<T>(\n name: string,\n fn: () => Promise<T>,\n attributes?: ClientAttributes\n ): Promise<T> {\n const started =\n enabled && options.sink ? globalThis.performance.now() : undefined\n const span = safely(() =>\n enabled ? recording?.startSpan(context(name, attributes)) : undefined\n )\n try {\n const value = await fn()\n safely(() => span?.end('success'))\n return value\n } catch (error) {\n safely(() => span?.end('error'))\n throw error\n } finally {\n if (started !== undefined)\n emit({\n name,\n entryType: 'measure',\n durationMs: Math.max(0, globalThis.performance.now() - started),\n attributes,\n })\n }\n },\n measureSince(\n name: string,\n startName: string,\n id: string,\n attributes?: ClientAttributes\n ) {\n safely(() => {\n if (!enabled || !recording) return\n const bucket = marks.get(id)\n const start = bucket?.marks.get(startName)\n if (\n start === undefined ||\n bucket!.emitted.has(name) ||\n bucket!.emitted.size >= 64\n )\n return\n bucket!.emitted.add(name)\n const durationMs = Math.max(0, recording.getStats().nowMs - start)\n recording.recordSpan({\n ...context(name, { ...attributes, id, startName }),\n timestampMs: start,\n durationMs,\n outcome: 'success',\n })\n emit({\n name,\n entryType: 'measure',\n durationMs,\n attributes: { ...attributes, id },\n })\n })\n },\n clear(id: string) {\n marks.delete(id)\n },\n }\n return {\n /** Once per client lifetime: elapsed time from client creation to the app-defined ready signal. */\n reportAppReady() {\n if (readyReported || !enabled) return\n readyReported = true\n trace.metric(\n 'app.ready.after_tracer_init',\n Math.max(0, globalThis.performance.now() - readinessStartMs),\n {\n unit: 'ms',\n source: 'app-readiness',\n definition:\n 'Tracer initialization to app ready signal; excludes earlier JS and native startup',\n }\n )\n },\n trace,\n start: () => enqueue(startCurrent),\n stop: () => enqueue(stopCurrent),\n clear: () =>\n enqueue(async () => {\n const wasEnabled = enabled\n await startCurrent()\n if (!wasEnabled) await stopCurrent()\n }),\n getRecording: () => recording,\n getError: () => snapshot.error,\n getSnapshot: () => snapshot,\n subscribe(listener: () => void) {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n open() {\n if (!disposed) publish({ visible: true })\n },\n close() {\n publish({ visible: false })\n },\n reportError,\n canShare: Boolean(options.share),\n canProfile: Boolean(options.profiler),\n canShareProfile: Boolean(options.shareProfile),\n export: () =>\n enqueue(async () => {\n if (!recording || !options.share) return\n await stopCurrent()\n await options.share(recording, 'recording')\n }),\n /** Share a snapshot while recording continues, e.g. right after catching a problem. */\n shareTrace: (format: TraceFormat = 'perfetto') =>\n enqueue(async () => {\n if (recording && options.share) await options.share(recording, format)\n }),\n /**\n * Mark the moment a tester saw a problem. With an idle profiler this also captures\n * a bounded Hermes profile, so the flag ships with what the JS thread was doing.\n */\n flag: (note?: string) => {\n trace.mark('flag', { source: 'flag', note })\n const profiler = options.profiler\n const windowMs = options.flagProfileMs ?? 10000\n if (!profiler || windowMs <= 0) return\n // enqueue already reports failures; the catches only avoid unhandled rejections.\n enqueue(async () => {\n if (!enabled || profiler.isProfiling()) return\n profiler.startProfiling()\n setTimeout(() => {\n enqueue(async () => {\n if (profiler.isProfiling()) await profiler.stopProfiling()\n }).catch(() => {})\n }, windowMs)\n }).catch(() => {})\n },\n toggleProfile: () =>\n enqueue(async () => {\n if (!enabled || !options.profiler) return\n if (options.profiler.isProfiling())\n await options.profiler.stopProfiling()\n else options.profiler.startProfiling()\n }),\n shareProfile: () =>\n enqueue(async () => {\n const path = options.profiler?.getProfilePath()\n if (path) await options.shareProfile?.(path)\n }),\n playground: () =>\n enqueue(async () => {\n if (enabled && recording)\n publish({ playground: await recordPlayground(recording) })\n }),\n dispose() {\n if (disposed) return tail\n disposed = true\n enabled = false\n publish({ visible: false })\n const result = tail.then(async () => {\n try {\n await stopCurrent()\n } finally {\n try {\n recording?.dispose()\n } finally {\n recording = undefined\n listeners.clear()\n }\n }\n })\n tail = result.catch(reportError)\n return result\n },\n }\n}\nexport type TraceClient = ReturnType<typeof createTraceClient>\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Tracing"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/expo/ExpoAdapter.ts
|
|
9
|
+
import * as FileSystem from "expo-file-system/legacy";
|
|
10
|
+
import * as Sharing from "expo-sharing";
|
|
11
|
+
function createExpoTraceSharing(options = {}) {
|
|
12
|
+
const shareFile = async (uri, mimeType) => {
|
|
13
|
+
if (!await Sharing.isAvailableAsync())
|
|
14
|
+
throw new Error("Native file sharing is unavailable on this device");
|
|
15
|
+
await Sharing.shareAsync(uri, {
|
|
16
|
+
mimeType,
|
|
17
|
+
dialogTitle: options.dialogTitle ?? "Share performance recording"
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
async share(recording, format = "recording") {
|
|
22
|
+
if (!FileSystem.cacheDirectory)
|
|
23
|
+
throw new Error("Application cache is unavailable");
|
|
24
|
+
const prefix = format === "perfetto" ? "perfetto-trace" : "native-trace";
|
|
25
|
+
const uri = `${FileSystem.cacheDirectory}${prefix}-${recording.getStats().sessionId}-${Date.now()}.json`;
|
|
26
|
+
const json = format === "perfetto" ? await recording.exportTraceEvents() : await recording.exportJson();
|
|
27
|
+
try {
|
|
28
|
+
await FileSystem.writeAsStringAsync(uri, json, {
|
|
29
|
+
encoding: FileSystem.EncodingType.UTF8
|
|
30
|
+
});
|
|
31
|
+
await shareFile(uri, "application/json");
|
|
32
|
+
} finally {
|
|
33
|
+
await FileSystem.deleteAsync(uri, { idempotent: true });
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
async shareProfile(path) {
|
|
37
|
+
await shareFile(
|
|
38
|
+
path.startsWith("file://") ? path : `file://${path}`,
|
|
39
|
+
"application/octet-stream"
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async function registerTraceDevMenu(client, options = {}) {
|
|
45
|
+
try {
|
|
46
|
+
const register = options.registerDevMenuItems ?? __require("expo-dev-client").registerDevMenuItems;
|
|
47
|
+
await register([
|
|
48
|
+
{
|
|
49
|
+
name: options.name ?? "Performance inspector",
|
|
50
|
+
shouldCollapse: true,
|
|
51
|
+
callback: () => client.open()
|
|
52
|
+
}
|
|
53
|
+
]);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
client.reportError(error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
createExpoTraceSharing,
|
|
60
|
+
registerTraceDevMenu
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=expo.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/expo/ExpoAdapter.ts"],
|
|
4
|
+
"sourcesContent": ["import * as FileSystem from 'expo-file-system/legacy'\nimport * as Sharing from 'expo-sharing'\nimport type { TraceClient, TraceFormat } from '../client/createTraceClient'\nimport type { Recording } from '../specs/Recording.nitro'\nexport interface ExpoSharingOptions {\n dialogTitle?: string\n}\n/** Native OS file sharing. No remote upload or file-path export to telemetry. */\nexport function createExpoTraceSharing(options: ExpoSharingOptions = {}) {\n const shareFile = async (uri: string, mimeType: string) => {\n if (!(await Sharing.isAvailableAsync()))\n throw new Error('Native file sharing is unavailable on this device')\n await Sharing.shareAsync(uri, {\n mimeType,\n dialogTitle: options.dialogTitle ?? 'Share performance recording',\n })\n }\n return {\n async share(recording: Recording, format: TraceFormat = 'recording') {\n if (!FileSystem.cacheDirectory)\n throw new Error('Application cache is unavailable')\n const prefix = format === 'perfetto' ? 'perfetto-trace' : 'native-trace'\n const uri = `${FileSystem.cacheDirectory}${prefix}-${\n recording.getStats().sessionId\n }-${Date.now()}.json`\n // Both formats serialize off the JS thread; only the finished string crosses JSI.\n const json =\n format === 'perfetto'\n ? await recording.exportTraceEvents()\n : await recording.exportJson()\n try {\n await FileSystem.writeAsStringAsync(uri, json, {\n encoding: FileSystem.EncodingType.UTF8,\n })\n await shareFile(uri, 'application/json')\n } finally {\n await FileSystem.deleteAsync(uri, { idempotent: true })\n }\n },\n async shareProfile(path: string) {\n await shareFile(\n path.startsWith('file://') ? path : `file://${path}`,\n 'application/octet-stream'\n )\n },\n }\n}\n/** Register only in a development build. The consumer owns client disposal. */\nexport async function registerTraceDevMenu(\n client: TraceClient,\n options: {\n name?: string\n registerDevMenuItems?: typeof import('expo-dev-client').registerDevMenuItems\n } = {}\n) {\n try {\n const register =\n options.registerDevMenuItems ??\n (require('expo-dev-client') as typeof import('expo-dev-client'))\n .registerDevMenuItems\n await register([\n {\n name: options.name ?? 'Performance inspector',\n shouldCollapse: true,\n callback: () => client.open(),\n },\n ])\n } catch (error) {\n client.reportError(error)\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;AAAA,YAAY,gBAAgB;AAC5B,YAAY,aAAa;AAOlB,SAAS,uBAAuB,UAA8B,CAAC,GAAG;AACvE,QAAM,YAAY,OAAO,KAAa,aAAqB;AACzD,QAAI,CAAE,MAAc,yBAAiB;AACnC,YAAM,IAAI,MAAM,mDAAmD;AACrE,UAAc,mBAAW,KAAK;AAAA,MAC5B;AAAA,MACA,aAAa,QAAQ,eAAe;AAAA,IACtC,CAAC;AAAA,EACH;AACA,SAAO;AAAA,IACL,MAAM,MAAM,WAAsB,SAAsB,aAAa;AACnE,UAAI,CAAY;AACd,cAAM,IAAI,MAAM,kCAAkC;AACpD,YAAM,SAAS,WAAW,aAAa,mBAAmB;AAC1D,YAAM,MAAM,GAAc,yBAAc,GAAG,MAAM,IAC/C,UAAU,SAAS,EAAE,SACvB,IAAI,KAAK,IAAI,CAAC;AAEd,YAAM,OACJ,WAAW,aACP,MAAM,UAAU,kBAAkB,IAClC,MAAM,UAAU,WAAW;AACjC,UAAI;AACF,cAAiB,8BAAmB,KAAK,MAAM;AAAA,UAC7C,UAAqB,wBAAa;AAAA,QACpC,CAAC;AACD,cAAM,UAAU,KAAK,kBAAkB;AAAA,MACzC,UAAE;AACA,cAAiB,uBAAY,KAAK,EAAE,YAAY,KAAK,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,IACA,MAAM,aAAa,MAAc;AAC/B,YAAM;AAAA,QACJ,KAAK,WAAW,SAAS,IAAI,OAAO,UAAU,IAAI;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,qBACpB,QACA,UAGI,CAAC,GACL;AACA,MAAI;AACF,UAAM,WACJ,QAAQ,wBACP,UAAQ,iBAAiB,EACvB;AACL,UAAM,SAAS;AAAA,MACb;AAAA,QACE,MAAM,QAAQ,QAAQ;AAAA,QACtB,gBAAgB;AAAA,QAChB,UAAU,MAAM,OAAO,KAAK;AAAA,MAC9B;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO,YAAY,KAAK;AAAA,EAC1B;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/index.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"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,oBAAoB;AAGtB,IAAM,UACX,aAAa,mBAAmC,SAAS;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// src/plugins/performance.ts
|
|
2
|
+
function createPerformancePlugin(api, onEntry) {
|
|
3
|
+
return {
|
|
4
|
+
id: "performance",
|
|
5
|
+
start({ recording, reportError }) {
|
|
6
|
+
const offset = recording.getStats().nowMs - api.performance.now();
|
|
7
|
+
let stopped = false;
|
|
8
|
+
const ingest = (entries) => {
|
|
9
|
+
if (stopped) return;
|
|
10
|
+
for (const entry of entries) {
|
|
11
|
+
try {
|
|
12
|
+
const timestampMs = entry.startTime + offset;
|
|
13
|
+
if (timestampMs < 0) continue;
|
|
14
|
+
const data = entry;
|
|
15
|
+
onEntry?.({
|
|
16
|
+
name: entry.name,
|
|
17
|
+
entryType: entry.entryType,
|
|
18
|
+
durationMs: entry.duration,
|
|
19
|
+
value: typeof data.value === "string" || typeof data.value === "number" ? data.value : void 0,
|
|
20
|
+
attributes: data.detail
|
|
21
|
+
});
|
|
22
|
+
const context = {
|
|
23
|
+
name: entry.name.slice(0, 128),
|
|
24
|
+
correlationId: typeof data.detail?.id === "string" ? data.detail.id.slice(0, 128) : "",
|
|
25
|
+
attributes: [
|
|
26
|
+
{ key: "source", value: "performance" },
|
|
27
|
+
{ key: "source.startTimeMs", value: String(entry.startTime) }
|
|
28
|
+
]
|
|
29
|
+
};
|
|
30
|
+
if (entry.entryType === "longtask")
|
|
31
|
+
recording.recordSpan({
|
|
32
|
+
...context,
|
|
33
|
+
name: "js.longtask",
|
|
34
|
+
timestampMs,
|
|
35
|
+
durationMs: entry.duration,
|
|
36
|
+
outcome: "success"
|
|
37
|
+
});
|
|
38
|
+
else if (entry.entryType === "measure")
|
|
39
|
+
recording.recordSpan({
|
|
40
|
+
...context,
|
|
41
|
+
timestampMs,
|
|
42
|
+
durationMs: entry.duration,
|
|
43
|
+
outcome: "success"
|
|
44
|
+
});
|
|
45
|
+
else if (entry.entryType === "mark")
|
|
46
|
+
recording.mark({ ...context, timestampMs });
|
|
47
|
+
else if (entry.entryType === "metric" && typeof data.value === "number" && Number.isFinite(data.value))
|
|
48
|
+
recording.recordMetric({
|
|
49
|
+
...context,
|
|
50
|
+
timestampMs,
|
|
51
|
+
value: data.value,
|
|
52
|
+
unit: typeof data.detail?.unit === "string" ? data.detail.unit.slice(0, 32) : "unspecified"
|
|
53
|
+
});
|
|
54
|
+
} catch (error) {
|
|
55
|
+
reportError(error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const observer = new api.PerformanceObserver(
|
|
60
|
+
(list) => ingest(list.getEntries())
|
|
61
|
+
);
|
|
62
|
+
const supported = api.PerformanceObserver.supportedEntryTypes;
|
|
63
|
+
const entryTypes = ["mark", "measure", "metric", "longtask"].filter(
|
|
64
|
+
(type) => supported ? supported.includes(type) : type !== "longtask"
|
|
65
|
+
);
|
|
66
|
+
try {
|
|
67
|
+
observer.observe({ entryTypes });
|
|
68
|
+
} catch (error) {
|
|
69
|
+
observer.disconnect();
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
stop() {
|
|
74
|
+
if (stopped) return;
|
|
75
|
+
try {
|
|
76
|
+
ingest(observer.takeRecords());
|
|
77
|
+
} finally {
|
|
78
|
+
stopped = true;
|
|
79
|
+
observer.disconnect();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
createPerformancePlugin
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=performance.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/plugins/performance.ts"],
|
|
4
|
+
"sourcesContent": ["import type { TracingEntry } from '../client/TracingSink'\nimport type performance from 'react-native-performance'\nimport type { PerformanceObserver } from 'react-native-performance'\nimport type { TracePlugin } from './TracePlugin'\n/** Default measurement-source dependencies; supports the installed RN performance API. */\nexport interface PerformancePluginOptions {\n /** Same clock used by the supplied observer's entries. */\n performance: typeof performance\n /** PerformanceObserver from react-native-performance. */\n PerformanceObserver: typeof PerformanceObserver\n}\n/** Observe user timing without patching globals, clearing shared buffers or timing network bodies. */\nexport function createPerformancePlugin(\n api: PerformancePluginOptions,\n onEntry?: (entry: TracingEntry) => void\n): TracePlugin {\n return {\n id: 'performance',\n start({ recording, reportError }) {\n const offset = recording.getStats().nowMs - api.performance.now()\n let stopped = false\n const ingest = (\n entries: ReturnType<PerformanceObserver['takeRecords']>\n ) => {\n if (stopped) return\n for (const entry of entries) {\n try {\n const timestampMs = entry.startTime + offset\n if (timestampMs < 0) continue // Previous history is outside this recording.\n const data = entry as typeof entry & {\n value?: unknown\n detail?: { id?: unknown; unit?: unknown }\n }\n onEntry?.({\n name: entry.name,\n entryType: entry.entryType,\n durationMs: entry.duration,\n value:\n typeof data.value === 'string' || typeof data.value === 'number'\n ? data.value\n : undefined,\n attributes: data.detail,\n })\n const context = {\n name: entry.name.slice(0, 128),\n correlationId:\n typeof data.detail?.id === 'string'\n ? data.detail.id.slice(0, 128)\n : '',\n attributes: [\n { key: 'source', value: 'performance' },\n { key: 'source.startTimeMs', value: String(entry.startTime) },\n ],\n }\n if (entry.entryType === 'longtask')\n recording.recordSpan({\n ...context,\n name: 'js.longtask',\n timestampMs,\n durationMs: entry.duration,\n outcome: 'success',\n })\n else if (entry.entryType === 'measure')\n recording.recordSpan({\n ...context,\n timestampMs,\n durationMs: entry.duration,\n outcome: 'success',\n })\n else if (entry.entryType === 'mark')\n recording.mark({ ...context, timestampMs })\n else if (\n entry.entryType === 'metric' &&\n typeof data.value === 'number' &&\n Number.isFinite(data.value)\n )\n recording.recordMetric({\n ...context,\n timestampMs,\n value: data.value,\n unit:\n typeof data.detail?.unit === 'string'\n ? data.detail.unit.slice(0, 32)\n : 'unspecified',\n })\n } catch (error) {\n reportError(error)\n }\n }\n }\n const observer = new api.PerformanceObserver((list) =>\n ingest(list.getEntries())\n )\n // Global RN observers reject unknown types; react-native-performance lacks longtask.\n const supported = (\n api.PerformanceObserver as { supportedEntryTypes?: readonly string[] }\n ).supportedEntryTypes\n const entryTypes = ['mark', 'measure', 'metric', 'longtask'].filter(\n (type) => (supported ? supported.includes(type) : type !== 'longtask')\n )\n try {\n observer.observe({ entryTypes } as never)\n } catch (error) {\n observer.disconnect()\n throw error\n }\n return {\n stop() {\n if (stopped) return\n try {\n ingest(observer.takeRecords())\n } finally {\n stopped = true\n observer.disconnect()\n }\n },\n }\n },\n }\n}\n"],
|
|
5
|
+
"mappings": ";AAYO,SAAS,wBACd,KACA,SACa;AACb,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM,EAAE,WAAW,YAAY,GAAG;AAChC,YAAM,SAAS,UAAU,SAAS,EAAE,QAAQ,IAAI,YAAY,IAAI;AAChE,UAAI,UAAU;AACd,YAAM,SAAS,CACb,YACG;AACH,YAAI,QAAS;AACb,mBAAW,SAAS,SAAS;AAC3B,cAAI;AACF,kBAAM,cAAc,MAAM,YAAY;AACtC,gBAAI,cAAc,EAAG;AACrB,kBAAM,OAAO;AAIb,sBAAU;AAAA,cACR,MAAM,MAAM;AAAA,cACZ,WAAW,MAAM;AAAA,cACjB,YAAY,MAAM;AAAA,cAClB,OACE,OAAO,KAAK,UAAU,YAAY,OAAO,KAAK,UAAU,WACpD,KAAK,QACL;AAAA,cACN,YAAY,KAAK;AAAA,YACnB,CAAC;AACD,kBAAM,UAAU;AAAA,cACd,MAAM,MAAM,KAAK,MAAM,GAAG,GAAG;AAAA,cAC7B,eACE,OAAO,KAAK,QAAQ,OAAO,WACvB,KAAK,OAAO,GAAG,MAAM,GAAG,GAAG,IAC3B;AAAA,cACN,YAAY;AAAA,gBACV,EAAE,KAAK,UAAU,OAAO,cAAc;AAAA,gBACtC,EAAE,KAAK,sBAAsB,OAAO,OAAO,MAAM,SAAS,EAAE;AAAA,cAC9D;AAAA,YACF;AACA,gBAAI,MAAM,cAAc;AACtB,wBAAU,WAAW;AAAA,gBACnB,GAAG;AAAA,gBACH,MAAM;AAAA,gBACN;AAAA,gBACA,YAAY,MAAM;AAAA,gBAClB,SAAS;AAAA,cACX,CAAC;AAAA,qBACM,MAAM,cAAc;AAC3B,wBAAU,WAAW;AAAA,gBACnB,GAAG;AAAA,gBACH;AAAA,gBACA,YAAY,MAAM;AAAA,gBAClB,SAAS;AAAA,cACX,CAAC;AAAA,qBACM,MAAM,cAAc;AAC3B,wBAAU,KAAK,EAAE,GAAG,SAAS,YAAY,CAAC;AAAA,qBAE1C,MAAM,cAAc,YACpB,OAAO,KAAK,UAAU,YACtB,OAAO,SAAS,KAAK,KAAK;AAE1B,wBAAU,aAAa;AAAA,gBACrB,GAAG;AAAA,gBACH;AAAA,gBACA,OAAO,KAAK;AAAA,gBACZ,MACE,OAAO,KAAK,QAAQ,SAAS,WACzB,KAAK,OAAO,KAAK,MAAM,GAAG,EAAE,IAC5B;AAAA,cACR,CAAC;AAAA,UACL,SAAS,OAAO;AACd,wBAAY,KAAK;AAAA,UACnB;AAAA,QACF;AAAA,MACF;AACA,YAAM,WAAW,IAAI,IAAI;AAAA,QAAoB,CAAC,SAC5C,OAAO,KAAK,WAAW,CAAC;AAAA,MAC1B;AAEA,YAAM,YACJ,IAAI,oBACJ;AACF,YAAM,aAAa,CAAC,QAAQ,WAAW,UAAU,UAAU,EAAE;AAAA,QAC3D,CAAC,SAAU,YAAY,UAAU,SAAS,IAAI,IAAI,SAAS;AAAA,MAC7D;AACA,UAAI;AACF,iBAAS,QAAQ,EAAE,WAAW,CAAU;AAAA,MAC1C,SAAS,OAAO;AACd,iBAAS,WAAW;AACpB,cAAM;AAAA,MACR;AACA,aAAO;AAAA,QACL,OAAO;AACL,cAAI,QAAS;AACb,cAAI;AACF,mBAAO,SAAS,YAAY,CAAC;AAAA,UAC/B,UAAE;AACA,sBAAU;AACV,qBAAS,WAAW;AAAA,UACtB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|