@allstak/react-native 0.3.4 → 0.4.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.ts CHANGED
@@ -33,6 +33,18 @@ declare class HttpTransport {
33
33
  private lastFlushDurationMs;
34
34
  constructor(baseUrl: string, apiKey: string, enabled?: boolean);
35
35
  send(path: string, payload: unknown): Promise<void>;
36
+ /**
37
+ * One-shot POST that resolves with the parsed JSON response body. Used
38
+ * by `captureException` to retrieve the server-assigned event id so
39
+ * follow-up attachment uploads can be linked.
40
+ *
41
+ * Fail-open: returns `null` on any error (network, non-2xx, parse).
42
+ * Respects {@link timeoutMs} via `AbortController`. Bounded retries.
43
+ */
44
+ sendAndRead<T = any>(path: string, payload: unknown, options?: {
45
+ timeoutMs?: number;
46
+ retries?: number;
47
+ }): Promise<T | null>;
36
48
  private enqueueOrDispatch;
37
49
  private dispatch;
38
50
  private doFetch;
@@ -438,9 +450,117 @@ interface ConsoleCaptureOptions {
438
450
  /** @internal — for tests. Resets the wrap-once flag. */
439
451
  declare function __resetConsoleInstrumentationFlagForTest(): void;
440
452
 
453
+ /**
454
+ * Runtime detection for React Native screenshot capture.
455
+ *
456
+ * Determines whether native screenshot APIs (specifically
457
+ * `react-native-view-shot`) are usable in the current host:
458
+ * - 'expo-go' — Expo Go sandbox; native modules cannot be added
459
+ * at runtime → screenshots silently skipped.
460
+ * - 'expo-dev-client'— Expo dev/prod build that bundles native deps.
461
+ * - 'rn-cli' — bare react-native (CLI) build.
462
+ * - 'unknown' — anything we couldn't classify; treat as allowed
463
+ * but log a __DEV__ warning.
464
+ */
465
+ type RuntimeMode = 'expo-go' | 'expo-dev-client' | 'rn-cli' | 'unknown';
466
+ /**
467
+ * Best-effort detection of the host runtime. Cached after first call.
468
+ */
469
+ declare function detectRuntimeMode(): RuntimeMode;
470
+ /** @internal — reset for tests */
471
+ declare function __resetRuntimeModeForTest(): void;
472
+ /** Whether a runtime allows attempting a native screenshot via view-shot. */
473
+ declare function runtimeAllowsScreenshot(mode?: RuntimeMode): boolean;
474
+
475
+ /**
476
+ * Flat screenshot API for `@allstak/react-native`.
477
+ *
478
+ * Mirrors the props the wizard emits (`captureScreenshotOnError`,
479
+ * `screenshotRedaction`, etc.) and orchestrates native capture via the
480
+ * optional `react-native-view-shot` peer dep.
481
+ *
482
+ * Fail-open contract: the event MUST always send even when capture is
483
+ * unavailable, throws, times out, or the upload fails. The capture
484
+ * subsystem is allowed to log in __DEV__ but must never reject into the
485
+ * host app's promise chain.
486
+ */
487
+
488
+ type ScreenshotRedactionMode = 'strict' | 'balanced' | 'custom';
489
+ type ScreenshotMaskStyle = 'solid' | 'blur';
490
+ type ScreenshotFormat = 'png' | 'jpg' | 'webp';
491
+ type ScreenshotNativeMode = 'auto' | 'view-shot' | 'disabled';
492
+ type ScreenshotFailPolicy = 'disable-screenshot' | 'send-event-only';
493
+ interface ScreenshotConfig {
494
+ captureScreenshotOnError: boolean;
495
+ screenshotRedaction: ScreenshotRedactionMode;
496
+ screenshotMaskStyle: ScreenshotMaskStyle;
497
+ screenshotMaxBytes: number;
498
+ screenshotQuality: number;
499
+ screenshotFormat: ScreenshotFormat;
500
+ screenshotSampleRate: number;
501
+ screenshotOnUnhandledOnly: boolean;
502
+ screenshotUploadTimeoutMs: number;
503
+ screenshotCaptureTimeoutMs: number;
504
+ screenshotNativeMode: ScreenshotNativeMode;
505
+ screenshotFailPolicy: ScreenshotFailPolicy;
506
+ beforeScreenshotCapture?: (ctx: ScreenshotContext) => boolean | Promise<boolean>;
507
+ beforeScreenshotUpload?: ((payload: ScreenshotUpload, meta: ScreenshotMetadata) => ScreenshotUpload | null | Promise<ScreenshotUpload | null>);
508
+ isScreenshotAllowed?: (ctx: ScreenshotContext) => boolean | Promise<boolean>;
509
+ }
510
+ interface ScreenshotContext {
511
+ error?: Error;
512
+ unhandled?: boolean;
513
+ runtimeMode: RuntimeMode;
514
+ }
515
+ interface ScreenshotUpload {
516
+ /** Base64-encoded image bytes (no data: prefix). */
517
+ dataBase64: string;
518
+ contentType: string;
519
+ width: number;
520
+ height: number;
521
+ sizeBytes: number;
522
+ }
523
+ interface ScreenshotMetadata {
524
+ captureMethod: string;
525
+ redactionMode: ScreenshotRedactionMode;
526
+ maskStyle: ScreenshotMaskStyle;
527
+ format: ScreenshotFormat;
528
+ width: number;
529
+ height: number;
530
+ sizeBytes: number;
531
+ maskedElements?: number;
532
+ privacyComponentsDetected?: number;
533
+ runtimeMode: RuntimeMode;
534
+ }
535
+ declare const DEFAULT_SCREENSHOT_CONFIG: ScreenshotConfig;
536
+ /**
537
+ * Merge partial config from `init()` / provider props with sensible
538
+ * defaults. Any `undefined` field falls back to the default. Numeric
539
+ * fields are clamped to safe ranges.
540
+ */
541
+ declare function resolveScreenshotConfig(partial: Partial<ScreenshotConfig> | undefined): ScreenshotConfig;
542
+ declare function isViewShotAvailable(): boolean;
543
+ /**
544
+ * Attempt a native screenshot via react-native-view-shot. Returns
545
+ * `null` if anything goes wrong (timeout, missing dep, no root ref).
546
+ * Never throws. Toggles `__setCapturing(true)` for the duration of the
547
+ * capture so masking primitives swap to their placeholder render.
548
+ */
549
+ declare function captureViaViewShot(config: ScreenshotConfig): Promise<ScreenshotUpload | null>;
550
+ /**
551
+ * Top-level orchestrator. Returns an upload + metadata if a screenshot
552
+ * is captured, or `null` if anything (sampling, gates, capture, etc.)
553
+ * skipped it. Never throws.
554
+ */
555
+ declare function maybeCaptureScreenshot(config: ScreenshotConfig, ctx: ScreenshotContext): Promise<{
556
+ upload: ScreenshotUpload;
557
+ metadata: ScreenshotMetadata;
558
+ } | null>;
559
+ declare function pickScreenshotConfig(source: Record<string, unknown>): Partial<ScreenshotConfig>;
560
+
441
561
  declare const INGEST_HOST = "https://api.allstak.sa";
442
562
  declare const SDK_NAME = "allstak-react-native";
443
- declare const SDK_VERSION = "0.3.4";
563
+ declare const SDK_VERSION = "0.4.0";
444
564
 
445
565
  interface AllStakConfig {
446
566
  /** Project API key (`ask_live_…`). Required. */
@@ -518,6 +638,22 @@ interface AllStakConfig {
518
638
  * hurt app navigation, JS thread responsiveness, or telemetry delivery.
519
639
  */
520
640
  screenshot?: ScreenshotCaptureOptions;
641
+ /** Enable on-error screenshot capture. Default: false. */
642
+ captureScreenshotOnError?: boolean;
643
+ screenshotRedaction?: ScreenshotRedactionMode;
644
+ screenshotMaskStyle?: ScreenshotMaskStyle;
645
+ screenshotMaxBytes?: number;
646
+ screenshotQuality?: number;
647
+ screenshotFormat?: ScreenshotFormat;
648
+ screenshotSampleRate?: number;
649
+ screenshotOnUnhandledOnly?: boolean;
650
+ screenshotUploadTimeoutMs?: number;
651
+ screenshotCaptureTimeoutMs?: number;
652
+ screenshotNativeMode?: ScreenshotNativeMode;
653
+ screenshotFailPolicy?: ScreenshotFailPolicy;
654
+ beforeScreenshotCapture?: ScreenshotConfig['beforeScreenshotCapture'];
655
+ beforeScreenshotUpload?: ScreenshotConfig['beforeScreenshotUpload'];
656
+ isScreenshotAllowed?: ScreenshotConfig['isScreenshotAllowed'];
521
657
  /** SDK identity overrides (set automatically by installReactNative). */
522
658
  sdkName?: string;
523
659
  sdkVersion?: string;
@@ -617,6 +753,14 @@ declare class AllStakClient {
617
753
  /** Snapshot of recent failed HTTP requests for error-linking. */
618
754
  getRecentFailedHttp(): readonly HttpRequestIngestItem[];
619
755
  captureException(error: Error, context?: Record<string, unknown>): void;
756
+ /**
757
+ * Flat screenshot API path. Capture first (so masking primitives can
758
+ * swap), send the event with a `screenshot.status` metadata tag, read
759
+ * back the server-assigned errorId, then upload the attachment.
760
+ *
761
+ * Fail-open at every step.
762
+ */
763
+ private runFlatScreenshotPipeline;
620
764
  /** Start a new span. Auto-parented to any currently-active span. */
621
765
  startSpan(operation: string, options?: {
622
766
  description?: string;
@@ -842,8 +986,23 @@ interface AllStakProviderProps extends ReactNativeInstallOptions {
842
986
  resetError: () => void;
843
987
  }) => React.ReactNode);
844
988
  onError?: (error: Error, componentStack?: string) => void;
989
+ captureScreenshotOnError?: boolean;
990
+ screenshotRedaction?: ScreenshotRedactionMode;
991
+ screenshotMaskStyle?: ScreenshotMaskStyle;
992
+ screenshotMaxBytes?: number;
993
+ screenshotQuality?: number;
994
+ screenshotFormat?: ScreenshotFormat;
995
+ screenshotSampleRate?: number;
996
+ screenshotOnUnhandledOnly?: boolean;
997
+ screenshotUploadTimeoutMs?: number;
998
+ screenshotCaptureTimeoutMs?: number;
999
+ screenshotNativeMode?: ScreenshotNativeMode;
1000
+ screenshotFailPolicy?: ScreenshotFailPolicy;
1001
+ beforeScreenshotCapture?: AllStakConfig['beforeScreenshotCapture'];
1002
+ beforeScreenshotUpload?: AllStakConfig['beforeScreenshotUpload'];
1003
+ isScreenshotAllowed?: AllStakConfig['isScreenshotAllowed'];
845
1004
  }
846
- declare function AllStakProvider({ children, apiKey, environment, release, host, user, tags, debug, enableHttpTracking, httpTracking, captureConsole, sampleRate, beforeSend, replay, tracesSampleRate, service, dist, destroyOnUnmount, fallback, onError, autoErrorHandler, autoPromiseRejections, autoDeviceTags, autoAppStateBreadcrumbs, autoNetworkCapture, autoFetchBreadcrumbs, autoConsoleBreadcrumbs, autoNavigationBreadcrumbs, }: AllStakProviderProps): React.ReactElement;
1005
+ declare function AllStakProvider({ children, apiKey, environment, release, host, user, tags, debug, enableHttpTracking, httpTracking, captureConsole, sampleRate, beforeSend, replay, tracesSampleRate, service, dist, destroyOnUnmount, fallback, onError, autoErrorHandler, autoPromiseRejections, autoDeviceTags, autoAppStateBreadcrumbs, autoNetworkCapture, autoFetchBreadcrumbs, autoConsoleBreadcrumbs, autoNavigationBreadcrumbs, captureScreenshotOnError, screenshotRedaction, screenshotMaskStyle, screenshotMaxBytes, screenshotQuality, screenshotFormat, screenshotSampleRate, screenshotOnUnhandledOnly, screenshotUploadTimeoutMs, screenshotCaptureTimeoutMs, screenshotNativeMode, screenshotFailPolicy, beforeScreenshotCapture, beforeScreenshotUpload, isScreenshotAllowed, }: AllStakProviderProps): React.ReactElement;
847
1006
  declare function useAllStak(): {
848
1007
  captureException: (error: Error, ctx?: Record<string, unknown>) => void;
849
1008
  captureMessage: (msg: string, level?: "fatal" | "error" | "warning" | "info") => void;
@@ -857,6 +1016,81 @@ declare function useAllStak(): {
857
1016
  /** @internal — for tests. Resets the module-level remount-guard. */
858
1017
  declare function __resetProviderInstanceForTest(): void;
859
1018
 
1019
+ /**
1020
+ * Privacy / masking primitives for AllStak React Native screenshots.
1021
+ *
1022
+ * Three concerns:
1023
+ * 1. A registry of refs / views the capture path should mask when it
1024
+ * takes a snapshot.
1025
+ * 2. An "isCapturing" flag that masking components subscribe to so they
1026
+ * can swap their children for a redacted placeholder during a capture.
1027
+ * 3. Light wrappers (`AllStakMaskedView`, `AllStakPrivacyView`,
1028
+ * `AllStakTextInput`, `AllStakSensitiveText`) that opt-in to the
1029
+ * isCapturing swap.
1030
+ *
1031
+ * All wrappers are no-ops when react-native is not installed (e.g. JS
1032
+ * test environment) — they just render their children.
1033
+ */
1034
+
1035
+ type PrivacyLevel = 'mask' | 'hide' | 'show';
1036
+ /** @internal — for tests. */
1037
+ declare function __resetPrivacyStateForTest(): void;
1038
+ /** Whether a capture is currently in progress. */
1039
+ declare function isCapturingScreenshot(): boolean;
1040
+ /** Register a sensitive ref. Returns an unregister function. */
1041
+ declare function registerSensitiveRef(ref: unknown): () => void;
1042
+ /**
1043
+ * Hook returning the privacy state — host apps can build their own
1044
+ * masking UI on top of this.
1045
+ */
1046
+ declare function useAllStakPrivacy(): {
1047
+ isCapturing: boolean;
1048
+ registerSensitiveRef: typeof registerSensitiveRef;
1049
+ };
1050
+ interface AllStakMaskedViewProps {
1051
+ children?: React.ReactNode;
1052
+ maskLabel?: string;
1053
+ maskColor?: string;
1054
+ hideScreenshot?: boolean;
1055
+ privacy?: PrivacyLevel;
1056
+ style?: any;
1057
+ [key: string]: unknown;
1058
+ }
1059
+ /**
1060
+ * Masks its children during a screenshot capture. While the SDK is
1061
+ * capturing, this component renders a solid placeholder instead of its
1062
+ * children; the rest of the time it's a transparent passthrough.
1063
+ */
1064
+ declare function AllStakMaskedView({ children, maskLabel, maskColor, hideScreenshot, privacy, style, ...rest }: AllStakMaskedViewProps): React.ReactElement;
1065
+ /**
1066
+ * Stricter variant — defaults to hiding the contents from screenshots
1067
+ * entirely. Use for credit-card fields, IBANs, passwords, etc.
1068
+ */
1069
+ declare function AllStakPrivacyView(props: AllStakMaskedViewProps): React.ReactElement;
1070
+ interface AllStakTextInputProps {
1071
+ privacy?: PrivacyLevel;
1072
+ style?: any;
1073
+ maskColor?: string;
1074
+ [key: string]: unknown;
1075
+ }
1076
+ /**
1077
+ * `TextInput` wrapper that swaps to a solid masked box during capture.
1078
+ * Always treated as sensitive unless `privacy="show"`.
1079
+ */
1080
+ declare function AllStakTextInput({ privacy, style, maskColor, ...rest }: AllStakTextInputProps): React.ReactElement;
1081
+ interface AllStakSensitiveTextProps {
1082
+ children?: React.ReactNode;
1083
+ privacy?: PrivacyLevel;
1084
+ style?: any;
1085
+ maskLabel?: string;
1086
+ [key: string]: unknown;
1087
+ }
1088
+ /**
1089
+ * Wraps a Text element so it renders the mask label during capture
1090
+ * instead of its actual children. Default privacy is `'mask'`.
1091
+ */
1092
+ declare function AllStakSensitiveText({ children, privacy, style, maskLabel, ...rest }: AllStakSensitiveTextProps): React.ReactElement;
1093
+
860
1094
  /**
861
1095
  * React Native navigation breadcrumbs — two opt-in helpers:
862
1096
  *
@@ -1029,4 +1263,4 @@ declare function __devTriggerNativeCrash(): Promise<void>;
1029
1263
  */
1030
1264
  declare function drainPendingNativeCrashes(release?: string): Promise<void>;
1031
1265
 
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 };
1266
+ export { ALWAYS_REDACT_HEADERS, ALWAYS_REDACT_QUERY, AllStak, AllStakClient, type AllStakConfig, AllStakMaskedView, type AllStakMaskedViewProps, AllStakPrivacyView, AllStakProvider, type AllStakProviderProps, AllStakSensitiveText, type AllStakSensitiveTextProps, AllStakTextInput, type AllStakTextInputProps, type ArchitectureInfo, type Breadcrumb, type ConsoleCaptureOptions, DEFAULT_REDACT_BODY_FIELDS, DEFAULT_SCREENSHOT_CONFIG, type HttpRequestEvent, HttpRequestModule, type HttpTrackingOptions, INGEST_HOST, type PrivacyLevel, REDACTED, type ReactNativeInstallOptions, ReplaySurrogate, type ReplaySurrogateOptions, type RuntimeMode, SDK_NAME, SDK_VERSION, Scope, type ScreenshotArtifact, type ScreenshotCaptureOptions, type ScreenshotConfig, type ScreenshotContext, type ScreenshotFailPolicy, type ScreenshotFormat, type ScreenshotMaskStyle, type ScreenshotMetadata, type ScreenshotNativeMode, type ScreenshotRedactionMode, type ScreenshotUpload, type TransportStats, __devTriggerNativeCrash, __resetAutoNavigationFlagForTest, __resetConsoleInstrumentationFlagForTest, __resetPrivacyStateForTest, __resetProviderInstanceForTest, __resetRuntimeModeForTest, __setNativeModuleForTest, applyArchitectureTags, captureBodyResult, captureViaViewShot, detectArchitecture, detectRuntimeMode, drainPendingNativeCrashes, installReactNative, instrumentNavigationFromLinking, instrumentReactNavigation, isCapturingScreenshot, isViewShotAvailable, maybeCaptureScreenshot, pickScreenshotConfig, redactUrl, registerSensitiveRef, resolveScreenshotConfig, runtimeAllowsScreenshot, sanitizeHeaders, tryAutoInstrumentNavigation, useAllStak, useAllStakPrivacy };