@maple-dev/browser 0.3.0 → 0.4.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maple Tech Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -31,7 +31,9 @@ That single call:
31
31
  ingest (`POST /v1/traces`);
32
32
  - records the session with rrweb, chunking events (~5s / 100KB windows),
33
33
  gzipping them with the native `CompressionStream`, and uploading to
34
- `POST /v1/sessionReplays/blob`;
34
+ `POST /v1/sessionReplays/blob`. rrweb ships in a lazy code-split chunk loaded
35
+ only once a session is sampled in, so a `sampleRate` below 1 costs the
36
+ unsampled visitors nothing beyond the ~8 kB gzipped base SDK;
35
37
  - writes session metadata at start (`active`) and on page hide (`ended`),
36
38
  including the trace ids observed during the session.
37
39
 
@@ -44,16 +46,49 @@ metadata rows and stamped as `user.id` on future browser-created spans.
44
46
  ```ts
45
47
  MapleBrowser.identify(user.id)
46
48
 
49
+ // or the full identity — email, name, and the company/team to group by
50
+ MapleBrowser.identify({
51
+ id: user.id,
52
+ email: user.email,
53
+ groupId: org.id,
54
+ groupName: org.name,
55
+ traits: { plan: "pro" },
56
+ })
57
+
47
58
  // after sign-out
48
59
  MapleBrowser.identify(null)
49
60
  ```
50
61
 
62
+ Each call replaces the identity rather than merging it.
63
+
64
+ ## Custom events
65
+
66
+ `track(name, props)` records a product event as a `session_events` row with
67
+ `Type='custom'`, so it shows up inline in the session transcript rather than in
68
+ a separate analytics silo. Calls before `init()` finishes are queued.
69
+
70
+ ```ts
71
+ MapleBrowser.track("checkout_completed", { plan: "pro", seats: 12 })
72
+ ```
73
+
74
+ ## Linking a marketing site to your app
75
+
76
+ The visitor id lives in localStorage **and** a cookie scoped to your registered
77
+ domain, so `example.com` and `app.example.com` resolve to the same `VisitorId`
78
+ and an anonymous pre-signup visit links to the account it becomes. Session ids
79
+ stay per-origin; `VisitorId` is the join key. Override the scope with
80
+ `privacy.crossSubdomainCookie` / `privacy.cookieDomain`.
81
+
51
82
  ## Privacy
52
83
 
53
84
  `maskAllInputs` (default **on**) masks every `<input>` value. Use rrweb's
54
85
  attribute hooks (`data-rr-block`, `.rr-block`, `.rr-ignore`) to block elements
55
86
  or subtrees from capture.
56
87
 
88
+ `privacy.requireConsent` holds all capture until `MapleBrowser.setConsent(true)`.
89
+ Global Privacy Control is honored by default and suppresses the persistent
90
+ visitor id; `doNotTrack` is not, unless `privacy.respectDoNotTrack` is set.
91
+
57
92
  ## Notes
58
93
 
59
94
  - Replay event blobs live in object storage; only small, queryable metadata is
package/dist/index.d.mts CHANGED
@@ -1,3 +1,35 @@
1
+ //#region ../browser-session/src/identity.d.ts
2
+ /**
3
+ * Who the current visitor is.
4
+ *
5
+ * Held in module memory only — never written to localStorage/sessionStorage.
6
+ * An email at rest in browser storage is a PII surface with no upside here: the
7
+ * identity is re-attached to every metadata row the SDK posts, so there is
8
+ * nothing to persist across a reload that the host app won't re-`identify()`.
9
+ */
10
+ /** Trait values a host app may pass. Coerced to strings before they leave. */
11
+ type TraitValue = string | number | boolean | null | undefined;
12
+ interface MapleIdentity {
13
+ readonly id?: string;
14
+ readonly email?: string;
15
+ readonly username?: string;
16
+ /** Company / team / tenant — the grouping dimension in the sessions UI. */
17
+ readonly groupId?: string;
18
+ readonly groupName?: string;
19
+ /** Open-ended attributes (plan, role, …). Capped; see `MAX_TRAITS`. */
20
+ readonly traits?: Readonly<Record<string, TraitValue>>;
21
+ }
22
+ /**
23
+ * `identify` accepts a bare user id as well as the full object — the string
24
+ * form is what every existing caller passes, and keeping it means this can ship
25
+ * without touching them.
26
+ */
27
+ type IdentifyInput = string | null | undefined | MapleIdentity;
28
+ //#endregion
29
+ //#region ../browser-session/src/track.d.ts
30
+ /** Properties a host app may attach to a custom event. */
31
+ type TrackProps = Readonly<Record<string, unknown>>;
32
+ //#endregion
1
33
  //#region src/config.d.ts
2
34
  /** Public configuration for `MapleBrowser.init`. */
