bitfab 0.27.2 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -30,6 +30,91 @@ type AllowedEnvVars = {
30
30
  OPENAI_API_KEY?: string;
31
31
  };
32
32
 
33
+ /**
34
+ * Per-trace database snapshot ref capture.
35
+ *
36
+ * Every root span carries a `DbSnapshotRef` that pins the DB state at trace
37
+ * open by wall-clock timestamp. Capturing the timestamp is free (no IO) and
38
+ * harmless, so it happens on every trace regardless of configuration: that
39
+ * lets any trace be replayed against a historical branch later. A `provider`
40
+ * is attached only when the customer configured `dbSnapshot`; when absent it
41
+ * is resolved at replay time. The Bitfab service uses the timestamp to
42
+ * materialize an ephemeral branch from `customer-main`.
43
+ */
44
+ declare const SUPPORTED_PROVIDERS: readonly ["neon"];
45
+ type DbSnapshotProvider = (typeof SUPPORTED_PROVIDERS)[number];
46
+ interface DbSnapshotConfig {
47
+ /** Discriminator for the server-side resolver. */
48
+ provider: DbSnapshotProvider;
49
+ }
50
+ interface DbSnapshotRef {
51
+ /**
52
+ * The wall-clock ISO timestamp the SDK observed immediately before
53
+ * invoking the wrapped function. The name encodes its provenance:
54
+ * SDK-observed, wall clock (not monotonic), captured before user code
55
+ * began executing. Always present.
56
+ */
57
+ sdkWallClockBeforeFn: string;
58
+ /**
59
+ * The configured provider for server-side branch resolution. Only set when
60
+ * the customer configured `dbSnapshot`; otherwise the provider is resolved
61
+ * at replay time.
62
+ */
63
+ provider?: DbSnapshotProvider;
64
+ }
65
+
66
+ /**
67
+ * Shared error type for Bitfab SDK runtime errors. Lives in its own
68
+ * module to avoid import cycles between `http.ts` and modules that need
69
+ * to throw structured errors (e.g. `dbSnapshot.ts` validation).
70
+ */
71
+ declare class BitfabError extends Error {
72
+ readonly url?: string | undefined;
73
+ constructor(message: string, url?: string | undefined);
74
+ }
75
+
76
+ /**
77
+ * HTTP client utilities for Bitfab API requests.
78
+ *
79
+ * This module provides:
80
+ * - HttpClient class for making API requests
81
+ * - awaitOnExit helper for fire-and-forget operations that must complete before process exit
82
+ */
83
+
84
+ /**
85
+ * Wait for all pending fire-and-forget operations (spans, traces) to complete.
86
+ * Useful in tests and scripts to ensure all data has been sent before asserting or exiting.
87
+ *
88
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 5000)
89
+ */
90
+ declare function flushTraces(timeoutMs?: number): Promise<void>;
91
+ /**
92
+ * How the API key is supplied internally: either a literal string or a
93
+ * function resolved each time the key is needed (at request/send time). The
94
+ * function form is what defers key resolution past module-load construction
95
+ * so an env var loaded after the client is built (the ESM dotenv-hoisting
96
+ * case) is still picked up.
97
+ */
98
+ type ApiKeyInput = string | (() => string | undefined);
99
+ interface TokenUsage {
100
+ input: number | null;
101
+ output: number | null;
102
+ cached: number | null;
103
+ total: number | null;
104
+ }
105
+ /**
106
+ * Describes a single file edited as part of a code change.
107
+ *
108
+ * - `path`: file path (relative to the repo root, or any consistent root)
109
+ * - `before`: file contents before the change ("" for newly created files)
110
+ * - `after`: file contents after the change ("" for deleted files)
111
+ */
112
+ interface CodeChangeFile {
113
+ path: string;
114
+ before: string;
115
+ after: string;
116
+ }
117
+
33
118
  /**
34
119
  * Claude Agent SDK handler for Bitfab tracing.
35
120
  *
@@ -40,6 +125,7 @@ type AllowedEnvVars = {
40
125
  * 1. SDK hooks (PreToolUse, PostToolUse, etc.) for tool/subagent lifecycle
41
126
  * 2. Stream wrapping for LLM turn capture from the message stream
42
127
  */
