@groundcover/browser 1.0.9 → 2.0.0-rc.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.
- package/CHANGELOG.md +45 -0
- package/README.md +86 -10
- package/dist/index.d.mts +98 -164
- package/dist/index.d.ts +98 -164
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,51 @@ 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.0.0-rc.1] — 2026-09-29
|
|
8
|
+
|
|
9
|
+
Second release candidate of `2.0.0`. Network and exception shaping move into the core shared with
|
|
10
|
+
`@groundcover/react-native`. The `/json/rum` envelope is unchanged; the changes below are the only
|
|
11
|
+
differences on the wire.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`tracing.propagationUrls` treats only `*` as a wildcard.** Every other character kept its regex
|
|
16
|
+
meaning, so `https://api.example.com/*` also matched `https://api-example.com/…` and trace headers
|
|
17
|
+
(plus any `tracing.origin` header) were sent to lookalike hosts.
|
|
18
|
+
- **A path pattern such as `"/api/*"` matches same-origin requests only, whether they are written as
|
|
19
|
+
relative or absolute URLs.** XHR requests opened with a relative URL were never matched (XHR stores
|
|
20
|
+
the resolved URL), and a protocol-relative `//other-host/api/…` was. Patterns are matched against
|
|
21
|
+
the URL the browser actually requests, so `https://app/api/../private` no longer matches
|
|
22
|
+
`https://app/api/*`.
|
|
23
|
+
- **`fetch` events keep their trace ids when a configured header name has capitals.** `fetch` stores
|
|
24
|
+
request headers lowercased, so `traceIdHeaderName: "X-Trace-Id"` or
|
|
25
|
+
`propagationHeaders: ["X-Custom"]` never matched on read-back.
|
|
26
|
+
- **A read-only `fetch` no longer costs the XHR capture** (and no longer throws out of
|
|
27
|
+
initialization); the two transports are instrumented independently.
|
|
28
|
+
- **Navigation instrumentation wraps the history methods present at initialization**, keeping a
|
|
29
|
+
router that wrapped them after the SDK was constructed.
|
|
30
|
+
|
|
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
|
+
|
|
7
52
|
## [1.0.9]
|
|
8
53
|
|
|
9
54
|
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
|
@@ -32,6 +32,7 @@ for the full product guide.
|
|
|
32
32
|
- [Session lifecycle](#session-lifecycle)
|
|
33
33
|
- [Performance considerations](#performance-considerations)
|
|
34
34
|
- [API reference](#api-reference)
|
|
35
|
+
- [Migrating from 1.x to 2.0.0](#migrating-from-1x-to-200)
|
|
35
36
|
- [Migrating to 1.0.0](#migrating-to-100)
|
|
36
37
|
|
|
37
38
|
---
|
|
@@ -80,6 +81,11 @@ groundcover.sendCustomEvent({ event: "plan_upgraded", attributes: { plan: "pro"
|
|
|
80
81
|
`init()` takes connection/identity fields at the top level and all behavioral knobs under
|
|
81
82
|
`options`, grouped by concern.
|
|
82
83
|
|
|
84
|
+
The first successful `init()` initializes the SDK. Every later call is silently ignored, even with
|
|
85
|
+
a different `appId` or config. Calls made during initialization are also ignored; if initialization
|
|
86
|
+
fails, a later call can retry. Use [`updateConfig()`](#updating-config-at-runtime) or the other runtime
|
|
87
|
+
APIs for supported changes.
|
|
88
|
+
|
|
83
89
|
```ts
|
|
84
90
|
groundcover.init({
|
|
85
91
|
// ── Connection & identity ──
|
|
@@ -89,7 +95,7 @@ groundcover.init({
|
|
|
89
95
|
|
|
90
96
|
options: {
|
|
91
97
|
debug,
|
|
92
|
-
sessionSampleRate,
|
|
98
|
+
sessionSampleRate,
|
|
93
99
|
enabledEvents, excludedUrls,
|
|
94
100
|
sessionMaxDuration,
|
|
95
101
|
beforeSend, enrichEvent,
|
|
@@ -108,7 +114,7 @@ groundcover.init({
|
|
|
108
114
|
| `apiKey` | `string` | ✅ | Your groundcover RUM API key. |
|
|
109
115
|
| `dsn` | `string` | ✅ | RUM intake endpoint. A bare host is upgraded to `https://`. |
|
|
110
116
|
| `cluster` | `string` | ✅ | Target groundcover cluster. |
|
|
111
|
-
| `appId` | `string` | ✅ |
|
|
117
|
+
| `appId` | `string` | ✅ | Required application identifier; cannot be empty or whitespace-only. Reported unchanged as `service.name`. |
|
|
112
118
|
| `environment` | `string` | — | Deployment environment (e.g. `production`, `staging`). |
|
|
113
119
|
| `namespace` | `string` | — | Logical grouping/namespace for the app. |
|
|
114
120
|
| `releaseId` | `string` | — | Release/version identifier (e.g. a semver or commit hash). |
|
|
@@ -122,7 +128,6 @@ groundcover.init({
|
|
|
122
128
|
|---|---|---|---|
|
|
123
129
|
| `debug` | `boolean` | `false` | Verbose SDK console logging. |
|
|
124
130
|
| `sessionSampleRate` | `number` | `1` | Fraction of sessions captured (0–1). |
|
|
125
|
-
| `eventSampleRate` | `number` | `1` | Fraction of events captured (0–1). |
|
|
126
131
|
| `enabledEvents` | `Array<…>` | `[]` | Instrumentations to enable. **Empty = all.** Members: `dom`, `network`, `exceptions`, `logs`, `pageload`, `navigation`, `performance`, `replay`. Note: `replay` still requires an explicit [`startReplayRecording()`](#session-replay) call — it never auto-starts. |
|
|
127
132
|
| `excludedUrls` | `Array<string \| RegExp>` | — | Network requests matching these are not captured. |
|
|
128
133
|
| `sessionMaxDuration` | `number` | `4h` | Target max session length in ms (1 min – 8 h). See [session lifecycle](#session-lifecycle). |
|
|
@@ -140,7 +145,7 @@ Distributed-tracing header propagation for outgoing requests.
|
|
|
140
145
|
|
|
141
146
|
| Option | Type | Default | Description |
|
|
142
147
|
|---|---|---|---|
|
|
143
|
-
| `propagationUrls` | `string[]` | `[]` | Request URLs
|
|
148
|
+
| `propagationUrls` | `string[]` | `[]` | Request URLs that receive injected tracing headers. Each pattern must match the whole URL; only `*` is a wildcard. A path pattern such as `"/api/*"` matches same-origin requests only. |
|
|
144
149
|
| `propagationHeaders` | `string[]` | `[]` | Header names to read/propagate onto traced requests. |
|
|
145
150
|
| `traceIdHeaderName` | `string` | `""` | Header carrying the trace id. |
|
|
146
151
|
| `spanIdHeaderName` | `string` | `""` | Header carrying the span id. |
|
|
@@ -181,7 +186,9 @@ content use [`privacy`](#privacy--data-masking).
|
|
|
181
186
|
|
|
182
187
|
### Updating config at runtime
|
|
183
188
|
|
|
184
|
-
`updateConfig`
|
|
189
|
+
`updateConfig` accepts these optional fields: `cluster`, `environment`, `namespace`, `releaseId`,
|
|
190
|
+
`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` /
|
|
185
192
|
`privacy.replay` one level deeper), so a partial update preserves the other keys in the group:
|
|
186
193
|
|
|
187
194
|
```ts
|
|
@@ -423,14 +430,20 @@ every other guarantee here is stated for that case.
|
|
|
423
430
|
|
|
424
431
|
### Micro-frontend session synchronization
|
|
425
432
|
|
|
426
|
-
|
|
433
|
+
Initialize the shared SDK once in the shell with a shared `sessionId` so the micro-frontends report
|
|
434
|
+
under one session. Each micro-frontend uses that same SDK to capture events:
|
|
427
435
|
|
|
428
436
|
```ts
|
|
437
|
+
// Shell
|
|
429
438
|
const sharedSessionId = "session-12345";
|
|
430
|
-
groundcover.init({
|
|
431
|
-
|
|
439
|
+
groundcover.init({ apiKey, dsn, cluster, appId: "your-app-id", sessionId: sharedSessionId });
|
|
440
|
+
|
|
441
|
+
// Micro-frontend using the shared SDK
|
|
442
|
+
groundcover.sendCustomEvent({ event: "checkout_opened", attributes: { cartId: "cart-123" } });
|
|
432
443
|
```
|
|
433
444
|
|
|
445
|
+
If you need to explicitly rebind the shared SDK to another session, use `setSessionId()`.
|
|
446
|
+
|
|
434
447
|
---
|
|
435
448
|
|
|
436
449
|
## Performance considerations
|
|
@@ -438,7 +451,8 @@ groundcover.init({ /* …mfe… */ apiKey, dsn, cluster, appId: "micro-frontend"
|
|
|
438
451
|
- **Batching & compression** — events are buffered (`transport.batchSize` / `transport.batchTimeout`) and
|
|
439
452
|
gzipped (`transport.compression`) to minimize request count and payload size.
|
|
440
453
|
- **Web Worker offload** — replay packing and gzip run off the main thread (see above).
|
|
441
|
-
- **Sampling** —
|
|
454
|
+
- **Sampling** — use `sessionSampleRate` to select whole sessions. Events within selected
|
|
455
|
+
sessions are not randomly sampled; enabled-event settings, filtering, and privacy controls still apply.
|
|
442
456
|
- **Scope what you capture** — drop noisy endpoints with `excludedUrls`, and disable unused
|
|
443
457
|
instrumentations via `enabledEvents`.
|
|
444
458
|
- **Lazy session rotation** — no background timers; rotation work happens only on real activity.
|
|
@@ -453,7 +467,7 @@ All methods are available on the default export and on `window.groundcover`.
|
|
|
453
467
|
|
|
454
468
|
| Method | Description |
|
|
455
469
|
|---|---|
|
|
456
|
-
| `init(config)` | Initialize the SDK and install instrumentation. |
|
|
470
|
+
| `init(config)` | Initialize the SDK and install instrumentation once; calls after successful initialization are ignored. |
|
|
457
471
|
| `identifyUser(user)` | Attach user identity to subsequent events. |
|
|
458
472
|
| `sendCustomEvent({ event, attributes })` | Emit a custom business event. |
|
|
459
473
|
| `captureException(error, metadata?)` | Capture a handled error with optional context. |
|
|
@@ -500,6 +514,68 @@ groundcover.captureException(new Error("Payment failed"), {
|
|
|
500
514
|
|
|
501
515
|
---
|
|
502
516
|
|
|
517
|
+
## Migrating from 1.x to 2.0.0
|
|
518
|
+
|
|
519
|
+
`2.0.0` removes event-level sampling and makes browser application identity fixed after the first
|
|
520
|
+
successful initialization. These are breaking changes; review your initialization and runtime
|
|
521
|
+
updates before upgrading:
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
npm install @groundcover/browser@2.0.0-rc.1
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
| Change | Migration |
|
|
528
|
+
|---|---|
|
|
529
|
+
| `options.eventSampleRate` is removed | Delete it from initialization and runtime updates. Choose `options.sessionSampleRate` explicitly if you need to limit capture volume. |
|
|
530
|
+
| `appId` is required and cannot be blank | Supply a non-empty, non-whitespace string at initialization. Its value is preserved exactly. |
|
|
531
|
+
| Each SDK instance initializes once | Initialize in your application's bootstrap code. Use runtime APIs instead of calling `init()` again. |
|
|
532
|
+
| `appId` cannot be updated | Exclude it from `updateConfig()`, including when spreading an initialization config. Its presence rejects the entire update, even if its value is unchanged or `undefined`. |
|
|
533
|
+
|
|
534
|
+
### Why event-level sampling was removed
|
|
535
|
+
|
|
536
|
+
Randomly dropping individual events leaves gaps in user journeys and can distort funnel analysis.
|
|
537
|
+
The SDK now uses `sessionSampleRate` to select sessions without randomly dropping individual events
|
|
538
|
+
within them. Enabled-event settings, filtering, and privacy controls still apply; session replay
|
|
539
|
+
still requires an explicit start.
|
|
540
|
+
|
|
541
|
+
> **Volume warning:** If you previously set `eventSampleRate` below `1`, upgrading can increase event
|
|
542
|
+
> volume. The removed option has no effect: passing it warns and strips it from stored configuration.
|
|
543
|
+
> `sessionSampleRate` is not a rename or an equivalent numeric replacement: `0.1` selects roughly 10%
|
|
544
|
+
> of sessions, rather than sampling 10% of events within sessions. Rates are never automatically
|
|
545
|
+
> converted. If event sampling was left at its default of `1`, this removal does not increase capture
|
|
546
|
+
> through sampling alone.
|
|
547
|
+
|
|
548
|
+
For example, if you deliberately choose to capture 10% of sessions:
|
|
549
|
+
|
|
550
|
+
```ts
|
|
551
|
+
groundcover.init({
|
|
552
|
+
apiKey, dsn, cluster,
|
|
553
|
+
appId: "checkout",
|
|
554
|
+
options: { sessionSampleRate: 0.1 },
|
|
555
|
+
});
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### Initialize once; update supported fields explicitly
|
|
559
|
+
|
|
560
|
+
Missing, non-string, or blank `appId` values produce a warning and leave the SDK uninitialized.
|
|
561
|
+
After correcting the input, call `init()` again. A failed initialization also permits an explicit
|
|
562
|
+
retry; calls during initialization or after success are silently ignored, regardless of `appId`.
|
|
563
|
+
|
|
564
|
+
Do not spread your initialization config into a runtime update:
|
|
565
|
+
|
|
566
|
+
```ts
|
|
567
|
+
// Pass only the fields you intend to change, without appId.
|
|
568
|
+
groundcover.updateConfig({ dsn: newDsn, apiKey: newApiKey, cluster: newCluster });
|
|
569
|
+
groundcover.identifyUser({ id: "user-123" });
|
|
570
|
+
await groundcover.setSessionId("shared-session-id");
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
An update containing `appId` warns and applies **none** of its fields. Use `identifyUser()` for user
|
|
574
|
+
identity and `setSessionId()` for session identity; neither changes the application identity.
|
|
575
|
+
For micro-frontends, initialize the shared SDK once in the shell and reuse it in each frontend.
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
503
579
|
## Migrating to 1.0.0
|
|
504
580
|
|
|
505
581
|
`1.0.0` restructures `options` by concern (a clean break from `0.x`) and removes the deprecated
|
package/dist/index.d.mts
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* `TType` lets a platform name its own event kinds without editing core, and every core class
|
|
3
|
+
* flows it through. Defaults to `string`, because the set of NAMES is open — a platform that
|
|
4
|
+
* wants a closed union passes its own. Shared shapes stay shared; only the vocabulary is open.
|
|
4
5
|
*/
|
|
5
|
-
type
|
|
6
|
-
/**
|
|
7
|
-
* `TType` is what lets a platform package name its own event kinds without
|
|
8
|
-
* editing core: React Native can pass `KnownEventType | "tap" | "screen_view"`
|
|
9
|
-
* and every core class below flows it through. It defaults to
|
|
10
|
-
* `KnownEventType`, so nothing that only deals in the shipped browser kinds
|
|
11
|
-
* has to spell it out.
|
|
12
|
-
*
|
|
13
|
-
* Shared shapes are still shared — the point is that the set of names is open,
|
|
14
|
-
* not that each platform reinvents the envelope.
|
|
15
|
-
*/
|
|
16
|
-
type BaseEvent<TType extends string = KnownEventType> = {
|
|
6
|
+
type BaseEvent<TType extends string = string> = {
|
|
17
7
|
type: TType;
|
|
18
8
|
timestamp?: number;
|
|
19
9
|
end_timestamp?: number;
|
|
@@ -33,30 +23,6 @@ type UserIdentifiers = {
|
|
|
33
23
|
organization: string;
|
|
34
24
|
properties: Record<string, unknown>;
|
|
35
25
|
};
|
|
36
|
-
type DomEventAttributes = {
|
|
37
|
-
dom_event_type: string;
|
|
38
|
-
dom_event_coordinates: {
|
|
39
|
-
clientX: number;
|
|
40
|
-
clientY: number;
|
|
41
|
-
};
|
|
42
|
-
dom_event_target: {
|
|
43
|
-
tagName: string;
|
|
44
|
-
id: string;
|
|
45
|
-
className: string;
|
|
46
|
-
text: string;
|
|
47
|
-
role: string;
|
|
48
|
-
accessibleName: string;
|
|
49
|
-
ariaLabel: string;
|
|
50
|
-
title: string;
|
|
51
|
-
alt: string;
|
|
52
|
-
placeholder: string;
|
|
53
|
-
name: string;
|
|
54
|
-
inputType: string;
|
|
55
|
-
href: string;
|
|
56
|
-
};
|
|
57
|
-
dom_event_selector: string;
|
|
58
|
-
dom_event_key_code: string;
|
|
59
|
-
};
|
|
60
26
|
type NetworkEventAttributes = {
|
|
61
27
|
type: "HTTP";
|
|
62
28
|
resource_name: string;
|
|
@@ -119,31 +85,6 @@ type LogEventAttributes = {
|
|
|
119
85
|
message: string;
|
|
120
86
|
level: string;
|
|
121
87
|
} & Record<string, unknown>;
|
|
122
|
-
type PageLoadEventAttributes = {
|
|
123
|
-
page_url: string;
|
|
124
|
-
page_resources: {
|
|
125
|
-
count: number;
|
|
126
|
-
totalSize: number;
|
|
127
|
-
totalDuration: number;
|
|
128
|
-
byType: {
|
|
129
|
-
[key: string]: {
|
|
130
|
-
count: number;
|
|
131
|
-
size: number;
|
|
132
|
-
duration: number;
|
|
133
|
-
};
|
|
134
|
-
};
|
|
135
|
-
};
|
|
136
|
-
page_referrer: string;
|
|
137
|
-
page_load_time: number;
|
|
138
|
-
};
|
|
139
|
-
type NavigationEventAttributes = {
|
|
140
|
-
page_url: string;
|
|
141
|
-
from_url?: string;
|
|
142
|
-
metadata?: Record<string, unknown>;
|
|
143
|
-
duration_ms: number;
|
|
144
|
-
start_timestamp: number;
|
|
145
|
-
end_timestamp: number;
|
|
146
|
-
};
|
|
147
88
|
type UserDefinedEventAttributes = {
|
|
148
89
|
custom_event_name: string;
|
|
149
90
|
custom_event_attributes?: Record<string, unknown>;
|
|
@@ -154,44 +95,9 @@ type PerformanceEventAttributes = {
|
|
|
154
95
|
performance_metric_id: string;
|
|
155
96
|
performance_metric_navigation_type: string;
|
|
156
97
|
};
|
|
157
|
-
type ReplayEventAttributes = {
|
|
158
|
-
/**
|
|
159
|
-
* Groundcover session replay payload.
|
|
160
|
-
*
|
|
161
|
-
* NOTE: This key is intentionally prefixed to avoid collisions with customer attributes.
|
|
162
|
-
*/
|
|
163
|
-
_gc_replay_data: {
|
|
164
|
-
events: string[];
|
|
165
|
-
};
|
|
166
|
-
/**
|
|
167
|
-
* Indicates this batch starts with a full DOM snapshot.
|
|
168
|
-
* Full snapshots are taken at regular intervals to allow seeking directly to any point.
|
|
169
|
-
* Queryable for filtering/indexing purposes.
|
|
170
|
-
*/
|
|
171
|
-
replay_is_full_snapshot?: boolean;
|
|
172
|
-
/**
|
|
173
|
-
* Timestamp when the full snapshot was taken (if replay_is_full_snapshot is true).
|
|
174
|
-
*/
|
|
175
|
-
replay_full_snapshot_timestamp?: number;
|
|
176
|
-
};
|
|
177
98
|
|
|
178
|
-
type Event$1<T extends string, A> = Omit<BaseEvent<T>, "attributes"> & {
|
|
179
|
-
type: T;
|
|
180
|
-
attributes: A;
|
|
181
|
-
};
|
|
182
|
-
type EventTypes$1 = {
|
|
183
|
-
"dom.event": Event$1<"dom.event", DomEventAttributes>;
|
|
184
|
-
exception: Event$1<"exception", ErrorEventAttributes>;
|
|
185
|
-
network: Event$1<"network", NetworkEventAttributes>;
|
|
186
|
-
log: Event$1<"log", LogEventAttributes>;
|
|
187
|
-
pageload: Event$1<"pageload", PageLoadEventAttributes>;
|
|
188
|
-
navigation: Event$1<"navigation", NavigationEventAttributes>;
|
|
189
|
-
custom: Event$1<"custom", UserDefinedEventAttributes>;
|
|
190
|
-
performance: Event$1<"performance", PerformanceEventAttributes>;
|
|
191
|
-
replay: Event$1<"replay", ReplayEventAttributes>;
|
|
192
|
-
};
|
|
193
99
|
type PrivacyLevel = "mask-sensitive" | "mask-all" | "allow";
|
|
194
|
-
/** The
|
|
100
|
+
/** The event surface a redactor field belongs to. */
|
|
195
101
|
type RedactKind = "request-body" | "response-body" | "query" | "header" | "log" | "error";
|
|
196
102
|
interface RedactField {
|
|
197
103
|
/** Immediate key of the value; `""` for whole-string fields (log/error message). */
|
|
@@ -233,23 +139,19 @@ interface PrivacyOptions$1 {
|
|
|
233
139
|
/** Extra case-insensitive key substrings treated as sensitive, merged with the built-in patterns. */
|
|
234
140
|
sensitiveKeys?: string[];
|
|
235
141
|
/**
|
|
236
|
-
* Per-field custom redaction hook for
|
|
142
|
+
* Per-field custom redaction hook for captured events. Called on each leaf
|
|
237
143
|
* value during the redaction walk with the original typed value; see
|
|
238
144
|
* {@link Redactor}. For arbitrary whole-event changes use `enrichEvent`.
|
|
239
145
|
*/
|
|
240
146
|
redact?: Redactor;
|
|
241
|
-
/**
|
|
242
|
-
* Session-recording masking — replay is a platform feature (rrweb on the
|
|
243
|
-
* browser), so its masking surface is typed by the platform package: the
|
|
244
|
-
* browser SDK narrows this to `{ maskTextFn?, maskInputFn? }` over
|
|
245
|
-
* HTMLElement (see the browser package's `config/types.ts`). Core never
|
|
246
|
-
* reads it — it is resolved platform-side at record() time.
|
|
247
|
-
*/
|
|
248
|
-
replay?: unknown;
|
|
249
147
|
}
|
|
250
148
|
/** Distributed-tracing header propagation for outgoing network requests. */
|
|
251
149
|
interface TracingOptions {
|
|
252
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* Request URLs that receive injected tracing headers: whole-URL matches where
|
|
152
|
+
* only `*` is a wildcard. Which strings a pattern is matched against is the
|
|
153
|
+
* platform's (the browser adds a same-origin request's path).
|
|
154
|
+
*/
|
|
253
155
|
propagationUrls?: string[];
|
|
254
156
|
/** Inbound header names to read/propagate onto traced requests. */
|
|
255
157
|
propagationHeaders?: string[];
|
|
@@ -269,25 +171,23 @@ interface TransportOptions {
|
|
|
269
171
|
batchSize?: number;
|
|
270
172
|
/** Max ms a batch waits before flushing regardless of size (default 10000). */
|
|
271
173
|
batchTimeout?: number;
|
|
272
|
-
/** Gzip-compress outgoing batches; offloaded to the
|
|
174
|
+
/** Gzip-compress outgoing batches; offloaded to the platform's async encoder when it has one (default true). */
|
|
273
175
|
compression?: boolean;
|
|
274
176
|
}
|
|
275
|
-
interface SDKOptions$1<TEvent extends BaseEvent<string> =
|
|
177
|
+
interface SDKOptions$1<TEvent extends BaseEvent<string> = BaseEvent<string>> {
|
|
276
178
|
/**
|
|
277
179
|
* Which signal listeners to enable, by name. Empty array = all. The NAMES
|
|
278
180
|
* are platform-defined (each platform ships its own listener set) — the
|
|
279
|
-
* platform package narrows this to its literal union
|
|
280
|
-
* package's `config/types.ts`).
|
|
181
|
+
* platform package narrows this to its literal union.
|
|
281
182
|
*/
|
|
282
183
|
enabledEvents: string[];
|
|
283
|
-
eventSampleRate: number;
|
|
284
184
|
sessionSampleRate: number;
|
|
285
185
|
debug: boolean;
|
|
286
186
|
excludedUrls?: Array<string | RegExp>;
|
|
287
|
-
beforeSend
|
|
288
|
-
enrichEvent
|
|
187
|
+
beforeSend?(event: TEvent): boolean;
|
|
188
|
+
enrichEvent?(event: TEvent): TEvent;
|
|
289
189
|
/**
|
|
290
|
-
* Unified privacy / data-masking config
|
|
190
|
+
* Unified privacy / data-masking config for every captured surface.
|
|
291
191
|
* ON by default (`level: 'mask-sensitive'`); see {@link PrivacyOptions}.
|
|
292
192
|
*/
|
|
293
193
|
privacy?: PrivacyOptions$1;
|
|
@@ -296,51 +196,16 @@ interface SDKOptions$1<TEvent extends BaseEvent<string> = EventTypes$1[keyof Eve
|
|
|
296
196
|
/** Batching & delivery of outgoing events; see {@link TransportOptions}. */
|
|
297
197
|
transport?: TransportOptions;
|
|
298
198
|
/**
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
|
|
303
|
-
replay?: unknown;
|
|
304
|
-
/**
|
|
305
|
-
* Target maximum wall-clock duration of a session, in milliseconds.
|
|
306
|
-
*
|
|
307
|
-
* Enforced LAZILY, on activity — not by a background timer. Once the cap has
|
|
308
|
-
* elapsed, the next user/business event (click, navigation, log, custom,
|
|
309
|
-
* network, exception, …) flushes buffered events under the current session
|
|
310
|
-
* id, then mints a fresh session id and restarts replay recording if it was
|
|
311
|
-
* active.
|
|
312
|
-
*
|
|
313
|
-
* Because it is activity-gated, this is NOT a hard upper bound: a session
|
|
314
|
-
* only rotates when the next qualifying event arrives. An idle or
|
|
315
|
-
* backgrounded tab that produces no such events — including one that is only
|
|
316
|
-
* emitting session-replay heartbeats, which never trigger rotation on their
|
|
317
|
-
* own — keeps the same session id past the cap until activity resumes. This
|
|
318
|
-
* is deliberate: it avoids minting "phantom" sessions for dormant tabs. (An
|
|
319
|
-
* idle tab with replay on is ultimately bounded by the 30-minute user-idle
|
|
320
|
-
* pause — recording stops when no user presence is detected — not by this
|
|
321
|
-
* cap.)
|
|
199
|
+
* Target maximum wall-clock duration of a session, in ms. Enforced LAZILY on activity, so NOT
|
|
200
|
+
* a hard bound — an idle session keeps its id past the cap, which deliberately avoids minting
|
|
201
|
+
* phantom sessions. Also bounded by a 30-minute inactivity gap, counting raw input as
|
|
202
|
+
* presence so passive reading does not end a session.
|
|
322
203
|
*
|
|
323
|
-
*
|
|
324
|
-
* lazy way: when a user-interaction event (click, navigation, pageload,
|
|
325
|
-
* custom — not background network/log/performance traffic) arrives after 30+
|
|
326
|
-
* minutes without one, the session rotates first and replay recording
|
|
327
|
-
* restarts for the returning user. Raw user input (scroll, pointer, key,
|
|
328
|
-
* touch) also counts as presence even when it produces no SDK event, so
|
|
329
|
-
* passive engagement — reading, watching — doesn't end the session. The
|
|
330
|
-
* same gap check runs at init, so a reload after a long break also starts a
|
|
331
|
-
* fresh session.
|
|
332
|
-
*
|
|
333
|
-
* The flush is best-effort and the rotation always proceeds — it does not
|
|
334
|
-
* wait for or depend on successful delivery, so if that network request
|
|
335
|
-
* fails the batch may be lost while the new session id still takes effect.
|
|
336
|
-
*
|
|
337
|
-
* Defaults to 4 hours when omitted; must be between 1 minute and 8 hours.
|
|
338
|
-
* Values outside that range or otherwise invalid fall back to the 4-hour
|
|
339
|
-
* default with a `console.warn`.
|
|
204
|
+
* Defaults to 4 hours; must be 1 minute to 8 hours, else falls back with a warning.
|
|
340
205
|
*/
|
|
341
206
|
sessionMaxDuration?: number;
|
|
342
207
|
}
|
|
343
|
-
interface SDKConfigInput$1<TEvent extends BaseEvent<string> =
|
|
208
|
+
interface SDKConfigInput$1<TEvent extends BaseEvent<string> = BaseEvent<string>> {
|
|
344
209
|
apiKey: string;
|
|
345
210
|
cluster: string;
|
|
346
211
|
environment: string;
|
|
@@ -353,6 +218,76 @@ interface SDKConfigInput$1<TEvent extends BaseEvent<string> = EventTypes$1[keyof
|
|
|
353
218
|
sessionId?: string;
|
|
354
219
|
}
|
|
355
220
|
|
|
221
|
+
type DomEventAttributes = {
|
|
222
|
+
dom_event_type: string;
|
|
223
|
+
dom_event_coordinates: {
|
|
224
|
+
clientX: number;
|
|
225
|
+
clientY: number;
|
|
226
|
+
};
|
|
227
|
+
dom_event_target: {
|
|
228
|
+
tagName: string;
|
|
229
|
+
id: string;
|
|
230
|
+
className: string;
|
|
231
|
+
text: string;
|
|
232
|
+
role: string;
|
|
233
|
+
accessibleName: string;
|
|
234
|
+
ariaLabel: string;
|
|
235
|
+
title: string;
|
|
236
|
+
alt: string;
|
|
237
|
+
placeholder: string;
|
|
238
|
+
name: string;
|
|
239
|
+
inputType: string;
|
|
240
|
+
href: string;
|
|
241
|
+
};
|
|
242
|
+
dom_event_selector: string;
|
|
243
|
+
dom_event_key_code: string;
|
|
244
|
+
};
|
|
245
|
+
type PageLoadEventAttributes = {
|
|
246
|
+
page_url: string;
|
|
247
|
+
page_resources: {
|
|
248
|
+
count: number;
|
|
249
|
+
totalSize: number;
|
|
250
|
+
totalDuration: number;
|
|
251
|
+
byType: {
|
|
252
|
+
[key: string]: {
|
|
253
|
+
count: number;
|
|
254
|
+
size: number;
|
|
255
|
+
duration: number;
|
|
256
|
+
};
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
page_referrer: string;
|
|
260
|
+
page_load_time: number;
|
|
261
|
+
};
|
|
262
|
+
type NavigationEventAttributes = {
|
|
263
|
+
page_url: string;
|
|
264
|
+
from_url?: string;
|
|
265
|
+
metadata?: Record<string, unknown>;
|
|
266
|
+
duration_ms: number;
|
|
267
|
+
start_timestamp: number;
|
|
268
|
+
end_timestamp: number;
|
|
269
|
+
};
|
|
270
|
+
type ReplayEventAttributes = {
|
|
271
|
+
/**
|
|
272
|
+
* Groundcover session replay payload.
|
|
273
|
+
*
|
|
274
|
+
* NOTE: This key is intentionally prefixed to avoid collisions with customer attributes.
|
|
275
|
+
*/
|
|
276
|
+
_gc_replay_data: {
|
|
277
|
+
events: string[];
|
|
278
|
+
};
|
|
279
|
+
/**
|
|
280
|
+
* Indicates this batch starts with a full DOM snapshot.
|
|
281
|
+
* Full snapshots are taken at regular intervals to allow seeking directly to any point.
|
|
282
|
+
* Queryable for filtering/indexing purposes.
|
|
283
|
+
*/
|
|
284
|
+
replay_is_full_snapshot?: boolean;
|
|
285
|
+
/**
|
|
286
|
+
* Timestamp when the full snapshot was taken (if replay_is_full_snapshot is true).
|
|
287
|
+
*/
|
|
288
|
+
replay_full_snapshot_timestamp?: number;
|
|
289
|
+
};
|
|
290
|
+
|
|
356
291
|
/**
|
|
357
292
|
* The view an event was captured on. Browser-owned: core has no notion of a
|
|
358
293
|
* "current view" — it merges whatever the platform's `enrichAttributes`
|
|
@@ -412,13 +347,13 @@ interface ReplayMaskingOptions {
|
|
|
412
347
|
/** rrweb `maskInputFn` pass-through. */
|
|
413
348
|
maskInputFn?: (text: string, el: HTMLElement) => string;
|
|
414
349
|
}
|
|
415
|
-
interface PrivacyOptions extends
|
|
350
|
+
interface PrivacyOptions extends PrivacyOptions$1 {
|
|
416
351
|
/** CSS selectors whose text/inputs are always masked (replay + DOM), regardless of `level` except `'allow'`. */
|
|
417
352
|
maskSelectors?: string[];
|
|
418
353
|
/** Session-recording (rrweb replay) masking — the only place replay can be masked. */
|
|
419
354
|
replay?: ReplayMaskingOptions;
|
|
420
355
|
}
|
|
421
|
-
interface SDKOptions extends Omit<SDKOptions$1, "privacy" | "
|
|
356
|
+
interface SDKOptions extends Omit<SDKOptions$1, "privacy" | "enabledEvents" | "beforeSend" | "enrichEvent"> {
|
|
422
357
|
/**
|
|
423
358
|
* Inspect each event before it is queued; return false to drop it. Typed
|
|
424
359
|
* over the BROWSER event map, so `attributes.location` is visible here.
|
|
@@ -442,7 +377,7 @@ interface SDKOptions extends Omit<SDKOptions$1, "privacy" | "replay" | "enabledE
|
|
|
442
377
|
interface SDKConfigInput extends Omit<SDKConfigInput$1, "options"> {
|
|
443
378
|
options?: Partial<SDKOptions>;
|
|
444
379
|
}
|
|
445
|
-
type SDKConfigUpdate = Partial<Omit<SDKConfigInput, "sessionId" | "user">> & {
|
|
380
|
+
type SDKConfigUpdate = Partial<Omit<SDKConfigInput, "appId" | "sessionId" | "user">> & {
|
|
446
381
|
user?: SDKConfigInput["user"] | null;
|
|
447
382
|
};
|
|
448
383
|
|
|
@@ -470,7 +405,6 @@ declare class SessionManager {
|
|
|
470
405
|
setSessionId(newSessionId?: string): Promise<void>;
|
|
471
406
|
startReplayRecording(): void;
|
|
472
407
|
stopReplayRecording(): void;
|
|
473
|
-
handoffForReinit(): void;
|
|
474
408
|
destroy(): void;
|
|
475
409
|
}
|
|
476
410
|
|
|
@@ -491,11 +425,11 @@ declare global {
|
|
|
491
425
|
groundcover?: typeof groundcover;
|
|
492
426
|
}
|
|
493
427
|
}
|
|
494
|
-
declare function init(params
|
|
428
|
+
declare function init(params: {
|
|
495
429
|
cluster?: string;
|
|
496
430
|
environment?: string;
|
|
497
431
|
namespace?: string;
|
|
498
|
-
appId
|
|
432
|
+
appId: string;
|
|
499
433
|
releaseId?: string;
|
|
500
434
|
user?: Partial<UserIdentifiers>;
|
|
501
435
|
dsn?: string;
|