@squasher-ai/browser 0.1.1 → 0.3.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 (109) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +3 -42
  3. package/dist/_vendor/result-runtime/attempt.d.ts +17 -0
  4. package/dist/_vendor/result-runtime/attempt.js +62 -0
  5. package/dist/_vendor/sdk-runtime/batching/index.d.ts +42 -0
  6. package/dist/_vendor/sdk-runtime/batching/index.js +48 -0
  7. package/dist/_vendor/sdk-runtime/errors/headers.d.ts +6 -0
  8. package/dist/_vendor/sdk-runtime/errors/headers.js +44 -0
  9. package/dist/_vendor/sdk-runtime/errors/index.d.ts +95 -0
  10. package/dist/_vendor/sdk-runtime/errors/index.js +157 -0
  11. package/dist/_vendor/sdk-runtime/headers.d.ts +48 -0
  12. package/dist/_vendor/sdk-runtime/headers.js +67 -0
  13. package/dist/_vendor/sdk-runtime/platform.d.ts +33 -0
  14. package/dist/_vendor/sdk-runtime/platform.js +173 -0
  15. package/dist/_vendor/sdk-runtime/retry.d.ts +50 -0
  16. package/dist/_vendor/sdk-runtime/retry.js +104 -0
  17. package/dist/_vendor/sdk-runtime/runtime/actionable-error.d.ts +37 -0
  18. package/dist/_vendor/sdk-runtime/runtime/actionable-error.js +123 -0
  19. package/dist/_vendor/sdk-runtime/runtime/environment.d.ts +18 -0
  20. package/dist/_vendor/sdk-runtime/runtime/environment.js +81 -0
  21. package/dist/_vendor/sdk-runtime/runtime/public-sdk-runtime.d.ts +12 -0
  22. package/dist/_vendor/sdk-runtime/runtime/public-sdk-runtime.js +38 -0
  23. package/dist/_vendor/sdk-runtime/runtime/redaction.d.ts +14 -0
  24. package/dist/_vendor/sdk-runtime/runtime/redaction.js +120 -0
  25. package/dist/_vendor/sdk-runtime/runtime/release.d.ts +35 -0
  26. package/dist/_vendor/sdk-runtime/runtime/release.js +120 -0
  27. package/dist/_vendor/sdk-runtime/sampling/index.d.ts +43 -0
  28. package/dist/_vendor/sdk-runtime/sampling/index.js +70 -0
  29. package/dist/_vendor/telemetry-contract/sdk/public-contract.d.ts +175 -0
  30. package/dist/_vendor/telemetry-contract/sdk/public-contract.js +5 -0
  31. package/dist/autocapture.d.ts +14 -19
  32. package/dist/autocapture.js +77 -95
  33. package/dist/client.d.ts +12 -20
  34. package/dist/client.js +56 -72
  35. package/dist/config.d.ts +24 -0
  36. package/dist/config.js +26 -0
  37. package/dist/console-capture.d.ts +7 -0
  38. package/dist/console-capture.js +79 -0
  39. package/dist/errors.d.ts +2 -3
  40. package/dist/errors.js +8 -5
  41. package/dist/index.d.ts +5 -39
  42. package/dist/index.js +4 -82
  43. package/dist/next.d.ts +39 -0
  44. package/dist/next.js +67 -0
  45. package/dist/react.d.ts +0 -1
  46. package/dist/react.js +12 -10
  47. package/dist/replay-network.d.ts +20 -0
  48. package/dist/replay-network.js +193 -0
  49. package/dist/replay-privacy.d.ts +2 -3
  50. package/dist/replay-privacy.js +47 -17
  51. package/dist/replay-retry.d.ts +40 -0
  52. package/dist/replay-retry.js +193 -0
  53. package/dist/replay.d.ts +18 -6
  54. package/dist/replay.js +131 -71
  55. package/dist/runtime/client-singleton.d.ts +24 -0
  56. package/dist/runtime/client-singleton.js +66 -0
  57. package/dist/runtime/client.d.ts +21 -0
  58. package/dist/runtime/client.js +12 -0
  59. package/dist/runtime/replay.d.ts +12 -0
  60. package/dist/runtime/replay.js +15 -0
  61. package/dist/session.d.ts +0 -11
  62. package/dist/session.js +20 -21
  63. package/dist/telemetry.d.ts +1 -2
  64. package/dist/telemetry.js +13 -10
  65. package/dist/trace-context.d.ts +8 -0
  66. package/dist/trace-context.js +13 -0
  67. package/dist/transport.d.ts +11 -20
  68. package/dist/transport.js +86 -66
  69. package/dist/types.d.ts +38 -139
  70. package/dist/types.js +0 -7
  71. package/dist/vitals.d.ts +55 -3
  72. package/dist/vitals.js +115 -16
  73. package/package.json +11 -3
  74. package/dist/__tests__/client.test.d.ts +0 -2
  75. package/dist/__tests__/client.test.d.ts.map +0 -1
  76. package/dist/__tests__/client.test.js +0 -103
  77. package/dist/__tests__/errors.test.d.ts +0 -2
  78. package/dist/__tests__/errors.test.d.ts.map +0 -1
  79. package/dist/__tests__/errors.test.js +0 -80
  80. package/dist/__tests__/replay-privacy.test.d.ts +0 -2
  81. package/dist/__tests__/replay-privacy.test.d.ts.map +0 -1
  82. package/dist/__tests__/replay-privacy.test.js +0 -124
  83. package/dist/__tests__/replay-startup.test.d.ts +0 -2
  84. package/dist/__tests__/replay-startup.test.d.ts.map +0 -1
  85. package/dist/__tests__/replay-startup.test.js +0 -99
  86. package/dist/__tests__/replay.test.d.ts +0 -2
  87. package/dist/__tests__/replay.test.d.ts.map +0 -1
  88. package/dist/__tests__/replay.test.js +0 -217
  89. package/dist/__tests__/session.test.d.ts +0 -2
  90. package/dist/__tests__/session.test.d.ts.map +0 -1
  91. package/dist/__tests__/session.test.js +0 -46
  92. package/dist/__tests__/transport.test.d.ts +0 -2
  93. package/dist/__tests__/transport.test.d.ts.map +0 -1
  94. package/dist/__tests__/transport.test.js +0 -101
  95. package/dist/__tests__/types.test.d.ts +0 -2
  96. package/dist/__tests__/types.test.d.ts.map +0 -1
  97. package/dist/__tests__/types.test.js +0 -139
  98. package/dist/autocapture.d.ts.map +0 -1
  99. package/dist/client.d.ts.map +0 -1
  100. package/dist/errors.d.ts.map +0 -1
  101. package/dist/index.d.ts.map +0 -1
  102. package/dist/react.d.ts.map +0 -1
  103. package/dist/replay-privacy.d.ts.map +0 -1
  104. package/dist/replay.d.ts.map +0 -1
  105. package/dist/session.d.ts.map +0 -1
  106. package/dist/telemetry.d.ts.map +0 -1
  107. package/dist/transport.d.ts.map +0 -1
  108. package/dist/types.d.ts.map +0 -1
  109. package/dist/vitals.d.ts.map +0 -1
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Squasher
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Squasher
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # @squasher-ai/browser
2
2
 
