@aj-2000-test/goodlogs-sdk 0.2.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,103 +1,5 @@
1
- type Severity = "debug" | "info" | "warn" | "error" | "fatal";
2
- interface GoodLogsOptions {
3
- /** API key (gl_sk_... for logs, gl_pk_... for events only) */
4
- apiKey: string;
5
- /** API endpoint (default: auto-resolved from API key region) */
6
- endpoint?: string;
7
- /** Flush interval in ms (default: 5000) */
8
- flushInterval?: number;
9
- /** Max batch size before auto-flush (default: 50) */
10
- batchSize?: number;
11
- /** Default context merged into every log/event */
12
- defaultContext?: Record<string, unknown>;
13
- /** Called on flush errors */
14
- onError?: (error: Error) => void;
15
- /** Disable SDK (useful for tests) */
16
- disabled?: boolean;
17
- /** Send SDK diagnostics to platform logs (default: true) */
18
- telemetry?: boolean;
19
- /** Auto-capture click events on elements with data-gl-event attribute (default: true in browser) */
20
- autocapture?: boolean;
21
- }
22
- interface LogEntry {
23
- severity: Severity;
24
- message: string;
25
- properties?: Record<string, unknown>;
26
- timestamp?: string;
27
- }
28
- interface EventEntry {
29
- event: string;
30
- distinctId?: string;
31
- properties?: Record<string, unknown>;
32
- timestamp?: string;
33
- }
34
-
35
- declare class GoodLogs {
36
- private apiKey;
37
- private endpoint;
38
- private flushInterval;
39
- private batchSize;
40
- private defaultContext;
41
- private onError;
42
- private disabled;
43
- private telemetry;
44
- private logBuffer;
45
- private eventBuffer;
46
- private timer;
47
- private visibilityHandler;
48
- private clickHandler;
49
- private lastPath;
50
- private anonymousId;
51
- private sessionId;
52
- constructor(options: GoodLogsOptions);
53
- log(severity: Severity, message: string, properties?: Record<string, unknown>): void;
54
- debug(message: string, properties?: Record<string, unknown>): void;
55
- info(message: string, properties?: Record<string, unknown>): void;
56
- warn(message: string, properties?: Record<string, unknown>): void;
57
- error(message: string, properties?: Record<string, unknown>): void;
58
- fatal(message: string, properties?: Record<string, unknown>): void;
59
- /** Set the user ID for all subsequent events. Replaces the anonymous ID. */
60
- identify(userId: string): void;
61
- /** Get the current anonymous/user ID. */
62
- getDistinctId(): string;
63
- /** Reset identity — generates a new anonymous ID (e.g., on logout). */
64
- reset(): void;
65
- /** Get the current session ID. */
66
- getSessionId(): string;
67
- /** Start a new session (e.g., on navigation reset). */
68
- newSession(): void;
69
- /** Set a specific session ID. */
70
- setSessionId(id: string): void;
71
- track(event: string, properties?: Record<string, unknown> & {
72
- distinctId?: string;
73
- }): void;
74
- flush(): Promise<void>;
75
- /** Flush remaining data and stop the timer */
76
- shutdown(): Promise<void>;
77
- private sendLogs;
78
- private sendEvents;
79
- private postWithRetry;
80
- private startTimer;
81
- private stopTimer;
82
- /**
83
- * In browsers: flush via fetch+keepalive when page goes hidden or closes.
84
- * keepalive lets the request complete even after the page unloads,
85
- * while still supporting custom headers (unlike sendBeacon).
86
- */
87
- private attachPageLifecycle;
88
- /** Auto-capture Core Web Vitals using PerformanceObserver */
89
- private captureWebVitals;
90
- /** Auto-capture page views on route changes (SPA-aware via History API) */
91
- private attachPageviewCapture;
92
- /** Auto-capture clicks on elements with text content or data-gl-event */
93
- private attachClickCapture;
94
- private detachClickCapture;
95
- private detachPageLifecycle;
96
- /** Fire-and-forget flush using fetch with keepalive — survives page unload */
97
- private keepaliveFlush;
98
- /** Fire-and-forget telemetry to platform logs. Never throws, never recurses. */
99
- private sendTelemetry;
100
- }
1
+ import { G as GoodLogs } from './client-w3t1Yzjd.js';
2
+ export { C as CaptureContext, E as ErrorBreadcrumb, a as ErrorEntry, b as ErrorFrame, c as EventEntry, d as GoodLogsOptions, L as LogEntry, S as Severity } from './client-w3t1Yzjd.js';
101
3
 
