@deeptracer/core 0.6.2 → 0.6.4

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
@@ -74,7 +74,7 @@ const result = await logger.startSpan("fetch-user", async (span) => {
74
74
  })
75
75
 
76
76
  // Flush before shutdown
77
- logger.destroy()
77
+ await logger.destroy()
78
78
  ```
79
79
 
80
80
  ## Configuration
@@ -90,7 +90,7 @@ const logger = createLogger({
90
90
 
91
91
  // Optional
92
92
  batchSize: 50, // Logs to buffer before sending (default: 50)
93
- flushIntervalMs: 5000, // Max ms between flushes (default: 5000)
93
+ flushIntervalMs: 5000, // Max ms between flushes (default: 5000 — 200 in serverless environments, auto-detected via VERCEL or AWS_LAMBDA_FUNCTION_NAME)
94
94
  debug: false, // Mirror logs to console (default: false)
95
95
  })
96
96
  ```
@@ -104,7 +104,7 @@ const logger = createLogger({
104
104
  | `service` | `string` | `"server"` | Service name (e.g., `"api"`, `"worker"`, `"web"`) |
105
105
  | `environment` | `string` | `NODE_ENV` / `"production"` | Deployment environment |
106
106
  | `batchSize` | `number` | `50` | Number of log entries to buffer before flushing |
107
- | `flushIntervalMs` | `number` | `5000` | Milliseconds between automatic flushes |
107
+ | `flushIntervalMs` | `number` | `5000 (200 in serverless environments — auto-detected via VERCEL or AWS_LAMBDA_FUNCTION_NAME)` | Milliseconds between automatic flushes |
108
108
  | `debug` | `boolean` | `false` | When `true`, all log calls also print to the console |
109
109
 
110
110
  ## API Reference
@@ -364,7 +364,7 @@ logger.llmUsage({
364
364
 
365
365
  #### `forRequest(request)`
366
366
 
367
- Create a request-scoped logger that extracts distributed trace context from incoming HTTP headers. The returned logger attaches `trace_id`, `span_id`, `request_id`, and `vercel_id` to all subsequent logs, errors, and spans.
367
+ Create a request-scoped logger that extracts distributed trace context from incoming HTTP headers. The returned logger attaches `trace_id`, `span_id`, `request_id`, and `vercel_id` to all subsequent logs, errors, and spans. Child loggers share the same transport as the root logger — logs from children are flushed together with the parent.
368
368
 
369
369
  ```ts
370
370
  const reqLogger = logger.forRequest(request: Request): Logger
@@ -396,7 +396,7 @@ app.get("/api/users", async (c) => {
396
396
 
397
397
  #### `withContext(name)`
398
398
 
399
- Create a new logger that includes a context name in every log entry. Useful for distinguishing logs from different modules or subsystems.
399
+ Create a new logger that includes a context name in every log entry. Useful for distinguishing logs from different modules or subsystems. Child loggers share the same transport as the root logger — logs from children are flushed together with the parent.
400
400
 
401
401
  ```ts
402
402
  const dbLogger = logger.withContext("database")
@@ -411,12 +411,12 @@ authLogger.info("Token refreshed") // context: "auth"
411
411
 
412
412
  ### Lifecycle
413
413
 
414
- #### `flush()`
414
+ #### `flush(): Promise<void>`
415
415
 
416
416
  Immediately send all buffered log entries. Call this before your process exits or when you want to ensure logs are delivered.
417
417
 
418
418
  ```ts
419
- logger.flush()
419
+ await logger.flush()
420
420
  ```
421
421
 
422
422
  #### `destroy()`
@@ -424,12 +424,14 @@ logger.flush()
424
424
  Stop the internal batch timer and flush any remaining log entries. Call this during graceful shutdown.
425
425
 
426
426
  ```ts
427
- process.on("SIGTERM", () => {
428
- logger.destroy()
427
+ process.on("SIGTERM", async () => {
428
+ await logger.destroy()
429
429
  process.exit(0)
430
430
  })
431
431
  ```
432
432
 
433
+ > **Note on child loggers:** Calling `destroy()` on a child logger (returned by `withContext()` or `forRequest()`) flushes the shared buffer and drains in-flight requests, but does **not** stop the root logger's batch timer. Only calling `destroy()` on the root logger stops the timer.
434
+
433
435
  ## Type Reference
434
436
 
435
437
  ### LoggerConfig
@@ -441,7 +443,7 @@ interface LoggerConfig {
441
443
  endpoint: string
442
444
  apiKey: string
443
445
  batchSize?: number // default: 50
444
- flushIntervalMs?: number // default: 5000
446
+ flushIntervalMs?: number // default: 5000 (200 in serverless environments — auto-detected via VERCEL or AWS_LAMBDA_FUNCTION_NAME)
445
447
  debug?: boolean // default: false
446
448
  }
447
449
  ```
@@ -571,6 +573,25 @@ Log entries are buffered and sent in batches to reduce network overhead:
571
573
 
572
574
  Error reports (`captureError`) and span data (`startSpan`, `startInactiveSpan`) are **not batched** -- they are sent immediately.
573
575
 
576
+ ### Serverless environments (Vercel, AWS Lambda)
577
+
578
+ In serverless functions, the execution context may freeze immediately after the HTTP response is sent, before the automatic flush timer fires. DeepTracer handles this in two ways:
579
+
580
+ - **Auto-detected interval**: When `VERCEL` or `AWS_LAMBDA_FUNCTION_NAME` is set, the default `flushIntervalMs` drops to 200ms.
581
+ - **Explicit flush**: Call `await logger.flush()` before returning a response to guarantee delivery.
582
+
583
+ For **`@deeptracer/nextjs`** users, `withRouteHandler` works with any handler function including third-party ones (Auth.js, Better Auth, Stripe webhooks) — just wrap the exported handler. Only use `waitUntil` if the library doesn't export individual `GET`/`POST` functions:
584
+
585
+ ```ts
586
+ import { waitUntil } from "@vercel/functions"
587
+
588
+ export const POST = async (req: Request) => {
589
+ const response = await thirdPartyHandler(req)
590
+ waitUntil(logger.flush()) // extends function lifetime, non-blocking
591
+ return response
592
+ }
593
+ ```
594
+
574
595
  ## Transport
575
596
 
576
597
  The transport layer sends data to four DeepTracer ingestion endpoints:
@@ -587,7 +608,7 @@ All requests include:
587
608
  - `Content-Type: application/json` header
588
609
  - `service` and `environment` fields in the JSON body
589
610
 
590
- If a request fails, a warning is logged to the console. The SDK does not retry failed requests -- it is designed to be non-blocking and never crash your application.
611
+ If a request fails with a network error or a 5xx response, the SDK retries up to **3 times** with exponential backoff (1s → 2s → 4s, +20% jitter). 4xx errors (bad auth, invalid payload) are not retried. After all retries are exhausted, a single warning is logged to the console subsequent failures for the same endpoint are suppressed to avoid console spam. The SDK never throws on transport errors.
591
612
 
592
613
  ## Monorepo
593
614
 
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var SDK_VERSION = "0.6.2";
2
+ var SDK_VERSION = "0.6.4";
3
3
  var SDK_NAME = "core";
4
4
 
5
5
  // src/transport.ts
@@ -172,7 +172,8 @@ var Batcher = class {
172
172
  constructor(config, onFlush) {
173
173
  this.onFlush = onFlush;
174
174
  this.batchSize = config.batchSize ?? 50;
175
- this.flushIntervalMs = config.flushIntervalMs ?? 5e3;
175
+ const isServerless = typeof process !== "undefined" && !!(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME);
176
+ this.flushIntervalMs = config.flushIntervalMs ?? (isServerless ? 200 : 5e3);
176
177
  this.startTimer();
177
178
  }
178
179
  buffer = [];
@@ -265,30 +266,34 @@ var _originalConsole = {
265
266
  var Logger = class _Logger {
266
267
  batcher;
267
268
  transport;
269
+ isRoot;
268
270
  effectiveLevel;
269
271
  contextName;
270
272
  config;
271
273
  state;
272
274
  requestMeta;
273
- constructor(config, contextName, requestMeta, state) {
275
+ constructor(config, contextName, requestMeta, state, sharedBatcher, sharedTransport) {
274
276
  this.config = config;
275
277
  this.contextName = contextName;
276
278
  this.requestMeta = requestMeta;
277
279
  this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
278
- const hasKey = !!config.apiKey;
279
- const hasEndpoint = !!config.endpoint;
280
- if (!hasKey && !hasEndpoint) {
281
- _originalConsole.warn(
282
- "[@deeptracer/core] No API key or endpoint configured. Running in local-only mode (logging methods work, but events are not sent). Set DEEPTRACER_KEY and DEEPTRACER_ENDPOINT to enable."
283
- );
284
- } else if (!hasKey) {
285
- _originalConsole.warn("[@deeptracer/core] No `apiKey` provided. Events will not be sent.");
286
- } else if (!hasEndpoint) {
287
- _originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
280
+ this.isRoot = !sharedBatcher;
281
+ if (this.isRoot) {
282
+ const hasKey = !!config.apiKey;
283
+ const hasEndpoint = !!config.endpoint;
284
+ if (!hasKey && !hasEndpoint) {
285
+ _originalConsole.warn(
286
+ "[@deeptracer/core] No API key or endpoint configured. Running in local-only mode (logging methods work, but events are not sent). Set DEEPTRACER_KEY and DEEPTRACER_ENDPOINT to enable."
287
+ );
288
+ } else if (!hasKey) {
289
+ _originalConsole.warn("[@deeptracer/core] No `apiKey` provided. Events will not be sent.");
290
+ } else if (!hasEndpoint) {
291
+ _originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
292
+ }
288
293
  }
289
294
  this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
290
- this.transport = new Transport(config);
291
- this.batcher = new Batcher(
295
+ this.transport = sharedTransport ?? new Transport(config);
296
+ this.batcher = sharedBatcher ?? new Batcher(
292
297
  { batchSize: config.batchSize, flushIntervalMs: config.flushIntervalMs },
293
298
  (entries) => {
294
299
  this.transport.sendLogs(entries);
@@ -476,7 +481,14 @@ var Logger = class _Logger {
476
481
  // ---------------------------------------------------------------------------
477
482
  /** Create a context-scoped logger. All logs include the context name. Gets an independent copy of state. */
478
483
  withContext(name) {
479
- return new _Logger(this.config, name, this.requestMeta, cloneState(this.state));
484
+ return new _Logger(
485
+ this.config,
486
+ name,
487
+ this.requestMeta,
488
+ cloneState(this.state),
489
+ this.batcher,
490
+ this.transport
491
+ );
480
492
  }
481
493
  /** Create a request-scoped logger that extracts trace context from headers. Gets an independent copy of state. */
482
494
  forRequest(request) {
@@ -503,7 +515,9 @@ var Logger = class _Logger {
503
515
  request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
504
516
  vercel_id: vercelId
505
517
  },
506
- cloneState(this.state)
518
+ cloneState(this.state),
519
+ this.batcher,
520
+ this.transport
507
521
  );
508
522
  }
509
523
  // ---------------------------------------------------------------------------
@@ -638,11 +652,25 @@ var Logger = class _Logger {
638
652
  this.transport.sendTrace(hookResult.data);
639
653
  },
640
654
  startSpan: (childOp, fn) => {
641
- const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
655
+ const childLogger = new _Logger(
656
+ this.config,
657
+ this.contextName,
658
+ childMeta,
659
+ this.state,
660
+ this.batcher,
661
+ this.transport
662
+ );
642
663
  return childLogger.startSpan(childOp, fn);
643
664
  },
644
665
  startInactiveSpan: (childOp) => {
645
- const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
666
+ const childLogger = new _Logger(
667
+ this.config,
668
+ this.contextName,
669
+ childMeta,
670
+ this.state,
671
+ this.batcher,
672
+ this.transport
673
+ );
646
674
  return childLogger.startInactiveSpan(childOp);
647
675
  },
648
676
  getHeaders: () => {
@@ -667,9 +695,19 @@ var Logger = class _Logger {
667
695
  // ---------------------------------------------------------------------------
668
696
  // Lifecycle
669
697
  // ---------------------------------------------------------------------------
670
- /** Immediately flush all batched log entries. */
671
- flush() {
698
+ /**
699
+ * Flush all batched log entries and wait for in-flight HTTP requests to complete.
700
+ *
701
+ * @returns Promise that resolves when all pending logs have been sent.
702
+ *
703
+ * @example
704
+ * ```ts
705
+ * await logger.flush() // ensure logs are sent before response is returned
706
+ * ```
707
+ */
708
+ async flush() {
672
709
  this.batcher.flush();
710
+ await this.transport.drain();
673
711
  }
674
712
  /**
675
713
  * Stop the batch timer, flush remaining logs, and wait for in-flight requests.
@@ -684,7 +722,11 @@ var Logger = class _Logger {
684
722
  * ```
685
723
  */
686
724
  async destroy(timeoutMs) {
687
- await this.batcher.destroy();
725
+ if (this.isRoot) {
726
+ await this.batcher.destroy();
727
+ } else {
728
+ this.batcher.flush();
729
+ }
688
730
  await this.transport.drain(timeoutMs);
689
731
  }
690
732
  };
package/dist/index.cjs CHANGED
@@ -33,7 +33,8 @@ var Batcher = class {
33
33
  constructor(config, onFlush) {
34
34
  this.onFlush = onFlush;
35
35
  this.batchSize = config.batchSize ?? 50;
36
- this.flushIntervalMs = config.flushIntervalMs ?? 5e3;
36
+ const isServerless = typeof process !== "undefined" && !!(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME);
37
+ this.flushIntervalMs = config.flushIntervalMs ?? (isServerless ? 200 : 5e3);
37
38
  this.startTimer();
38
39
  }
39
40
  buffer = [];
@@ -63,7 +64,7 @@ var Batcher = class {
63
64
  };
64
65
 
65
66
  // src/version.ts
66
- var SDK_VERSION = "0.6.2";
67
+ var SDK_VERSION = "0.6.4";
67
68
  var SDK_NAME = "core";
68
69
 
69
70
  // src/transport.ts
@@ -295,30 +296,34 @@ var _originalConsole = {
295
296
  var Logger = class _Logger {
296
297
  batcher;
297
298
  transport;
299
+ isRoot;
298
300
  effectiveLevel;
299
301
  contextName;
300
302
  config;
301
303
  state;
302
304
  requestMeta;
303
- constructor(config, contextName, requestMeta, state) {
305
+ constructor(config, contextName, requestMeta, state, sharedBatcher, sharedTransport) {
304
306
  this.config = config;
305
307
  this.contextName = contextName;
306
308
  this.requestMeta = requestMeta;
307
309
  this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
308
- const hasKey = !!config.apiKey;
309
- const hasEndpoint = !!config.endpoint;
310
- if (!hasKey && !hasEndpoint) {
311
- _originalConsole.warn(
312
- "[@deeptracer/core] No API key or endpoint configured. Running in local-only mode (logging methods work, but events are not sent). Set DEEPTRACER_KEY and DEEPTRACER_ENDPOINT to enable."
313
- );
314
- } else if (!hasKey) {
315
- _originalConsole.warn("[@deeptracer/core] No `apiKey` provided. Events will not be sent.");
316
- } else if (!hasEndpoint) {
317
- _originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
310
+ this.isRoot = !sharedBatcher;
311
+ if (this.isRoot) {
312
+ const hasKey = !!config.apiKey;
313
+ const hasEndpoint = !!config.endpoint;
314
+ if (!hasKey && !hasEndpoint) {
315
+ _originalConsole.warn(
316
+ "[@deeptracer/core] No API key or endpoint configured. Running in local-only mode (logging methods work, but events are not sent). Set DEEPTRACER_KEY and DEEPTRACER_ENDPOINT to enable."
317
+ );
318
+ } else if (!hasKey) {
319
+ _originalConsole.warn("[@deeptracer/core] No `apiKey` provided. Events will not be sent.");
320
+ } else if (!hasEndpoint) {
321
+ _originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
322
+ }
318
323
  }
319
324
  this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
320
- this.transport = new Transport(config);
321
- this.batcher = new Batcher(
325
+ this.transport = sharedTransport ?? new Transport(config);
326
+ this.batcher = sharedBatcher ?? new Batcher(
322
327
  { batchSize: config.batchSize, flushIntervalMs: config.flushIntervalMs },
323
328
  (entries) => {
324
329
  this.transport.sendLogs(entries);
@@ -506,7 +511,14 @@ var Logger = class _Logger {
506
511
  // ---------------------------------------------------------------------------
507
512
  /** Create a context-scoped logger. All logs include the context name. Gets an independent copy of state. */
508
513
  withContext(name) {
509
- return new _Logger(this.config, name, this.requestMeta, cloneState(this.state));
514
+ return new _Logger(
515
+ this.config,
516
+ name,
517
+ this.requestMeta,
518
+ cloneState(this.state),
519
+ this.batcher,
520
+ this.transport
521
+ );
510
522
  }
511
523
  /** Create a request-scoped logger that extracts trace context from headers. Gets an independent copy of state. */
512
524
  forRequest(request) {
@@ -533,7 +545,9 @@ var Logger = class _Logger {
533
545
  request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
534
546
  vercel_id: vercelId
535
547
  },
536
- cloneState(this.state)
548
+ cloneState(this.state),
549
+ this.batcher,
550
+ this.transport
537
551
  );
538
552
  }
539
553
  // ---------------------------------------------------------------------------
@@ -668,11 +682,25 @@ var Logger = class _Logger {
668
682
  this.transport.sendTrace(hookResult.data);
669
683
  },
670
684
  startSpan: (childOp, fn) => {
671
- const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
685
+ const childLogger = new _Logger(
686
+ this.config,
687
+ this.contextName,
688
+ childMeta,
689
+ this.state,
690
+ this.batcher,
691
+ this.transport
692
+ );
672
693
  return childLogger.startSpan(childOp, fn);
673
694
  },
674
695
  startInactiveSpan: (childOp) => {
675
- const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
696
+ const childLogger = new _Logger(
697
+ this.config,
698
+ this.contextName,
699
+ childMeta,
700
+ this.state,
701
+ this.batcher,
702
+ this.transport
703
+ );
676
704
  return childLogger.startInactiveSpan(childOp);
677
705
  },
678
706
  getHeaders: () => {
@@ -697,9 +725,19 @@ var Logger = class _Logger {
697
725
  // ---------------------------------------------------------------------------
698
726
  // Lifecycle
699
727
  // ---------------------------------------------------------------------------
700
- /** Immediately flush all batched log entries. */
701
- flush() {
728
+ /**
729
+ * Flush all batched log entries and wait for in-flight HTTP requests to complete.
730
+ *
731
+ * @returns Promise that resolves when all pending logs have been sent.
732
+ *
733
+ * @example
734
+ * ```ts
735
+ * await logger.flush() // ensure logs are sent before response is returned
736
+ * ```
737
+ */
738
+ async flush() {
702
739
  this.batcher.flush();
740
+ await this.transport.drain();
703
741
  }
704
742
  /**
705
743
  * Stop the batch timer, flush remaining logs, and wait for in-flight requests.
@@ -714,7 +752,11 @@ var Logger = class _Logger {
714
752
  * ```
715
753
  */
716
754
  async destroy(timeoutMs) {
717
- await this.batcher.destroy();
755
+ if (this.isRoot) {
756
+ await this.batcher.destroy();
757
+ } else {
758
+ this.batcher.flush();
759
+ }
718
760
  await this.transport.drain(timeoutMs);
719
761
  }
720
762
  };
@@ -771,7 +813,7 @@ var noopLogger = {
771
813
  startInactiveSpan: () => NOOP_INACTIVE_SPAN,
772
814
  wrap: (_operation, fn) => fn,
773
815
  // Lifecycle — resolve immediately
774
- flush: noop,
816
+ flush: () => Promise.resolve(),
775
817
  destroy: () => Promise.resolve()
776
818
  };
777
819
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { L as Logger } from './logger-CzZg2_vM.cjs';
2
- export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveSpan, b as LLMUsageReport, c as LogEntry, d as LogLevel, e as LoggerConfig, M as MiddlewareOptions, S as Span, f as SpanData, U as User, g as createLogger } from './logger-CzZg2_vM.cjs';
1
+ import { L as Logger } from './logger-DyJENLNA.cjs';
2
+ export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveSpan, b as LLMUsageReport, c as LogEntry, d as LogLevel, e as LoggerConfig, M as MiddlewareOptions, S as Span, f as SpanData, U as User, g as createLogger } from './logger-DyJENLNA.cjs';
3
3
 
4
4
  /**
5
5
  * A Logger-compatible object where every method is a silent no-op.
@@ -18,7 +18,7 @@ export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveS
18
18
  declare const noopLogger: Logger;
19
19
 
20
20
  /** SDK version. Update on each release. */
21
- declare const SDK_VERSION = "0.6.2";
21
+ declare const SDK_VERSION = "0.6.4";
22
22
  declare const SDK_NAME = "core";
23
23
 
24
24
  export { Logger, SDK_NAME, SDK_VERSION, noopLogger };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { L as Logger } from './logger-CzZg2_vM.js';
2
- export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveSpan, b as LLMUsageReport, c as LogEntry, d as LogLevel, e as LoggerConfig, M as MiddlewareOptions, S as Span, f as SpanData, U as User, g as createLogger } from './logger-CzZg2_vM.js';
1
+ import { L as Logger } from './logger-DyJENLNA.js';
2
+ export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveSpan, b as LLMUsageReport, c as LogEntry, d as LogLevel, e as LoggerConfig, M as MiddlewareOptions, S as Span, f as SpanData, U as User, g as createLogger } from './logger-DyJENLNA.js';
3
3
 
4
4
  /**
5
5
  * A Logger-compatible object where every method is a silent no-op.
@@ -18,7 +18,7 @@ export { B as BeforeSendEvent, a as Breadcrumb, E as ErrorReport, I as InactiveS
18
18
  declare const noopLogger: Logger;
19
19
 
20
20
  /** SDK version. Update on each release. */
21
- declare const SDK_VERSION = "0.6.2";
21
+ declare const SDK_VERSION = "0.6.4";
22
22
  declare const SDK_NAME = "core";
23
23
 
24
24
  export { Logger, SDK_NAME, SDK_VERSION, noopLogger };
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  SDK_NAME,
4
4
  SDK_VERSION,
5
5
  createLogger
6
- } from "./chunk-DHFWC5TL.js";
6
+ } from "./chunk-QAJHHVX4.js";
7
7
 
8
8
  // src/noop-logger.ts
9
9
  var NOOP_INACTIVE_SPAN = {
@@ -54,7 +54,7 @@ var noopLogger = {
54
54
  startInactiveSpan: () => NOOP_INACTIVE_SPAN,
55
55
  wrap: (_operation, fn) => fn,
56
56
  // Lifecycle — resolve immediately
57
- flush: noop,
57
+ flush: () => Promise.resolve(),
58
58
  destroy: () => Promise.resolve()
59
59
  };
60
60
  export {
package/dist/internal.cjs CHANGED
@@ -33,7 +33,8 @@ var Batcher = class {
33
33
  constructor(config, onFlush) {
34
34
  this.onFlush = onFlush;
35
35
  this.batchSize = config.batchSize ?? 50;
36
- this.flushIntervalMs = config.flushIntervalMs ?? 5e3;
36
+ const isServerless = typeof process !== "undefined" && !!(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME);
37
+ this.flushIntervalMs = config.flushIntervalMs ?? (isServerless ? 200 : 5e3);
37
38
  this.startTimer();
38
39
  }
39
40
  buffer = [];
@@ -63,7 +64,7 @@ var Batcher = class {
63
64
  };
64
65
 
65
66
  // src/version.ts
66
- var SDK_VERSION = "0.6.2";
67
+ var SDK_VERSION = "0.6.4";
67
68
  var SDK_NAME = "core";
68
69
 
69
70
  // src/transport.ts
@@ -295,30 +296,34 @@ var _originalConsole = {
295
296
  var Logger = class _Logger {
296
297
  batcher;
297
298
  transport;
299
+ isRoot;
298
300
  effectiveLevel;
299
301
  contextName;
300
302
  config;
301
303
  state;
302
304
  requestMeta;
303
- constructor(config, contextName, requestMeta, state) {
305
+ constructor(config, contextName, requestMeta, state, sharedBatcher, sharedTransport) {
304
306
  this.config = config;
305
307
  this.contextName = contextName;
306
308
  this.requestMeta = requestMeta;
307
309
  this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
308
- const hasKey = !!config.apiKey;
309
- const hasEndpoint = !!config.endpoint;
310
- if (!hasKey && !hasEndpoint) {
311
- _originalConsole.warn(
312
- "[@deeptracer/core] No API key or endpoint configured. Running in local-only mode (logging methods work, but events are not sent). Set DEEPTRACER_KEY and DEEPTRACER_ENDPOINT to enable."
313
- );
314
- } else if (!hasKey) {
315
- _originalConsole.warn("[@deeptracer/core] No `apiKey` provided. Events will not be sent.");
316
- } else if (!hasEndpoint) {
317
- _originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
310
+ this.isRoot = !sharedBatcher;
311
+ if (this.isRoot) {
312
+ const hasKey = !!config.apiKey;
313
+ const hasEndpoint = !!config.endpoint;
314
+ if (!hasKey && !hasEndpoint) {
315
+ _originalConsole.warn(
316
+ "[@deeptracer/core] No API key or endpoint configured. Running in local-only mode (logging methods work, but events are not sent). Set DEEPTRACER_KEY and DEEPTRACER_ENDPOINT to enable."
317
+ );
318
+ } else if (!hasKey) {
319
+ _originalConsole.warn("[@deeptracer/core] No `apiKey` provided. Events will not be sent.");
320
+ } else if (!hasEndpoint) {
321
+ _originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
322
+ }
318
323
  }
319
324
  this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
320
- this.transport = new Transport(config);
321
- this.batcher = new Batcher(
325
+ this.transport = sharedTransport ?? new Transport(config);
326
+ this.batcher = sharedBatcher ?? new Batcher(
322
327
  { batchSize: config.batchSize, flushIntervalMs: config.flushIntervalMs },
323
328
  (entries) => {
324
329
  this.transport.sendLogs(entries);
@@ -506,7 +511,14 @@ var Logger = class _Logger {
506
511
  // ---------------------------------------------------------------------------
507
512
  /** Create a context-scoped logger. All logs include the context name. Gets an independent copy of state. */
508
513
  withContext(name) {
509
- return new _Logger(this.config, name, this.requestMeta, cloneState(this.state));
514
+ return new _Logger(
515
+ this.config,
516
+ name,
517
+ this.requestMeta,
518
+ cloneState(this.state),
519
+ this.batcher,
520
+ this.transport
521
+ );
510
522
  }
511
523
  /** Create a request-scoped logger that extracts trace context from headers. Gets an independent copy of state. */
512
524
  forRequest(request) {
@@ -533,7 +545,9 @@ var Logger = class _Logger {
533
545
  request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
534
546
  vercel_id: vercelId
535
547
  },
536
- cloneState(this.state)
548
+ cloneState(this.state),
549
+ this.batcher,
550
+ this.transport
537
551
  );
538
552
  }
539
553
  // ---------------------------------------------------------------------------
@@ -668,11 +682,25 @@ var Logger = class _Logger {
668
682
  this.transport.sendTrace(hookResult.data);
669
683
  },
670
684
  startSpan: (childOp, fn) => {
671
- const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
685
+ const childLogger = new _Logger(
686
+ this.config,
687
+ this.contextName,
688
+ childMeta,
689
+ this.state,
690
+ this.batcher,
691
+ this.transport
692
+ );
672
693
  return childLogger.startSpan(childOp, fn);
673
694
  },
674
695
  startInactiveSpan: (childOp) => {
675
- const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
696
+ const childLogger = new _Logger(
697
+ this.config,
698
+ this.contextName,
699
+ childMeta,
700
+ this.state,
701
+ this.batcher,
702
+ this.transport
703
+ );
676
704
  return childLogger.startInactiveSpan(childOp);
677
705
  },
678
706
  getHeaders: () => {
@@ -697,9 +725,19 @@ var Logger = class _Logger {
697
725
  // ---------------------------------------------------------------------------
698
726
  // Lifecycle
699
727
  // ---------------------------------------------------------------------------
700
- /** Immediately flush all batched log entries. */
701
- flush() {
728
+ /**
729
+ * Flush all batched log entries and wait for in-flight HTTP requests to complete.
730
+ *
731
+ * @returns Promise that resolves when all pending logs have been sent.
732
+ *
733
+ * @example
734
+ * ```ts
735
+ * await logger.flush() // ensure logs are sent before response is returned
736
+ * ```
737
+ */
738
+ async flush() {
702
739
  this.batcher.flush();
740
+ await this.transport.drain();
703
741
  }
704
742
  /**
705
743
  * Stop the batch timer, flush remaining logs, and wait for in-flight requests.
@@ -714,7 +752,11 @@ var Logger = class _Logger {
714
752
  * ```
715
753
  */
716
754
  async destroy(timeoutMs) {
717
- await this.batcher.destroy();
755
+ if (this.isRoot) {
756
+ await this.batcher.destroy();
757
+ } else {
758
+ this.batcher.flush();
759
+ }
718
760
  await this.transport.drain(timeoutMs);
719
761
  }
720
762
  };
@@ -1,72 +1,4 @@
1
- import { e as LoggerConfig, c as LogEntry, E as ErrorReport, f as SpanData } from './logger-CzZg2_vM.cjs';
2
- export { L as Logger, h as LoggerState, M as MiddlewareOptions, _ as _originalConsole, p as parseTraceparent } from './logger-CzZg2_vM.cjs';
3
-
4
- /**
5
- * HTTP transport for sending data to the DeepTracer ingestion API.
6
- *
7
- * Features:
8
- * - Automatic retry with exponential backoff (3 retries, 1s/2s/4s + jitter)
9
- * - Only retries on network errors and 5xx (not 4xx client errors)
10
- * - SDK version header on every request (`x-deeptracer-sdk: core/0.3.0`)
11
- * - In-flight request tracking for graceful shutdown via `drain()`
12
- * - Silent no-op when no API key or endpoint is configured (no retries, no console noise)
13
- * - Warn-once per failure type — first failure for each send type (logs, error, trace)
14
- * logs a warning, subsequent identical failures are silently dropped
15
- */
16
- declare class Transport {
17
- private config;
18
- private inFlightRequests;
19
- /**
20
- * When true, all send methods become silent no-ops.
21
- * Set automatically when no auth key or no endpoint is configured.
22
- * This prevents pointless network requests and console noise during
23
- * local development without API keys.
24
- */
25
- private readonly disabled;
26
- /**
27
- * Tracks which send types (logs, error, trace, LLM usage) have already
28
- * logged a failure warning. After the first failure for a given type,
29
- * subsequent failures are silently dropped to prevent console spam
30
- * (e.g., when the ingestion endpoint is unreachable during development).
31
- */
32
- private warnedLabels;
33
- constructor(config: Pick<LoggerConfig, "endpoint" | "apiKey" | "service" | "environment">);
34
- private get authKey();
35
- /**
36
- * Send a request with automatic retry and exponential backoff.
37
- * Retries up to `maxRetries` times on network errors and 5xx responses.
38
- * Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
39
- *
40
- * After the first total failure for a given label, subsequent failures
41
- * are silently dropped (no more console warnings).
42
- */
43
- private sendWithRetry;
44
- /** Add +/- 20% jitter to a delay to prevent thundering herd. */
45
- private jitter;
46
- private sleep;
47
- /** Track an in-flight request and remove it when done. */
48
- private track;
49
- sendLogs(logs: LogEntry[]): Promise<void>;
50
- sendError(error: ErrorReport): Promise<void>;
51
- sendTrace(span: SpanData): Promise<void>;
52
- sendLLMUsage(report: {
53
- model: string;
54
- provider: string;
55
- operation: string;
56
- input_tokens: number;
57
- output_tokens: number;
58
- cost_usd: number;
59
- latency_ms: number;
60
- metadata?: Record<string, unknown>;
61
- }): Promise<void>;
62
- /**
63
- * Wait for all in-flight requests to complete, with a timeout.
64
- * Used by `logger.destroy()` to ensure data is sent before process exit.
65
- *
66
- * @param timeoutMs - Maximum time to wait (default: 2000ms)
67
- */
68
- drain(timeoutMs?: number): Promise<void>;
69
- }
1
+ export { L as Logger, e as LoggerConfig, h as LoggerState, M as MiddlewareOptions, T as Transport, _ as _originalConsole, p as parseTraceparent } from './logger-DyJENLNA.cjs';
70
2
 
71
3
  /**
72
4
  * Parse console.log/info/warn/error arguments into a structured `{ message, metadata }` pair.
@@ -82,4 +14,4 @@ declare function parseConsoleArgs(args: unknown[]): {
82
14
  metadata?: Record<string, unknown>;
83
15
  };
84
16
 
85
- export { LoggerConfig, Transport, parseConsoleArgs };
17
+ export { parseConsoleArgs };
@@ -1,72 +1,4 @@
1
- import { e as LoggerConfig, c as LogEntry, E as ErrorReport, f as SpanData } from './logger-CzZg2_vM.js';
2
- export { L as Logger, h as LoggerState, M as MiddlewareOptions, _ as _originalConsole, p as parseTraceparent } from './logger-CzZg2_vM.js';
3
-
4
- /**
5
- * HTTP transport for sending data to the DeepTracer ingestion API.
6
- *
7
- * Features:
8
- * - Automatic retry with exponential backoff (3 retries, 1s/2s/4s + jitter)
9
- * - Only retries on network errors and 5xx (not 4xx client errors)
10
- * - SDK version header on every request (`x-deeptracer-sdk: core/0.3.0`)
11
- * - In-flight request tracking for graceful shutdown via `drain()`
12
- * - Silent no-op when no API key or endpoint is configured (no retries, no console noise)
13
- * - Warn-once per failure type — first failure for each send type (logs, error, trace)
14
- * logs a warning, subsequent identical failures are silently dropped
15
- */
16
- declare class Transport {
17
- private config;
18
- private inFlightRequests;
19
- /**
20
- * When true, all send methods become silent no-ops.
21
- * Set automatically when no auth key or no endpoint is configured.
22
- * This prevents pointless network requests and console noise during
23
- * local development without API keys.
24
- */
25
- private readonly disabled;
26
- /**
27
- * Tracks which send types (logs, error, trace, LLM usage) have already
28
- * logged a failure warning. After the first failure for a given type,
29
- * subsequent failures are silently dropped to prevent console spam
30
- * (e.g., when the ingestion endpoint is unreachable during development).
31
- */
32
- private warnedLabels;
33
- constructor(config: Pick<LoggerConfig, "endpoint" | "apiKey" | "service" | "environment">);
34
- private get authKey();
35
- /**
36
- * Send a request with automatic retry and exponential backoff.
37
- * Retries up to `maxRetries` times on network errors and 5xx responses.
38
- * Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
39
- *
40
- * After the first total failure for a given label, subsequent failures
41
- * are silently dropped (no more console warnings).
42
- */
43
- private sendWithRetry;
44
- /** Add +/- 20% jitter to a delay to prevent thundering herd. */
45
- private jitter;
46
- private sleep;
47
- /** Track an in-flight request and remove it when done. */
48
- private track;
49
- sendLogs(logs: LogEntry[]): Promise<void>;
50
- sendError(error: ErrorReport): Promise<void>;
51
- sendTrace(span: SpanData): Promise<void>;
52
- sendLLMUsage(report: {
53
- model: string;
54
- provider: string;
55
- operation: string;
56
- input_tokens: number;
57
- output_tokens: number;
58
- cost_usd: number;
59
- latency_ms: number;
60
- metadata?: Record<string, unknown>;
61
- }): Promise<void>;
62
- /**
63
- * Wait for all in-flight requests to complete, with a timeout.
64
- * Used by `logger.destroy()` to ensure data is sent before process exit.
65
- *
66
- * @param timeoutMs - Maximum time to wait (default: 2000ms)
67
- */
68
- drain(timeoutMs?: number): Promise<void>;
69
- }
1
+ export { L as Logger, e as LoggerConfig, h as LoggerState, M as MiddlewareOptions, T as Transport, _ as _originalConsole, p as parseTraceparent } from './logger-DyJENLNA.js';
70
2
 
71
3
  /**
72
4
  * Parse console.log/info/warn/error arguments into a structured `{ message, metadata }` pair.
@@ -82,4 +14,4 @@ declare function parseConsoleArgs(args: unknown[]): {
82
14
  metadata?: Record<string, unknown>;
83
15
  };
84
16
 
85
- export { LoggerConfig, Transport, parseConsoleArgs };
17
+ export { parseConsoleArgs };
package/dist/internal.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  Transport,
4
4
  _originalConsole,
5
5
  parseTraceparent
6
- } from "./chunk-DHFWC5TL.js";
6
+ } from "./chunk-QAJHHVX4.js";
7
7
 
8
8
  // src/internal.ts
9
9
  function safeStringify(value) {
@@ -209,6 +209,89 @@ type BeforeSendEvent = {
209
209
  data: LLMUsageReport;
210
210
  };
211
211
 
212
+ declare class Batcher {
213
+ private onFlush;
214
+ private buffer;
215
+ private timer;
216
+ private batchSize;
217
+ private flushIntervalMs;
218
+ constructor(config: {
219
+ batchSize?: number;
220
+ flushIntervalMs?: number;
221
+ }, onFlush: (entries: LogEntry[]) => void);
222
+ add(entry: LogEntry): void;
223
+ flush(): void;
224
+ private startTimer;
225
+ destroy(): Promise<void>;
226
+ }
227
+
228
+ /**
229
+ * HTTP transport for sending data to the DeepTracer ingestion API.
230
+ *
231
+ * Features:
232
+ * - Automatic retry with exponential backoff (3 retries, 1s/2s/4s + jitter)
233
+ * - Only retries on network errors and 5xx (not 4xx client errors)
234
+ * - SDK version header on every request (`x-deeptracer-sdk: core/0.3.0`)
235
+ * - In-flight request tracking for graceful shutdown via `drain()`
236
+ * - Silent no-op when no API key or endpoint is configured (no retries, no console noise)
237
+ * - Warn-once per failure type — first failure for each send type (logs, error, trace)
238
+ * logs a warning, subsequent identical failures are silently dropped
239
+ */
240
+ declare class Transport {
241
+ private config;
242
+ private inFlightRequests;
243
+ /**
244
+ * When true, all send methods become silent no-ops.
245
+ * Set automatically when no auth key or no endpoint is configured.
246
+ * This prevents pointless network requests and console noise during
247
+ * local development without API keys.
248
+ */
249
+ private readonly disabled;
250
+ /**
251
+ * Tracks which send types (logs, error, trace, LLM usage) have already
252
+ * logged a failure warning. After the first failure for a given type,
253
+ * subsequent failures are silently dropped to prevent console spam
254
+ * (e.g., when the ingestion endpoint is unreachable during development).
255
+ */
256
+ private warnedLabels;
257
+ constructor(config: Pick<LoggerConfig, "endpoint" | "apiKey" | "service" | "environment">);
258
+ private get authKey();
259
+ /**
260
+ * Send a request with automatic retry and exponential backoff.
261
+ * Retries up to `maxRetries` times on network errors and 5xx responses.
262
+ * Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
263
+ *
264
+ * After the first total failure for a given label, subsequent failures
265
+ * are silently dropped (no more console warnings).
266
+ */
267
+ private sendWithRetry;
268
+ /** Add +/- 20% jitter to a delay to prevent thundering herd. */
269
+ private jitter;
270
+ private sleep;
271
+ /** Track an in-flight request and remove it when done. */
272
+ private track;
273
+ sendLogs(logs: LogEntry[]): Promise<void>;
274
+ sendError(error: ErrorReport): Promise<void>;
275
+ sendTrace(span: SpanData): Promise<void>;
276
+ sendLLMUsage(report: {
277
+ model: string;
278
+ provider: string;
279
+ operation: string;
280
+ input_tokens: number;
281
+ output_tokens: number;
282
+ cost_usd: number;
283
+ latency_ms: number;
284
+ metadata?: Record<string, unknown>;
285
+ }): Promise<void>;
286
+ /**
287
+ * Wait for all in-flight requests to complete, with a timeout.
288
+ * Used by `logger.destroy()` to ensure data is sent before process exit.
289
+ *
290
+ * @param timeoutMs - Maximum time to wait (default: 2000ms)
291
+ */
292
+ drain(timeoutMs?: number): Promise<void>;
293
+ }
294
+
212
295
  /**
213
296
  * Mutable state for a Logger instance.
214
297
  * The root Logger creates this; `withContext()` and `forRequest()` clone it
@@ -276,6 +359,7 @@ declare const _originalConsole: {
276
359
  declare class Logger {
277
360
  private batcher;
278
361
  private transport;
362
+ private readonly isRoot;
279
363
  private effectiveLevel;
280
364
  protected contextName?: string;
281
365
  protected config: LoggerConfig;
@@ -291,7 +375,7 @@ declare class Logger {
291
375
  span_id?: string;
292
376
  request_id?: string;
293
377
  vercel_id?: string;
294
- }, state?: LoggerState);
378
+ }, state?: LoggerState, sharedBatcher?: Batcher, sharedTransport?: Transport);
295
379
  /**
296
380
  * Set the current user context. Attached to all subsequent logs, errors, spans, and LLM reports.
297
381
  * Only affects this logger instance — child loggers created via `withContext()` or `forRequest()`
@@ -378,8 +462,17 @@ declare class Logger {
378
462
  startInactiveSpan(operation: string): InactiveSpan;
379
463
  /** Wrap a function with automatic tracing and error capture. */
380
464
  wrap<TArgs extends unknown[], TReturn>(operation: string, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
381
- /** Immediately flush all batched log entries. */
382
- flush(): void;
465
+ /**
466
+ * Flush all batched log entries and wait for in-flight HTTP requests to complete.
467
+ *
468
+ * @returns Promise that resolves when all pending logs have been sent.
469
+ *
470
+ * @example
471
+ * ```ts
472
+ * await logger.flush() // ensure logs are sent before response is returned
473
+ * ```
474
+ */
475
+ flush(): Promise<void>;
383
476
  /**
384
477
  * Stop the batch timer, flush remaining logs, and wait for in-flight requests.
385
478
  *
@@ -397,4 +490,4 @@ declare class Logger {
397
490
  /** Create a new DeepTracer logger instance. */
398
491
  declare function createLogger(config: LoggerConfig): Logger;
399
492
 
400
- export { type BeforeSendEvent as B, type ErrorReport as E, type InactiveSpan as I, Logger as L, type MiddlewareOptions as M, type Span as S, type User as U, _originalConsole as _, type Breadcrumb as a, type LLMUsageReport as b, type LogEntry as c, type LogLevel as d, type LoggerConfig as e, type SpanData as f, createLogger as g, type LoggerState as h, parseTraceparent as p };
493
+ export { type BeforeSendEvent as B, type ErrorReport as E, type InactiveSpan as I, Logger as L, type MiddlewareOptions as M, type Span as S, Transport as T, type User as U, _originalConsole as _, type Breadcrumb as a, type LLMUsageReport as b, type LogEntry as c, type LogLevel as d, type LoggerConfig as e, type SpanData as f, createLogger as g, type LoggerState as h, parseTraceparent as p };
@@ -209,6 +209,89 @@ type BeforeSendEvent = {
209
209
  data: LLMUsageReport;
210
210
  };
211
211
 
212
+ declare class Batcher {
213
+ private onFlush;
214
+ private buffer;
215
+ private timer;
216
+ private batchSize;
217
+ private flushIntervalMs;
218
+ constructor(config: {
219
+ batchSize?: number;
220
+ flushIntervalMs?: number;
221
+ }, onFlush: (entries: LogEntry[]) => void);
222
+ add(entry: LogEntry): void;
223
+ flush(): void;
224
+ private startTimer;
225
+ destroy(): Promise<void>;
226
+ }
227
+
228
+ /**
229
+ * HTTP transport for sending data to the DeepTracer ingestion API.
230
+ *
231
+ * Features:
232
+ * - Automatic retry with exponential backoff (3 retries, 1s/2s/4s + jitter)
233
+ * - Only retries on network errors and 5xx (not 4xx client errors)
234
+ * - SDK version header on every request (`x-deeptracer-sdk: core/0.3.0`)
235
+ * - In-flight request tracking for graceful shutdown via `drain()`
236
+ * - Silent no-op when no API key or endpoint is configured (no retries, no console noise)
237
+ * - Warn-once per failure type — first failure for each send type (logs, error, trace)
238
+ * logs a warning, subsequent identical failures are silently dropped
239
+ */
240
+ declare class Transport {
241
+ private config;
242
+ private inFlightRequests;
243
+ /**
244
+ * When true, all send methods become silent no-ops.
245
+ * Set automatically when no auth key or no endpoint is configured.
246
+ * This prevents pointless network requests and console noise during
247
+ * local development without API keys.
248
+ */
249
+ private readonly disabled;
250
+ /**
251
+ * Tracks which send types (logs, error, trace, LLM usage) have already
252
+ * logged a failure warning. After the first failure for a given type,
253
+ * subsequent failures are silently dropped to prevent console spam
254
+ * (e.g., when the ingestion endpoint is unreachable during development).
255
+ */
256
+ private warnedLabels;
257
+ constructor(config: Pick<LoggerConfig, "endpoint" | "apiKey" | "service" | "environment">);
258
+ private get authKey();
259
+ /**
260
+ * Send a request with automatic retry and exponential backoff.
261
+ * Retries up to `maxRetries` times on network errors and 5xx responses.
262
+ * Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
263
+ *
264
+ * After the first total failure for a given label, subsequent failures
265
+ * are silently dropped (no more console warnings).
266
+ */
267
+ private sendWithRetry;
268
+ /** Add +/- 20% jitter to a delay to prevent thundering herd. */
269
+ private jitter;
270
+ private sleep;
271
+ /** Track an in-flight request and remove it when done. */
272
+ private track;
273
+ sendLogs(logs: LogEntry[]): Promise<void>;
274
+ sendError(error: ErrorReport): Promise<void>;
275
+ sendTrace(span: SpanData): Promise<void>;
276
+ sendLLMUsage(report: {
277
+ model: string;
278
+ provider: string;
279
+ operation: string;
280
+ input_tokens: number;
281
+ output_tokens: number;
282
+ cost_usd: number;
283
+ latency_ms: number;
284
+ metadata?: Record<string, unknown>;
285
+ }): Promise<void>;
286
+ /**
287
+ * Wait for all in-flight requests to complete, with a timeout.
288
+ * Used by `logger.destroy()` to ensure data is sent before process exit.
289
+ *
290
+ * @param timeoutMs - Maximum time to wait (default: 2000ms)
291
+ */
292
+ drain(timeoutMs?: number): Promise<void>;
293
+ }
294
+
212
295
  /**
213
296
  * Mutable state for a Logger instance.
214
297
  * The root Logger creates this; `withContext()` and `forRequest()` clone it
@@ -276,6 +359,7 @@ declare const _originalConsole: {
276
359
  declare class Logger {
277
360
  private batcher;
278
361
  private transport;
362
+ private readonly isRoot;
279
363
  private effectiveLevel;
280
364
  protected contextName?: string;
281
365
  protected config: LoggerConfig;
@@ -291,7 +375,7 @@ declare class Logger {
291
375
  span_id?: string;
292
376
  request_id?: string;
293
377
  vercel_id?: string;
294
- }, state?: LoggerState);
378
+ }, state?: LoggerState, sharedBatcher?: Batcher, sharedTransport?: Transport);
295
379
  /**
296
380
  * Set the current user context. Attached to all subsequent logs, errors, spans, and LLM reports.
297
381
  * Only affects this logger instance — child loggers created via `withContext()` or `forRequest()`
@@ -378,8 +462,17 @@ declare class Logger {
378
462
  startInactiveSpan(operation: string): InactiveSpan;
379
463
  /** Wrap a function with automatic tracing and error capture. */
380
464
  wrap<TArgs extends unknown[], TReturn>(operation: string, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
381
- /** Immediately flush all batched log entries. */
382
- flush(): void;
465
+ /**
466
+ * Flush all batched log entries and wait for in-flight HTTP requests to complete.
467
+ *
468
+ * @returns Promise that resolves when all pending logs have been sent.
469
+ *
470
+ * @example
471
+ * ```ts
472
+ * await logger.flush() // ensure logs are sent before response is returned
473
+ * ```
474
+ */
475
+ flush(): Promise<void>;
383
476
  /**
384
477
  * Stop the batch timer, flush remaining logs, and wait for in-flight requests.
385
478
  *
@@ -397,4 +490,4 @@ declare class Logger {
397
490
  /** Create a new DeepTracer logger instance. */
398
491
  declare function createLogger(config: LoggerConfig): Logger;
399
492
 
400
- export { type BeforeSendEvent as B, type ErrorReport as E, type InactiveSpan as I, Logger as L, type MiddlewareOptions as M, type Span as S, type User as U, _originalConsole as _, type Breadcrumb as a, type LLMUsageReport as b, type LogEntry as c, type LogLevel as d, type LoggerConfig as e, type SpanData as f, createLogger as g, type LoggerState as h, parseTraceparent as p };
493
+ export { type BeforeSendEvent as B, type ErrorReport as E, type InactiveSpan as I, Logger as L, type MiddlewareOptions as M, type Span as S, Transport as T, type User as U, _originalConsole as _, type Breadcrumb as a, type LLMUsageReport as b, type LogEntry as c, type LogLevel as d, type LoggerConfig as e, type SpanData as f, createLogger as g, type LoggerState as h, parseTraceparent as p };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeptracer/core",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Core SDK for DeepTracer — Logger class, types, transport, batcher, tracing",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",