5xx-sdk 1.1.0 → 1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/browser.ts"],"sourcesContent":["import { FiveXX } from \"./client\";\nimport type { FiveXXOptions, AnalyticsBeacon, AnalyticsBatchPayload } from \"./types\";\n\n/** UTM and tracking params we keep when sanitizing URLs */\nconst ALLOWED_QUERY_PARAMS = new Set([\n \"utm_source\",\n \"utm_medium\",\n \"utm_campaign\",\n \"utm_term\",\n \"utm_content\",\n \"ref\",\n]);\n\n/**\n * Browser-specific FiveXX client with automatic error capture\n */\nexport class FiveXXBrowser extends FiveXX {\n private autoCapture = false;\n private originalOnError: OnErrorEventHandler | null = null;\n private originalOnUnhandledRejection: ((event: PromiseRejectionEvent) => void) | null = null;\n\n // Analytics properties\n private analyticsEnabled = false;\n private sessionId: string;\n private analyticsBuffer: AnalyticsBeacon[] = [];\n private flushInterval: ReturnType<typeof setInterval> | null = null;\n private originalPushState: typeof history.pushState | null = null;\n private originalReplaceState: typeof history.replaceState | null = null;\n private boundPopstateHandler: (() => void) | null = null;\n private boundVisibilityHandler: (() => void) | null = null;\n private boundBeforeUnloadHandler: (() => void) | null = null;\n\n constructor(options: FiveXXOptions) {\n super(options);\n\n // Generate session ID\n this.sessionId =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? crypto.randomUUID()\n : \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n\n // Auto-detect environment from URL\n if (typeof window !== \"undefined\" && !options.environment) {\n const hostname = window.location.hostname;\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\") {\n this.setEnvironment(\"development\");\n }\n }\n }\n\n /**\n * Enable automatic capture of unhandled errors and promise rejections\n */\n enableAutoCapture(): void {\n if (this.autoCapture || typeof window === \"undefined\") return;\n\n this.autoCapture = true;\n\n // Capture unhandled errors\n this.originalOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n this.captureError(error, {\n source,\n lineno,\n colno,\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n } else {\n this.captureMessage(String(message), {\n source,\n lineno,\n colno,\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n }\n\n // Call original handler if it exists\n if (this.originalOnError) {\n return this.originalOnError(message, source, lineno, colno, error);\n }\n return false;\n };\n\n // Capture unhandled promise rejections\n this.originalOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = (event) => {\n const error = event.reason;\n if (error instanceof Error) {\n this.captureError(error, {\n type: \"unhandledRejection\",\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n } else {\n this.captureMessage(String(error), {\n type: \"unhandledRejection\",\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n }\n\n if (this.originalOnUnhandledRejection) {\n this.originalOnUnhandledRejection(event);\n }\n };\n }\n\n /**\n * Disable automatic capture\n */\n disableAutoCapture(): void {\n if (!this.autoCapture || typeof window === \"undefined\") return;\n\n this.autoCapture = false;\n window.onerror = this.originalOnError;\n window.onunhandledrejection = this.originalOnUnhandledRejection;\n }\n\n // ---------------------------------------------------------------------------\n // Analytics\n // ---------------------------------------------------------------------------\n\n /**\n * Enable opt-in analytics tracking.\n * Tracks page views automatically, including SPA navigations.\n */\n enableAnalytics(): void {\n if (this.analyticsEnabled || typeof window === \"undefined\") return;\n\n this.analyticsEnabled = true;\n\n // Track the current page immediately\n this.trackPageView();\n\n // Monkey-patch history methods for SPA navigation tracking\n this.originalPushState = history.pushState.bind(history);\n this.originalReplaceState = history.replaceState.bind(history);\n\n const self = this;\n\n history.pushState = function (...args: Parameters<typeof history.pushState>) {\n self.originalPushState!(...args);\n self.trackPageView();\n };\n\n history.replaceState = function (...args: Parameters<typeof history.replaceState>) {\n self.originalReplaceState!(...args);\n self.trackPageView();\n };\n\n // Listen for popstate (browser back/forward)\n this.boundPopstateHandler = () => this.trackPageView();\n window.addEventListener(\"popstate\", this.boundPopstateHandler);\n\n // Start flush interval (every 5 seconds)\n this.flushInterval = setInterval(() => this.flushAnalytics(), 5000);\n\n // Flush on visibility change (tab hidden) and before unload\n this.boundVisibilityHandler = () => {\n if (document.visibilityState === \"hidden\") {\n this.flushAnalyticsBeacon();\n }\n };\n document.addEventListener(\"visibilitychange\", this.boundVisibilityHandler);\n\n this.boundBeforeUnloadHandler = () => this.flushAnalyticsBeacon();\n window.addEventListener(\"beforeunload\", this.boundBeforeUnloadHandler);\n }\n\n /**\n * Track a custom event (stored for future use, logs for now)\n */\n trackEvent(name: string, metadata?: Record<string, unknown>): void {\n if (!this.analyticsEnabled) return;\n console.debug(\"[5xx] trackEvent:\", name, metadata);\n }\n\n // ---------------------------------------------------------------------------\n // Private analytics helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Capture a page view and add it to the buffer\n */\n private trackPageView(): void {\n if (typeof window === \"undefined\") return;\n\n const url = new URL(window.location.href);\n\n const beacon: AnalyticsBeacon = {\n path: url.pathname,\n referrer: document.referrer || undefined,\n screenWidth: window.innerWidth,\n };\n\n // Extract UTM params\n const utmSource = url.searchParams.get(\"utm_source\");\n const utmMedium = url.searchParams.get(\"utm_medium\");\n const utmCampaign = url.searchParams.get(\"utm_campaign\");\n\n if (utmSource) beacon.utmSource = utmSource;\n if (utmMedium) beacon.utmMedium = utmMedium;\n if (utmCampaign) beacon.utmCampaign = utmCampaign;\n\n this.analyticsBuffer.push(beacon);\n }\n\n /**\n * Flush the analytics buffer by POSTing to the server\n */\n private async flushAnalytics(): Promise<void> {\n if (this.analyticsBuffer.length === 0) return;\n\n const payload: AnalyticsBatchPayload = {\n events: [...this.analyticsBuffer],\n sessionId: this.sessionId,\n };\n\n // Optimistically clear the buffer; we will restore on failure\n const snapshot = this.analyticsBuffer;\n this.analyticsBuffer = [];\n\n try {\n const response = await fetch(`${this.getEndpoint()}/api/analytics`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.getApiKey(),\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n // Put events back for retry\n this.analyticsBuffer = snapshot.concat(this.analyticsBuffer);\n }\n } catch {\n // Network error - put events back for retry\n this.analyticsBuffer = snapshot.concat(this.analyticsBuffer);\n }\n }\n\n /**\n * Flush analytics using navigator.sendBeacon (for beforeunload / visibilitychange)\n */\n private flushAnalyticsBeacon(): void {\n if (this.analyticsBuffer.length === 0) return;\n\n const payload: AnalyticsBatchPayload = {\n events: [...this.analyticsBuffer],\n sessionId: this.sessionId,\n };\n\n const blob = new Blob([JSON.stringify(payload)], {\n type: \"application/json\",\n });\n\n const sent = navigator.sendBeacon(`${this.getEndpoint()}/api/analytics`, blob);\n\n if (sent) {\n this.analyticsBuffer = [];\n }\n // If sendBeacon fails, keep buffer for next flush attempt\n }\n\n /**\n * Clean up analytics listeners and intervals\n */\n cleanupAnalytics(): void {\n if (!this.analyticsEnabled) return;\n\n this.analyticsEnabled = false;\n\n // Clear flush interval\n if (this.flushInterval !== null) {\n clearInterval(this.flushInterval);\n this.flushInterval = null;\n }\n\n // Restore original pushState / replaceState\n if (this.originalPushState) {\n history.pushState = this.originalPushState;\n this.originalPushState = null;\n }\n if (this.originalReplaceState) {\n history.replaceState = this.originalReplaceState;\n this.originalReplaceState = null;\n }\n\n // Remove popstate listener\n if (this.boundPopstateHandler) {\n window.removeEventListener(\"popstate\", this.boundPopstateHandler);\n this.boundPopstateHandler = null;\n }\n\n // Remove visibility change listener\n if (this.boundVisibilityHandler) {\n document.removeEventListener(\"visibilitychange\", this.boundVisibilityHandler);\n this.boundVisibilityHandler = null;\n }\n\n // Remove beforeunload listener\n if (this.boundBeforeUnloadHandler) {\n window.removeEventListener(\"beforeunload\", this.boundBeforeUnloadHandler);\n this.boundBeforeUnloadHandler = null;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -14,12 +14,28 @@ interface User {
14
14
  email?: string;
