brass-runtime 1.16.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +287 -23
  3. package/dist/agent/cli/main.cjs +38 -38
  4. package/dist/agent/cli/main.js +6 -6
  5. package/dist/agent/cli/main.mjs +6 -6
  6. package/dist/agent/index.cjs +7 -7
  7. package/dist/agent/index.d.ts +1 -1
  8. package/dist/agent/index.js +6 -6
  9. package/dist/agent/index.mjs +6 -6
  10. package/dist/chunk-2HQTDLHF.mjs +683 -0
  11. package/dist/chunk-36I3M4UC.mjs +370 -0
  12. package/dist/{chunk-QY5FKYEQ.js → chunk-3AYM6WPJ.js} +570 -51
  13. package/dist/chunk-3LOYJFRR.cjs +300 -0
  14. package/dist/chunk-3Y2RIUMM.js +300 -0
  15. package/dist/{chunk-7XOPAB5Q.js → chunk-4P2HHGAX.mjs} +83 -5
  16. package/dist/{chunk-N6VHMOWB.cjs → chunk-4ROBZFL6.cjs} +128 -128
  17. package/dist/{chunk-NC5SDRYE.js → chunk-52OB2ROS.js} +4 -4
  18. package/dist/{chunk-JX3LZQJH.cjs → chunk-52PPNNI4.cjs} +82 -20
  19. package/dist/{chunk-5YOQOXEQ.cjs → chunk-5EC274J5.cjs} +676 -293
  20. package/dist/chunk-5QC7LRZ3.js +229 -0
  21. package/dist/{chunk-7TL2LHQJ.js → chunk-5VRJNBLZ.mjs} +524 -141
  22. package/dist/chunk-62AZW6UT.cjs +313 -0
  23. package/dist/chunk-6IXXWIUM.js +683 -0
  24. package/dist/chunk-6RY2FFN4.mjs +2024 -0
  25. package/dist/chunk-74ZTY6CP.js +2871 -0
  26. package/dist/chunk-7CMJS3QE.mjs +2871 -0
  27. package/dist/{chunk-2WC63LJK.mjs → chunk-7JIJOVCT.js} +20 -10
  28. package/dist/chunk-7X3K5RMS.js +2024 -0
  29. package/dist/chunk-7ZPEZ57L.cjs +2024 -0
  30. package/dist/{chunk-FM4W4QPL.js → chunk-A2OM6NEH.mjs} +5 -4
  31. package/dist/chunk-AGR5B2BC.cjs +683 -0
  32. package/dist/chunk-B33ICAKP.js +313 -0
  33. package/dist/{chunk-J3H54ZRV.mjs → chunk-B5JD23U7.mjs} +1 -1
  34. package/dist/{chunk-F5EUMJL7.mjs → chunk-BKK77SBA.js} +83 -5
  35. package/dist/{chunk-U5KWK3PX.mjs → chunk-C3MDXTRZ.js} +11 -0
  36. package/dist/{chunk-SPUEME2B.cjs → chunk-CZIVE6NT.cjs} +12 -1
  37. package/dist/{chunk-TDVMADDN.js → chunk-DNFJLJMW.mjs} +11 -0
  38. package/dist/{chunk-XDZOO4L5.js → chunk-EJ6BPYVR.mjs} +79 -17
  39. package/dist/chunk-EOC4UHBS.mjs +229 -0
  40. package/dist/chunk-F6XWZQY4.cjs +777 -0
  41. package/dist/{chunk-7LVI2GIN.js → chunk-FH2X7BVP.js} +507 -72
  42. package/dist/{chunk-OOGJ73B6.js → chunk-FHQGHPMO.mjs} +20 -10
  43. package/dist/{chunk-WQ5QNU5R.cjs → chunk-GLE2WY7Z.cjs} +652 -217
  44. package/dist/{chunk-G6IQOE4P.mjs → chunk-GYM3LLGS.mjs} +507 -72
  45. package/dist/{chunk-TVN5I4U6.cjs → chunk-JF5WGYJJ.cjs} +25 -24
  46. package/dist/{chunk-CY33PGEX.mjs → chunk-KH4SYAOS.mjs} +570 -51
  47. package/dist/chunk-KN32XNTH.mjs +313 -0
  48. package/dist/chunk-KQLYONSE.cjs +2871 -0
  49. package/dist/{chunk-7HUOJA4W.cjs → chunk-KZJQ723N.cjs} +90 -80
  50. package/dist/{chunk-CCKHV5BT.mjs → chunk-L2SYFEBS.js} +5 -4
  51. package/dist/{chunk-IJT6RRQ5.cjs → chunk-L6VB5N7Q.cjs} +20 -9
  52. package/dist/{chunk-ZGLD4TVZ.mjs → chunk-MBEJI5HF.mjs} +4 -4
  53. package/dist/{chunk-PRWCB3QL.mjs → chunk-MIIYDLGM.js} +524 -141
  54. package/dist/{chunk-H55LI6WY.js → chunk-MOO4L7F4.mjs} +15 -4
  55. package/dist/chunk-MVGUEJ5Z.cjs +370 -0
  56. package/dist/chunk-PD4EJTQC.cjs +229 -0
  57. package/dist/chunk-PWC3RBQE.mjs +300 -0
  58. package/dist/{chunk-MWXMNYJS.cjs → chunk-Q2I37RP3.cjs} +643 -124
  59. package/dist/{chunk-VFIUZG7J.mjs → chunk-RKGKFN2A.js} +79 -17
  60. package/dist/{chunk-NYL4D7SK.cjs → chunk-SA6HUJVI.cjs} +5 -5
  61. package/dist/chunk-SK7UZRNI.mjs +777 -0
  62. package/dist/{chunk-K2T3DV26.mjs → chunk-TRM4JUZQ.js} +15 -4
  63. package/dist/chunk-UB4B6OFY.js +370 -0
  64. package/dist/{chunk-G3XGCZDQ.js → chunk-UCUBNWM2.js} +1 -1
  65. package/dist/chunk-VWIPB6I5.js +777 -0
  66. package/dist/{chunk-JNFRRJYH.cjs → chunk-WBGRHGBP.cjs} +270 -192
  67. package/dist/{client-CtFmoDvM.d.ts → client-CZHU674n.d.ts} +211 -36
  68. package/dist/core/index.cjs +135 -9
  69. package/dist/core/index.d.ts +238 -33
  70. package/dist/core/index.js +155 -29
  71. package/dist/core/index.mjs +155 -29
  72. package/dist/{effect-CGNl5Rqp.d.ts → effect-DIUHZ9IN.d.ts} +89 -1
  73. package/dist/effectRunner-CFLC32IK.cjs +8 -0
  74. package/dist/{effectRunner-A4CHJXJI.js → effectRunner-L4S7IPT3.js} +2 -2
  75. package/dist/{effectRunner-OPUF6QRN.mjs → effectRunner-NNGG75QA.mjs} +2 -2
  76. package/dist/http/index.cjs +324 -2986
  77. package/dist/http/index.d.ts +54 -68
  78. package/dist/http/index.js +238 -2900
  79. package/dist/http/index.mjs +238 -2900
  80. package/dist/http/testing.cjs +14 -12
  81. package/dist/http/testing.d.ts +5 -4
  82. package/dist/http/testing.js +10 -8
  83. package/dist/http/testing.mjs +10 -8
  84. package/dist/index.cjs +423 -255
  85. package/dist/index.d.ts +87 -69
  86. package/dist/index.js +301 -133
  87. package/dist/index.mjs +301 -133
  88. package/dist/observability/index.cjs +18 -531
  89. package/dist/observability/index.d.ts +81 -8
  90. package/dist/observability/index.js +25 -538
  91. package/dist/observability/index.mjs +25 -538
  92. package/dist/perf/cli.cjs +401 -0
  93. package/dist/perf/cli.d.ts +1 -0
  94. package/dist/perf/cli.js +401 -0
  95. package/dist/perf/cli.mjs +401 -0
  96. package/dist/perf/index.cjs +141 -0
  97. package/dist/perf/index.d.ts +483 -0
  98. package/dist/perf/index.js +141 -0
  99. package/dist/perf/index.mjs +141 -0
  100. package/dist/schedule-CK3Ml_7p.d.ts +259 -0
  101. package/dist/schema/index.cjs +6 -2
  102. package/dist/schema/index.d.ts +3 -1
  103. package/dist/schema/index.js +5 -1
  104. package/dist/schema/index.mjs +5 -1
  105. package/dist/{server-C8hDXA74.d.ts → server-D6JZ15_e.d.ts} +16 -4
  106. package/dist/{stream-dvSs0QS5.d.ts → stream-B4oK9JFP.d.ts} +1 -1
  107. package/dist/{tracer-B5tRH9H7.d.ts → tracer-Hwt1cl7h.d.ts} +13 -54
  108. package/dist/{tracing-Dt9S_6V8.d.ts → tracing-DqbTKGcf.d.ts} +1 -1
  109. package/docs/ARCHITECTURE.md +292 -0
  110. package/docs/README.md +65 -0
  111. package/docs/adr/0001-ai-context-pack.md +32 -0
  112. package/docs/agent-apply-mode.md +104 -0
  113. package/docs/agent-approvals.md +110 -0
  114. package/docs/agent-batch.md +185 -0
  115. package/docs/agent-boundaries.md +112 -0
  116. package/docs/agent-chat-sessions.md +160 -0
  117. package/docs/agent-ci.md +17 -0
  118. package/docs/agent-cli.md +405 -0
  119. package/docs/agent-config.md +480 -0
  120. package/docs/agent-context-discovery.md +159 -0
  121. package/docs/agent-copilot-like-dx.md +126 -0
  122. package/docs/agent-declarative-optimized-planning.md +138 -0
  123. package/docs/agent-dx.md +224 -0
  124. package/docs/agent-env-files.md +126 -0
  125. package/docs/agent-follow-up-context.md +43 -0
  126. package/docs/agent-global-usage.md +180 -0
  127. package/docs/agent-init.md +109 -0
  128. package/docs/agent-install-and-configure.md +516 -0
  129. package/docs/agent-language-workspace-ux.md +99 -0
  130. package/docs/agent-llm-adapters.md +123 -0
  131. package/docs/agent-local-install.md +190 -0
  132. package/docs/agent-local-tests.md +51 -0
  133. package/docs/agent-observability.md +155 -0
  134. package/docs/agent-patch-quality-loop.md +162 -0
  135. package/docs/agent-presets.md +22 -0
  136. package/docs/agent-project-commands.md +237 -0
  137. package/docs/agent-project-intelligence.md +156 -0
  138. package/docs/agent-redaction.md +18 -0
  139. package/docs/agent-release-readiness.md +76 -0
  140. package/docs/agent-rollback-safety.md +162 -0
  141. package/docs/agent-rollback.md +23 -0
  142. package/docs/agent-run-artifacts.md +16 -0
  143. package/docs/agent-vscode-auto-discovery.md +137 -0
  144. package/docs/agent-vscode-batch-runner.md +100 -0
  145. package/docs/agent-vscode-chat-layout.md +90 -0
  146. package/docs/agent-vscode-clean-install.md +147 -0
  147. package/docs/agent-vscode-code-actions.md +70 -0
  148. package/docs/agent-vscode-diff-preview.md +45 -0
  149. package/docs/agent-vscode-inline-assist.md +56 -0
  150. package/docs/agent-vscode-install.md +186 -0
  151. package/docs/agent-vscode-model-setup.md +97 -0
  152. package/docs/agent-vscode-patch-preview.md +92 -0
  153. package/docs/agent-vscode-problems.md +79 -0
  154. package/docs/agent-vscode-project-dashboard.md +106 -0
  155. package/docs/agent-vscode-run-history.md +92 -0
  156. package/docs/agent-vscode-ux.md +73 -0
  157. package/docs/ai/INVARIANTS.md +84 -0
  158. package/docs/ai/PROJECT_MAP.md +338 -0
  159. package/docs/ai/PUBLIC_API.md +339 -0
  160. package/docs/ai/VALIDATION_MATRIX.md +67 -0
  161. package/docs/api-polish.md +37 -0
  162. package/docs/cancellation.md +162 -0
  163. package/docs/coverage.md +46 -0
  164. package/docs/framework-integrations.md +38 -0
  165. package/docs/frameworks/angular.md +153 -0
  166. package/docs/frameworks/express.md +125 -0
  167. package/docs/frameworks/fastify.md +124 -0
  168. package/docs/frameworks/nestjs.md +282 -0
  169. package/docs/frameworks/nextjs.md +147 -0
  170. package/docs/frameworks/react.md +139 -0
  171. package/docs/frameworks/vanilla.md +224 -0
  172. package/docs/getting-started.md +159 -0
  173. package/docs/guides/README.md +40 -0
  174. package/docs/guides/circuit-breaker.md +89 -0
  175. package/docs/guides/error-handling.md +91 -0
  176. package/docs/guides/getting-started.md +107 -0
  177. package/docs/guides/layers.md +189 -0
  178. package/docs/guides/metrics.md +101 -0
  179. package/docs/guides/resource-management.md +141 -0
  180. package/docs/guides/retry.md +215 -0
  181. package/docs/guides/semaphore.md +66 -0
  182. package/docs/guides/streams.md +117 -0
  183. package/docs/guides/supervisors.md +98 -0
  184. package/docs/guides/testing.md +162 -0
  185. package/docs/guides/tracing.md +71 -0
  186. package/docs/http-recipes.md +399 -0
  187. package/docs/http.md +749 -0
  188. package/docs/modules.md +285 -0
  189. package/docs/nestjs.md +6 -0
  190. package/docs/observability-collector-smoke.md +31 -0
  191. package/docs/observability-framework-examples.md +110 -0
  192. package/docs/observability.md +649 -0
  193. package/docs/otel-collector-smoke.yaml +27 -0
  194. package/docs/performance-profiler.md +199 -0
  195. package/docs/production-readiness.md +73 -0
  196. package/docs/recipes/README.md +12 -0
  197. package/docs/recipes/http-server.md +45 -0
  198. package/docs/recipes/layers.md +44 -0
  199. package/docs/recipes/performance.md +47 -0
  200. package/docs/recipes/runtime.md +41 -0
  201. package/docs/recipes/testing.md +41 -0
  202. package/docs/release.md +53 -0
  203. package/docs/wasm-bounded-queues.md +44 -0
  204. package/docs/wasm-engine-observability-benchmarks.md +85 -0
  205. package/docs/wasm-fiber-engine.md +117 -0
  206. package/docs/wasm-scheduler-state-machine.md +122 -0
  207. package/docs/wasm-stream-chunks.md +54 -0
  208. package/package.json +22 -2
  209. package/dist/chunk-45F7OKGT.cjs +0 -104
  210. package/dist/chunk-7V4KY4RL.mjs +0 -104
  211. package/dist/chunk-DJQ7OMMB.cjs +0 -144
  212. package/dist/chunk-GOV47PPB.mjs +0 -552
  213. package/dist/chunk-JF4XXPZ5.cjs +0 -552
  214. package/dist/chunk-KCPT2D6G.js +0 -552
  215. package/dist/chunk-NOYZIMUJ.mjs +0 -144
  216. package/dist/chunk-PNVFW245.js +0 -144
  217. package/dist/chunk-ROJC3NBJ.js +0 -104
  218. package/dist/effectRunner-3ZHAD3LE.cjs +0 -8
  219. package/dist/schedule-Fque9Abz.d.ts +0 -70
