@groundcover/browser 2.2.0-rc.0 → 2.2.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +30 -33
  2. package/README.md +10 -12
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,10 +4,14 @@ 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.2.0-rc.0] — 2026-11-05
7
+ ## [2.2.1] — 2026-11-15
8
8
 
9
- First release candidate of `2.2.0`. Issues for thrown or rejected values that aren't `Error`s start
10
- new groups once; see Changed.
9
+ No changes to the SDK's behaviour from `2.2.0`: source comments and documentation only.
10
+
11
+ ## [2.2.0] — 2026-11-10
12
+
13
+ Stable release of `2.2.0-rc.0`, with no changes since. Issues for thrown or rejected values that
14
+ aren't `Error`s start new groups once; see Changed.
11
15
 
12
16
  ### Added
13
17
 
@@ -65,8 +69,8 @@ new groups once; see Changed.
65
69
  ## [2.1.1] — 2026-10-26
66
70
 
67
71
  Stable release of `2.1.1-rc.1`. Session replay takes its periodic full snapshot every 5 minutes
68
- instead of every 30 seconds. No configuration or API changes from `2.1.0`. `2.1.1-rc.0`, which tried
69
- moving checkouts to idle time instead, was not pursued.
72
+ instead of every 30 seconds. No configuration or API changes from `2.1.0`. `2.1.1-rc.1` supersedes
73
+ `2.1.1-rc.0`.
70
74
 
71
75
  The type declarations are byte-for-byte those of `2.1.0` and rc.1. The shipped JavaScript differs
72
76
  from rc.1 only in the text of the removed-option warnings below.
@@ -75,12 +79,11 @@ from rc.1 only in the text of the removed-option warnings below.
75
79
 
76
80
  - **Session replay's periodic full snapshot (rrweb's `checkoutEveryNms`) runs every 5 minutes**
77
81
  instead of every 30 seconds. Each checkout serializes the whole DOM synchronously, inside whichever
78
- recorded event triggers it (often a click, input or scroll), and uploads the full tree; on a
79
- ~7.8k-element dashboard that is ~50ms of main-thread work. 5 minutes matches other rrweb-based SDKs
80
- (PostHog, Grafana Faro, and Amplitude's recommended setting), so checkouts run 10× less often and
81
- send 10× fewer full snapshots. Every recording still starts with a full snapshot. A player that
82
- seeks from the nearest earlier full snapshot may fetch more data to reach a point deep in a long
83
- recording.
82
+ recorded event triggers it (often a click, input or scroll), and uploads the full tree; on a large
83
+ page that is tens of milliseconds of main-thread work. 5 minutes is a common interval for
84
+ rrweb-based recorders, so checkouts run 10× less often and send 10× fewer full snapshots. Every
85
+ recording still starts with a full snapshot. A player that seeks from the nearest earlier full
86
+ snapshot may fetch more data to reach a point deep in a long recording.
84
87
  - **The warnings for removed options point to this package's README on npm.** The console warnings
85
88
  for `enableMasking`, `maskFields` and `eventSampleRate` now name the README section to read
86
89
  ("Migrating to 1.0.0" or "Migrating from 1.x to 2.0.0") and link to the npm package page, instead
@@ -109,15 +112,14 @@ are otherwise unchanged.
109
112
  `preserveDrawingBuffer: true`).
110
113
  - **`fps` sets CPU cost and time resolution, not bytes.** rrweb re-encodes every canvas on every
111
114
  tick whether or not it changed, so the rate drives CPU even on a static page; a frame identical to
112
- the previous one is dropped, so bytes grow only when content changes. On a six-chart test
113
- dashboard, 1 fps used about 12% of a CPU core against about 35% at 4 fps, with the same bytes. A
114
- canvas state shorter than `1/fps` seconds may not appear in the replay, so raise `fps` for
115
- animated canvases.
115
+ the previous one is dropped, so bytes grow only when content changes. For scale, 4 fps costs a few
116
+ times the CPU of 1 fps for the same bytes. A canvas state shorter than `1/fps` seconds may not
117
+ appear in the replay, so raise `fps` for animated canvases.
116
118
  - **Changing `replay.canvas` through `updateConfig` restarts the active recording**, like
117
119
  `replay.blockedSelectors` and `privacy`. A partial update merges into the current canvas options,
118
120
  so `{ canvas: { fps: 8 } }` keeps capture enabled.
