brass-runtime 1.14.0 → 1.15.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 (44) hide show
  1. package/README.md +6 -3
  2. package/dist/agent/cli/main.cjs +44 -43
  3. package/dist/agent/cli/main.js +5 -4
  4. package/dist/agent/cli/main.mjs +5 -4
  5. package/dist/agent/index.cjs +4 -3
  6. package/dist/agent/index.d.ts +1 -1
  7. package/dist/agent/index.js +3 -2
  8. package/dist/agent/index.mjs +3 -2
  9. package/dist/{chunk-WJESVBWN.js → chunk-3QMOKAS5.js} +9 -7
  10. package/dist/{chunk-BMRF4FN6.js → chunk-4NHES7VK.mjs} +59 -237
  11. package/dist/chunk-AR22SXML.js +1043 -0
  12. package/dist/{chunk-4N2JEK4H.mjs → chunk-BDF4AMWX.mjs} +27 -151
  13. package/dist/chunk-BDYEENHT.js +224 -0
  14. package/dist/{chunk-JT7D6M5H.js → chunk-BMH5AV44.js} +27 -151
  15. package/dist/chunk-ELOOF35R.mjs +131 -0
  16. package/dist/chunk-JFPU5GQI.mjs +1043 -0
  17. package/dist/{chunk-MQF7HZ7Y.mjs → chunk-K6M7MDZ4.mjs} +9 -7
  18. package/dist/chunk-MS34J5LY.cjs +224 -0
  19. package/dist/{chunk-UWMMYKVK.mjs → chunk-PPUXIH5R.js} +59 -237
  20. package/dist/chunk-R3R2FVLG.cjs +131 -0
  21. package/dist/chunk-STVLQ3XD.cjs +489 -0
  22. package/dist/{chunk-BKBFSOGT.cjs → chunk-TGIFUAK4.cjs} +26 -150
  23. package/dist/chunk-TO7IKXYT.js +131 -0
  24. package/dist/chunk-UMAZLXAB.mjs +224 -0
  25. package/dist/{chunk-XTMZTVIT.cjs → chunk-VEZNF5GZ.cjs} +136 -134
  26. package/dist/chunk-XPZNXSVN.cjs +1043 -0
  27. package/dist/core/index.cjs +216 -0
  28. package/dist/core/index.d.ts +673 -0
  29. package/dist/core/index.js +216 -0
  30. package/dist/core/index.mjs +216 -0
  31. package/dist/{effect-DM56H743.d.ts → effect-CMOQKX8y.d.ts} +12 -11
  32. package/dist/http/index.cjs +2557 -235
  33. package/dist/http/index.d.ts +1514 -4
  34. package/dist/http/index.js +2549 -227
  35. package/dist/http/index.mjs +2549 -227
  36. package/dist/index.cjs +237 -1168
  37. package/dist/index.d.ts +7 -673
  38. package/dist/index.js +77 -1008
  39. package/dist/index.mjs +77 -1008
  40. package/dist/stream-FQm9h4Mg.d.ts +74 -0
  41. package/dist/tracing-DNT9jEbr.d.ts +106 -0
  42. package/package.json +11 -3
  43. package/dist/chunk-SKVY72E5.cjs +0 -667
  44. package/dist/stream-Oqe6WeLE.d.ts +0 -173
@@ -1,7 +1,10 @@
1
+ import {
2
+ race
3
+ } from "./chunk-ELOOF35R.mjs";
1
4
  import {
2
5
  Cause,
3
6
  Exit,
4
- async,
7
+ asyncEffect,
5
8
  asyncFail,
6
9
  asyncFlatMap,
7
10
  asyncFold,
@@ -9,9 +12,8 @@ import {
9
12
  asyncSucceed,
10
13
  asyncSync,
11
14
  fromPromiseAbortable,
12
- race,
13
15
  withScopeAsync
14
- } from "./chunk-4N2JEK4H.mjs";
16
+ } from "./chunk-BDF4AMWX.mjs";
15
17
 
16
18
  // src/agent/core/state.ts
