@bitfab/sdk 0.65.0 → 0.65.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cloudReplay.py +207 -30
- package/dist/autoTrace.cjs +28 -0
- package/dist/autoTrace.cjs.map +1 -1
- package/dist/autoTrace.d.cts +2 -1
- package/dist/autoTrace.d.ts +2 -1
- package/dist/autoTrace.js +3 -1
- package/dist/{chunk-3W6RLPGK.js → chunk-BRMGNMDO.js} +4 -4
- package/dist/chunk-BRMGNMDO.js.map +1 -0
- package/dist/{chunk-WW2RMMTA.js → chunk-CLP2L5PU.js} +2 -2
- package/dist/{chunk-WW2RMMTA.js.map → chunk-CLP2L5PU.js.map} +1 -1
- package/dist/{chunk-JIGT4NC5.js → chunk-HLH7TN2A.js} +2 -2
- package/dist/{chunk-TNIJXUGC.js → chunk-LCV2JYXL.js} +2 -2
- package/dist/{chunk-TNIJXUGC.js.map → chunk-LCV2JYXL.js.map} +1 -1
- package/dist/{chunk-SUXEIG4U.js → chunk-NRE5CJPR.js} +29 -13
- package/dist/chunk-NRE5CJPR.js.map +1 -0
- package/dist/{chunk-MN3E2RUU.js → chunk-PTCLRG4E.js} +3 -3
- package/dist/{chunk-YWXQM6J3.js → chunk-QRNHRY7F.js} +28 -1
- package/dist/chunk-QRNHRY7F.js.map +1 -0
- package/dist/{chunk-IBWW3SP4.js → chunk-YVJAOGHE.js} +2 -2
- package/dist/{chunk-JXIW4FOF.js → chunk-Z26K57WZ.js} +2 -2
- package/dist/{chunk-GSHCHCB5.js → chunk-ZG6SHKEF.js} +12 -41
- package/dist/chunk-ZG6SHKEF.js.map +1 -0
- package/dist/{http-7LTYEMJO.js → http-VN52X47M.js} +2 -2
- package/dist/{http-NNVOMI63.js → http-WP4YPPKC.js} +2 -2
- package/dist/index.cjs +37 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/dist/node.cjs +37 -7
- package/dist/node.cjs.map +1 -1
- package/dist/node.js +4 -4
- package/dist/{replay-D7AN6O25.js → replay-463SEV53.js} +3 -3
- package/dist/{replay-L56SESG7.js → replay-OT4A4HVF.js} +3 -3
- package/dist/replayCli.js +3 -3
- package/dist/seedCli.js +3 -3
- package/dist/transform/babel.cjs +11 -40
- package/dist/transform/babel.cjs.map +1 -1
- package/dist/transform/babel.js +1 -1
- package/dist/transform/bun.cjs +11 -40
- package/dist/transform/bun.cjs.map +1 -1
- package/dist/transform/bun.js +3 -3
- package/dist/transform/esbuild.cjs +11 -40
- package/dist/transform/esbuild.cjs.map +1 -1
- package/dist/transform/esbuild.js +3 -3
- package/dist/transform/loaderRuntime.cjs +11 -40
- package/dist/transform/loaderRuntime.cjs.map +1 -1
- package/dist/transform/loaderRuntime.js +2 -2
- package/dist/transform/nest.cjs +11 -40
- package/dist/transform/nest.cjs.map +1 -1
- package/dist/transform/nest.js +3 -3
- package/dist/transform/next.cjs +11 -40
- package/dist/transform/next.cjs.map +1 -1
- package/dist/transform/next.js +3 -3
- package/dist/transform/nodeLoader.js +11 -40
- package/dist/transform/nodeLoader.js.map +1 -1
- package/dist/transform/rolldown.cjs +11 -40
- package/dist/transform/rolldown.cjs.map +1 -1
- package/dist/transform/rolldown.js +3 -3
- package/dist/transform/rollup.cjs +11 -40
- package/dist/transform/rollup.cjs.map +1 -1
- package/dist/transform/rollup.js +3 -3
- package/dist/transform/rsbuild.cjs +11 -40
- package/dist/transform/rsbuild.cjs.map +1 -1
- package/dist/transform/rsbuild.js +3 -3
- package/dist/transform/rspack.cjs +11 -40
- package/dist/transform/rspack.cjs.map +1 -1
- package/dist/transform/rspack.js +3 -3
- package/dist/transform/swc.cjs +11 -40
- package/dist/transform/swc.cjs.map +1 -1
- package/dist/transform/swc.js +2 -2
- package/dist/transform/unplugin.cjs +11 -40
- package/dist/transform/unplugin.cjs.map +1 -1
- package/dist/transform/unplugin.js +3 -3
- package/dist/transform/vite.cjs +11 -40
- package/dist/transform/vite.cjs.map +1 -1
- package/dist/transform/vite.js +3 -3
- package/dist/transform/webpack.cjs +11 -40
- package/dist/transform/webpack.cjs.map +1 -1
- package/dist/transform/webpack.js +3 -3
- package/package.json +11 -11
- package/dist/chunk-3W6RLPGK.js.map +0 -1
- package/dist/chunk-GSHCHCB5.js.map +0 -1
- package/dist/chunk-SUXEIG4U.js.map +0 -1
- package/dist/chunk-YWXQM6J3.js.map +0 -1
- /package/dist/{chunk-JIGT4NC5.js.map → chunk-HLH7TN2A.js.map} +0 -0
- /package/dist/{chunk-MN3E2RUU.js.map → chunk-PTCLRG4E.js.map} +0 -0
- /package/dist/{chunk-IBWW3SP4.js.map → chunk-YVJAOGHE.js.map} +0 -0
- /package/dist/{chunk-JXIW4FOF.js.map → chunk-Z26K57WZ.js.map} +0 -0
- /package/dist/{http-7LTYEMJO.js.map → http-VN52X47M.js.map} +0 -0
- /package/dist/{http-NNVOMI63.js.map → http-WP4YPPKC.js.map} +0 -0
- /package/dist/{replay-D7AN6O25.js.map → replay-463SEV53.js.map} +0 -0
- /package/dist/{replay-L56SESG7.js.map → replay-OT4A4HVF.js.map} +0 -0
package/cloudReplay.py
CHANGED
|
@@ -116,6 +116,8 @@ PUSH_TRIGGER = re.compile(
|
|
|
116
116
|
r"^[ \t]*\"?(?:on\"?[ \t]*:.*\bpush\b|push\"?[ \t]*:)", re.MULTILINE
|
|
117
117
|
)
|
|
118
118
|
DISPATCH_INPUTS = ("execution_id", "request", KEY_INPUT)
|
|
119
|
+
PUSH_SUBJECT = "Bitfab replay started on push"
|
|
120
|
+
PUSH_CONDITION = f"github.event_name != 'push' || !startsWith(github.ref_name, '{PREFIX}') || startsWith(github.event.head_commit.message, '{PUSH_SUBJECT}')"
|
|
119
121
|
BRANCH_NAME = re.compile(r"[A-Za-z0-9][A-Za-z0-9._/-]*")
|
|
120
122
|
ENV_NAME = re.compile(r"[A-Za-z_][A-Za-z0-9_]*")
|
|
121
123
|
RESERVED_ENV_PREFIXES = ("GITHUB_", "RUNNER_", "ACTIONS_", "BITFAB_REPLAY_")
|
|
@@ -254,7 +256,8 @@ Set up once:
|
|
|
254
256
|
[--runs-on LABEL] [--secret-prefix PREFIX] [--check COMMAND]
|
|
255
257
|
Writes .github/workflows/bitfab-replay.yml, the only file cloud replay keeps
|
|
256
258
|
in the repository, and lists what is left to do. On an existing workflow it
|
|
257
|
-
adds only the lines a newer SDK needs
|
|
259
|
+
adds only the lines a newer SDK needs, such as the push trigger that lets a
|
|
260
|
+
replay run without GitHub access, and lists what it changed.
|
|
258
261
|
--cloud-update [same options] [--remove-old-key-secrets]
|
|
259
262
|
The same command as --cloud-init, for bringing an existing setup up to date.
|
|
260
263
|
It also lists BITFAB_REPLAY_KEY_* secrets an older SDK left in the
|
|
@@ -266,6 +269,16 @@ Set up once:
|
|
|
266
269
|
GitHub access comes from the GitHub CLI when it is logged in, otherwise from GH_TOKEN
|
|
267
270
|
or GITHUB_TOKEN, otherwise from the github.com credential git already stores. Without
|
|
268
271
|
the GitHub CLI, --cloud-secrets lists the secrets to create by hand and where.
|
|
272
|
+
|
|
273
|
+
Without GitHub access, or with access that cannot read or push to the repository, a
|
|
274
|
+
replay still runs when git can push the snapshot branch and the workflow also starts
|
|
275
|
+
on a push to a bitfab-replay/ branch, as one written or updated by --cloud-init does.
|
|
276
|
+
This command then warns, prints where to watch the run, and returns once the branch
|
|
277
|
+
is pushed, with no updates and exit code 0. The run uses the workflow's BITFAB_API_KEY
|
|
278
|
+
secret, and --cloud-full-output and --cloud-allow-file are refused, since only GitHub
|
|
279
|
+
access can confirm the repository is private. Delete the snapshot branch once the run
|
|
280
|
+
finishes. With access, a replay starts through the GitHub API as before, and its
|
|
281
|
+
snapshot commit asks GitHub not to start any workflow on the push.
|
|
269
282
|
"""
|
|
270
283
|
|
|
271
284
|
|
|
@@ -281,6 +294,10 @@ class DispatchRejected(ValueError):
|
|
|
281
294
|
self.record = record
|
|
282
295
|
|
|
283
296
|
|
|
297
|
+
class GithubUnreachable(ValueError):
|
|
298
|
+
pass
|
|
299
|
+
|
|
300
|
+
|
|
284
301
|
class KeepRedirect(urllib.request.HTTPRedirectHandler):
|
|
285
302
|
def redirect_request(self, *args, **kwargs):
|
|
286
303
|
return None
|
|
@@ -939,7 +956,15 @@ def sensitive(path):
|
|
|
939
956
|
)
|
|
940
957
|
|
|
941
958
|
|
|
942
|
-
def
|
|
959
|
+
def snapshot_subject(execution_id, on_push):
|
|
960
|
+
if on_push:
|
|
961
|
+
return f"{PUSH_SUBJECT} {execution_id}"
|
|
962
|
+
return f"Bitfab replay {execution_id} [skip actions]"
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
def snapshot(
|
|
966
|
+
root, workflow, files, request, *, preview=False, allowed=(), on_push=False
|
|
967
|
+
):
|
|
943
968
|
if git(root, "ls-files", "-u"):
|
|
944
969
|
raise ValueError("Resolve merge conflicts before snapshotting")
|
|
945
970
|
head = git(root, "rev-parse", "HEAD")
|
|
@@ -1014,7 +1039,7 @@ def snapshot(root, workflow, files, request, *, preview=False, allowed=()):
|
|
|
1014
1039
|
tree,
|
|
1015
1040
|
"-p",
|
|
1016
1041
|
head,
|
|
1017
|
-
input=f"
|
|
1042
|
+
input=f"{snapshot_subject(request['id'], on_push)}\n\n{json.dumps(request)}\n",
|
|
1018
1043
|
)
|
|
1019
1044
|
return {**summary, "sha": sha}
|
|
1020
1045
|
|
|
@@ -1050,9 +1075,8 @@ def execution_lock(directory, execution_id):
|
|
|
1050
1075
|
def find_run(record):
|
|
1051
1076
|
if record.get("snapshot") is False:
|
|
1052
1077
|
return find_branch_run(record)
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
)
|
|
1078
|
+
event = "push" if record.get("startedOnPush") else "workflow_dispatch"
|
|
1079
|
+
query = urlencode({"event": event, "branch": record["branch"], "per_page": 100})
|
|
1056
1080
|
runs = api(
|
|
1057
1081
|
record["repository"], f"actions/workflows/{record['workflow']}/runs?{query}"
|
|
1058
1082
|
)
|
|
@@ -1274,15 +1298,19 @@ def http_status(error):
|
|
|
1274
1298
|
|
|
1275
1299
|
|
|
1276
1300
|
def preflight(repo, workflow, *, pushes=True, full_output=False, allows_files=False):
|
|
1277
|
-
|
|
1301
|
+
try:
|
|
1302
|
+
access = github_access()
|
|
1303
|
+
except ValueError as error:
|
|
1304
|
+
raise GithubUnreachable(str(error)) from error
|
|
1278
1305
|
try:
|
|
1279
1306
|
details = api(repo, "")
|
|
1280
1307
|
except RuntimeError as error:
|
|
1281
|
-
|
|
1308
|
+
refused = getattr(error, "http_status", None) in (401, 403, 404)
|
|
1309
|
+
raise (GithubUnreachable if refused else ValueError)(
|
|
1282
1310
|
f"GitHub access from {access['source']} cannot read {repo}{http_status(error)}; use an account or token with write access to it"
|
|
1283
1311
|
) from error
|
|
1284
1312
|
if pushes and (details or {}).get("permissions", {}).get("push") is False:
|
|
1285
|
-
raise
|
|
1313
|
+
raise GithubUnreachable(
|
|
1286
1314
|
f"GitHub access from {access['source']} cannot push to {repo}; use an account or token with write access to it"
|
|
1287
1315
|
)
|
|
1288
1316
|
if full_output and (details or {}).get("private") is False:
|
|
@@ -1344,6 +1372,12 @@ def submit(root, repo, workflow, parsed, path):
|
|
|
1344
1372
|
record = json.loads(path.read_text())
|
|
1345
1373
|
if record["request"] != request or record["repository"].lower() != repo.lower():
|
|
1346
1374
|
raise ValueError("Execution ID already belongs to a different request")
|
|
1375
|
+
if record.get("startedOnPush") and record["state"] != "prepared":
|
|
1376
|
+
try:
|
|
1377
|
+
github_access()
|
|
1378
|
+
except ValueError as error:
|
|
1379
|
+
record["unfollowed"] = str(error)
|
|
1380
|
+
return record
|
|
1347
1381
|
status(record, fetch_result=False)
|
|
1348
1382
|
if record["state"] == "prepared":
|
|
1349
1383
|
raise ValueError(
|
|
@@ -1351,17 +1385,24 @@ def submit(root, repo, workflow, parsed, path):
|
|
|
1351
1385
|
)
|
|
1352
1386
|
refuse_rejected(record)
|
|
1353
1387
|
return record
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1388
|
+
unfollowed = None
|
|
1389
|
+
try:
|
|
1390
|
+
preflight(
|
|
1391
|
+
repo,
|
|
1392
|
+
workflow,
|
|
1393
|
+
full_output=request.get("fullOutput") is True,
|
|
1394
|
+
allows_files=bool(allowed),
|
|
1395
|
+
)
|
|
1396
|
+
except GithubUnreachable as error:
|
|
1397
|
+
unfollowed = str(error)
|
|
1398
|
+
refuse_unfollowed(root, repo, workflow, request, allowed, unfollowed)
|
|
1360
1399
|
if dry_run(request["args"]):
|
|
1361
1400
|
progress(
|
|
1362
1401
|
"--dry-run dispatches a GitHub run that checks secrets and resolves the traces without replaying; it receives the workflow's secrets"
|
|
1363
1402
|
)
|
|
1364
|
-
source = snapshot(
|
|
1403
|
+
source = snapshot(
|
|
1404
|
+
root, workflow, files, request, allowed=allowed, on_push=bool(unfollowed)
|
|
1405
|
+
)
|
|
1365
1406
|
describe_snapshot(source)
|
|
1366
1407
|
record = {
|
|
1367
1408
|
"id": execution_id,
|
|
@@ -1370,6 +1411,7 @@ def submit(root, repo, workflow, parsed, path):
|
|
|
1370
1411
|
"branch": PREFIX + execution_id,
|
|
1371
1412
|
"request": request,
|
|
1372
1413
|
"state": "prepared",
|
|
1414
|
+
**({"startedOnPush": True} if unfollowed else {}),
|
|
1373
1415
|
**source,
|
|
1374
1416
|
}
|
|
1375
1417
|
save(path, record)
|
|
@@ -1389,6 +1431,9 @@ def submit(root, repo, workflow, parsed, path):
|
|
|
1389
1431
|
) from error
|
|
1390
1432
|
record["state"] = "dispatch_unknown"
|
|
1391
1433
|
save(path, record)
|
|
1434
|
+
if unfollowed:
|
|
1435
|
+
record["unfollowed"] = unfollowed
|
|
1436
|
+
return record
|
|
1392
1437
|
text = within(root, f"{WORKFLOW_DIRECTORY}/{workflow}").read_text()
|
|
1393
1438
|
declared = declared_inputs(text)
|
|
1394
1439
|
key_inputs = issue_key_token(root, record, text)
|
|
@@ -1400,6 +1445,62 @@ def submit(root, repo, workflow, parsed, path):
|
|
|
1400
1445
|
)
|
|
1401
1446
|
|
|
1402
1447
|
|
|
1448
|
+
def push_trigger(lines):
|
|
1449
|
+
for index, line in enumerate(lines):
|
|
1450
|
+
if re.fullmatch(r'"?on"?[ \t]*:[ \t]*(#.*)?', line):
|
|
1451
|
+
end = block_end(lines, index, 0)
|
|
1452
|
+
step = child_indent(lines, index, end, " ")
|
|
1453
|
+
row = next(
|
|
1454
|
+
(
|
|
1455
|
+
row
|
|
1456
|
+
for row in range(index + 1, end)
|
|
1457
|
+
if re.fullmatch(rf'{step}"?push"?[ \t]*:.*', lines[row])
|
|
1458
|
+
),
|
|
1459
|
+
None,
|
|
1460
|
+
)
|
|
1461
|
+
if row is None:
|
|
1462
|
+
return None
|
|
1463
|
+
return lines[row : block_end(lines, row, len(step))]
|
|
1464
|
+
if re.match(r'"?on"?[ \t]*:', line):
|
|
1465
|
+
return [line] if re.search(r"\bpush\b", line) else None
|
|
1466
|
+
return None
|
|
1467
|
+
|
|
1468
|
+
|
|
1469
|
+
def starts_on_push(text):
|
|
1470
|
+
trigger = push_trigger(text.splitlines()) or []
|
|
1471
|
+
return any(PREFIX in line for line in trigger) and not any(
|
|
1472
|
+
"branches-ignore" in line for line in trigger
|
|
1473
|
+
)
|
|
1474
|
+
|
|
1475
|
+
|
|
1476
|
+
def refuse_unfollowed(root, repo, workflow, request, allowed, reason):
|
|
1477
|
+
path = f"{WORKFLOW_DIRECTORY}/{workflow}"
|
|
1478
|
+
if not starts_on_push(within(root, path).read_text()):
|
|
1479
|
+
raise ValueError(
|
|
1480
|
+
f"{reason}. Without it a replay can still run, with no updates here, once {path} also starts on a push to a {PREFIX} branch: run bitfab-replay --cloud-update and commit the workflow it updates"
|
|
1481
|
+
)
|
|
1482
|
+
if request.get("fullOutput") is True:
|
|
1483
|
+
raise ValueError(
|
|
1484
|
+
f"--cloud-full-output writes every trace's input and output into the Actions job log, so it needs GitHub access that confirms {repo} is private: {reason}"
|
|
1485
|
+
)
|
|
1486
|
+
if allowed:
|
|
1487
|
+
raise ValueError(
|
|
1488
|
+
f"{ALLOW_FLAG} uploads a credential-like file to a snapshot branch, so it needs GitHub access that confirms {repo} is private: {reason}"
|
|
1489
|
+
)
|
|
1490
|
+
|
|
1491
|
+
|
|
1492
|
+
def report_unfollowed(record, reason):
|
|
1493
|
+
progress(
|
|
1494
|
+
f"Warning: the replay started on GitHub, but this command gets no updates on it: {reason}"
|
|
1495
|
+
)
|
|
1496
|
+
progress(
|
|
1497
|
+
f"It runs with the workflow's BITFAB_API_KEY secret, since replaying as you needs GitHub access. Watch it at https://github.com/{record['repository']}/actions/workflows/{record['workflow']}; its experiment appears in Bitfab when it finishes"
|
|
1498
|
+
)
|
|
1499
|
+
progress(
|
|
1500
|
+
f"Once it finishes, delete its snapshot branch with git push origin --delete {record['branch']}, or with --cloud-cleanup {record['id']} from a machine with GitHub access"
|
|
1501
|
+
)
|
|
1502
|
+
|
|
1503
|
+
|
|
1403
1504
|
def local_client(root, request):
|
|
1404
1505
|
try:
|
|
1405
1506
|
output = command(
|
|
@@ -1736,6 +1837,11 @@ def run_cli(argv):
|
|
|
1736
1837
|
raise
|
|
1737
1838
|
if record.get("preview"):
|
|
1738
1839
|
return record, None
|
|
1840
|
+
reason = record.pop("unfollowed", None)
|
|
1841
|
+
if reason:
|
|
1842
|
+
report_unfollowed(record, reason)
|
|
1843
|
+
save(path, record)
|
|
1844
|
+
return record, None
|
|
1739
1845
|
else:
|
|
1740
1846
|
if not path.exists():
|
|
1741
1847
|
raise ValueError(
|
|
@@ -2791,7 +2897,7 @@ def push_triggers(root, workflow):
|
|
|
2791
2897
|
|
|
2792
2898
|
|
|
2793
2899
|
def workflow_document(steps, run, directory, env, *, runs_on, environment):
|
|
2794
|
-
job = {"runs-on": runs_on}
|
|
2900
|
+
job = {"if": PUSH_CONDITION, "runs-on": runs_on}
|
|
2795
2901
|
if environment:
|
|
2796
2902
|
job["environment"] = environment
|
|
2797
2903
|
job["steps"] = [
|
|
@@ -2816,7 +2922,8 @@ def workflow_document(steps, run, directory, env, *, runs_on, environment):
|
|
|
2816
2922
|
"request": {"type": "string", "required": False},
|
|
2817
2923
|
KEY_INPUT: {"type": "string", "required": False},
|
|
2818
2924
|
}
|
|
2819
|
-
}
|
|
2925
|
+
},
|
|
2926
|
+
"push": {"branches": [PREFIX + "**"]},
|
|
2820
2927
|
},
|
|
2821
2928
|
"permissions": {"contents": "read", "id-token": "write"},
|
|
2822
2929
|
"jobs": {"replay": job},
|
|
@@ -2830,10 +2937,18 @@ def indentation(line):
|
|
|
2830
2937
|
def block_end(lines, start, indent):
|
|
2831
2938
|
end = start + 1
|
|
2832
2939
|
while end < len(lines) and (
|
|
2833
|
-
not lines[end].strip()
|
|
2940
|
+
not lines[end].strip()
|
|
2941
|
+
or lines[end].lstrip().startswith("#")
|
|
2942
|
+
or indentation(lines[end]) > indent
|
|
2834
2943
|
):
|
|
2835
2944
|
end += 1
|
|
2836
|
-
while end > start + 1 and
|
|
2945
|
+
while end > start + 1 and (
|
|
2946
|
+
not lines[end - 1].strip()
|
|
2947
|
+
or (
|
|
2948
|
+
lines[end - 1].lstrip().startswith("#")
|
|
2949
|
+
and indentation(lines[end - 1]) <= indent
|
|
2950
|
+
)
|
|
2951
|
+
):
|
|
2837
2952
|
end -= 1
|
|
2838
2953
|
return end
|
|
2839
2954
|
|
|
@@ -2938,19 +3053,67 @@ def add_id_token_permission(lines):
|
|
|
2938
3053
|
if not re.fullmatch(r'"?permissions"?[ \t]*:[ \t]*(#.*)?', line):
|
|
2939
3054
|
continue
|
|
2940
3055
|
end = block_end(lines, index, 0)
|
|
2941
|
-
|
|
2942
|
-
(
|
|
2943
|
-
lines[row][: indentation(lines[row])]
|
|
2944
|
-
for row in range(index + 1, end)
|
|
2945
|
-
if lines[row].strip()
|
|
2946
|
-
),
|
|
2947
|
-
" ",
|
|
2948
|
-
)
|
|
2949
|
-
lines.insert(end, f"{child}id-token: write")
|
|
3056
|
+
lines.insert(end, f"{child_indent(lines, index, end, ' ')}id-token: write")
|
|
2950
3057
|
return True
|
|
2951
3058
|
return False
|
|
2952
3059
|
|
|
2953
3060
|
|
|
3061
|
+
def holds_yaml(line):
|
|
3062
|
+
return bool(line.strip()) and not line.lstrip().startswith("#")
|
|
3063
|
+
|
|
3064
|
+
|
|
3065
|
+
def child_indent(lines, index, end, fallback):
|
|
3066
|
+
return next(
|
|
3067
|
+
(
|
|
3068
|
+
lines[row][: indentation(lines[row])]
|
|
3069
|
+
for row in range(index + 1, end)
|
|
3070
|
+
if holds_yaml(lines[row])
|
|
3071
|
+
),
|
|
3072
|
+
fallback,
|
|
3073
|
+
)
|
|
3074
|
+
|
|
3075
|
+
|
|
3076
|
+
def add_push_trigger(lines):
|
|
3077
|
+
for index, line in enumerate(lines):
|
|
3078
|
+
if not re.fullmatch(r'"?on"?[ \t]*:[ \t]*(#.*)?', line):
|
|
3079
|
+
continue
|
|
3080
|
+
end = block_end(lines, index, 0)
|
|
3081
|
+
step = child_indent(lines, index, end, " ")
|
|
3082
|
+
lines[end:end] = [
|
|
3083
|
+
f"{step}push:",
|
|
3084
|
+
f"{step * 2}branches:",
|
|
3085
|
+
f"{step * 3}- {PREFIX}**",
|
|
3086
|
+
]
|
|
3087
|
+
return True
|
|
3088
|
+
return False
|
|
3089
|
+
|
|
3090
|
+
|
|
3091
|
+
def add_push_condition(lines):
|
|
3092
|
+
jobs = next(
|
|
3093
|
+
(
|
|
3094
|
+
index
|
|
3095
|
+
for index, line in enumerate(lines)
|
|
3096
|
+
if re.fullmatch(r'"?jobs"?[ \t]*:[ \t]*(#.*)?', line)
|
|
3097
|
+
),
|
|
3098
|
+
None,
|
|
3099
|
+
)
|
|
3100
|
+
if jobs is None:
|
|
3101
|
+
return False
|
|
3102
|
+
end = block_end(lines, jobs, 0)
|
|
3103
|
+
job = next((row for row in range(jobs + 1, end) if holds_yaml(lines[row])), None)
|
|
3104
|
+
if job is None or not lines[job].rstrip().endswith(":"):
|
|
3105
|
+
return False
|
|
3106
|
+
job_end = block_end(lines, job, indentation(lines[job]))
|
|
3107
|
+
step = child_indent(lines, job, job_end, " " * (indentation(lines[job]) + 2))
|
|
3108
|
+
if any(
|
|
3109
|
+
re.fullmatch(rf'{step}"?if"?[ \t]*:.*', lines[row])
|
|
3110
|
+
for row in range(job + 1, job_end)
|
|
3111
|
+
):
|
|
3112
|
+
return False
|
|
3113
|
+
lines.insert(job + 1, f"{step}if: {json.dumps(PUSH_CONDITION)}")
|
|
3114
|
+
return True
|
|
3115
|
+
|
|
3116
|
+
|
|
2954
3117
|
def secret_scope(environment):
|
|
2955
3118
|
return f"environments/{environment}/" if environment else "actions/"
|
|
2956
3119
|
|
|
@@ -3041,6 +3204,20 @@ def update_workflow(root, path, *, remove_old_key_secrets=False):
|
|
|
3041
3204
|
by_hand.append(
|
|
3042
3205
|
f"{name} (type: string, required: false) under on.workflow_dispatch.inputs"
|
|
3043
3206
|
)
|
|
3207
|
+
if not starts_on_push(text):
|
|
3208
|
+
if push_trigger(lines) is None and add_push_trigger(lines):
|
|
3209
|
+
updated.append(
|
|
3210
|
+
f"Started the workflow on a push to a {PREFIX} branch too, so a replay runs without GitHub access, with no updates on it"
|
|
3211
|
+
)
|
|
3212
|
+
else:
|
|
3213
|
+
by_hand.append(f"{PREFIX}** in on.push.branches")
|
|
3214
|
+
if push_trigger(lines) is not None and PUSH_SUBJECT not in text:
|
|
3215
|
+
if add_push_condition(lines):
|
|
3216
|
+
updated.append(
|
|
3217
|
+
"Skipped the push run of a replay started through the GitHub API, so each replay runs once"
|
|
3218
|
+
)
|
|
3219
|
+
else:
|
|
3220
|
+
by_hand.append(f"if: {json.dumps(PUSH_CONDITION)} on the replay job")
|
|
3044
3221
|
if not re.search(r'^"?run-name"?[ \t]*:', text, re.MULTILINE):
|
|
3045
3222
|
add_run_name(lines)
|
|
3046
3223
|
updated.append("Named each run after its execution")
|
|
@@ -3095,7 +3272,7 @@ def update_workflow(root, path, *, remove_old_key_secrets=False):
|
|
|
3095
3272
|
def initialize(argv, name="--cloud-init"):
|
|
3096
3273
|
parser = argparse.ArgumentParser(
|
|
3097
3274
|
prog=f"bitfab-replay {name}",
|
|
3098
|
-
description="Write .github/workflows/bitfab-replay.yml, the only file cloud replay keeps in the repository, and list what is left to do. It detects the runtime, package manager, install command, and replay command from the directory you run it in. On an existing workflow it only adds what a newer SDK needs (the execution_id and key_id inputs, the run name, and the id-token: write permission), removes the BITFAB_REPLAY_BITFAB_API_KEY line older SDKs wrote, lists what it changed, and lists the BITFAB_REPLAY_KEY_* secrets older SDKs left in the repository; edit it directly for anything else.",
|
|
3275
|
+
description="Write .github/workflows/bitfab-replay.yml, the only file cloud replay keeps in the repository, and list what is left to do. It detects the runtime, package manager, install command, and replay command from the directory you run it in. On an existing workflow it only adds what a newer SDK needs (the execution_id and key_id inputs, the push trigger and the condition that skips a duplicate push run, the run name, and the id-token: write permission), removes the BITFAB_REPLAY_BITFAB_API_KEY line older SDKs wrote, lists what it changed, and lists the BITFAB_REPLAY_KEY_* secrets older SDKs left in the repository; edit it directly for anything else.",
|
|
3099
3276
|
)
|
|
3100
3277
|
parser.add_argument(
|
|
3101
3278
|
"--secret",
|
package/dist/autoTrace.cjs
CHANGED
|
@@ -27,6 +27,7 @@ __export(autoTrace_exports, {
|
|
|
27
27
|
clearAutoTraceNodeConfiguration: () => clearAutoTraceNodeConfiguration,
|
|
28
28
|
currentAutoTraceEntries: () => currentAutoTraceEntries,
|
|
29
29
|
invokeThroughAutoTraceEntries: () => invokeThroughAutoTraceEntries,
|
|
30
|
+
runAsAutoTraceRootFunction: () => runAsAutoTraceRootFunction,
|
|
30
31
|
runWithAutoTraceEntry: () => runWithAutoTraceEntry,
|
|
31
32
|
runWithAutoTraceNodeConfiguration: () => runWithAutoTraceNodeConfiguration,
|
|
32
33
|
runWithAutoTraceRootContext: () => runWithAutoTraceRootContext
|
|
@@ -155,6 +156,29 @@ function runWithAutoTraceNodeConfiguration(nodeConfiguration, fn) {
|
|
|
155
156
|
}
|
|
156
157
|
return result;
|
|
157
158
|
}
|
|
159
|
+
function runAsAutoTraceRootFunction(functionName, fn) {
|
|
160
|
+
const scope = currentAutoTraceScope();
|
|
161
|
+
if (!scope || scope.entries.length === 0 || functionName === "") {
|
|
162
|
+
return fn();
|
|
163
|
+
}
|
|
164
|
+
const rootFunction = {
|
|
165
|
+
name: functionName,
|
|
166
|
+
entering: true
|
|
167
|
+
};
|
|
168
|
+
try {
|
|
169
|
+
return runWithAutoTraceScope({ ...scope, rootFunction }, fn);
|
|
170
|
+
} finally {
|
|
171
|
+
rootFunction.entering = false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function isRootFunctionEntry(scope, simpleName) {
|
|
175
|
+
const rootFunction = scope.rootFunction;
|
|
176
|
+
if (rootFunction === void 0 || !rootFunction.entering) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
rootFunction.entering = false;
|
|
180
|
+
return rootFunction.name === simpleName;
|
|
181
|
+
}
|
|
158
182
|
var SUBTREE_TRACING_DOCS_URL = "https://docs.bitfab.ai/typescript-sdk#experimental-subtree-tracing";
|
|
159
183
|
function noteTransformedModule() {
|
|
160
184
|
autoTraceGlobal.__bitfab_auto_trace_transformed_v1__ = true;
|
|
@@ -264,6 +288,9 @@ function __bitfabAutoSpan(definition, inputs, fn) {
|
|
|
264
288
|
}
|
|
265
289
|
const nameParts = definition.name.split(".");
|
|
266
290
|
const simpleName = nameParts[nameParts.length - 1];
|
|
291
|
+
if (isRootFunctionEntry(scope, simpleName)) {
|
|
292
|
+
return fn();
|
|
293
|
+
}
|
|
267
294
|
const nodeConfiguration = simpleName === scope.nodeConfiguration?.functionName ? shareFinalize(scope.nodeConfiguration) : void 0;
|
|
268
295
|
return invokeThroughAutoTraceEntries(
|
|
269
296
|
scope.entries,
|
|
@@ -319,6 +346,7 @@ function _resetAutoTraceTransformDetection() {
|
|
|
319
346
|
clearAutoTraceNodeConfiguration,
|
|
320
347
|
currentAutoTraceEntries,
|
|
321
348
|
invokeThroughAutoTraceEntries,
|
|
349
|
+
runAsAutoTraceRootFunction,
|
|
322
350
|
runWithAutoTraceEntry,
|
|
323
351
|
runWithAutoTraceNodeConfiguration,
|
|
324
352
|
runWithAutoTraceRootContext
|
package/dist/autoTrace.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/autoTrace.ts","../src/asyncStorage.ts","../src/captureSuppression.ts","../src/warnOnce.ts"],"sourcesContent":["import {\n type AsyncLocalStorageLike,\n createAsyncLocalStorage,\n} from \"./asyncStorage.js\"\nimport { isCaptureSuppressed } from \"./captureSuppression.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\nexport interface AutoTraceFunctionDefinition {\n id: string\n name: string\n file: string\n line: number\n column: number\n async?: boolean\n wrapper?: boolean\n}\n\nexport interface AutoTraceNodeConfiguration {\n functionName: string\n name?: string\n type?: \"llm\" | \"agent\" | \"function\" | \"guardrail\" | \"handoff\" | \"custom\"\n capture: boolean\n experimentId?: string\n /** @deprecated Use experimentId. */\n testRunId?: string\n mockOnReplay?: boolean\n replayReusable?: boolean\n // biome-ignore lint/suspicious/noExplicitAny: node finalizers receive the configured function's result, whose type is owned by the caller\n finalize?: (result: any) => unknown | Promise<unknown>\n}\n\nexport interface NestedTraceLink {\n traceFunctionKey: string\n traceId?: string\n rootSpanId?: string\n}\n\nexport interface AutoTraceEntry {\n context: AutoTraceContext\n depth: number\n spanStack: unknown\n}\n\nexport interface AutoTraceContext {\n readonly traceFunctionKey: string\n invoke<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n entry: AutoTraceEntry,\n nodeConfiguration?: AutoTraceNodeConfiguration,\n ): T\n invokeNestedRoot<T>(\n name: string,\n functionName: string,\n inputs: unknown[],\n fn: () => T,\n entry: AutoTraceEntry,\n link: NestedTraceLink | undefined,\n ): T\n}\n\ninterface AutoTraceScope {\n entries: readonly AutoTraceEntry[]\n nodeConfiguration?: AutoTraceNodeConfiguration\n}\n\ninterface AutoTraceState {\n storage: AsyncLocalStorageLike<AutoTraceScope> | null\n browserScope: AutoTraceScope | undefined\n // Older SDK copies read this field when sharing the process-wide V4 state.\n capturePolicies: WeakMap<object, Map<string, ReadonlySet<string>>>\n activeRoots: number\n}\n\ninterface AutoTraceGlobal {\n __bitfabAutoTraceStateV4?: AutoTraceState\n __bitfab_auto_trace_transformed_v1__?: boolean\n}\n\ninterface AutoTraceAsyncGenerator {\n next(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n return(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n throw(error?: unknown): Promise<IteratorResult<unknown, unknown>>\n [Symbol.asyncIterator](): AutoTraceAsyncGenerator\n}\n\nconst autoTraceGlobal = globalThis as unknown as AutoTraceGlobal\nconst autoTraceState: AutoTraceState =\n autoTraceGlobal.__bitfabAutoTraceStateV4 ?? {\n storage: null,\n browserScope: undefined,\n capturePolicies: new WeakMap(),\n activeRoots: 0,\n }\nautoTraceGlobal.__bitfabAutoTraceStateV4 = autoTraceState\n\nfunction initializeAutoTraceStorage(): void {\n autoTraceState.storage ??= createAsyncLocalStorage<AutoTraceScope>()\n}\n\nfunction runWithAutoTraceScope<T>(scope: AutoTraceScope, fn: () => T): T {\n initializeAutoTraceStorage()\n if (autoTraceState.storage) {\n return autoTraceState.storage.run(scope, fn)\n }\n\n const previous = autoTraceState.browserScope\n autoTraceState.browserScope = scope\n try {\n return fn()\n } finally {\n autoTraceState.browserScope = previous\n }\n}\n\nexport function currentAutoTraceEntries(): readonly AutoTraceEntry[] {\n return currentAutoTraceScope()?.entries ?? []\n}\n\nfunction replaceEntry(\n entries: readonly AutoTraceEntry[],\n previous: AutoTraceEntry,\n updated: AutoTraceEntry,\n): readonly AutoTraceEntry[] {\n return entries.map((entry) => (entry === previous ? updated : entry))\n}\n\nexport function runWithAutoTraceEntry<T>(\n previous: AutoTraceEntry,\n updated: AutoTraceEntry,\n fn: () => T,\n): T {\n const result = runWithAutoTraceScope(\n { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },\n fn,\n )\n if (isAutoTraceAsyncGenerator(result)) {\n return wrapAutoTraceEntryAsyncGenerator(previous, updated, result) as T\n }\n return result\n}\n\nfunction wrapAutoTraceEntryAsyncGenerator(\n previous: AutoTraceEntry,\n updated: AutoTraceEntry,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceScope(\n { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },\n () => source[method](value),\n )\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nexport function clearAutoTraceNodeConfiguration<T>(fn: () => T): T {\n return runWithAutoTraceScope({ entries: currentAutoTraceEntries() }, fn)\n}\n\nexport function runWithAutoTraceNodeConfiguration<T>(\n nodeConfiguration: AutoTraceNodeConfiguration,\n fn: () => T,\n): T {\n const scope = currentAutoTraceScope()\n if (!scope || scope.entries.length === 0) {\n return fn()\n }\n\n const result = runWithAutoTraceScope({ ...scope, nodeConfiguration }, fn)\n if (isAutoTraceAsyncGenerator(result)) {\n return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result) as T\n }\n return result\n}\n\nconst SUBTREE_TRACING_DOCS_URL =\n \"https://docs.bitfab.ai/typescript-sdk#experimental-subtree-tracing\"\n\nfunction noteTransformedModule(): void {\n autoTraceGlobal.__bitfab_auto_trace_transformed_v1__ = true\n}\n\nfunction transformInstalled(): boolean {\n return autoTraceGlobal.__bitfab_auto_trace_transformed_v1__ === true\n}\n\nfunction runsOnNode(): boolean {\n return typeof process !== \"undefined\" && Boolean(process.versions?.node)\n}\n\nfunction closeAutoTraceRoot(): void {\n autoTraceState.activeRoots -= 1\n}\n\nfunction settleAutoTraceRoot(context: AutoTraceContext): void {\n closeAutoTraceRoot()\n if (transformInstalled() || !runsOnNode()) {\n return\n }\n warnOnce(\n \"auto-trace-transform-missing\",\n `trace root \"${context.traceFunctionKey}\" recorded only its own span. ` +\n \"No module in this build was compiled by @bitfab/sdk/transform, so calls \" +\n \"beneath the root were not discovered. Add the SDK's transform adapter \" +\n `to the server build: ${SUBTREE_TRACING_DOCS_URL}`,\n )\n}\n\nexport function runWithAutoTraceRootContext<T>(\n context: AutoTraceContext,\n spanStack: unknown,\n fn: () => T,\n): T {\n autoTraceState.activeRoots += 1\n const entries = [\n ...currentAutoTraceEntries(),\n { context, depth: 0, spanStack },\n ]\n let result: T\n try {\n result = runWithAutoTraceScope({ entries }, fn)\n } catch (error) {\n settleAutoTraceRoot(context)\n throw error\n }\n\n if (isAutoTraceAsyncGenerator(result)) {\n closeAutoTraceRoot()\n return wrapAutoTraceAsyncGenerator(context, spanStack, result) as T\n }\n\n if (result instanceof Promise) {\n return result.finally(() => {\n settleAutoTraceRoot(context)\n }) as T\n }\n\n settleAutoTraceRoot(context)\n return result\n}\n\nexport function invokeThroughAutoTraceEntries<T>(\n entries: readonly AutoTraceEntry[],\n step: (entry: AutoTraceEntry, next: () => T) => T,\n fn: () => T,\n): T {\n let run = fn\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index] as AutoTraceEntry\n const next = run\n run = () => step(entry, next)\n }\n return run()\n}\n\nfunction isAutoTraceAsyncGenerator(\n value: unknown,\n): value is AutoTraceAsyncGenerator {\n if (value === null || typeof value !== \"object\") {\n return false\n }\n const candidate = value as Record<PropertyKey, unknown>\n return (\n typeof candidate.next === \"function\" &&\n typeof candidate.return === \"function\" &&\n typeof candidate.throw === \"function\" &&\n typeof candidate[Symbol.asyncIterator] === \"function\"\n )\n}\n\nfunction wrapAutoTraceAsyncGenerator(\n context: AutoTraceContext,\n spanStack: unknown,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceRootContext(context, spanStack, () => source[method](value))\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nfunction wrapAutoTraceNodeAsyncGenerator(\n nodeConfiguration: AutoTraceNodeConfiguration,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceNodeConfiguration(nodeConfiguration, () =>\n source[method](value),\n )\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nfunction shareFinalize(\n configuration: AutoTraceNodeConfiguration,\n): AutoTraceNodeConfiguration {\n const finalize = configuration.finalize\n if (finalize === undefined) {\n return configuration\n }\n let settled: Promise<unknown> | undefined\n return {\n ...configuration,\n finalize: (result: unknown) => {\n settled ??= Promise.resolve().then(() => finalize(result))\n return settled\n },\n }\n}\n\nexport function __bitfabAutoSpan<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n): T {\n noteTransformedModule()\n const scope = currentAutoTraceScope()\n if (!scope || scope.entries.length === 0 || isCaptureSuppressed()) {\n return fn()\n }\n const nameParts = definition.name.split(\".\")\n const simpleName = nameParts[nameParts.length - 1]\n const nodeConfiguration =\n simpleName === scope.nodeConfiguration?.functionName\n ? shareFinalize(scope.nodeConfiguration)\n : undefined\n return invokeThroughAutoTraceEntries(\n scope.entries,\n (entry, next) =>\n entry.context.invoke(definition, inputs, next, entry, nodeConfiguration),\n fn,\n )\n}\n\n/**\n * Preserve a function's original call arguments for transform cases where\n * parameter bindings discard them, such as destructured arrow parameters.\n *\n * This helper is internal transform/runtime protocol. The proxy preserves the\n * target's callability, arity, async identity, and non-constructibility while\n * only allocating a trace closure beneath an active automatic trace root.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoWrap<T extends (...args: never[]) => unknown>(\n definition: AutoTraceFunctionDefinition,\n fn: T,\n): T {\n noteTransformedModule()\n if (fn.name === \"\") {\n const nameParts = definition.name.split(\".\")\n const inferredName = nameParts[nameParts.length - 1]\n if (inferredName !== undefined) {\n Object.defineProperty(fn, \"name\", {\n configurable: true,\n value: inferredName,\n })\n }\n }\n\n const target = fn as unknown as (...args: unknown[]) => unknown\n return new Proxy(target, {\n apply(callTarget, thisArg, args) {\n if (!__bitfabAutoTraceActive()) {\n return Reflect.apply(callTarget, thisArg, args)\n }\n return __bitfabAutoSpan(definition, args, () =>\n Reflect.apply(callTarget, thisArg, args),\n )\n },\n }) as unknown as T\n}\n\n/**\n * Return whether the current call is inside an automatic trace root.\n *\n * Build transforms use this before allocating function metadata, captured\n * inputs, or an invocation closure. It is internal transform/runtime protocol,\n * not a supported application API.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoTraceActive(): boolean {\n if (autoTraceState.activeRoots === 0 || isCaptureSuppressed()) {\n return false\n }\n return currentAutoTraceEntries().length > 0\n}\n\nfunction currentAutoTraceScope(): AutoTraceScope | undefined {\n initializeAutoTraceStorage()\n return autoTraceState.storage?.getStore() ?? autoTraceState.browserScope\n}\n\nexport function _resetAutoTraceTransformDetection(): void {\n autoTraceGlobal.__bitfab_auto_trace_transformed_v1__ = undefined\n}\n","/**\n * Shared AsyncLocalStorage loader.\n *\n * Provides two ways to initialize AsyncLocalStorage:\n *\n * 1. **Synchronous registration** (preferred for Node.js):\n * `asyncStorageNode.ts` calls `registerAsyncLocalStorageClass()` at module\n * evaluation time, so the class is available immediately - no async gap.\n * The `node.ts` entry point imports it before anything else.\n *\n * 2. **Async dynamic import** (fallback for the default entry point):\n * Loads `node:async_hooks` via a bundler-safe dynamic import. This is used\n * by the default `index.ts` entry point so the SDK works in browsers\n * (where the import silently fails) and in Node.js when imported via the\n * default entry point.\n *\n * ## Why the dynamic import looks like this\n *\n * We need to handle three environments:\n *\n * 1. **Pure Node.js** - `import(\"node:async_hooks\")` works natively.\n * 2. **Webpack/Turbopack (Next.js server)** - The bundler processes\n * `import()` calls at build time. The `webpackIgnore` magic comment tells\n * webpack (and turbopack) to emit a native `import()` call instead of\n * trying to resolve it, so Node.js handles it at runtime.\n * 3. **Browsers / Edge** - The `process.versions?.node` guard prevents\n * execution entirely. If it somehow runs, `.catch(() => {})` swallows\n * the failure.\n */\n\nexport interface AsyncLocalStorageLike<T> {\n getStore(): T | undefined\n run<R>(store: T, fn: () => R): R\n}\n\nlet AsyncLocalStorageClass: (new () => AsyncLocalStorageLike<unknown>) | null =\n null\nlet initDone = false\n\n/**\n * Register the AsyncLocalStorage class synchronously.\n *\n * Called by `asyncStorageNode.ts` at module evaluation time so the class\n * is available before any span is created - no async gap, no race condition.\n *\n * Safe to call multiple times; subsequent calls are no-ops.\n */\nexport function registerAsyncLocalStorageClass(\n cls: new () => AsyncLocalStorageLike<unknown>,\n): void {\n if (!AsyncLocalStorageClass) {\n AsyncLocalStorageClass = cls\n }\n initDone = true\n}\n\n/**\n * Assert that AsyncLocalStorage was registered successfully.\n *\n * Called by `node.ts` after importing `asyncStorageNode.ts` to catch\n * import-order bugs at startup rather than silently degrading to the\n * browser fallback (flat spans with no nesting).\n *\n * This should ONLY be called from the Node.js entry point where we\n * know `node:async_hooks` must be available.\n */\nexport function assertAsyncStorageRegistered(): void {\n if (!AsyncLocalStorageClass) {\n console.warn(\n \"Bitfab: AsyncLocalStorage not available - nested span context will not propagate.\",\n )\n }\n}\n\nexport const asyncStorageReady: Promise<void> = (\n typeof process !== \"undefined\" && process.versions?.node\n ? // The join trick hides \"node:async_hooks\" from static analysis so\n // bundlers that ban Node.js built-ins don't fail at build time.\n // webpackIgnore tells webpack/turbopack to emit a native import()\n // so Node.js can resolve the module at runtime.\n import(\n /* webpackIgnore: true */\n [\"node\", \"async_hooks\"].join(\":\")\n )\n .then(\n (mod: {\n AsyncLocalStorage: new () => AsyncLocalStorageLike<unknown>\n }) => {\n registerAsyncLocalStorageClass(mod.AsyncLocalStorage)\n },\n )\n .catch(() => {})\n : Promise.resolve()\n).then(() => {\n initDone = true\n})\n\nexport function isAsyncStorageInitDone(): boolean {\n return initDone\n}\n\nexport function createAsyncLocalStorage<T>(): AsyncLocalStorageLike<T> | null {\n return AsyncLocalStorageClass\n ? (new AsyncLocalStorageClass() as AsyncLocalStorageLike<T>)\n : null\n}\n","interface CaptureSuppressionState {\n depth: number\n}\n\ninterface CaptureSuppressionGlobal {\n __bitfabCaptureSuppressionV1?: CaptureSuppressionState\n}\n\nconst suppressionGlobal = globalThis as unknown as CaptureSuppressionGlobal\nconst suppressionState: CaptureSuppressionState =\n suppressionGlobal.__bitfabCaptureSuppressionV1 ?? { depth: 0 }\nsuppressionGlobal.__bitfabCaptureSuppressionV1 = suppressionState\n\nexport function isCaptureSuppressed(): boolean {\n return suppressionState.depth > 0\n}\n\nexport function runWithCaptureSuppressed<T>(fn: () => T): T {\n suppressionState.depth += 1\n try {\n return fn()\n } finally {\n suppressionState.depth -= 1\n }\n}\n","/**\n * Emit a `console.warn` at most once per distinct `key` for the life of the\n * process.\n *\n * The SDK must NEVER crash a host app, so every failure on the user's path\n * degrades silently (a span is dropped, a call runs untraced, a payload is\n * stubbed). Silent is safe but undebuggable: a user who suddenly has no traces,\n * or sees `<unserializable>` in a span, has no signal as to why. A one-time\n * warning per distinct issue restores that signal without spamming the console\n * from a hot path.\n *\n * Keys should identify the specific degradation (e.g. include the traced\n * function key) so each distinct issue warns once, not just the first one seen.\n */\nconst warned = new Set<string>()\n\nexport function warn(message: string): void {\n try {\n console.warn(`[bitfab] ${message}`)\n } catch {\n // Logging must never crash the host app (e.g. a closed/replaced console).\n }\n}\n\nexport function warnOnce(key: string, message: string): void {\n if (warned.has(key)) {\n return\n }\n warned.add(key)\n warn(message)\n}\n\nexport function writeOnce(\n key: string,\n line: string,\n write: (line: string) => void = console.warn,\n): void {\n if (warned.has(key)) {\n return\n }\n warned.add(key)\n try {\n write(line)\n } catch {}\n}\n\n/** Test-only: clear the dedup set so a warning can fire again. */\nexport function _resetWarnOnce(): void {\n warned.clear()\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/autoTrace.ts","../src/asyncStorage.ts","../src/captureSuppression.ts","../src/warnOnce.ts"],"sourcesContent":["import {\n type AsyncLocalStorageLike,\n createAsyncLocalStorage,\n} from \"./asyncStorage.js\"\nimport { isCaptureSuppressed } from \"./captureSuppression.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\nexport interface AutoTraceFunctionDefinition {\n id: string\n name: string\n file: string\n line: number\n column: number\n async?: boolean\n wrapper?: boolean\n}\n\nexport interface AutoTraceNodeConfiguration {\n functionName: string\n name?: string\n type?: \"llm\" | \"agent\" | \"function\" | \"guardrail\" | \"handoff\" | \"custom\"\n capture: boolean\n experimentId?: string\n /** @deprecated Use experimentId. */\n testRunId?: string\n mockOnReplay?: boolean\n replayReusable?: boolean\n // biome-ignore lint/suspicious/noExplicitAny: node finalizers receive the configured function's result, whose type is owned by the caller\n finalize?: (result: any) => unknown | Promise<unknown>\n}\n\nexport interface NestedTraceLink {\n traceFunctionKey: string\n traceId?: string\n rootSpanId?: string\n}\n\nexport interface AutoTraceEntry {\n context: AutoTraceContext\n depth: number\n spanStack: unknown\n}\n\nexport interface AutoTraceContext {\n readonly traceFunctionKey: string\n invoke<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n entry: AutoTraceEntry,\n nodeConfiguration?: AutoTraceNodeConfiguration,\n ): T\n invokeNestedRoot<T>(\n name: string,\n functionName: string,\n inputs: unknown[],\n fn: () => T,\n entry: AutoTraceEntry,\n link: NestedTraceLink | undefined,\n ): T\n}\n\ninterface AutoTraceRootFunction {\n name: string\n entering: boolean\n}\n\ninterface AutoTraceScope {\n entries: readonly AutoTraceEntry[]\n nodeConfiguration?: AutoTraceNodeConfiguration\n rootFunction?: AutoTraceRootFunction\n}\n\ninterface AutoTraceState {\n storage: AsyncLocalStorageLike<AutoTraceScope> | null\n browserScope: AutoTraceScope | undefined\n // Older SDK copies read this field when sharing the process-wide V4 state.\n capturePolicies: WeakMap<object, Map<string, ReadonlySet<string>>>\n activeRoots: number\n}\n\ninterface AutoTraceGlobal {\n __bitfabAutoTraceStateV4?: AutoTraceState\n __bitfab_auto_trace_transformed_v1__?: boolean\n}\n\ninterface AutoTraceAsyncGenerator {\n next(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n return(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n throw(error?: unknown): Promise<IteratorResult<unknown, unknown>>\n [Symbol.asyncIterator](): AutoTraceAsyncGenerator\n}\n\nconst autoTraceGlobal = globalThis as unknown as AutoTraceGlobal\nconst autoTraceState: AutoTraceState =\n autoTraceGlobal.__bitfabAutoTraceStateV4 ?? {\n storage: null,\n browserScope: undefined,\n capturePolicies: new WeakMap(),\n activeRoots: 0,\n }\nautoTraceGlobal.__bitfabAutoTraceStateV4 = autoTraceState\n\nfunction initializeAutoTraceStorage(): void {\n autoTraceState.storage ??= createAsyncLocalStorage<AutoTraceScope>()\n}\n\nfunction runWithAutoTraceScope<T>(scope: AutoTraceScope, fn: () => T): T {\n initializeAutoTraceStorage()\n if (autoTraceState.storage) {\n return autoTraceState.storage.run(scope, fn)\n }\n\n const previous = autoTraceState.browserScope\n autoTraceState.browserScope = scope\n try {\n return fn()\n } finally {\n autoTraceState.browserScope = previous\n }\n}\n\nexport function currentAutoTraceEntries(): readonly AutoTraceEntry[] {\n return currentAutoTraceScope()?.entries ?? []\n}\n\nfunction replaceEntry(\n entries: readonly AutoTraceEntry[],\n previous: AutoTraceEntry,\n updated: AutoTraceEntry,\n): readonly AutoTraceEntry[] {\n return entries.map((entry) => (entry === previous ? updated : entry))\n}\n\nexport function runWithAutoTraceEntry<T>(\n previous: AutoTraceEntry,\n updated: AutoTraceEntry,\n fn: () => T,\n): T {\n const result = runWithAutoTraceScope(\n { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },\n fn,\n )\n if (isAutoTraceAsyncGenerator(result)) {\n return wrapAutoTraceEntryAsyncGenerator(previous, updated, result) as T\n }\n return result\n}\n\nfunction wrapAutoTraceEntryAsyncGenerator(\n previous: AutoTraceEntry,\n updated: AutoTraceEntry,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceScope(\n { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },\n () => source[method](value),\n )\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nexport function clearAutoTraceNodeConfiguration<T>(fn: () => T): T {\n return runWithAutoTraceScope({ entries: currentAutoTraceEntries() }, fn)\n}\n\nexport function runWithAutoTraceNodeConfiguration<T>(\n nodeConfiguration: AutoTraceNodeConfiguration,\n fn: () => T,\n): T {\n const scope = currentAutoTraceScope()\n if (!scope || scope.entries.length === 0) {\n return fn()\n }\n\n const result = runWithAutoTraceScope({ ...scope, nodeConfiguration }, fn)\n if (isAutoTraceAsyncGenerator(result)) {\n return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result) as T\n }\n return result\n}\n\nexport function runAsAutoTraceRootFunction<T>(\n functionName: string,\n fn: () => T,\n): T {\n const scope = currentAutoTraceScope()\n if (!scope || scope.entries.length === 0 || functionName === \"\") {\n return fn()\n }\n const rootFunction: AutoTraceRootFunction = {\n name: functionName,\n entering: true,\n }\n try {\n return runWithAutoTraceScope({ ...scope, rootFunction }, fn)\n } finally {\n rootFunction.entering = false\n }\n}\n\nfunction isRootFunctionEntry(\n scope: AutoTraceScope,\n simpleName: string | undefined,\n): boolean {\n const rootFunction = scope.rootFunction\n if (rootFunction === undefined || !rootFunction.entering) {\n return false\n }\n rootFunction.entering = false\n return rootFunction.name === simpleName\n}\n\nconst SUBTREE_TRACING_DOCS_URL =\n \"https://docs.bitfab.ai/typescript-sdk#experimental-subtree-tracing\"\n\nfunction noteTransformedModule(): void {\n autoTraceGlobal.__bitfab_auto_trace_transformed_v1__ = true\n}\n\nfunction transformInstalled(): boolean {\n return autoTraceGlobal.__bitfab_auto_trace_transformed_v1__ === true\n}\n\nfunction runsOnNode(): boolean {\n return typeof process !== \"undefined\" && Boolean(process.versions?.node)\n}\n\nfunction closeAutoTraceRoot(): void {\n autoTraceState.activeRoots -= 1\n}\n\nfunction settleAutoTraceRoot(context: AutoTraceContext): void {\n closeAutoTraceRoot()\n if (transformInstalled() || !runsOnNode()) {\n return\n }\n warnOnce(\n \"auto-trace-transform-missing\",\n `trace root \"${context.traceFunctionKey}\" recorded only its own span. ` +\n \"No module in this build was compiled by @bitfab/sdk/transform, so calls \" +\n \"beneath the root were not discovered. Add the SDK's transform adapter \" +\n `to the server build: ${SUBTREE_TRACING_DOCS_URL}`,\n )\n}\n\nexport function runWithAutoTraceRootContext<T>(\n context: AutoTraceContext,\n spanStack: unknown,\n fn: () => T,\n): T {\n autoTraceState.activeRoots += 1\n const entries = [\n ...currentAutoTraceEntries(),\n { context, depth: 0, spanStack },\n ]\n let result: T\n try {\n result = runWithAutoTraceScope({ entries }, fn)\n } catch (error) {\n settleAutoTraceRoot(context)\n throw error\n }\n\n if (isAutoTraceAsyncGenerator(result)) {\n closeAutoTraceRoot()\n return wrapAutoTraceAsyncGenerator(context, spanStack, result) as T\n }\n\n if (result instanceof Promise) {\n return result.finally(() => {\n settleAutoTraceRoot(context)\n }) as T\n }\n\n settleAutoTraceRoot(context)\n return result\n}\n\nexport function invokeThroughAutoTraceEntries<T>(\n entries: readonly AutoTraceEntry[],\n step: (entry: AutoTraceEntry, next: () => T) => T,\n fn: () => T,\n): T {\n let run = fn\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index] as AutoTraceEntry\n const next = run\n run = () => step(entry, next)\n }\n return run()\n}\n\nfunction isAutoTraceAsyncGenerator(\n value: unknown,\n): value is AutoTraceAsyncGenerator {\n if (value === null || typeof value !== \"object\") {\n return false\n }\n const candidate = value as Record<PropertyKey, unknown>\n return (\n typeof candidate.next === \"function\" &&\n typeof candidate.return === \"function\" &&\n typeof candidate.throw === \"function\" &&\n typeof candidate[Symbol.asyncIterator] === \"function\"\n )\n}\n\nfunction wrapAutoTraceAsyncGenerator(\n context: AutoTraceContext,\n spanStack: unknown,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceRootContext(context, spanStack, () => source[method](value))\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nfunction wrapAutoTraceNodeAsyncGenerator(\n nodeConfiguration: AutoTraceNodeConfiguration,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceNodeConfiguration(nodeConfiguration, () =>\n source[method](value),\n )\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nfunction shareFinalize(\n configuration: AutoTraceNodeConfiguration,\n): AutoTraceNodeConfiguration {\n const finalize = configuration.finalize\n if (finalize === undefined) {\n return configuration\n }\n let settled: Promise<unknown> | undefined\n return {\n ...configuration,\n finalize: (result: unknown) => {\n settled ??= Promise.resolve().then(() => finalize(result))\n return settled\n },\n }\n}\n\nexport function __bitfabAutoSpan<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n): T {\n noteTransformedModule()\n const scope = currentAutoTraceScope()\n if (!scope || scope.entries.length === 0 || isCaptureSuppressed()) {\n return fn()\n }\n const nameParts = definition.name.split(\".\")\n const simpleName = nameParts[nameParts.length - 1]\n if (isRootFunctionEntry(scope, simpleName)) {\n return fn()\n }\n const nodeConfiguration =\n simpleName === scope.nodeConfiguration?.functionName\n ? shareFinalize(scope.nodeConfiguration)\n : undefined\n return invokeThroughAutoTraceEntries(\n scope.entries,\n (entry, next) =>\n entry.context.invoke(definition, inputs, next, entry, nodeConfiguration),\n fn,\n )\n}\n\n/**\n * Preserve a function's original call arguments for transform cases where\n * parameter bindings discard them, such as destructured arrow parameters.\n *\n * This helper is internal transform/runtime protocol. The proxy preserves the\n * target's callability, arity, async identity, and non-constructibility while\n * only allocating a trace closure beneath an active automatic trace root.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoWrap<T extends (...args: never[]) => unknown>(\n definition: AutoTraceFunctionDefinition,\n fn: T,\n): T {\n noteTransformedModule()\n if (fn.name === \"\") {\n const nameParts = definition.name.split(\".\")\n const inferredName = nameParts[nameParts.length - 1]\n if (inferredName !== undefined) {\n Object.defineProperty(fn, \"name\", {\n configurable: true,\n value: inferredName,\n })\n }\n }\n\n const target = fn as unknown as (...args: unknown[]) => unknown\n return new Proxy(target, {\n apply(callTarget, thisArg, args) {\n if (!__bitfabAutoTraceActive()) {\n return Reflect.apply(callTarget, thisArg, args)\n }\n return __bitfabAutoSpan(definition, args, () =>\n Reflect.apply(callTarget, thisArg, args),\n )\n },\n }) as unknown as T\n}\n\n/**\n * Return whether the current call is inside an automatic trace root.\n *\n * Build transforms use this before allocating function metadata, captured\n * inputs, or an invocation closure. It is internal transform/runtime protocol,\n * not a supported application API.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoTraceActive(): boolean {\n if (autoTraceState.activeRoots === 0 || isCaptureSuppressed()) {\n return false\n }\n return currentAutoTraceEntries().length > 0\n}\n\nfunction currentAutoTraceScope(): AutoTraceScope | undefined {\n initializeAutoTraceStorage()\n return autoTraceState.storage?.getStore() ?? autoTraceState.browserScope\n}\n\nexport function _resetAutoTraceTransformDetection(): void {\n autoTraceGlobal.__bitfab_auto_trace_transformed_v1__ = undefined\n}\n","/**\n * Shared AsyncLocalStorage loader.\n *\n * Provides two ways to initialize AsyncLocalStorage:\n *\n * 1. **Synchronous registration** (preferred for Node.js):\n * `asyncStorageNode.ts` calls `registerAsyncLocalStorageClass()` at module\n * evaluation time, so the class is available immediately - no async gap.\n * The `node.ts` entry point imports it before anything else.\n *\n * 2. **Async dynamic import** (fallback for the default entry point):\n * Loads `node:async_hooks` via a bundler-safe dynamic import. This is used\n * by the default `index.ts` entry point so the SDK works in browsers\n * (where the import silently fails) and in Node.js when imported via the\n * default entry point.\n *\n * ## Why the dynamic import looks like this\n *\n * We need to handle three environments:\n *\n * 1. **Pure Node.js** - `import(\"node:async_hooks\")` works natively.\n * 2. **Webpack/Turbopack (Next.js server)** - The bundler processes\n * `import()` calls at build time. The `webpackIgnore` magic comment tells\n * webpack (and turbopack) to emit a native `import()` call instead of\n * trying to resolve it, so Node.js handles it at runtime.\n * 3. **Browsers / Edge** - The `process.versions?.node` guard prevents\n * execution entirely. If it somehow runs, `.catch(() => {})` swallows\n * the failure.\n */\n\nexport interface AsyncLocalStorageLike<T> {\n getStore(): T | undefined\n run<R>(store: T, fn: () => R): R\n}\n\nlet AsyncLocalStorageClass: (new () => AsyncLocalStorageLike<unknown>) | null =\n null\nlet initDone = false\n\n/**\n * Register the AsyncLocalStorage class synchronously.\n *\n * Called by `asyncStorageNode.ts` at module evaluation time so the class\n * is available before any span is created - no async gap, no race condition.\n *\n * Safe to call multiple times; subsequent calls are no-ops.\n */\nexport function registerAsyncLocalStorageClass(\n cls: new () => AsyncLocalStorageLike<unknown>,\n): void {\n if (!AsyncLocalStorageClass) {\n AsyncLocalStorageClass = cls\n }\n initDone = true\n}\n\n/**\n * Assert that AsyncLocalStorage was registered successfully.\n *\n * Called by `node.ts` after importing `asyncStorageNode.ts` to catch\n * import-order bugs at startup rather than silently degrading to the\n * browser fallback (flat spans with no nesting).\n *\n * This should ONLY be called from the Node.js entry point where we\n * know `node:async_hooks` must be available.\n */\nexport function assertAsyncStorageRegistered(): void {\n if (!AsyncLocalStorageClass) {\n console.warn(\n \"Bitfab: AsyncLocalStorage not available - nested span context will not propagate.\",\n )\n }\n}\n\nexport const asyncStorageReady: Promise<void> = (\n typeof process !== \"undefined\" && process.versions?.node\n ? // The join trick hides \"node:async_hooks\" from static analysis so\n // bundlers that ban Node.js built-ins don't fail at build time.\n // webpackIgnore tells webpack/turbopack to emit a native import()\n // so Node.js can resolve the module at runtime.\n import(\n /* webpackIgnore: true */\n [\"node\", \"async_hooks\"].join(\":\")\n )\n .then(\n (mod: {\n AsyncLocalStorage: new () => AsyncLocalStorageLike<unknown>\n }) => {\n registerAsyncLocalStorageClass(mod.AsyncLocalStorage)\n },\n )\n .catch(() => {})\n : Promise.resolve()\n).then(() => {\n initDone = true\n})\n\nexport function isAsyncStorageInitDone(): boolean {\n return initDone\n}\n\nexport function createAsyncLocalStorage<T>(): AsyncLocalStorageLike<T> | null {\n return AsyncLocalStorageClass\n ? (new AsyncLocalStorageClass() as AsyncLocalStorageLike<T>)\n : null\n}\n","interface CaptureSuppressionState {\n depth: number\n}\n\ninterface CaptureSuppressionGlobal {\n __bitfabCaptureSuppressionV1?: CaptureSuppressionState\n}\n\nconst suppressionGlobal = globalThis as unknown as CaptureSuppressionGlobal\nconst suppressionState: CaptureSuppressionState =\n suppressionGlobal.__bitfabCaptureSuppressionV1 ?? { depth: 0 }\nsuppressionGlobal.__bitfabCaptureSuppressionV1 = suppressionState\n\nexport function isCaptureSuppressed(): boolean {\n return suppressionState.depth > 0\n}\n\nexport function runWithCaptureSuppressed<T>(fn: () => T): T {\n suppressionState.depth += 1\n try {\n return fn()\n } finally {\n suppressionState.depth -= 1\n }\n}\n","/**\n * Emit a `console.warn` at most once per distinct `key` for the life of the\n * process.\n *\n * The SDK must NEVER crash a host app, so every failure on the user's path\n * degrades silently (a span is dropped, a call runs untraced, a payload is\n * stubbed). Silent is safe but undebuggable: a user who suddenly has no traces,\n * or sees `<unserializable>` in a span, has no signal as to why. A one-time\n * warning per distinct issue restores that signal without spamming the console\n * from a hot path.\n *\n * Keys should identify the specific degradation (e.g. include the traced\n * function key) so each distinct issue warns once, not just the first one seen.\n */\nconst warned = new Set<string>()\n\nexport function warn(message: string): void {\n try {\n console.warn(`[bitfab] ${message}`)\n } catch {\n // Logging must never crash the host app (e.g. a closed/replaced console).\n }\n}\n\nexport function warnOnce(key: string, message: string): void {\n if (warned.has(key)) {\n return\n }\n warned.add(key)\n warn(message)\n}\n\nexport function writeOnce(\n key: string,\n line: string,\n write: (line: string) => void = console.warn,\n): void {\n if (warned.has(key)) {\n return\n }\n warned.add(key)\n try {\n write(line)\n } catch {}\n}\n\n/** Test-only: clear the dedup set so a warning can fire again. */\nexport function _resetWarnOnce(): void {\n warned.clear()\n}\n"],"mappings":"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","names":[]}
|
package/dist/autoTrace.d.cts
CHANGED
|
@@ -38,6 +38,7 @@ declare function currentAutoTraceEntries(): readonly AutoTraceEntry[];
|
|
|
38
38
|
declare function runWithAutoTraceEntry<T>(previous: AutoTraceEntry, updated: AutoTraceEntry, fn: () => T): T;
|
|
39
39
|
declare function clearAutoTraceNodeConfiguration<T>(fn: () => T): T;
|
|
40
40
|
declare function runWithAutoTraceNodeConfiguration<T>(nodeConfiguration: AutoTraceNodeConfiguration, fn: () => T): T;
|
|
41
|
+
declare function runAsAutoTraceRootFunction<T>(functionName: string, fn: () => T): T;
|
|
41
42
|
declare function runWithAutoTraceRootContext<T>(context: AutoTraceContext, spanStack: unknown, fn: () => T): T;
|
|
42
43
|
declare function invokeThroughAutoTraceEntries<T>(entries: readonly AutoTraceEntry[], step: (entry: AutoTraceEntry, next: () => T) => T, fn: () => T): T;
|
|
43
44
|
declare function __bitfabAutoSpan<T>(definition: AutoTraceFunctionDefinition, inputs: unknown[], fn: () => T): T;
|
|
@@ -64,4 +65,4 @@ declare function __bitfabAutoWrap<T extends (...args: never[]) => unknown>(defin
|
|
|
64
65
|
declare function __bitfabAutoTraceActive(): boolean;
|
|
65
66
|
declare function _resetAutoTraceTransformDetection(): void;
|
|
66
67
|
|
|
67
|
-
export { type AutoTraceContext, type AutoTraceEntry, type AutoTraceFunctionDefinition, type AutoTraceNodeConfiguration, type NestedTraceLink, __bitfabAutoSpan, __bitfabAutoTraceActive, __bitfabAutoWrap, _resetAutoTraceTransformDetection, clearAutoTraceNodeConfiguration, currentAutoTraceEntries, invokeThroughAutoTraceEntries, runWithAutoTraceEntry, runWithAutoTraceNodeConfiguration, runWithAutoTraceRootContext };
|
|
68
|
+
export { type AutoTraceContext, type AutoTraceEntry, type AutoTraceFunctionDefinition, type AutoTraceNodeConfiguration, type NestedTraceLink, __bitfabAutoSpan, __bitfabAutoTraceActive, __bitfabAutoWrap, _resetAutoTraceTransformDetection, clearAutoTraceNodeConfiguration, currentAutoTraceEntries, invokeThroughAutoTraceEntries, runAsAutoTraceRootFunction, runWithAutoTraceEntry, runWithAutoTraceNodeConfiguration, runWithAutoTraceRootContext };
|
package/dist/autoTrace.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ declare function currentAutoTraceEntries(): readonly AutoTraceEntry[];
|
|
|
38
38
|
declare function runWithAutoTraceEntry<T>(previous: AutoTraceEntry, updated: AutoTraceEntry, fn: () => T): T;
|
|
39
39
|
declare function clearAutoTraceNodeConfiguration<T>(fn: () => T): T;
|
|
40
40
|
declare function runWithAutoTraceNodeConfiguration<T>(nodeConfiguration: AutoTraceNodeConfiguration, fn: () => T): T;
|
|
41
|
+
declare function runAsAutoTraceRootFunction<T>(functionName: string, fn: () => T): T;
|
|
41
42
|
declare function runWithAutoTraceRootContext<T>(context: AutoTraceContext, spanStack: unknown, fn: () => T): T;
|
|
42
43
|
declare function invokeThroughAutoTraceEntries<T>(entries: readonly AutoTraceEntry[], step: (entry: AutoTraceEntry, next: () => T) => T, fn: () => T): T;
|
|
43
44
|
declare function __bitfabAutoSpan<T>(definition: AutoTraceFunctionDefinition, inputs: unknown[], fn: () => T): T;
|
|
@@ -64,4 +65,4 @@ declare function __bitfabAutoWrap<T extends (...args: never[]) => unknown>(defin
|
|
|
64
65
|
declare function __bitfabAutoTraceActive(): boolean;
|
|
65
66
|
declare function _resetAutoTraceTransformDetection(): void;
|
|
66
67
|
|
|
67
|
-
export { type AutoTraceContext, type AutoTraceEntry, type AutoTraceFunctionDefinition, type AutoTraceNodeConfiguration, type NestedTraceLink, __bitfabAutoSpan, __bitfabAutoTraceActive, __bitfabAutoWrap, _resetAutoTraceTransformDetection, clearAutoTraceNodeConfiguration, currentAutoTraceEntries, invokeThroughAutoTraceEntries, runWithAutoTraceEntry, runWithAutoTraceNodeConfiguration, runWithAutoTraceRootContext };
|
|
68
|
+
export { type AutoTraceContext, type AutoTraceEntry, type AutoTraceFunctionDefinition, type AutoTraceNodeConfiguration, type NestedTraceLink, __bitfabAutoSpan, __bitfabAutoTraceActive, __bitfabAutoWrap, _resetAutoTraceTransformDetection, clearAutoTraceNodeConfiguration, currentAutoTraceEntries, invokeThroughAutoTraceEntries, runAsAutoTraceRootFunction, runWithAutoTraceEntry, runWithAutoTraceNodeConfiguration, runWithAutoTraceRootContext };
|
package/dist/autoTrace.js
CHANGED
|
@@ -6,10 +6,11 @@ import {
|
|
|
6
6
|
clearAutoTraceNodeConfiguration,
|
|
7
7
|
currentAutoTraceEntries,
|
|
8
8
|
invokeThroughAutoTraceEntries,
|
|
9
|
+
runAsAutoTraceRootFunction,
|
|
9
10
|
runWithAutoTraceEntry,
|
|
10
11
|
runWithAutoTraceNodeConfiguration,
|
|
11
12
|
runWithAutoTraceRootContext
|
|
12
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QRNHRY7F.js";
|
|
13
14
|
import "./chunk-MT36GJMW.js";
|
|
14
15
|
export {
|
|
15
16
|
__bitfabAutoSpan,
|
|
@@ -19,6 +20,7 @@ export {
|
|
|
19
20
|
clearAutoTraceNodeConfiguration,
|
|
20
21
|
currentAutoTraceEntries,
|
|
21
22
|
invokeThroughAutoTraceEntries,
|
|
23
|
+
runAsAutoTraceRootFunction,
|
|
22
24
|
runWithAutoTraceEntry,
|
|
23
25
|
runWithAutoTraceNodeConfiguration,
|
|
24
26
|
runWithAutoTraceRootContext
|
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
serializeReplayResult,
|
|
7
7
|
warnJudgeAssertionsDeprecated,
|
|
8
8
|
withCliFlags
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-Z26K57WZ.js";
|
|
10
10
|
import {
|
|
11
11
|
BitfabError,
|
|
12
12
|
asyncStorageReady,
|
|
13
13
|
createAsyncLocalStorage,
|
|
14
14
|
warnOnce
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-CLP2L5PU.js";
|
|
16
16
|
|
|
17
17
|
// src/autoTrace.ts
|
|
18
18
|
var autoTraceGlobal = globalThis;
|
|
@@ -458,7 +458,7 @@ async function seedFromRegistry(registry, pipeline, cases, options = {}) {
|
|
|
458
458
|
sessionId: seedCase.sessionId
|
|
459
459
|
})
|
|
460
460
|
);
|
|
461
|
-
const { flushTraces } = await import("./http-
|
|
461
|
+
const { flushTraces } = await import("./http-WP4YPPKC.js");
|
|
462
462
|
await flushTraces(3e4);
|
|
463
463
|
return { pipeline, traceFunctionKey, traceIds };
|
|
464
464
|
}
|
|
@@ -1173,4 +1173,4 @@ export {
|
|
|
1173
1173
|
runRegistryMain,
|
|
1174
1174
|
runIfEntrypoint
|
|
1175
1175
|
};
|
|
1176
|
-
//# sourceMappingURL=chunk-
|
|
1176
|
+
//# sourceMappingURL=chunk-BRMGNMDO.js.map
|