@bitfab/sdk 0.36.1 → 0.36.3
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/{chunk-HD4DRDRE.js → chunk-4CTDZMG5.js} +3 -3
- package/dist/{chunk-6ZBZBR5K.js → chunk-M2GISXGV.js} +166 -40
- package/dist/chunk-M2GISXGV.js.map +1 -0
- package/dist/index.cjs +175 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -6
- package/dist/index.d.ts +57 -6
- package/dist/index.js +10 -4
- package/dist/node.cjs +175 -43
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +10 -4
- package/dist/node.js.map +1 -1
- package/dist/replay-ZH25RPKH.js +17 -0
- package/package.json +1 -1
- package/dist/chunk-6ZBZBR5K.js.map +0 -1
- package/dist/replay-ZR4KIZIB.js +0 -11
- /package/dist/{chunk-HD4DRDRE.js.map → chunk-4CTDZMG5.js.map} +0 -0
- /package/dist/{replay-ZR4KIZIB.js.map → replay-ZH25RPKH.js.map} +0 -0
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
toJsonSafe,
|
|
17
17
|
toJsonSafeReport,
|
|
18
18
|
warnOnce
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-M2GISXGV.js";
|
|
20
20
|
|
|
21
21
|
// src/processorPayload.ts
|
|
22
22
|
var SERIALIZATION_DEGRADED_STEP = "serialization_degraded";
|
|
@@ -3337,7 +3337,7 @@ var Bitfab = class {
|
|
|
3337
3337
|
`Function is wrapped with trace function key '${wrappedKey}' but replay was called with '${traceFunctionKey}'. Pass matching keys, or pass the unwrapped function to replay it under the explicit key.`
|
|
3338
3338
|
);
|
|
3339
3339
|
}
|
|
3340
|
-
const { replay: doReplay } = await import("./replay-
|
|
3340
|
+
const { replay: doReplay } = await import("./replay-ZH25RPKH.js");
|
|
3341
3341
|
return doReplay(
|
|
3342
3342
|
this.httpClient,
|
|
3343
3343
|
this.serviceUrl,
|
|
@@ -3554,4 +3554,4 @@ export {
|
|
|
3554
3554
|
BitfabFunction,
|
|
3555
3555
|
finalizers
|
|
3556
3556
|
};
|
|
3557
|
-
//# sourceMappingURL=chunk-
|
|
3557
|
+
//# sourceMappingURL=chunk-4CTDZMG5.js.map
|
|
@@ -278,7 +278,7 @@ function encodeRequestBody(body) {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
// src/version.generated.ts
|
|
281
|
-
var __version__ = "0.36.
|
|
281
|
+
var __version__ = "0.36.3";
|
|
282
282
|
|
|
283
283
|
// src/constants.ts
|
|
284
284
|
var DEFAULT_SERVICE_URL = "https://bitfab.ai";
|
|
@@ -1598,9 +1598,11 @@ var HttpClient = class {
|
|
|
1598
1598
|
/**
|
|
1599
1599
|
* Fetch an external span by ID.
|
|
1600
1600
|
* Blocking GET request.
|
|
1601
|
+
* The replay view limits rawData to input/output serialization fields.
|
|
1601
1602
|
*/
|
|
1602
|
-
async getExternalSpan(spanId) {
|
|
1603
|
-
const
|
|
1603
|
+
async getExternalSpan(spanId, options) {
|
|
1604
|
+
const query = options?.view === "replay" ? "?view=replay" : "";
|
|
1605
|
+
const url = `${this.serviceUrl}/api/sdk/externalSpans/${spanId}${query}`;
|
|
1604
1606
|
const controller = new AbortController();
|
|
1605
1607
|
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
1606
1608
|
try {
|
|
@@ -1638,9 +1640,18 @@ var HttpClient = class {
|
|
|
1638
1640
|
* Pass `includeOutputs: false` for a payload-free tree (structure +
|
|
1639
1641
|
* `externalSpanId` only), so recorded outputs are fetched lazily per mocked
|
|
1640
1642
|
* span instead of all up front. Omit it (default eager) for `mock: "all"`.
|
|
1643
|
+
* Pass `includeRootOutput: false` when the root was already fetched.
|
|
1641
1644
|
*/
|
|
1642
1645
|
async getSpanTree(externalSpanId, options) {
|
|
1643
|
-
const
|
|
1646
|
+
const searchParams = new URLSearchParams();
|
|
1647
|
+
if (options?.includeOutputs === false) {
|
|
1648
|
+
searchParams.set("includeOutputs", "false");
|
|
1649
|
+
}
|
|
1650
|
+
if (options?.includeRootOutput === false) {
|
|
1651
|
+
searchParams.set("includeRootOutput", "false");
|
|
1652
|
+
}
|
|
1653
|
+
const encodedQuery = searchParams.toString();
|
|
1654
|
+
const query = encodedQuery ? `?${encodedQuery}` : "";
|
|
1644
1655
|
const url = `${this.serviceUrl}/api/sdk/replay/spanTree/${externalSpanId}${query}`;
|
|
1645
1656
|
const controller = new AbortController();
|
|
1646
1657
|
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
@@ -1921,11 +1932,78 @@ function reportReplayProgress(progress) {
|
|
|
1921
1932
|
return;
|
|
1922
1933
|
}
|
|
1923
1934
|
try {
|
|
1924
|
-
stderr.write(
|
|
1925
|
-
|
|
1935
|
+
stderr.write(
|
|
1936
|
+
`${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress, replayJsonReplacer)}
|
|
1937
|
+
`
|
|
1938
|
+
);
|
|
1926
1939
|
} catch {
|
|
1927
1940
|
}
|
|
1928
1941
|
}
|
|
1942
|
+
var ReplayError = class extends BitfabError {
|
|
1943
|
+
constructor(message, items, testRunId, testRunUrl, cause) {
|
|
1944
|
+
super(message, testRunUrl);
|
|
1945
|
+
this.items = items;
|
|
1946
|
+
this.testRunId = testRunId;
|
|
1947
|
+
this.testRunUrl = testRunUrl;
|
|
1948
|
+
this.cause = cause;
|
|
1949
|
+
this.name = "ReplayError";
|
|
1950
|
+
}
|
|
1951
|
+
};
|
|
1952
|
+
var DbBranchReplayError = class extends BitfabError {
|
|
1953
|
+
constructor(code, message, originalTraceId, cause) {
|
|
1954
|
+
super(message);
|
|
1955
|
+
this.code = code;
|
|
1956
|
+
this.originalTraceId = originalTraceId;
|
|
1957
|
+
this.cause = cause;
|
|
1958
|
+
this.name = "DbBranchReplayError";
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
function errorMessage(error) {
|
|
1962
|
+
return error instanceof Error ? error.message : String(error);
|
|
1963
|
+
}
|
|
1964
|
+
function replayItemErrorMessage(error) {
|
|
1965
|
+
if (error instanceof DbBranchReplayError) {
|
|
1966
|
+
return `Replay requested a database branch for trace ${error.originalTraceId} but it could not be resolved (${error.code}): ${error.message}. The function was not run, because replaying it against the live database would produce a result that looks valid but did not use the historical data you asked for.`;
|
|
1967
|
+
}
|
|
1968
|
+
return errorMessage(error);
|
|
1969
|
+
}
|
|
1970
|
+
function replayJsonReplacer(_key, value) {
|
|
1971
|
+
if (value instanceof Error) {
|
|
1972
|
+
const serialized = {
|
|
1973
|
+
name: value.name,
|
|
1974
|
+
message: value.message,
|
|
1975
|
+
stack: value.stack
|
|
1976
|
+
};
|
|
1977
|
+
if (value instanceof DbBranchReplayError) {
|
|
1978
|
+
serialized.code = value.code;
|
|
1979
|
+
serialized.originalTraceId = value.originalTraceId;
|
|
1980
|
+
if (value.cause !== void 0) {
|
|
1981
|
+
serialized.cause = value.cause;
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
return serialized;
|
|
1985
|
+
}
|
|
1986
|
+
return value;
|
|
1987
|
+
}
|
|
1988
|
+
function serializeReplayResult(result) {
|
|
1989
|
+
return JSON.stringify(result, replayJsonReplacer, 2);
|
|
1990
|
+
}
|
|
1991
|
+
async function preserveReplayFailure(operation, items, testRunId, testRunUrl) {
|
|
1992
|
+
try {
|
|
1993
|
+
return await operation();
|
|
1994
|
+
} catch (cause) {
|
|
1995
|
+
if (cause instanceof ReplayError) {
|
|
1996
|
+
throw cause;
|
|
1997
|
+
}
|
|
1998
|
+
throw new ReplayError(
|
|
1999
|
+
errorMessage(cause),
|
|
2000
|
+
items,
|
|
2001
|
+
testRunId,
|
|
2002
|
+
testRunUrl,
|
|
2003
|
+
cause
|
|
2004
|
+
);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
1929
2007
|
function deserializeInputs(spanData) {
|
|
1930
2008
|
const inputMeta = spanData.input_meta;
|
|
1931
2009
|
const rawInput = spanData.input;
|
|
@@ -1983,25 +2061,41 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
|
|
|
1983
2061
|
let originalOutput;
|
|
1984
2062
|
let result;
|
|
1985
2063
|
let error = null;
|
|
2064
|
+
let traceError = null;
|
|
2065
|
+
let replayError = null;
|
|
1986
2066
|
const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
|
|
1987
2067
|
const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
|
|
1988
2068
|
try {
|
|
1989
2069
|
if (includeDbBranchLease && !lease && !leaseError) {
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
2070
|
+
let resolved;
|
|
2071
|
+
try {
|
|
2072
|
+
resolved = await httpClient.resolveDbBranchLease(
|
|
2073
|
+
testRunId,
|
|
2074
|
+
originalTraceId,
|
|
2075
|
+
dbBranchSettings
|
|
2076
|
+
);
|
|
2077
|
+
} catch (cause) {
|
|
2078
|
+
throw new DbBranchReplayError(
|
|
2079
|
+
"lease_request_failed",
|
|
2080
|
+
`Bitfab could not request the database branch: ${errorMessage(cause)}`,
|
|
2081
|
+
originalTraceId,
|
|
2082
|
+
cause
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
1995
2085
|
lease = resolved.lease ?? void 0;
|
|
1996
2086
|
leaseError = resolved.leaseError ?? void 0;
|
|
1997
2087
|
dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
|
|
1998
2088
|
}
|
|
1999
2089
|
if (leaseError) {
|
|
2000
|
-
throw new
|
|
2001
|
-
|
|
2090
|
+
throw new DbBranchReplayError(
|
|
2091
|
+
leaseError.code,
|
|
2092
|
+
leaseError.message,
|
|
2093
|
+
originalTraceId
|
|
2002
2094
|
);
|
|
2003
2095
|
}
|
|
2004
|
-
const span = await httpClient.getExternalSpan(originalSpanId
|
|
2096
|
+
const span = await httpClient.getExternalSpan(originalSpanId, {
|
|
2097
|
+
view: "replay"
|
|
2098
|
+
});
|
|
2005
2099
|
const spanData = span.rawData?.span_data ?? {};
|
|
2006
2100
|
inputs = deserializeInputs(spanData);
|
|
2007
2101
|
originalOutput = deserializeOutput(spanData);
|
|
@@ -2021,7 +2115,8 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
|
|
|
2021
2115
|
if (needTree) {
|
|
2022
2116
|
try {
|
|
2023
2117
|
const treeResponse = await httpClient.getSpanTree(originalSpanId, {
|
|
2024
|
-
includeOutputs
|
|
2118
|
+
includeOutputs,
|
|
2119
|
+
includeRootOutput: false
|
|
2025
2120
|
});
|
|
2026
2121
|
if (treeResponse.root) {
|
|
2027
2122
|
mockTree = buildMockTree(treeResponse.root);
|
|
@@ -2043,7 +2138,7 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
|
|
|
2043
2138
|
const fetchSpanOutput = mockTree && !includeOutputs ? (externalSpanId) => {
|
|
2044
2139
|
let pending = outputCache.get(externalSpanId);
|
|
2045
2140
|
if (!pending) {
|
|
2046
|
-
pending = httpClient.getExternalSpan(externalSpanId).then(
|
|
2141
|
+
pending = httpClient.getExternalSpan(externalSpanId, { view: "replay" }).then(
|
|
2047
2142
|
(s) => deserializeOutput(
|
|
2048
2143
|
s.rawData?.span_data ?? {}
|
|
2049
2144
|
)
|
|
@@ -2052,25 +2147,31 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
|
|
|
2052
2147
|
}
|
|
2053
2148
|
return pending;
|
|
2054
2149
|
} : void 0;
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2150
|
+
try {
|
|
2151
|
+
const maybePromise = runWithReplayContext(
|
|
2152
|
+
{
|
|
2153
|
+
testRunId,
|
|
2154
|
+
traceId: replayedTraceId,
|
|
2155
|
+
inputSourceSpanId: span.id,
|
|
2156
|
+
inputSourceTraceId: span.externalTraceId,
|
|
2157
|
+
sourceBitfabTraceId: originalTraceId,
|
|
2158
|
+
mockTree,
|
|
2159
|
+
callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
|
|
2160
|
+
mockStrategy,
|
|
2161
|
+
mockOverrides: hasOverrides ? resolvedOverrides : void 0,
|
|
2162
|
+
fetchSpanOutput,
|
|
2163
|
+
dbBranchLease: lease
|
|
2164
|
+
},
|
|
2165
|
+
() => fn(...inputs)
|
|
2166
|
+
);
|
|
2167
|
+
result = maybePromise instanceof Promise ? await maybePromise : maybePromise;
|
|
2168
|
+
} catch (e) {
|
|
2169
|
+
traceError = e;
|
|
2170
|
+
error = errorMessage(e);
|
|
2171
|
+
}
|
|
2072
2172
|
} catch (e) {
|
|
2073
|
-
|
|
2173
|
+
replayError = e;
|
|
2174
|
+
error = replayItemErrorMessage(e);
|
|
2074
2175
|
} finally {
|
|
2075
2176
|
if (lease) {
|
|
2076
2177
|
try {
|
|
@@ -2099,6 +2200,8 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
|
|
|
2099
2200
|
result,
|
|
2100
2201
|
originalOutput,
|
|
2101
2202
|
error,
|
|
2203
|
+
traceError,
|
|
2204
|
+
replayError,
|
|
2102
2205
|
durationMs: serverItem.durationMs ?? null,
|
|
2103
2206
|
// Filled in by replay() from the complete-replay response once the
|
|
2104
2207
|
// replay traces are persisted and their spans aggregated server-side.
|
|
@@ -2223,6 +2326,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
|
|
|
2223
2326
|
);
|
|
2224
2327
|
const mockStrategy = options?.mock ?? "marked";
|
|
2225
2328
|
const maxConcurrency = options?.maxConcurrency ?? 10;
|
|
2329
|
+
const fullTestRunUrl = `${serviceUrl}${testRunUrl}`;
|
|
2226
2330
|
const resolvedOverrides = [
|
|
2227
2331
|
...normalizeMockOverrides(options?.mockOverride),
|
|
2228
2332
|
...registeredOverrides
|
|
@@ -2279,6 +2383,8 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
|
|
|
2279
2383
|
result: item.result,
|
|
2280
2384
|
originalOutput: item.originalOutput,
|
|
2281
2385
|
error: item.error,
|
|
2386
|
+
traceError: item.traceError,
|
|
2387
|
+
replayError: item.replayError,
|
|
2282
2388
|
durationMs: item.durationMs,
|
|
2283
2389
|
tokens: item.tokens,
|
|
2284
2390
|
model: item.model,
|
|
@@ -2289,8 +2395,18 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
|
|
|
2289
2395
|
}
|
|
2290
2396
|
} : void 0
|
|
2291
2397
|
);
|
|
2292
|
-
await
|
|
2293
|
-
|
|
2398
|
+
await preserveReplayFailure(
|
|
2399
|
+
() => waitForReplayPersistence(httpClient, testRunId, replayedTraceIds),
|
|
2400
|
+
resultItems,
|
|
2401
|
+
testRunId,
|
|
2402
|
+
fullTestRunUrl
|
|
2403
|
+
);
|
|
2404
|
+
const completeResult = await preserveReplayFailure(
|
|
2405
|
+
() => httpClient.completeReplay(testRunId),
|
|
2406
|
+
resultItems,
|
|
2407
|
+
testRunId,
|
|
2408
|
+
fullTestRunUrl
|
|
2409
|
+
);
|
|
2294
2410
|
const serverTraceIds = completeResult.traceIds;
|
|
2295
2411
|
const replayTokens = completeResult.tokens;
|
|
2296
2412
|
if (serverTraceIds !== void 0) {
|
|
@@ -2313,9 +2429,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
|
|
|
2313
2429
|
}
|
|
2314
2430
|
if (completedCount > 0 && missing.length === completedCount) {
|
|
2315
2431
|
const serverCount = completeResult.traceCount !== void 0 ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.` : "";
|
|
2316
|
-
|
|
2432
|
+
const cause = new BitfabError(
|
|
2317
2433
|
`Replay completed but the server has no persisted trace for any of the ${completedCount} completed item(s) (testRunId ${testRunId}).${serverCount} Trace uploads were awaited, so either the uploads failed (check for "Bitfab: Failed to create" errors above) or the replayed function is not wrapped with withSpan.`
|
|
2318
2434
|
);
|
|
2435
|
+
throw new ReplayError(
|
|
2436
|
+
cause.message,
|
|
2437
|
+
resultItems,
|
|
2438
|
+
testRunId,
|
|
2439
|
+
fullTestRunUrl,
|
|
2440
|
+
cause
|
|
2441
|
+
);
|
|
2319
2442
|
}
|
|
2320
2443
|
if (missing.length > 0) {
|
|
2321
2444
|
try {
|
|
@@ -2329,7 +2452,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
|
|
|
2329
2452
|
const result = {
|
|
2330
2453
|
items: resultItems,
|
|
2331
2454
|
testRunId,
|
|
2332
|
-
testRunUrl:
|
|
2455
|
+
testRunUrl: fullTestRunUrl
|
|
2333
2456
|
};
|
|
2334
2457
|
await writeReplayResultFile(result);
|
|
2335
2458
|
try {
|
|
@@ -2357,7 +2480,7 @@ async function writeReplayResultFile(result) {
|
|
|
2357
2480
|
import("fs/promises")
|
|
2358
2481
|
]);
|
|
2359
2482
|
await mkdir(dirname(resultPath), { recursive: true });
|
|
2360
|
-
await writeFile(resultPath, `${
|
|
2483
|
+
await writeFile(resultPath, `${serializeReplayResult(result)}
|
|
2361
2484
|
`);
|
|
2362
2485
|
} catch (err) {
|
|
2363
2486
|
try {
|
|
@@ -2393,6 +2516,9 @@ export {
|
|
|
2393
2516
|
resolveMockValue,
|
|
2394
2517
|
BITFAB_PROGRESS_PREFIX,
|
|
2395
2518
|
reportReplayProgress,
|
|
2519
|
+
ReplayError,
|
|
2520
|
+
DbBranchReplayError,
|
|
2521
|
+
serializeReplayResult,
|
|
2396
2522
|
replay
|
|
2397
2523
|
};
|
|
2398
|
-
//# sourceMappingURL=chunk-
|
|
2524
|
+
//# sourceMappingURL=chunk-M2GISXGV.js.map
|