@@ -3,11 +3,11 @@ import {
3
3
  Cause,
4
4
  Exit,
5
5
  asyncEffect
6
- } from "./chunk-PNVFW245.js";
6
+ } from "./chunk-UB4B6OFY.js";
7
7
  import {
8
8
  Schema,
9
9
  parseConfig
10
- } from "./chunk-TDVMADDN.js";
10
+ } from "./chunk-C3MDXTRZ.js";
11
11
 
12
12
  // src/core/runtime/ringBuffer.ts
13
13
  var PushStatus = /* @__PURE__ */ ((PushStatus3) => {
@@ -1029,7 +1029,8 @@ function makeForkPolicy(env, hooks) {
1029
1029
  const trace = forkTrace(svc, parentCtx?.trace ?? null);
1030
1030
  fiber.fiberContext = {
1031
1031
  log: parentCtx?.log ?? emptyContext,
1032
- trace
1032
+ trace,
1033
+ fiberRefs: parentCtx?.fiberRefs ? new Map(parentCtx.fiberRefs) : void 0
1033
1034
  };
1034
1035
  fiber.parentFiberId = parent?.id;
1035
1036
  fiber.name = svc.childName(parent?.name);
@@ -1249,6 +1250,13 @@ var ProgramBuilder = class {
1249
1250
  };
1250
1251
  return this.add(current.scopeId === void 0 ? base : { ...base, scopeId: current.scopeId });
1251
1252
  }
1253
+ case "Interruptibility":
1254
+ case "InterruptibilityRestore":
1255
+ return this.visit(current.effect);
1256
+ case "FiberRefLocally":
1257
+ return this.visit(desugarFiberRefLocally(current.refId, current.value, current.effect));
1258
+ case "InterruptibilityMask":
1259
+ return this.visit(current.body((effect2) => effect2));
1252
1260
  case "HostAction": {
1253
1261
  const base = {
1254
1262
  tag: "HostAction",
@@ -1261,6 +1269,49 @@ var ProgramBuilder = class {
1261
1269
  }
1262
1270
  }
1263
1271
  };
1272
+ function desugarFiberRefLocally(refId, value, effect) {
1273
+ return {
1274
+ _tag: "FlatMap",
1275
+ first: {
1276
+ _tag: "Sync",
1277
+ thunk: () => enterFiberRefLocal(refId, value)
1278
+ },
1279
+ andThen: (restore) => ({
1280
+ _tag: "Fold",
1281
+ first: effect,
1282
+ onFailure: (error) => restoreThen(restore, { _tag: "Fail", error }),
1283
+ onSuccess: (result) => restoreThen(restore, { _tag: "Succeed", value: result })
1284
+ })
1285
+ };
1286
+ }
1287
+ function restoreThen(restore, next) {
1288
+ return {
1289
+ _tag: "FlatMap",
1290
+ first: {
1291
+ _tag: "Sync",
1292
+ thunk: () => restore()
1293
+ },
1294
+ andThen: () => next
1295
+ };
1296
+ }
1297
+ function enterFiberRefLocal(refId, value) {
1298
+ const fiber = getCurrentFiber();
1299
+ if (!fiber) return () => void 0;
1300
+ fiber.fiberContext ??= { log: emptyContext, trace: null };
1301
+ const refs = fiber.fiberContext.fiberRefs ??= /* @__PURE__ */ new Map();
1302
+ const hadValue = refs.has(refId);
1303
+ const previousValue = refs.get(refId);
1304
+ refs.set(refId, value);
1305
+ let active = true;
1306
+ const restore = () => {
1307
+ if (!active) return;
1308
+ active = false;
1309
+ if (hadValue) refs.set(refId, previousValue);
1310
+ else refs.delete(refId);
1311
+ };
1312
+ fiber.addFinalizer?.(() => restore());
1313
+ return restore;
1314
+ }
1264
1315
 
1265
1316
  // src/core/runtime/engine/FiberHandleImpl.ts
1266
1317
  var EngineFiberHandle = class {
@@ -1295,7 +1346,7 @@ var EngineFiberHandle = class {
1295
1346
  queued = false;
1296
1347
  status() {
1297
1348
  if (this.result == null) return "Running";
1298
- if (this.result._tag === "Failure" && this.result.cause._tag === "Interrupt") return "Interrupted";
1349
+ if (this.result._tag === "Failure" && Cause.isInterruptedOnly(this.result.cause)) return "Interrupted";
1299
1350
  return "Done";
1300
1351
  }
1301
1352
  engineStatus() {
@@ -1368,8 +1419,8 @@ var EngineFiberHandle = class {
1368
1419
  if (this.result != null) return;
1369
1420
  this.runFinalizersOnce(exit);
1370
1421
  this.result = exit;
1371
- this.internalStatus = exit._tag === "Success" ? "done" : exit.cause._tag === "Interrupt" ? "interrupted" : "failed";
1372
- const status = exit._tag === "Success" ? "success" : exit.cause._tag === "Interrupt" ? "interrupted" : "failure";
1422
+ this.internalStatus = exit._tag === "Success" ? "done" : Cause.isInterruptedOnly(exit.cause) ? "interrupted" : "failed";
1423
+ const status = exit._tag === "Success" ? "success" : Cause.isInterruptedOnly(exit.cause) ? "interrupted" : "failure";
1373
1424
  this.emit({
1374
1425
  type: "fiber.end",
1375
1426
  fiberId: this.id,
@@ -1382,16 +1433,18 @@ var EngineFiberHandle = class {
1382
1433
  runFinalizersOnce(exit) {
1383
1434
  if (this.finalizersDrained) return;
1384
1435
  this.finalizersDrained = true;
1385
- while (this.finalizers.length > 0) {
1386
- const finalizer = this.finalizers.pop();
1387
- try {
1388
- const eff = finalizer(exit);
1389
- if (eff && typeof eff === "object" && "_tag" in eff) {
1390
- this.runtime.fork(eff);
1436
+ withCurrentFiber(this, () => {
1437
+ while (this.finalizers.length > 0) {
1438
+ const finalizer = this.finalizers.pop();
1439
+ try {
1440
+ const eff = finalizer(exit);
1441
+ if (eff && typeof eff === "object" && "_tag" in eff) {
1442
+ this.runtime.fork(eff);
1443
+ }
1444
+ } catch {
1391
1445
  }
1392
- } catch {
1393
1446
  }
1394
- }
1447
+ });
1395
1448
  }
1396
1449
  };
1397
1450
 
@@ -2594,15 +2647,32 @@ var WasmFiberEngine = class {
2594
2647
  return;
2595
2648
  }
2596
2649
  const cause = exit.cause;
2597
- if (cause._tag === "Interrupt") {
2650
+ if (Cause.isInterruptedOnly(cause)) {
2598
2651
  this.interruptState(state, cause);
2599
2652
  return;
2600
2653
  }
2601
- if (cause._tag === "Fail") {
2602
- this.resumeWithError(state, cause.error);
2603
- return;
2654
+ if (Cause.isFailureOnly(cause)) {
2655
+ const failure = Cause.firstFailure(cause);
2656
+ if (failure._tag === "Some") {
2657
+ this.resumeWithError(state, failure.value);
2658
+ return;
2659
+ }
2660
+ }
2661
+ this.completeCause(state, cause);
2662
+ }
2663
+ completeCause(state, cause) {
2664
+ if (state.completed) return;
2665
+ state.completed = true;
2666
+ const interrupted = Cause.isInterruptedOnly(cause);
2667
+ state.status = interrupted ? "interrupted" : "failed";
2668
+ this.fiberRegistry?.markDone(state.fiberId, interrupted ? "interrupted" : "failed");
2669
+ if (interrupted) {
2670
+ this.interruptedFibers += 1;
2671
+ } else {
2672
+ this.failedFibers += 1;
2604
2673
  }
2605
- this.completeDie(state, cause.defect);
2674
+ this.cleanupState(state);
2675
+ state.handle.complete(Exit.failCause(cause));
2606
2676
  }
2607
2677
  resumeWithValue(state, value) {
2608
2678
  this.pendingResumes.set(state.fiberId, { kind: "value", ref: state.registry.register(value) });
@@ -2727,6 +2797,21 @@ function hasBinaryVmAbi(mod) {
2727
2797
  }
2728
2798
  }
2729
2799
 
2800
+ // src/core/runtime/clock.ts
2801
+ var liveClock = {
2802
+ now: () => {
2803
+ if (typeof performance !== "undefined" && typeof performance.now === "function") {
2804
+ return performance.now();
2805
+ }
2806
+ return Date.now();
2807
+ },
2808
+ setTimeout: (task, ms) => setTimeout(task, Math.max(0, Math.floor(ms))),
2809
+ clearTimeout: (timer) => clearTimeout(timer)
2810
+ };
2811
+ function runtimeClockFromEnv(env) {
2812
+ return env?.brass?.clock ?? liveClock;
2813
+ }
2814
+
2730
2815
  // src/core/runtime/runtime.ts
2731
2816
  var NoopHooks = {
2732
2817
  emit() {
@@ -2858,23 +2943,46 @@ var Runtime = class _Runtime {
2858
2943
  return this.fiberEngine.shutdown?.();
2859
2944
  }
2860
2945
  unsafeRunAsync(effect, cb) {
2946
+ if (this.tryRunNativeTopLevel(effect, cb)) return;
2861
2947
  const fiber = this.fork(effect);
2862
2948
  fiber.join(cb);
2863
2949
  }
2864
2950
  toPromise(effect) {
2865
2951
  return new Promise((resolve, reject) => {
2866
- const fiber = this.fork(effect);
2867
- fiber.join((exit) => {
2868
- if (exit._tag === "Success") resolve(exit.value);
2952
+ const complete = (exit) => {
2953
+ if (exit._tag === "Success") {
2954
+ resolve(exit.value);
2955
+ return;
2956
+ }
2957
+ const failure = Cause.firstFailure(exit.cause);
2958
+ if (failure._tag === "Some") reject(failure.value);
2869
2959
  else {
2870
- const c = exit.cause;
2871
- if (c?._tag === "Fail") reject(c.error);
2872
- else if (c?._tag === "Die") reject(c.defect instanceof Error ? c.defect : new Error(String(c.defect)));
2873
- else reject(new Error("Interrupted"));
2960
+ const defect = Cause.firstDefect(exit.cause);
2961
+ if (defect._tag === "Some") {
2962
+ reject(defect.value instanceof Error ? defect.value : new Error(String(defect.value)));
2963
+ } else if (Cause.containsInterrupt(exit.cause)) {
2964
+ reject(new Error("Interrupted"));
2965
+ } else {
2966
+ reject(Cause.toError(exit.cause));
2967
+ }
2874
2968
  }
2969
+ };
2970
+ if (this.tryRunNativeTopLevel(effect, complete)) return;
2971
+ const fiber = this.fork(effect);
2972
+ fiber.join((exit) => {
2973
+ complete(exit);
2875
2974
  });
2876
2975
  });
2877
2976
  }
2977
+ tryRunNativeTopLevel(effect, cb) {
2978
+ if (this.hooks !== NoopHooks) return false;
2979
+ if (getCurrentFiber() !== null) return false;
2980
+ if (this.scheduler !== globalScheduler) return false;
2981
+ if (this.lane !== void 0 || this.inferLane) return false;
2982
+ if (this.engineMode !== "ts") return false;
2983
+ new NativeTopLevelRunner(this, effect, cb).start();
2984
+ return true;
2985
+ }
2878
2986
  // helper: correr un efecto y “tirar” el resultado
2879
2987
  unsafeRun(effect) {
2880
2988
  this.unsafeRunAsync(effect, () => {
@@ -2882,10 +2990,11 @@ var Runtime = class _Runtime {
2882
2990
  }
2883
2991
  delay(ms, eff) {
2884
2992
  return asyncEffect((_env, cb) => {
2885
- const handle = setTimeout(() => {
2993
+ const clock = runtimeClockFromEnv(this.env);
2994
+ const handle = clock.setTimeout(() => {
2886
2995
  this.unsafeRunAsync(eff, cb);
2887
2996
  }, ms);
2888
- return () => clearTimeout(handle);
2997
+ return () => clock.clearTimeout(handle);
2889
2998
  });
2890
2999
  }
2891
3000
  // util para crear runtime default
@@ -2900,6 +3009,243 @@ var Runtime = class _Runtime {
2900
3009
  this.emit({ type: "log", level, message, fields });
2901
3010
  }
2902
3011
  };
3012
+ var NATIVE_FAST_PATH_STEP_BUDGET = 32768;
3013
+ var NativeTopLevelRunner = class {
3014
+ constructor(runtime, effect, cb) {
3015
+ this.runtime = runtime;
3016
+ this.current = effect;
3017
+ this.joiners.push(cb);
3018
+ this.frame = {
3019
+ id: 0,
3020
+ runtime,
3021
+ name: "native-fast-path",
3022
+ fiberContext: { trace: null },
3023
+ lane: runtime.lane,
3024
+ status: () => this.result ? "Done" : "Running",
3025
+ join: (joiner) => {
3026
+ if (this.result) joiner(this.result);
3027
+ else this.joiners.push(joiner);
3028
+ },
3029
+ interrupt: () => void 0,
3030
+ addFinalizer: (finalizer) => {
3031
+ this.finalizers.push(finalizer);
3032
+ }
3033
+ };
3034
+ }
3035
+ runtime;
3036
+ current;
3037
+ stack = [];
3038
+ joiners = [];
3039
+ finalizers = [];
3040
+ result;
3041
+ yielded = false;
3042
+ frame;
3043
+ start() {
3044
+ this.runLoop();
3045
+ }
3046
+ runLoop() {
3047
+ this.withFrame(() => {
3048
+ this.yielded = false;
3049
+ let budget = NATIVE_FAST_PATH_STEP_BUDGET;
3050
+ while (!this.result && budget-- > 0) {
3051
+ const current = this.current;
3052
+ switch (current._tag) {
3053
+ case "Succeed":
3054
+ this.onSuccess(current.value);
3055
+ break;
3056
+ case "Fail":
3057
+ this.onCause(Cause.fail(current.error));
3058
+ break;
3059
+ case "Sync":
3060
+ try {
3061
+ this.onSuccess(current.thunk(this.runtime.env));
3062
+ } catch (error) {
3063
+ this.onCause(Cause.fail(error));
3064
+ }
3065
+ break;
3066
+ case "FlatMap":
3067
+ this.stack.push({ _tag: "SuccessCont", k: current.andThen });
3068
+ this.current = current.first;
3069
+ break;
3070
+ case "Fold":
3071
+ this.stack.push({
3072
+ _tag: "FoldCont",
3073
+ onFailure: current.onFailure,
3074
+ onSuccess: current.onSuccess
3075
+ });
3076
+ this.current = current.first;
3077
+ break;
3078
+ case "Async":
3079
+ if (this.runAsync(current)) break;
3080
+ return;
3081
+ case "Fork":
3082
+ this.onSuccess(this.runtime.fork(current.effect, current.scopeId));
3083
+ break;
3084
+ case "Interruptibility":
3085
+ this.stack.push({ _tag: "InterruptibilityCont" });
3086
+ this.current = current.effect;
3087
+ break;
3088
+ case "InterruptibilityMask":
3089
+ this.stack.push({ _tag: "InterruptibilityCont" });
3090
+ try {
3091
+ this.current = current.body((effect) => ({
3092
+ _tag: "InterruptibilityRestore",
3093
+ depth: 0,
3094
+ effect
3095
+ }));
3096
+ } catch (error) {
3097
+ this.onCause(Cause.die(error));
3098
+ }
3099
+ break;
3100
+ case "InterruptibilityRestore":
3101
+ this.stack.push({ _tag: "InterruptibilityCont" });
3102
+ this.current = current.effect;
3103
+ break;
3104
+ case "FiberRefLocally": {
3105
+ const refs = this.fiberRefs();
3106
+ const hadValue = refs.has(current.refId);
3107
+ const previousValue = refs.get(current.refId);
3108
+ refs.set(current.refId, current.value);
3109
+ this.stack.push({
3110
+ _tag: "FiberRefCont",
3111
+ refId: current.refId,
3112
+ hadValue,
3113
+ previousValue
3114
+ });
3115
+ this.current = current.effect;
3116
+ break;
3117
+ }
3118
+ default:
3119
+ this.onCause(Cause.fail(new Error(`Unknown opcode: ${current._tag}`)));
3120
+ break;
3121
+ }
3122
+ }
3123
+ if (!this.result && !this.yielded) {
3124
+ this.yielded = true;
3125
+ queueMicrotask(() => this.runLoop());
3126
+ }
3127
+ });
3128
+ }
3129
+ runAsync(current) {
3130
+ let registered = false;
3131
+ let settled = false;
3132
+ let syncExit;
3133
+ const resume = (exit) => {
3134
+ if (settled) return;
3135
+ settled = true;
3136
+ if (!registered) {
3137
+ syncExit = exit;
3138
+ return;
3139
+ }
3140
+ queueMicrotask(() => this.resumeAsync(exit));
3141
+ };
3142
+ try {
3143
+ current.register(this.runtime.env, resume);
3144
+ } catch (error) {
3145
+ this.onCause(Cause.die(error));
3146
+ return true;
3147
+ }
3148
+ registered = true;
3149
+ if (syncExit) {
3150
+ this.consumeExit(syncExit);
3151
+ return true;
3152
+ }
3153
+ return false;
3154
+ }
3155
+ resumeAsync(exit) {
3156
+ if (this.result) return;
3157
+ this.withFrame(() => this.consumeExit(exit));
3158
+ if (!this.result) this.runLoop();
3159
+ }
3160
+ consumeExit(exit) {
3161
+ if (exit._tag === "Success") this.onSuccess(exit.value);
3162
+ else this.onCause(exit.cause);
3163
+ }
3164
+ onSuccess(value) {
3165
+ let currentValue = value;
3166
+ while (true) {
3167
+ const frame = this.stack.pop();
3168
+ if (!frame) {
3169
+ this.notify(Exit.succeed(currentValue));
3170
+ return;
3171
+ }
3172
+ if (frame._tag === "InterruptibilityCont") continue;
3173
+ if (frame._tag === "FiberRefCont") {
3174
+ this.restoreFiberRef(frame);
3175
+ continue;
3176
+ }
3177
+ if (frame._tag === "SuccessCont") {
3178
+ try {
3179
+ this.current = frame.k(currentValue);
3180
+ } catch (error) {
3181
+ this.notify(Exit.failCause(Cause.die(error)));
3182
+ }
3183
+ return;
3184
+ }
3185
+ try {
3186
+ this.current = frame.onSuccess(currentValue);
3187
+ } catch (error) {
3188
+ this.notify(Exit.failCause(Cause.die(error)));
3189
+ }
3190
+ return;
3191
+ }
3192
+ }
3193
+ onCause(cause) {
3194
+ let currentCause = cause;
3195
+ while (this.stack.length > 0) {
3196
+ const frame = this.stack.pop();
3197
+ if (frame._tag === "InterruptibilityCont") continue;
3198
+ if (frame._tag === "FiberRefCont") {
3199
+ this.restoreFiberRef(frame);
3200
+ continue;
3201
+ }
3202
+ if (frame._tag === "FoldCont") {
3203
+ if (!Cause.isFailureOnly(currentCause)) continue;
3204
+ const failure = Cause.firstFailure(currentCause);
3205
+ if (failure._tag === "None") break;
3206
+ try {
3207
+ this.current = frame.onFailure(failure.value);
3208
+ return;
3209
+ } catch (error) {
3210
+ currentCause = Cause.fail(error);
3211
+ continue;
3212
+ }
3213
+ }
3214
+ }
3215
+ this.notify(Exit.failCause(currentCause));
3216
+ }
3217
+ notify(exit) {
3218
+ if (this.result) return;
3219
+ this.result = exit;
3220
+ this.runFinalizers(exit);
3221
+ for (const joiner of this.joiners) joiner(exit);
3222
+ this.joiners.length = 0;
3223
+ }
3224
+ runFinalizers(exit) {
3225
+ while (this.finalizers.length > 0) {
3226
+ const finalizer = this.finalizers.pop();
3227
+ try {
3228
+ const result = finalizer(exit);
3229
+ if (result && typeof result === "object" && "_tag" in result) {
3230
+ this.runtime.unsafeRunAsync(result, () => void 0);
3231
+ }
3232
+ } catch {
3233
+ }
3234
+ }
3235
+ }
3236
+ fiberRefs() {
3237
+ this.frame.fiberContext.fiberRefs ??= /* @__PURE__ */ new Map();
3238
+ return this.frame.fiberContext.fiberRefs;
3239
+ }
3240
+ restoreFiberRef(frame) {
3241
+ const refs = this.fiberRefs();
3242
+ if (frame.hadValue) refs.set(frame.refId, frame.previousValue);
3243
+ else refs.delete(frame.refId);
3244
+ }
3245
+ withFrame(body) {
3246
+ return withCurrentFiber(this.frame, body);
3247
+ }
3248
+ };
2903
3249
  function fork(effect, env) {
2904
3250
  return Runtime.make(env ?? {}).fork(effect);
2905
3251
  }
@@ -3126,6 +3472,7 @@ var RuntimeFiber = class {
3126
3472
  stack = [];
3127
3473
  fiberFinalizers = [];
3128
3474
  finalizersDrained = false;
3475
+ interruptibilityDepth = 0;
3129
3476
  fiberContext;
3130
3477
  name;
3131
3478
  scopeId;
@@ -3164,14 +3511,8 @@ var RuntimeFiber = class {
3164
3511
  this.schedule("async-resume");
3165
3512
  return;
3166
3513
  }
3167
- const cause = exit.cause;
3168
- if (cause._tag === "Interrupt") {
3169
- this.notify(Exit.failCause(Cause.interrupt()));
3170
- } else if (cause._tag === "Fail") {
3171
- this.current = Async.fail(cause.error);
3514
+ if (this.onCause(exit.cause)) {
3172
3515
  this.schedule("async-resume");
3173
- } else {
3174
- this.notify(Exit.failCause(Cause.die(cause.defect)));
3175
3516
  }
3176
3517
  };
3177
3518
  this.boundStep = () => {
@@ -3230,7 +3571,7 @@ var RuntimeFiber = class {
3230
3571
  }
3231
3572
  status() {
3232
3573
  if (this.result == null) return "Running";
3233
- if (this.result._tag === "Failure" && this.result.cause._tag === "Interrupt") return "Interrupted";
3574
+ if (this.result._tag === "Failure" && Cause.isInterruptedOnly(this.result.cause)) return "Interrupted";
3234
3575
  return "Done";
3235
3576
  }
3236
3577
  join(cb) {
@@ -3241,7 +3582,9 @@ var RuntimeFiber = class {
3241
3582
  if (this.result != null) return;
3242
3583
  if (this.interrupted) return;
3243
3584
  this.interrupted = true;
3244
- this.schedule("interrupt-step");
3585
+ if (this.isInterruptible()) {
3586
+ this.schedule("interrupt-step");
3587
+ }
3245
3588
  }
3246
3589
  schedule(tag = "step") {
3247
3590
  if (this.runState === RUN.DONE || this.runState === RUN.QUEUED) return;
@@ -3284,7 +3627,7 @@ var RuntimeFiber = class {
3284
3627
  this.closing = exit;
3285
3628
  this.runFinalizersOnce(exit);
3286
3629
  this.result = exit;
3287
- const status = exit._tag === "Success" ? "success" : exit.cause._tag === "Interrupt" ? "interrupted" : "failure";
3630
+ const status = exit._tag === "Success" ? "success" : Cause.isInterruptedOnly(exit.cause) ? "interrupted" : "failure";
3288
3631
  this.emit({
3289
3632
  type: "fiber.end",
3290
3633
  fiberId: this.id,
@@ -3294,46 +3637,109 @@ var RuntimeFiber = class {
3294
3637
  for (const j of this.joiners) j(exit);
3295
3638
  this.joiners.length = 0;
3296
3639
  }
3640
+ isInterruptible() {
3641
+ return this.interruptibilityDepth === 0;
3642
+ }
3643
+ shouldInterruptNow() {
3644
+ return this.interrupted && this.isInterruptible();
3645
+ }
3646
+ enterInterruptibility(mode) {
3647
+ const previousDepth = this.interruptibilityDepth;
3648
+ this.interruptibilityDepth = mode === "uninterruptible" ? previousDepth + 1 : 0;
3649
+ return previousDepth;
3650
+ }
3651
+ restoreInterruptibility(previousDepth) {
3652
+ this.interruptibilityDepth = Math.max(0, previousDepth);
3653
+ }
3654
+ fiberRefs() {
3655
+ const ctx = this.fiberContext;
3656
+ if (!ctx.fiberRefs) ctx.fiberRefs = /* @__PURE__ */ new Map();
3657
+ return ctx.fiberRefs;
3658
+ }
3659
+ restoreFiberRef(frame) {
3660
+ const refs = this.fiberRefs();
3661
+ if (frame.hadValue) refs.set(frame.refId, frame.previousValue);
3662
+ else refs.delete(frame.refId);
3663
+ }
3297
3664
  onSuccess(value) {
3298
- const frame = this.stack.pop();
3299
- if (!frame) {
3300
- this.notify(Exit.succeed(value));
3301
- return;
3302
- }
3303
- if (frame._tag === "SuccessCont") {
3665
+ let currentValue = value;
3666
+ while (true) {
3667
+ const frame = this.stack.pop();
3668
+ if (!frame) {
3669
+ if (this.shouldInterruptNow()) {
3670
+ this.notify(Exit.failCause(Cause.interrupt()));
3671
+ } else {
3672
+ this.notify(Exit.succeed(currentValue));
3673
+ }
3674
+ return;
3675
+ }
3676
+ if (frame._tag === "InterruptibilityCont") {
3677
+ this.restoreInterruptibility(frame.previousDepth);
3678
+ if (this.shouldInterruptNow()) {
3679
+ this.notify(Exit.failCause(Cause.interrupt()));
3680
+ return;
3681
+ }
3682
+ continue;
3683
+ }
3684
+ if (frame._tag === "FiberRefCont") {
3685
+ this.restoreFiberRef(frame);
3686
+ continue;
3687
+ }
3688
+ if (frame._tag === "SuccessCont") {
3689
+ try {
3690
+ this.current = frame.k(currentValue);
3691
+ } catch (e) {
3692
+ this.notify(Exit.failCause(Cause.die(e)));
3693
+ }
3694
+ return;
3695
+ }
3304
3696
  try {
3305
- this.current = frame.k(value);
3697
+ this.current = frame.onSuccess(currentValue);
3306
3698
  } catch (e) {
3307
3699
  this.notify(Exit.failCause(Cause.die(e)));
3308
3700
  }
3309
3701
  return;
3310
3702
  }
3311
- try {
3312
- this.current = frame.onSuccess(value);
3313
- } catch (e) {
3314
- this.notify(Exit.failCause(Cause.die(e)));
3315
- }
3316
3703
  }
3317
3704
  onFailure(error) {
3705
+ this.onCause(Cause.fail(error));
3706
+ }
3707
+ onCause(cause) {
3708
+ let currentCause = cause;
3318
3709
  while (this.stack.length > 0) {
3319
3710
  const fr = this.stack.pop();
3711
+ if (fr._tag === "InterruptibilityCont") {
3712
+ this.restoreInterruptibility(fr.previousDepth);
3713
+ if (this.shouldInterruptNow() && !Cause.isInterruptedOnly(currentCause)) {
3714
+ currentCause = Cause.then(currentCause, Cause.interrupt());
3715
+ }
3716
+ continue;
3717
+ }
3718
+ if (fr._tag === "FiberRefCont") {
3719
+ this.restoreFiberRef(fr);
3720
+ continue;
3721
+ }
3320
3722
  if (fr._tag === "FoldCont") {
3723
+ if (!Cause.isFailureOnly(currentCause)) continue;
3724
+ const failure = Cause.firstFailure(currentCause);
3725
+ if (failure._tag === "None") break;
3321
3726
  try {
3322
- this.current = fr.onFailure(error);
3323
- return;
3727
+ this.current = fr.onFailure(failure.value);
3728
+ return true;
3324
3729
  } catch (e) {
3325
- error = e;
3730
+ currentCause = Cause.fail(e);
3326
3731
  continue;
3327
3732
  }
3328
3733
  }
3329
3734
  }
3330
- this.notify(Exit.failCause(Cause.fail(error)));
3735
+ this.notify(Exit.failCause(currentCause));
3736
+ return false;
3331
3737
  }
3332
3738
  budget = DEFAULT_BUDGET2;
3333
3739
  step() {
3334
3740
  if (this.result != null) return STEP.DONE;
3335
- if (this.interrupted) {
3336
- this.notify(Exit.failCause(Cause.interrupt()));
3741
+ if (this.shouldInterruptNow()) {
3742
+ this.onCause(Cause.interrupt());
3337
3743
  return STEP.DONE;
3338
3744
  }
3339
3745
  this.budget = __benchmarkBudget ?? DEFAULT_BUDGET2;
@@ -3388,14 +3794,7 @@ var RuntimeFiber = class {
3388
3794
  if (resolvedExit._tag === "Success") {
3389
3795
  this.onSuccess(resolvedExit.value);
3390
3796
  } else {
3391
- const cause = resolvedExit.cause;
3392
- if (cause._tag === "Interrupt") {
3393
- this.notify(Exit.failCause(Cause.interrupt()));
3394
- } else if (cause._tag === "Fail") {
3395
- this.onFailure(cause.error);
3396
- } else {
3397
- this.notify(Exit.failCause(Cause.die(cause.defect)));
3398
- }
3797
+ this.onCause(resolvedExit.cause);
3399
3798
  }
3400
3799
  break;
3401
3800
  }
@@ -3417,6 +3816,47 @@ var RuntimeFiber = class {
3417
3816
  this.onSuccess(child);
3418
3817
  break;
3419
3818
  }
3819
+ case "Interruptibility": {
3820
+ const previousDepth = this.enterInterruptibility(current.mode);
3821
+ this.stack.push({ _tag: "InterruptibilityCont", previousDepth });
3822
+ this.current = current.effect;
3823
+ break;
3824
+ }
3825
+ case "InterruptibilityMask": {
3826
+ const previousDepth = this.enterInterruptibility("uninterruptible");
3827
+ this.stack.push({ _tag: "InterruptibilityCont", previousDepth });
3828
+ try {
3829
+ this.current = current.body((effect) => ({
3830
+ _tag: "InterruptibilityRestore",
3831
+ depth: previousDepth,
3832
+ effect
3833
+ }));
3834
+ } catch (e) {
3835
+ this.onCause(Cause.die(e));
3836
+ }
3837
+ break;
3838
+ }
3839
+ case "InterruptibilityRestore": {
3840
+ const previousDepth = this.interruptibilityDepth;
3841
+ this.restoreInterruptibility(current.depth);
3842
+ this.stack.push({ _tag: "InterruptibilityCont", previousDepth });
3843
+ this.current = current.effect;
3844
+ break;
3845
+ }
3846
+ case "FiberRefLocally": {
3847
+ const refs = this.fiberRefs();
3848
+ const hadValue = refs.has(current.refId);
3849
+ const previousValue = refs.get(current.refId);
3850
+ refs.set(current.refId, current.value);
3851
+ this.stack.push({
3852
+ _tag: "FiberRefCont",
3853
+ refId: current.refId,
3854
+ hadValue,
3855
+ previousValue
3856
+ });
3857
+ this.current = current.effect;
3858
+ break;
3859
+ }
3420
3860
  case "Sync": {
3421
3861
  try {
3422
3862
  const a = current.thunk(this.env);
@@ -3508,14 +3948,7 @@ var RuntimeFiber = class {
3508
3948
  continue;
3509
3949
  } else {
3510
3950
  this.stack.push({ _tag: "SuccessCont", k: andThen });
3511
- const cause = exit.cause;
3512
- if (cause._tag === "Fail") {
3513
- this.onFailure(cause.error);
3514
- } else if (cause._tag === "Interrupt") {
3515
- this.notify(Exit.failCause(Cause.interrupt()));
3516
- } else {
3517
- this.notify(Exit.failCause(Cause.die(cause.defect)));
3518
- }
3951
+ this.onCause(exit.cause);
3519
3952
  return this.result != null ? TRAMPOLINE.DONE : TRAMPOLINE.CONTINUE;
3520
3953
  }
3521
3954
  }
@@ -3634,6 +4067,8 @@ export {
3634
4067
  makeFiberReadyQueue,
3635
4068
  WasmFiberEngine,
3636
4069
  runtimeCapabilities,
4070
+ liveClock,
4071
+ runtimeClockFromEnv,
3637
4072
  NoopHooks,
3638
4073
  Runtime,
3639
4074
  fork,