@bitfab/sdk 0.65.4 → 0.65.5
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/autoTrace-CZu0BXhG.js +270 -0
- package/dist/autoTrace-CZu0BXhG.js.map +1 -0
- package/dist/autoTrace-KM9pYqk9.cjs +395 -0
- package/dist/autoTrace-KM9pYqk9.cjs.map +1 -0
- package/dist/autoTrace.cjs +15 -353
- package/dist/autoTrace.d.cts +44 -44
- package/dist/autoTrace.d.ts +44 -44
- package/dist/autoTrace.js +1 -28
- package/dist/babelPlugin-C70OxrqA.js +209 -0
- package/dist/babelPlugin-C70OxrqA.js.map +1 -0
- package/dist/babelPlugin-Nta4-VcL.cjs +232 -0
- package/dist/babelPlugin-Nta4-VcL.cjs.map +1 -0
- package/dist/http-CG1Irqxx.js +2154 -0
- package/dist/http-CG1Irqxx.js.map +1 -0
- package/dist/index-BFkAwvuc.d.cts +4410 -0
- package/dist/index-BFkAwvuc.d.ts +4410 -0
- package/dist/index.cjs +48 -12504
- package/dist/index.d.cts +2 -4443
- package/dist/index.d.ts +2 -4443
- package/dist/index.js +3 -96
- package/dist/loaderRuntime-0huddOOP.d.ts +12 -0
- package/dist/loaderRuntime-CslfDFO7.d.cts +12 -0
- package/dist/node.cjs +56 -12520
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +2 -1
- package/dist/node.d.ts +2 -1
- package/dist/node.js +10 -105
- package/dist/node.js.map +1 -1
- package/dist/registryCommand-Di8x0YoJ.js +1111 -0
- package/dist/registryCommand-Di8x0YoJ.js.map +1 -0
- package/dist/replayCli.js +49 -87
- package/dist/replayCli.js.map +1 -1
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/seedCli.js +10 -24
- package/dist/seedCli.js.map +1 -1
- package/dist/src-BRKm0P_S.cjs +8434 -0
- package/dist/src-BRKm0P_S.cjs.map +1 -0
- package/dist/src-CfFkki5l.js +6011 -0
- package/dist/src-CfFkki5l.js.map +1 -0
- package/dist/transform/babel.cjs +5 -422
- package/dist/transform/babel.d.cts +16 -16
- package/dist/transform/babel.d.ts +16 -16
- package/dist/transform/babel.js +1 -7
- package/dist/transform/bun.cjs +9 -478
- package/dist/transform/bun.cjs.map +1 -1
- package/dist/transform/bun.d.cts +5 -7
- package/dist/transform/bun.d.ts +5 -7
- package/dist/transform/bun.js +6 -11
- package/dist/transform/bun.js.map +1 -1
- package/dist/transform/esbuild.cjs +9 -478
- package/dist/transform/esbuild.cjs.map +1 -1
- package/dist/transform/esbuild.d.cts +5 -7
- package/dist/transform/esbuild.d.ts +5 -7
- package/dist/transform/esbuild.js +6 -11
- package/dist/transform/esbuild.js.map +1 -1
- package/dist/transform/loaderRuntime.cjs +85 -532
- package/dist/transform/loaderRuntime.cjs.map +1 -1
- package/dist/transform/loaderRuntime.d.cts +2 -12
- package/dist/transform/loaderRuntime.d.ts +2 -12
- package/dist/transform/loaderRuntime.js +56 -98
- package/dist/transform/loaderRuntime.js.map +1 -1
- package/dist/transform/nest.cjs +12 -481
- package/dist/transform/nest.cjs.map +1 -1
- package/dist/transform/nest.d.cts +8 -9
- package/dist/transform/nest.d.ts +8 -9
- package/dist/transform/nest.js +9 -14
- package/dist/transform/nest.js.map +1 -1
- package/dist/transform/next.cjs +56 -528
- package/dist/transform/next.cjs.map +1 -1
- package/dist/transform/next.d.cts +25 -25
- package/dist/transform/next.d.ts +24 -24
- package/dist/transform/next.js +52 -60
- package/dist/transform/next.js.map +1 -1
- package/dist/transform/nodeLoader.js +260 -506
- package/dist/transform/nodeLoader.js.map +1 -1
- package/dist/transform/register.js +4 -1
- package/dist/transform/register.js.map +1 -1
- package/dist/transform/rolldown.cjs +9 -478
- package/dist/transform/rolldown.cjs.map +1 -1
- package/dist/transform/rolldown.d.cts +5 -7
- package/dist/transform/rolldown.d.ts +5 -7
- package/dist/transform/rolldown.js +6 -11
- package/dist/transform/rolldown.js.map +1 -1
- package/dist/transform/rollup.cjs +9 -478
- package/dist/transform/rollup.cjs.map +1 -1
- package/dist/transform/rollup.d.cts +5 -7
- package/dist/transform/rollup.d.ts +5 -7
- package/dist/transform/rollup.js +6 -11
- package/dist/transform/rollup.js.map +1 -1
- package/dist/transform/rsbuild.cjs +9 -478
- package/dist/transform/rsbuild.cjs.map +1 -1
- package/dist/transform/rsbuild.d.cts +5 -7
- package/dist/transform/rsbuild.d.ts +5 -7
- package/dist/transform/rsbuild.js +6 -11
- package/dist/transform/rsbuild.js.map +1 -1
- package/dist/transform/rspack.cjs +9 -478
- package/dist/transform/rspack.cjs.map +1 -1
- package/dist/transform/rspack.d.cts +5 -7
- package/dist/transform/rspack.d.ts +5 -7
- package/dist/transform/rspack.js +6 -11
- package/dist/transform/rspack.js.map +1 -1
- package/dist/transform/swc.cjs +18 -486
- package/dist/transform/swc.cjs.map +1 -1
- package/dist/transform/swc.d.cts +15 -14
- package/dist/transform/swc.d.ts +15 -14
- package/dist/transform/swc.js +14 -32
- package/dist/transform/swc.js.map +1 -1
- package/dist/transform/unplugin.cjs +20 -476
- package/dist/transform/unplugin.cjs.map +1 -1
- package/dist/transform/unplugin.d.cts +4 -6
- package/dist/transform/unplugin.d.ts +4 -6
- package/dist/transform/unplugin.js +19 -8
- package/dist/transform/unplugin.js.map +1 -1
- package/dist/transform/vite.cjs +9 -478
- package/dist/transform/vite.cjs.map +1 -1
- package/dist/transform/vite.d.cts +5 -7
- package/dist/transform/vite.d.ts +5 -7
- package/dist/transform/vite.js +6 -11
- package/dist/transform/vite.js.map +1 -1
- package/dist/transform/webpack.cjs +9 -478
- package/dist/transform/webpack.cjs.map +1 -1
- package/dist/transform/webpack.d.cts +5 -7
- package/dist/transform/webpack.d.ts +5 -7
- package/dist/transform/webpack.js +6 -11
- package/dist/transform/webpack.js.map +1 -1
- package/dist/transform-BcyUocwm.js +36 -0
- package/dist/transform-BcyUocwm.js.map +1 -0
- package/dist/transform-BjxHGGKc.cjs +47 -0
- package/dist/transform-BjxHGGKc.cjs.map +1 -0
- package/dist/transformOptions-BsjCELkh.d.cts +11 -0
- package/dist/transformOptions-BsjCELkh.d.ts +11 -0
- package/package.json +5 -5
- package/dist/autoTrace.cjs.map +0 -1
- package/dist/autoTrace.js.map +0 -1
- package/dist/chunk-27B3UBSS.js +0 -2547
- package/dist/chunk-27B3UBSS.js.map +0 -1
- package/dist/chunk-B2M4KELA.js +0 -1912
- package/dist/chunk-B2M4KELA.js.map +0 -1
- package/dist/chunk-I233ERUH.js +0 -2979
- package/dist/chunk-I233ERUH.js.map +0 -1
- package/dist/chunk-ISU6FQKY.js +0 -6877
- package/dist/chunk-ISU6FQKY.js.map +0 -1
- package/dist/chunk-MT36GJMW.js +0 -106
- package/dist/chunk-MT36GJMW.js.map +0 -1
- package/dist/chunk-PTCLRG4E.js +0 -28
- package/dist/chunk-PTCLRG4E.js.map +0 -1
- package/dist/chunk-QRNHRY7F.js +0 -270
- package/dist/chunk-QRNHRY7F.js.map +0 -1
- package/dist/chunk-R6M54SPO.js +0 -1176
- package/dist/chunk-R6M54SPO.js.map +0 -1
- package/dist/chunk-SOP5AFMH.js +0 -2060
- package/dist/chunk-SOP5AFMH.js.map +0 -1
- package/dist/chunk-YVJAOGHE.js +0 -45
- package/dist/chunk-YVJAOGHE.js.map +0 -1
- package/dist/chunk-ZG6SHKEF.js +0 -404
- package/dist/chunk-ZG6SHKEF.js.map +0 -1
- package/dist/http-LL3JD2JE.js +0 -24
- package/dist/http-LL3JD2JE.js.map +0 -1
- package/dist/http-QZDTQC3C.js +0 -23
- package/dist/http-QZDTQC3C.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/replay-636XZIS2.js +0 -29
- package/dist/replay-636XZIS2.js.map +0 -1
- package/dist/replay-S4DNF4VR.js +0 -28
- package/dist/replay-S4DNF4VR.js.map +0 -1
- package/dist/transform/babel.cjs.map +0 -1
- package/dist/transform/babel.js.map +0 -1
- package/dist/transformOptions-Df2_Chtc.d.cts +0 -10
- package/dist/transformOptions-Df2_Chtc.d.ts +0 -10
|
@@ -0,0 +1,2154 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
+
import { f as warn, g as runWithCaptureSuppressed, p as warnOnce, v as asyncStorageReady, y as createAsyncLocalStorage } from "./autoTrace-CZu0BXhG.js";
|
|
3
|
+
import { SpanStatusCode } from "@opentelemetry/api";
|
|
4
|
+
import { ExportResultCode } from "@opentelemetry/core";
|
|
5
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
6
|
+
import { AlwaysOnSampler, BasicTracerProvider, BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
7
|
+
//#region src/version.generated.ts
|
|
8
|
+
const __version__ = "0.65.5";
|
|
9
|
+
const __packageName__ = "@bitfab/sdk";
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/traceCompletion.ts
|
|
12
|
+
var TraceCompletion = class {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.traces = /* @__PURE__ */ new Map();
|
|
15
|
+
this.closed = /* @__PURE__ */ new Map();
|
|
16
|
+
}
|
|
17
|
+
state(traceId) {
|
|
18
|
+
let state = this.traces.get(traceId);
|
|
19
|
+
if (state === void 0) {
|
|
20
|
+
state = {
|
|
21
|
+
spanIds: /* @__PURE__ */ new Set(),
|
|
22
|
+
active: /* @__PURE__ */ new Set()
|
|
23
|
+
};
|
|
24
|
+
this.traces.set(traceId, state);
|
|
25
|
+
}
|
|
26
|
+
return state;
|
|
27
|
+
}
|
|
28
|
+
start(traceId, spanId) {
|
|
29
|
+
if (this.closed.has(traceId)) return;
|
|
30
|
+
const state = this.state(traceId);
|
|
31
|
+
state.spanIds.add(spanId);
|
|
32
|
+
state.active.add(spanId);
|
|
33
|
+
}
|
|
34
|
+
open(traceId) {
|
|
35
|
+
if (!this.closed.has(traceId)) this.state(traceId);
|
|
36
|
+
}
|
|
37
|
+
hold(traceId, key) {
|
|
38
|
+
this.state(traceId).active.add(key);
|
|
39
|
+
}
|
|
40
|
+
record(traceId, spanId) {
|
|
41
|
+
if (!this.closed.has(traceId)) this.state(traceId).spanIds.add(spanId);
|
|
42
|
+
}
|
|
43
|
+
end(traceId, spanId) {
|
|
44
|
+
const state = this.traces.get(traceId);
|
|
45
|
+
if (state !== void 0) {
|
|
46
|
+
state.active.delete(spanId);
|
|
47
|
+
this.drain(traceId, state);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
abort(traceId, spanId) {
|
|
51
|
+
const state = this.traces.get(traceId);
|
|
52
|
+
if (state === void 0) return;
|
|
53
|
+
state.active.delete(spanId);
|
|
54
|
+
state.spanIds.delete(spanId);
|
|
55
|
+
if (state.active.size === 0 && state.spanIds.size === 0 && state.complete === void 0) {
|
|
56
|
+
this.traces.delete(traceId);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.drain(traceId, state);
|
|
60
|
+
}
|
|
61
|
+
close(traceId, complete, dropped = false) {
|
|
62
|
+
const count = this.closed.get(traceId);
|
|
63
|
+
if (count !== void 0) {
|
|
64
|
+
complete(count);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const state = this.traces.get(traceId);
|
|
68
|
+
if (state === void 0) return;
|
|
69
|
+
state.complete = complete;
|
|
70
|
+
if (dropped) state.active.clear();
|
|
71
|
+
this.drain(traceId, state);
|
|
72
|
+
}
|
|
73
|
+
drain(traceId, state) {
|
|
74
|
+
if (state.active.size !== 0 || state.complete === void 0) return;
|
|
75
|
+
this.traces.delete(traceId);
|
|
76
|
+
this.closed.set(traceId, state.spanIds.size);
|
|
77
|
+
if (this.closed.size > 1024) {
|
|
78
|
+
const oldest = this.closed.keys().next().value;
|
|
79
|
+
if (oldest !== void 0) this.closed.delete(oldest);
|
|
80
|
+
}
|
|
81
|
+
state.complete(state.spanIds.size);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/readEnv.ts
|
|
86
|
+
function readEnv(name) {
|
|
87
|
+
if (typeof process !== "undefined" && process.env) return process.env[name];
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/compress.ts
|
|
91
|
+
const DISABLE_COMPRESSION_ENV = "BITFAB_DISABLE_COMPRESSION";
|
|
92
|
+
const MIN_COMPRESSED_BYTES = 8192;
|
|
93
|
+
let gzipNode;
|
|
94
|
+
(typeof process !== "undefined" && process.versions?.node ? import(
|
|
95
|
+
/* webpackIgnore: true */
|
|
96
|
+
["node", "zlib"].join(":")
|
|
97
|
+
).then(({ gzip }) => {
|
|
98
|
+
gzipNode = (data) => new Promise((resolve, reject) => {
|
|
99
|
+
gzip(data, (error, result) => {
|
|
100
|
+
if (error) reject(error);
|
|
101
|
+
else resolve(result);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}).catch(() => {}) : Promise.resolve()).then(() => {});
|
|
105
|
+
function toArrayBuffer(view) {
|
|
106
|
+
return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
|
|
107
|
+
}
|
|
108
|
+
function compressedRequest(body, rawBytes, compressed) {
|
|
109
|
+
if (compressed.byteLength >= rawBytes) return {
|
|
110
|
+
body,
|
|
111
|
+
rawBytes,
|
|
112
|
+
wireBytes: rawBytes
|
|
113
|
+
};
|
|
114
|
+
return {
|
|
115
|
+
body: compressed instanceof Uint8Array ? toArrayBuffer(compressed) : compressed,
|
|
116
|
+
contentEncoding: "gzip",
|
|
117
|
+
rawBytes,
|
|
118
|
+
wireBytes: compressed.byteLength
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
async function gzipViaStream(bytes) {
|
|
122
|
+
const stream = new Blob([bytes]).stream().pipeThrough(new CompressionStream("gzip"));
|
|
123
|
+
return await new Response(stream).arrayBuffer();
|
|
124
|
+
}
|
|
125
|
+
function encodeRequestBody(body) {
|
|
126
|
+
if (readEnv(DISABLE_COMPRESSION_ENV)) {
|
|
127
|
+
const rawBytes = new TextEncoder().encode(body).byteLength;
|
|
128
|
+
return {
|
|
129
|
+
body,
|
|
130
|
+
rawBytes,
|
|
131
|
+
wireBytes: rawBytes
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const bytes = new TextEncoder().encode(body);
|
|
135
|
+
if (bytes.byteLength < MIN_COMPRESSED_BYTES) return {
|
|
136
|
+
body,
|
|
137
|
+
rawBytes: bytes.byteLength,
|
|
138
|
+
wireBytes: bytes.byteLength
|
|
139
|
+
};
|
|
140
|
+
if (gzipNode) return gzipNode(bytes).then((compressed) => compressedRequest(body, bytes.byteLength, compressed), () => ({
|
|
141
|
+
body,
|
|
142
|
+
rawBytes: bytes.byteLength,
|
|
143
|
+
wireBytes: bytes.byteLength
|
|
144
|
+
}));
|
|
145
|
+
if (typeof CompressionStream === "undefined") return {
|
|
146
|
+
body,
|
|
147
|
+
rawBytes: bytes.byteLength,
|
|
148
|
+
wireBytes: bytes.byteLength
|
|
149
|
+
};
|
|
150
|
+
return gzipViaStream(bytes).then((compressed) => compressedRequest(body, bytes.byteLength, compressed), () => ({
|
|
151
|
+
body,
|
|
152
|
+
rawBytes: bytes.byteLength,
|
|
153
|
+
wireBytes: bytes.byteLength
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/errors.ts
|
|
158
|
+
var BitfabError = class extends Error {
|
|
159
|
+
constructor(message, url, status, retryAfterMs) {
|
|
160
|
+
super(message);
|
|
161
|
+
this.url = url;
|
|
162
|
+
this.status = status;
|
|
163
|
+
this.retryAfterMs = retryAfterMs;
|
|
164
|
+
this.name = "BitfabError";
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var MixedTracingError = class extends Error {
|
|
168
|
+
constructor(message) {
|
|
169
|
+
super(message);
|
|
170
|
+
this.name = "MixedTracingError";
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/gitCommand.ts
|
|
175
|
+
const EXIT_GRACE_MS = 500;
|
|
176
|
+
function isUnrefable(value) {
|
|
177
|
+
return typeof value === "object" && value !== null && "unref" in value && typeof value.unref === "function";
|
|
178
|
+
}
|
|
179
|
+
function unrefStream(stream) {
|
|
180
|
+
if (isUnrefable(stream)) stream.unref();
|
|
181
|
+
}
|
|
182
|
+
function terminate(child) {
|
|
183
|
+
if (child.pid && process.platform !== "win32") try {
|
|
184
|
+
process.kill(-child.pid, "SIGTERM");
|
|
185
|
+
return;
|
|
186
|
+
} catch {
|
|
187
|
+
child.kill("SIGTERM");
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
child.kill("SIGTERM");
|
|
191
|
+
}
|
|
192
|
+
async function gitRunner(options) {
|
|
193
|
+
let spawn;
|
|
194
|
+
try {
|
|
195
|
+
({spawn} = await import("child_process"));
|
|
196
|
+
} catch {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
return (dir, args, env) => new Promise((resolve) => {
|
|
200
|
+
let child;
|
|
201
|
+
try {
|
|
202
|
+
child = spawn("git", args, {
|
|
203
|
+
cwd: dir,
|
|
204
|
+
detached: process.platform !== "win32",
|
|
205
|
+
stdio: [
|
|
206
|
+
"ignore",
|
|
207
|
+
"pipe",
|
|
208
|
+
"pipe"
|
|
209
|
+
],
|
|
210
|
+
...env ? { env: {
|
|
211
|
+
...process.env,
|
|
212
|
+
...env
|
|
213
|
+
} } : {}
|
|
214
|
+
});
|
|
215
|
+
} catch {
|
|
216
|
+
resolve(null);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const chunks = [];
|
|
220
|
+
let size = 0;
|
|
221
|
+
let overflow = false;
|
|
222
|
+
let exitCode = null;
|
|
223
|
+
let done = false;
|
|
224
|
+
const timers = [];
|
|
225
|
+
const schedule = (callback, ms) => {
|
|
226
|
+
const timer = setTimeout(callback, ms);
|
|
227
|
+
if (!options.keepProcessAlive) timer.unref();
|
|
228
|
+
timers.push(timer);
|
|
229
|
+
};
|
|
230
|
+
const finish = () => {
|
|
231
|
+
if (done) return;
|
|
232
|
+
done = true;
|
|
233
|
+
for (const timer of timers) clearTimeout(timer);
|
|
234
|
+
child.stdout?.destroy();
|
|
235
|
+
child.stderr?.destroy();
|
|
236
|
+
resolve(exitCode === 0 && !overflow ? Buffer.concat(chunks).toString("utf8") : null);
|
|
237
|
+
};
|
|
238
|
+
child.stdout?.on("data", (chunk) => {
|
|
239
|
+
size += chunk.length;
|
|
240
|
+
if (size > options.maxBuffer) {
|
|
241
|
+
overflow = true;
|
|
242
|
+
terminate(child);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
chunks.push(chunk);
|
|
246
|
+
});
|
|
247
|
+
child.stderr?.resume();
|
|
248
|
+
child.on("error", () => {
|
|
249
|
+
exitCode = null;
|
|
250
|
+
finish();
|
|
251
|
+
});
|
|
252
|
+
child.on("exit", (code) => {
|
|
253
|
+
exitCode = code;
|
|
254
|
+
schedule(finish, EXIT_GRACE_MS);
|
|
255
|
+
});
|
|
256
|
+
child.on("close", (code) => {
|
|
257
|
+
exitCode = code ?? exitCode;
|
|
258
|
+
finish();
|
|
259
|
+
});
|
|
260
|
+
schedule(() => terminate(child), options.timeoutMs);
|
|
261
|
+
if (!options.keepProcessAlive) {
|
|
262
|
+
child.unref();
|
|
263
|
+
unrefStream(child.stdout);
|
|
264
|
+
unrefStream(child.stderr);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region src/gitState.ts
|
|
270
|
+
const GIT_TIMEOUT_MS = 3e4;
|
|
271
|
+
const GIT_MAX_BUFFER = 1048576;
|
|
272
|
+
const DISABLE_ENV = "BITFAB_DISABLE_GIT_STATE";
|
|
273
|
+
const SHA_PATTERN = /^[0-9a-f]{40}$/;
|
|
274
|
+
function sha(value) {
|
|
275
|
+
const trimmed = value?.trim();
|
|
276
|
+
return trimmed && SHA_PATTERN.test(trimmed) ? trimmed : null;
|
|
277
|
+
}
|
|
278
|
+
function text(value) {
|
|
279
|
+
const trimmed = value?.trim();
|
|
280
|
+
return trimmed ? trimmed : null;
|
|
281
|
+
}
|
|
282
|
+
function isEmptyGitState(state) {
|
|
283
|
+
return Object.values(state).every((value) => value === null);
|
|
284
|
+
}
|
|
285
|
+
async function resolveGitState(cwd) {
|
|
286
|
+
const git = await gitRunner({
|
|
287
|
+
timeoutMs: GIT_TIMEOUT_MS,
|
|
288
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
289
|
+
keepProcessAlive: true
|
|
290
|
+
});
|
|
291
|
+
if (!git) return null;
|
|
292
|
+
const run = async (args, env) => (await git(cwd, args, env))?.trim() ?? null;
|
|
293
|
+
const [refs, email, branch] = await Promise.all([
|
|
294
|
+
run([
|
|
295
|
+
"rev-parse",
|
|
296
|
+
"--show-toplevel",
|
|
297
|
+
"HEAD",
|
|
298
|
+
"HEAD^{tree}"
|
|
299
|
+
]),
|
|
300
|
+
run(["config", "user.email"]),
|
|
301
|
+
run([
|
|
302
|
+
"symbolic-ref",
|
|
303
|
+
"--short",
|
|
304
|
+
"-q",
|
|
305
|
+
"HEAD"
|
|
306
|
+
])
|
|
307
|
+
]);
|
|
308
|
+
const [root, commitSha, baseSha] = (refs ?? "").split("\n");
|
|
309
|
+
if (!root) return null;
|
|
310
|
+
const state = {
|
|
311
|
+
githubEmail: text(email),
|
|
312
|
+
branch: text(branch),
|
|
313
|
+
commitSha: sha(commitSha),
|
|
314
|
+
baseSha: sha(baseSha),
|
|
315
|
+
experimentSha: await resolveWorkingTreeSha(run, root.trim())
|
|
316
|
+
};
|
|
317
|
+
return isEmptyGitState(state) ? null : state;
|
|
318
|
+
}
|
|
319
|
+
async function resolveWorkingTreeSha(run, root) {
|
|
320
|
+
let indexPath;
|
|
321
|
+
let cleanup;
|
|
322
|
+
try {
|
|
323
|
+
const { mkdtemp, rm } = await import("fs/promises");
|
|
324
|
+
const { join } = await import("path");
|
|
325
|
+
const { tmpdir } = await import("os");
|
|
326
|
+
const dir = await mkdtemp(join(tmpdir(), "bitfab-git-"));
|
|
327
|
+
indexPath = join(dir, "index");
|
|
328
|
+
cleanup = () => rm(dir, {
|
|
329
|
+
recursive: true,
|
|
330
|
+
force: true
|
|
331
|
+
});
|
|
332
|
+
} catch {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
const env = { GIT_INDEX_FILE: indexPath };
|
|
337
|
+
if (await run(["read-tree", "HEAD"], env) === null) return null;
|
|
338
|
+
if (await run([
|
|
339
|
+
"add",
|
|
340
|
+
"-A",
|
|
341
|
+
"--",
|
|
342
|
+
root
|
|
343
|
+
], env) === null) return null;
|
|
344
|
+
return sha(await run(["write-tree"], env));
|
|
345
|
+
} catch {
|
|
346
|
+
return null;
|
|
347
|
+
} finally {
|
|
348
|
+
await cleanup().catch(() => {});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
function resolvedGitState() {
|
|
352
|
+
if (typeof process === "undefined" || process.env?.[DISABLE_ENV]) return Promise.resolve(null);
|
|
353
|
+
let cwd;
|
|
354
|
+
try {
|
|
355
|
+
cwd = process.cwd?.() ?? ".";
|
|
356
|
+
} catch {
|
|
357
|
+
return Promise.resolve(null);
|
|
358
|
+
}
|
|
359
|
+
return resolveGitState(cwd).catch(() => null);
|
|
360
|
+
}
|
|
361
|
+
//#endregion
|
|
362
|
+
//#region src/replayContext.ts
|
|
363
|
+
let replayContextStorage = null;
|
|
364
|
+
const REPLAY_CONTEXT_STORAGE_SYMBOL = Symbol.for("bitfab.replayContextStorage");
|
|
365
|
+
const replayContextReady = asyncStorageReady.then(() => {
|
|
366
|
+
const shared = globalThis;
|
|
367
|
+
const existing = shared[REPLAY_CONTEXT_STORAGE_SYMBOL];
|
|
368
|
+
if (existing) {
|
|
369
|
+
replayContextStorage = existing;
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const created = createAsyncLocalStorage();
|
|
373
|
+
if (created) {
|
|
374
|
+
shared[REPLAY_CONTEXT_STORAGE_SYMBOL] = created;
|
|
375
|
+
replayContextStorage = created;
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
function getReplayContext() {
|
|
379
|
+
return replayContextStorage?.getStore() ?? null;
|
|
380
|
+
}
|
|
381
|
+
function runWithReplayContext(ctx, fn) {
|
|
382
|
+
if (replayContextStorage) return replayContextStorage.run(ctx, fn);
|
|
383
|
+
return fn();
|
|
384
|
+
}
|
|
385
|
+
//#endregion
|
|
386
|
+
//#region src/payloadBudget.ts
|
|
387
|
+
const MAX_SPAN_CARRIER_BYTES = 28e5;
|
|
388
|
+
const MAX_COMPRESSIBLE_SPAN_CARRIER_BYTES = 78e5;
|
|
389
|
+
const textEncoder = typeof TextEncoder !== "undefined" ? new TextEncoder() : null;
|
|
390
|
+
function byteLength(value) {
|
|
391
|
+
return textEncoder ? textEncoder.encode(value).length : value.length;
|
|
392
|
+
}
|
|
393
|
+
function carrierByteLength(body) {
|
|
394
|
+
return carrierBytesOf(textEncoder ? textEncoder.encode(body) : null, body);
|
|
395
|
+
}
|
|
396
|
+
function carrierBytesOf(encoded, body) {
|
|
397
|
+
if (!encoded) return body.length + 2;
|
|
398
|
+
let extra = 2;
|
|
399
|
+
for (let i = 0; i < encoded.length; i++) {
|
|
400
|
+
const byte = encoded[i];
|
|
401
|
+
if (byte === 34 || byte === 92) extra += 1;
|
|
402
|
+
else if (byte < 32) extra += byte === 8 || byte === 9 || byte === 10 || byte === 12 || byte === 13 ? 1 : 5;
|
|
403
|
+
}
|
|
404
|
+
return encoded.length + extra;
|
|
405
|
+
}
|
|
406
|
+
const MAX_BYTES_PER_UNIT = 3;
|
|
407
|
+
function fitsCarrierBudget(body, maxBytes = MAX_SPAN_CARRIER_BYTES) {
|
|
408
|
+
const units = body.length;
|
|
409
|
+
if (units * MAX_BYTES_PER_UNIT + 2 <= maxBytes) return true;
|
|
410
|
+
if (units + 2 > maxBytes) return false;
|
|
411
|
+
return carrierByteLength(body) <= maxBytes;
|
|
412
|
+
}
|
|
413
|
+
const STRUCTURAL_SPAN_KEYS = /* @__PURE__ */ new Set([
|
|
414
|
+
"name",
|
|
415
|
+
"type",
|
|
416
|
+
"function_name",
|
|
417
|
+
"error_source"
|
|
418
|
+
]);
|
|
419
|
+
function asRecord(value) {
|
|
420
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
421
|
+
}
|
|
422
|
+
function cloneTrimmable(payload) {
|
|
423
|
+
const copy = { ...payload };
|
|
424
|
+
const containers = [];
|
|
425
|
+
const spanData = asRecord(copy.span_data);
|
|
426
|
+
if (spanData) {
|
|
427
|
+
const clone = { ...spanData };
|
|
428
|
+
copy.span_data = clone;
|
|
429
|
+
containers.push(clone);
|
|
430
|
+
}
|
|
431
|
+
const rawSpan = asRecord(copy.rawSpan);
|
|
432
|
+
const rawSpanData = rawSpan && asRecord(rawSpan.span_data);
|
|
433
|
+
if (rawSpan && rawSpanData) {
|
|
434
|
+
const clone = { ...rawSpanData };
|
|
435
|
+
copy.rawSpan = {
|
|
436
|
+
...rawSpan,
|
|
437
|
+
span_data: clone
|
|
438
|
+
};
|
|
439
|
+
containers.push(clone);
|
|
440
|
+
}
|
|
441
|
+
if (containers.length === 0) containers.push(copy);
|
|
442
|
+
return {
|
|
443
|
+
copy,
|
|
444
|
+
containers
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function collectCandidates(containers) {
|
|
448
|
+
const candidates = [];
|
|
449
|
+
for (const container of containers) for (const [key, value] of Object.entries(container)) {
|
|
450
|
+
if (STRUCTURAL_SPAN_KEYS.has(key) || value == null) continue;
|
|
451
|
+
let size;
|
|
452
|
+
try {
|
|
453
|
+
size = byteLength(JSON.stringify(value) ?? "");
|
|
454
|
+
} catch {
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
candidates.push({
|
|
458
|
+
container,
|
|
459
|
+
key,
|
|
460
|
+
size
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
return candidates.sort((a, b) => b.size - a.size);
|
|
464
|
+
}
|
|
465
|
+
function trimPayloadToBudget(payload, encode, maxBytes = MAX_SPAN_CARRIER_BYTES) {
|
|
466
|
+
const { copy, containers } = cloneTrimmable(payload);
|
|
467
|
+
const candidates = collectCandidates(containers);
|
|
468
|
+
if (candidates.length === 0) return;
|
|
469
|
+
const trimmed = [];
|
|
470
|
+
for (const candidate of candidates) {
|
|
471
|
+
candidate.container[candidate.key] = `<unserializable: too_large_${candidate.size}_bytes>`;
|
|
472
|
+
trimmed.push(candidate.key);
|
|
473
|
+
let body;
|
|
474
|
+
try {
|
|
475
|
+
body = encode(copy);
|
|
476
|
+
} catch {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (fitsCarrierBudget(body, maxBytes)) return {
|
|
480
|
+
value: copy,
|
|
481
|
+
trimmed
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
function markPayloadTrimmed(value, trimmed, maxBytes = MAX_SPAN_CARRIER_BYTES) {
|
|
486
|
+
value.errors = [...Array.isArray(value.errors) ? value.errors : [], {
|
|
487
|
+
source: "sdk",
|
|
488
|
+
step: "payload_budget",
|
|
489
|
+
error: `trimmed oversized field(s) to fit the ${maxBytes}-byte span carrier budget: ${[...new Set(trimmed)].join(", ")}`
|
|
490
|
+
}];
|
|
491
|
+
}
|
|
492
|
+
//#endregion
|
|
493
|
+
//#region src/serializePayload.ts
|
|
494
|
+
function serializePayloadBody(payload, maxCarrierBytes = MAX_SPAN_CARRIER_BYTES) {
|
|
495
|
+
return runWithCaptureSuppressed(() => encodeWithinBudget(payload, maxCarrierBytes));
|
|
496
|
+
}
|
|
497
|
+
function encodeWithinBudget(payload, maxCarrierBytes) {
|
|
498
|
+
const encoded = encodePayloadBody(payload);
|
|
499
|
+
if (fitsCarrierBudget(encoded.body, maxCarrierBytes)) return {
|
|
500
|
+
body: encoded.body,
|
|
501
|
+
dropped: encoded.dropped
|
|
502
|
+
};
|
|
503
|
+
return applyPayloadBudget(encoded, maxCarrierBytes);
|
|
504
|
+
}
|
|
505
|
+
function applyPayloadBudget(encoded, maxCarrierBytes) {
|
|
506
|
+
const result = encoded.value ? trimPayloadToBudget(encoded.value, (value) => encodePayloadBody(value).body, maxCarrierBytes) : void 0;
|
|
507
|
+
if (!result) return {
|
|
508
|
+
body: encoded.body,
|
|
509
|
+
dropped: encoded.dropped
|
|
510
|
+
};
|
|
511
|
+
warnOnce("payload:over-budget", `a span payload exceeded the ${maxCarrierBytes}-byte carrier budget; its largest field(s) (${[...new Set(result.trimmed)].join(", ")}) were replaced with placeholders so the span still ships. The span is incomplete and may not be replayable.`);
|
|
512
|
+
markPayloadTrimmed(result.value, result.trimmed, maxCarrierBytes);
|
|
513
|
+
return {
|
|
514
|
+
body: encodePayloadBody(result.value).body,
|
|
515
|
+
dropped: encoded.dropped
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
function encodePayloadBody(payload) {
|
|
519
|
+
try {
|
|
520
|
+
return {
|
|
521
|
+
body: JSON.stringify(payload),
|
|
522
|
+
dropped: [],
|
|
523
|
+
value: payload
|
|
524
|
+
};
|
|
525
|
+
} catch {
|
|
526
|
+
const dropped = [];
|
|
527
|
+
const sanitize = (value, seen) => {
|
|
528
|
+
const t = typeof value;
|
|
529
|
+
if (value === null || t === "string" || t === "number" || t === "boolean") return value;
|
|
530
|
+
if (t === "bigint") {
|
|
531
|
+
dropped.push("BigInt");
|
|
532
|
+
return "<unserializable: BigInt>";
|
|
533
|
+
}
|
|
534
|
+
if (t === "function") {
|
|
535
|
+
const name = value.name || "Function";
|
|
536
|
+
dropped.push(name);
|
|
537
|
+
return `<unserializable: ${name}>`;
|
|
538
|
+
}
|
|
539
|
+
if (t === "symbol") {
|
|
540
|
+
dropped.push("Symbol");
|
|
541
|
+
return "<unserializable: Symbol>";
|
|
542
|
+
}
|
|
543
|
+
if (t !== "object") return;
|
|
544
|
+
const obj = value;
|
|
545
|
+
const className = obj.constructor?.name || "object";
|
|
546
|
+
if (seen.has(obj)) {
|
|
547
|
+
dropped.push(className);
|
|
548
|
+
return `<cycle: ${className}>`;
|
|
549
|
+
}
|
|
550
|
+
seen.add(obj);
|
|
551
|
+
let result;
|
|
552
|
+
if (Array.isArray(obj)) result = obj.map((item) => sanitize(item, seen));
|
|
553
|
+
else if (typeof obj.toJSON === "function") try {
|
|
554
|
+
result = sanitize(obj.toJSON(), seen);
|
|
555
|
+
} catch {
|
|
556
|
+
dropped.push(className);
|
|
557
|
+
result = `<unserializable: ${className}>`;
|
|
558
|
+
}
|
|
559
|
+
else try {
|
|
560
|
+
const out = {};
|
|
561
|
+
for (const [k, v] of Object.entries(obj)) out[k] = sanitize(v, seen);
|
|
562
|
+
result = out;
|
|
563
|
+
} catch {
|
|
564
|
+
warnOnce("payload:field-getter-threw", "a value with a throwing getter/proxy could not be serialized into a span payload; it was replaced with a placeholder. The span still ships with its other fields intact.");
|
|
565
|
+
dropped.push(className);
|
|
566
|
+
result = `<unserializable: ${className}>`;
|
|
567
|
+
}
|
|
568
|
+
seen.delete(obj);
|
|
569
|
+
return result;
|
|
570
|
+
};
|
|
571
|
+
let sanitized;
|
|
572
|
+
try {
|
|
573
|
+
sanitized = sanitize(payload, /* @__PURE__ */ new WeakSet());
|
|
574
|
+
} catch (error) {
|
|
575
|
+
const marker = { error: `payload_serialize_failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
576
|
+
return {
|
|
577
|
+
body: JSON.stringify(marker),
|
|
578
|
+
dropped,
|
|
579
|
+
value: marker
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
const isRecord = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
|
|
583
|
+
if (dropped.length > 0 && isRecord) {
|
|
584
|
+
const obj = sanitized;
|
|
585
|
+
obj.errors = [...Array.isArray(obj.errors) ? obj.errors : [], {
|
|
586
|
+
source: "sdk",
|
|
587
|
+
step: "json_serialize",
|
|
588
|
+
error: `stubbed non-serializable value(s): ${[...new Set(dropped)].join(", ")}`
|
|
589
|
+
}];
|
|
590
|
+
}
|
|
591
|
+
return {
|
|
592
|
+
body: JSON.stringify(sanitized),
|
|
593
|
+
dropped,
|
|
594
|
+
value: isRecord ? sanitized : void 0
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
//#endregion
|
|
599
|
+
//#region src/policyRefresh.ts
|
|
600
|
+
var PolicyRefresh = class {
|
|
601
|
+
constructor() {
|
|
602
|
+
this.refreshAfter = 0;
|
|
603
|
+
}
|
|
604
|
+
due() {
|
|
605
|
+
return this.inFlight === void 0 && Date.now() >= this.refreshAfter;
|
|
606
|
+
}
|
|
607
|
+
hold(durationMs) {
|
|
608
|
+
this.refreshAfter = Date.now() + durationMs;
|
|
609
|
+
}
|
|
610
|
+
releaseHold() {
|
|
611
|
+
this.refreshAfter = 0;
|
|
612
|
+
}
|
|
613
|
+
run(read, onLoaded, onFailed) {
|
|
614
|
+
if (!this.due()) return;
|
|
615
|
+
let request;
|
|
616
|
+
try {
|
|
617
|
+
request = read().then(onLoaded).catch(onFailed).finally(() => {
|
|
618
|
+
this.inFlight = void 0;
|
|
619
|
+
});
|
|
620
|
+
} catch (error) {
|
|
621
|
+
onFailed(error);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
this.inFlight = request;
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region src/spanOrigin.ts
|
|
629
|
+
const SPAN_ORIGIN_NAME = "bitfab.sdk.typescript";
|
|
630
|
+
const SPAN_INSTRUMENTATIONS = [
|
|
631
|
+
"span",
|
|
632
|
+
"trace",
|
|
633
|
+
"openai-agents",
|
|
634
|
+
"langgraph",
|
|
635
|
+
"claude-agent-sdk",
|
|
636
|
+
"vercel-ai",
|
|
637
|
+
"rivet"
|
|
638
|
+
];
|
|
639
|
+
const FRAMEWORK_INSTRUMENTATION_SET = /* @__PURE__ */ new Set([
|
|
640
|
+
"openai-agents",
|
|
641
|
+
"langgraph",
|
|
642
|
+
"claude-agent-sdk",
|
|
643
|
+
"vercel-ai",
|
|
644
|
+
"rivet"
|
|
645
|
+
]);
|
|
646
|
+
function isFrameworkInstrumentation(value) {
|
|
647
|
+
return typeof value === "string" && FRAMEWORK_INSTRUMENTATION_SET.has(value);
|
|
648
|
+
}
|
|
649
|
+
function makeSpanOrigin(instrumentation) {
|
|
650
|
+
return {
|
|
651
|
+
name: SPAN_ORIGIN_NAME,
|
|
652
|
+
version: __version__,
|
|
653
|
+
instrumentation: { name: instrumentation }
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
function isRecord$1(value) {
|
|
657
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
658
|
+
}
|
|
659
|
+
function spanOriginOf(payload) {
|
|
660
|
+
const rawSpan = payload.rawSpan;
|
|
661
|
+
if (!isRecord$1(rawSpan)) return;
|
|
662
|
+
const origin = rawSpan.span_origin;
|
|
663
|
+
if (!isRecord$1(origin) || !isRecord$1(origin.instrumentation)) return;
|
|
664
|
+
const { name, version } = origin;
|
|
665
|
+
const instrumentation = origin.instrumentation.name;
|
|
666
|
+
if (typeof name !== "string" || typeof version !== "string" || typeof instrumentation !== "string" || !SPAN_INSTRUMENTATIONS.includes(instrumentation)) return;
|
|
667
|
+
return {
|
|
668
|
+
name,
|
|
669
|
+
version,
|
|
670
|
+
instrumentation: { name: instrumentation }
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
function spanInstrumentationOf(payload) {
|
|
674
|
+
return spanOriginOf(payload)?.instrumentation.name;
|
|
675
|
+
}
|
|
676
|
+
function recordedByFramework(payload) {
|
|
677
|
+
return isFrameworkInstrumentation(spanInstrumentationOf(payload));
|
|
678
|
+
}
|
|
679
|
+
//#endregion
|
|
680
|
+
//#region src/simulationPlan.ts
|
|
681
|
+
const SIMULATION_PLAN_REFRESH_MS = 6e4;
|
|
682
|
+
const SIMULATION_PLAN_RETRY_MS = 1e4;
|
|
683
|
+
const SIMULATION_PLAN_READ_TIMEOUT_MS = 5e3;
|
|
684
|
+
const SIMULATION_PLAN_MAX_HELD = 1e3;
|
|
685
|
+
const DISABLE_SIMULATION_PLAN_ENV = "BITFAB_DISABLE_SIM_PLAN";
|
|
686
|
+
const NO_API_KEY_FOR_SIMULATION_PLAN = "no API key is set";
|
|
687
|
+
const ROOT_TRACE_FUNCTION_KEY_FIELD = "rootTraceFunctionKey";
|
|
688
|
+
const DECLARED_NODE_FIELD = "declaredNode";
|
|
689
|
+
const CONTENT_OFF_KEY = "content_off_by_simulation_plan";
|
|
690
|
+
const CONTENT_KEYS = [
|
|
691
|
+
"input",
|
|
692
|
+
"input_meta",
|
|
693
|
+
"output",
|
|
694
|
+
"output_meta",
|
|
695
|
+
"replay_recording",
|
|
696
|
+
"prompt"
|
|
697
|
+
];
|
|
698
|
+
function planWaitSliceMs(timeoutMs) {
|
|
699
|
+
return Math.min(SIMULATION_PLAN_READ_TIMEOUT_MS, Math.max(timeoutMs, 0) / 2);
|
|
700
|
+
}
|
|
701
|
+
function parseSimulationPlan(body) {
|
|
702
|
+
if (typeof body !== "object" || body === null) return null;
|
|
703
|
+
const nodes = body.nodes;
|
|
704
|
+
if (!Array.isArray(nodes)) return null;
|
|
705
|
+
const contentOff = /* @__PURE__ */ new Map();
|
|
706
|
+
for (const node of nodes) {
|
|
707
|
+
if (typeof node !== "object" || node === null) continue;
|
|
708
|
+
const { traceFunctionKey, name, captureContent } = node;
|
|
709
|
+
if (typeof traceFunctionKey !== "string" || typeof name !== "string" || typeof captureContent !== "boolean") continue;
|
|
710
|
+
if (captureContent) continue;
|
|
711
|
+
const names = contentOff.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
|
|
712
|
+
names.add(name);
|
|
713
|
+
contentOff.set(traceFunctionKey, names);
|
|
714
|
+
}
|
|
715
|
+
return contentOff;
|
|
716
|
+
}
|
|
717
|
+
function traceIdOf(payload) {
|
|
718
|
+
const traceId = payload.traceId;
|
|
719
|
+
if (typeof traceId === "string") return traceId;
|
|
720
|
+
const id = payload.id;
|
|
721
|
+
return typeof id === "string" ? id : void 0;
|
|
722
|
+
}
|
|
723
|
+
function isRecord(value) {
|
|
724
|
+
return typeof value === "object" && value !== null;
|
|
725
|
+
}
|
|
726
|
+
function rawSpanOf(payload) {
|
|
727
|
+
return isRecord(payload.rawSpan) ? payload.rawSpan : void 0;
|
|
728
|
+
}
|
|
729
|
+
function spanDataOf(payload) {
|
|
730
|
+
const spanData = rawSpanOf(payload)?.span_data;
|
|
731
|
+
return isRecord(spanData) ? spanData : void 0;
|
|
732
|
+
}
|
|
733
|
+
function spanNameOf(payload) {
|
|
734
|
+
const name = spanDataOf(payload)?.name;
|
|
735
|
+
return typeof name === "string" ? name : void 0;
|
|
736
|
+
}
|
|
737
|
+
function stripContent(payload) {
|
|
738
|
+
const rawSpan = rawSpanOf(payload);
|
|
739
|
+
const spanData = spanDataOf(payload);
|
|
740
|
+
if (rawSpan === void 0 || spanData === void 0) return payload;
|
|
741
|
+
const kept = { ...spanData };
|
|
742
|
+
for (const key of CONTENT_KEYS) delete kept[key];
|
|
743
|
+
kept[CONTENT_OFF_KEY] = true;
|
|
744
|
+
return {
|
|
745
|
+
...payload,
|
|
746
|
+
rawSpan: {
|
|
747
|
+
...rawSpan,
|
|
748
|
+
span_data: kept
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
function simulationPlanEnvDisabled() {
|
|
753
|
+
const value = readEnv(DISABLE_SIMULATION_PLAN_ENV);
|
|
754
|
+
return typeof value === "string" && value.trim() !== "";
|
|
755
|
+
}
|
|
756
|
+
function missingSimulationPlanEndpoint(error) {
|
|
757
|
+
return error instanceof BitfabError && error.status === 404;
|
|
758
|
+
}
|
|
759
|
+
function isTraceRootSpan(payload) {
|
|
760
|
+
const parentId = rawSpanOf(payload)?.parent_id;
|
|
761
|
+
return parentId === void 0 || parentId === null;
|
|
762
|
+
}
|
|
763
|
+
function declaredInCode(payload) {
|
|
764
|
+
return payload[DECLARED_NODE_FIELD] === true;
|
|
765
|
+
}
|
|
766
|
+
function recordedError(payload) {
|
|
767
|
+
const error = spanDataOf(payload)?.error;
|
|
768
|
+
return error !== void 0 && error !== null;
|
|
769
|
+
}
|
|
770
|
+
var SimulationPlan = class {
|
|
771
|
+
constructor(source, enabled = true) {
|
|
772
|
+
this.source = source;
|
|
773
|
+
this.enabled = enabled;
|
|
774
|
+
this.policyRefresh = new PolicyRefresh();
|
|
775
|
+
this.firstReadOver = false;
|
|
776
|
+
this.rootWaitOver = false;
|
|
777
|
+
this.held = [];
|
|
778
|
+
this.stopped = false;
|
|
779
|
+
this.loaded = new Promise((resolve) => {
|
|
780
|
+
this.resolveLoaded = resolve;
|
|
781
|
+
});
|
|
782
|
+
this.firstReadEnded = new Promise((resolve) => {
|
|
783
|
+
this.resolveFirstReadEnded = resolve;
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
disabled() {
|
|
787
|
+
return !this.enabled || simulationPlanEnvDisabled();
|
|
788
|
+
}
|
|
789
|
+
refresh() {
|
|
790
|
+
if (this.stopped || this.disabled()) return;
|
|
791
|
+
this.policyRefresh.run(() => this.source.getSimulationPlan(), (body) => {
|
|
792
|
+
const parsed = parseSimulationPlan(body);
|
|
793
|
+
if (parsed === null) this.scheduleRetry("sim-plan-unreadable", "the sim plan response was not understood");
|
|
794
|
+
else this.markLoaded(parsed);
|
|
795
|
+
this.endFirstRead();
|
|
796
|
+
}, (error) => {
|
|
797
|
+
if (missingSimulationPlanEndpoint(error)) this.markLoaded(/* @__PURE__ */ new Map());
|
|
798
|
+
else this.scheduleRetry("sim-plan-unavailable", `could not read the sim plan: ${error instanceof Error ? error.message : String(error)}`);
|
|
799
|
+
this.endFirstRead();
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
markLoaded(parsed) {
|
|
803
|
+
if (this.stopped) return;
|
|
804
|
+
this.contentOffByKey = parsed;
|
|
805
|
+
this.policyRefresh.hold(SIMULATION_PLAN_REFRESH_MS);
|
|
806
|
+
this.resolveLoaded?.();
|
|
807
|
+
this.resolveLoaded = void 0;
|
|
808
|
+
}
|
|
809
|
+
scheduleRetry(warnKey, reason) {
|
|
810
|
+
if (this.stopped) return;
|
|
811
|
+
this.policyRefresh.hold(SIMULATION_PLAN_RETRY_MS);
|
|
812
|
+
if (this.contentOffByKey !== void 0) return;
|
|
813
|
+
warnOnce(warnKey, `${reason}. Until a read succeeds, spans are sent without their inputs and outputs, except each trace's root span and spans recorded by a framework integration. The read is retried on the next span after ${SIMULATION_PLAN_RETRY_MS / 1e3}s.`);
|
|
814
|
+
}
|
|
815
|
+
endFirstRead() {
|
|
816
|
+
this.endRootWait();
|
|
817
|
+
if (!this.firstReadOver) {
|
|
818
|
+
this.firstReadOver = true;
|
|
819
|
+
this.resolveFirstReadEnded?.();
|
|
820
|
+
this.resolveFirstReadEnded = void 0;
|
|
821
|
+
}
|
|
822
|
+
this.releaseHeld();
|
|
823
|
+
}
|
|
824
|
+
endRootWait() {
|
|
825
|
+
this.rootWaitOver = true;
|
|
826
|
+
if (this.rootWaitTimer !== void 0) {
|
|
827
|
+
clearTimeout(this.rootWaitTimer);
|
|
828
|
+
this.rootWaitTimer = void 0;
|
|
829
|
+
}
|
|
830
|
+
this.resolveRootWait?.();
|
|
831
|
+
this.resolveRootWait = void 0;
|
|
832
|
+
}
|
|
833
|
+
waitForFirstRead() {
|
|
834
|
+
this.refresh();
|
|
835
|
+
if (this.rootWaitOver || this.disabled() || !this.holdingForFirstRead()) return;
|
|
836
|
+
if (this.rootWait === void 0) {
|
|
837
|
+
this.rootWait = new Promise((resolve) => {
|
|
838
|
+
this.resolveRootWait = resolve;
|
|
839
|
+
});
|
|
840
|
+
this.rootWaitTimer = setTimeout(() => this.endRootWait(), SIMULATION_PLAN_READ_TIMEOUT_MS);
|
|
841
|
+
}
|
|
842
|
+
return this.rootWait;
|
|
843
|
+
}
|
|
844
|
+
holdingForFirstRead() {
|
|
845
|
+
return this.contentOffByKey === void 0 && !this.firstReadOver && !this.stopped;
|
|
846
|
+
}
|
|
847
|
+
unavailableNow() {
|
|
848
|
+
return !this.disabled() && this.contentOffByKey === void 0 && this.firstReadOver;
|
|
849
|
+
}
|
|
850
|
+
firstLoad() {
|
|
851
|
+
if (this.contentOffByKey !== void 0 || this.stopped || this.disabled()) return;
|
|
852
|
+
return this.loaded;
|
|
853
|
+
}
|
|
854
|
+
send(payload, traceFunctionKey, submit, drop) {
|
|
855
|
+
this.refresh();
|
|
856
|
+
if (this.disabled() || traceFunctionKey === void 0 || spanNameOf(payload) === void 0 || recordedByFramework(payload)) {
|
|
857
|
+
submit(payload);
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
const entry = {
|
|
861
|
+
payload,
|
|
862
|
+
traceFunctionKey,
|
|
863
|
+
submit,
|
|
864
|
+
drop
|
|
865
|
+
};
|
|
866
|
+
if (this.holdingForFirstRead()) {
|
|
867
|
+
this.hold(entry);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
this.submitEntry(entry);
|
|
871
|
+
}
|
|
872
|
+
sendTrace(payload, submit) {
|
|
873
|
+
this.refresh();
|
|
874
|
+
if (this.disabled() || !this.holdingForFirstRead() || !this.holdsSpanOfTrace(traceIdOf(payload))) {
|
|
875
|
+
submit(payload);
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
this.hold({
|
|
879
|
+
payload,
|
|
880
|
+
traceFunctionKey: void 0,
|
|
881
|
+
submit
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
holdsSpanOfTrace(traceId) {
|
|
885
|
+
if (traceId === void 0) return false;
|
|
886
|
+
return this.held.some((entry) => entry.traceFunctionKey !== void 0 && traceIdOf(entry.payload) === traceId);
|
|
887
|
+
}
|
|
888
|
+
hold(entry) {
|
|
889
|
+
this.held.push(entry);
|
|
890
|
+
let overflowed = false;
|
|
891
|
+
while (this.held.length > SIMULATION_PLAN_MAX_HELD) {
|
|
892
|
+
const oldest = this.held.shift();
|
|
893
|
+
this.submitEntry(oldest);
|
|
894
|
+
overflowed = true;
|
|
895
|
+
}
|
|
896
|
+
if (overflowed) warnOnce("sim-plan-held-overflow", `more than ${SIMULATION_PLAN_MAX_HELD} records were waiting for the sim plan, so the oldest were sent without their inputs and outputs.`);
|
|
897
|
+
}
|
|
898
|
+
payloadToSend(entry) {
|
|
899
|
+
if (entry.traceFunctionKey === void 0 || declaredInCode(entry.payload)) return entry.payload;
|
|
900
|
+
if (this.contentOffByKey !== void 0) return this.apply(entry.payload, entry.traceFunctionKey);
|
|
901
|
+
if (recordedByFramework(entry.payload) || isTraceRootSpan(entry.payload)) return entry.payload;
|
|
902
|
+
return stripContent(entry.payload);
|
|
903
|
+
}
|
|
904
|
+
submitEntry(entry) {
|
|
905
|
+
if (entry.traceFunctionKey !== void 0 && this.skipsSpan(entry.payload, entry.traceFunctionKey)) {
|
|
906
|
+
entry.drop?.();
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
try {
|
|
910
|
+
entry.submit(this.payloadToSend(entry));
|
|
911
|
+
} catch (error) {
|
|
912
|
+
entry.drop?.();
|
|
913
|
+
warnOnce("sim-plan-held-span-dropped", `a span held for the sim plan was dropped when released: ${error instanceof Error ? error.message : String(error)}`);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
releaseHeld() {
|
|
917
|
+
const held = this.held;
|
|
918
|
+
this.held = [];
|
|
919
|
+
for (const entry of held) this.submitEntry(entry);
|
|
920
|
+
}
|
|
921
|
+
releaseHeldWithoutPlan() {
|
|
922
|
+
if (this.held.length === 0) return;
|
|
923
|
+
if (this.contentOffByKey === void 0) warnOnce("sim-plan-not-loaded-at-release", `${this.held.length} record(s) were sent without their inputs and outputs because the sim plan had not loaded`);
|
|
924
|
+
this.releaseHeld();
|
|
925
|
+
}
|
|
926
|
+
async release(timeoutMs) {
|
|
927
|
+
this.refresh();
|
|
928
|
+
if (this.held.length > 0) await this.waitForFirstReadEnd(timeoutMs);
|
|
929
|
+
this.releaseHeldWithoutPlan();
|
|
930
|
+
}
|
|
931
|
+
waitForFirstReadEnd(timeoutMs) {
|
|
932
|
+
if (this.firstReadOver) return Promise.resolve();
|
|
933
|
+
return new Promise((resolve) => {
|
|
934
|
+
const timer = setTimeout(resolve, Math.max(timeoutMs, 0));
|
|
935
|
+
this.firstReadEnded.then(() => {
|
|
936
|
+
clearTimeout(timer);
|
|
937
|
+
resolve();
|
|
938
|
+
});
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
stop() {
|
|
942
|
+
if (this.stopped) return;
|
|
943
|
+
this.releaseHeldWithoutPlan();
|
|
944
|
+
this.stopped = true;
|
|
945
|
+
this.endFirstRead();
|
|
946
|
+
}
|
|
947
|
+
contentOff(traceFunctionKey, spanName) {
|
|
948
|
+
return this.contentOffByKey?.get(traceFunctionKey)?.has(spanName) === true;
|
|
949
|
+
}
|
|
950
|
+
contentOffNow(traceFunctionKey, spanName) {
|
|
951
|
+
return !this.stopped && !this.disabled() && this.contentOff(traceFunctionKey, spanName);
|
|
952
|
+
}
|
|
953
|
+
skipsSpan(payload, traceFunctionKey) {
|
|
954
|
+
const name = spanNameOf(payload);
|
|
955
|
+
return name !== void 0 && this.contentOff(traceFunctionKey, name) && !isTraceRootSpan(payload) && !declaredInCode(payload) && spanInstrumentationOf(payload) !== void 0 && !recordedByFramework(payload) && !recordedError(payload);
|
|
956
|
+
}
|
|
957
|
+
apply(payload, traceFunctionKey) {
|
|
958
|
+
if (recordedByFramework(payload) || declaredInCode(payload)) return payload;
|
|
959
|
+
const name = spanNameOf(payload);
|
|
960
|
+
if (name === void 0 || !this.contentOff(traceFunctionKey, name)) return payload;
|
|
961
|
+
return stripContent(payload);
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
const activeRecords = /* @__PURE__ */ new Map();
|
|
965
|
+
const completedRecords = /* @__PURE__ */ new Map();
|
|
966
|
+
function findRecord(traceId) {
|
|
967
|
+
return activeRecords.get(traceId) ?? completedRecords.get(traceId);
|
|
968
|
+
}
|
|
969
|
+
function recordCallerTraceMetadata(traceId, metadata) {
|
|
970
|
+
if (typeof traceId !== "string" || traceId === "") return;
|
|
971
|
+
if (typeof metadata !== "object" || metadata === null) return;
|
|
972
|
+
if (Object.keys(metadata).length === 0) return;
|
|
973
|
+
const existing = findRecord(traceId);
|
|
974
|
+
if (existing) {
|
|
975
|
+
Object.assign(existing.caller, metadata);
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
activeRecords.set(traceId, {
|
|
979
|
+
caller: { ...metadata },
|
|
980
|
+
derived: {},
|
|
981
|
+
warnedKeys: /* @__PURE__ */ new Set()
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
function callerTraceMetadata(traceId) {
|
|
985
|
+
const record = findRecord(traceId);
|
|
986
|
+
if (!record || Object.keys(record.caller).length === 0) return;
|
|
987
|
+
return { ...record.caller };
|
|
988
|
+
}
|
|
989
|
+
function retireTraceMetadata(traceId) {
|
|
990
|
+
const record = activeRecords.get(traceId);
|
|
991
|
+
if (!record) return;
|
|
992
|
+
activeRecords.delete(traceId);
|
|
993
|
+
completedRecords.set(traceId, record);
|
|
994
|
+
while (completedRecords.size > 128) {
|
|
995
|
+
const oldest = completedRecords.keys().next();
|
|
996
|
+
if (oldest.done) return;
|
|
997
|
+
completedRecords.delete(oldest.value);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
function warnAboutShadowedKeys(traceId, record) {
|
|
1001
|
+
const shadowed = Object.keys(record.derived).filter((key) => key in record.caller && record.caller[key] !== record.derived[key] && !record.warnedKeys.has(key)).sort();
|
|
1002
|
+
if (shadowed.length === 0) return;
|
|
1003
|
+
for (const key of shadowed) record.warnedKeys.add(key);
|
|
1004
|
+
warn(`trace metadata key(s) ${shadowed.join(", ")} on trace ${traceId} were set both by the caller and by an integration's own trace export; the caller's value is the one kept on the trace.`);
|
|
1005
|
+
}
|
|
1006
|
+
function mergeCallerMetadataIntoTracePayload(payload) {
|
|
1007
|
+
const externalTrace = payload.externalTrace;
|
|
1008
|
+
if (typeof externalTrace !== "object" || externalTrace === null) return payload;
|
|
1009
|
+
const external = externalTrace;
|
|
1010
|
+
const traceId = typeof payload.id === "string" && payload.id !== "" ? payload.id : external.id;
|
|
1011
|
+
if (typeof traceId !== "string" || traceId === "") return payload;
|
|
1012
|
+
const record = findRecord(traceId);
|
|
1013
|
+
if (!record || Object.keys(record.caller).length === 0) return payload;
|
|
1014
|
+
const exported = external.metadata;
|
|
1015
|
+
if (typeof exported === "object" && exported !== null) Object.assign(record.derived, exported);
|
|
1016
|
+
warnAboutShadowedKeys(traceId, record);
|
|
1017
|
+
return {
|
|
1018
|
+
...payload,
|
|
1019
|
+
externalTrace: {
|
|
1020
|
+
...external,
|
|
1021
|
+
metadata: {
|
|
1022
|
+
...record.derived,
|
|
1023
|
+
...record.caller
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
//#endregion
|
|
1029
|
+
//#region src/transportTypes.ts
|
|
1030
|
+
var DeliveryError = class extends Error {
|
|
1031
|
+
constructor(message, options = {}) {
|
|
1032
|
+
super(message);
|
|
1033
|
+
this.name = "DeliveryError";
|
|
1034
|
+
this.retryable = options.retryable ?? false;
|
|
1035
|
+
this.oversized = options.oversized ?? false;
|
|
1036
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
//#endregion
|
|
1040
|
+
//#region src/unrefTimer.ts
|
|
1041
|
+
function unrefTimer(timer) {
|
|
1042
|
+
const handle = timer;
|
|
1043
|
+
if (typeof handle.unref === "function") handle.unref();
|
|
1044
|
+
}
|
|
1045
|
+
//#endregion
|
|
1046
|
+
//#region src/otel.ts
|
|
1047
|
+
const OPERATION_ATTRIBUTE = "bitfab.operation";
|
|
1048
|
+
const PAYLOAD_ATTRIBUTE = "bitfab.payload";
|
|
1049
|
+
const MAX_EXPORT_REQUEST_BYTES = 3e6;
|
|
1050
|
+
const MAX_DECOMPRESSED_REQUEST_BYTES = 8e6;
|
|
1051
|
+
const MAX_REQUEST_BYTES_ENV = "BITFAB_OTEL_MAX_REQUEST_BYTES";
|
|
1052
|
+
const EXPORT_CONCURRENCY_ENV = "BITFAB_OTEL_EXPORT_CONCURRENCY";
|
|
1053
|
+
const MAX_QUEUE_SIZE = 16384;
|
|
1054
|
+
const DIRECT_MAX_EXPORT_BATCH_SIZE = 512;
|
|
1055
|
+
const DIRECT_MAX_REQUEST_BATCH_SIZE = 256;
|
|
1056
|
+
const DEFAULT_EXPORT_CONCURRENCY = 32;
|
|
1057
|
+
const MAX_EXPORT_CONCURRENCY = 64;
|
|
1058
|
+
const SCHEDULE_DELAY_MILLIS = 5e3;
|
|
1059
|
+
const EXPORT_TIMEOUT_MILLIS = 3e4;
|
|
1060
|
+
const RETRY_BASE_DELAY_MILLIS = 100;
|
|
1061
|
+
const RETRY_BACKOFF_CEILING_MILLIS = 5e3;
|
|
1062
|
+
const MAX_SEND_ATTEMPTS = 3;
|
|
1063
|
+
const DEFAULT_LIFECYCLE_TIMEOUT_MS$1 = 3e4;
|
|
1064
|
+
const liveTransports = /* @__PURE__ */ new Set();
|
|
1065
|
+
const carrierRefs = /* @__PURE__ */ new WeakMap();
|
|
1066
|
+
function readBoundedIntEnv(name, max, fallback, warnKey) {
|
|
1067
|
+
const raw = readEnv(name);
|
|
1068
|
+
if (raw === void 0) return fallback;
|
|
1069
|
+
const value = Number(raw);
|
|
1070
|
+
if (Number.isInteger(value) && value > 0 && value <= max) return value;
|
|
1071
|
+
warnOnce(warnKey, `${name} must be a positive integer no greater than ${max}; using ${fallback}`);
|
|
1072
|
+
return fallback;
|
|
1073
|
+
}
|
|
1074
|
+
function logError(message, error) {
|
|
1075
|
+
try {
|
|
1076
|
+
if (error === void 0) console.error(`[bitfab] ${message}`);
|
|
1077
|
+
else console.error(`[bitfab] ${message}`, error);
|
|
1078
|
+
} catch {}
|
|
1079
|
+
}
|
|
1080
|
+
function otlpValue(value) {
|
|
1081
|
+
if (typeof value === "boolean") return { boolValue: value };
|
|
1082
|
+
if (typeof value === "number") return Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value };
|
|
1083
|
+
if (typeof value === "string") return { stringValue: value };
|
|
1084
|
+
if (Array.isArray(value)) return { arrayValue: { values: value.map(otlpValue) } };
|
|
1085
|
+
return { stringValue: String(value) };
|
|
1086
|
+
}
|
|
1087
|
+
function otlpAttributes(attributes) {
|
|
1088
|
+
if (!attributes) return [];
|
|
1089
|
+
return Object.entries(attributes).filter(([, value]) => value !== void 0).map(([key, value]) => ({
|
|
1090
|
+
key,
|
|
1091
|
+
value: otlpValue(value)
|
|
1092
|
+
}));
|
|
1093
|
+
}
|
|
1094
|
+
function hrTimeToNanoString(time) {
|
|
1095
|
+
if (!time) return "0";
|
|
1096
|
+
return `${time[0]}${String(time[1]).padStart(9, "0")}`;
|
|
1097
|
+
}
|
|
1098
|
+
function spanToOtlp(span) {
|
|
1099
|
+
const spanContext = span.spanContext();
|
|
1100
|
+
const result = {
|
|
1101
|
+
traceId: spanContext.traceId,
|
|
1102
|
+
spanId: spanContext.spanId,
|
|
1103
|
+
name: span.name,
|
|
1104
|
+
kind: span.kind + 1,
|
|
1105
|
+
startTimeUnixNano: hrTimeToNanoString(span.startTime),
|
|
1106
|
+
endTimeUnixNano: hrTimeToNanoString(span.endTime),
|
|
1107
|
+
attributes: otlpAttributes(span.attributes),
|
|
1108
|
+
droppedAttributesCount: span.droppedAttributesCount,
|
|
1109
|
+
droppedEventsCount: span.droppedEventsCount,
|
|
1110
|
+
droppedLinksCount: span.droppedLinksCount,
|
|
1111
|
+
status: {
|
|
1112
|
+
code: span.status.code,
|
|
1113
|
+
...span.status.message ? { message: span.status.message } : {}
|
|
1114
|
+
},
|
|
1115
|
+
flags: spanContext.traceFlags
|
|
1116
|
+
};
|
|
1117
|
+
const parentSpanId = span.parentSpanContext?.spanId;
|
|
1118
|
+
if (parentSpanId) result.parentSpanId = parentSpanId;
|
|
1119
|
+
if (spanContext.traceState) result.traceState = spanContext.traceState.serialize();
|
|
1120
|
+
return result;
|
|
1121
|
+
}
|
|
1122
|
+
const SPAN_SEPARATOR_BYTES = 1;
|
|
1123
|
+
function encodeSpan(span) {
|
|
1124
|
+
const json = JSON.stringify(spanToOtlp(span));
|
|
1125
|
+
return {
|
|
1126
|
+
json,
|
|
1127
|
+
size: byteLength(json),
|
|
1128
|
+
ref: carrierRefs.get(span)
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
function trimEncodedSpan(span) {
|
|
1132
|
+
try {
|
|
1133
|
+
const carrier = JSON.parse(span.json);
|
|
1134
|
+
const attribute = carrier.attributes?.find((entry) => entry.key === PAYLOAD_ATTRIBUTE);
|
|
1135
|
+
const payloadBody = attribute?.value?.stringValue;
|
|
1136
|
+
if (!attribute?.value || payloadBody === void 0) return;
|
|
1137
|
+
const payload = JSON.parse(payloadBody);
|
|
1138
|
+
attribute.value.stringValue = serializePayloadBody(payload, MAX_SPAN_CARRIER_BYTES).body;
|
|
1139
|
+
const json = JSON.stringify(carrier);
|
|
1140
|
+
return {
|
|
1141
|
+
json,
|
|
1142
|
+
size: byteLength(json)
|
|
1143
|
+
};
|
|
1144
|
+
} catch {
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
async function prepareRequest(body) {
|
|
1149
|
+
const prepared = encodeRequestBody(body);
|
|
1150
|
+
return prepared instanceof Promise ? await prepared : prepared;
|
|
1151
|
+
}
|
|
1152
|
+
function requestEnvelope(first) {
|
|
1153
|
+
const scope = first.instrumentationScope;
|
|
1154
|
+
const head = `{"resourceSpans":[{"resource":${JSON.stringify({ attributes: otlpAttributes(first.resource.attributes) })},"scopeSpans":[{"scope":${JSON.stringify({
|
|
1155
|
+
name: scope.name,
|
|
1156
|
+
version: scope.version ?? ""
|
|
1157
|
+
})},"spans":[`;
|
|
1158
|
+
const tail = "]}]}]}";
|
|
1159
|
+
return {
|
|
1160
|
+
head,
|
|
1161
|
+
tail,
|
|
1162
|
+
size: byteLength(head) + byteLength(tail)
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
function encodeRequest(envelope, spans) {
|
|
1166
|
+
return envelope.head + spans.map((span) => span.json).join(",") + envelope.tail;
|
|
1167
|
+
}
|
|
1168
|
+
function delay(ms) {
|
|
1169
|
+
return new Promise((resolve) => {
|
|
1170
|
+
unrefTimer(setTimeout(resolve, ms));
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
async function withDeadline(work, timeoutMs) {
|
|
1174
|
+
let timer;
|
|
1175
|
+
try {
|
|
1176
|
+
return await Promise.race([work, new Promise((resolve) => {
|
|
1177
|
+
timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs));
|
|
1178
|
+
unrefTimer(timer);
|
|
1179
|
+
})]);
|
|
1180
|
+
} finally {
|
|
1181
|
+
if (timer) clearTimeout(timer);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
async function mapWithConcurrency(items, limit, task) {
|
|
1185
|
+
const results = new Array(items.length);
|
|
1186
|
+
let next = 0;
|
|
1187
|
+
const workers = Array.from({ length: Math.min(Math.max(limit, 1), items.length) }, async () => {
|
|
1188
|
+
while (next < items.length) {
|
|
1189
|
+
const index = next;
|
|
1190
|
+
next += 1;
|
|
1191
|
+
results[index] = await task(items[index]);
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
await Promise.all(workers);
|
|
1195
|
+
return results;
|
|
1196
|
+
}
|
|
1197
|
+
function isRetryable(error) {
|
|
1198
|
+
return error instanceof DeliveryError && error.retryable;
|
|
1199
|
+
}
|
|
1200
|
+
function isOversized(error) {
|
|
1201
|
+
return error instanceof DeliveryError && error.oversized;
|
|
1202
|
+
}
|
|
1203
|
+
function retryWaitMillis(error, attempt, remainingMillis) {
|
|
1204
|
+
const requested = error instanceof DeliveryError ? error.retryAfterMs : void 0;
|
|
1205
|
+
const affordable = remainingMillis / 2;
|
|
1206
|
+
if (requested !== void 0) return requested < affordable ? requested : null;
|
|
1207
|
+
const backoff = Math.min(RETRY_BASE_DELAY_MILLIS * 2 ** attempt, RETRY_BACKOFF_CEILING_MILLIS);
|
|
1208
|
+
const jittered = backoff / 2 + Math.random() * (backoff / 2);
|
|
1209
|
+
return jittered < affordable ? jittered : null;
|
|
1210
|
+
}
|
|
1211
|
+
var BitfabSpanExporter = class {
|
|
1212
|
+
constructor(directSender, maxRequestBytes, maxRequestBatchSize, exportConcurrency, onDelivered, exportTimeoutMillis = EXPORT_TIMEOUT_MILLIS) {
|
|
1213
|
+
this.directSender = directSender;
|
|
1214
|
+
this.maxRequestBytes = maxRequestBytes;
|
|
1215
|
+
this.maxRequestBatchSize = maxRequestBatchSize;
|
|
1216
|
+
this.exportConcurrency = exportConcurrency;
|
|
1217
|
+
this.onDelivered = onDelivered;
|
|
1218
|
+
this.exportTimeoutMillis = exportTimeoutMillis;
|
|
1219
|
+
this.throttledUntil = 0;
|
|
1220
|
+
}
|
|
1221
|
+
export(spans, resultCallback) {
|
|
1222
|
+
this.exportAsync(spans).then((succeeded) => {
|
|
1223
|
+
resultCallback({ code: succeeded ? ExportResultCode.SUCCESS : ExportResultCode.FAILED });
|
|
1224
|
+
}, (error) => {
|
|
1225
|
+
resultCallback({
|
|
1226
|
+
code: ExportResultCode.FAILED,
|
|
1227
|
+
error
|
|
1228
|
+
});
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
async exportAsync(spans) {
|
|
1232
|
+
if (spans.length === 0) return true;
|
|
1233
|
+
let encoded;
|
|
1234
|
+
let envelope;
|
|
1235
|
+
try {
|
|
1236
|
+
encoded = spans.map(encodeSpan);
|
|
1237
|
+
envelope = requestEnvelope(spans[0]);
|
|
1238
|
+
} catch (error) {
|
|
1239
|
+
logError("failed to encode an OpenTelemetry span batch", error);
|
|
1240
|
+
return false;
|
|
1241
|
+
}
|
|
1242
|
+
return (await mapWithConcurrency(this.buildRequestBatches(envelope, encoded), this.exportConcurrency, (batch) => this.send(envelope, batch))).every(Boolean);
|
|
1243
|
+
}
|
|
1244
|
+
buildRequestBatches(envelope, spans) {
|
|
1245
|
+
const batches = [];
|
|
1246
|
+
let current = [];
|
|
1247
|
+
let size = envelope.size;
|
|
1248
|
+
for (const span of spans) {
|
|
1249
|
+
const addition = span.size + (current.length > 0 ? SPAN_SEPARATOR_BYTES : 0);
|
|
1250
|
+
if (current.length > 0 && (current.length >= this.maxRequestBatchSize || size + addition > this.maxRequestBytes)) {
|
|
1251
|
+
batches.push({
|
|
1252
|
+
spans: current,
|
|
1253
|
+
size
|
|
1254
|
+
});
|
|
1255
|
+
current = [];
|
|
1256
|
+
size = envelope.size;
|
|
1257
|
+
}
|
|
1258
|
+
current.push(span);
|
|
1259
|
+
size += span.size + (current.length > 1 ? SPAN_SEPARATOR_BYTES : 0);
|
|
1260
|
+
}
|
|
1261
|
+
if (current.length > 0) batches.push({
|
|
1262
|
+
spans: current,
|
|
1263
|
+
size
|
|
1264
|
+
});
|
|
1265
|
+
return batches;
|
|
1266
|
+
}
|
|
1267
|
+
async send(envelope, batch) {
|
|
1268
|
+
try {
|
|
1269
|
+
let requestSpans = batch.spans;
|
|
1270
|
+
let requestRawBytes = batch.size;
|
|
1271
|
+
let alreadyTrimmed = false;
|
|
1272
|
+
while (true) {
|
|
1273
|
+
if (requestRawBytes <= MAX_DECOMPRESSED_REQUEST_BYTES) {
|
|
1274
|
+
const prepared = await prepareRequest(encodeRequest(envelope, requestSpans));
|
|
1275
|
+
if (prepared.wireBytes <= this.maxRequestBytes) {
|
|
1276
|
+
await this.sendWithRetries(prepared);
|
|
1277
|
+
this.reportDelivered(batch.spans);
|
|
1278
|
+
return true;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
if (batch.spans.length !== 1) {
|
|
1282
|
+
logError("an OpenTelemetry span batch exceeded the configured request-size target and could not be exported");
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
if (alreadyTrimmed) {
|
|
1286
|
+
logError("a single OpenTelemetry span exceeded the configured request-size target after trimming");
|
|
1287
|
+
return false;
|
|
1288
|
+
}
|
|
1289
|
+
const trimmed = trimEncodedSpan(batch.spans[0]);
|
|
1290
|
+
if (!trimmed) {
|
|
1291
|
+
logError("a single OpenTelemetry span exceeded the configured request-size target and could not be trimmed");
|
|
1292
|
+
return false;
|
|
1293
|
+
}
|
|
1294
|
+
requestSpans = [trimmed];
|
|
1295
|
+
requestRawBytes = envelope.size + trimmed.size;
|
|
1296
|
+
alreadyTrimmed = true;
|
|
1297
|
+
}
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
if (isOversized(error)) {
|
|
1300
|
+
logError(batch.spans.length === 1 ? "a single OpenTelemetry span exceeded the ingestion request limit and could not be exported" : "an OpenTelemetry span batch exceeded the ingestion request limit and could not be exported");
|
|
1301
|
+
return false;
|
|
1302
|
+
}
|
|
1303
|
+
logError("failed to export an OpenTelemetry span batch", error);
|
|
1304
|
+
return false;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
recordThrottle(error) {
|
|
1308
|
+
const requested = error instanceof DeliveryError ? error.retryAfterMs : void 0;
|
|
1309
|
+
if (requested !== void 0) this.throttledUntil = Math.max(this.throttledUntil, Date.now() + requested);
|
|
1310
|
+
}
|
|
1311
|
+
async awaitThrottle(deadline) {
|
|
1312
|
+
const remaining = this.throttledUntil - Date.now();
|
|
1313
|
+
if (remaining <= 0) return;
|
|
1314
|
+
if (remaining >= (deadline - Date.now()) / 2) throw new DeliveryError(`OTLP ingestion is throttled for another ${remaining}ms, longer than the export budget`);
|
|
1315
|
+
await delay(remaining);
|
|
1316
|
+
}
|
|
1317
|
+
async sendWithRetries(request) {
|
|
1318
|
+
const deadline = Date.now() + this.exportTimeoutMillis;
|
|
1319
|
+
for (let attempt = 0; attempt < MAX_SEND_ATTEMPTS; attempt += 1) try {
|
|
1320
|
+
await this.awaitThrottle(deadline);
|
|
1321
|
+
await this.directSender(request, Math.max(0, deadline - Date.now()));
|
|
1322
|
+
return;
|
|
1323
|
+
} catch (error) {
|
|
1324
|
+
if (isOversized(error)) throw error;
|
|
1325
|
+
this.recordThrottle(error);
|
|
1326
|
+
if (attempt === 2 || !isRetryable(error)) throw error;
|
|
1327
|
+
const wait = retryWaitMillis(error, attempt, deadline - Date.now());
|
|
1328
|
+
if (wait === null) throw error;
|
|
1329
|
+
await delay(wait);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
reportDelivered(spans) {
|
|
1333
|
+
if (this.onDelivered === void 0) return;
|
|
1334
|
+
const refs = spans.map((span) => span.ref).filter((ref) => ref !== void 0);
|
|
1335
|
+
if (refs.length === 0) return;
|
|
1336
|
+
try {
|
|
1337
|
+
this.onDelivered(refs);
|
|
1338
|
+
} catch (error) {
|
|
1339
|
+
logError("a delivery listener threw", error);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
async shutdown() {}
|
|
1343
|
+
async forceFlush() {}
|
|
1344
|
+
};
|
|
1345
|
+
var DeliveryTrackingExporter = class {
|
|
1346
|
+
constructor(exporter) {
|
|
1347
|
+
this.exporter = exporter;
|
|
1348
|
+
this.failedExports = 0;
|
|
1349
|
+
}
|
|
1350
|
+
export(spans, resultCallback) {
|
|
1351
|
+
try {
|
|
1352
|
+
this.exporter.export(spans, (result) => {
|
|
1353
|
+
if (result.code !== ExportResultCode.SUCCESS) this.failedExports += 1;
|
|
1354
|
+
resultCallback(result);
|
|
1355
|
+
});
|
|
1356
|
+
} catch (error) {
|
|
1357
|
+
this.failedExports += 1;
|
|
1358
|
+
resultCallback({
|
|
1359
|
+
code: ExportResultCode.FAILED,
|
|
1360
|
+
error
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
takeFailedExports() {
|
|
1365
|
+
const failed = this.failedExports;
|
|
1366
|
+
this.failedExports = 0;
|
|
1367
|
+
return failed;
|
|
1368
|
+
}
|
|
1369
|
+
shutdown() {
|
|
1370
|
+
return this.exporter.shutdown();
|
|
1371
|
+
}
|
|
1372
|
+
forceFlush() {
|
|
1373
|
+
return this.exporter.forceFlush?.() ?? Promise.resolve();
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
var OtelBatchTransport = class {
|
|
1377
|
+
constructor(options) {
|
|
1378
|
+
this.closed = false;
|
|
1379
|
+
const maxRequestBytes = options.maxRequestBytes ?? MAX_EXPORT_REQUEST_BYTES;
|
|
1380
|
+
const maxRequestBatchSize = options.maxRequestBatchSize ?? DIRECT_MAX_REQUEST_BATCH_SIZE;
|
|
1381
|
+
if (maxRequestBatchSize <= 0) throw new BitfabError("maxRequestBatchSize must be a positive integer");
|
|
1382
|
+
this.deliveryTracker = new DeliveryTrackingExporter(new BitfabSpanExporter(options.directSender, maxRequestBytes, maxRequestBatchSize, options.exportConcurrency ?? DEFAULT_EXPORT_CONCURRENCY, options.onDelivered, options.exportTimeoutMillis ?? EXPORT_TIMEOUT_MILLIS));
|
|
1383
|
+
this.processor = new BatchSpanProcessor(this.deliveryTracker, {
|
|
1384
|
+
maxQueueSize: options.maxQueueSize ?? MAX_QUEUE_SIZE,
|
|
1385
|
+
maxExportBatchSize: options.maxExportBatchSize ?? DIRECT_MAX_EXPORT_BATCH_SIZE,
|
|
1386
|
+
scheduledDelayMillis: SCHEDULE_DELAY_MILLIS,
|
|
1387
|
+
exportTimeoutMillis: options.exportTimeoutMillis ?? EXPORT_TIMEOUT_MILLIS
|
|
1388
|
+
});
|
|
1389
|
+
this.provider = new BasicTracerProvider({
|
|
1390
|
+
sampler: new AlwaysOnSampler(),
|
|
1391
|
+
resource: resourceFromAttributes({
|
|
1392
|
+
"service.name": "bitfab-typescript-sdk",
|
|
1393
|
+
"service.version": __version__
|
|
1394
|
+
}),
|
|
1395
|
+
spanLimits: {
|
|
1396
|
+
attributeCountLimit: 2,
|
|
1397
|
+
attributeValueLengthLimit: Number.POSITIVE_INFINITY
|
|
1398
|
+
},
|
|
1399
|
+
spanProcessors: [this.processor]
|
|
1400
|
+
});
|
|
1401
|
+
this.tracer = this.provider.getTracer("bitfab", __version__);
|
|
1402
|
+
liveTransports.add(this);
|
|
1403
|
+
}
|
|
1404
|
+
submit(operation, payload, meta = {}) {
|
|
1405
|
+
if (this.closed) {
|
|
1406
|
+
warnOnce("otel-submit-after-shutdown", "OpenTelemetry transport is shut down; dropping spans");
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
try {
|
|
1410
|
+
const { body, dropped } = serializePayloadBody(payload, MAX_COMPRESSIBLE_SPAN_CARRIER_BYTES);
|
|
1411
|
+
if (dropped.length > 0) warnOnce("otel-carrier-payload-stubbed", `a span payload held non-serializable value(s) (${[...new Set(dropped)].join(", ")}); they were stubbed so the span still ships, but the trace may be incomplete or not replayable.`);
|
|
1412
|
+
const span = this.tracer.startSpan(meta.name ?? `bitfab.${operation}`, {
|
|
1413
|
+
attributes: {
|
|
1414
|
+
[OPERATION_ATTRIBUTE]: operation,
|
|
1415
|
+
[PAYLOAD_ATTRIBUTE]: body
|
|
1416
|
+
},
|
|
1417
|
+
startTime: meta.startTime
|
|
1418
|
+
});
|
|
1419
|
+
if (meta.ref !== void 0) carrierRefs.set(span, meta.ref);
|
|
1420
|
+
if (meta.errored === true) span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1421
|
+
endSpan(span, meta.endTime);
|
|
1422
|
+
} catch (error) {
|
|
1423
|
+
logError("failed to queue an OpenTelemetry span", error);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
async flush(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS$1) {
|
|
1427
|
+
const pending = (this.pendingFlush ?? Promise.resolve(true)).then(() => this.forceFlushOnce());
|
|
1428
|
+
this.pendingFlush = pending.catch(() => false);
|
|
1429
|
+
return withDeadline(pending, timeoutMs);
|
|
1430
|
+
}
|
|
1431
|
+
async forceFlushOnce() {
|
|
1432
|
+
try {
|
|
1433
|
+
await this.processor.forceFlush();
|
|
1434
|
+
} catch (error) {
|
|
1435
|
+
logError("failed to flush OpenTelemetry spans", error);
|
|
1436
|
+
this.deliveryTracker.takeFailedExports();
|
|
1437
|
+
return false;
|
|
1438
|
+
}
|
|
1439
|
+
return this.deliveryTracker.takeFailedExports() === 0;
|
|
1440
|
+
}
|
|
1441
|
+
async shutdown(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS$1) {
|
|
1442
|
+
const deadline = Date.now() + Math.max(timeoutMs, 0);
|
|
1443
|
+
this.closed = true;
|
|
1444
|
+
const flushed = await this.flush(Math.max(0, deadline - Date.now()));
|
|
1445
|
+
liveTransports.delete(this);
|
|
1446
|
+
const shutdownCompleted = await withDeadline(this.provider.shutdown().then(() => true).catch((error) => {
|
|
1447
|
+
logError("failed to shut down the OpenTelemetry transport", error);
|
|
1448
|
+
return false;
|
|
1449
|
+
}), Math.max(0, deadline - Date.now()));
|
|
1450
|
+
return flushed && shutdownCompleted;
|
|
1451
|
+
}
|
|
1452
|
+
};
|
|
1453
|
+
function endSpan(span, endTime) {
|
|
1454
|
+
span.end(endTime);
|
|
1455
|
+
}
|
|
1456
|
+
function createOtelTransport(options) {
|
|
1457
|
+
return new OtelBatchTransport({
|
|
1458
|
+
...options,
|
|
1459
|
+
exportConcurrency: readBoundedIntEnv(EXPORT_CONCURRENCY_ENV, MAX_EXPORT_CONCURRENCY, DEFAULT_EXPORT_CONCURRENCY, "otel-export-concurrency-invalid"),
|
|
1460
|
+
maxRequestBytes: readBoundedIntEnv(MAX_REQUEST_BYTES_ENV, MAX_EXPORT_REQUEST_BYTES, MAX_EXPORT_REQUEST_BYTES, "otel-max-request-bytes-invalid")
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
async function forEachLiveTransport(timeoutMs, run) {
|
|
1464
|
+
const deadline = Date.now() + Math.max(timeoutMs, 0);
|
|
1465
|
+
let succeeded = true;
|
|
1466
|
+
for (const transport of [...liveTransports]) succeeded = await run(transport, Math.max(0, deadline - Date.now())) && succeeded;
|
|
1467
|
+
return succeeded;
|
|
1468
|
+
}
|
|
1469
|
+
function flushOtelTransports(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS$1) {
|
|
1470
|
+
return forEachLiveTransport(timeoutMs, (transport, remaining) => transport.flush(remaining));
|
|
1471
|
+
}
|
|
1472
|
+
function shutdownOtelTransports(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS$1) {
|
|
1473
|
+
return forEachLiveTransport(timeoutMs, (transport, remaining) => transport.shutdown(remaining));
|
|
1474
|
+
}
|
|
1475
|
+
//#endregion
|
|
1476
|
+
//#region src/transport.ts
|
|
1477
|
+
function createTraceTransport(options) {
|
|
1478
|
+
return createOtelTransport(options);
|
|
1479
|
+
}
|
|
1480
|
+
function flushTraceTransports(timeoutMs) {
|
|
1481
|
+
return flushOtelTransports(timeoutMs);
|
|
1482
|
+
}
|
|
1483
|
+
function shutdownTraceTransports(timeoutMs) {
|
|
1484
|
+
return shutdownOtelTransports(timeoutMs);
|
|
1485
|
+
}
|
|
1486
|
+
//#endregion
|
|
1487
|
+
//#region src/http.ts
|
|
1488
|
+
var http_exports = /* @__PURE__ */ __exportAll({
|
|
1489
|
+
BitfabError: () => BitfabError,
|
|
1490
|
+
HttpClient: () => HttpClient,
|
|
1491
|
+
SPAN_TYPES: () => SPAN_TYPES,
|
|
1492
|
+
awaitOnExit: () => awaitOnExit,
|
|
1493
|
+
awaitPendingRequests: () => awaitPendingRequests,
|
|
1494
|
+
experimentIdWireFields: () => experimentIdWireFields,
|
|
1495
|
+
flushTraces: () => flushTraces,
|
|
1496
|
+
parseRetryAfterMs: () => parseRetryAfterMs,
|
|
1497
|
+
serializePayloadBody: () => serializePayloadBody
|
|
1498
|
+
});
|
|
1499
|
+
const REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS = 3e5;
|
|
1500
|
+
const REPLAY_COMPLETE_REQUEST_TIMEOUT_MS = 12e4;
|
|
1501
|
+
const REPLAY_INTERRUPT_REQUEST_TIMEOUT_MS = 5e3;
|
|
1502
|
+
const REPLAY_HEARTBEAT_REQUEST_TIMEOUT_MS = 5e3;
|
|
1503
|
+
const OTLP_TRACES_ENDPOINT = "/api/sdk/otel/v1/traces";
|
|
1504
|
+
const RETRYABLE_STATUSES = /* @__PURE__ */ new Set([
|
|
1505
|
+
429,
|
|
1506
|
+
500,
|
|
1507
|
+
502,
|
|
1508
|
+
503,
|
|
1509
|
+
504
|
|
1510
|
+
]);
|
|
1511
|
+
const EXIT_FLUSH_TIMEOUT_MS = 5e3;
|
|
1512
|
+
const DEFAULT_LIFECYCLE_TIMEOUT_MS = 3e4;
|
|
1513
|
+
const pendingTracePromises = /* @__PURE__ */ new Set();
|
|
1514
|
+
const liveHttpClients = /* @__PURE__ */ new Set();
|
|
1515
|
+
async function releaseHeldExternalSpans(timeoutMs) {
|
|
1516
|
+
const deadline = Date.now() + Math.max(timeoutMs, 0);
|
|
1517
|
+
let released = true;
|
|
1518
|
+
for (const client of [...liveHttpClients]) released = await client.releaseHeldExternalSpans?.(Math.max(0, deadline - Date.now())) !== false && released;
|
|
1519
|
+
return released;
|
|
1520
|
+
}
|
|
1521
|
+
function stopSimulationPlans() {
|
|
1522
|
+
for (const client of [...liveHttpClients]) client.stopSimulationPlan?.();
|
|
1523
|
+
}
|
|
1524
|
+
function awaitOnExit(promise) {
|
|
1525
|
+
pendingTracePromises.add(promise);
|
|
1526
|
+
promise.finally(() => {
|
|
1527
|
+
pendingTracePromises.delete(promise);
|
|
1528
|
+
}).catch(() => {});
|
|
1529
|
+
return promise;
|
|
1530
|
+
}
|
|
1531
|
+
async function flushTraces(timeoutMs = 5e3) {
|
|
1532
|
+
const deadline = Date.now() + Math.max(timeoutMs, 0);
|
|
1533
|
+
const released = await releaseHeldExternalSpans(planWaitSliceMs(timeoutMs));
|
|
1534
|
+
const requestsFlushed = await awaitPendingRequests(Math.max(0, deadline - Date.now()));
|
|
1535
|
+
const releasedAfterDeferred = await releaseHeldExternalSpans(0);
|
|
1536
|
+
const transportsFlushed = await flushTraceTransports(Math.max(0, deadline - Date.now()));
|
|
1537
|
+
return released && releasedAfterDeferred && requestsFlushed && transportsFlushed;
|
|
1538
|
+
}
|
|
1539
|
+
async function awaitPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS) {
|
|
1540
|
+
await replayContextReady.catch(() => {});
|
|
1541
|
+
return waitForPromises(Array.from(pendingTracePromises), timeoutMs);
|
|
1542
|
+
}
|
|
1543
|
+
async function waitForPromises(promises, timeoutMs) {
|
|
1544
|
+
if (promises.length === 0) return true;
|
|
1545
|
+
let timer;
|
|
1546
|
+
try {
|
|
1547
|
+
return await Promise.race([Promise.allSettled(promises).then(() => true), new Promise((resolve) => {
|
|
1548
|
+
timer = setTimeout(() => resolve(false), timeoutMs);
|
|
1549
|
+
unrefTimer(timer);
|
|
1550
|
+
})]);
|
|
1551
|
+
} finally {
|
|
1552
|
+
if (timer) clearTimeout(timer);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
if (typeof process !== "undefined" && process.versions != null && process.versions.node != null) {
|
|
1556
|
+
let isFlushing = false;
|
|
1557
|
+
process.on("beforeExit", () => {
|
|
1558
|
+
if (isFlushing) return;
|
|
1559
|
+
isFlushing = true;
|
|
1560
|
+
const planWaitMs = SIMULATION_PLAN_READ_TIMEOUT_MS;
|
|
1561
|
+
const stopFlushing = () => {
|
|
1562
|
+
isFlushing = false;
|
|
1563
|
+
};
|
|
1564
|
+
const deadline = setTimeout(stopFlushing, 1e4);
|
|
1565
|
+
unrefTimer(deadline);
|
|
1566
|
+
releaseHeldExternalSpans(planWaitMs).catch(() => {}).then(() => {
|
|
1567
|
+
stopSimulationPlans();
|
|
1568
|
+
}).then(() => Promise.allSettled([...Array.from(pendingTracePromises).map((p) => p.catch(() => {})), shutdownTraceTransports(EXIT_FLUSH_TIMEOUT_MS).catch(() => false)])).then(() => {
|
|
1569
|
+
clearTimeout(deadline);
|
|
1570
|
+
stopFlushing();
|
|
1571
|
+
});
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
const SPAN_TYPES = [
|
|
1575
|
+
"llm",
|
|
1576
|
+
"agent",
|
|
1577
|
+
"function",
|
|
1578
|
+
"guardrail",
|
|
1579
|
+
"handoff",
|
|
1580
|
+
"custom"
|
|
1581
|
+
];
|
|
1582
|
+
function readHeader(response, name) {
|
|
1583
|
+
try {
|
|
1584
|
+
return response.headers?.get(name) ?? null;
|
|
1585
|
+
} catch {
|
|
1586
|
+
return null;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
function parseRetryAfterMs(header) {
|
|
1590
|
+
const value = header?.trim();
|
|
1591
|
+
if (!value) return;
|
|
1592
|
+
const seconds = Number(value);
|
|
1593
|
+
if (Number.isFinite(seconds)) return seconds >= 0 ? seconds * 1e3 : void 0;
|
|
1594
|
+
const at = Date.parse(value);
|
|
1595
|
+
if (Number.isNaN(at)) return;
|
|
1596
|
+
return Math.max(0, at - Date.now());
|
|
1597
|
+
}
|
|
1598
|
+
function carrierMeta(operation, payload, ref) {
|
|
1599
|
+
return {
|
|
1600
|
+
ref,
|
|
1601
|
+
name: carrierName(operation, payload),
|
|
1602
|
+
startTime: payloadTimestamp(payload, "started_at"),
|
|
1603
|
+
endTime: payloadTimestamp(payload, "ended_at"),
|
|
1604
|
+
errored: payloadHasError(payload)
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
function carrierName(operation, payload) {
|
|
1608
|
+
if (operation === "external_span") {
|
|
1609
|
+
const spanData = asPayloadRecord(asPayloadRecord(payload.rawSpan)?.span_data);
|
|
1610
|
+
if (typeof spanData?.name === "string") return spanData.name;
|
|
1611
|
+
}
|
|
1612
|
+
if (typeof payload.traceFunctionKey === "string") return payload.traceFunctionKey;
|
|
1613
|
+
return `bitfab.${operation}`;
|
|
1614
|
+
}
|
|
1615
|
+
function payloadTimestamp(payload, field) {
|
|
1616
|
+
const rawSpan = asPayloadRecord(payload.rawSpan);
|
|
1617
|
+
const rawTrace = asPayloadRecord(payload.externalTrace) ?? asPayloadRecord(payload.rawTrace);
|
|
1618
|
+
const raw = rawSpan?.[field] ?? rawTrace?.[field];
|
|
1619
|
+
if (typeof raw !== "string") return;
|
|
1620
|
+
const parsed = Date.parse(raw);
|
|
1621
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
1622
|
+
}
|
|
1623
|
+
function payloadHasError(payload) {
|
|
1624
|
+
if (asPayloadRecord(asPayloadRecord(payload.rawSpan)?.span_data)?.error != null) return true;
|
|
1625
|
+
const errors = payload.errors;
|
|
1626
|
+
return Array.isArray(errors) ? errors.length > 0 : Boolean(errors);
|
|
1627
|
+
}
|
|
1628
|
+
function asPayloadRecord(value) {
|
|
1629
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1630
|
+
}
|
|
1631
|
+
function carrierRef(payload) {
|
|
1632
|
+
const traceId = sourceTraceIdOf(payload);
|
|
1633
|
+
if (traceId === void 0) return;
|
|
1634
|
+
const rawSpan = payload.rawSpan;
|
|
1635
|
+
if (rawSpan === void 0) return { traceId };
|
|
1636
|
+
const spanId = rawSpan?.id;
|
|
1637
|
+
return {
|
|
1638
|
+
traceId,
|
|
1639
|
+
spanId: typeof spanId === "string" ? spanId : `submission-${++carrierSeq}`
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
function sourceTraceIdOf(payload) {
|
|
1643
|
+
if (typeof payload.sourceTraceId === "string") return payload.sourceTraceId;
|
|
1644
|
+
const id = (payload.externalTrace ?? payload.rawTrace)?.id;
|
|
1645
|
+
return typeof id === "string" ? id : void 0;
|
|
1646
|
+
}
|
|
1647
|
+
let carrierSeq = 0;
|
|
1648
|
+
function describeError(error) {
|
|
1649
|
+
return error instanceof Error ? error.message : String(error);
|
|
1650
|
+
}
|
|
1651
|
+
function warnDroppedExternalSpan(error) {
|
|
1652
|
+
warnOnce("external-span-dropped", `a span was dropped because the send step failed: ${describeError(error)}`);
|
|
1653
|
+
}
|
|
1654
|
+
function warnDroppedExternalTrace(error) {
|
|
1655
|
+
warnOnce("external-trace-dropped", `a trace was dropped because the send step failed: ${describeError(error)}`);
|
|
1656
|
+
}
|
|
1657
|
+
var HttpClient = class {
|
|
1658
|
+
constructor(config) {
|
|
1659
|
+
this.traceDeliveries = /* @__PURE__ */ new Map();
|
|
1660
|
+
this.deferredWork = /* @__PURE__ */ new Set();
|
|
1661
|
+
this.traceCompletion = new TraceCompletion();
|
|
1662
|
+
this.closed = false;
|
|
1663
|
+
this.apiKey = config.apiKey;
|
|
1664
|
+
this.serviceUrl = config.serviceUrl;
|
|
1665
|
+
this.timeout = config.timeout ?? 12e4;
|
|
1666
|
+
liveHttpClients.add(this);
|
|
1667
|
+
}
|
|
1668
|
+
resolveApiKey() {
|
|
1669
|
+
return typeof this.apiKey === "function" ? this.apiKey() : this.apiKey;
|
|
1670
|
+
}
|
|
1671
|
+
hasApiKey() {
|
|
1672
|
+
try {
|
|
1673
|
+
const apiKey = this.resolveApiKey();
|
|
1674
|
+
return apiKey !== void 0 && apiKey.trim() !== "";
|
|
1675
|
+
} catch {
|
|
1676
|
+
return false;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
getTraceTransport() {
|
|
1680
|
+
if (this.closed) {
|
|
1681
|
+
warnOnce("http-client-closed", "the Bitfab client is closed; dropping spans");
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
if (!this.traceTransport) this.traceTransport = createTraceTransport({
|
|
1685
|
+
directSender: (request, timeoutMs) => this.deliverCarriers(request, timeoutMs),
|
|
1686
|
+
onDelivered: (refs) => this.recordDeliveredCarriers(refs)
|
|
1687
|
+
});
|
|
1688
|
+
return this.traceTransport;
|
|
1689
|
+
}
|
|
1690
|
+
async deliverCarriers(request, timeoutMs) {
|
|
1691
|
+
let response;
|
|
1692
|
+
try {
|
|
1693
|
+
response = await this.sendPrepared(OTLP_TRACES_ENDPOINT, request, { timeout: timeoutMs });
|
|
1694
|
+
} catch (error) {
|
|
1695
|
+
const status = error instanceof BitfabError ? error.status : void 0;
|
|
1696
|
+
if (status === void 0) throw new DeliveryError(`OTLP ingestion failed: ${String(error)}`, { retryable: true });
|
|
1697
|
+
throw new DeliveryError(`OTLP ingestion failed with HTTP ${status}`, {
|
|
1698
|
+
retryable: RETRYABLE_STATUSES.has(status),
|
|
1699
|
+
oversized: status === 413,
|
|
1700
|
+
...error instanceof BitfabError && error.retryAfterMs !== void 0 ? { retryAfterMs: error.retryAfterMs } : {}
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
const serverTraceIds = asPayloadRecord(response?.traceIds);
|
|
1704
|
+
if (serverTraceIds !== void 0) this.recordServerTraceIds(serverTraceIds);
|
|
1705
|
+
const partialSuccess = asPayloadRecord(response?.partialSuccess);
|
|
1706
|
+
const rejected = partialSuccess?.rejectedSpans;
|
|
1707
|
+
if (rejected !== void 0 && rejected !== "0" && rejected !== 0) throw new DeliveryError(`OTLP ingestion rejected ${rejected} span(s): ${partialSuccess?.errorMessage ?? "no reason provided"}`);
|
|
1708
|
+
}
|
|
1709
|
+
trackTraceDeliveries(traceIds) {
|
|
1710
|
+
for (const traceId of traceIds) if (!this.traceDeliveries.has(traceId)) this.traceDeliveries.set(traceId, {
|
|
1711
|
+
submittedSpanIds: /* @__PURE__ */ new Set(),
|
|
1712
|
+
ackedSpanIds: /* @__PURE__ */ new Set(),
|
|
1713
|
+
closed: false,
|
|
1714
|
+
closingAcked: false
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1717
|
+
peekServerTraceId(traceId) {
|
|
1718
|
+
return this.traceDeliveries.get(traceId)?.serverTraceId;
|
|
1719
|
+
}
|
|
1720
|
+
hasClosedDeliveries(traceIds) {
|
|
1721
|
+
return traceIds.some((traceId) => this.traceDeliveries.get(traceId)?.closed);
|
|
1722
|
+
}
|
|
1723
|
+
takeTraceDeliveries(traceIds) {
|
|
1724
|
+
const reports = {};
|
|
1725
|
+
for (const traceId of traceIds) {
|
|
1726
|
+
const delivery = this.traceDeliveries.get(traceId);
|
|
1727
|
+
if (delivery === void 0) continue;
|
|
1728
|
+
this.traceDeliveries.delete(traceId);
|
|
1729
|
+
reports[traceId] = {
|
|
1730
|
+
spanCount: delivery.submittedSpanIds.size,
|
|
1731
|
+
closed: delivery.closed,
|
|
1732
|
+
delivered: delivery.closingAcked && [...delivery.submittedSpanIds].every((spanId) => delivery.ackedSpanIds.has(spanId)),
|
|
1733
|
+
serverTraceId: delivery.serverTraceId
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
return reports;
|
|
1737
|
+
}
|
|
1738
|
+
recordedMeta(operation, payload, ref) {
|
|
1739
|
+
this.recordSubmittedCarrier(ref);
|
|
1740
|
+
return carrierMeta(operation, payload, ref);
|
|
1741
|
+
}
|
|
1742
|
+
recordSubmittedCarrier(ref) {
|
|
1743
|
+
if (ref === void 0) return;
|
|
1744
|
+
const delivery = this.traceDeliveries.get(ref.traceId);
|
|
1745
|
+
if (delivery === void 0) return;
|
|
1746
|
+
if (ref.spanId === void 0) delivery.closed = true;
|
|
1747
|
+
else delivery.submittedSpanIds.add(ref.spanId);
|
|
1748
|
+
}
|
|
1749
|
+
recordServerTraceIds(map) {
|
|
1750
|
+
for (const [sourceTraceId, serverTraceId] of Object.entries(map)) {
|
|
1751
|
+
if (typeof serverTraceId !== "string") continue;
|
|
1752
|
+
const delivery = this.traceDeliveries.get(sourceTraceId);
|
|
1753
|
+
if (delivery === void 0) continue;
|
|
1754
|
+
delivery.serverTraceId = serverTraceId;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
recordDeliveredCarriers(refs) {
|
|
1758
|
+
for (const ref of refs) {
|
|
1759
|
+
const delivery = this.traceDeliveries.get(ref.traceId);
|
|
1760
|
+
if (delivery === void 0) continue;
|
|
1761
|
+
if (ref.spanId === void 0) delivery.closingAcked = true;
|
|
1762
|
+
else delivery.ackedSpanIds.add(ref.spanId);
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
trackDeferred(promise) {
|
|
1766
|
+
this.deferredWork.add(promise);
|
|
1767
|
+
promise.finally(() => this.deferredWork.delete(promise)).catch(() => {});
|
|
1768
|
+
return awaitOnExit(promise);
|
|
1769
|
+
}
|
|
1770
|
+
async settleDeferredWork(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS) {
|
|
1771
|
+
const deadline = Date.now() + Math.max(timeoutMs, 0);
|
|
1772
|
+
const released = await this.releaseHeldExternalSpans?.(planWaitSliceMs(timeoutMs));
|
|
1773
|
+
await replayContextReady.catch(() => {});
|
|
1774
|
+
const settled = await waitForPromises(Array.from(this.deferredWork), Math.max(0, deadline - Date.now()));
|
|
1775
|
+
const releasedAfterDeferred = await this.releaseHeldExternalSpans?.(0);
|
|
1776
|
+
return released !== false && releasedAfterDeferred !== false && settled;
|
|
1777
|
+
}
|
|
1778
|
+
async waitForPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS) {
|
|
1779
|
+
const deadline = Date.now() + Math.max(timeoutMs, 0);
|
|
1780
|
+
const settled = await this.settleDeferredWork(Math.max(0, deadline - Date.now()));
|
|
1781
|
+
const flushed = await this.traceTransport?.flush(Math.max(0, deadline - Date.now())) ?? true;
|
|
1782
|
+
return settled && flushed;
|
|
1783
|
+
}
|
|
1784
|
+
close(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS) {
|
|
1785
|
+
if (this.closing) return this.closing;
|
|
1786
|
+
const deadline = Date.now() + Math.max(timeoutMs, 0);
|
|
1787
|
+
this.closing = (async () => {
|
|
1788
|
+
liveHttpClients.delete(this);
|
|
1789
|
+
const settled = await this.settleDeferredWork(Math.max(0, deadline - Date.now()));
|
|
1790
|
+
this.stopSimulationPlan?.();
|
|
1791
|
+
this.closed = true;
|
|
1792
|
+
this.externalSpanTransform = void 0;
|
|
1793
|
+
this.externalTraceTransform = void 0;
|
|
1794
|
+
this.releaseHeldExternalSpans = void 0;
|
|
1795
|
+
this.stopSimulationPlan = void 0;
|
|
1796
|
+
const transport = this.traceTransport;
|
|
1797
|
+
this.traceTransport = void 0;
|
|
1798
|
+
const shutdownOk = await transport?.shutdown(Math.max(0, deadline - Date.now())) ?? true;
|
|
1799
|
+
return settled && shutdownOk;
|
|
1800
|
+
})();
|
|
1801
|
+
return this.closing;
|
|
1802
|
+
}
|
|
1803
|
+
async request(endpoint, payload, options) {
|
|
1804
|
+
const { body, dropped } = serializePayloadBody(payload);
|
|
1805
|
+
if (dropped.length > 0) try {
|
|
1806
|
+
console.warn(`Bitfab: request body to ${endpoint} held ${dropped.length} non-serializable value(s) (${[...new Set(dropped)].join(", ")}); they were stubbed so the span still sends, but the trace may be incomplete or not replayable. Capture a JSON-safe projection of this input to make it replayable.`);
|
|
1807
|
+
} catch {}
|
|
1808
|
+
return this.sendEncoded(endpoint, body, options);
|
|
1809
|
+
}
|
|
1810
|
+
async sendEncoded(endpoint, body, options) {
|
|
1811
|
+
const prepared = encodeRequestBody(body);
|
|
1812
|
+
const encoded = prepared instanceof Promise ? await prepared : prepared;
|
|
1813
|
+
return this.sendPrepared(endpoint, encoded, options);
|
|
1814
|
+
}
|
|
1815
|
+
async sendPrepared(endpoint, encoded, options) {
|
|
1816
|
+
const url = `${this.serviceUrl}${endpoint}`;
|
|
1817
|
+
const timeout = options?.timeout ?? this.timeout;
|
|
1818
|
+
const method = options?.method ?? "POST";
|
|
1819
|
+
const controller = new AbortController();
|
|
1820
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1821
|
+
const headers = {
|
|
1822
|
+
"Content-Type": "application/json",
|
|
1823
|
+
Authorization: `Bearer ${this.resolveApiKey() ?? ""}`
|
|
1824
|
+
};
|
|
1825
|
+
if (encoded.contentEncoding) headers["Content-Encoding"] = encoded.contentEncoding;
|
|
1826
|
+
try {
|
|
1827
|
+
const response = await fetch(url, {
|
|
1828
|
+
method,
|
|
1829
|
+
headers,
|
|
1830
|
+
body: encoded.body,
|
|
1831
|
+
signal: controller.signal
|
|
1832
|
+
});
|
|
1833
|
+
if (!response.ok) {
|
|
1834
|
+
const errorText = await response.text();
|
|
1835
|
+
throw new BitfabError(`HTTP ${response.status}: ${errorText.slice(0, 500)}`, void 0, response.status, parseRetryAfterMs(readHeader(response, "retry-after")));
|
|
1836
|
+
}
|
|
1837
|
+
const result = await response.json();
|
|
1838
|
+
if (result.error) {
|
|
1839
|
+
if (result.url) throw new BitfabError(`${result.error} Configure it at: ${this.serviceUrl}${result.url}`, result.url);
|
|
1840
|
+
throw new BitfabError(result.error);
|
|
1841
|
+
}
|
|
1842
|
+
return result;
|
|
1843
|
+
} catch (error) {
|
|
1844
|
+
if (error instanceof BitfabError) throw error;
|
|
1845
|
+
if (error instanceof Error) {
|
|
1846
|
+
if (error.name === "AbortError") throw new BitfabError(`Request timed out after ${timeout}ms`);
|
|
1847
|
+
throw new BitfabError(error.message);
|
|
1848
|
+
}
|
|
1849
|
+
throw new BitfabError("Unknown error occurred");
|
|
1850
|
+
} finally {
|
|
1851
|
+
clearTimeout(timeoutId);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
async lookupFunction(name) {
|
|
1855
|
+
return this.request("/api/sdk/functions/lookup", { name });
|
|
1856
|
+
}
|
|
1857
|
+
async getSimulationPlan() {
|
|
1858
|
+
if (!this.hasApiKey()) throw new BitfabError(NO_API_KEY_FOR_SIMULATION_PLAN);
|
|
1859
|
+
return this.get("/api/sdk/sim-plan", SIMULATION_PLAN_READ_TIMEOUT_MS);
|
|
1860
|
+
}
|
|
1861
|
+
async getTraceSpan(traceId, lookup) {
|
|
1862
|
+
const searchParams = new URLSearchParams();
|
|
1863
|
+
if (lookup.id !== void 0) searchParams.set("id", lookup.id);
|
|
1864
|
+
else {
|
|
1865
|
+
if (lookup.name !== void 0) searchParams.set("name", lookup.name);
|
|
1866
|
+
if (lookup.type !== void 0) searchParams.set("type", lookup.type);
|
|
1867
|
+
searchParams.set("occurrence", String(lookup.occurrence ?? "last"));
|
|
1868
|
+
}
|
|
1869
|
+
const endpoint = `/api/sdk/traces/${encodeURIComponent(traceId)}/span?${searchParams.toString()}`;
|
|
1870
|
+
return (await this.get(endpoint)).span;
|
|
1871
|
+
}
|
|
1872
|
+
async getSpan(spanId) {
|
|
1873
|
+
return (await this.get(`/api/sdk/spans/${encodeURIComponent(spanId)}`)).span;
|
|
1874
|
+
}
|
|
1875
|
+
async get(endpoint, timeoutMs, extraHeaders) {
|
|
1876
|
+
const url = `${this.serviceUrl}${endpoint}`;
|
|
1877
|
+
const timeout = timeoutMs ?? this.timeout;
|
|
1878
|
+
const controller = new AbortController();
|
|
1879
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1880
|
+
try {
|
|
1881
|
+
const response = await fetch(url, {
|
|
1882
|
+
method: "GET",
|
|
1883
|
+
headers: {
|
|
1884
|
+
Authorization: `Bearer ${this.resolveApiKey() ?? ""}`,
|
|
1885
|
+
...extraHeaders
|
|
1886
|
+
},
|
|
1887
|
+
signal: controller.signal
|
|
1888
|
+
});
|
|
1889
|
+
if (!response.ok) {
|
|
1890
|
+
const errorText = await response.text();
|
|
1891
|
+
throw new BitfabError(`HTTP ${response.status}: ${errorText.slice(0, 500)}`, void 0, response.status, parseRetryAfterMs(readHeader(response, "retry-after")));
|
|
1892
|
+
}
|
|
1893
|
+
return await response.json();
|
|
1894
|
+
} catch (error) {
|
|
1895
|
+
if (error instanceof BitfabError) throw error;
|
|
1896
|
+
if (error instanceof Error) {
|
|
1897
|
+
if (error.name === "AbortError") throw new BitfabError(`Request timed out after ${timeout}ms`);
|
|
1898
|
+
throw new BitfabError(error.message);
|
|
1899
|
+
}
|
|
1900
|
+
throw new BitfabError("Unknown error occurred");
|
|
1901
|
+
} finally {
|
|
1902
|
+
clearTimeout(timeoutId);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
sendInternalTrace(functionId, payload) {
|
|
1906
|
+
const body = {
|
|
1907
|
+
...payload,
|
|
1908
|
+
functionId,
|
|
1909
|
+
sdkPackage: __packageName__,
|
|
1910
|
+
sdkVersion: __version__
|
|
1911
|
+
};
|
|
1912
|
+
this.getTraceTransport()?.submit("internal_trace", body, carrierMeta("internal_trace", body, void 0));
|
|
1913
|
+
}
|
|
1914
|
+
sendExternalSpan(payload) {
|
|
1915
|
+
const ref = carrierRef(payload);
|
|
1916
|
+
if (ref?.spanId !== void 0) this.traceCompletion.record(ref.traceId, ref.spanId);
|
|
1917
|
+
const drop = () => {
|
|
1918
|
+
if (ref?.spanId !== void 0) this.traceCompletion.abort(ref.traceId, ref.spanId);
|
|
1919
|
+
};
|
|
1920
|
+
const gate = this.externalSpanTransform;
|
|
1921
|
+
if (gate === void 0) {
|
|
1922
|
+
this.submitExternalSpan(payload);
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
try {
|
|
1926
|
+
gate(payload, (ready) => this.submitExternalSpan(ready), drop);
|
|
1927
|
+
} catch (error) {
|
|
1928
|
+
drop();
|
|
1929
|
+
warnDroppedExternalSpan(error);
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
submitExternalSpan(payload) {
|
|
1933
|
+
const body = {
|
|
1934
|
+
...payload,
|
|
1935
|
+
sdkVersion: __version__
|
|
1936
|
+
};
|
|
1937
|
+
delete body[ROOT_TRACE_FUNCTION_KEY_FIELD];
|
|
1938
|
+
delete body[DECLARED_NODE_FIELD];
|
|
1939
|
+
this.getTraceTransport()?.submit("external_span", body, this.recordedMeta("external_span", payload, carrierRef(payload)));
|
|
1940
|
+
}
|
|
1941
|
+
sendExternalTrace(rawPayload) {
|
|
1942
|
+
const payload = mergeCallerMetadataIntoTracePayload(rawPayload);
|
|
1943
|
+
const traceId = sourceTraceIdOf(payload);
|
|
1944
|
+
if (payload.completed === true && traceId !== void 0) {
|
|
1945
|
+
this.traceCompletion.close(traceId, (expectedSpanCount) => this.sendCountedExternalTrace({
|
|
1946
|
+
...payload,
|
|
1947
|
+
expectedSpanCount
|
|
1948
|
+
}), payload.dropped === true);
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1951
|
+
if (traceId !== void 0) this.traceCompletion.open(traceId);
|
|
1952
|
+
this.sendCountedExternalTrace(payload);
|
|
1953
|
+
}
|
|
1954
|
+
sendCountedExternalTrace(payload) {
|
|
1955
|
+
try {
|
|
1956
|
+
const gate = this.externalTraceTransform;
|
|
1957
|
+
if (gate === void 0) this.submitExternalTrace(payload);
|
|
1958
|
+
else gate(payload, (ready) => this.submitExternalTrace(ready));
|
|
1959
|
+
} catch (error) {
|
|
1960
|
+
warnDroppedExternalTrace(error);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
submitExternalTrace(payload) {
|
|
1964
|
+
this.getTraceTransport()?.submit("external_trace", {
|
|
1965
|
+
...payload,
|
|
1966
|
+
sdkPackage: __packageName__,
|
|
1967
|
+
sdkVersion: __version__
|
|
1968
|
+
}, this.recordedMeta("external_trace", payload, payload.completed === true ? carrierRef(payload) : void 0));
|
|
1969
|
+
}
|
|
1970
|
+
async patchTrace(traceId, payload) {
|
|
1971
|
+
const endpoint = `/api/sdk/traces/${encodeURIComponent(traceId)}`;
|
|
1972
|
+
await this.request(endpoint, payload, { method: "PATCH" });
|
|
1973
|
+
}
|
|
1974
|
+
async startReplay(traceFunctionKey, limit, traceIds, name, codeChangeDescription, codeChangeFiles, includeDbBranchLease, experimentGroupId, datasetIds, graderIds, dbBranchSettings, attempts, includeOriginalMetadata, onlyWithAssertions, skipAssertionJudging, experimentalSelectiveReplay, notes, metadata, dryRun, experimentGroupName, invocation) {
|
|
1975
|
+
const payload = { traceFunctionKey };
|
|
1976
|
+
if (experimentalSelectiveReplay !== void 0) payload.experimentalSelectiveReplay = experimentalSelectiveReplay;
|
|
1977
|
+
if (limit !== void 0) payload.limit = limit;
|
|
1978
|
+
if (traceIds) payload.traceIds = traceIds;
|
|
1979
|
+
if (name !== void 0) payload.name = name;
|
|
1980
|
+
if (notes !== void 0) payload.notes = notes;
|
|
1981
|
+
if (metadata !== void 0) payload.metadata = metadata;
|
|
1982
|
+
if (codeChangeDescription !== void 0) payload.codeChangeDescription = codeChangeDescription;
|
|
1983
|
+
if (codeChangeFiles !== void 0) payload.codeChangeFiles = codeChangeFiles;
|
|
1984
|
+
if (includeDbBranchLease) {
|
|
1985
|
+
payload.includeDbBranchLease = true;
|
|
1986
|
+
payload.lazyDbBranchLease = true;
|
|
1987
|
+
}
|
|
1988
|
+
if (experimentGroupId !== void 0) payload.experimentGroupId = experimentGroupId;
|
|
1989
|
+
if (experimentGroupName !== void 0) payload.experimentGroupName = experimentGroupName;
|
|
1990
|
+
if (datasetIds !== void 0) {
|
|
1991
|
+
if (datasetIds.length === 1) payload.datasetId = datasetIds[0];
|
|
1992
|
+
else payload.datasetIds = datasetIds;
|
|
1993
|
+
}
|
|
1994
|
+
if (graderIds !== void 0) payload.graderIds = graderIds;
|
|
1995
|
+
if (dbBranchSettings !== void 0) payload.dbBranchSettings = dbBranchSettings;
|
|
1996
|
+
if (attempts !== void 0 && attempts > 1) payload.attempts = attempts;
|
|
1997
|
+
if (includeOriginalMetadata) payload.includeOriginalMetadata = true;
|
|
1998
|
+
if (onlyWithAssertions) payload.onlyWithAssertions = true;
|
|
1999
|
+
if (skipAssertionJudging !== true) payload.judgeAssertions = true;
|
|
2000
|
+
if (dryRun) payload.dryRun = true;
|
|
2001
|
+
if (invocation !== void 0) payload.invocation = invocation;
|
|
2002
|
+
const git = await resolvedGitState();
|
|
2003
|
+
if (git && !isEmptyGitState(git)) payload.git = git;
|
|
2004
|
+
const timeout = includeDbBranchLease ? REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS : 3e4;
|
|
2005
|
+
const response = await this.request("/api/sdk/replay/start", payload, { timeout });
|
|
2006
|
+
const { testRunId, testRunUrl, ...rest } = response;
|
|
2007
|
+
const experimentId = response.experimentId ?? testRunId;
|
|
2008
|
+
const experimentUrl = response.experimentUrl ?? testRunUrl;
|
|
2009
|
+
if (dryRun && response.experimentId === null) return {
|
|
2010
|
+
...rest,
|
|
2011
|
+
experimentId: null,
|
|
2012
|
+
experimentUrl: null
|
|
2013
|
+
};
|
|
2014
|
+
if (experimentId === void 0 || experimentId === null || experimentUrl === void 0 || experimentUrl === null) throw new BitfabError("Replay start response is missing the experiment ID or URL.");
|
|
2015
|
+
return {
|
|
2016
|
+
...rest,
|
|
2017
|
+
experimentId,
|
|
2018
|
+
experimentUrl
|
|
2019
|
+
};
|
|
2020
|
+
}
|
|
2021
|
+
async resumeReplay(experimentId, traceFunctionKey, codeChangeFiles, force) {
|
|
2022
|
+
const payload = {
|
|
2023
|
+
experimentId,
|
|
2024
|
+
traceFunctionKey,
|
|
2025
|
+
lazyDbBranchLease: true
|
|
2026
|
+
};
|
|
2027
|
+
if (force === true) payload.force = true;
|
|
2028
|
+
if (codeChangeFiles !== void 0) payload.codeChangeFiles = codeChangeFiles;
|
|
2029
|
+
const git = await resolvedGitState();
|
|
2030
|
+
if (git && !isEmptyGitState(git)) payload.git = git;
|
|
2031
|
+
const response = await this.request("/api/sdk/replay/resume", payload, { timeout: REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS });
|
|
2032
|
+
const { testRunId, testRunUrl, ...rest } = response;
|
|
2033
|
+
const resumedExperimentId = response.experimentId ?? testRunId;
|
|
2034
|
+
const experimentUrl = response.experimentUrl ?? testRunUrl;
|
|
2035
|
+
if (resumedExperimentId === void 0 || experimentUrl === void 0) throw new BitfabError("Replay resume response is missing the experiment ID or URL.");
|
|
2036
|
+
return {
|
|
2037
|
+
...rest,
|
|
2038
|
+
experimentId: resumedExperimentId,
|
|
2039
|
+
experimentUrl,
|
|
2040
|
+
work: rest.work ?? [],
|
|
2041
|
+
finished: rest.finished ?? [],
|
|
2042
|
+
skippedOriginalTraceIds: rest.skippedOriginalTraceIds ?? [],
|
|
2043
|
+
includeDbBranchLease: rest.includeDbBranchLease ?? false,
|
|
2044
|
+
dbBranchSettings: rest.dbBranchSettings ?? null
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
async getExternalSpan(spanId, options) {
|
|
2048
|
+
const query = options?.view === "replay" ? "?view=replay" : "";
|
|
2049
|
+
const url = `${this.serviceUrl}/api/sdk/externalSpans/${spanId}${query}`;
|
|
2050
|
+
const controller = new AbortController();
|
|
2051
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
2052
|
+
try {
|
|
2053
|
+
const response = await fetch(url, {
|
|
2054
|
+
method: "GET",
|
|
2055
|
+
headers: { Authorization: `Bearer ${this.resolveApiKey() ?? ""}` },
|
|
2056
|
+
signal: controller.signal
|
|
2057
|
+
});
|
|
2058
|
+
if (!response.ok) {
|
|
2059
|
+
const errorText = await response.text();
|
|
2060
|
+
throw new BitfabError(`HTTP ${response.status}: ${errorText.slice(0, 500)}`);
|
|
2061
|
+
}
|
|
2062
|
+
return await response.json();
|
|
2063
|
+
} catch (error) {
|
|
2064
|
+
if (error instanceof BitfabError) throw error;
|
|
2065
|
+
if (error instanceof Error) {
|
|
2066
|
+
if (error.name === "AbortError") throw new BitfabError("Request timed out after 30000ms");
|
|
2067
|
+
throw new BitfabError(error.message);
|
|
2068
|
+
}
|
|
2069
|
+
throw new BitfabError("Unknown error occurred");
|
|
2070
|
+
} finally {
|
|
2071
|
+
clearTimeout(timeoutId);
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
async getSpanTree(externalSpanId, options) {
|
|
2075
|
+
const searchParams = new URLSearchParams();
|
|
2076
|
+
if (options?.includeOutputs === false) searchParams.set("includeOutputs", "false");
|
|
2077
|
+
if (options?.includeRootOutput === false) searchParams.set("includeRootOutput", "false");
|
|
2078
|
+
const encodedQuery = searchParams.toString();
|
|
2079
|
+
const query = encodedQuery ? `?${encodedQuery}` : "";
|
|
2080
|
+
const url = `${this.serviceUrl}/api/sdk/replay/spanTree/${externalSpanId}${query}`;
|
|
2081
|
+
const controller = new AbortController();
|
|
2082
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
2083
|
+
try {
|
|
2084
|
+
const response = await fetch(url, {
|
|
2085
|
+
method: "GET",
|
|
2086
|
+
headers: { Authorization: `Bearer ${this.resolveApiKey() ?? ""}` },
|
|
2087
|
+
signal: controller.signal
|
|
2088
|
+
});
|
|
2089
|
+
if (!response.ok) {
|
|
2090
|
+
const errorText = await response.text();
|
|
2091
|
+
throw new BitfabError(`HTTP ${response.status}: ${errorText.slice(0, 500)}`);
|
|
2092
|
+
}
|
|
2093
|
+
return await response.json();
|
|
2094
|
+
} catch (error) {
|
|
2095
|
+
if (error instanceof BitfabError) throw error;
|
|
2096
|
+
if (error instanceof Error) {
|
|
2097
|
+
if (error.name === "AbortError") throw new BitfabError("Request timed out after 30000ms");
|
|
2098
|
+
throw new BitfabError(error.message);
|
|
2099
|
+
}
|
|
2100
|
+
throw new BitfabError("Unknown error occurred");
|
|
2101
|
+
} finally {
|
|
2102
|
+
clearTimeout(timeoutId);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
async getReplayStatus(experimentId, expectedSpanCounts) {
|
|
2106
|
+
return this.request("/api/sdk/replay/status", {
|
|
2107
|
+
...experimentIdWireFields(experimentId),
|
|
2108
|
+
expectedSpanCounts
|
|
2109
|
+
}, { timeout: 3e4 });
|
|
2110
|
+
}
|
|
2111
|
+
async completeReplay(experimentId) {
|
|
2112
|
+
return this.request("/api/sdk/replay/complete", experimentIdWireFields(experimentId), { timeout: REPLAY_COMPLETE_REQUEST_TIMEOUT_MS });
|
|
2113
|
+
}
|
|
2114
|
+
async interruptReplay(experimentId) {
|
|
2115
|
+
try {
|
|
2116
|
+
await this.request("/api/sdk/replay/interrupt", experimentIdWireFields(experimentId), { timeout: REPLAY_INTERRUPT_REQUEST_TIMEOUT_MS });
|
|
2117
|
+
return true;
|
|
2118
|
+
} catch {
|
|
2119
|
+
return false;
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
async heartbeatReplay(experimentId) {
|
|
2123
|
+
try {
|
|
2124
|
+
await this.request("/api/sdk/replay/heartbeat", experimentIdWireFields(experimentId), { timeout: REPLAY_HEARTBEAT_REQUEST_TIMEOUT_MS });
|
|
2125
|
+
} catch {}
|
|
2126
|
+
}
|
|
2127
|
+
async getReseedSource(traceId) {
|
|
2128
|
+
return this.get(`/api/sdk/traces/${encodeURIComponent(traceId)}/reseedSource`);
|
|
2129
|
+
}
|
|
2130
|
+
async reseedTrace(traceId, runTraceId) {
|
|
2131
|
+
return this.request(`/api/sdk/traces/${encodeURIComponent(traceId)}/reseed`, { runTraceId }, { timeout: 3e4 });
|
|
2132
|
+
}
|
|
2133
|
+
async resolveDbBranchLease(experimentId, traceId, dbBranchSettings, attempt) {
|
|
2134
|
+
return this.request("/api/sdk/replay/resolveDbBranchLease", {
|
|
2135
|
+
...experimentIdWireFields(experimentId),
|
|
2136
|
+
traceId,
|
|
2137
|
+
dbBranchSettings,
|
|
2138
|
+
...attempt !== void 0 && attempt > 0 ? { attempt } : {}
|
|
2139
|
+
}, { timeout: REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS });
|
|
2140
|
+
}
|
|
2141
|
+
async releaseDbBranchLease(neonBranchId) {
|
|
2142
|
+
await this.request("/api/sdk/replay/releaseDbBranchLease", { neonBranchId }, { timeout: 3e4 });
|
|
2143
|
+
}
|
|
2144
|
+
};
|
|
2145
|
+
function experimentIdWireFields(experimentId) {
|
|
2146
|
+
return {
|
|
2147
|
+
experimentId,
|
|
2148
|
+
testRunId: experimentId
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2151
|
+
//#endregion
|
|
2152
|
+
export { readEnv as C, MixedTracingError as S, getReplayContext as _, http_exports as a, gitRunner as b, recordCallerTraceMetadata as c, DECLARED_NODE_FIELD as d, ROOT_TRACE_FUNCTION_KEY_FIELD as f, MAX_COMPRESSIBLE_SPAN_CARRIER_BYTES as g, makeSpanOrigin as h, flushTraces as i, retireTraceMetadata as l, isFrameworkInstrumentation as m, SPAN_TYPES as n, unrefTimer as o, SimulationPlan as p, experimentIdWireFields as r, callerTraceMetadata as s, HttpClient as t, CONTENT_OFF_KEY as u, replayContextReady as v, __version__ as w, BitfabError as x, runWithReplayContext as y };
|
|
2153
|
+
|
|
2154
|
+
//# sourceMappingURL=http-CG1Irqxx.js.map
|