@symbiote-native/app-metrics 0.0.0-stage → 0.1.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 (137) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +183 -2
  3. package/build/angular/app-metrics-root.d.ts +5 -0
  4. package/build/angular/app-metrics-root.js +62 -0
  5. package/build/angular/index.d.ts +3 -0
  6. package/build/angular/index.js +5 -0
  7. package/build/angular/inject-network-request-observer.d.ts +5 -0
  8. package/build/angular/inject-network-request-observer.js +7 -0
  9. package/build/core/app-metrics.d.ts +24 -0
  10. package/build/core/app-metrics.js +47 -0
  11. package/build/core/index.d.ts +5 -0
  12. package/build/core/index.js +6 -0
  13. package/build/core/install-error-handler.d.ts +2 -0
  14. package/build/core/install-error-handler.js +45 -0
  15. package/build/core/native-module.d.ts +19 -0
  16. package/build/core/native-module.js +3 -0
  17. package/build/core/network-request-observer-lifecycle.d.ts +8 -0
  18. package/build/core/network-request-observer-lifecycle.js +19 -0
  19. package/build/core/network-request-observer-subscription.d.ts +15 -0
  20. package/build/core/network-request-observer-subscription.js +22 -0
  21. package/build/core/network-request-observer.d.ts +7 -0
  22. package/build/core/network-request-observer.js +1 -0
  23. package/build/core/report-caught-error.d.ts +2 -0
  24. package/build/core/report-caught-error.js +20 -0
  25. package/build/core/session.d.ts +12 -0
  26. package/build/core/session.js +1 -0
  27. package/build/core/types.d.ts +168 -0
  28. package/build/core/types.js +3 -0
  29. package/build/react/app-metrics-error-boundary.d.ts +26 -0
  30. package/build/react/app-metrics-error-boundary.js +28 -0
  31. package/build/react/app-metrics-root.d.ts +12 -0
  32. package/build/react/app-metrics-root.js +24 -0
  33. package/build/react/index.d.ts +4 -0
  34. package/build/react/index.js +4 -0
  35. package/build/react/use-network-request-observer.d.ts +5 -0
  36. package/build/react/use-network-request-observer.js +23 -0
  37. package/build/solid/app-metrics-error-boundary.d.ts +15 -0
  38. package/build/solid/app-metrics-error-boundary.js +17 -0
  39. package/build/solid/app-metrics-root.d.ts +9 -0
  40. package/build/solid/app-metrics-root.js +18 -0
  41. package/build/solid/index.d.ts +4 -0
  42. package/build/solid/index.js +4 -0
  43. package/build/solid/use-network-request-observer.d.ts +5 -0
  44. package/build/solid/use-network-request-observer.js +6 -0
  45. package/build/svelte/AppMetricsErrorBoundary.svelte +17 -0
  46. package/build/svelte/AppMetricsErrorBoundary.svelte.d.ts +4 -0
  47. package/build/svelte/AppMetricsRoot.svelte +22 -0
  48. package/build/svelte/AppMetricsRoot.svelte.d.ts +4 -0
  49. package/build/svelte/app-metrics-error-boundary-props.d.ts +12 -0
  50. package/build/svelte/app-metrics-error-boundary-props.js +3 -0
  51. package/build/svelte/app-metrics-root-props.d.ts +9 -0
  52. package/build/svelte/app-metrics-root-props.js +1 -0
  53. package/build/svelte/index.d.ts +7 -0
  54. package/build/svelte/index.js +4 -0
  55. package/build/svelte/use-network-request-observer.svelte.d.ts +3 -0
  56. package/build/svelte/use-network-request-observer.svelte.js +14 -0
  57. package/build/vue/app-metrics-error-boundary.d.ts +14 -0
  58. package/build/vue/app-metrics-error-boundary.js +27 -0
  59. package/build/vue/app-metrics-root.d.ts +7 -0
  60. package/build/vue/app-metrics-root.js +15 -0
  61. package/build/vue/index.d.ts +4 -0
  62. package/build/vue/index.js +4 -0
  63. package/build/vue/use-network-request-observer.d.ts +5 -0
  64. package/build/vue/use-network-request-observer.js +6 -0
  65. package/build-ngc/angular/app-metrics-root.d.ts +8 -0
  66. package/build-ngc/angular/app-metrics-root.js +20 -0
  67. package/build-ngc/angular/app-metrics-root.js.map +1 -0
  68. package/build-ngc/angular/index.d.ts +3 -0
  69. package/build-ngc/angular/index.js +6 -0
  70. package/build-ngc/angular/index.js.map +1 -0
  71. package/build-ngc/angular/inject-network-request-observer.d.ts +5 -0
  72. package/build-ngc/angular/inject-network-request-observer.js +8 -0
  73. package/build-ngc/angular/inject-network-request-observer.js.map +1 -0
  74. package/build-ngc/core/app-metrics.d.ts +24 -0
  75. package/build-ngc/core/app-metrics.js +48 -0
  76. package/build-ngc/core/app-metrics.js.map +1 -0
  77. package/build-ngc/core/index.d.ts +5 -0
  78. package/build-ngc/core/index.js +7 -0
  79. package/build-ngc/core/index.js.map +1 -0
  80. package/build-ngc/core/install-error-handler.d.ts +2 -0
  81. package/build-ngc/core/install-error-handler.js +46 -0
  82. package/build-ngc/core/install-error-handler.js.map +1 -0
  83. package/build-ngc/core/native-module.d.ts +19 -0
  84. package/build-ngc/core/native-module.js +4 -0
  85. package/build-ngc/core/native-module.js.map +1 -0
  86. package/build-ngc/core/network-request-observer-lifecycle.d.ts +8 -0
  87. package/build-ngc/core/network-request-observer-lifecycle.js +20 -0
  88. package/build-ngc/core/network-request-observer-lifecycle.js.map +1 -0
  89. package/build-ngc/core/network-request-observer-subscription.d.ts +15 -0
  90. package/build-ngc/core/network-request-observer-subscription.js +23 -0
  91. package/build-ngc/core/network-request-observer-subscription.js.map +1 -0
  92. package/build-ngc/core/network-request-observer.d.ts +7 -0
  93. package/build-ngc/core/network-request-observer.js +2 -0
  94. package/build-ngc/core/network-request-observer.js.map +1 -0
  95. package/build-ngc/core/report-caught-error.d.ts +2 -0
  96. package/build-ngc/core/report-caught-error.js +21 -0
  97. package/build-ngc/core/report-caught-error.js.map +1 -0
  98. package/build-ngc/core/session.d.ts +12 -0
  99. package/build-ngc/core/session.js +2 -0
  100. package/build-ngc/core/session.js.map +1 -0
  101. package/build-ngc/core/types.d.ts +168 -0
  102. package/build-ngc/core/types.js +4 -0
  103. package/build-ngc/core/types.js.map +1 -0
  104. package/native-link.json +12 -0
  105. package/package.json +147 -3
  106. package/src/angular/app-metrics-root.ts +14 -0
  107. package/src/angular/index.ts +8 -0
  108. package/src/angular/inject-network-request-observer.ts +18 -0
  109. package/src/core/app-metrics.ts +74 -0
  110. package/src/core/index.ts +52 -0
  111. package/src/core/install-error-handler.ts +55 -0
  112. package/src/core/native-module.ts +36 -0
  113. package/src/core/network-request-observer-lifecycle.ts +37 -0
  114. package/src/core/network-request-observer-subscription.ts +53 -0
  115. package/src/core/network-request-observer.ts +15 -0
  116. package/src/core/report-caught-error.ts +26 -0
  117. package/src/core/session.ts +17 -0
  118. package/src/core/types.ts +200 -0
  119. package/src/react/app-metrics-error-boundary.tsx +67 -0
  120. package/src/react/app-metrics-root.tsx +53 -0
  121. package/src/react/index.ts +11 -0
  122. package/src/react/use-network-request-observer.ts +41 -0
  123. package/src/solid/app-metrics-error-boundary.tsx +36 -0
  124. package/src/solid/app-metrics-root.tsx +29 -0
  125. package/src/solid/index.ts +12 -0
  126. package/src/solid/use-network-request-observer.ts +17 -0
  127. package/src/svelte/AppMetricsErrorBoundary.svelte +17 -0
  128. package/src/svelte/AppMetricsRoot.svelte +21 -0
  129. package/src/svelte/app-metrics-error-boundary-props.ts +17 -0
  130. package/src/svelte/app-metrics-root-props.ts +10 -0
  131. package/src/svelte/index.ts +10 -0
  132. package/src/svelte/svelte-compile.test-helper.ts +7 -0
  133. package/src/svelte/use-network-request-observer.svelte.ts +26 -0
  134. package/src/vue/app-metrics-error-boundary.ts +56 -0
  135. package/src/vue/app-metrics-root.ts +32 -0
  136. package/src/vue/index.ts +12 -0
  137. package/src/vue/use-network-request-observer.ts +17 -0
