@squasher-ai/browser 0.1.1 → 0.2.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 +21 -21
- package/README.md +2 -41
- package/dist/__tests__/client/harness.d.ts +18 -0
- package/dist/__tests__/client/harness.d.ts.map +1 -0
- package/dist/__tests__/client/harness.js +106 -0
- package/dist/__tests__/replay/coverage-harness.d.ts +29 -0
- package/dist/__tests__/replay/coverage-harness.d.ts.map +1 -0
- package/dist/__tests__/replay/coverage-harness.js +123 -0
- package/dist/__tests__/replay/test-helpers.d.ts +13 -0
- package/dist/__tests__/replay/test-helpers.d.ts.map +1 -0
- package/dist/__tests__/replay/test-helpers.js +9 -0
- package/dist/autocapture.d.ts +14 -18
- package/dist/autocapture.d.ts.map +1 -1
- package/dist/autocapture.js +77 -95
- package/dist/client.d.ts +12 -19
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +56 -72
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +26 -0
- package/dist/console-capture.d.ts +8 -0
- package/dist/console-capture.d.ts.map +1 -0
- package/dist/console-capture.js +79 -0
- package/dist/errors.d.ts +2 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +8 -5
- package/dist/index.d.ts +5 -38
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -82
- package/dist/next.d.ts +40 -0
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +67 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +12 -10
- package/dist/replay-network.d.ts +21 -0
- package/dist/replay-network.d.ts.map +1 -0
- package/dist/replay-network.js +193 -0
- package/dist/replay-privacy.d.ts +2 -2
- package/dist/replay-privacy.d.ts.map +1 -1
- package/dist/replay-privacy.js +47 -17
- package/dist/replay-retry.d.ts +41 -0
- package/dist/replay-retry.d.ts.map +1 -0
- package/dist/replay-retry.js +193 -0
- package/dist/replay.d.ts +18 -5
- package/dist/replay.d.ts.map +1 -1
- package/dist/replay.js +131 -71
- package/dist/runtime/client-singleton.d.ts +25 -0
- package/dist/runtime/client-singleton.d.ts.map +1 -0
- package/dist/runtime/client-singleton.js +66 -0
- package/dist/runtime/client.d.ts +22 -0
- package/dist/runtime/client.d.ts.map +1 -0
- package/dist/runtime/client.js +12 -0
- package/dist/runtime/replay.d.ts +13 -0
- package/dist/runtime/replay.d.ts.map +1 -0
- package/dist/runtime/replay.js +15 -0
- package/dist/session.d.ts +0 -10
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +20 -21
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +13 -10
- package/dist/trace-context.d.ts +9 -0
- package/dist/trace-context.d.ts.map +1 -0
- package/dist/trace-context.js +13 -0
- package/dist/transport.d.ts +11 -19
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +86 -66
- package/dist/types.d.ts +37 -135
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -7
- package/dist/vitals.d.ts +55 -2
- package/dist/vitals.d.ts.map +1 -1
- package/dist/vitals.js +115 -16
- package/package.json +25 -3
- package/dist/__tests__/client.test.d.ts +0 -2
- package/dist/__tests__/client.test.d.ts.map +0 -1
- package/dist/__tests__/client.test.js +0 -103
- package/dist/__tests__/errors.test.d.ts +0 -2
- package/dist/__tests__/errors.test.d.ts.map +0 -1
- package/dist/__tests__/errors.test.js +0 -80
- package/dist/__tests__/replay-privacy.test.d.ts +0 -2
- package/dist/__tests__/replay-privacy.test.d.ts.map +0 -1
- package/dist/__tests__/replay-privacy.test.js +0 -124
- package/dist/__tests__/replay-startup.test.d.ts +0 -2
- package/dist/__tests__/replay-startup.test.d.ts.map +0 -1
- package/dist/__tests__/replay-startup.test.js +0 -99
- package/dist/__tests__/replay.test.d.ts +0 -2
- package/dist/__tests__/replay.test.d.ts.map +0 -1
- package/dist/__tests__/replay.test.js +0 -217
- package/dist/__tests__/session.test.d.ts +0 -2
- package/dist/__tests__/session.test.d.ts.map +0 -1
- package/dist/__tests__/session.test.js +0 -46
- package/dist/__tests__/transport.test.d.ts +0 -2
- package/dist/__tests__/transport.test.d.ts.map +0 -1
- package/dist/__tests__/transport.test.js +0 -101
- package/dist/__tests__/types.test.d.ts +0 -2
- package/dist/__tests__/types.test.d.ts.map +0 -1
- package/dist/__tests__/types.test.js +0 -139
package/dist/transport.d.ts
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Browser transport.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* 2. Vitals → POST /v1/vitals/{project_id} (batched array)
|
|
4
|
+
* - Errors → POST /v1/ingest/{project_id} (per-event, immediate).
|
|
5
|
+
* - Vitals → POST /v1/vitals/{project_id} (batched).
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Vitals are buffered and flushed on:
|
|
12
|
-
* - Buffer reaching vitalsBufferSize (default: 10)
|
|
13
|
-
* - Timer tick (default: 10s)
|
|
14
|
-
* - Page visibility change to "hidden" (user leaving)
|
|
7
|
+
* Uses navigator.sendBeacon when available so requests survive page unload,
|
|
8
|
+
* falling back to `fetch({ keepalive: true })`. Vitals flush on buffer full,
|
|
9
|
+
* interval tick, and page visibilitychange/pagehide.
|
|
15
10
|
*/
|
|
16
|
-
import type { BrowserErrorEvent, VitalEvent } from "./types";
|
|
11
|
+
import type { BrowserErrorEvent, VitalEvent } from "./types.js";
|
|
17
12
|
export interface TransportConfig {
|
|
18
13
|
endpoint: string;
|
|
19
14
|
projectId: string;
|
|
@@ -28,20 +23,17 @@ export declare class Transport {
|
|
|
28
23
|
private flushTimer;
|
|
29
24
|
private disposed;
|
|
30
25
|
constructor(config: TransportConfig);
|
|
31
|
-
/**
|
|
26
|
+
/** Fire-and-forget. */
|
|
32
27
|
sendEvent(event: BrowserErrorEvent): void;
|
|
33
|
-
/**
|
|
28
|
+
/** @deprecated use {@link sendEvent}. */
|
|
34
29
|
sendError(event: BrowserErrorEvent): void;
|
|
35
|
-
/** Buffer a vital event. Auto-flushes when buffer is full. */
|
|
36
30
|
enqueueVital(event: VitalEvent): void;
|
|
37
|
-
/** Flush all buffered vitals immediately. */
|
|
38
31
|
flushVitals(): void;
|
|
39
|
-
/** Stop all timers and flush remaining data. */
|
|
40
32
|
dispose(): void;
|
|
41
33
|
private buildIngestUrl;
|
|
42
|
-
|
|
34
|
+
private buildVitalsUrl;
|
|
35
|
+
private buildUrl;
|
|
43
36
|
private trySendBeacon;
|
|
44
|
-
/** Send via fetch with keepalive and the API key header. */
|
|
45
37
|
private sendFetch;
|
|
46
38
|
}
|
|
47
39
|
//# sourceMappingURL=transport.d.ts.map
|
package/dist/transport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAiB,MAAM,YAAY,CAAC;AAa/E,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAWD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,QAAQ,CAAS;gBAEb,MAAM,EAAE,eAAe;IAuBnC,uBAAuB;IACvB,SAAS,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAuBzC,yCAAyC;IACzC,SAAS,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAIzC,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAUrC,WAAW,IAAI,IAAI;IAuBnB,OAAO,IAAI,IAAI;IASf,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,aAAa;YAcP,SAAS;CAwBxB"}
|
package/dist/transport.js
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Browser transport.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* 2. Vitals → POST /v1/vitals/{project_id} (batched array)
|
|
4
|
+
* - Errors → POST /v1/ingest/{project_id} (per-event, immediate).
|
|
5
|
+
* - Vitals → POST /v1/vitals/{project_id} (batched).
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Vitals are buffered and flushed on:
|
|
12
|
-
* - Buffer reaching vitalsBufferSize (default: 10)
|
|
13
|
-
* - Timer tick (default: 10s)
|
|
14
|
-
* - Page visibility change to "hidden" (user leaving)
|
|
7
|
+
* Uses navigator.sendBeacon when available so requests survive page unload,
|
|
8
|
+
* falling back to `fetch({ keepalive: true })`. Vitals flush on buffer full,
|
|
9
|
+
* interval tick, and page visibilitychange/pagehide.
|
|
15
10
|
*/
|
|
11
|
+
import { attempt, attemptAsync } from "@squasher-ai/result-utils";
|
|
12
|
+
import { getDefaultHeaders } from "@squasher-ai/sdk-core";
|
|
13
|
+
const SDK_NAME = "@squasher-ai/browser";
|
|
14
|
+
const SDK_VERSION = "0.2.0";
|
|
15
|
+
const BEACON_CONTENT_TYPE = "text/plain";
|
|
16
|
+
// One allocation per process; getDefaultHeaders is pure given package
|
|
17
|
+
// metadata and platform detection memoizes inside sdk-core.
|
|
18
|
+
const DEFAULT_TELEMETRY_HEADERS = getDefaultHeaders({
|
|
19
|
+
packageName: SDK_NAME,
|
|
20
|
+
packageVersion: SDK_VERSION,
|
|
21
|
+
});
|
|
22
|
+
function normalizeEndpoint(endpoint) {
|
|
23
|
+
const trimmed = endpoint.trim();
|
|
24
|
+
if (trimmed.length === 0) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return trimmed.replace(/\/+$/, "");
|
|
28
|
+
}
|
|
16
29
|
export class Transport {
|
|
17
30
|
config;
|
|
18
31
|
vitalsBuffer = [];
|
|
@@ -20,50 +33,47 @@ export class Transport {
|
|
|
20
33
|
disposed = false;
|
|
21
34
|
constructor(config) {
|
|
22
35
|
this.config = config;
|
|
23
|
-
// Start the vitals flush timer
|
|
24
36
|
this.flushTimer = setInterval(() => {
|
|
25
37
|
this.flushVitals();
|
|
26
38
|
}, config.vitalsFlushIntervalMs);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (document.visibilityState === "hidden") {
|
|
39
|
+
if (globalThis.document) {
|
|
40
|
+
globalThis.document.addEventListener("visibilitychange", () => {
|
|
41
|
+
if (globalThis.document.visibilityState === "hidden") {
|
|
31
42
|
this.flushVitals();
|
|
32
43
|
}
|
|
33
44
|
});
|
|
34
45
|
}
|
|
35
|
-
//
|
|
36
|
-
if (
|
|
37
|
-
window.addEventListener("pagehide", () => {
|
|
46
|
+
// `pagehide` fires in cases where `unload` does not (bfcache, iOS Safari).
|
|
47
|
+
if (globalThis.window) {
|
|
48
|
+
globalThis.window.addEventListener("pagehide", () => {
|
|
38
49
|
this.flushVitals();
|
|
39
50
|
});
|
|
40
51
|
}
|
|
41
52
|
}
|
|
42
|
-
|
|
43
|
-
/** Send a single telemetry event immediately. Fire-and-forget. */
|
|
53
|
+
/** Fire-and-forget. */
|
|
44
54
|
sendEvent(event) {
|
|
45
55
|
if (this.disposed)
|
|
46
56
|
return;
|
|
47
57
|
const url = this.buildIngestUrl();
|
|
58
|
+
const beaconUrl = this.buildIngestUrl({ beacon: true });
|
|
59
|
+
if (!url || !beaconUrl) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
48
62
|
const body = JSON.stringify(event);
|
|
49
|
-
|
|
50
|
-
if (this.trySendBeacon(this.buildIngestUrl({ beacon: true }), body)) {
|
|
63
|
+
if (this.trySendBeacon(beaconUrl, body)) {
|
|
51
64
|
if (this.config.debug) {
|
|
52
65
|
console.log("[squasher] Error sent via sendBeacon");
|
|
53
66
|
}
|
|
54
67
|
return;
|
|
55
68
|
}
|
|
56
|
-
// Fallback to fetch with keepalive
|
|
57
69
|
this.sendFetch(url, body).catch(() => {
|
|
58
|
-
//
|
|
70
|
+
// Best-effort in the browser.
|
|
59
71
|
});
|
|
60
72
|
}
|
|
61
|
-
/**
|
|
73
|
+
/** @deprecated use {@link sendEvent}. */
|
|
62
74
|
sendError(event) {
|
|
63
75
|
this.sendEvent(event);
|
|
64
76
|
}
|
|
65
|
-
// ─── Vitals buffering ───────────────────────────────────────────────
|
|
66
|
-
/** Buffer a vital event. Auto-flushes when buffer is full. */
|
|
67
77
|
enqueueVital(event) {
|
|
68
78
|
if (this.disposed)
|
|
69
79
|
return;
|
|
@@ -72,25 +82,25 @@ export class Transport {
|
|
|
72
82
|
this.flushVitals();
|
|
73
83
|
}
|
|
74
84
|
}
|
|
75
|
-
/** Flush all buffered vitals immediately. */
|
|
76
85
|
flushVitals() {
|
|
77
86
|
if (this.vitalsBuffer.length === 0)
|
|
78
87
|
return;
|
|
88
|
+
const url = this.buildVitalsUrl();
|
|
89
|
+
const beaconUrl = this.buildVitalsUrl({ beacon: true });
|
|
90
|
+
if (!url || !beaconUrl) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
79
93
|
const events = this.vitalsBuffer.splice(0);
|
|
80
|
-
const url = `${this.config.endpoint}/v1/vitals/${this.config.projectId}`;
|
|
81
94
|
const payload = { events };
|
|
82
95
|
const body = JSON.stringify(payload);
|
|
83
|
-
if (this.trySendBeacon(
|
|
96
|
+
if (this.trySendBeacon(beaconUrl, body)) {
|
|
84
97
|
if (this.config.debug) {
|
|
85
98
|
console.log(`[squasher] Flushed ${events.length} vitals via sendBeacon`);
|
|
86
99
|
}
|
|
87
100
|
return;
|
|
88
101
|
}
|
|
89
|
-
this.sendFetch(url, body).catch(() => {
|
|
90
|
-
// Best-effort
|
|
91
|
-
});
|
|
102
|
+
this.sendFetch(url, body).catch(() => { });
|
|
92
103
|
}
|
|
93
|
-
/** Stop all timers and flush remaining data. */
|
|
94
104
|
dispose() {
|
|
95
105
|
this.disposed = true;
|
|
96
106
|
if (this.flushTimer) {
|
|
@@ -99,47 +109,57 @@ export class Transport {
|
|
|
99
109
|
}
|
|
100
110
|
this.flushVitals();
|
|
101
111
|
}
|
|
102
|
-
// ─── Private helpers ────────────────────────────────────────────────
|
|
103
112
|
buildIngestUrl(options) {
|
|
104
|
-
|
|
113
|
+
return this.buildUrl("ingest", options);
|
|
114
|
+
}
|
|
115
|
+
buildVitalsUrl(options) {
|
|
116
|
+
return this.buildUrl("vitals", options);
|
|
117
|
+
}
|
|
118
|
+
buildUrl(kind, options) {
|
|
119
|
+
const endpoint = normalizeEndpoint(this.config.endpoint);
|
|
120
|
+
if (!endpoint) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const baseUrl = `${endpoint}/v1/${kind}/${this.config.projectId}`;
|
|
105
124
|
if (!options?.beacon) {
|
|
106
125
|
return baseUrl;
|
|
107
126
|
}
|
|
108
127
|
return `${baseUrl}?key=${encodeURIComponent(this.config.apiKey)}`;
|
|
109
128
|
}
|
|
110
|
-
/** Try sending via navigator.sendBeacon. Returns true if successful. */
|
|
111
129
|
trySendBeacon(url, body) {
|
|
112
|
-
if (
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
try {
|
|
116
|
-
const blob = new Blob([body], { type: "application/json" });
|
|
117
|
-
return navigator.sendBeacon(url, blob);
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
130
|
+
if (!globalThis.navigator?.sendBeacon) {
|
|
120
131
|
return false;
|
|
121
132
|
}
|
|
133
|
+
return attempt({
|
|
134
|
+
try: () => {
|
|
135
|
+
const blob = new Blob([body], { type: BEACON_CONTENT_TYPE });
|
|
136
|
+
return globalThis.navigator.sendBeacon(url, blob);
|
|
137
|
+
},
|
|
138
|
+
catch: () => false,
|
|
139
|
+
});
|
|
122
140
|
}
|
|
123
|
-
/** Send via fetch with keepalive and the API key header. */
|
|
124
141
|
async sendFetch(url, body) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
await attemptAsync({
|
|
143
|
+
try: async () => {
|
|
144
|
+
await fetch(url, {
|
|
145
|
+
method: "POST",
|
|
146
|
+
headers: {
|
|
147
|
+
...DEFAULT_TELEMETRY_HEADERS,
|
|
148
|
+
"Content-Type": "application/json",
|
|
149
|
+
"x-squasher-key": this.config.apiKey,
|
|
150
|
+
},
|
|
151
|
+
body,
|
|
152
|
+
keepalive: true,
|
|
153
|
+
});
|
|
154
|
+
if (this.config.debug) {
|
|
155
|
+
console.log("[squasher] Event sent via fetch");
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
catch: ({ cause }) => {
|
|
159
|
+
if (this.config.debug) {
|
|
160
|
+
console.warn("[squasher] Failed to send event:", cause);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
});
|
|
144
164
|
}
|
|
145
165
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
* @squasher-ai/api-spec. Shapes match the canonical wire protocol in
|
|
6
6
|
* packages/sdk-spec/protocol.schema.json.
|
|
7
7
|
*/
|
|
8
|
+
import type { AnalyticsContext, Breadcrumb as ApiBreadcrumb, IngestEvent, IngestResponse, JsonObject, Level, LlmContext, PageContext, SessionContext, StackFrame, TelemetryKind, TelemetryMeasurement, TelemetrySamplingConfig, ToolCallContext, TraceContext, UserContext, VisitorContext } from "@squasher-ai/api-spec";
|
|
8
9
|
export interface BrowserConfig {
|
|
9
10
|
/** API key (sq_pk_...). Required. */
|
|
10
11
|
apiKey: string;
|
|
11
12
|
/** Project ID (UUID). Required. */
|
|
12
13
|
projectId: string;
|
|
13
|
-
/**
|
|
14
|
+
/** Public edge ingestion endpoint. Default: "https://ingest.squasher.ai" */
|
|
14
15
|
endpoint?: string;
|
|
15
16
|
/** Environment tag (production, staging, development). */
|
|
16
17
|
environment?: string;
|
|
@@ -18,8 +19,8 @@ export interface BrowserConfig {
|
|
|
18
19
|
release?: string;
|
|
19
20
|
/** Enable debug logging to console. Default: false. */
|
|
20
21
|
debug?: boolean;
|
|
21
|
-
/**
|
|
22
|
-
|
|
22
|
+
/** Outcome-aware, deterministic event sampling. */
|
|
23
|
+
sampling?: TelemetrySamplingConfig;
|
|
23
24
|
/** Web Vitals sampling rate 0-1. Default: 1. */
|
|
24
25
|
vitalsSampleRate?: number;
|
|
25
26
|
/** Enable Core Web Vitals collection. Default: true. */
|
|
@@ -28,6 +29,8 @@ export interface BrowserConfig {
|
|
|
28
29
|
enableErrorCapture?: boolean;
|
|
29
30
|
/** Enable auto-capture breadcrumbs (navigation, clicks, fetch). Default: true. */
|
|
30
31
|
enableAutoBreadcrumbs?: boolean;
|
|
32
|
+
/** Capture `console.error(...)` calls as error events. Default: false. */
|
|
33
|
+
captureConsoleErrors?: boolean;
|
|
31
34
|
/**
|
|
32
35
|
* Hook invoked before every error event is sent.
|
|
33
36
|
* Return the event (possibly modified) to send, or null to drop.
|
|
@@ -39,11 +42,11 @@ export interface BrowserConfig {
|
|
|
39
42
|
vitalsBufferSize?: number;
|
|
40
43
|
/** Vitals flush interval in ms. Default: 10000. */
|
|
41
44
|
vitalsFlushIntervalMs?: number;
|
|
42
|
-
/** Optional session replay recording powered by rrweb. */
|
|
45
|
+
/** Optional session replay recording powered by rrweb. Enabled by default. */
|
|
43
46
|
replay?: ReplayConfig;
|
|
44
47
|
}
|
|
45
48
|
export interface ReplayConfig {
|
|
46
|
-
/** Enable rrweb session replay recording for this browser session. */
|
|
49
|
+
/** Enable rrweb session replay recording for this browser session. Default: true. */
|
|
47
50
|
enabled: boolean;
|
|
48
51
|
/** Session-level replay sampling rate from 0-1. Default: 1. */
|
|
49
52
|
sampleRate?: number;
|
|
@@ -56,7 +59,13 @@ export interface ReplayPrivacyConfig {
|
|
|
56
59
|
/** CSS selector for elements that should render as blocked placeholders. */
|
|
57
60
|
blockSelector?: string;
|
|
58
61
|
}
|
|
59
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Well-known web vital names. Includes the 5 Core Web Vitals plus the
|
|
64
|
+
* Next.js framework metrics emitted by `useReportWebVitals` from
|
|
65
|
+
* `next/web-vitals`. The wire format accepts arbitrary strings, so custom
|
|
66
|
+
* names from other frameworks pass through unchanged.
|
|
67
|
+
*/
|
|
68
|
+
export type VitalMetricName = "LCP" | "CLS" | "INP" | "FCP" | "TTFB" | "Next.js-hydration" | "Next.js-route-change-to-render" | "Next.js-render" | (string & {});
|
|
60
69
|
export type VitalRating = "good" | "needs-improvement" | "poor";
|
|
61
70
|
export type DeviceType = "mobile" | "tablet" | "desktop";
|
|
62
71
|
/** Single vital measurement sent to POST /v1/vitals/{project_id}. */
|
|
@@ -90,145 +99,38 @@ export interface VitalEvent {
|
|
|
90
99
|
device_type?: DeviceType;
|
|
91
100
|
/** Document referrer. */
|
|
92
101
|
referrer?: string;
|
|
102
|
+
/** Browser language, for example en-US. */
|
|
103
|
+
language?: string;
|
|
104
|
+
/** Browser time zone, for example America/Los_Angeles. */
|
|
105
|
+
timezone?: string;
|
|
106
|
+
/** URL pathname at measurement time. */
|
|
107
|
+
page_path?: string;
|
|
108
|
+
/** URL query string without the leading question mark. */
|
|
109
|
+
query_string?: string;
|
|
110
|
+
/** UTM source query parameter. */
|
|
111
|
+
utm_source?: string;
|
|
112
|
+
/** UTM medium query parameter. */
|
|
113
|
+
utm_medium?: string;
|
|
114
|
+
/** UTM campaign query parameter. */
|
|
115
|
+
utm_campaign?: string;
|
|
93
116
|
}
|
|
94
117
|
/** Batched payload sent to the vitals endpoint. */
|
|
95
118
|
export interface VitalsPayload {
|
|
96
119
|
events: VitalEvent[];
|
|
97
120
|
}
|
|
98
|
-
export type Level
|
|
99
|
-
export type
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
export
|
|
103
|
-
[
|
|
104
|
-
|
|
105
|
-
export interface VisitorContext {
|
|
106
|
-
visitor_id?: string;
|
|
107
|
-
anonymous_id?: string;
|
|
108
|
-
account_id?: string;
|
|
109
|
-
}
|
|
110
|
-
export interface AnalyticsContext {
|
|
111
|
-
event?: string;
|
|
112
|
-
category?: string;
|
|
113
|
-
funnel?: string;
|
|
114
|
-
step?: string;
|
|
115
|
-
properties?: JsonObject;
|
|
116
|
-
}
|
|
117
|
-
export interface PageContext {
|
|
118
|
-
name?: string;
|
|
119
|
-
path?: string;
|
|
120
|
-
title?: string;
|
|
121
|
-
referrer?: string;
|
|
122
|
-
search?: string;
|
|
123
|
-
screen_class?: string;
|
|
124
|
-
}
|
|
125
|
-
export interface SessionContext {
|
|
126
|
-
session_type?: string;
|
|
127
|
-
agent_id?: string;
|
|
128
|
-
run_id?: string;
|
|
129
|
-
workflow_id?: string;
|
|
130
|
-
step_id?: string;
|
|
131
|
-
status?: string;
|
|
132
|
-
duration_ms?: number;
|
|
133
|
-
}
|
|
134
|
-
export interface TraceContext {
|
|
135
|
-
trace_id?: string;
|
|
136
|
-
span_id?: string;
|
|
137
|
-
parent_span_id?: string;
|
|
138
|
-
span_name?: string;
|
|
139
|
-
span_kind?: string;
|
|
140
|
-
status?: string;
|
|
141
|
-
duration_ms?: number;
|
|
142
|
-
}
|
|
143
|
-
export interface ToolCallContext {
|
|
144
|
-
name?: string;
|
|
145
|
-
input?: JsonObject;
|
|
146
|
-
output?: JsonObject;
|
|
147
|
-
status?: string;
|
|
148
|
-
duration_ms?: number;
|
|
149
|
-
}
|
|
150
|
-
export interface LlmContext {
|
|
151
|
-
provider?: string;
|
|
152
|
-
model?: string;
|
|
153
|
-
prompt_tokens?: number;
|
|
154
|
-
completion_tokens?: number;
|
|
155
|
-
total_tokens?: number;
|
|
156
|
-
cost_usd?: number;
|
|
157
|
-
latency_ms?: number;
|
|
158
|
-
status?: string;
|
|
159
|
-
input?: JsonObject;
|
|
160
|
-
output?: JsonObject;
|
|
161
|
-
}
|
|
162
|
-
export interface TelemetryMeasurement {
|
|
163
|
-
name: string;
|
|
164
|
-
value: number;
|
|
165
|
-
unit?: string;
|
|
166
|
-
}
|
|
167
|
-
export interface BrowserErrorEvent {
|
|
168
|
-
message: string;
|
|
169
|
-
type?: string;
|
|
170
|
-
stack?: string;
|
|
171
|
-
frames?: StackFrame[];
|
|
172
|
-
level?: Level;
|
|
173
|
-
tags?: Record<string, string>;
|
|
174
|
-
user?: UserContext;
|
|
121
|
+
export type { AnalyticsContext, IngestResponse, JsonObject, Level, LlmContext, PageContext, SessionContext, StackFrame, TelemetryKind, TelemetryMeasurement, ToolCallContext, TraceContext, UserContext, VisitorContext, };
|
|
122
|
+
export type Breadcrumb = Omit<ApiBreadcrumb, "data"> & {
|
|
123
|
+
data?: JsonObject;
|
|
124
|
+
};
|
|
125
|
+
export type BrowserErrorEvent = Omit<IngestEvent, "breadcrumbs" | "extra" | "request"> & {
|
|
126
|
+
breadcrumbs?: Breadcrumb[];
|
|
127
|
+
extra?: JsonObject;
|
|
175
128
|
request?: {
|
|
176
129
|
url: string;
|
|
177
130
|
method?: string;
|
|
178
131
|
};
|
|
179
|
-
|
|
180
|
-
name: string;
|
|
181
|
-
version: string;
|
|
182
|
-
};
|
|
183
|
-
timestamp?: string;
|
|
184
|
-
release?: string;
|
|
185
|
-
environment?: string;
|
|
186
|
-
breadcrumbs?: Breadcrumb[];
|
|
187
|
-
extra?: Record<string, unknown>;
|
|
188
|
-
/** Session ID for correlation with Web Vitals. */
|
|
189
|
-
session_id?: string;
|
|
190
|
-
kind?: TelemetryKind;
|
|
191
|
-
event_name?: string;
|
|
192
|
-
distinct_id?: string;
|
|
193
|
-
visitor?: VisitorContext;
|
|
194
|
-
analytics?: AnalyticsContext;
|
|
195
|
-
page?: PageContext;
|
|
196
|
-
session?: SessionContext;
|
|
197
|
-
trace?: TraceContext;
|
|
198
|
-
tool_call?: ToolCallContext;
|
|
199
|
-
llm?: LlmContext;
|
|
200
|
-
attributes?: JsonObject;
|
|
201
|
-
measurements?: TelemetryMeasurement[];
|
|
202
|
-
}
|
|
132
|
+
};
|
|
203
133
|
export interface IngestBatchPayload {
|
|
204
134
|
events: BrowserErrorEvent[];
|
|
205
135
|
}
|
|
206
|
-
export interface StackFrame {
|
|
207
|
-
filename?: string;
|
|
208
|
-
function?: string;
|
|
209
|
-
lineno?: number;
|
|
210
|
-
colno?: number;
|
|
211
|
-
in_app?: boolean;
|
|
212
|
-
context_line?: string;
|
|
213
|
-
pre_context?: string[];
|
|
214
|
-
post_context?: string[];
|
|
215
|
-
}
|
|
216
|
-
export interface UserContext {
|
|
217
|
-
id?: string;
|
|
218
|
-
email?: string;
|
|
219
|
-
username?: string;
|
|
220
|
-
ip_address?: string;
|
|
221
|
-
}
|
|
222
|
-
export interface Breadcrumb {
|
|
223
|
-
timestamp?: string;
|
|
224
|
-
category?: string;
|
|
225
|
-
message?: string;
|
|
226
|
-
level?: string;
|
|
227
|
-
data?: Record<string, unknown>;
|
|
228
|
-
}
|
|
229
|
-
export interface IngestResponse {
|
|
230
|
-
id: string;
|
|
231
|
-
status: string;
|
|
232
|
-
accepted?: number;
|
|
233
|
-
}
|
|
234
136
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -1,8 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @squasher-ai/browser — Type definitions for the browser SDK.
|
|
3
|
-
*
|
|
4
|
-
* Defines its own types to avoid runtime dependency on @squasher-ai/node or
|
|
5
|
-
* @squasher-ai/api-spec. Shapes match the canonical wire protocol in
|
|
6
|
-
* packages/sdk-spec/protocol.schema.json.
|
|
7
|
-
*/
|
|
8
1
|
export {};
|
package/dist/vitals.d.ts
CHANGED
|
@@ -11,7 +11,15 @@
|
|
|
11
11
|
* Each metric fires once (LCP, FCP, TTFB) or accumulates (CLS, INP).
|
|
12
12
|
* Measurements are mapped to VitalEvent and queued via the transport.
|
|
13
13
|
*/
|
|
14
|
-
import type
|
|
14
|
+
import { type Metric } from "web-vitals";
|
|
15
|
+
import type { VitalEvent } from "./types.js";
|
|
16
|
+
declare global {
|
|
17
|
+
interface Navigator {
|
|
18
|
+
connection?: {
|
|
19
|
+
effectiveType?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
15
23
|
export interface VitalsCollectorConfig {
|
|
16
24
|
/** Sampling rate 0-1 for vitals. */
|
|
17
25
|
sampleRate: number;
|
|
@@ -22,9 +30,54 @@ export interface VitalsCollectorConfig {
|
|
|
22
30
|
/** Enable debug logging. */
|
|
23
31
|
debug: boolean;
|
|
24
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Shape accepted by external collectors that bridge into our transport
|
|
35
|
+
* (e.g. Next.js `useReportWebVitals`). Mirrors the relevant subset of the
|
|
36
|
+
* `web-vitals` Metric and Next's `NextWebVitalsMetric` so callers can pass
|
|
37
|
+
* the framework metric object through unchanged.
|
|
38
|
+
*/
|
|
39
|
+
export interface ExternalVitalInput {
|
|
40
|
+
name: string;
|
|
41
|
+
value: number;
|
|
42
|
+
rating?: string;
|
|
43
|
+
delta?: number;
|
|
44
|
+
navigationType?: string;
|
|
45
|
+
/** Unique identifier the underlying lib assigns to a measurement. */
|
|
46
|
+
id?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Map an externally-sourced web vital (Next.js custom metric or otherwise)
|
|
50
|
+
* to our VitalEvent wire shape so it can be enqueued through the transport.
|
|
51
|
+
*/
|
|
52
|
+
export declare function mapExternalVital(metric: ExternalVitalInput, config: VitalsCollectorConfig, route?: string): VitalEvent;
|
|
53
|
+
export interface VitalsCollectorHandle {
|
|
54
|
+
/**
|
|
55
|
+
* Stop forwarding metrics from the native `web-vitals` library to the
|
|
56
|
+
* transport. The library's observers cannot be unregistered, so callbacks
|
|
57
|
+
* still fire — they just no-op. Use this when an external collector (e.g.
|
|
58
|
+
* Next.js `useReportWebVitals`) takes over so we don't double-count.
|
|
59
|
+
*/
|
|
60
|
+
suppress: () => void;
|
|
61
|
+
}
|
|
62
|
+
export interface VitalsTransport {
|
|
63
|
+
enqueueVital(event: VitalEvent): void;
|
|
64
|
+
}
|
|
65
|
+
export interface VitalsRuntime {
|
|
66
|
+
getSessionId(): string;
|
|
67
|
+
observeCLS(callback: (metric: Metric) => void, options: {
|
|
68
|
+
reportAllChanges: boolean;
|
|
69
|
+
}): void;
|
|
70
|
+
observeFCP(callback: (metric: Metric) => void): void;
|
|
71
|
+
observeINP(callback: (metric: Metric) => void, options: {
|
|
72
|
+
reportAllChanges: boolean;
|
|
73
|
+
}): void;
|
|
74
|
+
observeLCP(callback: (metric: Metric) => void): void;
|
|
75
|
+
observeTTFB(callback: (metric: Metric) => void): void;
|
|
76
|
+
}
|
|
77
|
+
export declare const defaultVitalsRuntime: VitalsRuntime;
|
|
25
78
|
/**
|
|
26
79
|
* Start collecting all 5 Core Web Vitals and feed them to the transport.
|
|
27
80
|
* Call once during SDK initialization.
|
|
28
81
|
*/
|
|
29
|
-
export declare function startVitalsCollection(transport:
|
|
82
|
+
export declare function startVitalsCollection(transport: VitalsTransport, config: VitalsCollectorConfig, runtime?: VitalsRuntime): VitalsCollectorHandle;
|
|
30
83
|
//# sourceMappingURL=vitals.d.ts.map
|
package/dist/vitals.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitals.d.ts","sourceRoot":"","sources":["../src/vitals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"vitals.d.ts","sourceRoot":"","sources":["../src/vitals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAsC,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAG7E,OAAO,KAAK,EAAc,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,SAAS;QACjB,UAAU,CAAC,EAAE;YAAE,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KACzC;CACF;AAED,MAAM,WAAW,qBAAqB;IACpC,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,KAAK,EAAE,OAAO,CAAC;CAChB;AA4GD;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,qBAAqB,EAC7B,KAAK,CAAC,EAAE,MAAM,GACb,UAAU,CA0BZ;AAcD,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,IAAI,MAAM,CAAC;IACvB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,EAAE,OAAO,EAAE;QAAE,gBAAgB,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7F,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACrD,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,EAAE,OAAO,EAAE;QAAE,gBAAgB,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7F,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACrD,WAAW,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;CACvD;AAED,eAAO,MAAM,oBAAoB,EAAE,aAOlC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,eAAe,EAC1B,MAAM,EAAE,qBAAqB,EAC7B,OAAO,GAAE,aAAoC,GAC5C,qBAAqB,CA+BvB"}
|