128
+
43
129
  interface ActiveSpanContext$2 {
44
130
  traceId: string;
45
131
  spanId: string;
@@ -96,7 +182,7 @@ declare class BitfabClaudeAgentHandler {
96
182
  private rootInput;
97
183
  private rootOutput;
98
184
  constructor(config: {
99
- apiKey?: string;
185
+ apiKey?: ApiKeyInput;
100
186
  traceFunctionKey: string;
101
187
  serviceUrl?: string;
102
188
  timeout?: number;
@@ -285,83 +371,6 @@ declare class BitfabVercelAiHandler {
285
371
  get middleware(): BitfabLanguageModelMiddleware;
286
372
  }
287
373
 
288
- /**
289
- * Per-trace database snapshot ref capture.
290
- *
291
- * Every root span carries a `DbSnapshotRef` that pins the DB state at trace
292
- * open by wall-clock timestamp. Capturing the timestamp is free (no IO) and
293
- * harmless, so it happens on every trace regardless of configuration: that
294
- * lets any trace be replayed against a historical branch later. A `provider`
295
- * is attached only when the customer configured `dbSnapshot`; when absent it
296
- * is resolved at replay time. The Bitfab service uses the timestamp to
297
- * materialize an ephemeral branch from `customer-main`.
298
- */
299
- declare const SUPPORTED_PROVIDERS: readonly ["neon"];
300
- type DbSnapshotProvider = (typeof SUPPORTED_PROVIDERS)[number];
301
- interface DbSnapshotConfig {
302
- /** Discriminator for the server-side resolver. */
303
- provider: DbSnapshotProvider;
304
- }
305
- interface DbSnapshotRef {
306
- /**
307
- * The wall-clock ISO timestamp the SDK observed immediately before
308
- * invoking the wrapped function. The name encodes its provenance:
309
- * SDK-observed, wall clock (not monotonic), captured before user code
310
- * began executing. Always present.
311
- */
312
- sdkWallClockBeforeFn: string;
313
- /**
314
- * The configured provider for server-side branch resolution. Only set when
315
- * the customer configured `dbSnapshot`; otherwise the provider is resolved
316
- * at replay time.
317
- */
318
- provider?: DbSnapshotProvider;
319
- }
320
-
321
- /**
322
- * Shared error type for Bitfab SDK runtime errors. Lives in its own
323
- * module to avoid import cycles between `http.ts` and modules that need
324
- * to throw structured errors (e.g. `dbSnapshot.ts` validation).
325
- */
326
- declare class BitfabError extends Error {
327
- readonly url?: string | undefined;
328
- constructor(message: string, url?: string | undefined);
329
- }
330
-
331
- /**
332
- * HTTP client utilities for Bitfab API requests.
333
- *
334
- * This module provides:
335
- * - HttpClient class for making API requests
336
- * - awaitOnExit helper for fire-and-forget operations that must complete before process exit
337
- */
338
-
339
- /**
340
- * Wait for all pending fire-and-forget operations (spans, traces) to complete.
341
- * Useful in tests and scripts to ensure all data has been sent before asserting or exiting.
342
- *
343
- * @param timeoutMs - Maximum time to wait in milliseconds (default: 5000)
344
- */
345
- declare function flushTraces(timeoutMs?: number): Promise<void>;
346
- interface TokenUsage {
347
- input: number | null;
348
- output: number | null;
349
- cached: number | null;
350
- total: number | null;
351
- }
352
- /**
353
- * Describes a single file edited as part of a code change.
354
- *
355
- * - `path`: file path (relative to the repo root, or any consistent root)
356
- * - `before`: file contents before the change ("" for newly created files)
357
- * - `after`: file contents after the change ("" for deleted files)
358
- */
359
- interface CodeChangeFile {
360
- path: string;
361
- before: string;
362
- after: string;
363
- }
364
-
365
374
  /**
366
375
  * LangGraph/LangChain callback handler for Bitfab tracing.
367
376
  *
@@ -372,6 +381,7 @@ interface CodeChangeFile {
372
381
  * Duck-typed to match LangChain.js's BaseCallbackHandler interface.
373
382
  * No @langchain/core dependency required.
374
383
  */
384
+
375
385
  interface ActiveSpanContext$1 {
376
386
  traceId: string;
377
387
  spanId: string;
@@ -401,7 +411,7 @@ declare class BitfabLangGraphCallbackHandler {
401
411
  private runToSpan;
402
412
  private invocations;
403
413
  constructor(config: {
404
- apiKey?: string;
414
+ apiKey?: ApiKeyInput;
405
415
  traceFunctionKey: string;
406
416
  serviceUrl?: string;
407
417
  timeout?: number;
@@ -782,6 +792,7 @@ interface ReplayResult<T> {
782
792
  * This module provides utilities for sending external traces (e.g., from OpenAI API calls)
783
793
  * to Bitfab for monitoring and analysis.
784
794
  */
795
+
785
796
  interface Trace {
786
797
  traceId: string;
787
798
  toJSON(): unknown;
@@ -842,7 +853,7 @@ declare class BitfabOpenAITracingProcessor implements TracingProcessor {
842
853
  * @param config - Configuration options
843
854
  */
844
855
  constructor(config: {
845
- apiKey?: string;
856
+ apiKey?: ApiKeyInput;
846
857
  serviceUrl?: string;
847
858
  timeout?: number;
848
859
  getActiveSpanContext?: () => ActiveSpanContext | null;
@@ -1009,8 +1020,19 @@ declare function getCurrentSpan(): CurrentSpan;
1009
1020
  */
1010
1021
  declare function getCurrentTrace(): CurrentTrace;
1011
1022
  interface BitfabConfig {
1012
- /** The API key for Bitfab API authentication. When undefined or empty, tracing is disabled. */
1013
- apiKey?: string;
1023
+ /**
1024
+ * The API key for Bitfab API authentication. Resolved lazily, the first
1025
+ * time a span actually needs it, not at construction. When it resolves
1026
+ * empty, tracing is disabled (a no-op, unless `strict` is set).
1027
+ *
1028
+ * Accepts either a string or a function returning the key. The function
1029
+ * form is resolved at first use, so it survives the ESM trap where a shim
1030
+ * built at module load runs before the script body's `dotenv.config()`:
1031
+ * `apiKey: () => process.env.BITFAB_API_KEY`. When omitted (or it resolves
1032
+ * empty), the SDK also falls back to reading `BITFAB_API_KEY` from the
1033
+ * environment itself, again at first use.
1034
+ */
1035
+ apiKey?: string | (() => string | null | undefined);
1014
1036
  /** The base URL for the Bitfab API (default: https://bitfab.ai) */
1015
1037
  serviceUrl?: string;
1016
1038
  /** Request timeout in milliseconds (default: 120000) */
@@ -1019,6 +1041,14 @@ interface BitfabConfig {
1019
1041
  envVars?: AllowedEnvVars;
1020
1042
  /** Whether the client is enabled. Defaults to true. When false, withSpan returns the original function unwrapped. */
1021
1043
  enabled?: boolean;
1044
+ /**
1045
+ * Fail loud instead of degrading quietly. When true, the first traced call
1046
+ * with no resolvable API key throws a `BitfabError` rather than silently
1047
+ * disabling tracing. Off by default so a missing telemetry key never takes
1048
+ * down the host app; turn it on in standalone scripts where a run that
1049
+ * emits no traces is a failure you want surfaced immediately.
1050
+ */
1051
+ strict?: boolean;
1022
1052
  /** The generated BAML client instance (e.g., `b` from your baml_client). Used by wrapBAML() when no explicit client is passed. */
1023
1053
  bamlClient?: unknown;
1024
1054
  /**
@@ -1093,11 +1123,17 @@ declare class Bitfab {
1093
1123
  * function to pick up the per-trace branch URL.
1094
1124
  */
1095
1125
  static readonly ReplayEnvironment: typeof ReplayEnvironment;
1096
- private readonly apiKey;
1126
+ private readonly apiKeyConfig;
1127
+ /** Cached only once a non-empty key is found, so an early resolve (before env loaded) can't poison a later one. */
1128
+ private resolvedApiKey;
1129
+ /** Gate the empty-key warning to fire at most once. */
1130
+ private apiKeyWarned;
1097
1131
  private readonly serviceUrl;
1098
1132
  private readonly timeout;
1099
1133
  private readonly envVars;
1100
- private readonly enabled;
1134
+ /** The user's on/off intent. The effective enabled state ANDs this with "a key resolved" (see isTracingEnabled). */
1135
+ private readonly explicitlyEnabled;
1136
+ private readonly strict;
1101
1137
  private readonly httpClient;
1102
1138
  private readonly bamlClient;
1103
1139
  private readonly dbSnapshot;
@@ -1107,6 +1143,28 @@ declare class Bitfab {
1107
1143
  * @param config - Configuration options for the client
1108
1144
  */
1109
1145
  constructor(config: BitfabConfig);
1146
+ /**
1147
+ * Resolve the API key lazily, the first time a span actually needs it.
1148
+ *
1149
+ * The key is intentionally NOT read at construction. In ESM, a shim that
1150
+ * does `new Bitfab({ apiKey: process.env.BITFAB_API_KEY })` is hoisted and
1151
+ * evaluated before the importing script's body runs `dotenv.config()`, so
1152
+ * the key would be empty at construction even though it is set moments
1153
+ * later. Resolving here (at first `withSpan` call / first request) reads
1154
+ * the key after env loading has run.
1155
+ *
1156
+ * Resolution order: the configured value (string, or function called each
1157
+ * time it is still unresolved), then a fallback read of `BITFAB_API_KEY`
1158
+ * from the environment. Once a non-empty key is found it is cached, so an
1159
+ * early resolve that found nothing never poisons a later one.
1160
+ */
1161
+ private resolveApiKey;
1162
+ /**
1163
+ * Whether tracing should run, decided lazily at call time (not frozen at
1164
+ * construction). An explicit `enabled: false` short-circuits without ever
1165
+ * touching the key.
1166
+ */
1167
+ private isTracingEnabled;
1110
1168
  /**
1111
1169
  * Fetch the function with its current version and BAML prompt from the server.
1112
1170
  *
@@ -1531,7 +1589,7 @@ declare class BitfabFunction {
1531
1589
  /**
1532
1590
  * SDK version from package.json (injected at build time)
1533
1591
  */
1534
- declare const __version__ = "0.27.2";
1592
+ declare const __version__ = "0.28.0";
1535
1593
 
1536
1594
  /**
1537
1595
  * Constants for the Bitfab SDK.
package/dist/index.d.ts CHANGED
@@ -30,6 +30,91 @@ type AllowedEnvVars = {
30
30
  OPENAI_API_KEY?: string;
31
31
  };
32
32
 
33
+ /**
34
+ * Per-trace database snapshot ref capture.
35
+ *
36
+ * Every root span carries a `DbSnapshotRef` that pins the DB state at trace
37
+ * open by wall-clock timestamp. Capturing the timestamp is free (no IO) and
38
+ * harmless, so it happens on every trace regardless of configuration: that
39
+ * lets any trace be replayed against a historical branch later. A `provider`
40
+ * is attached only when the customer configured `dbSnapshot`; when absent it
41
+ * is resolved at replay time. The Bitfab service uses the timestamp to
42
+ * materialize an ephemeral branch from `customer-main`.
43
+ */
44
+ declare const SUPPORTED_PROVIDERS: readonly ["neon"];
45
+ type DbSnapshotProvider = (typeof SUPPORTED_PROVIDERS)[number];
46
+ interface DbSnapshotConfig {
47
+ /** Discriminator for the server-side resolver. */
48
+ provider: DbSnapshotProvider;
49
+ }
50
+ interface DbSnapshotRef {
51
+ /**
52
+ * The wall-clock ISO timestamp the SDK observed immediately before
53
+ * invoking the wrapped function. The name encodes its provenance:
54
+ * SDK-observed, wall clock (not monotonic), captured before user code
55
+ * began executing. Always present.
56
+ */
57
+ sdkWallClockBeforeFn: string;
58
+ /**
59
+ * The configured provider for server-side branch resolution. Only set when
60
+ * the customer configured `dbSnapshot`; otherwise the provider is resolved
61
+ * at replay time.
62
+ */
63
+ provider?: DbSnapshotProvider;
64
+ }
65
+
66
+ /**
67
+ * Shared error type for Bitfab SDK runtime errors. Lives in its own
68
+ * module to avoid import cycles between `http.ts` and modules that need
69
+ * to throw structured errors (e.g. `dbSnapshot.ts` validation).
70
+ */
71
+ declare class BitfabError extends Error {
72
+ readonly url?: string | undefined;
73
+ constructor(message: string, url?: string | undefined);
74
+ }
75
+
76
+ /**
77
+ * HTTP client utilities for Bitfab API requests.
78
+ *
79
+ * This module provides:
80
+ * - HttpClient class for making API requests
81
+ * - awaitOnExit helper for fire-and-forget operations that must complete before process exit
82
+ */
83
+
84
+ /**
85
+ * Wait for all pending fire-and-forget operations (spans, traces) to complete.
86
+ * Useful in tests and scripts to ensure all data has been sent before asserting or exiting.
87
+ *
88
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 5000)
89
+ */
90
+ declare function flushTraces(timeoutMs?: number): Promise<void>;
91
+ /**
92
+ * How the API key is supplied internally: either a literal string or a
93
+ * function resolved each time the key is needed (at request/send time). The
94
+ * function form is what defers key resolution past module-load construction
95
+ * so an env var loaded after the client is built (the ESM dotenv-hoisting
96
+ * case) is still picked up.
97
+ */
98
+ type ApiKeyInput = string | (() => string | undefined);
99
+ interface TokenUsage {
100
+ input: number | null;
101
+ output: number | null;
102
+ cached: number | null;
103
+ total: number | null;
104
+ }
105
+ /**
106
+ * Describes a single file edited as part of a code change.
107
+ *
108
+ * - `path`: file path (relative to the repo root, or any consistent root)
109
+ * - `before`: file contents before the change ("" for newly created files)
110
+ * - `after`: file contents after the change ("" for deleted files)
111
+ */
112
+ interface CodeChangeFile {
113
+ path: string;
114
+ before: string;
115
+ after: string;
116
+ }
117
+
33
118
  /**
34
119
  * Claude Agent SDK handler for Bitfab tracing.
35
120
  *
@@ -40,6 +125,7 @@ type AllowedEnvVars = {
40
125
  * 1. SDK hooks (PreToolUse, PostToolUse, etc.) for tool/subagent lifecycle
41
126
  * 2. Stream wrapping for LLM turn capture from the message stream
42
127
  */
128
+
43
129
  interface ActiveSpanContext$2 {
44
130
  traceId: string;
45
131
  spanId: string;
@@ -96,7 +182,7 @@ declare class BitfabClaudeAgentHandler {
96
182
  private rootInput;
97
183
  private rootOutput;
98
184
  constructor(config: {
99
- apiKey?: string;
185
+ apiKey?: ApiKeyInput;
100
186
  traceFunctionKey: string;
101
187
  serviceUrl?: string;
102
188
  timeout?: number;
@@ -285,83 +371,6 @@ declare class BitfabVercelAiHandler {
285
371
  get middleware(): BitfabLanguageModelMiddleware;
286
372
  }
287
373
 
288
- /**
289
- * Per-trace database snapshot ref capture.
290
- *
291
- * Every root span carries a `DbSnapshotRef` that pins the DB state at trace
292
- * open by wall-clock timestamp. Capturing the timestamp is free (no IO) and
293
- * harmless, so it happens on every trace regardless of configuration: that
294
- * lets any trace be replayed against a historical branch later. A `provider`
295
- * is attached only when the customer configured `dbSnapshot`; when absent it
296
- * is resolved at replay time. The Bitfab service uses the timestamp to
297
- * materialize an ephemeral branch from `customer-main`.
298
- */
299
- declare const SUPPORTED_PROVIDERS: readonly ["neon"];
300
- type DbSnapshotProvider = (typeof SUPPORTED_PROVIDERS)[number];
301
- interface DbSnapshotConfig {
302
- /** Discriminator for the server-side resolver. */
303
- provider: DbSnapshotProvider;
304
- }
305
- interface DbSnapshotRef {
306
- /**
307
- * The wall-clock ISO timestamp the SDK observed immediately before
308
- * invoking the wrapped function. The name encodes its provenance:
309
- * SDK-observed, wall clock (not monotonic), captured before user code
310
- * began executing. Always present.
311
- */
312
- sdkWallClockBeforeFn: string;
313
- /**
314
- * The configured provider for server-side branch resolution. Only set when
315
- * the customer configured `dbSnapshot`; otherwise the provider is resolved
316
- * at replay time.
317
- */
318
- provider?: DbSnapshotProvider;
319
- }
320
-
321
- /**
322
- * Shared error type for Bitfab SDK runtime errors. Lives in its own
323
- * module to avoid import cycles between `http.ts` and modules that need
324
- * to throw structured errors (e.g. `dbSnapshot.ts` validation).
325
- */
326
- declare class BitfabError extends Error {
327
- readonly url?: string | undefined;
328
- constructor(message: string, url?: string | undefined);
329
- }
330
-
331
- /**
332
- * HTTP client utilities for Bitfab API requests.
333
- *
334
- * This module provides:
335
- * - HttpClient class for making API requests
336
- * - awaitOnExit helper for fire-and-forget operations that must complete before process exit
337
- */
338
-
339
- /**
340
- * Wait for all pending fire-and-forget operations (spans, traces) to complete.
341
- * Useful in tests and scripts to ensure all data has been sent before asserting or exiting.
342
- *
343
- * @param timeoutMs - Maximum time to wait in milliseconds (default: 5000)
344
- */
345
- declare function flushTraces(timeoutMs?: number): Promise<void>;
346
- interface TokenUsage {
347
- input: number | null;
348
- output: number | null;
349
- cached: number | null;
350
- total: number | null;
351
- }
352
- /**
353
- * Describes a single file edited as part of a code change.
354
- *
355
- * - `path`: file path (relative to the repo root, or any consistent root)
356
- * - `before`: file contents before the change ("" for newly created files)
357
- * - `after`: file contents after the change ("" for deleted files)
358
- */
359
- interface CodeChangeFile {
360
- path: string;
361
- before: string;
362
- after: string;
363
- }
364
-
365
374
  /**
366
375
  * LangGraph/LangChain callback handler for Bitfab tracing.
367
376
  *
@@ -372,6 +381,7 @@ interface CodeChangeFile {
372
381
  * Duck-typed to match LangChain.js's BaseCallbackHandler interface.
373
382
  * No @langchain/core dependency required.
374
383
  */
384
+
375
385
  interface ActiveSpanContext$1 {
376
386
  traceId: string;
377
387
  spanId: string;
@@ -401,7 +411,7 @@ declare class BitfabLangGraphCallbackHandler {
401
411
  private runToSpan;
402
412
  private invocations;
403
413
  constructor(config: {
404
- apiKey?: string;
414
+ apiKey?: ApiKeyInput;
405
415
  traceFunctionKey: string;
406
416
  serviceUrl?: string;
407
417
  timeout?: number;
@@ -782,6 +792,7 @@ interface ReplayResult<T> {
782
792
  * This module provides utilities for sending external traces (e.g., from OpenAI API calls)
783
793
  * to Bitfab for monitoring and analysis.
784
794
  */
795
+
785
796
  interface Trace {
786
797
  traceId: string;
787
798
  toJSON(): unknown;
@@ -842,7 +853,7 @@ declare class BitfabOpenAITracingProcessor implements TracingProcessor {
842
853
  * @param config - Configuration options
843
854
  */
844
855
  constructor(config: {
845
- apiKey?: string;
856
+ apiKey?: ApiKeyInput;
846
857
  serviceUrl?: string;
847
858
  timeout?: number;
848
859
  getActiveSpanContext?: () => ActiveSpanContext | null;
@@ -1009,8 +1020,19 @@ declare function getCurrentSpan(): CurrentSpan;
1009
1020
  */
1010
1021
  declare function getCurrentTrace(): CurrentTrace;
1011
1022
  interface BitfabConfig {
1012
- /** The API key for Bitfab API authentication. When undefined or empty, tracing is disabled. */
1013
- apiKey?: string;
1023
+ /**
1024
+ * The API key for Bitfab API authentication. Resolved lazily, the first
1025
+ * time a span actually needs it, not at construction. When it resolves
1026
+ * empty, tracing is disabled (a no-op, unless `strict` is set).
1027
+ *
1028
+ * Accepts either a string or a function returning the key. The function
1029
+ * form is resolved at first use, so it survives the ESM trap where a shim
1030
+ * built at module load runs before the script body's `dotenv.config()`:
1031
+ * `apiKey: () => process.env.BITFAB_API_KEY`. When omitted (or it resolves
1032
+ * empty), the SDK also falls back to reading `BITFAB_API_KEY` from the
1033
+ * environment itself, again at first use.
1034
+ */
1035
+ apiKey?: string | (() => string | null | undefined);
1014
1036
  /** The base URL for the Bitfab API (default: https://bitfab.ai) */
1015
1037
  serviceUrl?: string;
1016
1038
  /** Request timeout in milliseconds (default: 120000) */
@@ -1019,6 +1041,14 @@ interface BitfabConfig {
1019
1041
  envVars?: AllowedEnvVars;
1020
1042
  /** Whether the client is enabled. Defaults to true. When false, withSpan returns the original function unwrapped. */
1021
1043
  enabled?: boolean;
1044
+ /**
1045
+ * Fail loud instead of degrading quietly. When true, the first traced call
1046
+ * with no resolvable API key throws a `BitfabError` rather than silently
1047
+ * disabling tracing. Off by default so a missing telemetry key never takes
1048
+ * down the host app; turn it on in standalone scripts where a run that
1049
+ * emits no traces is a failure you want surfaced immediately.
1050
+ */
1051
+ strict?: boolean;
1022
1052
  /** The generated BAML client instance (e.g., `b` from your baml_client). Used by wrapBAML() when no explicit client is passed. */
1023
1053
  bamlClient?: unknown;
1024
1054
  /**
@@ -1093,11 +1123,17 @@ declare class Bitfab {
1093
1123
  * function to pick up the per-trace branch URL.
1094
1124
  */
1095
1125
  static readonly ReplayEnvironment: typeof ReplayEnvironment;
1096
- private readonly apiKey;
1126
+ private readonly apiKeyConfig;
1127
+ /** Cached only once a non-empty key is found, so an early resolve (before env loaded) can't poison a later one. */
1128
+ private resolvedApiKey;
1129
+ /** Gate the empty-key warning to fire at most once. */
1130
+ private apiKeyWarned;
1097
1131
  private readonly serviceUrl;
1098
1132
  private readonly timeout;
1099
1133
  private readonly envVars;
1100
- private readonly enabled;
1134
+ /** The user's on/off intent. The effective enabled state ANDs this with "a key resolved" (see isTracingEnabled). */
1135
+ private readonly explicitlyEnabled;
1136
+ private readonly strict;
1101
1137
  private readonly httpClient;
1102
1138
  private readonly bamlClient;
1103
1139
  private readonly dbSnapshot;
@@ -1107,6 +1143,28 @@ declare class Bitfab {
1107
1143
  * @param config - Configuration options for the client
1108
1144
  */
1109
1145
  constructor(config: BitfabConfig);
1146
+ /**
1147
+ * Resolve the API key lazily, the first time a span actually needs it.
1148
+ *
1149
+ * The key is intentionally NOT read at construction. In ESM, a shim that
1150
+ * does `new Bitfab({ apiKey: process.env.BITFAB_API_KEY })` is hoisted and
1151
+ * evaluated before the importing script's body runs `dotenv.config()`, so
1152
+ * the key would be empty at construction even though it is set moments
1153
+ * later. Resolving here (at first `withSpan` call / first request) reads
1154
+ * the key after env loading has run.
1155
+ *
1156
+ * Resolution order: the configured value (string, or function called each
1157
+ * time it is still unresolved), then a fallback read of `BITFAB_API_KEY`
1158
+ * from the environment. Once a non-empty key is found it is cached, so an
1159
+ * early resolve that found nothing never poisons a later one.
1160
+ */
1161
+ private resolveApiKey;
1162
+ /**
1163
+ * Whether tracing should run, decided lazily at call time (not frozen at
1164
+ * construction). An explicit `enabled: false` short-circuits without ever
1165
+ * touching the key.
1166
+ */
1167
+ private isTracingEnabled;
1110
1168
  /**
1111
1169
  * Fetch the function with its current version and BAML prompt from the server.
1112
1170
  *
@@ -1531,7 +1589,7 @@ declare class BitfabFunction {
1531
1589
  /**
1532
1590
  * SDK version from package.json (injected at build time)
1533
1591
  */
1534
- declare const __version__ = "0.27.2";
1592
+ declare const __version__ = "0.28.0";
1535
1593
 
1536
1594
  /**
1537
1595
  * Constants for the Bitfab SDK.
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  flushTraces,
24
24
  getCurrentSpan,
25
25
  getCurrentTrace
26
- } from "./chunk-DW246LVL.js";
26
+ } from "./chunk-RS5Z6YXY.js";
27
27
  import {
28
28
  BITFAB_PROGRESS_PREFIX,
29
29
  BitfabError,