@bitfab/sdk 0.32.0 → 0.33.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
@@ -143,6 +143,124 @@ interface MockOverride {
143
143
  value: MockValue;
144
144
  }
145
145
 
146
+ /**
147
+ * Replay context propagation via AsyncLocalStorage.
148
+ *
149
+ * When set, the withSpan wrapper injects testRunId into the span payload
150
+ * so that new spans created during replay are linked to the test run.
151
+ * Optionally carries a mock tree so child spans can return historical
152
+ * outputs instead of executing.
153
+ */
154
+
155
+ /**
156
+ * A single span entry in the mock tree.
157
+ *
158
+ * Under the eager path (`mock: "all"`) `output`/`outputMeta` are populated
159
+ * inline. Under the lazy path (`marked` / overrides) they are absent and the
160
+ * recorded output is fetched on demand via `externalSpanId` - see
161
+ * {@link ReplayContext.fetchSpanOutput}.
162
+ */
163
+ interface MockSpan {
164
+ sourceSpanId: string;
165
+ /** Row id accepted by `getExternalSpan`, for the lazy per-span output fetch. */
166
+ externalSpanId?: string;
167
+ output?: unknown;
168
+ outputMeta?: unknown;
169
+ }
170
+ /**
171
+ * Per-item DB branch resolved by the Bitfab service from the source
172
+ * trace's `dbSnapshotRef`. Carried on the replay context so that
173
+ * customer code reads `databaseUrl` through `getCurrentReplayBranch()`, and so
174
+ * the process-isolated replay runner can materialize it into a `.env`
175
+ * overlay file before customer code initializes its DB client.
176
+ *
177
+ * `neonBranchId` is the literal Neon branch id; passing it to
178
+ * `releaseDbBranchLease` deletes that branch.
179
+ */
180
+ interface DbBranchLease {
181
+ neonBranchId: string;
182
+ /** Env var name the customer's app reads, e.g. "DATABASE_URL". */
183
+ envKey: string;
184
+ databaseUrl: string;
185
+ expiresAt: string;
186
+ /**
187
+ * The instant the branch was pinned to (the source trace's wall clock).
188
+ * Echoed back in `db_snapshot_usage` on the replayed trace's completion.
189
+ */
190
+ snapshotTimestamp?: string;
191
+ providerConsoleUrl?: string;
192
+ readOnly?: boolean;
193
+ /**
194
+ * The branch's region, e.g. `aws-us-east-1`. A compute runs in its project's
195
+ * region, so a runner elsewhere pays that round trip on every query.
196
+ */
197
+ region?: string;
198
+ }
199
+ /**
200
+ * Pre-built lookup table of historical span outputs.
201
+ * Keys are `${traceFunctionKey}:${spanName}:${callIndex}` so that repeated
202
+ * calls with the same (key, name) are matched by call order, but spans
203
+ * sharing only the traceFunctionKey (different name) do not collide.
204
+ */
205
+ interface MockTree {
206
+ spans: Map<string, MockSpan>;
207
+ }
208
+ interface ReplayContext {
209
+ testRunId: string;
210
+ traceId?: string;
211
+ inputSourceSpanId?: string;
212
+ /**
213
+ * External trace ID from `external_traces.id`. Used for span-chain
214
+ * lookup against the source platform's trace tree (Braintrust, etc.).
215
+ * NOT the same as the Bitfab `traceId` - see `sourceBitfabTraceId`.
216
+ */
217
+ inputSourceTraceId?: string;
218
+ /**
219
+ * The Bitfab `traces.id` of the historical trace that produced this
220
+ * replay item's input. This is what customer-facing surfaces (e.g.
221
+ * `ReplayBranch.traceId`) should expose, since it's the ID the
222
+ * customer sees in the Bitfab dashboard.
223
+ */
224
+ sourceBitfabTraceId?: string;
225
+ mockTree?: MockTree;
226
+ callCounters?: Map<string, number>;
227
+ mockStrategy?: "none" | "all" | "marked";
228
+ /**
229
+ * Resolved override chain for this replay, per-call overrides first then
230
+ * registered ones (first matcher wins). Empty/absent when no overrides apply.
231
+ */
232
+ mockOverrides?: MockOverride[];
233
+ /**
234
+ * Memoized lazy fetch of a span's recorded output (deserialized), keyed by
235
+ * `externalSpanId`. Present ONLY on the lazy path (`marked` / overrides);
236
+ * absent under `mock: "all"`, where outputs are inline on the mock tree. Its
237
+ * presence is the signal that outputs must be fetched rather than read inline.
238
+ */
239
+ fetchSpanOutput?: (externalSpanId: string) => Promise<unknown>;
240
+ dbBranchLease?: DbBranchLease;
241
+ /**
242
+ * Set to true by `ReplayBranch` the first time customer code actually
243
+ * obtains `databaseUrl` for this item. Reported on the trace completion inside
244
+ * `db_snapshot_usage` so the server can distinguish "branch was
245
+ * provisioned and exposed" from "branch URL was actually consumed".
246
+ * Any future consumption path that hands the URL to customer code by
247
+ * other means (e.g. a process-isolated runner writing an env overlay)
248
+ * must also set this.
249
+ */
250
+ dbSnapshotAccessed?: boolean;
251
+ /**
252
+ * Collector for the replay item's trace-persistence work. When present,
253
+ * the root span's send path pushes a promise that resolves only after
254
+ * every span upload AND the trace completion have been sent (registered
255
+ * synchronously at send time, so the replay runner can await it after
256
+ * the wrapped fn resolves). This is what lets replay guarantee traces
257
+ * are persisted server-side before `completeReplay` builds the
258
+ * trace-ID mapping. Absent outside replay, where sends stay
259
+ * fire-and-forget.
260
+ */
261
+ pendingPersistence?: Promise<unknown>[];
262
+ }
263
+
146
264
  /**
147
265
  * HTTP client utilities for Bitfab API requests.
148
266
  *
@@ -622,41 +740,20 @@ declare class BitfabOpenAIAgentHandler {
622
740
  }
623
741
 
624
742
  /**
625
- * Per-trace environment exposed to customer code during replay.
626
- *
627
- * The customer instantiates one `ReplayEnvironment` and passes it to
628
- * `bitfab.replay({ environment })`. Inside the replayed function they read
629
- * `env.databaseUrl` (and friends) to pick up the per-trace branch URL the
630
- * Bitfab service resolved from the source trace's snapshot reference.
631
- *
632
- * The constructor takes how each branch should be sized and warmed. That lives
633
- * here rather than on the replay options because the settings only mean
634
- * anything for a replay that has an environment.
635
- *
636
- * Outside replay, accessing `env.databaseUrl` throws. Customer code uses
637
- * the env only on the replay path; live request code keeps reading
638
- * `process.env.DATABASE_URL` the normal way.
639
- *
640
- * Concurrency-safe: getters resolve through the replay AsyncLocalStorage
641
- * context, so each in-flight replay item sees its own per-trace values
642
- * even when the SDK runs items in parallel.
743
+ * Replay historical traces through a function and create a test run.
643
744
  *
644
- * Internally, the resolved per-item state is a `DbBranchLease` (see
645
- * replayContext.ts) - that's the SDK server protocol term. We expose
646
- * its useful fields directly here so customer code never sees the word.
745
+ * The replay flow has three phases:
746
+ * 1. Start: fetches historical traces from the server and creates a test run
747
+ * 2. Execute: re-runs each trace's inputs through the provided function locally
748
+ * 3. Complete: marks the test run as completed on the server
647
749
  */
