@klime/browser 1.0.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,296 +1,415 @@
1
- const DEFAULT_ENDPOINT = "https://i.klime.com";
2
- const DEFAULT_FLUSH_INTERVAL = 2000;
3
- const DEFAULT_MAX_BATCH_SIZE = 20;
4
- const DEFAULT_MAX_QUEUE_SIZE = 1000;
5
- const DEFAULT_RETRY_MAX_ATTEMPTS = 5;
6
- const DEFAULT_RETRY_INITIAL_DELAY = 1000;
7
- const MAX_BATCH_SIZE = 100;
8
- const MAX_EVENT_SIZE_BYTES = 200 * 1024; // 200KB
9
- const MAX_BATCH_SIZE_BYTES = 10 * 1024 * 1024; // 10MB
10
- const SDK_VERSION = "1.0.1";
11
- export class KlimeClient {
12
- constructor(config) {
13
- this.queue = [];
14
- this.flushTimer = null;
15
- this.isShutdown = false;
16
- this.flushPromise = null;
17
- this.unloadHandler = null;
18
- if (!config.writeKey) {
19
- throw new Error("writeKey is required");
20
- }
21
- this.config = {
22
- writeKey: config.writeKey,
23
- endpoint: config.endpoint || DEFAULT_ENDPOINT,
24
- flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,
25
- maxBatchSize: Math.min(config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE, MAX_BATCH_SIZE),
26
- maxQueueSize: config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE,
27
- retryMaxAttempts: config.retryMaxAttempts ?? DEFAULT_RETRY_MAX_ATTEMPTS,
28
- retryInitialDelay: config.retryInitialDelay ?? DEFAULT_RETRY_INITIAL_DELAY,
29
- autoFlushOnUnload: config.autoFlushOnUnload ?? true,
30
- };
31
- if (this.config.autoFlushOnUnload && typeof window !== "undefined") {
32
- this.unloadHandler = () => {
33
- this.flush();
34
- };
35
- window.addEventListener("beforeunload", this.unloadHandler);
36
- }
37
- this.scheduleFlush();
1
+ // src/types.ts
2
+ var SendError = class extends Error {
3
+ constructor(message, events) {
4
+ super(message);
5
+ this.name = "SendError";
6
+ this.events = events;
7
+ }
8
+ };
9
+
10
+ // src/index.ts
11
+ var DEFAULT_ENDPOINT = "https://i.klime.com";
12
+ var DEFAULT_FLUSH_INTERVAL = 2e3;
13
+ var DEFAULT_MAX_BATCH_SIZE = 20;
14
+ var DEFAULT_MAX_QUEUE_SIZE = 1e3;
15
+ var DEFAULT_RETRY_MAX_ATTEMPTS = 5;
16
+ var DEFAULT_RETRY_INITIAL_DELAY = 1e3;
17
+ var MAX_BATCH_SIZE = 100;
18
+ var MAX_EVENT_SIZE_BYTES = 200 * 1024;
19
+ var MAX_BATCH_SIZE_BYTES = 10 * 1024 * 1024;
20
+ var SDK_VERSION = "1.1.0";
21
+ var createDefaultLogger = () => ({
22
+ debug: (message, ...args) => console.debug(`[Klime] ${message}`, ...args),
23
+ info: (message, ...args) => console.info(`[Klime] ${message}`, ...args),
24
+ warn: (message, ...args) => console.warn(`[Klime] ${message}`, ...args),
25
+ error: (message, ...args) => console.error(`[Klime] ${message}`, ...args)
26
+ });
27
+ var KlimeClient = class {
28
+ constructor(config) {
29
+ this.queue = [];
30
+ this.flushTimer = null;
31
+ this.isShutdown = false;
32
+ this.flushPromise = null;
33
+ this.unloadHandler = null;
34
+ if (!config.writeKey) {
35
+ throw new Error("writeKey is required");
38
36
  }
39
- track(event, properties, options) {
40
- if (this.isShutdown) {
41
- return;
42
- }
43
- const eventObj = {
44
- type: "track",
45
- messageId: this.generateUUID(),
46
- event,
47
- timestamp: this.generateTimestamp(),
48
- properties: properties || {},
49
- context: this.getContext(),
50
- };
51
- if (options?.userId) {
52
- eventObj.userId = options.userId;
53
- }
54
- if (options?.groupId) {
55
- eventObj.groupId = options.groupId;
56
- }
57
- this.enqueue(eventObj);
37
+ this.config = {
38
+ writeKey: config.writeKey,
39
+ endpoint: config.endpoint || DEFAULT_ENDPOINT,
40
+ flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,
41
+ maxBatchSize: Math.min(
42
+ config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE,
43
+ MAX_BATCH_SIZE
44
+ ),
45
+ maxQueueSize: config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE,
46
+ retryMaxAttempts: config.retryMaxAttempts ?? DEFAULT_RETRY_MAX_ATTEMPTS,
47
+ retryInitialDelay: config.retryInitialDelay ?? DEFAULT_RETRY_INITIAL_DELAY,
48
+ autoFlushOnUnload: config.autoFlushOnUnload ?? true,
49
+ logger: config.logger ?? createDefaultLogger(),
50
+ onError: config.onError,
51
+ onSuccess: config.onSuccess
52
+ };
53
+ if (this.config.autoFlushOnUnload && typeof window !== "undefined") {
54
+ this.unloadHandler = () => {
55
+ this.flush();
56
+ };
57
+ window.addEventListener("beforeunload", this.unloadHandler);
58
58
  }
59
- identify(userId, traits) {
60
- if (this.isShutdown) {
61
- return;
62
- }
63
- const eventObj = {
64
- type: "identify",
65
- messageId: this.generateUUID(),
66
- userId,
67
- timestamp: this.generateTimestamp(),
68
- traits: traits || {},
69
- context: this.getContext(),
70
- };
71
- this.enqueue(eventObj);
72
- }
73
- group(groupId, traits, options) {
74
- if (this.isShutdown) {
75
- return;
76
- }
77
- const eventObj = {
78
- type: "group",
79
- messageId: this.generateUUID(),
80
- groupId,
81
- timestamp: this.generateTimestamp(),
82
- traits: traits || {},
83
- context: this.getContext(),
84
- };
85
- if (options?.userId) {
86
- eventObj.userId = options.userId;
87
- }
88
- this.enqueue(eventObj);
59
+ this.scheduleFlush();
60
+ }
61
+ track(event, properties, options) {
62
+ if (this.isShutdown) {
63
+ return;
89
64
  }
90
- async flush() {
91
- if (this.flushPromise) {
92
- return this.flushPromise;
93
- }
94
- this.flushPromise = this.doFlush();
95
- try {
96
- await this.flushPromise;
97
- }
98
- finally {
99
- this.flushPromise = null;
100
- }
65
+ const eventObj = {
66
+ type: "track",
67
+ messageId: this.generateUUID(),
68
+ event,
69
+ timestamp: this.generateTimestamp(),
70
+ properties: properties || {},
71
+ context: this.getContext()
72
+ };
73
+ if (options?.userId) {
74
+ eventObj.userId = options.userId;
101
75
  }
102
- async shutdown() {
103
- if (this.isShutdown) {
104
- return;
105
- }
106
- this.isShutdown = true;
107
- if (this.unloadHandler && typeof window !== "undefined") {
108
- window.removeEventListener("beforeunload", this.unloadHandler);
76
+ if (options?.groupId) {
77
+ eventObj.groupId = options.groupId;
78
+ }
79
+ this.enqueue(eventObj);
80
+ }
81
+ identify(userId, traits) {
82
+ if (this.isShutdown) {
83
+ return;
84
+ }
85
+ const eventObj = {
86
+ type: "identify",
87
+ messageId: this.generateUUID(),
88
+ userId,
89
+ timestamp: this.generateTimestamp(),
90
+ traits: traits || {},
91
+ context: this.getContext()
92
+ };
93
+ this.enqueue(eventObj);
94
+ }
95
+ group(groupId, traits, options) {
96
+ if (this.isShutdown) {
97
+ return;
98
+ }
99
+ const eventObj = {
100
+ type: "group",
101
+ messageId: this.generateUUID(),
102
+ groupId,
103
+ timestamp: this.generateTimestamp(),
104
+ traits: traits || {},
105
+ context: this.getContext()
106
+ };
107
+ if (options?.userId) {
108
+ eventObj.userId = options.userId;
109
+ }
110
+ this.enqueue(eventObj);
111
+ }
112
+ /**
113
+ * Track an event synchronously. Returns BatchResponse or throws SendError.
114
+ */
115
+ async trackSync(event, properties, options) {
116
+ if (this.isShutdown) {
117
+ throw new SendError("Client is shutdown", []);
118
+ }
119
+ const eventObj = {
120
+ type: "track",
121
+ messageId: this.generateUUID(),
122
+ event,
123
+ timestamp: this.generateTimestamp(),
124
+ properties: properties || {},
125
+ context: this.getContext()
126
+ };
127
+ if (options?.userId) {
128
+ eventObj.userId = options.userId;
129
+ }
130
+ if (options?.groupId) {
131
+ eventObj.groupId = options.groupId;
132
+ }
133
+ return this.sendSync([eventObj]);
134
+ }
135
+ /**
136
+ * Identify a user synchronously. Returns BatchResponse or throws SendError.
137
+ */
138
+ async identifySync(userId, traits) {
139
+ if (this.isShutdown) {
140
+ throw new SendError("Client is shutdown", []);
141
+ }
142
+ const eventObj = {
143
+ type: "identify",
144
+ messageId: this.generateUUID(),
145
+ userId,
146
+ timestamp: this.generateTimestamp(),
147
+ traits: traits || {},
148
+ context: this.getContext()
149
+ };
150
+ return this.sendSync([eventObj]);
151
+ }
152
+ /**
153
+ * Associate a user with a group synchronously. Returns BatchResponse or throws SendError.
154
+ */
155
+ async groupSync(groupId, traits, options) {
156
+ if (this.isShutdown) {
157
+ throw new SendError("Client is shutdown", []);
158
+ }
159
+ const eventObj = {
160
+ type: "group",
161
+ messageId: this.generateUUID(),
162
+ groupId,
163
+ timestamp: this.generateTimestamp(),
164
+ traits: traits || {},
165
+ context: this.getContext()
166
+ };
167
+ if (options?.userId) {
168
+ eventObj.userId = options.userId;
169
+ }
170
+ return this.sendSync([eventObj]);
171
+ }
172
+ /**
173
+ * Return the number of events currently in the queue.
174
+ */
175
+ getQueueSize() {
176
+ return this.queue.length;
177
+ }
178
+ async flush() {
179
+ if (this.flushPromise) {
180
+ return this.flushPromise;
181
+ }
182
+ this.flushPromise = this.doFlush();
183
+ try {
184
+ await this.flushPromise;
185
+ } finally {
186
+ this.flushPromise = null;
187
+ }
188
+ }
189
+ async shutdown() {
190
+ if (this.isShutdown) {
191
+ return;
192
+ }
193
+ this.isShutdown = true;
194
+ if (this.unloadHandler && typeof window !== "undefined") {
195
+ window.removeEventListener("beforeunload", this.unloadHandler);
196
+ }
197
+ if (this.flushTimer) {
198
+ clearTimeout(this.flushTimer);
199
+ this.flushTimer = null;
200
+ }
201
+ await this.flush();
202
+ }
203
+ enqueue(event) {
204
+ const eventSize = this.estimateEventSize(event);
205
+ if (eventSize > MAX_EVENT_SIZE_BYTES) {
206
+ this.config.logger.warn(
207
+ `Event size (${eventSize} bytes) exceeds ${MAX_EVENT_SIZE_BYTES} bytes limit`
208
+ );
209
+ return;
210
+ }
211
+ if (this.queue.length >= this.config.maxQueueSize) {
212
+ const dropped = this.queue.shift();
213
+ this.config.logger.warn(`Queue full, dropping oldest event: ${dropped?.type}`);
214
+ }
215
+ this.queue.push(event);
216
+ this.config.logger.debug(`Enqueued ${event.type} event, queue size: ${this.queue.length}`);
217
+ if (this.queue.length >= this.config.maxBatchSize) {
218
+ this.flush();
219
+ }
220
+ }
221
+ async doFlush() {
222
+ if (this.queue.length === 0) {
223
+ return;
224
+ }
225
+ if (this.flushTimer) {
226
+ clearTimeout(this.flushTimer);
227
+ this.flushTimer = null;
228
+ }
229
+ while (this.queue.length > 0) {
230
+ const batch = this.extractBatch();
231
+ if (batch.length === 0) {
232
+ break;
233
+ }
234
+ await this.sendBatch(batch);
235
+ }
236
+ this.scheduleFlush();
237
+ }
238
+ extractBatch() {
239
+ const batch = [];
240
+ let batchSize = 0;
241
+ while (this.queue.length > 0 && batch.length < MAX_BATCH_SIZE) {
242
+ const event = this.queue[0];
243
+ const eventSize = this.estimateEventSize(event);
244
+ if (batchSize + eventSize > MAX_BATCH_SIZE_BYTES) {
245
+ break;
246
+ }
247
+ batch.push(this.queue.shift());
248
+ batchSize += eventSize;
249
+ }
250
+ return batch;
251
+ }
252
+ async sendBatch(batch) {
253
+ if (batch.length === 0) {
254
+ return;
255
+ }
256
+ this.config.logger.debug(`Sending batch of ${batch.length} events`);
257
+ const result = await this.doSend(batch);
258
+ if (result === null) {
259
+ const error = new Error(`Failed to send batch of ${batch.length} events after retries`);
260
+ this.invokeOnError(error, batch);
261
+ } else if (result.failed > 0 && result.errors) {
262
+ this.config.logger.warn(
263
+ `Batch partially failed. Accepted: ${result.accepted}, Failed: ${result.failed}`,
264
+ result.errors
265
+ );
266
+ this.invokeOnSuccess(result);
267
+ } else {
268
+ this.config.logger.debug(`Batch sent successfully. Accepted: ${result.accepted}`);
269
+ this.invokeOnSuccess(result);
270
+ }
271
+ }
272
+ async sendSync(events) {
273
+ this.config.logger.debug(`Sending ${events.length} events synchronously`);
274
+ const result = await this.doSend(events);
275
+ if (result === null) {
276
+ throw new SendError(`Failed to send ${events.length} events after retries`, events);
277
+ }
278
+ return result;
279
+ }
280
+ async doSend(batch) {
281
+ const request = { batch };
282
+ const requestUrl = `${this.config.endpoint}/v1/batch`;
283
+ let attempt = 0;
284
+ let delay = this.config.retryInitialDelay;
285
+ while (attempt < this.config.retryMaxAttempts) {
286
+ try {
287
+ const response = await fetch(requestUrl, {
288
+ method: "POST",
289
+ headers: {
290
+ "Content-Type": "application/json",
291
+ Authorization: `Bearer ${this.config.writeKey}`
292
+ },
293
+ body: JSON.stringify(request)
294
+ });
295
+ const data = await response.json();
296
+ if (response.ok) {
297
+ return data;
109
298
  }
110
- if (this.flushTimer) {
111
- clearTimeout(this.flushTimer);
112
- this.flushTimer = null;
299
+ if (response.status === 400 || response.status === 401) {
300
+ this.config.logger.error(`Permanent error (${response.status}):`, data);
301
+ return null;
113
302
  }
114
- await this.flush();
115
- }
116
- enqueue(event) {
117
- // Check event size
118
- const eventSize = this.estimateEventSize(event);
119
- if (eventSize > MAX_EVENT_SIZE_BYTES) {
120
- console.error(`Klime: Event size (${eventSize} bytes) exceeds ${MAX_EVENT_SIZE_BYTES} bytes limit`);
121
- return;
303
+ if (response.status === 429 || response.status === 503) {
304
+ const retryAfter = response.headers.get("Retry-After");
305
+ if (retryAfter) {
306
+ delay = parseInt(retryAfter, 10) * 1e3;
307
+ }
308
+ attempt++;
309
+ if (attempt < this.config.retryMaxAttempts) {
310
+ this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);
311
+ await this.sleep(delay);
312
+ delay = Math.min(delay * 2, 16e3);
313
+ continue;
314
+ }
122
315
  }
123
- // Drop oldest if queue is full
124
- if (this.queue.length >= this.config.maxQueueSize) {
125
- this.queue.shift();
316
+ attempt++;
317
+ if (attempt < this.config.retryMaxAttempts) {
318
+ this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);
319
+ await this.sleep(delay);
320
+ delay = Math.min(delay * 2, 16e3);
126
321
  }
127
- this.queue.push(event);
128
- // Check if we should flush immediately
129
- if (this.queue.length >= this.config.maxBatchSize) {
130
- this.flush();
322
+ } catch (error) {
323
+ attempt++;
324
+ if (attempt < this.config.retryMaxAttempts) {
325
+ this.config.logger.debug(`Retrying after ${delay}ms (attempt ${attempt})`);
326
+ await this.sleep(delay);
327
+ delay = Math.min(delay * 2, 16e3);
328
+ } else {
329
+ this.config.logger.error("Failed to send batch after retries:", error);
131
330
  }
331
+ }
132
332
  }
133
- async doFlush() {
134
- if (this.queue.length === 0) {
135
- return;
136
- }
137
- // Clear the flush timer
138
- if (this.flushTimer) {
139
- clearTimeout(this.flushTimer);
140
- this.flushTimer = null;
141
- }
142
- // Process batches
143
- while (this.queue.length > 0) {
144
- const batch = this.extractBatch();
145
- if (batch.length === 0) {
146
- break;
147
- }
148
- await this.sendBatch(batch);
149
- }
150
- // Schedule next flush
151
- this.scheduleFlush();
152
- }
153
- extractBatch() {
154
- const batch = [];
155
- let batchSize = 0;
156
- while (this.queue.length > 0 && batch.length < MAX_BATCH_SIZE) {
157
- const event = this.queue[0];
158
- const eventSize = this.estimateEventSize(event);
159
- // Check if adding this event would exceed batch size limit
160
- if (batchSize + eventSize > MAX_BATCH_SIZE_BYTES) {
161
- break;
162
- }
163
- batch.push(this.queue.shift());
164
- batchSize += eventSize;
165
- }
166
- return batch;
333
+ return null;
334
+ }
335
+ invokeOnError(error, batch) {
336
+ if (this.config.onError) {
337
+ try {
338
+ this.config.onError(error, batch);
339
+ } catch (e) {
340
+ this.config.logger.error("Error in onError callback:", e);
341
+ }
167
342
  }
168
- async sendBatch(batch) {
169
- if (batch.length === 0) {
170
- return;
171
- }
172
- const request = { batch };
173
- const url = `${this.config.endpoint}/v1/batch`;
174
- let attempt = 0;
175
- let delay = this.config.retryInitialDelay;
176
- while (attempt < this.config.retryMaxAttempts) {
177
- try {
178
- const response = await fetch(url, {
179
- method: "POST",
180
- headers: {
181
- "Content-Type": "application/json",
182
- Authorization: `Bearer ${this.config.writeKey}`,
183
- },
184
- body: JSON.stringify(request),
185
- });
186
- const data = await response.json();
187
- if (response.ok) {
188
- // Success - check for partial failures
189
- if (data.failed > 0 && data.errors) {
190
- console.warn(`Klime: Batch partially failed. Accepted: ${data.accepted}, Failed: ${data.failed}`, data.errors);
191
- }
192
- return;
193
- }
194
- // Handle error responses
195
- if (response.status === 400 || response.status === 401) {
196
- // Permanent errors - don't retry
197
- console.error(`Klime: Permanent error (${response.status}):`, data);
198
- return;
199
- }
200
- // Transient errors - retry with backoff
201
- if (response.status === 429 || response.status === 503) {
202
- const retryAfter = response.headers.get("Retry-After");
203
- if (retryAfter) {
204
- delay = parseInt(retryAfter, 10) * 1000;
205
- }
206
- attempt++;
207
- if (attempt < this.config.retryMaxAttempts) {
208
- await this.sleep(delay);
209
- delay = Math.min(delay * 2, 16000); // Cap at 16s
210
- continue;
211
- }
212
- }
213
- // Other errors - retry
214
- attempt++;
215
- if (attempt < this.config.retryMaxAttempts) {
216
- await this.sleep(delay);
217
- delay = Math.min(delay * 2, 16000);
218
- }
219
- }
220
- catch (error) {
221
- // Network errors - retry
222
- attempt++;
223
- if (attempt < this.config.retryMaxAttempts) {
224
- await this.sleep(delay);
225
- delay = Math.min(delay * 2, 16000);
226
- }
227
- else {
228
- console.error("Klime: Failed to send batch after retries:", error);
229
- }
230
- }
231
- }
343
+ }
344
+ invokeOnSuccess(response) {
345
+ if (this.config.onSuccess) {
346
+ try {
347
+ this.config.onSuccess(response);
348
+ } catch (e) {
349
+ this.config.logger.error("Error in onSuccess callback:", e);
350
+ }
232
351
  }
233
- scheduleFlush() {
234
- if (this.isShutdown || this.flushTimer) {
235
- return;
236
- }
237
- this.flushTimer = setTimeout(() => {
238
- this.flush();
239
- }, this.config.flushInterval);
352
+ }
353
+ scheduleFlush() {
354
+ if (this.isShutdown || this.flushTimer) {
355
+ return;
240
356
  }
241
- generateUUID() {
242
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
243
- return crypto.randomUUID();
244
- }
245
- // Fallback for older browsers
246
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
247
- const r = (Math.random() * 16) | 0;
248
- const v = c === "x" ? r : (r & 0x3) | 0x8;
249
- return v.toString(16);
250
- });
357
+ this.flushTimer = setTimeout(() => {
358
+ this.flush();
359
+ }, this.config.flushInterval);
360
+ }
361
+ generateUUID() {
362
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
363
+ return crypto.randomUUID();
251
364
  }
252
- generateTimestamp() {
253
- return new Date().toISOString();
254
- }
255
- getContext() {
256
- const context = {
257
- library: {
258
- name: "js-sdk",
259
- version: SDK_VERSION,
260
- },
261
- };
262
- if (typeof navigator !== "undefined") {
263
- if (navigator.userAgent) {
264
- context.userAgent = navigator.userAgent;
265
- }
266
- if (navigator.language) {
267
- context.locale = navigator.language;
268
- }
269
- }
270
- if (typeof Intl !== "undefined" && Intl.DateTimeFormat) {
271
- try {
272
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
273
- if (timezone) {
274
- context.timezone = timezone;
275
- }
276
- }
277
- catch (e) {
278
- // Ignore timezone errors
279
- }
280
- }
281
- return context;
365
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
366
+ const r = Math.random() * 16 | 0;
367
+ const v = c === "x" ? r : r & 3 | 8;
368
+ return v.toString(16);
369
+ });
370
+ }
371
+ generateTimestamp() {
372
+ return (/* @__PURE__ */ new Date()).toISOString();
373
+ }
374
+ getContext() {
375
+ const context = {
376
+ library: {
377
+ name: "js-sdk",
378
+ version: SDK_VERSION
379
+ }
380
+ };
381
+ if (typeof navigator !== "undefined") {
382
+ if (navigator.userAgent) {
383
+ context.userAgent = navigator.userAgent;
384
+ }
385
+ if (navigator.language) {
386
+ context.locale = navigator.language;
387
+ }
282
388
  }
283
- estimateEventSize(event) {
284
- // Rough estimate: JSON stringified size
285
- try {
286
- return JSON.stringify(event).length;
287
- }
288
- catch {
289
- // Fallback: rough estimate based on structure
290
- return 500; // Conservative estimate
389
+ if (typeof Intl !== "undefined" && Intl.DateTimeFormat) {
390
+ try {
391
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
392
+ if (timezone) {
393
+ context.timezone = timezone;
291
394
  }
395
+ } catch (e) {
396
+ }
292
397
  }
293
- sleep(ms) {
294
- return new Promise((resolve) => setTimeout(resolve, ms));
398
+ return context;
399
+ }
400
+ estimateEventSize(event) {
401
+ try {
402
+ return JSON.stringify(event).length;
403
+ } catch {
404
+ return 500;
295
405
  }
296
- }
406
+ }
407
+ sleep(ms) {
408
+ return new Promise((resolve) => setTimeout(resolve, ms));
409
+ }
410
+ };
411
+ export {
412
+ KlimeClient,
413
+ SendError
414
+ };
415
+ //# sourceMappingURL=index.js.map