bitfab 0.54.14 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.cjs CHANGED
@@ -97,7 +97,7 @@ var __version__, __packageName__;
97
97
  var init_version_generated = __esm({
98
98
  "src/version.generated.ts"() {
99
99
  "use strict";
100
- __version__ = "0.54.14";
100
+ __version__ = "0.57.0";
101
101
  __packageName__ = "bitfab";
102
102
  }
103
103
  });
@@ -979,19 +979,6 @@ var init_spanOrigin = __esm({
979
979
  }
980
980
  });
981
981
 
982
- // src/unrefTimer.ts
983
- function unrefTimer(timer) {
984
- const handle = timer;
985
- if (typeof handle.unref === "function") {
986
- handle.unref();
987
- }
988
- }
989
- var init_unrefTimer = __esm({
990
- "src/unrefTimer.ts"() {
991
- "use strict";
992
- }
993
- });
994
-
995
982
  // src/simulationPlan.ts
996
983
  function planWaitSliceMs(timeoutMs) {
997
984
  return Math.min(SIMULATION_PLAN_READ_TIMEOUT_MS, Math.max(timeoutMs, 0) / 2);
@@ -1064,6 +1051,10 @@ function simulationPlanEnvDisabled() {
1064
1051
  function missingSimulationPlanEndpoint(error) {
1065
1052
  return error instanceof BitfabError && error.status === 404;
1066
1053
  }
1054
+ function isTraceRootSpan(payload) {
1055
+ const parentId = rawSpanOf(payload)?.parent_id;
1056
+ return parentId === void 0 || parentId === null;
1057
+ }
1067
1058
  var SIMULATION_PLAN_REFRESH_MS, SIMULATION_PLAN_RETRY_MS, SIMULATION_PLAN_READ_TIMEOUT_MS, SIMULATION_PLAN_MAX_HELD, DISABLE_SIMULATION_PLAN_ENV, ROOT_TRACE_FUNCTION_KEY_FIELD, CONTENT_OFF_KEY, CONTENT_KEYS, SimulationPlan;
1068
1059
  var init_simulationPlan = __esm({
1069
1060
  "src/simulationPlan.ts"() {
@@ -1072,7 +1063,6 @@ var init_simulationPlan = __esm({
1072
1063
  init_policyRefresh();
1073
1064
  init_readEnv();
1074
1065
  init_spanOrigin();
1075
- init_unrefTimer();
1076
1066
  init_warnOnce();
1077
1067
  SIMULATION_PLAN_REFRESH_MS = 6e4;
1078
1068
  SIMULATION_PLAN_RETRY_MS = 1e4;
@@ -1087,14 +1077,16 @@ var init_simulationPlan = __esm({
1087
1077
  this.source = source;
1088
1078
  this.enabled = enabled;
1089
1079
  this.policyRefresh = new PolicyRefresh();
1090
- this.retryPending = false;
1091
- this.waitingForFirstLoad = 0;
1080
+ this.firstReadOver = false;
1081
+ this.rootWaitOver = false;
1092
1082
  this.held = [];
1093
- this.droppedWhileHolding = 0;
1094
1083
  this.stopped = false;
1095
1084
  this.loaded = new Promise((resolve) => {
1096
1085
  this.resolveLoaded = resolve;
1097
1086
  });
1087
+ this.firstReadEnded = new Promise((resolve) => {
1088
+ this.resolveFirstReadEnded = resolve;
1089
+ });
1098
1090
  }
1099
1091
  disabled() {
1100
1092
  return !this.enabled || simulationPlanEnvDisabled();
@@ -1112,19 +1104,21 @@ var init_simulationPlan = __esm({
1112
1104
  "sim-plan-unreadable",
1113
1105
  "the sim plan response was not understood"
1114
1106
  );
1115
- return;
1107
+ } else {
1108
+ this.markLoaded(parsed);
1116
1109
  }
1117
- this.markLoaded(parsed);
1110
+ this.endFirstRead();
1118
1111
  },
1119
1112
  (error) => {
1120
1113
  if (missingSimulationPlanEndpoint(error)) {
1121
1114
  this.markLoaded(/* @__PURE__ */ new Map());
1122
- return;
1115
+ } else {
1116
+ this.scheduleRetry(
1117
+ "sim-plan-unavailable",
1118
+ `could not read the sim plan: ${error instanceof Error ? error.message : String(error)}`
1119
+ );
1123
1120
  }
1124
- this.scheduleRetry(
1125
- "sim-plan-unavailable",
1126
- `could not read the sim plan: ${error instanceof Error ? error.message : String(error)}`
1127
- );
1121
+ this.endFirstRead();
1128
1122
  }
1129
1123
  );
1130
1124
  }
@@ -1134,11 +1128,8 @@ var init_simulationPlan = __esm({
1134
1128
  }
1135
1129
  this.contentOffByKey = parsed;
1136
1130
  this.policyRefresh.hold(SIMULATION_PLAN_REFRESH_MS);
1137
- this.retryPending = false;
1138
- this.clearRetryTimer();
1139
1131
  this.resolveLoaded?.();
1140
1132
  this.resolveLoaded = void 0;
1141
- this.releaseHeld();
1142
1133
  }
1143
1134
  scheduleRetry(warnKey, reason) {
1144
1135
  if (this.stopped) {
@@ -1148,39 +1139,50 @@ var init_simulationPlan = __esm({
1148
1139
  if (this.contentOffByKey !== void 0) {
1149
1140
  return;
1150
1141
  }
1151
- this.retryPending = true;
1152
1142
  warnOnce(
1153
1143
  warnKey,
1154
- `${reason}. Spans are held until the first read succeeds; while a record is held it is retried every ${SIMULATION_PLAN_RETRY_MS / 1e3}s, otherwise on the next span.`
1144
+ `${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.`
1155
1145
  );
1156
- this.armRetry();
1157
1146
  }
1158
- holdsWork() {
1159
- return this.held.length > 0 || this.waitingForFirstLoad > 0;
1160
- }
1161
- armRetry() {
1162
- if (this.stopped || !this.retryPending || this.retryTimer !== void 0 || !this.holdsWork()) {
1163
- return;
1147
+ endFirstRead() {
1148
+ this.endRootWait();
1149
+ if (!this.firstReadOver) {
1150
+ this.firstReadOver = true;
1151
+ this.resolveFirstReadEnded?.();
1152
+ this.resolveFirstReadEnded = void 0;
1164
1153
  }
1165
- const timer = setTimeout(() => {
1166
- this.retryTimer = void 0;
1167
- this.policyRefresh.releaseHold();
1168
- this.refresh();
1169
- }, SIMULATION_PLAN_RETRY_MS);
1170
- unrefTimer(timer);
1171
- this.retryTimer = timer;
1154
+ this.releaseHeld();
1172
1155
  }
1173
- clearRetryTimer() {
1174
- if (this.retryTimer !== void 0) {
1175
- clearTimeout(this.retryTimer);
1176
- this.retryTimer = void 0;
1156
+ endRootWait() {
1157
+ this.rootWaitOver = true;
1158
+ if (this.rootWaitTimer !== void 0) {
1159
+ clearTimeout(this.rootWaitTimer);
1160
+ this.rootWaitTimer = void 0;
1177
1161
  }
1162
+ this.resolveRootWait?.();
1163
+ this.resolveRootWait = void 0;
1178
1164
  }
1179
- syncRetryTimer() {
1180
- if (this.holdsWork()) {
1181
- return;
1165
+ waitForFirstRead() {
1166
+ this.refresh();
1167
+ if (this.rootWaitOver || this.disabled() || !this.holdingForFirstRead()) {
1168
+ return void 0;
1182
1169
  }
1183
- this.clearRetryTimer();
1170
+ if (this.rootWait === void 0) {
1171
+ this.rootWait = new Promise((resolve) => {
1172
+ this.resolveRootWait = resolve;
1173
+ });
1174
+ this.rootWaitTimer = setTimeout(
1175
+ () => this.endRootWait(),
1176
+ SIMULATION_PLAN_READ_TIMEOUT_MS
1177
+ );
1178
+ }
1179
+ return this.rootWait;
1180
+ }
1181
+ holdingForFirstRead() {
1182
+ return this.contentOffByKey === void 0 && !this.firstReadOver && !this.stopped;
1183
+ }
1184
+ unavailableNow() {
1185
+ return !this.disabled() && this.contentOffByKey === void 0 && this.firstReadOver;
1184
1186
  }
1185
1187
  firstLoad() {
1186
1188
  if (this.contentOffByKey !== void 0 || this.stopped || this.disabled()) {
@@ -1190,19 +1192,20 @@ var init_simulationPlan = __esm({
1190
1192
  }
1191
1193
  send(payload, traceFunctionKey, submit) {
1192
1194
  this.refresh();
1193
- if (this.stopped || this.disabled() || traceFunctionKey === void 0 || spanNameOf(payload) === void 0 || recordedByFramework(payload)) {
1195
+ if (this.disabled() || traceFunctionKey === void 0 || spanNameOf(payload) === void 0 || recordedByFramework(payload)) {
1194
1196
  submit(payload);
1195
1197
  return;
1196
1198
  }
1197
- if (this.contentOffByKey === void 0) {
1198
- this.hold({ payload, traceFunctionKey, submit });
1199
+ const entry = { payload, traceFunctionKey, submit };
1200
+ if (this.holdingForFirstRead()) {
1201
+ this.hold(entry);
1199
1202
  return;
1200
1203
  }
1201
- this.submitEntry({ payload, traceFunctionKey, submit });
1204
+ this.submitEntry(entry);
1202
1205
  }
1203
1206
  sendTrace(payload, submit) {
1204
1207
  this.refresh();
1205
- if (this.stopped || this.disabled() || this.contentOffByKey !== void 0 || !this.holdsSpanOfTrace(traceIdOf(payload))) {
1208
+ if (this.disabled() || !this.holdingForFirstRead() || !this.holdsSpanOfTrace(traceIdOf(payload))) {
1206
1209
  submit(payload);
1207
1210
  return;
1208
1211
  }
@@ -1218,17 +1221,34 @@ var init_simulationPlan = __esm({
1218
1221
  }
1219
1222
  hold(entry) {
1220
1223
  this.held.push(entry);
1224
+ let overflowed = false;
1221
1225
  while (this.held.length > SIMULATION_PLAN_MAX_HELD) {
1222
- this.held.shift();
1223
- this.droppedWhileHolding += 1;
1226
+ const oldest = this.held.shift();
1227
+ this.submitEntry(oldest);
1228
+ overflowed = true;
1229
+ }
1230
+ if (overflowed) {
1231
+ warnOnce(
1232
+ "sim-plan-held-overflow",
1233
+ `more than ${SIMULATION_PLAN_MAX_HELD} records were waiting for the sim plan, so the oldest were sent without their inputs and outputs.`
1234
+ );
1235
+ }
1236
+ }
1237
+ payloadToSend(entry) {
1238
+ if (entry.traceFunctionKey === void 0) {
1239
+ return entry.payload;
1240
+ }
1241
+ if (this.contentOffByKey !== void 0) {
1242
+ return this.apply(entry.payload, entry.traceFunctionKey);
1243
+ }
1244
+ if (recordedByFramework(entry.payload) || isTraceRootSpan(entry.payload)) {
1245
+ return entry.payload;
1224
1246
  }
1225
- this.armRetry();
1247
+ return stripContent(entry.payload);
1226
1248
  }
1227
1249
  submitEntry(entry) {
1228
1250
  try {
1229
- entry.submit(
1230
- entry.traceFunctionKey === void 0 ? entry.payload : this.apply(entry.payload, entry.traceFunctionKey)
1231
- );
1251
+ entry.submit(this.payloadToSend(entry));
1232
1252
  } catch (error) {
1233
1253
  warnOnce(
1234
1254
  "sim-plan-held-span-dropped",
@@ -1239,63 +1259,38 @@ var init_simulationPlan = __esm({
1239
1259
  releaseHeld() {
1240
1260
  const held = this.held;
1241
1261
  this.held = [];
1242
- this.syncRetryTimer();
1243
- this.warnDropped();
1244
1262
  for (const entry of held) {
1245
1263
  this.submitEntry(entry);
1246
1264
  }
1247
1265
  }
1248
- warnDropped() {
1249
- if (this.droppedWhileHolding === 0) {
1250
- return;
1251
- }
1252
- const dropped = this.droppedWhileHolding;
1253
- this.droppedWhileHolding = 0;
1254
- warnOnce(
1255
- "sim-plan-held-overflow",
1256
- `${dropped} record(s) were dropped while the sim plan was still loading; at most ${SIMULATION_PLAN_MAX_HELD} are held per client.`
1257
- );
1258
- }
1259
- warnNeverLoaded() {
1266
+ releaseHeldWithoutPlan() {
1260
1267
  if (this.held.length === 0) {
1261
1268
  return;
1262
1269
  }
1263
- warnOnce(
1264
- "sim-plan-never-loaded",
1265
- `${this.held.length} record(s) were not sent because the sim plan never loaded`
1266
- );
1270
+ if (this.contentOffByKey === void 0) {
1271
+ warnOnce(
1272
+ "sim-plan-not-loaded-at-release",
1273
+ `${this.held.length} record(s) were sent without their inputs and outputs because the sim plan had not loaded`
1274
+ );
1275
+ }
1276
+ this.releaseHeld();
1267
1277
  }
1268
1278
  async release(timeoutMs) {
1269
1279
  this.refresh();
1270
- if (this.holdsWork()) {
1271
- await this.waitForFirstLoad(timeoutMs);
1280
+ if (this.held.length > 0) {
1281
+ await this.waitForFirstReadEnd(timeoutMs);
1272
1282
  }
1273
- this.warnNeverLoaded();
1274
- this.warnDropped();
1275
- return this.held.length === 0;
1283
+ this.releaseHeldWithoutPlan();
1276
1284
  }
1277
- waitForFirstLoad(timeoutMs) {
1278
- const firstLoad = this.firstLoad();
1279
- if (firstLoad === void 0) {
1285
+ waitForFirstReadEnd(timeoutMs) {
1286
+ if (this.firstReadOver) {
1280
1287
  return Promise.resolve();
1281
1288
  }
1282
- this.waitingForFirstLoad += 1;
1283
- this.armRetry();
1284
1289
  return new Promise((resolve) => {
1285
- let settled2 = false;
1286
- const finish = () => {
1287
- if (settled2) {
1288
- return;
1289
- }
1290
- settled2 = true;
1291
- this.waitingForFirstLoad -= 1;
1292
- this.syncRetryTimer();
1293
- resolve();
1294
- };
1295
- const timer = setTimeout(finish, Math.max(timeoutMs, 0));
1296
- void firstLoad.then(() => {
1290
+ const timer = setTimeout(resolve, Math.max(timeoutMs, 0));
1291
+ void this.firstReadEnded.then(() => {
1297
1292
  clearTimeout(timer);
1298
- finish();
1293
+ resolve();
1299
1294
  });
1300
1295
  });
1301
1296
  }
@@ -1303,16 +1298,16 @@ var init_simulationPlan = __esm({
1303
1298
  if (this.stopped) {
1304
1299
  return;
1305
1300
  }
1301
+ this.releaseHeldWithoutPlan();
1306
1302
  this.stopped = true;
1307
- this.retryPending = false;
1308
- this.clearRetryTimer();
1309
- this.warnNeverLoaded();
1310
- this.held = [];
1311
- this.warnDropped();
1303
+ this.endFirstRead();
1312
1304
  }
1313
1305
  contentOff(traceFunctionKey, spanName) {
1314
1306
  return this.contentOffByKey?.get(traceFunctionKey)?.has(spanName) === true;
1315
1307
  }
1308
+ contentOffNow(traceFunctionKey, spanName) {
1309
+ return !this.stopped && !this.disabled() && this.contentOff(traceFunctionKey, spanName);
1310
+ }
1316
1311
  apply(payload, traceFunctionKey) {
1317
1312
  if (recordedByFramework(payload)) {
1318
1313
  return payload;
@@ -1443,6 +1438,19 @@ var init_transportTypes = __esm({
1443
1438
  }
1444
1439
  });
1445
1440
 
1441
+ // src/unrefTimer.ts
1442
+ function unrefTimer(timer) {
1443
+ const handle = timer;
1444
+ if (typeof handle.unref === "function") {
1445
+ handle.unref();
1446
+ }
1447
+ }
1448
+ var init_unrefTimer = __esm({
1449
+ "src/unrefTimer.ts"() {
1450
+ "use strict";
1451
+ }
1452
+ });
1453
+
1446
1454
  // src/otel.ts
1447
1455
  function readBoundedIntEnv(name, max, fallback, warnKey) {
1448
1456
  const raw = readEnv(name);
@@ -8286,6 +8294,25 @@ var BitfabVercelAiHandler = class {
8286
8294
  // src/client.ts
8287
8295
  init_warnOnce();
8288
8296
  var activeTraceStates = /* @__PURE__ */ new Map();
8297
+ function fitsTraceSpanBudget(payload) {
8298
+ if (!recordedByFramework(payload)) {
8299
+ return true;
8300
+ }
8301
+ const traceId = traceIdOf(payload);
8302
+ const spanBudget = traceId === void 0 ? void 0 : activeTraceStates.get(traceId)?.spanBudget;
8303
+ if (spanBudget === void 0) {
8304
+ return true;
8305
+ }
8306
+ if (spanBudget.spansUsed >= spanBudget.maxSpans) {
8307
+ spanBudget.truncate();
8308
+ return false;
8309
+ }
8310
+ spanBudget.spansUsed += 1;
8311
+ return true;
8312
+ }
8313
+ function rootTraceFunctionKeyOfTrace(traceId, fallback) {
8314
+ return activeTraceStates.get(traceId)?.traceFunctionKey ?? fallback;
8315
+ }
8289
8316
  function rootTraceFunctionKeyOf(payload) {
8290
8317
  const captured = payload[ROOT_TRACE_FUNCTION_KEY_FIELD];
8291
8318
  if (typeof captured === "string") {
@@ -8661,7 +8688,8 @@ function readBooleanEnv(name) {
8661
8688
  return void 0;
8662
8689
  }
8663
8690
  var DEFAULT_AUTO_TRACE_MAX_DEPTH = 30;
8664
- var DEFAULT_AUTO_TRACE_MAX_SPANS = 500;
8691
+ var DEFAULT_AUTO_TRACE_MAX_SPANS = 2048;
8692
+ var DEFAULT_AUTO_TRACE_MAX_CAPTURED_SUBTREE_SPANS = 512;
8665
8693
  var AUTO_TRACE_PROTOCOL = "ts-auto-v1";
8666
8694
  function spanOwnerName(receiver) {
8667
8695
  if (typeof receiver === "function") {
@@ -8732,6 +8760,9 @@ var Bitfab = class {
8732
8760
  this.httpClient.externalTraceTransform = (payload, submit) => this.simulationPlan.sendTrace(payload, submit);
8733
8761
  this.httpClient.releaseHeldExternalSpans = (timeoutMs) => this.simulationPlan.release(timeoutMs);
8734
8762
  this.httpClient.stopSimulationPlan = () => this.simulationPlan.stop();
8763
+ if (this.findApiKey(false) !== void 0) {
8764
+ this.simulationPlan.refresh();
8765
+ }
8735
8766
  this.datasets = new DatasetsClient(this.httpClient);
8736
8767
  this.assertionCategories = new AssertionCategoriesClient(this.httpClient);
8737
8768
  this.traces = new TracesClient(this.httpClient);
@@ -8888,10 +8919,23 @@ var Bitfab = class {
8888
8919
  options.maxDepth,
8889
8920
  DEFAULT_AUTO_TRACE_MAX_DEPTH
8890
8921
  );
8922
+ if (options.maxSpans !== void 0 && options.maxSpans < 1) {
8923
+ throw new BitfabError(
8924
+ `maxSpans must be at least 1 because the root span counts toward it (got ${options.maxSpans})`
8925
+ );
8926
+ }
8891
8927
  const maxSpans = autoTraceLimit(
8892
8928
  options.maxSpans,
8893
8929
  DEFAULT_AUTO_TRACE_MAX_SPANS
8894
8930
  );
8931
+ const maxCapturedSubtreeSpans = Math.min(
8932
+ autoTraceLimit(
8933
+ options.maxCapturedSubtreeSpans,
8934
+ DEFAULT_AUTO_TRACE_MAX_CAPTURED_SUBTREE_SPANS
8935
+ ),
8936
+ maxSpans
8937
+ );
8938
+ const rootIsAsync = fn.constructor.name === "AsyncFunction";
8895
8939
  const excluded = new Set(options.exclude ?? []);
8896
8940
  const includeWrappers = options.includeWrappers ?? false;
8897
8941
  const rootNameFor = (receiver) => options.name ?? (fn.name !== "" ? qualifiedSpanName(receiver, name) ?? name : name);
@@ -8907,7 +8951,7 @@ var Bitfab = class {
8907
8951
  spanOptions,
8908
8952
  function(...args) {
8909
8953
  self.simulationPlan.refresh();
8910
- let spansUsed = 0;
8954
+ let capturedSubtreeCount = 0;
8911
8955
  let truncated = false;
8912
8956
  const warnTruncated = () => {
8913
8957
  if (!truncated) {
@@ -8917,15 +8961,27 @@ var Bitfab = class {
8917
8961
  protocol: AUTO_TRACE_PROTOCOL,
8918
8962
  truncated: true,
8919
8963
  maxDepth,
8920
- maxSpans
8964
+ maxSpans,
8965
+ maxCapturedSubtreeSpans
8921
8966
  }
8922
8967
  });
8923
8968
  }
8924
8969
  warnOnce(
8925
8970
  `auto-trace-truncated:${traceFunctionKey}`,
8926
- `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
8971
+ `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxCapturedSubtreeSpans=${maxCapturedSubtreeSpans}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits, declare the calls you need with node(), or narrow the subtree with exclude.`
8927
8972
  );
8928
8973
  };
8974
+ const rootSpanStack = getSpanStack();
8975
+ const spanBudget = {
8976
+ spansUsed: 1,
8977
+ maxSpans,
8978
+ truncate: () => runWithSpanStack(rootSpanStack, warnTruncated)
8979
+ };
8980
+ const rootSpan = rootSpanStack[rootSpanStack.length - 1];
8981
+ const rootTraceState = rootSpan === void 0 ? void 0 : activeTraceStates.get(rootSpan.traceId);
8982
+ if (rootTraceState !== void 0 && rootTraceState.spanBudget === void 0) {
8983
+ rootTraceState.spanBudget = spanBudget;
8984
+ }
8929
8985
  const spanStackOf = (entry) => entry.spanStack;
8930
8986
  const openChild = (entry, childOptions, inputs, isAsync, invokeFn) => {
8931
8987
  const runInside = () => runWithAutoTraceEntry(
@@ -8954,12 +9010,25 @@ var Bitfab = class {
8954
9010
  return tracedChild(...inputs);
8955
9011
  });
8956
9012
  };
8957
- const overBudget = (entry) => {
8958
- if (entry.depth < maxDepth && spansUsed < maxSpans) {
8959
- return false;
9013
+ const rootTraceFunctionKeyOfEntry = (entry) => {
9014
+ const stack = spanStackOf(entry);
9015
+ const innermost = stack[stack.length - 1];
9016
+ return innermost === void 0 ? traceFunctionKey : rootTraceFunctionKeyOfTrace(innermost.traceId, traceFunctionKey);
9017
+ };
9018
+ const recordsSpan = (entry, spanName, declared) => {
9019
+ const countsTowardCapturedSubtree = !declared && !self.simulationPlan.contentOffNow(
9020
+ rootTraceFunctionKeyOfEntry(entry),
9021
+ spanName
9022
+ );
9023
+ if (entry.depth < maxDepth && spanBudget.spansUsed < maxSpans && (!countsTowardCapturedSubtree || capturedSubtreeCount < maxCapturedSubtreeSpans)) {
9024
+ spanBudget.spansUsed += 1;
9025
+ if (countsTowardCapturedSubtree) {
9026
+ capturedSubtreeCount += 1;
9027
+ }
9028
+ return true;
8960
9029
  }
8961
9030
  runWithSpanStack(spanStackOf(entry), warnTruncated);
8962
- return true;
9031
+ return false;
8963
9032
  };
8964
9033
  const autoTraceContext = {
8965
9034
  traceFunctionKey,
@@ -8973,13 +9042,13 @@ var Bitfab = class {
8973
9042
  if (nodeConfiguration?.capture === false) {
8974
9043
  return clearAutoTraceNodeConfiguration(invokeFn);
8975
9044
  }
8976
- if (overBudget(entry)) {
9045
+ const spanName = nodeConfiguration?.name ?? definition.name;
9046
+ if (!recordsSpan(entry, spanName, nodeConfiguration !== void 0)) {
8977
9047
  return invokeWithoutNode();
8978
9048
  }
8979
- spansUsed += 1;
8980
9049
  const mockOnReplay = nodeConfiguration?.mockOnReplay ?? options.mockOnReplayDefault;
8981
9050
  const childOptions = {
8982
- name: nodeConfiguration?.name ?? definition.name,
9051
+ name: spanName,
8983
9052
  type: nodeConfiguration?.type ?? "function",
8984
9053
  captureWhen: "nested",
8985
9054
  surface: "opt-out",
@@ -9006,10 +9075,9 @@ var Bitfab = class {
9006
9075
  );
9007
9076
  },
9008
9077
  invokeNestedRoot(nestedName, nestedFunctionName, inputs, invokeFn, entry, link) {
9009
- if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || overBudget(entry)) {
9078
+ if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || !recordsSpan(entry, nestedName, true)) {
9010
9079
  return invokeFn();
9011
9080
  }
9012
- spansUsed += 1;
9013
9081
  const childOptions = {
9014
9082
  name: nestedName,
9015
9083
  type: "function",
@@ -9036,6 +9104,12 @@ var Bitfab = class {
9036
9104
  }
9037
9105
  const enclosing = currentAutoTraceEntries();
9038
9106
  if (enclosing.length === 0) {
9107
+ const firstPlanRead = rootIsAsync ? self.simulationPlan.waitForFirstRead() : void 0;
9108
+ if (firstPlanRead !== void 0) {
9109
+ return firstPlanRead.then(
9110
+ () => tracedRoot.apply(this, args)
9111
+ );
9112
+ }
9039
9113
  return tracedRoot.apply(this, args);
9040
9114
  }
9041
9115
  const link = getReplayContext() || inSeedScope() ? void 0 : { traceFunctionKey };
@@ -9082,6 +9156,9 @@ var Bitfab = class {
9082
9156
  return autoTraceRoot;
9083
9157
  }
9084
9158
  applySimulationPlan(payload, submit) {
9159
+ if (!fitsTraceSpanBudget(payload)) {
9160
+ return;
9161
+ }
9085
9162
  this.simulationPlan.send(payload, rootTraceFunctionKeyOf(payload), submit);
9086
9163
  }
9087
9164
  /**
@@ -9116,15 +9193,24 @@ var Bitfab = class {
9116
9193
  * from the environment. Once a non-empty key is found it is cached, so an
9117
9194
  * early resolve that found nothing never poisons a later one.
9118
9195
  */
9119
- resolveApiKey() {
9196
+ findApiKey(callsKeyFunction) {
9120
9197
  if (this.resolvedApiKey !== void 0) {
9121
9198
  return this.resolvedApiKey;
9122
9199
  }
9200
+ if (typeof this.apiKeyConfig === "function" && !callsKeyFunction) {
9201
+ return void 0;
9202
+ }
9123
9203
  const fromConfig = typeof this.apiKeyConfig === "function" ? this.apiKeyConfig() : this.apiKeyConfig;
9124
9204
  const candidate = fromConfig && fromConfig.trim() !== "" ? fromConfig : readEnv2("BITFAB_API_KEY");
9125
9205
  const key = candidate && candidate.trim() !== "" ? candidate : void 0;
9126
9206
  if (key) {
9127
9207
  this.resolvedApiKey = key;
9208
+ }
9209
+ return key;
9210
+ }
9211
+ resolveApiKey() {
9212
+ const key = this.findApiKey(true);
9213
+ if (key) {
9128
9214
  return key;
9129
9215
  }
9130
9216
  if (this.strict) {
@@ -9744,7 +9830,10 @@ var Bitfab = class {
9744
9830
  self.httpClient.traceCompletion.start(traceId, spanId);
9745
9831
  startedSpan = { traceId, spanId };
9746
9832
  const functionName = fn.name !== "" ? fn.name : void 0;
9747
- const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
9833
+ const rootTraceFunctionKey = rootTraceFunctionKeyOfTrace(
9834
+ traceId,
9835
+ traceFunctionKey
9836
+ );
9748
9837
  const baseSpanParams = {
9749
9838
  traceFunctionKey,
9750
9839
  rootTraceFunctionKey,
@@ -10266,14 +10355,25 @@ var Bitfab = class {
10266
10355
  ...params.testRunId && { testRunId: params.testRunId }
10267
10356
  });
10268
10357
  }
10358
+ contentOffBySimulationPlan(params) {
10359
+ if (params.rootTraceFunctionKey === void 0 || isFrameworkInstrumentation(params.instrumentation)) {
10360
+ return false;
10361
+ }
10362
+ return this.simulationPlan.contentOffNow(
10363
+ params.rootTraceFunctionKey,
10364
+ params.spanName
10365
+ ) || params.parentSpanId !== null && this.simulationPlan.unavailableNow();
10366
+ }
10269
10367
  /**
10270
10368
  * Send a wrapper span from function execution.
10271
10369
  * Internal method to record spans when using withSpan.
10272
10370
  * Queued on the client's span transport; delivery is the transport's job.
10273
10371
  */
10274
10372
  sendWrapperSpan(params) {
10275
- const serializedInputs = params.captureContent ? serializeValue(params.inputs) : void 0;
10276
- const serializedResult = params.captureContent ? serializeValue(params.result) : void 0;
10373
+ const contentOff = this.contentOffBySimulationPlan(params);
10374
+ const buildsContent = params.captureContent && !contentOff;
10375
+ const serializedInputs = buildsContent ? serializeValue(params.inputs) : void 0;
10376
+ const serializedResult = buildsContent ? serializeValue(params.result) : void 0;
10277
10377
  const externalSpan = {
10278
10378
  id: params.spanId,
10279
10379
  trace_id: params.traceId,
@@ -10324,7 +10424,8 @@ var Bitfab = class {
10324
10424
  ...params.captureContent && params.contexts && params.contexts.length > 0 && {
10325
10425
  contexts: params.contexts
10326
10426
  },
10327
- ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt }
10427
+ ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt },
10428
+ ...contentOff && { [CONTENT_OFF_KEY]: true }
10328
10429
  }
10329
10430
  };
10330
10431
  if (params.parentSpanId) {