@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.
Files changed (98) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +2 -41
  3. package/dist/__tests__/client/harness.d.ts +18 -0
  4. package/dist/__tests__/client/harness.d.ts.map +1 -0
  5. package/dist/__tests__/client/harness.js +106 -0
  6. package/dist/__tests__/replay/coverage-harness.d.ts +29 -0
  7. package/dist/__tests__/replay/coverage-harness.d.ts.map +1 -0
  8. package/dist/__tests__/replay/coverage-harness.js +123 -0
  9. package/dist/__tests__/replay/test-helpers.d.ts +13 -0
  10. package/dist/__tests__/replay/test-helpers.d.ts.map +1 -0
  11. package/dist/__tests__/replay/test-helpers.js +9 -0
  12. package/dist/autocapture.d.ts +14 -18
  13. package/dist/autocapture.d.ts.map +1 -1
  14. package/dist/autocapture.js +77 -95
  15. package/dist/client.d.ts +12 -19
  16. package/dist/client.d.ts.map +1 -1
  17. package/dist/client.js +56 -72
  18. package/dist/config.d.ts +25 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +26 -0
  21. package/dist/console-capture.d.ts +8 -0
  22. package/dist/console-capture.d.ts.map +1 -0
  23. package/dist/console-capture.js +79 -0
  24. package/dist/errors.d.ts +2 -2
  25. package/dist/errors.d.ts.map +1 -1
  26. package/dist/errors.js +8 -5
  27. package/dist/index.d.ts +5 -38
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +4 -82
  30. package/dist/next.d.ts +40 -0
  31. package/dist/next.d.ts.map +1 -0
  32. package/dist/next.js +67 -0
  33. package/dist/react.d.ts.map +1 -1
  34. package/dist/react.js +12 -10
  35. package/dist/replay-network.d.ts +21 -0
  36. package/dist/replay-network.d.ts.map +1 -0
  37. package/dist/replay-network.js +193 -0
  38. package/dist/replay-privacy.d.ts +2 -2
  39. package/dist/replay-privacy.d.ts.map +1 -1
  40. package/dist/replay-privacy.js +47 -17
  41. package/dist/replay-retry.d.ts +41 -0
  42. package/dist/replay-retry.d.ts.map +1 -0
  43. package/dist/replay-retry.js +193 -0
  44. package/dist/replay.d.ts +18 -5
  45. package/dist/replay.d.ts.map +1 -1
  46. package/dist/replay.js +131 -71
  47. package/dist/runtime/client-singleton.d.ts +25 -0
  48. package/dist/runtime/client-singleton.d.ts.map +1 -0
  49. package/dist/runtime/client-singleton.js +66 -0
  50. package/dist/runtime/client.d.ts +22 -0
  51. package/dist/runtime/client.d.ts.map +1 -0
  52. package/dist/runtime/client.js +12 -0
  53. package/dist/runtime/replay.d.ts +13 -0
  54. package/dist/runtime/replay.d.ts.map +1 -0
  55. package/dist/runtime/replay.js +15 -0
  56. package/dist/session.d.ts +0 -10
  57. package/dist/session.d.ts.map +1 -1
  58. package/dist/session.js +20 -21
  59. package/dist/telemetry.d.ts +1 -1
  60. package/dist/telemetry.d.ts.map +1 -1
  61. package/dist/telemetry.js +13 -10
  62. package/dist/trace-context.d.ts +9 -0
  63. package/dist/trace-context.d.ts.map +1 -0
  64. package/dist/trace-context.js +13 -0
  65. package/dist/transport.d.ts +11 -19
  66. package/dist/transport.d.ts.map +1 -1
  67. package/dist/transport.js +86 -66
  68. package/dist/types.d.ts +37 -135
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/types.js +0 -7
  71. package/dist/vitals.d.ts +55 -2
  72. package/dist/vitals.d.ts.map +1 -1
  73. package/dist/vitals.js +115 -16
  74. package/package.json +25 -3
  75. package/dist/__tests__/client.test.d.ts +0 -2
  76. package/dist/__tests__/client.test.d.ts.map +0 -1
  77. package/dist/__tests__/client.test.js +0 -103
  78. package/dist/__tests__/errors.test.d.ts +0 -2
  79. package/dist/__tests__/errors.test.d.ts.map +0 -1
  80. package/dist/__tests__/errors.test.js +0 -80
  81. package/dist/__tests__/replay-privacy.test.d.ts +0 -2
  82. package/dist/__tests__/replay-privacy.test.d.ts.map +0 -1
  83. package/dist/__tests__/replay-privacy.test.js +0 -124
  84. package/dist/__tests__/replay-startup.test.d.ts +0 -2
  85. package/dist/__tests__/replay-startup.test.d.ts.map +0 -1
  86. package/dist/__tests__/replay-startup.test.js +0 -99
  87. package/dist/__tests__/replay.test.d.ts +0 -2
  88. package/dist/__tests__/replay.test.d.ts.map +0 -1
  89. package/dist/__tests__/replay.test.js +0 -217
  90. package/dist/__tests__/session.test.d.ts +0 -2
  91. package/dist/__tests__/session.test.d.ts.map +0 -1
  92. package/dist/__tests__/session.test.js +0 -46
  93. package/dist/__tests__/transport.test.d.ts +0 -2
  94. package/dist/__tests__/transport.test.d.ts.map +0 -1
  95. package/dist/__tests__/transport.test.js +0 -101
  96. package/dist/__tests__/types.test.d.ts +0 -2
  97. package/dist/__tests__/types.test.d.ts.map +0 -1
  98. package/dist/__tests__/types.test.js +0 -139
