bitfab 0.64.2 → 0.64.4

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/cloudReplay.py CHANGED
@@ -40,6 +40,7 @@ OUTPUT_BEGIN = "bitfab-replay-output-begin"
40
40
  OUTPUT_END = "bitfab-replay-output-end"
41
41
  LOG_TAIL_LINES = 40
42
42
  OUTPUT_LIMIT = 16 * 1024 * 1024
43
+ DISK_LIMIT = 1024 * 1024 * 1024
43
44
  NEW_FILES_LIMIT = 20 * 1024 * 1024
44
45
  POLL_SECONDS = 5
45
46
  ITEM_ERROR_FIELDS = (
@@ -52,6 +53,14 @@ ITEM_ERROR_FIELDS = (
52
53
  ITEM_ID_FIELDS = ("originalTraceId", "original_trace_id", "traceId", "trace_id")
53
54
  ITEM_ERROR_LINES = 20
54
55
  ITEM_ERROR_LENGTH = 500
56
+ SUMMARY_ERROR_ITEMS = 100
57
+ EXPERIMENT_FIELDS = {
58
+ "experimentId": ("experimentId", "experiment_id"),
59
+ "experimentUrl": ("experimentUrl", "experiment_url"),
60
+ "testRunId": ("testRunId", "test_run_id"),
61
+ "testRunUrl": ("testRunUrl", "test_run_url"),
62
+ "attempts": ("attempts",),
63
+ }
55
64
  UUID = re.compile(r"^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$")
56
65
  SHA = re.compile(r"^[0-9a-f]{40}$")
57
66
  GITHUB_REMOTE = re.compile(
@@ -59,6 +68,15 @@ GITHUB_REMOTE = re.compile(
59
68
  )
60
69
  LOG_TIMESTAMP = re.compile(r"^?\d{4}-\d\d-\d\dT[\d:.]+Z ?")
61
70
  EXPERIMENT_LINE = re.compile(rb"^\[replay\] Experiment ([0-9a-f-]{36}):")
71
+ PROGRESS_PREFIX = b"@@bitfab:progress "
72
+ PROGRESS_PAYLOAD_FIELDS = (
73
+ "input",
74
+ "result",
75
+ "originalOutput",
76
+ "original_output",
77
+ "selectiveReplay",
78
+ "selective_replay",
79
+ )
62
80
  SECRET_REFERENCE = re.compile(
63
81
  r"[\"']?([A-Za-z_][A-Za-z0-9_]*)[\"']?[ \t]*:[ \t]*[\"']?\$\{\{\s*secrets(?:\.([A-Za-z_][A-Za-z0-9_]*)|\[\s*[\"']([A-Za-z_][A-Za-z0-9_]*)[\"']\s*\])\s*\}\}"
64
82
  )
@@ -77,7 +95,7 @@ FOLLOW_FLAGS = (
77
95
  "--cloud-cleanup",
78
96
  )
79
97
  CLOUD_VALUE_FLAGS = (*FOLLOW_FLAGS, "--cloud-request-id", "--cloud-timeout")
80
- CLOUD_SWITCHES = ("--cloud", "--cloud-preview", "--cloud-detach")
98
+ CLOUD_SWITCHES = ("--cloud", "--cloud-preview", "--cloud-detach", "--cloud-full-output")
81
99
  RENAMED_FLAGS = {
82
100
  "--cloud-dry-run": "--cloud-preview",
83
101
  "--cloud-check": "--dry-run",
@@ -113,9 +131,17 @@ does not ignore) from the same directory, and this command prints the replay's o
113
131
  and exits with its exit code. Credential-like files are refused. Requires git and
114
132
  Python 3.10+ on macOS or Linux, with a github.com origin.
115
133
 
134
+ The replay's stderr comes back as it printed it. Its stdout result comes back as a
135
+ short summary instead of every item: the experiment ID and URL, how many traces were
136
+ replayed, same, changed, and errored, each errored trace with its error, and the exit
137
+ code. Every item's input and output are already saved in the experiment in Bitfab.
138
+
116
139
  Options added by --cloud:
117
140
  --cloud-preview List what the snapshot would contain and push nothing.
118
141
  --cloud-detach Return after dispatch instead of waiting.
142
+ --cloud-full-output Print the replay's whole stdout result, every item included,
143
+ instead of the summary. Large runs can exceed what the
144
+ GitHub job log holds.
119
145
  --cloud-timeout MIN Stop the replay after MIN minutes (1..7200).
120
146
  --cloud-request-id ID Recover a submission whose response was lost.
121
147
 
@@ -310,6 +336,16 @@ def parse_environment_file(text):
310
336
  return values
311
337
 
312
338
 
339
+ def secret_value(value):
340
+ if "\n" not in value:
341
+ return value
342
+ try:
343
+ parsed = json.loads(value)
344
+ except ValueError:
345
+ return value
346
+ return json.dumps(parsed, separators=(",", ":"))
347
+
348
+
313
349
  def ensure_environment(repo, environment):
314
350
  try:
315
351
  api(repo, f"environments/{environment}")
@@ -412,7 +448,7 @@ def configure_secrets(argv):
412
448
  repo,
413
449
  *(["--env", environment] if environment else []),
414
450
  ],
415
- input=values.get(name, values.get(targets[name])),
451
+ input=secret_value(values.get(name, values.get(targets[name]))),
416
452
  env={**os.environ, "GH_TOKEN": token},
417
453
  )
418
454
  result["set"] = [targets[name] for name in found]
@@ -592,10 +628,8 @@ def validate_arguments(args):
592
628
  if not isinstance(args, list) or not all(isinstance(value, str) for value in args):
593
629
  raise ValueError("Replay arguments must be a list of strings")
594
630
  for value in args:
595
- if "\x00" in value or "\n" in value or len(value) > 1000:
596
- raise ValueError(
597
- "Replay options must be single-line values of at most 1000 characters"
598
- )
631
+ if "\x00" in value or "\n" in value:
632
+ raise ValueError("Replay options must be single-line values")
599
633
  if value.startswith("--cloud"):
600
634
  raise ValueError("The runner replays locally and never dispatches again")
601
635
  if sum(len(value) for value in args) > 16000:
@@ -639,6 +673,8 @@ def replay_request(root, parsed):
639
673
  }
