brass-runtime 1.15.0 → 1.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +673 -136
  3. package/dist/agent/cli/main.cjs +40 -35
  4. package/dist/agent/cli/main.js +9 -4
  5. package/dist/agent/cli/main.mjs +9 -4
  6. package/dist/agent/index.cjs +8 -4
  7. package/dist/agent/index.d.ts +1 -1
  8. package/dist/agent/index.js +7 -3
  9. package/dist/agent/index.mjs +7 -3
  10. package/dist/chunk-2HQTDLHF.mjs +683 -0
  11. package/dist/chunk-36I3M4UC.mjs +370 -0
  12. package/dist/chunk-3AYM6WPJ.js +1629 -0
  13. package/dist/chunk-3LOYJFRR.cjs +300 -0
  14. package/dist/chunk-3RG5ZIWI.js +10 -0
  15. package/dist/chunk-3Y2RIUMM.js +300 -0
  16. package/dist/{chunk-VEZNF5GZ.cjs → chunk-4ROBZFL6.cjs} +130 -126
  17. package/dist/{chunk-3QMOKAS5.js → chunk-52OB2ROS.js} +9 -5
  18. package/dist/chunk-52PPNNI4.cjs +416 -0
  19. package/dist/chunk-5EC274J5.cjs +2874 -0
  20. package/dist/chunk-5QC7LRZ3.js +229 -0
  21. package/dist/chunk-5VRJNBLZ.mjs +2874 -0
  22. package/dist/chunk-62AZW6UT.cjs +313 -0
  23. package/dist/chunk-6IXXWIUM.js +683 -0
  24. package/dist/chunk-74ZTY6CP.js +2871 -0
  25. package/dist/chunk-76YMRMH2.cjs +777 -0
  26. package/dist/chunk-7CMJS3QE.mjs +2871 -0
  27. package/dist/{chunk-4NHES7VK.mjs → chunk-7JIJOVCT.js} +27 -13
  28. package/dist/chunk-A2OM6NEH.mjs +194 -0
  29. package/dist/chunk-AGR5B2BC.cjs +683 -0
  30. package/dist/chunk-AVNQLJ5V.js +777 -0
  31. package/dist/chunk-B33ICAKP.js +313 -0
  32. package/dist/{chunk-ELOOF35R.mjs → chunk-B5JD23U7.mjs} +1 -1
  33. package/dist/chunk-BABBZK4Y.js +2024 -0
  34. package/dist/chunk-C3MDXTRZ.js +354 -0
  35. package/dist/chunk-CIZFIMK5.js +2193 -0
  36. package/dist/chunk-CZIVE6NT.cjs +354 -0
  37. package/dist/chunk-DNFJLJMW.mjs +354 -0
  38. package/dist/chunk-DNFO2EIZ.mjs +777 -0
  39. package/dist/chunk-EJ6BPYVR.mjs +416 -0
  40. package/dist/chunk-ENKODRU3.cjs +2193 -0
  41. package/dist/chunk-EOC4UHBS.mjs +229 -0
  42. package/dist/{chunk-BMH5AV44.js → chunk-FH2X7BVP.js} +756 -440
  43. package/dist/{chunk-PPUXIH5R.js → chunk-FHQGHPMO.mjs} +27 -13
  44. package/dist/{chunk-TGIFUAK4.cjs → chunk-GLE2WY7Z.cjs} +951 -635
  45. package/dist/{chunk-BDF4AMWX.mjs → chunk-GYM3LLGS.mjs} +756 -440
  46. package/dist/chunk-HLWLMW2F.mjs +2024 -0
  47. package/dist/chunk-JF5WGYJJ.cjs +194 -0
  48. package/dist/chunk-KH4SYAOS.mjs +1629 -0
  49. package/dist/chunk-KN32XNTH.mjs +313 -0
  50. package/dist/chunk-KQLYONSE.cjs +2871 -0
  51. package/dist/{chunk-STVLQ3XD.cjs → chunk-KZJQ723N.cjs} +92 -78
  52. package/dist/chunk-L2SYFEBS.js +194 -0
  53. package/dist/chunk-L6VB5N7Q.cjs +104 -0
  54. package/dist/{chunk-K6M7MDZ4.mjs → chunk-MBEJI5HF.mjs} +9 -5
  55. package/dist/chunk-MIIYDLGM.js +2874 -0
  56. package/dist/chunk-MOO4L7F4.mjs +104 -0
  57. package/dist/chunk-MT3OWDPC.mjs +2193 -0
  58. package/dist/chunk-MVGUEJ5Z.cjs +370 -0
  59. package/dist/chunk-OBGZSXTJ.cjs +10 -0
  60. package/dist/chunk-PD4EJTQC.cjs +229 -0
  61. package/dist/chunk-PWC3RBQE.mjs +300 -0
  62. package/dist/chunk-Q2I37RP3.cjs +1629 -0
  63. package/dist/chunk-RKGKFN2A.js +416 -0
  64. package/dist/{chunk-R3R2FVLG.cjs → chunk-SA6HUJVI.cjs} +5 -5
  65. package/dist/chunk-TRM4JUZQ.js +104 -0
  66. package/dist/chunk-UB4B6OFY.js +370 -0
  67. package/dist/{chunk-TO7IKXYT.js → chunk-UCUBNWM2.js} +1 -1
  68. package/dist/chunk-VN44DYYT.cjs +2024 -0
  69. package/dist/chunk-Y6FXYEAI.mjs +10 -0
  70. package/dist/client-CZHU674n.d.ts +820 -0
  71. package/dist/core/index.cjs +198 -4
  72. package/dist/core/index.d.ts +311 -212
  73. package/dist/core/index.js +237 -43
  74. package/dist/core/index.mjs +237 -43
  75. package/dist/{effect-CMOQKX8y.d.ts → effect-DIUHZ9IN.d.ts} +195 -1
  76. package/dist/effectRunner-CFLC32IK.cjs +8 -0
  77. package/dist/effectRunner-L4S7IPT3.js +8 -0
  78. package/dist/effectRunner-NNGG75QA.mjs +8 -0
  79. package/dist/http/index.cjs +1227 -2971
  80. package/dist/http/index.d.ts +826 -280
  81. package/dist/http/index.js +1089 -2833
  82. package/dist/http/index.mjs +1089 -2833
  83. package/dist/http/testing.cjs +161 -0
  84. package/dist/http/testing.d.ts +43 -0
  85. package/dist/http/testing.js +161 -0
  86. package/dist/http/testing.mjs +161 -0
  87. package/dist/index.cjs +486 -250
  88. package/dist/index.d.ts +87 -95
  89. package/dist/index.js +391 -155
  90. package/dist/index.mjs +391 -155
  91. package/dist/observability/index.cjs +162 -0
  92. package/dist/observability/index.d.ts +152 -0
  93. package/dist/observability/index.js +162 -0
  94. package/dist/observability/index.mjs +162 -0
  95. package/dist/perf/cli.cjs +401 -0
  96. package/dist/perf/cli.d.ts +1 -0
  97. package/dist/perf/cli.js +401 -0
  98. package/dist/perf/cli.mjs +401 -0
  99. package/dist/perf/index.cjs +141 -0
  100. package/dist/perf/index.d.ts +483 -0
  101. package/dist/perf/index.js +141 -0
  102. package/dist/perf/index.mjs +141 -0
  103. package/dist/schedule-CK3Ml_7p.d.ts +259 -0
  104. package/dist/schema/index.cjs +29 -0
  105. package/dist/schema/index.d.ts +179 -0
  106. package/dist/schema/index.js +29 -0
  107. package/dist/schema/index.mjs +29 -0
  108. package/dist/server-GJPg8ZSG.d.ts +675 -0
  109. package/dist/{stream-FQm9h4Mg.d.ts → stream-B4oK9JFP.d.ts} +1 -1
  110. package/dist/tracer-Hwt1cl7h.d.ts +189 -0
  111. package/dist/tracing-DqbTKGcf.d.ts +148 -0
  112. package/docs/ARCHITECTURE.md +292 -0
  113. package/docs/README.md +63 -0
  114. package/docs/adr/0001-ai-context-pack.md +32 -0
  115. package/docs/agent-apply-mode.md +104 -0
  116. package/docs/agent-approvals.md +110 -0
  117. package/docs/agent-batch.md +185 -0
  118. package/docs/agent-boundaries.md +112 -0
  119. package/docs/agent-chat-sessions.md +160 -0
  120. package/docs/agent-ci.md +17 -0
  121. package/docs/agent-cli.md +405 -0
  122. package/docs/agent-config.md +480 -0
  123. package/docs/agent-context-discovery.md +159 -0
  124. package/docs/agent-copilot-like-dx.md +126 -0
  125. package/docs/agent-declarative-optimized-planning.md +138 -0
  126. package/docs/agent-dx.md +224 -0
  127. package/docs/agent-env-files.md +126 -0
  128. package/docs/agent-follow-up-context.md +43 -0
  129. package/docs/agent-global-usage.md +180 -0
  130. package/docs/agent-init.md +109 -0
  131. package/docs/agent-install-and-configure.md +516 -0
  132. package/docs/agent-language-workspace-ux.md +99 -0
  133. package/docs/agent-llm-adapters.md +123 -0
  134. package/docs/agent-local-install.md +190 -0
  135. package/docs/agent-local-tests.md +51 -0
  136. package/docs/agent-observability.md +155 -0
  137. package/docs/agent-patch-quality-loop.md +162 -0
  138. package/docs/agent-presets.md +22 -0
  139. package/docs/agent-project-commands.md +237 -0
  140. package/docs/agent-project-intelligence.md +156 -0
  141. package/docs/agent-redaction.md +18 -0
  142. package/docs/agent-release-readiness.md +76 -0
  143. package/docs/agent-rollback-safety.md +162 -0
  144. package/docs/agent-rollback.md +23 -0
  145. package/docs/agent-run-artifacts.md +16 -0
  146. package/docs/agent-vscode-auto-discovery.md +137 -0
  147. package/docs/agent-vscode-batch-runner.md +100 -0
  148. package/docs/agent-vscode-chat-layout.md +90 -0
  149. package/docs/agent-vscode-clean-install.md +147 -0
  150. package/docs/agent-vscode-code-actions.md +70 -0
  151. package/docs/agent-vscode-diff-preview.md +45 -0
  152. package/docs/agent-vscode-inline-assist.md +56 -0
  153. package/docs/agent-vscode-install.md +186 -0
  154. package/docs/agent-vscode-model-setup.md +97 -0
  155. package/docs/agent-vscode-patch-preview.md +92 -0
  156. package/docs/agent-vscode-problems.md +79 -0
  157. package/docs/agent-vscode-project-dashboard.md +106 -0
  158. package/docs/agent-vscode-run-history.md +92 -0
  159. package/docs/agent-vscode-ux.md +73 -0
  160. package/docs/ai/INVARIANTS.md +84 -0
  161. package/docs/ai/PROJECT_MAP.md +338 -0
  162. package/docs/ai/PUBLIC_API.md +336 -0
  163. package/docs/ai/VALIDATION_MATRIX.md +67 -0
  164. package/docs/api-polish.md +37 -0
  165. package/docs/cancellation.md +162 -0
  166. package/docs/coverage.md +46 -0
  167. package/docs/getting-started.md +159 -0
  168. package/docs/guides/README.md +40 -0
  169. package/docs/guides/circuit-breaker.md +89 -0
  170. package/docs/guides/error-handling.md +91 -0
  171. package/docs/guides/getting-started.md +107 -0
  172. package/docs/guides/layers.md +189 -0
  173. package/docs/guides/metrics.md +101 -0
  174. package/docs/guides/resource-management.md +141 -0
  175. package/docs/guides/retry.md +215 -0
  176. package/docs/guides/semaphore.md +66 -0
  177. package/docs/guides/streams.md +117 -0
  178. package/docs/guides/supervisors.md +98 -0
  179. package/docs/guides/testing.md +162 -0
  180. package/docs/guides/tracing.md +71 -0
  181. package/docs/http-recipes.md +399 -0
  182. package/docs/http.md +749 -0
  183. package/docs/modules.md +285 -0
  184. package/docs/observability-collector-smoke.md +31 -0
  185. package/docs/observability-framework-examples.md +98 -0
  186. package/docs/observability.md +542 -0
  187. package/docs/otel-collector-smoke.yaml +27 -0
  188. package/docs/performance-profiler.md +199 -0
  189. package/docs/production-readiness.md +73 -0
  190. package/docs/recipes/README.md +12 -0
  191. package/docs/recipes/http-server.md +45 -0
  192. package/docs/recipes/layers.md +44 -0
  193. package/docs/recipes/performance.md +47 -0
  194. package/docs/recipes/runtime.md +41 -0
  195. package/docs/recipes/testing.md +41 -0
  196. package/docs/release.md +53 -0
  197. package/docs/wasm-bounded-queues.md +44 -0
  198. package/docs/wasm-engine-observability-benchmarks.md +85 -0
  199. package/docs/wasm-fiber-engine.md +117 -0
  200. package/docs/wasm-scheduler-state-machine.md +122 -0
  201. package/docs/wasm-stream-chunks.md +54 -0
  202. package/package.json +48 -2
  203. package/dist/chunk-AR22SXML.js +0 -1043
  204. package/dist/chunk-BDYEENHT.js +0 -224
  205. package/dist/chunk-JFPU5GQI.mjs +0 -1043
  206. package/dist/chunk-MS34J5LY.cjs +0 -224
  207. package/dist/chunk-UMAZLXAB.mjs +0 -224
  208. package/dist/chunk-XPZNXSVN.cjs +0 -1043
  209. package/dist/tracing-DNT9jEbr.d.ts +0 -106
