@groundcover/browser 2.0.0-rc.1 → 2.1.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -25
- package/README.md +55 -3
- package/dist/index.d.mts +46 -2
- package/dist/index.d.ts +46 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,64 @@ All notable changes to `@groundcover/browser` are documented here. This project
|
|
|
4
4
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the
|
|
5
5
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format.
|
|
6
6
|
|
|
7
|
-
## [2.
|
|
7
|
+
## [2.1.0-rc.0] — 2026-10-06
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
First release candidate of `2.1.0`, on top of `2.0.0`. Adds opt-in canvas capture to session replay;
|
|
10
|
+
nothing changes unless `options.replay.canvas.enabled` is set.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Session replay can capture `<canvas>`-rendered content** (e.g. chart data series that replayed
|
|
15
|
+
as empty frames) via `options.replay.canvas`. Off by default. `enabled` maps to rrweb
|
|
16
|
+
`recordCanvas`, `fps` (default 4, clamped to 1–15 with a warning) to `sampling.canvas`, and
|
|
17
|
+
`imageType` / `imageQuality` (default `image/webp` at 0.6) to `dataURLOptions`. Canvas frames are
|
|
18
|
+
pixel snapshots: they increase replay bandwidth and page CPU, and are **not** covered by `privacy`
|
|
19
|
+
text/input masking. WebGL capture is best-effort only (the page's context must use
|
|
20
|
+
`preserveDrawingBuffer: true`).
|
|
21
|
+
- **Changing `replay.canvas` through `updateConfig` restarts the active recording**, like
|
|
22
|
+
`replay.blockedSelectors` and `privacy`. A partial update merges into the current canvas options,
|
|
23
|
+
so `{ canvas: { fps: 8 } }` keeps capture enabled.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **rrweb recorder errors stay inside the SDK.** Observer failures that fire after `record()`
|
|
28
|
+
returns are routed through the SDK's error handler instead of reaching the host page.
|
|
29
|
+
- **`updateConfig` restarts the recording only for keys the update itself sets.** An inherited
|
|
30
|
+
(non-own) `privacy` or `replay` key no longer splits the recording without changing the config.
|
|
31
|
+
|
|
32
|
+
## [2.0.0] — 2026-10-06
|
|
33
|
+
|
|
34
|
+
Stable release of the `2.0.0-rc.0` and `2.0.0-rc.1` line. **Contains breaking changes from `1.x`** —
|
|
35
|
+
see [Migrating from 1.x to 2.0.0](./README.md#migrating-from-1x-to-200).
|
|
36
|
+
|
|
37
|
+
The shipped `dist/` is byte-for-byte rc.1's — nothing landed after it, in the browser package or in
|
|
38
|
+
the shared core it bundles; the version field, this entry and the migration guide's install command
|
|
39
|
+
are the only differences in the package. Network and exception shaping now live in the core shared
|
|
40
|
+
with `@groundcover/react-native`; the `/json/rum` envelope keeps its shape, and what changes on the
|
|
41
|
+
wire is listed below.
|
|
42
|
+
|
|
43
|
+
Against `1.0.9`, the exported `EventTypes`, `PrivacyOptions`, `Redactor`, `RedactField`, `RedactKind`
|
|
44
|
+
and `PrivacyLevel` are structurally identical. `SDKOptions` drops `eventSampleRate`, `init()` requires
|
|
45
|
+
`appId`, and `updateConfig()` no longer types `appId`. TypeScript enforces `appId` on every `init()`
|
|
46
|
+
call, but flags the two removed fields only where they are written directly in an object literal: a
|
|
47
|
+
variable or spread that also carries valid fields still compiles (an initialization config spread
|
|
48
|
+
into `updateConfig()`, say) and reaches the runtime handling below.
|
|
49
|
+
|
|
50
|
+
### Changed (breaking)
|
|
51
|
+
|
|
52
|
+
- **Event-level sampling is removed.** `options.eventSampleRate` warns and is ignored, on `init` and
|
|
53
|
+
on `updateConfig`; use `options.sessionSampleRate` to select whole sessions. Rates are not
|
|
54
|
+
converted.
|
|
55
|
+
- **`appId` is required and fixed per SDK instance.** It must be a non-blank string, its value is
|
|
56
|
+
preserved exactly, the first successful `init` wins (later calls are ignored; a failed init may be
|
|
57
|
+
retried), and `updateConfig` rejects any update that contains `appId`.
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- **`span_name` carries the upper-cased method**, like `operation.name`: `fetch(url, { method: "post" })`
|
|
62
|
+
is the span `POST /path`, not a separate `post /path`. A missing method reads `UNKNOWN`.
|
|
63
|
+
- **An opaque host object passed without a key is labelled `opaque_node`** (was `dom_node`) by the
|
|
64
|
+
enricher's placeholder. Keyed placeholders are unchanged.
|
|
12
65
|
|
|
13
66
|
### Fixed
|
|
14
67
|
|
|
@@ -28,27 +81,6 @@ differences on the wire.
|
|
|
28
81
|
- **Navigation instrumentation wraps the history methods present at initialization**, keeping a
|
|
29
82
|
router that wrapped them after the SDK was constructed.
|
|
30
83
|
|
|
31
|
-
### Changed
|
|
32
|
-
|
|
33
|
-
- **`span_name` carries the upper-cased method**, like `operation.name`: `fetch(url, { method: "post" })`
|
|
34
|
-
is the span `POST /path`, not a separate `post /path`. A missing method reads `UNKNOWN`.
|
|
35
|
-
- **An opaque host object passed without a key is labelled `opaque_node`** (was `dom_node`) by the
|
|
36
|
-
enricher's placeholder. Keyed placeholders are unchanged.
|
|
37
|
-
|
|
38
|
-
## [2.0.0-rc.0] — 2026-09-28
|
|
39
|
-
|
|
40
|
-
First release candidate of `2.0.0`. **Contains breaking changes from `1.x`** — see
|
|
41
|
-
[Migrating from 1.x to 2.0.0](./README.md#migrating-from-1x-to-200).
|
|
42
|
-
|
|
43
|
-
### Changed (breaking)
|
|
44
|
-
|
|
45
|
-
- **Event-level sampling is removed.** `options.eventSampleRate` warns and is ignored, on `init` and
|
|
46
|
-
on `updateConfig`; use `options.sessionSampleRate` to select whole sessions. Rates are not
|
|
47
|
-
converted.
|
|
48
|
-
- **`appId` is required and fixed per SDK instance.** It must be a non-blank string, its value is
|
|
49
|
-
preserved exactly, the first successful `init` wins (later calls are ignored; a failed init may be
|
|
50
|
-
retried), and `updateConfig` rejects any update that contains `appId`.
|
|
51
|
-
|
|
52
84
|
## [1.0.9]
|
|
53
85
|
|
|
54
86
|
Stable release of `1.0.9-rc.0`. The shipped `dist/` is byte-for-byte the RC's — nothing landed after
|
package/README.md
CHANGED
|
@@ -179,17 +179,68 @@ content use [`privacy`](#privacy--data-masking).
|
|
|
179
179
|
| Option | Type | Default | Description |
|
|
180
180
|
|---|---|---|---|
|
|
181
181
|
| `blockedSelectors` | `string[]` | — | CSS selectors whose elements (and subtrees) are excluded from recording. Useful for noisy extension-injected DOM (e.g. Grammarly). |
|
|
182
|
+
| `canvas` | `ReplayCanvasOptions` | off | **Opt-in** capture of `<canvas>`-rendered content (charts, WebGL widgets). Off by default — see [Canvas capture](#canvas-capture-opt-in) for the fields and tradeoffs. |
|
|
182
183
|
|
|
183
184
|
> ⚠️ Don’t confuse `options.replay.blockedSelectors` (recording noise reduction) with
|
|
184
185
|
> `options.privacy.replay.*` (rrweb masking callbacks). They live at different levels and serve
|
|
185
186
|
> different purposes.
|
|
186
187
|
|
|
188
|
+
#### Canvas capture (opt-in)
|
|
189
|
+
|
|
190
|
+
By default rrweb only serializes the DOM/SVG around a `<canvas>`, so anything **drawn to a canvas**
|
|
191
|
+
— chart data series, WebGL scenes — is **not** recorded and replays as an empty frame. Set
|
|
192
|
+
`options.replay.canvas.enabled` to capture canvas pixels as periodic image snapshots.
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
groundcover.init({
|
|
196
|
+
// …
|
|
197
|
+
options: {
|
|
198
|
+
enabledEvents: ["replay" /* … */],
|
|
199
|
+
replay: {
|
|
200
|
+
canvas: {
|
|
201
|
+
enabled: true, // default false
|
|
202
|
+
fps: 4, // default 4, clamped to [1, 15]
|
|
203
|
+
imageType: "image/webp", // default 'image/webp' ('image/jpeg' | 'image/png')
|
|
204
|
+
imageQuality: 0.6, // default 0.6 (lossy formats only)
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
| Field | Type | Default | Maps to rrweb |
|
|
212
|
+
|---|---|---|---|
|
|
213
|
+
| `enabled` | `boolean` | `false` | `recordCanvas` |
|
|
214
|
+
| `fps` | `number` | `4` (clamped `[1, 15]`) | `sampling.canvas` |
|
|
215
|
+
| `imageType` | `'image/webp' \| 'image/jpeg' \| 'image/png'` | `'image/webp'` | `dataURLOptions.type` |
|
|
216
|
+
| `imageQuality` | `number` (0–1) | `0.6` | `dataURLOptions.quality` |
|
|
217
|
+
|
|
218
|
+
> ⚠️ **Canvas capture is expensive and off by default for good reason.** Enable it only when you
|
|
219
|
+
> knowingly accept the tradeoffs:
|
|
220
|
+
> - **Bandwidth** — every snapshot is a serialized image, so replay payloads grow substantially on
|
|
221
|
+
> canvas-heavy pages. Keep `fps` low and prefer lossy `image/webp`/`image/jpeg`.
|
|
222
|
+
> - **CPU** — snapshotting runs on the recorded (end-user) page and adds work to a busy dashboard.
|
|
223
|
+
> - **Privacy** — canvas pixels **bypass `privacy` text/input masking entirely**. Whatever is drawn
|
|
224
|
+
> is captured verbatim; do not enable canvas capture on views that render sensitive data to a
|
|
225
|
+
> canvas.
|
|
226
|
+
|
|
227
|
+
> **WebGL:** capture is **best-effort and not officially supported** by this option. Snapshotting a
|
|
228
|
+
> WebGL/WebGL2 canvas only yields pixels if the page created its context with
|
|
229
|
+
> `preserveDrawingBuffer: true`; otherwise frames may come back blank. 2D canvases (the common chart
|
|
230
|
+
> case) are captured reliably.
|
|
231
|
+
|
|
232
|
+
Changing `replay.canvas` (or `replay.blockedSelectors`) via `updateConfig` restarts the active
|
|
233
|
+
recording so the new options take effect at rrweb `record()` time. A partial `canvas` update merges
|
|
234
|
+
into the current one, so `{ canvas: { fps: 8 } }` keeps capture enabled; pass `enabled: false` to
|
|
235
|
+
turn it off.
|
|
236
|
+
|
|
187
237
|
### Updating config at runtime
|
|
188
238
|
|
|
189
239
|
`updateConfig` accepts these optional fields: `cluster`, `environment`, `namespace`, `releaseId`,
|
|
190
240
|
`dsn`, `apiKey`, `options`, and `user`. `appId` cannot be updated. `sessionId` is not accepted;
|
|
191
|
-
use the separate `setSessionId()` API. Nested groups merge one level deep (and `tracing.origin
|
|
192
|
-
`privacy.replay` one level deeper), so a partial update preserves the other keys in
|
|
241
|
+
use the separate `setSessionId()` API. Nested groups merge one level deep (and `tracing.origin`,
|
|
242
|
+
`privacy.replay` and `replay.canvas` one level deeper), so a partial update preserves the other keys in
|
|
243
|
+
the group:
|
|
193
244
|
|
|
194
245
|
```ts
|
|
195
246
|
groundcover.updateConfig({
|
|
@@ -320,6 +371,7 @@ record-time masking from your [`privacy`](#privacy--data-masking) config:
|
|
|
320
371
|
- `privacy.level` / `privacy.maskSelectors` → rrweb `maskAllInputs` + `maskTextSelector`
|
|
321
372
|
- `privacy.replay.maskTextFn` / `maskInputFn` → rrweb `maskTextFn` / `maskInputFn`
|
|
322
373
|
- `options.replay.blockedSelectors` → rrweb `blockSelector` (noise reduction)
|
|
374
|
+
- `options.replay.canvas` → rrweb `recordCanvas` + `sampling.canvas` + `dataURLOptions` (opt-in, off by default — see [Canvas capture](#canvas-capture-opt-in))
|
|
323
375
|
|
|
324
376
|
Replay recording does **not** start automatically — even when `replay` is in `enabledEvents`. You
|
|
325
377
|
must start it explicitly (e.g. after obtaining user consent):
|
|
@@ -521,7 +573,7 @@ successful initialization. These are breaking changes; review your initializatio
|
|
|
521
573
|
updates before upgrading:
|
|
522
574
|
|
|
523
575
|
```bash
|
|
524
|
-
npm install @groundcover/browser
|
|
576
|
+
npm install @groundcover/browser@^2.0.0
|
|
525
577
|
```
|
|
526
578
|
|
|
527
579
|
| Change | Migration |
|
package/dist/index.d.mts
CHANGED
|
@@ -324,6 +324,44 @@ type EventTypes = {
|
|
|
324
324
|
};
|
|
325
325
|
/** The browser SDK's listener names for `enabledEvents`. */
|
|
326
326
|
type BrowserEventName = "dom" | "network" | "exceptions" | "logs" | "pageload" | "navigation" | "performance" | "replay";
|
|
327
|
+
/**
|
|
328
|
+
* Opt-in canvas capture for session replay. Charts and other `<canvas>`-drawn
|
|
329
|
+
* content (2D or WebGL) are NOT recorded by default; rrweb only serializes the
|
|
330
|
+
* DOM/SVG around them, so canvas-rendered data series replay as empty frames.
|
|
331
|
+
* Enabling this makes rrweb snapshot canvas pixels.
|
|
332
|
+
*
|
|
333
|
+
* ⚠️ HIGH COST — off by default for good reason:
|
|
334
|
+
* - Bandwidth: canvas frames serialize as images, inflating replay payloads.
|
|
335
|
+
* - CPU: snapshotting canvases is costly on the recorded (customer) page.
|
|
336
|
+
* - Privacy: canvas pixels bypass text/input masking entirely — whatever is
|
|
337
|
+
* drawn is captured verbatim, regardless of the `privacy` config.
|
|
338
|
+
*/
|
|
339
|
+
interface ReplayCanvasOptions {
|
|
340
|
+
/**
|
|
341
|
+
* Enable canvas capture. Defaults to `false` (canvas is not recorded). Maps
|
|
342
|
+
* to rrweb's `recordCanvas`.
|
|
343
|
+
*/
|
|
344
|
+
enabled?: boolean;
|
|
345
|
+
/**
|
|
346
|
+
* Snapshot frame rate, in frames per second. Defaults to 4 and is clamped to
|
|
347
|
+
* [1, 15]; out-of-range values are clamped with a `console.warn`. Maps to
|
|
348
|
+
* rrweb's `sampling.canvas`. Higher values mean smoother playback but larger
|
|
349
|
+
* payloads and more CPU.
|
|
350
|
+
*/
|
|
351
|
+
fps?: number;
|
|
352
|
+
/**
|
|
353
|
+
* Image format for canvas snapshots. Defaults to `'image/webp'` (much smaller
|
|
354
|
+
* than rrweb's default lossless `image/png`). Maps to rrweb
|
|
355
|
+
* `dataURLOptions.type`.
|
|
356
|
+
*/
|
|
357
|
+
imageType?: "image/webp" | "image/jpeg" | "image/png";
|
|
358
|
+
/**
|
|
359
|
+
* Lossy compression quality in [0, 1] for `image/webp` / `image/jpeg`.
|
|
360
|
+
* Defaults to 0.6 (ignored for `image/png`). Maps to rrweb
|
|
361
|
+
* `dataURLOptions.quality`.
|
|
362
|
+
*/
|
|
363
|
+
imageQuality?: number;
|
|
364
|
+
}
|
|
327
365
|
/**
|
|
328
366
|
* Session-replay (rrweb) recording controls. This is NOT a privacy surface —
|
|
329
367
|
* to mask sensitive content use `privacy`.
|
|
@@ -339,6 +377,12 @@ interface ReplayOptions {
|
|
|
339
377
|
* sensitive content use `privacy` instead.
|
|
340
378
|
*/
|
|
341
379
|
blockedSelectors?: string[];
|
|
380
|
+
/**
|
|
381
|
+
* Opt-in canvas capture (chart data series, WebGL-backed widgets). Off by
|
|
382
|
+
* default. Capturing canvas is bandwidth-, CPU-, and privacy-sensitive — see
|
|
383
|
+
* {@link ReplayCanvasOptions}.
|
|
384
|
+
*/
|
|
385
|
+
canvas?: ReplayCanvasOptions;
|
|
342
386
|
}
|
|
343
387
|
/** Session-recording (rrweb replay) masking — the only place replay can be masked. */
|
|
344
388
|
interface ReplayMaskingOptions {
|
|
@@ -369,8 +413,8 @@ interface SDKOptions extends Omit<SDKOptions$1, "privacy" | "enabledEvents" | "b
|
|
|
369
413
|
*/
|
|
370
414
|
privacy?: PrivacyOptions;
|
|
371
415
|
/**
|
|
372
|
-
* Session-replay recording controls (noise reduction
|
|
373
|
-
* `privacy` instead. See {@link ReplayOptions}.
|
|
416
|
+
* Session-replay recording controls (noise reduction, opt-in canvas capture).
|
|
417
|
+
* For replay MASKING use `privacy` instead. See {@link ReplayOptions}.
|
|
374
418
|
*/
|
|
375
419
|
replay?: ReplayOptions;
|
|
376
420
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -324,6 +324,44 @@ type EventTypes = {
|
|
|
324
324
|
};
|
|
325
325
|
/** The browser SDK's listener names for `enabledEvents`. */
|
|
326
326
|
type BrowserEventName = "dom" | "network" | "exceptions" | "logs" | "pageload" | "navigation" | "performance" | "replay";
|
|
327
|
+
/**
|
|
328
|
+
* Opt-in canvas capture for session replay. Charts and other `<canvas>`-drawn
|
|
329
|
+
* content (2D or WebGL) are NOT recorded by default; rrweb only serializes the
|
|
330
|
+
* DOM/SVG around them, so canvas-rendered data series replay as empty frames.
|
|
331
|
+
* Enabling this makes rrweb snapshot canvas pixels.
|
|
332
|
+
*
|
|
333
|
+
* ⚠️ HIGH COST — off by default for good reason:
|
|
334
|
+
* - Bandwidth: canvas frames serialize as images, inflating replay payloads.
|
|
335
|
+
* - CPU: snapshotting canvases is costly on the recorded (customer) page.
|
|
336
|
+
* - Privacy: canvas pixels bypass text/input masking entirely — whatever is
|
|
337
|
+
* drawn is captured verbatim, regardless of the `privacy` config.
|
|
338
|
+
*/
|
|
339
|
+
interface ReplayCanvasOptions {
|
|
340
|
+
/**
|
|
341
|
+
* Enable canvas capture. Defaults to `false` (canvas is not recorded). Maps
|
|
342
|
+
* to rrweb's `recordCanvas`.
|
|
343
|
+
*/
|
|
344
|
+
enabled?: boolean;
|
|
345
|
+
/**
|
|
346
|
+
* Snapshot frame rate, in frames per second. Defaults to 4 and is clamped to
|
|
347
|
+
* [1, 15]; out-of-range values are clamped with a `console.warn`. Maps to
|
|
348
|
+
* rrweb's `sampling.canvas`. Higher values mean smoother playback but larger
|
|
349
|
+
* payloads and more CPU.
|
|
350
|
+
*/
|
|
351
|
+
fps?: number;
|
|
352
|
+
/**
|
|
353
|
+
* Image format for canvas snapshots. Defaults to `'image/webp'` (much smaller
|
|
354
|
+
* than rrweb's default lossless `image/png`). Maps to rrweb
|
|
355
|
+
* `dataURLOptions.type`.
|
|
356
|
+
*/
|
|
357
|
+
imageType?: "image/webp" | "image/jpeg" | "image/png";
|
|
358
|
+
/**
|
|
359
|
+
* Lossy compression quality in [0, 1] for `image/webp` / `image/jpeg`.
|
|
360
|
+
* Defaults to 0.6 (ignored for `image/png`). Maps to rrweb
|
|
361
|
+
* `dataURLOptions.quality`.
|
|
362
|
+
*/
|
|
363
|
+
imageQuality?: number;
|
|
364
|
+
}
|
|
327
365
|
/**
|
|
328
366
|
* Session-replay (rrweb) recording controls. This is NOT a privacy surface —
|
|
329
367
|
* to mask sensitive content use `privacy`.
|
|
@@ -339,6 +377,12 @@ interface ReplayOptions {
|
|
|
339
377
|
* sensitive content use `privacy` instead.
|
|
340
378
|
*/
|
|
341
379
|
blockedSelectors?: string[];
|
|
380
|
+
/**
|
|
381
|
+
* Opt-in canvas capture (chart data series, WebGL-backed widgets). Off by
|
|
382
|
+
* default. Capturing canvas is bandwidth-, CPU-, and privacy-sensitive — see
|
|
383
|
+
* {@link ReplayCanvasOptions}.
|
|
384
|
+
*/
|
|
385
|
+
canvas?: ReplayCanvasOptions;
|
|
342
386
|
}
|
|
343
387
|
/** Session-recording (rrweb replay) masking — the only place replay can be masked. */
|
|
344
388
|
interface ReplayMaskingOptions {
|
|
@@ -369,8 +413,8 @@ interface SDKOptions extends Omit<SDKOptions$1, "privacy" | "enabledEvents" | "b
|
|
|
369
413
|
*/
|
|
370
414
|
privacy?: PrivacyOptions;
|
|
371
415
|
/**
|
|
372
|
-
* Session-replay recording controls (noise reduction
|
|
373
|
-
* `privacy` instead. See {@link ReplayOptions}.
|
|
416
|
+
* Session-replay recording controls (noise reduction, opt-in canvas capture).
|
|
417
|
+
* For replay MASKING use `privacy` instead. See {@link ReplayOptions}.
|
|
374
418
|
*/
|
|
375
419
|
replay?: ReplayOptions;
|
|
376
420
|
}
|