tracebeam-sdk 0.1.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 ADDED
@@ -0,0 +1,580 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ ConfigError: () => ConfigError,
24
+ DEFAULT_CONFIG: () => DEFAULT_CONFIG,
25
+ TraceBeamSDK: () => TraceBeamSDK,
26
+ loadConfigFromEnv: () => loadConfigFromEnv
27
+ });
28
+ module.exports = __toCommonJS(src_exports);
29
+
30
+ // src/config.ts
31
+ var DEFAULT_CONFIG = {
32
+ environment: "development",
33
+ endpoint: "https://ingest.tracebeam.io",
34
+ batchSize: 100,
35
+ flushInterval: 5e3,
36
+ timeout: 1e4,
37
+ maxQueueSize: 1e4,
38
+ sampleRate: 1,
39
+ debug: false
40
+ };
41
+ var ENV_VARS = {
42
+ API_KEY: "TRACEBEAM_API_KEY",
43
+ PROJECT_ID: "TRACEBEAM_PROJECT_ID",
44
+ ENVIRONMENT: "TRACEBEAM_ENVIRONMENT",
45
+ ENDPOINT: "TRACEBEAM_ENDPOINT",
46
+ BATCH_SIZE: "TRACEBEAM_BATCH_SIZE",
47
+ FLUSH_INTERVAL: "TRACEBEAM_FLUSH_INTERVAL",
48
+ TIMEOUT: "TRACEBEAM_HTTP_TIMEOUT",
49
+ MAX_QUEUE_SIZE: "TRACEBEAM_MAX_QUEUE_SIZE",
50
+ SAMPLE_RATE: "TRACEBEAM_SAMPLE_RATE",
51
+ DEBUG: "TRACEBEAM_DEBUG"
52
+ };
53
+ var ConfigError = class extends Error {
54
+ constructor(message) {
55
+ super(message);
56
+ this.name = "ConfigError";
57
+ }
58
+ };
59
+ function loadConfigFromEnv() {
60
+ const apiKey = process.env[ENV_VARS.API_KEY];
61
+ const projectId = process.env[ENV_VARS.PROJECT_ID];
62
+ if (!apiKey) {
63
+ throw new ConfigError(`Missing required environment variable: ${ENV_VARS.API_KEY}`);
64
+ }
65
+ if (!projectId) {
66
+ throw new ConfigError(`Missing required environment variable: ${ENV_VARS.PROJECT_ID}`);
67
+ }
68
+ return {
69
+ apiKey,
70
+ projectId,
71
+ environment: process.env[ENV_VARS.ENVIRONMENT] || DEFAULT_CONFIG.environment,
72
+ endpoint: process.env[ENV_VARS.ENDPOINT] || DEFAULT_CONFIG.endpoint,
73
+ batchSize: parseIntEnv(ENV_VARS.BATCH_SIZE, DEFAULT_CONFIG.batchSize),
74
+ flushInterval: parseIntEnv(ENV_VARS.FLUSH_INTERVAL, DEFAULT_CONFIG.flushInterval),
75
+ timeout: parseIntEnv(ENV_VARS.TIMEOUT, DEFAULT_CONFIG.timeout),
76
+ maxQueueSize: parseIntEnv(ENV_VARS.MAX_QUEUE_SIZE, DEFAULT_CONFIG.maxQueueSize),
77
+ sampleRate: parseFloatEnv(ENV_VARS.SAMPLE_RATE, DEFAULT_CONFIG.sampleRate),
78
+ debug: parseBoolEnv(ENV_VARS.DEBUG, DEFAULT_CONFIG.debug)
79
+ };
80
+ }
81
+ function mergeConfig(config) {
82
+ return {
83
+ apiKey: config.apiKey,
84
+ projectId: config.projectId,
85
+ environment: config.environment ?? DEFAULT_CONFIG.environment,
86
+ endpoint: config.endpoint ?? DEFAULT_CONFIG.endpoint,
87
+ batchSize: config.batchSize ?? DEFAULT_CONFIG.batchSize,
88
+ flushInterval: config.flushInterval ?? DEFAULT_CONFIG.flushInterval,
89
+ timeout: config.timeout ?? DEFAULT_CONFIG.timeout,
90
+ maxQueueSize: config.maxQueueSize ?? DEFAULT_CONFIG.maxQueueSize,
91
+ sampleRate: config.sampleRate ?? DEFAULT_CONFIG.sampleRate,
92
+ debug: config.debug ?? DEFAULT_CONFIG.debug
93
+ };
94
+ }
95
+ function validateConfig(config) {
96
+ if (!config.apiKey || config.apiKey.trim() === "") {
97
+ throw new ConfigError("apiKey is required");
98
+ }
99
+ if (!config.projectId || config.projectId.trim() === "") {
100
+ throw new ConfigError("projectId is required");
101
+ }
102
+ if (config.environment !== void 0 && config.environment.length > 64) {
103
+ throw new ConfigError("environment must be at most 64 characters");
104
+ }
105
+ if (config.batchSize !== void 0 && (config.batchSize < 1 || config.batchSize > 1e4)) {
106
+ throw new ConfigError("batchSize must be between 1 and 10000");
107
+ }
108
+ if (config.sampleRate !== void 0 && (config.sampleRate < 0 || config.sampleRate > 1)) {
109
+ throw new ConfigError("sampleRate must be between 0 and 1");
110
+ }
111
+ }
112
+ function parseIntEnv(name, defaultValue) {
113
+ const value = process.env[name];
114
+ if (!value) return defaultValue;
115
+ const parsed = parseInt(value, 10);
116
+ return isNaN(parsed) ? defaultValue : parsed;
117
+ }
118
+ function parseFloatEnv(name, defaultValue) {
119
+ const value = process.env[name];
120
+ if (!value) return defaultValue;
121
+ const parsed = parseFloat(value);
122
+ return isNaN(parsed) ? defaultValue : parsed;
123
+ }
124
+ function parseBoolEnv(name, defaultValue) {
125
+ const value = process.env[name];
126
+ if (!value) return defaultValue;
127
+ return value.toLowerCase() === "true" || value === "1";
128
+ }
129
+
130
+ // src/transport.ts
131
+ var defaultLogger = {
132
+ debug: (msg, ...args) => console.debug(`[tracebeam] ${msg}`, ...args),
133
+ warn: (msg, ...args) => console.warn(`[tracebeam] ${msg}`, ...args),
134
+ error: (msg, ...args) => console.error(`[tracebeam] ${msg}`, ...args)
135
+ };
136
+ var Transport = class {
137
+ endpoint;
138
+ apiKey;
139
+ timeout;
140
+ logger;
141
+ debug;
142
+ state = "active";
143
+ constructor(options) {
144
+ this.endpoint = options.endpoint.replace(/\/$/, "");
145
+ this.apiKey = options.apiKey;
146
+ this.timeout = options.timeout;
147
+ this.debug = options.debug;
148
+ this.logger = options.logger ?? defaultLogger;
149
+ }
150
+ /**
151
+ * Get current transport state
152
+ */
153
+ getState() {
154
+ return this.state;
155
+ }
156
+ /**
157
+ * Check if transport is active
158
+ */
159
+ isActive() {
160
+ return this.state === "active";
161
+ }
162
+ /**
163
+ * Send a batch of events to the Ingest API
164
+ * Implements retry with exponential backoff
165
+ */
166
+ async send(events) {
167
+ if (!this.isActive()) {
168
+ return {
169
+ success: false,
170
+ error: "Transport disabled",
171
+ message: `Transport is ${this.state}`,
172
+ code: 0
173
+ };
174
+ }
175
+ const batch = { events };
176
+ const url = `${this.endpoint}/api/v1/events`;
177
+ let lastError = null;
178
+ const maxRetries = 3;
179
+ const baseDelay = 1e3;
180
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
181
+ try {
182
+ const response = await this.executeRequest(url, batch);
183
+ if (response.success) {
184
+ if (this.debug) {
185
+ this.logger.debug(`Sent ${events.length} events successfully`);
186
+ }
187
+ return response;
188
+ }
189
+ const errorResponse = response;
190
+ lastError = errorResponse;
191
+ switch (errorResponse.code) {
192
+ case 401:
193
+ this.state = "disabled";
194
+ this.logger.error("Invalid API key. SDK disabled.");
195
+ return errorResponse;
196
+ case 402:
197
+ this.state = "quota_exceeded";
198
+ this.logger.warn("Event quota exceeded. SDK paused.");
199
+ return errorResponse;
200
+ case 429:
201
+ const retryAfter = errorResponse.retry_after ?? 1;
202
+ if (attempt < maxRetries) {
203
+ await this.sleep(retryAfter * 1e3);
204
+ continue;
205
+ }
206
+ return errorResponse;
207
+ case 400:
208
+ this.logger.warn("Bad request:", errorResponse.message);
209
+ return errorResponse;
210
+ default:
211
+ if (errorResponse.code >= 500 && attempt < maxRetries) {
212
+ const delay = this.calculateBackoff(attempt, baseDelay);
213
+ if (this.debug) {
214
+ this.logger.debug(`Retry ${attempt + 1}/${maxRetries} after ${delay}ms`);
215
+ }
216
+ await this.sleep(delay);
217
+ continue;
218
+ }
219
+ return errorResponse;
220
+ }
221
+ } catch (error) {
222
+ if (attempt < maxRetries) {
223
+ const delay = this.calculateBackoff(attempt, baseDelay);
224
+ if (this.debug) {
225
+ this.logger.debug(`Network error, retry ${attempt + 1}/${maxRetries} after ${delay}ms`);
226
+ }
227
+ await this.sleep(delay);
228
+ continue;
229
+ }
230
+ const networkError = {
231
+ success: false,
232
+ error: "Network Error",
233
+ message: error instanceof Error ? error.message : "Unknown error",
234
+ code: 0
235
+ };
236
+ return networkError;
237
+ }
238
+ }
239
+ return lastError ?? {
240
+ success: false,
241
+ error: "Max retries exceeded",
242
+ message: "Failed after maximum retry attempts",
243
+ code: 0
244
+ };
245
+ }
246
+ /**
247
+ * Execute HTTP request
248
+ */
249
+ async executeRequest(url, batch) {
250
+ const controller = new AbortController();
251
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
252
+ try {
253
+ const response = await fetch(url, {
254
+ method: "POST",
255
+ headers: {
256
+ "Content-Type": "application/json",
257
+ "Authorization": `Bearer ${this.apiKey}`
258
+ },
259
+ body: JSON.stringify(batch),
260
+ signal: controller.signal
261
+ });
262
+ const data = await response.json();
263
+ return data;
264
+ } finally {
265
+ clearTimeout(timeoutId);
266
+ }
267
+ }
268
+ /**
269
+ * Calculate backoff delay with jitter
270
+ */
271
+ calculateBackoff(attempt, baseDelay) {
272
+ const exponentialDelay = baseDelay * Math.pow(2, attempt);
273
+ const jitter = exponentialDelay * 0.1 * (Math.random() * 2 - 1);
274
+ return Math.round(exponentialDelay + jitter);
275
+ }
276
+ /**
277
+ * Sleep for specified milliseconds
278
+ */
279
+ sleep(ms) {
280
+ return new Promise((resolve) => setTimeout(resolve, ms));
281
+ }
282
+ };
283
+
284
+ // src/queue.ts
285
+ var EventQueue = class {
286
+ queue = [];
287
+ options;
288
+ onFlush;
289
+ flushTimer = null;
290
+ isFlushing = false;
291
+ constructor(options, onFlush) {
292
+ this.options = options;
293
+ this.onFlush = onFlush;
294
+ }
295
+ /**
296
+ * Start the background flush timer
297
+ */
298
+ start() {
299
+ if (this.flushTimer) return;
300
+ this.flushTimer = setInterval(() => {
301
+ this.flush().catch(() => {
302
+ });
303
+ }, this.options.flushInterval);
304
+ if (this.flushTimer.unref) {
305
+ this.flushTimer.unref();
306
+ }
307
+ }
308
+ /**
309
+ * Stop the background flush timer
310
+ */
311
+ stop() {
312
+ if (this.flushTimer) {
313
+ clearInterval(this.flushTimer);
314
+ this.flushTimer = null;
315
+ }
316
+ }
317
+ /**
318
+ * Add an event to the queue
319
+ * Returns immediately (non-blocking)
320
+ */
321
+ add(event) {
322
+ if (this.queue.length >= this.options.maxQueueSize) {
323
+ this.queue.shift();
324
+ if (this.options.debug) {
325
+ console.warn("[tracebeam] Queue full, dropping oldest event");
326
+ }
327
+ }
328
+ this.queue.push(event);
329
+ if (this.queue.length >= this.options.batchSize) {
330
+ this.flush().catch(() => {
331
+ });
332
+ }
333
+ }
334
+ /**
335
+ * Flush all queued events
336
+ */
337
+ async flush() {
338
+ if (this.isFlushing || this.queue.length === 0) {
339
+ return;
340
+ }
341
+ this.isFlushing = true;
342
+ try {
343
+ const events = this.queue.splice(0, this.queue.length);
344
+ await this.onFlush(events);
345
+ } finally {
346
+ this.isFlushing = false;
347
+ }
348
+ }
349
+ /**
350
+ * Get current queue size
351
+ */
352
+ size() {
353
+ return this.queue.length;
354
+ }
355
+ /**
356
+ * Check if queue is empty
357
+ */
358
+ isEmpty() {
359
+ return this.queue.length === 0;
360
+ }
361
+ };
362
+ function createEvent(projectId, environment, error, options = {}, globalTags = {}, globalExtra = {}) {
363
+ if (!projectId || projectId.trim() === "") {
364
+ throw new ConfigError('createEvent: "projectId" must be a non-empty string.');
365
+ }
366
+ if (!environment || environment.trim() === "") {
367
+ throw new ConfigError('createEvent: "environment" must be a non-empty string.');
368
+ }
369
+ const level = options.level ?? "error";
370
+ const timestamp = options.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
371
+ const tags = {
372
+ ...globalTags,
373
+ ...options.tags
374
+ };
375
+ const extra = {
376
+ ...globalExtra,
377
+ ...options.extra
378
+ };
379
+ const truncatedError = error.length > 1e4 ? error.slice(0, 1e4) : error;
380
+ return {
381
+ project_id: projectId,
382
+ error: truncatedError,
383
+ level,
384
+ environment,
385
+ timestamp,
386
+ tags,
387
+ extra
388
+ };
389
+ }
390
+
391
+ // src/client.ts
392
+ var TraceBeamSDK = class _TraceBeamSDK {
393
+ config;
394
+ transport;
395
+ queue;
396
+ globalTags = {};
397
+ globalExtra = {};
398
+ userId = null;
399
+ isInitialized = true;
400
+ /**
401
+ * Create SDK instance from configuration
402
+ */
403
+ constructor(config) {
404
+ validateConfig(config);
405
+ this.config = mergeConfig(config);
406
+ this.transport = new Transport({
407
+ endpoint: this.config.endpoint,
408
+ apiKey: this.config.apiKey,
409
+ timeout: this.config.timeout,
410
+ debug: this.config.debug
411
+ });
412
+ this.queue = new EventQueue(
413
+ {
414
+ batchSize: this.config.batchSize,
415
+ flushInterval: this.config.flushInterval,
416
+ maxQueueSize: this.config.maxQueueSize,
417
+ debug: this.config.debug
418
+ },
419
+ this.handleFlush.bind(this)
420
+ );
421
+ this.queue.start();
422
+ if (this.config.debug) {
423
+ console.debug("[tracebeam] Initialized", {
424
+ projectId: this.config.projectId,
425
+ environment: this.config.environment,
426
+ endpoint: this.config.endpoint
427
+ });
428
+ }
429
+ }
430
+ /**
431
+ * Create SDK instance from environment variables
432
+ *
433
+ * Required env vars:
434
+ * - TRACEBEAM_API_KEY
435
+ * - TRACEBEAM_PROJECT_ID
436
+ *
437
+ * Optional env vars:
438
+ * - TRACEBEAM_ENVIRONMENT (default: 'development')
439
+ * - TRACEBEAM_ENDPOINT (default: 'https://ingest.tracebeam.io')
440
+ * - TRACEBEAM_BATCH_SIZE (default: 100)
441
+ * - TRACEBEAM_FLUSH_INTERVAL (default: 5000)
442
+ * - TRACEBEAM_HTTP_TIMEOUT (default: 10000)
443
+ * - TRACEBEAM_MAX_QUEUE_SIZE (default: 10000)
444
+ * - TRACEBEAM_SAMPLE_RATE (default: 1.0)
445
+ * - TRACEBEAM_DEBUG (default: false)
446
+ */
447
+ static fromEnv() {
448
+ const config = loadConfigFromEnv();
449
+ return new _TraceBeamSDK(config);
450
+ }
451
+ /**
452
+ * Capture an exception/error
453
+ * Returns immediately (non-blocking)
454
+ */
455
+ captureException(error, options = {}) {
456
+ if (!this.canCapture()) return;
457
+ const errorMessage = error instanceof Error ? `${error.name}: ${error.message}
458
+ ${error.stack ?? ""}` : String(error);
459
+ const event = this.createEventWithContext(errorMessage, {
460
+ level: "error",
461
+ ...options
462
+ });
463
+ this.queue.add(event);
464
+ }
465
+ /**
466
+ * Capture a message/event
467
+ * Returns immediately (non-blocking)
468
+ */
469
+ captureMessage(message, options = {}) {
470
+ if (!this.canCapture()) return;
471
+ const event = this.createEventWithContext(message, {
472
+ level: "info",
473
+ ...options
474
+ });
475
+ this.queue.add(event);
476
+ }
477
+ /**
478
+ * Set the current user ID
479
+ * Will be included in all subsequent events
480
+ */
481
+ setUser(userId) {
482
+ this.userId = userId;
483
+ if (userId) {
484
+ this.globalExtra["user_id"] = userId;
485
+ } else {
486
+ delete this.globalExtra["user_id"];
487
+ }
488
+ }
489
+ /**
490
+ * Set a global tag
491
+ * Will be included in all subsequent events
492
+ */
493
+ setTag(key, value) {
494
+ this.globalTags[key] = value;
495
+ }
496
+ /**
497
+ * Set multiple global tags
498
+ * Will be included in all subsequent events
499
+ */
500
+ setTags(tags) {
501
+ Object.assign(this.globalTags, tags);
502
+ }
503
+ /**
504
+ * Set global extra context
505
+ * Will be included in all subsequent events
506
+ */
507
+ setExtra(key, value) {
508
+ this.globalExtra[key] = value;
509
+ }
510
+ /**
511
+ * Set multiple global extra context values
512
+ */
513
+ setExtras(extras) {
514
+ Object.assign(this.globalExtra, extras);
515
+ }
516
+ /**
517
+ * Manually flush queued events
518
+ * Call this to ensure events are sent before process exit
519
+ */
520
+ async flush() {
521
+ await this.queue.flush();
522
+ }
523
+ /**
524
+ * Graceful shutdown
525
+ * Flushes remaining events and stops background workers
526
+ */
527
+ async close() {
528
+ this.isInitialized = false;
529
+ this.queue.stop();
530
+ await this.flush();
531
+ if (this.config.debug) {
532
+ console.debug("[tracebeam] Closed");
533
+ }
534
+ }
535
+ /**
536
+ * Check if SDK is active and can capture events
537
+ */
538
+ isActive() {
539
+ return this.isInitialized && this.transport.isActive();
540
+ }
541
+ // Private methods
542
+ canCapture() {
543
+ if (!this.isInitialized) return false;
544
+ if (!this.transport.isActive()) return false;
545
+ if (this.config.sampleRate < 1) {
546
+ if (Math.random() > this.config.sampleRate) {
547
+ return false;
548
+ }
549
+ }
550
+ return true;
551
+ }
552
+ createEventWithContext(error, options) {
553
+ return createEvent(
554
+ this.config.projectId,
555
+ this.config.environment,
556
+ error,
557
+ options,
558
+ this.globalTags,
559
+ this.globalExtra
560
+ );
561
+ }
562
+ async handleFlush(events) {
563
+ if (events.length === 0) return;
564
+ try {
565
+ await this.transport.send(events);
566
+ } catch (error) {
567
+ if (this.config.debug) {
568
+ console.error("[tracebeam] Failed to flush events:", error);
569
+ }
570
+ }
571
+ }
572
+ };
573
+ // Annotate the CommonJS export names for ESM import in node:
574
+ 0 && (module.exports = {
575
+ ConfigError,
576
+ DEFAULT_CONFIG,
577
+ TraceBeamSDK,
578
+ loadConfigFromEnv
579
+ });
580
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/transport.ts","../src/queue.ts","../src/client.ts"],"sourcesContent":["/**\n * TraceBeam SDK for Node.js\n * \n * A lightweight, non-blocking telemetry SDK for sending errors\n * and events to the TraceBeam API Observability Platform.\n * \n * @example\n * ```typescript\n * import { TraceBeamSDK } from 'tracebeam-sdk';\n * \n * // Initialize from environment variables\n * const sdk = TraceBeamSDK.fromEnv();\n * \n * // Capture an exception\n * try {\n * await doSomething();\n * } catch (error) {\n * sdk.captureException(error);\n * }\n * \n * // Capture a message\n * sdk.captureMessage('User signed up', { level: 'info' });\n * \n * // Graceful shutdown\n * await sdk.close();\n * ```\n * \n * @packageDocumentation\n */\n\n// Main client\nexport { TraceBeamSDK } from './client.js';\n\n// Types\nexport type {\n TraceBeamConfig,\n Event,\n EventLevel,\n CaptureOptions,\n Tags,\n Extra,\n EventBatch,\n TransportResponse,\n TransportSuccessResponse,\n TransportErrorResponse,\n} from './types.js';\n\n// Configuration\nexport { ConfigError, loadConfigFromEnv, DEFAULT_CONFIG } from './config.js';\n","import type { TraceBeamConfig } from './types.js';\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONFIG = {\n environment: 'development',\n endpoint: 'https://ingest.tracebeam.io',\n batchSize: 100,\n flushInterval: 5000,\n timeout: 10000,\n maxQueueSize: 10000,\n sampleRate: 1.0,\n debug: false,\n} as const;\n\n/**\n * Environment variable names\n */\nconst ENV_VARS = {\n API_KEY: 'TRACEBEAM_API_KEY',\n PROJECT_ID: 'TRACEBEAM_PROJECT_ID',\n ENVIRONMENT: 'TRACEBEAM_ENVIRONMENT',\n ENDPOINT: 'TRACEBEAM_ENDPOINT',\n BATCH_SIZE: 'TRACEBEAM_BATCH_SIZE',\n FLUSH_INTERVAL: 'TRACEBEAM_FLUSH_INTERVAL',\n TIMEOUT: 'TRACEBEAM_HTTP_TIMEOUT',\n MAX_QUEUE_SIZE: 'TRACEBEAM_MAX_QUEUE_SIZE',\n SAMPLE_RATE: 'TRACEBEAM_SAMPLE_RATE',\n DEBUG: 'TRACEBEAM_DEBUG',\n} as const;\n\n/**\n * Configuration error thrown when required values are missing\n */\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Load configuration from environment variables\n */\nexport function loadConfigFromEnv(): TraceBeamConfig {\n const apiKey = process.env[ENV_VARS.API_KEY];\n const projectId = process.env[ENV_VARS.PROJECT_ID];\n\n if (!apiKey) {\n throw new ConfigError(`Missing required environment variable: ${ENV_VARS.API_KEY}`);\n }\n\n if (!projectId) {\n throw new ConfigError(`Missing required environment variable: ${ENV_VARS.PROJECT_ID}`);\n }\n\n return {\n apiKey,\n projectId,\n environment: process.env[ENV_VARS.ENVIRONMENT] || DEFAULT_CONFIG.environment,\n endpoint: process.env[ENV_VARS.ENDPOINT] || DEFAULT_CONFIG.endpoint,\n batchSize: parseIntEnv(ENV_VARS.BATCH_SIZE, DEFAULT_CONFIG.batchSize),\n flushInterval: parseIntEnv(ENV_VARS.FLUSH_INTERVAL, DEFAULT_CONFIG.flushInterval),\n timeout: parseIntEnv(ENV_VARS.TIMEOUT, DEFAULT_CONFIG.timeout),\n maxQueueSize: parseIntEnv(ENV_VARS.MAX_QUEUE_SIZE, DEFAULT_CONFIG.maxQueueSize),\n sampleRate: parseFloatEnv(ENV_VARS.SAMPLE_RATE, DEFAULT_CONFIG.sampleRate),\n debug: parseBoolEnv(ENV_VARS.DEBUG, DEFAULT_CONFIG.debug),\n };\n}\n\n/**\n * Merge user config with defaults\n */\nexport function mergeConfig(config: TraceBeamConfig): Required<TraceBeamConfig> {\n return {\n apiKey: config.apiKey,\n projectId: config.projectId,\n environment: config.environment ?? DEFAULT_CONFIG.environment,\n endpoint: config.endpoint ?? DEFAULT_CONFIG.endpoint,\n batchSize: config.batchSize ?? DEFAULT_CONFIG.batchSize,\n flushInterval: config.flushInterval ?? DEFAULT_CONFIG.flushInterval,\n timeout: config.timeout ?? DEFAULT_CONFIG.timeout,\n maxQueueSize: config.maxQueueSize ?? DEFAULT_CONFIG.maxQueueSize,\n sampleRate: config.sampleRate ?? DEFAULT_CONFIG.sampleRate,\n debug: config.debug ?? DEFAULT_CONFIG.debug,\n };\n}\n\n/**\n * Validate configuration\n */\nexport function validateConfig(config: TraceBeamConfig): void {\n if (!config.apiKey || config.apiKey.trim() === '') {\n throw new ConfigError('apiKey is required');\n }\n\n if (!config.projectId || config.projectId.trim() === '') {\n throw new ConfigError('projectId is required');\n }\n\n if (config.environment !== undefined && config.environment.length > 64) {\n throw new ConfigError('environment must be at most 64 characters');\n }\n\n if (config.batchSize !== undefined && (config.batchSize < 1 || config.batchSize > 10000)) {\n throw new ConfigError('batchSize must be between 1 and 10000');\n }\n\n if (config.sampleRate !== undefined && (config.sampleRate < 0 || config.sampleRate > 1)) {\n throw new ConfigError('sampleRate must be between 0 and 1');\n }\n}\n\n// Helper functions for parsing environment variables\n\nfunction parseIntEnv(name: string, defaultValue: number): number {\n const value = process.env[name];\n if (!value) return defaultValue;\n const parsed = parseInt(value, 10);\n return isNaN(parsed) ? defaultValue : parsed;\n}\n\nfunction parseFloatEnv(name: string, defaultValue: number): number {\n const value = process.env[name];\n if (!value) return defaultValue;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? defaultValue : parsed;\n}\n\nfunction parseBoolEnv(name: string, defaultValue: boolean): boolean {\n const value = process.env[name];\n if (!value) return defaultValue;\n return value.toLowerCase() === 'true' || value === '1';\n}\n","import type { Event, EventBatch, TransportResponse, TransportErrorResponse } from './types.js';\n\n/**\n * Transport state\n */\nexport type TransportState = 'active' | 'disabled' | 'quota_exceeded';\n\n/**\n * Logger interface for transport\n */\nexport interface TransportLogger {\n debug: (message: string, ...args: unknown[]) => void;\n warn: (message: string, ...args: unknown[]) => void;\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Transport options\n */\nexport interface TransportOptions {\n endpoint: string;\n apiKey: string;\n timeout: number;\n debug: boolean;\n logger?: TransportLogger;\n}\n\n/**\n * Default console logger\n */\nconst defaultLogger: TransportLogger = {\n debug: (msg, ...args) => console.debug(`[tracebeam] ${msg}`, ...args),\n warn: (msg, ...args) => console.warn(`[tracebeam] ${msg}`, ...args),\n error: (msg, ...args) => console.error(`[tracebeam] ${msg}`, ...args),\n};\n\n/**\n * HTTP transport for sending events to the Ingest API\n */\nexport class Transport {\n private readonly endpoint: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n private readonly logger: TransportLogger;\n private readonly debug: boolean;\n\n private state: TransportState = 'active';\n\n constructor(options: TransportOptions) {\n this.endpoint = options.endpoint.replace(/\\/$/, ''); // Remove trailing slash\n this.apiKey = options.apiKey;\n this.timeout = options.timeout;\n this.debug = options.debug;\n this.logger = options.logger ?? defaultLogger;\n }\n\n /**\n * Get current transport state\n */\n getState(): TransportState {\n return this.state;\n }\n\n /**\n * Check if transport is active\n */\n isActive(): boolean {\n return this.state === 'active';\n }\n\n /**\n * Send a batch of events to the Ingest API\n * Implements retry with exponential backoff\n */\n async send(events: Event[]): Promise<TransportResponse> {\n if (!this.isActive()) {\n return {\n success: false,\n error: 'Transport disabled',\n message: `Transport is ${this.state}`,\n code: 0,\n };\n }\n\n const batch: EventBatch = { events };\n const url = `${this.endpoint}/api/v1/events`;\n\n let lastError: TransportErrorResponse | null = null;\n const maxRetries = 3;\n const baseDelay = 1000;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await this.executeRequest(url, batch);\n\n if (response.success) {\n if (this.debug) {\n this.logger.debug(`Sent ${events.length} events successfully`);\n }\n return response;\n }\n\n // Handle specific error codes\n const errorResponse = response as TransportErrorResponse;\n lastError = errorResponse;\n\n switch (errorResponse.code) {\n case 401:\n // Invalid API key - disable SDK\n this.state = 'disabled';\n this.logger.error('Invalid API key. SDK disabled.');\n return errorResponse;\n\n case 402:\n // Quota exceeded - stop sending\n this.state = 'quota_exceeded';\n this.logger.warn('Event quota exceeded. SDK paused.');\n return errorResponse;\n\n case 429:\n // Rate limited - retry after delay\n const retryAfter = errorResponse.retry_after ?? 1;\n if (attempt < maxRetries) {\n await this.sleep(retryAfter * 1000);\n continue;\n }\n return errorResponse;\n\n case 400:\n // Bad request - don't retry\n this.logger.warn('Bad request:', errorResponse.message);\n return errorResponse;\n\n default:\n // 5xx errors - retry with backoff\n if (errorResponse.code >= 500 && attempt < maxRetries) {\n const delay = this.calculateBackoff(attempt, baseDelay);\n if (this.debug) {\n this.logger.debug(`Retry ${attempt + 1}/${maxRetries} after ${delay}ms`);\n }\n await this.sleep(delay);\n continue;\n }\n return errorResponse;\n }\n } catch (error) {\n // Network error - retry with backoff\n if (attempt < maxRetries) {\n const delay = this.calculateBackoff(attempt, baseDelay);\n if (this.debug) {\n this.logger.debug(`Network error, retry ${attempt + 1}/${maxRetries} after ${delay}ms`);\n }\n await this.sleep(delay);\n continue;\n }\n\n const networkError: TransportErrorResponse = {\n success: false,\n error: 'Network Error',\n message: error instanceof Error ? error.message : 'Unknown error',\n code: 0,\n };\n return networkError;\n }\n }\n\n return lastError ?? {\n success: false,\n error: 'Max retries exceeded',\n message: 'Failed after maximum retry attempts',\n code: 0,\n };\n }\n\n /**\n * Execute HTTP request\n */\n private async executeRequest(url: string, batch: EventBatch): Promise<TransportResponse> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(batch),\n signal: controller.signal,\n });\n\n const data = await response.json() as TransportResponse;\n return data;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Calculate backoff delay with jitter\n */\n private calculateBackoff(attempt: number, baseDelay: number): number {\n const exponentialDelay = baseDelay * Math.pow(2, attempt);\n const jitter = exponentialDelay * 0.1 * (Math.random() * 2 - 1); // ±10% jitter\n return Math.round(exponentialDelay + jitter);\n }\n\n /**\n * Sleep for specified milliseconds\n */\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n","import type { Event, Tags, Extra, CaptureOptions, EventLevel } from './types.js';\nimport { ConfigError } from './config.js';\n\n/**\n * Queue flush callback\n */\nexport type FlushCallback = (events: Event[]) => Promise<void>;\n\n/**\n * Queue options\n */\nexport interface QueueOptions {\n /** Max events per batch before auto-flush */\n batchSize: number;\n /** Flush interval in milliseconds */\n flushInterval: number;\n /** Max events in queue */\n maxQueueSize: number;\n /** Debug logging */\n debug: boolean;\n}\n\n/**\n * Event queue with batching support\n * \n * Accumulates events and flushes them either when:\n * - Batch size is reached (default: 100)\n * - Flush interval elapsed (default: 5 seconds)\n * - Manual flush() is called\n */\nexport class EventQueue {\n private readonly queue: Event[] = [];\n private readonly options: QueueOptions;\n private readonly onFlush: FlushCallback;\n\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private isFlushing = false;\n\n constructor(options: QueueOptions, onFlush: FlushCallback) {\n this.options = options;\n this.onFlush = onFlush;\n }\n\n /**\n * Start the background flush timer\n */\n start(): void {\n if (this.flushTimer) return;\n\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {\n // Errors handled in flush()\n });\n }, this.options.flushInterval);\n\n // Don't block Node.js from exiting\n if (this.flushTimer.unref) {\n this.flushTimer.unref();\n }\n }\n\n /**\n * Stop the background flush timer\n */\n stop(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n }\n\n /**\n * Add an event to the queue\n * Returns immediately (non-blocking)\n */\n add(event: Event): void {\n // Check if queue is full\n if (this.queue.length >= this.options.maxQueueSize) {\n // Drop oldest event\n this.queue.shift();\n if (this.options.debug) {\n console.warn('[tracebeam] Queue full, dropping oldest event');\n }\n }\n\n this.queue.push(event);\n\n // Auto-flush if batch size reached\n if (this.queue.length >= this.options.batchSize) {\n this.flush().catch(() => {\n // Errors handled in flush()\n });\n }\n }\n\n /**\n * Flush all queued events\n */\n async flush(): Promise<void> {\n // Prevent concurrent flushes\n if (this.isFlushing || this.queue.length === 0) {\n return;\n }\n\n this.isFlushing = true;\n\n try {\n // Extract events to flush (leave queue empty for new events)\n const events = this.queue.splice(0, this.queue.length);\n await this.onFlush(events);\n } finally {\n this.isFlushing = false;\n }\n }\n\n /**\n * Get current queue size\n */\n size(): number {\n return this.queue.length;\n }\n\n /**\n * Check if queue is empty\n */\n isEmpty(): boolean {\n return this.queue.length === 0;\n }\n}\n\n/**\n * Event builder utility\n */\nexport function createEvent(\n projectId: string,\n environment: string,\n error: string,\n options: CaptureOptions = {},\n globalTags: Tags = {},\n globalExtra: Extra = {}\n): Event {\n // Validate required parameters\n if (!projectId || projectId.trim() === '') {\n throw new ConfigError('createEvent: \"projectId\" must be a non-empty string.');\n }\n if (!environment || environment.trim() === '') {\n throw new ConfigError('createEvent: \"environment\" must be a non-empty string.');\n }\n\n const level: EventLevel = options.level ?? 'error';\n const timestamp = options.timestamp ?? new Date().toISOString();\n\n // Merge tags (options override globals)\n const tags: Tags = {\n ...globalTags,\n ...options.tags,\n };\n\n // Merge extra (options override globals)\n const extra: Extra = {\n ...globalExtra,\n ...options.extra,\n };\n\n // Truncate error message to 10,000 chars\n const truncatedError = error.length > 10000 ? error.slice(0, 10000) : error;\n\n return {\n project_id: projectId,\n error: truncatedError,\n level,\n environment,\n timestamp,\n tags,\n extra,\n };\n}\n","import type { TraceBeamConfig, CaptureOptions, Tags, Extra, Event } from './types.js';\nimport { loadConfigFromEnv, mergeConfig, validateConfig } from './config.js';\nimport { Transport } from './transport.js';\nimport { EventQueue, createEvent } from './queue.js';\n\n/**\n * TraceBeamSDK client for capturing and sending events\n * \n * @example\n * ```typescript\n * // Initialize from environment variables\n * const sdk = TraceBeamSDK.fromEnv();\n * \n * // Capture an exception\n * try {\n * doSomething();\n * } catch (error) {\n * sdk.captureException(error);\n * }\n * \n * // Capture a message\n * sdk.captureMessage('User signup completed', {\n * level: 'info',\n * tags: { feature: 'auth' }\n * });\n * \n * // Graceful shutdown\n * await sdk.close();\n * ```\n */\nexport class TraceBeamSDK {\n private readonly config: Required<TraceBeamConfig>;\n private readonly transport: Transport;\n private readonly queue: EventQueue;\n\n private globalTags: Tags = {};\n private globalExtra: Extra = {};\n private userId: string | null = null;\n\n private isInitialized = true;\n\n /**\n * Create SDK instance from configuration\n */\n constructor(config: TraceBeamConfig) {\n validateConfig(config);\n this.config = mergeConfig(config);\n\n this.transport = new Transport({\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n timeout: this.config.timeout,\n debug: this.config.debug,\n });\n\n this.queue = new EventQueue(\n {\n batchSize: this.config.batchSize,\n flushInterval: this.config.flushInterval,\n maxQueueSize: this.config.maxQueueSize,\n debug: this.config.debug,\n },\n this.handleFlush.bind(this)\n );\n\n // Start background flush timer\n this.queue.start();\n\n if (this.config.debug) {\n console.debug('[tracebeam] Initialized', {\n projectId: this.config.projectId,\n environment: this.config.environment,\n endpoint: this.config.endpoint,\n });\n }\n }\n\n /**\n * Create SDK instance from environment variables\n * \n * Required env vars:\n * - TRACEBEAM_API_KEY\n * - TRACEBEAM_PROJECT_ID\n * \n * Optional env vars:\n * - TRACEBEAM_ENVIRONMENT (default: 'development')\n * - TRACEBEAM_ENDPOINT (default: 'https://ingest.tracebeam.io')\n * - TRACEBEAM_BATCH_SIZE (default: 100)\n * - TRACEBEAM_FLUSH_INTERVAL (default: 5000)\n * - TRACEBEAM_HTTP_TIMEOUT (default: 10000)\n * - TRACEBEAM_MAX_QUEUE_SIZE (default: 10000)\n * - TRACEBEAM_SAMPLE_RATE (default: 1.0)\n * - TRACEBEAM_DEBUG (default: false)\n */\n static fromEnv(): TraceBeamSDK {\n const config = loadConfigFromEnv();\n return new TraceBeamSDK(config);\n }\n\n /**\n * Capture an exception/error\n * Returns immediately (non-blocking)\n */\n captureException(error: Error | string, options: CaptureOptions = {}): void {\n if (!this.canCapture()) return;\n\n const errorMessage = error instanceof Error\n ? `${error.name}: ${error.message}\\n${error.stack ?? ''}`\n : String(error);\n\n const event = this.createEventWithContext(errorMessage, {\n level: 'error',\n ...options,\n });\n\n this.queue.add(event);\n }\n\n /**\n * Capture a message/event\n * Returns immediately (non-blocking)\n */\n captureMessage(message: string, options: CaptureOptions = {}): void {\n if (!this.canCapture()) return;\n\n const event = this.createEventWithContext(message, {\n level: 'info',\n ...options,\n });\n\n this.queue.add(event);\n }\n\n /**\n * Set the current user ID\n * Will be included in all subsequent events\n */\n setUser(userId: string | null): void {\n this.userId = userId;\n if (userId) {\n this.globalExtra['user_id'] = userId;\n } else {\n delete this.globalExtra['user_id'];\n }\n }\n\n /**\n * Set a global tag\n * Will be included in all subsequent events\n */\n setTag(key: string, value: string): void {\n this.globalTags[key] = value;\n }\n\n /**\n * Set multiple global tags\n * Will be included in all subsequent events\n */\n setTags(tags: Tags): void {\n Object.assign(this.globalTags, tags);\n }\n\n /**\n * Set global extra context\n * Will be included in all subsequent events\n */\n setExtra(key: string, value: unknown): void {\n this.globalExtra[key] = value;\n }\n\n /**\n * Set multiple global extra context values\n */\n setExtras(extras: Extra): void {\n Object.assign(this.globalExtra, extras);\n }\n\n /**\n * Manually flush queued events\n * Call this to ensure events are sent before process exit\n */\n async flush(): Promise<void> {\n await this.queue.flush();\n }\n\n /**\n * Graceful shutdown\n * Flushes remaining events and stops background workers\n */\n async close(): Promise<void> {\n this.isInitialized = false;\n this.queue.stop();\n await this.flush();\n\n if (this.config.debug) {\n console.debug('[tracebeam] Closed');\n }\n }\n\n /**\n * Check if SDK is active and can capture events\n */\n isActive(): boolean {\n return this.isInitialized && this.transport.isActive();\n }\n\n // Private methods\n\n private canCapture(): boolean {\n if (!this.isInitialized) return false;\n if (!this.transport.isActive()) return false;\n\n // Sample rate check\n if (this.config.sampleRate < 1.0) {\n if (Math.random() > this.config.sampleRate) {\n return false;\n }\n }\n\n return true;\n }\n\n private createEventWithContext(error: string, options: CaptureOptions): Event {\n return createEvent(\n this.config.projectId,\n this.config.environment,\n error,\n options,\n this.globalTags,\n this.globalExtra\n );\n }\n\n private async handleFlush(events: Event[]): Promise<void> {\n if (events.length === 0) return;\n\n try {\n await this.transport.send(events);\n } catch (error) {\n if (this.config.debug) {\n console.error('[tracebeam] Failed to flush events:', error);\n }\n // Events are lost, but we don't crash the app\n }\n }\n}\n"],"mappings":"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","names":[]}