@klime/browser 1.2.0 → 1.2.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/README.md CHANGED
@@ -222,7 +222,7 @@ await client.shutdown();
222
222
  - **Automatic Batching**: Events are automatically batched and sent every 2 seconds or when the batch size reaches 20 events
223
223
  - **Automatic Retries**: Failed requests are automatically retried with exponential backoff
224
224
  - **Browser Context**: Automatically captures userAgent, locale, and timezone
225
- - **Page Unload Handling**: Automatically flushes events when the page is about to unload
225
+ - **Page Unload Handling**: Flushes on `visibilitychange` (when tab is hidden), `pagehide`, and `beforeunload`, and uses `fetch` with `keepalive: true` (when batch ≤64KB) so requests can complete after the page unloads
226
226
  - **Zero Dependencies**: Uses only native browser APIs
227
227
  - **Universal Module Support**: Works with ESM and CommonJS (no `transpilePackages` needed)
228
228
 
@@ -265,7 +265,9 @@ client.track("Button Clicked", { button: "signup" }, { userId: "user_123" });
265
265
  navigate("/dashboard");
266
266
  ```
267
267
 
268
- The only blocking operation is `await flush()`, which waits for all queued events to be sent. The SDK automatically flushes on page unload, so explicit `flush()` calls are rarely needed.
268
+ The only blocking operation is `await flush()`, which waits for all queued events to be sent. The SDK automatically flushes on page unload (and uses `keepalive` so the request can complete after the page is gone).
269
+
270
+ **SPAs (e.g. Next.js)**: Client-side route changes do not trigger `beforeunload` or `pagehide`. To avoid losing events on navigation, call `flush()` when the route changes (e.g. in your router's `onRouteChange` or in a `useEffect` that depends on `pathname`).
269
271
 
270
272
  ## Configuration
271
273
 
package/dist/index.cjs CHANGED
@@ -44,6 +44,7 @@ var DEFAULT_RETRY_INITIAL_DELAY = 1e3;
44
44
  var MAX_BATCH_SIZE = 100;
45
45
  var MAX_EVENT_SIZE_BYTES = 200 * 1024;
46
46
  var MAX_BATCH_SIZE_BYTES = 10 * 1024 * 1024;
47
+ var KEEPALIVE_MAX_BODY_BYTES = 64 * 1024;
47
48
  var SDK_VERSION = "1.1.0";
48
49
  var createDefaultLogger = () => ({
49
50
  debug: (message, ...args) => console.debug(`[Klime] ${message}`, ...args),
@@ -58,6 +59,7 @@ var KlimeClient = class {
58
59
  this.isShutdown = false;
59
60
  this.flushPromise = null;
60
61
  this.unloadHandler = null;
62
+ this.visibilityChangeHandler = null;
61
63
  if (!config.writeKey) {
62
64
  throw new Error("writeKey is required");
63
65
  }
@@ -82,6 +84,13 @@ var KlimeClient = class {
82
84
  this.flush();
83
85
  };
84
86
  window.addEventListener("beforeunload", this.unloadHandler);
87
+ window.addEventListener("pagehide", this.unloadHandler);
88
+ this.visibilityChangeHandler = () => {
89
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") {
90
+ this.flush();
91
+ }
92
+ };
93
+ document.addEventListener("visibilitychange", this.visibilityChangeHandler);
85
94
  }
86
95
  this.scheduleFlush();
87
96
  }
@@ -220,6 +229,10 @@ var KlimeClient = class {
220
229
  this.isShutdown = true;
221
230
  if (this.unloadHandler && typeof window !== "undefined") {
222
231
  window.removeEventListener("beforeunload", this.unloadHandler);
232
+ window.removeEventListener("pagehide", this.unloadHandler);
233
+ }
234
+ if (this.visibilityChangeHandler && typeof document !== "undefined") {
235
+ document.removeEventListener("visibilitychange", this.visibilityChangeHandler);
223
236
  }
224
237
  if (this.flushTimer) {
225
238
  clearTimeout(this.flushTimer);
@@ -307,6 +320,8 @@ var KlimeClient = class {
307
320
  async doSend(batch) {
308
321
  const request = { batch };
309
322
  const requestUrl = `${this.config.endpoint}/v1/batch`;
323
+ const body = JSON.stringify(request);
324
+ const useKeepalive = body.length <= KEEPALIVE_MAX_BODY_BYTES;
310
325
  let attempt = 0;
311
326
  let delay = this.config.retryInitialDelay;
312
327
  while (attempt < this.config.retryMaxAttempts) {
@@ -317,7 +332,8 @@ var KlimeClient = class {
317
332
  "Content-Type": "application/json",
318
333
  Authorization: `Bearer ${this.config.writeKey}`
319
334
  },
320
- body: JSON.stringify(request)
335
+ body,
336
+ keepalive: useKeepalive
321
337
  });
322
338
  const data = await response.json();
323
339
  if (response.ok) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts"],"sourcesContent":["import {\n KlimeConfig,\n TrackOptions,\n Event,\n BatchRequest,\n BatchResponse,\n EventContext,\n Logger,\n SendError,\n} from \"./types\";\n\n// Re-export types for users\nexport { SendError, BatchResponse, Logger } from \"./types\";\nexport type { KlimeConfig, TrackOptions, Event } from \"./types\";\n\nconst DEFAULT_ENDPOINT = \"https://i.klime.com\";\nconst DEFAULT_FLUSH_INTERVAL = 2000;\nconst DEFAULT_MAX_BATCH_SIZE = 20;\nconst DEFAULT_MAX_QUEUE_SIZE = 1000;\nconst DEFAULT_RETRY_MAX_ATTEMPTS = 5;\nconst DEFAULT_RETRY_INITIAL_DELAY = 1000;\nconst MAX_BATCH_SIZE = 100;\nconst MAX_EVENT_SIZE_BYTES = 200 * 1024; // 200KB\nconst MAX_BATCH_SIZE_BYTES = 10 * 1024 * 1024; // 10MB\nconst SDK_VERSION = \"1.1.0\";\n\n// Default logger that wraps console with [Klime] prefix\nconst createDefaultLogger = (): Logger => ({\n debug: (message: string, ...args: any[]) =>\n console.debug(`[Klime] ${message}`, ...args),\n info: (message: string, ...args: any[]) =>\n console.info(`[Klime] ${message}`, ...args),\n warn: (message: string, ...args: any[]) =>\n console.warn(`[Klime] ${message}`, ...args),\n error: (message: string, ...args: any[]) =>\n console.error(`[Klime] ${message}`, ...args),\n});\n\n// Internal config type with required fields and optional callbacks/logger\ninterface InternalConfig {\n writeKey: string;\n endpoint: string;\n flushInterval: number;\n maxBatchSize: number;\n maxQueueSize: number;\n retryMaxAttempts: number;\n retryInitialDelay: number;\n autoFlushOnUnload: boolean;\n logger: Logger;\n onError?: (error: Error, events: Event[]) => void;\n onSuccess?: (response: BatchResponse) => void;\n}\n\nexport class KlimeClient {\n private config: InternalConfig;\n private queue: Event[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private isShutdown = false;\n private flushPromise: Promise<void> | null = null;\n private unloadHandler: ((e: BeforeUnloadEvent) => void) | null = null;\n\n constructor(config: KlimeConfig) {\n if (!config.writeKey) {\n throw new Error(\"writeKey is required\");\n }\n\n this.config = {\n writeKey: config.writeKey,\n endpoint: config.endpoint || DEFAULT_ENDPOINT,\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n maxBatchSize: Math.min(\n config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE,\n MAX_BATCH_SIZE\n ),\n maxQueueSize: config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE,\n retryMaxAttempts: config.retryMaxAttempts ?? DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay:\n config.retryInitialDelay ?? DEFAULT_RETRY_INITIAL_DELAY,\n autoFlushOnUnload: config.autoFlushOnUnload ?? true,\n logger: config.logger ?? createDefaultLogger(),\n onError: config.onError,\n onSuccess: config.onSuccess,\n };\n\n if (this.config.autoFlushOnUnload && typeof window !== \"undefined\") {\n this.unloadHandler = () => {\n this.flush();\n };\n window.addEventListener(\"beforeunload\", this.unloadHandler);\n }\n\n this.scheduleFlush();\n }\n\n track(\n event: string,\n properties?: Record<string, any>,\n options?: TrackOptions\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"track\",\n messageId: this.generateUUID(),\n event,\n timestamp: this.generateTimestamp(),\n properties: properties || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n if (options?.groupId) {\n eventObj.groupId = options.groupId;\n }\n\n this.enqueue(eventObj);\n }\n\n identify(userId: string, traits?: Record<string, any>): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"identify\",\n messageId: this.generateUUID(),\n userId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n this.enqueue(eventObj);\n }\n\n group(\n groupId: string,\n traits?: Record<string, any>,\n options?: TrackOptions\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"group\",\n messageId: this.generateUUID(),\n groupId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n\n this.enqueue(eventObj);\n }\n\n /**\n * Track an event synchronously. Returns BatchResponse or throws SendError.\n */\n async trackSync(\n event: string,\n properties?: Record<string, any>,\n options?: TrackOptions\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"track\",\n messageId: this.generateUUID(),\n event,\n timestamp: this.generateTimestamp(),\n properties: properties || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n if (options?.groupId) {\n eventObj.groupId = options.groupId;\n }\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Identify a user synchronously. Returns BatchResponse or throws SendError.\n */\n async identifySync(\n userId: string,\n traits?: Record<string, any>\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"identify\",\n messageId: this.generateUUID(),\n userId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Associate a user with a group synchronously. Returns BatchResponse or throws SendError.\n */\n async groupSync(\n groupId: string,\n traits?: Record<string, any>,\n options?: TrackOptions\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"group\",\n messageId: this.generateUUID(),\n groupId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Return the number of events currently in the queue.\n */\n getQueueSize(): number {\n return this.queue.length;\n }\n\n async flush(): Promise<void> {\n if (this.flushPromise) {\n return this.flushPromise;\n }\n\n this.flushPromise = this.doFlush();\n try {\n await this.flushPromise;\n } finally {\n this.flushPromise = null;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.isShutdown) {\n return;\n }\n\n this.isShutdown = true;\n\n if (this.unloadHandler && typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", this.unloadHandler);\n }\n\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n await this.flush();\n }\n\n private enqueue(event: Event): void {\n // Check event size\n const eventSize = this.estimateEventSize(event);\n if (eventSize > MAX_EVENT_SIZE_BYTES) {\n this.config.logger.warn(\n `Event size (${eventSize} bytes) exceeds ${MAX_EVENT_SIZE_BYTES} bytes limit`\n );\n return;\n }\n\n // Drop oldest if queue is full\n if (this.queue.length >= this.config.maxQueueSize) {\n const dropped = this.queue.shift();\n this.config.logger.warn(`Queue full, dropping oldest event: ${dropped?.type}`);\n }\n\n this.queue.push(event);\n this.config.logger.debug(`Enqueued ${event.type} event, queue size: ${this.queue.length}`);\n\n // Check if we should flush immediately\n if (this.queue.length >= this.config.maxBatchSize) {\n this.flush();\n }\n }\n\n private async doFlush(): Promise<void> {\n if (this.queue.length === 0) {\n return;\n }\n\n // Clear the flush timer\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n // Process batches\n while (this.queue.length > 0) {\n const batch = this.extractBatch();\n if (batch.length === 0) {\n break;\n }\n\n await this.sendBatch(batch);\n }\n\n // Schedule next flush\n this.scheduleFlush();\n }\n\n private extractBatch(): Event[] {\n const batch: Event[] = [];\n let batchSize = 0;\n\n while (this.queue.length > 0 && batch.length < MAX_BATCH_SIZE) {\n const event = this.queue[0];\n const eventSize = this.estimateEventSize(event);\n\n // Check if adding this event would exceed batch size limit\n if (batchSize + eventSize > MAX_BATCH_SIZE_BYTES) {\n break;\n }\n\n batch.push(this.queue.shift()!);\n batchSize += eventSize;\n }\n\n return batch;\n }\n\n private async sendBatch(batch: Event[]): Promise<void> {\n if (batch.length === 0) {\n return;\n }\n\n this.config.logger.debug(`Sending batch of ${batch.length} events`);\n const result = await this.doSend(batch);\n\n if (result === null) {\n // Send failed after all retries\n const error = new Error(`Failed to send batch of ${batch.length} events after retries`);\n this.invokeOnError(error, batch);\n } else if (result.failed > 0 && result.errors) {\n this.config.logger.warn(\n `Batch partially failed. Accepted: ${result.accepted}, Failed: ${result.failed}`,\n result.errors\n );\n // Still invoke success callback since some events were accepted\n this.invokeOnSuccess(result);\n } else {\n this.config.logger.debug(`Batch sent successfully. Accepted: ${result.accepted}`);\n this.invokeOnSuccess(result);\n }\n }\n\n private async sendSync(events: Event[]): Promise<BatchResponse> {\n this.config.logger.debug(`Sending ${events.length} events synchronously`);\n const result = await this.doSend(events);\n\n if (result === null) {\n throw new SendError(`Failed to send ${events.length} events after retries`, events);\n }\n\n return result;\n }\n\n private async doSend(batch: Event[]): Promise<BatchResponse | null> {\n const request: BatchRequest = { batch };\n const requestUrl = `${this.config.endpoint}/v1/batch`;\n\n let attempt = 0;\n let delay = this.config.retryInitialDelay;\n\n while (attempt < this.config.retryMaxAttempts) {\n try {\n const response = await fetch(requestUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.writeKey}`,\n },\n body: JSON.stringify(request),\n });\n\n const data: BatchResponse = await response.json();\n\n if (response.ok) {\n return data;\n }\n\n // Handle error responses\n if (response.status === 400 || response.status === 401) {\n // Permanent errors - don't retry\n this.config.logger.error(`Permanent error (${response.status}):`, data);\n return null;\n }\n\n // Transient errors - retry with backoff\n if (response.status === 429 || response.status === 503) {\n const retryAfter = response.headers.get(\"Retry-After\");\n if (retryAfter) {\n delay = parseInt(retryAfter, 10) * 1000;\n }\n\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000); // Cap at 16s\n continue;\n }\n }\n\n // Other errors - retry\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000);\n }\n } catch (error) {\n // Network errors - retry\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000);\n } else {\n this.config.logger.error(\"Failed to send batch after retries:\", error);\n }\n }\n }\n\n return null;\n }\n\n private invokeOnError(error: Error, batch: Event[]): void {\n if (this.config.onError) {\n try {\n this.config.onError(error, batch);\n } catch (e) {\n this.config.logger.error(\"Error in onError callback:\", e);\n }\n }\n }\n\n private invokeOnSuccess(response: BatchResponse): void {\n if (this.config.onSuccess) {\n try {\n this.config.onSuccess(response);\n } catch (e) {\n this.config.logger.error(\"Error in onSuccess callback:\", e);\n }\n }\n }\n\n private scheduleFlush(): void {\n if (this.isShutdown || this.flushTimer) {\n return;\n }\n\n this.flushTimer = setTimeout(() => {\n this.flush();\n }, this.config.flushInterval);\n }\n\n private generateUUID(): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older browsers\n return \"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\n private generateTimestamp(): string {\n return new Date().toISOString();\n }\n\n private getContext(): EventContext {\n const context: EventContext = {\n library: {\n name: \"js-sdk\",\n version: SDK_VERSION,\n },\n };\n\n if (typeof navigator !== \"undefined\") {\n if (navigator.userAgent) {\n context.userAgent = navigator.userAgent;\n }\n if (navigator.language) {\n context.locale = navigator.language;\n }\n }\n\n if (typeof Intl !== \"undefined\" && Intl.DateTimeFormat) {\n try {\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n if (timezone) {\n context.timezone = timezone;\n }\n } catch (e) {\n // Ignore timezone errors\n }\n }\n\n return context;\n }\n\n private estimateEventSize(event: Event): number {\n // Rough estimate: JSON stringified size\n try {\n return JSON.stringify(event).length;\n } catch {\n // Fallback: rough estimate based on structure\n return 500; // Conservative estimate\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","export interface Logger {\n debug(message: string, ...args: any[]): void;\n info(message: string, ...args: any[]): void;\n warn(message: string, ...args: any[]): void;\n error(message: string, ...args: any[]): void;\n}\n\nexport interface KlimeConfig {\n writeKey: string;\n endpoint?: string;\n flushInterval?: number; // milliseconds, default 2000\n maxBatchSize?: number; // default 20, max 100\n maxQueueSize?: number; // default 1000\n retryMaxAttempts?: number; // default 5\n retryInitialDelay?: number; // milliseconds, default 1000\n autoFlushOnUnload?: boolean; // default true\n logger?: Logger; // optional custom logger\n onError?: (error: Error, events: Event[]) => void; // callback for batch failures\n onSuccess?: (response: BatchResponse) => void; // callback for successful sends\n}\n\nexport interface TrackOptions {\n userId?: string;\n groupId?: string;\n}\n\nexport interface Event {\n type: 'track' | 'identify' | 'group';\n messageId: string;\n event?: string; // required for track\n userId?: string; // required for identify\n groupId?: string; // required for group\n timestamp: string; // ISO 8601\n properties?: Record<string, any>; // for track\n traits?: Record<string, any>; // for identify/group\n context?: EventContext;\n}\n\nexport interface EventContext {\n library?: {\n name: string;\n version: string;\n };\n userAgent?: string;\n locale?: string;\n timezone?: string;\n}\n\nexport interface BatchRequest {\n batch: Event[];\n}\n\nexport interface BatchResponse {\n status: string;\n accepted: number;\n failed: number;\n errors?: ValidationError[];\n}\n\nexport interface ValidationError {\n index: number;\n message: string;\n code: string;\n}\n\nexport class SendError extends Error {\n events: Event[];\n\n constructor(message: string, events: Event[]) {\n super(message);\n this.name = 'SendError';\n this.events = events;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACiEO,IAAM,YAAN,cAAwB,MAAM;AAAA,EAGnC,YAAY,SAAiB,QAAiB;AAC5C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;;;AD1DA,IAAM,mBAAmB;AACzB,IAAM,yBAAyB;AAC/B,IAAM,yBAAyB;AAC/B,IAAM,yBAAyB;AAC/B,IAAM,6BAA6B;AACnC,IAAM,8BAA8B;AACpC,IAAM,iBAAiB;AACvB,IAAM,uBAAuB,MAAM;AACnC,IAAM,uBAAuB,KAAK,OAAO;AACzC,IAAM,cAAc;AAGpB,IAAM,sBAAsB,OAAe;AAAA,EACzC,OAAO,CAAC,YAAoB,SAC1B,QAAQ,MAAM,WAAW,OAAO,IAAI,GAAG,IAAI;AAAA,EAC7C,MAAM,CAAC,YAAoB,SACzB,QAAQ,KAAK,WAAW,OAAO,IAAI,GAAG,IAAI;AAAA,EAC5C,MAAM,CAAC,YAAoB,SACzB,QAAQ,KAAK,WAAW,OAAO,IAAI,GAAG,IAAI;AAAA,EAC5C,OAAO,CAAC,YAAoB,SAC1B,QAAQ,MAAM,WAAW,OAAO,IAAI,GAAG,IAAI;AAC/C;AAiBO,IAAM,cAAN,MAAkB;AAAA,EAQvB,YAAY,QAAqB;AANjC,SAAQ,QAAiB,CAAC;AAC1B,SAAQ,aAAmD;AAC3D,SAAQ,aAAa;AACrB,SAAQ,eAAqC;AAC7C,SAAQ,gBAAyD;AAG/D,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAEA,SAAK,SAAS;AAAA,MACZ,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO,YAAY;AAAA,MAC7B,eAAe,OAAO,iBAAiB;AAAA,MACvC,cAAc,KAAK;AAAA,QACjB,OAAO,gBAAgB;AAAA,QACvB;AAAA,MACF;AAAA,MACA,cAAc,OAAO,gBAAgB;AAAA,MACrC,kBAAkB,OAAO,oBAAoB;AAAA,MAC7C,mBACE,OAAO,qBAAqB;AAAA,MAC9B,mBAAmB,OAAO,qBAAqB;AAAA,MAC/C,QAAQ,OAAO,UAAU,oBAAoB;AAAA,MAC7C,SAAS,OAAO;AAAA,MAChB,WAAW,OAAO;AAAA,IACpB;AAEA,QAAI,KAAK,OAAO,qBAAqB,OAAO,WAAW,aAAa;AAClE,WAAK,gBAAgB,MAAM;AACzB,aAAK,MAAM;AAAA,MACb;AACA,aAAO,iBAAiB,gBAAgB,KAAK,aAAa;AAAA,IAC5D;AAEA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,MACE,OACA,YACA,SACM;AACN,QAAI,KAAK,YAAY;AACnB;AAAA,IACF;AAEA,UAAM,WAAkB;AAAA,MACtB,MAAM;AAAA,MACN,WAAW,KAAK,aAAa;AAAA,MAC7B;AAAA,MACA,WAAW,KAAK,kBAAkB;AAAA,MAClC,YAAY,cAAc,CAAC;AAAA,MAC3B,SAAS,KAAK,WAAW;AAAA,IAC3B;AAEA,QAAI,SAAS,QAAQ;AACnB,eAAS,SAAS,QAAQ;AAAA,IAC5B;AACA,QAAI,SAAS,SAAS;AACpB,eAAS,UAAU,QAAQ;AAAA,IAC7B;AAEA,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA,EAEA,SAAS,QAAgB,QAAoC;AAC3D,QAAI,KAAK,YAAY;AACnB;AAAA,IACF;AAEA,UAAM,WAAkB;AAAA,MACtB,MAAM;AAAA,MACN,WAAW,KAAK,aAAa;AAAA,MAC7B;AAAA,MACA,WAAW,KAAK,kBAAkB;AAAA,MAClC,QAAQ,UAAU,CAAC;AAAA,MACnB,SAAS,KAAK,WAAW;AAAA,IAC3B;AAEA,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA,EAEA,MACE,SACA,QACA,SACM;AACN,QAAI,KAAK,YAAY;AACnB;AAAA,IACF;AAEA,UAAM,WAAkB;AAAA,MACtB,MAAM;AAAA,MACN,WAAW,KAAK,aAAa;AAAA,MAC7B;AAAA,MACA,WAAW,KAAK,kBAAkB;AAAA,MAClC,QAAQ,UAAU,CAAC;AAAA,MACnB,SAAS,KAAK,WAAW;AAAA,IAC3B;AAEA,QAAI,SAAS,QAAQ;AACnB,eAAS,SAAS,QAAQ;AAAA,IAC5B;AAEA,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UACJ,OACA,YACA,SACwB;AACxB,QAAI,KAAK,YAAY;AACnB,YAAM,IAAI,UAAU,sBAAsB,CAAC,CAAC;AAAA,IAC9C;AAEA,UAAM,WAAkB;AAAA,MACtB,MAAM;AAAA,MACN,WAAW,KAAK,aAAa;AAAA,MAC7B;AAAA,MACA,WAAW,KAAK,kBAAkB;AAAA,MAClC,YAAY,cAAc,CAAC;AAAA,MAC3B,SAAS,KAAK,WAAW;AAAA,IAC3B;AAEA,QAAI,SAAS,QAAQ;AACnB,eAAS,SAAS,QAAQ;AAAA,IAC5B;AACA,QAAI,SAAS,SAAS;AACpB,eAAS,UAAU,QAAQ;AAAA,IAC7B;AAEA,WAAO,KAAK,SAAS,CAAC,QAAQ,CAAC;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aACJ,QACA,QACwB;AACxB,QAAI,KAAK,YAAY;AACnB,YAAM,IAAI,UAAU,sBAAsB,CAAC,CAAC;AAAA,IAC9C;AAEA,UAAM,WAAkB;AAAA,MACtB,MAAM;AAAA,MACN,WAAW,KAAK,aAAa;AAAA,MAC7B;AAAA,MACA,WAAW,KAAK,kBAAkB;AAAA,MAClC,QAAQ,UAAU,CAAC;AAAA,MACnB,SAAS,KAAK,WAAW;AAAA,IAC3B;AAEA,WAAO,KAAK,SAAS,CAAC,QAAQ,CAAC;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UACJ,SACA,QACA,SACwB;AACxB,QAAI,KAAK,YAAY;AACnB,YAAM,IAAI,UAAU,sBAAsB,CAAC,CAAC;AAAA,IAC9C;AAEA,UAAM,WAAkB;AAAA,MACtB,MAAM;AAAA,MACN,WAAW,KAAK,aAAa;AAAA,MAC7B;AAAA,MACA,WAAW,KAAK,kBAAkB;AAAA,MAClC,QAAQ,UAAU,CAAC;AAAA,MACnB,SAAS,KAAK,WAAW;AAAA,IAC3B;AAEA,QAAI,SAAS,QAAQ;AACnB,eAAS,SAAS,QAAQ;AAAA,IAC5B;AAEA,WAAO,KAAK,SAAS,CAAC,QAAQ,CAAC;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,cAAc;AACrB,aAAO,KAAK;AAAA,IACd;AAEA,SAAK,eAAe,KAAK,QAAQ;AACjC,QAAI;AACF,YAAM,KAAK;AAAA,IACb,UAAE;AACA,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAC9B,QAAI,KAAK,YAAY;AACnB;AAAA,IACF;AAEA,SAAK,aAAa;AAElB,QAAI,KAAK,iBAAiB,OAAO,WAAW,aAAa;AACvD,aAAO,oBAAoB,gBAAgB,KAAK,aAAa;AAAA,IAC/D;AAEA,QAAI,KAAK,YAAY;AACnB,mBAAa,KAAK,UAAU;AAC5B,WAAK,aAAa;AAAA,IACpB;AAEA,UAAM,KAAK,MAAM;AAAA,EACnB;AAAA,EAEQ,QAAQ,OAAoB;AAElC,UAAM,YAAY,KAAK,kBAAkB,KAAK;AAC9C,QAAI,YAAY,sBAAsB;AACpC,WAAK,OAAO,OAAO;AAAA,QACjB,eAAe,SAAS,mBAAmB,oBAAoB;AAAA,MACjE;AACA;AAAA,IACF;AAGA,QAAI,KAAK,MAAM,UAAU,KAAK,OAAO,cAAc;AACjD,YAAM,UAAU,KAAK,MAAM,MAAM;AACjC,WAAK,OAAO,OAAO,KAAK,sCAAsC,SAAS,IAAI,EAAE;AAAA,IAC/E;AAEA,SAAK,MAAM,KAAK,KAAK;AACrB,SAAK,OAAO,OAAO,MAAM,YAAY,MAAM,IAAI,uBAAuB,KAAK,MAAM,MAAM,EAAE;AAGzF,QAAI,KAAK,MAAM,UAAU,KAAK,OAAO,cAAc;AACjD,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEA,MAAc,UAAyB;AACrC,QAAI,KAAK,MAAM,WAAW,GAAG;AAC3B;AAAA,IACF;AAGA,QAAI,KAAK,YAAY;AACnB,mBAAa,KAAK,UAAU;AAC5B,WAAK,aAAa;AAAA,IACpB;AAGA,WAAO,KAAK,MAAM,SAAS,GAAG;AAC5B,YAAM,QAAQ,KAAK,aAAa;AAChC,UAAI,MAAM,WAAW,GAAG;AACtB;AAAA,MACF;AAEA,YAAM,KAAK,UAAU,KAAK;AAAA,IAC5B;AAGA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,eAAwB;AAC9B,UAAM,QAAiB,CAAC;AACxB,QAAI,YAAY;AAEhB,WAAO,KAAK,MAAM,SAAS,KAAK,MAAM,SAAS,gBAAgB;AAC7D,YAAM,QAAQ,KAAK,MAAM,CAAC;AAC1B,YAAM,YAAY,KAAK,kBAAkB,KAAK;AAG9C,UAAI,YAAY,YAAY,sBAAsB;AAChD;AAAA,MACF;AAEA,YAAM,KAAK,KAAK,MAAM,MAAM,CAAE;AAC9B,mBAAa;AAAA,IACf;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,UAAU,OAA+B;AACrD,QAAI,MAAM,WAAW,GAAG;AACtB;AAAA,IACF;AAEA,SAAK,OAAO,OAAO,MAAM,oBAAoB,MAAM,MAAM,SAAS;AAClE,UAAM,SAAS,MAAM,KAAK,OAAO,KAAK;AAEtC,QAAI,WAAW,MAAM;AAEnB,YAAM,QAAQ,IAAI,MAAM,2BAA2B,MAAM,MAAM,uBAAuB;AACtF,WAAK,cAAc,OAAO,KAAK;AAAA,IACjC,WAAW,OAAO,SAAS,KAAK,OAAO,QAAQ;AAC7C,WAAK,OAAO,OAAO;AAAA,QACjB,qCAAqC,OAAO,QAAQ,aAAa,OAAO,MAAM;AAAA,QAC9E,OAAO;AAAA,MACT;AAEA,WAAK,gBAAgB,MAAM;AAAA,IAC7B,OAAO;AACL,WAAK,OAAO,OAAO,MAAM,sCAAsC,OAAO,QAAQ,EAAE;AAChF,WAAK,gBAAgB,MAAM;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAc,SAAS,QAAyC;AAC9D,SAAK,OAAO,OAAO,MAAM,WAAW,OAAO,MAAM,uBAAuB;AACxE,UAAM,SAAS,MAAM,KAAK,OAAO,MAAM;AAEvC,QAAI,WAAW,MAAM;AACnB,YAAM,IAAI,UAAU,kBAAkB,OAAO,MAAM,yBAAyB,MAAM;AAAA,IACpF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,OAAO,OAA+C;AAClE,UAAM,UAAwB,EAAE,MAAM;AACtC,UAAM,aAAa,GAAG,KAAK,OAAO,QAAQ;AAE1C,QAAI,UAAU;AACd,QAAI,QAAQ,KAAK,OAAO;AAExB,WAAO,UAAU,KAAK,OAAO,kBAAkB;AAC7C,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,YAAY;AAAA,UACvC,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,eAAe,UAAU,KAAK,OAAO,QAAQ;AAAA,UAC/C;AAAA,UACA,MAAM,KAAK,UAAU,OAAO;AAAA,QAC9B,CAAC;AAED,cAAM,OAAsB,MAAM,SAAS,KAAK;AAEhD,YAAI,SAAS,IAAI;AACf,iBAAO;AAAA,QACT;AAGA,YAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AAEtD,eAAK,OAAO,OAAO,MAAM,oBAAoB,SAAS,MAAM,MAAM,IAAI;AACtE,iBAAO;AAAA,QACT;AAGA,YAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,gBAAM,aAAa,SAAS,QAAQ,IAAI,aAAa;AACrD,cAAI,YAAY;AACd,oBAAQ,SAAS,YAAY,EAAE,IAAI;AAAA,UACrC;AAEA;AACA,cAAI,UAAU,KAAK,OAAO,kBAAkB;AAC1C,iBAAK,OAAO,OAAO,MAAM,kBAAkB,KAAK,eAAe,OAAO,GAAG;AACzE,kBAAM,KAAK,MAAM,KAAK;AACtB,oBAAQ,KAAK,IAAI,QAAQ,GAAG,IAAK;AACjC;AAAA,UACF;AAAA,QACF;AAGA;AACA,YAAI,UAAU,KAAK,OAAO,kBAAkB;AAC1C,eAAK,OAAO,OAAO,MAAM,kBAAkB,KAAK,eAAe,OAAO,GAAG;AACzE,gBAAM,KAAK,MAAM,KAAK;AACtB,kBAAQ,KAAK,IAAI,QAAQ,GAAG,IAAK;AAAA,QACnC;AAAA,MACF,SAAS,OAAO;AAEd;AACA,YAAI,UAAU,KAAK,OAAO,kBAAkB;AAC1C,eAAK,OAAO,OAAO,MAAM,kBAAkB,KAAK,eAAe,OAAO,GAAG;AACzE,gBAAM,KAAK,MAAM,KAAK;AACtB,kBAAQ,KAAK,IAAI,QAAQ,GAAG,IAAK;AAAA,QACnC,OAAO;AACL,eAAK,OAAO,OAAO,MAAM,uCAAuC,KAAK;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,cAAc,OAAc,OAAsB;AACxD,QAAI,KAAK,OAAO,SAAS;AACvB,UAAI;AACF,aAAK,OAAO,QAAQ,OAAO,KAAK;AAAA,MAClC,SAAS,GAAG;AACV,aAAK,OAAO,OAAO,MAAM,8BAA8B,CAAC;AAAA,MAC1D;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,gBAAgB,UAA+B;AACrD,QAAI,KAAK,OAAO,WAAW;AACzB,UAAI;AACF,aAAK,OAAO,UAAU,QAAQ;AAAA,MAChC,SAAS,GAAG;AACV,aAAK,OAAO,OAAO,MAAM,gCAAgC,CAAC;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,cAAc,KAAK,YAAY;AACtC;AAAA,IACF;AAEA,SAAK,aAAa,WAAW,MAAM;AACjC,WAAK,MAAM;AAAA,IACb,GAAG,KAAK,OAAO,aAAa;AAAA,EAC9B;AAAA,EAEQ,eAAuB;AAC7B,QAAI,OAAO,WAAW,eAAe,OAAO,YAAY;AACtD,aAAO,OAAO,WAAW;AAAA,IAC3B;AAEA,WAAO,uCAAuC,QAAQ,SAAS,CAAC,MAAM;AACpE,YAAM,IAAK,KAAK,OAAO,IAAI,KAAM;AACjC,YAAM,IAAI,MAAM,MAAM,IAAK,IAAI,IAAO;AACtC,aAAO,EAAE,SAAS,EAAE;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEQ,oBAA4B;AAClC,YAAO,oBAAI,KAAK,GAAE,YAAY;AAAA,EAChC;AAAA,EAEQ,aAA2B;AACjC,UAAM,UAAwB;AAAA,MAC5B,SAAS;AAAA,QACP,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,IACF;AAEA,QAAI,OAAO,cAAc,aAAa;AACpC,UAAI,UAAU,WAAW;AACvB,gBAAQ,YAAY,UAAU;AAAA,MAChC;AACA,UAAI,UAAU,UAAU;AACtB,gBAAQ,SAAS,UAAU;AAAA,MAC7B;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,eAAe,KAAK,gBAAgB;AACtD,UAAI;AACF,cAAM,WAAW,KAAK,eAAe,EAAE,gBAAgB,EAAE;AACzD,YAAI,UAAU;AACZ,kBAAQ,WAAW;AAAA,QACrB;AAAA,MACF,SAAS,GAAG;AAAA,MAEZ;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkB,OAAsB;AAE9C,QAAI;AACF,aAAO,KAAK,UAAU,KAAK,EAAE;AAAA,IAC/B,QAAQ;AAEN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,MAAM,IAA2B;AACvC,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACzD;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts"],"sourcesContent":["import {\n KlimeConfig,\n TrackOptions,\n Event,\n BatchRequest,\n BatchResponse,\n EventContext,\n Logger,\n SendError,\n} from \"./types\";\n\n// Re-export types for users\nexport { SendError, BatchResponse, Logger } from \"./types\";\nexport type { KlimeConfig, TrackOptions, Event } from \"./types\";\n\nconst DEFAULT_ENDPOINT = \"https://i.klime.com\";\nconst DEFAULT_FLUSH_INTERVAL = 2000;\nconst DEFAULT_MAX_BATCH_SIZE = 20;\nconst DEFAULT_MAX_QUEUE_SIZE = 1000;\nconst DEFAULT_RETRY_MAX_ATTEMPTS = 5;\nconst DEFAULT_RETRY_INITIAL_DELAY = 1000;\nconst MAX_BATCH_SIZE = 100;\nconst MAX_EVENT_SIZE_BYTES = 200 * 1024; // 200KB\nconst MAX_BATCH_SIZE_BYTES = 10 * 1024 * 1024; // 10MB\n/** Max body size for fetch keepalive (spec limit). Requests larger than this omit keepalive. */\nconst KEEPALIVE_MAX_BODY_BYTES = 64 * 1024; // 64KB\nconst SDK_VERSION = \"1.1.0\";\n\n// Default logger that wraps console with [Klime] prefix\nconst createDefaultLogger = (): Logger => ({\n debug: (message: string, ...args: any[]) =>\n console.debug(`[Klime] ${message}`, ...args),\n info: (message: string, ...args: any[]) =>\n console.info(`[Klime] ${message}`, ...args),\n warn: (message: string, ...args: any[]) =>\n console.warn(`[Klime] ${message}`, ...args),\n error: (message: string, ...args: any[]) =>\n console.error(`[Klime] ${message}`, ...args),\n});\n\n// Internal config type with required fields and optional callbacks/logger\ninterface InternalConfig {\n writeKey: string;\n endpoint: string;\n flushInterval: number;\n maxBatchSize: number;\n maxQueueSize: number;\n retryMaxAttempts: number;\n retryInitialDelay: number;\n autoFlushOnUnload: boolean;\n logger: Logger;\n onError?: (error: Error, events: Event[]) => void;\n onSuccess?: (response: BatchResponse) => void;\n}\n\nexport class KlimeClient {\n private config: InternalConfig;\n private queue: Event[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private isShutdown = false;\n private flushPromise: Promise<void> | null = null;\n private unloadHandler: (() => void) | null = null;\n private visibilityChangeHandler: (() => void) | null = null;\n\n constructor(config: KlimeConfig) {\n if (!config.writeKey) {\n throw new Error(\"writeKey is required\");\n }\n\n this.config = {\n writeKey: config.writeKey,\n endpoint: config.endpoint || DEFAULT_ENDPOINT,\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n maxBatchSize: Math.min(\n config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE,\n MAX_BATCH_SIZE\n ),\n maxQueueSize: config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE,\n retryMaxAttempts: config.retryMaxAttempts ?? DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay:\n config.retryInitialDelay ?? DEFAULT_RETRY_INITIAL_DELAY,\n autoFlushOnUnload: config.autoFlushOnUnload ?? true,\n logger: config.logger ?? createDefaultLogger(),\n onError: config.onError,\n onSuccess: config.onSuccess,\n };\n\n if (this.config.autoFlushOnUnload && typeof window !== \"undefined\") {\n this.unloadHandler = () => {\n this.flush();\n };\n window.addEventListener(\"beforeunload\", this.unloadHandler);\n window.addEventListener(\"pagehide\", this.unloadHandler);\n this.visibilityChangeHandler = () => {\n if (typeof document !== \"undefined\" && document.visibilityState === \"hidden\") {\n this.flush();\n }\n };\n document.addEventListener(\"visibilitychange\", this.visibilityChangeHandler);\n }\n\n this.scheduleFlush();\n }\n\n track(\n event: string,\n properties?: Record<string, any>,\n options?: TrackOptions\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"track\",\n messageId: this.generateUUID(),\n event,\n timestamp: this.generateTimestamp(),\n properties: properties || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n if (options?.groupId) {\n eventObj.groupId = options.groupId;\n }\n\n this.enqueue(eventObj);\n }\n\n identify(userId: string, traits?: Record<string, any>): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"identify\",\n messageId: this.generateUUID(),\n userId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n this.enqueue(eventObj);\n }\n\n group(\n groupId: string,\n traits?: Record<string, any>,\n options?: TrackOptions\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"group\",\n messageId: this.generateUUID(),\n groupId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n\n this.enqueue(eventObj);\n }\n\n /**\n * Track an event synchronously. Returns BatchResponse or throws SendError.\n */\n async trackSync(\n event: string,\n properties?: Record<string, any>,\n options?: TrackOptions\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"track\",\n messageId: this.generateUUID(),\n event,\n timestamp: this.generateTimestamp(),\n properties: properties || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n if (options?.groupId) {\n eventObj.groupId = options.groupId;\n }\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Identify a user synchronously. Returns BatchResponse or throws SendError.\n */\n async identifySync(\n userId: string,\n traits?: Record<string, any>\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"identify\",\n messageId: this.generateUUID(),\n userId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Associate a user with a group synchronously. Returns BatchResponse or throws SendError.\n */\n async groupSync(\n groupId: string,\n traits?: Record<string, any>,\n options?: TrackOptions\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"group\",\n messageId: this.generateUUID(),\n groupId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Return the number of events currently in the queue.\n */\n getQueueSize(): number {\n return this.queue.length;\n }\n\n async flush(): Promise<void> {\n if (this.flushPromise) {\n return this.flushPromise;\n }\n\n this.flushPromise = this.doFlush();\n try {\n await this.flushPromise;\n } finally {\n this.flushPromise = null;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.isShutdown) {\n return;\n }\n\n this.isShutdown = true;\n\n if (this.unloadHandler && typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", this.unloadHandler);\n window.removeEventListener(\"pagehide\", this.unloadHandler);\n }\n if (this.visibilityChangeHandler && typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", this.visibilityChangeHandler);\n }\n\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n await this.flush();\n }\n\n private enqueue(event: Event): void {\n // Check event size\n const eventSize = this.estimateEventSize(event);\n if (eventSize > MAX_EVENT_SIZE_BYTES) {\n this.config.logger.warn(\n `Event size (${eventSize} bytes) exceeds ${MAX_EVENT_SIZE_BYTES} bytes limit`\n );\n return;\n }\n\n // Drop oldest if queue is full\n if (this.queue.length >= this.config.maxQueueSize) {\n const dropped = this.queue.shift();\n this.config.logger.warn(`Queue full, dropping oldest event: ${dropped?.type}`);\n }\n\n this.queue.push(event);\n this.config.logger.debug(`Enqueued ${event.type} event, queue size: ${this.queue.length}`);\n\n // Check if we should flush immediately\n if (this.queue.length >= this.config.maxBatchSize) {\n this.flush();\n }\n }\n\n private async doFlush(): Promise<void> {\n if (this.queue.length === 0) {\n return;\n }\n\n // Clear the flush timer\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n // Process batches\n while (this.queue.length > 0) {\n const batch = this.extractBatch();\n if (batch.length === 0) {\n break;\n }\n\n await this.sendBatch(batch);\n }\n\n // Schedule next flush\n this.scheduleFlush();\n }\n\n private extractBatch(): Event[] {\n const batch: Event[] = [];\n let batchSize = 0;\n\n while (this.queue.length > 0 && batch.length < MAX_BATCH_SIZE) {\n const event = this.queue[0];\n const eventSize = this.estimateEventSize(event);\n\n // Check if adding this event would exceed batch size limit\n if (batchSize + eventSize > MAX_BATCH_SIZE_BYTES) {\n break;\n }\n\n batch.push(this.queue.shift()!);\n batchSize += eventSize;\n }\n\n return batch;\n }\n\n private async sendBatch(batch: Event[]): Promise<void> {\n if (batch.length === 0) {\n return;\n }\n\n this.config.logger.debug(`Sending batch of ${batch.length} events`);\n const result = await this.doSend(batch);\n\n if (result === null) {\n // Send failed after all retries\n const error = new Error(`Failed to send batch of ${batch.length} events after retries`);\n this.invokeOnError(error, batch);\n } else if (result.failed > 0 && result.errors) {\n this.config.logger.warn(\n `Batch partially failed. Accepted: ${result.accepted}, Failed: ${result.failed}`,\n result.errors\n );\n // Still invoke success callback since some events were accepted\n this.invokeOnSuccess(result);\n } else {\n this.config.logger.debug(`Batch sent successfully. Accepted: ${result.accepted}`);\n this.invokeOnSuccess(result);\n }\n }\n\n private async sendSync(events: Event[]): Promise<BatchResponse> {\n this.config.logger.debug(`Sending ${events.length} events synchronously`);\n const result = await this.doSend(events);\n\n if (result === null) {\n throw new SendError(`Failed to send ${events.length} events after retries`, events);\n }\n\n return result;\n }\n\n private async doSend(batch: Event[]): Promise<BatchResponse | null> {\n const request: BatchRequest = { batch };\n const requestUrl = `${this.config.endpoint}/v1/batch`;\n const body = JSON.stringify(request);\n const useKeepalive = body.length <= KEEPALIVE_MAX_BODY_BYTES;\n\n let attempt = 0;\n let delay = this.config.retryInitialDelay;\n\n while (attempt < this.config.retryMaxAttempts) {\n try {\n const response = await fetch(requestUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.writeKey}`,\n },\n body,\n keepalive: useKeepalive,\n });\n\n const data: BatchResponse = await response.json();\n\n if (response.ok) {\n return data;\n }\n\n // Handle error responses\n if (response.status === 400 || response.status === 401) {\n // Permanent errors - don't retry\n this.config.logger.error(`Permanent error (${response.status}):`, data);\n return null;\n }\n\n // Transient errors - retry with backoff\n if (response.status === 429 || response.status === 503) {\n const retryAfter = response.headers.get(\"Retry-After\");\n if (retryAfter) {\n delay = parseInt(retryAfter, 10) * 1000;\n }\n\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000); // Cap at 16s\n continue;\n }\n }\n\n // Other errors - retry\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000);\n }\n } catch (error) {\n // Network errors - retry\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000);\n } else {\n this.config.logger.error(\"Failed to send batch after retries:\", error);\n }\n }\n }\n\n return null;\n }\n\n private invokeOnError(error: Error, batch: Event[]): void {\n if (this.config.onError) {\n try {\n this.config.onError(error, batch);\n } catch (e) {\n this.config.logger.error(\"Error in onError callback:\", e);\n }\n }\n }\n\n private invokeOnSuccess(response: BatchResponse): void {\n if (this.config.onSuccess) {\n try {\n this.config.onSuccess(response);\n } catch (e) {\n this.config.logger.error(\"Error in onSuccess callback:\", e);\n }\n }\n }\n\n private scheduleFlush(): void {\n if (this.isShutdown || this.flushTimer) {\n return;\n }\n\n this.flushTimer = setTimeout(() => {\n this.flush();\n }, this.config.flushInterval);\n }\n\n private generateUUID(): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older browsers\n return \"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\n private generateTimestamp(): string {\n return new Date().toISOString();\n }\n\n private getContext(): EventContext {\n const context: EventContext = {\n library: {\n name: \"js-sdk\",\n version: SDK_VERSION,\n },\n };\n\n if (typeof navigator !== \"undefined\") {\n if (navigator.userAgent) {\n context.userAgent = navigator.userAgent;\n }\n if (navigator.language) {\n context.locale = navigator.language;\n }\n }\n\n if (typeof Intl !== \"undefined\" && Intl.DateTimeFormat) {\n try {\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n if (timezone) {\n context.timezone = timezone;\n }\n } catch (e) {\n // Ignore timezone errors\n }\n }\n\n return context;\n }\n\n private estimateEventSize(event: Event): number {\n // Rough estimate: JSON stringified size\n try {\n return JSON.stringify(event).length;\n } catch {\n // Fallback: rough estimate based on structure\n return 500; // Conservative estimate\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","export interface Logger {\n debug(message: string, ...args: any[]): void;\n info(message: string, ...args: any[]): void;\n warn(message: string, ...args: any[]): void;\n error(message: string, ...args: any[]): void;\n}\n\nexport interface KlimeConfig {\n writeKey: string;\n endpoint?: string;\n flushInterval?: number; // milliseconds, default 2000\n maxBatchSize?: number; // default 20, max 100\n maxQueueSize?: number; // default 1000\n retryMaxAttempts?: number; // default 5\n retryInitialDelay?: number; // milliseconds, default 1000\n autoFlushOnUnload?: boolean; // default true\n logger?: Logger; // optional custom logger\n onError?: (error: Error, events: Event[]) => void; // callback for batch failures\n onSuccess?: (response: BatchResponse) => void; // callback for successful sends\n}\n\nexport interface TrackOptions {\n userId?: string;\n groupId?: string;\n}\n\nexport interface Event {\n type: 'track' | 'identify' | 'group';\n messageId: string;\n event?: string; // required for track\n userId?: string; // required for identify\n groupId?: string; // required for group\n timestamp: string; // ISO 8601\n properties?: Record<string, any>; // for track\n traits?: Record<string, any>; // for identify/group\n context?: EventContext;\n}\n\nexport interface EventContext {\n library?: {\n name: string;\n version: string;\n };\n userAgent?: string;\n locale?: string;\n timezone?: string;\n}\n\nexport interface BatchRequest {\n batch: Event[];\n}\n\nexport interface BatchResponse {\n status: string;\n accepted: number;\n failed: number;\n errors?: ValidationError[];\n}\n\nexport interface ValidationError {\n index: number;\n message: string;\n code: string;\n}\n\nexport class SendError extends Error {\n events: Event[];\n\n constructor(message: string, events: Event[]) {\n super(message);\n this.name = 'SendError';\n this.events = events;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -64,6 +64,7 @@ declare class KlimeClient {
