@allstak/react-native 0.3.1 → 0.3.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/dist/index.d.ts CHANGED
@@ -1,22 +1,48 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  /**
4
- * Minimal HTTP transport for React Native. Uses the global `fetch` (always
5
- * present in RN >= 0.60) with a 3s timeout. Failed sends fall into a small
6
- * in-memory ring buffer that we retry on the next successful flush.
4
+ * Fail-open HTTP transport for React Native. Telemetry sends are best-effort:
5
+ * they use a short timeout, never reject into the host app, and fall into a
6
+ * bounded in-memory ring buffer with circuit-breaker backoff when AllStak is
7
+ * unavailable.
7
8
  *
8
9
  * No window, no AbortController fallback shims — RN exposes both natively.
9
10
  */
11
+ interface TransportStats {
12
+ queued: number;
13
+ sent: number;
14
+ failed: number;
15
+ dropped: number;
16
+ consecutiveFailures: number;
17
+ circuitOpenUntil: number;
18
+ lastTransportLatencyMs?: number;
19
+ lastFlushDurationMs?: number;
20
+ }
10
21
  declare class HttpTransport {
11
22
  private baseUrl;
12
23
  private apiKey;
24
+ private enabled;
13
25
  private buffer;
14
26
  private flushing;
15
- constructor(baseUrl: string, apiKey: string);
27
+ private consecutiveFailures;
28
+ private circuitOpenUntil;
29
+ private sent;
30
+ private failed;
31
+ private dropped;
32
+ private lastTransportLatencyMs;
33
+ private lastFlushDurationMs;
34
+ constructor(baseUrl: string, apiKey: string, enabled?: boolean);
16
35
  send(path: string, payload: unknown): Promise<void>;
36
+ private enqueueOrDispatch;
37
+ private dispatch;
17
38
  private doFetch;
39
+ private push;
40
+ private scheduleFlush;
18
41
  private flushBuffer;
42
+ private recordFailure;
19
43
  getBufferSize(): number;
44
+ noteDropped(count?: number): void;
45
+ getStats(): TransportStats;
20
46
  /**
21
47
  * Wait for the in-flight retry-buffer to drain. Resolves `true` if the
22
48
  * buffer empties within `timeoutMs` (default 2000ms), `false` otherwise.
@@ -44,6 +70,10 @@ declare class HttpTransport {
44
70
  /** What instrumentation hands to the module per request. */
45
71
  interface HttpRequestEvent {
46
72
  type: 'http_request';
73
+ traceId: string;
74
+ requestId: string;
75
+ spanId?: string;
76
+ parentSpanId?: string;
47
77
  method: string;
48
78
  url: string;
49
79
  statusCode?: number;
@@ -55,11 +85,19 @@ interface HttpRequestEvent {
55
85
  requestHeaders?: Record<string, string>;
56
86
  responseHeaders?: Record<string, string>;
57
87
  error?: string;
58
- traceId?: string;
88
+ requestBodyStatus?: string;
89
+ responseBodyStatus?: string;
90
+ requestBodyRedactedFields?: string[];
91
+ responseBodyRedactedFields?: string[];
92
+ requestBodyTruncated?: boolean;
93
+ responseBodyTruncated?: boolean;
94
+ capturePolicy?: string;
95
+ linkConfidence?: 'exact' | 'inferred' | 'weak' | 'none';
59
96
  }
60
97
  interface HttpRequestIngestItem {
61
98
  type: 'http_request';
62
99
  traceId: string;
100
+ requestId: string;
63
101
  direction: 'outbound';
64
102
  method: string;
65
103
  host: string;
@@ -74,6 +112,16 @@ interface HttpRequestIngestItem {
74
112
  requestHeaders?: Record<string, string>;
75
113
  responseHeaders?: Record<string, string>;
76
114
  error?: string;
115
+ spanId?: string;
116
+ parentSpanId?: string;
117
+ requestBodyStatus?: string;
118
+ responseBodyStatus?: string;
119
+ requestBodyRedactedFields?: string[];
120
+ responseBodyRedactedFields?: string[];
121
+ requestBodyTruncated?: boolean;
122
+ responseBodyTruncated?: boolean;
123
+ capturePolicy?: string;
124
+ linkConfidence?: 'exact' | 'inferred' | 'weak' | 'none';
77
125
  environment?: string;
78
126
  release?: string;
79
127
  dist?: string;
@@ -241,9 +289,19 @@ interface ReplaySurrogateOptions {
241
289
  }
242
290
  interface SurrogateEvent {
243
291
  ts: number;
244
- k: 'screen' | 'appstate' | 'manual';
292
+ k: 'screen' | 'appstate' | 'manual' | 'request' | 'exception' | 'response' | 'action' | 'retry';
245
293
  data: Record<string, unknown>;
246
294
  }
295
+ interface TimelineContext {
296
+ traceId?: string;
297
+ requestId?: string;
298
+ spanId?: string;
299
+ eventId?: string;
300
+ release?: string;
301
+ dist?: string;
302
+ screen?: string;
303
+ route?: string;
304
+ }
247
305
  declare class ReplaySurrogate {
248
306
  private transport;
249
307
  private buffer;
@@ -256,11 +314,13 @@ declare class ReplaySurrogate {
256
314
  /** Enable recording for this session if sample-rate roll passes. */
257
315
  start(): boolean;
258
316
  /** Record a screen view. Filters params through the safeParams allow-list. */
259
- recordScreenView(routeName: string, params?: Record<string, unknown>): void;
317
+ recordScreenView(routeName: string, params?: Record<string, unknown>, context?: TimelineContext): void;
260
318
  /** Record an AppState transition (foreground/background/inactive). */
261
- recordAppState(next: string): void;
319
+ recordAppState(next: string, context?: TimelineContext): void;
262
320
  /** Record a free-form, customer-validated checkpoint. */
263
- recordManual(label: string, data?: Record<string, unknown>): void;
321
+ recordManual(label: string, data?: Record<string, unknown>, context?: TimelineContext): void;
322
+ /** Record a forensic mobile session timeline marker. This is not replay. */
323
+ recordTimelineMarker(kind: SurrogateEvent['k'], label: string, data?: Record<string, unknown>, context?: TimelineContext): void;
264
324
  destroy(): void;
265
325
  /** @internal — for tests. */
266
326
  isActive(): boolean;
@@ -270,6 +330,28 @@ declare class ReplaySurrogate {
270
330
  private flush;
271
331
  }
272
332
 
333
+ /**
334
+ * URL + header + body redaction utilities for HTTP instrumentation.
335
+ *
336
+ * Hard rules:
337
+ * - Authorization, Cookie, X-API-Key, Set-Cookie are ALWAYS redacted
338
+ * (host app cannot opt back into capturing them).
339
+ * - Query params named `token`, `password`, `api_key`, `apikey`,
340
+ * `authorization`, `auth`, `secret`, `access_token`, `refresh_token`,
341
+ * `session` are ALWAYS redacted.
342
+ * - Host app may add additional names via `redactHeaders` /
343
+ * `redactQueryParams`; the always-list is the floor, not the ceiling.
344
+ * - Bodies are truncated to `maxBodyBytes` (default 4096) and replaced
345
+ * with `'<binary>'` when not safely-stringifiable.
346
+ *
347
+ * URL pattern matching for ignoredUrls / allowedUrls accepts strings
348
+ * (substring match) or RegExp (test-based). String matching is
349
+ * case-insensitive on the URL.
350
+ */
351
+ declare const ALWAYS_REDACT_HEADERS: Set<string>;
352
+ declare const ALWAYS_REDACT_QUERY: Set<string>;
353
+ declare const REDACTED = "[REDACTED]";
354
+ declare const DEFAULT_REDACT_BODY_FIELDS: string[];
273
355
  interface HttpTrackingOptions {
274
356
  /** Capture request body. Default false. Truncated to maxBodyBytes. */
275
357
  captureRequestBody?: boolean;
@@ -296,7 +378,38 @@ interface HttpTrackingOptions {
296
378
  allowedUrls?: (string | RegExp)[];
297
379
  /** Max bytes per captured body. Default 4096. */
298
380
  maxBodyBytes?: number;
381
+ /** Content types eligible for body capture. Default JSON + text payloads. */
382
+ allowedContentTypes?: string[];
383
+ /** Additional JSON body fields to redact recursively. */
384
+ redactBodyFields?: string[];
299
385
  }
386
+ interface CapturedBody {
387
+ body?: string;
388
+ status: 'disabled' | 'captured' | 'redacted' | 'truncated' | 'unsupported' | 'empty';
389
+ redactedFields: string[];
390
+ truncated: boolean;
391
+ capturePolicy: string;
392
+ }
393
+ /**
394
+ * Redact sensitive query-string params in a URL. Returns the sanitized
395
+ * URL string. Falls back to the input when URL parsing fails (relative
396
+ * URLs in test environments).
397
+ */
398
+ declare function redactUrl(url: string, opts: HttpTrackingOptions): string;
399
+ /**
400
+ * Filter + redact an HTTP header dictionary. Returns a NEW object — does
401
+ * not mutate the input. When `captureHeaders` is false returns undefined
402
+ * (no headers in the wire payload at all).
403
+ */
404
+ declare function sanitizeHeaders(headers: Record<string, string | string[] | undefined> | undefined, opts: HttpTrackingOptions): Record<string, string> | undefined;
405
+ /**
406
+ * Truncate + safely-stringify a body. Returns:
407
+ * - undefined when capture is disabled
408
+ * - the stringified body when it's a string / number / plain object
409
+ * - '<binary>' when it's a Blob / FormData / ArrayBuffer / etc
410
+ * - truncated string with `…[truncated]` suffix when over maxBodyBytes
411
+ */
412
+ declare function captureBodyResult(body: unknown, enabled: boolean, maxBodyBytes: number, opts?: HttpTrackingOptions, contentType?: string): CapturedBody;
300
413
 
301
414
  /**
302
415
  * Per-console-method capture flags. Defaults are set to keep the
@@ -398,6 +511,13 @@ interface AllStakConfig {
398
511
  * — the event is sent as-is so a buggy hook can't black-hole telemetry.
399
512
  */
400
513
  beforeSend?: (event: ErrorIngestPayload) => ErrorIngestPayload | null | undefined | Promise<ErrorIngestPayload | null | undefined>;
514
+ /**
515
+ * Optional fail-open screenshot capture. Off by default and provider-based
516
+ * so Expo/RN apps choose their own native or JS screenshot implementation.
517
+ * The SDK bounds timeout/size/sampling and drops screenshots before it can
518
+ * hurt app navigation, JS thread responsiveness, or telemetry delivery.
519
+ */
520
+ screenshot?: ScreenshotCaptureOptions;
401
521
  /** SDK identity overrides (set automatically by installReactNative). */
402
522
  sdkName?: string;
403
523
  sdkVersion?: string;
@@ -406,6 +526,28 @@ interface AllStakConfig {
406
526
  commitSha?: string;
407
527
  branch?: string;
408
528
  }
529
+ interface ScreenshotArtifact {
530
+ data?: string;
531
+ contentType?: 'image/png' | 'image/jpeg' | 'image/webp';
532
+ width?: number;
533
+ height?: number;
534
+ sizeBytes?: number;
535
+ redacted?: boolean;
536
+ redactionStrategy?: string;
537
+ }
538
+ interface ScreenshotCaptureOptions {
539
+ enabled?: boolean;
540
+ captureOnError?: boolean;
541
+ timeoutMs?: number;
542
+ maxBytes?: number;
543
+ sampleRate?: number;
544
+ provider?: (reason: {
545
+ type: 'error';
546
+ error: Error;
547
+ traceId?: string;
548
+ requestId?: string;
549
+ }) => ScreenshotArtifact | null | undefined | Promise<ScreenshotArtifact | null | undefined>;
550
+ }
409
551
  interface Breadcrumb {
410
552
  timestamp: string;
411
553
  type: string;
@@ -421,6 +563,7 @@ interface PayloadFrame {
421
563
  colno?: number;
422
564
  inApp?: boolean;
423
565
  platform?: string;
566
+ debugId?: string;
424
567
  }
425
568
  interface ErrorIngestPayload {
426
569
  exceptionClass: string;
@@ -435,6 +578,12 @@ interface ErrorIngestPayload {
435
578
  environment?: string;
436
579
  release?: string;
437
580
  sessionId?: string;
581
+ traceId?: string;
582
+ spanId?: string;
583
+ parentSpanId?: string;
584
+ requestId?: string;
585
+ replayId?: string;
586
+ service?: string;
438
587
  user?: {
439
588
  id?: string;
440
589
  email?: string;
@@ -442,6 +591,12 @@ interface ErrorIngestPayload {
442
591
  metadata?: Record<string, unknown>;
443
592
  breadcrumbs?: Breadcrumb[];
444
593
  fingerprint?: string[];
594
+ debugMeta?: {
595
+ images: Array<{
596
+ type: string;
597
+ debugId: string;
598
+ }>;
599
+ };
445
600
  }
446
601
  declare class AllStakClient {
447
602
  private transport;
@@ -517,8 +672,11 @@ declare class AllStakClient {
517
672
  }): void;
518
673
  getSessionId(): string;
519
674
  getConfig(): AllStakConfig;
675
+ getTransportStats(): TransportStats;
520
676
  destroy(): void;
521
677
  private sendLog;
678
+ private shouldCaptureScreenshot;
679
+ private withScreenshotMetadata;
522
680
  private passesSampleRate;
523
681
  /**
524
682
  * Returns the effective config layer = base config + every scope on the
@@ -590,6 +748,7 @@ declare const AllStak: {
590
748
  instrumentAxios<T = any>(axios: T): T;
591
749
  getSessionId(): string;
592
750
  getConfig(): AllStakConfig | null;
751
+ getTransportStats(): TransportStats;
593
752
  destroy(): void;
594
753
  /** @internal — exposed for testing */
595
754
  _getInstance(): AllStakClient | null;
@@ -870,4 +1029,4 @@ declare function __devTriggerNativeCrash(): Promise<void>;
870
1029
  */
871
1030
  declare function drainPendingNativeCrashes(release?: string): Promise<void>;
872
1031
 
873
- export { AllStak, AllStakClient, type AllStakConfig, AllStakProvider, type AllStakProviderProps, type ArchitectureInfo, type Breadcrumb, type ConsoleCaptureOptions, type HttpRequestEvent, HttpRequestModule, type HttpTrackingOptions, INGEST_HOST, type ReactNativeInstallOptions, ReplaySurrogate, type ReplaySurrogateOptions, SDK_NAME, SDK_VERSION, Scope, __devTriggerNativeCrash, __resetAutoNavigationFlagForTest, __resetConsoleInstrumentationFlagForTest, __resetProviderInstanceForTest, __setNativeModuleForTest, applyArchitectureTags, detectArchitecture, drainPendingNativeCrashes, installReactNative, instrumentNavigationFromLinking, instrumentReactNavigation, tryAutoInstrumentNavigation, useAllStak };
1032
+ export { ALWAYS_REDACT_HEADERS, ALWAYS_REDACT_QUERY, AllStak, AllStakClient, type AllStakConfig, AllStakProvider, type AllStakProviderProps, type ArchitectureInfo, type Breadcrumb, type ConsoleCaptureOptions, DEFAULT_REDACT_BODY_FIELDS, type HttpRequestEvent, HttpRequestModule, type HttpTrackingOptions, INGEST_HOST, REDACTED, type ReactNativeInstallOptions, ReplaySurrogate, type ReplaySurrogateOptions, SDK_NAME, SDK_VERSION, Scope, type ScreenshotArtifact, type ScreenshotCaptureOptions, type TransportStats, __devTriggerNativeCrash, __resetAutoNavigationFlagForTest, __resetConsoleInstrumentationFlagForTest, __resetProviderInstanceForTest, __setNativeModuleForTest, applyArchitectureTags, captureBodyResult, detectArchitecture, drainPendingNativeCrashes, installReactNative, instrumentNavigationFromLinking, instrumentReactNavigation, redactUrl, sanitizeHeaders, tryAutoInstrumentNavigation, useAllStak };