@@ -0,0 +1,79 @@
1
+ import { buildErrorEvent, buildMessageEvent } from "./errors.js";
2
+ export function captureConsole(onBreadcrumb, options) {
3
+ const origError = console.error.bind(console);
4
+ const origWarn = console.warn.bind(console);
5
+ console.error = (...args) => {
6
+ if (!isInternalSquasherConsole(args)) {
7
+ const message = formatConsoleArgs(args);
8
+ if (options.captureBreadcrumbs) {
9
+ onBreadcrumb({
10
+ category: "console",
11
+ message: message.slice(0, 200),
12
+ level: "error",
13
+ });
14
+ }
15
+ options.onConsoleError?.(buildConsoleErrorEvent(args, message));
16
+ }
17
+ origError(...args);
18
+ };
19
+ console.warn = (...args) => {
20
+ if (options.captureBreadcrumbs && !isInternalSquasherConsole(args)) {
21
+ onBreadcrumb({
22
+ category: "console",
23
+ message: formatConsoleArgs(args).slice(0, 200),
24
+ level: "warning",
25
+ });
26
+ }
27
+ origWarn(...args);
28
+ };
29
+ return () => {
30
+ console.error = origError;
31
+ console.warn = origWarn;
32
+ };
33
+ }
34
+ function buildConsoleErrorEvent(args, message) {
35
+ const error = args.find((arg) => arg instanceof Error);
36
+ if (error instanceof Error) {
37
+ const event = buildErrorEvent(error, {
38
+ argument_count: args.length,
39
+ source: "console",
40
+ });
41
+ event.message = message || event.message;
42
+ event.type = event.type === "Error" ? "ConsoleError" : `ConsoleError(${event.type})`;
43
+ return event;
44
+ }
45
+ const event = buildMessageEvent(message || "console.error", "error");
46
+ event.type = "ConsoleError";
47
+ event.extra = {
48
+ argument_count: args.length,
49
+ source: "console",
50
+ };
51
+ return event;
52
+ }
53
+ function isInternalSquasherConsole(args) {
54
+ const first = args[0];
55
+ return (Object.prototype.toString.call(first) === "[object String]" &&
56
+ String(first).startsWith("[squasher]"));
57
+ }
58
+ function formatConsoleArgs(args) {
59
+ return args.map(formatConsoleArg).join(" ").slice(0, 1_000);
60
+ }
61
+ function formatConsoleArg(arg) {
62
+ if (arg instanceof Error) {
63
+ return `${arg.name}: ${arg.message}`;
64
+ }
65
+ if (arg === null) {
66
+ return "null";
67
+ }
68
+ if (arg === undefined) {
69
+ return "undefined";
70
+ }
71
+ const tag = Object.prototype.toString.call(arg);
72
+ if (tag === "[object String]" ||
73
+ tag === "[object Number]" ||
74
+ tag === "[object Boolean]" ||
75
+ tag === "[object BigInt]") {
76
+ return String(arg);
77
+ }
78
+ return Object.prototype.toString.call(arg);
79
+ }
package/dist/errors.d.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * Parses Error.stack into StackFrame[] using the same regex pattern as
9
9
  * @squasher-ai/node. In-app heuristic: node_modules = not in_app.
