@reopt-ai/data-sdk-client 0.1.6 → 0.2.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 +141 -7
- package/dist/client-B1GlWwVq.d.ts +744 -0
- package/dist/client-B1GlWwVq.d.ts.map +1 -0
- package/dist/client-BCrui21p.d.cts +744 -0
- package/dist/client-BCrui21p.d.cts.map +1 -0
- package/dist/exceptions-C9Fh0BIR.js +285 -0
- package/dist/exceptions-C9Fh0BIR.js.map +1 -0
- package/dist/exceptions-CuhGo9A5.cjs +289 -0
- package/dist/exceptions-CuhGo9A5.cjs.map +1 -0
- package/dist/index.cjs +75 -1874
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +35 -33
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -70
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +51 -1919
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +31 -0
- package/dist/next.d.cts.map +1 -0
- package/dist/next.d.ts +8 -10
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +36 -49
- package/dist/next.js.map +1 -1
- package/dist/observe-D-BHMwrO.cjs +54 -0
- package/dist/observe-D-BHMwrO.cjs.map +1 -0
- package/dist/observe-D1pNg1qL.js +54 -0
- package/dist/observe-D1pNg1qL.js.map +1 -0
- package/dist/react.cjs +105 -1863
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +80 -0
- package/dist/react.d.cts.map +1 -0
- package/dist/react.d.ts +52 -46
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +118 -23
- package/dist/react.js.map +1 -1
- package/dist/registry-BPhiH_l9.js +1775 -0
- package/dist/registry-BPhiH_l9.js.map +1 -0
- package/dist/registry-CGqrOtf4.cjs +1810 -0
- package/dist/registry-CGqrOtf4.cjs.map +1 -0
- package/dist/tracing-DAhaKkl0.cjs +93 -0
- package/dist/tracing-DAhaKkl0.cjs.map +1 -0
- package/dist/tracing-Dt1RVuQ9.js +93 -0
- package/dist/tracing-Dt1RVuQ9.js.map +1 -0
- package/package.json +31 -16
- package/dist/chunk-4MTDZBRS.js +0 -57
- package/dist/chunk-4MTDZBRS.js.map +0 -1
- package/dist/chunk-SYCBGBTH.js +0 -1627
- package/dist/chunk-SYCBGBTH.js.map +0 -1
- package/dist/chunk-YRP3I3OD.js +0 -106
- package/dist/chunk-YRP3I3OD.js.map +0 -1
- package/dist/client-BCd2fgmx.d.ts +0 -581
- package/dist/exceptions-NQHZUDYO.js +0 -9
- package/dist/exceptions-NQHZUDYO.js.map +0 -1
- package/dist/tracing-LC3NZND7.js +0 -91
- package/dist/tracing-LC3NZND7.js.map +0 -1
package/README.md
CHANGED
|
@@ -104,9 +104,11 @@ init({
|
|
|
104
104
|
scrollDepth: true,
|
|
105
105
|
exceptions: false, // $exception for uncaught errors and unhandled rejections; loads as its own chunk when on
|
|
106
106
|
},
|
|
107
|
+
release: undefined, // build id stamped on every event as $release_id; see below
|
|
107
108
|
tracingHeaders: false, // opt-in: add reopt-device-id to same-origin fetch/XHR (true) or to listed hosts; loads as its own chunk
|
|
108
109
|
normalizePath: (pathname) => pathname, // see below; applied to every path the SDK stamps itself
|
|
109
110
|
fetch: undefined, // transport override for tests
|
|
111
|
+
observe: undefined, // local lifecycle observer for devtools; never sent over the network
|
|
110
112
|
consent: { categories: ["analytics", "marketing"], defaultConsent: true },
|
|
111
113
|
batch: { size: 100, intervalMs: 1000, maxBytes: 400_000 },
|
|
112
114
|
retry: { maxRetries: 3, baseDelay: 1000, maxDelay: 30000, jitter: 0.1 },
|
|
@@ -115,6 +117,42 @@ init({
|
|
|
115
117
|
});
|
|
116
118
|
```
|
|
117
119
|
|
|
120
|
+
## Release tracking
|
|
121
|
+
|
|
122
|
+
`release` stamps every event with `$release_id`. Error tracking reads it to say
|
|
123
|
+
which build an issue first and last appeared in, and — once you resolve an issue
|
|
124
|
+
"in" a release — to tell a plain reopen from a **regression**, where the fix you
|
|
125
|
+
declared did not hold.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
init({ writeKey: "wk_…", release: "1.4.0" });
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Most apps do not know their version at the call site. The SDK falls back to
|
|
132
|
+
`globalThis.__REOPT_RELEASE__`, which is where a build step writes it:
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
// vite.config.js
|
|
136
|
+
export default { define: { __REOPT_RELEASE__: JSON.stringify(process.env.GIT_SHA) } };
|
|
137
|
+
|
|
138
|
+
// next.config.js
|
|
139
|
+
module.exports = {
|
|
140
|
+
webpack: (config, { webpack }) => {
|
|
141
|
+
config.plugins.push(
|
|
142
|
+
new webpack.DefinePlugin({ __REOPT_RELEASE__: JSON.stringify(process.env.VERCEL_GIT_COMMIT_SHA) })
|
|
143
|
+
);
|
|
144
|
+
return config;
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
An explicit `release` wins over the global. With neither, the property is
|
|
150
|
+
omitted entirely — not sent as an empty string, which would create a release
|
|
151
|
+
named `""` and label every issue with it.
|
|
152
|
+
|
|
153
|
+
The label is yours: a version, a commit sha, a build id. The server never issues
|
|
154
|
+
one and never rejects an event for carrying an unfamiliar release.
|
|
155
|
+
|
|
118
156
|
## Runtime-resolved keys, manual page views, external consent
|
|
119
157
|
|
|
120
158
|
The three things a multi-tenant host needs, in the shape it needs them:
|
|
@@ -134,6 +172,7 @@ const writeKey = await resolveBrandWriteKey(brandId);
|
|
|
134
172
|
- **`register(properties)`** attaches properties to every event from then on — including the automatic ones. This is how a host puts its own breakdown axis (`page_id`, a tenant) on `$web_vitals` and `$pageleave`, which the SDK otherwise stamps with only a path. An event's own properties win; `reset()` clears them.
|
|
135
173
|
- **Fail-open.** A missing `writeKey` or `baseUrl` logs a warning and yields a disabled client whose every call is a no-op; nothing throws. Analytics must never be why a page fails.
|
|
136
174
|
- **`fetch`** injects the transport. A test can hand in a recording function and assert on the exact payload the SDK built, instead of intercepting the network.
|
|
175
|
+
- **`observe`** receives local configuration, enqueue/drop, identity, consent, and pause/resume facts in lifecycle order. Its implementation loads as an opt-in chunk, buffers facts while that chunk arrives, ignores callback errors, and never receives the write key or event properties. Use it for diagnostics such as `@reopt-ai/data-sdk-devtool`, not application behavior.
|
|
137
176
|
|
|
138
177
|
## Bootstrap and caching (Next.js)
|
|
139
178
|
|
|
@@ -145,7 +184,102 @@ const writeKey = await resolveBrandWriteKey(brandId);
|
|
|
145
184
|
|
|
146
185
|
## Size
|
|
147
186
|
|
|
148
|
-
|
|
187
|
+
### `$exception_list` — the structured form
|
|
188
|
+
|
|
189
|
+
Alongside the flat keys, an exception carries the parsed cause chain. The flat
|
|
190
|
+
keys still describe the outermost error and are unchanged, so anything written
|
|
191
|
+
against them keeps working; `$exception_list` is what the issue page renders and
|
|
192
|
+
what fingerprinting groups on.
|
|
193
|
+
|
|
194
|
+
| Field | Meaning |
|
|
195
|
+
| --------------------- | ------------------------------------------------------------------------------------- |
|
|
196
|
+
| `type` / `value` | `TypeError` / the message. For a non-`Error` throw the SDK derives both. |
|
|
197
|
+
| `mechanism.handled` | `false` when nothing caught it. Causes are `true` — they were caught and re-thrown. |
|
|
198
|
+
| `mechanism.type` | `onerror` \| `unhandledrejection` \| `manual` \| `console` \| `nextjs_onRequestError` |
|
|
199
|
+
| `mechanism.synthetic` | The SDK invented the type because what was thrown was not an `Error`. |
|
|
200
|
+
| `stacktrace.frames[]` | `filename`, `function`, `lineno`, `colno`, `in_app` — innermost first. |
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"$exception_type": "TypeError",
|
|
205
|
+
"$exception_message": "cart.items is not a function",
|
|
206
|
+
"$exception_list": [
|
|
207
|
+
{
|
|
208
|
+
"type": "TypeError",
|
|
209
|
+
"value": "cart.items is not a function",
|
|
210
|
+
"mechanism": { "handled": false, "type": "onerror" },
|
|
211
|
+
"stacktrace": {
|
|
212
|
+
"type": "raw",
|
|
213
|
+
"frames": [
|
|
214
|
+
{
|
|
215
|
+
"filename": "https://shop.example.com/main.a1b2c3d4.js",
|
|
216
|
+
"function": "handleCheckout",
|
|
217
|
+
"lineno": 412,
|
|
218
|
+
"colno": 19,
|
|
219
|
+
"in_app": true
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### Throttling
|
|
229
|
+
|
|
230
|
+
Automatic capture is throttled per exception `type` — a token bucket of 10 with
|
|
231
|
+
one token back every 10s. One component stuck in a rejection loop can fire
|
|
232
|
+
thousands of identical events a second; unthrottled that fills the visitor's
|
|
233
|
+
network and the customer's quota with a single bug, and buries every other error
|
|
234
|
+
in the issue list.
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
capture: {
|
|
238
|
+
exceptions: true,
|
|
239
|
+
exceptionRateLimit: { bucketSize: 20, refillSeconds: 5 }, // or `false` for no limit
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Per type, so a runaway `TypeError` cannot silence a `RangeError` that starts
|
|
244
|
+
later. Never applied to `captureException()` — a report you asked for explicitly
|
|
245
|
+
is not noise the SDK gets to drop. When throttling kicks in, `debug: true` logs
|
|
246
|
+
it once per type.
|
|
247
|
+
|
|
248
|
+
#### Breadcrumbs
|
|
249
|
+
|
|
250
|
+
`$exception_steps` carries what happened just before the error — up to 20 steps,
|
|
251
|
+
each with a 200-character message and at most 1 KB of serialized `data`.
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
client.addExceptionStep({ category: "fetch", message: "POST /orders", data: { status: 500 } });
|
|
255
|
+
// …later, any exception carries the trail
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`capture.exceptionSteps: true` also records a `navigation` step on every page
|
|
259
|
+
view. Off by default: navigation history on every error is a privacy decision
|
|
260
|
+
the host makes, not the SDK. `addExceptionStep()` works either way.
|
|
261
|
+
|
|
262
|
+
The trail is copied onto an exception, not moved — a second error in the same
|
|
263
|
+
session sees the same history rather than an empty one. One buffer per page, not
|
|
264
|
+
per client.
|
|
265
|
+
|
|
266
|
+
A cause chain is carried outermost first, up to four links. A stack made
|
|
267
|
+
entirely of `chrome-extension://` frames is **not reported** — it is a bug in a
|
|
268
|
+
visitor's extension, which the site cannot reproduce or fix.
|
|
269
|
+
|
|
270
|
+
`captureException(error, options?)` takes `{ fingerprint?, level?, properties? }`.
|
|
271
|
+
`fingerprint` is a _suggestion_ — the server bounds it and decides — and is how
|
|
272
|
+
you say "group these two apart" or "group these together". The pre-options shape
|
|
273
|
+
`captureException(error, { myProperty: 1 })` still works: an object carrying none
|
|
274
|
+
of the three option keys is read as properties.
|
|
275
|
+
|
|
276
|
+
`captureException()` is the one place the list can be absent. The parsers live
|
|
277
|
+
in the exception chunk, and a manual capture made before that chunk has loaded
|
|
278
|
+
reports the flat keys only; the server falls back to fingerprinting those, so
|
|
279
|
+
the event still groups. Turning on `capture.exceptions` loads the chunk at init,
|
|
280
|
+
which is the usual case.
|
|
281
|
+
|
|
282
|
+
The production bundle is checked on every build (`scripts/check-size.mjs`): each entry is bundled as a consumer would (minified, `NODE_ENV=production`, framework externals) and must stay under **10.65 KB gzip** for the vanilla entry (10.9 / 11.15 KB for `./react` / `./next`) and carry no zod. Opt-in features (observer formatting, tracing headers, exception capture) are separate chunks. Event validation in production is a hand-written mirror of the contract; the zod schema runs in development only and is dropped by the consumer's bundler.
|
|
149
283
|
|
|
150
284
|
## What it does that you would otherwise have to remember
|
|
151
285
|
|
|
@@ -161,9 +295,9 @@ The production bundle is checked on every build (`scripts/check-size.mjs`): each
|
|
|
161
295
|
|
|
162
296
|
Names and property keys are exported from `@reopt-ai/data-contract/events` (`AUTO_EVENT_NAMES`, `AUTO_EVENT_PROPERTIES`); the low-cardinality subset suitable as rollup dimensions is `AUTO_EVENT_ROLLUP_KEYS`. Derive catalogue entries from those rather than retyping them.
|
|
163
297
|
|
|
164
|
-
| Event | Properties
|
|
165
|
-
| ------------- |
|
|
166
|
-
| `$pageview` | `path`, `origin`, `title`, `referrer`, `utm_*`, `search` (Next, when present), plus anything `normalizePath` lifts
|
|
167
|
-
| `$pageleave` | `path`, `origin`, `duration` (s), `scroll_depth` (0–100)
|
|
168
|
-
| `$web_vitals` | `metric_name`, `metric_id`, `value`, `delta`, `rating`, `navigation_type`, `path`
|
|
169
|
-
| `$exception` | `$exception_type`, `$exception_message`, `$exception_stack`, `$exception_source`, `$exception_handled`, `path`
|
|
298
|
+
| Event | Properties |
|
|
299
|
+
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
300
|
+
| `$pageview` | `path`, `origin`, `title`, `referrer`, `utm_*`, `search` (Next, when present), plus anything `normalizePath` lifts |
|
|
301
|
+
| `$pageleave` | `path`, `origin`, `duration` (s), `scroll_depth` (0–100) |
|
|
302
|
+
| `$web_vitals` | `metric_name`, `metric_id`, `value`, `delta`, `rating`, `navigation_type`, `path` |
|
|
303
|
+
| `$exception` | `$exception_type`, `$exception_message`, `$exception_stack`, `$exception_source`, `$exception_handled`, `$exception_list`, `path` |
|