3
35
  interface MapleBrowserConfig {
@@ -16,10 +48,18 @@ interface MapleBrowserConfig {
16
48
  readonly serviceVersion?: string;
17
49
  /** Deployment environment, e.g. "production". */
18
50
  readonly environment?: string;
19
- /** Optional user id attached to replay sessions and future browser spans. */
51
+ /**
52
+ * Optional user id attached to replay sessions and future browser spans.
53
+ *
54
+ * @deprecated Pass `user` instead — it carries email, name, and the
55
+ * company/team grouping the Sessions UI can filter by.
56
+ */
20
57
  readonly userId?: string | null | undefined;
58
+ /** End-user identity attached to sessions and browser spans. */
59
+ readonly user?: MapleIdentity | undefined;
21
60
  readonly tracing?: {
22
- /** Default true. */readonly enabled?: boolean;
61
+ /** Default true. */
62
+ readonly enabled?: boolean;
23
63
  /**
24
64
  * Auto-instrument `fetch()` to create network spans. Default true. Set
25
65
  * false when another tracer (e.g. the Effect client SDK) already
@@ -29,23 +69,52 @@ interface MapleBrowserConfig {
29
69
  readonly instrumentFetch?: boolean;
30
70
  };
31
71
  readonly replay?: {
32
- /** Default true. */readonly enabled?: boolean; /** Fraction of sessions to record, 0–1. Default 1. */
72
+ /** Default true. */
73
+ readonly enabled?: boolean;
74
+ /** Fraction of sessions to record, 0–1. Default 1. */
33
75
  readonly sampleRate?: number;
34
76
  };
35
77
  readonly privacy?: {
36
- /** Mask all `<input>` values. Default true. */readonly maskAllInputs?: boolean;
78
+ /** Mask all `<input>` values. Default true. */
79
+ readonly maskAllInputs?: boolean;
37
80
  /**
38
81
  * Mask all text in the rrweb recording and omit captured click target
39
82
  * text from session events. Default false.
40
83
  */
41
84
  readonly maskAllText?: boolean;
85
+ /**
86
+ * Store a persistent visitor id (localStorage) so unique visitors and
87
+ * new-vs-returning are measurable. Default true. Turning it off also
88
+ * purges any id already stored.
89
+ */
90
+ readonly persistVisitorId?: boolean;
91
+ /**
92
+ * Scope the visitor-id cookie to the registered domain, so a marketing site
93
+ * and an app on sibling subdomains (`example.com` and `app.example.com`)
94
+ * resolve to the same visitor and a pre-signup visit links to the account it
95
+ * becomes. Default true. Set false to keep the cookie host-only.
96
+ */
97
+ readonly crossSubdomainCookie?: boolean;
98
+ /**
99
+ * Explicit cookie `Domain=` (no leading dot), e.g. `"example.com"`. Defaults
100
+ * to the broadest domain the browser accepts, discovered by probing. `""`
101
+ * forces a host-only cookie.
102
+ */
103
+ readonly cookieDomain?: string;
104
+ /** Capture nothing until `MapleBrowser.setConsent(true)`. Default false. */
105
+ readonly requireConsent?: boolean;
106
+ /** Send `identify()`'s email to the warehouse. Default true. */
107
+ readonly captureUserEmail?: boolean;
108
+ /** Treat `navigator.doNotTrack` like Global Privacy Control. Default false. */
109
+ readonly respectDoNotTrack?: boolean;
42
110
  };
43
111
  }
44
112
  //#endregion
45
113
  //#region src/init.d.ts
46
114
  interface MapleBrowserHandle {
115
+ /** Empty until consent is granted when `requireConsent` is enabled. */
47
116
  readonly sessionId: string;
48
- /** Tear down tracing + replay (flushing the final chunk). */
117
+ /** Tear down tracing + session capture, flushing the final buffers. */
49
118
  readonly shutdown: () => Promise<void>;
50
119
  }
51
120
  //#endregion
@@ -62,11 +131,26 @@ interface MapleBrowserHandle {
62
131
  * ingestKey: "maple_pk_...",
63
132
  * serviceName: "acme-web",
64
133
  * })
134
+ *
135
+ * MapleBrowser.identify({ id: user.id, email: user.email, groupId: org.id, groupName: org.name })
136
+ * MapleBrowser.track("checkout_completed", { plan: "pro", seats: 5 })
65
137
  * ```
66
138
  */
67
139
  declare const MapleBrowser: {
68
- init: (config: MapleBrowserConfig) => MapleBrowserHandle; /** Attach, replace, or clear the user id on the active session. Safe to call repeatedly. */
69
- identify: (userId?: string | null) => void;
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;
70
154
  };
71
155
  //#endregion
72
- export { MapleBrowser, type MapleBrowserConfig, type MapleBrowserHandle };
156
+ export { type IdentifyInput, MapleBrowser, type MapleBrowserConfig, type MapleBrowserHandle, type MapleIdentity, type TrackProps, type TraitValue };