@logbrew/react-native 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -106,6 +106,30 @@ try {
106
106
 
107
107
  Set `includeStack: true` only when your app has decided stack text is safe to send. Non-`Error` thrown values are accepted and converted into issue messages so app error handlers do not need custom guards.
108
108
 
109
+ ### Reversible nonfatal global reports
110
+
111
+ Install the optional global JavaScript handler before root registration when you want supported nonfatal `ErrorUtils` failures captured without an app-owned capture call:
112
+
113
+ ```js
114
+ import { installLogBrewReactNativeGlobalErrorHandler } from "@logbrew/react-native/global-errors";
115
+
116
+ const errorHandler = installLogBrewReactNativeGlobalErrorHandler({
117
+ client,
118
+ onDiagnostic({ code }) {
119
+ console.warn(`LogBrew error handler: ${code}`);
120
+ }
121
+ });
122
+
123
+ // Roll back during teardown or when disabling the integration.
124
+ errorHandler.remove();
125
+ ```
126
+
127
+ Installation is idempotent for the active React Native `ErrorUtils` object. The wrapper captures a fixed-content, path-bounded issue for nonfatal global JavaScript errors and then calls the handler that was installed before it. Capture and diagnostic callback failures cannot prevent that prior handler from running. `remove()` reinstates the previous handler only while LogBrew still owns the global slot, so a later integration is not overwritten.
128
+
129
+ Fatal JavaScript errors are chained without capture. The JavaScript package has no synchronous native durable handoff and does not retain fatal events across process termination. Fatal replay requires a bounded synchronous native store plus next-launch delivery acknowledgement. Unhandled Promise rejections are not installed or patched because React Native does not expose one stable supported ownership seam across its runtimes.
130
+
131
+ Automatic events exclude the original error message, raw stack, arbitrary metadata, full URLs, hosts, query strings, and local absolute paths. `onDiagnostic` receives only a fixed code. This integration does not provide native crash capture, ANR/watchdog capture, fatal persistence, or exactly-once fatal replay.
132
+
109
133
  When you prepare React Native release artifacts, wrap the app-owned Metro config once. Production bundles and source maps receive one matching Debug ID, while development and hot-reload serialization remain unchanged:
110
134
 
111
135
  ```js
@@ -0,0 +1,366 @@
1
+ "use strict";
2
+
3
+ const { createReactNativeErrorEvent } = require("./index.cjs");
4
+
5
+ const AUTOMATIC_ERROR_MESSAGE = "React Native global JavaScript report";
6
+ const MAX_STACK_BYTES = 16 * 1024;
7
+ const MAX_STACK_FRAMES = 32;
8
+ const SAFE_ERROR_NAMES = new Set([
9
+ "Error",
10
+ "EvalError",
11
+ "RangeError",
12
+ "ReferenceError",
13
+ "SyntaxError",
14
+ "TypeError",
15
+ "URIError"
16
+ ]);
17
+ const installations = new WeakMap();
18
+ let nextEventSequence = 0;
19
+
20
+ function installLogBrewReactNativeGlobalErrorHandler({
21
+ client,
22
+ errorUtils = globalThis?.ErrorUtils,
23
+ onDiagnostic
24
+ } = {}) {
25
+ const issue = safeFunction(client, "issue");
26
+ const getGlobalHandler = safeFunction(errorUtils, "getGlobalHandler");
27
+ const setGlobalHandler = safeFunction(errorUtils, "setGlobalHandler");
28
+ if (!issue || !getGlobalHandler || !setGlobalHandler || !isObjectLike(errorUtils)) {
29
+ emitDiagnostic(onDiagnostic, "handler_unavailable");
30
+ return inactiveInstallation();
31
+ }
32
+
33
+ const existing = installations.get(errorUtils);
34
+ if (existing?.health().active) {
35
+ return existing;
36
+ }
37
+
38
+ let previousHandler;
39
+ try {
40
+ previousHandler = getGlobalHandler.call(errorUtils);
41
+ } catch {
42
+ emitDiagnostic(onDiagnostic, "handler_unavailable");
43
+ return inactiveInstallation();
44
+ }
45
+ if (typeof previousHandler !== "function") {
46
+ emitDiagnostic(onDiagnostic, "handler_unavailable");
47
+ return inactiveInstallation();
48
+ }
49
+
50
+ const state = {
51
+ active: true,
52
+ capturedEvents: 0,
53
+ handling: false,
54
+ lastOutcome: "idle",
55
+ suppressedEvents: 0
56
+ };
57
+ const capturedErrors = new WeakSet();
58
+ const handler = (error, isFatal) => {
59
+ if (!state.active) {
60
+ previousHandler(error, isFatal);
61
+ return;
62
+ }
63
+ if (state.handling) {
64
+ recordSuppression(state, onDiagnostic, "recursive_capture_suppressed");
65
+ return;
66
+ }
67
+ state.handling = true;
68
+ try {
69
+ if (isFatal === true) {
70
+ state.lastOutcome = "fatal_unsupported";
71
+ emitDiagnostic(onDiagnostic, "fatal_capture_requires_sync_store");
72
+ } else if (isObjectLike(error) && capturedErrors.has(error)) {
73
+ recordSuppression(state, onDiagnostic, "duplicate_capture_suppressed");
74
+ } else {
75
+ captureNonfatalError(client, issue, error, capturedErrors, state, onDiagnostic);
76
+ }
77
+ } finally {
78
+ try {
79
+ if (typeof previousHandler === "function") {
80
+ previousHandler(error, isFatal);
81
+ }
82
+ } finally {
83
+ state.handling = false;
84
+ }
85
+ }
86
+ };
87
+
88
+ const installation = Object.freeze({
89
+ health() {
90
+ return healthSnapshot(state);
91
+ },
92
+ remove() {
93
+ if (!state.active) {
94
+ return false;
95
+ }
96
+ let ownsHandler;
97
+ try {
98
+ ownsHandler = getGlobalHandler.call(errorUtils) === handler;
99
+ } catch {
100
+ return false;
101
+ }
102
+ if (!ownsHandler) {
103
+ state.active = false;
104
+ state.lastOutcome = "handler_replaced";
105
+ installations.delete(errorUtils);
106
+ return false;
107
+ }
108
+ try {
109
+ setGlobalHandler.call(errorUtils, previousHandler);
110
+ } catch {
111
+ state.lastOutcome = "remove_failed";
112
+ return false;
113
+ }
114
+ state.active = false;
115
+ state.lastOutcome = "removed";
116
+ installations.delete(errorUtils);
117
+ return true;
118
+ }
119
+ });
120
+
121
+ try {
122
+ setGlobalHandler.call(errorUtils, handler);
123
+ } catch {
124
+ state.active = false;
125
+ try {
126
+ if (getGlobalHandler.call(errorUtils) === handler) {
127
+ setGlobalHandler.call(errorUtils, previousHandler);
128
+ }
129
+ } catch {
130
+ // An inactive wrapper only delegates if a platform setter failed after mutation.
131
+ }
132
+ emitDiagnostic(onDiagnostic, "handler_unavailable");
133
+ return inactiveInstallation();
134
+ }
135
+ installations.set(errorUtils, installation);
136
+ return installation;
137
+ }
138
+
139
+ function captureNonfatalError(client, issue, error, capturedErrors, state, onDiagnostic) {
140
+ const tracksIdentity = isObjectLike(error);
141
+ if (tracksIdentity) {
142
+ capturedErrors.add(error);
143
+ }
144
+ try {
145
+ const event = createAutomaticErrorEvent(error);
146
+ issue.call(client, event.id, event.timestamp, event.attributes);
147
+ state.capturedEvents = incrementBounded(state.capturedEvents);
148
+ state.lastOutcome = "captured";
149
+ } catch {
150
+ if (tracksIdentity) {
151
+ capturedErrors.delete(error);
152
+ }
153
+ state.lastOutcome = "capture_failed";
154
+ emitDiagnostic(onDiagnostic, "capture_failed");
155
+ }
156
+ }
157
+
158
+ function createAutomaticErrorEvent(error) {
159
+ const sanitizedError = new Error(AUTOMATIC_ERROR_MESSAGE);
160
+ sanitizedError.name = safeErrorName(error);
161
+ const stack = safeStack(error);
162
+ if (stack) {
163
+ sanitizedError.stack = stack;
164
+ } else {
165
+ delete sanitizedError.stack;
166
+ }
167
+ const event = createReactNativeErrorEvent(sanitizedError, {
168
+ id: nextEventId(),
169
+ includeStack: false
170
+ });
171
+ return {
172
+ ...event,
173
+ attributes: {
174
+ ...event.attributes,
175
+ title: AUTOMATIC_ERROR_MESSAGE,
176
+ message: AUTOMATIC_ERROR_MESSAGE,
177
+ metadata: {
178
+ ...event.attributes.metadata,
179
+ automatic: true,
180
+ fatal: false,
181
+ handled: true,
182
+ mechanism: "react_native_error_utils",
183
+ source: "react-native.global_error"
184
+ }
185
+ }
186
+ };
187
+ }
188
+
189
+ function safeStack(error) {
190
+ const stack = safeReadProperty(error, "stack");
191
+ const candidate = typeof stack === "string"
192
+ ? stack.slice(0, MAX_STACK_BYTES)
193
+ : "";
194
+ const frames = [];
195
+ for (const line of candidate.split(/\r?\n/u)) {
196
+ const frame = safeStackFrame(line);
197
+ if (frame) {
198
+ frames.push(` at frame (${frame})`);
199
+ if (frames.length === MAX_STACK_FRAMES) {
200
+ break;
201
+ }
202
+ }
203
+ }
204
+ return frames.length === 0
205
+ ? undefined
206
+ : `${safeErrorName(error)}: ${AUTOMATIC_ERROR_MESSAGE}\n${frames.join("\n")}`;
207
+ }
208
+
209
+ function safeStackFrame(line) {
210
+ let location = typeof line === "string" ? line.trim() : "";
211
+ if (!location) {
212
+ return undefined;
213
+ }
214
+ if (location.startsWith("at ")) {
215
+ location = location.slice(3).trim();
216
+ if (location.endsWith(")") && location.includes("(")) {
217
+ location = location.slice(location.lastIndexOf("(") + 1, -1);
218
+ }
219
+ } else if (location.includes("@")) {
220
+ location = location.slice(location.lastIndexOf("@") + 1);
221
+ }
222
+ const parts = location.split(":");
223
+ if (parts.length < 3) {
224
+ return undefined;
225
+ }
226
+ const column = positiveInteger(parts.pop());
227
+ const lineNumber = positiveInteger(parts.pop());
228
+ const filename = safeStackFilename(parts.join(":"));
229
+ if (!filename || lineNumber === undefined || column === undefined) {
230
+ return undefined;
231
+ }
232
+ return `${filename}:${lineNumber}:${column}`;
233
+ }
234
+
235
+ function safeStackFilename(value) {
236
+ let filename = String(value ?? "").trim().replace(/\\/gu, "/");
237
+ if (!filename || filename.length > 2048 || hasControlCharacter(filename)) {
238
+ return undefined;
239
+ }
240
+ try {
241
+ if (/^[a-z][a-z0-9+.-]*:/iu.test(filename)) {
242
+ const parsed = new URL(filename);
243
+ if (!["app:", "http:", "https:"].includes(parsed.protocol)
244
+ || parsed.username
245
+ || urlAuthority(filename).includes("@")) {
246
+ return undefined;
247
+ }
248
+ filename = parsed.pathname;
249
+ } else {
250
+ filename = filename.split(/[?#]/u, 1)[0];
251
+ if (filename.startsWith("/") || /^[A-Za-z]:\//u.test(filename)) {
252
+ return undefined;
253
+ }
254
+ }
255
+ } catch {
256
+ return undefined;
257
+ }
258
+ return filename && filename.length <= 2048 && !hasControlCharacter(filename)
259
+ ? filename
260
+ : undefined;
261
+ }
262
+
263
+ function urlAuthority(value) {
264
+ const schemeMarker = value.indexOf("://");
265
+ if (schemeMarker < 0) {
266
+ return "";
267
+ }
268
+ const start = schemeMarker + 3;
269
+ const end = value.indexOf("/", start);
270
+ return value.slice(start, end < 0 ? value.length : end);
271
+ }
272
+
273
+ function safeErrorName(error) {
274
+ const name = safeReadProperty(error, "name");
275
+ const candidate = typeof name === "string" ? name : "Error";
276
+ return SAFE_ERROR_NAMES.has(candidate) ? candidate : "Error";
277
+ }
278
+
279
+ function safeReadProperty(value, property) {
280
+ if (!isObjectLike(value)) {
281
+ return undefined;
282
+ }
283
+ try {
284
+ return value[property];
285
+ } catch {
286
+ return undefined;
287
+ }
288
+ }
289
+
290
+ function safeFunction(value, property) {
291
+ const candidate = safeReadProperty(value, property);
292
+ return typeof candidate === "function" ? candidate : undefined;
293
+ }
294
+
295
+ function hasControlCharacter(value) {
296
+ return Array.from(value).some((character) => {
297
+ const code = character.codePointAt(0);
298
+ return code !== undefined && (code <= 31 || code === 127);
299
+ });
300
+ }
301
+
302
+ function positiveInteger(value) {
303
+ if (!/^[1-9][0-9]*$/u.test(String(value))) {
304
+ return undefined;
305
+ }
306
+ const number = Number(value);
307
+ return Number.isSafeInteger(number) && number <= 2147483647 ? number : undefined;
308
+ }
309
+
310
+ function nextEventId() {
311
+ nextEventSequence = incrementBounded(nextEventSequence);
312
+ return `evt_rn_global_${Date.now().toString(36)}_${nextEventSequence.toString(36)}`;
313
+ }
314
+
315
+ function incrementBounded(value) {
316
+ return value >= Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : value + 1;
317
+ }
318
+
319
+ function recordSuppression(state, onDiagnostic, code) {
320
+ state.suppressedEvents = incrementBounded(state.suppressedEvents);
321
+ state.lastOutcome = code === "recursive_capture_suppressed" ? "recursive_suppressed" : "duplicate_suppressed";
322
+ emitDiagnostic(onDiagnostic, code);
323
+ }
324
+
325
+ function emitDiagnostic(onDiagnostic, code) {
326
+ if (typeof onDiagnostic !== "function") {
327
+ return;
328
+ }
329
+ try {
330
+ onDiagnostic(Object.freeze({ code }));
331
+ } catch {
332
+ // Diagnostics must never interfere with application error handling.
333
+ }
334
+ }
335
+
336
+ function inactiveInstallation() {
337
+ const snapshot = Object.freeze({
338
+ active: false,
339
+ capturedEvents: 0,
340
+ lastOutcome: "unavailable",
341
+ suppressedEvents: 0
342
+ });
343
+ return Object.freeze({
344
+ health: () => snapshot,
345
+ remove: () => false
346
+ });
347
+ }
348
+
349
+ function healthSnapshot(state) {
350
+ return Object.freeze({
351
+ active: state.active,
352
+ capturedEvents: state.capturedEvents,
353
+ lastOutcome: state.lastOutcome,
354
+ suppressedEvents: state.suppressedEvents
355
+ });
356
+ }
357
+
358
+ function isObjectLike(value) {
359
+ return value !== null && (typeof value === "object" || typeof value === "function");
360
+ }
361
+
362
+ const defaultExport = {
363
+ installLogBrewReactNativeGlobalErrorHandler
364
+ };
365
+
366
+ module.exports = { ...defaultExport, default: defaultExport };
@@ -0,0 +1,63 @@
1
+ import type { LogBrewClient } from "@logbrew/sdk";
2
+
3
+ export type ReactNativeGlobalErrorHandler = (error: unknown, isFatal?: boolean) => void;
4
+
5
+ export type ReactNativeErrorUtilsLike = {
6
+ getGlobalHandler(): ReactNativeGlobalErrorHandler | undefined;
7
+ setGlobalHandler(handler: ReactNativeGlobalErrorHandler | undefined): void;
8
+ };
9
+
10
+ export type ReactNativeGlobalErrorDiagnosticCode =
11
+ | "capture_failed"
12
+ | "duplicate_capture_suppressed"
13
+ | "fatal_capture_requires_sync_store"
14
+ | "handler_unavailable"
15
+ | "recursive_capture_suppressed";
16
+
17
+ export type ReactNativeGlobalErrorDiagnostic = Readonly<{
18
+ code: ReactNativeGlobalErrorDiagnosticCode;
19
+ }>;
20
+
21
+ export type ReactNativeGlobalErrorHealth = Readonly<{
22
+ active: boolean;
23
+ capturedEvents: number;
24
+ lastOutcome:
25
+ | "capture_failed"
26
+ | "captured"
27
+ | "duplicate_suppressed"
28
+ | "fatal_unsupported"
29
+ | "handler_replaced"
30
+ | "idle"
31
+ | "recursive_suppressed"
32
+ | "remove_failed"
33
+ | "removed"
34
+ | "unavailable";
35
+ suppressedEvents: number;
36
+ }>;
37
+
38
+ export type InstallLogBrewReactNativeGlobalErrorHandlerOptions = {
39
+ client: Pick<LogBrewClient, "issue">;
40
+ errorUtils?: ReactNativeErrorUtilsLike;
41
+ onDiagnostic?: (diagnostic: ReactNativeGlobalErrorDiagnostic) => void;
42
+ };
43
+
44
+ export type LogBrewReactNativeGlobalErrorHandlerInstallation = Readonly<{
45
+ health(): ReactNativeGlobalErrorHealth;
46
+ remove(): boolean;
47
+ }>;
48
+
49
+ /**
50
+ * Install reversible automatic capture for nonfatal React Native global JavaScript errors.
51
+ *
52
+ * Fatal errors are chained without capture until a synchronous native durable handoff is
53
+ * available. This helper does not install Promise rejection handling.
54
+ */
55
+ export declare function installLogBrewReactNativeGlobalErrorHandler(
56
+ options: InstallLogBrewReactNativeGlobalErrorHandlerOptions
57
+ ): LogBrewReactNativeGlobalErrorHandlerInstallation;
58
+
59
+ declare const logBrewReactNativeGlobalErrors: {
60
+ installLogBrewReactNativeGlobalErrorHandler: typeof installLogBrewReactNativeGlobalErrorHandler;
61
+ };
62
+
63
+ export default logBrewReactNativeGlobalErrors;
@@ -0,0 +1,63 @@
1
+ import type { LogBrewClient } from "@logbrew/sdk";
2
+
3
+ export type ReactNativeGlobalErrorHandler = (error: unknown, isFatal?: boolean) => void;
4
+
5
+ export type ReactNativeErrorUtilsLike = {
6
+ getGlobalHandler(): ReactNativeGlobalErrorHandler | undefined;
7
+ setGlobalHandler(handler: ReactNativeGlobalErrorHandler | undefined): void;
8
+ };
9
+
10
+ export type ReactNativeGlobalErrorDiagnosticCode =
11
+ | "capture_failed"
12
+ | "duplicate_capture_suppressed"
13
+ | "fatal_capture_requires_sync_store"
14
+ | "handler_unavailable"
15
+ | "recursive_capture_suppressed";
16
+
17
+ export type ReactNativeGlobalErrorDiagnostic = Readonly<{
18
+ code: ReactNativeGlobalErrorDiagnosticCode;
19
+ }>;
20
+
21
+ export type ReactNativeGlobalErrorHealth = Readonly<{
22
+ active: boolean;
23
+ capturedEvents: number;
24
+ lastOutcome:
25
+ | "capture_failed"
26
+ | "captured"
27
+ | "duplicate_suppressed"
28
+ | "fatal_unsupported"
29
+ | "handler_replaced"
30
+ | "idle"
31
+ | "recursive_suppressed"
32
+ | "remove_failed"
33
+ | "removed"
34
+ | "unavailable";
35
+ suppressedEvents: number;
36
+ }>;
37
+
38
+ export type InstallLogBrewReactNativeGlobalErrorHandlerOptions = {
39
+ client: Pick<LogBrewClient, "issue">;
40
+ errorUtils?: ReactNativeErrorUtilsLike;
41
+ onDiagnostic?: (diagnostic: ReactNativeGlobalErrorDiagnostic) => void;
42
+ };
43
+
44
+ export type LogBrewReactNativeGlobalErrorHandlerInstallation = Readonly<{
45
+ health(): ReactNativeGlobalErrorHealth;
46
+ remove(): boolean;
47
+ }>;
48
+
49
+ /**
50
+ * Install reversible automatic capture for nonfatal React Native global JavaScript errors.
51
+ *
52
+ * Fatal errors are chained without capture until a synchronous native durable handoff is
53
+ * available. This helper does not install Promise rejection handling.
54
+ */
55
+ export declare function installLogBrewReactNativeGlobalErrorHandler(
56
+ options: InstallLogBrewReactNativeGlobalErrorHandlerOptions
57
+ ): LogBrewReactNativeGlobalErrorHandlerInstallation;
58
+
59
+ declare const logBrewReactNativeGlobalErrors: {
60
+ installLogBrewReactNativeGlobalErrorHandler: typeof installLogBrewReactNativeGlobalErrorHandler;
61
+ };
62
+
63
+ export default logBrewReactNativeGlobalErrors;
@@ -0,0 +1,7 @@
1
+ import implementation from "./global-errors.cjs";
2
+
3
+ export const {
4
+ installLogBrewReactNativeGlobalErrorHandler
5
+ } = implementation;
6
+
7
+ export default implementation;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logbrew/react-native",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "React Native screen, error, trace, action, and network timeline helpers for LogBrew.",
5
5
  "type": "module",
6
6
  "main": "./index.cjs",
@@ -31,6 +31,17 @@
31
31
  },
32
32
  "default": "./lifecycle.js"
33
33
  },
34
+ "./global-errors": {
35
+ "import": {
36
+ "types": "./global-errors.d.ts",
37
+ "default": "./global-errors.js"
38
+ },
39
+ "require": {
40
+ "types": "./global-errors.d.cts",
41
+ "default": "./global-errors.cjs"
42
+ },
43
+ "default": "./global-errors.js"
44
+ },
34
45
  "./instrumentation": {
35
46
  "import": {
36
47
  "types": "./instrumentation.d.ts",
@@ -116,6 +127,10 @@
116
127
  "lifecycle.js",
117
128
  "lifecycle.d.ts",
118
129
  "lifecycle.d.cts",
130
+ "global-errors.cjs",
131
+ "global-errors.js",
132
+ "global-errors.d.ts",
133
+ "global-errors.d.cts",
119
134
  "metadata.cjs",
120
135
  "metadata.js",
121
136
  "native-bridge.cjs",
@@ -163,6 +178,6 @@
163
178
  "react-native": ">=0.72"
164
179
  },
165
180
  "scripts": {
166
- "test": "node --check index.js && node --check index.cjs && node --check index.native.js && node --check apollo.js && node --check apollo.cjs && node --check instrumentation.js && node --check instrumentation.cjs && node --check lifecycle.js && node --check lifecycle.cjs && node --check metadata.js && node --check metadata.cjs && node --check native-bridge.js && node --check native-bridge.cjs && node --check resource-fetch.js && node --check resource-fetch.cjs && node --check release-artifacts.js && node --check release-artifacts.cjs && node --check metro.js && node --check metro.cjs && node --check examples/index.mjs && node --check examples/apollo-link-spans.mjs && node --check examples/instrumentation-kit.mjs && node --check examples/lifecycle-spans.mjs && node --check examples/native-bridge-scope.mjs && node --check examples/navigation-resource-spans.mjs && node --check examples/readme-example.mjs && node --check examples/real-user-smoke.mjs && node --check examples/resource-fetch-spans.mjs && node --check examples/trace-correlation.mjs && node --test"
181
+ "test": "node --check index.js && node --check index.cjs && node --check index.native.js && node --check apollo.js && node --check apollo.cjs && node --check instrumentation.js && node --check instrumentation.cjs && node --check lifecycle.js && node --check lifecycle.cjs && node --check global-errors.js && node --check global-errors.cjs && node --check metadata.js && node --check metadata.cjs && node --check native-bridge.js && node --check native-bridge.cjs && node --check resource-fetch.js && node --check resource-fetch.cjs && node --check release-artifacts.js && node --check release-artifacts.cjs && node --check metro.js && node --check metro.cjs && node --check examples/index.mjs && node --check examples/apollo-link-spans.mjs && node --check examples/instrumentation-kit.mjs && node --check examples/lifecycle-spans.mjs && node --check examples/native-bridge-scope.mjs && node --check examples/navigation-resource-spans.mjs && node --check examples/readme-example.mjs && node --check examples/real-user-smoke.mjs && node --check examples/resource-fetch-spans.mjs && node --check examples/trace-correlation.mjs && node --test"
167
182
  }
168
183
  }