@deeptracer/core 0.3.1 → 0.4.2

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/internal.cjs CHANGED
@@ -21,7 +21,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var internal_exports = {};
22
22
  __export(internal_exports, {
23
23
  Logger: () => Logger,
24
- _originalConsole: () => _originalConsole
24
+ Transport: () => Transport,
25
+ _originalConsole: () => _originalConsole,
26
+ parseConsoleArgs: () => parseConsoleArgs,
27
+ parseTraceparent: () => parseTraceparent
25
28
  });
26
29
  module.exports = __toCommonJS(internal_exports);
27
30
 
@@ -60,21 +63,51 @@ var Batcher = class {
60
63
  };
61
64
 
62
65
  // src/version.ts
63
- var SDK_VERSION = "0.3.1";
66
+ var SDK_VERSION = "0.4.2";
64
67
  var SDK_NAME = "core";
65
68
 
66
69
  // src/transport.ts
67
70
  var Transport = class {
68
71
  constructor(config) {
69
72
  this.config = config;
73
+ const hasKey = !!(config.secretKey || config.publicKey);
74
+ const hasEndpoint = !!config.endpoint;
75
+ this.disabled = !hasKey || !hasEndpoint;
76
+ if (config.secretKey?.startsWith("dt_secret_") && typeof globalThis.window !== "undefined") {
77
+ console.error(
78
+ "[@deeptracer/core] WARNING: `secretKey` (dt_secret_...) detected in a browser bundle. This exposes your server key to end users. Use `publicKey` (dt_public_...) for client-side code."
79
+ );
80
+ }
70
81
  }
71
82
  inFlightRequests = /* @__PURE__ */ new Set();
83
+ /**
84
+ * When true, all send methods become silent no-ops.
85
+ * Set automatically when no auth key or no endpoint is configured.
86
+ * This prevents pointless network requests and console noise during
87
+ * local development without API keys.
88
+ */
89
+ disabled;
90
+ /**
91
+ * Tracks which send types (logs, error, trace, LLM usage) have already
92
+ * logged a failure warning. After the first failure for a given type,
93
+ * subsequent failures are silently dropped to prevent console spam
94
+ * (e.g., when the ingestion endpoint is unreachable during development).
95
+ */
96
+ warnedLabels = /* @__PURE__ */ new Set();
97
+ /** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
98
+ get authKey() {
99
+ return this.config.secretKey ?? this.config.publicKey ?? "";
100
+ }
72
101
  /**
73
102
  * Send a request with automatic retry and exponential backoff.
74
103
  * Retries up to `maxRetries` times on network errors and 5xx responses.
75
104
  * Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
105
+ *
106
+ * After the first total failure for a given label, subsequent failures
107
+ * are silently dropped (no more console warnings).
76
108
  */
77
109
  async sendWithRetry(url, body, label, maxRetries = 3) {
110
+ if (this.disabled) return;
78
111
  const baseDelays = [1e3, 2e3, 4e3];
79
112
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
80
113
  try {
@@ -82,33 +115,45 @@ var Transport = class {
82
115
  method: "POST",
83
116
  headers: {
84
117
  "Content-Type": "application/json",
85
- Authorization: `Bearer ${this.config.apiKey}`,
118
+ Authorization: `Bearer ${this.authKey}`,
86
119
  "x-deeptracer-sdk": `${SDK_NAME}/${SDK_VERSION}`
87
120
  },
88
121
  body: JSON.stringify(body)
89
122
  });
90
- if (res.ok) return;
123
+ if (res.ok) {
124
+ this.warnedLabels.delete(label);
125
+ return;
126
+ }
91
127
  if (res.status >= 400 && res.status < 500) {
92
- console.warn(
93
- `[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText}`
94
- );
128
+ if (!this.warnedLabels.has(label)) {
129
+ this.warnedLabels.add(label);
130
+ console.warn(
131
+ `[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText}`
132
+ );
133
+ }
95
134
  return;
96
135
  }
97
136
  if (attempt < maxRetries) {
98
137
  await this.sleep(this.jitter(baseDelays[attempt]));
99
138
  continue;
100
139
  }
101
- console.warn(
102
- `[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText} (exhausted ${maxRetries} retries)`
103
- );
140
+ if (!this.warnedLabels.has(label)) {
141
+ this.warnedLabels.add(label);
142
+ console.warn(
143
+ `[@deeptracer/core] Failed to send ${label}: ${res.status} ${res.statusText} (exhausted ${maxRetries} retries). Suppressing further warnings.`
144
+ );
145
+ }
104
146
  } catch {
105
147
  if (attempt < maxRetries) {
106
148
  await this.sleep(this.jitter(baseDelays[attempt]));
107
149
  continue;
108
150
  }
109
- console.warn(
110
- `[@deeptracer/core] Failed to send ${label} (exhausted ${maxRetries} retries)`
111
- );
151
+ if (!this.warnedLabels.has(label)) {
152
+ this.warnedLabels.add(label);
153
+ console.warn(
154
+ `[@deeptracer/core] Failed to send ${label} (exhausted ${maxRetries} retries). Suppressing further warnings.`
155
+ );
156
+ }
112
157
  }
113
158
  }