640
674
  if "--cloud-timeout" in parsed["cloud"]:
641
675
  request["timeoutMinutes"] = int(parsed["cloud"]["--cloud-timeout"])
676
+ if "--cloud-full-output" in parsed["switches"]:
677
+ request["fullOutput"] = True
642
678
  return request, files
643
679
 
644
680
 
@@ -862,9 +898,7 @@ def outcome(record):
862
898
  raise ValueError("Replay result does not match this execution")
863
899
  record["exitCode"] = result["exitCode"]
864
900
  parsed = last_json(result.get("stdout", "")) or {}
865
- test_run = result.get("testRunId") or parsed.get(
866
- "testRunId", parsed.get("test_run_id")
867
- )
901
+ test_run = result.get("testRunId") or experiment_fields(parsed).get("testRunId")
868
902
  if isinstance(test_run, str) and UUID.fullmatch(test_run):
869
903
  record["testRunId"] = test_run
870
904
  if result.get("stoppedEarly"):
@@ -889,7 +923,22 @@ def print_outcome(found):
889
923
  for line in replay_output(lines) or []:
890
924
  print(line, file=sys.stderr)
891
925
  sys.stderr.flush()
926
+ if result.get("stdoutOmittedBytes"):
927
+ progress(
928
+ f"The replay also printed {result['stdoutOmittedBytes'] // (1024 * 1024)} MiB to stdout before its result, such as a library's logging; only the end was kept"
929
+ )
892
930
  print(result.get("stdout", ""), end="", flush=True)
931
+ summary = last_json(result.get("stdout", "")) or {}
932
+ if summary.get("cloudSummary") is True:
933
+ progress(
934
+ "Printed a summary of the result; every item's input and output are in the experiment"
935
+ + (
936
+ f" at {summary['experimentUrl']}"
937
+ if summary.get("experimentUrl")
938
+ else ""
939
+ )
940
+ + ". Add --cloud-full-output to print every item here instead"
941
+ )
893
942
  if record.get("stoppedEarly"):