17
19
  var initialAgentState = (goal) => ({
@@ -1425,10 +1427,10 @@ var decideNextAction = (state) => {
1425
1427
  };
1426
1428
 
1427
1429
  // src/agent/core/events.ts
1428
- var nowMillis = () => async((_env, cb) => {
1430
+ var nowMillis = () => asyncEffect((_env, cb) => {
1429
1431
  cb({ _tag: "Success", value: Date.now() });
1430
1432
  });
1431
- var emitAgentEvent = (event) => async((env, cb) => {
1433
+ var emitAgentEvent = (event) => asyncEffect((env, cb) => {
1432
1434
  try {
1433
1435
  env.events?.emit(event);
1434
1436
  } catch {
@@ -1684,7 +1686,7 @@ var retry = (make, options) => {
1684
1686
  };
1685
1687
 
1686
1688
  // src/agent/tools/timeout.ts
1687
- var sleep = (ms) => async((_env, cb) => {
1689
+ var sleep = (ms) => asyncEffect((_env, cb) => {
1688
1690
  const id = setTimeout(() => cb({ _tag: "Success", value: void 0 }), ms);
1689
1691
  return () => clearTimeout(id);
1690
1692
  });
@@ -2124,7 +2126,7 @@ var chunkToString = (chunk) => {
2124
2126
  return typeof maybeToString === "function" ? maybeToString.call(chunk, "utf8") : String(chunk);
2125
2127
  };
2126
2128
  var NodeShell = {
2127
- exec: (command, options) => async((_env, cb) => {
2129
+ exec: (command, options) => asyncEffect((_env, cb) => {
2128
2130
  const [bin, ...args] = command;
2129
2131
  if (!bin) {
2130
2132
  cb(
@@ -0,0 +1,224 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+
8
+ var _chunkTGIFUAK4cjs = require('./chunk-TGIFUAK4.cjs');
9
+
10
+ // src/core/runtime/combinators.ts
11
+ function sleep(ms) {
12
+ return _chunkTGIFUAK4cjs.asyncEffect.call(void 0, (_env, cb) => {
13
+ const delay = Math.max(0, Math.floor(ms));
14
+ const id = setTimeout(() => cb({ _tag: "Success", value: void 0 }), delay);
15
+ return () => clearTimeout(id);
16
+ });
17
+ }
18
+ function timeout(effect, ms) {
19
+ return _chunkTGIFUAK4cjs.asyncEffect.call(void 0, (env, cb) => {
20
+ let done = false;
21
+ let timerId;
22
+ let effectRunning = true;
23
+ timerId = setTimeout(() => {
24
+ if (done) return;
25
+ done = true;
26
+ effectRunning = false;
27
+ cb({
28
+ _tag: "Failure",
29
+ cause: { _tag: "Fail", error: { _tag: "TimeoutError", ms } }
30
+ });
31
+ }, Math.max(0, Math.floor(ms)));
32
+ const runtime = _chunkTGIFUAK4cjs.unsafeGetCurrentRuntime.call(void 0, );
33
+ if (runtime) {
34
+ const fiber = runtime.fork(effect);
35
+ fiber.join((exit) => {
36
+ if (done) return;
37
+ done = true;
38
+ clearTimeout(timerId);
39
+ cb(exit);
40
+ });
41
+ return () => {
42
+ if (done) return;
43
+ done = true;
44
+ clearTimeout(timerId);
45
+ fiber.interrupt();
46
+ };
47
+ }
48
+ return () => {
49
+ if (done) return;
50
+ done = true;
51
+ clearTimeout(timerId);
52
+ };
53
+ });
54
+ }
55
+ function retry(effect, policy) {
56
+ const shouldRetry = _nullishCoalesce(policy.shouldRetry, () => ( (() => true)));
57
+ const jitter = _nullishCoalesce(policy.jitter, () => ( "full"));
58
+ const maxElapsedMs = policy.maxElapsedMs;
59
+ const computeDelay = (attempt) => {
60
+ const exp = policy.baseDelayMs * Math.pow(2, attempt);
61
+ const capped = Math.min(exp, policy.maxDelayMs);
62
+ if (jitter === "none") return capped;
63
+ return Math.floor(Math.random() * capped);
64
+ };
65
+ const loop = (attempt, startedAt) => _chunkTGIFUAK4cjs.asyncFold.call(void 0,
66
+ effect,
67
+ (error) => {
68
+ if (attempt >= policy.maxRetries) return _chunkTGIFUAK4cjs.asyncFail.call(void 0, error);
69
+ if (!shouldRetry(error, attempt)) return _chunkTGIFUAK4cjs.asyncFail.call(void 0, error);
70
+ if (maxElapsedMs !== void 0) {
71
+ const elapsed = performance.now() - startedAt;
72
+ if (elapsed >= maxElapsedMs) return _chunkTGIFUAK4cjs.asyncFail.call(void 0, error);
73
+ }
74
+ const delay = computeDelay(attempt);
75
+ return _chunkTGIFUAK4cjs.asyncFlatMap.call(void 0, sleep(delay), () => loop(attempt + 1, startedAt));
76
+ },
77
+ (value) => _chunkTGIFUAK4cjs.asyncSucceed.call(void 0, value)
78
+ );
79
+ return _chunkTGIFUAK4cjs.asyncFlatMap.call(void 0,
80
+ { _tag: "Sync", thunk: () => performance.now() },
81
+ (startedAt) => loop(0, startedAt)
82
+ );
83
+ }
84
+ function retryN(effect, n) {
85
+ return retry(effect, {
86
+ maxRetries: n,
87
+ baseDelayMs: 0,
88
+ maxDelayMs: 0,
89
+ jitter: "none"
90
+ });
91
+ }
92
+ function retryWithBackoff(effect, opts = {}) {
93
+ return retry(effect, {
94
+ maxRetries: _nullishCoalesce(opts.maxRetries, () => ( 3)),
95
+ baseDelayMs: _nullishCoalesce(opts.baseDelayMs, () => ( 100)),
96
+ maxDelayMs: _nullishCoalesce(opts.maxDelayMs, () => ( 1e4)),
97
+ maxElapsedMs: opts.maxElapsedMs,
98
+ shouldRetry: opts.shouldRetry,
99
+ jitter: "full"
100
+ });
101
+ }
102
+
103
+ // src/core/runtime/circuitBreaker.ts
104
+ function makeCircuitBreaker(config = {}) {
105
+ const failureThreshold = _nullishCoalesce(config.failureThreshold, () => ( 5));
106
+ const resetTimeoutMs = _nullishCoalesce(config.resetTimeoutMs, () => ( 3e4));
107
+ const successThreshold = _nullishCoalesce(config.successThreshold, () => ( 1));
108
+ const isFailure = _nullishCoalesce(config.isFailure, () => ( (() => true)));
109
+ const onStateChange = config.onStateChange;
110
+ let currentState = "closed";
111
+ let consecutiveFailures = 0;
112
+ let consecutiveSuccesses = 0;
113
+ let openedAt = 0;
114
+ let totalRequests = 0;
115
+ let totalFailures = 0;
116
+ let totalSuccesses = 0;
117
+ let totalRejected = 0;
118
+ let lastFailureTime = null;
119
+ let lastSuccessTime = null;
120
+ const transition = (to) => {
121
+ if (currentState === to) return;
122
+ const from = currentState;
123
+ currentState = to;
124
+ _optionalChain([onStateChange, 'optionalCall', _ => _(from, to)]);
125
+ };
126
+ const onSuccess = () => {
127
+ totalSuccesses++;
128
+ lastSuccessTime = Date.now();
129
+ consecutiveFailures = 0;
130
+ if (currentState === "half-open") {
131
+ consecutiveSuccesses++;
132
+ if (consecutiveSuccesses >= successThreshold) {
133
+ consecutiveSuccesses = 0;
134
+ transition("closed");
135
+ }
136
+ }
137
+ };
138
+ const onFailure = (error) => {
139
+ if (!isFailure(error)) {
140
+ onSuccess();
141
+ return;
142
+ }
143
+ totalFailures++;
144
+ lastFailureTime = Date.now();
145
+ consecutiveSuccesses = 0;
146
+ consecutiveFailures++;
147
+ if (currentState === "half-open") {
148
+ openedAt = Date.now();
149
+ transition("open");
150
+ } else if (currentState === "closed" && consecutiveFailures >= failureThreshold) {
151
+ openedAt = Date.now();
152
+ transition("open");
153
+ }
154
+ };
155
+ const shouldAllow = () => {
156
+ switch (currentState) {
157
+ case "closed":
158
+ return true;
159
+ case "open": {
160
+ const elapsed = Date.now() - openedAt;
161
+ if (elapsed >= resetTimeoutMs) {
162
+ transition("half-open");
163
+ return true;
164
+ }
165
+ return false;
166
+ }
167
+ case "half-open":
168
+ return true;
169
+ }
170
+ };
171
+ const protect = (effect) => {
172
+ totalRequests++;
173
+ if (!shouldAllow()) {
174
+ totalRejected++;
175
+ return _chunkTGIFUAK4cjs.asyncFail.call(void 0, {
176
+ _tag: "CircuitBreakerOpen",
177
+ openSince: openedAt,
178
+ failures: consecutiveFailures
179
+ });
180
+ }
181
+ return _chunkTGIFUAK4cjs.asyncFold.call(void 0,
182
+ effect,
183
+ (error) => {
184
+ onFailure(error);
185
+ return _chunkTGIFUAK4cjs.asyncFail.call(void 0, error);
186
+ },
187
+ (value) => {
188
+ onSuccess();
189
+ return _chunkTGIFUAK4cjs.asyncSucceed.call(void 0, value);
190
+ }
191
+ );
192
+ };
193
+ const stats = () => ({
194
+ state: currentState,
195
+ failures: consecutiveFailures,
196
+ successes: consecutiveSuccesses,
197
+ totalRequests,
198
+ totalFailures,
199
+ totalSuccesses,
200
+ totalRejected,
201
+ lastFailureTime,
202
+ lastSuccessTime
203
+ });
204
+ const reset = () => {
205
+ consecutiveFailures = 0;
206
+ consecutiveSuccesses = 0;
207
+ transition("closed");
208
+ };
209
+ return {
210
+ state: () => currentState,
211
+ protect,
212
+ stats,
213
+ reset
214
+ };
215
+ }
216
+
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+ exports.sleep = sleep; exports.timeout = timeout; exports.retry = retry; exports.retryN = retryN; exports.retryWithBackoff = retryWithBackoff; exports.makeCircuitBreaker = makeCircuitBreaker;
@@ -1,8 +1,11 @@
1
+ import {
2
+ raceWith
3
+ } from "./chunk-TO7IKXYT.js";
1
4
  import {
2
5
  Cause,
3
6
  Exit,
4
7
  Scope,
5
- async,
8
+ asyncEffect,
6
9
  asyncFail,
7
10
  asyncFlatMap,
8
11
  asyncFold,
@@ -16,220 +19,12 @@ import {
16
19
  mapError,
17
20
  none,
18
21
  orElseOptional,
19
- raceWith,
20
22
  some,
21
23
  succeed,
22
24
  sync,
23
25
  unsafeGetCurrentRuntime,
24
26
  unsafeRunFoldWithEnv
25
- } from "./chunk-4N2JEK4H.mjs";
26
-
27
- // src/core/runtime/combinators.ts
28
- function sleep(ms) {
29
- return async((_env, cb) => {
30
- const delay = Math.max(0, Math.floor(ms));
31
- const id = setTimeout(() => cb({ _tag: "Success", value: void 0 }), delay);
32
- return () => clearTimeout(id);
33
- });
34
- }
35
- function timeout(effect, ms) {
36
- return async((env, cb) => {
37
- let done = false;
38
- let timerId;
39
- let effectRunning = true;
40
- timerId = setTimeout(() => {
41
- if (done) return;
42
- done = true;
43
- effectRunning = false;
44
- cb({
45
- _tag: "Failure",
46
- cause: { _tag: "Fail", error: { _tag: "TimeoutError", ms } }
47
- });
48
- }, Math.max(0, Math.floor(ms)));
49
- const runtime = unsafeGetCurrentRuntime();
50
- if (runtime) {
51
- const fiber = runtime.fork(effect);
52
- fiber.join((exit) => {
53
- if (done) return;
54
- done = true;
55
- clearTimeout(timerId);
56
- cb(exit);
57
- });
58
- return () => {
59
- if (done) return;
60
- done = true;
61
- clearTimeout(timerId);
62
- fiber.interrupt();
63
- };
64
- }
65
- return () => {
66
- if (done) return;
67
- done = true;
68
- clearTimeout(timerId);
69
- };
70
- });
71
- }
72
- function retry(effect, policy) {
73
- const shouldRetry = policy.shouldRetry ?? (() => true);
74
- const jitter = policy.jitter ?? "full";
75
- const maxElapsedMs = policy.maxElapsedMs;
76
- const computeDelay = (attempt) => {
77
- const exp = policy.baseDelayMs * Math.pow(2, attempt);
78
- const capped = Math.min(exp, policy.maxDelayMs);
79
- if (jitter === "none") return capped;
80
- return Math.floor(Math.random() * capped);
81
- };
82
- const loop = (attempt, startedAt) => asyncFold(
83
- effect,
84
- (error) => {
85
- if (attempt >= policy.maxRetries) return asyncFail(error);
86
- if (!shouldRetry(error, attempt)) return asyncFail(error);
87
- if (maxElapsedMs !== void 0) {
88
- const elapsed = performance.now() - startedAt;
89
- if (elapsed >= maxElapsedMs) return asyncFail(error);
90
- }
91
- const delay = computeDelay(attempt);
92
- return asyncFlatMap(sleep(delay), () => loop(attempt + 1, startedAt));
93
- },
94
- (value) => asyncSucceed(value)
95
- );
96
- return asyncFlatMap(
97
- { _tag: "Sync", thunk: () => performance.now() },
98
- (startedAt) => loop(0, startedAt)
99
- );
100
- }
101
- function retryN(effect, n) {
102
- return retry(effect, {
103
- maxRetries: n,
104
- baseDelayMs: 0,
105
- maxDelayMs: 0,
106
- jitter: "none"
107
- });
108
- }
109
- function retryWithBackoff(effect, opts = {}) {
110
- return retry(effect, {
111
- maxRetries: opts.maxRetries ?? 3,
112
- baseDelayMs: opts.baseDelayMs ?? 100,
113
- maxDelayMs: opts.maxDelayMs ?? 1e4,
114
- maxElapsedMs: opts.maxElapsedMs,
115
- shouldRetry: opts.shouldRetry,
116
- jitter: "full"
117
- });
118
- }
119
-
120
- // src/core/runtime/circuitBreaker.ts
121
- function makeCircuitBreaker(config = {}) {
122
- const failureThreshold = config.failureThreshold ?? 5;
123
- const resetTimeoutMs = config.resetTimeoutMs ?? 3e4;
124
- const successThreshold = config.successThreshold ?? 1;
125
- const isFailure = config.isFailure ?? (() => true);
126
- const onStateChange = config.onStateChange;
127
- let currentState = "closed";
128
- let consecutiveFailures = 0;
129
- let consecutiveSuccesses = 0;
130
- let openedAt = 0;
131
- let totalRequests = 0;
132
- let totalFailures = 0;
133
- let totalSuccesses = 0;
134
- let totalRejected = 0;
135
- let lastFailureTime = null;
136
- let lastSuccessTime = null;
137
- const transition = (to) => {
138
- if (currentState === to) return;
139
- const from = currentState;
140
- currentState = to;
141
- onStateChange?.(from, to);
142
- };
143
- const onSuccess = () => {
144
- totalSuccesses++;
145
- lastSuccessTime = Date.now();
146
- consecutiveFailures = 0;
147
- if (currentState === "half-open") {
148
- consecutiveSuccesses++;
149
- if (consecutiveSuccesses >= successThreshold) {
150
- consecutiveSuccesses = 0;
151
- transition("closed");
152
- }
153
- }
154
- };
155
- const onFailure = (error) => {
156
- if (!isFailure(error)) {
157
- onSuccess();
158
- return;
159
- }
160
- totalFailures++;
161
- lastFailureTime = Date.now();
162
- consecutiveSuccesses = 0;
163
- consecutiveFailures++;
164
- if (currentState === "half-open") {
165
- openedAt = Date.now();
166
- transition("open");
167
- } else if (currentState === "closed" && consecutiveFailures >= failureThreshold) {
168
- openedAt = Date.now();
169
- transition("open");
170
- }
171
- };
172
- const shouldAllow = () => {
173
- switch (currentState) {
174
- case "closed":
175
- return true;
176
- case "open": {
177
- const elapsed = Date.now() - openedAt;
178
- if (elapsed >= resetTimeoutMs) {
179
- transition("half-open");
180
- return true;
181
- }
182
- return false;
183
- }
184
- case "half-open":
185
- return true;
186
- }
187
- };
188
- const protect = (effect) => {
189
- totalRequests++;
190
- if (!shouldAllow()) {
191
- totalRejected++;
192
- return asyncFail({
193
- _tag: "CircuitBreakerOpen",
194
- openSince: openedAt,
195
- failures: consecutiveFailures
196
- });
197
- }
198
- return asyncFold(
199
- effect,
200
- (error) => {
201
- onFailure(error);
202
- return asyncFail(error);
203
- },
204
- (value) => {
205
- onSuccess();
206
- return asyncSucceed(value);
207
- }
208
- );
209
- };
210
- const stats = () => ({
211
- state: currentState,
212
- failures: consecutiveFailures,
213
- successes: consecutiveSuccesses,
214
- totalRequests,
215
- totalFailures,
216
- totalSuccesses,
217
- totalRejected,
218
- lastFailureTime,
219
- lastSuccessTime
220
- });
221
- const reset = () => {
222
- consecutiveFailures = 0;
223
- consecutiveSuccesses = 0;
224
- transition("closed");
225
- };
226
- return {
227
- state: () => currentState,
228
- protect,
229
- stats,
230
- reset
231
- };
232
- }
27
+ } from "./chunk-BMH5AV44.js";
233
28
 
234
29
  // src/core/stream/stream.ts
235
30
  var widenOpt = (opt) => opt._tag === "None" ? none : some(opt.value);
@@ -280,7 +75,7 @@ function streamToRaceWithHandler(winnerSide, leftStream, rightStream, flip, id)
280
75
  return asyncSucceed([a, next]);
281
76
  }
282
77
  if (exit.cause._tag === "Interrupt") {
283
- return async((_env, cb) => {
78
+ return asyncEffect((_env, cb) => {
284
79
  cb(Exit.failCause(Cause.interrupt()));
285
80
  });
286
81
  }
@@ -295,7 +90,7 @@ function makeMergePull(onLeft, onRight, flip, mergePullId) {
295
90
  const id = ++mergePullId;
296
91
  const onLeftHandler = streamToRaceWithHandler("L", onLeft, onRight, flip, id);
297
92
  const onRightHandler = streamToRaceWithHandler("R", onLeft, onRight, flip, id);
298
- return async((_env, cb) => {
93
+ return asyncEffect((_env, cb) => {
299
94
  const runtime = unsafeGetCurrentRuntime();
300
95
  const scope = new Scope(runtime);
301
96
  const handler = raceWith(
@@ -356,7 +151,7 @@ function uncons(self) {
356
151
  case "Merge":
357
152
  return makeMergePull(self.left, self.right, self.flip, 0);
358
153
  case "Scoped":
359
- return async((env, cb) => {
154
+ return asyncEffect((env, cb) => {
360
155
  const runtime = unsafeGetCurrentRuntime();
361
156
  const scope = new Scope(runtime);
362
157
  const fiber = getCurrentFiber();
@@ -377,7 +172,7 @@ function uncons(self) {
377
172
  scope.close(exit);
378
173
  };
379
174
  const wrap = (s) => fromPull(
380
- async((env2, cb2) => {
175
+ asyncEffect((env2, cb2) => {
381
176
  const pull = uncons(s);
382
177
  unsafeRunFoldWithEnv(
383
178
  pull,
@@ -405,7 +200,7 @@ function uncons(self) {
405
200
  });
406
201
  });
407
202
  case "Managed":
408
- return async((env, cb) => {
203
+ return asyncEffect((env, cb) => {
409
204
  const runtime = unsafeGetCurrentRuntime();
410
205
  const scope = new Scope(runtime);
411
206
  getCurrentFiber()?.addFinalizer((exit) => {
@@ -433,16 +228,19 @@ function uncons(self) {
433
228
  const { stream: inner, release } = ex.value;
434
229
  scope.addFinalizer((exit) => release(exit));
435
230
  const wrap = (s) => fromPull(
436
- async((env2, cb2) => {
437
- uncons(s)(env2, (ex2) => {
438
- if (ex2._tag === "Failure") {
231
+ asyncEffect((env2, cb2) => {
232
+ unsafeRunFoldWithEnv(
233
+ uncons(s),
234
+ env2,
235
+ (cause) => {
236
+ const ex2 = Exit.failCause(cause);
439
237
  closeWith(ex2);
440
238
  cb2(ex2);
441
- return;
239
+ },
240
+ ([a, tail]) => {
241
+ cb2(Exit.succeed([a, wrap(tail)]));
442
242
  }
443
- const [a, tail] = ex2.value;
444
- cb2(Exit.succeed([a, wrap(tail)]));
445
- });
243
+ );
446
244
  })
447
245
  );
448
246
  unsafeGetCurrentRuntime().fork(uncons(wrap(inner))).join(cb);
@@ -602,49 +400,73 @@ function drainStreamSyncFull(stream) {
602
400
  }
603
401
  }
604
402
  }
605
- function readerStream(reader, normalizeError) {
606
- const pull = async((_, cb) => {
607
- reader.read().then(({ done, value }) => {
608
- if (done) {
609
- cb({ _tag: "Failure", cause: { _tag: "Fail", error: none } });
403
+ function readerStream(reader, normalizeError, signal) {
404
+ const pull = asyncEffect((_, cb) => {
405
+ let done = false;
406
+ const cleanup = () => signal?.removeEventListener("abort", abort);
407
+ const finish = (exit) => {
408
+ if (done) return;
409
+ done = true;
410
+ cleanup();
411
+ cb(exit);
412
+ };
413
+ const abort = () => {
414
+ try {
415
+ reader.cancel();
416
+ } catch {
417
+ }
418
+ const error = typeof DOMException === "function" ? new DOMException("aborted", "AbortError") : new Error("aborted");
419
+ finish({ _tag: "Failure", cause: { _tag: "Fail", error: some(normalizeError(error)) } });
420
+ };
421
+ if (signal?.aborted) {
422
+ abort();
423
+ return;
424
+ }
425
+ signal?.addEventListener("abort", abort, { once: true });
426
+ reader.read().then(({ done: done2, value }) => {
427
+ if (done2) {
428
+ finish({ _tag: "Failure", cause: { _tag: "Fail", error: none } });
610
429
  return;
611
430
  }
612
- cb({
431
+ finish({
613
432
  _tag: "Success",
614
433
  value: [value, fromPull(pull)]
615
434
  });
616
435
  }).catch((e) => {
617
- cb({ _tag: "Failure", cause: { _tag: "Fail", error: some(normalizeError(e)) } });
436
+ finish({ _tag: "Failure", cause: { _tag: "Fail", error: some(normalizeError(e)) } });
618
437
  });
438
+ return () => {
439
+ cleanup();
440
+ try {
441
+ reader.cancel();
442
+ } catch {
443
+ }
444
+ };
619
445
  });
620
446
  return fromPull(pull);
621
447
  }
622
- function streamFromReadableStream(body, normalizeError) {
448
+ function streamFromReadableStream(body, normalizeError, options = {}) {
623
449
  if (!body) return emptyStream();
624
450
  let reader;
625
451
  return unwrapScoped(
626
452
  // acquire: produce un ZStream
627
453
  sync(() => {
628
454
  reader = body.getReader();
629
- return readerStream(reader, normalizeError);
455
+ return readerStream(reader, normalizeError, options.signal);
630
456
  }),
631
457
  // release: se corre en fin / error / interrupción
632
458
  () => asyncSync(() => {
633
459
  try {
634
460
  reader?.cancel();
635
461
  } catch {
462
+ } finally {
463
+ options.onRelease?.();
636
464
  }
637
465
  })
638
466
  );
639
467
  }
640
468
 
641
469
  export {
642
- sleep,
643
- timeout,
644
- retry,
645
- retryN,
646
- retryWithBackoff,
647
- makeCircuitBreaker,
648
470
  widenOpt,
649
471
  fromPull,
650
472
  unwrapScoped,