10
10
  */
11
- import type { BrowserErrorEvent, StackFrame } from "./types";
11
+ import type { BrowserErrorEvent, JsonObject, StackFrame } from "./types.js";
12
12
  /**
13
13
  * Parse an Error.stack string into structured StackFrame[].
14
14
  */
@@ -16,7 +16,7 @@ export declare function parseStack(stack?: string): StackFrame[] | undefined;
16
16
  /**
17
17
  * Build a BrowserErrorEvent from an Error object.
18
18
  */
19
- export declare function buildErrorEvent(error: Error, extra?: Record<string, unknown>): BrowserErrorEvent;
19
+ export declare function buildErrorEvent(error: Error, extra?: JsonObject): BrowserErrorEvent;
20
20
  /**
21
21
  * Build a BrowserErrorEvent from a string message.
22
22
  */
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAW7D;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE,GAAG,SAAS,CAkCnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,iBAAiB,CAWhG;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,iBAAiB,CAAC,OAAO,CAAU,GACzC,iBAAiB,CAOnB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAC1C,MAAM,IAAI,CAuCZ"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAW5E;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE,GAAG,SAAS,CA8BnE;AAWD;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,iBAAiB,CAWnF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,iBAAiB,CAAC,OAAO,CAAU,GACzC,iBAAiB,CAOnB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAC1C,MAAM,IAAI,CAuCZ"}
package/dist/errors.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * @squasher-ai/node. In-app heuristic: node_modules = not in_app.
10
10
  */
11
11
  const SDK_NAME = "@squasher-ai/browser";
12
- const SDK_VERSION = "0.1.0";
12
+ const SDK_VERSION = "0.2.0";
13
13
  /** Stack trace line regex — works for V8 (Chrome, Node) and SpiderMonkey (Firefox). */
14
14
  const STACK_LINE_RE = /^\s*at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?/;
15
15
  /** Firefox stack format: "functionName@filename:line:col" */