894
943
  progress(
895
944
  f"Replay stopped early: {record['stoppedEarly']}. Traces that finished are saved"
@@ -1049,7 +1098,10 @@ def submit(root, repo, workflow, parsed, path):
1049
1098
  def report_steps(record, shown):
1050
1099
  job = replay_job(record)
1051
1100
  for step in (job or {}).get("steps", []):
1052
- if step.get("status") != "queued" and step.get("name") not in shown:
1101
+ if (
1102
+ step.get("status") in ("in_progress", "completed")
1103
+ and step.get("name") not in shown
1104
+ ):
1053
1105
  shown.add(step.get("name"))
1054
1106
  progress(step.get("name"))
1055
1107
 
@@ -1186,8 +1238,12 @@ def execute():
1186
1238
  previous = signal.signal(signal.SIGTERM, raise_interrupt)
1187
1239
  print(OUTPUT_BEGIN, flush=True)
1188
1240
  try:
1189
- code, stdout, stopped = run_command(
1190
- directory, args, request.get("timeoutMinutes"), experiment
1241
+ code, stdout, omitted, stopped = run_command(
1242
+ directory,
1243
+ args,
1244
+ request.get("timeoutMinutes"),
1245
+ experiment,
1246
+ summarize=request.get("fullOutput") is not True,
1191
1247
  )
1192
1248
  finally:
1193
1249
  print(OUTPUT_END, flush=True)
@@ -1198,6 +1254,8 @@ def execute():
1198
1254
  "exitCode": code,
1199
1255
  "stdout": stdout,
1200
1256
  }
1257
+ if omitted:
1258
+ result["stdoutOmittedBytes"] = omitted
1201
1259
  if stopped:
1202
1260
  result["stoppedEarly"] = stopped
1203
1261
  if UUID.fullmatch(experiment.get("id", "")):
@@ -1224,6 +1282,15 @@ def check_secrets(root):
1224
1282
  + ", ".join(f"{name} (secret {targets[name]})" for name in empty)
1225
1283
  + ". GitHub passes a secret that does not exist as an empty string. Create each one under Settings, Secrets and variables, Actions, in the repository or in the job's Environment"
1226
1284
  )
1285
+ for name in targets:
1286
+ if any(
1287
+ 0 < len(line.strip()) < 4
1288
+ for line in os.environ.get(name, "").splitlines()[1:]
1289
+ ):
1290
+ print(
1291
+ f"::warning title=Bitfab replay::{name} has a line of three characters or fewer, such as a lone brace in multi-line JSON, and GitHub masks that text everywhere in this log. Store it on one line; bitfab-replay --cloud-secrets does this for JSON",
1292
+ flush=True,
1293
+ )
1227
1294
 
1228
1295
 
1229
1296
  def run_check_command(directory):
@@ -1259,10 +1326,75 @@ def item_errors(items):
1259
1326
  text = " ".join(str(error).split())
1260
1327
  if len(text) > ITEM_ERROR_LENGTH:
1261
1328
  text = text[:ITEM_ERROR_LENGTH] + "..."
1262
- errors.append((trace, text))
1329
+ errored = {"originalTraceId": trace, "error": text}
1330
+ if isinstance(item.get("attempt"), int):
1331
+ errored["attempt"] = item["attempt"]
1332
+ errors.append(errored)
1263
1333
  return errors
1264
1334
 
1265
1335
 