648
- interface ReplayEnvironmentSnapshot {
649
- databaseUrl: string;
650
- expiresAt: string;
651
- providerConsoleUrl?: string;
652
- readOnly?: boolean;
653
- region?: string;
654
- traceId: string;
655
- }
750
+
751
+ type MockStrategy = "none" | "all" | "marked";
656
752
  /**
657
- * Per-lease settings for the DB-snapshot branch a replay item runs against.
658
- * Passed to the `ReplayEnvironment` constructor, since branching only happens
659
- * for a replay that has an environment.
753
+ * How the DB-snapshot branch each replay item runs against is sized and warmed.
754
+ *
755
+ * Passing this object at all is what turns database branching on, so `{}` means
756
+ * "branch every item, with the mirror project's own defaults".
660
757
  */
661
758
  interface DbBranchOptions {
662
759
  /**
@@ -675,68 +772,12 @@ interface DbBranchOptions {
675
772
  maxCu?: number;
676
773
  /**
677
774
  * SQL that warms the branch's cache. The server appends it to the branch's
678
- * readiness check, so it runs BEFORE your function sees the lease and its
679
- * time is not charged to the replayed call. Invalid SQL fails the lease
680
- * rather than silently leaving the branch cold.
775
+ * readiness check, so it runs BEFORE your function sees the branch and its
776
+ * time is not charged to the replayed call. Invalid SQL fails the branch
777
+ * rather than silently leaving it cold.
681
778
  */
682
779
  warmupSql?: string;
683
780
  }
