@bitfab/sdk 0.54.14 → 0.57.1

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
@@ -88,7 +88,7 @@ var __version__, __packageName__;
88
88
  var init_version_generated = __esm({
89
89
  "src/version.generated.ts"() {
90
90
  "use strict";
91
- __version__ = "0.54.14";
91
+ __version__ = "0.57.1";
92
92
  __packageName__ = "@bitfab/sdk";
93
93
  }
94
94
  });
@@ -970,19 +970,6 @@ var init_spanOrigin = __esm({
970
970
  }
971
971
  });
972
972
 
973
- // src/unrefTimer.ts
974
- function unrefTimer(timer) {
975
- const handle = timer;
976
- if (typeof handle.unref === "function") {
977
- handle.unref();
978
- }
979
- }
980
- var init_unrefTimer = __esm({
981
- "src/unrefTimer.ts"() {
982
- "use strict";
983
- }
984
- });
985
-
986
973
  // src/simulationPlan.ts
987
974
  function planWaitSliceMs(timeoutMs) {
988
975
  return Math.min(SIMULATION_PLAN_READ_TIMEOUT_MS, Math.max(timeoutMs, 0) / 2);
@@ -1055,6 +1042,10 @@ function simulationPlanEnvDisabled() {
1055
1042
  function missingSimulationPlanEndpoint(error) {
1056
1043
  return error instanceof BitfabError && error.status === 404;
1057
1044
  }
1045
+ function isTraceRootSpan(payload) {
1046
+ const parentId = rawSpanOf(payload)?.parent_id;
1047
+ return parentId === void 0 || parentId === null;
1048
+ }
1058
1049
  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;
1059
1050
  var init_simulationPlan = __esm({
1060
1051
  "src/simulationPlan.ts"() {
@@ -1063,7 +1054,6 @@ var init_simulationPlan = __esm({
1063
1054
  init_policyRefresh();
1064
1055
  init_readEnv();
1065
1056
  init_spanOrigin();
1066
- init_unrefTimer();
1067
1057
  init_warnOnce();
1068
1058
  SIMULATION_PLAN_REFRESH_MS = 6e4;
1069
1059
  SIMULATION_PLAN_RETRY_MS = 1e4;
@@ -1078,14 +1068,16 @@ var init_simulationPlan = __esm({
1078
1068
  this.source = source;
1079
1069
  this.enabled = enabled;
1080
1070
  this.policyRefresh = new PolicyRefresh();
1081
- this.retryPending = false;
1082
- this.waitingForFirstLoad = 0;
1071
+ this.firstReadOver = false;
1072
+ this.rootWaitOver = false;
1083
1073
  this.held = [];
1084
- this.droppedWhileHolding = 0;
1085
1074
  this.stopped = false;
1086
1075
  this.loaded = new Promise((resolve) => {
1087
1076
  this.resolveLoaded = resolve;
1088
1077
  });
1078
+ this.firstReadEnded = new Promise((resolve) => {
1079
+ this.resolveFirstReadEnded = resolve;
1080
+ });
1089
1081
  }
1090
1082
  disabled() {
1091
1083
  return !this.enabled || simulationPlanEnvDisabled();
@@ -1103,19 +1095,21 @@ var init_simulationPlan = __esm({
1103
1095
  "sim-plan-unreadable",
1104
1096
  "the sim plan response was not understood"
1105
1097
  );
1106
- return;
1098
+ } else {
1099
+ this.markLoaded(parsed);
1107
1100
  }
1108
- this.markLoaded(parsed);
1101
+ this.endFirstRead();
1109
1102
  },
1110
1103
  (error) => {
1111
1104
  if (missingSimulationPlanEndpoint(error)) {
1112
1105
  this.markLoaded(/* @__PURE__ */ new Map());
1113
- return;
1106
+ } else {
1107
+ this.scheduleRetry(
1108
+ "sim-plan-unavailable",
1109
+ `could not read the sim plan: ${error instanceof Error ? error.message : String(error)}`
1110
+ );
1114
1111
  }
1115
- this.scheduleRetry(
1116
- "sim-plan-unavailable",
1117
- `could not read the sim plan: ${error instanceof Error ? error.message : String(error)}`
1118
- );
1112
+ this.endFirstRead();
1119
1113
  }
1120
1114
  );
1121
1115
  }
@@ -1125,11 +1119,8 @@ var init_simulationPlan = __esm({
1125
1119
  }
1126
1120
  this.contentOffByKey = parsed;
1127
1121
  this.policyRefresh.hold(SIMULATION_PLAN_REFRESH_MS);
1128
- this.retryPending = false;
1129
- this.clearRetryTimer();
1130
1122
  this.resolveLoaded?.();
1131
1123
  this.resolveLoaded = void 0;
1132
- this.releaseHeld();
1133
1124
  }
1134
1125
  scheduleRetry(warnKey, reason) {
1135
1126
  if (this.stopped) {
@@ -1139,39 +1130,50 @@ var init_simulationPlan = __esm({
1139
1130
  if (this.contentOffByKey !== void 0) {
1140
1131
  return;
1141
1132
  }
1142
- this.retryPending = true;
1143
1133
  warnOnce(
1144
1134
  warnKey,
1145
- `${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.`
1135
+ `${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.`
1146
1136
  );
1147
- this.armRetry();
1148
1137
  }
1149
- holdsWork() {
1150
- return this.held.length > 0 || this.waitingForFirstLoad > 0;
1151
- }
1152
- armRetry() {
1153
- if (this.stopped || !this.retryPending || this.retryTimer !== void 0 || !this.holdsWork()) {
1154
- return;
1138
+ endFirstRead() {
1139
+ this.endRootWait();
1140
+ if (!this.firstReadOver) {
1141
+ this.firstReadOver = true;
1142
+ this.resolveFirstReadEnded?.();
1143
+ this.resolveFirstReadEnded = void 0;
1155
1144
  }
1156
- const timer = setTimeout(() => {
1157
- this.retryTimer = void 0;
1158
- this.policyRefresh.releaseHold();
1159
- this.refresh();
1160
- }, SIMULATION_PLAN_RETRY_MS);
1161
- unrefTimer(timer);
1162
- this.retryTimer = timer;
1145
+ this.releaseHeld();
1163
1146
  }
1164
- clearRetryTimer() {
1165
- if (this.retryTimer !== void 0) {
1166
- clearTimeout(this.retryTimer);
1167
- this.retryTimer = void 0;
1147
+ endRootWait() {
1148
+ this.rootWaitOver = true;
1149
+ if (this.rootWaitTimer !== void 0) {
1150
+ clearTimeout(this.rootWaitTimer);
1151
+ this.rootWaitTimer = void 0;
1168
1152
  }
1153
+ this.resolveRootWait?.();
1154
+ this.resolveRootWait = void 0;
1169
1155
  }
1170
- syncRetryTimer() {
1171
- if (this.holdsWork()) {
1172
- return;
1156
+ waitForFirstRead() {
1157
+ this.refresh();
1158
+ if (this.rootWaitOver || this.disabled() || !this.holdingForFirstRead()) {
1159
+ return void 0;
1173
1160
  }
1174
- this.clearRetryTimer();
1161
+ if (this.rootWait === void 0) {
1162
+ this.rootWait = new Promise((resolve) => {
1163
+ this.resolveRootWait = resolve;
1164
+ });
1165
+ this.rootWaitTimer = setTimeout(
1166
+ () => this.endRootWait(),
1167
+ SIMULATION_PLAN_READ_TIMEOUT_MS
1168
+ );
1169
+ }
1170
+ return this.rootWait;
1171
+ }
1172
+ holdingForFirstRead() {
1173
+ return this.contentOffByKey === void 0 && !this.firstReadOver && !this.stopped;
1174
+ }
1175
+ unavailableNow() {
1176
+ return !this.disabled() && this.contentOffByKey === void 0 && this.firstReadOver;
1175
1177
  }
1176
1178
  firstLoad() {
1177
1179
  if (this.contentOffByKey !== void 0 || this.stopped || this.disabled()) {
@@ -1181,19 +1183,20 @@ var init_simulationPlan = __esm({
1181
1183
  }
1182
1184
  send(payload, traceFunctionKey, submit) {
1183
1185
  this.refresh();
1184
- if (this.stopped || this.disabled() || traceFunctionKey === void 0 || spanNameOf(payload) === void 0 || recordedByFramework(payload)) {
1186
+ if (this.disabled() || traceFunctionKey === void 0 || spanNameOf(payload) === void 0 || recordedByFramework(payload)) {
1185
1187
  submit(payload);
1186
1188
  return;
1187
1189
  }
1188
- if (this.contentOffByKey === void 0) {
1189
- this.hold({ payload, traceFunctionKey, submit });
1190
+ const entry = { payload, traceFunctionKey, submit };
1191
+ if (this.holdingForFirstRead()) {
1192
+ this.hold(entry);
1190
1193
  return;
1191
1194
  }
1192
- this.submitEntry({ payload, traceFunctionKey, submit });
1195
+ this.submitEntry(entry);
1193
1196
  }
1194
1197
  sendTrace(payload, submit) {
1195
1198
  this.refresh();
1196
- if (this.stopped || this.disabled() || this.contentOffByKey !== void 0 || !this.holdsSpanOfTrace(traceIdOf(payload))) {
1199
+ if (this.disabled() || !this.holdingForFirstRead() || !this.holdsSpanOfTrace(traceIdOf(payload))) {
1197
1200
  submit(payload);
1198
1201
  return;
1199
1202
  }
@@ -1209,17 +1212,34 @@ var init_simulationPlan = __esm({
1209
1212
  }
1210
1213
  hold(entry) {
1211
1214
  this.held.push(entry);
1215
+ let overflowed = false;
1212
1216
  while (this.held.length > SIMULATION_PLAN_MAX_HELD) {
1213
- this.held.shift();
1214
- this.droppedWhileHolding += 1;
1217
+ const oldest = this.held.shift();
1218
+ this.submitEntry(oldest);
1219
+ overflowed = true;
1220
+ }
1221
+ if (overflowed) {
1222
+ warnOnce(
1223
+ "sim-plan-held-overflow",
1224
+ `more than ${SIMULATION_PLAN_MAX_HELD} records were waiting for the sim plan, so the oldest were sent without their inputs and outputs.`
1225
+ );
1226
+ }
1227
+ }
1228
+ payloadToSend(entry) {
1229
+ if (entry.traceFunctionKey === void 0) {
1230
+ return entry.payload;
1231
+ }
1232
+ if (this.contentOffByKey !== void 0) {
1233
+ return this.apply(entry.payload, entry.traceFunctionKey);
1234
+ }
1235
+ if (recordedByFramework(entry.payload) || isTraceRootSpan(entry.payload)) {
1236
+ return entry.payload;
1215
1237
  }
1216
- this.armRetry();
1238
+ return stripContent(entry.payload);
1217
1239
  }
1218
1240
  submitEntry(entry) {
1219
1241
  try {
1220
- entry.submit(
1221
- entry.traceFunctionKey === void 0 ? entry.payload : this.apply(entry.payload, entry.traceFunctionKey)
1222
- );
1242
+ entry.submit(this.payloadToSend(entry));
1223
1243
  } catch (error) {
1224
1244
  warnOnce(
1225
1245
  "sim-plan-held-span-dropped",
@@ -1230,63 +1250,38 @@ var init_simulationPlan = __esm({
1230
1250
  releaseHeld() {
1231
1251
  const held = this.held;
1232
1252
  this.held = [];
1233
- this.syncRetryTimer();
1234
- this.warnDropped();
1235
1253
  for (const entry of held) {
1236
1254
  this.submitEntry(entry);
1237
1255
  }
1238
1256
  }
1239
- warnDropped() {
1240
- if (this.droppedWhileHolding === 0) {
1241
- return;
1242
- }
1243
- const dropped = this.droppedWhileHolding;
1244
- this.droppedWhileHolding = 0;
1245
- warnOnce(
1246
- "sim-plan-held-overflow",
1247
- `${dropped} record(s) were dropped while the sim plan was still loading; at most ${SIMULATION_PLAN_MAX_HELD} are held per client.`
1248
- );
1249
- }
1250
- warnNeverLoaded() {
1257
+ releaseHeldWithoutPlan() {
1251
1258
  if (this.held.length === 0) {
1252
1259
  return;
1253
1260
  }
1254
- warnOnce(
1255
- "sim-plan-never-loaded",
1256
- `${this.held.length} record(s) were not sent because the sim plan never loaded`
1257
- );
1261
+ if (this.contentOffByKey === void 0) {
1262
+ warnOnce(
1263
+ "sim-plan-not-loaded-at-release",
1264
+ `${this.held.length} record(s) were sent without their inputs and outputs because the sim plan had not loaded`
1265
+ );
1266
+ }
1267
+ this.releaseHeld();
1258
1268
  }
1259
1269
  async release(timeoutMs) {
1260
1270
  this.refresh();
1261
- if (this.holdsWork()) {
1262
- await this.waitForFirstLoad(timeoutMs);
1271
+ if (this.held.length > 0) {
1272
+ await this.waitForFirstReadEnd(timeoutMs);
1263
1273
  }
1264
- this.warnNeverLoaded();
1265
- this.warnDropped();
1266
- return this.held.length === 0;
1274
+ this.releaseHeldWithoutPlan();
1267
1275
  }
1268
- waitForFirstLoad(timeoutMs) {
1269
- const firstLoad = this.firstLoad();
1270
- if (firstLoad === void 0) {
1276
+ waitForFirstReadEnd(timeoutMs) {
1277
+ if (this.firstReadOver) {
1271
1278
  return Promise.resolve();
1272
1279
  }
1273
- this.waitingForFirstLoad += 1;
1274
- this.armRetry();
1275
1280
  return new Promise((resolve) => {
1276
- let settled2 = false;
1277
- const finish = () => {
1278
- if (settled2) {
1279
- return;
1280
- }
1281
- settled2 = true;
1282
- this.waitingForFirstLoad -= 1;
1283
- this.syncRetryTimer();
1284
- resolve();
1285
- };
1286
- const timer = setTimeout(finish, Math.max(timeoutMs, 0));
1287
- void firstLoad.then(() => {
1281
+ const timer = setTimeout(resolve, Math.max(timeoutMs, 0));
1282
+ void this.firstReadEnded.then(() => {
1288
1283
  clearTimeout(timer);
1289
- finish();
1284
+ resolve();
1290
1285
  });
1291
1286
  });
1292
1287
  }
@@ -1294,16 +1289,16 @@ var init_simulationPlan = __esm({
1294
1289
  if (this.stopped) {
1295
1290
  return;
1296
1291
  }
1292
+ this.releaseHeldWithoutPlan();
1297
1293
  this.stopped = true;
1298
- this.retryPending = false;
1299
- this.clearRetryTimer();
1300
- this.warnNeverLoaded();
1301
- this.held = [];
1302
- this.warnDropped();
1294
+ this.endFirstRead();
1303
1295
  }
1304
1296
  contentOff(traceFunctionKey, spanName) {
1305
1297
  return this.contentOffByKey?.get(traceFunctionKey)?.has(spanName) === true;
1306
1298
  }
1299
+ contentOffNow(traceFunctionKey, spanName) {
1300
+ return !this.stopped && !this.disabled() && this.contentOff(traceFunctionKey, spanName);
1301
+ }
1307
1302
  apply(payload, traceFunctionKey) {
1308
1303
  if (recordedByFramework(payload)) {
1309
1304
  return payload;
@@ -1434,6 +1429,19 @@ var init_transportTypes = __esm({
1434
1429
  }
1435
1430
  });
1436
1431
 
1432
+ // src/unrefTimer.ts
1433
+ function unrefTimer(timer) {
1434
+ const handle = timer;
1435
+ if (typeof handle.unref === "function") {
1436
+ handle.unref();
1437
+ }
1438
+ }
1439
+ var init_unrefTimer = __esm({
1440
+ "src/unrefTimer.ts"() {
1441
+ "use strict";
1442
+ }
1443
+ });
1444
+
1437
1445
  // src/otel.ts
1438
1446
  function readBoundedIntEnv(name, max, fallback, warnKey) {
1439
1447
  const raw = readEnv(name);
@@ -8277,6 +8285,25 @@ var BitfabVercelAiHandler = class {
8277
8285
  // src/client.ts
8278
8286
  init_warnOnce();
8279
8287
  var activeTraceStates = /* @__PURE__ */ new Map();
8288
+ function fitsTraceSpanBudget(payload) {
8289
+ if (!recordedByFramework(payload)) {
8290
+ return true;
8291
+ }
8292
+ const traceId = traceIdOf(payload);
8293
+ const spanBudget = traceId === void 0 ? void 0 : activeTraceStates.get(traceId)?.spanBudget;
8294
+ if (spanBudget === void 0) {
8295
+ return true;
8296
+ }
8297
+ if (spanBudget.spansUsed >= spanBudget.maxSpans) {
8298
+ spanBudget.truncate();
8299
+ return false;
8300
+ }
8301
+ spanBudget.spansUsed += 1;
8302
+ return true;
8303
+ }
8304
+ function rootTraceFunctionKeyOfTrace(traceId, fallback) {
8305
+ return activeTraceStates.get(traceId)?.traceFunctionKey ?? fallback;
8306
+ }
8280
8307
  function rootTraceFunctionKeyOf(payload) {
8281
8308
  const captured = payload[ROOT_TRACE_FUNCTION_KEY_FIELD];
8282
8309
  if (typeof captured === "string") {
@@ -8652,7 +8679,8 @@ function readBooleanEnv(name) {
8652
8679
  return void 0;
8653
8680
  }
8654
8681
  var DEFAULT_AUTO_TRACE_MAX_DEPTH = 30;
8655
- var DEFAULT_AUTO_TRACE_MAX_SPANS = 500;
8682
+ var DEFAULT_AUTO_TRACE_MAX_SPANS = 2048;
8683
+ var DEFAULT_AUTO_TRACE_MAX_CAPTURED_SUBTREE_SPANS = 512;
8656
8684
  var AUTO_TRACE_PROTOCOL = "ts-auto-v1";
8657
8685
  function spanOwnerName(receiver) {
8658
8686
  if (typeof receiver === "function") {
@@ -8723,6 +8751,9 @@ var Bitfab = class {
8723
8751
  this.httpClient.externalTraceTransform = (payload, submit) => this.simulationPlan.sendTrace(payload, submit);
8724
8752
  this.httpClient.releaseHeldExternalSpans = (timeoutMs) => this.simulationPlan.release(timeoutMs);
8725
8753
  this.httpClient.stopSimulationPlan = () => this.simulationPlan.stop();
8754
+ if (this.findApiKey(false) !== void 0) {
8755
+ this.simulationPlan.refresh();
8756
+ }
8726
8757
  this.datasets = new DatasetsClient(this.httpClient);
8727
8758
  this.assertionCategories = new AssertionCategoriesClient(this.httpClient);
8728
8759
  this.traces = new TracesClient(this.httpClient);
@@ -8879,10 +8910,23 @@ var Bitfab = class {
8879
8910
  options.maxDepth,
8880
8911
  DEFAULT_AUTO_TRACE_MAX_DEPTH
8881
8912
  );
8913
+ if (options.maxSpans !== void 0 && options.maxSpans < 1) {
8914
+ throw new BitfabError(
8915
+ `maxSpans must be at least 1 because the root span counts toward it (got ${options.maxSpans})`
8916
+ );
8917
+ }
8882
8918
  const maxSpans = autoTraceLimit(
8883
8919
  options.maxSpans,
8884
8920
  DEFAULT_AUTO_TRACE_MAX_SPANS
8885
8921
  );
8922
+ const maxCapturedSubtreeSpans = Math.min(
8923
+ autoTraceLimit(
8924
+ options.maxCapturedSubtreeSpans,
8925
+ DEFAULT_AUTO_TRACE_MAX_CAPTURED_SUBTREE_SPANS
8926
+ ),
8927
+ maxSpans
8928
+ );
8929
+ const rootIsAsync = fn.constructor.name === "AsyncFunction";
8886
8930
  const excluded = new Set(options.exclude ?? []);
8887
8931
  const includeWrappers = options.includeWrappers ?? false;
8888
8932
  const rootNameFor = (receiver) => options.name ?? (fn.name !== "" ? qualifiedSpanName(receiver, name) ?? name : name);
@@ -8898,7 +8942,7 @@ var Bitfab = class {
8898
8942
  spanOptions,
8899
8943
  function(...args) {
8900
8944
  self.simulationPlan.refresh();
8901
- let spansUsed = 0;
8945
+ let capturedSubtreeCount = 0;
8902
8946
  let truncated = false;
8903
8947
  const warnTruncated = () => {
8904
8948
  if (!truncated) {
@@ -8908,15 +8952,27 @@ var Bitfab = class {
8908
8952
  protocol: AUTO_TRACE_PROTOCOL,
8909
8953
  truncated: true,
8910
8954
  maxDepth,
8911
- maxSpans
8955
+ maxSpans,
8956
+ maxCapturedSubtreeSpans
8912
8957
  }
8913
8958
  });
8914
8959
  }
8915
8960
  warnOnce(
8916
8961
  `auto-trace-truncated:${traceFunctionKey}`,
8917
- `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
8962
+ `"${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.`
8918
8963
  );
8919
8964
  };
8965
+ const rootSpanStack = getSpanStack();
8966
+ const spanBudget = {
8967
+ spansUsed: 1,
8968
+ maxSpans,
8969
+ truncate: () => runWithSpanStack(rootSpanStack, warnTruncated)
8970
+ };
8971
+ const rootSpan = rootSpanStack[rootSpanStack.length - 1];
8972
+ const rootTraceState = rootSpan === void 0 ? void 0 : activeTraceStates.get(rootSpan.traceId);
8973
+ if (rootTraceState !== void 0 && rootTraceState.spanBudget === void 0) {
8974
+ rootTraceState.spanBudget = spanBudget;
8975
+ }
8920
8976
  const spanStackOf = (entry) => entry.spanStack;
8921
8977
  const openChild = (entry, childOptions, inputs, isAsync, invokeFn) => {
8922
8978
  const runInside = () => runWithAutoTraceEntry(
@@ -8945,12 +9001,25 @@ var Bitfab = class {
8945
9001
  return tracedChild(...inputs);
8946
9002
  });
8947
9003
  };
8948
- const overBudget = (entry) => {
8949
- if (entry.depth < maxDepth && spansUsed < maxSpans) {
8950
- return false;
9004
+ const rootTraceFunctionKeyOfEntry = (entry) => {
9005
+ const stack = spanStackOf(entry);
9006
+ const innermost = stack[stack.length - 1];
9007
+ return innermost === void 0 ? traceFunctionKey : rootTraceFunctionKeyOfTrace(innermost.traceId, traceFunctionKey);
9008
+ };
9009
+ const recordsSpan = (entry, spanName, declared) => {
9010
+ const countsTowardCapturedSubtree = !declared && !self.simulationPlan.contentOffNow(
9011
+ rootTraceFunctionKeyOfEntry(entry),
9012
+ spanName
9013
+ );
9014
+ if (entry.depth < maxDepth && spanBudget.spansUsed < maxSpans && (!countsTowardCapturedSubtree || capturedSubtreeCount < maxCapturedSubtreeSpans)) {
9015
+ spanBudget.spansUsed += 1;
9016
+ if (countsTowardCapturedSubtree) {
9017
+ capturedSubtreeCount += 1;
9018
+ }
9019
+ return true;
8951
9020
  }
8952
9021
  runWithSpanStack(spanStackOf(entry), warnTruncated);
8953
- return true;
9022
+ return false;
8954
9023
  };
8955
9024
  const autoTraceContext = {
8956
9025
  traceFunctionKey,
@@ -8964,13 +9033,13 @@ var Bitfab = class {
8964
9033
  if (nodeConfiguration?.capture === false) {
8965
9034
  return clearAutoTraceNodeConfiguration(invokeFn);
8966
9035
  }
8967
- if (overBudget(entry)) {
9036
+ const spanName = nodeConfiguration?.name ?? definition.name;
9037
+ if (!recordsSpan(entry, spanName, nodeConfiguration !== void 0)) {
8968
9038
  return invokeWithoutNode();
8969
9039
  }
8970
- spansUsed += 1;
8971
9040
  const mockOnReplay = nodeConfiguration?.mockOnReplay ?? options.mockOnReplayDefault;
8972
9041
  const childOptions = {
8973
- name: nodeConfiguration?.name ?? definition.name,
9042
+ name: spanName,
8974
9043
  type: nodeConfiguration?.type ?? "function",
8975
9044
  captureWhen: "nested",
8976
9045
  surface: "opt-out",
@@ -8997,10 +9066,9 @@ var Bitfab = class {
8997
9066
  );
8998
9067
  },
8999
9068
  invokeNestedRoot(nestedName, nestedFunctionName, inputs, invokeFn, entry, link) {
9000
- if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || overBudget(entry)) {
9069
+ if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || !recordsSpan(entry, nestedName, true)) {
9001
9070
  return invokeFn();
9002
9071
  }
9003
- spansUsed += 1;
9004
9072
  const childOptions = {
9005
9073
  name: nestedName,
9006
9074
  type: "function",
@@ -9027,6 +9095,12 @@ var Bitfab = class {
9027
9095
  }
9028
9096
  const enclosing = currentAutoTraceEntries();
9029
9097
  if (enclosing.length === 0) {
9098
+ const firstPlanRead = rootIsAsync ? self.simulationPlan.waitForFirstRead() : void 0;
9099
+ if (firstPlanRead !== void 0) {
9100
+ return firstPlanRead.then(
9101
+ () => tracedRoot.apply(this, args)
9102
+ );
9103
+ }
9030
9104
  return tracedRoot.apply(this, args);
9031
9105
  }
9032
9106
  const link = getReplayContext() || inSeedScope() ? void 0 : { traceFunctionKey };
@@ -9073,6 +9147,9 @@ var Bitfab = class {
9073
9147
  return autoTraceRoot;
9074
9148
  }
9075
9149
  applySimulationPlan(payload, submit) {
9150
+ if (!fitsTraceSpanBudget(payload)) {
9151
+ return;
9152
+ }
9076
9153
  this.simulationPlan.send(payload, rootTraceFunctionKeyOf(payload), submit);
9077
9154
  }
9078
9155
  /**
@@ -9107,15 +9184,24 @@ var Bitfab = class {
9107
9184
  * from the environment. Once a non-empty key is found it is cached, so an
9108
9185
  * early resolve that found nothing never poisons a later one.
9109
9186
  */
9110
- resolveApiKey() {
9187
+ findApiKey(callsKeyFunction) {
9111
9188
  if (this.resolvedApiKey !== void 0) {
9112
9189
  return this.resolvedApiKey;
9113
9190
  }
9191
+ if (typeof this.apiKeyConfig === "function" && !callsKeyFunction) {
9192
+ return void 0;
9193
+ }
9114
9194
  const fromConfig = typeof this.apiKeyConfig === "function" ? this.apiKeyConfig() : this.apiKeyConfig;
9115
9195
  const candidate = fromConfig && fromConfig.trim() !== "" ? fromConfig : readEnv2("BITFAB_API_KEY");
9116
9196
  const key = candidate && candidate.trim() !== "" ? candidate : void 0;
9117
9197
  if (key) {
9118
9198
  this.resolvedApiKey = key;
9199
+ }
9200
+ return key;
9201
+ }
9202
+ resolveApiKey() {
9203
+ const key = this.findApiKey(true);
9204
+ if (key) {
9119
9205
  return key;
9120
9206
  }
9121
9207
  if (this.strict) {
@@ -9735,7 +9821,10 @@ var Bitfab = class {
9735
9821
  self.httpClient.traceCompletion.start(traceId, spanId);
9736
9822
  startedSpan = { traceId, spanId };
9737
9823
  const functionName = fn.name !== "" ? fn.name : void 0;
9738
- const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
9824
+ const rootTraceFunctionKey = rootTraceFunctionKeyOfTrace(
9825
+ traceId,
9826
+ traceFunctionKey
9827
+ );
9739
9828
  const baseSpanParams = {
9740
9829
  traceFunctionKey,
9741
9830
  rootTraceFunctionKey,
@@ -10257,14 +10346,25 @@ var Bitfab = class {
10257
10346
  ...params.testRunId && { testRunId: params.testRunId }
10258
10347
  });
10259
10348
  }
10349
+ contentOffBySimulationPlan(params) {
10350
+ if (params.rootTraceFunctionKey === void 0 || isFrameworkInstrumentation(params.instrumentation)) {
10351
+ return false;
10352
+ }
10353
+ return this.simulationPlan.contentOffNow(
10354
+ params.rootTraceFunctionKey,
10355
+ params.spanName
10356
+ ) || params.parentSpanId !== null && this.simulationPlan.unavailableNow();
10357
+ }
10260
10358
  /**
10261
10359
  * Send a wrapper span from function execution.
10262
10360
  * Internal method to record spans when using withSpan.
10263
10361
  * Queued on the client's span transport; delivery is the transport's job.
10264
10362
  */
10265
10363
  sendWrapperSpan(params) {
10266
- const serializedInputs = params.captureContent ? serializeValue(params.inputs) : void 0;
10267
- const serializedResult = params.captureContent ? serializeValue(params.result) : void 0;
10364
+ const contentOff = this.contentOffBySimulationPlan(params);
10365
+ const buildsContent = params.captureContent && !contentOff;
10366
+ const serializedInputs = buildsContent ? serializeValue(params.inputs) : void 0;
10367
+ const serializedResult = buildsContent ? serializeValue(params.result) : void 0;
10268
10368
  const externalSpan = {
10269
10369
  id: params.spanId,
10270
10370
  trace_id: params.traceId,
@@ -10315,7 +10415,8 @@ var Bitfab = class {
10315
10415
  ...params.captureContent && params.contexts && params.contexts.length > 0 && {
10316
10416
  contexts: params.contexts
10317
10417
  },
10318
- ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt }
10418
+ ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt },
10419
+ ...contentOff && { [CONTENT_OFF_KEY]: true }
10319
10420
  }
10320
10421
  };
10321
10422
  if (params.parentSpanId) {