@@ -1,121 +1,13 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
- // src/core/types/asyncEffect.ts
9
- var Async = {
10
- succeed: (value) => ({ _tag: "Succeed", value }),
11
- fail: (error) => ({ _tag: "Fail", error }),
12
- sync: (thunk) => ({ _tag: "Sync", thunk }),
13
- async: (register) => ({ _tag: "Async", register })
14
- };
15
- function asyncFold(fa, onFailure, onSuccess) {
16
- return {
17
- _tag: "Fold",
18
- first: fa,
19
- onFailure,
20
- onSuccess
21
- };
22
- }
23
- function asyncCatchAll(fa, handler) {
24
- return asyncFold(fa, handler, asyncSucceed);
25
- }
26
- function asyncMapError(fa, f) {
27
- return asyncFold(fa, (e) => asyncFail(f(e)), asyncSucceed);
28
- }
29
- var SUCCEED_UNDEFINED = { _tag: "Succeed", value: void 0 };
30
- var SUCCEED_TRUE = { _tag: "Succeed", value: true };
31
- var SUCCEED_FALSE = { _tag: "Succeed", value: false };
32
- var SUCCEED_NULL = { _tag: "Succeed", value: null };
33
- var unit = () => SUCCEED_UNDEFINED;
34
- var asyncSucceed = (value) => {
35
- if (value === void 0) return SUCCEED_UNDEFINED;
36
- if (value === true) return SUCCEED_TRUE;
37
- if (value === false) return SUCCEED_FALSE;
38
- if (value === null) return SUCCEED_NULL;
39
- return { _tag: "Succeed", value };
40
- };
41
- var asyncFail = (error) => ({
42
- _tag: "Fail",
43
- error
44
- });
45
- var asyncSync = (thunk) => ({
46
- _tag: "Sync",
47
- thunk
48
- });
49
- var asyncTotal = (thunk) => asyncSync(() => thunk());
50
- var asyncEffect = (register) => ({
51
- _tag: "Async",
52
- register
53
- });
54
- function asyncMap(fa, f) {
55
- return asyncFlatMap(fa, (a) => asyncSucceed(f(a)));
56
- }
57
- function asyncFlatMap(fa, f) {
58
- return {
59
- _tag: "FlatMap",
60
- first: fa,
61
- andThen: f
62
- };
63
- }
64
- function acquireRelease(acquire, release, scope) {
65
- return asyncFlatMap(acquire, (resource) => {
66
- scope.addFinalizer((exit) => release(resource, exit));
67
- return asyncSucceed(resource);
68
- });
69
- }
70
- function asyncInterruptible(register) {
71
- return asyncEffect(register);
72
- }
73
- var withAsyncPromise = (run) => (eff) => {
74
- const anyEff = eff;
75
- if (!anyEff.toPromise) {
76
- anyEff.toPromise = (env) => run(eff, env);
77
- anyEff.unsafeRunPromise = () => run(eff, {});
78
- }
79
- return anyEff;
80
- };
81
- var mapAsync = (fa, f) => asyncFlatMap(fa, (a) => asyncSucceed(f(a)));
82
- var mapTryAsync = (fa, f) => asyncFlatMap(fa, (a) => asyncSync(() => f(a)));
83
-
84
- // src/core/types/option.ts
85
- var none = { _tag: "None" };
86
- var some = (value) => ({ _tag: "Some", value });
87
-
88
- // src/core/types/effect.ts
89
- var Cause = {
90
- fail: (error) => ({ _tag: "Fail", error }),
91
- interrupt: () => ({ _tag: "Interrupt" }),
92
- die: (defect) => ({ _tag: "Die", defect })
93
- };
94
- var Exit = {
95
- succeed: (value) => ({
96
- _tag: "Success",
97
- value
98
- }),
99
- failCause: (cause) => ({
100
- _tag: "Failure",
101
- cause
102
- })
103
- };
104
- var succeed = (value) => asyncSucceed(value);
105
- var fail = (error) => asyncFail(error);
106
- var sync = (thunk) => asyncSync((env) => thunk(env));
107
- var map = (fa, f) => asyncMap(fa, f);
108
- var flatMap = (fa, f) => asyncFlatMap(fa, f);
109
- var mapError = (fa, f) => asyncMapError(fa, f);
110
- var catchAll = (fa, handler) => asyncFold(fa, handler, asyncSucceed);
111
- function orElseOptional(fa, that) {
112
- return asyncFold(
113
- fa,
114
- (opt) => opt._tag === "Some" ? asyncFail(opt) : that(),
115
- asyncSucceed
116
- );
117
- }
118
- var end = () => fail(none);
1
+ import {
2
+ Async,
3
+ Cause,
4
+ Exit,
5
+ asyncEffect
6
+ } from "./chunk-UB4B6OFY.js";
7
+ import {
8
+ Schema,
9
+ parseConfig
10
+ } from "./chunk-C3MDXTRZ.js";
119
11
 