119
121
  - **README: canvas capture recipes** for dashboards, animated canvases, constrained bandwidth and
120
- CPU-sensitive pages, with measured costs for scale.
122
+ CPU-sensitive pages, with costs for scale.
121
123
 
122
124
  ### Fixed
123
125
 
@@ -185,9 +187,9 @@ it, in the browser package or in the shared core it bundles; the version field a
185
187
  only differences in the package.
186
188
 
187
189
  A wire-level ordering fix — sessions could report a start time later than events they carried,
188
- producing negative durations in the RUM session drawer — plus two `enrichEvent` corrections found
189
- while closing it. No API change and no configuration change: the `/json/rum` envelope keeps the same
190
- shape, and only the value of `session_start_time` on a rotated session changes.
190
+ producing negative session durations — plus two `enrichEvent` corrections. No API change and no
191
+ configuration change: the `/json/rum` envelope keeps the same shape, and only the value of
192
+ `session_start_time` on a rotated session changes.
191
193
 
192
194
  ### Fixed
193
195
 
@@ -238,10 +240,7 @@ structurally identical to 1.0.7, the published bundle contains the same 10 files
238
240
  `/json/rum` wire format is unchanged (pinned by a golden characterization suite). The generated
239
241
  declarations are no longer byte-for-byte identical to 1.0.7 — core's internal event types are now
240
242
  generic over the event vocabulary so the React Native package can extend it — but the exported
241
- surface is the same and `attributes.location` is still on the browser event map. The two behaviour
242
- changes below are the reason this shipped as an RC first rather than straight as a patch. The RC
243
- line was verified end-to-end against a live deployment (batches accepted, envelope matching the
244
- golden wire format, `attributes.location` intact, zero console errors).
243
+ surface is the same and `attributes.location` is still on the browser event map.
245
244
 
246
245
  ### Changed
247
246
 
@@ -261,14 +260,12 @@ golden wire format, `attributes.location` intact, zero console errors).
261
260
  - **A passing `console.assert()` is no longer captured as a log.** `console.assert(cond, …)` prints
262
261
  nothing when `cond` is truthy, but the SDK recorded *every* call as a `log` event — so assertions
263
262
  that passed silently filled RUM with lines the console itself never showed. Only failing
264
- assertions are captured now, matching the console's own semantics. Landed after `1.0.8-rc.7`,
265
- alongside the React Native SDK, which hit this hard: RN's event-target shim asserts on every
266
- DevTools-WebSocket event and stormed the listener.
263
+ assertions are captured now, matching the console's own semantics. Landed after `1.0.8-rc.7`.
267
264
  - **`groundcover.startNavigation()` / `endNavigation()` can no longer throw into your code.** The
268
265
  manual navigation API read `location.href` with no error boundary, so on a page with an
269
266
  instrumented or restricted `location` getter the exception propagated out of the SDK and into the
270
267
  caller's own stack. The automatic navigation path was already contained; these two now are as
271
- well. Pre-existing since before the core extraction, and unrelated to it.
268
+ well.
272
269
  - **The current view's title is no longer discarded when view derivation fails.** The error boundary
273
270
  around the browser's view provider returned a hardcoded empty view, so a throw anywhere after the
274
271
  document title had already been read (a hostile `location` getter, a user-supplied redactor)
@@ -291,10 +288,10 @@ golden wire format, `attributes.location` intact, zero console errors).
291
288
  ### Internal
292
289
 
293
290
  - The platform-agnostic pipeline (config, session policy, event enrichment, batching, redaction,
294
- transport) now lives in a private `@groundcover/rum-core` package, inlined into this bundle at
295
- build time. It compiles with no DOM lib so platform coupling fails the build, and the network
296
- send, storage, device metadata and view derivation are injected by this package. Groundwork for
297
- the React Native SDK; no effect on the published browser artifact.
291
+ transport) now lives in `@groundcover/rum-core`, an unpublished workspace package, inlined into
292
+ this bundle at build time. It compiles with no DOM lib so platform coupling fails the build, and
293
+ the network send, storage, device metadata and view derivation are injected by this package.
294
+ Groundwork for the React Native SDK; no effect on the published browser artifact.
298
295
 
299
296
  ## [1.0.5]
300
297
 
@@ -338,8 +335,8 @@ golden wire format, `attributes.location` intact, zero console errors).
338
335
 
