vident-rum 0.8.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.
Files changed (46) hide show
  1. package/README.md +424 -0
  2. package/dist/client.d.ts +67 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +207 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/errors.d.ts +8 -0
  7. package/dist/errors.d.ts.map +1 -0
  8. package/dist/errors.js +67 -0
  9. package/dist/errors.js.map +1 -0
  10. package/dist/events.d.ts +78 -0
  11. package/dist/events.d.ts.map +1 -0
  12. package/dist/events.js +11 -0
  13. package/dist/events.js.map +1 -0
  14. package/dist/index.d.ts +5 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +3 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/instrumentation/fetch.d.ts +16 -0
  19. package/dist/instrumentation/fetch.d.ts.map +1 -0
  20. package/dist/instrumentation/fetch.js +109 -0
  21. package/dist/instrumentation/fetch.js.map +1 -0
  22. package/dist/instrumentation/xhr.d.ts +16 -0
  23. package/dist/instrumentation/xhr.d.ts.map +1 -0
  24. package/dist/instrumentation/xhr.js +129 -0
  25. package/dist/instrumentation/xhr.js.map +1 -0
  26. package/dist/replay.d.ts +66 -0
  27. package/dist/replay.d.ts.map +1 -0
  28. package/dist/replay.js +289 -0
  29. package/dist/replay.js.map +1 -0
  30. package/dist/session.d.ts +11 -0
  31. package/dist/session.d.ts.map +1 -0
  32. package/dist/session.js +176 -0
  33. package/dist/session.js.map +1 -0
  34. package/dist/trace-context.d.ts +37 -0
  35. package/dist/trace-context.d.ts.map +1 -0
  36. package/dist/trace-context.js +113 -0
  37. package/dist/trace-context.js.map +1 -0
  38. package/dist/transport.d.ts +15 -0
  39. package/dist/transport.d.ts.map +1 -0
  40. package/dist/transport.js +101 -0
  41. package/dist/transport.js.map +1 -0
  42. package/dist/vitals.d.ts +12 -0
  43. package/dist/vitals.d.ts.map +1 -0
  44. package/dist/vitals.js +48 -0
  45. package/dist/vitals.js.map +1 -0
  46. package/package.json +34 -0