120
12
  // src/core/runtime/ringBuffer.ts
121
13
  var PushStatus = /* @__PURE__ */ ((PushStatus3) => {
@@ -441,13 +333,47 @@ function resolveWasmScheduler() {
441
333
  var LaneState = class {
442
334
  constructor(key, initial, max) {
443
335
  this.key = key;
336
+ this.initial = initial;
337
+ this.max = max;
444
338
  this.queue = makeBoundedRingBuffer(initial, max, { engine: "ts" });
445
339
  }
446
340
  key;
341
+ initial;
342
+ max;
447
343
  queue;
344
+ tagQueue;
345
+ sharedTag;
448
346
  enqueuedTasks = 0;
449
347
  executedTasks = 0;
450
348
  droppedTasks = 0;
349
+ recordTag(tag, queuedBefore) {
350
+ if (this.tagQueue) {
351
+ this.tagQueue.push(tag);
352
+ return;
353
+ }
354
+ if (queuedBefore === 0 || this.sharedTag === void 0) {
355
+ this.sharedTag = tag;
356
+ return;
357
+ }
358
+ if (this.sharedTag === tag) return;
359
+ const tags = makeBoundedRingBuffer(this.initial, this.max, { engine: "ts" });
360
+ for (let i = 0; i < queuedBefore; i++) tags.push(this.sharedTag);
361
+ tags.push(tag);
362
+ this.tagQueue = tags;
363
+ }
364
+ shiftTag() {
365
+ if (this.tagQueue) {
366
+ const tag2 = this.tagQueue.shift() ?? this.sharedTag ?? this.key;
367
+ if (this.queue.length === 0) {
368
+ this.tagQueue = void 0;
369
+ this.sharedTag = void 0;
370
+ }
371
+ return tag2;
372
+ }
373
+ const tag = this.sharedTag ?? this.key;
374
+ if (this.queue.length === 0) this.sharedTag = void 0;
375
+ return tag;
376
+ }
451
377
  };
452
378
  var JsSchedulerState = class {
453
379
  constructor(options) {
@@ -473,6 +399,27 @@ var JsSchedulerState = class {
473
399
  return n;
474
400
  }
475
401
  };
402
+ var JsSingleSchedulerState = class {
403
+ constructor(options) {
404
+ this.options = options;
405
+ this.queue = makeBoundedRingBuffer(
406
+ options.initialCapacity ?? 1024,
407
+ options.maxCapacity ?? SCHEDULER_QUEUE_CAPACITY,
408
+ { engine: "ts" }
409
+ );
410
+ }
411
+ options;
412
+ queue;
413
+ flushing = false;
414
+ scheduled = false;
415
+ scheduledFlushes = 0;
416
+ completedFlushes = 0;
417
+ enqueuedTasks = 0;
418
+ executedTasks = 0;
419
+ droppedTasks = 0;
420
+ yieldedByBudget = 0;
421
+ totalLength = 0;
422
+ };
476
423
  var WasmSchedulerState = class {
477
424
  machine;
478
425
  nextRef = 1;
@@ -710,9 +657,9 @@ function inferLane(tag) {
710
657
  }
711
658
  function extractTaggedLane(tag, prefix) {
712
659
  if (!tag.startsWith(prefix)) return void 0;
713
- const end2 = tag.indexOf("|", prefix.length);
714
- if (end2 < 0) return void 0;
715
- const value = tag.slice(prefix.length, end2);
660
+ const end = tag.indexOf("|", prefix.length);
661
+ if (end < 0) return void 0;
662
+ const value = tag.slice(prefix.length, end);
716
663
  return value.length > 0 ? value : void 0;
717
664
  }
718
665
  function firstSeparatorIndex(value) {
@@ -726,6 +673,7 @@ function firstSeparatorIndex(value) {
726
673
  var Scheduler = class {
727
674
  engine;
728
675
  js;
676
+ jsSingle;
729
677
  wasm;
730
678
  flushBudget;
731
679
  microThreshold;
@@ -734,6 +682,7 @@ var Scheduler = class {
734
682
  maxLanes;
735
683
  fallbackUsed;
736
684
  boundFlush = () => this.flush();
685
+ shiftedTag = "anonymous";
737
686
  constructor(options = {}) {
738
687
  this.flushBudget = options.flushBudget ?? FLUSH_BUDGET;
739
688
  this.microThreshold = options.microThreshold ?? MICRO_THRESHOLD;
@@ -748,7 +697,11 @@ var Scheduler = class {
748
697
  return;
749
698
  }
750
699
  if (requested === "ts") {
751
- this.js = new JsSchedulerState({ ...options, engine: "ts" });
700
+ if (options.laneMode === "single") {
701
+ this.jsSingle = new JsSingleSchedulerState({ ...options, engine: "ts" });
702
+ } else {
703
+ this.js = new JsSchedulerState({ ...options, engine: "ts" });
704
+ }
752
705
  this.engine = "ts";
753
706
  this.fallbackUsed = false;
754
707
  return;
@@ -758,14 +711,42 @@ var Scheduler = class {
758
711
  schedule(task, tag = "anonymous") {
759
712
  if (typeof task !== "function") return "dropped";
760
713
  if (this.wasm) return this.scheduleWasm(task, tag);
714
+ if (this.jsSingle) return this.scheduleJsSingle(task);
761
715
  return this.scheduleJs(task, tag);
762
716
  }
763
717
  scheduleBatch(tasks) {
764
718
  if (this.wasm) return this.scheduleBatchWasm(tasks);
719
+ if (this.jsSingle) return this.scheduleBatchJsSingle(tasks);
765
720
  return tasks.map(({ fn, tag }) => this.schedule(fn, tag));
766
721
  }
767
722
  stats() {
768
723
  if (this.wasm) return this.wasm.stats();
724
+ if (this.jsSingle) {
725
+ const js2 = this.jsSingle;
726
+ return {
727
+ engine: "ts",
728
+ fallbackUsed: false,
729
+ data: {
730
+ len: js2.totalLength,
731
+ capacity: js2.queue.capacity,
732
+ phase: js2.flushing ? "flushing" : js2.scheduled ? "scheduled" : "idle",
733
+ scheduledFlushes: js2.scheduledFlushes,
734
+ completedFlushes: js2.completedFlushes,
735
+ enqueuedTasks: js2.enqueuedTasks,
736
+ executedTasks: js2.executedTasks,
737
+ droppedTasks: js2.droppedTasks,
738
+ yieldedByBudget: js2.yieldedByBudget,
739
+ lanes: [{
740
+ key: "single",
741
+ len: js2.queue.length,
742
+ capacity: js2.queue.capacity,
743
+ enqueuedTasks: js2.enqueuedTasks,
744
+ executedTasks: js2.executedTasks,
745
+ droppedTasks: js2.droppedTasks
746
+ }]
747
+ }
748
+ };
749
+ }
769
750
  const js = this.js;
770
751
  const lanes = Array.from(js.lanes.values()).map((lane) => ({ key: lane.key, len: lane.queue.length, capacity: lane.queue.capacity, enqueuedTasks: lane.enqueuedTasks, executedTasks: lane.executedTasks, droppedTasks: lane.droppedTasks }));
771
752
  return { engine: "ts", fallbackUsed: false, data: { len: js.totalLength, capacity: js.totalCapacity, phase: js.flushing ? "flushing" : js.scheduled ? "scheduled" : "idle", scheduledFlushes: js.scheduledFlushes, completedFlushes: js.completedFlushes, enqueuedTasks: js.enqueuedTasks, executedTasks: js.executedTasks, droppedTasks: js.droppedTasks, yieldedByBudget: js.yieldedByBudget, lanes } };
@@ -821,13 +802,44 @@ var Scheduler = class {
821
802
  const js = this.js;
822
803
  const lane = new LaneState(key, this.laneCapacity, this.laneCapacity);
823
804
  js.lanes.set(key, lane);
824
- js.laneOrder.push(key);
805
+ js.laneOrder.push(lane);
825
806
  return lane;
826
807
  }
808
+ scheduleJsSingle(task) {
809
+ const js = this.jsSingle;
810
+ const status = js.queue.push(task);
811
+ js.enqueuedTasks++;
812
+ if ((status & 2) !== 0) {
813
+ js.droppedTasks++;
814
+ if (!js.flushing && !js.scheduled && js.totalLength > 0) {
815
+ js.scheduled = true;
816
+ js.scheduledFlushes++;
817
+ this.requestFlush(js.totalLength > this.microThreshold ? "macro" : "micro");
818
+ }
819
+ return "dropped";
820
+ }
821
+ js.totalLength++;
822
+ if (js.flushing) return "accepted";
823
+ if (!js.scheduled) {
824
+ js.scheduled = true;
825
+ js.scheduledFlushes++;
826
+ this.requestFlush(js.totalLength > this.microThreshold ? "macro" : "micro");
827
+ }
828
+ return "accepted";
829
+ }
830
+ scheduleBatchJsSingle(tasks) {
831
+ const results = new Array(tasks.length);
832
+ for (let i = 0; i < tasks.length; i++) {
833
+ const task = tasks[i].fn;
834
+ results[i] = typeof task === "function" ? this.scheduleJsSingle(task) : "dropped";
835
+ }
836
+ return results;
837
+ }
827
838
  scheduleJs(task, tag) {
828
839
  const js = this.js;
829
840
  const lane = this.getOrCreateLane(inferLane(tag));
830
- const status = lane.queue.push({ task, tag });
841
+ const queuedBefore = lane.queue.length;
842
+ const status = lane.queue.push(task);
831
843
  lane.enqueuedTasks++;
832
844
  js.enqueuedTasks++;
833
845
  if ((status & 2) !== 0) {
@@ -840,6 +852,7 @@ var Scheduler = class {
840
852
  }
841
853
  return "dropped";
842
854
  }
855
+ lane.recordTag(tag, queuedBefore);
843
856
  js.totalLength++;
844
857
  if (js.flushing) return "accepted";
845
858
  if (!js.scheduled) {
@@ -855,6 +868,7 @@ var Scheduler = class {
855
868
  }
856
869
  flush() {
857
870
  if (this.wasm) return this.flushWasm();
871
+ if (this.jsSingle) return this.flushJsSingle();
858
872
  this.flushJs();
859
873
  }
860
874
  flushWasm() {
@@ -879,15 +893,47 @@ var Scheduler = class {
879
893
  else if (policy === 1) this.requestFlush("macro");
880
894
  }
881
895
  }
896
+ flushJsSingle() {
897
+ const js = this.jsSingle;
898
+ if (js.flushing) return;
899
+ js.flushing = true;
900
+ js.scheduled = false;
901
+ let ran = 0;
902
+ try {
903
+ while (ran < this.flushBudget) {
904
+ const task = js.queue.shift();
905
+ if (!task) break;
906
+ js.totalLength--;
907
+ ran++;
908
+ js.executedTasks++;
909
+ try {
910
+ task();
911
+ } catch (e) {
912
+ console.error("[Scheduler] task threw (laneMode=single)", e);
913
+ }
914
+ }
915
+ } finally {
916
+ js.flushing = false;
917
+ js.completedFlushes++;
918
+ if (js.totalLength > 0 && !js.scheduled) {
919
+ js.scheduled = true;
920
+ js.scheduledFlushes++;
921
+ const kind = ran >= this.flushBudget || js.totalLength > this.microThreshold ? "macro" : "micro";
922
+ if (ran >= this.flushBudget) js.yieldedByBudget++;
923
+ this.requestFlush(kind);
924
+ }
925
+ }
926
+ }
882
927
  shiftFromNextLane() {
883
928
  const js = this.js;
884
929
  const n = js.laneOrder.length;
885
930
  if (n === 0) return void 0;
886
931
  if (js.rrRemaining > 0) {
887
932
  const currentIdx = (js.rrIndex + n - 1) % n;
888
- const currentLane = js.lanes.get(js.laneOrder[currentIdx]);
889
- const next = currentLane?.queue.shift();
933
+ const currentLane = js.laneOrder[currentIdx];
934
+ const next = currentLane.queue.shift();
890
935
  if (next) {
936
+ this.shiftedTag = currentLane.shiftTag();
891
937
  js.rrRemaining--;
892
938
  currentLane.executedTasks++;
893
939
  js.totalLength--;
@@ -897,14 +943,15 @@ var Scheduler = class {
897
943
  }
898
944
  for (let scanned = 0; scanned < n; scanned++) {
899
945
  const idx = js.rrIndex % n;
900
- const key = js.laneOrder[idx];
946
+ const lane = js.laneOrder[idx];
901
947
  js.rrIndex = (idx + 1) % n;
902
- const lane = js.lanes.get(key);
903
- if (!lane || lane.queue.length === 0) continue;
948
+ if (lane.queue.length === 0) continue;
904
949
  js.rrRemaining = Math.max(0, this.laneBudget - 1);
905
950
  lane.executedTasks++;
906
951
  js.totalLength--;
907
- return lane.queue.shift();
952
+ const next = lane.queue.shift();
953
+ if (next) this.shiftedTag = lane.shiftTag();
954
+ return next;
908
955
  }
909
956
  return void 0;
910
957
  }
@@ -921,9 +968,9 @@ var Scheduler = class {
921
968
  ran++;
922
969
  js.executedTasks++;
923
970
  try {
924
- next.task();
971
+ next();
925
972
  } catch (e) {
926
- console.error(`[Scheduler] task threw (tag=${next.tag})`, e);
973
+ console.error(`[Scheduler] task threw (tag=${this.shiftedTag})`, e);
927
974
  }
928
975
  }
929
976
  } finally {
@@ -941,6 +988,27 @@ var Scheduler = class {
941
988
  };
942
989
  var globalScheduler = new Scheduler();
943
990
 
991
+ // src/core/runtime/contex.ts
992
+ var emptyContext = { parent: null, patch: /* @__PURE__ */ Object.create(null) };
993
+ function ctxExtend(parent, patch) {
994
+ return { parent, patch };
995
+ }
996
+ function ctxToObject(ctx) {
997
+ const out = /* @__PURE__ */ Object.create(null);
998
+ const seen = /* @__PURE__ */ new Set();
999
+ let cur = ctx;
1000
+ while (cur) {
1001
+ for (const k of Object.keys(cur.patch)) {
1002
+ if (!seen.has(k)) {
1003
+ out[k] = cur.patch[k];
1004
+ seen.add(k);
1005
+ }
1006
+ }
1007
+ cur = cur.parent;
1008
+ }
1009
+ return out;
1010
+ }
1011
+
944
1012
  // src/core/runtime/hostAction.ts
945
1013
  var DefaultHostExecutor = {
946
1014
  async execute(action) {
@@ -952,9 +1020,6 @@ var DefaultHostExecutor = {
952
1020
  }
953
1021
  };
954
1022
 
955
- // src/core/runtime/contex.ts
956
- var emptyContext = { parent: null, patch: /* @__PURE__ */ Object.create(null) };
957
-
958
1023
  // src/core/runtime/forkPolicy.ts
959
1024
  function makeForkPolicy(env, hooks) {
960
1025
  const svc = resolveForkServices(env);
@@ -964,7 +1029,8 @@ function makeForkPolicy(env, hooks) {
964
1029
  const trace = forkTrace(svc, parentCtx?.trace ?? null);
965
1030
  fiber.fiberContext = {
966
1031
  log: parentCtx?.log ?? emptyContext,
967
- trace
1032
+ trace,
1033
+ fiberRefs: parentCtx?.fiberRefs ? new Map(parentCtx.fiberRefs) : void 0
968
1034
  };
969
1035
  fiber.parentFiberId = parent?.id;
970
1036
  fiber.name = svc.childName(parent?.name);
@@ -978,7 +1044,16 @@ function makeForkPolicy(env, hooks) {
978
1044
  // ✅ ahora viaja
979
1045
  name: fiber.name
980
1046
  },
981
- { fiberId: parent?.id, traceId: parentCtx?.trace?.traceId, spanId: parentCtx?.trace?.spanId }
1047
+ {
1048
+ fiberId: fiber.id,
1049
+ scopeId: fiber.scopeId,
1050
+ traceId: trace?.traceId,
1051
+ spanId: trace?.spanId,
1052
+ parentSpanId: trace?.parentSpanId,
1053
+ traceState: trace?.traceState,
1054
+ baggage: trace?.baggage,
1055
+ sampled: trace?.sampled
1056
+ }
982
1057
  );
983
1058
  }
984
1059
  };
@@ -991,8 +1066,9 @@ function resolveForkServices(env) {
991
1066
  const brass = env?.brass;
992
1067
  const tracer = brass?.tracer ?? defaultTracer;
993
1068
  const seed = brass?.traceSeed;
1069
+ const baggage = brass?.baggage;
994
1070
  const childName = brass?.childName ?? ((p) => p ? `${p}/child` : void 0);
995
- return { tracer, seed, childName };
1071
+ return { tracer, seed, baggage, childName };
996
1072
  }
997
1073
  function randomRuntimeId(prefix) {
998
1074
  const cryptoLike = globalThis.crypto;
@@ -1007,11 +1083,22 @@ function forkTrace(svc, parentTrace) {
1007
1083
  traceId: parentTrace.traceId,
1008
1084
  spanId: svc.tracer.newSpanId(),
1009
1085
  parentSpanId: parentTrace.spanId,
1010
- sampled: parentTrace.sampled
1086
+ sampled: parentTrace.sampled,
1087
+ traceState: parentTrace.traceState,
1088
+ baggage: parentTrace.baggage
1011
1089
  };
1012
1090
  }
1013
- if (svc.seed) return { ...svc.seed };
1014
- return { traceId: svc.tracer.newTraceId(), spanId: svc.tracer.newSpanId(), sampled: true };
1091
+ if (svc.seed) {
1092
+ const baggage2 = svc.seed.baggage ?? svc.baggage;
1093
+ return baggage2 ? { ...svc.seed, baggage: baggage2 } : { ...svc.seed };
1094
+ }
1095
+ const baggage = svc.baggage;
1096
+ return {
1097
+ traceId: svc.tracer.newTraceId(),
1098
+ spanId: svc.tracer.newSpanId(),
1099
+ sampled: true,
1100
+ ...baggage ? { baggage } : {}
1101
+ };
1015
1102
  }
1016
1103
 
1017
1104
  // src/core/runtime/engine/opcodes.ts
@@ -1163,6 +1250,13 @@ var ProgramBuilder = class {
1163
1250
  };
1164
1251
  return this.add(current.scopeId === void 0 ? base : { ...base, scopeId: current.scopeId });
1165
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));
1166
1260
  case "HostAction": {
1167
1261
  const base = {
1168
1262
  tag: "HostAction",
@@ -1175,6 +1269,49 @@ var ProgramBuilder = class {
1175
1269
  }
1176
1270
  }
1177
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
+ }
1178
1315
 
1179
1316
  // src/core/runtime/engine/FiberHandleImpl.ts
1180
1317
  var EngineFiberHandle = class {
@@ -1209,7 +1346,7 @@ var EngineFiberHandle = class {
1209
1346
  queued = false;
1210
1347
  status() {
1211
1348
  if (this.result == null) return "Running";
1212
- 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";
1213
1350
  return "Done";
1214
1351
  }
1215
1352
  engineStatus() {
@@ -1282,8 +1419,8 @@ var EngineFiberHandle = class {
1282
1419
  if (this.result != null) return;
1283
1420
  this.runFinalizersOnce(exit);
1284
1421
  this.result = exit;
1285
- this.internalStatus = exit._tag === "Success" ? "done" : exit.cause._tag === "Interrupt" ? "interrupted" : "failed";
1286
- 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";
1287
1424
  this.emit({
1288
1425
  type: "fiber.end",
1289
1426
  fiberId: this.id,
@@ -1296,16 +1433,18 @@ var EngineFiberHandle = class {
1296
1433
  runFinalizersOnce(exit) {
1297
1434
  if (this.finalizersDrained) return;
1298
1435
  this.finalizersDrained = true;
1299
- while (this.finalizers.length > 0) {
1300
- const finalizer = this.finalizers.pop();
1301
- try {
1302
- const eff = finalizer(exit);
1303
- if (eff && typeof eff === "object" && "_tag" in eff) {
1304
- 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 {
1305
1445
  }
1306
- } catch {
1307
1446
  }
1308
- }
1447
+ });
1309
1448
  }
1310
1449
  };
1311
1450
 
@@ -1605,19 +1744,6 @@ var WasmPackFiberBridge = class {
1605
1744
  this.maxEventsPerCall = Math.max(this.maxEventsPerCall, events.length);
1606
1745
  return events;
1607
1746
  }
1608
- decodeBinary(words) {
1609
- this.binaryEventCalls += 1;
1610
- const events = decodeEventBatch(words);
1611
- this.eventsReceived += events.length;
1612
- this.maxEventsPerCall = Math.max(this.maxEventsPerCall, events.length);
1613
- return events;
1614
- }
1615
- decodeJson(json) {
1616
- this.jsonEventCalls += 1;
1617
- this.eventsReceived += 1;
1618
- this.maxEventsPerCall = Math.max(this.maxEventsPerCall, 1);
1619
- return JSON.parse(json);
1620
- }
1621
1747
  memory() {
1622
1748
  const memory = this.vm.memory?.();
1623
1749
  if (!memory?.buffer) throw new Error("brass-runtime WASM memory is not available");
@@ -1997,9 +2123,9 @@ function inferLane2(tag) {
1997
2123
  }
1998
2124
  function extractTaggedLane2(tag, prefix) {
1999
2125
  if (!tag.startsWith(prefix)) return void 0;
2000
- const end2 = tag.indexOf("|", prefix.length);
2001
- if (end2 < 0) return void 0;
2002
- const value = tag.slice(prefix.length, end2);
2126
+ const end = tag.indexOf("|", prefix.length);
2127
+ if (end < 0) return void 0;
2128
+ const value = tag.slice(prefix.length, end);
2003
2129
  return value.length > 0 ? value : void 0;
2004
2130
  }
2005
2131
  function firstSeparatorIndex2(value) {
@@ -2103,7 +2229,7 @@ var WasmFiberEngine = class {
2103
2229
  }
2104
2230
  this.kind = this.bridge.kind;
2105
2231
  this.fiberRegistry = new WasmFiberRegistryBridge();
2106
- this.readyQueue = makeFiberReadyQueue({ engine: "wasm" });
2232
+ this.readyQueue = makeFiberReadyQueue({ engine: "wasm", ...options.readyQueue });
2107
2233
  this.timerWheel = makeWasmTimerWheel({ onExpired: (events) => this.onTimerExpired(events) });
2108
2234
  }
2109
2235
  runtime;
@@ -2521,15 +2647,32 @@ var WasmFiberEngine = class {
2521
2647
  return;
2522
2648
  }
2523
2649
  const cause = exit.cause;
2524
- if (cause._tag === "Interrupt") {
2650
+ if (Cause.isInterruptedOnly(cause)) {
2525
2651
  this.interruptState(state, cause);
2526
2652
  return;
2527
2653
  }
2528
- if (cause._tag === "Fail") {
2529
- this.resumeWithError(state, cause.error);
2530
- 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
+ }
2531
2660
  }
2532
- this.completeDie(state, cause.defect);
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;
2673
+ }
2674
+ this.cleanupState(state);
2675
+ state.handle.complete(Exit.failCause(cause));
2533
2676
  }
2534
2677
  resumeWithValue(state, value) {
2535
2678
  this.pendingResumes.set(state.fiberId, { kind: "value", ref: state.registry.register(value) });
@@ -2654,6 +2797,21 @@ function hasBinaryVmAbi(mod) {
2654
2797
  }
2655
2798
  }
2656
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
+
2657
2815
  // src/core/runtime/runtime.ts
2658
2816
  var NoopHooks = {
2659
2817
  emit() {
@@ -2666,6 +2824,12 @@ function normalizeRuntimeEngineMode(value) {
2666
2824
  function unreachableEngine(value) {
2667
2825
  throw new Error(`brass-runtime unsupported engine '${String(value)}'`);
2668
2826
  }
2827
+ var runtimeOptionsSchema = Schema.object({
2828
+ env: Schema.any(),
2829
+ lane: Schema.string({ minLength: 1 }).optional(),
2830
+ inferLane: Schema.boolean().optional(),
2831
+ engine: Schema.enum(["ts", "wasm"]).optional()
2832
+ }, { unknownKeys: "passthrough" });
2669
2833
  var Runtime = class _Runtime {
2670
2834
  env;
2671
2835
  scheduler;
@@ -2681,6 +2845,7 @@ var Runtime = class _Runtime {
2681
2845
  // opcional: registry para observabilidad
2682
2846
  registry;
2683
2847
  constructor(args) {
2848
+ parseConfig("RuntimeOptions", runtimeOptionsSchema, args);
2684
2849
  this.env = args.env;
2685
2850
  this.scheduler = args.scheduler ?? globalScheduler;
2686
2851
  this.lane = args.lane;
@@ -2746,7 +2911,11 @@ var Runtime = class _Runtime {
2746
2911
  scopeId: f?.scopeId,
2747
2912
  // ✅ FIX: era f?.scope
2748
2913
  traceId: f?.fiberContext?.trace?.traceId,
2749
- spanId: f?.fiberContext?.trace?.spanId
2914
+ spanId: f?.fiberContext?.trace?.spanId,
2915
+ parentSpanId: f?.fiberContext?.trace?.parentSpanId,
2916
+ traceState: f?.fiberContext?.trace?.traceState,
2917
+ baggage: f?.fiberContext?.trace?.baggage,
2918
+ sampled: f?.fiberContext?.trace?.sampled
2750
2919
  };
2751
2920
  this.hooks.emit(ev, ctx);
2752
2921
  }
@@ -2774,23 +2943,46 @@ var Runtime = class _Runtime {
2774
2943
  return this.fiberEngine.shutdown?.();
2775
2944
  }
2776
2945
  unsafeRunAsync(effect, cb) {
2946
+ if (this.tryRunNativeTopLevel(effect, cb)) return;
2777
2947
  const fiber = this.fork(effect);
2778
2948
  fiber.join(cb);
2779
2949
  }
2780
2950
  toPromise(effect) {
2781
2951
  return new Promise((resolve, reject) => {
2782
- const fiber = this.fork(effect);
2783
- fiber.join((exit) => {
2784
- 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);
2785
2959
  else {
2786
- const c = exit.cause;
2787
- if (c?._tag === "Fail") reject(c.error);
2788
- else if (c?._tag === "Die") reject(c.defect instanceof Error ? c.defect : new Error(String(c.defect)));
2789
- 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
+ }
2790
2968
  }
2969
+ };
2970
+ if (this.tryRunNativeTopLevel(effect, complete)) return;
2971
+ const fiber = this.fork(effect);
2972
+ fiber.join((exit) => {
2973
+ complete(exit);
2791
2974
  });
2792
2975
  });
2793
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
+ }
2794
2986
  // helper: correr un efecto y “tirar” el resultado
2795
2987
  unsafeRun(effect) {
2796
2988
  this.unsafeRunAsync(effect, () => {
@@ -2798,10 +2990,11 @@ var Runtime = class _Runtime {
2798
2990
  }
2799
2991
  delay(ms, eff) {
2800
2992
  return asyncEffect((_env, cb) => {
2801
- const handle = setTimeout(() => {
2993
+ const clock = runtimeClockFromEnv(this.env);
2994
+ const handle = clock.setTimeout(() => {
2802
2995
  this.unsafeRunAsync(eff, cb);
2803
2996
  }, ms);
2804
- return () => clearTimeout(handle);
2997
+ return () => clock.clearTimeout(handle);
2805
2998
  });
2806
2999
  }
2807
3000
  // util para crear runtime default
@@ -2816,6 +3009,243 @@ var Runtime = class _Runtime {
2816
3009
  this.emit({ type: "log", level, message, fields });
2817
3010
  }
2818
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
+ };
2819
3249
  function fork(effect, env) {
2820
3250
  return Runtime.make(env ?? {}).fork(effect);
2821
3251
  }
@@ -3042,6 +3472,7 @@ var RuntimeFiber = class {
3042
3472
  stack = [];
3043
3473
  fiberFinalizers = [];
3044
3474
  finalizersDrained = false;
3475
+ interruptibilityDepth = 0;
3045
3476
  fiberContext;
3046
3477
  name;
3047
3478
  scopeId;
@@ -3080,14 +3511,8 @@ var RuntimeFiber = class {
3080
3511
  this.schedule("async-resume");
3081
3512
  return;
3082
3513
  }
3083
- const cause = exit.cause;
3084
- if (cause._tag === "Interrupt") {
3085
- this.notify(Exit.failCause(Cause.interrupt()));
3086
- } else if (cause._tag === "Fail") {
3087
- this.current = Async.fail(cause.error);
3514
+ if (this.onCause(exit.cause)) {
3088
3515
  this.schedule("async-resume");
3089
- } else {
3090
- this.notify(Exit.failCause(Cause.die(cause.defect)));
3091
3516
  }
3092
3517
  };
3093
3518
  this.boundStep = () => {
@@ -3122,7 +3547,11 @@ var RuntimeFiber = class {
3122
3547
  fiberId: this.id,
3123
3548
  scopeId: this.scopeId,
3124
3549
  traceId: this.fiberContext?.trace?.traceId,
3125
- spanId: this.fiberContext?.trace?.spanId
3550
+ spanId: this.fiberContext?.trace?.spanId,
3551
+ parentSpanId: this.fiberContext?.trace?.parentSpanId,
3552
+ traceState: this.fiberContext?.trace?.traceState,
3553
+ baggage: this.fiberContext?.trace?.baggage,
3554
+ sampled: this.fiberContext?.trace?.sampled
3126
3555
  });
3127
3556
  }
3128
3557
  addFinalizer(f) {
@@ -3142,7 +3571,7 @@ var RuntimeFiber = class {
3142
3571
  }
3143
3572
  status() {
3144
3573
  if (this.result == null) return "Running";
3145
- 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";
3146
3575
  return "Done";
3147
3576
  }
3148
3577
  join(cb) {
@@ -3153,7 +3582,9 @@ var RuntimeFiber = class {
3153
3582
  if (this.result != null) return;
3154
3583
  if (this.interrupted) return;
3155
3584
  this.interrupted = true;
3156
- this.schedule("interrupt-step");
3585
+ if (this.isInterruptible()) {
3586
+ this.schedule("interrupt-step");
3587
+ }
3157
3588
  }
3158
3589
  schedule(tag = "step") {
3159
3590
  if (this.runState === RUN.DONE || this.runState === RUN.QUEUED) return;
@@ -3196,7 +3627,7 @@ var RuntimeFiber = class {
3196
3627
  this.closing = exit;
3197
3628
  this.runFinalizersOnce(exit);
3198
3629
  this.result = exit;
3199
- 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";
3200
3631
  this.emit({
3201
3632
  type: "fiber.end",
3202
3633
  fiberId: this.id,
@@ -3206,46 +3637,109 @@ var RuntimeFiber = class {
3206
3637
  for (const j of this.joiners) j(exit);
3207
3638
  this.joiners.length = 0;
3208
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
+ }
3209
3664
  onSuccess(value) {
3210
- const frame = this.stack.pop();
3211
- if (!frame) {
3212
- this.notify(Exit.succeed(value));
3213
- return;
3214
- }
3215
- 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
+ }
3216
3696
  try {
3217
- this.current = frame.k(value);
3697
+ this.current = frame.onSuccess(currentValue);
3218
3698
  } catch (e) {
3219
3699
  this.notify(Exit.failCause(Cause.die(e)));
3220
3700
  }
3221
3701
  return;
3222
3702
  }
3223
- try {
3224
- this.current = frame.onSuccess(value);
3225
- } catch (e) {
3226
- this.notify(Exit.failCause(Cause.die(e)));
3227
- }
3228
3703
  }
3229
3704
  onFailure(error) {
3705
+ this.onCause(Cause.fail(error));
3706
+ }
3707
+ onCause(cause) {
3708
+ let currentCause = cause;
3230
3709
  while (this.stack.length > 0) {
3231
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
+ }
3232
3722
  if (fr._tag === "FoldCont") {
3723
+ if (!Cause.isFailureOnly(currentCause)) continue;
3724
+ const failure = Cause.firstFailure(currentCause);
3725
+ if (failure._tag === "None") break;
3233
3726
  try {
3234
- this.current = fr.onFailure(error);
3235
- return;
3727
+ this.current = fr.onFailure(failure.value);
3728
+ return true;
3236
3729
  } catch (e) {
3237
- error = e;
3730
+ currentCause = Cause.fail(e);
3238
3731
  continue;
3239
3732
  }
3240
3733
  }
3241
3734
  }
3242
- this.notify(Exit.failCause(Cause.fail(error)));
3735
+ this.notify(Exit.failCause(currentCause));
3736
+ return false;
3243
3737
  }
3244
3738
  budget = DEFAULT_BUDGET2;
3245
3739
  step() {
3246
3740
  if (this.result != null) return STEP.DONE;
3247
- if (this.interrupted) {
3248
- this.notify(Exit.failCause(Cause.interrupt()));
3741
+ if (this.shouldInterruptNow()) {
3742
+ this.onCause(Cause.interrupt());
3249
3743
  return STEP.DONE;
3250
3744
  }
3251
3745
  this.budget = __benchmarkBudget ?? DEFAULT_BUDGET2;
@@ -3300,14 +3794,7 @@ var RuntimeFiber = class {
3300
3794
  if (resolvedExit._tag === "Success") {
3301
3795
  this.onSuccess(resolvedExit.value);
3302
3796
  } else {
3303
- const cause = resolvedExit.cause;
3304
- if (cause._tag === "Interrupt") {
3305
- this.notify(Exit.failCause(Cause.interrupt()));
3306
- } else if (cause._tag === "Fail") {
3307
- this.onFailure(cause.error);
3308
- } else {
3309
- this.notify(Exit.failCause(Cause.die(cause.defect)));
3310
- }
3797
+ this.onCause(resolvedExit.cause);
3311
3798
  }
3312
3799
  break;
3313
3800
  }
@@ -3329,6 +3816,47 @@ var RuntimeFiber = class {
3329
3816
  this.onSuccess(child);
3330
3817
  break;
3331
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
+ }
3332
3860
  case "Sync": {
3333
3861
  try {
3334
3862
  const a = current.thunk(this.env);
@@ -3420,14 +3948,7 @@ var RuntimeFiber = class {
3420
3948
  continue;
3421
3949
  } else {
3422
3950
  this.stack.push({ _tag: "SuccessCont", k: andThen });
3423
- const cause = exit.cause;
3424
- if (cause._tag === "Fail") {
3425
- this.onFailure(cause.error);
3426
- } else if (cause._tag === "Interrupt") {
3427
- this.notify(Exit.failCause(Cause.interrupt()));
3428
- } else {
3429
- this.notify(Exit.failCause(Cause.die(cause.defect)));
3430
- }
3951
+ this.onCause(exit.cause);
3431
3952
  return this.result != null ? TRAMPOLINE.DONE : TRAMPOLINE.CONTINUE;
3432
3953
  }
3433
3954
  }
@@ -3514,214 +4035,7 @@ var JsFiberEngine = class {
3514
4035
  }
3515
4036
  };
3516
4037
 
3517
- // src/core/runtime/scope.ts
3518
- var nextScopeId = 1;
3519
- function awaitAll(fibers) {
3520
- return asyncEffect((_env, cb) => {
3521
- let remaining = fibers.length;
3522
- if (remaining === 0) {
3523
- cb({ _tag: "Success", value: void 0 });
3524
- return;
3525
- }
3526
- for (const f of fibers) {
3527
- f.join(() => {
3528
- remaining -= 1;
3529
- if (remaining === 0) cb({ _tag: "Success", value: void 0 });
3530
- });
3531
- }
3532
- });
3533
- }
3534
- var Scope = class _Scope {
3535
- constructor(runtime, parentScopeId) {
3536
- this.runtime = runtime;
3537
- this.parentScopeId = parentScopeId;
3538
- this.id = nextScopeId++;
3539
- const inferredParent = this.parentScopeId ?? getCurrentFiber()?.scopeId;
3540
- if (this.runtime.hasActiveHooks()) {
3541
- this.runtime.emit({
3542
- type: "scope.open",
3543
- scopeId: this.id,
3544
- parentScopeId: inferredParent
3545
- });
3546
- }
3547
- }
3548
- runtime;
3549
- parentScopeId;
3550
- id;
3551
- closed = false;
3552
- children = /* @__PURE__ */ new Set();
3553
- subScopes = /* @__PURE__ */ new Set();
3554
- finalizers = [];
3555
- /** registra un finalizer (LIFO) */
3556
- addFinalizer(f) {
3557
- if (this.closed) {
3558
- throw new Error("Trying to add finalizer to closed scope");
3559
- }
3560
- this.finalizers.push(f);
3561
- }
3562
- /** crea un sub scope (mismo runtime) */
3563
- subScope() {
3564
- if (this.closed) throw new Error("Scope closed");
3565
- const s = new _Scope(this.runtime, this.id);
3566
- this.subScopes.add(s);
3567
- return s;
3568
- }
3569
- /** ✅ fork en este scope */
3570
- fork(eff) {
3571
- if (this.closed) throw new Error("Scope closed");
3572
- const f = this.runtime.fork(eff, this.id);
3573
- this.children.add(f);
3574
- f.join(() => this.children.delete(f));
3575
- return f;
3576
- }
3577
- /** close fire-and-forget (no bloquea) */
3578
- close(exit = { _tag: "Success", value: void 0 }) {
3579
- this.runtime.fork(this.closeAsync(exit));
3580
- }
3581
- /** Emit the scope.close event if hooks are active. */
3582
- emitCloseEvent(exit) {
3583
- if (this.runtime.hasActiveHooks()) {
3584
- const status = exit._tag === "Success" ? "success" : exit.cause._tag === "Interrupt" ? "interrupted" : "failure";
3585
- this.runtime.emit({
3586
- type: "scope.close",
3587
- scopeId: this.id,
3588
- status,
3589
- error: exit._tag === "Failure" && exit.cause._tag === "Fail" ? exit.cause.error : void 0
3590
- });
3591
- }
3592
- }
3593
- /**
3594
- * Build an effect that executes finalizers in LIFO order.
3595
- *
3596
- * Optimization over the original: instead of wrapping every finalizer in
3597
- * `asyncFold(fin(exit), () => unit(), () => unit())` which creates 3 effect
3598
- * nodes per finalizer (Fold + 2 Succeed), we use a single Sync thunk per
3599
- * finalizer that catches errors inline. When the finalizer returns a
3600
- * Succeed effect (like `unit()`), the Sync thunk completes without creating
3601
- * additional effect nodes.
3602
- */
3603
- buildFinalizerEffect(exit) {
3604
- const fins = this.finalizers;
3605
- if (fins.length === 0) return unit();
3606
- let chain = unit();
3607
- for (let i = fins.length - 1; i >= 0; i--) {
3608
- const fin = fins[i];
3609
- chain = asyncFlatMap(chain, () => {
3610
- let result;
3611
- try {
3612
- result = fin(exit);
3613
- } catch {
3614
- return unit();
3615
- }
3616
- if (result._tag === "Succeed") {
3617
- return unit();
3618
- }
3619
- return asyncFold(
3620
- result,
3621
- () => unit(),
3622
- () => unit()
3623
- );
3624
- });
3625
- }
3626
- return chain;
3627
- }
3628
- closeAsync(exit = { _tag: "Success", value: void 0 }, opts = { awaitChildren: true }) {
3629
- return asyncFlatMap(
3630
- unit(),
3631
- () => asyncEffect((env, cb) => {
3632
- if (this.closed) {
3633
- cb({ _tag: "Success", value: void 0 });
3634
- return;
3635
- }
3636
- this.closed = true;
3637
- const children = Array.from(this.children);
3638
- const subScopes = Array.from(this.subScopes);
3639
- for (const child of children) {
3640
- child.interrupt();
3641
- }
3642
- const closeSubs = subScopes.reduceRight(
3643
- (acc, s) => asyncFlatMap(acc, () => s.closeAsync(exit, opts)),
3644
- unit()
3645
- );
3646
- const runFinalizers = this.buildFinalizerEffect(exit);
3647
- const needsAwait = opts.awaitChildren && children.length > 0;
3648
- const awaitChildrenEff = needsAwait ? awaitAll(children) : unit();
3649
- const hasSubScopes = subScopes.length > 0;
3650
- const hasNoFinalizers = this.finalizers.length === 0;
3651
- if (!hasSubScopes && !needsAwait && hasNoFinalizers) {
3652
- this.emitCloseEvent(exit);
3653
- cb({ _tag: "Success", value: void 0 });
3654
- return;
3655
- }
3656
- const all = asyncFlatMap(closeSubs, () => asyncFlatMap(awaitChildrenEff, () => runFinalizers));
3657
- this.runtime.fork(all).join(() => {
3658
- this.emitCloseEvent(exit);
3659
- cb({ _tag: "Success", value: void 0 });
3660
- });
3661
- })
3662
- );
3663
- }
3664
- };
3665
- function withScopeAsync(runtime, f) {
3666
- return asyncEffect((_env, cb) => {
3667
- const scope = new Scope(runtime);
3668
- let done = false;
3669
- const completeAfterClose = (exit) => {
3670
- runtime.fork(scope.closeAsync(exit)).join(() => {
3671
- if (done) return;
3672
- done = true;
3673
- cb(exit);
3674
- });
3675
- };
3676
- const fiber = runtime.fork(f(scope));
3677
- fiber.join(completeAfterClose);
3678
- return () => {
3679
- if (done) return;
3680
- fiber.interrupt();
3681
- runtime.fork(scope.closeAsync(Exit.failCause(Cause.interrupt())));
3682
- };
3683
- });
3684
- }
3685
- function withScope(runtime, f) {
3686
- return withScopeAsync(runtime, (scope) => {
3687
- const out = f(scope);
3688
- if (out && typeof out === "object" && "_tag" in out) return out;
3689
- return unit();
3690
- });
3691
- }
3692
-
3693
4038
  export {
3694
- __require,
3695
- Async,
3696
- asyncFold,
3697
- asyncCatchAll,
3698
- asyncMapError,
3699
- unit,
3700
- asyncSucceed,
3701
- asyncFail,
3702
- asyncSync,
3703
- asyncTotal,
3704
- asyncEffect,
3705
- asyncMap,
3706
- asyncFlatMap,
3707
- acquireRelease,
3708
- asyncInterruptible,
3709
- withAsyncPromise,
3710
- mapAsync,
3711
- mapTryAsync,
3712
- none,
3713
- some,
3714
- Cause,
3715
- Exit,
3716
- succeed,
3717
- fail,
3718
- sync,
3719
- map,
3720
- flatMap,
3721
- mapError,
3722
- catchAll,
3723
- orElseOptional,
3724
- end,
3725
4039
  PushStatus,
3726
4040
  RingBuffer,
3727
4041
  resolveWasmModule,
@@ -3731,6 +4045,9 @@ export {
3731
4045
  inferCallerLaneFromStack,
3732
4046
  Scheduler,
3733
4047
  globalScheduler,
4048
+ emptyContext,
4049
+ ctxExtend,
4050
+ ctxToObject,
3734
4051
  DefaultHostExecutor,
3735
4052
  JsFiberEngine,
3736
4053
  HostRegistry,
@@ -3750,6 +4067,8 @@ export {
3750
4067
  makeFiberReadyQueue,
3751
4068
  WasmFiberEngine,
3752
4069
  runtimeCapabilities,
4070
+ liveClock,
4071
+ runtimeClockFromEnv,
3753
4072
  NoopHooks,
3754
4073
  Runtime,
3755
4074
  fork,
@@ -3766,8 +4085,5 @@ export {
3766
4085
  RuntimeFiber,
3767
4086
  getCurrentFiber,
3768
4087
  unsafeGetCurrentRuntime,
3769
- withCurrentFiber,
3770
- Scope,
3771
- withScopeAsync,
3772
- withScope
4088
+ withCurrentFiber
3773
4089
  };