64
64
  private isShutdown;
65
65
  private flushPromise;
66
66
  private unloadHandler;
67
+ private visibilityChangeHandler;
67
68
  constructor(config: KlimeConfig);
68
69
  track(event: string, properties?: Record<string, any>, options?: TrackOptions): void;
69
70
  identify(userId: string, traits?: Record<string, any>): void;
package/dist/index.d.ts CHANGED
@@ -64,6 +64,7 @@ declare class KlimeClient {
64
64
  private isShutdown;
65
65
  private flushPromise;
66
66
  private unloadHandler;
67
+ private visibilityChangeHandler;
67
68
  constructor(config: KlimeConfig);
68
69
  track(event: string, properties?: Record<string, any>, options?: TrackOptions): void;
69
70
  identify(userId: string, traits?: Record<string, any>): void;
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ var DEFAULT_RETRY_INITIAL_DELAY = 1e3;
17
17
  var MAX_BATCH_SIZE = 100;
18
18
  var MAX_EVENT_SIZE_BYTES = 200 * 1024;
19
19
  var MAX_BATCH_SIZE_BYTES = 10 * 1024 * 1024;
20
+ var KEEPALIVE_MAX_BODY_BYTES = 64 * 1024;
20
21
  var SDK_VERSION = "1.1.0";
21
22
  var createDefaultLogger = () => ({
22
23
  debug: (message, ...args) => console.debug(`[Klime] ${message}`, ...args),
@@ -31,6 +32,7 @@ var KlimeClient = class {
31
32
  this.isShutdown = false;
32
33
  this.flushPromise = null;
33
34
  this.unloadHandler = null;
35
+ this.visibilityChangeHandler = null;
34
36
  if (!config.writeKey) {
35
37
  throw new Error("writeKey is required");
36
38
  }
@@ -55,6 +57,13 @@ var KlimeClient = class {
55
57
  this.flush();
56
58
  };
57
59
  window.addEventListener("beforeunload", this.unloadHandler);
60
+ window.addEventListener("pagehide", this.unloadHandler);
61
+ this.visibilityChangeHandler = () => {
62
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") {
63
+ this.flush();
64
+ }
65
+ };
66
+ document.addEventListener("visibilitychange", this.visibilityChangeHandler);
58
67
  }
59
68
  this.scheduleFlush();
60
69
  }
@@ -193,6 +202,10 @@ var KlimeClient = class {
193
202
  this.isShutdown = true;
194
203
  if (this.unloadHandler && typeof window !== "undefined") {
195
204
  window.removeEventListener("beforeunload", this.unloadHandler);
205
+ window.removeEventListener("pagehide", this.unloadHandler);
206
+ }
207
+ if (this.visibilityChangeHandler && typeof document !== "undefined") {
208
+ document.removeEventListener("visibilitychange", this.visibilityChangeHandler);
196
209
  }
197
210
  if (this.flushTimer) {
198
211
  clearTimeout(this.flushTimer);
@@ -280,6 +293,8 @@ var KlimeClient = class {
280
293
  async doSend(batch) {
281
294
  const request = { batch };
282
295
  const requestUrl = `${this.config.endpoint}/v1/batch`;
296
+ const body = JSON.stringify(request);
297
+ const useKeepalive = body.length <= KEEPALIVE_MAX_BODY_BYTES;
283
298
  let attempt = 0;
284
299
  let delay = this.config.retryInitialDelay;
285
300
  while (attempt < this.config.retryMaxAttempts) {
@@ -290,7 +305,8 @@ var KlimeClient = class {
290
305
  "Content-Type": "application/json",
291
306
  Authorization: `Bearer ${this.config.writeKey}`
292
307
  },
293
- body: JSON.stringify(request)
308
+ body,
309
+ keepalive: useKeepalive
294
310
  });
295
311
  const data = await response.json();
296
312
  if (response.ok) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/index.ts"],"sourcesContent":["export interface Logger {\n debug(message: string, ...args: any[]): void;\n info(message: string, ...args: any[]): void;\n warn(message: string, ...args: any[]): void;\n error(message: string, ...args: any[]): void;\n}\n\nexport interface KlimeConfig {\n writeKey: string;\n endpoint?: string;\n flushInterval?: number; // milliseconds, default 2000\n maxBatchSize?: number; // default 20, max 100\n maxQueueSize?: number; // default 1000\n retryMaxAttempts?: number; // default 5\n retryInitialDelay?: number; // milliseconds, default 1000\n autoFlushOnUnload?: boolean; // default true\n logger?: Logger; // optional custom logger\n onError?: (error: Error, events: Event[]) => void; // callback for batch failures\n onSuccess?: (response: BatchResponse) => void; // callback for successful sends\n}\n\nexport interface TrackOptions {\n userId?: string;\n groupId?: string;\n}\n\nexport interface Event {\n type: 'track' | 'identify' | 'group';\n messageId: string;\n event?: string; // required for track\n userId?: string; // required for identify\n groupId?: string; // required for group\n timestamp: string; // ISO 8601\n properties?: Record<string, any>; // for track\n traits?: Record<string, any>; // for identify/group\n context?: EventContext;\n}\n\nexport interface EventContext {\n library?: {\n name: string;\n version: string;\n };\n userAgent?: string;\n locale?: string;\n timezone?: string;\n}\n\nexport interface BatchRequest {\n batch: Event[];\n}\n\nexport interface BatchResponse {\n status: string;\n accepted: number;\n failed: number;\n errors?: ValidationError[];\n}\n\nexport interface ValidationError {\n index: number;\n message: string;\n code: string;\n}\n\nexport class SendError extends Error {\n events: Event[];\n\n constructor(message: string, events: Event[]) {\n super(message);\n this.name = 'SendError';\n this.events = events;\n }\n}\n","import {\n KlimeConfig,\n TrackOptions,\n Event,\n BatchRequest,\n BatchResponse,\n EventContext,\n Logger,\n SendError,\n} from \"./types\";\n\n// Re-export types for users\nexport { SendError, BatchResponse, Logger } from \"./types\";\nexport type { KlimeConfig, TrackOptions, Event } from \"./types\";\n\nconst DEFAULT_ENDPOINT = \"https://i.klime.com\";\nconst DEFAULT_FLUSH_INTERVAL = 2000;\nconst DEFAULT_MAX_BATCH_SIZE = 20;\nconst DEFAULT_MAX_QUEUE_SIZE = 1000;\nconst DEFAULT_RETRY_MAX_ATTEMPTS = 5;\nconst DEFAULT_RETRY_INITIAL_DELAY = 1000;\nconst MAX_BATCH_SIZE = 100;\nconst MAX_EVENT_SIZE_BYTES = 200 * 1024; // 200KB\nconst MAX_BATCH_SIZE_BYTES = 10 * 1024 * 1024; // 10MB\nconst SDK_VERSION = \"1.1.0\";\n\n// Default logger that wraps console with [Klime] prefix\nconst createDefaultLogger = (): Logger => ({\n debug: (message: string, ...args: any[]) =>\n console.debug(`[Klime] ${message}`, ...args),\n info: (message: string, ...args: any[]) =>\n console.info(`[Klime] ${message}`, ...args),\n warn: (message: string, ...args: any[]) =>\n console.warn(`[Klime] ${message}`, ...args),\n error: (message: string, ...args: any[]) =>\n console.error(`[Klime] ${message}`, ...args),\n});\n\n// Internal config type with required fields and optional callbacks/logger\ninterface InternalConfig {\n writeKey: string;\n endpoint: string;\n flushInterval: number;\n maxBatchSize: number;\n maxQueueSize: number;\n retryMaxAttempts: number;\n retryInitialDelay: number;\n autoFlushOnUnload: boolean;\n logger: Logger;\n onError?: (error: Error, events: Event[]) => void;\n onSuccess?: (response: BatchResponse) => void;\n}\n\nexport class KlimeClient {\n private config: InternalConfig;\n private queue: Event[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private isShutdown = false;\n private flushPromise: Promise<void> | null = null;\n private unloadHandler: ((e: BeforeUnloadEvent) => void) | null = null;\n\n constructor(config: KlimeConfig) {\n if (!config.writeKey) {\n throw new Error(\"writeKey is required\");\n }\n\n this.config = {\n writeKey: config.writeKey,\n endpoint: config.endpoint || DEFAULT_ENDPOINT,\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n maxBatchSize: Math.min(\n config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE,\n MAX_BATCH_SIZE\n ),\n maxQueueSize: config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE,\n retryMaxAttempts: config.retryMaxAttempts ?? DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay:\n config.retryInitialDelay ?? DEFAULT_RETRY_INITIAL_DELAY,\n autoFlushOnUnload: config.autoFlushOnUnload ?? true,\n logger: config.logger ?? createDefaultLogger(),\n onError: config.onError,\n onSuccess: config.onSuccess,\n };\n\n if (this.config.autoFlushOnUnload && typeof window !== \"undefined\") {\n this.unloadHandler = () => {\n this.flush();\n };\n window.addEventListener(\"beforeunload\", this.unloadHandler);\n }\n\n this.scheduleFlush();\n }\n\n track(\n event: string,\n properties?: Record<string, any>,\n options?: TrackOptions\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"track\",\n messageId: this.generateUUID(),\n event,\n timestamp: this.generateTimestamp(),\n properties: properties || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n if (options?.groupId) {\n eventObj.groupId = options.groupId;\n }\n\n this.enqueue(eventObj);\n }\n\n identify(userId: string, traits?: Record<string, any>): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"identify\",\n messageId: this.generateUUID(),\n userId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n this.enqueue(eventObj);\n }\n\n group(\n groupId: string,\n traits?: Record<string, any>,\n options?: TrackOptions\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"group\",\n messageId: this.generateUUID(),\n groupId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n\n this.enqueue(eventObj);\n }\n\n /**\n * Track an event synchronously. Returns BatchResponse or throws SendError.\n */\n async trackSync(\n event: string,\n properties?: Record<string, any>,\n options?: TrackOptions\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"track\",\n messageId: this.generateUUID(),\n event,\n timestamp: this.generateTimestamp(),\n properties: properties || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n if (options?.groupId) {\n eventObj.groupId = options.groupId;\n }\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Identify a user synchronously. Returns BatchResponse or throws SendError.\n */\n async identifySync(\n userId: string,\n traits?: Record<string, any>\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"identify\",\n messageId: this.generateUUID(),\n userId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Associate a user with a group synchronously. Returns BatchResponse or throws SendError.\n */\n async groupSync(\n groupId: string,\n traits?: Record<string, any>,\n options?: TrackOptions\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"group\",\n messageId: this.generateUUID(),\n groupId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Return the number of events currently in the queue.\n */\n getQueueSize(): number {\n return this.queue.length;\n }\n\n async flush(): Promise<void> {\n if (this.flushPromise) {\n return this.flushPromise;\n }\n\n this.flushPromise = this.doFlush();\n try {\n await this.flushPromise;\n } finally {\n this.flushPromise = null;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.isShutdown) {\n return;\n }\n\n this.isShutdown = true;\n\n if (this.unloadHandler && typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", this.unloadHandler);\n }\n\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n await this.flush();\n }\n\n private enqueue(event: Event): void {\n // Check event size\n const eventSize = this.estimateEventSize(event);\n if (eventSize > MAX_EVENT_SIZE_BYTES) {\n this.config.logger.warn(\n `Event size (${eventSize} bytes) exceeds ${MAX_EVENT_SIZE_BYTES} bytes limit`\n );\n return;\n }\n\n // Drop oldest if queue is full\n if (this.queue.length >= this.config.maxQueueSize) {\n const dropped = this.queue.shift();\n this.config.logger.warn(`Queue full, dropping oldest event: ${dropped?.type}`);\n }\n\n this.queue.push(event);\n this.config.logger.debug(`Enqueued ${event.type} event, queue size: ${this.queue.length}`);\n\n // Check if we should flush immediately\n if (this.queue.length >= this.config.maxBatchSize) {\n this.flush();\n }\n }\n\n private async doFlush(): Promise<void> {\n if (this.queue.length === 0) {\n return;\n }\n\n // Clear the flush timer\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n // Process batches\n while (this.queue.length > 0) {\n const batch = this.extractBatch();\n if (batch.length === 0) {\n break;\n }\n\n await this.sendBatch(batch);\n }\n\n // Schedule next flush\n this.scheduleFlush();\n }\n\n private extractBatch(): Event[] {\n const batch: Event[] = [];\n let batchSize = 0;\n\n while (this.queue.length > 0 && batch.length < MAX_BATCH_SIZE) {\n const event = this.queue[0];\n const eventSize = this.estimateEventSize(event);\n\n // Check if adding this event would exceed batch size limit\n if (batchSize + eventSize > MAX_BATCH_SIZE_BYTES) {\n break;\n }\n\n batch.push(this.queue.shift()!);\n batchSize += eventSize;\n }\n\n return batch;\n }\n\n private async sendBatch(batch: Event[]): Promise<void> {\n if (batch.length === 0) {\n return;\n }\n\n this.config.logger.debug(`Sending batch of ${batch.length} events`);\n const result = await this.doSend(batch);\n\n if (result === null) {\n // Send failed after all retries\n const error = new Error(`Failed to send batch of ${batch.length} events after retries`);\n this.invokeOnError(error, batch);\n } else if (result.failed > 0 && result.errors) {\n this.config.logger.warn(\n `Batch partially failed. Accepted: ${result.accepted}, Failed: ${result.failed}`,\n result.errors\n );\n // Still invoke success callback since some events were accepted\n this.invokeOnSuccess(result);\n } else {\n this.config.logger.debug(`Batch sent successfully. Accepted: ${result.accepted}`);\n this.invokeOnSuccess(result);\n }\n }\n\n private async sendSync(events: Event[]): Promise<BatchResponse> {\n this.config.logger.debug(`Sending ${events.length} events synchronously`);\n const result = await this.doSend(events);\n\n if (result === null) {\n throw new SendError(`Failed to send ${events.length} events after retries`, events);\n }\n\n return result;\n }\n\n private async doSend(batch: Event[]): Promise<BatchResponse | null> {\n const request: BatchRequest = { batch };\n const requestUrl = `${this.config.endpoint}/v1/batch`;\n\n let attempt = 0;\n let delay = this.config.retryInitialDelay;\n\n while (attempt < this.config.retryMaxAttempts) {\n try {\n const response = await fetch(requestUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.writeKey}`,\n },\n body: JSON.stringify(request),\n });\n\n const data: BatchResponse = await response.json();\n\n if (response.ok) {\n return data;\n }\n\n // Handle error responses\n if (response.status === 400 || response.status === 401) {\n // Permanent errors - don't retry\n this.config.logger.error(`Permanent error (${response.status}):`, data);\n return null;\n }\n\n // Transient errors - retry with backoff\n if (response.status === 429 || response.status === 503) {\n const retryAfter = response.headers.get(\"Retry-After\");\n if (retryAfter) {\n delay = parseInt(retryAfter, 10) * 1000;\n }\n\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000); // Cap at 16s\n continue;\n }\n }\n\n // Other errors - retry\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000);\n }\n } catch (error) {\n // Network errors - retry\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000);\n } else {\n this.config.logger.error(\"Failed to send batch after retries:\", error);\n }\n }\n }\n\n return null;\n }\n\n private invokeOnError(error: Error, batch: Event[]): void {\n if (this.config.onError) {\n try {\n this.config.onError(error, batch);\n } catch (e) {\n this.config.logger.error(\"Error in onError callback:\", e);\n }\n }\n }\n\n private invokeOnSuccess(response: BatchResponse): void {\n if (this.config.onSuccess) {\n try {\n this.config.onSuccess(response);\n } catch (e) {\n this.config.logger.error(\"Error in onSuccess callback:\", e);\n }\n }\n }\n\n private scheduleFlush(): void {\n if (this.isShutdown || this.flushTimer) {\n return;\n }\n\n this.flushTimer = setTimeout(() => {\n this.flush();\n }, this.config.flushInterval);\n }\n\n private generateUUID(): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older browsers\n return \"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\n private generateTimestamp(): string {\n return new Date().toISOString();\n }\n\n private getContext(): EventContext {\n const context: EventContext = {\n library: {\n name: \"js-sdk\",\n version: SDK_VERSION,\n },\n };\n\n if (typeof navigator !== \"undefined\") {\n if (navigator.userAgent) {\n context.userAgent = navigator.userAgent;\n }\n if (navigator.language) {\n context.locale = navigator.language;\n }\n }\n\n if (typeof Intl !== \"undefined\" && Intl.DateTimeFormat) {\n try {\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n if (timezone) {\n context.timezone = timezone;\n }\n } catch (e) {\n // Ignore timezone errors\n }\n }\n\n return context;\n }\n\n private estimateEventSize(event: Event): number {\n // Rough estimate: JSON stringified size\n try {\n return JSON.stringify(event).length;\n } catch {\n // Fallback: rough estimate based on structure\n return 500; // Conservative estimate\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/types.ts","../src/index.ts"],"sourcesContent":["export interface Logger {\n debug(message: string, ...args: any[]): void;\n info(message: string, ...args: any[]): void;\n warn(message: string, ...args: any[]): void;\n error(message: string, ...args: any[]): void;\n}\n\nexport interface KlimeConfig {\n writeKey: string;\n endpoint?: string;\n flushInterval?: number; // milliseconds, default 2000\n maxBatchSize?: number; // default 20, max 100\n maxQueueSize?: number; // default 1000\n retryMaxAttempts?: number; // default 5\n retryInitialDelay?: number; // milliseconds, default 1000\n autoFlushOnUnload?: boolean; // default true\n logger?: Logger; // optional custom logger\n onError?: (error: Error, events: Event[]) => void; // callback for batch failures\n onSuccess?: (response: BatchResponse) => void; // callback for successful sends\n}\n\nexport interface TrackOptions {\n userId?: string;\n groupId?: string;\n}\n\nexport interface Event {\n type: 'track' | 'identify' | 'group';\n messageId: string;\n event?: string; // required for track\n userId?: string; // required for identify\n groupId?: string; // required for group\n timestamp: string; // ISO 8601\n properties?: Record<string, any>; // for track\n traits?: Record<string, any>; // for identify/group\n context?: EventContext;\n}\n\nexport interface EventContext {\n library?: {\n name: string;\n version: string;\n };\n userAgent?: string;\n locale?: string;\n timezone?: string;\n}\n\nexport interface BatchRequest {\n batch: Event[];\n}\n\nexport interface BatchResponse {\n status: string;\n accepted: number;\n failed: number;\n errors?: ValidationError[];\n}\n\nexport interface ValidationError {\n index: number;\n message: string;\n code: string;\n}\n\nexport class SendError extends Error {\n events: Event[];\n\n constructor(message: string, events: Event[]) {\n super(message);\n this.name = 'SendError';\n this.events = events;\n }\n}\n","import {\n KlimeConfig,\n TrackOptions,\n Event,\n BatchRequest,\n BatchResponse,\n EventContext,\n Logger,\n SendError,\n} from \"./types\";\n\n// Re-export types for users\nexport { SendError, BatchResponse, Logger } from \"./types\";\nexport type { KlimeConfig, TrackOptions, Event } from \"./types\";\n\nconst DEFAULT_ENDPOINT = \"https://i.klime.com\";\nconst DEFAULT_FLUSH_INTERVAL = 2000;\nconst DEFAULT_MAX_BATCH_SIZE = 20;\nconst DEFAULT_MAX_QUEUE_SIZE = 1000;\nconst DEFAULT_RETRY_MAX_ATTEMPTS = 5;\nconst DEFAULT_RETRY_INITIAL_DELAY = 1000;\nconst MAX_BATCH_SIZE = 100;\nconst MAX_EVENT_SIZE_BYTES = 200 * 1024; // 200KB\nconst MAX_BATCH_SIZE_BYTES = 10 * 1024 * 1024; // 10MB\n/** Max body size for fetch keepalive (spec limit). Requests larger than this omit keepalive. */\nconst KEEPALIVE_MAX_BODY_BYTES = 64 * 1024; // 64KB\nconst SDK_VERSION = \"1.1.0\";\n\n// Default logger that wraps console with [Klime] prefix\nconst createDefaultLogger = (): Logger => ({\n debug: (message: string, ...args: any[]) =>\n console.debug(`[Klime] ${message}`, ...args),\n info: (message: string, ...args: any[]) =>\n console.info(`[Klime] ${message}`, ...args),\n warn: (message: string, ...args: any[]) =>\n console.warn(`[Klime] ${message}`, ...args),\n error: (message: string, ...args: any[]) =>\n console.error(`[Klime] ${message}`, ...args),\n});\n\n// Internal config type with required fields and optional callbacks/logger\ninterface InternalConfig {\n writeKey: string;\n endpoint: string;\n flushInterval: number;\n maxBatchSize: number;\n maxQueueSize: number;\n retryMaxAttempts: number;\n retryInitialDelay: number;\n autoFlushOnUnload: boolean;\n logger: Logger;\n onError?: (error: Error, events: Event[]) => void;\n onSuccess?: (response: BatchResponse) => void;\n}\n\nexport class KlimeClient {\n private config: InternalConfig;\n private queue: Event[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private isShutdown = false;\n private flushPromise: Promise<void> | null = null;\n private unloadHandler: (() => void) | null = null;\n private visibilityChangeHandler: (() => void) | null = null;\n\n constructor(config: KlimeConfig) {\n if (!config.writeKey) {\n throw new Error(\"writeKey is required\");\n }\n\n this.config = {\n writeKey: config.writeKey,\n endpoint: config.endpoint || DEFAULT_ENDPOINT,\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n maxBatchSize: Math.min(\n config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE,\n MAX_BATCH_SIZE\n ),\n maxQueueSize: config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE,\n retryMaxAttempts: config.retryMaxAttempts ?? DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay:\n config.retryInitialDelay ?? DEFAULT_RETRY_INITIAL_DELAY,\n autoFlushOnUnload: config.autoFlushOnUnload ?? true,\n logger: config.logger ?? createDefaultLogger(),\n onError: config.onError,\n onSuccess: config.onSuccess,\n };\n\n if (this.config.autoFlushOnUnload && typeof window !== \"undefined\") {\n this.unloadHandler = () => {\n this.flush();\n };\n window.addEventListener(\"beforeunload\", this.unloadHandler);\n window.addEventListener(\"pagehide\", this.unloadHandler);\n this.visibilityChangeHandler = () => {\n if (typeof document !== \"undefined\" && document.visibilityState === \"hidden\") {\n this.flush();\n }\n };\n document.addEventListener(\"visibilitychange\", this.visibilityChangeHandler);\n }\n\n this.scheduleFlush();\n }\n\n track(\n event: string,\n properties?: Record<string, any>,\n options?: TrackOptions\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"track\",\n messageId: this.generateUUID(),\n event,\n timestamp: this.generateTimestamp(),\n properties: properties || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n if (options?.groupId) {\n eventObj.groupId = options.groupId;\n }\n\n this.enqueue(eventObj);\n }\n\n identify(userId: string, traits?: Record<string, any>): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"identify\",\n messageId: this.generateUUID(),\n userId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n this.enqueue(eventObj);\n }\n\n group(\n groupId: string,\n traits?: Record<string, any>,\n options?: TrackOptions\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const eventObj: Event = {\n type: \"group\",\n messageId: this.generateUUID(),\n groupId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n\n this.enqueue(eventObj);\n }\n\n /**\n * Track an event synchronously. Returns BatchResponse or throws SendError.\n */\n async trackSync(\n event: string,\n properties?: Record<string, any>,\n options?: TrackOptions\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"track\",\n messageId: this.generateUUID(),\n event,\n timestamp: this.generateTimestamp(),\n properties: properties || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n if (options?.groupId) {\n eventObj.groupId = options.groupId;\n }\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Identify a user synchronously. Returns BatchResponse or throws SendError.\n */\n async identifySync(\n userId: string,\n traits?: Record<string, any>\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"identify\",\n messageId: this.generateUUID(),\n userId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Associate a user with a group synchronously. Returns BatchResponse or throws SendError.\n */\n async groupSync(\n groupId: string,\n traits?: Record<string, any>,\n options?: TrackOptions\n ): Promise<BatchResponse> {\n if (this.isShutdown) {\n throw new SendError(\"Client is shutdown\", []);\n }\n\n const eventObj: Event = {\n type: \"group\",\n messageId: this.generateUUID(),\n groupId,\n timestamp: this.generateTimestamp(),\n traits: traits || {},\n context: this.getContext(),\n };\n\n if (options?.userId) {\n eventObj.userId = options.userId;\n }\n\n return this.sendSync([eventObj]);\n }\n\n /**\n * Return the number of events currently in the queue.\n */\n getQueueSize(): number {\n return this.queue.length;\n }\n\n async flush(): Promise<void> {\n if (this.flushPromise) {\n return this.flushPromise;\n }\n\n this.flushPromise = this.doFlush();\n try {\n await this.flushPromise;\n } finally {\n this.flushPromise = null;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.isShutdown) {\n return;\n }\n\n this.isShutdown = true;\n\n if (this.unloadHandler && typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", this.unloadHandler);\n window.removeEventListener(\"pagehide\", this.unloadHandler);\n }\n if (this.visibilityChangeHandler && typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", this.visibilityChangeHandler);\n }\n\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n await this.flush();\n }\n\n private enqueue(event: Event): void {\n // Check event size\n const eventSize = this.estimateEventSize(event);\n if (eventSize > MAX_EVENT_SIZE_BYTES) {\n this.config.logger.warn(\n `Event size (${eventSize} bytes) exceeds ${MAX_EVENT_SIZE_BYTES} bytes limit`\n );\n return;\n }\n\n // Drop oldest if queue is full\n if (this.queue.length >= this.config.maxQueueSize) {\n const dropped = this.queue.shift();\n this.config.logger.warn(`Queue full, dropping oldest event: ${dropped?.type}`);\n }\n\n this.queue.push(event);\n this.config.logger.debug(`Enqueued ${event.type} event, queue size: ${this.queue.length}`);\n\n // Check if we should flush immediately\n if (this.queue.length >= this.config.maxBatchSize) {\n this.flush();\n }\n }\n\n private async doFlush(): Promise<void> {\n if (this.queue.length === 0) {\n return;\n }\n\n // Clear the flush timer\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n // Process batches\n while (this.queue.length > 0) {\n const batch = this.extractBatch();\n if (batch.length === 0) {\n break;\n }\n\n await this.sendBatch(batch);\n }\n\n // Schedule next flush\n this.scheduleFlush();\n }\n\n private extractBatch(): Event[] {\n const batch: Event[] = [];\n let batchSize = 0;\n\n while (this.queue.length > 0 && batch.length < MAX_BATCH_SIZE) {\n const event = this.queue[0];\n const eventSize = this.estimateEventSize(event);\n\n // Check if adding this event would exceed batch size limit\n if (batchSize + eventSize > MAX_BATCH_SIZE_BYTES) {\n break;\n }\n\n batch.push(this.queue.shift()!);\n batchSize += eventSize;\n }\n\n return batch;\n }\n\n private async sendBatch(batch: Event[]): Promise<void> {\n if (batch.length === 0) {\n return;\n }\n\n this.config.logger.debug(`Sending batch of ${batch.length} events`);\n const result = await this.doSend(batch);\n\n if (result === null) {\n // Send failed after all retries\n const error = new Error(`Failed to send batch of ${batch.length} events after retries`);\n this.invokeOnError(error, batch);\n } else if (result.failed > 0 && result.errors) {\n this.config.logger.warn(\n `Batch partially failed. Accepted: ${result.accepted}, Failed: ${result.failed}`,\n result.errors\n );\n // Still invoke success callback since some events were accepted\n this.invokeOnSuccess(result);\n } else {\n this.config.logger.debug(`Batch sent successfully. Accepted: ${result.accepted}`);\n this.invokeOnSuccess(result);\n }\n }\n\n private async sendSync(events: Event[]): Promise<BatchResponse> {\n this.config.logger.debug(`Sending ${events.length} events synchronously`);\n const result = await this.doSend(events);\n\n if (result === null) {\n throw new SendError(`Failed to send ${events.length} events after retries`, events);\n }\n\n return result;\n }\n\n private async doSend(batch: Event[]): Promise<BatchResponse | null> {\n const request: BatchRequest = { batch };\n const requestUrl = `${this.config.endpoint}/v1/batch`;\n const body = JSON.stringify(request);\n const useKeepalive = body.length <= KEEPALIVE_MAX_BODY_BYTES;\n\n let attempt = 0;\n let delay = this.config.retryInitialDelay;\n\n while (attempt < this.config.retryMaxAttempts) {\n try {\n const response = await fetch(requestUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.writeKey}`,\n },\n body,\n keepalive: useKeepalive,\n });\n\n const data: BatchResponse = await response.json();\n\n if (response.ok) {\n return data;\n }\n\n // Handle error responses\n if (response.status === 400 || response.status === 401) {\n // Permanent errors - don't retry\n this.config.logger.error(`Permanent error (${response.status}):`, data);\n return null;\n }\n\n // Transient errors - retry with backoff\n if (response.status === 429 || response.status === 503) {\n const retryAfter = response.headers.get(\"Retry-After\");\n if (retryAfter) {\n delay = parseInt(retryAfter, 10) * 1000;\n }\n\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000); // Cap at 16s\n continue;\n }\n }\n\n // Other errors - retry\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000);\n }\n } catch (error) {\n // Network errors - retry\n attempt++;\n if (attempt < this.config.retryMaxAttempts) {\n this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);\n await this.sleep(delay);\n delay = Math.min(delay * 2, 16000);\n } else {\n this.config.logger.error(\"Failed to send batch after retries:\", error);\n }\n }\n }\n\n return null;\n }\n\n private invokeOnError(error: Error, batch: Event[]): void {\n if (this.config.onError) {\n try {\n this.config.onError(error, batch);\n } catch (e) {\n this.config.logger.error(\"Error in onError callback:\", e);\n }\n }\n }\n\n private invokeOnSuccess(response: BatchResponse): void {\n if (this.config.onSuccess) {\n try {\n this.config.onSuccess(response);\n } catch (e) {\n this.config.logger.error(\"Error in onSuccess callback:\", e);\n }\n }\n }\n\n private scheduleFlush(): void {\n if (this.isShutdown || this.flushTimer) {\n return;\n }\n\n this.flushTimer = setTimeout(() => {\n this.flush();\n }, this.config.flushInterval);\n }\n\n private generateUUID(): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older browsers\n return \"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\n private generateTimestamp(): string {\n return new Date().toISOString();\n }\n\n private getContext(): EventContext {\n const context: EventContext = {\n library: {\n name: \"js-sdk\",\n version: SDK_VERSION,\n },\n };\n\n if (typeof navigator !== \"undefined\") {\n if (navigator.userAgent) {\n context.userAgent = navigator.userAgent;\n }\n if (navigator.language) {\n context.locale = navigator.language;\n }\n }\n\n if (typeof Intl !== \"undefined\" && Intl.DateTimeFormat) {\n try {\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n if (timezone) {\n context.timezone = timezone;\n }\n } catch (e) {\n // Ignore timezone errors\n }\n }\n\n return context;\n }\n\n private estimateEventSize(event: Event): number {\n // Rough estimate: JSON stringified size\n try {\n return JSON.stringify(event).length;\n } catch {\n // Fallback: rough estimate based on structure\n return 500; // Conservative estimate\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klime/browser",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "type": "module",
5
5
  "description": "Klime SDK for browsers",
6
6
  "main": "dist/index.cjs",