vedatrace 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,17 +1,14 @@
1
- import { b as VedaTraceTransport, B as BatcherConfig, c as VedaTraceEdgeContext, I as InternalLogEntry, V as VedaTraceLoggerInterface, R as RuntimeType$1, a as VedaTraceConfig, L as LogMetadata, d as RedactionConfig } from './types-BU0UESs9.mjs';
2
- export { e as VedaTraceLevel, f as VedaTraceLog } from './types-BU0UESs9.mjs';
1
+ import { b as VedaTraceTransport, B as BatcherConfig, c as VedaTraceEdgeContext, I as InternalLogEntry, V as VedaTraceLoggerInterface, R as RuntimeType$1, a as VedaTraceConfig, L as LogMetadata, d as RedactionConfig } from './types-CSBzeGyK.mjs';
2
+ export { e as VedaTraceLevel, f as VedaTraceLog } from './types-CSBzeGyK.mjs';
3
3
  export { ConsoleFormat, ConsoleTransportConfig, HttpTransportConfig, VedaTraceConsoleTransport, VedaTraceHttpTransport, VedaTraceHttpTransportBrowser } from './transports/index.mjs';
4
4
 
5
5
  /**
6
6
  * VedaTrace Batcher - Context-Aware for Cloudflare Workers
7
7
  *
8
- * Key features:
9
- * 1. Stores EdgeContext for waitUntil() integration
10
- * 2. setContext() method for post-initialization context attachment
11
- * 3. Fire-and-forget flush wrapped in ctx.waitUntil() when context is available
12
- * 4. Debounced flush to avoid excessive network calls
13
- * 5. Automatic flush on each log entry when context is present
14
- * 6. All callbacks moved into BatcherConfig for cleaner API
8
+ * Three flush modes:
9
+ * 1. Reliable mode (context or waitUntilFn): debounced flush + waitUntil for guaranteed delivery
10
+ * 2. Immediate mode: flush() called directly from add() during handler execution
11
+ * 3. Batch mode: periodic/batch-size flush for long-running environments
15
12
  */
16
13
 
