@allstak/react-native 0.3.4 → 0.4.1

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 CHANGED
@@ -5,6 +5,59 @@ All notable changes to `@allstak/react-native` are documented in this file.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.1] — 2026-05-18
9
+
10
+ ### Fixed
11
+
12
+ - Masking primitives (`AllStakMaskedView`, `AllStakPrivacyView`,
13
+ `AllStakTextInput`, `AllStakSensitiveText`) now resolve the
14
+ `react-native` module reference lazily at render time instead of
15
+ at module-load time. Caught during simulator cert: Metro bundles
16
+ `react-native` separately from the SDK, so a top-of-file
17
+ `require('react-native')` could resolve to a stale stub and cause
18
+ `View config getter callback for component TextInput must be a function`
19
+ red-screens in dev. Render-time resolution fixes this on every
20
+ Metro reload.
21
+ - Provider's root-view wrapper uses the same lazy resolution.
22
+
23
+ ## [0.4.0] — 2026-05-18
24
+
25
+ ### Added
26
+
27
+ - **Flat screenshot API** on `AllStakProvider` and `AllStak.init()`:
28
+ `captureScreenshotOnError`, `screenshotRedaction`,
29
+ `screenshotMaskStyle`, `screenshotMaxBytes`, `screenshotQuality`,
30
+ `screenshotFormat`, `screenshotSampleRate`,
31
+ `screenshotOnUnhandledOnly`, `screenshotUploadTimeoutMs`,
32
+ `screenshotCaptureTimeoutMs`, `screenshotNativeMode`,
33
+ `screenshotFailPolicy`, `beforeScreenshotCapture`,
34
+ `beforeScreenshotUpload`, `isScreenshotAllowed`. Matches the props
35
+ the AllStak wizard (`@allstak/wizard@>=0.1.16`) writes — no manual
36
+ callback wiring required.
37
+ - **Masking primitives** for privacy-safe captures:
38
+ `AllStakMaskedView`, `AllStakPrivacyView`, `AllStakTextInput`,
39
+ `AllStakSensitiveText`, plus the `useAllStakPrivacy()` hook.
40
+ - **Native capture via `react-native-view-shot`** as an optional peer
41
+ dependency. The SDK lazy-requires it; absence is a silent no-op
42
+ (event still ships).
43
+ - **Runtime detection** (`detectRuntimeMode`): `expo-go` |
44
+ `expo-dev-client` | `rn-cli` | `unknown`. Expo Go is detected and
45
+ screenshots are skipped silently with status
46
+ `screenshot.status: unsupported_runtime`.
47
+ - **Attachment upload pipeline** posts the captured image to
48
+ `POST /ingest/v1/errors/{eventId}/attachments` (JSON / base64 wire
49
+ format) with capture metadata. Bounded retries, per-attempt timeout,
50
+ fail-open at every step.
51
+
52
+ ### Changed
53
+
54
+ - `AllStakProvider` now wraps `children` in a ref'd root view so
55
+ view-shot can capture by reference. Backward-compatible.
56
+ - The callback-based `config.screenshot.provider` API from 0.3.x is
57
+ retained for backward compatibility; if both APIs are configured the
58
+ flat API wins and a one-time deprecation warning is logged.
59
+ - Bumped `SDK_VERSION` to `0.4.0`.
60
+
8
61
  ## [0.3.1] — 2026-05-11
9
62
 
10
63
  ### Added
package/README.md CHANGED
@@ -1,156 +1,459 @@
1
1
  # @allstak/react-native
2
2
 
3
- AllStak React Native SDK for Expo and React Native CLI apps. It captures JavaScript errors, render errors, unhandled promises where available, breadcrumbs, HTTP metadata, release/environment/device tags, user context, and native crashes when native modules are linked in a dev client or native build.
3
+ AllStak's React Native SDK captures JS errors, render errors, unhandled promises, logs, HTTP breadcrumbs/events, navigation breadcrumbs, device tags, and source maps from React Native apps.
4
4
 
5
- Stability: beta. Live dashboard certification and native crash proof are not claimed until verified with real credentials and a native build.
5
+ Use one wrapper, keep privacy-first defaults, support Hermes, and upload React Native source maps through build hooks instead of manual release chores.
6
6
 