15
15
  name?: string;
16
16
  }
17
+ interface AnalyticsBeacon {
18
+ path: string;
19
+ referrer?: string;
20
+ utmSource?: string;
21
+ utmMedium?: string;
22
+ utmCampaign?: string;
23
+ screenWidth?: number;
24
+ }
25
+ interface AnalyticsBatchPayload {
26
+ events: AnalyticsBeacon[];
27
+ sessionId?: string;
28
+ }
17
29
 
18
30
  declare class FiveXX {
19
31
  private apiKey;
20
32
  private endpoint;
21
33
  private environment;
22
34
  private user;
35
+ /** @internal */
36
+ protected getApiKey(): string;
37
+ /** @internal */
38
+ protected getEndpoint(): string;
23
39
  constructor(options: FiveXXOptions);
24
40
  /**
25
41
  * Set the environment (e.g., "production", "development", "staging")
@@ -43,4 +59,4 @@ declare class FiveXX {
43
59
  private send;
44
60
  }
45
61
 
46
- export { type ErrorPayload as E, FiveXX as F, type User as U, type FiveXXOptions as a };
62
+ export { type AnalyticsBatchPayload as A, type ErrorPayload as E, FiveXX as F, type User as U, type AnalyticsBeacon as a, type FiveXXOptions as b };
@@ -14,12 +14,28 @@ interface User {
14
14
  email?: string;
15
15
  name?: string;
16
16
  }
17
+ interface AnalyticsBeacon {
18
+ path: string;
19
+ referrer?: string;
20
+ utmSource?: string;
21
+ utmMedium?: string;
22
+ utmCampaign?: string;
23
+ screenWidth?: number;
24
+ }
25
+ interface AnalyticsBatchPayload {
26
+ events: AnalyticsBeacon[];
27
+ sessionId?: string;
28
+ }
17
29
 
18
30
  declare class FiveXX {
19
31
  private apiKey;
20
32
  private endpoint;
21
33
  private environment;
22
34
  private user;
35
+ /** @internal */
36
+ protected getApiKey(): string;
37
+ /** @internal */
38
+ protected getEndpoint(): string;
23
39
  constructor(options: FiveXXOptions);
24
40
  /**
25
41
  * Set the environment (e.g., "production", "development", "staging")
@@ -43,4 +59,4 @@ declare class FiveXX {
43
59
  private send;
44
60
  }
45
61
 
46
- export { type ErrorPayload as E, FiveXX as F, type User as U, type FiveXXOptions as a };
62
+ export { type AnalyticsBatchPayload as A, type ErrorPayload as E, FiveXX as F, type User as U, type AnalyticsBeacon as a, type FiveXXOptions as b };
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- export { E as ErrorPayload, F as FiveXX, a as FiveXXOptions, U as User } from './client-BhKj28Zi.mjs';
1
+ export { A as AnalyticsBatchPayload, a as AnalyticsBeacon, E as ErrorPayload, F as FiveXX, b as FiveXXOptions, U as User } from './client-t5SsLKrz.mjs';
2
2
  export { FiveXXBrowser } from './browser.mjs';
3
3
  export { FiveXXNode } from './node.mjs';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { E as ErrorPayload, F as FiveXX, a as FiveXXOptions, U as User } from './client-BhKj28Zi.js';
1
+ export { A as AnalyticsBatchPayload, a as AnalyticsBeacon, E as ErrorPayload, F as FiveXX, b as FiveXXOptions, U as User } from './client-t5SsLKrz.js';
2
2
  export { FiveXXBrowser } from './browser.js';
3
3
  export { FiveXXNode } from './node.js';
package/dist/index.js CHANGED
@@ -34,6 +34,14 @@ var FiveXX = class {
34
34
  this.endpoint = options.endpoint.replace(/\/$/, "");
35
35
  this.environment = options.environment || "production";
36
36
  }
37
+ /** @internal */
38
+ getApiKey() {
39
+ return this.apiKey;
40
+ }
41
+ /** @internal */
42
+ getEndpoint() {
43
+ return this.endpoint;
44
+ }
37
45
  /**
38
46
  * Set the environment (e.g., "production", "development", "staging")
39
47
  */
@@ -108,6 +116,20 @@ var FiveXXBrowser = class extends FiveXX {
108
116
  this.autoCapture = false;
109
117
  this.originalOnError = null;
110
118
  this.originalOnUnhandledRejection = null;
119
+ // Analytics properties
120
+ this.analyticsEnabled = false;
121
+ this.analyticsBuffer = [];
122
+ this.flushInterval = null;
123
+ this.originalPushState = null;
124
+ this.originalReplaceState = null;
125
+ this.boundPopstateHandler = null;
126
+ this.boundVisibilityHandler = null;
127
+ this.boundBeforeUnloadHandler = null;
128
+ this.sessionId = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
129
+ const r = Math.random() * 16 | 0;
130
+ const v = c === "x" ? r : r & 3 | 8;
131
+ return v.toString(16);
132
+ });
111
133
  if (typeof window !== "undefined" && !options.environment) {
112
134
  const hostname = window.location.hostname;
113
135
  if (hostname === "localhost" || hostname === "127.0.0.1") {
@@ -175,6 +197,144 @@ var FiveXXBrowser = class extends FiveXX {
175
197
  window.onerror = this.originalOnError;
176
198
  window.onunhandledrejection = this.originalOnUnhandledRejection;
177
199
  }
200
+ // ---------------------------------------------------------------------------
201
+ // Analytics
202
+ // ---------------------------------------------------------------------------
203
+ /**
204
+ * Enable opt-in analytics tracking.
205
+ * Tracks page views automatically, including SPA navigations.
206
+ */
207
+ enableAnalytics() {
208
+ if (this.analyticsEnabled || typeof window === "undefined") return;
209
+ this.analyticsEnabled = true;
210
+ this.trackPageView();
211
+ this.originalPushState = history.pushState.bind(history);
212
+ this.originalReplaceState = history.replaceState.bind(history);
213
+ const self = this;
214
+ history.pushState = function(...args) {
215
+ self.originalPushState(...args);
216
+ self.trackPageView();
217
+ };
218
+ history.replaceState = function(...args) {
219
+ self.originalReplaceState(...args);
220
+ self.trackPageView();
221
+ };
222
+ this.boundPopstateHandler = () => this.trackPageView();
223
+ window.addEventListener("popstate", this.boundPopstateHandler);
224
+ this.flushInterval = setInterval(() => this.flushAnalytics(), 5e3);
225
+ this.boundVisibilityHandler = () => {
226
+ if (document.visibilityState === "hidden") {
227
+ this.flushAnalyticsBeacon();
228
+ }
229
+ };
230
+ document.addEventListener("visibilitychange", this.boundVisibilityHandler);
231
+ this.boundBeforeUnloadHandler = () => this.flushAnalyticsBeacon();
232
+ window.addEventListener("beforeunload", this.boundBeforeUnloadHandler);
233
+ }
234
+ /**
235
+ * Track a custom event (stored for future use, logs for now)
236
+ */
237
+ trackEvent(name, metadata) {
238
+ if (!this.analyticsEnabled) return;
239
+ console.debug("[5xx] trackEvent:", name, metadata);
240
+ }
241
+ // ---------------------------------------------------------------------------
242
+ // Private analytics helpers
243
+ // ---------------------------------------------------------------------------
244
+ /**
245
+ * Capture a page view and add it to the buffer
246
+ */
247
+ trackPageView() {
248
+ if (typeof window === "undefined") return;
249
+ const url = new URL(window.location.href);
250
+ const beacon = {
251
+ path: url.pathname,
252
+ referrer: document.referrer || void 0,
253
+ screenWidth: window.innerWidth
254
+ };
255
+ const utmSource = url.searchParams.get("utm_source");
256
+ const utmMedium = url.searchParams.get("utm_medium");
257
+ const utmCampaign = url.searchParams.get("utm_campaign");
258
+ if (utmSource) beacon.utmSource = utmSource;
259
+ if (utmMedium) beacon.utmMedium = utmMedium;
260
+ if (utmCampaign) beacon.utmCampaign = utmCampaign;
261
+ this.analyticsBuffer.push(beacon);
262
+ }
263
+ /**
264
+ * Flush the analytics buffer by POSTing to the server
265
+ */
266
+ async flushAnalytics() {
267
+ if (this.analyticsBuffer.length === 0) return;
268
+ const payload = {
269
+ events: [...this.analyticsBuffer],
270
+ sessionId: this.sessionId
271
+ };
272
+ const snapshot = this.analyticsBuffer;
273
+ this.analyticsBuffer = [];
274
+ try {
275
+ const response = await fetch(`${this.getEndpoint()}/api/analytics`, {
276
+ method: "POST",
277
+ headers: {
278
+ "Content-Type": "application/json",
279
+ "X-API-Key": this.getApiKey()
280
+ },
281
+ body: JSON.stringify(payload)
282
+ });
283
+ if (!response.ok) {
284
+ this.analyticsBuffer = snapshot.concat(this.analyticsBuffer);
285
+ }
286
+ } catch {
287
+ this.analyticsBuffer = snapshot.concat(this.analyticsBuffer);
288
+ }
289
+ }
290
+ /**
291
+ * Flush analytics using navigator.sendBeacon (for beforeunload / visibilitychange)
292
+ */
293
+ flushAnalyticsBeacon() {
294
+ if (this.analyticsBuffer.length === 0) return;
295
+ const payload = {
296
+ events: [...this.analyticsBuffer],
297
+ sessionId: this.sessionId
298
+ };
299
+ const blob = new Blob([JSON.stringify(payload)], {
300
+ type: "application/json"
301
+ });
302
+ const sent = navigator.sendBeacon(`${this.getEndpoint()}/api/analytics`, blob);
303
+ if (sent) {
304
+ this.analyticsBuffer = [];
305
+ }
306
+ }
307
+ /**
308
+ * Clean up analytics listeners and intervals
309
+ */
310
+ cleanupAnalytics() {
311
+ if (!this.analyticsEnabled) return;
312
+ this.analyticsEnabled = false;
313
+ if (this.flushInterval !== null) {
314
+ clearInterval(this.flushInterval);
315
+ this.flushInterval = null;
316
+ }
317
+ if (this.originalPushState) {
318
+ history.pushState = this.originalPushState;
319
+ this.originalPushState = null;
320
+ }
321
+ if (this.originalReplaceState) {
322
+ history.replaceState = this.originalReplaceState;
323
+ this.originalReplaceState = null;
324
+ }
325
+ if (this.boundPopstateHandler) {
326
+ window.removeEventListener("popstate", this.boundPopstateHandler);
327
+ this.boundPopstateHandler = null;
328
+ }
329
+ if (this.boundVisibilityHandler) {
330
+ document.removeEventListener("visibilitychange", this.boundVisibilityHandler);
331
+ this.boundVisibilityHandler = null;
332
+ }
333
+ if (this.boundBeforeUnloadHandler) {
334
+ window.removeEventListener("beforeunload", this.boundBeforeUnloadHandler);
335
+ this.boundBeforeUnloadHandler = null;
336
+ }
337
+ }
178
338
  };
179
339
 
180
340
  // src/node.ts
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/browser.ts","../src/node.ts"],"sourcesContent":["export { FiveXX } from \"./client\";\nexport { FiveXXBrowser } from \"./browser\";\nexport { FiveXXNode } from \"./node\";\nexport type { FiveXXOptions, ErrorPayload, User } from \"./types\";\n","import type { FiveXXOptions, ErrorPayload, User } from \"./types\";\n\nexport class FiveXX {\n private apiKey: string;\n private endpoint: string;\n private environment: string;\n private user: User | null = null;\n\n constructor(options: FiveXXOptions) {\n this.apiKey = options.apiKey;\n this.endpoint = options.endpoint.replace(/\\/$/, \"\"); // Remove trailing slash\n this.environment = options.environment || \"production\";\n }\n\n /**\n * Set the environment (e.g., \"production\", \"development\", \"staging\")\n */\n setEnvironment(env: string): void {\n this.environment = env;\n }\n\n /**\n * Set user context for errors\n */\n setUser(user: User | null): void {\n this.user = user;\n }\n\n /**\n * Capture an error and send it to the 5xx server\n */\n async captureError(\n error: Error,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message: error.message || String(error),\n stack: error.stack,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Capture a message as an error\n */\n async captureMessage(\n message: string,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Send error payload to the server\n */\n private async send(payload: ErrorPayload): Promise<string | null> {\n try {\n const response = await fetch(`${this.endpoint}/api/errors`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n console.error(`5xx: Failed to send error (${response.status})`);\n return null;\n }\n\n const data = await response.json();\n return data.id;\n } catch (err) {\n console.error(\"5xx: Failed to send error\", err);\n return null;\n }\n }\n}\n","import { FiveXX } from \"./client\";\nimport type { FiveXXOptions } from \"./types\";\n\n/**\n * Browser-specific FiveXX client with automatic error capture\n */\nexport class FiveXXBrowser extends FiveXX {\n private autoCapture = false;\n private originalOnError: OnErrorEventHandler | null = null;\n private originalOnUnhandledRejection: ((event: PromiseRejectionEvent) => void) | null = null;\n\n constructor(options: FiveXXOptions) {\n super(options);\n\n // Auto-detect environment from URL\n if (typeof window !== \"undefined\" && !options.environment) {\n const hostname = window.location.hostname;\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\") {\n this.setEnvironment(\"development\");\n }\n }\n }\n\n /**\n * Enable automatic capture of unhandled errors and promise rejections\n */\n enableAutoCapture(): void {\n if (this.autoCapture || typeof window === \"undefined\") return;\n\n this.autoCapture = true;\n\n // Capture unhandled errors\n this.originalOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n this.captureError(error, {\n source,\n lineno,\n colno,\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n } else {\n this.captureMessage(String(message), {\n source,\n lineno,\n colno,\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n }\n\n // Call original handler if it exists\n if (this.originalOnError) {\n return this.originalOnError(message, source, lineno, colno, error);\n }\n return false;\n };\n\n // Capture unhandled promise rejections\n this.originalOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = (event) => {\n const error = event.reason;\n if (error instanceof Error) {\n this.captureError(error, {\n type: \"unhandledRejection\",\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n } else {\n this.captureMessage(String(error), {\n type: \"unhandledRejection\",\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n }\n\n if (this.originalOnUnhandledRejection) {\n this.originalOnUnhandledRejection(event);\n }\n };\n }\n\n /**\n * Disable automatic capture\n */\n disableAutoCapture(): void {\n if (!this.autoCapture || typeof window === \"undefined\") return;\n\n this.autoCapture = false;\n window.onerror = this.originalOnError;\n window.onunhandledrejection = this.originalOnUnhandledRejection;\n }\n}\n","import { FiveXX } from \"./client\";\nimport type { FiveXXOptions } from \"./types\";\n\ninterface NodeOptions extends FiveXXOptions {\n exitOnFatalError?: boolean;\n}\n\n/**\n * Node.js-specific FiveXX client with automatic error capture\n */\nexport class FiveXXNode extends FiveXX {\n private autoCapture = false;\n private exitOnFatalError: boolean;\n\n constructor(options: NodeOptions) {\n super(options);\n this.exitOnFatalError = options.exitOnFatalError ?? true;\n\n // Auto-detect environment from NODE_ENV\n if (!options.environment && process.env.NODE_ENV) {\n this.setEnvironment(process.env.NODE_ENV);\n }\n }\n\n /**\n * Enable automatic capture of uncaught exceptions and unhandled rejections\n */\n enableAutoCapture(): void {\n if (this.autoCapture) return;\n\n this.autoCapture = true;\n\n // Capture uncaught exceptions\n process.on(\"uncaughtException\", async (error) => {\n console.error(\"5xx: Uncaught exception:\", error);\n await this.captureError(error, {\n type: \"uncaughtException\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n\n if (this.exitOnFatalError) {\n process.exit(1);\n }\n });\n\n // Capture unhandled promise rejections\n process.on(\"unhandledRejection\", async (reason) => {\n console.error(\"5xx: Unhandled rejection:\", reason);\n if (reason instanceof Error) {\n await this.captureError(reason, {\n type: \"unhandledRejection\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n } else {\n await this.captureMessage(String(reason), {\n type: \"unhandledRejection\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n }\n });\n }\n\n /**\n * Wrap an async function to capture errors\n */\n wrapAsync<T extends (...args: unknown[]) => Promise<unknown>>(\n fn: T,\n metadata?: Record<string, unknown>\n ): T {\n return (async (...args: Parameters<T>) => {\n try {\n return await fn(...args);\n } catch (error) {\n if (error instanceof Error) {\n await this.captureError(error, metadata);\n }\n throw error;\n }\n }) as T;\n }\n\n /**\n * Wrap an HTTP route handler to automatically capture errors.\n * Works with Next.js, Express, Fastify, and any framework.\n * Captures the error with request metadata, then re-throws\n * so the framework's own error handling still works.\n *\n * Usage (Next.js):\n * export const GET = fivexx.wrapHandler(async (req) => {\n * return NextResponse.json(data);\n * });\n *\n * Usage (Express):\n * app.get('/api', fivexx.wrapHandler(async (req, res) => {\n * res.json(data);\n * }));\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wrapHandler<T extends (...args: any[]) => Promise<any>>(fn: T): T {\n const self = this;\n return (async function (...args: Parameters<T>) {\n try {\n return await fn(...args);\n } catch (error) {\n const metadata: Record<string, unknown> = {\n type: \"handlerError\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n };\n\n // Extract request info from first argument (works with Next.js Request, Express req, etc.)\n const req = args[0];\n if (req && typeof req === \"object\") {\n if (\"url\" in req) metadata.url = String(req.url);\n if (\"method\" in req) metadata.method = String(req.method);\n }\n\n if (error instanceof Error) {\n await self.captureError(error, metadata);\n } else {\n await self.captureMessage(String(error), metadata);\n }\n throw error;\n }\n }) as T;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/browser.ts","../src/node.ts"],"sourcesContent":["export { FiveXX } from \"./client\";\nexport { FiveXXBrowser } from \"./browser\";\nexport { FiveXXNode } from \"./node\";\nexport type {\n FiveXXOptions,\n ErrorPayload,\n User,\n AnalyticsBeacon,\n AnalyticsBatchPayload,\n} from \"./types\";\n","import type { FiveXXOptions, ErrorPayload, User } from \"./types\";\n\nexport class FiveXX {\n private apiKey: string;\n private endpoint: string;\n private environment: string;\n private user: User | null = null;\n\n /** @internal */\n protected getApiKey(): string {\n return this.apiKey;\n }\n\n /** @internal */\n protected getEndpoint(): string {\n return this.endpoint;\n }\n\n constructor(options: FiveXXOptions) {\n this.apiKey = options.apiKey;\n this.endpoint = options.endpoint.replace(/\\/$/, \"\"); // Remove trailing slash\n this.environment = options.environment || \"production\";\n }\n\n /**\n * Set the environment (e.g., \"production\", \"development\", \"staging\")\n */\n setEnvironment(env: string): void {\n this.environment = env;\n }\n\n /**\n * Set user context for errors\n */\n setUser(user: User | null): void {\n this.user = user;\n }\n\n /**\n * Capture an error and send it to the 5xx server\n */\n async captureError(\n error: Error,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message: error.message || String(error),\n stack: error.stack,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Capture a message as an error\n */\n async captureMessage(\n message: string,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Send error payload to the server\n */\n private async send(payload: ErrorPayload): Promise<string | null> {\n try {\n const response = await fetch(`${this.endpoint}/api/errors`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n console.error(`5xx: Failed to send error (${response.status})`);\n return null;\n }\n\n const data = await response.json();\n return data.id;\n } catch (err) {\n console.error(\"5xx: Failed to send error\", err);\n return null;\n }\n }\n}\n","import { FiveXX } from \"./client\";\nimport type { FiveXXOptions, AnalyticsBeacon, AnalyticsBatchPayload } from \"./types\";\n\n/** UTM and tracking params we keep when sanitizing URLs */\nconst ALLOWED_QUERY_PARAMS = new Set([\n \"utm_source\",\n \"utm_medium\",\n \"utm_campaign\",\n \"utm_term\",\n \"utm_content\",\n \"ref\",\n]);\n\n/**\n * Browser-specific FiveXX client with automatic error capture\n */\nexport class FiveXXBrowser extends FiveXX {\n private autoCapture = false;\n private originalOnError: OnErrorEventHandler | null = null;\n private originalOnUnhandledRejection: ((event: PromiseRejectionEvent) => void) | null = null;\n\n // Analytics properties\n private analyticsEnabled = false;\n private sessionId: string;\n private analyticsBuffer: AnalyticsBeacon[] = [];\n private flushInterval: ReturnType<typeof setInterval> | null = null;\n private originalPushState: typeof history.pushState | null = null;\n private originalReplaceState: typeof history.replaceState | null = null;\n private boundPopstateHandler: (() => void) | null = null;\n private boundVisibilityHandler: (() => void) | null = null;\n private boundBeforeUnloadHandler: (() => void) | null = null;\n\n constructor(options: FiveXXOptions) {\n super(options);\n\n // Generate session ID\n this.sessionId =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? crypto.randomUUID()\n : \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n\n // Auto-detect environment from URL\n if (typeof window !== \"undefined\" && !options.environment) {\n const hostname = window.location.hostname;\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\") {\n this.setEnvironment(\"development\");\n }\n }\n }\n\n /**\n * Enable automatic capture of unhandled errors and promise rejections\n */\n enableAutoCapture(): void {\n if (this.autoCapture || typeof window === \"undefined\") return;\n\n this.autoCapture = true;\n\n // Capture unhandled errors\n this.originalOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n this.captureError(error, {\n source,\n lineno,\n colno,\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n } else {\n this.captureMessage(String(message), {\n source,\n lineno,\n colno,\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n }\n\n // Call original handler if it exists\n if (this.originalOnError) {\n return this.originalOnError(message, source, lineno, colno, error);\n }\n return false;\n };\n\n // Capture unhandled promise rejections\n this.originalOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = (event) => {\n const error = event.reason;\n if (error instanceof Error) {\n this.captureError(error, {\n type: \"unhandledRejection\",\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n } else {\n this.captureMessage(String(error), {\n type: \"unhandledRejection\",\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n }\n\n if (this.originalOnUnhandledRejection) {\n this.originalOnUnhandledRejection(event);\n }\n };\n }\n\n /**\n * Disable automatic capture\n */\n disableAutoCapture(): void {\n if (!this.autoCapture || typeof window === \"undefined\") return;\n\n this.autoCapture = false;\n window.onerror = this.originalOnError;\n window.onunhandledrejection = this.originalOnUnhandledRejection;\n }\n\n // ---------------------------------------------------------------------------\n // Analytics\n // ---------------------------------------------------------------------------\n\n /**\n * Enable opt-in analytics tracking.\n * Tracks page views automatically, including SPA navigations.\n */\n enableAnalytics(): void {\n if (this.analyticsEnabled || typeof window === \"undefined\") return;\n\n this.analyticsEnabled = true;\n\n // Track the current page immediately\n this.trackPageView();\n\n // Monkey-patch history methods for SPA navigation tracking\n this.originalPushState = history.pushState.bind(history);\n this.originalReplaceState = history.replaceState.bind(history);\n\n const self = this;\n\n history.pushState = function (...args: Parameters<typeof history.pushState>) {\n self.originalPushState!(...args);\n self.trackPageView();\n };\n\n history.replaceState = function (...args: Parameters<typeof history.replaceState>) {\n self.originalReplaceState!(...args);\n self.trackPageView();\n };\n\n // Listen for popstate (browser back/forward)\n this.boundPopstateHandler = () => this.trackPageView();\n window.addEventListener(\"popstate\", this.boundPopstateHandler);\n\n // Start flush interval (every 5 seconds)\n this.flushInterval = setInterval(() => this.flushAnalytics(), 5000);\n\n // Flush on visibility change (tab hidden) and before unload\n this.boundVisibilityHandler = () => {\n if (document.visibilityState === \"hidden\") {\n this.flushAnalyticsBeacon();\n }\n };\n document.addEventListener(\"visibilitychange\", this.boundVisibilityHandler);\n\n this.boundBeforeUnloadHandler = () => this.flushAnalyticsBeacon();\n window.addEventListener(\"beforeunload\", this.boundBeforeUnloadHandler);\n }\n\n /**\n * Track a custom event (stored for future use, logs for now)\n */\n trackEvent(name: string, metadata?: Record<string, unknown>): void {\n if (!this.analyticsEnabled) return;\n console.debug(\"[5xx] trackEvent:\", name, metadata);\n }\n\n // ---------------------------------------------------------------------------\n // Private analytics helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Capture a page view and add it to the buffer\n */\n private trackPageView(): void {\n if (typeof window === \"undefined\") return;\n\n const url = new URL(window.location.href);\n\n const beacon: AnalyticsBeacon = {\n path: url.pathname,\n referrer: document.referrer || undefined,\n screenWidth: window.innerWidth,\n };\n\n // Extract UTM params\n const utmSource = url.searchParams.get(\"utm_source\");\n const utmMedium = url.searchParams.get(\"utm_medium\");\n const utmCampaign = url.searchParams.get(\"utm_campaign\");\n\n if (utmSource) beacon.utmSource = utmSource;\n if (utmMedium) beacon.utmMedium = utmMedium;\n if (utmCampaign) beacon.utmCampaign = utmCampaign;\n\n this.analyticsBuffer.push(beacon);\n }\n\n /**\n * Flush the analytics buffer by POSTing to the server\n */\n private async flushAnalytics(): Promise<void> {\n if (this.analyticsBuffer.length === 0) return;\n\n const payload: AnalyticsBatchPayload = {\n events: [...this.analyticsBuffer],\n sessionId: this.sessionId,\n };\n\n // Optimistically clear the buffer; we will restore on failure\n const snapshot = this.analyticsBuffer;\n this.analyticsBuffer = [];\n\n try {\n const response = await fetch(`${this.getEndpoint()}/api/analytics`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.getApiKey(),\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n // Put events back for retry\n this.analyticsBuffer = snapshot.concat(this.analyticsBuffer);\n }\n } catch {\n // Network error - put events back for retry\n this.analyticsBuffer = snapshot.concat(this.analyticsBuffer);\n }\n }\n\n /**\n * Flush analytics using navigator.sendBeacon (for beforeunload / visibilitychange)\n */\n private flushAnalyticsBeacon(): void {\n if (this.analyticsBuffer.length === 0) return;\n\n const payload: AnalyticsBatchPayload = {\n events: [...this.analyticsBuffer],\n sessionId: this.sessionId,\n };\n\n const blob = new Blob([JSON.stringify(payload)], {\n type: \"application/json\",\n });\n\n const sent = navigator.sendBeacon(`${this.getEndpoint()}/api/analytics`, blob);\n\n if (sent) {\n this.analyticsBuffer = [];\n }\n // If sendBeacon fails, keep buffer for next flush attempt\n }\n\n /**\n * Clean up analytics listeners and intervals\n */\n cleanupAnalytics(): void {\n if (!this.analyticsEnabled) return;\n\n this.analyticsEnabled = false;\n\n // Clear flush interval\n if (this.flushInterval !== null) {\n clearInterval(this.flushInterval);\n this.flushInterval = null;\n }\n\n // Restore original pushState / replaceState\n if (this.originalPushState) {\n history.pushState = this.originalPushState;\n this.originalPushState = null;\n }\n if (this.originalReplaceState) {\n history.replaceState = this.originalReplaceState;\n this.originalReplaceState = null;\n }\n\n // Remove popstate listener\n if (this.boundPopstateHandler) {\n window.removeEventListener(\"popstate\", this.boundPopstateHandler);\n this.boundPopstateHandler = null;\n }\n\n // Remove visibility change listener\n if (this.boundVisibilityHandler) {\n document.removeEventListener(\"visibilitychange\", this.boundVisibilityHandler);\n this.boundVisibilityHandler = null;\n }\n\n // Remove beforeunload listener\n if (this.boundBeforeUnloadHandler) {\n window.removeEventListener(\"beforeunload\", this.boundBeforeUnloadHandler);\n this.boundBeforeUnloadHandler = null;\n }\n }\n}\n","import { FiveXX } from \"./client\";\nimport type { FiveXXOptions } from \"./types\";\n\ninterface NodeOptions extends FiveXXOptions {\n exitOnFatalError?: boolean;\n}\n\n/**\n * Node.js-specific FiveXX client with automatic error capture\n */\nexport class FiveXXNode extends FiveXX {\n private autoCapture = false;\n private exitOnFatalError: boolean;\n\n constructor(options: NodeOptions) {\n super(options);\n this.exitOnFatalError = options.exitOnFatalError ?? true;\n\n // Auto-detect environment from NODE_ENV\n if (!options.environment && process.env.NODE_ENV) {\n this.setEnvironment(process.env.NODE_ENV);\n }\n }\n\n /**\n * Enable automatic capture of uncaught exceptions and unhandled rejections\n */\n enableAutoCapture(): void {\n if (this.autoCapture) return;\n\n this.autoCapture = true;\n\n // Capture uncaught exceptions\n process.on(\"uncaughtException\", async (error) => {\n console.error(\"5xx: Uncaught exception:\", error);\n await this.captureError(error, {\n type: \"uncaughtException\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n\n if (this.exitOnFatalError) {\n process.exit(1);\n }\n });\n\n // Capture unhandled promise rejections\n process.on(\"unhandledRejection\", async (reason) => {\n console.error(\"5xx: Unhandled rejection:\", reason);\n if (reason instanceof Error) {\n await this.captureError(reason, {\n type: \"unhandledRejection\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n } else {\n await this.captureMessage(String(reason), {\n type: \"unhandledRejection\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n }\n });\n }\n\n /**\n * Wrap an async function to capture errors\n */\n wrapAsync<T extends (...args: unknown[]) => Promise<unknown>>(\n fn: T,\n metadata?: Record<string, unknown>\n ): T {\n return (async (...args: Parameters<T>) => {\n try {\n return await fn(...args);\n } catch (error) {\n if (error instanceof Error) {\n await this.captureError(error, metadata);\n }\n throw error;\n }\n }) as T;\n }\n\n /**\n * Wrap an HTTP route handler to automatically capture errors.\n * Works with Next.js, Express, Fastify, and any framework.\n * Captures the error with request metadata, then re-throws\n * so the framework's own error handling still works.\n *\n * Usage (Next.js):\n * export const GET = fivexx.wrapHandler(async (req) => {\n * return NextResponse.json(data);\n * });\n *\n * Usage (Express):\n * app.get('/api', fivexx.wrapHandler(async (req, res) => {\n * res.json(data);\n * }));\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wrapHandler<T extends (...args: any[]) => Promise<any>>(fn: T): T {\n const self = this;\n return (async function (...args: Parameters<T>) {\n try {\n return await fn(...args);\n } catch (error) {\n const metadata: Record<string, unknown> = {\n type: \"handlerError\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n };\n\n // Extract request info from first argument (works with Next.js Request, Express req, etc.)\n const req = args[0];\n if (req && typeof req === \"object\") {\n if (\"url\" in req) metadata.url = String(req.url);\n if (\"method\" in req) metadata.method = String(req.method);\n }\n\n if (error instanceof Error) {\n await self.captureError(error, metadata);\n } else {\n await self.captureMessage(String(error), metadata);\n }\n throw error;\n }\n }) as T;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  FiveXXBrowser
3
- } from "./chunk-LD3XNYST.mjs";
3
+ } from "./chunk-IAF5CKNL.mjs";
4
4
  import {
5
5
  FiveXXNode
6
- } from "./chunk-JCBAF7DF.mjs";
6
+ } from "./chunk-762E5RVI.mjs";
7
7
  import {
8
8
  FiveXX
9
- } from "./chunk-5YY5E33R.mjs";
9
+ } from "./chunk-G4LKAXG5.mjs";
10
10
  export {
11
11
  FiveXX,
12
12
  FiveXXBrowser,
package/dist/node.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { F as FiveXX, a as FiveXXOptions } from './client-BhKj28Zi.mjs';
1
+ import { F as FiveXX, b as FiveXXOptions } from './client-t5SsLKrz.mjs';
2
2
 
3
3
  interface NodeOptions extends FiveXXOptions {
4
4
  exitOnFatalError?: boolean;
package/dist/node.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { F as FiveXX, a as FiveXXOptions } from './client-BhKj28Zi.js';
1
+ import { F as FiveXX, b as FiveXXOptions } from './client-t5SsLKrz.js';
2
2
 
3
3
  interface NodeOptions extends FiveXXOptions {
4
4
  exitOnFatalError?: boolean;
package/dist/node.js CHANGED
@@ -32,6 +32,14 @@ var FiveXX = class {
32
32
  this.endpoint = options.endpoint.replace(/\/$/, "");
33
33
  this.environment = options.environment || "production";
34
34
  }
35
+ /** @internal */
36
+ getApiKey() {
37
+ return this.apiKey;
38
+ }
39
+ /** @internal */
40
+ getEndpoint() {
41
+ return this.endpoint;
42
+ }
35
43
  /**
36
44
  * Set the environment (e.g., "production", "development", "staging")
37
45
  */
package/dist/node.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/node.ts","../src/client.ts"],"sourcesContent":["import { FiveXX } from \"./client\";\nimport type { FiveXXOptions } from \"./types\";\n\ninterface NodeOptions extends FiveXXOptions {\n exitOnFatalError?: boolean;\n}\n\n/**\n * Node.js-specific FiveXX client with automatic error capture\n */\nexport class FiveXXNode extends FiveXX {\n private autoCapture = false;\n private exitOnFatalError: boolean;\n\n constructor(options: NodeOptions) {\n super(options);\n this.exitOnFatalError = options.exitOnFatalError ?? true;\n\n // Auto-detect environment from NODE_ENV\n if (!options.environment && process.env.NODE_ENV) {\n this.setEnvironment(process.env.NODE_ENV);\n }\n }\n\n /**\n * Enable automatic capture of uncaught exceptions and unhandled rejections\n */\n enableAutoCapture(): void {\n if (this.autoCapture) return;\n\n this.autoCapture = true;\n\n // Capture uncaught exceptions\n process.on(\"uncaughtException\", async (error) => {\n console.error(\"5xx: Uncaught exception:\", error);\n await this.captureError(error, {\n type: \"uncaughtException\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n\n if (this.exitOnFatalError) {\n process.exit(1);\n }\n });\n\n // Capture unhandled promise rejections\n process.on(\"unhandledRejection\", async (reason) => {\n console.error(\"5xx: Unhandled rejection:\", reason);\n if (reason instanceof Error) {\n await this.captureError(reason, {\n type: \"unhandledRejection\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n } else {\n await this.captureMessage(String(reason), {\n type: \"unhandledRejection\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n }\n });\n }\n\n /**\n * Wrap an async function to capture errors\n */\n wrapAsync<T extends (...args: unknown[]) => Promise<unknown>>(\n fn: T,\n metadata?: Record<string, unknown>\n ): T {\n return (async (...args: Parameters<T>) => {\n try {\n return await fn(...args);\n } catch (error) {\n if (error instanceof Error) {\n await this.captureError(error, metadata);\n }\n throw error;\n }\n }) as T;\n }\n\n /**\n * Wrap an HTTP route handler to automatically capture errors.\n * Works with Next.js, Express, Fastify, and any framework.\n * Captures the error with request metadata, then re-throws\n * so the framework's own error handling still works.\n *\n * Usage (Next.js):\n * export const GET = fivexx.wrapHandler(async (req) => {\n * return NextResponse.json(data);\n * });\n *\n * Usage (Express):\n * app.get('/api', fivexx.wrapHandler(async (req, res) => {\n * res.json(data);\n * }));\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wrapHandler<T extends (...args: any[]) => Promise<any>>(fn: T): T {\n const self = this;\n return (async function (...args: Parameters<T>) {\n try {\n return await fn(...args);\n } catch (error) {\n const metadata: Record<string, unknown> = {\n type: \"handlerError\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n };\n\n // Extract request info from first argument (works with Next.js Request, Express req, etc.)\n const req = args[0];\n if (req && typeof req === \"object\") {\n if (\"url\" in req) metadata.url = String(req.url);\n if (\"method\" in req) metadata.method = String(req.method);\n }\n\n if (error instanceof Error) {\n await self.captureError(error, metadata);\n } else {\n await self.captureMessage(String(error), metadata);\n }\n throw error;\n }\n }) as T;\n }\n}\n","import type { FiveXXOptions, ErrorPayload, User } from \"./types\";\n\nexport class FiveXX {\n private apiKey: string;\n private endpoint: string;\n private environment: string;\n private user: User | null = null;\n\n constructor(options: FiveXXOptions) {\n this.apiKey = options.apiKey;\n this.endpoint = options.endpoint.replace(/\\/$/, \"\"); // Remove trailing slash\n this.environment = options.environment || \"production\";\n }\n\n /**\n * Set the environment (e.g., \"production\", \"development\", \"staging\")\n */\n setEnvironment(env: string): void {\n this.environment = env;\n }\n\n /**\n * Set user context for errors\n */\n setUser(user: User | null): void {\n this.user = user;\n }\n\n /**\n * Capture an error and send it to the 5xx server\n */\n async captureError(\n error: Error,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message: error.message || String(error),\n stack: error.stack,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Capture a message as an error\n */\n async captureMessage(\n message: string,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Send error payload to the server\n */\n private async send(payload: ErrorPayload): Promise<string | null> {\n try {\n const response = await fetch(`${this.endpoint}/api/errors`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n console.error(`5xx: Failed to send error (${response.status})`);\n return null;\n }\n\n const data = await response.json();\n return data.id;\n } catch (err) {\n console.error(\"5xx: Failed to send error\", err);\n return null;\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/node.ts","../src/client.ts"],"sourcesContent":["import { FiveXX } from \"./client\";\nimport type { FiveXXOptions } from \"./types\";\n\ninterface NodeOptions extends FiveXXOptions {\n exitOnFatalError?: boolean;\n}\n\n/**\n * Node.js-specific FiveXX client with automatic error capture\n */\nexport class FiveXXNode extends FiveXX {\n private autoCapture = false;\n private exitOnFatalError: boolean;\n\n constructor(options: NodeOptions) {\n super(options);\n this.exitOnFatalError = options.exitOnFatalError ?? true;\n\n // Auto-detect environment from NODE_ENV\n if (!options.environment && process.env.NODE_ENV) {\n this.setEnvironment(process.env.NODE_ENV);\n }\n }\n\n /**\n * Enable automatic capture of uncaught exceptions and unhandled rejections\n */\n enableAutoCapture(): void {\n if (this.autoCapture) return;\n\n this.autoCapture = true;\n\n // Capture uncaught exceptions\n process.on(\"uncaughtException\", async (error) => {\n console.error(\"5xx: Uncaught exception:\", error);\n await this.captureError(error, {\n type: \"uncaughtException\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n\n if (this.exitOnFatalError) {\n process.exit(1);\n }\n });\n\n // Capture unhandled promise rejections\n process.on(\"unhandledRejection\", async (reason) => {\n console.error(\"5xx: Unhandled rejection:\", reason);\n if (reason instanceof Error) {\n await this.captureError(reason, {\n type: \"unhandledRejection\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n } else {\n await this.captureMessage(String(reason), {\n type: \"unhandledRejection\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n });\n }\n });\n }\n\n /**\n * Wrap an async function to capture errors\n */\n wrapAsync<T extends (...args: unknown[]) => Promise<unknown>>(\n fn: T,\n metadata?: Record<string, unknown>\n ): T {\n return (async (...args: Parameters<T>) => {\n try {\n return await fn(...args);\n } catch (error) {\n if (error instanceof Error) {\n await this.captureError(error, metadata);\n }\n throw error;\n }\n }) as T;\n }\n\n /**\n * Wrap an HTTP route handler to automatically capture errors.\n * Works with Next.js, Express, Fastify, and any framework.\n * Captures the error with request metadata, then re-throws\n * so the framework's own error handling still works.\n *\n * Usage (Next.js):\n * export const GET = fivexx.wrapHandler(async (req) => {\n * return NextResponse.json(data);\n * });\n *\n * Usage (Express):\n * app.get('/api', fivexx.wrapHandler(async (req, res) => {\n * res.json(data);\n * }));\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wrapHandler<T extends (...args: any[]) => Promise<any>>(fn: T): T {\n const self = this;\n return (async function (...args: Parameters<T>) {\n try {\n return await fn(...args);\n } catch (error) {\n const metadata: Record<string, unknown> = {\n type: \"handlerError\",\n nodeVersion: process.version,\n platform: process.platform,\n pid: process.pid,\n };\n\n // Extract request info from first argument (works with Next.js Request, Express req, etc.)\n const req = args[0];\n if (req && typeof req === \"object\") {\n if (\"url\" in req) metadata.url = String(req.url);\n if (\"method\" in req) metadata.method = String(req.method);\n }\n\n if (error instanceof Error) {\n await self.captureError(error, metadata);\n } else {\n await self.captureMessage(String(error), metadata);\n }\n throw error;\n }\n }) as T;\n }\n}\n","import type { FiveXXOptions, ErrorPayload, User } from \"./types\";\n\nexport class FiveXX {\n private apiKey: string;\n private endpoint: string;\n private environment: string;\n private user: User | null = null;\n\n /** @internal */\n protected getApiKey(): string {\n return this.apiKey;\n }\n\n /** @internal */\n protected getEndpoint(): string {\n return this.endpoint;\n }\n\n constructor(options: FiveXXOptions) {\n this.apiKey = options.apiKey;\n this.endpoint = options.endpoint.replace(/\\/$/, \"\"); // Remove trailing slash\n this.environment = options.environment || \"production\";\n }\n\n /**\n * Set the environment (e.g., \"production\", \"development\", \"staging\")\n */\n setEnvironment(env: string): void {\n this.environment = env;\n }\n\n /**\n * Set user context for errors\n */\n setUser(user: User | null): void {\n this.user = user;\n }\n\n /**\n * Capture an error and send it to the 5xx server\n */\n async captureError(\n error: Error,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message: error.message || String(error),\n stack: error.stack,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Capture a message as an error\n */\n async captureMessage(\n message: string,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Send error payload to the server\n */\n private async send(payload: ErrorPayload): Promise<string | null> {\n try {\n const response = await fetch(`${this.endpoint}/api/errors`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n console.error(`5xx: Failed to send error (${response.status})`);\n return null;\n }\n\n const data = await response.json();\n return data.id;\n } catch (err) {\n console.error(\"5xx: Failed to send error\", err);\n return null;\n }\n }\n}\n"],"mappings":"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","names":[]}
package/dist/node.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FiveXXNode
3
- } from "./chunk-JCBAF7DF.mjs";
4
- import "./chunk-5YY5E33R.mjs";
3
+ } from "./chunk-762E5RVI.mjs";
4
+ import "./chunk-G4LKAXG5.mjs";
5
5
  export {
6
6
  FiveXXNode
7
7
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "5xx-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Lightweight error tracking SDK for JavaScript/TypeScript applications",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["import type { FiveXXOptions, ErrorPayload, User } from \"./types\";\n\nexport class FiveXX {\n private apiKey: string;\n private endpoint: string;\n private environment: string;\n private user: User | null = null;\n\n constructor(options: FiveXXOptions) {\n this.apiKey = options.apiKey;\n this.endpoint = options.endpoint.replace(/\\/$/, \"\"); // Remove trailing slash\n this.environment = options.environment || \"production\";\n }\n\n /**\n * Set the environment (e.g., \"production\", \"development\", \"staging\")\n */\n setEnvironment(env: string): void {\n this.environment = env;\n }\n\n /**\n * Set user context for errors\n */\n setUser(user: User | null): void {\n this.user = user;\n }\n\n /**\n * Capture an error and send it to the 5xx server\n */\n async captureError(\n error: Error,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message: error.message || String(error),\n stack: error.stack,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Capture a message as an error\n */\n async captureMessage(\n message: string,\n metadata?: Record<string, unknown>\n ): Promise<string | null> {\n const payload: ErrorPayload = {\n message,\n environment: this.environment,\n metadata: {\n ...metadata,\n ...(this.user && { user: this.user }),\n },\n };\n\n return this.send(payload);\n }\n\n /**\n * Send error payload to the server\n */\n private async send(payload: ErrorPayload): Promise<string | null> {\n try {\n const response = await fetch(`${this.endpoint}/api/errors`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": this.apiKey,\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n console.error(`5xx: Failed to send error (${response.status})`);\n return null;\n }\n\n const data = await response.json();\n return data.id;\n } catch (err) {\n console.error(\"5xx: Failed to send error\", err);\n return null;\n }\n }\n}\n"],"mappings":";AAEO,IAAM,SAAN,MAAa;AAAA,EAMlB,YAAY,SAAwB;AAFpC,SAAQ,OAAoB;AAG1B,SAAK,SAAS,QAAQ;AACtB,SAAK,WAAW,QAAQ,SAAS,QAAQ,OAAO,EAAE;AAClD,SAAK,cAAc,QAAQ,eAAe;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,KAAmB;AAChC,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,MAAyB;AAC/B,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aACJ,OACA,UACwB;AACxB,UAAM,UAAwB;AAAA,MAC5B,SAAS,MAAM,WAAW,OAAO,KAAK;AAAA,MACtC,OAAO,MAAM;AAAA,MACb,aAAa,KAAK;AAAA,MAClB,UAAU;AAAA,QACR,GAAG;AAAA,QACH,GAAI,KAAK,QAAQ,EAAE,MAAM,KAAK,KAAK;AAAA,MACrC;AAAA,IACF;AAEA,WAAO,KAAK,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eACJ,SACA,UACwB;AACxB,UAAM,UAAwB;AAAA,MAC5B;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,UAAU;AAAA,QACR,GAAG;AAAA,QACH,GAAI,KAAK,QAAQ,EAAE,MAAM,KAAK,KAAK;AAAA,MACrC;AAAA,IACF;AAEA,WAAO,KAAK,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,KAAK,SAA+C;AAChE,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,GAAG,KAAK,QAAQ,eAAe;AAAA,QAC1D,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,aAAa,KAAK;AAAA,QACpB;AAAA,QACA,MAAM,KAAK,UAAU,OAAO;AAAA,MAC9B,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,gBAAQ,MAAM,8BAA8B,SAAS,MAAM,GAAG;AAC9D,eAAO;AAAA,MACT;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO,KAAK;AAAA,IACd,SAAS,KAAK;AACZ,cAAQ,MAAM,6BAA6B,GAAG;AAC9C,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
@@ -1,84 +0,0 @@
1
- import {
2
- FiveXX
3
- } from "./chunk-5YY5E33R.mjs";
4
-
5
- // src/browser.ts
6
- var FiveXXBrowser = class extends FiveXX {
7
- constructor(options) {
8
- super(options);
9
- this.autoCapture = false;
10
- this.originalOnError = null;
11
- this.originalOnUnhandledRejection = null;
12
- if (typeof window !== "undefined" && !options.environment) {
13
- const hostname = window.location.hostname;
14
- if (hostname === "localhost" || hostname === "127.0.0.1") {
15
- this.setEnvironment("development");
16
- }
17
- }
18
- }
19
- /**
20
- * Enable automatic capture of unhandled errors and promise rejections
21
- */
22
- enableAutoCapture() {
23
- if (this.autoCapture || typeof window === "undefined") return;
24
- this.autoCapture = true;
25
- this.originalOnError = window.onerror;
26
- window.onerror = (message, source, lineno, colno, error) => {
27
- if (error) {
28
- this.captureError(error, {
29
- source,
30
- lineno,
31
- colno,
32
- url: window.location.href,
33
- userAgent: navigator.userAgent
34
- });
35
- } else {
36
- this.captureMessage(String(message), {
37
- source,
38
- lineno,
39
- colno,
40
- url: window.location.href,
41
- userAgent: navigator.userAgent
42
- });
43
- }
44
- if (this.originalOnError) {
45
- return this.originalOnError(message, source, lineno, colno, error);
46
- }
47
- return false;
48
- };
49
- this.originalOnUnhandledRejection = window.onunhandledrejection;
50
- window.onunhandledrejection = (event) => {
51
- const error = event.reason;
52
- if (error instanceof Error) {
53
- this.captureError(error, {
54
- type: "unhandledRejection",
55
- url: window.location.href,
56
- userAgent: navigator.userAgent
57
- });
58
- } else {
59
- this.captureMessage(String(error), {
60
- type: "unhandledRejection",
61
- url: window.location.href,
62
- userAgent: navigator.userAgent
63
- });
64
- }
65
- if (this.originalOnUnhandledRejection) {
66
- this.originalOnUnhandledRejection(event);
67
- }
68
- };
69
- }
70
- /**
71
- * Disable automatic capture
72
- */
73
- disableAutoCapture() {
74
- if (!this.autoCapture || typeof window === "undefined") return;
75
- this.autoCapture = false;
76
- window.onerror = this.originalOnError;
77
- window.onunhandledrejection = this.originalOnUnhandledRejection;
78
- }
79
- };
80
-
81
- export {
82
- FiveXXBrowser
83
- };
84
- //# sourceMappingURL=chunk-LD3XNYST.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/browser.ts"],"sourcesContent":["import { FiveXX } from \"./client\";\nimport type { FiveXXOptions } from \"./types\";\n\n/**\n * Browser-specific FiveXX client with automatic error capture\n */\nexport class FiveXXBrowser extends FiveXX {\n private autoCapture = false;\n private originalOnError: OnErrorEventHandler | null = null;\n private originalOnUnhandledRejection: ((event: PromiseRejectionEvent) => void) | null = null;\n\n constructor(options: FiveXXOptions) {\n super(options);\n\n // Auto-detect environment from URL\n if (typeof window !== \"undefined\" && !options.environment) {\n const hostname = window.location.hostname;\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\") {\n this.setEnvironment(\"development\");\n }\n }\n }\n\n /**\n * Enable automatic capture of unhandled errors and promise rejections\n */\n enableAutoCapture(): void {\n if (this.autoCapture || typeof window === \"undefined\") return;\n\n this.autoCapture = true;\n\n // Capture unhandled errors\n this.originalOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n this.captureError(error, {\n source,\n lineno,\n colno,\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n } else {\n this.captureMessage(String(message), {\n source,\n lineno,\n colno,\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n }\n\n // Call original handler if it exists\n if (this.originalOnError) {\n return this.originalOnError(message, source, lineno, colno, error);\n }\n return false;\n };\n\n // Capture unhandled promise rejections\n this.originalOnUnhandledRejection = window.onunhandledrejection;\n window.onunhandledrejection = (event) => {\n const error = event.reason;\n if (error instanceof Error) {\n this.captureError(error, {\n type: \"unhandledRejection\",\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n } else {\n this.captureMessage(String(error), {\n type: \"unhandledRejection\",\n url: window.location.href,\n userAgent: navigator.userAgent,\n });\n }\n\n if (this.originalOnUnhandledRejection) {\n this.originalOnUnhandledRejection(event);\n }\n };\n }\n\n /**\n * Disable automatic capture\n */\n disableAutoCapture(): void {\n if (!this.autoCapture || typeof window === \"undefined\") return;\n\n this.autoCapture = false;\n window.onerror = this.originalOnError;\n window.onunhandledrejection = this.originalOnUnhandledRejection;\n }\n}\n"],"mappings":";;;;;AAMO,IAAM,gBAAN,cAA4B,OAAO;AAAA,EAKxC,YAAY,SAAwB;AAClC,UAAM,OAAO;AALf,SAAQ,cAAc;AACtB,SAAQ,kBAA8C;AACtD,SAAQ,+BAAgF;AAMtF,QAAI,OAAO,WAAW,eAAe,CAAC,QAAQ,aAAa;AACzD,YAAM,WAAW,OAAO,SAAS;AACjC,UAAI,aAAa,eAAe,aAAa,aAAa;AACxD,aAAK,eAAe,aAAa;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB,QAAI,KAAK,eAAe,OAAO,WAAW,YAAa;AAEvD,SAAK,cAAc;AAGnB,SAAK,kBAAkB,OAAO;AAC9B,WAAO,UAAU,CAAC,SAAS,QAAQ,QAAQ,OAAO,UAAU;AAC1D,UAAI,OAAO;AACT,aAAK,aAAa,OAAO;AAAA,UACvB;AAAA,UACA;AAAA,UACA;AAAA,UACA,KAAK,OAAO,SAAS;AAAA,UACrB,WAAW,UAAU;AAAA,QACvB,CAAC;AAAA,MACH,OAAO;AACL,aAAK,eAAe,OAAO,OAAO,GAAG;AAAA,UACnC;AAAA,UACA;AAAA,UACA;AAAA,UACA,KAAK,OAAO,SAAS;AAAA,UACrB,WAAW,UAAU;AAAA,QACvB,CAAC;AAAA,MACH;AAGA,UAAI,KAAK,iBAAiB;AACxB,eAAO,KAAK,gBAAgB,SAAS,QAAQ,QAAQ,OAAO,KAAK;AAAA,MACnE;AACA,aAAO;AAAA,IACT;AAGA,SAAK,+BAA+B,OAAO;AAC3C,WAAO,uBAAuB,CAAC,UAAU;AACvC,YAAM,QAAQ,MAAM;AACpB,UAAI,iBAAiB,OAAO;AAC1B,aAAK,aAAa,OAAO;AAAA,UACvB,MAAM;AAAA,UACN,KAAK,OAAO,SAAS;AAAA,UACrB,WAAW,UAAU;AAAA,QACvB,CAAC;AAAA,MACH,OAAO;AACL,aAAK,eAAe,OAAO,KAAK,GAAG;AAAA,UACjC,MAAM;AAAA,UACN,KAAK,OAAO,SAAS;AAAA,UACrB,WAAW,UAAU;AAAA,QACvB,CAAC;AAAA,MACH;AAEA,UAAI,KAAK,8BAA8B;AACrC,aAAK,6BAA6B,KAAK;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBAA2B;AACzB,QAAI,CAAC,KAAK,eAAe,OAAO,WAAW,YAAa;AAExD,SAAK,cAAc;AACnB,WAAO,UAAU,KAAK;AACtB,WAAO,uBAAuB,KAAK;AAAA,EACrC;AACF;","names":[]}