@maple-dev/browser 0.8.0 → 0.9.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 +64 -3
- package/dist/index.d.mts +72 -19
- package/dist/index.mjs +265 -51
- package/dist/{replay-session-BYZfi3iZ.mjs → replay-session-gSlAYwqV.mjs} +41 -8
- package/dist/{sink-D9w1kg0Q.mjs → sink-DHPiMgU0.mjs} +445 -78
- package/package.json +11 -10
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ import { MapleBrowser } from "@maple-dev/browser"
|
|
|
19
19
|
MapleBrowser.init({
|
|
20
20
|
ingestKey: "maple_pk_...", // public ingest key
|
|
21
21
|
serviceName: "acme-web",
|
|
22
|
+
region: "eu", // "us" (default) or "eu"; must match your organization's region
|
|
22
23
|
environment: "production",
|
|
23
24
|
replay: { enabled: true, sampleRate: 1.0 },
|
|
24
25
|
privacy: { maskAllInputs: true },
|
|
@@ -35,7 +36,35 @@ That single call:
|
|
|
35
36
|
only once a session is sampled in, so a `sampleRate` below 1 costs the
|
|
36
37
|
unsampled visitors nothing beyond the base SDK (see [Bundle size](#bundle-size));
|
|
37
38
|
- writes session metadata at start (`active`) and on page hide (`ended`),
|
|
38
|
-
including the trace ids observed during the session
|
|
39
|
+
including the trace ids observed during the session;
|
|
40
|
+
- captures uncaught errors and unhandled promise rejections as error spans, so
|
|
41
|
+
browser crashes reach Maple's error tracking.
|
|
42
|
+
|
|
43
|
+
## Errors
|
|
44
|
+
|
|
45
|
+
Every uncaught error and unhandled rejection becomes a span with status `Error`
|
|
46
|
+
and an `exception` event, which is the shape Maple fingerprints — so browser
|
|
47
|
+
crashes group beside your server-side errors instead of in a silo.
|
|
48
|
+
|
|
49
|
+
Errors your app _catches_ never reach the global handlers, because catching them
|
|
50
|
+
is what stops them. Report those explicitly:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
try {
|
|
54
|
+
render()
|
|
55
|
+
} catch (error) {
|
|
56
|
+
MapleBrowser.captureException(error, { name: "browser.render_error" })
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Opt out of the global handlers with `tracing: { captureErrors: false }` — worth
|
|
61
|
+
doing only when another tracker already owns them, or the same crash is recorded
|
|
62
|
+
twice.
|
|
63
|
+
|
|
64
|
+
A cross-origin script reports to the browser as a bare `"Script error."` with no
|
|
65
|
+
stack and no filename. Those are dropped rather than recorded: they all
|
|
66
|
+
fingerprint to one contentless issue that buries the real ones. Add
|
|
67
|
+
`crossorigin` to the script tag to get the real error instead.
|
|
39
68
|
|
|
40
69
|
## Bundle size
|
|
41
70
|
|
|
@@ -43,8 +72,8 @@ Bundled, minified and gzipped, as your bundler would ship it:
|
|
|
43
72
|
|
|
44
73
|
| | gzipped | what it is |
|
|
45
74
|
| ---------------- | ------- | --------------------------------------------------------- |
|
|
46
|
-
| **eager** | ~
|
|
47
|
-
| ↳ our code alone | ~
|
|
75
|
+
| **eager** | ~36 kB | every page load, before any sampling decision |
|
|
76
|
+
| ↳ our code alone | ~13 kB | the marginal cost if your app already ships OpenTelemetry |
|
|
48
77
|
| **lazy** | ~61 kB | rrweb — downloaded only by sessions sampled into replay |
|
|
49
78
|
|
|
50
79
|
The eager figure is ~90% OpenTelemetry. If your app already uses the OTel web
|
|
@@ -89,6 +118,26 @@ a separate analytics silo. Calls before `init()` finishes are queued.
|
|
|
89
118
|
MapleBrowser.track("checkout_completed", { plan: "pro", seats: 12 })
|
|
90
119
|
```
|
|
91
120
|
|
|
121
|
+
## Regions
|
|
122
|
+
|
|
123
|
+
Maple runs separate US and EU instances, and an ingest key only works in the
|
|
124
|
+
region it was created in. Set `region: "eu"` for an organization on
|
|
125
|
+
`app.eu.maple.dev`; the SDK then sends to `https://ingest.eu.maple.dev`. An
|
|
126
|
+
explicit `endpoint` (a proxy, or self-hosted ingest) always wins over `region`.
|
|
127
|
+
|
|
128
|
+
## Tracing across origins
|
|
129
|
+
|
|
130
|
+
`fetch` spans carry the W3C `traceparent` header to same-origin requests only.
|
|
131
|
+
When your API lives on another origin, list it so browser and backend spans
|
|
132
|
+
join one trace, and allow the `traceparent` header in the API's CORS policy:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
MapleBrowser.init({
|
|
136
|
+
// ...
|
|
137
|
+
tracing: { propagateTraceHeaderCorsUrls: [/^https:\/\/api\.example\.com\//] },
|
|
138
|
+
})
|
|
139
|
+
```
|
|
140
|
+
|
|
92
141
|
## Linking a marketing site to your app
|
|
93
142
|
|
|
94
143
|
The visitor id lives in localStorage **and** a cookie scoped to your registered
|
|
@@ -103,6 +152,18 @@ stay per-origin; `VisitorId` is the join key. Override the scope with
|
|
|
103
152
|
attribute hooks (`data-rr-block`, `.rr-block`, `.rr-ignore`) to block elements
|
|
104
153
|
or subtrees from capture.
|
|
105
154
|
|
|
155
|
+
URLs are redacted before they leave the page: the values of credential-shaped
|
|
156
|
+
query and fragment parameters (`token`, `code`, `access_token`, `password`, …)
|
|
157
|
+
become `REDACTED` in session rows, events, network events, replay meta events
|
|
158
|
+
and span attributes. Add your own rewriting with `privacy.sanitizeUrl`, for
|
|
159
|
+
example to collapse ids in paths:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
privacy: {
|
|
163
|
+
sanitizeUrl: (url) => url.replace(/\/users\/\d+/, "/users/:id")
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
106
167
|
`privacy.requireConsent` holds all capture until `MapleBrowser.setConsent(true)`.
|
|
107
168
|
Global Privacy Control is honored by default and suppresses the persistent
|
|
108
169
|
visitor id; `doNotTrack` is not, unless `privacy.respectDoNotTrack` is set.
|
package/dist/index.d.mts
CHANGED
|
@@ -26,10 +26,14 @@ interface MapleIdentity {
|
|
|
26
26
|
*/
|
|
27
27
|
type IdentifyInput = string | null | undefined | MapleIdentity;
|
|
28
28
|
//#endregion
|
|
29
|
-
//#region ../browser-session/src/events/
|
|
29
|
+
//#region ../browser-session/src/events/props.d.ts
|
|
30
30
|
/** Properties a host app may attach to a custom event. */
|
|
31
31
|
type TrackProps = Readonly<Record<string, unknown>>;
|
|
32
32
|
//#endregion
|
|
33
|
+
//#region ../browser-session/src/platform/region.d.ts
|
|
34
|
+
/** A Maple hosting region. Each is a separate instance with its own ingest keys. */
|
|
35
|
+
type MapleRegion = "us" | "eu";
|
|
36
|
+
//#endregion
|
|
33
37
|
//#region src/config.d.ts
|
|
34
38
|
/** Public configuration for `MapleBrowser.init`. */
|
|
35
39
|
interface MapleBrowserConfig {
|
|
@@ -37,7 +41,13 @@ interface MapleBrowserConfig {
|
|
|
37
41
|
readonly ingestKey: string;
|
|
38
42
|
/** Service name reported on traces and stored on replay sessions. */
|
|
39
43
|
readonly serviceName: string;
|
|
40
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Region your Maple organization lives in: `"us"` (default,
|
|
46
|
+
* `https://ingest.maple.dev`) or `"eu"` (`https://ingest.eu.maple.dev`).
|
|
47
|
+
* Ingest keys belong to one region. Ignored when `endpoint` is set.
|
|
48
|
+
*/
|
|
49
|
+
readonly region?: MapleRegion;
|
|
50
|
+
/** Maple ingest base URL. Overrides `region`; use it for a proxy or self-hosted ingest. */
|
|
41
51
|
readonly endpoint?: string;
|
|
42
52
|
/**
|
|
43
53
|
* Logical group this service belongs to, emitted as the OTel
|
|
@@ -67,6 +77,19 @@ interface MapleBrowserConfig {
|
|
|
67
77
|
* sink, and disabling this avoids redundant duplicate network spans.
|
|
68
78
|
*/
|
|
69
79
|
readonly instrumentFetch?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Capture uncaught errors and unhandled promise rejections as error
|
|
82
|
+
* spans. Default true. Turn off only when another tracker already owns
|
|
83
|
+
* the page's global error handlers, or the same crash lands twice.
|
|
84
|
+
*/
|
|
85
|
+
readonly captureErrors?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Cross-origin URLs whose `fetch()` requests carry the W3C `traceparent`
|
|
88
|
+
* header, so the browser span and your backend's span join one trace.
|
|
89
|
+
* Same-origin requests always carry it. Your API must allow the
|
|
90
|
+
* `traceparent` header in CORS. Example: `[/^https:\/\/api\.example\.com\//]`.
|
|
91
|
+
*/
|
|
92
|
+
readonly propagateTraceHeaderCorsUrls?: ReadonlyArray<string | RegExp>;
|
|
70
93
|
};
|
|
71
94
|
readonly replay?: {
|
|
72
95
|
/** Default true. */
|
|
@@ -107,9 +130,25 @@ interface MapleBrowserConfig {
|
|
|
107
130
|
readonly captureUserEmail?: boolean;
|
|
108
131
|
/** Treat `navigator.doNotTrack` like Global Privacy Control. Default false. */
|
|
109
132
|
readonly respectDoNotTrack?: boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Rewrite every URL before it leaves the page: session entry and exit
|
|
135
|
+
* URLs, event rows, network events, replay meta events, and span
|
|
136
|
+
* attributes. Runs after the built-in redaction, which already replaces
|
|
137
|
+
* the values of credential-shaped query and fragment parameters
|
|
138
|
+
* (`token`, `code`, `access_token`, `password`, …).
|
|
139
|
+
*/
|
|
140
|
+
readonly sanitizeUrl?: (url: string) => string;
|
|
110
141
|
};
|
|
111
142
|
}
|
|
112
143
|
//#endregion
|
|
144
|
+
//#region src/errors.d.ts
|
|
145
|
+
interface CaptureExceptionOptions {
|
|
146
|
+
/** Span name. Default `"exception"`. */
|
|
147
|
+
readonly name?: string | undefined;
|
|
148
|
+
/** Extra span attributes. */
|
|
149
|
+
readonly attributes?: Record<string, string | number | boolean> | undefined;
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
113
152
|
//#region src/init.d.ts
|
|
114
153
|
interface MapleBrowserHandle {
|
|
115
154
|
/** Empty until consent is granted when `requireConsent` is enabled. */
|
|
@@ -119,6 +158,34 @@ interface MapleBrowserHandle {
|
|
|
119
158
|
}
|
|
120
159
|
//#endregion
|
|
121
160
|
//#region src/index.d.ts
|
|
161
|
+
/** The `MapleBrowser` namespace object. */
|
|
162
|
+
interface MapleBrowserApi {
|
|
163
|
+
init: (config: MapleBrowserConfig) => MapleBrowserHandle;
|
|
164
|
+
/**
|
|
165
|
+
* Attach, replace, or clear the end-user identity on the active session.
|
|
166
|
+
* Accepts a bare user id or the full identity object. Safe to call repeatedly,
|
|
167
|
+
* and before `init` (the latest call is applied when `init` runs).
|
|
168
|
+
*/
|
|
169
|
+
identify: (input?: IdentifyInput) => void;
|
|
170
|
+
/**
|
|
171
|
+
* Record a custom product event against the active session. Safe to call
|
|
172
|
+
* before `init` — events are queued (capped) and drained once the session
|
|
173
|
+
* starts.
|
|
174
|
+
*/
|
|
175
|
+
track: (name: string, props?: TrackProps) => void;
|
|
176
|
+
/**
|
|
177
|
+
* Report an error your app already caught — the case the global handlers
|
|
178
|
+
* cannot see, because catching it is what stops it reaching them. A
|
|
179
|
+
* framework error boundary is the canonical caller. The same error object
|
|
180
|
+
* is recorded once, even if it is rethrown afterwards.
|
|
181
|
+
*
|
|
182
|
+
* BOUNDARY: a thrown value is unparsed by definition — JavaScript can throw
|
|
183
|
+
* anything. `captureException` narrows it before it reaches a span.
|
|
184
|
+
*/
|
|
185
|
+
captureException: (error: unknown, options?: CaptureExceptionOptions) => void;
|
|
186
|
+
/** Grant or revoke consent when `privacy.requireConsent` is on. */
|
|
187
|
+
setConsent: (granted: boolean) => void;
|
|
188
|
+
}
|
|
122
189
|
/**
|
|
123
190
|
* Maple browser SDK. One call wires up OpenTelemetry tracing and rrweb session
|
|
124
191
|
* replay, both tagged with a shared session id.
|
|
@@ -130,27 +197,13 @@ interface MapleBrowserHandle {
|
|
|
130
197
|
* MapleBrowser.init({
|
|
131
198
|
* ingestKey: "maple_pk_...",
|
|
132
199
|
* serviceName: "acme-web",
|
|
200
|
+
* region: "eu", // omit for the US region
|
|
133
201
|
* })
|
|
134
202
|
*
|
|
135
203
|
* MapleBrowser.identify({ id: user.id, email: user.email, groupId: org.id, groupName: org.name })
|
|
136
204
|
* MapleBrowser.track("checkout_completed", { plan: "pro", seats: 5 })
|
|
137
205
|
* ```
|
|
138
206
|
*/
|
|
139
|
-
declare const MapleBrowser:
|
|
140
|
-
init: (config: MapleBrowserConfig) => MapleBrowserHandle;
|
|
141
|
-
/**
|
|
142
|
-
* Attach, replace, or clear the end-user identity on the active session.
|
|
143
|
-
* Accepts a bare user id or the full identity object. Safe to call repeatedly.
|
|
144
|
-
*/
|
|
145
|
-
identify: (input?: IdentifyInput) => void;
|
|
146
|
-
/**
|
|
147
|
-
* Record a custom product event against the active session. Safe to call
|
|
148
|
-
* before `init` — events are queued (capped) and drained once the session
|
|
149
|
-
* starts.
|
|
150
|
-
*/
|
|
151
|
-
track: (name: string, props?: TrackProps) => void;
|
|
152
|
-
/** Grant or revoke consent when `privacy.requireConsent` is on. */
|
|
153
|
-
setConsent: (granted: boolean) => void;
|
|
154
|
-
};
|
|
207
|
+
declare const MapleBrowser: MapleBrowserApi;
|
|
155
208
|
//#endregion
|
|
156
|
-
export { type IdentifyInput, MapleBrowser, type MapleBrowserConfig, type MapleBrowserHandle, type MapleIdentity, type TrackProps, type TraitValue };
|
|
209
|
+
export { type CaptureExceptionOptions, type IdentifyInput, MapleBrowser, MapleBrowserApi, type MapleBrowserConfig, type MapleBrowserHandle, type MapleIdentity, type MapleRegion, type TrackProps, type TraitValue };
|