1336
+ def item_field(item, camel, snake):
1337
+ return item[camel] if camel in item else item.get(snake)
1338
+
1339
+
1340
+ def canonical(value):
1341
+ return json.dumps(value, separators=(",", ":"))
1342
+
1343
+
1344
+ def experiment_fields(parsed):
1345
+ fields = {}
1346
+ for name, spellings in EXPERIMENT_FIELDS.items():
1347
+ value = next(
1348
+ (parsed[key] for key in spellings if parsed.get(key) is not None), None
1349
+ )
1350
+ if value is not None:
1351
+ fields[name] = value
1352
+ return fields
1353
+
1354
+
1355
+ def replay_summary(parsed):
1356
+ items = [item for item in parsed["items"] if isinstance(item, dict)]
1357
+ replayed = [item for item in items if not carried_over(item)]
1358
+ errors = item_errors(replayed)
1359
+ counts = {
1360
+ "replayed": len(replayed),
1361
+ "carriedOver": len(items) - len(replayed),
1362
+ "same": 0,
1363
+ "changed": 0,
1364
+ "matchedExpected": 0,
1365
+ "missedExpected": 0,
1366
+ "errored": len(errors),
1367
+ }
1368
+ for item in replayed:
1369
+ if item_errored(item):
1370
+ continue
1371
+ equal = canonical(item.get("result")) == canonical(
1372
+ item_field(item, "originalOutput", "original_output")
1373
+ )
1374
+ if item_field(item, "ingestionType", "ingestion_type") == "seeded":
1375
+ counts["matchedExpected" if equal else "missedExpected"] += 1
1376
+ else:
1377
+ counts["same" if equal else "changed"] += 1
1378
+ summary = {
1379
+ "cloudSummary": True,
1380
+ **experiment_fields(parsed),
1381
+ "counts": counts,
1382
+ "erroredItems": errors[:SUMMARY_ERROR_ITEMS],
1383
+ }
1384
+ if len(errors) > SUMMARY_ERROR_ITEMS:
1385
+ summary["erroredItemsOmitted"] = len(errors) - SUMMARY_ERROR_ITEMS
1386
+ return summary
1387
+
1388
+
1389
+ def result_summary(stdout):
1390
+ parsed = last_json(stdout) or {}
1391
+ if parsed.get("cloudSummary") is True:
1392
+ return parsed
1393
+ if isinstance(parsed.get("items"), list):
1394
+ return replay_summary(parsed)
1395
+ return None
1396
+
1397
+
1266
1398
  def item_errored(item):