339
336
  ### Fixed
340
337
 
341
- - **README images now render on npm.** The logo used a relative path and the CI badge pointed at the
342
- internal GitHub repo, so both 404'd on the npm package page. The logo is now served from the
338
+ - **README images now render on npm.** The logo used a relative path and the CI badge pointed at a
339
+ private repository, so both 404'd on the npm package page. The logo is now served from the
343
340
  published package via jsDelivr and the CI-status badge was removed.
344
341
 
345
342
  ## [1.0.0]
package/README.md CHANGED
@@ -62,7 +62,7 @@ one exception — it must be started explicitly with
62
62
 
63
63
  ```ts
64
64
  // Tie events to a user
65
- groundcover.identifyUser({ id: "u_123", email: "john@acme.com", organization: "acme" });
65
+ groundcover.identifyUser({ id: "u_123", email: "user@example.com", organization: "acme" });
66
66
 
67
67
  // Capture a handled error
68
68
  groundcover.captureException(new Error("Checkout failed"), { feature: "checkout" });
@@ -247,10 +247,9 @@ previous one, so an unchanged canvas sends nothing between full snapshots. The s
247
247
  the time resolution: a canvas state that lasts less than `1/fps` seconds, such as a brief transition
248
248
  or a hover highlight, may not appear in the replay. Raise `fps` when those moments matter.
249
249
 
250
- For scale, on a test dashboard with six canvas charts on a 2× display, canvas capture added about
251
- 280 KB/min while the charts were static and about 1 MB/min while they refreshed every 10 s. The
252
- recorder used about 12% of a CPU core at 1 fps and about 35% at 4 fps, with the same bytes. PNG at
253
- 4 fps used about 10%.
250
+ For scale, a dashboard with a handful of canvas charts adds a few hundred KB per minute while the
251
+ charts are static and around 1 MB per minute while they redraw. The recorder's CPU cost grows with
252
+ `fps` while the bytes stay the same, and PNG costs less CPU than webp at the same rate.
254
253
 
255
254
  Changing `replay.canvas` (or `replay.blockedSelectors`) via `updateConfig` restarts the active
256
255
  recording so the new options take effect at rrweb `record()` time. A partial `canvas` update merges
@@ -313,10 +312,9 @@ static imports before its body, so a client built at module scope is often const
313
312
 
314
313
  **`Request`-object calls are captured.** Clients that call
315
314
  `fetch(new Request(url, { method, body }))` (openapi-fetch does) carry the method and body on the
316
- `Request` rather than in an `init` argument; the SDK reads the method from either (since 1.0.4) and
317
- the request *body* from either (since 1.0.5). Method, URL, headers, status, request body, and
318
- response body are recorded. The `Request` body is read from a clone taken before the request is
319
- sent, so the app's copy is never consumed.
315
+ `Request` rather than in an `init` argument; the SDK reads the method and the request *body* from
316
+ either. Method, URL, headers, status, request body, and response body are recorded. The `Request`
317
+ body is read from a clone taken before the request is sent, so the app's copy is never consumed.
320
318
 
321
319
  Request and response bodies are captured the same way: up to a size cap, with redaction applied
322
320
  *before* truncation so sensitive keys are always masked. A body larger than the cap is recorded as
@@ -554,8 +552,8 @@ All methods are available on the default export and on `window.groundcover`.
554
552
 
555
553
  ### Structured logs
556
554
 
557
- `groundcover.logger` mirrors Sentry’s `logger` pattern — one method per level, second arg is the
558
- attributes object. Nested objects are flattened to dotted keys:
555
+ `groundcover.logger` has one method per level; the second argument is the attributes object.
556
+ Nested objects are flattened to dotted keys:
559
557
 
560
558
  ```ts
561
559
  groundcover.logger.warn("Checkout failed", {
@@ -573,7 +571,7 @@ set by the SDK and can’t be overridden.
573
571
  ```ts
574
572
  groundcover.identifyUser({
575
573
  id: "u_123",
576
- email: "john@acme.com",
574
+ email: "user@example.com",
577
575
  organization: "acme",
578
576
  });
579
577
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groundcover/browser",
3
- "version": "2.2.0-rc.0",
3
+ "version": "2.2.1",
4
4
  "description": "groundcover Real User Monitoring (RUM) SDK for the browser \u2014 performance, errors, logs, distributed tracing and session replay",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",