@allstak/react-native 0.1.3 → 0.3.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.d.mts CHANGED
@@ -1 +1,695 @@
1
- export { AllStak, ReactNativeInstallOptions, installReactNative } from '@allstak/js/react-native';
1
+ /**
2
+ * Minimal HTTP transport for React Native. Uses the global `fetch` (always
3
+ * present in RN >= 0.60) with a 3s timeout. Failed sends fall into a small
4
+ * in-memory ring buffer that we retry on the next successful flush.
5
+ *
6
+ * No window, no AbortController fallback shims — RN exposes both natively.
7
+ */
8
+ declare class HttpTransport {
9
+ private baseUrl;
10
+ private apiKey;
11
+ private buffer;
12
+ private flushing;
13
+ constructor(baseUrl: string, apiKey: string);
14
+ send(path: string, payload: unknown): Promise<void>;
15
+ private doFetch;
16
+ private flushBuffer;
17
+ getBufferSize(): number;
18
+ /**
19
+ * Wait for the in-flight retry-buffer to drain. Resolves `true` if the
20
+ * buffer empties within `timeoutMs` (default 2000ms), `false` otherwise.
21
+ * Useful before navigation away or during native crash drain.
22
+ */
23
+ flush(timeoutMs?: number): Promise<boolean>;
24
+ }
25
+
26
+ /**
27
+ * HTTP request batching + transport for the React Native SDK.
28
+ *
29
+ * Mirrors the wire shape used by `@allstak/js`'s HttpRequestModule so the
30
+ * existing backend ingest endpoint (`/ingest/v1/http-requests`) accepts
31
+ * events from this SDK without a schema change. Adds optional rich fields
32
+ * (headers, bodies, error string) — these ride alongside the existing
33
+ * required fields and are tolerated as additive metadata server-side.
34
+ *
35
+ * Batching:
36
+ * - flushes on a 5s timer OR when 20 events queue up
37
+ * - flushes immediately on `destroy()`
38
+ * - `getRecentFailed(n)` returns the last n failed requests (statusCode
39
+ * >= 400 OR error set), used by error-linking on the next captureException
40
+ */
41
+
42
+ /** What instrumentation hands to the module per request. */
43
+ interface HttpRequestEvent {
44
+ type: 'http_request';
45
+ method: string;
46
+ url: string;
47
+ statusCode?: number;
48
+ durationMs: number;
49
+ requestSize?: number;
50
+ responseSize?: number;
51
+ requestBody?: string;
52
+ responseBody?: string;
53
+ requestHeaders?: Record<string, string>;
54
+ responseHeaders?: Record<string, string>;
55
+ error?: string;
56
+ traceId?: string;
57
+ }
58
+ interface HttpRequestIngestItem {
59
+ type: 'http_request';
60
+ traceId: string;
61
+ direction: 'outbound';
62
+ method: string;
63
+ host: string;
64
+ path: string;
65
+ url: string;
66
+ statusCode: number;
67
+ durationMs: number;
68
+ requestSize?: number;
69
+ responseSize?: number;
70
+ requestBody?: string;
71
+ responseBody?: string;
72
+ requestHeaders?: Record<string, string>;
73
+ responseHeaders?: Record<string, string>;
74
+ error?: string;
75
+ environment?: string;
76
+ release?: string;
77
+ dist?: string;
78
+ platform?: string;
79
+ 'sdk.name'?: string;
80
+ 'sdk.version'?: string;
81
+ timestamp: string;
82
+ }
83
+ interface ModuleDefaults {
84
+ environment?: string;
85
+ release?: string;
86
+ dist?: string;
87
+ platform?: string;
88
+ sdkName?: string;
89
+ sdkVersion?: string;
90
+ }
91
+ declare class HttpRequestModule {
92
+ private transport;
93
+ private queue;
94
+ private recentFailed;
95
+ private flushTimer;
96
+ private destroyed;
97
+ private defaults;
98
+ constructor(transport: HttpTransport);
99
+ setDefaults(defaults: ModuleDefaults): void;
100
+ capture(ev: HttpRequestEvent): void;
101
+ /** Snapshot of the last failed requests for error-linking. Newest last. */
102
+ getRecentFailed(): ReadonlyArray<HttpRequestIngestItem>;
103
+ flush(): void;
104
+ destroy(): void;
105
+ /** @internal — for tests. */
106
+ getQueueSize(): number;
107
+ }
108
+
109
+ /**
110
+ * Per-call scoped context isolation.
111
+ *
112
+ * A `Scope` carries the same shape as the top-level config (user, tags,
113
+ * extras, contexts, fingerprint, level) but only applies inside the
114
+ * `withScope` callback that owns it. The client merges the active scope
115
+ * stack on top of the base config when building each event payload, so:
116
+ *
117
+ * - context set inside `withScope` does NOT leak out
118
+ * - nested scopes layer additively (later wins on key conflicts)
119
+ * - throwing or async work in the callback still pops the scope
120
+ *
121
+ * Use this on the server (SSR / RSC / API route handlers) to attach
122
+ * per-request user/tags without leaking that data into another request
123
+ * being processed concurrently.
124
+ */
125
+ type Severity = 'fatal' | 'error' | 'warning' | 'info' | 'debug';
126
+ declare class Scope {
127
+ user?: {
128
+ id?: string;
129
+ email?: string;
130
+ };
131
+ tags: Record<string, string>;
132
+ extras: Record<string, unknown>;
133
+ contexts: Record<string, Record<string, unknown>>;
134
+ fingerprint?: string[];
135
+ level?: Severity;
136
+ setUser(user: {
137
+ id?: string;
138
+ email?: string;
139
+ }): this;
140
+ setTag(key: string, value: string): this;
141
+ setTags(tags: Record<string, string>): this;
142
+ setExtra(key: string, value: unknown): this;
143
+ setExtras(extras: Record<string, unknown>): this;
144
+ setContext(name: string, ctx: Record<string, unknown> | null): this;
145
+ setLevel(level: Severity): this;
146
+ setFingerprint(fingerprint: string[] | null): this;
147
+ clear(): this;
148
+ }
149
+
150
+ /**
151
+ * Lightweight distributed tracing primitives.
152
+ *
153
+ * A `Span` represents a unit of work — `startSpan('http.client', { description: 'GET /api/users' })`
154
+ * returns a Span; call `span.finish()` when the work completes. Spans
155
+ * batch into the transport's `/ingest/v1/spans` channel and ship every 5s
156
+ * (or when 20 spans accumulate).
157
+ *
158
+ * Trace propagation: each span carries a `traceId` (UUID, generated lazily
159
+ * on first call to `getTraceId()`) and a `spanId`. Nested calls to
160
+ * `startSpan()` automatically inherit the active span as their parent.
161
+ *
162
+ * Sampling: `tracesSampleRate` (config) gates whether `startSpan` actually
163
+ * records anything — drops when `Math.random() >= rate`. The returned
164
+ * Span is a no-op shim in that case so call sites don't need to null-check.
165
+ */
166
+
167
+ interface SpanData {
168
+ traceId: string;
169
+ spanId: string;
170
+ parentSpanId: string;
171
+ operation: string;
172
+ description: string;
173
+ status: 'ok' | 'error' | 'timeout';
174
+ durationMs: number;
175
+ startTimeMillis: number;
176
+ endTimeMillis: number;
177
+ service: string;
178
+ environment: string;
179
+ tags: Record<string, string>;
180
+ data: string;
181
+ }
182
+ declare class Span {
183
+ private _traceId;
184
+ private _spanId;
185
+ private _parentSpanId;
186
+ private _operation;
187
+ private _description;
188
+ private _service;
189
+ private _environment;
190
+ private _tags;
191
+ private _onFinish;
192
+ private _finished;
193
+ private _startTimeMillis;
194
+ private _data;
195
+ constructor(_traceId: string, _spanId: string, _parentSpanId: string, _operation: string, _description: string, _service: string, _environment: string, _tags: Record<string, string>, _onFinish: (data: SpanData) => void);
196
+ setTag(key: string, value: string): this;
197
+ setData(data: string): this;
198
+ setDescription(description: string): this;
199
+ finish(status?: 'ok' | 'error' | 'timeout'): void;
200
+ get traceId(): string;
201
+ get spanId(): string;
202
+ get isFinished(): boolean;
203
+ }
204
+
205
+ /**
206
+ * React Native "replay surrogate" — a privacy-first view-state breadcrumb
207
+ * recorder for environments where binary screen capture isn't available
208
+ * (Expo Go, JS-only test runners, or apps that can't link a native module
209
+ * for legal/compliance reasons).
210
+ *
211
+ * **What it captures (chronological, opt-in via sampleRate):**
212
+ * - the active route name on every navigation event
213
+ * - AppState foreground/background transitions (already covered by
214
+ * installReactNative's AppState breadcrumb wiring — we reuse that)
215
+ * - explicit `recordScreenView(name, params)` calls from the host app
216
+ * (used by router integrations or manual checkpoints)
217
+ *
218
+ * **What it intentionally does NOT capture:**
219
+ * - any user input values (text fields, password inputs, search queries)
220
+ * - any rendered text content from the visible screen
221
+ * - screenshots of any kind
222
+ * - URL path parameters by default (only the route name + opt-in `safeParams`)
223
+ *
224
+ * Hard rule: by default `safeParams` is `[]` and route params are dropped.
225
+ * Callers must explicitly enumerate which param keys are safe to log.
226
+ */
227
+
228
+ interface ReplaySurrogateOptions {
229
+ enabled?: boolean;
230
+ /** Probability in [0, 1] per session that recording happens. Default 0 (opt-in). */
231
+ sampleRate?: number;
232
+ /**
233
+ * Whitelist of route-param keys that are safe to record alongside the
234
+ * route name. Anything not on this list is dropped. Default `[]`.
235
+ */
236
+ safeParams?: string[];
237
+ /** Max events buffered before forced flush. Default 200. */
238
+ maxBufferedEvents?: number;
239
+ }
240
+ interface SurrogateEvent {
241
+ ts: number;
242
+ k: 'screen' | 'appstate' | 'manual';
243
+ data: Record<string, unknown>;
244
+ }
245
+ declare class ReplaySurrogate {
246
+ private transport;
247
+ private buffer;
248
+ private flushTimer;
249
+ private opts;
250
+ private sessionId;
251
+ private active;
252
+ private destroyed;
253
+ constructor(transport: HttpTransport, sessionId: string, options?: ReplaySurrogateOptions);
254
+ /** Enable recording for this session if sample-rate roll passes. */
255
+ start(): boolean;
256
+ /** Record a screen view. Filters params through the safeParams allow-list. */
257
+ recordScreenView(routeName: string, params?: Record<string, unknown>): void;
258
+ /** Record an AppState transition (foreground/background/inactive). */
259
+ recordAppState(next: string): void;
260
+ /** Record a free-form, customer-validated checkpoint. */
261
+ recordManual(label: string, data?: Record<string, unknown>): void;
262
+ destroy(): void;
263
+ /** @internal — for tests. */
264
+ isActive(): boolean;
265
+ /** @internal — for tests. */
266
+ getBuffer(): ReadonlyArray<SurrogateEvent>;
267
+ private push;
268
+ private flush;
269
+ }
270
+
271
+ interface HttpTrackingOptions {
272
+ /** Capture request body. Default false. Truncated to maxBodyBytes. */
273
+ captureRequestBody?: boolean;
274
+ /** Capture response body. Default false. Truncated to maxBodyBytes. */
275
+ captureResponseBody?: boolean;
276
+ /**
277
+ * Capture request + response headers. Default false. Hard-redacted
278
+ * names are always stripped regardless of this flag.
279
+ */
280
+ captureHeaders?: boolean;
281
+ /** Additional header names to redact (case-insensitive). */
282
+ redactHeaders?: string[];
283
+ /** Additional query-param names to redact (case-insensitive). */
284
+ redactQueryParams?: string[];
285
+ /**
286
+ * Skip URLs matching any of these patterns. String = case-insensitive
287
+ * substring match; RegExp = `.test()` against the full URL.
288
+ */
289
+ ignoredUrls?: (string | RegExp)[];
290
+ /**
291
+ * If non-empty, only capture URLs matching at least one of these
292
+ * patterns. Takes precedence over ignoredUrls.
293
+ */
294
+ allowedUrls?: (string | RegExp)[];
295
+ /** Max bytes per captured body. Default 4096. */
296
+ maxBodyBytes?: number;
297
+ }
298
+
299
+ declare const INGEST_HOST = "https://api.allstak.sa";
300
+ declare const SDK_NAME = "allstak-react-native";
301
+ declare const SDK_VERSION = "0.3.0";
302
+
303
+ interface AllStakConfig {
304
+ /** Project API key (`ask_live_…`). Required. */
305
+ apiKey: string;
306
+ /** Optional ingest host override; defaults to {@link INGEST_HOST}. */
307
+ host?: string;
308
+ environment?: string;
309
+ release?: string;
310
+ user?: {
311
+ id?: string;
312
+ email?: string;
313
+ };
314
+ tags?: Record<string, string>;
315
+ /** Per-event extra data attached to every capture (override per call via context arg). */
316
+ extras?: Record<string, unknown>;
317
+ /** Named context bags (e.g. `app`, `device`). Each lives under `metadata['context.<name>']`. */
318
+ contexts?: Record<string, Record<string, unknown>>;
319
+ /**
320
+ * Default severity level for events that don't specify their own.
321
+ * Affects `captureException` (sets `payload.level`) and the default of
322
+ * `captureMessage`. Customer-set default severity, mirrors `setLevel`.
323
+ */
324
+ level?: 'fatal' | 'error' | 'warning' | 'info' | 'debug';
325
+ /**
326
+ * Custom grouping fingerprint applied to every event. The backend uses
327
+ * this in place of stack-based grouping. Customer-set grouping override —
328
+ * `setFingerprint`. Pass an empty array or `null` to clear.
329
+ */
330
+ fingerprint?: string[];
331
+ /** Probability in [0, 1] that any new span is recorded. Default 1. */
332
+ tracesSampleRate?: number;
333
+ /** Service name attached to every span (defaults to release if unset). */
334
+ service?: string;
335
+ /**
336
+ * Privacy-first view-state replay surrogate. **Off by default.** Enable
337
+ * with `replay: { sampleRate: 0.1, safeParams: ['screenId'] }`. Captures
338
+ * route names + AppState transitions + manual checkpoints — never inputs
339
+ * or rendered text. See `src/replay-surrogate.ts` for the privacy contract.
340
+ */
341
+ replay?: ReplaySurrogateOptions;
342
+ /**
343
+ * Auto-instrument outbound HTTP — wraps `fetch`, `XMLHttpRequest`, and
344
+ * (when present) `axios`. Default: false. Combine with `httpTracking`
345
+ * to control body/header capture and redaction. Idempotent.
346
+ */
347
+ enableHttpTracking?: boolean;
348
+ /**
349
+ * Privacy + capture controls for HTTP instrumentation. Bodies and
350
+ * headers are OFF by default; auth headers and sensitive query params
351
+ * are ALWAYS redacted.
352
+ */
353
+ httpTracking?: HttpTrackingOptions;
354
+ maxBreadcrumbs?: number;
355
+ /**
356
+ * Probability in [0, 1] that any given error is sent. Default: 1 (no sampling).
357
+ * Applied per event before {@link beforeSend}.
358
+ */
359
+ sampleRate?: number;
360
+ /**
361
+ * Mutate or drop an event before it is sent. Return `null` (or a falsy
362
+ * value) to drop. Sync or async. Errors thrown inside the hook are caught
363
+ * — the event is sent as-is so a buggy hook can't black-hole telemetry.
364
+ */
365
+ beforeSend?: (event: ErrorIngestPayload) => ErrorIngestPayload | null | undefined | Promise<ErrorIngestPayload | null | undefined>;
366
+ /** SDK identity overrides (set automatically by installReactNative). */
367
+ sdkName?: string;
368
+ sdkVersion?: string;
369
+ platform?: string;
370
+ dist?: string;
371
+ commitSha?: string;
372
+ branch?: string;
373
+ }
374
+ interface Breadcrumb {
375
+ timestamp: string;
376
+ type: string;
377
+ message: string;
378
+ level: string;
379
+ data?: Record<string, unknown>;
380
+ }
381
+ interface PayloadFrame {
382
+ filename?: string;
383
+ absPath?: string;
384
+ function?: string;
385
+ lineno?: number;
386
+ colno?: number;
387
+ inApp?: boolean;
388
+ platform?: string;
389
+ }
390
+ interface ErrorIngestPayload {
391
+ exceptionClass: string;
392
+ message: string;
393
+ stackTrace?: string[];
394
+ frames?: PayloadFrame[];
395
+ platform?: string;
396
+ sdkName?: string;
397
+ sdkVersion?: string;
398
+ dist?: string;
399
+ level: string;
400
+ environment?: string;
401
+ release?: string;
402
+ sessionId?: string;
403
+ user?: {
404
+ id?: string;
405
+ email?: string;
406
+ };
407
+ metadata?: Record<string, unknown>;
408
+ breadcrumbs?: Breadcrumb[];
409
+ fingerprint?: string[];
410
+ }
411
+ declare class AllStakClient {
412
+ private transport;
413
+ private config;
414
+ private sessionId;
415
+ private breadcrumbs;
416
+ private maxBreadcrumbs;
417
+ private scopeStack;
418
+ private tracing;
419
+ private replay;
420
+ private httpRequests;
421
+ private _instrumentAxios;
422
+ constructor(config: AllStakConfig);
423
+ /** Access the replay surrogate (or null if not initialized / sampled out). */
424
+ getReplay(): ReplaySurrogate | null;
425
+ /** Manually instrument an axios instance. No-op when HTTP tracking is off. */
426
+ instrumentAxios<T = any>(axios: T): T;
427
+ /** Snapshot of recent failed HTTP requests for error-linking. */
428
+ getRecentFailedHttp(): readonly HttpRequestIngestItem[];
429
+ captureException(error: Error, context?: Record<string, unknown>): void;
430
+ /** Start a new span. Auto-parented to any currently-active span. */
431
+ startSpan(operation: string, options?: {
432
+ description?: string;
433
+ tags?: Record<string, string>;
434
+ }): Span;
435
+ /** Get (and lazily create) the active trace ID. */
436
+ getTraceId(): string;
437
+ /** Override the active trace ID, e.g. from an inbound request header. */
438
+ setTraceId(traceId: string): void;
439
+ /** ID of the currently-active span, or null. */
440
+ getCurrentSpanId(): string | null;
441
+ /** Reset the trace ID and the active span stack. */
442
+ resetTrace(): void;
443
+ captureMessage(message: string, level?: 'fatal' | 'error' | 'warning' | 'info', options?: {
444
+ as?: 'log' | 'error' | 'both';
445
+ }): void;
446
+ addBreadcrumb(type: string, message: string, level?: string, data?: Record<string, unknown>): void;
447
+ clearBreadcrumbs(): void;
448
+ setUser(user: {
449
+ id?: string;
450
+ email?: string;
451
+ }): void;
452
+ setTag(key: string, value: string): void;
453
+ /** Bulk-set tags. Merges with existing tags. */
454
+ setTags(tags: Record<string, string>): void;
455
+ /** Set a single extra value. */
456
+ setExtra(key: string, value: unknown): void;
457
+ /** Bulk-set extras. Merges with existing extras. */
458
+ setExtras(extras: Record<string, unknown>): void;
459
+ /**
460
+ * Attach a named context bag (e.g. `app`, `device`, `runtime`) — appears
461
+ * under `metadata['context.<name>']` on every subsequent event. Pass
462
+ * `null` to remove a previously-set context.
463
+ */
464
+ setContext(name: string, ctx: Record<string, unknown> | null): void;
465
+ /**
466
+ * Wait for the in-flight retry-buffer to drain. Resolves `true` if the
467
+ * buffer empties within `timeoutMs` (default 2000ms), `false` otherwise.
468
+ */
469
+ flush(timeoutMs?: number): Promise<boolean>;
470
+ /** Set the default severity level applied to subsequent captures. */
471
+ setLevel(level: 'fatal' | 'error' | 'warning' | 'info' | 'debug'): void;
472
+ /**
473
+ * Set a custom grouping fingerprint applied to subsequent events.
474
+ * Pass `null` or an empty array to clear and revert to default grouping.
475
+ */
476
+ setFingerprint(fingerprint: string[] | null): void;
477
+ setIdentity(identity: {
478
+ sdkName?: string;
479
+ sdkVersion?: string;
480
+ platform?: string;
481
+ dist?: string;
482
+ }): void;
483
+ getSessionId(): string;
484
+ getConfig(): AllStakConfig;
485
+ destroy(): void;
486
+ private sendLog;
487
+ private passesSampleRate;
488
+ /**
489
+ * Returns the effective config layer = base config + every scope on the
490
+ * stack. Inner code reads from this instead of `this.config` directly so
491
+ * scope-only overrides (set inside `withScope`) flow into the wire
492
+ * payload without leaking out of the callback.
493
+ */
494
+ private effective;
495
+ private buildMetadata;
496
+ /**
497
+ * Run `callback` with a fresh, temporary {@link Scope} that isolates
498
+ * any user/tag/extra/context/fingerprint/level it sets. The scope is
499
+ * popped automatically when the callback returns or throws — including
500
+ * for `Promise`-returning callbacks (the pop runs in `.finally`).
501
+ *
502
+ * Use this on the server to attach per-request context without leaking
503
+ * across concurrent requests.
504
+ */
505
+ withScope<T>(callback: (scope: Scope) => T): T;
506
+ /** Direct access to the topmost active scope, or null. @internal */
507
+ getCurrentScope(): Scope | null;
508
+ private sendThroughBeforeSend;
509
+ private releaseTags;
510
+ }
511
+ declare const AllStak: {
512
+ init(config: AllStakConfig): AllStakClient;
513
+ captureException(error: Error, context?: Record<string, unknown>): void;
514
+ captureMessage(message: string, level?: "fatal" | "error" | "warning" | "info", options?: {
515
+ as?: "log" | "error" | "both";
516
+ }): void;
517
+ addBreadcrumb(type: string, message: string, level?: string, data?: Record<string, unknown>): void;
518
+ clearBreadcrumbs(): void;
519
+ setUser(user: {
520
+ id?: string;
521
+ email?: string;
522
+ }): void;
523
+ setTag(key: string, value: string): void;
524
+ setTags(tags: Record<string, string>): void;
525
+ setExtra(key: string, value: unknown): void;
526
+ setExtras(extras: Record<string, unknown>): void;
527
+ setContext(name: string, ctx: Record<string, unknown> | null): void;
528
+ setLevel(level: "fatal" | "error" | "warning" | "info" | "debug"): void;
529
+ setFingerprint(fingerprint: string[] | null): void;
530
+ flush(timeoutMs?: number): Promise<boolean>;
531
+ setIdentity(identity: {
532
+ sdkName?: string;
533
+ sdkVersion?: string;
534
+ platform?: string;
535
+ dist?: string;
536
+ }): void;
537
+ /**
538
+ * Run `callback` with a fresh scoped context. Any user/tag/extra/context/
539
+ * fingerprint/level set on the passed `Scope` is visible only inside the
540
+ * callback (and any captures made within it). Pop is automatic, including
541
+ * for async callbacks and thrown errors.
542
+ */
543
+ withScope<T>(callback: (scope: Scope) => T): T;
544
+ startSpan(operation: string, options?: {
545
+ description?: string;
546
+ tags?: Record<string, string>;
547
+ }): Span;
548
+ getTraceId(): string;
549
+ setTraceId(traceId: string): void;
550
+ getCurrentSpanId(): string | null;
551
+ resetTrace(): void;
552
+ /** Access the privacy-first replay surrogate (or null if disabled / sampled out). */
553
+ getReplay(): ReplaySurrogate | null;
554
+ /** Manually instrument an axios instance. No-op when HTTP tracking is off. */
555
+ instrumentAxios<T = any>(axios: T): T;
556
+ getSessionId(): string;
557
+ getConfig(): AllStakConfig | null;
558
+ destroy(): void;
559
+ /** @internal — exposed for testing */
560
+ _getInstance(): AllStakClient | null;
561
+ };
562
+
563
+ /**
564
+ * React Native navigation breadcrumbs — two opt-in helpers:
565
+ *
566
+ * - instrumentReactNavigation(navigationRef): call once after the
567
+ * NavigationContainer is mounted. Subscribes to `state` events on the
568
+ * NavigationContainerRef and emits a breadcrumb whenever the active
569
+ * route name changes. Works with @react-navigation/native v6+ without
570
+ * adding it as a dependency (the ref shape is duck-typed).
571
+ *
572
+ * - instrumentNavigationFromLinking(): registers a Linking event
573
+ * listener so deep links also appear in breadcrumbs. Useful when the
574
+ * app uses Linking.openURL(...) instead of (or alongside) a router.
575
+ *
576
+ * Both helpers are idempotent and never throw if the underlying RN module
577
+ * isn't present (Expo Go, JS-only test runs).
578
+ */
579
+ type NavigationRef = {
580
+ getCurrentRoute?: () => {
581
+ name?: string;
582
+ } | undefined;
583
+ addListener?: (event: string, cb: () => void) => () => void;
584
+ };
585
+ interface ReactNavigationOptions {
586
+ /**
587
+ * Whitelist of route-param keys safe to record alongside the route name.
588
+ * Anything outside this list is dropped — params commonly carry user IDs,
589
+ * order numbers, etc. Default `[]`.
590
+ */
591
+ safeParams?: string[];
592
+ /**
593
+ * Also forward the screen view to the replay surrogate (if active).
594
+ * Default true — the surrogate itself decides whether it's recording.
595
+ */
596
+ forwardToReplay?: boolean;
597
+ }
598
+ /**
599
+ * Subscribe to a `@react-navigation/native` NavigationContainerRef and
600
+ * emit a navigation breadcrumb whenever the active route changes. Captures:
601
+ *
602
+ * - route name change (from -> to)
603
+ * - whitelisted route params (via `safeParams`)
604
+ * - state change → forwarded to replay surrogate when enabled
605
+ *
606
+ * Idempotent — installs once per ref. Returns an unsubscribe function.
607
+ */
608
+ declare function instrumentReactNavigation(navigationRef: NavigationRef, options?: ReactNavigationOptions): () => void;
609
+ /**
610
+ * Register a Linking listener so `openURL`/deep-link launches surface
611
+ * as breadcrumbs. No-op if `react-native` isn't available (test env).
612
+ */
613
+ declare function instrumentNavigationFromLinking(): void;
614
+
615
+ /**
616
+ * React Native architecture / runtime detection.
617
+ *
618
+ * **Status:** the JS-level check is implemented and tested. The native
619
+ * AllStak modules (Java + Obj-C) are written in legacy module style and
620
+ * are known to interoperate with the New Architecture (Fabric +
621
+ * TurboModules) via the RN interop layer. End-to-end integration on a
622
+ * real Fabric build has not yet been verified — see README §"New
623
+ * Architecture support" for current status.
624
+ *
625
+ * The two booleans returned here are read off well-known global flags
626
+ * that RN exposes to JS:
627
+ *
628
+ * - `globalThis.__turboModuleProxy` — present when TurboModules is
629
+ * enabled (New Architecture).
630
+ * - `globalThis.RN$Bridgeless` — present when bridgeless mode is on.
631
+ *
632
+ * If the host app surfaces this through `AllStak.setTag('rn.newArch', '1')`
633
+ * we can correlate New-Arch crashes specifically and prioritize a fix.
634
+ */
635
+ interface ArchitectureInfo {
636
+ /** True when TurboModules / New Architecture is detected at runtime. */
637
+ newArchitecture: boolean;
638
+ /** True when bridgeless mode is detected. */
639
+ bridgeless: boolean;
640
+ /** True when the JS engine is Hermes. */
641
+ hermes: boolean;
642
+ /** Free-form tag suitable for `AllStak.setTag('rn.architecture', ...)`. */
643
+ tag: 'new-arch' | 'old-arch' | 'unknown';
644
+ }
645
+ declare function detectArchitecture(): ArchitectureInfo;
646
+ /**
647
+ * Convenience: stamp `rn.architecture`, `rn.bridgeless`, and `rn.hermes`
648
+ * tags on the active AllStak singleton based on detection. Safe to call
649
+ * any time after `AllStak.init()` and before the first capture.
650
+ */
651
+ declare function applyArchitectureTags(setTag: (key: string, value: string) => void): ArchitectureInfo;
652
+
653
+ /**
654
+ * @allstak/react-native — standalone React Native SDK.
655
+ *
656
+ * Self-contained: depends only on `react-native` (peer) and the global
657
+ * `fetch`/`AbortController` that RN guarantees. Contains no `window`,
658
+ * `document`, `localStorage`, `sessionStorage`, or browser DOM event
659
+ * listeners.
660
+ *
661
+ * Usage:
662
+ *
663
+ * AllStak.init({ apiKey, environment, release });
664
+ * installReactNative();
665
+ *
666
+ * Native crash capture (Java/Kotlin on Android, Obj-C/Swift on iOS) lives
667
+ * under the `native/` directory in this package. See README.
668
+ */
669
+
670
+ interface ReactNativeInstallOptions {
671
+ /** Auto-capture unhandled JS exceptions via ErrorUtils. Default: true */
672
+ autoErrorHandler?: boolean;
673
+ /** Auto-capture unhandled promise rejections (Hermes). Default: true */
674
+ autoPromiseRejections?: boolean;
675
+ /** Auto-attach Platform.* info as tags. Default: true */
676
+ autoDeviceTags?: boolean;
677
+ /** Auto-emit breadcrumbs on AppState change. Default: true */
678
+ autoAppStateBreadcrumbs?: boolean;
679
+ /** Auto-instrument XHR (RN's fetch is XHR-based) for network breadcrumbs. Default: true */
680
+ autoNetworkCapture?: boolean;
681
+ /** Wrap `globalThis.fetch` to record HTTP breadcrumbs. Default: true */
682
+ autoFetchBreadcrumbs?: boolean;
683
+ /** Wrap `console.warn`/`console.error` to record log breadcrumbs. Default: true */
684
+ autoConsoleBreadcrumbs?: boolean;
685
+ }
686
+ declare function __setNativeModuleForTest(mod: any): void;
687
+ /**
688
+ * Drain any native crash stashed by AllStakCrashHandler on the previous
689
+ * launch and ship it to /ingest/v1/errors. No-op when the native module
690
+ * is not linked (Expo Go, JS-only test runners, etc).
691
+ */
692
+ declare function drainPendingNativeCrashes(release?: string): Promise<void>;
693
+ declare function installReactNative(options?: ReactNativeInstallOptions): void;
694
+
695
+ export { AllStak, AllStakClient, type AllStakConfig, type ArchitectureInfo, type Breadcrumb, type HttpRequestEvent, HttpRequestModule, type HttpTrackingOptions, INGEST_HOST, type ReactNativeInstallOptions, ReplaySurrogate, type ReplaySurrogateOptions, SDK_NAME, SDK_VERSION, Scope, __setNativeModuleForTest, applyArchitectureTags, detectArchitecture, drainPendingNativeCrashes, installReactNative, instrumentNavigationFromLinking, instrumentReactNavigation };