684
- declare class ReplayEnvironment {
685
- /**
686
- * The branch settings this environment was constructed with, readable
687
- * anywhere. Every other accessor reports the lease the server resolved and
688
- * is therefore replay-only.
689
- */
690
- readonly dbBranch: DbBranchOptions;
691
- constructor(options?: DbBranchOptions);
692
- /**
693
- * The per-trace branch URL for the item currently being replayed.
694
- * Throws if read outside a replay item.
695
- */
696
- get databaseUrl(): string;
697
- /** When the per-trace branch URL stops being valid. ISO-8601. */
698
- get expiresAt(): string;
699
- /** Deep link to the branch in the provider console, if available. */
700
- get providerConsoleUrl(): string | undefined;
701
- /**
702
- * True if the branch is read-only. Customer code can use this to skip
703
- * write operations during replay when the provider returned a read-only
704
- * lease.
705
- */
706
- get readOnly(): boolean | undefined;
707
- /**
708
- * The branch's region, e.g. `aws-us-east-1`. A compute runs in its project's
709
- * region, so a replay runner elsewhere pays that round trip on every query.
710
- */
711
- get region(): string | undefined;
712
- /** The historical trace ID that produced the input for this replay item. */
713
- get traceId(): string;
714
- /** True when read inside a replay item that has a resolved branch. */
715
- get active(): boolean;
716
- /** Non-throwing variant for callers that handle the inactive case. */
717
- snapshot(): ReplayEnvironmentSnapshot | null;
718
- /**
719
- * Record on the replay context that customer code obtained the branch
720
- * URL. Only `databaseUrl` and `snapshot()` count - `active`, `readOnly`
721
- * and friends inspect the lease without exposing the connection string,
722
- * so they don't prove the replayed code could have connected to the
723
- * branch.
724
- */
725
- private markAccessed;
726
- private read;
727
- private require;
728
- }
729
-
730
- /**
731
- * Replay historical traces through a function and create a test run.
732
- *
733
- * The replay flow has three phases:
734
- * 1. Start: fetches historical traces from the server and creates a test run
735
- * 2. Execute: re-runs each trace's inputs through the provided function locally
736
- * 3. Complete: marks the test run as completed on the server
737
- */
738
-
739
- type MockStrategy = "none" | "all" | "marked";
740
781
  interface ReplayOptions {
741
782
  /**
742
783
  * Maximum number of traces to replay (1-100, default 5). Ignored when
@@ -779,13 +820,18 @@ interface ReplayOptions {
779
820
  */
780
821
  mockOverride?: MockOverride | MockOverride[];
781
822
  /**
782
- * Per-trace environment. When the source trace carries a DB branching
783
- * snapshot, the SDK populates `environment.databaseUrl` before invoking
784
- * `fn` for that item and resets it after. Customer code reads from the
785
- * environment to pick up the per-trace branch URL. Compute size and cache
786
- * warm-up for each branch are configured on the environment's constructor.
823
+ * Run each item against a database branch restored to the state its source
824
+ * trace saw. Passing this object at all turns branching on, so `{}` enables
825
+ * it with the mirror project's own sizing; the fields tune how each branch is
826
+ * sized and warmed. Inside `fn`, read the resolved branch with
827
+ * `getCurrentReplayBranch()`.
828
+ *
829
+ * Items whose source trace carried no DB snapshot reference get no branch and
830
+ * run against the live database. An item whose branch was requested but could
831
+ * not be resolved fails instead of running, so a replay never silently
832
+ * reports a result that did not use the historical data you asked for.
787
833
  */
788
- environment?: ReplayEnvironment;
834
+ dbBranch?: DbBranchOptions;
789
835
  /** Group ID to associate this replay with an experiment group for live streaming in Studio. */
790
836
  experimentGroupId?: string;
791
837
  /**
@@ -1001,6 +1047,58 @@ interface ReplayResult<T> {
1001
1047
  testRunUrl: string;
1002
1048
  }
1003
1049
 
1050
+ /**
1051
+ * The database branch a single replay item runs against.
1052
+ *
1053
+ * `getCurrentReplayBranch()` hands you one inside a replayed function when the
1054
+ * source trace carried a DB snapshot reference and the Bitfab service resolved
1055
+ * a branch from it. Outside a replay item, or when no branch was resolved, that
1056
+ * accessor returns null and your code keeps reading `process.env.DATABASE_URL`
1057
+ * the normal way.
1058
+ *
1059
+ * Immutable and scoped to one item: the accessor builds it from the replay
1060
+ * AsyncLocalStorage context, so parallel replay items each see their own branch
1061
+ * and no lease state lives on a long-lived object.
1062
+ *
1063
+ * Internally the resolved per-item state is a `DbBranchLease` (see
1064
+ * replayContext.ts), the SDK/server protocol term. Its useful fields are
1065
+ * exposed directly here so customer code never sees the word.
1066
+ */
1067
+
1068
+ declare class ReplayBranch {
1069
+ #private;
1070
+ /** When this branch's URL stops being valid. ISO-8601. */
1071
+ readonly expiresAt: string;
1072
+ /** Deep link to the branch in the provider console, if available. */
1073
+ readonly providerConsoleUrl?: string;
1074
+ /**
1075
+ * True if the branch is read-only. Use it to skip write operations during
1076
+ * replay when the provider returned a read-only lease.
1077
+ */
1078
+ readonly readOnly?: boolean;
1079
+ /**
1080
+ * The branch's region, e.g. `aws-us-east-1`. A compute runs in its project's
1081
+ * region, so a replay runner elsewhere pays that round trip on every query.
1082
+ */
1083
+ readonly region?: string;
1084
+ /** The historical trace ID that produced the input for this replay item. */
1085
+ readonly traceId: string;
1086
+ /** @internal Built by `getCurrentReplayBranch()`; never constructed by callers. */
1087
+ constructor(lease: DbBranchLease, traceId: string, context: ReplayContext);
1088
+ /**
1089
+ * Connection string for this item's branch. Point your database client at it
1090
+ * instead of the live database for the duration of the replayed call.
1091
+ *
1092
+ * Reading it records on the trace that the replayed code obtained the branch
1093
+ * URL, which is what separates "a branch was provisioned" from "the branch
1094
+ * was actually used". The other fields inspect the lease without exposing the
1095
+ * connection string, so they deliberately do not record anything. That is
1096
+ * also why this is a getter and not a plain field: the URL is absent from
1097
+ * `JSON.stringify(branch)` and from logging the object.
1098
+ */
1099
+ get databaseUrl(): string;
1100
+ }
1101
+
1004
1102
  /**
1005
1103
  * Tracing utilities for external trace submission to Bitfab.
1006
1104
  *
@@ -1240,6 +1338,23 @@ interface CurrentTrace {
1240
1338
  * Returns a no-op object if called outside of a span context (methods do nothing).
1241
1339
  */
1242
1340
  declare function getCurrentSpan(): CurrentSpan;
1341
+ /**
1342
+ * Get the database branch the current replay item is running against.
1343
+ *
1344
+ * Call this from inside a function being replayed with `replay({ dbBranch })`
1345
+ * and point your database client at `branch.databaseUrl` so the replay reads
1346
+ * the data as it was at trace time:
1347
+ *
1348
+ * ```ts
1349
+ * const branch = getCurrentReplayBranch()
1350
+ * const url = branch?.databaseUrl ?? process.env.DATABASE_URL
1351
+ * ```
1352
+ *
1353
+ * Returns null outside a replay item, and for an item whose source trace
1354
+ * carried no DB snapshot reference, so live request code takes the same path
1355
+ * it always did.
1356
+ */
1357
+ declare function getCurrentReplayBranch(): ReplayBranch | null;
1243
1358
  /**
1244
1359
  * Get a handle to the current active trace.
1245
1360
  *
@@ -1347,12 +1462,6 @@ interface SpanOptions {
1347
1462
  * Client for making provider-based API calls via BAML.
1348
1463
  */
1349
1464
  declare class Bitfab {
1350
- /**
1351
- * Per-trace environment for `replay({ environment })`. Construct one,
1352
- * pass it to replay, and read `env.databaseUrl` inside the replayed
1353
- * function to pick up the per-trace branch URL.
1354
- */
1355
- static readonly ReplayEnvironment: typeof ReplayEnvironment;
1356
1465
  private readonly apiKeyConfig;
1357
1466
  /** Cached only once a non-empty key is found, so an early resolve (before env loaded) can't poison a later one. */
1358
1467
  private resolvedApiKey;
@@ -1854,7 +1963,7 @@ declare class BitfabFunction {
1854
1963
  /**
1855
1964
  * SDK version from package.json (injected at build time)
1856
1965
  */
1857
- declare const __version__ = "0.32.0";
1966
+ declare const __version__ = "0.33.0";
1858
1967
 
1859
1968
  /**
1860
1969
  * Constants for the Bitfab SDK.
@@ -1922,4 +2031,4 @@ declare const finalizers: {
1922
2031
  readableStream: typeof readableStream;
1923
2032
  };
1924
2033
 
1925
- export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CapturedSpan, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbBranchOptions, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, type MockOverride, type MockOverrideCtx, type MockStrategy, type MockValue, type NodeMatcher, type ProviderDefinition, ReplayEnvironment, type ReplayEnvironmentSnapshot, type ReplayItem, type ReplayOptions, type ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanNodeMeta, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentSpan, getCurrentTrace, reportReplayProgress };
2034
+ export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CapturedSpan, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbBranchOptions, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, type MockOverride, type MockOverrideCtx, type MockStrategy, type MockValue, type NodeMatcher, type ProviderDefinition, ReplayBranch, type ReplayItem, type ReplayOptions, type ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanNodeMeta, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentReplayBranch, getCurrentSpan, getCurrentTrace, reportReplayProgress };