102
4
  interface LogRecord {
103
5
  id: number;
@@ -423,4 +325,154 @@ declare function resolveRegion(apiKey: string): string;
423
325
  /** Resolve API endpoint from key. User-provided endpoint always wins. */
424
326
  declare function resolveEndpoint(apiKey: string, userEndpoint?: string): string;
425
327
 
426
- export { type AiChatRequest, type AiChatResponse, type AiToolCall, type AlertRule, type CreateAlertRule, type CreateSlo, type EventEntry, GoodLogs, GoodLogsApiError, GoodLogsClient, type GoodLogsClientOptions, type GoodLogsOptions, type GqlAutocompleteResult, type GqlBatchResult, type GqlResult, type LogEntry, type LogRecord, type MuteAlertRequest, type Nl2GqlResult, type NotifyChannel, type ProjectInfo, REGION_URLS, type SchemaField, type SchemaResponse, type Severity, type SloDefinition, type TelemetryEvent, type TelemetryOptions, type UpdateAlertRule, type UpdateSlo, resolveEndpoint, resolveRegion, sendTelemetry };
328
+ /**
329
+ * Node.js framework adapters for GoodLogs tracing.
330
+ *
331
+ * Each adapter accepts a GoodLogs client instance and returns a middleware /
332
+ * plugin / interceptor that starts a span per incoming request and finishes
333
+ * it when the response is sent. Adapters are structurally typed — we don't
334
+ * depend on express / fastify / @nestjs/common at runtime.
335
+ *
336
+ * All adapters honour W3C traceparent in incoming headers so multi-service
337
+ * traces stitch together.
338
+ */
339
+
340
+ /** A subset of Express's req/res shape we actually touch. */
341
+ interface ExpressReq {
342
+ method?: string;
343
+ url?: string;
344
+ originalUrl?: string;
345
+ route?: {
346
+ path?: string;
347
+ };
348
+ headers?: Record<string, string | string[] | undefined>;
349
+ }
350
+ interface ExpressRes {
351
+ statusCode?: number;
352
+ on(event: "finish" | "close", cb: () => void): void;
353
+ }
354
+ type ExpressNext = (err?: unknown) => void;
355
+ /** A subset of Fastify's request/reply shape. */
356
+ interface FastifyRequest {
357
+ method?: string;
358
+ url?: string;
359
+ routerPath?: string;
360
+ routeOptions?: {
361
+ url?: string;
362
+ };
363
+ headers?: Record<string, string | string[] | undefined>;
364
+ }
365
+ interface FastifyReply {
366
+ statusCode?: number;
367
+ raw?: {
368
+ statusCode?: number;
369
+ };
370
+ }
371
+ interface FastifyInstance {
372
+ addHook(name: "onRequest", fn: (req: FastifyRequest, reply: FastifyReply, done: () => void) => void): void;
373
+ addHook(name: "onResponse", fn: (req: FastifyRequest, reply: FastifyReply, done: () => void) => void): void;
374
+ }
375
+ /** Parse a W3C traceparent header: 00-<trace 32>-<parent 16>-<flags 2>. */
376
+ declare function parseTraceparent(h: string | undefined | null): {
377
+ trace_id: string;
378
+ parent_span_id: string;
379
+ } | null;
380
+ /**
381
+ * Express / Connect / Restify-compatible middleware.
382
+ *
383
+ * Usage:
384
+ * import express from "express";
385
+ * import { goodlogsExpress, GoodLogs } from "@goodlogs/sdk";
386
+ * const gl = new GoodLogs({ apiKey: "...", useEnvelope: true });
387
+ * const app = express();
388
+ * app.use(goodlogsExpress(gl));
389
+ */
390
+ declare function goodlogsExpress(gl: GoodLogs): (req: ExpressReq, res: ExpressRes, next: ExpressNext) => void;
391
+ /**
392
+ * Fastify plugin. Registers onRequest + onResponse hooks.
393
+ *
394
+ * Usage:
395
+ * import Fastify from "fastify";
396
+ * import { goodlogsFastify, GoodLogs } from "@goodlogs/sdk";
397
+ * const gl = new GoodLogs({ apiKey: "...", useEnvelope: true });
398
+ * const app = Fastify();
399
+ * app.register(goodlogsFastify(gl));
400
+ */
401
+ declare function goodlogsFastify(gl: GoodLogs): (fastify: FastifyInstance, _opts: unknown, done: () => void) => void;
402
+ /**
403
+ * NestJS interceptor.
404
+ *
405
+ * Usage:
406
+ * import { Module } from "@nestjs/common";
407
+ * import { goodlogsNestInterceptor, GoodLogs } from "@goodlogs/sdk";
408
+ * const gl = new GoodLogs({ apiKey: "...", useEnvelope: true });
409
+ * @Module({
410
+ * providers: [{ provide: APP_INTERCEPTOR, useValue: goodlogsNestInterceptor(gl) }],
411
+ * })
412
+ * export class AppModule {}
413
+ *
414
+ * The returned value is shaped like a NestInterceptor (`intercept(ctx, next)`).
415
+ * `next.handle()` must return a stream-like with `pipe()` — we use a small
416
+ * adapter so we don't depend on rxjs.
417
+ */
418
+ interface NestExecutionContext {
419
+ switchToHttp(): {
420
+ getRequest(): ExpressReq;
421
+ getResponse(): ExpressRes;
422
+ };
423
+ }
424
+ interface NestCallHandler {
425
+ handle(): {
426
+ subscribe?(observer: {
427
+ next?: (v: unknown) => void;
428
+ error?: (e: unknown) => void;
429
+ complete?: () => void;
430
+ }): {
431
+ unsubscribe?: () => void;
432
+ };
433
+ pipe?(...args: unknown[]): unknown;
434
+ };
435
+ }
436
+ declare function goodlogsNestInterceptor(gl: GoodLogs): {
437
+ intercept(ctx: NestExecutionContext, next: NestCallHandler): {
438
+ subscribe?(observer: {
439
+ next?: (v: unknown) => void;
440
+ error?: (e: unknown) => void;
441
+ complete?: () => void;
442
+ }): {
443
+ unsubscribe?: () => void;
444
+ };
445
+ pipe?(...args: unknown[]): unknown;
446
+ } | {
447
+ unsubscribe: () => void | undefined;
448
+ };
449
+ };
450
+ /** Hook process.on("uncaughtException") and ("unhandledRejection") so
451
+ * uncaught failures become captureException entries before the process
452
+ * exits. Idempotent via a Symbol.for marker.
453
+ *
454
+ * Important: uncaughtException is, by design, *terminal*. Node will exit
455
+ * after our handler returns unless someone else also subscribed. We flush
456
+ * synchronously on a best-effort basis (gl.flush returns a Promise — we
457
+ * schedule a microtask via setImmediate to give the envelope POST a chance
458
+ * to land before Node tears down). */
459
+ declare function instrumentNodeProcess(gl: GoodLogs): void;
460
+
461
+ /**
462
+ * Patch Node's built-in `http` and `https` modules so every outgoing request
463
+ * becomes an `op:http.client` span and injects W3C traceparent. Mirrors what
464
+ * the browser SDK does for `fetch` automatically.
465
+ *
466
+ * Usage:
467
+ * import { instrumentNodeHttp, GoodLogs } from "@goodlogs/sdk";
468
+ * const gl = new GoodLogs({ apiKey: "...", useEnvelope: true });
469
+ * instrumentNodeHttp(gl); // call once on startup
470
+ *
471
+ * Idempotent: calling twice is a no-op.
472
+ */
473
+
474
+ declare function instrumentNodeHttp(gl: GoodLogs, opts?: {
475
+ endpoint?: string;
476
+ }): void;
477
+
478
+ export { type AiChatRequest, type AiChatResponse, type AiToolCall, type AlertRule, type CreateAlertRule, type CreateSlo, GoodLogs, GoodLogsApiError, GoodLogsClient, type GoodLogsClientOptions, type GqlAutocompleteResult, type GqlBatchResult, type GqlResult, type LogRecord, type MuteAlertRequest, type Nl2GqlResult, type NotifyChannel, type ProjectInfo, REGION_URLS, type SchemaField, type SchemaResponse, type SloDefinition, type TelemetryEvent, type TelemetryOptions, type UpdateAlertRule, type UpdateSlo, goodlogsExpress, goodlogsFastify, goodlogsNestInterceptor, instrumentNodeHttp, instrumentNodeProcess, parseTraceparent, resolveEndpoint, resolveRegion, sendTelemetry };
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
- var m={us:"https://goodlogs-api-us.happyhill-a7c56143.centralindia.azurecontainerapps.io",eu:"https://goodlogs-api-eu.yellowmeadow-422296f6.japaneast.azurecontainerapps.io",ap:"https://goodlogs-api-ap.delightfulsand-90b72c09.southeastasia.azurecontainerapps.io"};function _(r){let e=r.split("_");return e.length>=4&&e[0]==="gl"?e[2]:"eu"}function d(r,e){if(e)return e;let t=_(r);return m[t]||m.eu}var R=5e3,I=50,u="0.2.2",h="gl_anon_id",g="gl_session_id";function c(){return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{let e=Math.random()*16|0;return (r==="x"?e:e&3|8).toString(16)})}function $(){let r={$goodlogs_sdk:"js",$goodlogs_sdk_version:u};return typeof navigator>"u"||(typeof screen<"u"&&(r.$screen=`${screen.width}x${screen.height}`),typeof navigator<"u"&&(r.$language=navigator.language??""),typeof location<"u"&&(r.$url=location.href,r.$path=location.pathname,r.$page=location.pathname.split("/").filter(Boolean).pop()||"/"),typeof document<"u"&&(document.referrer&&(r.$referrer=document.referrer),document.title&&(r.$title=document.title))),r}function P(r,e){let t={$session_id:r,$distinct_id:e,$goodlogs_sdk:"js",$goodlogs_sdk_version:u};return typeof navigator>"u"||typeof location<"u"&&(t.$url=location.href,t.$path=location.pathname),t}function x(){if(!(typeof document<"u"))try{let e=new Error().stack?.split(`
2
- `);if(!e)return;for(let t=3;t<Math.min(e.length,8);t++){let n=e[t]?.trim();if(!n||n.includes("goodlogs")&&(n.includes("client.")||n.includes("index.")))continue;let i=n.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):\d+\)?/);if(i){let o=i[1]||"<anonymous>",s=i[2]?.replace(/^.*[/\\]/,"")??"",a=i[3];return `${o}@${s}:${a}`}}}catch{}}function T(){if(typeof localStorage<"u"){let r=localStorage.getItem(h);if(r)return r;let e=c();return localStorage.setItem(h,e),e}return c()}function A(){if(typeof sessionStorage<"u"){let r=sessionStorage.getItem(g);if(r)return r;let e=c();return sessionStorage.setItem(g,e),e}return c()}var v=class{constructor(e){this.logBuffer=[];this.eventBuffer=[];this.timer=null;this.visibilityHandler=null;this.clickHandler=null;this.lastPath="";this.apiKey=e.apiKey,this.endpoint=d(e.apiKey,e.endpoint).replace(/\/+$/,""),this.flushInterval=e.flushInterval??R,this.batchSize=e.batchSize??I,this.defaultContext=e.defaultContext??{},this.onError=e.onError??(()=>{}),this.disabled=e.disabled??false,this.telemetry=e.telemetry??true,this.anonymousId=T(),this.sessionId=A(),this.disabled&&typeof console<"u"&&console.warn("[GoodLogs] SDK is disabled. No events or logs will be sent."),this.disabled||(this.startTimer(),this.attachPageLifecycle(),e.autocapture!==false&&(this.attachClickCapture(),this.captureWebVitals(),this.attachPageviewCapture()),this.sendTelemetry("init","info"));}log(e,t,n){if(this.disabled)return;let i=65536,o=t;t.length>i&&(o=t.slice(0,i-100)+`
1
+ var S=(o=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(o,{get:(t,e)=>(typeof require<"u"?require:t)[e]}):o)(function(o){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+o+'" is not supported')});var I={us:"https://goodlogs-api-us.happyhill-a7c56143.centralindia.azurecontainerapps.io",eu:"https://goodlogs-api-eu.yellowmeadow-422296f6.japaneast.azurecontainerapps.io",ap:"https://goodlogs-api-ap.delightfulsand-90b72c09.southeastasia.azurecontainerapps.io"};function B(o){let t=o.split("_");return t.length>=4&&t[0]==="gl"?t[2]:"eu"}function y(o,t){if(t)return t;let e=B(o);return I[e]||I.eu}var G=5e3,F=50,v="0.3.1",w="gl_anon_id",_="gl_session_id";function b(){return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,o=>{let t=Math.random()*16|0;return (o==="x"?t:t&3|8).toString(16)})}function M(){let o={$goodlogs_sdk:"js",$goodlogs_sdk_version:v};return typeof navigator>"u"||(typeof screen<"u"&&(o.$screen=`${screen.width}x${screen.height}`),typeof navigator<"u"&&(o.$language=navigator.language??""),typeof location<"u"&&(o.$url=location.href,o.$path=location.pathname,o.$page=location.pathname.split("/").filter(Boolean).pop()||"/"),typeof document<"u"&&(document.referrer&&(o.$referrer=document.referrer),document.title&&(o.$title=document.title))),o}function U(o,t){let e={$session_id:o,$distinct_id:t,$goodlogs_sdk:"js",$goodlogs_sdk_version:v};return typeof navigator>"u"||typeof location<"u"&&(e.$url=location.href,e.$path=location.pathname),e}function D(){if(!(typeof document<"u"))try{let t=new Error().stack?.split(`
2
+ `);if(!t)return;for(let e=3;e<Math.min(t.length,8);e++){let n=t[e]?.trim();if(!n||n.includes("goodlogs")&&(n.includes("client.")||n.includes("index.")))continue;let r=n.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):\d+\)?/);if(r){let s=r[1]||"<anonymous>",i=r[2]?.replace(/^.*[/\\]/,"")??"",d=r[3];return `${s}@${i}:${d}`}}}catch{}}function K(){if(typeof localStorage<"u"){let o=localStorage.getItem(w);if(o)return o;let t=b();return localStorage.setItem(w,t),t}return b()}function X(){if(typeof sessionStorage<"u"){let o=sessionStorage.getItem(_);if(o)return o;let t=b();return sessionStorage.setItem(_,t),t}return b()}function z(){let o="";for(let t=0;t<32;t++)o+=(Math.random()*16|0).toString(16);return o}function V(){let o="";for(let t=0;t<16;t++)o+=(Math.random()*16|0).toString(16);return o}function W(o,t){switch(o){case "lcp":return t<=2500?"good":t<=4e3?"needs-improvement":"poor";case "inp":return t<=200?"good":t<=500?"needs-improvement":"poor";case "cls":return t<=.1?"good":t<=.25?"needs-improvement":"poor";case "fcp":return t<=1800?"good":t<=3e3?"needs-improvement":"poor";case "ttfb":return t<=800?"good":t<=1800?"needs-improvement":"poor";default:return}}function J(o){if(!o)return [];let t=[];for(let e of o.split(`
3
+ `)){let n=e.trim();if(!n||n.startsWith("Error")||n.startsWith("at Error"))continue;let r=/^at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/.exec(n);if(r){let s=r[1]?.trim(),i=r[2];t.push({function:s&&s!=="<anonymous>"?s:void 0,filename:i,lineno:Number(r[3]),colno:Number(r[4]),abs_path:i,in_app:!i.includes("node_modules/")&&!i.includes("/dist/")&&!i.startsWith("internal/")});continue}if(r=/^([^@]*)@(.+?):(\d+):(\d+)$/.exec(n),r){let s=r[1]?.trim(),i=r[2];t.push({function:s||void 0,filename:i,lineno:Number(r[3]),colno:Number(r[4]),abs_path:i,in_app:!i.includes("node_modules/")&&!i.includes("/dist/")});}}return t}var R=class R{constructor(t){this.originalFetch=null;this.xhrPatched=false;this.logBuffer=[];this.eventBuffer=[];this.errorBuffer=[];this.vitalBuffer=[];this.spanBuffer=[];this.breadcrumbBuffer=[];this.timer=null;this.visibilityHandler=null;this.clickHandler=null;this.lastPath="";this.navTransaction=null;this.errorHandler=null;this.rejectionHandler=null;this.apiKey=t.apiKey,this.endpoint=y(t.apiKey,t.endpoint).replace(/\/+$/,""),this.flushInterval=t.flushInterval??G,this.batchSize=t.batchSize??F,this.defaultContext=t.defaultContext??{},this.onError=t.onError??(()=>{}),this.disabled=t.disabled??false,this.telemetry=t.telemetry??true,this.useEnvelope=t.useEnvelope??false,this.autoFetch=t.autoFetch??(this.useEnvelope&&t.autocapture!==false),this.anonymousId=K(),this.sessionId=X(),this.disabled&&typeof console<"u"&&console.warn("[GoodLogs] SDK is disabled. No events or logs will be sent."),this.disabled||(this.startTimer(),this.attachPageLifecycle(),t.autocapture!==false&&(this.attachClickCapture(),this.captureWebVitals(),this.attachPageviewCapture(),this.attachGlobalErrorHandlers()),this.autoFetch&&(this.attachFetchInstrumentation(),this.attachXhrInstrumentation()),this.sendTelemetry("init","info"));}log(t,e,n){if(this.disabled)return;let r=65536,s=e;e.length>r&&(s=e.slice(0,r-100)+`
3
4
 
4
- [truncated \u2014 original ${t.length} chars, limit ${i}]`,this.onError(new Error(`Log message truncated from ${t.length} to ${i} chars`)));let s=x(),a={severity:e,message:o,properties:{...this.defaultContext,...P(this.sessionId,this.anonymousId),...s?{code_location:s}:{},...n},timestamp:new Date().toISOString()};this.logBuffer.push(a),this.logBuffer.length>=this.batchSize&&this.flush();}debug(e,t){this.log("debug",e,t);}info(e,t){this.log("info",e,t);}warn(e,t){this.log("warn",e,t);}error(e,t){this.log("error",e,t);}fatal(e,t){this.log("fatal",e,t);}identify(e){this.anonymousId=e,typeof localStorage<"u"&&localStorage.setItem(h,e);}getDistinctId(){return this.anonymousId}reset(){this.anonymousId=c(),this.sessionId=c(),typeof localStorage<"u"&&localStorage.setItem(h,this.anonymousId),typeof sessionStorage<"u"&&sessionStorage.setItem(g,this.sessionId);}getSessionId(){return this.sessionId}newSession(){this.sessionId=c(),typeof sessionStorage<"u"&&sessionStorage.setItem(g,this.sessionId);}setSessionId(e){this.sessionId=e,typeof sessionStorage<"u"&&sessionStorage.setItem(g,e);}track(e,t){if(this.disabled)return;let{distinctId:n,...i}=t??{},o={event:e,distinctId:n??this.anonymousId,properties:{...$(),...i,$session_id:this.sessionId},timestamp:new Date().toISOString()};this.eventBuffer.push(o),this.eventBuffer.length>=this.batchSize&&this.flush();}async flush(){let e=this.logBuffer.splice(0),t=this.eventBuffer.splice(0),n=[];e.length>0&&n.push(this.sendLogs(e)),t.length>0&&n.push(this.sendEvents(t)),await Promise.all(n);}async shutdown(){this.stopTimer(),this.detachPageLifecycle(),this.detachClickCapture(),await this.flush();}async sendLogs(e){for(let n=0;n<e.length;n+=500){let o=e.slice(n,n+500).map(s=>({severity:s.severity,message:s.message,properties:s.properties,timestamp:s.timestamp}));await this.postWithRetry("/v1/logs",o,s=>{for(let a of s)this.logBuffer.push({severity:a.severity,message:a.message,properties:a.properties,timestamp:a.timestamp});});}}async sendEvents(e){for(let n=0;n<e.length;n+=500){let o=e.slice(n,n+500).map(s=>({event:s.event,distinctId:s.distinctId,properties:s.properties,timestamp:s.timestamp}));await this.postWithRetry("/v1/events",o,s=>{for(let a of s)this.eventBuffer.push({event:a.event,distinctId:a.distinctId,properties:a.properties,timestamp:a.timestamp});});}}async postWithRetry(e,t,n,i=0){try{let o=await fetch(`${this.endpoint}${e}`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"X-GoodLogs-SDK":`js/${u}`},body:JSON.stringify({batch:t})});if(o.status===429||o.status===503){if(i<4){let a=Math.min(1e3*Math.pow(2,i),8e3),l=Math.random()*500;return await new Promise(p=>setTimeout(p,a+l)),this.postWithRetry(e,t,n,i+1)}this.onError(new Error(`GoodLogs rate limited after ${i} retries`));return}if(!o.ok){let a=await o.text().catch(()=>""),l=new Error(`GoodLogs API error ${o.status}: ${a}`);this.onError(l),o.status>=500&&i===0&&n(t);return}let s=await o.json().catch(()=>null);if(s&&s.rejected&&s.rejected>0){let a=t.slice(s.accepted??0);a.length>0&&n(a);}}catch(o){let s=o instanceof Error?o:new Error(String(o));i===0&&n(t),this.onError(s);}}startTimer(){this.timer=setInterval(()=>{this.flush();},this.flushInterval);let e=this.timer;typeof e?.unref=="function"&&e.unref();}stopTimer(){this.timer!==null&&(clearInterval(this.timer),this.timer=null);}attachPageLifecycle(){typeof document>"u"||(this.visibilityHandler=()=>{document.visibilityState==="hidden"&&this.keepaliveFlush();},document.addEventListener("visibilitychange",this.visibilityHandler));}captureWebVitals(){if(!(typeof PerformanceObserver>"u")){try{new PerformanceObserver(e=>{let t=e.getEntries()[0];t&&this.track("$web_vital",{properties:{$metric:"FCP",$value_ms:Math.round(t.startTime)}});}).observe({type:"paint",buffered:!0});}catch{}try{new PerformanceObserver(e=>{let t=e.getEntries(),n=t[t.length-1];n&&this.track("$web_vital",{properties:{$metric:"LCP",$value_ms:Math.round(n.startTime)}});}).observe({type:"largest-contentful-paint",buffered:!0});}catch{}try{let e=0;if(new PerformanceObserver(t=>{for(let n of t.getEntries())n.hadRecentInput||(e+=n.value);}).observe({type:"layout-shift",buffered:!0}),typeof document<"u"){let t=()=>{e>0&&this.track("$web_vital",{properties:{$metric:"CLS",$value:Math.round(e*1e3)/1e3}});};document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&t();});}}catch{}try{if(typeof performance<"u"){let e=performance.getEntriesByType?.("navigation")?.[0];e?.responseStart&&this.track("$web_vital",{properties:{$metric:"TTFB",$value_ms:Math.round(e.responseStart)}});}}catch{}try{new PerformanceObserver(e=>{for(let t of e.getEntries()){let n=t.duration;n>0&&this.track("$web_vital",{properties:{$metric:"INP",$value_ms:Math.round(n)}});}}).observe({type:"event",buffered:!0});}catch{}}}attachPageviewCapture(){if(typeof document>"u"||typeof location>"u")return;this.lastPath=location.pathname,this.track("$pageview");let e=()=>{typeof location<"u"&&location.pathname!==this.lastPath&&(this.lastPath=location.pathname,this.track("$pageview"));};if(typeof history<"u"){let t=history.pushState,n=history.replaceState;history.pushState=function(...i){t.apply(this,i),e();},history.replaceState=function(...i){n.apply(this,i),e();};}typeof addEventListener<"u"&&addEventListener("popstate",e);}attachClickCapture(){typeof document>"u"||(this.clickHandler=e=>{let n=e.target?.closest?.("a, button, [data-gl-event], [role='button']");if(!n)return;let i=n.getAttribute?.("data-gl-event"),o=n.tagName?.toLowerCase()??"",s=(n.textContent??"").trim().slice(0,50),a=n.getAttribute?.("href")??void 0,l=(n.className??"").toString().slice(0,80);this.track(i||"$click",{properties:{$element_tag:o,$element_text:s||void 0,$element_href:a,$element_classes:l||void 0}});},document.addEventListener("click",this.clickHandler));}detachClickCapture(){this.clickHandler&&typeof document<"u"&&(document.removeEventListener("click",this.clickHandler),this.clickHandler=null);}detachPageLifecycle(){this.visibilityHandler&&typeof document<"u"&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null);}keepaliveFlush(){let e=this.logBuffer.splice(0),t=this.eventBuffer.splice(0),n={"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"X-GoodLogs-SDK":`js/${u}`};e.length>0&&fetch(`${this.endpoint}/v1/logs`,{method:"POST",headers:n,body:JSON.stringify({batch:e.map(i=>({severity:i.severity,message:i.message,properties:i.properties,timestamp:i.timestamp}))}),keepalive:true}).catch(()=>{}),t.length>0&&fetch(`${this.endpoint}/v1/events`,{method:"POST",headers:n,body:JSON.stringify({batch:t.map(i=>({event:i.event,distinctId:i.distinctId,properties:i.properties,timestamp:i.timestamp}))}),keepalive:true}).catch(()=>{});}sendTelemetry(e,t,n){!this.telemetry||this.disabled||fetch(`${this.endpoint}/v1/telemetry`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"X-GoodLogs-SDK":`js/${u}`},body:JSON.stringify({source:"sdk",event:e,level:t,metadata:{...n,sdk_version:u}}),keepalive:true}).catch(()=>{});}};var y=class{constructor(e){if(!e.apiKey)throw new Error("apiKey is required");if(!e.apiKey.startsWith("gl_sk_"))throw new Error("GoodLogsClient requires a secret API key (gl_sk_...)");this.apiKey=e.apiKey,this.endpoint=d(e.apiKey,e.endpoint),this.timeout=e.timeout??3e4,this.alerts=new b(this),this.slos=new S(this),this.ai=new k(this);}async _request(e,t,n){let i=`${this.endpoint}${t}`,o={Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},s=new AbortController,a=setTimeout(()=>s.abort(),this.timeout);try{let l=await fetch(i,{method:e,headers:o,body:n?JSON.stringify(n):void 0,signal:s.signal});if(!l.ok){let p=await l.json().catch(()=>({})),E=p?.error?.message??`API error ${l.status}`;throw new f(l.status,E,p?.error?.code)}return l.status===204?void 0:await l.json()}finally{clearTimeout(a);}}_get(e){return this._request("GET",e)}_post(e,t){return this._request("POST",e,t)}_put(e,t){return this._request("PUT",e,t)}_delete(e){return this._request("DELETE",e)}info(){return this._get("/v1/info")}schema(){return this._get("/v1/schema")}gql(e){return this._post("/v1/gql/query",{q:e})}gqlBatch(e){return this._post("/v1/gql",{queries:e})}gqlAutocomplete(e,t){let n=`/v1/gql/autocomplete?q=${encodeURIComponent(e)}`;return t!==void 0&&(n+=`&cursor=${t}`),this._get(n)}nl2gql(e,t){return this._post("/v1/gql/nl",{prompt:e,mode:t})}},b=class{constructor(e){this.client=e;}list(){return this.client._get("/v1/alerts")}create(e){return this.client._post("/v1/alerts",e)}update(e,t){return this.client._put(`/v1/alerts/${e}`,t)}delete(e){return this.client._delete(`/v1/alerts/${e}`)}mute(e,t){return this.client._post(`/v1/alerts/${e}/mute`,{minutes:t})}},S=class{constructor(e){this.client=e;}list(){return this.client._get("/v1/slos")}create(e){return this.client._post("/v1/slos",e)}update(e,t){return this.client._put(`/v1/slos/${e}`,t)}delete(e){return this.client._delete(`/v1/slos/${e}`)}},k=class{constructor(e){this.client=e;}chat(e,t){return this.client._post("/v1/ai/chat",{message:e,session_id:t})}},f=class extends Error{constructor(t,n,i){super(n);this.status=t;this.code=i;this.name="GoodLogsApiError";}};var w="0.1.0";function C(r,e){let t=d(e?.apiKey??"",e?.endpoint).replace(/\/+$/,""),n={"Content-Type":"application/json","X-GoodLogs-SDK":w};e?.token&&(n.Authorization=`Bearer ${e.token}`),fetch(`${t}/v1/telemetry`,{method:"POST",headers:n,body:JSON.stringify({source:r.source,event:r.event,level:r.level??"info",metadata:{...r.metadata,sdk_version:w}}),keepalive:true}).catch(()=>{});}export{v as GoodLogs,f as GoodLogsApiError,y as GoodLogsClient,m as REGION_URLS,d as resolveEndpoint,_ as resolveRegion,C as sendTelemetry};
5
+ [truncated \u2014 original ${e.length} chars, limit ${r}]`,this.onError(new Error(`Log message truncated from ${e.length} to ${r} chars`)));let i=D(),d={severity:t,message:s,properties:{...this.defaultContext,...U(this.sessionId,this.anonymousId),...i?{code_location:i}:{},...n},timestamp:new Date().toISOString()};this.logBuffer.push(d),this.logBuffer.length>=this.batchSize&&this.flush();}debug(t,e){this.log("debug",t,e);}info(t,e){this.log("info",t,e);}warn(t,e){this.log("warn",t,e);}error(t,e){this.log("error",t,e);}fatal(t,e){this.log("fatal",t,e);}identify(t){this.anonymousId=t,typeof localStorage<"u"&&localStorage.setItem(w,t);}getDistinctId(){return this.anonymousId}reset(){this.anonymousId=b(),this.sessionId=b(),typeof localStorage<"u"&&localStorage.setItem(w,this.anonymousId),typeof sessionStorage<"u"&&sessionStorage.setItem(_,this.sessionId);}getSessionId(){return this.sessionId}newSession(){this.sessionId=b(),typeof sessionStorage<"u"&&sessionStorage.setItem(_,this.sessionId);}setSessionId(t){this.sessionId=t,typeof sessionStorage<"u"&&sessionStorage.setItem(_,t);}track(t,e){if(this.disabled)return;let{distinctId:n,...r}=e??{},s={event:t,distinctId:n??this.anonymousId,properties:{...M(),...r,$session_id:this.sessionId},timestamp:new Date().toISOString()};this.eventBuffer.push(s),this.eventBuffer.length>=this.batchSize&&this.flush();}addBreadcrumb(t){if(this.disabled)return;let e={ts:t.ts??new Date().toISOString(),...t};this.breadcrumbBuffer.push(e),this.breadcrumbBuffer.length>R.MAX_BREADCRUMBS&&this.breadcrumbBuffer.shift();}captureException(t,e){if(this.disabled)return;let n=this.buildErrorEntry(t,e);this.useEnvelope?(this.errorBuffer.push(n),this.errorBuffer.length>=this.batchSize&&this.flush()):this.error(n.message,{exception_type:n.exception_type,frames:n.frames});}captureMessage(t,e){if(this.disabled)return;let n={level:e?.level??"info",message:t,platform:typeof document<"u"?"browser":"node",frames:[],breadcrumbs:this.breadcrumbBuffer.slice(),fingerprint:e?.fingerprint,tags:e?.tags,extra:e?.extra,user_id:e?.user_id??this.anonymousId,timestamp:new Date().toISOString()};this.useEnvelope?(this.errorBuffer.push(n),this.errorBuffer.length>=this.batchSize&&this.flush()):this.warn(t);}buildErrorEntry(t,e){let n,r,s=[];if(t instanceof Error)n=t.name,r=t.message,s=J(t.stack);else if(typeof t=="string")r=t;else try{r=JSON.stringify(t);}catch{r=String(t);}return {level:e?.level??"error",platform:typeof document<"u"?"browser":"node",exception_type:n,message:r,frames:s,breadcrumbs:this.breadcrumbBuffer.slice(),fingerprint:e?.fingerprint,tags:e?.tags,extra:e?.extra,user_id:e?.user_id??this.anonymousId,timestamp:new Date().toISOString(),trace_id:this.navTransaction?.trace_id,span_id:this.navTransaction?.span_id}}captureVital(t,e,n){if(this.disabled||!Number.isFinite(e)||e<0)return;let r=n?.rating??W(t,e),s={metric:t,value_ms:t==="cls"?e:Math.round(e),rating:r,route:n?.route??(typeof location<"u"?location.pathname:void 0),page_url:typeof location<"u"?location.href:void 0,session_id:this.sessionId,user_id:this.anonymousId,attributes:n?.attributes,timestamp:new Date().toISOString()};this.useEnvelope?(this.vitalBuffer.push(s),this.vitalBuffer.length>=this.batchSize&&this.flush()):this.track("$web_vital",{properties:{$metric:t.toUpperCase(),$value_ms:s.value_ms,$rating:r}});}startTransaction(t){return this.makeSpan(void 0,t)}startSpan(t){return this.makeSpan(void 0,t)}makeSpan(t,e){let n=e?.trace_id??e?.parent?.trace_id??t?.trace_id??z(),r=V(),s=e?.parent?.span_id??t?.span_id,i=Date.now(),d=new Date(i).toISOString(),a={...e?.attributes??{}},c="unset",u=[],h=false,f=this,g={span_id:r,trace_id:n,setAttribute(p,l){a[p]=l;},setStatus(p){c=p;},addEvent(p,l){u.push({ts:new Date().toISOString(),name:p,attributes:l});},startChild(p){return f.makeSpan(g,p)},finish(){if(h)return;h=true;let p=Date.now(),l={span_id:r,trace_id:n,parent_span_id:s,name:e?.name,op:e?.op,status:c==="unset"?"ok":c,kind:e?.kind,attributes:a,events:u,start_time:d,end_time:new Date(p).toISOString(),timestamp:d,duration_ms:p-i};f.useEnvelope&&(f.spanBuffer.push(l),f.spanBuffer.length>=f.batchSize&&f.flush());}};return g}async flush(){let t=this.logBuffer.splice(0),e=this.eventBuffer.splice(0),n=this.errorBuffer.splice(0),r=this.vitalBuffer.splice(0),s=this.spanBuffer.splice(0),i=[];this.useEnvelope?(t.length>0||e.length>0||n.length>0||r.length>0||s.length>0)&&i.push(this.sendEnvelope(t,e,n,r,s)):(t.length>0&&i.push(this.sendLogs(t)),e.length>0&&i.push(this.sendEvents(e))),await Promise.all(i);}async shutdown(){this.stopTimer(),this.detachPageLifecycle(),this.detachClickCapture(),this.detachFetchInstrumentation(),this.detachXhrInstrumentation(),this.detachGlobalErrorHandlers(),this.navTransaction&&(this.navTransaction.finish(),this.navTransaction=null),await this.flush();}async sendLogs(t){for(let n=0;n<t.length;n+=500){let s=t.slice(n,n+500).map(i=>({severity:i.severity,message:i.message,properties:i.properties,timestamp:i.timestamp}));await this.postWithRetry("/v1/logs",s,i=>{for(let d of i)this.logBuffer.push({severity:d.severity,message:d.message,properties:d.properties,timestamp:d.timestamp});});}}async sendEvents(t){for(let n=0;n<t.length;n+=500){let s=t.slice(n,n+500).map(i=>({event:i.event,distinctId:i.distinctId,properties:i.properties,timestamp:i.timestamp}));await this.postWithRetry("/v1/events",s,i=>{for(let d of i)this.eventBuffer.push({event:d.event,distinctId:d.distinctId,properties:d.properties,timestamp:d.timestamp});});}}async sendEnvelope(t,e,n,r,s){let d=[...t.map(a=>({kind:"log",entry:a})),...e.map(a=>({kind:"event",entry:a})),...n.map(a=>({kind:"error",entry:a})),...r.map(a=>({kind:"vital",entry:a})),...s.map(a=>({kind:"span",entry:a}))];for(let a=0;a<d.length;a+=1e3){let c=d.slice(a,a+1e3),u=JSON.stringify({v:1,sdk:`js@${v}`,sent_at:new Date().toISOString()}),h=c.map(g=>{if(g.kind==="log"){let l=g.entry;return JSON.stringify({type:"log",severity:l.severity,message:l.message,properties:l.properties,timestamp:l.timestamp})}if(g.kind==="event"){let l=g.entry;return JSON.stringify({type:"event",event:l.event,distinctId:l.distinctId,properties:l.properties,timestamp:l.timestamp})}if(g.kind==="error"){let l=g.entry;return JSON.stringify({type:"error",...l})}if(g.kind==="vital"){let l=g.entry;return JSON.stringify({type:"vital",...l})}let p=g.entry;return JSON.stringify({type:"span",...p})}),f=[u,...h].join(`
6
+ `);await this.postEnvelopeWithRetry(f,c);}}async postEnvelopeWithRetry(t,e,n=0){try{let r=await fetch(`${this.endpoint}/v1/envelope`,{method:"POST",headers:{"Content-Type":"application/x-goodlogs-envelope+ndjson",Authorization:`Bearer ${this.apiKey}`,"X-GoodLogs-SDK":`js/${v}`},body:t});if(r.status===429||r.status===503){if(n<4){let s=Math.min(1e3*Math.pow(2,n),8e3),i=Math.random()*500;return await new Promise(d=>setTimeout(d,s+i)),this.postEnvelopeWithRetry(t,e,n+1)}this.onError(new Error(`GoodLogs rate limited after ${n} retries`));return}if(!r.ok){let s=await r.text().catch(()=>"");if(this.onError(new Error(`GoodLogs envelope error ${r.status}: ${s}`)),r.status>=500&&n===0)for(let i of e)i.kind==="log"?this.logBuffer.push(i.entry):i.kind==="event"?this.eventBuffer.push(i.entry):i.kind==="error"?this.errorBuffer.push(i.entry):i.kind==="vital"?this.vitalBuffer.push(i.entry):this.spanBuffer.push(i.entry);}}catch(r){if(n===0)for(let s of e)s.kind==="log"?this.logBuffer.push(s.entry):s.kind==="event"?this.eventBuffer.push(s.entry):s.kind==="error"?this.errorBuffer.push(s.entry):s.kind==="vital"?this.vitalBuffer.push(s.entry):this.spanBuffer.push(s.entry);this.onError(r instanceof Error?r:new Error(String(r)));}}async postWithRetry(t,e,n,r=0){try{let s=await fetch(`${this.endpoint}${t}`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"X-GoodLogs-SDK":`js/${v}`},body:JSON.stringify({batch:e})});if(s.status===429||s.status===503){if(r<4){let d=Math.min(1e3*Math.pow(2,r),8e3),a=Math.random()*500;return await new Promise(c=>setTimeout(c,d+a)),this.postWithRetry(t,e,n,r+1)}this.onError(new Error(`GoodLogs rate limited after ${r} retries`));return}if(!s.ok){let d=await s.text().catch(()=>""),a=new Error(`GoodLogs API error ${s.status}: ${d}`);this.onError(a),s.status>=500&&r===0&&n(e);return}let i=await s.json().catch(()=>null);if(i&&i.rejected&&i.rejected>0){let d=e.slice(i.accepted??0);d.length>0&&n(d);}}catch(s){let i=s instanceof Error?s:new Error(String(s));r===0&&n(e),this.onError(i);}}startTimer(){this.timer=setInterval(()=>{this.flush();},this.flushInterval);let t=this.timer;typeof t?.unref=="function"&&t.unref();}stopTimer(){this.timer!==null&&(clearInterval(this.timer),this.timer=null);}attachPageLifecycle(){typeof document>"u"||(this.visibilityHandler=()=>{document.visibilityState==="hidden"&&this.keepaliveFlush();},document.addEventListener("visibilitychange",this.visibilityHandler));}captureWebVitals(){if(typeof PerformanceObserver>"u")return;let t=(e,n)=>{if(this.useEnvelope)this.captureVital(e.toLowerCase(),n);else {let r=e==="CLS"?"$value":"$value_ms";this.track("$web_vital",{properties:{$metric:e,[r]:e==="CLS"?n:Math.round(n)}});}};try{new PerformanceObserver(e=>{let n=e.getEntries()[0];n&&t("FCP",n.startTime);}).observe({type:"paint",buffered:!0});}catch{}try{new PerformanceObserver(e=>{let n=e.getEntries(),r=n[n.length-1];r&&t("LCP",r.startTime);}).observe({type:"largest-contentful-paint",buffered:!0});}catch{}try{let e=0;if(new PerformanceObserver(n=>{for(let r of n.getEntries())r.hadRecentInput||(e+=r.value);}).observe({type:"layout-shift",buffered:!0}),typeof document<"u"){let n=()=>{e>0&&t("CLS",Math.round(e*1e3)/1e3);};document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&n();});}}catch{}try{if(typeof performance<"u"){let e=performance.getEntriesByType?.("navigation")?.[0];e?.responseStart&&t("TTFB",e.responseStart);}}catch{}try{new PerformanceObserver(e=>{for(let n of e.getEntries()){let r=n.duration;r>0&&t("INP",r);}}).observe({type:"event",buffered:!0});}catch{}}attachPageviewCapture(){if(typeof document>"u"||typeof location>"u")return;this.lastPath=location.pathname,this.track("$pageview"),this.startNavTransaction(this.lastPath,"initial");let t=(e="push")=>{typeof location<"u"&&location.pathname!==this.lastPath&&(this.lastPath=location.pathname,this.track("$pageview"),this.startNavTransaction(this.lastPath,e));};if(typeof history<"u"){let e=history.pushState,n=history.replaceState;history.pushState=function(...r){e.apply(this,r),t("push");},history.replaceState=function(...r){n.apply(this,r),t("replace");};}typeof addEventListener<"u"&&addEventListener("popstate",()=>t("popstate"));}startNavTransaction(t,e){try{this.navTransaction&&(this.navTransaction.finish(),this.navTransaction=null),this.navTransaction=this.startTransaction({op:"navigation",name:t,attributes:{"navigation.type":e,"http.url":typeof location<"u"?location.href:t}});let n=this.navTransaction;setTimeout(()=>{this.navTransaction===n&&(n.finish(),this.navTransaction=null);},3e4);}catch{}}attachGlobalErrorHandlers(){let t=globalThis;typeof t.addEventListener=="function"&&(this.errorHandler||this.rejectionHandler||(this.errorHandler=e=>{let n=e,r=n.error??new Error(n.message??"Uncaught error");try{this.captureException(r,{tags:{source:"window.onerror"},extra:n.filename?{filename:n.filename,lineno:n.lineno,colno:n.colno}:void 0});}catch{}},this.rejectionHandler=e=>{let r=e.reason,s=r;if(!(r instanceof Error)){let i;if(typeof r=="string")i=r;else try{i=JSON.stringify(r);}catch{i=String(r);}s=new Error(i);}try{this.captureException(s,{tags:{source:"unhandledrejection"}});}catch{}},t.addEventListener("error",this.errorHandler),t.addEventListener("unhandledrejection",this.rejectionHandler)));}detachGlobalErrorHandlers(){let t=globalThis;typeof t.removeEventListener=="function"&&(this.errorHandler&&(t.removeEventListener("error",this.errorHandler),this.errorHandler=null),this.rejectionHandler&&(t.removeEventListener("unhandledrejection",this.rejectionHandler),this.rejectionHandler=null));}attachFetchInstrumentation(){if(typeof fetch>"u")return;let t=globalThis;if(this.originalFetch)return;this.originalFetch=t.fetch;let e=t.fetch.bind(globalThis),n=this;t.fetch=function(s,i){let d="",a="GET";if(typeof s=="string")d=s;else if(s&&typeof s=="object"){let h=s;d=h.url??"",a=h.method??a;}let c=i??{};if(c.method?a=String(c.method).toUpperCase():typeof s=="object"&&(a=s.method?.toUpperCase()??a),d.startsWith(n.endpoint))return e(s,c);let u=n.startSpan({op:"http.client",name:`${a} ${d}`,attributes:{"http.method":a,"http.url":d},parent:n.navTransaction??void 0});try{let h=`00-${u.trace_id}-${u.span_id}-01`,f={...c},g=f.headers??{};return f.headers={...g,traceparent:h},e(s,f).then(p=>{let l=p;return typeof l.status=="number"&&u.setAttribute("http.status_code",l.status),u.setStatus(l.ok===!1?"error":"ok"),u.finish(),p}).catch(p=>{throw u.setStatus("error"),u.setAttribute("error.message",p instanceof Error?p.message:String(p)),u.finish(),p})}catch(h){throw u.setStatus("error"),u.finish(),h}};}detachFetchInstrumentation(){this.originalFetch&&(globalThis.fetch=this.originalFetch,this.originalFetch=null);}attachXhrInstrumentation(){let e=globalThis.XMLHttpRequest;if(!e||!e.prototype)return;let n=Symbol.for("goodlogs.xhr.patched"),r=e.prototype;if(r[n]){this.xhrPatched=true;return}let s=r.open,i=r.setRequestHeader,d=r.send,a=this;r.open=function(u,h,...f){return this.__gl_method=typeof u=="string"?u.toUpperCase():"GET",this.__gl_url=typeof h=="string"?h:String(h??""),this.__gl_headers_set=false,s.apply(this,[u,h,...f])},r.setRequestHeader=function(u,h){return this.__gl_headers_set=true,i.apply(this,[u,h])},r.send=function(u){let h=this.__gl_url||"",f=this.__gl_method||"GET";if(h.startsWith(a.endpoint))return d.apply(this,[u]);let g=a.startSpan({op:"http.client",name:`${f} ${h}`,attributes:{"http.method":f,"http.url":h},parent:a.navTransaction??void 0});try{let m=`00-${g.trace_id}-${g.span_id}-01`;i.apply(this,["traceparent",m]);}catch{}let p=(m,E,O)=>{m&&g.setAttribute("http.status_code",m),O&&g.setAttribute("error.message",O),g.setStatus(E?"ok":"error"),g.finish();},l=this.addEventListener;return typeof l=="function"?(l.call(this,"load",()=>{let m=Number(this.status||0);p(m,m>0&&m<500);}),l.call(this,"error",()=>p(0,false,"network error")),l.call(this,"abort",()=>p(0,false,"aborted")),l.call(this,"timeout",()=>p(0,false,"timeout"))):p(0,true),d.apply(this,[u])},r[n]=true,r.__gl_orig_open=s,r.__gl_orig_set_header=i,r.__gl_orig_send=d,this.xhrPatched=true;}detachXhrInstrumentation(){if(!this.xhrPatched)return;let e=globalThis.XMLHttpRequest?.prototype;if(!e)return;let n=Symbol.for("goodlogs.xhr.patched");e.__gl_orig_open&&(e.open=e.__gl_orig_open),e.__gl_orig_set_header&&(e.setRequestHeader=e.__gl_orig_set_header),e.__gl_orig_send&&(e.send=e.__gl_orig_send),delete e.__gl_orig_open,delete e.__gl_orig_set_header,delete e.__gl_orig_send,delete e[n],this.xhrPatched=false;}attachClickCapture(){typeof document>"u"||(this.clickHandler=t=>{let n=t.target?.closest?.("a, button, [data-gl-event], [role='button']");if(!n)return;let r=n.getAttribute?.("data-gl-event"),s=n.tagName?.toLowerCase()??"",i=(n.textContent??"").trim().slice(0,50),d=n.getAttribute?.("href")??void 0,a=(n.className??"").toString().slice(0,80);this.track(r||"$click",{properties:{$element_tag:s,$element_text:i||void 0,$element_href:d,$element_classes:a||void 0}});},document.addEventListener("click",this.clickHandler));}detachClickCapture(){this.clickHandler&&typeof document<"u"&&(document.removeEventListener("click",this.clickHandler),this.clickHandler=null);}detachPageLifecycle(){this.visibilityHandler&&typeof document<"u"&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null);}keepaliveFlush(){let t=this.logBuffer.splice(0),e=this.eventBuffer.splice(0),n={"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"X-GoodLogs-SDK":`js/${v}`};t.length>0&&fetch(`${this.endpoint}/v1/logs`,{method:"POST",headers:n,body:JSON.stringify({batch:t.map(r=>({severity:r.severity,message:r.message,properties:r.properties,timestamp:r.timestamp}))}),keepalive:true}).catch(()=>{}),e.length>0&&fetch(`${this.endpoint}/v1/events`,{method:"POST",headers:n,body:JSON.stringify({batch:e.map(r=>({event:r.event,distinctId:r.distinctId,properties:r.properties,timestamp:r.timestamp}))}),keepalive:true}).catch(()=>{});}sendTelemetry(t,e,n){!this.telemetry||this.disabled||fetch(`${this.endpoint}/v1/telemetry`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"X-GoodLogs-SDK":`js/${v}`},body:JSON.stringify({source:"sdk",event:t,level:e,metadata:{...n,sdk_version:v}}),keepalive:true}).catch(()=>{});}};R.MAX_BREADCRUMBS=50;var C=R;var $=class{constructor(t){if(!t.apiKey)throw new Error("apiKey is required");if(!t.apiKey.startsWith("gl_sk_"))throw new Error("GoodLogsClient requires a secret API key (gl_sk_...)");this.apiKey=t.apiKey,this.endpoint=y(t.apiKey,t.endpoint),this.timeout=t.timeout??3e4,this.alerts=new L(this),this.slos=new P(this),this.ai=new A(this);}async _request(t,e,n){let r=`${this.endpoint}${e}`,s={Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},i=new AbortController,d=setTimeout(()=>i.abort(),this.timeout);try{let a=await fetch(r,{method:t,headers:s,body:n?JSON.stringify(n):void 0,signal:i.signal});if(!a.ok){let c=await a.json().catch(()=>({})),u=c?.error?.message??`API error ${a.status}`;throw new T(a.status,u,c?.error?.code)}return a.status===204?void 0:await a.json()}finally{clearTimeout(d);}}_get(t){return this._request("GET",t)}_post(t,e){return this._request("POST",t,e)}_put(t,e){return this._request("PUT",t,e)}_delete(t){return this._request("DELETE",t)}info(){return this._get("/v1/info")}schema(){return this._get("/v1/schema")}gql(t){return this._post("/v1/gql/query",{q:t})}gqlBatch(t){return this._post("/v1/gql",{queries:t})}gqlAutocomplete(t,e){let n=`/v1/gql/autocomplete?q=${encodeURIComponent(t)}`;return e!==void 0&&(n+=`&cursor=${e}`),this._get(n)}nl2gql(t,e){return this._post("/v1/gql/nl",{prompt:t,mode:e})}},L=class{constructor(t){this.client=t;}list(){return this.client._get("/v1/alerts")}create(t){return this.client._post("/v1/alerts",t)}update(t,e){return this.client._put(`/v1/alerts/${t}`,e)}delete(t){return this.client._delete(`/v1/alerts/${t}`)}mute(t,e){return this.client._post(`/v1/alerts/${t}/mute`,{minutes:e})}},P=class{constructor(t){this.client=t;}list(){return this.client._get("/v1/slos")}create(t){return this.client._post("/v1/slos",t)}update(t,e){return this.client._put(`/v1/slos/${t}`,e)}delete(t){return this.client._delete(`/v1/slos/${t}`)}},A=class{constructor(t){this.client=t;}chat(t,e){return this.client._post("/v1/ai/chat",{message:t,session_id:e})}},T=class extends Error{constructor(e,n,r){super(n);this.status=e;this.code=r;this.name="GoodLogsApiError";}};var q="0.1.0";function Y(o,t){let e=y(t?.apiKey??"",t?.endpoint).replace(/\/+$/,""),n={"Content-Type":"application/json","X-GoodLogs-SDK":q};t?.token&&(n.Authorization=`Bearer ${t.token}`),fetch(`${e}/v1/telemetry`,{method:"POST",headers:n,body:JSON.stringify({source:o.source,event:o.event,level:o.level??"info",metadata:{...o.metadata,sdk_version:q}}),keepalive:true}).catch(()=>{});}function x(o){if(!o)return null;let t=o.trim().split("-");if(t.length!==4)return null;let[e,n,r,s]=t;return e.length!==2||n.length!==32||r.length!==16||s.length!==2||!/^[0-9a-f]+$/.test(n)||!/^[0-9a-f]+$/.test(r)?null:{trace_id:n,parent_span_id:r}}function N(o,t){if(!o)return;let e=o[t]??o[t.toLowerCase()];return Array.isArray(e)?e[0]:e}function Q(o){return function(e,n,r){let s=(e.method??"GET").toUpperCase(),i=e.originalUrl??e.url??"",d=x(N(e.headers,"traceparent")),a=o.startTransaction({op:"http.server",name:`${s} ${i}`,trace_id:d?.trace_id,attributes:{"http.method":s,"http.url":i}}),c=false,u=()=>{if(c)return;c=true;let h=e.route?.path;h&&a.setAttribute("http.route",h);let f=n.statusCode??200;a.setAttribute("http.status_code",f),a.setStatus(f>=500?"error":"ok"),a.finish();};n.on("finish",u),n.on("close",u),e.goodlogs={span:a},r();}}function Z(o){return function(e,n,r){e.addHook("onRequest",(s,i,d)=>{let a=(s.method??"GET").toUpperCase(),c=s.url??"",u=x(N(s.headers,"traceparent")),h=o.startTransaction({op:"http.server",name:`${a} ${c}`,trace_id:u?.trace_id,attributes:{"http.method":a,"http.url":c}});s.__goodlogsSpan=h,d();}),e.addHook("onResponse",(s,i,d)=>{let a=s.__goodlogsSpan;if(a){let c=s.routerPath??s.routeOptions?.url;c&&a.setAttribute("http.route",c);let u=i.statusCode??i.raw?.statusCode??200;a.setAttribute("http.status_code",u),a.setStatus(u>=500?"error":"ok"),a.finish();}d();}),r();}}function tt(o){return {intercept(t,e){let n=t.switchToHttp(),r=n.getRequest(),s=n.getResponse(),i=(r.method??"GET").toUpperCase(),d=r.originalUrl??r.url??"",a=x(N(r.headers,"traceparent")),c=o.startTransaction({op:"http.server",name:`${i} ${d}`,trace_id:a?.trace_id,attributes:{"http.method":i,"http.url":d}}),u=false,h=(g,p)=>{if(u)return;u=true;let l=r.route?.path;l&&c.setAttribute("http.route",l);let m=g??s.statusCode??200;c.setAttribute("http.status_code",m),c.setStatus(p||m>=500?"error":"ok"),c.finish();};s.on("finish",()=>h()),s.on("close",()=>h());let f=e.handle();if(f&&typeof f.subscribe=="function"){let g=f.subscribe({next:()=>{},error:p=>{c.setAttribute("error.message",p instanceof Error?p.message:String(p)),h(500,true);},complete:()=>h()});return {unsubscribe:()=>g.unsubscribe?.()}}return f}}}function et(o){let t=globalThis.process;if(!t||typeof t.on!="function")return;let e=t,n=Symbol.for("goodlogs.node-process.patched");e[n]||(t.on("uncaughtException",r=>{try{o.captureException(r instanceof Error?r:new Error(String(r)),{tags:{source:"uncaughtException"},level:"fatal"}),o.flush();}catch{}}),t.on("unhandledRejection",r=>{try{let s=r instanceof Error?r:new Error(typeof r=="string"?r:(()=>{try{return JSON.stringify(r)}catch{return String(r)}})());o.captureException(s,{tags:{source:"unhandledRejection"}});}catch{}}),e[n]=true);}var H=globalThis.URL;function k(o){return !!H&&o instanceof H}var j=Symbol.for("goodlogs.node-http.patched");function nt(...o){let t=o[0],e=o[1],n="GET",r="";if(typeof t=="string")r=t,e&&typeof e=="object"&&!k(e)&&(n=String(e.method??n).toUpperCase());else if(k(t))r=t.toString(),e&&typeof e=="object"&&!k(e)&&(n=String(e.method??n).toUpperCase());else if(t&&typeof t=="object"){let i=t;n=String(i.method??n).toUpperCase();let d=(i.protocol??"http:").replace(":",""),a=i.hostname??i.host??"localhost",c=i.port?`:${i.port}`:"";r=`${d}://${a}${c}${i.path??"/"}`;}return {method:n,url:r,isOurs:i=>!!i&&r.startsWith(i)}}function rt(o,t,e){let n=o[0]&&typeof o[0]=="object"&&!k(o[0])?o[0]:o[1]&&typeof o[1]=="object"&&!k(o[1])?o[1]:void 0;n&&(n.headers||(n.headers={}),!(t in n.headers)&&!(t.toLowerCase()in n.headers)&&(n.headers[t]=e));}function st(o,t){let e=t?.endpoint??o.endpoint??"",n=r=>{let s=r;if(s[j])return;s[j]=true;let i=r.request.bind(r);r.request=function(...a){let{method:c,url:u,isOurs:h}=nt(...a);if(!u||h(e))return i(...a);let f=o.startTransaction({op:"http.client",name:`${c} ${u}`,attributes:{"http.method":c,"http.url":u}});rt(a,"traceparent",`00-${f.trace_id}-${f.span_id}-01`);let g=false,p=(m,E)=>{g||(g=true,typeof m=="number"&&f.setAttribute("http.status_code",m),E?(f.setAttribute("error.message",E.message),f.setStatus("error")):f.setStatus(typeof m=="number"&&m>=500?"error":"ok"),f.finish());},l=i(...a);return l.on("response",m=>p(m.statusCode)),l.on("error",m=>p(void 0,m)),l.on("close",()=>p()),l};};if(typeof S=="function"){try{let r=S("http");n(r);}catch{}try{let r=S("https");n(r);}catch{}}}
7
+ export{C as GoodLogs,T as GoodLogsApiError,$ as GoodLogsClient,I as REGION_URLS,Q as goodlogsExpress,Z as goodlogsFastify,tt as goodlogsNestInterceptor,st as instrumentNodeHttp,et as instrumentNodeProcess,x as parseTraceparent,y as resolveEndpoint,B as resolveRegion,Y as sendTelemetry};
@@ -0,0 +1,2 @@
1
+ 'use strict';var C="https://cdn.jsdelivr.net/npm/rrweb@2.0.0-alpha.18/dist/rrweb.umd.cjs";async function $(n,e={}){if(typeof document>"u")return null;let i=e.sampleRate??1;if(i<1&&Math.random()>i)return null;let s=e.rrwebRecord??await P(e.cdnUrl??C);if(!s)return null;let t=n.endpoint,r=n.apiKey,a=n.sessionId,v=n.getDistinctId(),h=e.flushIntervalMs??5e3,y=e.flushBytes??5e5,c=[],d=0,w=0,f=false,u=false;m(t,r,{session_id:a,distinct_id:v,start_url:typeof location<"u"?location.href:null,last_url:typeof location<"u"?location.href:null},e.onError);let l=async()=>{if(c.length===0)return;let o=c,I=o[0].timestamp,g=o[o.length-1].timestamp,S=o.length;c=[],d=0;let E=w++;try{let p=JSON.stringify(o),T=await O(p),B=`${t}/v1/replay/chunks?session_id=${encodeURIComponent(a)}&seq=${E}&start_ts=${encodeURIComponent(new Date(I).toISOString())}&end_ts=${encodeURIComponent(new Date(g).toISOString())}&event_count=${S}`;await fetch(B,{method:"POST",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/gzip","Content-Encoding":"gzip"},body:T,keepalive:!0});}catch(p){e.onError?.(p);}m(t,r,{session_id:a,last_url:typeof location<"u"?location.href:null,last_activity_at:new Date(g).toISOString(),has_error:f||void 0},e.onError);},k=s({emit:o=>{u||(c.push(o),d+=256,d>=y&&l());},checkoutEveryNms:6e4,maskAllInputs:e.maskAllInputs??true,blockSelector:e.blockSelector??"[data-gl-block]",maskTextSelector:e.maskTextSelector??"[data-gl-mask]"}),R=setInterval(()=>{l();},h),b=()=>{document?.visibilityState==="hidden"&&l();};document.addEventListener("visibilitychange",b);let _=setInterval(()=>{globalThis.__gl_replay_has_error__&&(f=true);},1e3);return {sessionId:a,flush:l,stop:()=>{if(!u){u=true,clearInterval(R),clearInterval(_),document?.removeEventListener("visibilitychange",b);try{k();}catch(o){e.onError?.(o);}l(),m(t,r,{session_id:a,ended_at:new Date().toISOString()},e.onError);}}}}async function m(n,e,i,s){try{await fetch(`${n}/v1/replay/sessions`,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i),keepalive:!0});}catch(t){s?.(t);}}async function O(n){if(typeof CompressionStream>"u"||typeof Blob>"u"||typeof Response>"u")return n;let i=new Blob([n]).stream().pipeThrough(new CompressionStream("gzip")),s=await new Response(i).arrayBuffer();return new Blob([s],{type:"application/gzip"})}async function P(n){let e=globalThis;if(e.rrweb?.record)return e.rrweb.record;try{return await new Promise((i,s)=>{let t=globalThis.document;if(!t){s(new Error("no document"));return}let r=t.createElement("script");r.src=n,r.async=!0,r.onload=()=>i(),r.onerror=()=>s(new Error(`failed to load ${n}`)),t.head.appendChild(r);}),e.rrweb?.record??null}catch{return null}}
2
+ exports.startReplay=$;
@@ -0,0 +1,70 @@
1
+ import { G as GoodLogs } from './client-w3t1Yzjd.cjs';
2
+
3
+ /**
4
+ * Session Replay (rrweb) — optional, lazy-loaded.
5
+ *
6
+ * Usage:
7
+ * import { GoodLogs } from "@aj-2000-test/goodlogs-sdk";
8
+ * import { startReplay } from "@aj-2000-test/goodlogs-sdk/replay";
9
+ *
10
+ * const gl = new GoodLogs({ apiKey: "gl_pk_..." });
11
+ * startReplay(gl);
12
+ *
13
+ * Capture is *not* a video — it's the rrweb DOM-mutation stream gzipped
14
+ * and shipped to /v1/replay/chunks. See docs/storage-design.md for storage.
15
+ *
16
+ * rrweb is loaded from a CDN at runtime so the core SDK bundle stays small.
17
+ * Pass a local `rrwebRecord` instead if you bundle rrweb yourself.
18
+ */
19
+
20
+ interface RrwebRecord {
21
+ (opts: {
22
+ emit: (event: RrwebEvent, isCheckout?: boolean) => void;
23
+ checkoutEveryNms?: number;
24
+ maskAllInputs?: boolean;
25
+ maskInputOptions?: Record<string, boolean>;
26
+ blockClass?: string;
27
+ blockSelector?: string;
28
+ ignoreClass?: string;
29
+ maskTextClass?: string;
30
+ maskTextSelector?: string;
31
+ sampling?: Record<string, unknown>;
32
+ }): () => void;
33
+ }
34
+ interface RrwebEvent {
35
+ type: number;
36
+ data: unknown;
37
+ timestamp: number;
38
+ }
39
+ interface ReplayOptions {
40
+ /** Provide rrweb's `record` yourself (bundled). Skips CDN load. */
41
+ rrwebRecord?: RrwebRecord;
42
+ /** CDN URL for rrweb when `rrwebRecord` is not provided. */
43
+ cdnUrl?: string;
44
+ /** Flush queued events every N ms (default 5000). */
45
+ flushIntervalMs?: number;
46
+ /** Force flush when queue reaches this size in bytes (default 500_000). */
47
+ flushBytes?: number;
48
+ /** Sample rate 0..1 (default 1 — always record). Errors override sampling. */
49
+ sampleRate?: number;
50
+ /** Block any DOM matching this CSS selector. */
51
+ blockSelector?: string;
52
+ /** Mask text of nodes matching this selector. */
53
+ maskTextSelector?: string;
54
+ /** Mask all <input>/<textarea> text by default. */
55
+ maskAllInputs?: boolean;
56
+ /** Custom logger for errors. */
57
+ onError?: (e: unknown) => void;
58
+ }
59
+ interface ReplayHandle {
60
+ stop: () => void;
61
+ flush: () => Promise<void>;
62
+ sessionId: string;
63
+ }
64
+ /**
65
+ * Start recording. Returns a handle with `stop()` and `flush()`.
66
+ * Calling more than once is a no-op (returns the existing handle).
67
+ */
68
+ declare function startReplay(gl: GoodLogs, options?: ReplayOptions): Promise<ReplayHandle | null>;
69
+
70
+ export { type ReplayOptions, type RrwebEvent, startReplay };
@@ -0,0 +1,70 @@
1
+ import { G as GoodLogs } from './client-w3t1Yzjd.js';
2
+
3
+ /**
4
+ * Session Replay (rrweb) — optional, lazy-loaded.
5
+ *
6
+ * Usage:
7
+ * import { GoodLogs } from "@aj-2000-test/goodlogs-sdk";
8
+ * import { startReplay } from "@aj-2000-test/goodlogs-sdk/replay";
9
+ *
10
+ * const gl = new GoodLogs({ apiKey: "gl_pk_..." });
11
+ * startReplay(gl);
12
+ *
13
+ * Capture is *not* a video — it's the rrweb DOM-mutation stream gzipped
14
+ * and shipped to /v1/replay/chunks. See docs/storage-design.md for storage.
15
+ *
16
+ * rrweb is loaded from a CDN at runtime so the core SDK bundle stays small.
17
+ * Pass a local `rrwebRecord` instead if you bundle rrweb yourself.
18
+ */
19
+
20
+ interface RrwebRecord {
21
+ (opts: {
22
+ emit: (event: RrwebEvent, isCheckout?: boolean) => void;
23
+ checkoutEveryNms?: number;
24
+ maskAllInputs?: boolean;
25
+ maskInputOptions?: Record<string, boolean>;
26
+ blockClass?: string;
27
+ blockSelector?: string;
28
+ ignoreClass?: string;
29
+ maskTextClass?: string;
30
+ maskTextSelector?: string;
31
+ sampling?: Record<string, unknown>;
32
+ }): () => void;
33
+ }
34
+ interface RrwebEvent {
35
+ type: number;
36
+ data: unknown;
37
+ timestamp: number;
38
+ }
39
+ interface ReplayOptions {
40
+ /** Provide rrweb's `record` yourself (bundled). Skips CDN load. */
41
+ rrwebRecord?: RrwebRecord;
42
+ /** CDN URL for rrweb when `rrwebRecord` is not provided. */
43
+ cdnUrl?: string;
44
+ /** Flush queued events every N ms (default 5000). */
45
+ flushIntervalMs?: number;
46
+ /** Force flush when queue reaches this size in bytes (default 500_000). */
47
+ flushBytes?: number;
48
+ /** Sample rate 0..1 (default 1 — always record). Errors override sampling. */
49
+ sampleRate?: number;
50
+ /** Block any DOM matching this CSS selector. */
51
+ blockSelector?: string;
52
+ /** Mask text of nodes matching this selector. */
53
+ maskTextSelector?: string;
54
+ /** Mask all <input>/<textarea> text by default. */
55
+ maskAllInputs?: boolean;
56
+ /** Custom logger for errors. */
57
+ onError?: (e: unknown) => void;
58
+ }
59
+ interface ReplayHandle {
60
+ stop: () => void;
61
+ flush: () => Promise<void>;
62
+ sessionId: string;
63
+ }
64
+ /**
65
+ * Start recording. Returns a handle with `stop()` and `flush()`.
66
+ * Calling more than once is a no-op (returns the existing handle).
67
+ */
68
+ declare function startReplay(gl: GoodLogs, options?: ReplayOptions): Promise<ReplayHandle | null>;
69
+
70
+ export { type ReplayOptions, type RrwebEvent, startReplay };
package/dist/replay.js ADDED
@@ -0,0 +1,2 @@
1
+ var C="https://cdn.jsdelivr.net/npm/rrweb@2.0.0-alpha.18/dist/rrweb.umd.cjs";async function $(n,e={}){if(typeof document>"u")return null;let i=e.sampleRate??1;if(i<1&&Math.random()>i)return null;let s=e.rrwebRecord??await P(e.cdnUrl??C);if(!s)return null;let t=n.endpoint,r=n.apiKey,a=n.sessionId,v=n.getDistinctId(),h=e.flushIntervalMs??5e3,y=e.flushBytes??5e5,c=[],d=0,w=0,f=false,u=false;m(t,r,{session_id:a,distinct_id:v,start_url:typeof location<"u"?location.href:null,last_url:typeof location<"u"?location.href:null},e.onError);let l=async()=>{if(c.length===0)return;let o=c,I=o[0].timestamp,g=o[o.length-1].timestamp,S=o.length;c=[],d=0;let E=w++;try{let p=JSON.stringify(o),T=await O(p),B=`${t}/v1/replay/chunks?session_id=${encodeURIComponent(a)}&seq=${E}&start_ts=${encodeURIComponent(new Date(I).toISOString())}&end_ts=${encodeURIComponent(new Date(g).toISOString())}&event_count=${S}`;await fetch(B,{method:"POST",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/gzip","Content-Encoding":"gzip"},body:T,keepalive:!0});}catch(p){e.onError?.(p);}m(t,r,{session_id:a,last_url:typeof location<"u"?location.href:null,last_activity_at:new Date(g).toISOString(),has_error:f||void 0},e.onError);},k=s({emit:o=>{u||(c.push(o),d+=256,d>=y&&l());},checkoutEveryNms:6e4,maskAllInputs:e.maskAllInputs??true,blockSelector:e.blockSelector??"[data-gl-block]",maskTextSelector:e.maskTextSelector??"[data-gl-mask]"}),R=setInterval(()=>{l();},h),b=()=>{document?.visibilityState==="hidden"&&l();};document.addEventListener("visibilitychange",b);let _=setInterval(()=>{globalThis.__gl_replay_has_error__&&(f=true);},1e3);return {sessionId:a,flush:l,stop:()=>{if(!u){u=true,clearInterval(R),clearInterval(_),document?.removeEventListener("visibilitychange",b);try{k();}catch(o){e.onError?.(o);}l(),m(t,r,{session_id:a,ended_at:new Date().toISOString()},e.onError);}}}}async function m(n,e,i,s){try{await fetch(`${n}/v1/replay/sessions`,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(i),keepalive:!0});}catch(t){s?.(t);}}async function O(n){if(typeof CompressionStream>"u"||typeof Blob>"u"||typeof Response>"u")return n;let i=new Blob([n]).stream().pipeThrough(new CompressionStream("gzip")),s=await new Response(i).arrayBuffer();return new Blob([s],{type:"application/gzip"})}async function P(n){let e=globalThis;if(e.rrweb?.record)return e.rrweb.record;try{return await new Promise((i,s)=>{let t=globalThis.document;if(!t){s(new Error("no document"));return}let r=t.createElement("script");r.src=n,r.async=!0,r.onload=()=>i(),r.onerror=()=>s(new Error(`failed to load ${n}`)),t.head.appendChild(r);}),e.rrweb?.record??null}catch{return null}}
2
+ export{$ as startReplay};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-2000-test/goodlogs-sdk",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "GoodLogs SDK — ingest logs/events + programmatic API client for queries, alerts, AI",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -11,11 +11,20 @@
11
11
  "import": "./dist/index.js",
12
12
  "require": "./dist/index.cjs",
13
13
  "types": "./dist/index.d.ts"
14
+ },
15
+ "./replay": {
16
+ "import": "./dist/replay.js",
17
+ "require": "./dist/replay.cjs",
18
+ "types": "./dist/replay.d.ts"
14
19
  }
15
20
  },
16
21
  "files": [
17
- "dist"
22
+ "dist",
23
+ "bin"
18
24
  ],
25
+ "bin": {
26
+ "goodlogs": "bin/goodlogs.cjs"
27
+ },
19
28
  "sideEffects": false,
20
29
  "scripts": {
21
30
  "build": "tsup",