package/dist/replay.js ADDED
@@ -0,0 +1,289 @@
1
+ import { gzipSync } from "fflate";
2
+ import { record } from "rrweb";
3
+ const MAX_CHUNK_SIZE = 64 * 1024; // 64KB uncompressed
4
+ const FLUSH_INTERVAL = 5000; // 5 seconds
5
+ const BUFFER_DURATION_MS = 60_000; // 60 seconds rolling buffer
6
+ const BUFFER_CLEANUP_INTERVAL = 10_000; // Cleanup every 10 seconds
7
+ // Selectors for privacy control
8
+ const BLOCK_SELECTOR = "[data-sw-block], .rr-block";
9
+ const MASK_SELECTOR = "[data-sw-mask], .rr-mask";
10
+ const UNMASK_SELECTOR = "[data-sw-unmask]";
11
+ // Efficient base64 encoding for Uint8Array
12
+ function uint8ToBase64(bytes) {
13
+ let binary = "";
14
+ for (const byte of bytes) {
15
+ binary += String.fromCharCode(byte);
16
+ }
17
+ return btoa(binary);
18
+ }
19
+ /**
20
+ * Session Replay Recorder with Rolling Buffer
21
+ *
22
+ * Architecture:
23
+ * - Always records to memory when enabled
24
+ * - If sampled (sampleRate): uploads immediately
25
+ * - If not sampled: keeps 60s rolling buffer in memory
26
+ * - On error: flushes buffer and starts uploading (if onErrorSampleRate passes)
27
+ * - Zero network cost for sessions without errors that weren't sampled
28
+ */
29
+ export function createReplayRecorder(config, transportConfig, onError) {
30
+ // Event buffer - always populated while recording
31
+ const buffer = [];
32
+ let estimatedSize = 0;
33
+ // Upload state
34
+ let chunkIndex = 0;
35
+ let flushTimer = null;
36
+ let bufferCleanupTimer = null;
37
+ // Recording state
38
+ let isRecording = false;
39
+ let stopRecordingFn = null;
40
+ let hasErrors = false;
41
+ let mode = "buffer";
42
+ // Sampling decisions (made once at session start)
43
+ const shouldUploadImmediately = Math.random() < (config.sampleRate ?? 0.1);
44
+ let wasUpgradedByError = false;
45
+ function getRecordOptions() {
46
+ const privacyMode = config.privacyMode ?? "strict";
47
+ const maskAllInputs = privacyMode !== "permissive";
48
+ const maskAllText = privacyMode === "strict";
49
+ return {
50
+ emit: handleEvent,
51
+ sampling: {
52
+ mousemove: true,
53
+ mouseInteraction: true,
54
+ scroll: 150,
55
+ input: "last",
56
+ },
57
+ maskAllInputs,
58
+ maskAllText,
59
+ maskTextSelector: maskAllText ? undefined : MASK_SELECTOR,
60
+ unmaskTextSelector: maskAllText ? UNMASK_SELECTOR : undefined,
61
+ blockSelector: BLOCK_SELECTOR,
62
+ slimDOMOptions: {
63
+ script: true,
64
+ comment: true,
65
+ headFavicon: true,
66
+ headWhitespace: true,
67
+ headMetaSocial: true,
68
+ headMetaRobots: true,
69
+ headMetaHttpEquiv: true,
70
+ headMetaVerification: true,
71
+ headMetaAuthorship: true,
72
+ },
73
+ // Handle rrweb internal errors (e.g., e.matches on non-Element nodes)
74
+ errorHandler: (error) => {
75
+ // Suppress known rrweb bugs, log others
76
+ const msg = error instanceof Error ? error.message : String(error);
77
+ if (msg.includes("matches is not a function")) {
78
+ return; // Known rrweb bug with Text/Comment nodes
79
+ }
80
+ console.warn("[Vident Replay] Recording error:", msg);
81
+ },
82
+ };
83
+ }
84
+ function handleEvent(event) {
85
+ buffer.push(event);
86
+ estimatedSize += JSON.stringify(event).length + 1;
87
+ if (mode === "upload") {
88
+ // In upload mode, flush when chunk is large enough
89
+ if (estimatedSize >= MAX_CHUNK_SIZE) {
90
+ flush();
91
+ }
92
+ else {
93
+ scheduleFlush();
94
+ }
95
+ }
96
+ // In buffer mode, events just accumulate (cleaned up periodically)
97
+ }
98
+ function scheduleFlush() {
99
+ if (flushTimer || mode !== "upload")
100
+ return;
101
+ flushTimer = setTimeout(() => {
102
+ flushTimer = null;
103
+ flush();
104
+ }, FLUSH_INTERVAL);
105
+ }
106
+ function preparePayload(batch) {
107
+ const compressed = gzipSync(new TextEncoder().encode(JSON.stringify(batch)));
108
+ return JSON.stringify({
109
+ sessionId: transportConfig.sessionId,
110
+ chunkIndex,
111
+ data: uint8ToBase64(compressed),
112
+ isFullSnapshot: chunkIndex === 0,
113
+ timestamp: Date.now(),
114
+ hasErrors,
115
+ });
116
+ }
117
+ async function flush() {
118
+ if (buffer.length === 0 || mode !== "upload")
119
+ return;
120
+ const batch = buffer.splice(0);
121
+ estimatedSize = 0;
122
+ try {
123
+ await fetch(`${transportConfig.baseUrl}/v1/ingest/replays`, {
124
+ method: "POST",
125
+ headers: {
126
+ "Content-Type": "application/json",
127
+ "x-api-key": transportConfig.apiKey,
128
+ },
129
+ body: preparePayload(batch),
130
+ keepalive: true,
131
+ });
132
+ chunkIndex++;
133
+ }
134
+ catch (error) {
135
+ console.warn("[Vident Replay] Failed to send chunk:", error);
136
+ }
137
+ }
138
+ function flushBeacon() {
139
+ if (buffer.length === 0 || mode !== "upload")
140
+ return;
141
+ const batch = buffer.splice(0);
142
+ estimatedSize = 0;
143
+ try {
144
+ fetch(`${transportConfig.baseUrl}/v1/ingest/replays`, {
145
+ method: "POST",
146
+ headers: {
147
+ "Content-Type": "application/json",
148
+ "x-api-key": transportConfig.apiKey,
149
+ },
150
+ body: preparePayload(batch),
151
+ keepalive: true,
152
+ }).catch(() => {
153
+ // Silently ignore - page is likely unloading
154
+ });
155
+ chunkIndex++;
156
+ }
157
+ catch {
158
+ // Ignore errors during page unload
159
+ }
160
+ }
161
+ /**
162
+ * Clean up old events from buffer (only in buffer mode)
163
+ * Keeps last 60 seconds of events
164
+ */
165
+ function cleanupBuffer() {
166
+ if (mode !== "buffer" || buffer.length === 0)
167
+ return;
168
+ const cutoff = Date.now() - BUFFER_DURATION_MS;
169
+ let removeCount = 0;
170
+ // Find how many events to remove (they're chronologically ordered)
171
+ for (const event of buffer) {
172
+ if (event.timestamp < cutoff) {
173
+ removeCount++;
174
+ }
175
+ else {
176
+ break;
177
+ }
178
+ }
179
+ if (removeCount > 0) {
180
+ buffer.splice(0, removeCount);
181
+ // Recalculate size estimate
182
+ estimatedSize = buffer.reduce((sum, e) => sum + JSON.stringify(e).length + 1, 0);
183
+ }
184
+ }
185
+ /**
186
+ * Switch from buffer mode to upload mode
187
+ * Flushes the entire buffer and starts uploading
188
+ */
189
+ function switchToUploadMode() {
190
+ if (mode === "upload")
191
+ return;
192
+ mode = "upload";
193
+ // Stop buffer cleanup
194
+ if (bufferCleanupTimer) {
195
+ clearInterval(bufferCleanupTimer);
196
+ bufferCleanupTimer = null;
197
+ }
198
+ // Flush the buffer immediately
199
+ if (buffer.length > 0) {
200
+ flush();
201
+ }
202
+ }
203
+ function start() {
204
+ if (isRecording)
205
+ return;
206
+ isRecording = true;
207
+ // Determine initial mode
208
+ if (shouldUploadImmediately) {
209
+ mode = "upload";
210
+ }
211
+ else {
212
+ mode = "buffer";
213
+ // Start buffer cleanup interval
214
+ bufferCleanupTimer = setInterval(cleanupBuffer, BUFFER_CLEANUP_INTERVAL);
215
+ }
216
+ // Start rrweb recording
217
+ const stop = record(getRecordOptions());
218
+ stopRecordingFn = stop ?? null;
219
+ // Setup unload handlers
220
+ window.addEventListener("visibilitychange", handleVisibilityChange);
221
+ window.addEventListener("pagehide", handlePageHide);
222
+ }
223
+ function stop() {
224
+ if (!isRecording)
225
+ return;
226
+ isRecording = false;
227
+ if (stopRecordingFn) {
228
+ stopRecordingFn();
229
+ stopRecordingFn = null;
230
+ }
231
+ if (flushTimer) {
232
+ clearTimeout(flushTimer);
233
+ flushTimer = null;
234
+ }
235
+ if (bufferCleanupTimer) {
236
+ clearInterval(bufferCleanupTimer);
237
+ bufferCleanupTimer = null;
238
+ }
239
+ // Final flush only if in upload mode
240
+ if (mode === "upload") {
241
+ flush();
242
+ }
243
+ window.removeEventListener("visibilitychange", handleVisibilityChange);
244
+ window.removeEventListener("pagehide", handlePageHide);
245
+ }
246
+ function handleVisibilityChange() {
247
+ if (document.visibilityState === "hidden" && mode === "upload") {
248
+ flushBeacon();
249
+ }
250
+ }
251
+ function handlePageHide() {
252
+ if (mode === "upload") {
253
+ flushBeacon();
254
+ }
255
+ }
256
+ /**
257
+ * Mark that an error occurred in this session
258
+ * If in buffer mode, switches to upload mode (subject to onErrorSampleRate)
259
+ */
260
+ function markError() {
261
+ hasErrors = true;
262
+ // If already uploading, nothing to do
263
+ if (mode === "upload")
264
+ return;
265
+ // Check if we should upgrade to upload mode
266
+ const onErrorRate = config.onErrorSampleRate ?? 1.0;
267
+ if (Math.random() < onErrorRate) {
268
+ wasUpgradedByError = true;
269
+ switchToUploadMode();
270
+ onError?.();
271
+ }
272
+ }
273
+ // Auto-start recording when enabled
274
+ if (config.enabled) {
275
+ // Defer to next tick to ensure DOM is ready
276
+ setTimeout(start, 0);
277
+ }
278
+ return {
279
+ start,
280
+ stop,
281
+ markError,
282
+ isRecording: () => isRecording,
283
+ isUploading: () => mode === "upload",
284
+ wasUpgradedByError: () => wasUpgradedByError,
285
+ /** Force switch to upload mode (for manual control) */
286
+ startUploading: switchToUploadMode,
287
+ };
288
+ }
289
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export type StorageMode = "cookie" | "sessionStorage";
2
+ export declare function setStorageMode(mode: StorageMode): void;
3
+ export type SessionInfo = {
4
+ sessionId: string;
5
+ isNew: boolean;
6
+ };
7
+ export declare function getOrCreateSession(): SessionInfo;
8
+ export declare function refreshSession(): void;
9
+ export declare function endSession(): void;
10
+ export declare function getSessionId(): string | null;
11
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,gBAAgB,CAAA;AAIrD,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAEtD;AAuJD,MAAM,MAAM,WAAW,GAAG;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,OAAO,CAAA;CACd,CAAA;AAED,wBAAgB,kBAAkB,IAAI,WAAW,CAehD;AAED,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAED,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAG5C"}
@@ -0,0 +1,176 @@
1
+ const SESSION_KEY = "vident_session";
2
+ const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 min inactivity timeout
3
+ const SESSION_MAX_DURATION_MS = 4 * 60 * 60 * 1000; // 4 hour max duration
4
+ let storageMode = "cookie";
5
+ export function setStorageMode(mode) {
6
+ storageMode = mode;
7
+ }
8
+ function generateSessionId() {
9
+ const bytes = new Uint8Array(16);
10
+ crypto.getRandomValues(bytes);
11
+ return Array.from(bytes)
12
+ .map((b) => b.toString(16).padStart(2, "0"))
13
+ .join("");
14
+ }
15
+ // Cookie operations
16
+ function parseCookieValue(name) {
17
+ const cookies = document.cookie.split("; ");
18
+ for (const cookie of cookies) {
19
+ const [key, ...rest] = cookie.split("=");
20
+ if (key === name) {
21
+ const value = rest.join("=");
22
+ return value ? decodeURIComponent(value) : null;
23
+ }
24
+ }
25
+ return null;
26
+ }
27
+ function getCookie(name) {
28
+ try {
29
+ return parseCookieValue(name);
30
+ }
31
+ catch {
32
+ return null;
33
+ }
34
+ }
35
+ function setCookie(name, value) {
36
+ try {
37
+ // Session cookie (no max-age) - cleared when browser closes
38
+ // SameSite=Lax allows cookie to be sent on OAuth redirects back to our site
39
+ document.cookie = `${name}=${encodeURIComponent(value)}; path=/; SameSite=Lax`;
40
+ }
41
+ catch {
42
+ // Cookies may be unavailable
43
+ }
44
+ }
45
+ function deleteCookie(name) {
46
+ try {
47
+ document.cookie = `${name}=; path=/; max-age=0`;
48
+ }
49
+ catch {
50
+ // Ignore errors
51
+ }
52
+ }
53
+ // localStorage fallback for environments where cookies are restricted
54
+ function getLocalStorage(key) {
55
+ try {
56
+ return localStorage.getItem(key);
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ }
62
+ function setLocalStorage(key, value) {
63
+ try {
64
+ localStorage.setItem(key, value);
65
+ }
66
+ catch {
67
+ // localStorage may be unavailable
68
+ }
69
+ }
70
+ function deleteLocalStorage(key) {
71
+ try {
72
+ localStorage.removeItem(key);
73
+ }
74
+ catch {
75
+ // Ignore errors
76
+ }
77
+ }
78
+ // sessionStorage operations
79
+ function getSessionStorage(key) {
80
+ try {
81
+ return sessionStorage.getItem(key);
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
87
+ function setSessionStorage(key, value) {
88
+ try {
89
+ sessionStorage.setItem(key, value);
90
+ }
91
+ catch {
92
+ // sessionStorage may be unavailable
93
+ }
94
+ }
95
+ function deleteSessionStorage(key) {
96
+ try {
97
+ sessionStorage.removeItem(key);
98
+ }
99
+ catch {
100
+ // Ignore errors
101
+ }
102
+ }
103
+ function parseSessionData(value) {
104
+ if (!value)
105
+ return null;
106
+ try {
107
+ return JSON.parse(value);
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ // Storage abstraction based on mode
114
+ function getStoredSession() {
115
+ if (storageMode === "sessionStorage") {
116
+ return parseSessionData(getSessionStorage(SESSION_KEY));
117
+ }
118
+ // Cookie mode: try cookie first, fallback to localStorage
119
+ const cookieData = parseSessionData(getCookie(SESSION_KEY));
120
+ if (cookieData)
121
+ return cookieData;
122
+ return parseSessionData(getLocalStorage(SESSION_KEY));
123
+ }
124
+ function storeSession(data) {
125
+ const value = JSON.stringify(data);
126
+ if (storageMode === "sessionStorage") {
127
+ setSessionStorage(SESSION_KEY, value);
128
+ return;
129
+ }
130
+ // Cookie mode: store in both cookie and localStorage (fallback)
131
+ setCookie(SESSION_KEY, value);
132
+ setLocalStorage(SESSION_KEY, value);
133
+ }
134
+ function clearSession() {
135
+ if (storageMode === "sessionStorage") {
136
+ deleteSessionStorage(SESSION_KEY);
137
+ return;
138
+ }
139
+ deleteCookie(SESSION_KEY);
140
+ deleteLocalStorage(SESSION_KEY);
141
+ }
142
+ function isSessionValid(session) {
143
+ const now = Date.now();
144
+ const inactivityValid = now - session.lastActivity < SESSION_TIMEOUT_MS;
145
+ const durationValid = now - session.startTime < SESSION_MAX_DURATION_MS;
146
+ return inactivityValid && durationValid;
147
+ }
148
+ export function getOrCreateSession() {
149
+ const existing = getStoredSession();
150
+ if (existing && isSessionValid(existing)) {
151
+ return { sessionId: existing.id, isNew: false };
152
+ }
153
+ const now = Date.now();
154
+ const newSession = {
155
+ id: generateSessionId(),
156
+ startTime: now,
157
+ lastActivity: now,
158
+ };
159
+ storeSession(newSession);
160
+ return { sessionId: newSession.id, isNew: true };
161
+ }
162
+ export function refreshSession() {
163
+ const existing = getStoredSession();
164
+ if (existing && isSessionValid(existing)) {
165
+ existing.lastActivity = Date.now();
166
+ storeSession(existing);
167
+ }
168
+ }
169
+ export function endSession() {
170
+ clearSession();
171
+ }
172
+ export function getSessionId() {
173
+ const existing = getStoredSession();
174
+ return existing && isSessionValid(existing) ? existing.id : null;
175
+ }
176
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * W3C Trace Context utilities for browser-side distributed tracing.
3
+ * Implements the W3C Trace Context specification:
4
+ * https://www.w3.org/TR/trace-context/
5
+ *
6
+ * traceparent format: version-traceId-spanId-flags
7
+ * Example: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
8
+ */
9
+ export type TraceparentData = {
10
+ traceId: string;
11
+ spanId: string;
12
+ sampled: boolean;
13
+ };
14
+ /**
15
+ * Generate a random 32-character hex trace ID (16 bytes).
16
+ * Uses crypto.getRandomValues for cryptographically secure randomness.
17
+ */
18
+ export declare function generateTraceId(): string;
19
+ /**
20
+ * Generate a random 16-character hex span ID (8 bytes).
21
+ */
22
+ export declare function generateSpanId(): string;
23
+ /**
24
+ * Parse a W3C traceparent header into its components.
25
+ * Returns null if the header is invalid.
26
+ */
27
+ export declare function parseTraceparent(header: string): TraceparentData | null;
28
+ /**
29
+ * Create a W3C traceparent header value.
30
+ */
31
+ export declare function createTraceparent(traceId: string, spanId: string, sampled: boolean): string;
32
+ /**
33
+ * Check if a URL should have trace context propagated.
34
+ * Propagates to same-origin, same root domain, or explicitly allowed origins.
35
+ */
36
+ export declare function shouldPropagate(url: string, propagateToOrigins?: (string | RegExp)[]): boolean;
37
+ //# sourceMappingURL=trace-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-context.d.ts","sourceRoot":"","sources":["../src/trace-context.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;CAChB,CAAA;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAMxC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAMvC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAkBvE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACd,MAAM,CAGR;AAeD;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,GAAG,EAAE,MAAM,EACX,kBAAkB,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GACtC,OAAO,CAuCT"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * W3C Trace Context utilities for browser-side distributed tracing.
3
+ * Implements the W3C Trace Context specification:
4
+ * https://www.w3.org/TR/trace-context/
5
+ *
6
+ * traceparent format: version-traceId-spanId-flags
7
+ * Example: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
8
+ */
9
+ const TRACEPARENT_REGEX = /^00-([a-f0-9]{32})-([a-f0-9]{16})-([a-f0-9]{2})$/;
10
+ /**
11
+ * Generate a random 32-character hex trace ID (16 bytes).
12
+ * Uses crypto.getRandomValues for cryptographically secure randomness.
13
+ */
14
+ export function generateTraceId() {
15
+ const bytes = new Uint8Array(16);
16
+ crypto.getRandomValues(bytes);
17
+ return Array.from(bytes)
18
+ .map((b) => b.toString(16).padStart(2, "0"))
19
+ .join("");
20
+ }
21
+ /**
22
+ * Generate a random 16-character hex span ID (8 bytes).
23
+ */
24
+ export function generateSpanId() {
25
+ const bytes = new Uint8Array(8);
26
+ crypto.getRandomValues(bytes);
27
+ return Array.from(bytes)
28
+ .map((b) => b.toString(16).padStart(2, "0"))
29
+ .join("");
30
+ }
31
+ /**
32
+ * Parse a W3C traceparent header into its components.
33
+ * Returns null if the header is invalid.
34
+ */
35
+ export function parseTraceparent(header) {
36
+ const match = header.match(TRACEPARENT_REGEX);
37
+ if (!match)
38
+ return null;
39
+ const [, traceId, spanId, flags] = match;
40
+ if (!traceId || !spanId || !flags)
41
+ return null;
42
+ // Validate trace ID is not all zeros
43
+ if (traceId === "00000000000000000000000000000000")
44
+ return null;
45
+ // Validate span ID is not all zeros
46
+ if (spanId === "0000000000000000")
47
+ return null;
48
+ return {
49
+ traceId,
50
+ spanId,
51
+ sampled: (Number.parseInt(flags, 16) & 0x01) === 1,
52
+ };
53
+ }
54
+ /**
55
+ * Create a W3C traceparent header value.
56
+ */
57
+ export function createTraceparent(traceId, spanId, sampled) {
58
+ const flags = sampled ? "01" : "00";
59
+ return `00-${traceId}-${spanId}-${flags}`;
60
+ }
61
+ /**
62
+ * Extract the root domain from a hostname (e.g., "app.example.com" -> "example.com")
63
+ */
64
+ function getRootDomain(hostname) {
65
+ const parts = hostname.split(".");
66
+ // Handle localhost and IP addresses
67
+ if (parts.length <= 2 || hostname === "localhost") {
68
+ return hostname;
69
+ }
70
+ // Return last two parts (e.g., "example.com")
71
+ return parts.slice(-2).join(".");
72
+ }
73
+ /**
74
+ * Check if a URL should have trace context propagated.
75
+ * Propagates to same-origin, same root domain, or explicitly allowed origins.
76
+ */
77
+ export function shouldPropagate(url, propagateToOrigins) {
78
+ let parsedUrl;
79
+ try {
80
+ parsedUrl = new URL(url, window.location.origin);
81
+ }
82
+ catch {
83
+ return false;
84
+ }
85
+ // Always propagate to same origin
86
+ if (parsedUrl.origin === window.location.origin) {
87
+ return true;
88
+ }
89
+ // Auto-propagate to same root domain (e.g., app.example.com -> api.example.com)
90
+ const currentRootDomain = getRootDomain(window.location.hostname);
91
+ const targetRootDomain = getRootDomain(parsedUrl.hostname);
92
+ if (currentRootDomain === targetRootDomain) {
93
+ return true;
94
+ }
95
+ // Check against allowlist
96
+ if (propagateToOrigins && propagateToOrigins.length > 0) {
97
+ for (const pattern of propagateToOrigins) {
98
+ if (typeof pattern === "string") {
99
+ if (parsedUrl.origin === pattern ||
100
+ parsedUrl.href.startsWith(pattern)) {
101
+ return true;
102
+ }
103
+ }
104
+ else if (pattern instanceof RegExp) {
105
+ if (pattern.test(parsedUrl.href)) {
106
+ return true;
107
+ }
108
+ }
109
+ }
110
+ }
111
+ return false;
112
+ }
113
+ //# sourceMappingURL=trace-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-context.js","sourceRoot":"","sources":["../src/trace-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { RumEvent } from "./events.js";
2
+ export type TransportConfig = {
3
+ apiKey: string;
4
+ baseUrl: string;
5
+ appName?: string;
6
+ flushInterval?: number;
7
+ maxBatchSize?: number;
8
+ };
9
+ export declare function createTransport(config: TransportConfig): {
10
+ enqueue: (event: RumEvent) => void;
11
+ flush: () => Promise<void>;
12
+ flushBeacon: () => void;
13
+ };
14
+ export type Transport = ReturnType<typeof createTransport>;
15
+ //# sourceMappingURL=transport.d.ts.map