@koderlabs/tasks-sdk-rn 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.
package/dist/index.cjs ADDED
@@ -0,0 +1,584 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ BreadcrumbBuffer: () => BreadcrumbBuffer,
24
+ attachReactNavigation: () => attachReactNavigation,
25
+ getBuffer: () => getBuffer,
26
+ getClient: () => getClient,
27
+ init: () => init,
28
+ recordNavigation: () => recordNavigation,
29
+ useExpoRouterReporter: () => useExpoRouterReporter
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+ var import_tasks_sdk = require("@koderlabs/tasks-sdk");
33
+
34
+ // src/breadcrumbs.ts
35
+ var BreadcrumbBuffer = class {
36
+ constructor(max = 50) {
37
+ this.max = max;
38
+ }
39
+ max;
40
+ buf = [];
41
+ add(b) {
42
+ this.buf.push(b);
43
+ if (this.buf.length > this.max) this.buf.splice(0, this.buf.length - this.max);
44
+ }
45
+ drain() {
46
+ const out = this.buf.slice();
47
+ return out;
48
+ }
49
+ clear() {
50
+ this.buf = [];
51
+ }
52
+ };
53
+
54
+ // src/wrap-sentinel.ts
55
+ var INSTANT_TASKS_WRAPPED = /* @__PURE__ */ Symbol.for("@koderlabs/tasks-sdk-rn.wrapped");
56
+ function unwrap(fn) {
57
+ let cur = fn;
58
+ while (cur && cur[INSTANT_TASKS_WRAPPED]) {
59
+ cur = cur[INSTANT_TASKS_WRAPPED].original;
60
+ }
61
+ return cur;
62
+ }
63
+ function markWrapped(wrapper, original) {
64
+ wrapper[INSTANT_TASKS_WRAPPED] = { original };
65
+ return wrapper;
66
+ }
67
+
68
+ // src/console.ts
69
+ var LEVELS = ["warn", "error"];
70
+ function installConsoleBreadcrumbs(breadcrumbs) {
71
+ if (typeof console === "undefined") return () => void 0;
72
+ const originals = {};
73
+ const wrappers = {};
74
+ for (const level of LEVELS) {
75
+ const existing = console[level];
76
+ if (typeof existing !== "function") continue;
77
+ const original = unwrap(existing);
78
+ originals[level] = original;
79
+ const wrapper = (...args) => {
80
+ try {
81
+ breadcrumbs.add({
82
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
83
+ category: "console",
84
+ level: level === "warn" ? "warning" : "error",
85
+ message: args.map((a) => typeof a === "string" ? a : safeStringify(a)).join(" ").slice(0, 1e3)
86
+ });
87
+ } catch {
88
+ }
89
+ original.apply(console, args);
90
+ };
91
+ markWrapped(wrapper, original);
92
+ wrappers[level] = wrapper;
93
+ console[level] = wrapper;
94
+ }
95
+ return () => {
96
+ for (const level of LEVELS) {
97
+ const orig = originals[level];
98
+ const wrapper = wrappers[level];
99
+ if (!orig || !wrapper) continue;
100
+ const current = console[level];
101
+ if (current === wrapper) {
102
+ console[level] = orig;
103
+ } else {
104
+ console[level] = unwrap(current);
105
+ }
106
+ }
107
+ };
108
+ }
109
+ function safeStringify(v) {
110
+ try {
111
+ return JSON.stringify(v);
112
+ } catch {
113
+ return String(v);
114
+ }
115
+ }
116
+
117
+ // src/platform.ts
118
+ function detectPlatform() {
119
+ try {
120
+ const rn = (typeof require !== "undefined" ? require : null)?.("react-native");
121
+ if (!rn) return empty();
122
+ const Platform = rn.Platform ?? {};
123
+ const NativeModules = rn.NativeModules ?? {};
124
+ return {
125
+ os: String(Platform.OS ?? "unknown"),
126
+ osVersion: String(Platform.Version ?? ""),
127
+ deviceModel: String(NativeModules?.PlatformConstants?.Model ?? ""),
128
+ bundleId: String(NativeModules?.PlatformConstants?.bundleIdentifier ?? "")
129
+ };
130
+ } catch {
131
+ return empty();
132
+ }
133
+ }
134
+ function empty() {
135
+ return { os: "unknown", osVersion: "", deviceModel: "", bundleId: "" };
136
+ }
137
+
138
+ // src/errors.ts
139
+ function reportError(client, err, ctx = { mechanism: "notify" }) {
140
+ const env = client.options;
141
+ const platform = ctx.platform ?? detectPlatform();
142
+ void client.send({
143
+ kind: "error",
144
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
145
+ release: env.release,
146
+ environment: env.environment,
147
+ user: env.user,
148
+ url: `mobile://${platform.os}`,
149
+ userAgent: `react-native/${platform.os} ${platform.osVersion} ${platform.deviceModel}`.trim(),
150
+ viewport: { width: 0, height: 0 },
151
+ exception: {
152
+ type: err.name || "Error",
153
+ value: err.message || String(err),
154
+ stack: err.stack,
155
+ mechanism: ctx.mechanism
156
+ },
157
+ level: ctx.level ?? "error",
158
+ breadcrumbs: ctx.breadcrumbs?.drain(),
159
+ custom: { platform }
160
+ });
161
+ }
162
+ function installGlobalErrorHandler(client, breadcrumbs) {
163
+ if (typeof ErrorUtils === "undefined" || !ErrorUtils?.setGlobalHandler) return () => void 0;
164
+ const prev = unwrap(ErrorUtils.getGlobalHandler());
165
+ const handler = (err, isFatal) => {
166
+ try {
167
+ reportError(client, err, {
168
+ mechanism: "onerror",
169
+ level: isFatal ? "fatal" : "error",
170
+ breadcrumbs
171
+ });
172
+ } finally {
173
+ prev?.(err, isFatal);
174
+ }
175
+ };
176
+ markWrapped(handler, prev);
177
+ ErrorUtils.setGlobalHandler(handler);
178
+ return () => {
179
+ const current = ErrorUtils.getGlobalHandler();
180
+ if (current === handler) {
181
+ ErrorUtils.setGlobalHandler(prev);
182
+ } else {
183
+ ErrorUtils.setGlobalHandler(unwrap(current));
184
+ }
185
+ };
186
+ }
187
+ function installRejectionTracker(client, breadcrumbs) {
188
+ if (typeof HermesInternal !== "undefined" && HermesInternal?.enablePromiseRejectionTracker) {
189
+ HermesInternal.enablePromiseRejectionTracker({
190
+ allRejections: true,
191
+ onUnhandled: (_id, reason) => {
192
+ const err = reason instanceof Error ? reason : new Error(String(reason));
193
+ reportError(client, err, { mechanism: "unhandledrejection", level: "error", breadcrumbs });
194
+ }
195
+ });
196
+ return () => void 0;
197
+ }
198
+ if (typeof process !== "undefined" && typeof process.on === "function") {
199
+ const fn = (reason) => {
200
+ const err = reason instanceof Error ? reason : new Error(String(reason));
201
+ reportError(client, err, { mechanism: "unhandledrejection", level: "error", breadcrumbs });
202
+ };
203
+ process.on("unhandledRejection", fn);
204
+ return () => process.off("unhandledRejection", fn);
205
+ }
206
+ return () => void 0;
207
+ }
208
+
209
+ // src/network.ts
210
+ function scrubUrl(raw, includeQuery) {
211
+ if (includeQuery) return raw;
212
+ const qIdx = raw.indexOf("?");
213
+ const hIdx = raw.indexOf("#");
214
+ const cut = Math.min(qIdx === -1 ? raw.length : qIdx, hIdx === -1 ? raw.length : hIdx);
215
+ return raw.slice(0, cut);
216
+ }
217
+ function installFetchBreadcrumbs(buffer, opts = {}) {
218
+ if (typeof globalThis.fetch !== "function") return () => void 0;
219
+ const original = unwrap(globalThis.fetch);
220
+ const bound = original.bind(globalThis);
221
+ const include = opts.includeUrls ?? [];
222
+ const exclude = opts.excludeUrls ?? [
223
+ // Always skip own ingest path so error reporting doesn't generate breadcrumbs
224
+ // that get sent in the next event payload (recursive amplification).
225
+ /\/api\/v1\/sdk\/events/
226
+ ];
227
+ const slowMs = opts.slowThresholdMs ?? 2e3;
228
+ const includeQuery = opts.includeQueryString === true;
229
+ const wrapper = async (input, init2) => {
230
+ const rawUrl = typeof input === "string" ? input : input.url ?? "";
231
+ const method = (init2?.method ?? (typeof input !== "string" ? input.method : "GET") ?? "GET").toUpperCase();
232
+ if (include.length && !include.some((re) => re.test(rawUrl))) {
233
+ return bound(input, init2);
234
+ }
235
+ if (exclude.some((re) => re.test(rawUrl))) {
236
+ return bound(input, init2);
237
+ }
238
+ const url = scrubUrl(rawUrl, includeQuery);
239
+ const startedAt = Date.now();
240
+ let status;
241
+ let errorMessage;
242
+ try {
243
+ const res = await bound(input, init2);
244
+ status = res.status;
245
+ return res;
246
+ } catch (err) {
247
+ errorMessage = err instanceof Error ? err.message : String(err);
248
+ throw err;
249
+ } finally {
250
+ const durationMs = Date.now() - startedAt;
251
+ try {
252
+ buffer.add({
253
+ ts: new Date(startedAt).toISOString(),
254
+ category: "http",
255
+ message: `${method} ${url}${status ? ` \u2192 ${status}` : ""}`,
256
+ level: errorMessage || status && status >= 500 ? "error" : status && status >= 400 ? "warning" : "info",
257
+ data: {
258
+ method,
259
+ url,
260
+ status,
261
+ durationMs,
262
+ slow: durationMs >= slowMs ? true : void 0,
263
+ error: errorMessage
264
+ }
265
+ });
266
+ } catch {
267
+ }
268
+ }
269
+ };
270
+ markWrapped(wrapper, original);
271
+ globalThis.fetch = wrapper;
272
+ return () => {
273
+ const current = globalThis.fetch;
274
+ if (current === wrapper) {
275
+ globalThis.fetch = original;
276
+ } else {
277
+ globalThis.fetch = unwrap(current);
278
+ }
279
+ };
280
+ }
281
+
282
+ // src/app-state.ts
283
+ function installAppStateBreadcrumbs(buffer) {
284
+ let rn;
285
+ try {
286
+ rn = (typeof require !== "undefined" ? require : null)?.("react-native") ?? {};
287
+ } catch {
288
+ return () => void 0;
289
+ }
290
+ if (!rn.AppState?.addEventListener) return () => void 0;
291
+ let lastState = "active";
292
+ const subscription = rn.AppState.addEventListener("change", (nextState) => {
293
+ if (nextState === lastState) return;
294
+ try {
295
+ buffer.add({
296
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
297
+ category: "navigation",
298
+ message: `AppState: ${lastState} \u2192 ${nextState}`,
299
+ level: "info",
300
+ data: { from: lastState, to: nextState }
301
+ });
302
+ } catch {
303
+ }
304
+ lastState = nextState;
305
+ });
306
+ return () => {
307
+ if (typeof subscription === "function") subscription();
308
+ else subscription?.remove?.();
309
+ };
310
+ }
311
+
312
+ // src/navigation.ts
313
+ function recordNavigation(buffer, to, opts = {}) {
314
+ try {
315
+ buffer.add({
316
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
317
+ category: "navigation",
318
+ message: opts.from ? `${opts.from} \u2192 ${to}` : `navigate ${to}`,
319
+ level: "info",
320
+ data: {
321
+ from: opts.from,
322
+ to,
323
+ params: opts.params
324
+ }
325
+ });
326
+ } catch {
327
+ }
328
+ }
329
+ function attachReactNavigation(buffer, navRef) {
330
+ let lastRoute;
331
+ const unsub = navRef.addListener("state", () => {
332
+ const current = navRef.getCurrentRoute?.();
333
+ if (!current) return;
334
+ if (current.name === lastRoute) return;
335
+ recordNavigation(buffer, current.name, { from: lastRoute, params: current.params });
336
+ lastRoute = current.name;
337
+ });
338
+ return unsub;
339
+ }
340
+ function useExpoRouterReporter(buffer) {
341
+ let lastPath;
342
+ return (pathname) => {
343
+ if (pathname === lastPath) return;
344
+ recordNavigation(buffer, pathname, { from: lastPath });
345
+ lastPath = pathname;
346
+ };
347
+ }
348
+
349
+ // src/native-crash.ts
350
+ var CRASH_FILE = "tasks-native-crash.json";
351
+ async function recoverNativeCrash(client, platform, onError) {
352
+ let nativePkg = null;
353
+ try {
354
+ nativePkg = (typeof require !== "undefined" ? require : null)?.("@koderlabs/tasks-sdk-rn-native") ?? null;
355
+ } catch (e) {
356
+ onError?.({ stage: "native-pkg-load", message: e.message, cause: e });
357
+ }
358
+ if (nativePkg?.getPendingNativeCrash) {
359
+ try {
360
+ const report = await nativePkg.getPendingNativeCrash();
361
+ if (report) {
362
+ try {
363
+ await shipCrash(client, normaliseNativeReport(report), platform);
364
+ } catch (e) {
365
+ onError?.({ stage: "ship", message: e.message, cause: e });
366
+ }
367
+ try {
368
+ await nativePkg.purgePendingNativeCrash?.();
369
+ } catch (e) {
370
+ onError?.({ stage: "native-pkg-purge", message: e.message, cause: e });
371
+ }
372
+ return true;
373
+ }
374
+ } catch (e) {
375
+ onError?.({ stage: "native-pkg-get", message: e.message, cause: e });
376
+ }
377
+ }
378
+ let FileSystem = null;
379
+ try {
380
+ FileSystem = (typeof require !== "undefined" ? require : null)?.("expo-file-system") ?? null;
381
+ } catch (e) {
382
+ onError?.({ stage: "expo-fs-load", message: e.message, cause: e });
383
+ return false;
384
+ }
385
+ if (!FileSystem?.documentDirectory) return false;
386
+ const path = `${FileSystem.documentDirectory}${CRASH_FILE}`;
387
+ let info;
388
+ try {
389
+ info = await FileSystem.getInfoAsync(path);
390
+ } catch (e) {
391
+ onError?.({ stage: "expo-fs-info", message: e.message, cause: e });
392
+ return false;
393
+ }
394
+ if (!info.exists) return false;
395
+ let raw;
396
+ try {
397
+ raw = await FileSystem.readAsStringAsync(path);
398
+ } catch (e) {
399
+ onError?.({ stage: "expo-fs-read", message: e.message, cause: e });
400
+ return false;
401
+ }
402
+ let crash;
403
+ try {
404
+ crash = JSON.parse(raw);
405
+ } catch (e) {
406
+ onError?.({ stage: "expo-fs-parse", message: e.message, cause: e });
407
+ await FileSystem.deleteAsync(path, { idempotent: true }).catch(() => void 0);
408
+ return false;
409
+ }
410
+ try {
411
+ await shipCrash(client, crash, platform);
412
+ } catch (e) {
413
+ onError?.({ stage: "ship", message: e.message, cause: e });
414
+ }
415
+ try {
416
+ await FileSystem.deleteAsync(path, { idempotent: true });
417
+ } catch (e) {
418
+ onError?.({ stage: "expo-fs-delete", message: e.message, cause: e });
419
+ }
420
+ return true;
421
+ }
422
+ function normaliseNativeReport(r) {
423
+ if (r?.platform === "ios") {
424
+ const stackLines = [];
425
+ for (const t of r.threads ?? []) {
426
+ if (!t.crashed) continue;
427
+ for (const f of t.frames ?? []) {
428
+ stackLines.push(`0x${(f.instructionPointer >>> 0).toString(16)} ${f.symbol ?? "?"}`);
429
+ }
430
+ }
431
+ return {
432
+ platform: "ios",
433
+ name: r.exception?.name || r.signal?.name || "NativeCrash",
434
+ reason: r.exception?.reason || r.signal?.code || "",
435
+ callStackSymbols: stackLines,
436
+ userInfo: { signal: r.signal, appBundleId: r.appBundleId, appVersion: r.appVersion },
437
+ timestamp: r.timestamp
438
+ };
439
+ }
440
+ const stack = Array.isArray(r.frames) ? r.frames.join("\n") : Array.isArray(r.stack) ? r.stack.join("\n") : "";
441
+ return {
442
+ platform: "android",
443
+ name: r.signal || (r.kind === "anr" ? "ANR" : "NativeCrash"),
444
+ message: r.faultAddr || (r.kind === "anr" ? `Main thread blocked >${r.thresholdMs}ms` : ""),
445
+ stackTrace: stack,
446
+ threadName: r.kind === "anr" ? "main" : void 0,
447
+ timestamp: r.capturedAt || r.timestamp
448
+ };
449
+ }
450
+ async function shipCrash(client, crash, platform) {
451
+ const env = client.options;
452
+ const stack = crash.platform === "ios" ? (crash.callStackSymbols ?? []).join("\n") : crash.stackTrace ?? "";
453
+ const message = crash.platform === "ios" ? crash.reason ?? crash.name : crash.message ?? crash.name;
454
+ await client.send({
455
+ kind: "error",
456
+ ts: crash.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
457
+ release: env.release,
458
+ environment: env.environment,
459
+ user: env.user,
460
+ url: `mobile://${platform.os}`,
461
+ userAgent: `react-native/${platform.os} ${platform.osVersion} ${platform.deviceModel}`.trim(),
462
+ viewport: { width: 0, height: 0 },
463
+ exception: {
464
+ type: crash.name,
465
+ value: message,
466
+ stack,
467
+ mechanism: "native_crash"
468
+ },
469
+ level: "fatal",
470
+ breadcrumbs: [],
471
+ custom: {
472
+ platform,
473
+ nativeCrash: {
474
+ platform: crash.platform,
475
+ threadName: "threadName" in crash ? crash.threadName : void 0,
476
+ userInfo: "userInfo" in crash ? crash.userInfo : void 0
477
+ }
478
+ }
479
+ });
480
+ }
481
+
482
+ // src/index.ts
483
+ var currentClient = null;
484
+ var currentBuffer = null;
485
+ var teardownFns = [];
486
+ function init(opts) {
487
+ if (currentClient || teardownFns.length) {
488
+ for (const fn of teardownFns) {
489
+ try {
490
+ fn();
491
+ } catch {
492
+ }
493
+ }
494
+ teardownFns = [];
495
+ currentClient = null;
496
+ currentBuffer = null;
497
+ }
498
+ const buffer = new BreadcrumbBuffer(opts.maxBreadcrumbs ?? 50);
499
+ const client = (0, import_tasks_sdk.init)(opts);
500
+ currentClient = client;
501
+ currentBuffer = buffer;
502
+ teardownFns = [];
503
+ if (opts.captureGlobalErrors !== false) {
504
+ teardownFns.push(installGlobalErrorHandler(client, buffer));
505
+ }
506
+ if (opts.captureUnhandledRejections !== false) {
507
+ teardownFns.push(installRejectionTracker(client, buffer));
508
+ }
509
+ if (opts.captureConsole !== false) {
510
+ teardownFns.push(installConsoleBreadcrumbs(buffer));
511
+ }
512
+ if (opts.captureNetwork !== false) {
513
+ teardownFns.push(
514
+ installFetchBreadcrumbs(buffer, {
515
+ includeUrls: opts.networkIncludeUrls,
516
+ excludeUrls: opts.networkExcludeUrls,
517
+ slowThresholdMs: opts.networkSlowThresholdMs,
518
+ includeQueryString: opts.networkIncludeQueryString
519
+ })
520
+ );
521
+ }
522
+ if (opts.captureAppState !== false) {
523
+ teardownFns.push(installAppStateBreadcrumbs(buffer));
524
+ }
525
+ if (opts.captureNativeCrash !== false) {
526
+ void recoverNativeCrash(
527
+ client,
528
+ opts.platformOverride ? { ...detectPlatform(), ...opts.platformOverride } : detectPlatform(),
529
+ opts.onNativeCrashError
530
+ );
531
+ }
532
+ return {
533
+ client,
534
+ buffer,
535
+ captureException(err, ctx) {
536
+ const e = err instanceof Error ? err : new Error(String(err));
537
+ reportError(client, e, {
538
+ mechanism: "notify",
539
+ level: ctx?.level,
540
+ breadcrumbs: buffer,
541
+ platform: opts.platformOverride ? { ...detectPlatform(), ...opts.platformOverride } : detectPlatform()
542
+ });
543
+ },
544
+ addBreadcrumb(b) {
545
+ buffer.add({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...b });
546
+ },
547
+ recordNavigation(to, navOpts) {
548
+ recordNavigation(buffer, to, navOpts);
549
+ },
550
+ async flush() {
551
+ try {
552
+ await client.flushSpans();
553
+ } catch {
554
+ }
555
+ },
556
+ async close() {
557
+ for (const fn of teardownFns) {
558
+ try {
559
+ fn();
560
+ } catch {
561
+ }
562
+ }
563
+ teardownFns = [];
564
+ await client.flushSpans();
565
+ }
566
+ };
567
+ }
568
+ function getClient() {
569
+ return currentClient;
570
+ }
571
+ function getBuffer() {
572
+ return currentBuffer;
573
+ }
574
+ // Annotate the CommonJS export names for ESM import in node:
575
+ 0 && (module.exports = {
576
+ BreadcrumbBuffer,
577
+ attachReactNavigation,
578
+ getBuffer,
579
+ getClient,
580
+ init,
581
+ recordNavigation,
582
+ useExpoRouterReporter
583
+ });
584
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/breadcrumbs.ts","../src/wrap-sentinel.ts","../src/console.ts","../src/platform.ts","../src/errors.ts","../src/network.ts","../src/app-state.ts","../src/navigation.ts","../src/native-crash.ts"],"sourcesContent":["import { init as coreInit, type Client } from '@koderlabs/tasks-sdk';\n\nimport { BreadcrumbBuffer } from './breadcrumbs';\nimport { installConsoleBreadcrumbs } from './console';\nimport { installGlobalErrorHandler, installRejectionTracker, reportError } from './errors';\nimport { installFetchBreadcrumbs } from './network';\nimport { installAppStateBreadcrumbs } from './app-state';\nimport { recordNavigation, attachReactNavigation, useExpoRouterReporter } from './navigation';\nimport { recoverNativeCrash } from './native-crash';\nimport { detectPlatform } from './platform';\nimport type { RnInitOptions } from './types';\n\nlet currentClient: Client | null = null;\nlet currentBuffer: BreadcrumbBuffer | null = null;\nlet teardownFns: Array<() => void> = [];\n\nexport interface RnClientHandle {\n client: Client;\n buffer: BreadcrumbBuffer;\n /** Manually capture an error. */\n captureException(err: unknown, ctx?: { level?: 'fatal' | 'error' | 'warning' }): void;\n /** Add a manual breadcrumb. */\n addBreadcrumb(b: { category: 'navigation' | 'http' | 'console' | 'user' | 'custom'; message: string; data?: Record<string, unknown>; level?: 'info' | 'warning' | 'error' }): void;\n /** Record a navigation transition. */\n recordNavigation(to: string, opts?: { from?: string; params?: Record<string, unknown> }): void;\n /** Flush queued events / spans. Best-effort; resolves when done. */\n flush(): Promise<void>;\n /** Stop all auto-instrumentation. */\n close(): Promise<void>;\n}\n\nexport function init(opts: RnInitOptions): RnClientHandle {\n // Tear down any prior client synchronously before installing new wrappers —\n // otherwise multiple wrappers stack on console/fetch/ErrorUtils and teardownFns\n // from the prior init() are silently overwritten and never run.\n if (currentClient || teardownFns.length) {\n for (const fn of teardownFns) {\n try { fn(); } catch { /* swallow */ }\n }\n teardownFns = [];\n currentClient = null;\n currentBuffer = null;\n }\n\n const buffer = new BreadcrumbBuffer(opts.maxBreadcrumbs ?? 50);\n const client = coreInit(opts);\n currentClient = client;\n currentBuffer = buffer;\n teardownFns = [];\n\n if (opts.captureGlobalErrors !== false) {\n teardownFns.push(installGlobalErrorHandler(client, buffer));\n }\n if (opts.captureUnhandledRejections !== false) {\n teardownFns.push(installRejectionTracker(client, buffer));\n }\n if (opts.captureConsole !== false) {\n teardownFns.push(installConsoleBreadcrumbs(buffer));\n }\n if (opts.captureNetwork !== false) {\n teardownFns.push(\n installFetchBreadcrumbs(buffer, {\n includeUrls: opts.networkIncludeUrls,\n excludeUrls: opts.networkExcludeUrls,\n slowThresholdMs: opts.networkSlowThresholdMs,\n includeQueryString: opts.networkIncludeQueryString,\n }),\n );\n }\n if (opts.captureAppState !== false) {\n teardownFns.push(installAppStateBreadcrumbs(buffer));\n }\n\n // Drain any native-crash file from the previous launch (Expo config plugin\n // writes one when iOS NSException / Android Throwable escapes the runtime).\n // Fire-and-forget — best-effort, runs off the main bootstrap path.\n if (opts.captureNativeCrash !== false) {\n void recoverNativeCrash(\n client,\n opts.platformOverride ? { ...detectPlatform(), ...opts.platformOverride } : detectPlatform(),\n opts.onNativeCrashError,\n );\n }\n\n return {\n client,\n buffer,\n captureException(err, ctx) {\n const e = err instanceof Error ? err : new Error(String(err));\n reportError(client, e, {\n mechanism: 'notify',\n level: ctx?.level,\n breadcrumbs: buffer,\n platform: opts.platformOverride ? { ...detectPlatform(), ...opts.platformOverride } : detectPlatform(),\n });\n },\n addBreadcrumb(b) {\n buffer.add({ ts: new Date().toISOString(), ...b });\n },\n recordNavigation(to, navOpts) {\n recordNavigation(buffer, to, navOpts);\n },\n async flush() {\n // The core client buffers span output; errors are POSTed inline so\n // there's nothing extra to drain on the error path. flushSpans()\n // covers anything else queued by integrations.\n try {\n await client.flushSpans();\n } catch {\n /* best-effort */\n }\n },\n async close() {\n for (const fn of teardownFns) { try { fn(); } catch { /* swallow */ } }\n teardownFns = [];\n await client.flushSpans();\n },\n };\n}\n\nexport function getClient(): Client | null { return currentClient; }\nexport function getBuffer(): BreadcrumbBuffer | null { return currentBuffer; }\n\nexport type { RnInitOptions, Breadcrumb } from './types';\nexport { BreadcrumbBuffer } from './breadcrumbs';\nexport { recordNavigation, attachReactNavigation, useExpoRouterReporter } from './navigation';\n","import type { Breadcrumb } from './types';\n\nexport class BreadcrumbBuffer {\n private buf: Breadcrumb[] = [];\n constructor(private max = 50) {}\n\n add(b: Breadcrumb): void {\n this.buf.push(b);\n if (this.buf.length > this.max) this.buf.splice(0, this.buf.length - this.max);\n }\n\n drain(): Breadcrumb[] {\n const out = this.buf.slice();\n return out;\n }\n\n clear(): void {\n this.buf = [];\n }\n}\n","/**\n * Sentinel marker used by every monkey-patch wrapper in the RN SDK\n * (fetch, console.warn/error, ErrorUtils handler) so we can detect when\n * we are about to wrap something we already wrapped.\n *\n * Without this, calling `init()` twice — common during Fast Refresh and\n * tests — would stack N wrappers, emit N breadcrumbs per call, and teardown\n * would only ever unwind a single layer.\n */\nexport const INSTANT_TASKS_WRAPPED = Symbol.for('@koderlabs/tasks-sdk-rn.wrapped');\n\nexport interface Wrapped<T> {\n [INSTANT_TASKS_WRAPPED]?: { original: T };\n}\n\n/**\n * Return the deepest pre-existing original behind a function that may be\n * one or more InstantTasks wrappers. Returns the input unchanged if it\n * was not wrapped by us.\n */\nexport function unwrap<T extends (...args: any[]) => any>(fn: T): T {\n let cur: any = fn;\n while (cur && cur[INSTANT_TASKS_WRAPPED]) {\n cur = cur[INSTANT_TASKS_WRAPPED].original;\n }\n return cur as T;\n}\n\nexport function markWrapped<T extends (...args: any[]) => any>(wrapper: T, original: T): T {\n (wrapper as unknown as Wrapped<T>)[INSTANT_TASKS_WRAPPED] = { original };\n return wrapper;\n}\n","import type { BreadcrumbBuffer } from './breadcrumbs';\nimport { markWrapped, unwrap } from './wrap-sentinel';\n\ntype ConsoleFn = (...args: unknown[]) => void;\nconst LEVELS = ['warn', 'error'] as const;\ntype Level = (typeof LEVELS)[number];\n\nexport function installConsoleBreadcrumbs(breadcrumbs: BreadcrumbBuffer): () => void {\n if (typeof console === 'undefined') return () => undefined;\n\n // Capture originals per install in closure (not module scope) so multiple\n // install/teardown cycles don't lose the true original.\n const originals: Partial<Record<Level, ConsoleFn>> = {};\n const wrappers: Partial<Record<Level, ConsoleFn>> = {};\n\n for (const level of LEVELS) {\n const existing = (console as Record<string, ConsoleFn | undefined>)[level];\n if (typeof existing !== 'function') continue;\n const original = unwrap(existing) as ConsoleFn;\n originals[level] = original;\n const wrapper: ConsoleFn = (...args: unknown[]) => {\n try {\n breadcrumbs.add({\n ts: new Date().toISOString(),\n category: 'console',\n level: level === 'warn' ? 'warning' : 'error',\n message: args.map((a) => (typeof a === 'string' ? a : safeStringify(a))).join(' ').slice(0, 1000),\n });\n } catch {\n /* breadcrumbs are best-effort; swallow */\n }\n original.apply(console, args);\n };\n markWrapped(wrapper, original);\n wrappers[level] = wrapper;\n (console as Record<string, ConsoleFn>)[level] = wrapper;\n }\n\n return () => {\n for (const level of LEVELS) {\n const orig = originals[level];\n const wrapper = wrappers[level];\n if (!orig || !wrapper) continue;\n const current = (console as Record<string, ConsoleFn>)[level];\n if (current === wrapper) {\n (console as Record<string, ConsoleFn>)[level] = orig;\n } else {\n (console as Record<string, ConsoleFn>)[level] = unwrap(current) as ConsoleFn;\n }\n }\n };\n}\n\nfunction safeStringify(v: unknown): string {\n try { return JSON.stringify(v); } catch { return String(v); }\n}\n","/**\n * Resolves platform info via `react-native` if available at runtime.\n * Falls back to empty values when the import resolves but the modules\n * aren't initialised (unit tests, SSR, etc.).\n */\nexport interface PlatformInfo {\n os: string;\n osVersion: string;\n deviceModel: string;\n bundleId: string;\n}\n\nexport function detectPlatform(): PlatformInfo {\n try {\n // Dynamic require so this package can be unit-tested without RN.\n const rn = (typeof require !== 'undefined' ? require : null)?.('react-native');\n if (!rn) return empty();\n const Platform = rn.Platform ?? {};\n const NativeModules = rn.NativeModules ?? {};\n return {\n os: String(Platform.OS ?? 'unknown'),\n osVersion: String(Platform.Version ?? ''),\n deviceModel: String(NativeModules?.PlatformConstants?.Model ?? ''),\n bundleId: String(NativeModules?.PlatformConstants?.bundleIdentifier ?? ''),\n };\n } catch {\n return empty();\n }\n}\n\nfunction empty(): PlatformInfo {\n return { os: 'unknown', osVersion: '', deviceModel: '', bundleId: '' };\n}\n","import type { Client } from '@koderlabs/tasks-sdk';\nimport type { BreadcrumbBuffer } from './breadcrumbs';\nimport { detectPlatform, type PlatformInfo } from './platform';\nimport { markWrapped, unwrap } from './wrap-sentinel';\n\ndeclare const ErrorUtils: {\n getGlobalHandler(): (err: Error, isFatal?: boolean) => void;\n setGlobalHandler(fn: (err: Error, isFatal?: boolean) => void): void;\n} | undefined;\n\ndeclare const HermesInternal: {\n enablePromiseRejectionTracker?: (opts: {\n allRejections: boolean;\n onUnhandled: (id: number, error: unknown) => void;\n onHandled?: (id: number) => void;\n }) => void;\n} | undefined;\n\nexport function reportError(\n client: Client,\n err: Error,\n ctx: { mechanism: 'onerror' | 'unhandledrejection' | 'notify'; level?: 'fatal' | 'error' | 'warning'; breadcrumbs?: BreadcrumbBuffer; platform?: PlatformInfo } = { mechanism: 'notify' },\n): void {\n const env = client.options;\n const platform = ctx.platform ?? detectPlatform();\n void client.send({\n kind: 'error',\n ts: new Date().toISOString(),\n release: env.release,\n environment: env.environment,\n user: env.user,\n url: `mobile://${platform.os}`,\n userAgent: `react-native/${platform.os} ${platform.osVersion} ${platform.deviceModel}`.trim(),\n viewport: { width: 0, height: 0 },\n exception: {\n type: err.name || 'Error',\n value: err.message || String(err),\n stack: err.stack,\n mechanism: ctx.mechanism,\n },\n level: ctx.level ?? 'error',\n breadcrumbs: ctx.breadcrumbs?.drain() as any,\n custom: { platform },\n } as any);\n}\n\nexport function installGlobalErrorHandler(client: Client, breadcrumbs: BreadcrumbBuffer): () => void {\n if (typeof ErrorUtils === 'undefined' || !ErrorUtils?.setGlobalHandler) return () => undefined;\n // Strip any prior InstantTasks wrapper so re-init doesn't double-report.\n const prev = unwrap(ErrorUtils.getGlobalHandler());\n const handler = (err: Error, isFatal?: boolean) => {\n try {\n reportError(client, err, {\n mechanism: 'onerror',\n level: isFatal ? 'fatal' : 'error',\n breadcrumbs,\n });\n } finally {\n prev?.(err, isFatal);\n }\n };\n markWrapped(handler, prev);\n ErrorUtils.setGlobalHandler(handler);\n return () => {\n const current = ErrorUtils!.getGlobalHandler();\n if (current === handler) {\n ErrorUtils!.setGlobalHandler(prev);\n } else {\n ErrorUtils!.setGlobalHandler(unwrap(current));\n }\n };\n}\n\nexport function installRejectionTracker(client: Client, breadcrumbs: BreadcrumbBuffer): () => void {\n if (typeof HermesInternal !== 'undefined' && HermesInternal?.enablePromiseRejectionTracker) {\n HermesInternal.enablePromiseRejectionTracker({\n allRejections: true,\n onUnhandled: (_id, reason) => {\n const err = reason instanceof Error ? reason : new Error(String(reason));\n reportError(client, err, { mechanism: 'unhandledrejection', level: 'error', breadcrumbs });\n },\n });\n return () => undefined; // Hermes doesn't expose a deinstall hook\n }\n // Fallback for JSC / Node test environment\n if (typeof process !== 'undefined' && typeof process.on === 'function') {\n const fn = (reason: unknown) => {\n const err = reason instanceof Error ? reason : new Error(String(reason));\n reportError(client, err, { mechanism: 'unhandledrejection', level: 'error', breadcrumbs });\n };\n process.on('unhandledRejection', fn);\n return () => process.off('unhandledRejection', fn);\n }\n return () => undefined;\n}\n","/**\n * fetch() breadcrumb integration for React Native.\n *\n * Wraps the global `fetch` to record one breadcrumb per request, keyed by\n * method + URL + status. Mirrors the web SDK behaviour. RN ships a polyfilled\n * fetch (whatwg-fetch via the Hermes runtime); we patch that singleton.\n *\n * Body capture is NOT performed — risk of leaking secrets is too high and\n * many RN apps stream large blobs (uploads).\n *\n * The interceptor is non-blocking: failures inside the breadcrumb path never\n * disturb the original fetch result. We always re-throw the original error.\n */\nimport type { BreadcrumbBuffer } from './breadcrumbs';\nimport { markWrapped, unwrap } from './wrap-sentinel';\n\ntype FetchFn = typeof fetch;\n\ninterface InstallOptions {\n /** Allowlist — only record breadcrumbs for URLs matching one of these. */\n includeUrls?: RegExp[];\n /** Denylist — drop breadcrumbs whose URL matches any pattern. Default: skip ingest endpoint to avoid recursion. */\n excludeUrls?: RegExp[];\n /** Tag breadcrumbs slow above this ms threshold. */\n slowThresholdMs?: number;\n /**\n * Include URL query string in breadcrumb. Default false — query strings\n * commonly contain access tokens / session IDs / emails, all of which are\n * PII that the customer didn't opt into shipping.\n */\n includeQueryString?: boolean;\n}\n\n/**\n * Strip query string and fragment unless explicitly opted in. Defensive — most\n * RN apps embed user IDs / tokens in query params (deep links, OAuth flows).\n */\nfunction scrubUrl(raw: string, includeQuery: boolean): string {\n if (includeQuery) return raw;\n const qIdx = raw.indexOf('?');\n const hIdx = raw.indexOf('#');\n const cut = Math.min(qIdx === -1 ? raw.length : qIdx, hIdx === -1 ? raw.length : hIdx);\n return raw.slice(0, cut);\n}\n\n/**\n * Install fetch breadcrumb interceptor. Returns a teardown fn that restores\n * the original `fetch`. Safe to call multiple times — re-install simply\n * replaces the wrapper.\n */\nexport function installFetchBreadcrumbs(\n buffer: BreadcrumbBuffer,\n opts: InstallOptions = {},\n): () => void {\n if (typeof globalThis.fetch !== 'function') return () => undefined;\n\n // Unwrap any existing InstantTasks wrapper before installing — without this,\n // re-init (Fast Refresh, tests) stacks wrappers and emits N breadcrumbs per\n // call. We capture the deepest non-our-wrapper as the true original.\n const original: FetchFn = unwrap(globalThis.fetch);\n const bound: FetchFn = original.bind(globalThis);\n const include = opts.includeUrls ?? [];\n const exclude = opts.excludeUrls ?? [\n // Always skip own ingest path so error reporting doesn't generate breadcrumbs\n // that get sent in the next event payload (recursive amplification).\n /\\/api\\/v1\\/sdk\\/events/,\n ];\n const slowMs = opts.slowThresholdMs ?? 2000;\n const includeQuery = opts.includeQueryString === true;\n\n const wrapper: FetchFn = async (input, init) => {\n const rawUrl = typeof input === 'string' ? input : (input as Request).url ?? '';\n const method = (init?.method ?? (typeof input !== 'string' ? (input as Request).method : 'GET') ?? 'GET').toUpperCase();\n // Allow/deny lists run against the FULL URL — devs need to match against\n // query when whitelisting; only the breadcrumb value is scrubbed.\n if (include.length && !include.some((re) => re.test(rawUrl))) {\n return bound(input, init);\n }\n if (exclude.some((re) => re.test(rawUrl))) {\n return bound(input, init);\n }\n const url = scrubUrl(rawUrl, includeQuery);\n\n const startedAt = Date.now();\n let status: number | undefined;\n let errorMessage: string | undefined;\n try {\n const res = await bound(input, init);\n status = res.status;\n return res;\n } catch (err) {\n errorMessage = err instanceof Error ? err.message : String(err);\n throw err;\n } finally {\n const durationMs = Date.now() - startedAt;\n try {\n buffer.add({\n ts: new Date(startedAt).toISOString(),\n category: 'http',\n message: `${method} ${url}${status ? ` → ${status}` : ''}`,\n level: errorMessage || (status && status >= 500) ? 'error'\n : status && status >= 400 ? 'warning'\n : 'info',\n data: {\n method,\n url,\n status,\n durationMs,\n slow: durationMs >= slowMs ? true : undefined,\n error: errorMessage,\n },\n });\n } catch {\n /* breadcrumbs are best-effort; swallow */\n }\n }\n };\n\n markWrapped(wrapper, original);\n globalThis.fetch = wrapper;\n return () => {\n // Restore the original even if another wrapper has been layered on top of\n // ours since install — we unwrap to its inner original and substitute.\n const current = globalThis.fetch as FetchFn;\n if (current === wrapper) {\n globalThis.fetch = original;\n } else {\n globalThis.fetch = unwrap(current);\n }\n };\n}\n","/**\n * React Native AppState breadcrumb integration.\n *\n * Records foreground/background transitions so when an error fires the agent\n * can see whether the app had just resumed, was backgrounded, etc. Mirrors\n * the session-lifecycle context that web SDKs derive from `visibilitychange`.\n *\n * Requires `react-native` at runtime. In unit tests the dynamic require\n * fails silently and the install returns a no-op teardown.\n */\nimport type { BreadcrumbBuffer } from './breadcrumbs';\n\n/**\n * Install AppState subscriber that emits a breadcrumb every time the\n * application state transitions. Returns a teardown fn that removes the\n * subscription. Safe to call when `react-native` is not available — the\n * function detects that case and returns a no-op.\n */\nexport function installAppStateBreadcrumbs(buffer: BreadcrumbBuffer): () => void {\n let rn: { AppState?: { addEventListener: (event: string, fn: (state: string) => void) => { remove: () => void } | (() => void) } };\n try {\n rn = (typeof require !== 'undefined' ? require : null)?.('react-native') ?? {};\n } catch {\n return () => undefined;\n }\n if (!rn.AppState?.addEventListener) return () => undefined;\n\n let lastState = 'active';\n const subscription = rn.AppState.addEventListener('change', (nextState: string) => {\n if (nextState === lastState) return;\n try {\n buffer.add({\n ts: new Date().toISOString(),\n category: 'navigation',\n message: `AppState: ${lastState} → ${nextState}`,\n level: 'info',\n data: { from: lastState, to: nextState },\n });\n } catch {\n /* swallow */\n }\n lastState = nextState;\n });\n\n return () => {\n // Older RN returns a remove() function directly; newer returns a\n // NativeEventSubscription with a remove() method.\n if (typeof subscription === 'function') subscription();\n else subscription?.remove?.();\n };\n}\n","/**\n * Navigation breadcrumb helpers. Router-agnostic.\n *\n * Two integration styles are supported:\n *\n * 1. Manual — the app pushes a breadcrumb on every screen change by calling\n * `recordNavigation(from, to, params?)`. Works with any navigator (React\n * Navigation, Expo Router, custom).\n *\n * 2. Helper-attached — the app passes a navigation listener / state observer\n * into `attachReactNavigation()` or `attachExpoRouter()` which wires the\n * internal callbacks. These are thin wrappers — they only call\n * `recordNavigation` — but keep the integration surface obvious for\n * copy-paste setup code.\n *\n * Navigation breadcrumbs use category 'navigation' so triagers can filter\n * them alongside AppState transitions and deep-link openings.\n */\nimport type { BreadcrumbBuffer } from './breadcrumbs';\n\n/**\n * Record a manual navigation breadcrumb. Safe to call from any router.\n * Empty `from` is allowed for the initial route.\n */\nexport function recordNavigation(\n buffer: BreadcrumbBuffer,\n to: string,\n opts: { from?: string; params?: Record<string, unknown> } = {},\n): void {\n try {\n buffer.add({\n ts: new Date().toISOString(),\n category: 'navigation',\n message: opts.from ? `${opts.from} → ${to}` : `navigate ${to}`,\n level: 'info',\n data: {\n from: opts.from,\n to,\n params: opts.params,\n },\n });\n } catch {\n /* swallow — breadcrumbs are best-effort */\n }\n}\n\n/**\n * Attach to React Navigation 6/7 — pass the navigation container ref.\n * Listens to 'state' and records the active route name on every change.\n *\n * Usage:\n * const navRef = useNavigationContainerRef();\n * useEffect(() => attachReactNavigation(client.buffer, navRef), [navRef]);\n */\nexport function attachReactNavigation(\n buffer: BreadcrumbBuffer,\n navRef: {\n addListener: (event: 'state' | string, fn: () => void) => () => void;\n getCurrentRoute?: () => { name: string; params?: Record<string, unknown> } | undefined;\n },\n): () => void {\n let lastRoute: string | undefined;\n const unsub = navRef.addListener('state', () => {\n const current = navRef.getCurrentRoute?.();\n if (!current) return;\n if (current.name === lastRoute) return;\n recordNavigation(buffer, current.name, { from: lastRoute, params: current.params });\n lastRoute = current.name;\n });\n return unsub;\n}\n\n/**\n * Attach to Expo Router. Expo Router doesn't surface a single listener\n * channel — pass `usePathname()` output to `recordNavigation` from a\n * top-level effect. This helper provides a callback the app calls each\n * time its top-level `_layout.tsx` sees a path change.\n *\n * Usage:\n * const pathname = usePathname();\n * const reportPath = useExpoRouterReporter(client.buffer);\n * useEffect(() => reportPath(pathname), [pathname]);\n */\nexport function useExpoRouterReporter(buffer: BreadcrumbBuffer): (pathname: string) => void {\n let lastPath: string | undefined;\n return (pathname: string) => {\n if (pathname === lastPath) return;\n recordNavigation(buffer, pathname, { from: lastPath });\n lastPath = pathname;\n };\n}\n","/**\n * Native-crash retrieval — pairs with the Expo config plugin that installs\n * iOS / Android uncaught-exception handlers (see `plugin/src/index.ts`).\n *\n * On every cold start the SDK looks for a crash JSON file written by the\n * native handler from the *previous* run. If found, the file is parsed,\n * shipped as an error event with `mechanism: 'native_crash'`, and deleted\n * so it isn't re-sent on the next launch.\n *\n * Requires `expo-file-system` at runtime. When the dependency isn't\n * available (web preview, Node tests), this module no-ops and the SDK\n * continues without native-crash retrieval.\n */\nimport type { Client } from '@koderlabs/tasks-sdk';\nimport type { PlatformInfo } from './platform';\n\nconst CRASH_FILE = 'tasks-native-crash.json';\n\n/**\n * Stage-tagged failure reason. Distinguishes \"no crash\" (return false) from\n * an actual failure that silently dropped a crash report.\n *\n * Without this, operators see `recoverNativeCrash → false` and assume the app\n * was stable — the worst possible UX when a real crash decode is failing.\n */\nexport type NativeCrashStage =\n | 'native-pkg-load'\n | 'native-pkg-get'\n | 'native-pkg-purge'\n | 'expo-fs-load'\n | 'expo-fs-info'\n | 'expo-fs-read'\n | 'expo-fs-parse'\n | 'expo-fs-delete'\n | 'ship';\nexport interface NativeCrashError { stage: NativeCrashStage; message: string; cause?: unknown }\nexport type NativeCrashErrorHandler = (err: NativeCrashError) => void;\n\ninterface IosCrash {\n platform: 'ios';\n name: string;\n reason?: string;\n callStackSymbols?: string[];\n userInfo?: Record<string, unknown>;\n timestamp?: string;\n}\n\ninterface AndroidCrash {\n platform: 'android';\n name: string;\n message?: string;\n stackTrace?: string;\n threadName?: string;\n timestamp?: string;\n}\n\ntype NativeCrash = IosCrash | AndroidCrash;\n\n/**\n * Read + ship + delete the native-crash file from the previous cold start.\n * Returns `true` if a crash was found and shipped, `false` otherwise.\n *\n * Errors during read/ship/delete are swallowed — telemetry must never crash\n * the host app.\n */\nexport async function recoverNativeCrash(\n client: Client,\n platform: PlatformInfo,\n onError?: NativeCrashErrorHandler,\n): Promise<boolean> {\n // First check if the dedicated native package is installed. If so, prefer\n // its richer crash reports (PLCrashReporter on iOS, signal-trapped stacks\n // on Android) over the config-plugin's JSON-file fallback.\n let nativePkg: { getPendingNativeCrash?: (h?: unknown) => Promise<unknown>; purgePendingNativeCrash?: (h?: unknown) => Promise<void> } | null = null;\n try {\n nativePkg = (typeof require !== 'undefined' ? require : null)?.('@koderlabs/tasks-sdk-rn-native') ?? null;\n } catch (e) {\n onError?.({ stage: 'native-pkg-load', message: (e as Error).message, cause: e });\n /* fall through to file-based recovery */\n }\n if (nativePkg?.getPendingNativeCrash) {\n try {\n const report = await nativePkg.getPendingNativeCrash();\n if (report) {\n try {\n await shipCrash(client, normaliseNativeReport(report), platform);\n } catch (e) {\n onError?.({ stage: 'ship', message: (e as Error).message, cause: e });\n }\n try {\n await nativePkg.purgePendingNativeCrash?.();\n } catch (e) {\n onError?.({ stage: 'native-pkg-purge', message: (e as Error).message, cause: e });\n }\n return true;\n }\n } catch (e) {\n onError?.({ stage: 'native-pkg-get', message: (e as Error).message, cause: e });\n }\n }\n\n // Dynamic require so unit tests / web builds don't pull in expo-file-system.\n let FileSystem: {\n documentDirectory: string | null;\n readAsStringAsync: (uri: string) => Promise<string>;\n deleteAsync: (uri: string, opts?: { idempotent?: boolean }) => Promise<void>;\n getInfoAsync: (uri: string) => Promise<{ exists: boolean }>;\n } | null = null;\n try {\n FileSystem = (typeof require !== 'undefined' ? require : null)?.('expo-file-system') ?? null;\n } catch (e) {\n onError?.({ stage: 'expo-fs-load', message: (e as Error).message, cause: e });\n return false;\n }\n if (!FileSystem?.documentDirectory) return false;\n\n const path = `${FileSystem.documentDirectory}${CRASH_FILE}`;\n let info: { exists: boolean };\n try {\n info = await FileSystem.getInfoAsync(path);\n } catch (e) {\n onError?.({ stage: 'expo-fs-info', message: (e as Error).message, cause: e });\n return false;\n }\n if (!info.exists) return false;\n\n let raw: string;\n try {\n raw = await FileSystem.readAsStringAsync(path);\n } catch (e) {\n onError?.({ stage: 'expo-fs-read', message: (e as Error).message, cause: e });\n return false;\n }\n let crash: NativeCrash;\n try {\n crash = JSON.parse(raw) as NativeCrash;\n } catch (e) {\n onError?.({ stage: 'expo-fs-parse', message: (e as Error).message, cause: e });\n // Corrupted file — drop it so we don't keep retrying.\n await FileSystem.deleteAsync(path, { idempotent: true }).catch(() => undefined);\n return false;\n }\n\n try {\n await shipCrash(client, crash, platform);\n } catch (e) {\n onError?.({ stage: 'ship', message: (e as Error).message, cause: e });\n }\n try {\n await FileSystem.deleteAsync(path, { idempotent: true });\n } catch (e) {\n onError?.({ stage: 'expo-fs-delete', message: (e as Error).message, cause: e });\n }\n return true;\n}\n\n/**\n * Convert a report from `@koderlabs/tasks-sdk-rn-native` into the unified\n * shape `shipCrash` expects. The native package returns richer iOS payloads\n * (full thread/image tables) and Android signal/ANR shapes; we collapse\n * them onto the same minimal contract so the resource server sees one\n * schema regardless of source.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction normaliseNativeReport(r: any): NativeCrash {\n if (r?.platform === 'ios') {\n const stackLines: string[] = [];\n for (const t of (r.threads ?? [])) {\n if (!t.crashed) continue;\n for (const f of (t.frames ?? [])) {\n stackLines.push(`0x${(f.instructionPointer >>> 0).toString(16)} ${f.symbol ?? '?'}`);\n }\n }\n return {\n platform: 'ios',\n name: r.exception?.name || r.signal?.name || 'NativeCrash',\n reason: r.exception?.reason || r.signal?.code || '',\n callStackSymbols: stackLines,\n userInfo: { signal: r.signal, appBundleId: r.appBundleId, appVersion: r.appVersion },\n timestamp: r.timestamp,\n };\n }\n // Android — signal or ANR\n const stack = Array.isArray(r.frames)\n ? (r.frames as string[]).join('\\n')\n : Array.isArray(r.stack)\n ? (r.stack as string[]).join('\\n')\n : '';\n return {\n platform: 'android',\n name: r.signal || (r.kind === 'anr' ? 'ANR' : 'NativeCrash'),\n message: r.faultAddr || (r.kind === 'anr' ? `Main thread blocked >${r.thresholdMs}ms` : ''),\n stackTrace: stack,\n threadName: r.kind === 'anr' ? 'main' : undefined,\n timestamp: r.capturedAt || r.timestamp,\n };\n}\n\n// Throws on send failure — recoverNativeCrash() callers route via NativeCrashErrorHandler.\nasync function shipCrash(client: Client, crash: NativeCrash, platform: PlatformInfo): Promise<void> {\n const env = client.options;\n const stack = crash.platform === 'ios'\n ? (crash.callStackSymbols ?? []).join('\\n')\n : (crash.stackTrace ?? '');\n const message = crash.platform === 'ios'\n ? (crash.reason ?? crash.name)\n : (crash.message ?? crash.name);\n\n await client.send({\n kind: 'error',\n ts: crash.timestamp ?? new Date().toISOString(),\n release: env.release,\n environment: env.environment,\n user: env.user,\n url: `mobile://${platform.os}`,\n userAgent: `react-native/${platform.os} ${platform.osVersion} ${platform.deviceModel}`.trim(),\n viewport: { width: 0, height: 0 },\n exception: {\n type: crash.name,\n value: message,\n stack,\n mechanism: 'native_crash',\n },\n level: 'fatal',\n breadcrumbs: [],\n custom: {\n platform,\n nativeCrash: {\n platform: crash.platform,\n threadName: 'threadName' in crash ? crash.threadName : undefined,\n userInfo: 'userInfo' in crash ? crash.userInfo : undefined,\n },\n },\n } as unknown as Parameters<Client['send']>[0]);\n}\n"],"mappings":"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","names":["init","coreInit"]}