3
- Browser SDK for Squasher.
4
-
5
- Capture frontend errors, Core Web Vitals, automatic breadcrumbs, analytics-style events, and optional session replay from a browser app.
3
+ Official @squasher-ai/browser package for Squasher.
6
4
 
7
5
  ## Install
8
6
 
@@ -10,42 +8,5 @@ Capture frontend errors, Core Web Vitals, automatic breadcrumbs, analytics-style
10
8
  npm install @squasher-ai/browser
11
9
  ```
12
10
 
13
- ## Setup
14
-
15
- ```ts
16
- import { init } from "@squasher-ai/browser";
17
-
18
- init({
19
- apiKey: process.env.NEXT_PUBLIC_SQUASHER_API_KEY!,
20
- projectId: process.env.NEXT_PUBLIC_SQUASHER_PROJECT_ID!,
21
- environment: process.env.NODE_ENV,
22
- replay: {
23
- enabled: true,
24
- sampleRate: 0.1,
25
- },
26
- });
27
- ```
28
-
29
- ## React Error Boundary
30
-
31
- ```tsx
32
- import { SquasherErrorBoundary } from "@squasher-ai/browser/react";
33
-
34
- <SquasherErrorBoundary fallback={<div>Something went wrong.</div>}>
35
- <App />
36
- </SquasherErrorBoundary>;
37
- ```
38
-
39
- ## Manual Capture
40
-
41
- ```ts
42
- import { captureError, captureMessage, page, track } from "@squasher-ai/browser";
43
-
44
- track("checkout_started", { step: 1 });
45
- page("Checkout");
46
- captureMessage("Frontend boot complete", "info");
47
- captureError(new Error("Checkout failed"), { cartId: "cart_123" });
48
- ```
49
-
50
- Docs: https://docs.squasher.ai
51
- Homepage: https://squasher.ai
11
+ Docs: https://docs.squasher.ai/sdks/browser
12
+ Homepage: https://squasher.ai
@@ -0,0 +1,17 @@
1
+ export interface AttemptFailure<TCause = Error> {
2
+ cause: TCause;
3
+ error: Error;
4
+ }
5
+ export interface AttemptOptions<TTry, TCatch = TTry, TCause = Error> {
6
+ try: () => TTry;
7
+ catch: (failure: AttemptFailure<TCause>) => TCatch;
8
+ finally?: () => void;
9
+ }
10
+ export interface AttemptAsyncOptions<TTry, TCatch = TTry, TCause = Error> {
11
+ try: () => Promise<TTry>;
12
+ catch: (failure: AttemptFailure<TCause>) => Promise<TCatch> | TCatch;
13
+ finally?: () => Promise<void> | void;
14
+ }
15
+ export declare function toError<T>(cause: T, fallbackMessage?: string): Error;
16
+ export declare function attempt<TTry, TCatch = TTry, TCause = Error>(options: AttemptOptions<TTry, TCatch, TCause>): TTry | TCatch;
17
+ export declare function attemptAsync<TTry, TCatch = TTry, TCause = Error>(options: AttemptAsyncOptions<TTry, TCatch, TCause>): Promise<TTry | TCatch>;
@@ -0,0 +1,62 @@
1
+ export function toError(cause, fallbackMessage = "Unexpected error") {
2
+ if (cause instanceof Error)
3
+ return cause;
4
+ const nestedError = readProperty(cause, "error");
5
+ if (nestedError instanceof Error)
6
+ return nestedError;
7
+ const messageValue = readProperty(cause, "message");
8
+ if (Object.prototype.toString.call(messageValue) === "[object String]") {
9
+ const message = String(messageValue);
10
+ if (message.length > 0)
11
+ return new Error(message);
12
+ }
13
+ if (Object.prototype.toString.call(cause) === "[object String]") {
14
+ const message = String(cause);
15
+ if (message.length > 0)
16
+ return new Error(message);
17
+ }
18
+ return new Error(fallbackMessage, { cause });
19
+ }
20
+ function readProperty(owner, key) {
21
+ try {
22
+ const target = Object(owner);
23
+ let cursor = target;
24
+ while (cursor) {
25
+ const descriptor = Object.getOwnPropertyDescriptor(cursor, key);
26
+ if (descriptor) {
27
+ return "value" in descriptor ? descriptor.value : descriptor.get?.call(target);
28
+ }
29
+ cursor = Object.getPrototypeOf(cursor);
30
+ }
31
+ return undefined;
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ }
37
+ export function attempt(options) {
38
+ try {
39
+ return options.try();
40
+ }
41
+ catch (cause) {
42
+ // SAFETY: `TCause` is the caller-selected type for the catch channel.
43
+ const preservedCause = cause;
44
+ return options.catch({ cause: preservedCause, error: toError(preservedCause) });
45
+ }
46
+ finally {
47
+ options.finally?.();
48
+ }
49
+ }
50
+ export async function attemptAsync(options) {
51
+ try {
52
+ return await options.try();
53
+ }
54
+ catch (cause) {
55
+ // SAFETY: `TCause` is the caller-selected type for the catch channel.
56
+ const preservedCause = cause;
57
+ return await options.catch({ cause: preservedCause, error: toError(preservedCause) });
58
+ }
59
+ finally {
60
+ await options.finally?.();
61
+ }
62
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Batching primitives used by Squasher SDKs.
3
+ *
4
+ * The 1 MB default keeps request bodies bounded while amortizing per-request
5
+ * overhead. Callers may choose a lower limit when their runtime requires one.
6
+ */
7
+ /** Maximum serialized SDK batch body, in bytes. */
8
+ export declare const MAX_BATCH_BODY_BYTES = 1000000;
9
+ export interface BuildBatchesOptions<TItem> {
10
+ /**
11
+ * Static JSON immediately before the comma-separated serialized items.
12
+ * Keeping the envelope split lets the builder serialize each item once
13
+ * instead of repeatedly serializing a growing candidate array.
14
+ */
15
+ batchPrefix: string;
16
+ /** Static JSON immediately after the serialized items. */
17
+ batchSuffix: string;
18
+ /**
19
+ * Serialize a single item (no wrapper). Called when a batch of size 1 is
20
+ * flushed. Lets SDKs send `{...event}` instead of `{events: [{...}]}` for
21
+ * single-event flushes — half the bytes for the common case.
22
+ */
23
+ serializeSingle: (item: TItem) => string;
24
+ /** Override the default 1_000_000-byte ceiling (for tests). */
25
+ maxBatchBodyBytes?: number;
26
+ }
27
+ export interface BuiltBatch {
28
+ /** The exact request body (already serialized). */
29
+ body: string;
30
+ /** Number of items in this batch. */
31
+ itemCount: number;
32
+ }
33
+ /**
34
+ * Greedy batching: walk the items in order, adding each to the current batch
35
+ * unless doing so would exceed `MAX_BATCH_BODY_BYTES`. When it would, flush
36
+ * the current batch and start a new one with the offending item.
37
+ *
38
+ * An item that is itself larger than the limit becomes a single-item batch
39
+ * regardless — callers are expected to drop or split oversized items at a
40
+ * higher layer; this function does not silently drop data.
41
+ */
42
+ export declare function buildBatches<TItem>(items: TItem[], options: BuildBatchesOptions<TItem>): BuiltBatch[];
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Batching primitives used by Squasher SDKs.
3
+ *
4
+ * The 1 MB default keeps request bodies bounded while amortizing per-request
5
+ * overhead. Callers may choose a lower limit when their runtime requires one.
6
+ */
7
+ /** Maximum serialized SDK batch body, in bytes. */
8
+ export const MAX_BATCH_BODY_BYTES = 1_000_000;
9
+ const BODY_ENCODER = new TextEncoder();
10
+ /**
11
+ * Greedy batching: walk the items in order, adding each to the current batch
12
+ * unless doing so would exceed `MAX_BATCH_BODY_BYTES`. When it would, flush
13
+ * the current batch and start a new one with the offending item.
14
+ *
15
+ * An item that is itself larger than the limit becomes a single-item batch
16
+ * regardless — callers are expected to drop or split oversized items at a
17
+ * higher layer; this function does not silently drop data.
18
+ */
19
+ export function buildBatches(items, options) {
20
+ const max = options.maxBatchBodyBytes ?? MAX_BATCH_BODY_BYTES;
21
+ const batches = [];
22
+ let current = [];
23
+ const envelopeBytes = BODY_ENCODER.encode(options.batchPrefix).length +
24
+ BODY_ENCODER.encode(options.batchSuffix).length;
25
+ let currentBodyBytes = envelopeBytes;
26
+ const flush = () => {
27
+ if (current.length === 0)
28
+ return;
29
+ const body = current.length === 1
30
+ ? current[0]
31
+ : `${options.batchPrefix}${current.join(",")}${options.batchSuffix}`;
32
+ batches.push({ body, itemCount: current.length });
33
+ current = [];
34
+ currentBodyBytes = envelopeBytes;
35
+ };
36
+ for (const item of items) {
37
+ const serialized = options.serializeSingle(item);
38
+ const serializedBytes = BODY_ENCODER.encode(serialized).length;
39
+ const separatorBytes = current.length === 0 ? 0 : 1;
40
+ if (current.length > 0 && currentBodyBytes + separatorBytes + serializedBytes > max) {
41
+ flush();
42
+ }
43
+ currentBodyBytes += (current.length === 0 ? 0 : 1) + serializedBytes;
44
+ current.push(serialized);
45
+ }
46
+ flush();
47
+ return batches;
48
+ }
@@ -0,0 +1,6 @@
1
+ export type HeaderMap = Record<string, string>;
2
+ export interface HeaderLike {
3
+ get(name: string): string | null;
4
+ }
5
+ export type HeaderSource = HeaderLike | HeaderMap;
6
+ export declare function readHeader(headers: HeaderSource | undefined, name: string): string | undefined;
@@ -0,0 +1,44 @@
1
+ export function readHeader(headers, name) {
2
+ if (!headers)
3
+ return undefined;
4
+ const get = readProperty(headers, "get");
5
+ if (isHeaderGetter(get)) {
6
+ try {
7
+ const value = get.call(headers, name);
8
+ return Object.prototype.toString.call(value) === "[object String]"
9
+ ? String(value)
10
+ : undefined;
11
+ }
12
+ catch {
13
+ return undefined;
14
+ }
15
+ }
16
+ const normalizedName = name.toLowerCase();
17
+ for (const [key, value] of Object.entries(Object(headers))) {
18
+ if (key.toLowerCase() === normalizedName &&
19
+ Object.prototype.toString.call(value) === "[object String]") {
20
+ return String(value);
21
+ }
22
+ }
23
+ return undefined;
24
+ }
25
+ function isHeaderGetter(value) {
26
+ return Object.prototype.toString.call(value) === "[object Function]";
27
+ }
28
+ function readProperty(owner, key) {
29
+ try {
30
+ const target = Object(owner);
31
+ let cursor = target;
32
+ while (cursor) {
33
+ const descriptor = Object.getOwnPropertyDescriptor(cursor, key);
34
+ if (descriptor) {
35
+ return "value" in descriptor ? descriptor.value : descriptor.get?.call(target);
36
+ }
37
+ cursor = Object.getPrototypeOf(cursor);
38
+ }
39
+ return undefined;
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Typed error hierarchy for Squasher SDKs. Status-specific subclasses retain
3
+ * `SquasherApiError` as their common parent.
4
+ */
5
+ import { type HeaderSource } from "./headers.js";
6
+ export type { HeaderLike } from "./headers.js";
7
+ export interface ParsedErrorBody {
8
+ /** Squasher API convention: `{ error: "human readable message" }`. */
9
+ error?: string;
10
+ /** Optional structured message supplied by an API response. */
11
+ message?: string;
12
+ /** Optional structured error code supplied by an API response. */
13
+ code?: string;
14
+ }
15
+ /**
16
+ * Lookup that works for both the WHATWG `Headers` instance and a plain
17
+ * `Record<string, string>`. The api-client used to be Headers-only; SDK code
18
+ * sometimes hands us a plain object, so accept both.
19
+ */
20
+ /** Root of every Squasher SDK error. Lets callers `catch (e: SquasherError)`. */
21
+ export declare class SquasherError extends Error {
22
+ constructor(message: string);
23
+ }
24
+ /**
25
+ * Base class for every error returned by the Squasher API. Status-specific
26
+ * subclasses extend this; checks against `SquasherApiError` continue to match
27
+ * any of them.
28
+ */
29
+ export declare class SquasherApiError extends SquasherError {
30
+ readonly status: number;
31
+ readonly body: ParsedErrorBody | null;
32
+ readonly requestId: string | undefined;
33
+ constructor(status: number, body: ParsedErrorBody | null, message: string, headers?: HeaderSource);
34
+ /**
35
+ * Map an HTTP status to the most specific subclass. Falls back to the
36
+ * generic `SquasherApiError` for unrecognised statuses (e.g. 418).
37
+ * Network/abort failures throw `SquasherConnectionError` /
38
+ * `SquasherUserAbortError` instead — those never go through here.
39
+ */
40
+ static generate(status: number, body: ParsedErrorBody | null, fallbackMessage: string, headers?: HeaderSource): SquasherApiError;
41
+ }
42
+ export declare class BadRequestError extends SquasherApiError {
43
+ readonly status: 400;
44
+ constructor(body: ParsedErrorBody | null, message: string, headers?: HeaderSource);
45
+ }
46
+ export declare class AuthenticationError extends SquasherApiError {
47
+ readonly status: 401;
48
+ constructor(body: ParsedErrorBody | null, message: string, headers?: HeaderSource);
49
+ }
50
+ export declare class PermissionDeniedError extends SquasherApiError {
51
+ readonly status: 403;
52
+ constructor(body: ParsedErrorBody | null, message: string, headers?: HeaderSource);
53
+ }
54
+ export declare class NotFoundError extends SquasherApiError {
55
+ readonly status: 404;
56
+ constructor(body: ParsedErrorBody | null, message: string, headers?: HeaderSource);
57
+ }
58
+ export declare class ConflictError extends SquasherApiError {
59
+ readonly status: 409;
60
+ constructor(body: ParsedErrorBody | null, message: string, headers?: HeaderSource);
61
+ }
62
+ export declare class UnprocessableEntityError extends SquasherApiError {
63
+ readonly status: 422;
64
+ constructor(body: ParsedErrorBody | null, message: string, headers?: HeaderSource);
65
+ }
66
+ export declare class RateLimitError extends SquasherApiError {
67
+ readonly status: 429;
68
+ constructor(body: ParsedErrorBody | null, message: string, headers?: HeaderSource);
69
+ }
70
+ /** 5xx — keeps the actual status because the spread is too wide for a const. */
71
+ export declare class InternalServerError extends SquasherApiError {
72
+ constructor(status: number, body: ParsedErrorBody | null, message: string, headers?: HeaderSource);
73
+ }
74
+ /** Network-level failure (DNS, connection refused, TLS). */
75
+ export declare class SquasherConnectionError extends SquasherError {
76
+ readonly cause?: Error | undefined;
77
+ constructor(message: string, cause?: Error | undefined);
78
+ }
79
+ /** Specifically a connect-or-read timeout. Subclasses ConnectionError on purpose. */
80
+ export declare class SquasherConnectionTimeoutError extends SquasherConnectionError {
81
+ constructor(message?: string);
82
+ }
83
+ /** AbortController.abort() raised; surfaced separately so retry loops skip it. */
84
+ export declare class SquasherUserAbortError extends SquasherError {
85
+ constructor(message?: string);
86
+ }
87
+ /**
88
+ * Thrown when a Standard Webhooks payload fails signature verification —
89
+ * unknown or rotated secret, tampered body, replayed/expired timestamp,
90
+ * or malformed signature header. Extends SquasherError directly (not
91
+ * SquasherApiError) because webhook failures are not HTTP responses.
92
+ */
93
+ export declare class InvalidWebhookSignatureError extends SquasherError {
94
+ constructor(message: string);
95
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Typed error hierarchy for Squasher SDKs. Status-specific subclasses retain
3
+ * `SquasherApiError` as their common parent.
4
+ */
5
+ import { readHeader } from "./headers.js";
6
+ /**
7
+ * Lookup that works for both the WHATWG `Headers` instance and a plain
8
+ * `Record<string, string>`. The api-client used to be Headers-only; SDK code
9
+ * sometimes hands us a plain object, so accept both.
10
+ */
11
+ /** Root of every Squasher SDK error. Lets callers `catch (e: SquasherError)`. */
12
+ export class SquasherError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = "SquasherError";
16
+ }
17
+ }
18
+ /**
19
+ * Base class for every error returned by the Squasher API. Status-specific
20
+ * subclasses extend this; checks against `SquasherApiError` continue to match
21
+ * any of them.
22
+ */
23
+ export class SquasherApiError extends SquasherError {
24
+ status;
25
+ body;
26
+ requestId;
27
+ constructor(status, body, message, headers) {
28
+ super(buildMessage(body, message));
29
+ this.name = "SquasherApiError";
30
+ this.status = status;
31
+ this.body = body;
32
+ this.requestId = readHeader(headers, "x-request-id");
33
+ }
34
+ /**
35
+ * Map an HTTP status to the most specific subclass. Falls back to the
36
+ * generic `SquasherApiError` for unrecognised statuses (e.g. 418).
37
+ * Network/abort failures throw `SquasherConnectionError` /
38
+ * `SquasherUserAbortError` instead — those never go through here.
39
+ */
40
+ static generate(status, body, fallbackMessage, headers) {
41
+ if (status === 400)
42
+ return new BadRequestError(body, fallbackMessage, headers);
43
+ if (status === 401)
44
+ return new AuthenticationError(body, fallbackMessage, headers);
45
+ if (status === 403)
46
+ return new PermissionDeniedError(body, fallbackMessage, headers);
47
+ if (status === 404)
48
+ return new NotFoundError(body, fallbackMessage, headers);
49
+ if (status === 409)
50
+ return new ConflictError(body, fallbackMessage, headers);
51
+ if (status === 422)
52
+ return new UnprocessableEntityError(body, fallbackMessage, headers);
53
+ if (status === 429)
54
+ return new RateLimitError(body, fallbackMessage, headers);
55
+ if (status >= 500)
56
+ return new InternalServerError(status, body, fallbackMessage, headers);
57
+ return new SquasherApiError(status, body, fallbackMessage, headers);
58
+ }
59
+ }
60
+ function buildMessage(body, fallback) {
61
+ if (body?.error)
62
+ return body.error;
63
+ if (body?.message)
64
+ return body.message;
65
+ return fallback;
66
+ }
67
+ export class BadRequestError extends SquasherApiError {
68
+ status = 400;
69
+ constructor(body, message, headers) {
70
+ super(400, body, message, headers);
71
+ this.name = "BadRequestError";
72
+ }
73
+ }
74
+ export class AuthenticationError extends SquasherApiError {
75
+ status = 401;
76
+ constructor(body, message, headers) {
77
+ super(401, body, message, headers);
78
+ this.name = "AuthenticationError";
79
+ }
80
+ }
81
+ export class PermissionDeniedError extends SquasherApiError {
82
+ status = 403;
83
+ constructor(body, message, headers) {
84
+ super(403, body, message, headers);
85
+ this.name = "PermissionDeniedError";
86
+ }
87
+ }
88
+ export class NotFoundError extends SquasherApiError {
89
+ status = 404;
90
+ constructor(body, message, headers) {
91
+ super(404, body, message, headers);
92
+ this.name = "NotFoundError";
93
+ }
94
+ }
95
+ export class ConflictError extends SquasherApiError {
96
+ status = 409;
97
+ constructor(body, message, headers) {
98
+ super(409, body, message, headers);
99
+ this.name = "ConflictError";
100
+ }
101
+ }
102
+ export class UnprocessableEntityError extends SquasherApiError {
103
+ status = 422;
104
+ constructor(body, message, headers) {
105
+ super(422, body, message, headers);
106
+ this.name = "UnprocessableEntityError";
107
+ }
108
+ }
109
+ export class RateLimitError extends SquasherApiError {
110
+ status = 429;
111
+ constructor(body, message, headers) {
112
+ super(429, body, message, headers);
113
+ this.name = "RateLimitError";
114
+ }
115
+ }
116
+ /** 5xx — keeps the actual status because the spread is too wide for a const. */
117
+ export class InternalServerError extends SquasherApiError {
118
+ constructor(status, body, message, headers) {
119
+ super(status, body, message, headers);
120
+ this.name = "InternalServerError";
121
+ }
122
+ }
123
+ /** Network-level failure (DNS, connection refused, TLS). */
124
+ export class SquasherConnectionError extends SquasherError {
125
+ cause;
126
+ constructor(message, cause) {
127
+ super(message);
128
+ this.cause = cause;
129
+ this.name = "SquasherConnectionError";
130
+ }
131
+ }
132
+ /** Specifically a connect-or-read timeout. Subclasses ConnectionError on purpose. */
133
+ export class SquasherConnectionTimeoutError extends SquasherConnectionError {
134
+ constructor(message = "Request timed out") {
135
+ super(message);
136
+ this.name = "SquasherConnectionTimeoutError";
137
+ }
138
+ }
139
+ /** AbortController.abort() raised; surfaced separately so retry loops skip it. */
140
+ export class SquasherUserAbortError extends SquasherError {
141
+ constructor(message = "Request was aborted") {
142
+ super(message);
143
+ this.name = "SquasherUserAbortError";
144
+ }
145
+ }
146
+ /**
147
+ * Thrown when a Standard Webhooks payload fails signature verification —
148
+ * unknown or rotated secret, tampered body, replayed/expired timestamp,
149
+ * or malformed signature header. Extends SquasherError directly (not
150
+ * SquasherApiError) because webhook failures are not HTTP responses.
151
+ */
152
+ export class InvalidWebhookSignatureError extends SquasherError {
153
+ constructor(message) {
154
+ super(message);
155
+ this.name = "InvalidWebhookSignatureError";
156
+ }
157
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Default telemetry headers attached to every SDK-originated HTTP request.
3
+ *
4
+ * Every request identifies the language, package, package version, OS,
5
+ * architecture, and runtime. Retry count and timeout are added per request.
6
+ */
7
+ export interface DefaultHeadersOptions {
8
+ /** npm package name (e.g. "@squasher-ai/client", "@squasher-ai/node"). */
9
+ packageName: string;
10
+ /** Semver of the package shipping the request. */
11
+ packageVersion: string;
12
+ }
13
+ export interface RequestHeaderOptions {
14
+ /** Retry attempt count. Set to 0 on first attempt; incremented per retry. */
15
+ retryCount?: number;
16
+ /** Per-request timeout in milliseconds, surfaced as seconds in the header. */
17
+ timeoutMs?: number;
18
+ }
19
+ export interface TelemetryHeaders {
20
+ [name: string]: string;
21
+ }
22
+ /**
23
+ * Build the constant-per-process header set: lang, package, OS, arch, runtime.
24
+ * Cache the return value at the SDK-construction site rather than calling per
25
+ * request — platform detection is cached but header construction still
26
+ * allocates a fresh object.
27
+ */
28
+ export declare function getDefaultHeaders(opts: DefaultHeadersOptions): TelemetryHeaders;
29
+ /**
30
+ * Build the per-request header overlay: retry count and timeout. Returned as
31
+ * a separate object so callers can spread it on top of `getDefaultHeaders()`.
32
+ * Omits any field whose source is undefined so we don't ship empty headers.
33
+ */
34
+ export declare function getRequestHeaders(opts: RequestHeaderOptions): TelemetryHeaders;
35
+ /** Build the SDK User-Agent string used by standard HTTP access logs. */
36
+ export declare function getUserAgent(opts: DefaultHeadersOptions): string;
37
+ /** Header names used by SDK tests and request integrations. */
38
+ export declare const HEADER_NAMES: {
39
+ readonly lang: "X-Squasher-Lang";
40
+ readonly package: "X-Squasher-Package";
41
+ readonly packageVersion: "X-Squasher-Package-Version";
42
+ readonly os: "X-Squasher-OS";
43
+ readonly arch: "X-Squasher-Arch";
44
+ readonly runtime: "X-Squasher-Runtime";
45
+ readonly runtimeVersion: "X-Squasher-Runtime-Version";
46
+ readonly retryCount: "X-Squasher-Retry-Count";
47
+ readonly timeout: "X-Squasher-Timeout";
48
+ };