@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.mjs CHANGED
@@ -29,6 +29,58 @@ var HttpTransport = class {
29
29
  this.enqueueOrDispatch({ path, payload });
30
30
  return Promise.resolve();
31
31
  }
32
+ /**
33
+ * One-shot POST that resolves with the parsed JSON response body. Used
34
+ * by `captureException` to retrieve the server-assigned event id so
35
+ * follow-up attachment uploads can be linked.
36
+ *
37
+ * Fail-open: returns `null` on any error (network, non-2xx, parse).
38
+ * Respects {@link timeoutMs} via `AbortController`. Bounded retries.
39
+ */
40
+ async sendAndRead(path, payload, options = {}) {
41
+ if (!this.enabled) return null;
42
+ const timeoutMs = options.timeoutMs ?? 5e3;
43
+ const retries = Math.max(0, options.retries ?? 1);
44
+ let attempt = 0;
45
+ let lastError = null;
46
+ while (attempt <= retries) {
47
+ try {
48
+ const url = `${this.baseUrl}${path}`;
49
+ const controller = new AbortController();
50
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
51
+ try {
52
+ const res = await fetch(url, {
53
+ method: "POST",
54
+ headers: {
55
+ "Content-Type": "application/json",
56
+ "X-AllStak-Key": this.apiKey
57
+ },
58
+ body: JSON.stringify(payload),
59
+ signal: controller.signal
60
+ });
61
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
62
+ const text = await res.text();
63
+ if (!text) return null;
64
+ try {
65
+ return JSON.parse(text);
66
+ } catch {
67
+ return null;
68
+ }
69
+ } finally {
70
+ clearTimeout(timeoutId);
71
+ }
72
+ } catch (err) {
73
+ lastError = err;
74
+ attempt += 1;
75
+ if (attempt > retries) break;
76
+ await new Promise((r) => setTimeout(r, 200 * attempt));
77
+ }
78
+ }
79
+ if (lastError && typeof __DEV__ !== "undefined" && __DEV__) {
80
+ console.warn("[AllStak] sendAndRead failed:", lastError?.message);
81
+ }
82
+ return null;
83
+ }
32
84
  enqueueOrDispatch(item) {
33
85
  if (Date.now() < this.circuitOpenUntil) {
34
86
  this.push(item);
@@ -1383,10 +1435,342 @@ function unbindHttpInstrumentation() {
1383
1435
  _currentRuntime = null;
1384
1436
  }
1385
1437
 
1438
+ // src/runtime.ts
1439
+ var cached = null;
1440
+ function detectRuntimeMode() {
1441
+ if (cached) return cached;
1442
+ cached = computeRuntimeMode();
1443
+ return cached;
1444
+ }
1445
+ function __resetRuntimeModeForTest() {
1446
+ cached = null;
1447
+ }
1448
+ function computeRuntimeMode() {
1449
+ try {
1450
+ const Constants = require("expo-constants");
1451
+ const appOwnership = Constants?.default?.appOwnership ?? Constants?.appOwnership;
1452
+ if (appOwnership === "expo") return "expo-go";
1453
+ if (appOwnership === "standalone" || appOwnership === "guest") return "expo-dev-client";
1454
+ const exec = Constants?.default?.executionEnvironment ?? Constants?.executionEnvironment;
1455
+ if (exec === "storeClient") return "expo-go";
1456
+ if (exec === "standalone" || exec === "bare") return "expo-dev-client";
1457
+ } catch {
1458
+ }
1459
+ try {
1460
+ require("expo");
1461
+ return "expo-dev-client";
1462
+ } catch {
1463
+ }
1464
+ try {
1465
+ require("react-native");
1466
+ return "rn-cli";
1467
+ } catch {
1468
+ }
1469
+ return "unknown";
1470
+ }
1471
+ function runtimeAllowsScreenshot(mode = detectRuntimeMode()) {
1472
+ if (mode === "expo-go") return false;
1473
+ return true;
1474
+ }
1475
+ function tryRequire(id2) {
1476
+ try {
1477
+ return require(id2);
1478
+ } catch {
1479
+ return null;
1480
+ }
1481
+ }
1482
+
1483
+ // src/privacy.tsx
1484
+ import * as React from "react";
1485
+ var RN = tryRequire("react-native");
1486
+ var state = {
1487
+ isCapturing: false,
1488
+ sensitiveRefs: /* @__PURE__ */ new Set()
1489
+ };
1490
+ var listeners = /* @__PURE__ */ new Set();
1491
+ function __setCapturing(value) {
1492
+ if (state.isCapturing === value) return;
1493
+ state.isCapturing = value;
1494
+ for (const fn of listeners) {
1495
+ try {
1496
+ fn(value);
1497
+ } catch {
1498
+ }
1499
+ }
1500
+ }
1501
+ function __resetPrivacyStateForTest() {
1502
+ state.isCapturing = false;
1503
+ state.sensitiveRefs.clear();
1504
+ listeners.clear();
1505
+ }
1506
+ function isCapturingScreenshot() {
1507
+ return state.isCapturing;
1508
+ }
1509
+ function sensitiveRefCount() {
1510
+ return state.sensitiveRefs.size;
1511
+ }
1512
+ function registerSensitiveRef(ref) {
1513
+ state.sensitiveRefs.add(ref);
1514
+ return () => {
1515
+ state.sensitiveRefs.delete(ref);
1516
+ };
1517
+ }
1518
+ function useIsCapturing() {
1519
+ const [val, setVal] = React.useState(state.isCapturing);
1520
+ React.useEffect(() => {
1521
+ const fn = (v) => setVal(v);
1522
+ listeners.add(fn);
1523
+ return () => {
1524
+ listeners.delete(fn);
1525
+ };
1526
+ }, []);
1527
+ return val;
1528
+ }
1529
+ function useAllStakPrivacy() {
1530
+ const isCapturing = useIsCapturing();
1531
+ return { isCapturing, registerSensitiveRef };
1532
+ }
1533
+ var View = RN?.View ?? ((props) => React.createElement("View", props));
1534
+ var Text = RN?.Text ?? ((props) => React.createElement("Text", props));
1535
+ var TextInput = RN?.TextInput ?? ((props) => React.createElement("TextInput", props));
1536
+ var DEFAULT_MASK_COLOR = "#d8dde7";
1537
+ var DEFAULT_MASK_LABEL = "\u2022\u2022\u2022\u2022\u2022\u2022";
1538
+ function AllStakMaskedView({
1539
+ children,
1540
+ maskLabel = DEFAULT_MASK_LABEL,
1541
+ maskColor = DEFAULT_MASK_COLOR,
1542
+ hideScreenshot = false,
1543
+ privacy = "mask",
1544
+ style,
1545
+ ...rest
1546
+ }) {
1547
+ const isCapturing = useIsCapturing();
1548
+ if (!isCapturing || privacy === "show") {
1549
+ return React.createElement(View, { style, ...rest }, children);
1550
+ }
1551
+ if (privacy === "hide" || hideScreenshot) {
1552
+ return React.createElement(View, { style: [{ backgroundColor: maskColor }, style], ...rest });
1553
+ }
1554
+ return React.createElement(
1555
+ View,
1556
+ { style: [{ backgroundColor: maskColor, alignItems: "center", justifyContent: "center" }, style], ...rest },
1557
+ React.createElement(Text, { style: { color: "#3f4652", fontSize: 12 } }, maskLabel)
1558
+ );
1559
+ }
1560
+ function AllStakPrivacyView(props) {
1561
+ return React.createElement(AllStakMaskedView, { hideScreenshot: true, ...props });
1562
+ }
1563
+ function AllStakTextInput({
1564
+ privacy = "mask",
1565
+ style,
1566
+ maskColor = DEFAULT_MASK_COLOR,
1567
+ ...rest
1568
+ }) {
1569
+ const isCapturing = useIsCapturing();
1570
+ if (isCapturing && privacy !== "show") {
1571
+ return React.createElement(View, {
1572
+ style: [{ minHeight: 40, backgroundColor: maskColor, borderRadius: 4 }, style]
1573
+ });
1574
+ }
1575
+ return React.createElement(TextInput, { style, ...rest });
1576
+ }
1577
+ function AllStakSensitiveText({
1578
+ children,
1579
+ privacy = "mask",
1580
+ style,
1581
+ maskLabel = DEFAULT_MASK_LABEL,
1582
+ ...rest
1583
+ }) {
1584
+ const isCapturing = useIsCapturing();
1585
+ if (isCapturing && privacy !== "show") {
1586
+ return React.createElement(Text, { style, ...rest }, maskLabel);
1587
+ }
1588
+ return React.createElement(Text, { style, ...rest }, children);
1589
+ }
1590
+
1591
+ // src/screenshot.ts
1592
+ var DEFAULT_SCREENSHOT_CONFIG = {
1593
+ captureScreenshotOnError: false,
1594
+ screenshotRedaction: "strict",
1595
+ screenshotMaskStyle: "solid",
1596
+ screenshotMaxBytes: 5e5,
1597
+ screenshotQuality: 0.7,
1598
+ screenshotFormat: "jpg",
1599
+ screenshotSampleRate: 1,
1600
+ screenshotOnUnhandledOnly: true,
1601
+ screenshotUploadTimeoutMs: 8e3,
1602
+ screenshotCaptureTimeoutMs: 2e3,
1603
+ screenshotNativeMode: "auto",
1604
+ screenshotFailPolicy: "send-event-only"
1605
+ };
1606
+ function resolveScreenshotConfig(partial) {
1607
+ const c = { ...DEFAULT_SCREENSHOT_CONFIG, ...partial ?? {} };
1608
+ c.screenshotMaxBytes = clamp(c.screenshotMaxBytes, 1024, 5e6);
1609
+ c.screenshotQuality = clamp(c.screenshotQuality, 0, 1);
1610
+ c.screenshotSampleRate = clamp(c.screenshotSampleRate, 0, 1);
1611
+ c.screenshotUploadTimeoutMs = clamp(c.screenshotUploadTimeoutMs, 500, 6e4);
1612
+ c.screenshotCaptureTimeoutMs = clamp(c.screenshotCaptureTimeoutMs, 100, 3e4);
1613
+ return c;
1614
+ }
1615
+ function clamp(n, lo, hi) {
1616
+ if (typeof n !== "number" || !Number.isFinite(n)) return lo;
1617
+ return Math.max(lo, Math.min(hi, n));
1618
+ }
1619
+ var rootViewRef = null;
1620
+ function __setRootViewRef(ref) {
1621
+ rootViewRef = ref;
1622
+ }
1623
+ var warnedAboutBothApis = false;
1624
+ function warnIfBothApisPresent(callbackPresent, flatPresent) {
1625
+ if (!callbackPresent || !flatPresent || warnedAboutBothApis) return;
1626
+ warnedAboutBothApis = true;
1627
+ console.warn(
1628
+ "[AllStak] Both `screenshot.provider` (deprecated) and the flat `captureScreenshotOnError` API are configured. The flat API takes precedence. Remove `screenshot.provider` to silence this warning."
1629
+ );
1630
+ }
1631
+ function isViewShotAvailable() {
1632
+ return tryRequire("react-native-view-shot") !== null;
1633
+ }
1634
+ async function captureViaViewShot(config) {
1635
+ if (config.screenshotNativeMode === "disabled") return null;
1636
+ const viewShot = tryRequire("react-native-view-shot");
1637
+ if (!viewShot) return null;
1638
+ const captureRef = viewShot.captureRef ?? viewShot.default?.captureRef;
1639
+ if (typeof captureRef !== "function") return null;
1640
+ const refTarget = rootViewRef?.current;
1641
+ if (!refTarget) return null;
1642
+ const format = config.screenshotFormat === "jpg" ? "jpg" : config.screenshotFormat;
1643
+ const dimensions = readDimensions();
1644
+ __setCapturing(true);
1645
+ await new Promise((r) => setTimeout(r, 16));
1646
+ try {
1647
+ const captured = await Promise.race([
1648
+ Promise.resolve(captureRef(refTarget, {
1649
+ format,
1650
+ quality: config.screenshotQuality,
1651
+ result: "base64"
1652
+ })),
1653
+ new Promise((resolve) => setTimeout(() => resolve(null), config.screenshotCaptureTimeoutMs))
1654
+ ]);
1655
+ if (!captured || typeof captured !== "string") return null;
1656
+ const sizeBytes = estimateBase64Size(captured);
1657
+ if (sizeBytes > config.screenshotMaxBytes) {
1658
+ if (__DEV__) {
1659
+ console.warn(`[AllStak] Screenshot ${sizeBytes}B exceeds limit ${config.screenshotMaxBytes}B; dropping.`);
1660
+ }
1661
+ return null;
1662
+ }
1663
+ const contentType = format === "png" ? "image/png" : format === "webp" ? "image/webp" : "image/jpeg";
1664
+ return {
1665
+ dataBase64: captured,
1666
+ contentType,
1667
+ width: dimensions.width,
1668
+ height: dimensions.height,
1669
+ sizeBytes
1670
+ };
1671
+ } catch (err) {
1672
+ if (__DEV__) {
1673
+ console.warn("[AllStak] view-shot capture failed:", err?.message);
1674
+ }
1675
+ return null;
1676
+ } finally {
1677
+ __setCapturing(false);
1678
+ }
1679
+ }
1680
+ function estimateBase64Size(base64) {
1681
+ const padding = base64.endsWith("==") ? 2 : base64.endsWith("=") ? 1 : 0;
1682
+ return Math.floor(base64.length * 3 / 4) - padding;
1683
+ }
1684
+ function readDimensions() {
1685
+ try {
1686
+ const RN3 = tryRequire("react-native");
1687
+ const dims = RN3?.Dimensions?.get?.("window");
1688
+ if (dims && typeof dims.width === "number" && typeof dims.height === "number") {
1689
+ return { width: Math.round(dims.width), height: Math.round(dims.height) };
1690
+ }
1691
+ } catch {
1692
+ }
1693
+ return { width: 0, height: 0 };
1694
+ }
1695
+ async function maybeCaptureScreenshot(config, ctx) {
1696
+ try {
1697
+ if (!config.captureScreenshotOnError) return null;
1698
+ if (config.screenshotOnUnhandledOnly && ctx.unhandled === false) return null;
1699
+ if (config.screenshotSampleRate < 1 && Math.random() >= config.screenshotSampleRate) return null;
1700
+ if (!runtimeAllowsScreenshot(ctx.runtimeMode)) return null;
1701
+ if (config.isScreenshotAllowed) {
1702
+ try {
1703
+ const allowed = await config.isScreenshotAllowed(ctx);
1704
+ if (!allowed) return null;
1705
+ } catch {
1706
+ return null;
1707
+ }
1708
+ }
1709
+ if (config.beforeScreenshotCapture) {
1710
+ try {
1711
+ const cont = await config.beforeScreenshotCapture(ctx);
1712
+ if (!cont) return null;
1713
+ } catch {
1714
+ return null;
1715
+ }
1716
+ }
1717
+ const upload = await captureViaViewShot(config);
1718
+ if (!upload) return null;
1719
+ const metadata = {
1720
+ captureMethod: "react-native-view-shot",
1721
+ redactionMode: config.screenshotRedaction,
1722
+ maskStyle: config.screenshotMaskStyle,
1723
+ format: config.screenshotFormat,
1724
+ width: upload.width,
1725
+ height: upload.height,
1726
+ sizeBytes: upload.sizeBytes,
1727
+ privacyComponentsDetected: sensitiveRefCount(),
1728
+ runtimeMode: ctx.runtimeMode
1729
+ };
1730
+ if (config.beforeScreenshotUpload) {
1731
+ try {
1732
+ const filtered = await config.beforeScreenshotUpload(upload, metadata);
1733
+ if (!filtered) return null;
1734
+ return { upload: filtered, metadata };
1735
+ } catch {
1736
+ return null;
1737
+ }
1738
+ }
1739
+ return { upload, metadata };
1740
+ } catch (err) {
1741
+ if (__DEV__) {
1742
+ console.warn("[AllStak] maybeCaptureScreenshot fail-open:", err?.message);
1743
+ }
1744
+ return null;
1745
+ }
1746
+ }
1747
+ function pickScreenshotConfig(source) {
1748
+ const out = {};
1749
+ const pick = (key) => {
1750
+ if (source[key] !== void 0) out[key] = source[key];
1751
+ };
1752
+ pick("captureScreenshotOnError");
1753
+ pick("screenshotRedaction");
1754
+ pick("screenshotMaskStyle");
1755
+ pick("screenshotMaxBytes");
1756
+ pick("screenshotQuality");
1757
+ pick("screenshotFormat");
1758
+ pick("screenshotSampleRate");
1759
+ pick("screenshotOnUnhandledOnly");
1760
+ pick("screenshotUploadTimeoutMs");
1761
+ pick("screenshotCaptureTimeoutMs");
1762
+ pick("screenshotNativeMode");
1763
+ pick("screenshotFailPolicy");
1764
+ pick("beforeScreenshotCapture");
1765
+ pick("beforeScreenshotUpload");
1766
+ pick("isScreenshotAllowed");
1767
+ return out;
1768
+ }
1769
+
1386
1770
  // src/client.ts
1387
1771
  var INGEST_HOST = "https://api.allstak.sa";
1388
1772
  var SDK_NAME = "allstak-react-native";
1389
- var SDK_VERSION = "0.3.4";
1773
+ var SDK_VERSION = "0.4.0";
1390
1774
  var ERRORS_PATH = "/ingest/v1/errors";
1391
1775
  var LOGS_PATH = "/ingest/v1/logs";
1392
1776
  var VALID_BREADCRUMB_TYPES = /* @__PURE__ */ new Set(["http", "log", "ui", "navigation", "query", "default"]);
@@ -1565,6 +1949,18 @@ var AllStakClient = class {
1565
1949
  breadcrumbs: currentBreadcrumbs,
1566
1950
  fingerprint: eff.fingerprint
1567
1951
  };
1952
+ const flatPresent = this.config.captureScreenshotOnError === true;
1953
+ const callbackPresent = Boolean(this.config.screenshot?.provider);
1954
+ warnIfBothApisPresent(callbackPresent, flatPresent);
1955
+ if (flatPresent) {
1956
+ void this.runFlatScreenshotPipeline(error, payload).catch(() => {
1957
+ void this.sendThroughBeforeSend({
1958
+ ...payload,
1959
+ metadata: { ...payload.metadata ?? {}, "screenshot.status": "failed" }
1960
+ });
1961
+ });
1962
+ return;
1963
+ }
1568
1964
  if (this.shouldCaptureScreenshot()) {
1569
1965
  void this.withScreenshotMetadata(error, payload).then((enriched) => this.sendThroughBeforeSend(enriched)).catch(() => this.sendThroughBeforeSend({
1570
1966
  ...payload,
@@ -1580,6 +1976,86 @@ var AllStakClient = class {
1580
1976
  }
1581
1977
  });
1582
1978
  }
1979
+ /**
1980
+ * Flat screenshot API path. Capture first (so masking primitives can
1981
+ * swap), send the event with a `screenshot.status` metadata tag, read
1982
+ * back the server-assigned errorId, then upload the attachment.
1983
+ *
1984
+ * Fail-open at every step.
1985
+ */
1986
+ async runFlatScreenshotPipeline(error, payload) {
1987
+ const sc = resolveScreenshotConfig(pickScreenshotConfig(this.config));
1988
+ const runtimeMode = detectRuntimeMode();
1989
+ const ctx = { error, unhandled: true, runtimeMode };
1990
+ let captured = null;
1991
+ try {
1992
+ captured = await maybeCaptureScreenshot(sc, ctx);
1993
+ } catch {
1994
+ captured = null;
1995
+ }
1996
+ const status = !sc.captureScreenshotOnError ? "disabled" : captured ? "captured" : runtimeMode === "expo-go" ? "unsupported_runtime" : "unavailable";
1997
+ const eventPayload = {
1998
+ ...payload,
1999
+ metadata: {
2000
+ ...payload.metadata ?? {},
2001
+ "screenshot.status": status,
2002
+ "screenshot.runtimeMode": runtimeMode,
2003
+ ...captured ? {
2004
+ "screenshot.contentType": captured.upload.contentType,
2005
+ "screenshot.width": captured.upload.width,
2006
+ "screenshot.height": captured.upload.height,
2007
+ "screenshot.sizeBytes": captured.upload.sizeBytes,
2008
+ "screenshot.redactionMode": captured.metadata.redactionMode,
2009
+ "screenshot.maskStyle": captured.metadata.maskStyle,
2010
+ "screenshot.captureMethod": captured.metadata.captureMethod
2011
+ } : {}
2012
+ }
2013
+ };
2014
+ let finalPayload = eventPayload;
2015
+ if (this.config.beforeSend) {
2016
+ try {
2017
+ finalPayload = await this.config.beforeSend(eventPayload);
2018
+ } catch {
2019
+ finalPayload = eventPayload;
2020
+ }
2021
+ }
2022
+ if (!finalPayload) return;
2023
+ let eventId = null;
2024
+ try {
2025
+ const resp = await this.transport.sendAndRead(
2026
+ ERRORS_PATH,
2027
+ finalPayload,
2028
+ { timeoutMs: 5e3, retries: 1 }
2029
+ );
2030
+ eventId = resp?.data?.id ?? resp?.id ?? null;
2031
+ } catch {
2032
+ }
2033
+ if (!captured || !eventId) return;
2034
+ try {
2035
+ await this.transport.sendAndRead(
2036
+ `/ingest/v1/errors/${encodeURIComponent(eventId)}/attachments`,
2037
+ {
2038
+ kind: "screenshot",
2039
+ contentType: captured.upload.contentType,
2040
+ dataBase64: captured.upload.dataBase64,
2041
+ width: captured.upload.width,
2042
+ height: captured.upload.height,
2043
+ redactionMode: captured.metadata.redactionMode,
2044
+ captureMethod: captured.metadata.captureMethod,
2045
+ sizeBytes: captured.upload.sizeBytes,
2046
+ metadata: {
2047
+ maskStyle: captured.metadata.maskStyle,
2048
+ format: captured.metadata.format,
2049
+ runtimeMode: captured.metadata.runtimeMode,
2050
+ privacyComponentsDetected: captured.metadata.privacyComponentsDetected ?? 0,
2051
+ sdkVersion: SDK_VERSION
2052
+ }
2053
+ },
2054
+ { timeoutMs: sc.screenshotUploadTimeoutMs, retries: 2 }
2055
+ );
2056
+ } catch {
2057
+ }
2058
+ }
1583
2059
  /** Start a new span. Auto-parented to any currently-active span. */
1584
2060
  startSpan(operation, options) {
1585
2061
  return this.tracing.startSpan(operation, options);
@@ -2104,7 +2580,7 @@ function byteSize(value) {
2104
2580
  }
2105
2581
 
2106
2582
  // src/provider.tsx
2107
- import * as React from "react";
2583
+ import * as React2 from "react";
2108
2584
 
2109
2585
  // src/auto-breadcrumbs.ts
2110
2586
  var FETCH_FLAG2 = "__allstak_fetch_patched__";
@@ -2341,17 +2817,17 @@ function tryAutoInstrumentNavigation() {
2341
2817
  const rnav = require("@react-navigation/native");
2342
2818
  if (!rnav || !rnav.NavigationContainer) return false;
2343
2819
  if (rnav[NAV_AUTO_PATCH_FLAG]) return true;
2344
- const React2 = require("react");
2345
- if (!React2 || typeof React2.forwardRef !== "function") return false;
2820
+ const React3 = require("react");
2821
+ if (!React3 || typeof React3.forwardRef !== "function") return false;
2346
2822
  const OrigContainer = rnav.NavigationContainer;
2347
- const Wrapped = React2.forwardRef(function AllStakNavigationContainer(props, userRef) {
2348
- const internalRef = React2.useRef(null);
2349
- const setRef = React2.useCallback((r) => {
2823
+ const Wrapped = React3.forwardRef(function AllStakNavigationContainer(props, userRef) {
2824
+ const internalRef = React3.useRef(null);
2825
+ const setRef = React3.useCallback((r) => {
2350
2826
  internalRef.current = r;
2351
2827
  if (typeof userRef === "function") userRef(r);
2352
2828
  else if (userRef) userRef.current = r;
2353
2829
  }, [userRef]);
2354
- React2.useEffect(() => {
2830
+ React3.useEffect(() => {
2355
2831
  if (internalRef.current) {
2356
2832
  try {
2357
2833
  instrumentReactNavigation(internalRef.current);
@@ -2359,7 +2835,7 @@ function tryAutoInstrumentNavigation() {
2359
2835
  }
2360
2836
  }
2361
2837
  }, []);
2362
- return React2.createElement(OrigContainer, { ...props, ref: setRef });
2838
+ return React3.createElement(OrigContainer, { ...props, ref: setRef });
2363
2839
  });
2364
2840
  Wrapped.displayName = "AllStakNavigationContainer";
2365
2841
  try {
@@ -2589,9 +3065,11 @@ function installReactNative(options = {}) {
2589
3065
  }
2590
3066
 
2591
3067
  // src/provider.tsx
2592
- var AllStakContext = React.createContext(null);
3068
+ var RN2 = tryRequire("react-native");
3069
+ var RootView = RN2?.View ?? ((props) => React2.createElement("View", props));
3070
+ var AllStakContext = React2.createContext(null);
2593
3071
  var __providerOwnedInstance = null;
2594
- var AllStakErrorBoundary = class extends React.Component {
3072
+ var AllStakErrorBoundary = class extends React2.Component {
2595
3073
  constructor() {
2596
3074
  super(...arguments);
2597
3075
  this.state = { error: null };
@@ -2659,9 +3137,31 @@ function AllStakProvider({
2659
3137
  autoNetworkCapture,
2660
3138
  autoFetchBreadcrumbs,
2661
3139
  autoConsoleBreadcrumbs,
2662
- autoNavigationBreadcrumbs
3140
+ autoNavigationBreadcrumbs,
3141
+ captureScreenshotOnError,
3142
+ screenshotRedaction,
3143
+ screenshotMaskStyle,
3144
+ screenshotMaxBytes,
3145
+ screenshotQuality,
3146
+ screenshotFormat,
3147
+ screenshotSampleRate,
3148
+ screenshotOnUnhandledOnly,
3149
+ screenshotUploadTimeoutMs,
3150
+ screenshotCaptureTimeoutMs,
3151
+ screenshotNativeMode,
3152
+ screenshotFailPolicy,
3153
+ beforeScreenshotCapture,
3154
+ beforeScreenshotUpload,
3155
+ isScreenshotAllowed
2663
3156
  }) {
2664
- const clientRef = React.useRef(null);
3157
+ const clientRef = React2.useRef(null);
3158
+ const rootRef = React2.useRef(null);
3159
+ React2.useEffect(() => {
3160
+ __setRootViewRef(rootRef);
3161
+ return () => {
3162
+ __setRootViewRef(null);
3163
+ };
3164
+ }, []);
2665
3165
  if (!clientRef.current) {
2666
3166
  const existing = AllStak._getInstance();
2667
3167
  if (existing && __providerOwnedInstance === existing) {
@@ -2685,7 +3185,22 @@ function AllStakProvider({
2685
3185
  replay,
2686
3186
  tracesSampleRate,
2687
3187
  service,
2688
- dist
3188
+ dist,
3189
+ captureScreenshotOnError,
3190
+ screenshotRedaction,
3191
+ screenshotMaskStyle,
3192
+ screenshotMaxBytes,
3193
+ screenshotQuality,
3194
+ screenshotFormat,
3195
+ screenshotSampleRate,
3196
+ screenshotOnUnhandledOnly,
3197
+ screenshotUploadTimeoutMs,
3198
+ screenshotCaptureTimeoutMs,
3199
+ screenshotNativeMode,
3200
+ screenshotFailPolicy,
3201
+ beforeScreenshotCapture,
3202
+ beforeScreenshotUpload,
3203
+ isScreenshotAllowed
2689
3204
  };
2690
3205
  clientRef.current = AllStak.init(config);
2691
3206
  __providerOwnedInstance = clientRef.current;
@@ -2705,7 +3220,7 @@ function AllStakProvider({
2705
3220
  }
2706
3221
  }
2707
3222
  }
2708
- React.useEffect(() => {
3223
+ React2.useEffect(() => {
2709
3224
  return () => {
2710
3225
  if (destroyOnUnmount) {
2711
3226
  AllStak.destroy();
@@ -2715,10 +3230,16 @@ function AllStakProvider({
2715
3230
  }
2716
3231
  };
2717
3232
  }, [destroyOnUnmount, debug]);
2718
- return /* @__PURE__ */ React.createElement(AllStakContext.Provider, { value: clientRef.current }, /* @__PURE__ */ React.createElement(AllStakErrorBoundary, { fallback, onError, debug }, children));
3233
+ const boundary = /* @__PURE__ */ React2.createElement(AllStakErrorBoundary, { fallback, onError, debug }, children);
3234
+ const wrapped = RN2 ? React2.createElement(
3235
+ RootView,
3236
+ { ref: rootRef, style: { flex: 1 }, collapsable: false },
3237
+ boundary
3238
+ ) : boundary;
3239
+ return /* @__PURE__ */ React2.createElement(AllStakContext.Provider, { value: clientRef.current }, wrapped);
2719
3240
  }
2720
3241
  function useAllStak() {
2721
- return React.useMemo(
3242
+ return React2.useMemo(
2722
3243
  () => ({
2723
3244
  captureException: (error, ctx) => AllStak.captureException(error, ctx),
2724
3245
  captureMessage: (msg, level = "info") => AllStak.captureMessage(msg, level),
@@ -2788,8 +3309,13 @@ export {
2788
3309
  ALWAYS_REDACT_QUERY,
2789
3310
  AllStak,
2790
3311
  AllStakClient,
3312
+ AllStakMaskedView,
3313
+ AllStakPrivacyView,
2791
3314
  AllStakProvider,
3315
+ AllStakSensitiveText,
3316
+ AllStakTextInput,
2792
3317
  DEFAULT_REDACT_BODY_FIELDS,
3318
+ DEFAULT_SCREENSHOT_CONFIG,
2793
3319
  HttpRequestModule,
2794
3320
  INGEST_HOST,
2795
3321
  REDACTED,
@@ -2800,18 +3326,30 @@ export {
2800
3326
  __devTriggerNativeCrash,
2801
3327
  __resetAutoNavigationFlagForTest,
2802
3328
  __resetConsoleInstrumentationFlagForTest,
3329
+ __resetPrivacyStateForTest,
2803
3330
  __resetProviderInstanceForTest,
3331
+ __resetRuntimeModeForTest,
2804
3332
  __setNativeModuleForTest,
2805
3333
  applyArchitectureTags,
2806
3334
  captureBodyResult,
3335
+ captureViaViewShot,
2807
3336
  detectArchitecture,
3337
+ detectRuntimeMode,
2808
3338
  drainPendingNativeCrashes,
2809
3339
  installReactNative,
2810
3340
  instrumentNavigationFromLinking,
2811
3341
  instrumentReactNavigation,
3342
+ isCapturingScreenshot,
3343
+ isViewShotAvailable,
3344
+ maybeCaptureScreenshot,
3345
+ pickScreenshotConfig,
2812
3346
  redactUrl,
3347
+ registerSensitiveRef,
3348
+ resolveScreenshotConfig,
3349
+ runtimeAllowsScreenshot,
2813
3350
  sanitizeHeaders,
2814
3351
  tryAutoInstrumentNavigation,
2815
- useAllStak
3352
+ useAllStak,
3353
+ useAllStakPrivacy
2816
3354
  };
2817
3355
  //# sourceMappingURL=index.mjs.map