7
- ## 1. Automatic Setup With Wizard
7
+ [![npm version](https://img.shields.io/npm/v/@allstak/react-native.svg)](https://www.npmjs.com/package/@allstak/react-native)
8
+ [![CI](https://github.com/AllStak/allstak-react-native/actions/workflows/ci.yml/badge.svg)](https://github.com/AllStak/allstak-react-native/actions)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
10
 
9
- Recommended flow:
11
+ ## 1. Overview
12
+
13
+ Use `@allstak/react-native` when you want production mobile error context without wiring several separate tools: a provider-first setup, automatic JS/runtime capture, privacy-safe breadcrumbs, Hermes-aware tags, and source-map upload through EAS, Gradle, Xcode, or custom CI build hooks.
14
+
15
+ ## 2. Installation
10
16
 
11
17
  ```bash
12
- npx @allstak/wizard setup --integration react-native
18
+ npm install @allstak/react-native
13
19
  ```
14
20
 
15
- For Expo managed projects, this also patches static `app.json` plugin config. The only value you may need to enter is the AllStak ingest API key.
21
+ Peer expectations:
16
22
 
17
- ## 2. What The Wizard Changes
23
+ | Peer | Supported |
24
+ | --- | --- |
25
+ | React | `>=16.8.0` |
26
+ | React Native | `>=0.70` |
27
+ | Expo | Supported in Expo apps. Expo Go can use the JS SDK paths; native crash capture requires native modules in a dev client or native build. |
18
28
 
19
- The wizard:
29
+ The published package is standalone: no browser DOM, Node runtime, or `@allstak/js` dependency is required.
20
30
 
21
- - Installs `@allstak/react-native`.
22
- - Detects Expo managed, Expo bare/prebuilt, and React Native CLI projects.
23
- - Writes managed `ALLSTAK_*` and `EXPO_PUBLIC_ALLSTAK_*` env vars.
24
- - Detects `App.tsx`, `App.jsx`, `App.ts`, `App.js`, `src/App.*`, or root `index.*`.
25
- - Wraps the app root with `AllStakProvider`.
26
- - Preserves existing providers and app content.
27
- - Adds package scripts for verification and source-map upload.
28
- - Adds `@allstak/react-native` to `app.json expo.plugins[]` when a static Expo config exists.
29
- - Leaves native linking to React Native autolinking; no manual linking is required for standard RN CLI/dev-client builds.
30
- - Supports dry-run, repair, idempotent re-runs, and uninstall.
31
+ ## 3. Quick Start — Provider-first
31
32
 
32
- ## 3. Verification
33
+ Provider-first setup is the recommended path.
33
34
 
34
- After setup:
35
+ ```tsx
36
+ import { AllStakProvider } from "@allstak/react-native";
35
37
 
36
- ```bash
37
- npm run allstak:verify
38
- npx @allstak/wizard doctor --integration react-native
38
+ export default function App() {
39
+ return (
40
+ <AllStakProvider
41
+ apiKey="ask_live_..."
42
+ environment="production"
43
+ release="mobile@1.0.0+1"
44
+ dist="ios-hermes"
45
+ debug
46
+ >
47
+ <AppRoot />
48
+ </AllStakProvider>
49
+ );
50
+ }
39
51
  ```
40
52
 
41
- For Expo:
53
+ `AllStakProvider` automatically:
42
54
 
43
- ```bash
44
- npx expo config --type public
55
+ - initializes the SDK
56
+ - installs React Native integrations
57
+ - wraps children with an error boundary
58
+ - captures render errors
59
+ - captures global JS errors through `ErrorUtils`
60
+ - captures unhandled promise rejections, including Hermes-native promise rejections
61
+ - attaches platform, device, architecture, Hermes, release, dist, and environment tags
62
+ - installs console, HTTP, XHR, fetch, and AppState breadcrumbs according to config
63
+ - attempts navigation auto-instrumentation when possible
64
+
65
+ Navigation note: Metro/React Native static bundling currently prevents the SDK from guaranteeing automatic React Navigation patching in normal native Metro builds. The provider logs the status when `debug` is enabled. Use `instrumentReactNavigation(navigationRef)` when you need guaranteed navigation breadcrumbs.
66
+
67
+ ## 4. Verify It Works
68
+
69
+ Add a temporary test button or run these snippets after the provider has mounted:
70
+
71
+ ```tsx
72
+ import { AllStak } from "@allstak/react-native";
73
+
74
+ AllStak.captureException(new Error("AllStak test error"));
75
+ AllStak.captureMessage("AllStak test log");
76
+ console.warn("AllStak warning breadcrumb");
77
+ Promise.reject(new Error("AllStak unhandled rejection test"));
45
78
  ```
46
79
 
47
- For RN CLI, run your normal TypeScript/build checks. Dashboard delivery requires real credentials and must be verified in AllStak.
80
+ Expected result:
81
+
82
+ - with `debug`, Metro shows `[AllStak] Initialized — session <id>`
83
+ - the manual error appears in the AllStak dashboard
84
+ - the message appears as a log event
85
+ - the warning is attached as a breadcrumb to the next captured error
86
+ - the unhandled rejection is captured with `metadata.source = "unhandledRejection"`
87
+
88
+ ## 5. Automatic Capture Matrix
89
+
90
+ | Feature | Default | Config | Status | Notes |
91
+ | --- | --- | --- | --- | --- |
92
+ | Render errors | On with provider | `fallback`, `onError`; manual setup skips the boundary | Verified on iOS simulator | Captured with `metadata.source = "AllStakProvider.ErrorBoundary"` and component stack. |
93
+ | Global JS errors | On | `autoErrorHandler` | Verified on iOS simulator; unit-tested elsewhere | Uses `ErrorUtils.setGlobalHandler`. |
94
+ | Unhandled promises | On | `autoPromiseRejections` | Verified on iOS simulator | Uses Hermes rejection tracker plus polyfill/browser fallbacks. |
95
+ | Manual `captureException` | Manual | `AllStak.captureException(error)` | Verified on iOS simulator and backend contract tests | Posts to `/ingest/v1/errors`. |
96
+ | Manual `captureMessage` | Manual | `AllStak.captureMessage(message, level?)` | Verified on iOS simulator and backend contract tests | Info/warn go to logs; error/fatal also create error events. |
97
+ | `console.warn` / `console.error` | On | `autoConsoleBreadcrumbs`, `captureConsole` | Verified on iOS simulator | Breadcrumbs only; original console methods still run. |
98
+ | `console.log` / `console.info` | Off | `captureConsole={{ log: true, info: true }}` | Verified on iOS simulator | Opt-in only to avoid noisy dashboards. |
99
+ | Fetch breadcrumbs | On | `autoFetchBreadcrumbs` | Verified on iOS simulator | Query strings are stripped from breadcrumb URLs. |
100
+ | XHR breadcrumbs | On | `autoNetworkCapture` | Unit-tested; RN fetch is XHR-based in many setups | Skips AllStak ingest host to avoid recursion. |
101
+ | HTTP 4xx/5xx | On for breadcrumbs | `autoFetchBreadcrumbs`, `autoNetworkCapture` | Verified on iOS simulator | Error-level breadcrumb for status `>=400`. |
102
+ | Network failures | On for breadcrumbs | `autoFetchBreadcrumbs`, `autoNetworkCapture` | Verified on iOS simulator | Records failed request breadcrumb and rethrows original error. |
103
+ | Full HTTP request events | Off | `enableHttpTracking`, `httpTracking` | Verified on iOS simulator | Posts to `/ingest/v1/http_requests`; headers/bodies off by default. |
104
+ | AppState breadcrumbs | On | `autoAppStateBreadcrumbs` | Listener verified; OS transitions not fully scripted | Foreground/background transition testing is environment-dependent. |
105
+ | Navigation breadcrumbs | Best effort automatic, manual fallback guaranteed | `autoNavigationBreadcrumbs`, `instrumentReactNavigation(ref)` | Manual path verified on iOS simulator; auto path unit-tested under Node; Metro native auto-patch intentionally falls back | Use manual ref instrumentation for guaranteed React Navigation breadcrumbs. |
106
+ | Device/platform tags | On | `autoDeviceTags` | Verified on iOS simulator | Adds `device.os`, `device.osVersion`, `device.model` where available. |
107
+ | Hermes detection | On | automatic | Verified on iOS simulator | Adds `rn.hermes` and selects `ios-hermes` / `android-hermes` dist when possible. |
108
+ | Release/dist/environment tags | Environment defaults to `production`; release is caller-supplied; dist auto-detected unless overridden | `environment`, `release`, `dist` | Verified on iOS simulator | `release` and `dist` must match uploaded source maps for symbolication. |
109
+ | Native iOS crashes | Manual drain API; native module must be linked | `drainPendingNativeCrashes(release?)` | Verified on iOS simulator | Crash is stored by native handler and sent on next launch. Provider does not call this automatically. |
110
+ | Native Android crashes | Manual drain API; native module must be linked | `drainPendingNativeCrashes(release?)` | Implemented, not emulator/device verified | Android native module and dev crash trigger exist; emulator verification was blocked by disk in latest report. |
111
+ | Offline queue | On, in-memory only | transport internal | Backend-contract verified | Buffered retry works while process lives; events are lost after app restart. |
112
+ | Source maps | Build-time hook | EAS, Gradle, Xcode, or custom CI hooks | Build hooks implemented; backend upload path exists | Hooks inject `debugId` and upload maps. End-to-end Hermes symbolication still depends on matching release/dist/debugId. |
113
+
114
+ ## 6. Configuration Reference
115
+
116
+ `AllStakProvider` accepts the SDK config and React Native integration flags:
117
+
118
+ | Prop | Type | Default | Notes |
119
+ | --- | --- | --- | --- |
120
+ | `apiKey` | `string` | required | Runtime project API key such as `ask_live_...`. Not the source-map upload token. |
121
+ | `environment` | `string` | `"production"` | Attached to errors, logs, spans, and HTTP events. |
122
+ | `release` | `string` | unset | App release, for example `mobile@1.2.3+45`. Required for source-map matching. |
123
+ | `dist` | `string` | auto-detected | Override build flavor, for example `android-hermes`. |
124
+ | `debug` | `boolean` | `false` | Prints SDK init and selected integration status logs. |
125
+ | `fallback` | `ReactNode` or function | `null` on render error | Error boundary fallback UI. |
126
+ | `onError` | function | unset | Called after render error capture. |
127
+ | `destroyOnUnmount` | `boolean` | `false` | Keep `false` for app roots, Fast Refresh, and Strict Mode. |
128
+ | `captureConsole` | object | `{ warn: true, error: true, log: false, info: false }` | Per-method console breadcrumb flags. |
129
+ | `autoConsoleBreadcrumbs` | `boolean` | `true` | Kill switch for console wrapping. |
130
+ | `autoFetchBreadcrumbs` | `boolean` | `true` | Wraps `fetch` for HTTP breadcrumbs. |
131
+ | `autoNetworkCapture` | `boolean` | `true` | Wraps `XMLHttpRequest` for network breadcrumbs. |
132
+ | `enableHttpTracking` | `boolean` | `false` | Enables full HTTP request events. |
133
+ | `httpTracking` | `HttpTrackingOptions` | privacy-first defaults | Controls body/header capture, redaction, ignore lists, and byte limits. |
134
+ | `autoAppStateBreadcrumbs` | `boolean` | `true` | Captures AppState changes as breadcrumbs. |
135
+ | `autoDeviceTags` | `boolean` | `true` | Captures platform/device tags. |
136
+ | `autoNavigationBreadcrumbs` | `boolean` | `true` | Best-effort auto navigation patch; manual fallback is recommended for Metro-native builds. |
137
+
138
+ Common optional props also supported by the underlying client include `host`, `user`, `tags`, `sampleRate`, `beforeSend`, `tracesSampleRate`, `service`, and `replay`.
48
139
 
49
- ## 4. Rollback / Uninstall
140
+ ```tsx
141
+ <AllStakProvider
142
+ apiKey="ask_live_..."
143
+ environment="production"
144
+ release="mobile@1.2.3+45"
145
+ dist="android-hermes"
146
+ captureConsole={{ log: true, info: true }}
147
+ enableHttpTracking
148
+ >
149
+ <AppRoot />
150
+ </AllStakProvider>
151
+ ```
50
152
 
51
- ```bash
52
- npx @allstak/wizard uninstall --integration react-native
153
+ HTTP tracking defaults are intentionally conservative. Request bodies, response bodies, and headers are not captured unless explicitly enabled. Sensitive headers and query parameters are still redacted even when header/body capture is enabled.
154
+
155
+ ## 7. Manual / Advanced API
156
+
157
+ ```ts
158
+ import {
159
+ AllStak,
160
+ instrumentReactNavigation,
161
+ drainPendingNativeCrashes,
162
+ } from "@allstak/react-native";
163
+
164
+ AllStak.captureException(error);
165
+ AllStak.captureMessage("message");
166
+ AllStak.addBreadcrumb("ui", "Tapped checkout", "info", { screen: "Checkout" });
167
+ AllStak.setUser({ id: "user_123", email: "user@example.com" });
168
+ AllStak.setTag("key", "value");
169
+ AllStak.setContext("device", { model: "simulator" });
170
+ await AllStak.flush();
171
+ AllStak.destroy();
53
172
  ```
54
173
 
55
- Uninstall removes wizard-managed env blocks, package scripts, Expo plugin entries, imports, and provider wrappers. User-owned code outside wizard-managed setup is preserved.
174
+ Other advanced APIs include `setTags`, `setExtra`, `setExtras`, `setLevel`, `setFingerprint`, `withScope`, tracing helpers, `getReplay`, and manual `instrumentAxios`.
56
175
 
57
- ## 5. Manual Setup Fallback
176
+ Manual setup is available when you need full initialization control:
58
177
 
59
- Use manual setup only when the wizard cannot safely patch a custom root:
178
+ ```ts
179
+ import { AllStak, installReactNative } from "@allstak/react-native";
60
180
 
61
- ```bash
62
- npm install @allstak/react-native
181
+ AllStak.init({
182
+ apiKey: "ask_live_...",
183
+ environment: "production",
184
+ release: "mobile@1.2.3+45",
185
+ });
186
+
187
+ installReactNative();
63
188
  ```
64
189
 
190
+ Manual navigation fallback:
191
+
65
192
  ```tsx
66
- import { AllStakProvider } from '@allstak/react-native';
193
+ import { NavigationContainer, useNavigationContainerRef } from "@react-navigation/native";
194
+ import { instrumentReactNavigation } from "@allstak/react-native";
195
+
196
+ export function AppNavigation() {
197
+ const navigationRef = useNavigationContainerRef();
67
198
 
68
- export default function App() {
69
199
  return (
70
- <AllStakProvider
71
- apiKey={process.env.EXPO_PUBLIC_ALLSTAK_API_KEY ?? process.env.ALLSTAK_API_KEY}
72
- host={process.env.EXPO_PUBLIC_ALLSTAK_HOST ?? process.env.ALLSTAK_HOST}
73
- environment={process.env.EXPO_PUBLIC_ALLSTAK_ENVIRONMENT ?? 'production'}
74
- release={process.env.EXPO_PUBLIC_ALLSTAK_RELEASE ?? process.env.ALLSTAK_RELEASE}
75
- enableHttpTracking
200
+ <NavigationContainer
201
+ ref={navigationRef}
202
+ onReady={() => instrumentReactNavigation(navigationRef)}
76
203
  >
77
- {/* app */}
78
- </AllStakProvider>
204
+ {/* navigators */}
205
+ </NavigationContainer>
79
206
  );
80
207
  }
81
208
  ```
82
209
 
83
- Manual capture:
210
+ Auto navigation works only where the SDK can safely patch `@react-navigation/native`. In normal Metro-native builds, manual ref instrumentation is the guaranteed path.
84
211
 
85
- ```ts
86
- import { AllStak } from '@allstak/react-native';
212
+ ## 8. Source Maps — automatic via build hooks
213
+
214
+ React Native source maps become hands-off after adding one build hook for your build system. The hook injects a `debugId` into both the JS bundle and source map, then uploads the map to AllStak.
215
+
216
+ ### EAS / Expo
217
+
218
+ Add the AllStak config plugin to your `app.json` (or `app.config.js`):
219
+
220
+ ```json
221
+ {
222
+ "expo": {
223
+ "plugins": ["@allstak/react-native"]
224
+ }
225
+ }
226
+ ```
227
+
228
+ Then add the EAS post-build hook:
87
229
 
88
- AllStak.captureException(new Error('mobile failure'));
89
- AllStak.captureMessage('checkout opened');
90
- AllStak.setUser({ id: 'user_123' });
91
- AllStak.addBreadcrumb({ type: 'navigation', message: 'Checkout' });
230
+ ```json
231
+ {
232
+ "scripts": {
233
+ "eas-build-on-success": "node ./node_modules/@allstak/react-native/build-hooks/eas-post-bundle.js"
234
+ }
235
+ }
92
236
  ```
93
237
 
94
- ## 6. Configuration
238
+ Required environment:
95
239
 
96
- Provider props include:
240
+ - `ALLSTAK_UPLOAD_TOKEN`
241
+ - `ALLSTAK_RELEASE`
242
+ - `ALLSTAK_API_URL` optional, defaults to AllStak production API
97
243
 
98
- | Option | Default | Notes |
99
- | --- | --- | --- |
100
- | `apiKey` | required | Public mobile ingest key. |
101
- | `host` | `https://api.allstak.sa` | Override for self-hosted ingest. |
102
- | `environment` | `production` | Release environment tag. |
103
- | `release` | unset | App version or build number. |
104
- | `debug` | `false` | Enables SDK diagnostic logs. |
105
- | `enableHttpTracking` | `false` | Captures HTTP metadata with redaction. |
106
- | `autoCaptureJsErrors` | `true` | Captures ErrorUtils/global JS errors where available. |
107
- | `autoUnhandledRejections` | `true` | Captures promise rejections where supported. |
108
- | `captureConsole` | warn/error on | `log`/`info` stay off by default. |
109
- | `beforeSend` | unset | Last-chance scrub/drop hook. |
244
+ `ALLSTAK_UPLOAD_TOKEN` is a project-scoped upload token from Project Settings. It is not the runtime `apiKey`.
110
245
 
111
- ## 7. Privacy / PII / Redaction
246
+ ### Android Gradle
112
247
 
113
- Defaults are privacy-first:
248
+ Add this to `android/app/build.gradle` after the React Native Gradle plugin setup:
114
249
 
115
- - Authorization, cookie, API key, token, and secret headers are always redacted.
116
- - Sensitive query parameters are redacted.
117
- - Request/response body capture is disabled unless explicitly enabled.
118
- - Recursive JSON body redaction is available when body capture is enabled.
119
- - Queue size is capped and transport failures fail open.
120
- - Use `beforeSend` for app-specific PII removal.
250
+ ```groovy
251
+ apply from: "../../node_modules/@allstak/react-native/build-hooks/allstak-sourcemaps.gradle"
252
+ ```
121
253
 
122
- Do not send passwords, payment data, national IDs, raw tokens, or raw request/response bodies unless you have verified redaction in your app.
254
+ Supported Gradle properties / environment:
123
255
 
124
- ## 8. Source Maps / Releases
256
+ - `ALLSTAK_UPLOAD_TOKEN` or `allstakUploadToken`
257
+ - `ALLSTAK_RELEASE` or `allstakRelease`
258
+ - optional API URL override when self-hosting
125
259
 
126
- The wizard adds:
260
+ Then run your normal release task, for example:
127
261
 
128
262
  ```bash
129
- npm run allstak:sourcemaps
263
+ cd android
264
+ ./gradlew :app:bundleRelease
130
265
  ```
131
266
 
132
- Set the same release in your app and source-map upload:
267
+ ### iOS Xcode Build Phase
268
+
269
+ Add a Run Script build phase after "Bundle React Native code and images":
270
+
271
+ ```sh
272
+ "${SRCROOT}/../node_modules/@allstak/react-native/build-hooks/xcode-build-phase.sh"
273
+ ```
274
+
275
+ Set these in the build phase, `.xcconfig`, or CI shell:
276
+
277
+ ```sh
278
+ ALLSTAK_UPLOAD_TOKEN=aspk_...
279
+ ALLSTAK_RELEASE=mobile@1.2.3+45
280
+ ```
281
+
282
+ The script is designed for release builds; debug builds should not upload source maps.
283
+
284
+ ### Custom CI
133
285
 
134
286
  ```bash
135
- export ALLSTAK_RELEASE=my-app@1.2.3
136
- export ALLSTAK_SOURCEMAP_TOKEN=...
137
- npm run allstak:sourcemaps
287
+ node ./node_modules/@allstak/react-native/build-hooks/upload-sourcemaps.js \
288
+ --platform ios \
289
+ --bundle path/to/main.jsbundle \
290
+ --sourcemap path/to/main.jsbundle.map \
291
+ --release mobile@1.2.3+45 \
292
+ --dist ios-hermes
293
+ ```
294
+
295
+ Programmatic API:
296
+
297
+ ```js
298
+ const { uploadReactNativeSourcemap } = require("@allstak/react-native/sourcemaps");
299
+
300
+ await uploadReactNativeSourcemap({
301
+ platform: "ios",
302
+ bundle: "path/to/main.jsbundle",
303
+ sourcemap: "path/to/main.jsbundle.map",
304
+ release: "mobile@1.2.3+45",
305
+ dist: "ios-hermes",
306
+ token: process.env.ALLSTAK_UPLOAD_TOKEN,
307
+ });
308
+ ```
309
+
310
+ How matching works:
311
+
312
+ - `debugId` is injected into the bundle and the source map.
313
+ - The backend matches stack frames using `debugId`, `release`, and `dist`.
314
+ - Maps are uploaded to `/api/v1/artifacts/upload`.
315
+ - Upload auth uses `X-AllStak-Upload-Token`; do not use the runtime `ask_live_...` API key.
316
+
317
+ If no upload token is present, the hook can run in inject-only mode so CI can still produce bundles with debug IDs without uploading artifacts.
318
+
319
+ ## 9. Native Crashes
320
+
321
+ JS errors are verified. Native crash files exist for iOS and Android, and the SDK exports a drain API:
322
+
323
+ ```ts
324
+ import { drainPendingNativeCrashes } from "@allstak/react-native";
325
+
326
+ await drainPendingNativeCrashes("mobile@1.2.3+45");
138
327
  ```
139
328
 
140
- Expo EAS users can call the package build hook from their EAS workflow. RN CLI users can call the upload hook after Metro/Hermes source maps are generated.
329
+ The provider does not call `drainPendingNativeCrashes()` automatically. Call it once early after SDK initialization, before user flows start:
330
+
331
+ ```tsx
332
+ import { AllStakProvider, drainPendingNativeCrashes } from "@allstak/react-native";
333
+ import { useEffect } from "react";
334
+
335
+ function AppRoot() {
336
+ useEffect(() => {
337
+ drainPendingNativeCrashes("mobile@1.2.3+45");
338
+ }, []);
339
+
340
+ return <Routes />;
341
+ }
342
+ ```
343
+
344
+ Current verification status:
345
+
346
+ - iOS native crash capture and drain were verified end-to-end on an iOS simulator.
347
+ - Android native crash capture code exists and has parity with iOS, but emulator/device verification was not completed in the latest report.
348
+ - Do not mark Android native crash capture production-ready until an Android emulator or device run proves crash -> relaunch -> drain -> backend ingest.
349
+
350
+ Native modules are not available in Expo Go. Use a dev client or native build for native crash verification.
351
+
352
+ ## 10. Privacy Defaults
353
+
354
+ - Headers are off by default.
355
+ - Request bodies are off by default.
356
+ - Response bodies are off by default.
357
+ - `Authorization`, `Cookie`, `Set-Cookie`, `X-API-Key`, `X-Auth-Token`, and `Proxy-Authorization` are always redacted.
358
+ - Sensitive query parameters such as `token`, `password`, `api_key`, `authorization`, `secret`, `access_token`, `refresh_token`, and `jwt` are redacted.
359
+ - `console.log` and `console.info` are off by default.
360
+ - `console.warn` and `console.error` are captured as breadcrumbs by default.
361
+ - Source maps containing `sourcesContent` may be rejected when organization privacy mode requires stripped sources. Use `stripSources: true` or configure your build hook accordingly.
362
+
363
+ ## 11. Troubleshooting
364
+
365
+ ### Events not appearing
366
+
367
+ - Confirm `apiKey` is the runtime project key and starts with `ask_live_...`.
368
+ - Enable `debug` and check for `[AllStak] Initialized — session <id>`.
369
+ - Confirm the app can reach `https://api.allstak.sa`.
370
+ - For self-hosted installs, pass `host="https://your-api.example.com"`.
371
+ - Check the project/environment you are viewing in the dashboard.
372
+
373
+ ### Wrong `apiKey`
374
+
375
+ Runtime ingestion uses the project API key. Source-map upload uses `ALLSTAK_UPLOAD_TOKEN`. They are different credentials and are not interchangeable.
376
+
377
+ ### Upload token vs runtime API key confusion
378
+
379
+ - `apiKey="ask_live_..."`: ships runtime errors/logs/breadcrumbs.
380
+ - `ALLSTAK_UPLOAD_TOKEN=aspk_...`: uploads source maps and artifacts in CI.
381
+ - Never put the upload token in app code.
382
+
383
+ ### Source maps uploaded but stack is not symbolicated
384
+
385
+ - Ensure the runtime `release` matches `ALLSTAK_RELEASE`.
386
+ - Ensure runtime `dist` matches the uploaded map's `dist`.
387
+ - Confirm the event contains a matching `debugId` or release/dist combination.
388
+ - Confirm the map was uploaded to the same project as the runtime API key.
389
+
390
+ ### Release/dist mismatch
391
+
392
+ Use stable release names such as `mobile@1.2.3+45` and platform dists such as `ios-hermes`, `android-hermes`, `ios-jsc`, or `android-jsc`. Mismatched values prevent backend joining between event and source map.
393
+
394
+ ### Hermes stacks not resolving
395
+
396
+ Hermes stack traces need the correct Metro/Hermes source-map chain. Use the provided build hooks instead of uploading a random map file from an intermediate build step.
397
+
398
+ ### Navigation breadcrumbs not appearing
399
+
400
+ - In Metro-native builds, use `instrumentReactNavigation(navigationRef)`.
401
+ - Confirm `NavigationContainer` has mounted and `onReady` fires.
402
+ - Avoid deep imports that bypass `@react-navigation/native`.
403
+ - Enable `debug` to see whether auto navigation instrumentation was applied or skipped.
404
+
405
+ ### Metro / Expo issues
406
+
407
+ - Rebuild after adding native modules or source-map hooks.
408
+ - Expo Go cannot load custom native crash modules.
409
+ - For native crash testing, use an Expo dev client, simulator build, or physical device build.
410
+
411
+ ### Android Gradle hook not running
412
+
413
+ - Confirm the `apply from` path is relative to `android/app/build.gradle`.
414
+ - Confirm `ALLSTAK_RELEASE` and `ALLSTAK_UPLOAD_TOKEN` are visible to Gradle.
415
+ - Run with `--info` to verify the AllStak source-map task executes.
416
+
417
+ ### Xcode build phase path wrong
418
+
419
+ - The recommended path is `"${SRCROOT}/../node_modules/@allstak/react-native/build-hooks/xcode-build-phase.sh"`.
420
+ - Place the phase after React Native bundles JS.
421
+ - Confirm the script has executable permissions after install.
422
+
423
+ ### AppState breadcrumbs not easy to test
424
+
425
+ The listener registers at startup, but actual foreground/background transitions depend on simulator/device behavior. Verify by backgrounding and foregrounding the app, then capturing an error so breadcrumbs attach.
426
+
427
+ ### Docker/backend local issue is not an SDK issue
428
+
429
+ If local backend testing returns `401 INVALID_API_KEY` or nothing reaches ClickHouse, verify the API key exists in the same database used by the running backend. The latest backend verification report found that using the wrong local Postgres instance caused false SDK failures.
430
+
431
+ ## 12. Verification Status
432
+
433
+ Latest verification reports are in `docs/reports/`:
434
+
435
+ - `react-native-provider-verification.md`
436
+ - `react-native-backend-ingestion-verification.md`
437
+ - `react-native-production-readiness.md`
438
+ - `console-and-navigation-auto.md`
439
+
440
+ Current status from those reports:
441
+
442
+ | Area | Status |
443
+ | --- | --- |
444
+ | Unit tests | Latest production-readiness report: 132 passing total, including 126 unit tests and 6 live backend-contract tests. Earlier provider report recorded 98/98 before later additions. |
445
+ | iOS simulator verified paths | Provider init, render errors, global JS errors, unhandled promises, manual exception/message, console warn/error defaults, console log/info opt-in behavior, fetch breadcrumbs, HTTP 4xx/5xx/network failure, full HTTP request events, device/platform/Hermes/dist tags, manual React Navigation breadcrumbs, iOS native crash drain. |
446
+ | Android emulator verified paths | Not completed in latest production-readiness pass; emulator boot was blocked by disk. Android native crash and JS paths remain implemented but not device-verified. |
447
+ | Backend ingestion verified paths | `/ingest/v1/errors`, `/ingest/v1/logs`, `/ingest/v1/http_requests`; 8 canonical curl payload shapes accepted; live SDK events landed in ClickHouse; backend-contract tests cover buffering and invalid-key resilience. |
448
+ | Source-map backend status | `/api/v1/artifacts/upload` upload path exists and build hooks inject/upload debug-ID source maps. Full Hermes symbolication remains dependent on matching release/dist/debugId and should be validated per app release pipeline. |
449
+ | Remaining gaps | Android device/emulator verification, persistent offline queue, full AppState transition verification, and per-project source-map symbolication verification in release CI. |
141
450
 
142
- ## 9. Troubleshooting
451
+ ## Links
143
452
 
144
- - No events: verify `ALLSTAK_API_KEY` or `EXPO_PUBLIC_ALLSTAK_API_KEY` and confirm one provider wrapper.
145
- - Duplicate events: run `npx @allstak/wizard doctor --integration react-native`.
146
- - Expo Go native crashes missing: expected. Native modules require a dev client or native build.
147
- - Source maps missing: confirm `ALLSTAK_SOURCEMAP_TOKEN` and matching `release`.
148
- - Build fails after setup: run uninstall, then rerun setup with `--dry-run` and inspect the planned diff.
453
+ - Dashboard: https://app.allstak.sa
454
+ - Documentation: https://docs.allstak.sa
455
+ - Source: https://github.com/AllStak/allstak-react-native
149
456
 
150
- ## 10. Limitations
457
+ ## License
151
458
 
152
- - Native crash capture is not available in Expo Go.
153
- - Native crash proof requires a native build and dashboard verification.
154
- - Live dashboard delivery is not proven by local tests.
155
- - Some React Navigation breadcrumb paths may still need explicit app navigation lifecycle validation.
156
- - Stable production launch requires live certification against your dashboard.
459
+ MIT © AllStak
package/app.plugin.js CHANGED
@@ -3,6 +3,4 @@
3
3
  // app.json and Expo's `withPlugins` resolver finds it without an extra
4
4
  // import path. Expo looks for `app.plugin.js` at the package root by
5
5
  // convention.
6
- const plugin = require('./dist/expo-plugin.js');
7
-
8
- module.exports = plugin.default || plugin;
6
+ module.exports = require('./dist/expo-plugin.js');
@@ -36,7 +36,6 @@
36
36
  const fs = require('node:fs');
37
37
  const path = require('node:path');
38
38
 
39
- loadDotEnv();
40
39
  const args = parseArgs(process.argv.slice(2));
41
40
 
42
41
  const RELEASE = process.env.ALLSTAK_RELEASE;
@@ -174,17 +173,3 @@ function guessDist(platform) {
174
173
  if (platform === 'android') return 'android-hermes';
175
174
  return platform;
176
175
  }
177
-
178
- function loadDotEnv() {
179
- for (const file of ['.env.local', '.env']) {
180
- const full = path.resolve(process.cwd(), file);
181
- if (!fs.existsSync(full)) continue;
182
- for (const line of fs.readFileSync(full, 'utf8').split(/\r?\n/)) {
183
- const trimmed = line.trim();
184
- if (!trimmed || trimmed.startsWith('#')) continue;
185
- const match = /^([A-Z0-9_]+)\s*=\s*(.*)$/.exec(trimmed);
186
- if (!match || process.env[match[1]] !== undefined) continue;
187
- process.env[match[1]] = match[2].replace(/^['"]|['"]$/g, '');
188
- }
189
- }
190
- }