@@ -0,0 +1,168 @@
1
+ export type IAppStartupTimes = {
2
+ /** @platform ios */
3
+ loadTime?: number;
4
+ coldLaunchTime?: number;
5
+ warmLaunchTime?: number;
6
+ bundleLoadTime?: number;
7
+ timeToFirstRender?: number;
8
+ timeToInteractive?: number;
9
+ };
10
+ export type IMemoryUsageSnapshot = {
11
+ /** @platform ios */
12
+ allocated?: number;
13
+ physical: number;
14
+ available: number;
15
+ /** @platform android */
16
+ javaHeap?: number;
17
+ };
18
+ export type IFrameRateMetrics = {
19
+ renderedFrames: number;
20
+ expectedFrames: number;
21
+ droppedFrames: number;
22
+ /** Takes at least 700ms to render */
23
+ frozenFrames: number;
24
+ /** Takes at least 17ms to render */
25
+ slowFrames: number;
26
+ freezeTime: number;
27
+ sessionDuration: number;
28
+ };
29
+ export type IMetric = {
30
+ timestamp: string;
31
+ category: string;
32
+ name: string;
33
+ value: number;
34
+ sessionId: string;
35
+ routeName?: string | null;
36
+ params?: Record<string, unknown>;
37
+ };
38
+ export type IMetricAttributes = {
39
+ routeName?: string | null;
40
+ params?: Record<string, unknown>;
41
+ };
42
+ /** Ordered from least to most severe */
43
+ export type ILogSeverity = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
44
+ export type ILogAttributeValue = string | number | boolean | ILogAttributeValue[] | {
45
+ [key: string]: ILogAttributeValue;
46
+ };
47
+ export type ILogRecord = {
48
+ timestamp: string;
49
+ name: string;
50
+ body?: string | null;
51
+ attributes?: Record<string, ILogAttributeValue> | null;
52
+ severity: ILogSeverity;
53
+ };
54
+ export type ILogEventOptions = {
55
+ displayName?: string | null;
56
+ body?: string | null;
57
+ attributes?: Record<string, ILogAttributeValue> | null;
58
+ /** @default 'info' */
59
+ severity?: ILogSeverity | null;
60
+ };
61
+ export type ISessionType = 'main' | 'foreground' | 'screen' | 'custom' | 'unknown';
62
+ /** Every `IMetric` field except `sessionId`, implied by the owning session */
63
+ export type IMetricInput = Omit<IMetric, 'sessionId'>;
64
+ export type ICallStackFrame = {
65
+ /** @platform ios */
66
+ binaryName?: string | null;
67
+ /** @platform ios */
68
+ binaryUUID?: string | null;
69
+ /** @platform ios */
70
+ address?: number | null;
71
+ /** @platform ios */
72
+ offsetIntoBinaryTextSegment?: number | null;
73
+ /** @platform ios */
74
+ sampleCount?: number | null;
75
+ subFrames?: ICallStackFrame[] | null;
76
+ /** ios: on-device `dladdr` symbolication. android: the JVM stack-trace frame string */
77
+ symbol?: string | null;
78
+ };
79
+ export type ICallStack = {
80
+ threadAttributed?: boolean | null;
81
+ callStackRootFrames?: ICallStackFrame[] | null;
82
+ };
83
+ export type ICallStackTree = {
84
+ callStacks?: ICallStack[] | null;
85
+ };
86
+ /** ios (MetricKit) reports the numeric fields; android reports `exceptionReason` as a string */
87
+ export type ICrashReport = {
88
+ /** @platform ios */
89
+ exceptionType?: number | null;
90
+ /** @platform ios */
91
+ exceptionCode?: number | null;
92
+ /** Unix signal number, e.g. SIGSEGV = 11 */
93
+ signal?: number | null;
94
+ terminationReason?: string | null;
95
+ /** @platform ios */
96
+ virtualMemoryRegionInfo?: string | null;
97
+ /** ios: a structured MetricKit reason object. android: a plain composed string */
98
+ exceptionReason?: {
99
+ composedMessage: string;
100
+ formatString: string;
101
+ arguments: string[];
102
+ exceptionType: string;
103
+ className: string;
104
+ exceptionName: string;
105
+ } | string | null;
106
+ callStackTree?: ICallStackTree | null;
107
+ /** `null` for an orphan crash with no attributable session. @platform android */
108
+ sessionId?: string | null;
109
+ appVersion: string;
110
+ timestampBegin: string;
111
+ /** @platform ios */
112
+ timestampEnd?: string;
113
+ ingestedAt: string;
114
+ };
115
+ export type INetworkRequestStartedEvent = {
116
+ id: string;
117
+ url: string;
118
+ method: string;
119
+ startedAt: string;
120
+ };
121
+ export type INetworkRequestRedirect = {
122
+ fromUrl: string;
123
+ toUrl: string;
124
+ statusCode: number;
125
+ };
126
+ export type INetworkRequestCompletedEvent = {
127
+ id: string;
128
+ url: string;
129
+ method: string;
130
+ statusCode: number | null;
131
+ networkProtocol: string | null;
132
+ requestBytesSent: number | null;
133
+ responseBytesReceived: number | null;
134
+ errorDescription: string | null;
135
+ startedAt: string | null;
136
+ completedAt: string | null;
137
+ totalDuration: number;
138
+ redirects: INetworkRequestRedirect[];
139
+ };
140
+ /** An unset field places no constraint; fields AND together, entries within one OR together */
141
+ export type INetworkRequestFilter = {
142
+ hosts?: string[] | null;
143
+ methods?: string[] | null;
144
+ };
145
+ export type INetworkRequestObserverEvents = {
146
+ requestStarted(event: INetworkRequestStartedEvent): void;
147
+ requestCompleted(event: INetworkRequestCompletedEvent): void;
148
+ };
149
+ /** Debug-only, from `getInactiveSessions()` as a plain eager record, not a shared object */
150
+ export type IDebugSession = {
151
+ id: string;
152
+ type: ISessionType;
153
+ startDate: string;
154
+ endDate?: string | null;
155
+ metrics: IMetric[];
156
+ logs: ILogRecord[];
157
+ crashReport?: ICrashReport | null;
158
+ };
159
+ /** Recorded natively as an OpenTelemetry-shaped `js.exception` log event */
160
+ export type IReportErrorInput = {
161
+ source: 'global' | 'errorBoundary' | 'reportedByUser';
162
+ type?: string;
163
+ message: string;
164
+ stacktrace?: string;
165
+ /** The React component stack, error-boundary captures only */
166
+ componentStack?: string;
167
+ isFatal: boolean;
168
+ };
@@ -0,0 +1,3 @@
1
+ // Ported verbatim from expo-app-metrics's types.ts (sdk-57), renamed with this repo's
2
+ // `I`-prefix convention
3
+ export {};
@@ -0,0 +1,26 @@
1
+ import { Component, type ErrorInfo, type ReactElement, type ReactNode } from 'react';
2
+ export type IAppMetricsErrorBoundaryFallbackProps = {
3
+ /** The value the subtree threw, usually an `Error` but any value can be thrown */
4
+ error: unknown;
5
+ /** Clears the caught error and re-renders the children from a clean, re-mounted state */
6
+ resetError: () => void;
7
+ };
8
+ export type IAppMetricsErrorBoundaryProps = {
9
+ children: ReactNode;
10
+ /** A React element, a render function receiving `error`/`resetError`, or `null` */
11
+ fallback: ReactElement | null | ((props: IAppMetricsErrorBoundaryFallbackProps) => ReactNode);
12
+ };
13
+ type IState = {
14
+ /** Tracked separately from `error` since the thrown value itself can be falsy */
15
+ hasError: boolean;
16
+ error: unknown;
17
+ };
18
+ /** Records a render-phase error via `reportError` and renders `fallback` in place of it */
19
+ export declare class AppMetricsErrorBoundary extends Component<IAppMetricsErrorBoundaryProps, IState> {
20
+ state: IState;
21
+ static getDerivedStateFromError(error: unknown): IState;
22
+ componentDidCatch(error: unknown, errorInfo: ErrorInfo): void;
23
+ render(): ReactNode;
24
+ private resetError;
25
+ }
26
+ export {};
@@ -0,0 +1,28 @@
1
+ import { Component, } from 'react';
2
+ import { reportCaughtError } from '../core/report-caught-error.js';
3
+ /** Records a render-phase error via `reportError` and renders `fallback` in place of it */
4
+ export class AppMetricsErrorBoundary extends Component {
5
+ state = { hasError: false, error: null };
6
+ static getDerivedStateFromError(error) {
7
+ return { hasError: true, error };
8
+ }
9
+ componentDidCatch(error, errorInfo) {
10
+ if (__DEV__) {
11
+ console.warn('[app-metrics] AppMetricsErrorBoundary caught a render error:', error);
12
+ }
13
+ reportCaughtError(error, errorInfo.componentStack?.trim() || undefined);
14
+ }
15
+ render() {
16
+ if (!this.state.hasError) {
17
+ return this.props.children;
18
+ }
19
+ const { fallback } = this.props;
20
+ if (typeof fallback === 'function') {
21
+ return fallback({ error: this.state.error, resetError: this.resetError });
22
+ }
23
+ return fallback;
24
+ }
25
+ resetError = () => {
26
+ this.setState({ hasError: false, error: null });
27
+ };
28
+ }
@@ -0,0 +1,12 @@
1
+ import { type ComponentType, type ReactElement, type ReactNode } from 'react';
2
+ import { type IAppMetricsErrorBoundaryProps } from './app-metrics-error-boundary';
3
+ export type IAppMetricsRootProps = {
4
+ children: ReactNode;
5
+ /** Omitting it leaves the tree unwrapped; pass `null` to capture without rendering anything */
6
+ errorBoundaryFallback?: IAppMetricsErrorBoundaryProps['fallback'];
7
+ };
8
+ /** Marks the first render, so time-to-first-render is measured without a manual call */
9
+ export declare function AppMetricsRoot({ children, errorBoundaryFallback, }: IAppMetricsRootProps): ReactElement;
10
+ export declare namespace AppMetricsRoot {
11
+ var wrap: <P extends Record<string, unknown>>(WrappedComponent: ComponentType<P>) => ComponentType<P>;
12
+ }
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, } from 'react';
3
+ import { markFirstRender } from '../core/index.js';
4
+ import { AppMetricsErrorBoundary, } from './app-metrics-error-boundary.js';
5
+ /** Marks the first render, so time-to-first-render is measured without a manual call */
6
+ export function AppMetricsRoot({ children, errorBoundaryFallback, }) {
7
+ useEffect(() => {
8
+ markFirstRender();
9
+ }, []);
10
+ // Only OMITTING the prop leaves the tree unwrapped - an explicit `null` still mounts the
11
+ // boundary and renders nothing, so the error is captured rather than propagating
12
+ if (errorBoundaryFallback !== undefined) {
13
+ return (_jsx(AppMetricsErrorBoundary, { fallback: errorBoundaryFallback, children: children }));
14
+ }
15
+ return _jsx(_Fragment, { children: children });
16
+ }
17
+ /** Wraps `WrappedComponent` in a root, for one call at the app's entry point */
18
+ AppMetricsRoot.wrap = function wrap(WrappedComponent) {
19
+ function Wrapped(props) {
20
+ return (_jsx(AppMetricsRoot, { children: _jsx(WrappedComponent, { ...props }) }));
21
+ }
22
+ Wrapped.displayName = `AppMetricsRoot(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
23
+ return Wrapped;
24
+ };
@@ -0,0 +1,4 @@
1
+ export * from '../core';
2
+ export { AppMetricsErrorBoundary, type IAppMetricsErrorBoundaryFallbackProps, type IAppMetricsErrorBoundaryProps, } from './app-metrics-error-boundary';
3
+ export { AppMetricsRoot, type IAppMetricsRootProps } from './app-metrics-root';
4
+ export { useNetworkRequestObserver, type IUseNetworkRequestObserverOptions, } from './use-network-request-observer';
@@ -0,0 +1,4 @@
1
+ export * from '../core/index.js';
2
+ export { AppMetricsErrorBoundary, } from './app-metrics-error-boundary.js';
3
+ export { AppMetricsRoot } from './app-metrics-root.js';
4
+ export { useNetworkRequestObserver, } from './use-network-request-observer.js';
@@ -0,0 +1,5 @@
1
+ import { NetworkRequestObserver } from '../core';
2
+ import type { IUseNetworkRequestObserverOptions } from '../core/network-request-observer-lifecycle';
3
+ export type { IUseNetworkRequestObserverOptions } from '../core/network-request-observer-lifecycle';
4
+ /** Allocates a `NetworkRequestObserver` for the component's lifetime, releases it on unmount */
5
+ export declare function useNetworkRequestObserver(options?: IUseNetworkRequestObserverOptions): NetworkRequestObserver;
@@ -0,0 +1,23 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { useReleasingSharedObject } from 'expo-modules-core';
3
+ import { NetworkRequestObserver } from '../core/index.js';
4
+ import { filterKeyOf, subscribeNetworkRequestObserverEvents, } from '../core/network-request-observer-subscription.js';
5
+ /** Allocates a `NetworkRequestObserver` for the component's lifetime, releases it on unmount */
6
+ export function useNetworkRequestObserver(options = {}) {
7
+ const filterKey = filterKeyOf(options.filter);
8
+ const observer = useReleasingSharedObject(() => new NetworkRequestObserver(options.filter), []);
9
+ // The constructor already applied the initial filter - only a LATER change goes through
10
+ // `setFilter`, seeded with the mount key so the first effect run is a no-op
11
+ const appliedFilterKey = useRef(filterKey);
12
+ useEffect(() => {
13
+ if (appliedFilterKey.current === filterKey)
14
+ return;
15
+ appliedFilterKey.current = filterKey;
16
+ observer.setFilter(options.filter ?? null);
17
+ // eslint-disable-next-line react-hooks/exhaustive-deps
18
+ }, [observer, filterKey]);
19
+ const optionsRef = useRef(options);
20
+ optionsRef.current = options;
21
+ useEffect(() => subscribeNetworkRequestObserverEvents(observer, () => optionsRef.current), [observer]);
22
+ return observer;
23
+ }
@@ -0,0 +1,15 @@
1
+ import { type JSX } from 'solid-js';
2
+ export type IAppMetricsErrorBoundaryFallbackProps = {
3
+ /** The value the subtree threw, usually an `Error` but any value can be thrown */
4
+ error: unknown;
5
+ /** Clears the caught error and re-renders the children from a clean state */
6
+ resetError: () => void;
7
+ };
8
+ export type IAppMetricsErrorBoundaryFallback = JSX.Element | ((props: IAppMetricsErrorBoundaryFallbackProps) => JSX.Element);
9
+ export type IAppMetricsErrorBoundaryProps = {
10
+ /** A JSX element, a render function receiving `error`/`resetError`, or `null` */
11
+ fallback: IAppMetricsErrorBoundaryFallback;
12
+ children: JSX.Element;
13
+ };
14
+ /** Records a render-phase error, renders `fallback` in place of the failed subtree */
15
+ export declare function AppMetricsErrorBoundary(props: IAppMetricsErrorBoundaryProps): JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { ErrorBoundary } from 'solid-js';
2
+ import { reportCaughtError } from '../core/report-caught-error.js';
3
+ /** Records a render-phase error, renders `fallback` in place of the failed subtree */
4
+ export function AppMetricsErrorBoundary(props) {
5
+ return ErrorBoundary({
6
+ fallback: (error, resetError) => {
7
+ reportCaughtError(error);
8
+ const { fallback } = props;
9
+ return typeof fallback === 'function'
10
+ ? fallback({ error, resetError })
11
+ : fallback;
12
+ },
13
+ get children() {
14
+ return props.children;
15
+ },
16
+ });
17
+ }
@@ -0,0 +1,9 @@
1
+ import { type JSX } from 'solid-js';
2
+ import { type IAppMetricsErrorBoundaryFallback } from './app-metrics-error-boundary';
3
+ export type IAppMetricsRootProps = {
4
+ /** Omitting it leaves children unwrapped; pass `null` to capture without a fallback */
5
+ errorBoundaryFallback?: IAppMetricsErrorBoundaryFallback;
6
+ children: JSX.Element;
7
+ };
8
+ /** Marks the first render, so time-to-first-render is measured without a manual call */
9
+ export declare function AppMetricsRoot(props: IAppMetricsRootProps): JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { onMount } from 'solid-js';
2
+ import { markFirstRender } from '../core/index.js';
3
+ import { AppMetricsErrorBoundary, } from './app-metrics-error-boundary.js';
4
+ /** Marks the first render, so time-to-first-render is measured without a manual call */
5
+ export function AppMetricsRoot(props) {
6
+ onMount(() => markFirstRender());
7
+ // Only OMITTING the prop leaves children unwrapped - an explicit `null` still mounts the
8
+ // boundary and renders nothing, so the error is captured rather than propagating
9
+ if (props.errorBoundaryFallback === undefined) {
10
+ return props.children;
11
+ }
12
+ return AppMetricsErrorBoundary({
13
+ fallback: props.errorBoundaryFallback,
14
+ get children() {
15
+ return props.children;
16
+ },
17
+ });
18
+ }
@@ -0,0 +1,4 @@
1
+ export * from '../core';
2
+ export { AppMetricsErrorBoundary, type IAppMetricsErrorBoundaryFallback, type IAppMetricsErrorBoundaryFallbackProps, type IAppMetricsErrorBoundaryProps, } from './app-metrics-error-boundary';
3
+ export { AppMetricsRoot, type IAppMetricsRootProps } from './app-metrics-root';
4
+ export { useNetworkRequestObserver, type IUseNetworkRequestObserverOptions, } from './use-network-request-observer';
@@ -0,0 +1,4 @@
1
+ export * from '../core/index.js';
2
+ export { AppMetricsErrorBoundary, } from './app-metrics-error-boundary.js';
3
+ export { AppMetricsRoot } from './app-metrics-root.js';
4
+ export { useNetworkRequestObserver, } from './use-network-request-observer.js';
@@ -0,0 +1,5 @@
1
+ import type { NetworkRequestObserver } from '../core';
2
+ import type { IUseNetworkRequestObserverOptions } from '../core/network-request-observer-lifecycle';
3
+ export type { IUseNetworkRequestObserverOptions } from '../core/network-request-observer-lifecycle';
4
+ /** Solid twin of `expo-app-metrics`'s `useNetworkRequestObserver` */
5
+ export declare function useNetworkRequestObserver(getOptions?: () => IUseNetworkRequestObserverOptions): NetworkRequestObserver;
@@ -0,0 +1,6 @@
1
+ import { createEffect, onCleanup } from 'solid-js';
2
+ import { createNetworkRequestObserverLifecycle } from '../core/network-request-observer-lifecycle.js';
3
+ /** Solid twin of `expo-app-metrics`'s `useNetworkRequestObserver` */
4
+ export function useNetworkRequestObserver(getOptions = () => ({})) {
5
+ return createNetworkRequestObserverLifecycle(getOptions, createEffect, onCleanup);
6
+ }
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ // Records a render-phase error and renders `fallback` in place of the failed subtree - the
3
+ // Svelte twin of ../react's AppMetricsErrorBoundary and ../vue's, over `<svelte:boundary>`
4
+ import { reportCaughtError } from '../core/report-caught-error';
5
+ import type { IAppMetricsErrorBoundaryProps } from './app-metrics-error-boundary-props';
6
+
7
+ let { fallback, children }: IAppMetricsErrorBoundaryProps = $props();
8
+ </script>
9
+
10
+ <svelte:boundary onerror={(error) => reportCaughtError(error)}>
11
+ {@render children()}
12
+ {#snippet failed(error, reset)}
13
+ {#if fallback}
14
+ {@render fallback({ error, resetError: reset })}
15
+ {/if}
16
+ {/snippet}
17
+ </svelte:boundary>
@@ -0,0 +1,4 @@
1
+ import type { IAppMetricsErrorBoundaryProps } from './app-metrics-error-boundary-props';
2
+ declare const AppMetricsErrorBoundary: import("svelte").Component<IAppMetricsErrorBoundaryProps, {}, "">;
3
+ type AppMetricsErrorBoundary = ReturnType<typeof AppMetricsErrorBoundary>;
4
+ export default AppMetricsErrorBoundary;
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ // Marks the first render so time-to-first-render is measured without a manual call, the
3
+ // Svelte twin of ../react's AppMetricsRoot and ../vue's
4
+ import { onMount } from 'svelte';
5
+ import { markFirstRender } from '../core';
6
+ import AppMetricsErrorBoundary from './AppMetricsErrorBoundary.svelte';
7
+ import type { IAppMetricsRootProps } from './app-metrics-root-props';
8
+
9
+ let { errorBoundaryFallback, children: rootChildren }: IAppMetricsRootProps = $props();
10
+
11
+ onMount(() => markFirstRender());
12
+ </script>
13
+
14
+ {#if errorBoundaryFallback !== undefined}
15
+ <AppMetricsErrorBoundary fallback={errorBoundaryFallback}>
16
+ {#snippet children()}
17
+ {@render rootChildren()}
18
+ {/snippet}
19
+ </AppMetricsErrorBoundary>
20
+ {:else}
21
+ {@render rootChildren()}
22
+ {/if}
@@ -0,0 +1,4 @@
1
+ import type { IAppMetricsRootProps } from './app-metrics-root-props';
2
+ declare const AppMetricsRoot: import("svelte").Component<IAppMetricsRootProps, {}, "">;
3
+ type AppMetricsRoot = ReturnType<typeof AppMetricsRoot>;
4
+ export default AppMetricsRoot;
@@ -0,0 +1,12 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type IAppMetricsErrorBoundaryFallbackProps = {
3
+ /** The value the subtree threw, usually an `Error` but any value can be thrown */
4
+ error: unknown;
5
+ /** Clears the caught error and re-renders the default slot from a clean state */
6
+ resetError: () => void;
7
+ };
8
+ export type IAppMetricsErrorBoundaryProps = {
9
+ /** A snippet receiving `error`/`resetError`, or `null` to capture without rendering */
10
+ fallback: Snippet<[IAppMetricsErrorBoundaryFallbackProps]> | null;
11
+ children: Snippet;
12
+ };
@@ -0,0 +1,3 @@
1
+ // Split out like adapters/svelte/src/components/view-props.ts: `tsc --build` sees a `.svelte`
2
+ // import only through the ambient default-export declaration, never a named type it re-exports
3
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { IAppMetricsErrorBoundaryFallbackProps } from './app-metrics-error-boundary-props';
3
+ export type IAppMetricsRootProps = {
4
+ /** Omitting it leaves children unwrapped; pass `null` to capture without a fallback */
5
+ errorBoundaryFallback?: Snippet<[
6
+ IAppMetricsErrorBoundaryFallbackProps
7
+ ]> | null;
8
+ children: Snippet;
9
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ export * from '../core';
2
+ export type { IAppMetricsErrorBoundaryFallbackProps, IAppMetricsErrorBoundaryProps, } from './app-metrics-error-boundary-props';
3
+ export type { IAppMetricsRootProps } from './app-metrics-root-props';
4
+ export { default as AppMetricsErrorBoundary } from './AppMetricsErrorBoundary.svelte';
5
+ export { default as AppMetricsRoot } from './AppMetricsRoot.svelte';
6
+ export { useNetworkRequestObserver } from './use-network-request-observer.svelte';
7
+ export type { IUseNetworkRequestObserverOptions } from '../core/network-request-observer-lifecycle';
@@ -0,0 +1,4 @@
1
+ export * from '../core/index.js';
2
+ export { default as AppMetricsErrorBoundary } from './AppMetricsErrorBoundary.svelte';
3
+ export { default as AppMetricsRoot } from './AppMetricsRoot.svelte';
4
+ export { useNetworkRequestObserver } from './use-network-request-observer.svelte';
@@ -0,0 +1,3 @@
1
+ import type { NetworkRequestObserver } from '../core';
2
+ import type { IUseNetworkRequestObserverOptions } from '../core/network-request-observer-lifecycle';
3
+ export declare function useNetworkRequestObserver(getOptions?: () => IUseNetworkRequestObserverOptions): NetworkRequestObserver;
@@ -0,0 +1,14 @@
1
+ // `$effect` is a compiler macro, can't be passed by reference like `watchEffect`/`createEffect`,
2
+ // so it's wrapped instead of handed to `createNetworkRequestObserverLifecycle` directly
3
+ import { createNetworkRequestObserverLifecycle } from '../core/network-request-observer-lifecycle.js';
4
+ export function useNetworkRequestObserver(getOptions = () => ({})) {
5
+ const cleanups = [];
6
+ const observer = createNetworkRequestObserverLifecycle(getOptions, effect => {
7
+ $effect(effect);
8
+ }, cleanup => cleanups.push(cleanup));
9
+ $effect(() => () => {
10
+ for (const cleanup of cleanups)
11
+ cleanup();
12
+ });
13
+ return observer;
14
+ }
@@ -0,0 +1,14 @@
1
+ import { type VNode } from '@vue/runtime-core';
2
+ export type IAppMetricsErrorBoundaryFallbackProps = {
3
+ /** The value the subtree threw, usually an `Error` but any value can be thrown */
4
+ error: unknown;
5
+ /** Clears the caught error and re-renders the default slot from a clean state */
6
+ resetError: () => void;
7
+ };
8
+ export type IAppMetricsErrorBoundaryFallback = VNode | null | ((props: IAppMetricsErrorBoundaryFallbackProps) => VNode | null);
9
+ export type IAppMetricsErrorBoundaryProps = {
10
+ /** A VNode, a render function receiving `error`/`resetError`, or `null` */
11
+ fallback: IAppMetricsErrorBoundaryFallback;
12
+ };
13
+ /** Records a render-phase error, renders `fallback` in place of the default slot */
14
+ export declare const AppMetricsErrorBoundary: import("@vue/runtime-core").DefineSetupFnComponent<IAppMetricsErrorBoundaryProps, {}, {}, IAppMetricsErrorBoundaryProps & {}, import("@vue/runtime-core").PublicProps>;
@@ -0,0 +1,27 @@
1
+ import { defineComponent, onErrorCaptured, shallowRef, } from '@vue/runtime-core';
2
+ import { reportCaughtError } from '../core/report-caught-error.js';
3
+ /** Records a render-phase error, renders `fallback` in place of the default slot */
4
+ export const AppMetricsErrorBoundary = defineComponent((props, { slots }) => {
5
+ const hasError = shallowRef(false);
6
+ const caughtError = shallowRef(null);
7
+ // Returning `false` stops propagation, keeping the error off this engine's own
8
+ // uncaught-error channel, same asymmetry as adapters/vue's own render errors
9
+ onErrorCaptured(error => {
10
+ hasError.value = true;
11
+ caughtError.value = error;
12
+ reportCaughtError(error);
13
+ return false;
14
+ });
15
+ function resetError() {
16
+ hasError.value = false;
17
+ caughtError.value = null;
18
+ }
19
+ return () => {
20
+ if (!hasError.value)
21
+ return slots.default?.();
22
+ const { fallback } = props;
23
+ return typeof fallback === 'function'
24
+ ? fallback({ error: caughtError.value, resetError })
25
+ : fallback;
26
+ };
27
+ }, { name: 'AppMetricsErrorBoundary', props: ['fallback'] });
@@ -0,0 +1,7 @@
1
+ import { type IAppMetricsErrorBoundaryFallback } from './app-metrics-error-boundary';
2
+ export type IAppMetricsRootProps = {
3
+ /** Omitting it leaves the default slot unwrapped; pass `null` to capture without rendering */
4
+ errorBoundaryFallback?: IAppMetricsErrorBoundaryFallback;
5
+ };
6
+ /** Marks the first render, so time-to-first-render is measured without a manual call */
7
+ export declare const AppMetricsRoot: import("@vue/runtime-core").DefineSetupFnComponent<IAppMetricsRootProps, {}, {}, IAppMetricsRootProps & {}, import("@vue/runtime-core").PublicProps>;
@@ -0,0 +1,15 @@
1
+ import { defineComponent, h, onMounted } from '@vue/runtime-core';
2
+ import { markFirstRender } from '../core/index.js';
3
+ import { AppMetricsErrorBoundary, } from './app-metrics-error-boundary.js';
4
+ /** Marks the first render, so time-to-first-render is measured without a manual call */
5
+ export const AppMetricsRoot = defineComponent((props, { slots }) => {
6
+ onMounted(() => markFirstRender());
7
+ return () => {
8
+ // Only OMITTING the prop leaves the slot unwrapped - an explicit `null` still mounts the
9
+ // boundary and renders nothing, so the error is captured rather than propagating
10
+ if (props.errorBoundaryFallback !== undefined) {
11
+ return h(AppMetricsErrorBoundary, { fallback: props.errorBoundaryFallback }, slots.default);
12
+ }
13
+ return slots.default?.();
14
+ };
15
+ }, { name: 'AppMetricsRoot', props: ['errorBoundaryFallback'] });
@@ -0,0 +1,4 @@
1
+ export * from '../core';
2
+ export { AppMetricsErrorBoundary, type IAppMetricsErrorBoundaryFallback, type IAppMetricsErrorBoundaryFallbackProps, type IAppMetricsErrorBoundaryProps, } from './app-metrics-error-boundary';
3
+ export { AppMetricsRoot, type IAppMetricsRootProps } from './app-metrics-root';
4
+ export { useNetworkRequestObserver, type IUseNetworkRequestObserverOptions, } from './use-network-request-observer';
@@ -0,0 +1,4 @@
1
+ export * from '../core/index.js';
2
+ export { AppMetricsErrorBoundary, } from './app-metrics-error-boundary.js';
3
+ export { AppMetricsRoot } from './app-metrics-root.js';
4
+ export { useNetworkRequestObserver, } from './use-network-request-observer.js';
@@ -0,0 +1,5 @@
1
+ import type { NetworkRequestObserver } from '../core';
2
+ import type { IUseNetworkRequestObserverOptions } from '../core/network-request-observer-lifecycle';
3
+ export type { IUseNetworkRequestObserverOptions } from '../core/network-request-observer-lifecycle';
4
+ /** Vue twin of `expo-app-metrics`'s `useNetworkRequestObserver` */
5
+ export declare function useNetworkRequestObserver(getOptions?: () => IUseNetworkRequestObserverOptions): NetworkRequestObserver;
@@ -0,0 +1,6 @@
1
+ import { onUnmounted, watchEffect } from '@vue/runtime-core';
2
+ import { createNetworkRequestObserverLifecycle } from '../core/network-request-observer-lifecycle.js';
3
+ /** Vue twin of `expo-app-metrics`'s `useNetworkRequestObserver` */
4
+ export function useNetworkRequestObserver(getOptions = () => ({})) {
5
+ return createNetworkRequestObserverLifecycle(getOptions, watchEffect, onUnmounted);
6
+ }
@@ -0,0 +1,8 @@
1
+ import { type OnInit } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ /** Marks the first render, so time-to-first-render is measured without a manual call */
4
+ export declare class AppMetricsRoot implements OnInit {
5
+ ngOnInit(): void;
6
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppMetricsRoot, never>;
7
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppMetricsRoot, "app-metrics-root", never, {}, {}, never, ["*"], true, never>;
8
+ }