@allstak/react-native 0.3.2 → 0.3.4
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/README.md +95 -398
- package/app.plugin.js +3 -1
- package/build-hooks/upload-sourcemaps.js +15 -0
- package/dist/build/sourcemaps.js +18 -2
- package/dist/build/sourcemaps.js.map +1 -1
- package/dist/build/sourcemaps.mjs +20 -4
- package/dist/build/sourcemaps.mjs.map +1 -1
- package/dist/expo-plugin.js +1 -5
- package/dist/expo-plugin.js.map +1 -1
- package/dist/expo-plugin.mjs +1 -5
- package/dist/expo-plugin.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,459 +1,156 @@
|
|
|
1
1
|
# @allstak/react-native
|
|
2
2
|
|
|
3
|
-
AllStak
|
|
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.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Stability: beta. Live dashboard certification and native crash proof are not claimed until verified with real credentials and a native build.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
[](https://github.com/allstak-io/allstak-react-native/actions)
|
|
9
|
-
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
## 1. Automatic Setup With Wizard
|
|
10
8
|
|
|
11
|
-
|
|
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
|
|
9
|
+
Recommended flow:
|
|
16
10
|
|
|
17
11
|
```bash
|
|
18
|
-
|
|
12
|
+
npx @allstak/wizard setup --integration react-native
|
|
19
13
|
```
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
|
|
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. |
|
|
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.
|
|
28
16
|
|
|
29
|
-
|
|
17
|
+
## 2. What The Wizard Changes
|
|
30
18
|
|
|
31
|
-
|
|
19
|
+
The wizard:
|
|
32
20
|
|
|
33
|
-
|
|
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.
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
import { AllStakProvider } from "@allstak/react-native";
|
|
37
|
-
|
|
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
|
-
}
|
|
51
|
-
```
|
|
32
|
+
## 3. Verification
|
|
52
33
|
|
|
53
|
-
|
|
34
|
+
After setup:
|
|
54
35
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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"));
|
|
36
|
+
```bash
|
|
37
|
+
npm run allstak:verify
|
|
38
|
+
npx @allstak/wizard doctor --integration react-native
|
|
78
39
|
```
|
|
79
40
|
|
|
80
|
-
|
|
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`.
|
|
41
|
+
For Expo:
|
|
139
42
|
|
|
140
|
-
```
|
|
141
|
-
|
|
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>
|
|
43
|
+
```bash
|
|
44
|
+
npx expo config --type public
|
|
151
45
|
```
|
|
152
46
|
|
|
153
|
-
|
|
47
|
+
For RN CLI, run your normal TypeScript/build checks. Dashboard delivery requires real credentials and must be verified in AllStak.
|
|
154
48
|
|
|
155
|
-
##
|
|
49
|
+
## 4. Rollback / Uninstall
|
|
156
50
|
|
|
157
|
-
```
|
|
158
|
-
|
|
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();
|
|
51
|
+
```bash
|
|
52
|
+
npx @allstak/wizard uninstall --integration react-native
|
|
172
53
|
```
|
|
173
54
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
Manual setup is available when you need full initialization control:
|
|
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.
|
|
177
56
|
|
|
178
|
-
|
|
179
|
-
import { AllStak, installReactNative } from "@allstak/react-native";
|
|
57
|
+
## 5. Manual Setup Fallback
|
|
180
58
|
|
|
181
|
-
|
|
182
|
-
apiKey: "ask_live_...",
|
|
183
|
-
environment: "production",
|
|
184
|
-
release: "mobile@1.2.3+45",
|
|
185
|
-
});
|
|
59
|
+
Use manual setup only when the wizard cannot safely patch a custom root:
|
|
186
60
|
|
|
187
|
-
|
|
61
|
+
```bash
|
|
62
|
+
npm install @allstak/react-native
|
|
188
63
|
```
|
|
189
64
|
|
|
190
|
-
Manual navigation fallback:
|
|
191
|
-
|
|
192
65
|
```tsx
|
|
193
|
-
import {
|
|
194
|
-
import { instrumentReactNavigation } from "@allstak/react-native";
|
|
195
|
-
|
|
196
|
-
export function AppNavigation() {
|
|
197
|
-
const navigationRef = useNavigationContainerRef();
|
|
66
|
+
import { AllStakProvider } from '@allstak/react-native';
|
|
198
67
|
|
|
68
|
+
export default function App() {
|
|
199
69
|
return (
|
|
200
|
-
<
|
|
201
|
-
|
|
202
|
-
|
|
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
|
|
203
76
|
>
|
|
204
|
-
{/*
|
|
205
|
-
</
|
|
77
|
+
{/* app */}
|
|
78
|
+
</AllStakProvider>
|
|
206
79
|
);
|
|
207
80
|
}
|
|
208
81
|
```
|
|
209
82
|
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
```
|
|
83
|
+
Manual capture:
|
|
227
84
|
|
|
228
|
-
|
|
85
|
+
```ts
|
|
86
|
+
import { AllStak } from '@allstak/react-native';
|
|
229
87
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
}
|
|
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' });
|
|
236
92
|
```
|
|
237
93
|
|
|
238
|
-
|
|
94
|
+
## 6. Configuration
|
|
239
95
|
|
|
240
|
-
|
|
241
|
-
- `ALLSTAK_RELEASE`
|
|
242
|
-
- `ALLSTAK_API_URL` optional, defaults to AllStak production API
|
|
96
|
+
Provider props include:
|
|
243
97
|
|
|
244
|
-
|
|
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. |
|
|
245
110
|
|
|
246
|
-
|
|
111
|
+
## 7. Privacy / PII / Redaction
|
|
247
112
|
|
|
248
|
-
|
|
113
|
+
Defaults are privacy-first:
|
|
249
114
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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.
|
|
253
121
|
|
|
254
|
-
|
|
122
|
+
Do not send passwords, payment data, national IDs, raw tokens, or raw request/response bodies unless you have verified redaction in your app.
|
|
255
123
|
|
|
256
|
-
|
|
257
|
-
- `ALLSTAK_RELEASE` or `allstakRelease`
|
|
258
|
-
- optional API URL override when self-hosting
|
|
124
|
+
## 8. Source Maps / Releases
|
|
259
125
|
|
|
260
|
-
|
|
126
|
+
The wizard adds:
|
|
261
127
|
|
|
262
128
|
```bash
|
|
263
|
-
|
|
264
|
-
./gradlew :app:bundleRelease
|
|
129
|
+
npm run allstak:sourcemaps
|
|
265
130
|
```
|
|
266
131
|
|
|
267
|
-
|
|
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
|
|
132
|
+
Set the same release in your app and source-map upload:
|
|
285
133
|
|
|
286
134
|
```bash
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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");
|
|
135
|
+
export ALLSTAK_RELEASE=my-app@1.2.3
|
|
136
|
+
export ALLSTAK_SOURCEMAP_TOKEN=...
|
|
137
|
+
npm run allstak:sourcemaps
|
|
327
138
|
```
|
|
328
139
|
|
|
329
|
-
|
|
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. |
|
|
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.
|
|
450
141
|
|
|
451
|
-
##
|
|
142
|
+
## 9. Troubleshooting
|
|
452
143
|
|
|
453
|
-
-
|
|
454
|
-
-
|
|
455
|
-
-
|
|
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.
|
|
456
149
|
|
|
457
|
-
##
|
|
150
|
+
## 10. Limitations
|
|
458
151
|
|
|
459
|
-
|
|
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.
|
package/app.plugin.js
CHANGED
|
@@ -3,4 +3,6 @@
|
|
|
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
|
-
|
|
6
|
+
const plugin = require('./dist/expo-plugin.js');
|
|
7
|
+
|
|
8
|
+
module.exports = plugin.default || plugin;
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
const fs = require('node:fs');
|
|
37
37
|
const path = require('node:path');
|
|
38
38
|
|
|
39
|
+
loadDotEnv();
|
|
39
40
|
const args = parseArgs(process.argv.slice(2));
|
|
40
41
|
|
|
41
42
|
const RELEASE = process.env.ALLSTAK_RELEASE;
|
|
@@ -173,3 +174,17 @@ function guessDist(platform) {
|
|
|
173
174
|
if (platform === 'android') return 'android-hermes';
|
|
174
175
|
return platform;
|
|
175
176
|
}
|
|
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
|
+
}
|
package/dist/build/sourcemaps.js
CHANGED
|
@@ -83,14 +83,15 @@ async function uploadReactNativeSourcemap(opts) {
|
|
|
83
83
|
const log = opts.silent ? () => void 0 : (m) => console.log(`[allstak/sourcemaps] ${m}`);
|
|
84
84
|
const inject = injectReactNativeSourcemap(opts);
|
|
85
85
|
log(`bundle: ${(0, import_node_path.basename)(opts.bundle)} debugId: ${inject.debugId} ${inject.reused ? "(reused)" : "(new)"}`);
|
|
86
|
-
const
|
|
86
|
+
const env = loadAllStakEnv();
|
|
87
|
+
const token = opts.token ?? env.ALLSTAK_UPLOAD_TOKEN;
|
|
87
88
|
if (opts.injectOnly || !token) {
|
|
88
89
|
if (!opts.injectOnly && !token) {
|
|
89
90
|
log("skipping upload \u2014 no token (set ALLSTAK_UPLOAD_TOKEN or pass `token`)");
|
|
90
91
|
}
|
|
91
92
|
return inject;
|
|
92
93
|
}
|
|
93
|
-
const host = opts.host ??
|
|
94
|
+
const host = opts.host ?? env.ALLSTAK_HOST ?? DEFAULT_HOST;
|
|
94
95
|
const stripSources = opts.stripSources ?? false;
|
|
95
96
|
const steps = [];
|
|
96
97
|
const mapResult = await uploadOne(
|
|
@@ -133,6 +134,21 @@ async function uploadReactNativeSourcemap(opts) {
|
|
|
133
134
|
}
|
|
134
135
|
return { ...inject, uploaded: allOk, steps };
|
|
135
136
|
}
|
|
137
|
+
function loadAllStakEnv() {
|
|
138
|
+
const out = { ...process.env };
|
|
139
|
+
for (const file of [".env.local", ".env"]) {
|
|
140
|
+
const full = (0, import_node_path.resolve)(process.cwd(), file);
|
|
141
|
+
if (!(0, import_node_fs.existsSync)(full)) continue;
|
|
142
|
+
for (const line of (0, import_node_fs.readFileSync)(full, "utf8").split(/\r?\n/)) {
|
|
143
|
+
const trimmed = line.trim();
|
|
144
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
145
|
+
const match = /^([A-Z0-9_]+)\s*=\s*(.*)$/.exec(trimmed);
|
|
146
|
+
if (!match || out[match[1]] !== void 0) continue;
|
|
147
|
+
out[match[1]] = match[2].replace(/^['"]|['"]$/g, "");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
136
152
|
// Annotate the CommonJS export names for ESM import in node:
|
|
137
153
|
0 && (module.exports = {
|
|
138
154
|
DEFAULT_HOST,
|