114
159
  }
@@ -129,7 +174,6 @@ var Transport = class {
129
174
  const p = this.sendWithRetry(
130
175
  `${this.config.endpoint}/ingest/logs`,
131
176
  {
132
- product: this.config.product,
133
177
  service: this.config.service,
134
178
  environment: this.config.environment,
135
179
  logs
@@ -144,7 +188,6 @@ var Transport = class {
144
188
  `${this.config.endpoint}/ingest/errors`,
145
189
  {
146
190
  ...error,
147
- product: this.config.product,
148
191
  service: this.config.service,
149
192
  environment: this.config.environment
150
193
  },
@@ -158,7 +201,6 @@ var Transport = class {
158
201
  `${this.config.endpoint}/ingest/traces`,
159
202
  {
160
203
  ...span,
161
- product: this.config.product,
162
204
  service: this.config.service,
163
205
  environment: this.config.environment
164
206
  },
@@ -172,7 +214,6 @@ var Transport = class {
172
214
  `${this.config.endpoint}/ingest/llm`,
173
215
  {
174
216
  ...report,
175
- product: this.config.product,
176
217
  service: this.config.service,
177
218
  environment: this.config.environment
178
219
  },
@@ -206,6 +247,15 @@ function createLoggerState(maxBreadcrumbs) {
206
247
  maxBreadcrumbs
207
248
  };
208
249
  }
250
+ function cloneState(state) {
251
+ return {
252
+ user: state.user ? { ...state.user } : null,
253
+ tags: { ...state.tags },
254
+ contexts: Object.fromEntries(Object.entries(state.contexts).map(([k, v]) => [k, { ...v }])),
255
+ breadcrumbs: [...state.breadcrumbs],
256
+ maxBreadcrumbs: state.maxBreadcrumbs
257
+ };
258
+ }
209
259
  function addBreadcrumb(state, breadcrumb) {
210
260
  state.breadcrumbs.push(breadcrumb);
211
261
  if (state.breadcrumbs.length > state.maxBreadcrumbs) {
@@ -214,11 +264,33 @@ function addBreadcrumb(state, breadcrumb) {
214
264
  }
215
265
 
216
266
  // src/logger.ts
267
+ var LOG_LEVEL_VALUES = {
268
+ debug: 0,
269
+ info: 1,
270
+ warn: 2,
271
+ error: 3
272
+ };
217
273
  function generateId() {
218
274
  const bytes = new Uint8Array(8);
219
275
  crypto.getRandomValues(bytes);
220
276
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
221
277
  }
278
+ function generateTraceId() {
279
+ const bytes = new Uint8Array(16);
280
+ crypto.getRandomValues(bytes);
281
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
282
+ }
283
+ function parseTraceparent(header) {
284
+ const parts = header.trim().split("-");
285
+ if (parts.length !== 4) return null;
286
+ const [version, traceId, parentId, flags] = parts;
287
+ if (version !== "00") return null;
288
+ if (traceId.length !== 32 || !/^[0-9a-f]{32}$/.test(traceId)) return null;
289
+ if (parentId.length !== 16 || !/^[0-9a-f]{16}$/.test(parentId)) return null;
290
+ if (flags.length !== 2 || !/^[0-9a-f]{2}$/.test(flags)) return null;
291
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentId)) return null;
292
+ return { traceId, parentId, flags };
293
+ }
222
294
  var _originalConsole = {
223
295
  log: console.log,
224
296
  info: console.info,
@@ -229,6 +301,7 @@ var _originalConsole = {
229
301
  var Logger = class _Logger {
230
302
  batcher;
231
303
  transport;
304
+ effectiveLevel;
232
305
  contextName;
233
306
  config;
234
307
  state;
@@ -238,6 +311,20 @@ var Logger = class _Logger {
238
311
  this.contextName = contextName;
239
312
  this.requestMeta = requestMeta;
240
313
  this.state = state ?? createLoggerState(config.maxBreadcrumbs ?? 20);
314
+ const hasKey = !!(config.secretKey || config.publicKey);
315
+ const hasEndpoint = !!config.endpoint;
316
+ if (!hasKey && !hasEndpoint) {
317
+ _originalConsole.warn(
318
+ "[@deeptracer/core] No API key or endpoint configured. Running in local-only mode (logging methods work, but events are not sent). Set DEEPTRACER_SECRET_KEY and DEEPTRACER_ENDPOINT to enable."
319
+ );
320
+ } else if (!hasKey) {
321
+ _originalConsole.warn(
322
+ "[@deeptracer/core] No `secretKey` or `publicKey` provided. Events will not be sent."
323
+ );
324
+ } else if (!hasEndpoint) {
325
+ _originalConsole.warn("[@deeptracer/core] No `endpoint` provided. Events will not be sent.");
326
+ }
327
+ this.effectiveLevel = LOG_LEVEL_VALUES[config.level ?? (config.environment === "production" ? "info" : "debug")];
241
328
  this.transport = new Transport(config);
242
329
  this.batcher = new Batcher(
243
330
  { batchSize: config.batchSize, flushIntervalMs: config.flushIntervalMs },
@@ -251,7 +338,8 @@ var Logger = class _Logger {
251
338
  // ---------------------------------------------------------------------------
252
339
  /**
253
340
  * Set the current user context. Attached to all subsequent logs, errors, spans, and LLM reports.
254
- * Shared across all child loggers (withContext, forRequest).
341
+ * Only affects this logger instance — child loggers created via `withContext()` or `forRequest()`
342
+ * have their own independent state.
255
343
  *
256
344
  * @example
257
345
  * ```ts
@@ -373,26 +461,13 @@ var Logger = class _Logger {
373
461
  };
374
462
  }
375
463
  metadata = this.mergeStateMetadata(metadata);
376
- const entry = {
377
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
378
- level,
379
- message,
380
- metadata,
381
- context: this.contextName,
382
- trace_id: this.requestMeta?.trace_id,
383
- span_id: this.requestMeta?.span_id,
384
- request_id: this.requestMeta?.request_id,
385
- vercel_id: this.requestMeta?.vercel_id
386
- };
387
- const hookResult = this.applyBeforeSend({ type: "log", data: entry });
388
- if (hookResult === null) return;
389
- const finalEntry = hookResult.data;
464
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
390
465
  if (this.config.debug) {
391
466
  const prefix = this.contextName ? `[${this.contextName}]` : "";
392
467
  const lvl = level.toUpperCase().padEnd(5);
393
468
  const consoleFn = level === "error" ? _originalConsole.error : level === "warn" ? _originalConsole.warn : level === "debug" ? _originalConsole.debug : _originalConsole.log;
394
- if (finalEntry.metadata) {
395
- consoleFn(`${lvl} ${prefix} ${message}`, finalEntry.metadata);
469
+ if (metadata) {
470
+ consoleFn(`${lvl} ${prefix} ${message}`, metadata);
396
471
  } else {
397
472
  consoleFn(`${lvl} ${prefix} ${message}`);
398
473
  }
@@ -400,9 +475,23 @@ var Logger = class _Logger {
400
475
  addBreadcrumb(this.state, {
401
476
  type: "log",
402
477
  message: `[${level}] ${message}`,
403
- timestamp: entry.timestamp
478
+ timestamp
404
479
  });
405
- this.batcher.add(finalEntry);
480
+ if (LOG_LEVEL_VALUES[level] < this.effectiveLevel) return;
481
+ const entry = {
482
+ timestamp,
483
+ level,
484
+ message,
485
+ metadata,
486
+ context: this.contextName,
487
+ trace_id: this.requestMeta?.trace_id,
488
+ span_id: this.requestMeta?.span_id,
489
+ request_id: this.requestMeta?.request_id,
490
+ vercel_id: this.requestMeta?.vercel_id
491
+ };
492
+ const hookResult = this.applyBeforeSend({ type: "log", data: entry });
493
+ if (hookResult === null) return;
494
+ this.batcher.add(hookResult.data);
406
495
  }
407
496
  /** Log a debug message. */
408
497
  debug(message, dataOrError, error) {
@@ -423,22 +512,37 @@ var Logger = class _Logger {
423
512
  // ---------------------------------------------------------------------------
424
513
  // Child loggers
425
514
  // ---------------------------------------------------------------------------
426
- /** Create a context-scoped logger. All logs include the context name. Shares state with parent. */
515
+ /** Create a context-scoped logger. All logs include the context name. Gets an independent copy of state. */
427
516
  withContext(name) {
428
- return new _Logger(this.config, name, this.requestMeta, this.state);
517
+ return new _Logger(this.config, name, this.requestMeta, cloneState(this.state));
429
518
  }
430
- /** Create a request-scoped logger that extracts trace context from headers. Shares state with parent. */
519
+ /** Create a request-scoped logger that extracts trace context from headers. Gets an independent copy of state. */
431
520
  forRequest(request) {
432
- const vercelId = request.headers.get("x-vercel-id") || void 0;
521
+ let traceId;
522
+ let spanId;
523
+ const traceparent = request.headers.get("traceparent");
524
+ if (traceparent) {
525
+ const parsed = parseTraceparent(traceparent);
526
+ if (parsed) {
527
+ traceId = parsed.traceId;
528
+ spanId = parsed.parentId;
529
+ }
530
+ }
531
+ traceId = traceId || request.headers.get("x-trace-id") || void 0;
532
+ spanId = spanId || request.headers.get("x-span-id") || void 0;
433
533
  const requestId = request.headers.get("x-request-id") || void 0;
434
- const traceId = request.headers.get("x-trace-id") || void 0;
435
- const spanId = request.headers.get("x-span-id") || void 0;
436
- return new _Logger(this.config, this.contextName, {
437
- trace_id: traceId,
438
- span_id: spanId,
439
- request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
440
- vercel_id: vercelId
441
- }, this.state);
534
+ const vercelId = request.headers.get("x-vercel-id") || void 0;
535
+ return new _Logger(
536
+ this.config,
537
+ this.contextName,
538
+ {
539
+ trace_id: traceId,
540
+ span_id: spanId,
541
+ request_id: requestId || (vercelId ? vercelId.split("::").pop() : void 0),
542
+ vercel_id: vercelId
543
+ },
544
+ cloneState(this.state)
545
+ );
442
546
  }
443
547
  // ---------------------------------------------------------------------------
444
548
  // Error capture
@@ -457,7 +561,8 @@ var Logger = class _Logger {
457
561
  const enrichedContext = { ...context?.context };
458
562
  if (this.state.user) enrichedContext.user = this.state.user;
459
563
  if (Object.keys(this.state.tags).length > 0) enrichedContext._tags = { ...this.state.tags };
460
- if (Object.keys(this.state.contexts).length > 0) enrichedContext._contexts = { ...this.state.contexts };
564
+ if (Object.keys(this.state.contexts).length > 0)
565
+ enrichedContext._contexts = { ...this.state.contexts };
461
566
  const report = {
462
567
  error_message: err.message,
463
568
  stack_trace: err.stack || "",
@@ -538,7 +643,7 @@ var Logger = class _Logger {
538
643
  }
539
644
  /** Start a span with manual lifecycle. You must call span.end(). */
540
645
  startInactiveSpan(operation) {
541
- const traceId = this.requestMeta?.trace_id || generateId();
646
+ const traceId = this.requestMeta?.trace_id || generateTraceId();
542
647
  const parentSpanId = this.requestMeta?.span_id || "";
543
648
  const spanId = generateId();
544
649
  const startTime = (/* @__PURE__ */ new Date()).toISOString();
@@ -578,10 +683,16 @@ var Logger = class _Logger {
578
683
  const childLogger = new _Logger(this.config, this.contextName, childMeta, this.state);
579
684
  return childLogger.startInactiveSpan(childOp);
580
685
  },
581
- getHeaders: () => ({
582
- "x-trace-id": traceId,
583
- "x-span-id": spanId
584
- })
686
+ getHeaders: () => {
687
+ const headers = {
688
+ "x-trace-id": traceId,
689
+ "x-span-id": spanId
690
+ };
691
+ if (/^[0-9a-f]{32}$/.test(traceId)) {
692
+ headers.traceparent = `00-${traceId}-${spanId}-01`;
693
+ }
694
+ return headers;
695
+ }
585
696
  };
586
697
  return span;
587
698
  }
@@ -615,8 +726,71 @@ var Logger = class _Logger {
615
726
  await this.transport.drain(timeoutMs);
616
727
  }
617
728
  };
729
+
730
+ // src/internal.ts
731
+ function safeStringify(value) {
732
+ const seen = /* @__PURE__ */ new WeakSet();
733
+ return JSON.stringify(value, (_key, val) => {
734
+ if (val instanceof Error) {
735
+ return { name: val.name, message: val.message, stack: val.stack };
736
+ }
737
+ if (typeof val === "bigint") return val.toString();
738
+ if (typeof val === "symbol") return val.toString();
739
+ if (typeof val === "function") return `[Function: ${val.name || "anonymous"}]`;
740
+ if (val !== null && typeof val === "object") {
741
+ if (seen.has(val)) return "[Circular]";
742
+ seen.add(val);
743
+ }
744
+ return val;
745
+ });
746
+ }
747
+ function parseConsoleArgs(args) {
748
+ if (args.length === 0) return { message: "" };
749
+ const first = args[0];
750
+ if (typeof first === "string" && /%[sdifoc%]/.test(first)) {
751
+ return { message: args.map(String).join(" ") };
752
+ }
753
+ if (typeof first === "string") {
754
+ const messageParts = [first];
755
+ const metadata = {};
756
+ let metadataCount = 0;
757
+ for (let i = 1; i < args.length; i++) {
758
+ const arg = args[i];
759
+ if (arg instanceof Error) {
760
+ metadata[`error${metadataCount > 0 ? `_${metadataCount}` : ""}`] = {
761
+ name: arg.name,
762
+ message: arg.message,
763
+ stack: arg.stack
764
+ };
765
+ metadataCount++;
766
+ } else if (arg !== null && typeof arg === "object") {
767
+ Object.assign(metadata, arg);
768
+ metadataCount++;
769
+ } else if (arg !== void 0) {
770
+ messageParts.push(String(arg));
771
+ }
772
+ }
773
+ return {
774
+ message: messageParts.join(" "),
775
+ metadata: metadataCount > 0 ? metadata : void 0
776
+ };
777
+ }
778
+ if (first instanceof Error) {
779
+ return {
780
+ message: first.message,
781
+ metadata: { error: { name: first.name, message: first.message, stack: first.stack } }
782
+ };
783
+ }
784
+ if (first !== null && typeof first === "object") {
785
+ return { message: safeStringify(first) };
786
+ }
787
+ return { message: String(first) };
788
+ }
618
789
  // Annotate the CommonJS export names for ESM import in node:
619
790
  0 && (module.exports = {
620
791
  Logger,
621
- _originalConsole
792
+ Transport,
793
+ _originalConsole,
794
+ parseConsoleArgs,
795
+ parseTraceparent
622
796
  });
@@ -1 +1,86 @@
1
- export { d as Logger, e as LoggerConfig, h as LoggerState, M as MiddlewareOptions, _ as _originalConsole } from './internal-DdKQRgCs.cjs';
1
+ import { e as LoggerConfig, b as LogEntry, E as ErrorReport, f as SpanData } from './logger-BDTEt7Gi.cjs';
2
+ export { d as Logger, h as LoggerState, M as MiddlewareOptions, _ as _originalConsole, p as parseTraceparent } from './logger-BDTEt7Gi.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" | "secretKey" | "publicKey" | "service" | "environment">);
34
+ /** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
35
+ private get authKey();
36
+ /**
37
+ * Send a request with automatic retry and exponential backoff.
38
+ * Retries up to `maxRetries` times on network errors and 5xx responses.
39
+ * Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
40
+ *
41
+ * After the first total failure for a given label, subsequent failures
42
+ * are silently dropped (no more console warnings).
43
+ */
44
+ private sendWithRetry;
45
+ /** Add +/- 20% jitter to a delay to prevent thundering herd. */
46
+ private jitter;
47
+ private sleep;
48
+ /** Track an in-flight request and remove it when done. */
49
+ private track;
50
+ sendLogs(logs: LogEntry[]): Promise<void>;
51
+ sendError(error: ErrorReport): Promise<void>;
52
+ sendTrace(span: SpanData): Promise<void>;
53
+ sendLLMUsage(report: {
54
+ model: string;
55
+ provider: string;
56
+ operation: string;
57
+ input_tokens: number;
58
+ output_tokens: number;
59
+ cost_usd: number;
60
+ latency_ms: number;
61
+ metadata?: Record<string, unknown>;
62
+ }): Promise<void>;
63
+ /**
64
+ * Wait for all in-flight requests to complete, with a timeout.
65
+ * Used by `logger.destroy()` to ensure data is sent before process exit.
66
+ *
67
+ * @param timeoutMs - Maximum time to wait (default: 2000ms)
68
+ */
69
+ drain(timeoutMs?: number): Promise<void>;
70
+ }
71
+
72
+ /**
73
+ * Parse console.log/info/warn/error arguments into a structured `{ message, metadata }` pair.
74
+ *
75
+ * - First string arg → message; remaining objects → merged into metadata
76
+ * - If first string has printf patterns (`%s`, `%d`, `%o`, etc.) → join all as string, no metadata
77
+ * - First non-string arg → `safeStringify` it for message
78
+ * - Error objects → serialize `{ name, message, stack }` into metadata
79
+ * - Remaining primitives → append to message string
80
+ */
81
+ declare function parseConsoleArgs(args: unknown[]): {
82
+ message: string;
83
+ metadata?: Record<string, unknown>;
84
+ };
85
+
86
+ export { LoggerConfig, Transport, parseConsoleArgs };
@@ -1 +1,86 @@
1
- export { d as Logger, e as LoggerConfig, h as LoggerState, M as MiddlewareOptions, _ as _originalConsole } from './internal-DdKQRgCs.js';
1
+ import { e as LoggerConfig, b as LogEntry, E as ErrorReport, f as SpanData } from './logger-BDTEt7Gi.js';
2
+ export { d as Logger, h as LoggerState, M as MiddlewareOptions, _ as _originalConsole, p as parseTraceparent } from './logger-BDTEt7Gi.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" | "secretKey" | "publicKey" | "service" | "environment">);
34
+ /** Resolve the auth key: prefer secretKey (server), fall back to publicKey (client). */
35
+ private get authKey();
36
+ /**
37
+ * Send a request with automatic retry and exponential backoff.
38
+ * Retries up to `maxRetries` times on network errors and 5xx responses.
39
+ * Does NOT retry on 4xx (client errors — bad payload, auth failure, etc.).
40
+ *
41
+ * After the first total failure for a given label, subsequent failures
42
+ * are silently dropped (no more console warnings).
43
+ */
44
+ private sendWithRetry;
45
+ /** Add +/- 20% jitter to a delay to prevent thundering herd. */
46
+ private jitter;
47
+ private sleep;
48
+ /** Track an in-flight request and remove it when done. */
49
+ private track;
50
+ sendLogs(logs: LogEntry[]): Promise<void>;
51
+ sendError(error: ErrorReport): Promise<void>;
52
+ sendTrace(span: SpanData): Promise<void>;
53
+ sendLLMUsage(report: {
54
+ model: string;
55
+ provider: string;
56
+ operation: string;
57
+ input_tokens: number;
58
+ output_tokens: number;
59
+ cost_usd: number;
60
+ latency_ms: number;
61
+ metadata?: Record<string, unknown>;
62
+ }): Promise<void>;
63
+ /**
64
+ * Wait for all in-flight requests to complete, with a timeout.
65
+ * Used by `logger.destroy()` to ensure data is sent before process exit.
66
+ *
67
+ * @param timeoutMs - Maximum time to wait (default: 2000ms)
68
+ */
69
+ drain(timeoutMs?: number): Promise<void>;
70
+ }
71
+
72
+ /**
73
+ * Parse console.log/info/warn/error arguments into a structured `{ message, metadata }` pair.
74
+ *
75
+ * - First string arg → message; remaining objects → merged into metadata
76
+ * - If first string has printf patterns (`%s`, `%d`, `%o`, etc.) → join all as string, no metadata
77
+ * - First non-string arg → `safeStringify` it for message
78
+ * - Error objects → serialize `{ name, message, stack }` into metadata
79
+ * - Remaining primitives → append to message string
80
+ */
81
+ declare function parseConsoleArgs(args: unknown[]): {
82
+ message: string;
83
+ metadata?: Record<string, unknown>;
84
+ };
85
+
86
+ export { LoggerConfig, Transport, parseConsoleArgs };