@guidelytech/react-native 0.16.0 → 0.17.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/README.md +119 -2
- package/dist/index.cjs +1137 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +448 -188
- package/dist/index.d.ts +448 -188
- package/dist/index.js +1132 -79
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ tasks).
|
|
|
76
76
|
|
|
77
77
|
| | |
|
|
78
78
|
|---|---|
|
|
79
|
-
| `useGuidely()` | Client: `identify(id, traits?, account?)`, `setAccount`, `updateTraits`, `reset()`, `track(name, props?)`, `screen(name)`, `startGuide(idOrKey)`, `stopGuide()`, `dismissGuide()`, `openChecklist(key)`, `closeChecklist(key)`, `completeChecklistTask(key, taskId)`, `openResourceCenter()`, `closeResourceCenter()`, `openArticle(articleId)`, `refresh()`, `setConsent()`, `on(event, cb)`, `getGuides()`, `getActiveGuide()`, `getState()`, `startSessionRecording()`, `stopSessionRecording()`, `isRecording()`, `getSessionId()` |
|
|
79
|
+
| `useGuidely()` | Client: `identify(id, traits?, account?)`, `setAccount`, `updateTraits`, `reset()`, `track(name, props?)`, `screen(name)`, `startGuide(idOrKey)`, `stopGuide()`, `dismissGuide()`, `openChecklist(key)`, `closeChecklist(key)`, `completeChecklistTask(key, taskId)`, `openResourceCenter()`, `closeResourceCenter()`, `openArticle(articleId)`, `refresh()`, `setConsent()`, `on(event, cb)`, `getGuides()`, `getActiveGuide()`, `getState()`, `startSessionRecording()`, `stopSessionRecording()`, `isRecording()`, `getSessionId()`, `captureException(err, ctx?)`, `captureMessage(msg, level?)`, `addBreadcrumb()`, `setTag(s)`, `setExtra(s)`, `setContext()`, `setUser()` |
|
|
80
80
|
| `useGuidelyReady()` | `true` once config is loaded |
|
|
81
81
|
| `useGuidelyIdentify(id, traits?, account?)` | Identify when the signed-in user changes |
|
|
82
82
|
| `useGuidelyScreen(name)` | Report a screen view from a component |
|
|
@@ -91,7 +91,8 @@ Provider props: `projectId`, `apiUrl`, `environment`, `storage`, `user`, `debug`
|
|
|
91
91
|
`consent` (`granted` / `pending` / `denied`), `appVersion` (overrides the detected version, see below), `theme`,
|
|
92
92
|
`configRefreshMs`, `onNavigate`, `onError`, `showChecklistLauncher` (default `true`),
|
|
93
93
|
`showResourceCenterLauncher` (default `false`), `showMessengerLauncher` (default `true`), `insets`,
|
|
94
|
-
`launcherOffset` (default 72), `autocapture`, `appBuild`, `sessionReplay
|
|
94
|
+
`launcherOffset` (default 72), `autocapture`, `appBuild`, `sessionReplay`, `release`, `errors`
|
|
95
|
+
(see [Errors and crashes](#errors-and-crashes)).
|
|
95
96
|
|
|
96
97
|
## Product analytics (autocapture)
|
|
97
98
|
|
|
@@ -165,6 +166,122 @@ native-stack headers, some third-party native views) may not reach JavaScript to
|
|
|
165
166
|
then not captured. Coordinates are relative to the React Native root view (the window in a
|
|
166
167
|
full-screen app).
|
|
167
168
|
|
|
169
|
+
## Errors and crashes
|
|
170
|
+
|
|
171
|
+
The SDK reports JavaScript errors with the same capture API as Sentry's SDKs, to the project's
|
|
172
|
+
**Errors** page. Uncaught errors and unhandled promise rejections are captured automatically; caught
|
|
173
|
+
ones with `captureException`.
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
const guidely = useGuidely();
|
|
177
|
+
try {
|
|
178
|
+
await pay(cart);
|
|
179
|
+
} catch (err) {
|
|
180
|
+
guidely.captureException(err, { tags: { area: "checkout" }, extra: { cartSize: cart.length }, level: "error", fingerprint: ["{{ default }}", "checkout"], contexts: { payment: { provider: "stripe" } } });
|
|
181
|
+
}
|
|
182
|
+
guidely.captureMessage("Checkout took 30 s", "warning");
|
|
183
|
+
guidely.setTag("plan", "pro"); // setTags, setExtra, setExtras, setContext(name, ctx | null)
|
|
184
|
+
guidely.setUser({ id: "u_42", email: "ana@example.com" }); // identify() + email/username on errors; null = reset()
|
|
185
|
+
guidely.addBreadcrumb({ category: "cart", message: "Added item", data: { sku: "A1" } });
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
<GuidelyProvider
|
|
190
|
+
release="2.4.1" // default: the app version; must match --release of the source-map upload
|
|
191
|
+
errors={{
|
|
192
|
+
sampleRate: 1, // 0–1, crashes included
|
|
193
|
+
ignoreErrors: ["Network request failed", /^AbortError: /],
|
|
194
|
+
denyUrls: [], allowUrls: [], // against the innermost frame's file (app:///index.android.bundle)
|
|
195
|
+
beforeSend: ({ properties, detail }) => (properties.message.includes("ignore") ? null : { properties, detail }),
|
|
196
|
+
beforeBreadcrumb: (crumb) => (crumb.category === "console" ? null : crumb),
|
|
197
|
+
breadcrumbs: { console: true, http: true, navigation: true, taps: true, appLifecycle: true, guides: true }, // or false
|
|
198
|
+
captureErrors: true, // false: no automatic capture (captureException still works)
|
|
199
|
+
dist: "512", // default: the app build number
|
|
200
|
+
}}
|
|
201
|
+
…
|
|
202
|
+
>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Errors need the project's error tracking on (Settings → Privacy & data), `analytics` and consent:
|
|
206
|
+
nothing leaves the device before consent is granted, errors captured while consent is `pending` are
|
|
207
|
+
sent once it is granted and deleted when it is denied. The same error is sent at most 5 times per
|
|
208
|
+
launch, and at most 50 errors per session (crashes always go out).
|
|
209
|
+
|
|
210
|
+
**What is captured.** `ErrorUtils.setGlobalHandler` reports every uncaught JS error and then calls the
|
|
211
|
+
handler that was installed before (React Native's own, which shows the red box in development and
|
|
212
|
+
ends the app in release builds), with the same arguments, so nothing changes about how your app
|
|
213
|
+
crashes. Fatal errors are `level: "fatal"`, `handled: false`, `mechanism: "onerror"`; non-fatal ones
|
|
214
|
+
`level: "error"`. Unhandled promise rejections (`mechanism: "unhandledrejection"`, `level: "error"`)
|
|
215
|
+
come from Hermes' rejection tracker. On JavaScriptCore pass React Native's Promise polyfill tracker:
|
|
216
|
+
`errors={{ rejectionTracker: require("promise/setimmediate/rejection-tracking") }}`. In development
|
|
217
|
+
the SDK keeps React Native's "Possible unhandled promise rejection" warning.
|
|
218
|
+
|
|
219
|
+
**Crashes are saved first.** A fatal error ends a release app right after the handler, so the report
|
|
220
|
+
is written to `storage` the moment it happens and sent on the next launch (which starts a new
|
|
221
|
+
session; the crash keeps the session that crashed). React Native's handler is held back until the
|
|
222
|
+
report is written and, when the network allows, sent — at most 2 s (`FATAL_FLUSH_MS`); in
|
|
223
|
+
development it runs at once. AsyncStorage writes are asynchronous, so a report can still be lost if
|
|
224
|
+
the OS ends the process before the write lands; a synchronous `storage` (an MMKV adapter) always has
|
|
225
|
+
it. Without `storage` crash reports can't outlive the crash.
|
|
226
|
+
|
|
227
|
+
**Breadcrumbs** (the last 100 ride along with each error): `navigation` (`screen()`), `ui.click`
|
|
228
|
+
(taps, with the element's `selector`; never its text), `app.lifecycle` (`AppState`), `console`
|
|
229
|
+
(`console.warn` / `console.error`), `fetch` / `xhr` (method, URL without query, status, duration;
|
|
230
|
+
never Guidely's own requests; React Native's `fetch` runs on XMLHttpRequest and is recorded once, as
|
|
231
|
+
`fetch`) and `guide` (guides shown, stepped through, completed, dismissed). Tap breadcrumbs need the
|
|
232
|
+
provider's touch-observing wrapper (not with `autocapture={false}`).
|
|
233
|
+
|
|
234
|
+
**Each event** carries `properties` (type, message, the innermost 30 frames, `platform: "javascript"`,
|
|
235
|
+
`release`) and a Sentry-shaped `detail` (≤ 64 KB): the `cause` chain, breadcrumbs, tags, extra, user
|
|
236
|
+
and contexts `os`, `device` (model from `expo-device` / `react-native-device-info`, or Android's own
|
|
237
|
+
constants), `app` (version, build, foreground), `runtime` (`hermes` / `jsc`) and
|
|
238
|
+
`react_native_context` (engine, React Native version, new architecture, Expo). Keys that look like
|
|
239
|
+
credentials (`password`, `token`, `authorization`, `cookie`, …) are replaced with `[Filtered]`.
|
|
240
|
+
|
|
241
|
+
**Stack traces.** Hermes release frames (`at pay (address at index.android.bundle:1:9876)`: line 1,
|
|
242
|
+
column = bytecode offset) and JavaScriptCore frames (`pay@…/MyApp.app/main.jsbundle:1:2345`) are
|
|
243
|
+
reported against `app:///index.android.bundle` / `app:///main.jsbundle`, whatever folder the app is
|
|
244
|
+
installed in, so they map through source maps uploaded with `--url-prefix /`. Metro dev-server frames
|
|
245
|
+
keep their URL. Engine built-ins (`(native)`, `InternalBytecode.js`) and `node_modules` frames are
|
|
246
|
+
marked not in-app.
|
|
247
|
+
|
|
248
|
+
### Uploading Hermes source maps
|
|
249
|
+
|
|
250
|
+
Hermes needs the *composed* map (Metro's map combined with the Hermes bytecode map). Put the bundle and
|
|
251
|
+
its map side by side in one folder and upload with the same release the app reports:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Android: the release build composes the map; copy both next to each other
|
|
255
|
+
mkdir -p build/sourcemaps
|
|
256
|
+
cp android/app/build/generated/assets/react/release/index.android.bundle build/sourcemaps/
|
|
257
|
+
cp android/app/build/generated/sourcemaps/react/release/index.android.bundle.map build/sourcemaps/
|
|
258
|
+
|
|
259
|
+
# Or by hand (Android shown; iOS uses --platform ios and main.jsbundle)
|
|
260
|
+
npx react-native bundle --platform android --dev false --entry-file index.js \
|
|
261
|
+
--bundle-output build/sourcemaps/index.android.bundle --sourcemap-output build/sourcemaps/index.android.packager.map
|
|
262
|
+
node_modules/react-native/sdks/hermesc/osx-bin/hermesc -O -emit-binary -output-source-map \
|
|
263
|
+
-out=build/sourcemaps/index.android.bundle.hbc build/sourcemaps/index.android.bundle
|
|
264
|
+
node node_modules/react-native/scripts/compose-source-maps.js \
|
|
265
|
+
build/sourcemaps/index.android.packager.map build/sourcemaps/index.android.bundle.hbc.map \
|
|
266
|
+
-o build/sourcemaps/index.android.bundle.map
|
|
267
|
+
|
|
268
|
+
export GUIDELY_SOURCEMAP_KEY=gly_sk_… GUIDELY_API_URL=https://<your Guidely API>
|
|
269
|
+
npx @guidelytech/sourcemaps upload --dir build/sourcemaps --url-prefix / --release 2.4.1 --include .bundle.map
|
|
270
|
+
# iOS (main.jsbundle + main.jsbundle.map): --include .jsbundle.map
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
On iOS, set `export SOURCEMAP_FILE="$DERIVED_FILE_DIR/main.jsbundle.map"` in the *Bundle React Native
|
|
274
|
+
code and images* build phase; React Native then writes the composed map next to the build, and the
|
|
275
|
+
bundle is `main.jsbundle` inside the `.app`. `--release` must equal the `release` prop (default: the
|
|
276
|
+
app version, `CFBundleShortVersionString` / `versionName`).
|
|
277
|
+
|
|
278
|
+
### Native crashes
|
|
279
|
+
|
|
280
|
+
This SDK is pure JavaScript: it reports JavaScript errors only. Native crashes (signals,
|
|
281
|
+
`NSException`, JVM exceptions, ANRs) are reported by Guidely's native iOS and Android SDKs, which the
|
|
282
|
+
React Native SDK does not embed; capturing them in a React Native app means adding the native SDK
|
|
283
|
+
to the iOS/Android projects as well and is not set up by this package yet.
|
|
284
|
+
|
|
168
285
|
## Session replay
|
|
169
286
|
|
|
170
287
|
Records sessions for the dashboard's **Replays** player: masked screenshots (about one a second
|