17
14
  declare class VedaTraceBatcher {
@@ -20,30 +17,63 @@ declare class VedaTraceBatcher {
20
17
  private immediateFlush;
21
18
  private queue;
22
19
  private flushTimer;
23
- private flushDebounceTimer;
20
+ private flushQueued;
24
21
  private isFlushing;
25
22
  private pendingFlush;
26
23
  private context;
24
+ private waitUntilFn;
25
+ /**
26
+ * Set when the ingestion endpoint rejects our credentials. Every subsequent
27
+ * batch would fail identically, so we stop rather than spend a request (and a
28
+ * retry storm) per flush for the life of the process. start() clears it.
29
+ */
30
+ private halted;
27
31
  constructor(transports: VedaTraceTransport[], config: BatcherConfig, immediateFlush?: boolean);
28
- /** Attach execution context after initialization */
29
32
  setContext(ctx: VedaTraceEdgeContext): void;
30
- /** Get current context */
31
33
  getContext(): VedaTraceEdgeContext | undefined;
32
- /** Add log to queue with context-aware flush */
33
34
  add(log: InternalLogEntry): void;
34
- /** Debounced flush - prevents rapid-fire flushes */
35
35
  private debouncedFlush;
36
- /** Flush logs to all transports with waitUntil protection */
37
36
  flush(): Promise<void>;
38
37
  private sendWithRetry;
38
+ /** Stop accepting logs after an unrecoverable authentication failure. */
39
+ private halt;
40
+ private reportError;
39
41
  private startFlushTimer;
40
42
  stop(): void;
41
43
  start(): void;
42
44
  private delay;
43
45
  getQueueSize(): number;
46
+ /** True once an auth failure has shut the batcher down. */
47
+ isHalted(): boolean;
44
48
  setExecutionContext(ctx: VedaTraceEdgeContext): void;
45
49
  }
46
50
 
51
+ /**
52
+ * Transport error types
53
+ *
54
+ * The batcher needs to tell three cases apart:
55
+ * - retryable (network blip, timeout, 429, 5xx) — back off and try again
56
+ * - permanent (400 malformed batch) — retrying wastes the caller's time
57
+ * - fatal (401/403 bad key or blocked origin) — every future batch will
58
+ * fail the same way, so stop instead of burning a request per flush
59
+ */
60
+ declare class VedaTraceTransportError extends Error {
61
+ readonly name = "VedaTraceTransportError";
62
+ readonly status: number | undefined;
63
+ readonly retryable: boolean;
64
+ readonly fatal: boolean;
65
+ /** Server-requested backoff from a `Retry-After` header, in milliseconds. */
66
+ readonly retryAfterMs: number | undefined;
67
+ constructor(message: string, options?: {
68
+ status?: number;
69
+ retryable?: boolean;
70
+ fatal?: boolean;
71
+ retryAfterMs?: number;
72
+ });
73
+ /** Build an error from an HTTP response status. */
74
+ static fromStatus(status: number, body: string, retryAfterMs?: number): VedaTraceTransportError;
75
+ }
76
+
47
77
  /**
48
78
  * Core VedaTrace Logger implementation
49
79
  * Supports Cloudflare Workers / Pages via withContext() integration
@@ -80,12 +110,17 @@ declare class VedaTraceLogger implements VedaTraceLoggerInterface {
80
110
  * Browser lifecycle management for VedaTrace
81
111
  *
82
112
  * Handles:
83
- * - visibilitychange: flush when page becomes hidden
84
- * - pagehide: final flush when user leaves the page
85
- * - beforeunload: backup flush before page unload
113
+ * - visibilitychange: flush when the page becomes hidden
114
+ * - pagehide: final flush when the page goes away
86
115
  *
87
- * Uses fetch with keepalive: true for final flush to ensure
88
- * the request completes after the tab is closed.
116
+ * `beforeunload` and `unload` are deliberately not used. Registering either one
117
+ * makes Chrome and Safari ineligible for the back/forward cache, so a logging
118
+ * SDK that listens for them measurably slows down every back-navigation in the
119
+ * host app. `visibilitychange` + `pagehide` covers every case they did,
120
+ * including Safari, and is the pair the browsers themselves recommend.
121
+ *
122
+ * The final flush goes out through the batcher's normal HTTP transport, which
123
+ * sets `keepalive: true` in the browser so the request outlives the document.
89
124
  */
90
125
 
91
126
  interface BrowserLifecycleConfig {
@@ -101,8 +136,6 @@ declare class BrowserLifecycle {
101
136
  private config;
102
137
  private boundVisibilityHandler;
103
138
  private boundPageHideHandler;
104
- private boundBeforeUnloadHandler;
105
- private boundUnloadHandler;
106
139
  private isAttached;
107
140
  private pendingFlush;
108
141
  constructor(config: BrowserLifecycleConfig);
@@ -110,21 +143,18 @@ declare class BrowserLifecycle {
110
143
  attach(): void;
111
144
  /** Stop listening for browser lifecycle events */
112
145
  detach(): void;
113
- /** Handle visibility change - flush when page becomes hidden */
146
+ /**
147
+ * Flush when the page becomes hidden.
148
+ *
149
+ * This is the one that actually matters: on mobile, a backgrounded tab is
150
+ * often discarded without ever firing pagehide, so "hidden" is the last
151
+ * reliable moment to ship what we have.
152
+ */
114
153
  private handleVisibilityChange;
115
- /** Handle pagehide event - primary flush handler for Safari */
154
+ /** Final flush as the page is torn down or frozen into the bfcache. */
116
155
  private handlePageHide;
117
- /** Handle beforeunload - backup flush mechanism */
118
- private handleBeforeUnload;
119
- /** Handle unload - fallback for older browsers */
120
- private handleUnload;
121
- /** Schedule a debounced flush (for visibility change) */
156
+ /** Flush at most once at a time; keepalive carries it past the document. */
122
157
  private scheduleFlush;
123
- /**
124
- * Final flush using keepalive fetch
125
- * For sending logs after the page context is destroyed
126
- */
127
- private finalFlush;
128
158
  /** Check if handlers are attached */
129
159
  isActive(): boolean;
130
160
  }
@@ -149,6 +179,21 @@ declare function isServerless(): boolean;
149
179
  declare function isLongRunning(): boolean;
150
180
  declare function isBrowser(): boolean;
151
181
 
182
+ /**
183
+ * SDK version, inlined at build time.
184
+ *
185
+ * This file is generated by `scripts/sync-version.mjs` from package.json and is
186
+ * checked in so type-checking and tests work without a build step. Do not edit
187
+ * it by hand — `bun run build` and `changeset version` both regenerate it, and
188
+ * a test asserts it matches package.json.
189
+ *
190
+ * It exists because the previous `process.env.npm_package_version` read was
191
+ * wrong twice over: npm only sets that variable for its own lifecycle scripts,
192
+ * so it was always undefined for consumers, and the bare `process` reference
193
+ * survived bundling and threw a ReferenceError in browsers.
194
+ */
195
+ declare const SDK_VERSION = "0.3.1";
196
+
152
197
  /**
153
198
  * VedaTrace SDK - Universal JavaScript logging
154
199
  *
@@ -189,4 +234,4 @@ declare function vedatrace(config?: VedaTraceConfig): VedaTraceLoggerInterface;
189
234
  */
190
235
  declare function devVedatrace(config?: Omit<VedaTraceConfig, "apiKey" | "transports">): VedaTraceLoggerInterface;
191
236
 
192
- export { BatcherConfig, BrowserLifecycle, InternalLogEntry, LogMetadata, RedactionConfig, RuntimeType$1 as RuntimeType, VedaTraceBatcher, VedaTraceConfig, VedaTraceEdgeContext, VedaTraceLogger, VedaTraceLoggerInterface, VedaTraceTransport, vedatrace as default, detectRuntime, devVedatrace, isBrowser, isEdgeRuntime, isLongRunning, isServerless, redact, vedatrace };
237
+ export { BatcherConfig, BrowserLifecycle, InternalLogEntry, LogMetadata, RedactionConfig, RuntimeType$1 as RuntimeType, SDK_VERSION, VedaTraceBatcher, VedaTraceConfig, VedaTraceEdgeContext, VedaTraceLogger, VedaTraceLoggerInterface, VedaTraceTransport, VedaTraceTransportError, vedatrace as default, detectRuntime, devVedatrace, isBrowser, isEdgeRuntime, isLongRunning, isServerless, redact, vedatrace };
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
- import { VedaTraceHttpTransportBrowser, VedaTraceHttpTransport, VedaTraceConsoleTransport } from './transports/index.mjs';
1
+ import { i as isFatal, a as isRetryable, r as retryAfterMs, V as VedaTraceHttpTransportBrowser, b as VedaTraceHttpTransport, c as VedaTraceConsoleTransport } from './index-BcBZY8as.mjs';
2
+ export { d as VedaTraceTransportError } from './index-BcBZY8as.mjs';
2
3
 
3
4
  class VedaTraceBatcher {
4
5
  constructor(transports, config, immediateFlush = false) {
@@ -6,55 +7,53 @@ class VedaTraceBatcher {
6
7
  this.config = config;
7
8
  this.immediateFlush = immediateFlush;
8
9
  this.context = config.executionContext;
10
+ this.waitUntilFn = config.waitUntil;
9
11
  }
10
12
  queue = [];
11
13
  flushTimer = null;
12
- flushDebounceTimer = null;
14
+ flushQueued = false;
13
15
  isFlushing = false;
14
16
  pendingFlush = null;
15
17
  context;
16
- /** Attach execution context after initialization */
18
+ waitUntilFn;
19
+ /**
20
+ * Set when the ingestion endpoint rejects our credentials. Every subsequent
21
+ * batch would fail identically, so we stop rather than spend a request (and a
22
+ * retry storm) per flush for the life of the process. start() clears it.
23
+ */
24
+ halted = false;
17
25
  setContext(ctx) {
18
26
  this.context = ctx;
19
27
  }
20
- /** Get current context */
21
28
  getContext() {
22
29
  return this.context;
23
30
  }
24
- /** Add log to queue with context-aware flush */
25
31
  add(log) {
32
+ if (this.halted) return;
26
33
  this.queue.push(log);
27
- if (!this.flushTimer && !this.immediateFlush) {
34
+ if (this.context || this.waitUntilFn) {
35
+ this.debouncedFlush();
36
+ return;
37
+ }
38
+ if (this.immediateFlush) {
39
+ this.flush();
40
+ return;
41
+ }
42
+ if (!this.flushTimer) {
28
43
  this.startFlushTimer();
29
44
  }
30
- if (this.immediateFlush || this.context) {
31
- this.debouncedFlush();
32
- } else if (this.queue.length >= this.config.batchSize) {
45
+ if (this.queue.length >= this.config.batchSize) {
33
46
  this.flush();
34
47
  }
35
48
  }
36
- /** Debounced flush - prevents rapid-fire flushes */
37
49
  debouncedFlush() {
38
- if (this.flushDebounceTimer) {
39
- clearTimeout(this.flushDebounceTimer);
40
- }
41
- this.flushDebounceTimer = setTimeout(() => {
42
- this.flushDebounceTimer = null;
43
- this.flush().catch((error) => {
44
- if (this.config.onError) {
45
- this.config.onError(
46
- error instanceof Error ? error : new Error(String(error))
47
- );
48
- } else {
49
- console.error(
50
- "[VedaTrace] Debounced flush error:",
51
- error instanceof Error ? error.message : String(error)
52
- );
53
- }
54
- });
55
- }, 100);
50
+ if (this.flushQueued) return;
51
+ this.flushQueued = true;
52
+ queueMicrotask(() => {
53
+ this.flushQueued = false;
54
+ this.flush().catch((error) => this.reportError(error));
55
+ });
56
56
  }
57
- /** Flush logs to all transports with waitUntil protection */
58
57
  async flush() {
59
58
  if (this.isFlushing) {
60
59
  return this.pendingFlush ?? Promise.resolve();
@@ -68,10 +67,16 @@ class VedaTraceBatcher {
68
67
  const flushPromise = this.sendWithRetry(logsToSend).finally(() => {
69
68
  this.isFlushing = false;
70
69
  this.pendingFlush = null;
70
+ }).then(() => {
71
+ if (this.queue.length > 0 && !this.halted) {
72
+ return this.flush();
73
+ }
71
74
  });
72
75
  this.pendingFlush = flushPromise;
73
- if (this.context) {
76
+ if (this.context && typeof this.context.waitUntil === "function") {
74
77
  this.context.waitUntil(flushPromise);
78
+ } else if (typeof this.waitUntilFn === "function") {
79
+ this.waitUntilFn(flushPromise);
75
80
  }
76
81
  return flushPromise;
77
82
  }
@@ -81,26 +86,47 @@ class VedaTraceBatcher {
81
86
  try {
82
87
  await transport.send(logs);
83
88
  } catch (error) {
84
- errors.push(error instanceof Error ? error : new Error(String(error)));
89
+ errors.push(error);
85
90
  }
86
91
  }
87
- if (errors.length > 0 && errors.length === this.transports.length) {
88
- if (attempt < this.config.maxRetries) {
89
- await this.delay(this.config.retryDelay * (attempt + 1));
90
- return this.sendWithRetry(logs, attempt + 1);
91
- }
92
- const combinedError = new Error(
93
- `Failed to send logs after ${this.config.maxRetries} retries: ${errors.map((e) => e.message).join(", ")}`
94
- );
95
- if (this.config.onError) {
96
- this.config.onError(combinedError);
97
- } else {
98
- console.error("[VedaTrace]", combinedError.message);
99
- }
92
+ if (errors.length === 0 || errors.length < this.transports.length) {
93
+ this.config.onSuccess?.();
100
94
  return;
101
95
  }
102
- if (this.config.onSuccess) {
103
- this.config.onSuccess();
96
+ const fatalError = errors.find(isFatal);
97
+ if (fatalError) {
98
+ this.halt(fatalError);
99
+ return;
100
+ }
101
+ if (errors.some(isRetryable) && attempt < this.config.maxRetries) {
102
+ const backoff = this.config.retryDelay * (attempt + 1);
103
+ await this.delay(retryAfterMs(errors) ?? backoff);
104
+ return this.sendWithRetry(logs, attempt + 1);
105
+ }
106
+ const detail = errors.map(describeError).join(", ");
107
+ this.reportError(
108
+ new Error(
109
+ errors.some(isRetryable) ? `Failed to send ${logs.length} logs after ${this.config.maxRetries} retries: ${detail}` : `Failed to send ${logs.length} logs: ${detail}`
110
+ )
111
+ );
112
+ }
113
+ /** Stop accepting logs after an unrecoverable authentication failure. */
114
+ halt(error) {
115
+ this.halted = true;
116
+ this.queue = [];
117
+ this.stop();
118
+ this.reportError(
119
+ new Error(
120
+ `VedaTrace disabled: ${describeError(error)}. Check your API key and the key's allowed origins, then call logger.start() to resume.`
121
+ )
122
+ );
123
+ }
124
+ reportError(error) {
125
+ const normalized = error instanceof Error ? error : new Error(String(error));
126
+ if (this.config.onError) {
127
+ this.config.onError(normalized);
128
+ } else {
129
+ console.error("[VedaTrace]", normalized.message);
104
130
  }
105
131
  }
106
132
  startFlushTimer() {
@@ -109,22 +135,11 @@ class VedaTraceBatcher {
109
135
  }
110
136
  this.flushTimer = setInterval(() => {
111
137
  if (this.queue.length > 0) {
112
- this.flush().catch((error) => {
113
- if (this.config.onError) {
114
- this.config.onError(
115
- error instanceof Error ? error : new Error(String(error))
116
- );
117
- } else {
118
- console.error(
119
- "[VedaTrace] Flush error:",
120
- error instanceof Error ? error.message : String(error)
121
- );
122
- }
123
- });
138
+ this.flush().catch((error) => this.reportError(error));
124
139
  }
125
140
  }, this.config.flushInterval);
126
141
  if (this.config.unrefTimer === true) {
127
- this.flushTimer.unref();
142
+ this.flushTimer.unref?.();
128
143
  }
129
144
  }
130
145
  stop() {
@@ -132,12 +147,10 @@ class VedaTraceBatcher {
132
147
  clearInterval(this.flushTimer);
133
148
  this.flushTimer = null;
134
149
  }
135
- if (this.flushDebounceTimer) {
136
- clearTimeout(this.flushDebounceTimer);
137
- this.flushDebounceTimer = null;
138
- }
150
+ this.flushQueued = false;
139
151
  }
140
152
  start() {
153
+ this.halted = false;
141
154
  if (!this.flushTimer && !this.immediateFlush) {
142
155
  this.startFlushTimer();
143
156
  }
@@ -148,10 +161,17 @@ class VedaTraceBatcher {
148
161
  getQueueSize() {
149
162
  return this.queue.length;
150
163
  }
164
+ /** True once an auth failure has shut the batcher down. */
165
+ isHalted() {
166
+ return this.halted;
167
+ }
151
168
  setExecutionContext(ctx) {
152
169
  this.context = ctx;
153
170
  }
154
171
  }
172
+ function describeError(error) {
173
+ return error instanceof Error ? error.message : String(error);
174
+ }
155
175
 
156
176
  function detectRuntime() {
157
177
  if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") {
@@ -194,7 +214,8 @@ function isBrowser() {
194
214
  return detectRuntime() === "browser";
195
215
  }
196
216
 
197
- const SDK_VERSION = process.env.npm_package_version ?? "0.0.0";
217
+ const SDK_VERSION = "0.3.1";
218
+
198
219
  class VedaTraceLogger {
199
220
  batcher = null;
200
221
  runtime;
@@ -347,24 +368,17 @@ class BrowserLifecycle {
347
368
  this.config = config;
348
369
  this.boundVisibilityHandler = this.handleVisibilityChange.bind(this);
349
370
  this.boundPageHideHandler = this.handlePageHide.bind(this);
350
- this.boundBeforeUnloadHandler = this.handleBeforeUnload.bind(this);
351
- this.boundUnloadHandler = this.handleUnload.bind(this);
352
371
  }
353
372
  boundVisibilityHandler;
354
373
  boundPageHideHandler;
355
- boundBeforeUnloadHandler;
356
- boundUnloadHandler;
357
374
  isAttached = false;
358
375
  pendingFlush = null;
359
376
  /** Start listening for browser lifecycle events */
360
377
  attach() {
361
378
  if (this.isAttached) return;
362
- if (typeof document !== "undefined") {
363
- document.addEventListener("visibilitychange", this.boundVisibilityHandler);
364
- window.addEventListener("pagehide", this.boundPageHideHandler);
365
- window.addEventListener("beforeunload", this.boundBeforeUnloadHandler);
366
- window.addEventListener("unload", this.boundUnloadHandler);
367
- }
379
+ if (typeof document === "undefined" || typeof window === "undefined") return;
380
+ document.addEventListener("visibilitychange", this.boundVisibilityHandler);
381
+ window.addEventListener("pagehide", this.boundPageHideHandler);
368
382
  this.isAttached = true;
369
383
  if (this.config.debug) {
370
384
  console.log("[VedaTrace] Browser lifecycle handlers attached");
@@ -373,21 +387,25 @@ class BrowserLifecycle {
373
387
  /** Stop listening for browser lifecycle events */
374
388
  detach() {
375
389
  if (!this.isAttached) return;
376
- if (typeof document !== "undefined") {
390
+ if (typeof document !== "undefined" && typeof window !== "undefined") {
377
391
  document.removeEventListener(
378
392
  "visibilitychange",
379
393
  this.boundVisibilityHandler
380
394
  );
381
395
  window.removeEventListener("pagehide", this.boundPageHideHandler);
382
- window.removeEventListener("beforeunload", this.boundBeforeUnloadHandler);
383
- window.removeEventListener("unload", this.boundUnloadHandler);
384
396
  }
385
397
  this.isAttached = false;
386
398
  if (this.config.debug) {
387
399
  console.log("[VedaTrace] Browser lifecycle handlers detached");
388
400
  }
389
401
  }
390
- /** Handle visibility change - flush when page becomes hidden */
402
+ /**
403
+ * Flush when the page becomes hidden.
404
+ *
405
+ * This is the one that actually matters: on mobile, a backgrounded tab is
406
+ * often discarded without ever firing pagehide, so "hidden" is the last
407
+ * reliable moment to ship what we have.
408
+ */
391
409
  handleVisibilityChange() {
392
410
  if (document.visibilityState === "hidden") {
393
411
  if (this.config.debug) {
@@ -396,7 +414,7 @@ class BrowserLifecycle {
396
414
  this.scheduleFlush();
397
415
  }
398
416
  }
399
- /** Handle pagehide event - primary flush handler for Safari */
417
+ /** Final flush as the page is torn down or frozen into the bfcache. */
400
418
  handlePageHide(event) {
401
419
  if (this.config.debug) {
402
420
  console.log(
@@ -404,46 +422,16 @@ class BrowserLifecycle {
404
422
  event.persisted ? "(cached)" : "(navigation)"
405
423
  );
406
424
  }
407
- if (event.persisted) {
408
- this.scheduleFlush();
409
- } else {
410
- this.finalFlush();
411
- }
412
- }
413
- /** Handle beforeunload - backup flush mechanism */
414
- handleBeforeUnload(event) {
415
- if (this.config.debug) {
416
- console.log("[VedaTrace] Before unload event");
417
- }
418
- this.finalFlush();
419
- }
420
- /** Handle unload - fallback for older browsers */
421
- handleUnload() {
422
- if (this.config.debug) {
423
- console.log("[VedaTrace] Unload event");
424
- }
425
- this.finalFlush();
425
+ this.scheduleFlush();
426
426
  }
427
- /** Schedule a debounced flush (for visibility change) */
427
+ /** Flush at most once at a time; keepalive carries it past the document. */
428
428
  scheduleFlush() {
429
429
  if (this.pendingFlush) return;
430
- this.pendingFlush = this.config.flush().finally(() => {
430
+ this.pendingFlush = this.config.flush().catch(() => {
431
+ }).finally(() => {
431
432
  this.pendingFlush = null;
432
433
  });
433
434
  }
434
- /**
435
- * Final flush using keepalive fetch
436
- * For sending logs after the page context is destroyed
437
- */
438
- finalFlush() {
439
- for (const transport of this.config.transports) {
440
- if (transport.name === "http" && "flush" in transport) {
441
- transport.flush?.();
442
- }
443
- }
444
- this.config.flush().catch(() => {
445
- });
446
- }
447
435
  /** Check if handlers are attached */
448
436
  isActive() {
449
437
  return this.isAttached;
@@ -524,6 +512,16 @@ function redactPii(value, mask) {
524
512
  return result;
525
513
  }
526
514
 
515
+ function resolveApiKey(config) {
516
+ if (config.apiKey) return config.apiKey;
517
+ try {
518
+ if (typeof process !== "undefined" && process.env) {
519
+ return process.env.VEDATRACE_API_KEY || void 0;
520
+ }
521
+ } catch {
522
+ }
523
+ return void 0;
524
+ }
527
525
  const RUNTIME_FLUSH_INTERVALS = {
528
526
  node: 3e3,
529
527
  bun: 3e3,
@@ -534,15 +532,16 @@ const RUNTIME_FLUSH_INTERVALS = {
534
532
  };
535
533
  function vedatrace(config = {}) {
536
534
  const runtime = detectRuntime();
537
- const logger = new VedaTraceLogger(config);
538
- if (config.apiKey && (!config.transports || config.transports.length === 0)) {
535
+ const apiKey = resolveApiKey(config);
536
+ const logger = new VedaTraceLogger(apiKey ? { ...config, apiKey } : config);
537
+ if (apiKey && (!config.transports || config.transports.length === 0)) {
539
538
  const isBrowserEnv = isBrowser();
540
539
  const isServerlessEnv = isServerless();
541
540
  const isLongRunningEnv = isLongRunning();
542
541
  const HttpTransport = isBrowserEnv ? VedaTraceHttpTransportBrowser : VedaTraceHttpTransport;
543
542
  const httpConfig = {
544
- apiKey: config.apiKey,
545
- keepalive: isBrowserEnv
543
+ apiKey,
544
+ keepalive: isBrowserEnv || isServerlessEnv
546
545
  };
547
546
  if (config.endpoint) httpConfig.endpoint = config.endpoint;
548
547
  const httpTransport = new HttpTransport(httpConfig);
@@ -567,12 +566,15 @@ function vedatrace(config = {}) {
567
566
  unrefTimer: config.unrefTimer ?? shouldUnrefTimer,
568
567
  executionContext: config.executionContext,
569
568
  onError: config.onError,
570
- onSuccess: config.onSuccess
569
+ onSuccess: config.onSuccess,
570
+ debug: config.debug,
571
+ waitUntil: config.waitUntil
571
572
  },
572
573
  immediateFlush
573
574
  );
574
575
  logger.setBatcher(batcher);
575
- if (typeof process !== "undefined" && isLongRunningEnv) {
576
+ const isNodeRuntime = typeof process !== "undefined" && process.versions?.node;
577
+ if (typeof process !== "undefined" && (isLongRunningEnv || isNodeRuntime)) {
576
578
  const flushLogs = async () => {
577
579
  await batcher.flush();
578
580
  };
@@ -605,4 +607,4 @@ function devVedatrace(config = {}) {
605
607
  });
606
608
  }
607
609
 
608
- export { BrowserLifecycle, VedaTraceBatcher, VedaTraceConsoleTransport, VedaTraceHttpTransport, VedaTraceHttpTransportBrowser, VedaTraceLogger, vedatrace as default, detectRuntime, devVedatrace, isBrowser, isEdgeRuntime, isLongRunning, isServerless, redact, vedatrace };
610
+ export { BrowserLifecycle, SDK_VERSION, VedaTraceBatcher, VedaTraceConsoleTransport, VedaTraceHttpTransport, VedaTraceHttpTransportBrowser, VedaTraceLogger, vedatrace as default, detectRuntime, devVedatrace, isBrowser, isEdgeRuntime, isLongRunning, isServerless, redact, vedatrace };
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var index = require('../index.cjs');
4
- require('../transports/index.cjs');
4
+ require('../index-osD28Hs0.cjs');
5
5
 
6
6
  function vedaTraceMiddleware(config = {}) {
7
7
  const {
@@ -11,10 +11,11 @@ function vedaTraceMiddleware(config = {}) {
11
11
  logBody = false,
12
12
  ...vedaConfig
13
13
  } = config;
14
+ const baseLogger = index.default(vedaConfig);
14
15
  return (req, res, next) => {
15
16
  const requestId = generateRequestId(req);
16
17
  req.requestId = requestId;
17
- const logger = index.default(vedaConfig).child({
18
+ const logger = baseLogger.child({
18
19
  requestId,
19
20
  ...requestMetadata(req)
20
21
  });
@@ -38,8 +39,6 @@ function vedaTraceMiddleware(config = {}) {
38
39
  statusCode: res.statusCode,
39
40
  durationMs: duration
40
41
  });
41
- logger.flush().catch(() => {
42
- });
43
42
  });
44
43
  }
45
44
  next();
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, NextFunction } from 'express';
2
- import { V as VedaTraceLoggerInterface, a as VedaTraceConfig, L as LogMetadata } from '../types-BU0UESs9.cjs';
2
+ import { V as VedaTraceLoggerInterface, a as VedaTraceConfig, L as LogMetadata } from '../types-CSBzeGyK.cjs';
3
3
 
4
4
  /**
5
5
  * Express.js middleware integration for VedaTrace
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, NextFunction } from 'express';
2
- import { V as VedaTraceLoggerInterface, a as VedaTraceConfig, L as LogMetadata } from '../types-BU0UESs9.mjs';
2
+ import { V as VedaTraceLoggerInterface, a as VedaTraceConfig, L as LogMetadata } from '../types-CSBzeGyK.mjs';
3
3
 
4
4
  /**
5
5
  * Express.js middleware integration for VedaTrace
@@ -1,5 +1,5 @@
1
1
  import vedatrace from '../index.mjs';
2
- import '../transports/index.mjs';
2
+ import '../index-BcBZY8as.mjs';
3
3
 
4
4
  function vedaTraceMiddleware(config = {}) {
5
5
  const {
@@ -9,10 +9,11 @@ function vedaTraceMiddleware(config = {}) {
9
9
  logBody = false,
10
10
  ...vedaConfig
11
11
  } = config;
12
+ const baseLogger = vedatrace(vedaConfig);
12
13
  return (req, res, next) => {
13
14
  const requestId = generateRequestId(req);
14
15
  req.requestId = requestId;
15
- const logger = vedatrace(vedaConfig).child({
16
+ const logger = baseLogger.child({
16
17
  requestId,
17
18
  ...requestMetadata(req)
18
19
  });
@@ -36,8 +37,6 @@ function vedaTraceMiddleware(config = {}) {
36
37
  statusCode: res.statusCode,
37
38
  durationMs: duration
38
39
  });
39
- logger.flush().catch(() => {
40
- });
41
40
  });
42
41
  }
43
42
  next();