@allstak/react-native 0.4.1 → 0.5.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/CHANGELOG.md +61 -0
- package/dist/index.d.mts +245 -4
- package/dist/index.d.ts +245 -4
- package/dist/index.js +473 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +473 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1783,15 +1783,325 @@ function pickScreenshotConfig(source) {
|
|
|
1783
1783
|
return out;
|
|
1784
1784
|
}
|
|
1785
1785
|
|
|
1786
|
+
// src/contexts.ts
|
|
1787
|
+
function tryReq(id2) {
|
|
1788
|
+
try {
|
|
1789
|
+
return require(id2);
|
|
1790
|
+
} catch {
|
|
1791
|
+
return null;
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
function defaultExport(mod) {
|
|
1795
|
+
if (!mod) return null;
|
|
1796
|
+
return mod.default ?? mod;
|
|
1797
|
+
}
|
|
1798
|
+
function strOrUndef(v) {
|
|
1799
|
+
if (v == null) return void 0;
|
|
1800
|
+
const s = String(v);
|
|
1801
|
+
return s.length > 0 ? s : void 0;
|
|
1802
|
+
}
|
|
1803
|
+
function collectAutoContexts(opts = {}) {
|
|
1804
|
+
const captureDev = opts.captureDeviceContext !== false;
|
|
1805
|
+
const captureScreen = opts.captureScreenContext !== false;
|
|
1806
|
+
const contexts = {};
|
|
1807
|
+
const tags = {};
|
|
1808
|
+
const RN = tryReq("react-native");
|
|
1809
|
+
const Platform = RN?.Platform;
|
|
1810
|
+
const Dimensions = RN?.Dimensions;
|
|
1811
|
+
const NativeModules = RN?.NativeModules;
|
|
1812
|
+
const osName = strOrUndef(Platform?.OS);
|
|
1813
|
+
const osVersion = strOrUndef(Platform?.Version);
|
|
1814
|
+
const osConstants = Platform?.constants ?? {};
|
|
1815
|
+
if (osName) {
|
|
1816
|
+
contexts.os = {
|
|
1817
|
+
name: osName === "ios" ? "iOS" : osName === "android" ? "Android" : osName,
|
|
1818
|
+
version: osVersion,
|
|
1819
|
+
build: strOrUndef(osConstants?.osBuildId ?? osConstants?.Release)
|
|
1820
|
+
};
|
|
1821
|
+
tags["os.name"] = osName;
|
|
1822
|
+
if (osVersion) tags["os.version"] = osVersion;
|
|
1823
|
+
}
|
|
1824
|
+
const g = globalThis;
|
|
1825
|
+
const hermes = typeof g.HermesInternal !== "undefined";
|
|
1826
|
+
const fabric = typeof g.__turboModuleProxy !== "undefined";
|
|
1827
|
+
const turboModules = fabric;
|
|
1828
|
+
const bridgeless = typeof g.RN$Bridgeless !== "undefined" && !!g.RN$Bridgeless;
|
|
1829
|
+
const jsEngine = hermes ? "hermes" : "jsc";
|
|
1830
|
+
tags["js_engine"] = jsEngine;
|
|
1831
|
+
tags["fabric"] = String(fabric);
|
|
1832
|
+
tags["turbo_modules"] = String(turboModules);
|
|
1833
|
+
const hermesVersion = (() => {
|
|
1834
|
+
try {
|
|
1835
|
+
return g.HermesInternal?.getRuntimeProperties?.()?.["OSS Release Version"];
|
|
1836
|
+
} catch {
|
|
1837
|
+
return void 0;
|
|
1838
|
+
}
|
|
1839
|
+
})();
|
|
1840
|
+
contexts.runtime = {
|
|
1841
|
+
name: jsEngine,
|
|
1842
|
+
version: strOrUndef(hermesVersion) ?? "unknown",
|
|
1843
|
+
bridgeless
|
|
1844
|
+
};
|
|
1845
|
+
if (captureDev) {
|
|
1846
|
+
const device = {};
|
|
1847
|
+
if (osConstants?.Model) device.model = String(osConstants.Model);
|
|
1848
|
+
if (osConstants?.Brand) device.brand = String(osConstants.Brand);
|
|
1849
|
+
if (osConstants?.Manufacturer) device.manufacturer = String(osConstants.Manufacturer);
|
|
1850
|
+
if (osConstants?.systemName) device.systemName = String(osConstants.systemName);
|
|
1851
|
+
if (osConstants?.interfaceIdiom) device.family = String(osConstants.interfaceIdiom);
|
|
1852
|
+
const isSim = Boolean(osConstants?.isTesting) || typeof osConstants?.reactNativeVersion === "object" && String(osConstants?.systemName ?? "").toLowerCase().includes("simulator");
|
|
1853
|
+
if (isSim) {
|
|
1854
|
+
device.simulator = true;
|
|
1855
|
+
tags["simulator"] = "true";
|
|
1856
|
+
}
|
|
1857
|
+
const expoDevice = tryReq("expo-device");
|
|
1858
|
+
if (expoDevice) {
|
|
1859
|
+
const ed = defaultExport(expoDevice) ?? expoDevice;
|
|
1860
|
+
if (ed.modelName) device.model = String(ed.modelName);
|
|
1861
|
+
if (ed.brand) device.brand = String(ed.brand);
|
|
1862
|
+
if (ed.manufacturer) device.manufacturer = String(ed.manufacturer);
|
|
1863
|
+
if (ed.deviceYearClass != null) device.yearClass = ed.deviceYearClass;
|
|
1864
|
+
if (ed.totalMemory != null) device.memory_size = ed.totalMemory;
|
|
1865
|
+
if (typeof ed.supportedCpuArchitectures !== "undefined") {
|
|
1866
|
+
const arr = ed.supportedCpuArchitectures;
|
|
1867
|
+
if (Array.isArray(arr) && arr.length > 0) device.arch = String(arr[0]);
|
|
1868
|
+
}
|
|
1869
|
+
if (typeof ed.isDevice === "boolean" && !ed.isDevice) {
|
|
1870
|
+
device.simulator = true;
|
|
1871
|
+
tags["simulator"] = "true";
|
|
1872
|
+
}
|
|
1873
|
+
} else {
|
|
1874
|
+
const dinfo = tryReq("react-native-device-info");
|
|
1875
|
+
if (dinfo) {
|
|
1876
|
+
const d = defaultExport(dinfo) ?? dinfo;
|
|
1877
|
+
try {
|
|
1878
|
+
device.model = device.model ?? d.getModel?.();
|
|
1879
|
+
} catch {
|
|
1880
|
+
}
|
|
1881
|
+
try {
|
|
1882
|
+
device.manufacturer = device.manufacturer ?? d.getManufacturerSync?.();
|
|
1883
|
+
} catch {
|
|
1884
|
+
}
|
|
1885
|
+
try {
|
|
1886
|
+
device.memory_size = device.memory_size ?? d.getTotalMemorySync?.();
|
|
1887
|
+
} catch {
|
|
1888
|
+
}
|
|
1889
|
+
try {
|
|
1890
|
+
const isEm = d.isEmulatorSync?.();
|
|
1891
|
+
if (isEm) {
|
|
1892
|
+
device.simulator = true;
|
|
1893
|
+
tags["simulator"] = "true";
|
|
1894
|
+
}
|
|
1895
|
+
} catch {
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
if (captureScreen && Dimensions && typeof Dimensions.get === "function") {
|
|
1900
|
+
try {
|
|
1901
|
+
const screen = Dimensions.get("screen");
|
|
1902
|
+
if (screen?.width && screen?.height) {
|
|
1903
|
+
device.screen_width_pixels = Math.round(screen.width * (screen.scale ?? 1));
|
|
1904
|
+
device.screen_height_pixels = Math.round(screen.height * (screen.scale ?? 1));
|
|
1905
|
+
device.screen_density = screen.scale;
|
|
1906
|
+
device.orientation = screen.width >= screen.height ? "landscape" : "portrait";
|
|
1907
|
+
tags["app_orientation"] = device.orientation;
|
|
1908
|
+
}
|
|
1909
|
+
} catch {
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
if (opts.captureBattery) {
|
|
1913
|
+
const expoBattery = tryReq("expo-battery");
|
|
1914
|
+
if (expoBattery) {
|
|
1915
|
+
try {
|
|
1916
|
+
const eb = defaultExport(expoBattery) ?? expoBattery;
|
|
1917
|
+
device.battery_available = true;
|
|
1918
|
+
if (typeof eb.getBatteryLevelAsync === "function") {
|
|
1919
|
+
}
|
|
1920
|
+
} catch {
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
if (Object.keys(device).length > 0) {
|
|
1925
|
+
contexts.device = device;
|
|
1926
|
+
if (device.model) tags["device.model"] = String(device.model);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
const app = {};
|
|
1930
|
+
app.app_start_time = (/* @__PURE__ */ new Date()).toISOString();
|
|
1931
|
+
const expoApp = tryReq("expo-application");
|
|
1932
|
+
if (expoApp) {
|
|
1933
|
+
const ea = defaultExport(expoApp) ?? expoApp;
|
|
1934
|
+
if (ea.applicationName) app.app_name = String(ea.applicationName);
|
|
1935
|
+
if (ea.applicationId) app.app_identifier = String(ea.applicationId);
|
|
1936
|
+
if (ea.nativeBuildVersion) app.app_build = String(ea.nativeBuildVersion);
|
|
1937
|
+
if (ea.nativeApplicationVersion) app.app_version = String(ea.nativeApplicationVersion);
|
|
1938
|
+
} else {
|
|
1939
|
+
const dinfo = tryReq("react-native-device-info");
|
|
1940
|
+
if (dinfo) {
|
|
1941
|
+
const d = defaultExport(dinfo) ?? dinfo;
|
|
1942
|
+
try {
|
|
1943
|
+
app.app_name = d.getApplicationName?.();
|
|
1944
|
+
} catch {
|
|
1945
|
+
}
|
|
1946
|
+
try {
|
|
1947
|
+
app.app_identifier = d.getBundleId?.();
|
|
1948
|
+
} catch {
|
|
1949
|
+
}
|
|
1950
|
+
try {
|
|
1951
|
+
app.app_build = d.getBuildNumber?.();
|
|
1952
|
+
} catch {
|
|
1953
|
+
}
|
|
1954
|
+
try {
|
|
1955
|
+
app.app_version = d.getVersion?.();
|
|
1956
|
+
} catch {
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
if (Object.keys(app).length > 0) {
|
|
1961
|
+
contexts.app = app;
|
|
1962
|
+
if (app.app_version) tags["app.version"] = String(app.app_version);
|
|
1963
|
+
if (app.app_build) tags["app.build"] = String(app.app_build);
|
|
1964
|
+
}
|
|
1965
|
+
const rn = {
|
|
1966
|
+
hermes,
|
|
1967
|
+
fabric,
|
|
1968
|
+
turbo_modules: turboModules,
|
|
1969
|
+
bridgeless,
|
|
1970
|
+
js_engine: jsEngine
|
|
1971
|
+
};
|
|
1972
|
+
if (osConstants?.reactNativeVersion) {
|
|
1973
|
+
const v = osConstants.reactNativeVersion;
|
|
1974
|
+
if (typeof v === "object" && v.major != null) {
|
|
1975
|
+
rn.react_native_version = `${v.major}.${v.minor ?? 0}.${v.patch ?? 0}`;
|
|
1976
|
+
} else if (typeof v === "string") {
|
|
1977
|
+
rn.react_native_version = v;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
const expoConstants = tryReq("expo-constants");
|
|
1981
|
+
if (expoConstants) {
|
|
1982
|
+
const ec = defaultExport(expoConstants) ?? expoConstants;
|
|
1983
|
+
if (ec.expoVersion) rn.expo = ec.expoVersion;
|
|
1984
|
+
else if (ec.expoConfig?.sdkVersion) rn.expo = ec.expoConfig.sdkVersion;
|
|
1985
|
+
if (ec.appOwnership) rn.expo_application_ownership = String(ec.appOwnership);
|
|
1986
|
+
if (ec.executionEnvironment) rn.expo_execution_environment = String(ec.executionEnvironment);
|
|
1987
|
+
} else {
|
|
1988
|
+
rn.expo = false;
|
|
1989
|
+
}
|
|
1990
|
+
contexts.react_native = rn;
|
|
1991
|
+
if (rn.expo && rn.expo !== false) tags["expo"] = "true";
|
|
1992
|
+
if (rn.react_native_version) tags["rn.version"] = String(rn.react_native_version);
|
|
1993
|
+
return { contexts, tags };
|
|
1994
|
+
}
|
|
1995
|
+
function buildUserContext(user, opts = {}) {
|
|
1996
|
+
if (!user) return void 0;
|
|
1997
|
+
const out = {};
|
|
1998
|
+
if (user.id) out.id = user.id;
|
|
1999
|
+
if (user.username) out.username = user.username;
|
|
2000
|
+
if (opts.sendDefaultPii) {
|
|
2001
|
+
if (user.email) out.email = user.email;
|
|
2002
|
+
if (user.ip_address) out.ip_address = user.ip_address;
|
|
2003
|
+
}
|
|
2004
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
// src/mechanism.ts
|
|
2008
|
+
var URL_QUERY_RE = /\?.*$/;
|
|
2009
|
+
function sanitizeUrl(url) {
|
|
2010
|
+
if (!url) return "";
|
|
2011
|
+
const s = String(url).replace(URL_QUERY_RE, "");
|
|
2012
|
+
return s;
|
|
2013
|
+
}
|
|
2014
|
+
function exceptionClassName(err) {
|
|
2015
|
+
if (err && typeof err === "object") {
|
|
2016
|
+
const e = err;
|
|
2017
|
+
const fromName = e.name && e.name !== "Error" ? e.name : void 0;
|
|
2018
|
+
return fromName ?? e.constructor?.name ?? "Error";
|
|
2019
|
+
}
|
|
2020
|
+
return "Error";
|
|
2021
|
+
}
|
|
2022
|
+
function exceptionValue(err) {
|
|
2023
|
+
if (err == null) return "";
|
|
2024
|
+
if (err instanceof Error) return err.message ?? "";
|
|
2025
|
+
if (typeof err === "string") return err;
|
|
2026
|
+
try {
|
|
2027
|
+
return JSON.stringify(err);
|
|
2028
|
+
} catch {
|
|
2029
|
+
return String(err);
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
function buildExceptionChain(err, mechanism, handled) {
|
|
2033
|
+
const values = [];
|
|
2034
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2035
|
+
let cursor = err;
|
|
2036
|
+
let depth = 0;
|
|
2037
|
+
while (cursor && depth < 5 && !seen.has(cursor)) {
|
|
2038
|
+
seen.add(cursor);
|
|
2039
|
+
const e = cursor;
|
|
2040
|
+
const frames = parseStack(e?.stack);
|
|
2041
|
+
values.push({
|
|
2042
|
+
type: exceptionClassName(e),
|
|
2043
|
+
value: exceptionValue(e),
|
|
2044
|
+
stacktrace: frames.length > 0 ? { frames } : void 0,
|
|
2045
|
+
// Only the outermost exception carries the mechanism, like Sentry.
|
|
2046
|
+
...depth === 0 ? { mechanism: { type: mechanism, handled } } : {}
|
|
2047
|
+
});
|
|
2048
|
+
cursor = e?.cause;
|
|
2049
|
+
depth += 1;
|
|
2050
|
+
}
|
|
2051
|
+
return values.reverse();
|
|
2052
|
+
}
|
|
2053
|
+
function extractAxiosRequest(err) {
|
|
2054
|
+
if (!err || typeof err !== "object") return null;
|
|
2055
|
+
const e = err;
|
|
2056
|
+
if (e.isAxiosError !== true) return null;
|
|
2057
|
+
const cfg = e.config ?? {};
|
|
2058
|
+
const resp = e.response ?? null;
|
|
2059
|
+
const method = strUpper(cfg.method);
|
|
2060
|
+
const rawUrl = composeAxiosUrl(cfg);
|
|
2061
|
+
const url_sanitized = sanitizeUrl(rawUrl);
|
|
2062
|
+
const status_code = typeof resp?.status === "number" ? resp.status : void 0;
|
|
2063
|
+
const duration_ms = typeof e.duration === "number" ? e.duration : void 0;
|
|
2064
|
+
const category = classifyHttpError(e, status_code);
|
|
2065
|
+
return {
|
|
2066
|
+
method,
|
|
2067
|
+
url_sanitized,
|
|
2068
|
+
status_code,
|
|
2069
|
+
duration_ms,
|
|
2070
|
+
category
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
function composeAxiosUrl(cfg) {
|
|
2074
|
+
const base = typeof cfg?.baseURL === "string" ? cfg.baseURL.replace(/\/$/, "") : "";
|
|
2075
|
+
const path = typeof cfg?.url === "string" ? cfg.url : "";
|
|
2076
|
+
if (!base && !path) return "";
|
|
2077
|
+
if (path.startsWith("http://") || path.startsWith("https://")) return path;
|
|
2078
|
+
return base + path;
|
|
2079
|
+
}
|
|
2080
|
+
function strUpper(v) {
|
|
2081
|
+
if (typeof v !== "string" || v.length === 0) return void 0;
|
|
2082
|
+
return v.toUpperCase();
|
|
2083
|
+
}
|
|
2084
|
+
function classifyHttpError(err, status) {
|
|
2085
|
+
const code = typeof err?.code === "string" ? err.code.toUpperCase() : "";
|
|
2086
|
+
if (code === "ECONNABORTED" || code === "ETIMEDOUT") return "timeout";
|
|
2087
|
+
if (code === "ERR_CANCELED" || code === "CANCELED") return "cancel";
|
|
2088
|
+
if (typeof status === "number" && status >= 500) return "http_server_error";
|
|
2089
|
+
if (typeof status === "number" && status >= 400) return "http_client_error";
|
|
2090
|
+
return "network";
|
|
2091
|
+
}
|
|
2092
|
+
function maybeExtractHttpRequest(err) {
|
|
2093
|
+
return extractAxiosRequest(err);
|
|
2094
|
+
}
|
|
2095
|
+
|
|
1786
2096
|
// src/client.ts
|
|
1787
2097
|
var INGEST_HOST = "https://api.allstak.sa";
|
|
1788
2098
|
var SDK_NAME = "allstak-react-native";
|
|
1789
|
-
var SDK_VERSION = "0.
|
|
2099
|
+
var SDK_VERSION = "0.5.0";
|
|
1790
2100
|
var ERRORS_PATH = "/ingest/v1/errors";
|
|
1791
2101
|
var LOGS_PATH = "/ingest/v1/logs";
|
|
1792
2102
|
var VALID_BREADCRUMB_TYPES = /* @__PURE__ */ new Set(["http", "log", "ui", "navigation", "query", "default"]);
|
|
1793
2103
|
var VALID_BREADCRUMB_LEVELS = /* @__PURE__ */ new Set(["info", "warn", "error", "debug"]);
|
|
1794
|
-
var DEFAULT_MAX_BREADCRUMBS =
|
|
2104
|
+
var DEFAULT_MAX_BREADCRUMBS = 100;
|
|
1795
2105
|
function frameToString(f) {
|
|
1796
2106
|
const fn = f.function && f.function.length > 0 ? f.function : "<anonymous>";
|
|
1797
2107
|
const file = f.filename || f.absPath || "<anonymous>";
|
|
@@ -1820,6 +2130,12 @@ var AllStakClient = class {
|
|
|
1820
2130
|
this.replay = null;
|
|
1821
2131
|
this.httpRequests = null;
|
|
1822
2132
|
this._instrumentAxios = null;
|
|
2133
|
+
/** Auto-collected Sentry-shape contexts (device/os/app/react_native/runtime). */
|
|
2134
|
+
this.autoContexts = {};
|
|
2135
|
+
/** Auto-collected tags (device.model, os.name, js_engine, …). */
|
|
2136
|
+
this.autoTags = {};
|
|
2137
|
+
/** Current screen / transaction name — set via setCurrentScreen() or nav auto-instrument. */
|
|
2138
|
+
this.currentTransaction = null;
|
|
1823
2139
|
this.config = { ...config };
|
|
1824
2140
|
if (!this.config.environment) this.config.environment = "production";
|
|
1825
2141
|
if (!this.config.sdkName) this.config.sdkName = SDK_NAME;
|
|
@@ -1841,6 +2157,18 @@ var AllStakClient = class {
|
|
|
1841
2157
|
} catch {
|
|
1842
2158
|
}
|
|
1843
2159
|
}
|
|
2160
|
+
try {
|
|
2161
|
+
const opts = {
|
|
2162
|
+
captureDeviceContext: config.captureDeviceContext !== false,
|
|
2163
|
+
captureBattery: config.captureBattery === true,
|
|
2164
|
+
captureScreenContext: config.captureScreenContext !== false,
|
|
2165
|
+
sendDefaultPii: config.sendDefaultPii === true
|
|
2166
|
+
};
|
|
2167
|
+
const { contexts, tags } = collectAutoContexts(opts);
|
|
2168
|
+
this.autoContexts = contexts;
|
|
2169
|
+
this.autoTags = tags;
|
|
2170
|
+
} catch {
|
|
2171
|
+
}
|
|
1844
2172
|
if (config.enableHttpTracking) {
|
|
1845
2173
|
try {
|
|
1846
2174
|
this.httpRequests = new HttpRequestModule(this.transport);
|
|
@@ -1883,7 +2211,7 @@ var AllStakClient = class {
|
|
|
1883
2211
|
return this.httpRequests?.getRecentFailed() ?? [];
|
|
1884
2212
|
}
|
|
1885
2213
|
// ── Public API ────────────────────────────────────────────────────
|
|
1886
|
-
captureException(error, context) {
|
|
2214
|
+
captureException(error, context, opts) {
|
|
1887
2215
|
if (!this.passesSampleRate()) return;
|
|
1888
2216
|
const frames = parseStack(error.stack).map((f) => ({
|
|
1889
2217
|
...f,
|
|
@@ -1965,6 +2293,35 @@ var AllStakClient = class {
|
|
|
1965
2293
|
breadcrumbs: currentBreadcrumbs,
|
|
1966
2294
|
fingerprint: eff.fingerprint
|
|
1967
2295
|
};
|
|
2296
|
+
const mechanism = opts?.mechanism ?? "captureException";
|
|
2297
|
+
const handled = opts?.handled ?? (mechanism === "captureException" || mechanism === "errorboundary");
|
|
2298
|
+
payload.eventId = generateEventId();
|
|
2299
|
+
payload.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2300
|
+
payload.handled = handled;
|
|
2301
|
+
payload.mechanism = mechanism;
|
|
2302
|
+
if (this.currentTransaction) payload.transaction = this.currentTransaction;
|
|
2303
|
+
payload.exception = { values: buildExceptionChain(error, mechanism, handled) };
|
|
2304
|
+
const req = maybeExtractHttpRequest(error);
|
|
2305
|
+
if (req) payload.request = req;
|
|
2306
|
+
const userCtx = buildUserContext(eff.user, { sendDefaultPii: this.config.sendDefaultPii });
|
|
2307
|
+
const traceCtx = {};
|
|
2308
|
+
if (payload.traceId) traceCtx.trace_id = payload.traceId;
|
|
2309
|
+
if (payload.spanId) traceCtx.span_id = payload.spanId;
|
|
2310
|
+
if (payload.parentSpanId) traceCtx.parent_span_id = payload.parentSpanId;
|
|
2311
|
+
payload.contexts = {
|
|
2312
|
+
...this.autoContexts,
|
|
2313
|
+
...eff.contexts ?? {},
|
|
2314
|
+
...userCtx ? { user: userCtx } : {},
|
|
2315
|
+
...Object.keys(traceCtx).length > 0 ? { trace: traceCtx } : {}
|
|
2316
|
+
};
|
|
2317
|
+
payload.tags = {
|
|
2318
|
+
...this.autoTags,
|
|
2319
|
+
...this.config.tags ?? {},
|
|
2320
|
+
...eff.tags ?? {},
|
|
2321
|
+
environment: this.config.environment ?? "production",
|
|
2322
|
+
...this.config.release ? { release: this.config.release } : {},
|
|
2323
|
+
...this.config.dist ? { dist: this.config.dist } : {}
|
|
2324
|
+
};
|
|
1968
2325
|
const flatPresent = this.config.captureScreenshotOnError === true;
|
|
1969
2326
|
const callbackPresent = Boolean(this.config.screenshot?.provider);
|
|
1970
2327
|
warnIfBothApisPresent(callbackPresent, flatPresent);
|
|
@@ -2122,16 +2479,59 @@ var AllStakClient = class {
|
|
|
2122
2479
|
}
|
|
2123
2480
|
}
|
|
2124
2481
|
addBreadcrumb(type, message, level, data) {
|
|
2125
|
-
|
|
2482
|
+
let crumb = {
|
|
2126
2483
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2127
2484
|
type: VALID_BREADCRUMB_TYPES.has(type) ? type : "default",
|
|
2128
2485
|
message,
|
|
2129
2486
|
level: level && VALID_BREADCRUMB_LEVELS.has(level) ? level : "info",
|
|
2130
2487
|
...data ? { data } : {}
|
|
2131
2488
|
};
|
|
2489
|
+
if (crumb.type === "http" && (this.config.denyUrls || this.config.allowUrls)) {
|
|
2490
|
+
const url = typeof crumb.data?.url === "string" ? crumb.data.url : "";
|
|
2491
|
+
if (url) {
|
|
2492
|
+
if (this.config.denyUrls && this.config.denyUrls.some((p) => matchUrlPattern(url, p))) return;
|
|
2493
|
+
if (this.config.allowUrls && this.config.allowUrls.length > 0 && !this.config.allowUrls.some((p) => matchUrlPattern(url, p))) return;
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
if (crumb.data && this.config.scrubKeys && this.config.scrubKeys.length > 0) {
|
|
2497
|
+
crumb = { ...crumb, data: scrubObject(crumb.data, this.config.scrubKeys) };
|
|
2498
|
+
}
|
|
2499
|
+
if (this.config.beforeBreadcrumb) {
|
|
2500
|
+
try {
|
|
2501
|
+
const out = this.config.beforeBreadcrumb(crumb);
|
|
2502
|
+
if (out === null) return;
|
|
2503
|
+
if (out) crumb = out;
|
|
2504
|
+
} catch {
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2132
2507
|
if (this.breadcrumbs.length >= this.maxBreadcrumbs) this.breadcrumbs.shift();
|
|
2133
2508
|
this.breadcrumbs.push(crumb);
|
|
2134
2509
|
}
|
|
2510
|
+
/**
|
|
2511
|
+
* Set the current screen / route name. Stamps `transaction` on every
|
|
2512
|
+
* subsequent event and emits a `navigation` breadcrumb. Use this when
|
|
2513
|
+
* not on `@react-navigation/native` (the nav auto-instrument calls
|
|
2514
|
+
* this for you).
|
|
2515
|
+
*/
|
|
2516
|
+
setCurrentScreen(name) {
|
|
2517
|
+
if (!name) return;
|
|
2518
|
+
const prev = this.currentTransaction;
|
|
2519
|
+
this.currentTransaction = name;
|
|
2520
|
+
if (prev !== name) {
|
|
2521
|
+
this.addBreadcrumb("navigation", `${prev ?? "<start>"} -> ${name}`, "info", {
|
|
2522
|
+
from: prev,
|
|
2523
|
+
to: name
|
|
2524
|
+
});
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
/** @internal — current transaction (or undefined). */
|
|
2528
|
+
getCurrentTransaction() {
|
|
2529
|
+
return this.currentTransaction ?? void 0;
|
|
2530
|
+
}
|
|
2531
|
+
/** @internal — set transaction without emitting a breadcrumb. */
|
|
2532
|
+
__setTransactionSilent(name) {
|
|
2533
|
+
this.currentTransaction = name && name.length > 0 ? name : null;
|
|
2534
|
+
}
|
|
2135
2535
|
clearBreadcrumbs() {
|
|
2136
2536
|
this.breadcrumbs = [];
|
|
2137
2537
|
}
|
|
@@ -2412,9 +2812,9 @@ var AllStak = {
|
|
|
2412
2812
|
return instance;
|
|
2413
2813
|
}
|
|
2414
2814
|
},
|
|
2415
|
-
captureException(error, context) {
|
|
2815
|
+
captureException(error, context, opts) {
|
|
2416
2816
|
try {
|
|
2417
|
-
maybeInit()?.captureException(error, context);
|
|
2817
|
+
maybeInit()?.captureException(error, context, opts);
|
|
2418
2818
|
} catch {
|
|
2419
2819
|
}
|
|
2420
2820
|
},
|
|
@@ -2497,6 +2897,27 @@ var AllStak = {
|
|
|
2497
2897
|
} catch {
|
|
2498
2898
|
}
|
|
2499
2899
|
},
|
|
2900
|
+
/** Set the current screen / transaction name. Stamps event.transaction + emits nav breadcrumb. */
|
|
2901
|
+
setCurrentScreen(name) {
|
|
2902
|
+
try {
|
|
2903
|
+
maybeInit()?.setCurrentScreen(name);
|
|
2904
|
+
} catch {
|
|
2905
|
+
}
|
|
2906
|
+
},
|
|
2907
|
+
getCurrentTransaction() {
|
|
2908
|
+
try {
|
|
2909
|
+
return maybeInit()?.getCurrentTransaction();
|
|
2910
|
+
} catch {
|
|
2911
|
+
return void 0;
|
|
2912
|
+
}
|
|
2913
|
+
},
|
|
2914
|
+
/** @internal — set transaction without emitting a breadcrumb (nav auto-instrument uses this). */
|
|
2915
|
+
__setTransactionSilent(name) {
|
|
2916
|
+
try {
|
|
2917
|
+
maybeInit()?.__setTransactionSilent(name);
|
|
2918
|
+
} catch {
|
|
2919
|
+
}
|
|
2920
|
+
},
|
|
2500
2921
|
/**
|
|
2501
2922
|
* Run `callback` with a fresh scoped context. Any user/tag/extra/context/
|
|
2502
2923
|
* fingerprint/level set on the passed `Scope` is visible only inside the
|
|
@@ -2586,6 +3007,29 @@ var AllStak = {
|
|
|
2586
3007
|
return instance;
|
|
2587
3008
|
}
|
|
2588
3009
|
};
|
|
3010
|
+
function matchUrlPattern(url, p) {
|
|
3011
|
+
if (!url || !p) return false;
|
|
3012
|
+
if (typeof p === "string") return url.includes(p);
|
|
3013
|
+
try {
|
|
3014
|
+
return p.test(url);
|
|
3015
|
+
} catch {
|
|
3016
|
+
return false;
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
function scrubObject(obj, keys) {
|
|
3020
|
+
if (!obj || keys.length === 0) return obj;
|
|
3021
|
+
const out = {};
|
|
3022
|
+
const lower = new Set(keys.map((k) => k.toLowerCase()));
|
|
3023
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
3024
|
+
out[k] = lower.has(k.toLowerCase()) ? "[Filtered]" : v;
|
|
3025
|
+
}
|
|
3026
|
+
return out;
|
|
3027
|
+
}
|
|
3028
|
+
function generateEventId() {
|
|
3029
|
+
const hex = (n) => Math.floor(Math.random() * n).toString(16).padStart(1, "0");
|
|
3030
|
+
const seg = (len) => Array.from({ length: len }, () => hex(16)).join("");
|
|
3031
|
+
return `${seg(8)}-${seg(4)}-4${seg(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${seg(3)}-${seg(12)}`;
|
|
3032
|
+
}
|
|
2589
3033
|
function byteSize(value) {
|
|
2590
3034
|
if (!value) return 0;
|
|
2591
3035
|
try {
|
|
@@ -2790,6 +3234,10 @@ function instrumentReactNavigation(navigationRef, options = {}) {
|
|
|
2790
3234
|
);
|
|
2791
3235
|
} catch {
|
|
2792
3236
|
}
|
|
3237
|
+
try {
|
|
3238
|
+
AllStak.__setTransactionSilent?.(next);
|
|
3239
|
+
} catch {
|
|
3240
|
+
}
|
|
2793
3241
|
if (forwardToReplay) {
|
|
2794
3242
|
try {
|
|
2795
3243
|
const replay = AllStak.getReplay?.();
|
|
@@ -3029,7 +3477,7 @@ function installReactNative(options = {}) {
|
|
|
3029
3477
|
AllStak.captureException(error, {
|
|
3030
3478
|
source: "react-native-ErrorUtils",
|
|
3031
3479
|
fatal: String(Boolean(isFatal))
|
|
3032
|
-
});
|
|
3480
|
+
}, { mechanism: "onerror", handled: false });
|
|
3033
3481
|
} catch {
|
|
3034
3482
|
}
|
|
3035
3483
|
try {
|
|
@@ -3043,7 +3491,11 @@ function installReactNative(options = {}) {
|
|
|
3043
3491
|
const wrapTrackerReason = (rejection) => rejection instanceof Error ? rejection : new Error(`Unhandled promise rejection: ${String(rejection)}`);
|
|
3044
3492
|
const ship = (err) => {
|
|
3045
3493
|
try {
|
|
3046
|
-
AllStak.captureException(
|
|
3494
|
+
AllStak.captureException(
|
|
3495
|
+
err,
|
|
3496
|
+
{ source: "unhandledRejection" },
|
|
3497
|
+
{ mechanism: "onunhandledrejection", handled: false }
|
|
3498
|
+
);
|
|
3047
3499
|
} catch {
|
|
3048
3500
|
}
|
|
3049
3501
|
};
|
|
@@ -3107,7 +3559,7 @@ var AllStakErrorBoundary = class extends React2.Component {
|
|
|
3107
3559
|
AllStak.captureException(error, {
|
|
3108
3560
|
componentStack: info.componentStack ?? "",
|
|
3109
3561
|
source: "AllStakProvider.ErrorBoundary"
|
|
3110
|
-
});
|
|
3562
|
+
}, { mechanism: "errorboundary", handled: true });
|
|
3111
3563
|
if (this.props.debug) {
|
|
3112
3564
|
console.log(`[AllStak] Captured render error: ${error.message}`);
|
|
3113
3565
|
}
|
|
@@ -3225,6 +3677,10 @@ function AllStakProvider({
|
|
|
3225
3677
|
};
|
|
3226
3678
|
clientRef.current = AllStak.init(config);
|
|
3227
3679
|
__providerOwnedInstance = clientRef.current;
|
|
3680
|
+
try {
|
|
3681
|
+
AllStak.addBreadcrumb("default", "app.start", "info", { source: "AllStakProvider" });
|
|
3682
|
+
} catch {
|
|
3683
|
+
}
|
|
3228
3684
|
installReactNative({
|
|
3229
3685
|
autoErrorHandler,
|
|
3230
3686
|
autoPromiseRejections,
|
|
@@ -3318,7 +3774,7 @@ async function drainPendingNativeCrashes(release) {
|
|
|
3318
3774
|
AllStak.captureException(err, {
|
|
3319
3775
|
...payload?.metadata || {},
|
|
3320
3776
|
"native.crash": "true"
|
|
3321
|
-
});
|
|
3777
|
+
}, { mechanism: "native_crash", handled: false });
|
|
3322
3778
|
} catch {
|
|
3323
3779
|
}
|
|
3324
3780
|
}
|
|
@@ -3353,23 +3809,30 @@ export {
|
|
|
3353
3809
|
__resetRuntimeModeForTest,
|
|
3354
3810
|
__setNativeModuleForTest,
|
|
3355
3811
|
applyArchitectureTags,
|
|
3812
|
+
buildExceptionChain,
|
|
3813
|
+
buildUserContext,
|
|
3356
3814
|
captureBodyResult,
|
|
3357
3815
|
captureViaViewShot,
|
|
3816
|
+
classifyHttpError,
|
|
3817
|
+
collectAutoContexts,
|
|
3358
3818
|
detectArchitecture,
|
|
3359
3819
|
detectRuntimeMode,
|
|
3360
3820
|
drainPendingNativeCrashes,
|
|
3821
|
+
extractAxiosRequest,
|
|
3361
3822
|
installReactNative,
|
|
3362
3823
|
instrumentNavigationFromLinking,
|
|
3363
3824
|
instrumentReactNavigation,
|
|
3364
3825
|
isCapturingScreenshot,
|
|
3365
3826
|
isViewShotAvailable,
|
|
3366
3827
|
maybeCaptureScreenshot,
|
|
3828
|
+
maybeExtractHttpRequest,
|
|
3367
3829
|
pickScreenshotConfig,
|
|
3368
3830
|
redactUrl,
|
|
3369
3831
|
registerSensitiveRef,
|
|
3370
3832
|
resolveScreenshotConfig,
|
|
3371
3833
|
runtimeAllowsScreenshot,
|
|
3372
3834
|
sanitizeHeaders,
|
|
3835
|
+
sanitizeUrl,
|
|
3373
3836
|
tryAutoInstrumentNavigation,
|
|
3374
3837
|
useAllStak,
|
|
3375
3838
|
useAllStakPrivacy
|