@@ -33,10 +33,7 @@ export function parseStack(stack) {
33
33
  if (!match)
34
34
  continue;
35
35
  const [, fn, filename, lineno, colno] = match;
36
- const isExternal = filename?.includes("node_modules") ||
37
- filename?.includes("extensions/") ||
38
- filename?.startsWith("chrome-extension://") ||
39
- false;
36
+ const isExternal = isExternalFilename(filename);
40
37
  frames.push({
41
38
  function: fn || "<anonymous>",
42
39
  filename,
@@ -47,6 +44,12 @@ export function parseStack(stack) {
47
44
  }
48
45
  return frames.length > 0 ? frames : undefined;
49
46
  }
47
+ function isExternalFilename(filename) {
48
+ return (filename?.includes("node_modules") ||
49
+ filename?.includes("extensions/") ||
50
+ filename?.startsWith("chrome-extension://") ||
51
+ false);
52
+ }
50
53
  /**
51
54
  * Build a BrowserErrorEvent from an Error object.
52
55
  */
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * - Core Web Vitals (LCP, CLS, INP, FCP, TTFB)
6
6
  * - JavaScript errors (window.onerror, unhandledrejection)
7
7
  * - Navigation breadcrumbs, click breadcrumbs, fetch error breadcrumbs
8
+ * - Optional console.error events
8
9
  * - Session context for error ↔ vitals correlation
9
10
  *
10
11
  * Usage:
@@ -21,42 +22,8 @@
21
22
  * // Manual capture:
22
23
  * captureError(new Error('Something went wrong'));
23
24
  */
24
- export { BrowserClient } from "./client";
25
- export type { AnalyticsContext, Breadcrumb, BrowserConfig, BrowserErrorEvent, DeviceType, IngestBatchPayload, IngestResponse, JsonObject, LlmContext, Level, PageContext, ReplayConfig, ReplayPrivacyConfig, SessionContext, StackFrame, TelemetryKind, TelemetryMeasurement, ToolCallContext, UserContext, VitalEvent, VitalMetricName, VitalRating, TraceContext, VisitorContext, VitalsPayload, } from "./types";
26
- import { BrowserClient } from "./client";
27
- import type { Breadcrumb, BrowserConfig, BrowserErrorEvent, JsonObject, Level, UserContext } from "./types";
28
- /** Initialize the global Squasher browser client. Throws if called twice. */
29
- export declare function init(config: BrowserConfig): BrowserClient;
30
- /** Get the global client (throws if not initialized). */
31
- export declare function getClient(): BrowserClient;
32
- /** Capture an error using the global client. */
33
- export declare function captureError(error: Error, extra?: Record<string, unknown>): void;
34
- /** Capture a message using the global client. */
35
- export declare function captureMessage(message: string, level?: Level): void;
36
- /** Capture a generalized telemetry event using the global client. */
37
- export declare function captureTelemetry(event: BrowserErrorEvent): void;
38
- /** Track a product analytics event using the global client. */
39
- export declare function track(eventName: string, properties?: JsonObject, context?: Partial<BrowserErrorEvent>): void;
40
- /** Identify a distinct user or visitor using the global client. */
41
- export declare function identify(distinctId: string, traits?: JsonObject, context?: Partial<BrowserErrorEvent>): void;
42
- /** Capture a page navigation event using the global client. */
43
- export declare function page(name: string, properties?: JsonObject, context?: Partial<BrowserErrorEvent>): void;
44
- /** Capture a screen event using the global client. */
45
- export declare function screen(name: string, properties?: JsonObject, context?: Partial<BrowserErrorEvent>): void;
46
- /** Capture an agent span using the global client. */
47
- export declare function captureSpan(name: string, context?: Partial<BrowserErrorEvent>): void;
48
- /** Capture a tool call using the global client. */
49
- export declare function captureToolCall(name: string, context?: Partial<BrowserErrorEvent>): void;
50
- /** Capture an LLM generation event using the global client. */
51
- export declare function captureGeneration(message: string, context?: Partial<BrowserErrorEvent>): void;
52
- /** Set user context on the global client. */
53
- export declare function setUser(user: UserContext | undefined): void;
54
- /** Set a single tag on the global client. */
55
- export declare function setTag(key: string, value: string): void;
56
- /** Set multiple tags on the global client. */
57
- export declare function setTags(tags: Record<string, string>): void;
58
- /** Add a breadcrumb on the global client. */
59
- export declare function addBreadcrumb(crumb: Omit<Breadcrumb, "timestamp">): void;
60
- /** Close the global client (stop timers, flush vitals, remove handlers). */
61
- export declare function close(): void;
25
+ export { BrowserClient } from "./client.js";
26
+ export { addBreadcrumb, captureError, captureGeneration, captureMessage, captureSpan, captureTelemetry, captureToolCall, close, getClient, identify, init, page, screen, setTag, setTags, setUser, track, } from "./runtime/client-singleton.js";
27
+ export { createSpanId, createTraceContext, createTraceId } from "./trace-context.js";
28
+ export type { AnalyticsContext, Breadcrumb, BrowserConfig, BrowserErrorEvent, DeviceType, IngestBatchPayload, IngestResponse, JsonObject, Level, LlmContext, PageContext, ReplayConfig, ReplayPrivacyConfig, SessionContext, StackFrame, TelemetryKind, TelemetryMeasurement, ToolCallContext, TraceContext, UserContext, VisitorContext, VitalEvent, VitalMetricName, VitalRating, VitalsPayload, } from "./types.js";
62
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,KAAK,EACL,SAAS,EACT,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,MAAM,EACN,OAAO,EACP,OAAO,EACP,KAAK,GACN,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACrF,YAAY,EACV,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,KAAK,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,WAAW,EACX,cAAc,EACd,UAAU,EACV,eAAe,EACf,WAAW,EACX,aAAa,GACd,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  * - Core Web Vitals (LCP, CLS, INP, FCP, TTFB)
6
6
  * - JavaScript errors (window.onerror, unhandledrejection)
7
7
  * - Navigation breadcrumbs, click breadcrumbs, fetch error breadcrumbs
8
+ * - Optional console.error events
8
9
  * - Session context for error ↔ vitals correlation
9
10
  *
10
11
  * Usage:
@@ -21,85 +22,6 @@
21
22
  * // Manual capture:
22
23
  * captureError(new Error('Something went wrong'));
23
24
  */
24
- export { BrowserClient } from "./client";
25
- // ─── Global singleton ───────────────────────────────────────────────────────
26
- import { BrowserClient } from "./client";
27
- let _client = null;
28
- /** Initialize the global Squasher browser client. Throws if called twice. */
29
- export function init(config) {
30
- if (_client) {
31
- throw new Error("squasher.init() called more than once. Call close() first if re-initializing.");
32
- }
33
- _client = new BrowserClient(config);
34
- return _client;
35
- }
36
- /** Get the global client (throws if not initialized). */
37
- export function getClient() {
38
- if (!_client) {
39
- throw new Error("Squasher not initialized. Call init() first.");
40
- }
41
- return _client;
42
- }
43
- /** Capture an error using the global client. */
44
- export function captureError(error, extra) {
45
- getClient().captureError(error, extra);
46
- }
47
- /** Capture a message using the global client. */
48
- export function captureMessage(message, level) {
49
- getClient().captureMessage(message, level);
50
- }
51
- /** Capture a generalized telemetry event using the global client. */
52
- export function captureTelemetry(event) {
53
- getClient().captureTelemetry(event);
54
- }
55
- /** Track a product analytics event using the global client. */
56
- export function track(eventName, properties, context) {
57
- getClient().track(eventName, properties, context);
58
- }
59
- /** Identify a distinct user or visitor using the global client. */
60
- export function identify(distinctId, traits, context) {
61
- getClient().identify(distinctId, traits, context);
62
- }
63
- /** Capture a page navigation event using the global client. */
64
- export function page(name, properties, context) {
65
- getClient().page(name, properties, context);
66
- }
67
- /** Capture a screen event using the global client. */
68
- export function screen(name, properties, context) {
69
- getClient().screen(name, properties, context);
70
- }
71
- /** Capture an agent span using the global client. */
72
- export function captureSpan(name, context) {
73
- getClient().captureSpan(name, context);
74
- }
75
- /** Capture a tool call using the global client. */
76
- export function captureToolCall(name, context) {
77
- getClient().captureToolCall(name, context);
78
- }
79
- /** Capture an LLM generation event using the global client. */
80
- export function captureGeneration(message, context) {
81
- getClient().captureGeneration(message, context);
82
- }
83
- /** Set user context on the global client. */
84
- export function setUser(user) {
85
- getClient().setUser(user);
86
- }
87
- /** Set a single tag on the global client. */
88
- export function setTag(key, value) {
89
- getClient().setTag(key, value);
90
- }
91
- /** Set multiple tags on the global client. */
92
- export function setTags(tags) {
93
- getClient().setTags(tags);
94
- }
95
- /** Add a breadcrumb on the global client. */
96
- export function addBreadcrumb(crumb) {
97
- getClient().addBreadcrumb(crumb);
98
- }
99
- /** Close the global client (stop timers, flush vitals, remove handlers). */
100
- export function close() {
101
- if (_client) {
102
- _client.close();
103
- _client = null;
104
- }
105
- }
25
+ export { BrowserClient } from "./client.js";
26
+ export { addBreadcrumb, captureError, captureGeneration, captureMessage, captureSpan, captureTelemetry, captureToolCall, close, getClient, identify, init, page, screen, setTag, setTags, setUser, track, } from "./runtime/client-singleton.js";
27
+ export { createSpanId, createTraceContext, createTraceId } from "./trace-context.js";
package/dist/next.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Next.js Web Vitals bridge for @squasher-ai/browser.
3
+ *
4
+ * Drop `<SquasherNextWebVitals />` into your root layout to capture both
5
+ * Core Web Vitals (LCP, CLS, INP, FCP, TTFB) and Next.js framework metrics
6
+ * (`Next.js-hydration`, `Next.js-route-change-to-render`, `Next.js-render`).
7
+ *
8
+ * The component hard-imports `next/web-vitals` and `next/navigation` so it
9
+ * is **only** valid in a Next.js app. Non-Next consumers should rely on the
10
+ * auto-collector that runs from `init()` and not import this module.
11
+ *
12
+ * Internally it bridges Next's `useReportWebVitals` hook into the existing
13
+ * browser client transport, suppressing the SDK's native `web-vitals`
14
+ * collector on mount so Core metrics aren't reported twice.
15
+ *
16
+ * Usage:
17
+ * import { SquasherNextWebVitals } from '@squasher-ai/browser/next';
18
+ *
19
+ * export default function RootLayout({ children }) {
20
+ * return (
21
+ * <html>
22
+ * <body>
23
+ * <SquasherNextWebVitals />
24
+ * {children}
25
+ * </body>
26
+ * </html>
27
+ * );
28
+ * }
29
+ */
30
+ interface SquasherNextWebVitalsProps {
31
+ /**
32
+ * Override the route tag attached to every metric. Defaults to the
33
+ * current `usePathname()` value, with the pathname re-evaluated lazily
34
+ * so a single hook subscription doesn't re-fire on every navigation.
35
+ */
36
+ path?: string;
37
+ }
38
+ export declare function SquasherNextWebVitals({ path }?: SquasherNextWebVitalsProps): null;
39
+ export {};
40
+ //# sourceMappingURL=next.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../src/next.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAeH,UAAU,0BAA0B;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,qBAAqB,CAAC,EAAE,IAAI,EAAE,GAAE,0BAA+B,QA+B9E"}
package/dist/next.js ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Next.js Web Vitals bridge for @squasher-ai/browser.
3
+ *
4
+ * Drop `<SquasherNextWebVitals />` into your root layout to capture both
5
+ * Core Web Vitals (LCP, CLS, INP, FCP, TTFB) and Next.js framework metrics
6
+ * (`Next.js-hydration`, `Next.js-route-change-to-render`, `Next.js-render`).
7
+ *
8
+ * The component hard-imports `next/web-vitals` and `next/navigation` so it
9
+ * is **only** valid in a Next.js app. Non-Next consumers should rely on the
10
+ * auto-collector that runs from `init()` and not import this module.
11
+ *
12
+ * Internally it bridges Next's `useReportWebVitals` hook into the existing
13
+ * browser client transport, suppressing the SDK's native `web-vitals`
14
+ * collector on mount so Core metrics aren't reported twice.
15
+ *
16
+ * Usage:
17
+ * import { SquasherNextWebVitals } from '@squasher-ai/browser/next';
18
+ *
19
+ * export default function RootLayout({ children }) {
20
+ * return (
21
+ * <html>
22
+ * <body>
23
+ * <SquasherNextWebVitals />
24
+ * {children}
25
+ * </body>
26
+ * </html>
27
+ * );
28
+ * }
29
+ */
30
+ "use client";
31
+ import { usePathname } from "next/navigation";
32
+ import { useReportWebVitals } from "next/web-vitals";
33
+ import { useCallback, useEffect, useRef } from "react";
34
+ import { getClient } from "./runtime/client-singleton.js";
35
+ const SUPPORTED_WEB_VITALS = new Set(["CLS", "FCP", "INP", "LCP", "TTFB"]);
36
+ function isSupportedWebVital(name) {
37
+ return SUPPORTED_WEB_VITALS.has(name);
38
+ }
39
+ export function SquasherNextWebVitals({ path } = {}) {
40
+ const pathname = usePathname();
41
+ const currentPath = path ?? pathname ?? "/";
42
+ const stabilizedPath = useRef(currentPath);
43
+ useEffect(() => {
44
+ stabilizedPath.current = currentPath;
45
+ }, [currentPath]);
46
+ useEffect(() => {
47
+ try {
48
+ getClient().suppressNativeVitalsCollection();
49
+ }
50
+ catch {
51
+ // Squasher SDK not initialized — nothing to suppress. Bridge still
52
+ // runs so the host can call init() asynchronously.
53
+ }
54
+ }, []);
55
+ const report = useCallback((metric) => {
56
+ if (!isSupportedWebVital(metric.name))
57
+ return;
58
+ try {
59
+ getClient().recordWebVital(metric, stabilizedPath.current);
60
+ }
61
+ catch {
62
+ // SDK not yet initialized; drop this metric rather than throw.
63
+ }
64
+ }, []);
65
+ useReportWebVitals(report);
66
+ return null;
67
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlE,UAAU,KAAK;IACb,QAAQ,EAAE,SAAS,CAAC;IACpB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,iDAAiD;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;CACxD;AAED,UAAU,KAAK;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,qBAAsB,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;gBACpD,KAAK,EAAE,KAAK;IAKxB,MAAM,CAAC,wBAAwB,IAAI,KAAK;IAI/B,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI;IAa3D,MAAM,IAAI,SAAS;CAM7B"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKlE,UAAU,KAAK;IACb,QAAQ,EAAE,SAAS,CAAC;IACpB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,iDAAiD;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;CACxD;AAED,UAAU,KAAK;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,qBAAsB,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;gBACpD,KAAK,EAAE,KAAK;IAKxB,MAAM,CAAC,wBAAwB,IAAI,KAAK;IAI/B,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI;IAc3D,MAAM,IAAI,SAAS;CAM7B"}
package/dist/react.js CHANGED
@@ -12,7 +12,8 @@
12
12
  * </SquasherErrorBoundary>
13
13
  */
14
14
  import { Component } from "react";
15
- import { getClient } from "./index";
15
+ import { attempt } from "@squasher-ai/result-utils";
16
+ import { getClient } from "./runtime/client-singleton.js";
16
17
  export class SquasherErrorBoundary extends Component {
17
18
  constructor(props) {
18
19
  super(props);
@@ -22,15 +23,16 @@ export class SquasherErrorBoundary extends Component {
22
23
  return { hasError: true };
23
24
  }
24
25
  componentDidCatch(error, errorInfo) {
25
- try {
26
- const client = getClient();
27
- client.captureError(error, {
28
- componentStack: errorInfo.componentStack ?? undefined,
29
- });
30
- }
31
- catch {
32
- // SDK not initialized — silently ignore
33
- }
26
+ attempt({
27
+ try: () => {
28
+ const client = getClient();
29
+ const extra = {};
30
+ if (errorInfo.componentStack)
31
+ extra.componentStack = errorInfo.componentStack;
32
+ client.captureError(error, extra);
33
+ },
34
+ catch: () => undefined,
35
+ });
34
36
  this.props.onError?.(error, errorInfo);
35
37
  }
36
38
  render() {
@@ -0,0 +1,21 @@
1
+ export interface ReplayNetworkEventPayload {
2
+ durationMs: number;
3
+ initiatorType: string;
4
+ method?: string;
5
+ pageUrl: string;
6
+ protocol?: string | null;
7
+ requestUrl: string;
8
+ source: "fetch" | "resource";
9
+ startOffsetMs: number;
10
+ statusCode?: number | null;
11
+ statusText?: string | null;
12
+ transferSize?: number | null;
13
+ }
14
+ export interface ReplayNetworkCaptureOptions {
15
+ debug: boolean;
16
+ emitCustomEvent?: (tag: string, payload: ReplayNetworkEventPayload) => void;
17
+ ignoredUrlPrefixes?: string[];
18
+ replayStartedAtMs: number;
19
+ }
20
+ export declare function installReplayNetworkCapture({ debug, emitCustomEvent, ignoredUrlPrefixes, replayStartedAtMs, }: ReplayNetworkCaptureOptions): () => void;
21
+ //# sourceMappingURL=replay-network.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-network.d.ts","sourceRoot":"","sources":["../src/replay-network.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,GAAG,UAAU,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,KAAK,IAAI,CAAC;IAC5E,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAsED,wBAAgB,2BAA2B,CAAC,EAC1C,KAAK,EACL,eAAe,EACf,kBAAuB,EACvB,iBAAiB,GAClB,EAAE,2BAA2B,GAAG,MAAM,IAAI,CA6J1C"}