@spanwise/rum 0.4.3

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 (53) hide show
  1. package/dist/client.d.ts +51 -0
  2. package/dist/client.d.ts.map +1 -0
  3. package/dist/client.js +186 -0
  4. package/dist/client.js.map +1 -0
  5. package/dist/errors.d.ts +8 -0
  6. package/dist/errors.d.ts.map +1 -0
  7. package/dist/errors.js +67 -0
  8. package/dist/errors.js.map +1 -0
  9. package/dist/events.d.ts +78 -0
  10. package/dist/events.d.ts.map +1 -0
  11. package/dist/events.js +11 -0
  12. package/dist/events.js.map +1 -0
  13. package/dist/index.d.ts +4 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +3 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/instrumentation/fetch.d.ts +16 -0
  18. package/dist/instrumentation/fetch.d.ts.map +1 -0
  19. package/dist/instrumentation/fetch.js +109 -0
  20. package/dist/instrumentation/fetch.js.map +1 -0
  21. package/dist/instrumentation/xhr.d.ts +16 -0
  22. package/dist/instrumentation/xhr.d.ts.map +1 -0
  23. package/dist/instrumentation/xhr.js +129 -0
  24. package/dist/instrumentation/xhr.js.map +1 -0
  25. package/dist/otel.d.ts +55 -0
  26. package/dist/otel.d.ts.map +1 -0
  27. package/dist/otel.js +91 -0
  28. package/dist/otel.js.map +1 -0
  29. package/dist/session.d.ts +11 -0
  30. package/dist/session.d.ts.map +1 -0
  31. package/dist/session.js +176 -0
  32. package/dist/session.js.map +1 -0
  33. package/dist/span-transport.d.ts +18 -0
  34. package/dist/span-transport.d.ts.map +1 -0
  35. package/dist/span-transport.js +83 -0
  36. package/dist/span-transport.js.map +1 -0
  37. package/dist/spans.d.ts +30 -0
  38. package/dist/spans.d.ts.map +1 -0
  39. package/dist/spans.js +21 -0
  40. package/dist/spans.js.map +1 -0
  41. package/dist/trace-context.d.ts +37 -0
  42. package/dist/trace-context.d.ts.map +1 -0
  43. package/dist/trace-context.js +113 -0
  44. package/dist/trace-context.js.map +1 -0
  45. package/dist/transport.d.ts +15 -0
  46. package/dist/transport.d.ts.map +1 -0
  47. package/dist/transport.js +101 -0
  48. package/dist/transport.js.map +1 -0
  49. package/dist/vitals.d.ts +12 -0
  50. package/dist/vitals.d.ts.map +1 -0
  51. package/dist/vitals.js +48 -0
  52. package/dist/vitals.js.map +1 -0
  53. package/package.json +38 -0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * XMLHttpRequest instrumentation for browser-side resource tracking.