1267
1399
  return isinstance(item, dict) and any(
1268
1400
  item.get(field) is not None for field in ITEM_ERROR_FIELDS
@@ -1279,8 +1411,24 @@ def raise_interrupt(signum, frame):
1279
1411
  raise KeyboardInterrupt
1280
1412
 
1281
1413
 
1282
- def forward_stderr(stream, experiment):
1414
+ def without_item_payload(line):
1415
+ try:
1416
+ event = json.loads(line[len(PROGRESS_PREFIX) :])
1417
+ except ValueError:
1418
+ return line
1419
+ item = event.get("item") if isinstance(event, dict) else None
1420
+ if not isinstance(item, dict):
1421
+ return line
1422
+ event["item"] = {
1423
+ key: value for key, value in item.items() if key not in PROGRESS_PAYLOAD_FIELDS
1424
+ }
1425
+ return PROGRESS_PREFIX + json.dumps(event).encode() + b"\n"
1426
+
1427
+
1428
+ def forward_stderr(stream, experiment, summarize):
1283
1429
  for line in iter(stream.readline, b""):
1430
+ if summarize and line.startswith(PROGRESS_PREFIX):
1431
+ line = without_item_payload(line)
1284
1432
  sys.stdout.write(line.decode(errors="replace"))
1285
1433
  sys.stdout.flush()
1286
1434
  if "id" not in experiment:
@@ -1289,18 +1437,40 @@ def forward_stderr(stream, experiment):
1289
1437
  experiment["id"] = match[1].decode()
1290
1438
 
1291
1439
 
1292
- def last_json(text):
1440
+ def trailing_json(text):
1293
1441
  decoder = json.JSONDecoder()
1294
- result = None
1295
1442
  for offset in [0, *[i + 1 for i, value in enumerate(text) if value == "\n"]]:
1296
1443
  if text.startswith("{", offset):
1297
1444
  try:
1298
1445
  value, end = decoder.raw_decode(text, offset)
1299
- if not text[end:].strip() and isinstance(value, dict):
1300
- result = value
1301
1446
  except json.JSONDecodeError:
1302
- pass
1303
- return result
1447
+ continue
1448
+ if not text[end:].strip() and isinstance(value, dict):
1449
+ return offset, value
1450
+ return None, None
1451
+
1452
+
1453
+ def last_json(text):
1454
+ return trailing_json(text)[1]
1455
+
1456
+
1457
+ def relayed_stdout(output, code, summarize):
1458
+ if summarize:
1459
+ output.seek(0)
1460
+ parsed = last_json(output.read().decode(errors="replace"))
1461
+ if isinstance(parsed, dict) and isinstance(parsed.get("items"), list):
1462
+ return json.dumps({**replay_summary(parsed), "exitCode": code}) + "\n", 0
1463
+ return carried_stdout(output)
1464
+
1465
+
1466
+ def carried_stdout(output):
1467
+ start = max(0, os.fstat(output.fileno()).st_size - OUTPUT_LIMIT)
1468
+ output.seek(start)
1469
+ text = output.read().decode(errors="replace")
1470
+ if not start:
1471
+ return text, 0
1472
+ offset = trailing_json(text)[0] or 0
1473
+ return text[offset:], start + len(text[:offset].encode())
1304
1474
 
1305
1475
 
1306
1476
  def write_result(result):
@@ -1314,35 +1484,45 @@ def write_result(result):
1314
1484
  file.write(summary_markdown(result))
1315
1485
 
1316
1486
 
1487
+ def annotate(result):
1488
+ if result.get("stoppedEarly"):
1489
+ message = f"Replay stopped early: {result['stoppedEarly']}"
1490
+ elif result["exitCode"]:
1491
+ message = f"Replay exited {result['exitCode']}; bitfab-replay --cloud reports it as its own exit code"
1492
+ else:
1493
+ return
1494
+ print(f"::warning title=Bitfab replay::{message}", flush=True)
1495
+
1496
+
1317
1497
  def summary_markdown(result):
1318
- parsed = last_json(result["stdout"]) or {}
1319
- test_run = result.get("testRunId") or parsed.get(
1320
- "testRunId", parsed.get("test_run_id")
1321
- )
1322
- items = parsed.get("items") if isinstance(parsed.get("items"), list) else []
1323
- replayed = [item for item in items if not carried_over(item)]
1324
- errors = item_errors(replayed)
1498
+ summary = result_summary(result["stdout"]) or {}
1499
+ counts = summary.get("counts", {})
1500
+ test_run = result.get("testRunId") or summary.get("testRunId")
1501
+ errors = summary.get("erroredItems", [])
1325
1502
  lines = [f"Commit: `{result['commitSha']}`", f"Exit code: {result['exitCode']}"]
1326
1503
  if test_run:
1327
1504
  lines.insert(0, f"Test run: `{test_run}`")
1328
1505
  if result.get("stoppedEarly"):
1329
1506
  lines.append(f"Stopped early: {result['stoppedEarly']}")
1330
- elif items:
1331
- lines.append(f"Replayed: {len(replayed)}, errored: {len(errors)}")
1507
+ elif counts.get("replayed") or counts.get("carriedOver"):
1508
+ lines.append(
1509
+ f"Replayed: {counts['replayed']}, same: {counts['same']}, changed: {counts['changed']}, errored: {counts['errored']}"
1510
+ )
1332
1511
  text = "### Bitfab replay\n\n" + "\n\n".join(lines) + "\n"
1333
1512
  if errors:
1334
1513
  shown = [
1335
- f"trace {trace}: {error}" for trace, error in errors[:ITEM_ERROR_LINES]
1514
+ f"trace {error['originalTraceId']}: {error['error']}"
1515
+ for error in errors[:ITEM_ERROR_LINES]
1336
1516
  ]
1337
- if len(errors) > len(shown):
1338
- shown.append(f"and {len(errors) - len(shown)} more errored items")
1517
+ if counts.get("errored", 0) > len(shown):
1518
+ shown.append(f"and {counts['errored'] - len(shown)} more errored items")
1339
1519
  text += "\n#### Errored items\n\n" + "".join(
1340
1520
  f"- `{line.replace('`', chr(39))}`\n" for line in shown
1341
1521
  )
1342
1522
  return text
1343
1523
 
1344
1524
 
1345
- def run_command(directory, args, timeout, experiment):
1525
+ def run_command(directory, args, timeout, experiment, *, summarize=True):
1346
1526
  stopped = None
1347
1527
  with tempfile.TemporaryFile() as output:
1348
1528
  with subprocess.Popen(
@@ -1354,18 +1534,26 @@ def run_command(directory, args, timeout, experiment):
1354
1534
  start_new_session=True,
1355
1535
  ) as child:
1356
1536
  reader = threading.Thread(
1357
- target=forward_stderr, args=(child.stderr, experiment), daemon=True
1537
+ target=forward_stderr,
1538
+ args=(child.stderr, experiment, summarize),
1539
+ daemon=True,
1358
1540
  )
1359
1541
  reader.start()
1360
1542
  try:
1361
1543
  deadline = None if timeout is None else time.monotonic() + timeout * 60
1544
+ parent = os.getppid()
1545
+ checked = time.monotonic()
1362
1546
  while child.poll() is None:
1363
- if os.fstat(output.fileno()).st_size > OUTPUT_LIMIT:
1364
- raise ValueError("Replay output exceeded 16 MiB")
1547
+ if os.fstat(output.fileno()).st_size > DISK_LIMIT:
1548
+ raise ValueError("Replay printed more than 1 GiB to stdout")
1365
1549
  if deadline is not None and time.monotonic() >= deadline:
1366
1550
  stopped = f"it reached the {timeout}-minute --cloud-timeout"
1367
1551
  stop(child)
1368
1552
  break
1553
+ if time.monotonic() - checked >= 1:
1554
+ checked = time.monotonic()
1555
+ if os.getppid() != parent:
1556
+ raise KeyboardInterrupt
1369
1557
  time.sleep(0.1)
1370
1558
  except KeyboardInterrupt:
1371
1559
  stopped = "the GitHub run was cancelled"
@@ -1375,12 +1563,9 @@ def run_command(directory, args, timeout, experiment):
1375
1563
  raise
1376
1564
  finally:
1377
1565
  reader.join(timeout=5)
1378
- code = child.returncode
1379
- if output.tell() > OUTPUT_LIMIT:
1380
- raise ValueError("Replay output exceeded 16 MiB")
1381
- output.seek(0)
1382
- text = output.read().decode(errors="replace")
1383
- return (code if code >= 0 else 1), text, stopped
1566
+ code = child.returncode if child.returncode >= 0 else 1
1567
+ text, omitted = relayed_stdout(output, code, summarize)
1568
+ return code, text, omitted, stopped
1384
1569
 
1385
1570
 
1386
1571
  def stop(child):
@@ -1772,8 +1957,8 @@ def main():
1772
1957
  print_json(configure_secrets(argv[1:]))
1773
1958
  return 0
1774
1959
  if argv == ["--cloud-execute"]:
1775
- result = execute()
1776
- return result["exitCode"] or (1 if result.get("stoppedEarly") else 0)
1960
+ annotate(execute())
1961
+ return 0
1777
1962
  if "-h" in argv or "--help" in argv:
1778
1963
  print(HELP, end="")
1779
1964
  return 0
@@ -6,7 +6,7 @@ import {
6
6
  replayContextReady,
7
7
  runWithReplayContext,
8
8
  unrefTimer
9
- } from "./chunk-XHUW3NY6.js";
9
+ } from "./chunk-ZPVUSLIU.js";
10
10
  import {
11
11
  runWithCaptureSuppressed,
12
12
  warnOnce,
@@ -1884,4 +1884,4 @@ export {
1884
1884
  warnJudgeAssertionsDeprecated,
1885
1885
  replay
1886
1886
  };
1887
- //# sourceMappingURL=chunk-GLWAET3G.js.map
1887
+ //# sourceMappingURL=chunk-I6B5R2FP.js.map
@@ -2,7 +2,7 @@ import {
2
2
  BitfabError,
3
3
  warnOnce,
4
4
  writeOnce
5
- } from "./chunk-O632VPWV.js";
5
+ } from "./chunk-XASGXGQN.js";
6
6
 