3
+ * Intercepts XHR calls to inject traceparent headers and capture timing.
4
+ */
5
+ import { createBaseEvent } from "../events.js";
6
+ import { createTraceparent, generateSpanId, generateTraceId, shouldPropagate, } from "../trace-context.js";
7
+ // Module state for monkey-patching. Only one instrumentation instance supported.
8
+ let originalOpen = null;
9
+ let originalSend = null;
10
+ let currentConfig = null;
11
+ let onXHRError = null;
12
+ function createResourceEvent(config, data, duration, status) {
13
+ return {
14
+ type: "resource",
15
+ sessionId: config.sessionId,
16
+ userId: config.userId,
17
+ timestamp: data.startTime,
18
+ url: window.location.href,
19
+ userAgent: navigator.userAgent,
20
+ data: {
21
+ resourceUrl: data.url,
22
+ method: data.method,
23
+ status,
24
+ duration,
25
+ initiatorType: "xhr",
26
+ traceId: data.traceId,
27
+ },
28
+ };
29
+ }
30
+ export function instrumentXHR(config, onResource, onError) {
31
+ if (originalOpen)
32
+ return;
33
+ originalOpen = XMLHttpRequest.prototype.open;
34
+ originalSend = XMLHttpRequest.prototype.send;
35
+ currentConfig = config;
36
+ onXHRError = onError ?? null;
37
+ XMLHttpRequest.prototype.open = function (method, url, async, username, password) {
38
+ const urlString = url.toString();
39
+ const shouldInjectTrace = shouldPropagate(urlString, currentConfig?.propagateToOrigins);
40
+ this._spanwise = {
41
+ method,
42
+ url: urlString,
43
+ traceId: shouldInjectTrace ? generateTraceId() : undefined,
44
+ startTime: 0,
45
+ };
46
+ // biome-ignore lint/style/noNonNullAssertion: checked at function entry
47
+ originalOpen.call(this, method, url, async ?? true, username ?? null, password ?? null);
48
+ };
49
+ XMLHttpRequest.prototype.send = function (body) {
50
+ const data = this._spanwise;
51
+ // Skip internal requests (Next.js RSC, SDK telemetry) or if no tracking data
52
+ if (!data ||
53
+ data.url.includes("_rsc=") ||
54
+ (currentConfig?.ingestUrl && data.url.startsWith(currentConfig.ingestUrl))) {
55
+ // biome-ignore lint/style/noNonNullAssertion: checked at function entry
56
+ originalSend.call(this, body);
57
+ return;
58
+ }
59
+ // Only inject traceparent for allowed origins
60
+ if (data.traceId) {
61
+ const spanId = generateSpanId();
62
+ const traceparent = createTraceparent(data.traceId, spanId, true);
63
+ this.setRequestHeader("traceparent", traceparent);
64
+ }
65
+ data.startTime = Date.now();
66
+ const emitResource = (status) => {
67
+ const duration = Date.now() - data.startTime;
68
+ // biome-ignore lint/style/noNonNullAssertion: config set at function entry
69
+ onResource(createResourceEvent(currentConfig, data, duration, status));
70
+ };
71
+ this.addEventListener("load", () => emitResource(this.status));
72
+ this.addEventListener("error", () => {
73
+ emitResource();
74
+ // Emit error event with the failed URL for better debugging
75
+ if (onXHRError) {
76
+ // biome-ignore lint/style/noNonNullAssertion: config set at function entry
77
+ const config = currentConfig;
78
+ const errorEvent = {
79
+ ...createBaseEvent("error", config.sessionId, config.userId),
80
+ type: "error",
81
+ data: {
82
+ message: `XHR request failed: ${data.method} ${data.url}`,
83
+ failedUrl: data.url,
84
+ traceId: data.traceId,
85
+ },
86
+ };
87
+ onXHRError(errorEvent);
88
+ }
89
+ });
90
+ this.addEventListener("timeout", () => {
91
+ emitResource();
92
+ if (onXHRError) {
93
+ // biome-ignore lint/style/noNonNullAssertion: config set at function entry
94
+ const config = currentConfig;
95
+ const errorEvent = {
96
+ ...createBaseEvent("error", config.sessionId, config.userId),
97
+ type: "error",
98
+ data: {
99
+ message: `XHR request timed out: ${data.method} ${data.url}`,
100
+ failedUrl: data.url,
101
+ traceId: data.traceId,
102
+ },
103
+ };
104
+ onXHRError(errorEvent);
105
+ }
106
+ });
107
+ this.addEventListener("abort", () => emitResource());
108
+ // biome-ignore lint/style/noNonNullAssertion: checked at function entry
109
+ originalSend.call(this, body);
110
+ };
111
+ }
112
+ export function updateXHRConfig(userId) {
113
+ if (currentConfig) {
114
+ currentConfig.userId = userId;
115
+ }
116
+ }
117
+ export function restoreXHR() {
118
+ if (originalOpen) {
119
+ XMLHttpRequest.prototype.open = originalOpen;
120
+ originalOpen = null;
121
+ }
122
+ if (originalSend) {
123
+ XMLHttpRequest.prototype.send = originalSend;
124
+ originalSend = null;
125
+ }
126
+ currentConfig = null;
127
+ onXHRError = null;
128
+ }
129
+ //# sourceMappingURL=xhr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xhr.js","sourceRoot":"","sources":["../../src/instrumentation/xhr.ts"],"names":[],"mappings":"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"}
package/dist/otel.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * OpenTelemetry format converter for browser spans.
3
+ * Converts BrowserSpan format to OTLP (OpenTelemetry Protocol) format.
4
+ */
5
+ import type { BrowserSpan } from "./spans.js";
6
+ type OTLPAttribute = {
7
+ key: string;
8
+ value: {
9
+ stringValue: string;
10
+ };
11
+ } | {
12
+ key: string;
13
+ value: {
14
+ intValue: string;
15
+ };
16
+ } | {
17
+ key: string;
18
+ value: {
19
+ boolValue: boolean;
20
+ };
21
+ };
22
+ type OTLPSpan = {
23
+ traceId: string;
24
+ spanId: string;
25
+ parentSpanId?: string;
26
+ name: string;
27
+ kind: number;
28
+ startTimeUnixNano: string;
29
+ endTimeUnixNano: string;
30
+ attributes: OTLPAttribute[];
31
+ status: {
32
+ code: number;
33
+ message?: string;
34
+ };
35
+ };
36
+ type OTLPPayload = {
37
+ resourceSpans: Array<{
38
+ resource: {
39
+ attributes: OTLPAttribute[];
40
+ };
41
+ scopeSpans: Array<{
42
+ scope: {
43
+ name: string;
44
+ version: string;
45
+ };
46
+ spans: OTLPSpan[];
47
+ }>;
48
+ }>;
49
+ };
50
+ /**
51
+ * Convert an array of BrowserSpans to OTLP format for ingestion.
52
+ */
53
+ export declare function toOTLPSpans(spans: BrowserSpan[], serviceName?: string): OTLPPayload;
54
+ export {};
55
+ //# sourceMappingURL=otel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,KAAK,aAAa,GACf;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC/C;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC5C;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAA;AAEjD,KAAK,QAAQ,GAAG;IACf,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,iBAAiB,EAAE,MAAM,CAAA;IACzB,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,MAAM,EAAE;QACP,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACD,CAAA;AAED,KAAK,WAAW,GAAG;IAClB,aAAa,EAAE,KAAK,CAAC;QACpB,QAAQ,EAAE;YACT,UAAU,EAAE,aAAa,EAAE,CAAA;SAC3B,CAAA;QACD,UAAU,EAAE,KAAK,CAAC;YACjB,KAAK,EAAE;gBACN,IAAI,EAAE,MAAM,CAAA;gBACZ,OAAO,EAAE,MAAM,CAAA;aACf,CAAA;YACD,KAAK,EAAE,QAAQ,EAAE,CAAA;SACjB,CAAC,CAAA;KACF,CAAC,CAAA;CACF,CAAA;AAkCD;;GAEG;AACH,wBAAgB,WAAW,CAC1B,KAAK,EAAE,WAAW,EAAE,EACpB,WAAW,CAAC,EAAE,MAAM,GAClB,WAAW,CA2Db"}
package/dist/otel.js ADDED
@@ -0,0 +1,91 @@
1
+ /**
2
+ * OpenTelemetry format converter for browser spans.
3
+ * Converts BrowserSpan format to OTLP (OpenTelemetry Protocol) format.
4
+ */
5
+ // OpenTelemetry SpanKind values
6
+ // 0 = UNSPECIFIED, 1 = INTERNAL, 2 = SERVER, 3 = CLIENT, 4 = PRODUCER, 5 = CONSUMER
7
+ const SPAN_KIND_CLIENT = 3;
8
+ // OpenTelemetry StatusCode values
9
+ // 0 = UNSET, 1 = OK, 2 = ERROR
10
+ function statusToCode(status) {
11
+ switch (status) {
12
+ case "OK":
13
+ return 1;
14
+ case "ERROR":
15
+ return 2;
16
+ default:
17
+ return 0;
18
+ }
19
+ }
20
+ function attributeToOTLP(key, value) {
21
+ if (value === undefined)
22
+ return null;
23
+ if (typeof value === "number") {
24
+ return { key, value: { intValue: String(value) } };
25
+ }
26
+ if (typeof value === "boolean") {
27
+ return { key, value: { boolValue: value } };
28
+ }
29
+ return { key, value: { stringValue: String(value) } };
30
+ }
31
+ /**
32
+ * Convert an array of BrowserSpans to OTLP format for ingestion.
33
+ */
34
+ export function toOTLPSpans(spans, serviceName) {
35
+ const otlpSpans = spans.map((span) => {
36
+ const attributes = [];
37
+ // Convert span attributes to OTLP format
38
+ for (const [key, value] of Object.entries(span.attributes)) {
39
+ const attr = attributeToOTLP(key, value);
40
+ if (attr) {
41
+ attributes.push(attr);
42
+ }
43
+ }
44
+ return {
45
+ traceId: span.traceId,
46
+ spanId: span.spanId,
47
+ parentSpanId: span.parentSpanId,
48
+ name: span.name,
49
+ kind: SPAN_KIND_CLIENT,
50
+ startTimeUnixNano: String(span.startTime * 1_000_000),
51
+ endTimeUnixNano: String((span.endTime ?? span.startTime) * 1_000_000),
52
+ attributes,
53
+ status: {
54
+ code: statusToCode(span.status),
55
+ message: span.errorMessage,
56
+ },
57
+ };
58
+ });
59
+ return {
60
+ resourceSpans: [
61
+ {
62
+ resource: {
63
+ attributes: [
64
+ {
65
+ key: "service.name",
66
+ value: { stringValue: serviceName ?? "browser" },
67
+ },
68
+ {
69
+ key: "telemetry.sdk.name",
70
+ value: { stringValue: "@haspulse/rum" },
71
+ },
72
+ {
73
+ key: "telemetry.sdk.language",
74
+ value: { stringValue: "javascript" },
75
+ },
76
+ ],
77
+ },
78
+ scopeSpans: [
79
+ {
80
+ scope: {
81
+ name: "@haspulse/rum",
82
+ version: "0.3.0",
83
+ },
84
+ spans: otlpSpans,
85
+ },
86
+ ],
87
+ },
88
+ ],
89
+ };
90
+ }
91
+ //# sourceMappingURL=otel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel.js","sourceRoot":"","sources":["../src/otel.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 = "spanwise_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,18 @@
1
+ /**
2
+ * Span transport for batching and exporting browser spans.
3
+ * Handles periodic flushing and page unload scenarios.
4
+ */
5
+ import type { BrowserSpan } from "./spans.js";
6
+ export type SpanTransportConfig = {
7
+ apiKey: string;
8
+ baseUrl: string;
9
+ serviceName?: string;
10
+ flushInterval?: number;
11
+ maxBatchSize?: number;
12
+ };
13
+ export declare function createSpanTransport(config: SpanTransportConfig): {
14
+ enqueue: (span: BrowserSpan) => void;
15
+ flush: () => Promise<void>;
16
+ };
17
+ export type SpanTransport = ReturnType<typeof createSpanTransport>;
18
+ //# sourceMappingURL=span-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"span-transport.d.ts","sourceRoot":"","sources":["../src/span-transport.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,MAAM,mBAAmB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAKD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB;oBAcvC,WAAW,KAAG,IAAI;iBASjB,OAAO,CAAC,IAAI,CAAC;EAgErC;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAA"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Span transport for batching and exporting browser spans.
3
+ * Handles periodic flushing and page unload scenarios.
4
+ */
5
+ import { toOTLPSpans } from "./otel.js";
6
+ const DEFAULT_FLUSH_INTERVAL = 5000;
7
+ const DEFAULT_MAX_BATCH_SIZE = 50;
8
+ export function createSpanTransport(config) {
9
+ const queue = [];
10
+ let flushTimer = null;
11
+ const flushInterval = config.flushInterval ?? DEFAULT_FLUSH_INTERVAL;
12
+ const maxBatchSize = config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE;
13
+ function scheduleFlush() {
14
+ if (flushTimer)
15
+ return;
16
+ flushTimer = setTimeout(() => {
17
+ flushTimer = null;
18
+ flush();
19
+ }, flushInterval);
20
+ }
21
+ function enqueue(span) {
22
+ queue.push(span);
23
+ if (queue.length >= maxBatchSize) {
24
+ flush();
25
+ }
26
+ else {
27
+ scheduleFlush();
28
+ }
29
+ }
30
+ async function flush() {
31
+ if (flushTimer) {
32
+ clearTimeout(flushTimer);
33
+ flushTimer = null;
34
+ }
35
+ if (queue.length === 0)
36
+ return;
37
+ const batch = queue.splice(0);
38
+ const payload = toOTLPSpans(batch, config.serviceName);
39
+ try {
40
+ const response = await fetch(`${config.baseUrl}/v1/ingest/spans`, {
41
+ method: "POST",
42
+ headers: {
43
+ "Content-Type": "application/json",
44
+ "x-api-key": config.apiKey,
45
+ },
46
+ body: JSON.stringify(payload),
47
+ keepalive: true,
48
+ });
49
+ if (!response.ok) {
50
+ console.warn("[HasPulse RUM] Failed to send spans:", response.status);
51
+ }
52
+ }
53
+ catch (error) {
54
+ console.warn("[HasPulse RUM] Failed to send spans:", error);
55
+ }
56
+ }
57
+ function flushBeacon() {
58
+ if (queue.length === 0)
59
+ return;
60
+ const batch = queue.splice(0);
61
+ const payload = toOTLPSpans(batch, config.serviceName);
62
+ const blob = new Blob([JSON.stringify(payload)], {
63
+ type: "application/json",
64
+ });
65
+ navigator.sendBeacon(`${config.baseUrl}/v1/ingest/spans?key=${config.apiKey}`, blob);
66
+ }
67
+ function setupUnloadHandler() {
68
+ window.addEventListener("visibilitychange", () => {
69
+ if (document.visibilityState === "hidden") {
70
+ flushBeacon();
71
+ }
72
+ });
73
+ window.addEventListener("pagehide", () => {
74
+ flushBeacon();
75
+ });
76
+ }
77
+ setupUnloadHandler();
78
+ return {
79
+ enqueue,
80
+ flush,
81
+ };
82
+ }
83
+ //# sourceMappingURL=span-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"span-transport.js","sourceRoot":"","sources":["../src/span-transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Browser span types for distributed tracing.
3
+ * These spans are created for instrumented fetch/XHR requests
4
+ * and sent to the backend for correlation with server-side traces.
5
+ */
6
+ export type SpanStatus = "UNSET" | "OK" | "ERROR";
7
+ export type BrowserSpan = {
8
+ traceId: string;
9
+ spanId: string;
10
+ parentSpanId?: string;
11
+ name: string;
12
+ kind: "CLIENT";
13
+ startTime: number;
14
+ endTime?: number;
15
+ attributes: {
16
+ "http.method"?: string;
17
+ "http.url"?: string;
18
+ "http.status_code"?: number;
19
+ "http.request.body.size"?: number;
20
+ "http.response.body.size"?: number;
21
+ [key: string]: string | number | boolean | undefined;
22
+ };
23
+ status: SpanStatus;
24
+ errorMessage?: string;
25
+ };
26
+ /**
27
+ * Create a new browser span with the given properties.
28
+ */
29
+ export declare function createBrowserSpan(traceId: string, spanId: string, name: string, parentSpanId?: string): BrowserSpan;
30
+ //# sourceMappingURL=spans.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spans.d.ts","sourceRoot":"","sources":["../src/spans.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,GAAG,OAAO,CAAA;AAEjD,MAAM,MAAM,WAAW,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,QAAQ,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE;QACX,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B,wBAAwB,CAAC,EAAE,MAAM,CAAA;QACjC,yBAAyB,CAAC,EAAE,MAAM,CAAA;QAClC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;KACpD,CAAA;IACD,MAAM,EAAE,UAAU,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,YAAY,CAAC,EAAE,MAAM,GACnB,WAAW,CAWb"}
package/dist/spans.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Browser span types for distributed tracing.
3
+ * These spans are created for instrumented fetch/XHR requests
4
+ * and sent to the backend for correlation with server-side traces.
5
+ */
6
+ /**
7
+ * Create a new browser span with the given properties.
8
+ */
9
+ export function createBrowserSpan(traceId, spanId, name, parentSpanId) {
10
+ return {
11
+ traceId,
12
+ spanId,
13
+ parentSpanId,
14
+ name,
15
+ kind: "CLIENT",
16
+ startTime: Date.now(),
17
+ attributes: {},
18
+ status: "UNSET",
19
+ };
20
+ }
21
+ //# sourceMappingURL=spans.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spans.js","sourceRoot":"","sources":["../src/spans.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAwBH;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAChC,OAAe,EACf,MAAc,EACd,IAAY,EACZ,YAAqB;IAErB,OAAO;QACN,OAAO;QACP,MAAM;QACN,YAAY;QACZ,IAAI;QACJ,IAAI,EAAE,QAAQ;QACd,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,UAAU,EAAE,EAAE;QACd,MAAM,EAAE,OAAO;KACf,CAAA;AACF,CAAC"}