7
7
  // src/codeChange.ts
8
8
  var NUL = String.fromCharCode(0);
@@ -316,7 +316,7 @@ async function seedFromRegistry(registry, pipeline, cases, options = {}) {
316
316
  sessionId: seedCase.sessionId
317
317
  })
318
318
  );
319
- const { flushTraces: flushTraces2 } = await import("./http-IOT2GDD2.js");
319
+ const { flushTraces: flushTraces2 } = await import("./http-Y6T6T2AP.js");
320
320
  await flushTraces2(3e4);
321
321
  return { pipeline, traceFunctionKey, traceIds };
322
322
  }
@@ -1007,4 +1007,4 @@ export {
1007
1007
  runRegistryMain,
1008
1008
  runIfEntrypoint
1009
1009
  };
1010
- //# sourceMappingURL=chunk-FX4X7LOW.js.map
1010
+ //# sourceMappingURL=chunk-OEHQPSOB.js.map
@@ -17,7 +17,7 @@ import {
17
17
  serializeValue,
18
18
  toJsonSafe,
19
19
  toJsonSafeReport
20
- } from "./chunk-GLWAET3G.js";
20
+ } from "./chunk-I6B5R2FP.js";
21
21
  import {
22
22
  BitfabError,
23
23
  CONTENT_OFF_KEY,
@@ -36,7 +36,7 @@ import {
36
36
  readEnv,
37
37
  recordCallerTraceMetadata,
38
38
  retireTraceMetadata
39
- } from "./chunk-XHUW3NY6.js";
39
+ } from "./chunk-ZPVUSLIU.js";
40
40
  import {
41
41
  __privateAdd,
42
42
  __privateGet,
@@ -6253,7 +6253,7 @@ var Bitfab = class {
6253
6253
  await runWithSeedContext({ traceId }, async () => target(...args));
6254
6254
  } finally {
6255
6255
  try {
6256
- const { flushTraces: flushTraces2 } = await import("./http-MFXRJ6RS.js");
6256
+ const { flushTraces: flushTraces2 } = await import("./http-53RWIBXJ.js");
6257
6257
  await flushTraces2(3e4);
6258
6258
  } finally {
6259
6259
  unrecorded = activeTraceStates.delete(traceId);
@@ -6312,7 +6312,7 @@ var Bitfab = class {
6312
6312
  `Function is wrapped with trace function key '${wrappedKey}' but replay was called with '${traceFunctionKey}'. Pass matching keys, or pass the unwrapped function to replay it under the explicit key.`
6313
6313
  );
6314
6314
  }
6315
- const { replay: doReplay } = await import("./replay-QZQYRTAO.js");
6315
+ const { replay: doReplay } = await import("./replay-SIKHFPKA.js");
6316
6316
  return doReplay(
6317
6317
  this.httpClient,
6318
6318
  this.serviceUrl,
@@ -6658,7 +6658,7 @@ async function seedFromRegistry(registry, pipeline, cases, options = {}) {
6658
6658
  sessionId: seedCase.sessionId
6659
6659
  })
6660
6660
  );
6661
- const { flushTraces: flushTraces2 } = await import("./http-MFXRJ6RS.js");
6661
+ const { flushTraces: flushTraces2 } = await import("./http-53RWIBXJ.js");
6662
6662
  await flushTraces2(3e4);
6663
6663
  return { pipeline, traceFunctionKey, traceIds };
6664
6664
  }
@@ -6703,4 +6703,4 @@ export {
6703
6703
  reseedFromRegistry,
6704
6704
  seedFromRegistry
6705
6705
  };
6706
- //# sourceMappingURL=chunk-ENORQO5K.js.map
6706
+ //# sourceMappingURL=chunk-UMZDRAAK.js.map
@@ -181,7 +181,7 @@ function encodeRequestBody(body) {
181
181
  }
182
182
 
183
183
  // src/version.generated.ts
184
- var __version__ = "0.64.2";
184
+ var __version__ = "0.64.4";
185
185
  var __packageName__ = "bitfab";
186
186
 
187
187
  // src/errors.ts
@@ -2500,4 +2500,4 @@ export {
2500
2500
  HttpClient,
2501
2501
  experimentIdWireFields
2502
2502
  };
2503
- //# sourceMappingURL=chunk-O632VPWV.js.map
2503
+ //# sourceMappingURL=chunk-XASGXGQN.js.map