brass-runtime 1.13.7 → 1.14.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.
- package/README.md +231 -55
- package/dist/agent/cli/main.cjs +43 -43
- package/dist/agent/cli/main.js +2 -2
- package/dist/agent/cli/main.mjs +2 -2
- package/dist/agent/index.cjs +3 -3
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +2 -2
- package/dist/agent/index.mjs +2 -2
- package/dist/chunk-4N2JEK4H.mjs +3897 -0
- package/dist/chunk-BKBFSOGT.cjs +3897 -0
- package/dist/{chunk-XNOTJSMZ.mjs → chunk-BMRF4FN6.js} +268 -8
- package/dist/chunk-JT7D6M5H.js +3897 -0
- package/dist/{chunk-3R7ZYRK2.mjs → chunk-MQF7HZ7Y.mjs} +1 -1
- package/dist/chunk-SKVY72E5.cjs +667 -0
- package/dist/{chunk-ATHSSDUF.js → chunk-UWMMYKVK.mjs} +268 -8
- package/dist/{chunk-INZBKOHY.js → chunk-WJESVBWN.js} +1 -1
- package/dist/{chunk-XDINDYNA.cjs → chunk-XTMZTVIT.cjs} +134 -134
- package/dist/{effect-ISvXPLgc.d.ts → effect-DM56H743.d.ts} +191 -21
- package/dist/http/index.cjs +808 -140
- package/dist/http/index.d.ts +181 -8
- package/dist/http/index.js +793 -125
- package/dist/http/index.mjs +793 -125
- package/dist/index.cjs +1785 -137
- package/dist/index.d.ts +979 -36
- package/dist/index.js +1675 -27
- package/dist/index.mjs +1675 -27
- package/dist/stream-Oqe6WeLE.d.ts +173 -0
- package/package.json +1 -1
- package/wasm/pkg/brass_runtime_wasm_engine.d.ts +95 -16
- package/wasm/pkg/brass_runtime_wasm_engine.js +715 -15
- package/wasm/pkg/brass_runtime_wasm_engine_bg.wasm +0 -0
- package/wasm/pkg/brass_runtime_wasm_engine_bg.wasm.d.ts +78 -7
- package/dist/chunk-2P4PD6D7.cjs +0 -2557
- package/dist/chunk-7F2R7A2V.mjs +0 -2557
- package/dist/chunk-L6KKKM66.js +0 -2557
- package/dist/chunk-ZTDK2DLG.cjs +0 -407
- package/dist/stream-BvukHxCv.d.ts +0 -66
package/dist/index.mjs
CHANGED
|
@@ -8,29 +8,39 @@ import {
|
|
|
8
8
|
foreachStream,
|
|
9
9
|
fromArray,
|
|
10
10
|
fromPull,
|
|
11
|
+
makeCircuitBreaker,
|
|
11
12
|
managedStream,
|
|
12
13
|
mapStream,
|
|
13
14
|
merge,
|
|
14
15
|
mergeStream,
|
|
15
16
|
rangeStream,
|
|
17
|
+
retry,
|
|
18
|
+
retryN,
|
|
19
|
+
retryWithBackoff,
|
|
20
|
+
sleep,
|
|
16
21
|
streamFromReadableStream,
|
|
22
|
+
timeout,
|
|
17
23
|
uncons,
|
|
18
24
|
unwrapScoped,
|
|
19
25
|
widenOpt,
|
|
20
26
|
zip
|
|
21
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-UWMMYKVK.mjs";
|
|
22
28
|
import {
|
|
29
|
+
ABI_VERSION,
|
|
23
30
|
Async,
|
|
24
31
|
Cause,
|
|
25
32
|
DefaultHostExecutor,
|
|
33
|
+
EVENT_WORDS,
|
|
26
34
|
EngineFiberHandle,
|
|
35
|
+
EventKindCode,
|
|
27
36
|
Exit,
|
|
28
37
|
HostRegistry,
|
|
29
38
|
JsFiberEngine,
|
|
39
|
+
NONE_U32,
|
|
30
40
|
NoopHooks,
|
|
41
|
+
OpcodeTagCode,
|
|
31
42
|
ProgramBuilder,
|
|
32
43
|
PushStatus,
|
|
33
|
-
ReferenceWasmBridge,
|
|
34
44
|
RingBuffer,
|
|
35
45
|
Runtime,
|
|
36
46
|
RuntimeFiber,
|
|
@@ -39,6 +49,7 @@ import {
|
|
|
39
49
|
WasmFiberEngine,
|
|
40
50
|
WasmFiberRegistryBridge,
|
|
41
51
|
WasmPackFiberBridge,
|
|
52
|
+
abortablePromiseStats,
|
|
42
53
|
acquireRelease,
|
|
43
54
|
async,
|
|
44
55
|
asyncCatchAll,
|
|
@@ -53,6 +64,10 @@ import {
|
|
|
53
64
|
asyncTotal,
|
|
54
65
|
catchAll,
|
|
55
66
|
collectAllPar,
|
|
67
|
+
decodeEvent,
|
|
68
|
+
decodeEventBatch,
|
|
69
|
+
encodeOpcodeNodes,
|
|
70
|
+
encodeOpcodeProgram,
|
|
56
71
|
end,
|
|
57
72
|
fail,
|
|
58
73
|
flatMap,
|
|
@@ -61,7 +76,10 @@ import {
|
|
|
61
76
|
getBenchmarkBudget,
|
|
62
77
|
getCurrentFiber,
|
|
63
78
|
globalScheduler,
|
|
79
|
+
inferCallerLaneFromStack,
|
|
80
|
+
laneTag,
|
|
64
81
|
makeBoundedRingBuffer,
|
|
82
|
+
makeFiberReadyQueue,
|
|
65
83
|
map,
|
|
66
84
|
mapAsync,
|
|
67
85
|
mapError,
|
|
@@ -70,13 +88,17 @@ import {
|
|
|
70
88
|
orElseOptional,
|
|
71
89
|
race,
|
|
72
90
|
raceWith,
|
|
91
|
+
resetAbortablePromiseStats,
|
|
73
92
|
resolveWasmModule,
|
|
74
93
|
runtimeCapabilities,
|
|
94
|
+
runtimeForCaller,
|
|
95
|
+
sanitizeLaneKey,
|
|
75
96
|
setBenchmarkBudget,
|
|
76
97
|
some,
|
|
77
98
|
succeed,
|
|
78
99
|
sync,
|
|
79
100
|
toPromise,
|
|
101
|
+
toPromiseByCaller,
|
|
80
102
|
unit,
|
|
81
103
|
unsafeGetCurrentRuntime,
|
|
82
104
|
unsafeRunAsync,
|
|
@@ -86,7 +108,7 @@ import {
|
|
|
86
108
|
withScope,
|
|
87
109
|
withScopeAsync,
|
|
88
110
|
zipPar
|
|
89
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-4N2JEK4H.mjs";
|
|
90
112
|
|
|
91
113
|
// src/core/types/cancel.ts
|
|
92
114
|
function makeCancelToken() {
|
|
@@ -121,6 +143,135 @@ function linkAbortController(token, ac) {
|
|
|
121
143
|
return token.onCancel(() => ac.abort());
|
|
122
144
|
}
|
|
123
145
|
|
|
146
|
+
// src/core/runtime/resource.ts
|
|
147
|
+
function bracket(acquire, use, release) {
|
|
148
|
+
return async((env, cb) => {
|
|
149
|
+
const runtime = unsafeGetCurrentRuntime();
|
|
150
|
+
const scope = new Scope(runtime);
|
|
151
|
+
const acquireFiber = scope.fork(acquire);
|
|
152
|
+
acquireFiber.join((acquireExit) => {
|
|
153
|
+
if (acquireExit._tag === "Failure") {
|
|
154
|
+
scope.close(acquireExit);
|
|
155
|
+
cb(acquireExit);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const resource = acquireExit.value;
|
|
159
|
+
const useFiber = scope.fork(use(resource));
|
|
160
|
+
useFiber.join((useExit) => {
|
|
161
|
+
const releaseEffect = safeRelease(release, resource, useExit);
|
|
162
|
+
const releaseFiber = runtime.fork(releaseEffect);
|
|
163
|
+
releaseFiber.join(() => {
|
|
164
|
+
scope.close(useExit);
|
|
165
|
+
cb(useExit);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
return () => {
|
|
170
|
+
scope.close(Exit.failCause(Cause.interrupt()));
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
function safeRelease(release, resource, exit) {
|
|
175
|
+
return asyncFold(
|
|
176
|
+
(() => {
|
|
177
|
+
try {
|
|
178
|
+
return release(resource, exit);
|
|
179
|
+
} catch {
|
|
180
|
+
return unit();
|
|
181
|
+
}
|
|
182
|
+
})(),
|
|
183
|
+
() => unit(),
|
|
184
|
+
() => unit()
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
function ensuring(effect, finalizer) {
|
|
188
|
+
return async((env, cb) => {
|
|
189
|
+
const runtime = unsafeGetCurrentRuntime();
|
|
190
|
+
const fiber = runtime.fork(effect);
|
|
191
|
+
fiber.join((exit) => {
|
|
192
|
+
const fin = asyncFold(
|
|
193
|
+
(() => {
|
|
194
|
+
try {
|
|
195
|
+
return finalizer(exit);
|
|
196
|
+
} catch {
|
|
197
|
+
return unit();
|
|
198
|
+
}
|
|
199
|
+
})(),
|
|
200
|
+
() => unit(),
|
|
201
|
+
() => unit()
|
|
202
|
+
);
|
|
203
|
+
runtime.fork(fin).join(() => {
|
|
204
|
+
cb(exit);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
return () => {
|
|
208
|
+
fiber.interrupt();
|
|
209
|
+
};
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function managed(acquire, release) {
|
|
213
|
+
return {
|
|
214
|
+
_tag: "Managed",
|
|
215
|
+
acquire,
|
|
216
|
+
release: (resource, exit) => release(resource, exit)
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function useManaged(m, body) {
|
|
220
|
+
return bracket(m.acquire, body, m.release);
|
|
221
|
+
}
|
|
222
|
+
function managedAll(manageds) {
|
|
223
|
+
const acquire = async((env, cb) => {
|
|
224
|
+
const runtime = unsafeGetCurrentRuntime();
|
|
225
|
+
const resources = [];
|
|
226
|
+
let i = 0;
|
|
227
|
+
const acquireNext = () => {
|
|
228
|
+
if (i >= manageds.length) {
|
|
229
|
+
cb({ _tag: "Success", value: resources });
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const m = manageds[i];
|
|
233
|
+
const fiber = runtime.fork(m.acquire);
|
|
234
|
+
fiber.join((exit) => {
|
|
235
|
+
if (exit._tag === "Failure") {
|
|
236
|
+
releaseAcquired(runtime, manageds, resources, exit).then(() => {
|
|
237
|
+
cb(exit);
|
|
238
|
+
});
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
resources.push(exit.value);
|
|
242
|
+
i++;
|
|
243
|
+
acquireNext();
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
acquireNext();
|
|
247
|
+
});
|
|
248
|
+
const release = (resources, exit) => {
|
|
249
|
+
return async((_env, cb) => {
|
|
250
|
+
const runtime = unsafeGetCurrentRuntime();
|
|
251
|
+
releaseAcquired(runtime, manageds, resources, exit).then(() => {
|
|
252
|
+
cb({ _tag: "Success", value: void 0 });
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
return { _tag: "Managed", acquire, release };
|
|
257
|
+
}
|
|
258
|
+
async function releaseAcquired(runtime, manageds, resources, exit) {
|
|
259
|
+
for (let i = resources.length - 1; i >= 0; i--) {
|
|
260
|
+
try {
|
|
261
|
+
const m = manageds[i];
|
|
262
|
+
await new Promise((resolve) => {
|
|
263
|
+
const releaseEff = asyncFold(
|
|
264
|
+
m.release(resources[i], exit),
|
|
265
|
+
() => unit(),
|
|
266
|
+
() => unit()
|
|
267
|
+
);
|
|
268
|
+
runtime.fork(releaseEff).join(() => resolve());
|
|
269
|
+
});
|
|
270
|
+
} catch {
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
124
275
|
// src/core/runtime/linkedQueue.ts
|
|
125
276
|
var LinkedQueue = class {
|
|
126
277
|
head = null;
|
|
@@ -163,6 +314,788 @@ var LinkedQueue = class {
|
|
|
163
314
|
}
|
|
164
315
|
};
|
|
165
316
|
|
|
317
|
+
// src/core/runtime/semaphore.ts
|
|
318
|
+
function makeSemaphore(n) {
|
|
319
|
+
const capacity = Math.max(1, Math.floor(n));
|
|
320
|
+
let available = capacity;
|
|
321
|
+
let totalAcquired = 0;
|
|
322
|
+
let totalReleased = 0;
|
|
323
|
+
const waiters = new LinkedQueue();
|
|
324
|
+
const acquire = () => {
|
|
325
|
+
return async((_env, cb) => {
|
|
326
|
+
if (available > 0) {
|
|
327
|
+
available--;
|
|
328
|
+
totalAcquired++;
|
|
329
|
+
cb({ _tag: "Success", value: void 0 });
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const node = waiters.push(cb);
|
|
333
|
+
return () => {
|
|
334
|
+
waiters.remove(node);
|
|
335
|
+
};
|
|
336
|
+
});
|
|
337
|
+
};
|
|
338
|
+
const release = () => {
|
|
339
|
+
totalReleased++;
|
|
340
|
+
if (waiters.length > 0) {
|
|
341
|
+
const waiter = waiters.shift();
|
|
342
|
+
totalAcquired++;
|
|
343
|
+
waiter({ _tag: "Success", value: void 0 });
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
available++;
|
|
347
|
+
};
|
|
348
|
+
const withPermit = (effect) => {
|
|
349
|
+
return asyncFlatMap(
|
|
350
|
+
acquire(),
|
|
351
|
+
() => async((_env, cb) => {
|
|
352
|
+
const runtime = unsafeGetCurrentRuntime();
|
|
353
|
+
const fiber = runtime.fork(effect);
|
|
354
|
+
fiber.join((exit) => {
|
|
355
|
+
release();
|
|
356
|
+
cb(exit);
|
|
357
|
+
});
|
|
358
|
+
return () => {
|
|
359
|
+
fiber.interrupt();
|
|
360
|
+
release();
|
|
361
|
+
};
|
|
362
|
+
})
|
|
363
|
+
);
|
|
364
|
+
};
|
|
365
|
+
return {
|
|
366
|
+
capacity,
|
|
367
|
+
available: () => available,
|
|
368
|
+
waiting: () => waiters.length,
|
|
369
|
+
withPermit,
|
|
370
|
+
acquire,
|
|
371
|
+
release
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/core/runtime/ref.ts
|
|
376
|
+
function makeRef(initial) {
|
|
377
|
+
let value = initial;
|
|
378
|
+
return {
|
|
379
|
+
get: () => asyncSync(() => value),
|
|
380
|
+
set: (v) => asyncSync(() => {
|
|
381
|
+
value = v;
|
|
382
|
+
}),
|
|
383
|
+
update: (f) => asyncSync(() => {
|
|
384
|
+
value = f(value);
|
|
385
|
+
return value;
|
|
386
|
+
}),
|
|
387
|
+
modify: (f) => asyncSync(() => {
|
|
388
|
+
const [result, next] = f(value);
|
|
389
|
+
value = next;
|
|
390
|
+
return result;
|
|
391
|
+
}),
|
|
392
|
+
unsafeGet: () => value
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
function derivedRef(parent, get, set) {
|
|
396
|
+
return {
|
|
397
|
+
get: () => asyncSync(() => get(parent.unsafeGet())),
|
|
398
|
+
set: (b) => asyncSync(() => {
|
|
399
|
+
const current = parent.unsafeGet();
|
|
400
|
+
parent.set(set(current, b));
|
|
401
|
+
}),
|
|
402
|
+
update: (f) => asyncSync(() => {
|
|
403
|
+
const parentVal = parent.unsafeGet();
|
|
404
|
+
const currentB = get(parentVal);
|
|
405
|
+
const newB = f(currentB);
|
|
406
|
+
const newParent = set(parentVal, newB);
|
|
407
|
+
parent.unsafeGet = () => newParent;
|
|
408
|
+
return newB;
|
|
409
|
+
}),
|
|
410
|
+
modify: (f) => asyncSync(() => {
|
|
411
|
+
const parentVal = parent.unsafeGet();
|
|
412
|
+
const currentB = get(parentVal);
|
|
413
|
+
const [result, newB] = f(currentB);
|
|
414
|
+
const newParent = set(parentVal, newB);
|
|
415
|
+
parent.unsafeGet = () => newParent;
|
|
416
|
+
return result;
|
|
417
|
+
}),
|
|
418
|
+
unsafeGet: () => get(parent.unsafeGet())
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/core/runtime/schedule.ts
|
|
423
|
+
function recurs(n) {
|
|
424
|
+
return {
|
|
425
|
+
_tag: "Schedule",
|
|
426
|
+
initial: () => 0,
|
|
427
|
+
step: (count, _input) => {
|
|
428
|
+
const next = count + 1;
|
|
429
|
+
return [{ continue: next < n, delayMs: 0 }, next, next];
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
function fixed(delayMs) {
|
|
434
|
+
return {
|
|
435
|
+
_tag: "Schedule",
|
|
436
|
+
initial: () => 0,
|
|
437
|
+
step: (count, _input) => {
|
|
438
|
+
return [{ continue: true, delayMs }, count + 1, count + 1];
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
function exponential(baseMs, maxMs = Infinity) {
|
|
443
|
+
return {
|
|
444
|
+
_tag: "Schedule",
|
|
445
|
+
initial: () => 0,
|
|
446
|
+
step: (count, _input) => {
|
|
447
|
+
const delay = Math.min(baseMs * Math.pow(2, count), maxMs);
|
|
448
|
+
return [{ continue: true, delayMs: delay }, count + 1, count + 1];
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
function jittered(baseMs, maxMs = Infinity) {
|
|
453
|
+
return {
|
|
454
|
+
_tag: "Schedule",
|
|
455
|
+
initial: () => 0,
|
|
456
|
+
step: (count, _input) => {
|
|
457
|
+
const cap = Math.min(baseMs * Math.pow(2, count), maxMs);
|
|
458
|
+
const delay = Math.floor(Math.random() * cap);
|
|
459
|
+
return [{ continue: true, delayMs: delay }, count + 1, count + 1];
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function elapsed(maxMs) {
|
|
464
|
+
return {
|
|
465
|
+
_tag: "Schedule",
|
|
466
|
+
initial: () => performance.now(),
|
|
467
|
+
step: (startedAt, _input) => {
|
|
468
|
+
const el = performance.now() - startedAt;
|
|
469
|
+
return [{ continue: el < maxMs, delayMs: 0 }, startedAt, el];
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function whileInput(pred) {
|
|
474
|
+
return {
|
|
475
|
+
_tag: "Schedule",
|
|
476
|
+
initial: () => void 0,
|
|
477
|
+
step: (_state, input) => {
|
|
478
|
+
return [{ continue: pred(input), delayMs: 0 }, void 0, input];
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
function take(schedule, n) {
|
|
483
|
+
return {
|
|
484
|
+
_tag: "Schedule",
|
|
485
|
+
initial: () => ({ inner: schedule.initial(), count: 0 }),
|
|
486
|
+
step: (state, input) => {
|
|
487
|
+
if (state.count >= n) return [{ continue: false, delayMs: 0 }, state, void 0];
|
|
488
|
+
const [decision, nextInner, output] = schedule.step(state.inner, input);
|
|
489
|
+
const nextState = { inner: nextInner, count: state.count + 1 };
|
|
490
|
+
return [{ continue: decision.continue && state.count + 1 < n, delayMs: decision.delayMs }, nextState, output];
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
function andThen(first, second) {
|
|
495
|
+
return {
|
|
496
|
+
_tag: "Schedule",
|
|
497
|
+
initial: () => ({ phase: "first", inner: first.initial() }),
|
|
498
|
+
step: (state, input) => {
|
|
499
|
+
if (state.phase === "first") {
|
|
500
|
+
const [decision2, nextInner2, output2] = first.step(state.inner, input);
|
|
501
|
+
if (decision2.continue) {
|
|
502
|
+
return [decision2, { phase: "first", inner: nextInner2 }, output2];
|
|
503
|
+
}
|
|
504
|
+
return [{ continue: true, delayMs: decision2.delayMs }, { phase: "second", inner: second.initial() }, output2];
|
|
505
|
+
}
|
|
506
|
+
const [decision, nextInner, output] = second.step(state.inner, input);
|
|
507
|
+
return [decision, { phase: "second", inner: nextInner }, output];
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function intersect(left, right) {
|
|
512
|
+
return {
|
|
513
|
+
_tag: "Schedule",
|
|
514
|
+
initial: () => ({ left: left.initial(), right: right.initial() }),
|
|
515
|
+
step: (state, input) => {
|
|
516
|
+
const [ld, ls, lo] = left.step(state.left, input);
|
|
517
|
+
const [rd, rs, ro] = right.step(state.right, input);
|
|
518
|
+
const cont = ld.continue && rd.continue;
|
|
519
|
+
const delay = Math.max(ld.delayMs, rd.delayMs);
|
|
520
|
+
return [{ continue: cont, delayMs: delay }, { left: ls, right: rs }, [lo, ro]];
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
function union(left, right) {
|
|
525
|
+
return {
|
|
526
|
+
_tag: "Schedule",
|
|
527
|
+
initial: () => ({ left: left.initial(), right: right.initial() }),
|
|
528
|
+
step: (state, input) => {
|
|
529
|
+
const [ld, ls, lo] = left.step(state.left, input);
|
|
530
|
+
const [rd, rs, ro] = right.step(state.right, input);
|
|
531
|
+
const cont = ld.continue || rd.continue;
|
|
532
|
+
const delay = Math.min(ld.delayMs, rd.delayMs);
|
|
533
|
+
return [{ continue: cont, delayMs: delay }, { left: ls, right: rs }, [lo, ro]];
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
function retryWithSchedule(effect, schedule) {
|
|
538
|
+
const loop = (state) => asyncFold(
|
|
539
|
+
effect,
|
|
540
|
+
(error) => {
|
|
541
|
+
const [decision, nextState, _output] = schedule.step(state, error);
|
|
542
|
+
if (!decision.continue) return asyncFail(error);
|
|
543
|
+
if (decision.delayMs <= 0) return loop(nextState);
|
|
544
|
+
return asyncFlatMap(sleep(decision.delayMs), () => loop(nextState));
|
|
545
|
+
},
|
|
546
|
+
(value) => asyncSucceed(value)
|
|
547
|
+
);
|
|
548
|
+
return loop(schedule.initial());
|
|
549
|
+
}
|
|
550
|
+
function repeatWithSchedule(effect, schedule) {
|
|
551
|
+
const loop = (state, lastValue) => {
|
|
552
|
+
const [decision, nextState, _output] = schedule.step(state, lastValue);
|
|
553
|
+
if (!decision.continue) return asyncSucceed(lastValue);
|
|
554
|
+
if (decision.delayMs <= 0) {
|
|
555
|
+
return asyncFold(
|
|
556
|
+
effect,
|
|
557
|
+
(error) => asyncFail(error),
|
|
558
|
+
(value) => loop(nextState, value)
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
return asyncFlatMap(
|
|
562
|
+
sleep(decision.delayMs),
|
|
563
|
+
() => asyncFold(
|
|
564
|
+
effect,
|
|
565
|
+
(error) => asyncFail(error),
|
|
566
|
+
(value) => loop(nextState, value)
|
|
567
|
+
)
|
|
568
|
+
);
|
|
569
|
+
};
|
|
570
|
+
return asyncFold(
|
|
571
|
+
effect,
|
|
572
|
+
(error) => asyncFail(error),
|
|
573
|
+
(value) => loop(schedule.initial(), value)
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// src/core/runtime/shutdown.ts
|
|
578
|
+
async function gracefulShutdown(runtime, config = {}) {
|
|
579
|
+
const timeoutMs = config.timeoutMs ?? 3e4;
|
|
580
|
+
const startedAt = Date.now();
|
|
581
|
+
config.onStart?.();
|
|
582
|
+
let timedOut = false;
|
|
583
|
+
const shutdownPromise = (async () => {
|
|
584
|
+
try {
|
|
585
|
+
await runtime.shutdown();
|
|
586
|
+
} catch {
|
|
587
|
+
}
|
|
588
|
+
})();
|
|
589
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
590
|
+
setTimeout(() => {
|
|
591
|
+
timedOut = true;
|
|
592
|
+
resolve();
|
|
593
|
+
}, timeoutMs);
|
|
594
|
+
});
|
|
595
|
+
await Promise.race([shutdownPromise, timeoutPromise]);
|
|
596
|
+
const completedAt = Date.now();
|
|
597
|
+
const stats = {
|
|
598
|
+
startedAt,
|
|
599
|
+
completedAt,
|
|
600
|
+
elapsedMs: completedAt - startedAt,
|
|
601
|
+
timedOut
|
|
602
|
+
};
|
|
603
|
+
if (timedOut) {
|
|
604
|
+
config.onTimeout?.(stats);
|
|
605
|
+
} else {
|
|
606
|
+
config.onComplete?.(stats);
|
|
607
|
+
}
|
|
608
|
+
return stats;
|
|
609
|
+
}
|
|
610
|
+
function registerShutdownHooks(runtime, config = {}) {
|
|
611
|
+
let shuttingDown = false;
|
|
612
|
+
const handler = (signal) => {
|
|
613
|
+
if (shuttingDown) {
|
|
614
|
+
process.exit(1);
|
|
615
|
+
}
|
|
616
|
+
shuttingDown = true;
|
|
617
|
+
console.log(`
|
|
618
|
+
[brass-runtime] Received ${signal}, shutting down gracefully...`);
|
|
619
|
+
gracefulShutdown(runtime, {
|
|
620
|
+
...config,
|
|
621
|
+
onComplete: (stats) => {
|
|
622
|
+
config.onComplete?.(stats);
|
|
623
|
+
if (!config.onComplete) {
|
|
624
|
+
console.log(`[brass-runtime] Shutdown complete (${stats.elapsedMs}ms)`);
|
|
625
|
+
process.exit(0);
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
onTimeout: (stats) => {
|
|
629
|
+
config.onTimeout?.(stats);
|
|
630
|
+
if (!config.onTimeout) {
|
|
631
|
+
console.log(`[brass-runtime] Shutdown timed out after ${stats.elapsedMs}ms, forcing exit`);
|
|
632
|
+
process.exit(1);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
};
|
|
637
|
+
process.on("SIGTERM", () => handler("SIGTERM"));
|
|
638
|
+
process.on("SIGINT", () => handler("SIGINT"));
|
|
639
|
+
return () => {
|
|
640
|
+
process.removeAllListeners("SIGTERM");
|
|
641
|
+
process.removeAllListeners("SIGINT");
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// src/core/runtime/testing.ts
|
|
646
|
+
function makeTestRuntime(env, options) {
|
|
647
|
+
const runtime = Runtime.make(env ?? {});
|
|
648
|
+
const run = (effect) => runtime.toPromise(effect);
|
|
649
|
+
const runExit = (effect) => new Promise((resolve) => {
|
|
650
|
+
runtime.unsafeRunAsync(effect, resolve);
|
|
651
|
+
});
|
|
652
|
+
return { runtime, run, runExit };
|
|
653
|
+
}
|
|
654
|
+
async function assertSucceeds(effect, expected, runtime) {
|
|
655
|
+
const rt = runtime ?? Runtime.make({});
|
|
656
|
+
const exit = await new Promise((resolve) => {
|
|
657
|
+
rt.unsafeRunAsync(effect, resolve);
|
|
658
|
+
});
|
|
659
|
+
if (exit._tag !== "Success") {
|
|
660
|
+
throw new Error(`Expected success with ${JSON.stringify(expected)}, got failure: ${JSON.stringify(exit.cause)}`);
|
|
661
|
+
}
|
|
662
|
+
if (JSON.stringify(exit.value) !== JSON.stringify(expected)) {
|
|
663
|
+
throw new Error(`Expected ${JSON.stringify(expected)}, got ${JSON.stringify(exit.value)}`);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
async function assertFails(effect, expectedError, runtime) {
|
|
667
|
+
const rt = runtime ?? Runtime.make({});
|
|
668
|
+
const exit = await new Promise((resolve) => {
|
|
669
|
+
rt.unsafeRunAsync(effect, resolve);
|
|
670
|
+
});
|
|
671
|
+
if (exit._tag !== "Failure") {
|
|
672
|
+
throw new Error(`Expected failure with ${JSON.stringify(expectedError)}, got success: ${JSON.stringify(exit.value)}`);
|
|
673
|
+
}
|
|
674
|
+
const error = exit.cause.error;
|
|
675
|
+
if (JSON.stringify(error) !== JSON.stringify(expectedError)) {
|
|
676
|
+
throw new Error(`Expected error ${JSON.stringify(expectedError)}, got ${JSON.stringify(error)}`);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
async function assertFailsWith(effect, predicate, runtime) {
|
|
680
|
+
const rt = runtime ?? Runtime.make({});
|
|
681
|
+
const exit = await new Promise((resolve) => {
|
|
682
|
+
rt.unsafeRunAsync(effect, resolve);
|
|
683
|
+
});
|
|
684
|
+
if (exit._tag !== "Failure") {
|
|
685
|
+
throw new Error(`Expected failure, got success: ${JSON.stringify(exit.value)}`);
|
|
686
|
+
}
|
|
687
|
+
const error = exit.cause.error;
|
|
688
|
+
if (!predicate(error)) {
|
|
689
|
+
throw new Error(`Error did not match predicate: ${JSON.stringify(error)}`);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
async function assertCompletesWithin(effect, maxMs, runtime) {
|
|
693
|
+
const rt = runtime ?? Runtime.make({});
|
|
694
|
+
const start = performance.now();
|
|
695
|
+
const result = await rt.toPromise(effect);
|
|
696
|
+
const elapsed2 = performance.now() - start;
|
|
697
|
+
if (elapsed2 > maxMs) {
|
|
698
|
+
throw new Error(`Effect took ${elapsed2.toFixed(1)}ms, expected < ${maxMs}ms`);
|
|
699
|
+
}
|
|
700
|
+
return result;
|
|
701
|
+
}
|
|
702
|
+
function flakyEffect(failCount, successValue, errorValue) {
|
|
703
|
+
let calls = 0;
|
|
704
|
+
return async((_env, cb) => {
|
|
705
|
+
calls++;
|
|
706
|
+
if (calls <= failCount) {
|
|
707
|
+
cb({ _tag: "Failure", cause: { _tag: "Fail", error: errorValue } });
|
|
708
|
+
} else {
|
|
709
|
+
cb({ _tag: "Success", value: successValue });
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
function delayedEffect(ms, value) {
|
|
714
|
+
return async((_env, cb) => {
|
|
715
|
+
const id = setTimeout(() => cb({ _tag: "Success", value }), ms);
|
|
716
|
+
return () => clearTimeout(id);
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
function neverEffect() {
|
|
720
|
+
return async(() => {
|
|
721
|
+
return () => {
|
|
722
|
+
};
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// src/core/runtime/layer.ts
|
|
727
|
+
function layer(acquire, release) {
|
|
728
|
+
return {
|
|
729
|
+
_tag: "Layer",
|
|
730
|
+
build: (_deps) => asyncFlatMap(acquire(), (service) => asyncSucceed({
|
|
731
|
+
service,
|
|
732
|
+
release: release ? () => release(service) : () => unit()
|
|
733
|
+
}))
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function layerFrom() {
|
|
737
|
+
return (acquire, release) => ({
|
|
738
|
+
_tag: "Layer",
|
|
739
|
+
build: (deps) => asyncFlatMap(acquire(deps), (service) => asyncSucceed({
|
|
740
|
+
service,
|
|
741
|
+
release: release ? () => release(service) : () => unit()
|
|
742
|
+
}))
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
function layerSucceed(value) {
|
|
746
|
+
return {
|
|
747
|
+
_tag: "Layer",
|
|
748
|
+
build: () => asyncSucceed({ service: value, release: () => unit() })
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
function layerFail(error) {
|
|
752
|
+
return {
|
|
753
|
+
_tag: "Layer",
|
|
754
|
+
build: () => asyncFail(error)
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
function compose(from, to) {
|
|
758
|
+
return {
|
|
759
|
+
_tag: "Layer",
|
|
760
|
+
build: (deps) => asyncFlatMap(
|
|
761
|
+
from.build(deps),
|
|
762
|
+
({ service: mid, release: releaseMid }) => asyncFold(
|
|
763
|
+
to.build(mid),
|
|
764
|
+
(error) => asyncFlatMap(releaseMid(), () => asyncFail(error)),
|
|
765
|
+
({ service: out, release: releaseOut }) => asyncSucceed({
|
|
766
|
+
service: out,
|
|
767
|
+
release: () => asyncFlatMap(releaseOut(), () => releaseMid())
|
|
768
|
+
})
|
|
769
|
+
)
|
|
770
|
+
)
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
function merge2(left, right) {
|
|
774
|
+
return {
|
|
775
|
+
_tag: "Layer",
|
|
776
|
+
build: (deps) => asyncFlatMap(
|
|
777
|
+
left.build(deps),
|
|
778
|
+
({ service: a, release: releaseA }) => asyncFold(
|
|
779
|
+
right.build(deps),
|
|
780
|
+
(error) => asyncFlatMap(releaseA(), () => asyncFail(error)),
|
|
781
|
+
({ service: b, release: releaseB }) => asyncSucceed({
|
|
782
|
+
service: { ...a, ...b },
|
|
783
|
+
release: () => asyncFlatMap(releaseB(), () => releaseA())
|
|
784
|
+
})
|
|
785
|
+
)
|
|
786
|
+
)
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
function mapLayer(l, f) {
|
|
790
|
+
return {
|
|
791
|
+
_tag: "Layer",
|
|
792
|
+
build: (deps) => asyncFlatMap(
|
|
793
|
+
l.build(deps),
|
|
794
|
+
({ service, release }) => asyncSucceed({ service: f(service), release })
|
|
795
|
+
)
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
function provideLayer(l, use, deps) {
|
|
799
|
+
return asyncFlatMap(
|
|
800
|
+
l.build(deps ?? {}),
|
|
801
|
+
({ service, release }) => asyncFold(
|
|
802
|
+
use(service),
|
|
803
|
+
(error) => asyncFlatMap(release(), () => asyncFail(error)),
|
|
804
|
+
(value) => asyncFlatMap(release(), () => asyncSucceed(value))
|
|
805
|
+
)
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// src/core/runtime/workerPool.ts
|
|
810
|
+
function makeWorkerPool(config = {}) {
|
|
811
|
+
const size = config.size ?? 4;
|
|
812
|
+
const maxQueue = config.maxQueue ?? 1e3;
|
|
813
|
+
const taskTimeoutMs = config.taskTimeoutMs ?? 3e4;
|
|
814
|
+
let closed = false;
|
|
815
|
+
let busy = 0;
|
|
816
|
+
let completed = 0;
|
|
817
|
+
let failed = 0;
|
|
818
|
+
let timedOut = 0;
|
|
819
|
+
const queue = [];
|
|
820
|
+
const processNext = () => {
|
|
821
|
+
if (queue.length === 0 || busy >= size) return;
|
|
822
|
+
const task = queue.shift();
|
|
823
|
+
busy++;
|
|
824
|
+
setImmediate(() => {
|
|
825
|
+
if (task.timeoutId) clearTimeout(task.timeoutId);
|
|
826
|
+
try {
|
|
827
|
+
const result = task.fn();
|
|
828
|
+
busy--;
|
|
829
|
+
completed++;
|
|
830
|
+
task.resolve(result);
|
|
831
|
+
processNext();
|
|
832
|
+
} catch (e) {
|
|
833
|
+
busy--;
|
|
834
|
+
failed++;
|
|
835
|
+
task.reject({ _tag: "WorkerTaskError", message: String(e) });
|
|
836
|
+
processNext();
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
};
|
|
840
|
+
const execute = (fn) => {
|
|
841
|
+
if (closed) return asyncFail({ _tag: "WorkerPoolClosed" });
|
|
842
|
+
if (queue.length >= maxQueue) {
|
|
843
|
+
return asyncFail({ _tag: "WorkerPoolFull", queued: queue.length });
|
|
844
|
+
}
|
|
845
|
+
return async((_env, cb) => {
|
|
846
|
+
const task = {
|
|
847
|
+
fn,
|
|
848
|
+
resolve: (value) => cb({ _tag: "Success", value }),
|
|
849
|
+
reject: (error) => cb({ _tag: "Failure", cause: { _tag: "Fail", error } })
|
|
850
|
+
};
|
|
851
|
+
task.timeoutId = setTimeout(() => {
|
|
852
|
+
const idx = queue.indexOf(task);
|
|
853
|
+
if (idx >= 0) {
|
|
854
|
+
queue.splice(idx, 1);
|
|
855
|
+
timedOut++;
|
|
856
|
+
task.reject({ _tag: "WorkerTaskTimeout", ms: taskTimeoutMs });
|
|
857
|
+
}
|
|
858
|
+
}, taskTimeoutMs);
|
|
859
|
+
queue.push(task);
|
|
860
|
+
processNext();
|
|
861
|
+
return () => {
|
|
862
|
+
const idx = queue.indexOf(task);
|
|
863
|
+
if (idx >= 0) {
|
|
864
|
+
queue.splice(idx, 1);
|
|
865
|
+
if (task.timeoutId) clearTimeout(task.timeoutId);
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
});
|
|
869
|
+
};
|
|
870
|
+
const run = (taskSource, args = []) => {
|
|
871
|
+
return execute(() => {
|
|
872
|
+
const fn = new Function(...args.map((_, i) => `arg${i}`), taskSource);
|
|
873
|
+
return fn(...args);
|
|
874
|
+
});
|
|
875
|
+
};
|
|
876
|
+
return {
|
|
877
|
+
execute,
|
|
878
|
+
run,
|
|
879
|
+
stats: () => ({
|
|
880
|
+
size,
|
|
881
|
+
busy,
|
|
882
|
+
idle: size - busy,
|
|
883
|
+
queued: queue.length,
|
|
884
|
+
completed,
|
|
885
|
+
failed,
|
|
886
|
+
timedOut
|
|
887
|
+
}),
|
|
888
|
+
shutdown: async () => {
|
|
889
|
+
closed = true;
|
|
890
|
+
while (queue.length > 0) {
|
|
891
|
+
const task = queue.shift();
|
|
892
|
+
if (task.timeoutId) clearTimeout(task.timeoutId);
|
|
893
|
+
task.reject({ _tag: "WorkerPoolClosed" });
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// src/core/runtime/tracing.ts
|
|
900
|
+
var idCounter = 0;
|
|
901
|
+
function generateId() {
|
|
902
|
+
return (++idCounter).toString(16).padStart(16, "0");
|
|
903
|
+
}
|
|
904
|
+
function makeTracer(config) {
|
|
905
|
+
const completedSpans = [];
|
|
906
|
+
const sampleRate = config.sampleRate ?? 1;
|
|
907
|
+
const shouldSample = () => {
|
|
908
|
+
if (sampleRate >= 1) return true;
|
|
909
|
+
if (sampleRate <= 0) return false;
|
|
910
|
+
return Math.random() < sampleRate;
|
|
911
|
+
};
|
|
912
|
+
const span = (name, effect, attributes) => {
|
|
913
|
+
if (!shouldSample()) return effect;
|
|
914
|
+
const spanObj = {
|
|
915
|
+
name,
|
|
916
|
+
context: {
|
|
917
|
+
traceId: generateId(),
|
|
918
|
+
spanId: generateId()
|
|
919
|
+
},
|
|
920
|
+
startTime: performance.now(),
|
|
921
|
+
status: "unset",
|
|
922
|
+
attributes: { "service.name": config.serviceName, ...attributes },
|
|
923
|
+
events: []
|
|
924
|
+
};
|
|
925
|
+
return asyncFold(
|
|
926
|
+
effect,
|
|
927
|
+
(error) => {
|
|
928
|
+
spanObj.endTime = performance.now();
|
|
929
|
+
spanObj.status = "error";
|
|
930
|
+
spanObj.events.push({
|
|
931
|
+
name: "error",
|
|
932
|
+
time: performance.now(),
|
|
933
|
+
attributes: { "error.message": String(error) }
|
|
934
|
+
});
|
|
935
|
+
completedSpans.push(spanObj);
|
|
936
|
+
config.onSpanEnd?.(spanObj);
|
|
937
|
+
return asyncFail(error);
|
|
938
|
+
},
|
|
939
|
+
(value) => {
|
|
940
|
+
spanObj.endTime = performance.now();
|
|
941
|
+
spanObj.status = "ok";
|
|
942
|
+
completedSpans.push(spanObj);
|
|
943
|
+
config.onSpanEnd?.(spanObj);
|
|
944
|
+
return asyncSucceed(value);
|
|
945
|
+
}
|
|
946
|
+
);
|
|
947
|
+
};
|
|
948
|
+
return {
|
|
949
|
+
span,
|
|
950
|
+
spans: () => completedSpans,
|
|
951
|
+
clear: () => {
|
|
952
|
+
completedSpans.length = 0;
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// src/core/runtime/metrics.ts
|
|
958
|
+
var DEFAULT_BOUNDARIES = [1, 5, 10, 25, 50, 100, 250, 500, 1e3, 5e3, 1e4];
|
|
959
|
+
function makeMetrics() {
|
|
960
|
+
const counters = /* @__PURE__ */ new Map();
|
|
961
|
+
const gauges = /* @__PURE__ */ new Map();
|
|
962
|
+
const histograms = /* @__PURE__ */ new Map();
|
|
963
|
+
const key = (name, labels) => labels ? `${name}|${Object.entries(labels).sort().map(([k, v]) => `${k}=${v}`).join(",")}` : name;
|
|
964
|
+
const counter = (name, labels = {}) => {
|
|
965
|
+
const k = key(name, labels);
|
|
966
|
+
if (!counters.has(k)) counters.set(k, { labels, value: 0 });
|
|
967
|
+
const entry = counters.get(k);
|
|
968
|
+
return {
|
|
969
|
+
increment: (n = 1) => {
|
|
970
|
+
entry.value += Math.max(0, n);
|
|
971
|
+
},
|
|
972
|
+
value: () => entry.value
|
|
973
|
+
};
|
|
974
|
+
};
|
|
975
|
+
const gauge = (name, labels = {}) => {
|
|
976
|
+
const k = key(name, labels);
|
|
977
|
+
if (!gauges.has(k)) gauges.set(k, { labels, value: 0 });
|
|
978
|
+
const entry = gauges.get(k);
|
|
979
|
+
return {
|
|
980
|
+
set: (v) => {
|
|
981
|
+
entry.value = v;
|
|
982
|
+
},
|
|
983
|
+
increment: (n = 1) => {
|
|
984
|
+
entry.value += n;
|
|
985
|
+
},
|
|
986
|
+
decrement: (n = 1) => {
|
|
987
|
+
entry.value -= n;
|
|
988
|
+
},
|
|
989
|
+
value: () => entry.value
|
|
990
|
+
};
|
|
991
|
+
};
|
|
992
|
+
const histogram = (name, boundaries = DEFAULT_BOUNDARIES, labels = {}) => {
|
|
993
|
+
const k = key(name, labels);
|
|
994
|
+
if (!histograms.has(k)) {
|
|
995
|
+
const sorted = [...boundaries].sort((a, b) => a - b);
|
|
996
|
+
histograms.set(k, {
|
|
997
|
+
labels,
|
|
998
|
+
boundaries: sorted,
|
|
999
|
+
data: { boundaries: sorted, counts: new Array(sorted.length + 1).fill(0), sum: 0, count: 0, min: Infinity, max: -Infinity }
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
const entry = histograms.get(k);
|
|
1003
|
+
return {
|
|
1004
|
+
observe: (value) => {
|
|
1005
|
+
entry.data.sum += value;
|
|
1006
|
+
entry.data.count++;
|
|
1007
|
+
entry.data.min = Math.min(entry.data.min, value);
|
|
1008
|
+
entry.data.max = Math.max(entry.data.max, value);
|
|
1009
|
+
let placed = false;
|
|
1010
|
+
for (let i = 0; i < entry.boundaries.length; i++) {
|
|
1011
|
+
if (value <= entry.boundaries[i]) {
|
|
1012
|
+
entry.data.counts[i]++;
|
|
1013
|
+
placed = true;
|
|
1014
|
+
break;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
if (!placed) entry.data.counts[entry.boundaries.length]++;
|
|
1018
|
+
},
|
|
1019
|
+
buckets: () => ({ ...entry.data }),
|
|
1020
|
+
percentile: (p) => {
|
|
1021
|
+
const target = Math.ceil(entry.data.count * (p / 100));
|
|
1022
|
+
let cumulative = 0;
|
|
1023
|
+
for (let i = 0; i < entry.boundaries.length; i++) {
|
|
1024
|
+
cumulative += entry.data.counts[i];
|
|
1025
|
+
if (cumulative >= target) return entry.boundaries[i];
|
|
1026
|
+
}
|
|
1027
|
+
return entry.data.max;
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
};
|
|
1031
|
+
return {
|
|
1032
|
+
counter,
|
|
1033
|
+
gauge,
|
|
1034
|
+
histogram,
|
|
1035
|
+
snapshot: () => ({
|
|
1036
|
+
counters: Array.from(counters.entries()).map(([k, v]) => ({ name: k.split("|")[0], labels: v.labels, value: v.value })),
|
|
1037
|
+
gauges: Array.from(gauges.entries()).map(([k, v]) => ({ name: k.split("|")[0], labels: v.labels, value: v.value })),
|
|
1038
|
+
histograms: Array.from(histograms.entries()).map(([k, v]) => ({ name: k.split("|")[0], labels: v.labels, buckets: v.data }))
|
|
1039
|
+
}),
|
|
1040
|
+
reset: () => {
|
|
1041
|
+
counters.clear();
|
|
1042
|
+
gauges.clear();
|
|
1043
|
+
histograms.clear();
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// src/core/types/typedError.ts
|
|
1049
|
+
function catchTag(effect, tag, handler) {
|
|
1050
|
+
return asyncFold(
|
|
1051
|
+
effect,
|
|
1052
|
+
(error) => {
|
|
1053
|
+
if (typeof error === "object" && error !== null && "_tag" in error && error._tag === tag) {
|
|
1054
|
+
return handler(error);
|
|
1055
|
+
}
|
|
1056
|
+
return asyncFail(error);
|
|
1057
|
+
},
|
|
1058
|
+
(value) => asyncSucceed(value)
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
function catchTags(effect, handlers) {
|
|
1062
|
+
return asyncFold(
|
|
1063
|
+
effect,
|
|
1064
|
+
(error) => {
|
|
1065
|
+
if (typeof error === "object" && error !== null && "_tag" in error) {
|
|
1066
|
+
const handler = handlers[error._tag];
|
|
1067
|
+
if (handler) return handler(error);
|
|
1068
|
+
}
|
|
1069
|
+
return asyncFail(error);
|
|
1070
|
+
},
|
|
1071
|
+
(value) => asyncSucceed(value)
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
function mapError2(effect, f) {
|
|
1075
|
+
return asyncFold(
|
|
1076
|
+
effect,
|
|
1077
|
+
(error) => asyncFail(f(error)),
|
|
1078
|
+
(value) => asyncSucceed(value)
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
function tagError(effect, tag, enrich) {
|
|
1082
|
+
return asyncFold(
|
|
1083
|
+
effect,
|
|
1084
|
+
(error) => {
|
|
1085
|
+
const fields = enrich ? enrich(error) : {};
|
|
1086
|
+
return asyncFail({ _tag: tag, ...fields });
|
|
1087
|
+
},
|
|
1088
|
+
(value) => asyncSucceed(value)
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
function orElse(effect, fallback) {
|
|
1092
|
+
return asyncFold(
|
|
1093
|
+
effect,
|
|
1094
|
+
(error) => fallback(error),
|
|
1095
|
+
(value) => asyncSucceed(value)
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
166
1099
|
// src/core/stream/queue.ts
|
|
167
1100
|
function bounded(capacity, strategy = "backpressure", options = {}) {
|
|
168
1101
|
return asyncSync(() => makeQueue(capacity, strategy, options));
|
|
@@ -250,6 +1183,61 @@ function makeQueue(capacity, strategy, options) {
|
|
|
250
1183
|
takers.remove(node);
|
|
251
1184
|
};
|
|
252
1185
|
return canceler;
|
|
1186
|
+
}),
|
|
1187
|
+
offerBatch: (values) => asyncSync(() => {
|
|
1188
|
+
const results = [];
|
|
1189
|
+
for (let i = 0; i < values.length; i++) {
|
|
1190
|
+
if (closed) {
|
|
1191
|
+
results.push(false);
|
|
1192
|
+
continue;
|
|
1193
|
+
}
|
|
1194
|
+
const a = values[i];
|
|
1195
|
+
if (takers.length > 0) {
|
|
1196
|
+
const t = takers.shift();
|
|
1197
|
+
t({ _tag: "Success", value: a });
|
|
1198
|
+
results.push(true);
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
if (items.length < capacity) {
|
|
1202
|
+
items.push(a);
|
|
1203
|
+
results.push(true);
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
if (strategy === "dropping") {
|
|
1207
|
+
results.push(false);
|
|
1208
|
+
} else if (strategy === "sliding") {
|
|
1209
|
+
items.shift();
|
|
1210
|
+
items.push(a);
|
|
1211
|
+
results.push(true);
|
|
1212
|
+
} else {
|
|
1213
|
+
results.push(false);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return results;
|
|
1217
|
+
}),
|
|
1218
|
+
takeBatch: (n) => asyncSync(() => {
|
|
1219
|
+
const results = [];
|
|
1220
|
+
const count = Math.min(n, items.length + offerWaiters.length);
|
|
1221
|
+
for (let i = 0; i < count; i++) {
|
|
1222
|
+
if (items.length > 0) {
|
|
1223
|
+
results.push(items.shift());
|
|
1224
|
+
if (offerWaiters.length > 0 && items.length < capacity) {
|
|
1225
|
+
const w = offerWaiters.shift();
|
|
1226
|
+
items.push(w.a);
|
|
1227
|
+
w.cb(true);
|
|
1228
|
+
}
|
|
1229
|
+
} else if (offerWaiters.length > 0) {
|
|
1230
|
+
const w = offerWaiters.shift();
|
|
1231
|
+
w.cb(true);
|
|
1232
|
+
results.push(w.a);
|
|
1233
|
+
} else {
|
|
1234
|
+
break;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
if (results.length === 0 && closed) {
|
|
1238
|
+
throw QueueClosedErr;
|
|
1239
|
+
}
|
|
1240
|
+
return results;
|
|
253
1241
|
})
|
|
254
1242
|
};
|
|
255
1243
|
}
|
|
@@ -431,14 +1419,12 @@ function resolveWasmChunkBuffer() {
|
|
|
431
1419
|
cachedWasmChunkCtor = mod?.BrassWasmChunkBuffer ?? null;
|
|
432
1420
|
return cachedWasmChunkCtor;
|
|
433
1421
|
}
|
|
434
|
-
var
|
|
435
|
-
constructor(maxChunkSize
|
|
1422
|
+
var TsChunker = class {
|
|
1423
|
+
constructor(maxChunkSize) {
|
|
436
1424
|
this.maxChunkSize = maxChunkSize;
|
|
437
|
-
this.fallbackUsed = fallbackUsed;
|
|
438
1425
|
}
|
|
439
1426
|
maxChunkSize;
|
|
440
|
-
|
|
441
|
-
engine = "js";
|
|
1427
|
+
engine = "ts";
|
|
442
1428
|
values = [];
|
|
443
1429
|
emittedChunks = 0;
|
|
444
1430
|
emittedItems = 0;
|
|
@@ -472,8 +1458,8 @@ var JsChunker = class {
|
|
|
472
1458
|
}
|
|
473
1459
|
stats() {
|
|
474
1460
|
return {
|
|
475
|
-
engine: "
|
|
476
|
-
fallbackUsed:
|
|
1461
|
+
engine: "ts",
|
|
1462
|
+
fallbackUsed: false,
|
|
477
1463
|
data: {
|
|
478
1464
|
len: this.values.length,
|
|
479
1465
|
maxChunkSize: this.maxChunkSize,
|
|
@@ -522,10 +1508,10 @@ var WasmChunker = class {
|
|
|
522
1508
|
};
|
|
523
1509
|
function makeStreamChunker(chunkSize, options = {}) {
|
|
524
1510
|
const size = Math.max(1, chunkSize | 0);
|
|
525
|
-
const engine = options.engine ?? "
|
|
526
|
-
if (engine === "
|
|
1511
|
+
const engine = options.engine ?? "ts";
|
|
1512
|
+
if (engine === "ts") return new TsChunker(size);
|
|
527
1513
|
if (engine === "wasm") return new WasmChunker(size);
|
|
528
|
-
|
|
1514
|
+
throw new Error(`brass-runtime stream chunk engine must be 'ts' or 'wasm'; received '${String(engine)}'`);
|
|
529
1515
|
}
|
|
530
1516
|
function chunks(input, chunkSize, options = {}) {
|
|
531
1517
|
const size = Math.max(1, chunkSize | 0);
|
|
@@ -591,21 +1577,430 @@ function mapChunksEffect(chunkSize, f, options = {}) {
|
|
|
591
1577
|
});
|
|
592
1578
|
}
|
|
593
1579
|
|
|
1580
|
+
// src/core/stream/fusion.ts
|
|
1581
|
+
var _fusionEnabled = true;
|
|
1582
|
+
var _fusionVerbose = false;
|
|
1583
|
+
function setFusionEnabled(enabled) {
|
|
1584
|
+
_fusionEnabled = enabled;
|
|
1585
|
+
}
|
|
1586
|
+
function isFusionEnabled() {
|
|
1587
|
+
return _fusionEnabled;
|
|
1588
|
+
}
|
|
1589
|
+
function setFusionVerbose(verbose) {
|
|
1590
|
+
_fusionVerbose = verbose;
|
|
1591
|
+
}
|
|
1592
|
+
function isFusionVerbose() {
|
|
1593
|
+
return _fusionVerbose;
|
|
1594
|
+
}
|
|
1595
|
+
function getStats(pipeline) {
|
|
1596
|
+
const p = pipeline;
|
|
1597
|
+
if (p._fusedSteps && Array.isArray(p._fusedSteps)) {
|
|
1598
|
+
const metas = p._fusedSteps;
|
|
1599
|
+
return buildStats(metas);
|
|
1600
|
+
}
|
|
1601
|
+
if (p[PURE_PIPELINE_TAG]) {
|
|
1602
|
+
return null;
|
|
1603
|
+
}
|
|
1604
|
+
return null;
|
|
1605
|
+
}
|
|
1606
|
+
var PURE_PIPELINE_TAG = /* @__PURE__ */ Symbol("brass:pure-pipeline");
|
|
1607
|
+
function makeMapStep(fn) {
|
|
1608
|
+
return (a, _state) => ({ tag: "emit", value: fn(a) });
|
|
1609
|
+
}
|
|
1610
|
+
function makeFilterStep(pred) {
|
|
1611
|
+
return (a, _state) => pred(a) ? { tag: "emit", value: a } : { tag: "skip" };
|
|
1612
|
+
}
|
|
1613
|
+
function makeTakeStep(n, counterIndex) {
|
|
1614
|
+
return (a, state) => {
|
|
1615
|
+
if (state.counters[counterIndex] >= n) {
|
|
1616
|
+
return { tag: "halt" };
|
|
1617
|
+
}
|
|
1618
|
+
state.counters[counterIndex]++;
|
|
1619
|
+
return { tag: "emit", value: a };
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
function makeDropStep(n, counterIndex) {
|
|
1623
|
+
return (a, state) => {
|
|
1624
|
+
if (state.counters[counterIndex] < n) {
|
|
1625
|
+
state.counters[counterIndex]++;
|
|
1626
|
+
return { tag: "skip" };
|
|
1627
|
+
}
|
|
1628
|
+
return { tag: "emit", value: a };
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
function initState(counterCount) {
|
|
1632
|
+
return () => ({
|
|
1633
|
+
counters: new Array(counterCount).fill(0)
|
|
1634
|
+
});
|
|
1635
|
+
}
|
|
1636
|
+
function composeSteps(step1, step2) {
|
|
1637
|
+
return (a, state) => {
|
|
1638
|
+
const r1 = step1(a, state);
|
|
1639
|
+
if (r1.tag !== "emit") return r1;
|
|
1640
|
+
return step2(r1.value, state);
|
|
1641
|
+
};
|
|
1642
|
+
}
|
|
1643
|
+
function getPureTag(pipeline) {
|
|
1644
|
+
const tagged = pipeline;
|
|
1645
|
+
return tagged[PURE_PIPELINE_TAG] ?? null;
|
|
1646
|
+
}
|
|
1647
|
+
function getFusedSteps(pipeline) {
|
|
1648
|
+
const p = pipeline;
|
|
1649
|
+
if (p._fusedSteps && Array.isArray(p._fusedSteps)) {
|
|
1650
|
+
return p._fusedSteps;
|
|
1651
|
+
}
|
|
1652
|
+
return null;
|
|
1653
|
+
}
|
|
1654
|
+
function buildStepFromMetadata(meta, counterIndex) {
|
|
1655
|
+
switch (meta.kind) {
|
|
1656
|
+
case "map":
|
|
1657
|
+
return makeMapStep(meta.fn);
|
|
1658
|
+
case "filter":
|
|
1659
|
+
return makeFilterStep(meta.pred);
|
|
1660
|
+
case "take":
|
|
1661
|
+
return makeTakeStep(meta.n, counterIndex);
|
|
1662
|
+
case "drop":
|
|
1663
|
+
return makeDropStep(meta.n, counterIndex);
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
function buildStats(metas) {
|
|
1667
|
+
const steps = metas.map((m) => {
|
|
1668
|
+
switch (m.kind) {
|
|
1669
|
+
case "map":
|
|
1670
|
+
return { kind: "map" };
|
|
1671
|
+
case "filter":
|
|
1672
|
+
return { kind: "filter" };
|
|
1673
|
+
case "take":
|
|
1674
|
+
return { kind: "take", n: m.n };
|
|
1675
|
+
case "drop":
|
|
1676
|
+
return { kind: "drop", n: m.n };
|
|
1677
|
+
}
|
|
1678
|
+
});
|
|
1679
|
+
return {
|
|
1680
|
+
fusedSteps: steps.length,
|
|
1681
|
+
steps,
|
|
1682
|
+
hasTake: metas.some((m) => m.kind === "take"),
|
|
1683
|
+
hasDrop: metas.some((m) => m.kind === "drop")
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
function countCounters(metas) {
|
|
1687
|
+
let count = 0;
|
|
1688
|
+
for (const m of metas) {
|
|
1689
|
+
if (m.kind === "take" || m.kind === "drop") {
|
|
1690
|
+
count++;
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
return count;
|
|
1694
|
+
}
|
|
1695
|
+
function fuse(pipeline, options) {
|
|
1696
|
+
const verbose = options?.verbose ?? _fusionVerbose;
|
|
1697
|
+
if (options?.enabled === false || !_fusionEnabled && options?.enabled !== true) {
|
|
1698
|
+
if (verbose) {
|
|
1699
|
+
console.log("[FusionEngine] Fusion disabled by options");
|
|
1700
|
+
}
|
|
1701
|
+
return null;
|
|
1702
|
+
}
|
|
1703
|
+
const metas = collectMetadata(pipeline);
|
|
1704
|
+
if (!metas || metas.length === 0) {
|
|
1705
|
+
if (verbose) {
|
|
1706
|
+
console.log("[FusionEngine] Pipeline is not fusable (no pure tags detected)");
|
|
1707
|
+
}
|
|
1708
|
+
return null;
|
|
1709
|
+
}
|
|
1710
|
+
if (verbose) {
|
|
1711
|
+
console.log(
|
|
1712
|
+
`[FusionEngine] Fusing ${metas.length} steps: ${metas.map((m) => m.kind).join(" \u2192 ")}`
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
let counterIndex = 0;
|
|
1716
|
+
let composedStep = buildStepFromMetadata(
|
|
1717
|
+
metas[0],
|
|
1718
|
+
metas[0].kind === "take" || metas[0].kind === "drop" ? counterIndex++ : -1
|
|
1719
|
+
);
|
|
1720
|
+
for (let i = 1; i < metas.length; i++) {
|
|
1721
|
+
const meta = metas[i];
|
|
1722
|
+
const idx = meta.kind === "take" || meta.kind === "drop" ? counterIndex++ : -1;
|
|
1723
|
+
composedStep = composeSteps(composedStep, buildStepFromMetadata(meta, idx));
|
|
1724
|
+
}
|
|
1725
|
+
const counterCount = countCounters(metas);
|
|
1726
|
+
const stats = buildStats(metas);
|
|
1727
|
+
return {
|
|
1728
|
+
_tag: "FusedPipeline",
|
|
1729
|
+
step: composedStep,
|
|
1730
|
+
initState: initState(counterCount),
|
|
1731
|
+
stats
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
function collectMetadata(pipeline) {
|
|
1735
|
+
const fusedSteps = getFusedSteps(pipeline);
|
|
1736
|
+
if (fusedSteps) {
|
|
1737
|
+
return fusedSteps;
|
|
1738
|
+
}
|
|
1739
|
+
const tag = getPureTag(pipeline);
|
|
1740
|
+
if (tag) {
|
|
1741
|
+
return [tag];
|
|
1742
|
+
}
|
|
1743
|
+
return null;
|
|
1744
|
+
}
|
|
1745
|
+
function runFusedArray(input, fused) {
|
|
1746
|
+
const state = fused.initState();
|
|
1747
|
+
const output = [];
|
|
1748
|
+
for (let i = 0; i < input.length; i++) {
|
|
1749
|
+
const result = fused.step(input[i], state);
|
|
1750
|
+
switch (result.tag) {
|
|
1751
|
+
case "emit":
|
|
1752
|
+
output.push(result.value);
|
|
1753
|
+
break;
|
|
1754
|
+
case "skip":
|
|
1755
|
+
break;
|
|
1756
|
+
case "halt":
|
|
1757
|
+
return output;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
return output;
|
|
1761
|
+
}
|
|
1762
|
+
function drainStreamSync(stream) {
|
|
1763
|
+
const result = [];
|
|
1764
|
+
let cur = stream;
|
|
1765
|
+
while (true) {
|
|
1766
|
+
switch (cur._tag) {
|
|
1767
|
+
case "Empty":
|
|
1768
|
+
return result;
|
|
1769
|
+
case "FromArray": {
|
|
1770
|
+
const arr = cur.values;
|
|
1771
|
+
for (let i = 0; i < arr.length; i++) {
|
|
1772
|
+
result.push(arr[i]);
|
|
1773
|
+
}
|
|
1774
|
+
return result;
|
|
1775
|
+
}
|
|
1776
|
+
case "Emit": {
|
|
1777
|
+
const zio = cur.value;
|
|
1778
|
+
if (zio._tag === "Succeed") {
|
|
1779
|
+
result.push(zio.value);
|
|
1780
|
+
return result;
|
|
1781
|
+
}
|
|
1782
|
+
return null;
|
|
1783
|
+
}
|
|
1784
|
+
case "Concat": {
|
|
1785
|
+
const leftItems = drainStreamSync(cur.left);
|
|
1786
|
+
if (leftItems === null) return null;
|
|
1787
|
+
for (let i = 0; i < leftItems.length; i++) {
|
|
1788
|
+
result.push(leftItems[i]);
|
|
1789
|
+
}
|
|
1790
|
+
cur = cur.right;
|
|
1791
|
+
break;
|
|
1792
|
+
}
|
|
1793
|
+
default:
|
|
1794
|
+
return null;
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
function applyFused(stream, fused) {
|
|
1799
|
+
const inputArray = drainStreamSync(stream);
|
|
1800
|
+
if (inputArray !== null) {
|
|
1801
|
+
const outputArray = runFusedArray(inputArray, fused);
|
|
1802
|
+
return arrayToStream(outputArray);
|
|
1803
|
+
}
|
|
1804
|
+
const state = fused.initState();
|
|
1805
|
+
const loop = (cur) => fromPull(
|
|
1806
|
+
asyncFold(
|
|
1807
|
+
uncons(cur),
|
|
1808
|
+
// End-of-stream or error: propagate
|
|
1809
|
+
(opt) => asyncFail(opt),
|
|
1810
|
+
([a, tail]) => {
|
|
1811
|
+
const result = fused.step(a, state);
|
|
1812
|
+
switch (result.tag) {
|
|
1813
|
+
case "emit":
|
|
1814
|
+
return asyncSucceed([result.value, loop(tail)]);
|
|
1815
|
+
case "skip":
|
|
1816
|
+
return uncons(loop(tail));
|
|
1817
|
+
case "halt":
|
|
1818
|
+
return asyncFail(none);
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
)
|
|
1822
|
+
);
|
|
1823
|
+
return loop(stream);
|
|
1824
|
+
}
|
|
1825
|
+
function arrayToStream(values) {
|
|
1826
|
+
if (values.length === 0) return { _tag: "Empty" };
|
|
1827
|
+
return { _tag: "FromArray", values };
|
|
1828
|
+
}
|
|
1829
|
+
function serializeFusedPipeline(pipeline) {
|
|
1830
|
+
const p = pipeline;
|
|
1831
|
+
let metas = null;
|
|
1832
|
+
if (p._fusedSteps && Array.isArray(p._fusedSteps)) {
|
|
1833
|
+
metas = p._fusedSteps;
|
|
1834
|
+
} else if (p[PURE_PIPELINE_TAG]) {
|
|
1835
|
+
return null;
|
|
1836
|
+
}
|
|
1837
|
+
if (!metas || metas.length === 0) {
|
|
1838
|
+
return null;
|
|
1839
|
+
}
|
|
1840
|
+
const steps = metas.map((meta) => {
|
|
1841
|
+
switch (meta.kind) {
|
|
1842
|
+
case "map":
|
|
1843
|
+
return { kind: "map", fnSource: meta.fn.toString() };
|
|
1844
|
+
case "filter":
|
|
1845
|
+
return { kind: "filter", predSource: meta.pred.toString() };
|
|
1846
|
+
case "take":
|
|
1847
|
+
return { kind: "take", n: meta.n };
|
|
1848
|
+
case "drop":
|
|
1849
|
+
return { kind: "drop", n: meta.n };
|
|
1850
|
+
}
|
|
1851
|
+
});
|
|
1852
|
+
return { version: 1, steps };
|
|
1853
|
+
}
|
|
1854
|
+
function deserializeFusedPipeline(serialized) {
|
|
1855
|
+
try {
|
|
1856
|
+
if (serialized.version !== 1) {
|
|
1857
|
+
return null;
|
|
1858
|
+
}
|
|
1859
|
+
if (!serialized.steps || serialized.steps.length === 0) {
|
|
1860
|
+
return null;
|
|
1861
|
+
}
|
|
1862
|
+
const metas = [];
|
|
1863
|
+
for (const step of serialized.steps) {
|
|
1864
|
+
switch (step.kind) {
|
|
1865
|
+
case "map": {
|
|
1866
|
+
const fn = new Function("return " + step.fnSource)();
|
|
1867
|
+
if (typeof fn !== "function") return null;
|
|
1868
|
+
metas.push({ kind: "map", fn });
|
|
1869
|
+
break;
|
|
1870
|
+
}
|
|
1871
|
+
case "filter": {
|
|
1872
|
+
const pred = new Function("return " + step.predSource)();
|
|
1873
|
+
if (typeof pred !== "function") return null;
|
|
1874
|
+
metas.push({ kind: "filter", pred });
|
|
1875
|
+
break;
|
|
1876
|
+
}
|
|
1877
|
+
case "take": {
|
|
1878
|
+
if (typeof step.n !== "number" || step.n < 0) return null;
|
|
1879
|
+
metas.push({ kind: "take", n: step.n });
|
|
1880
|
+
break;
|
|
1881
|
+
}
|
|
1882
|
+
case "drop": {
|
|
1883
|
+
if (typeof step.n !== "number" || step.n < 0) return null;
|
|
1884
|
+
metas.push({ kind: "drop", n: step.n });
|
|
1885
|
+
break;
|
|
1886
|
+
}
|
|
1887
|
+
default:
|
|
1888
|
+
return null;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
const carrier = createDeserializedCarrier(metas);
|
|
1892
|
+
return carrier;
|
|
1893
|
+
} catch {
|
|
1894
|
+
return null;
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
function createDeserializedCarrier(metas) {
|
|
1898
|
+
let counterIndex = 0;
|
|
1899
|
+
let composedStep = buildStepFromMetadata(
|
|
1900
|
+
metas[0],
|
|
1901
|
+
metas[0].kind === "take" || metas[0].kind === "drop" ? counterIndex++ : -1
|
|
1902
|
+
);
|
|
1903
|
+
for (let i = 1; i < metas.length; i++) {
|
|
1904
|
+
const meta = metas[i];
|
|
1905
|
+
const idx = meta.kind === "take" || meta.kind === "drop" ? counterIndex++ : -1;
|
|
1906
|
+
composedStep = composeSteps(composedStep, buildStepFromMetadata(meta, idx));
|
|
1907
|
+
}
|
|
1908
|
+
const counterCount = countCounters(metas);
|
|
1909
|
+
const stats = buildStats(metas);
|
|
1910
|
+
const fusedRepr = {
|
|
1911
|
+
_tag: "FusedPipeline",
|
|
1912
|
+
step: composedStep,
|
|
1913
|
+
initState: initState(counterCount),
|
|
1914
|
+
stats
|
|
1915
|
+
};
|
|
1916
|
+
const pipeline = ((input) => {
|
|
1917
|
+
return applyFused(input, fusedRepr);
|
|
1918
|
+
});
|
|
1919
|
+
pipeline._fusedSteps = metas;
|
|
1920
|
+
return pipeline;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
594
1923
|
// src/core/stream/pipeline.ts
|
|
595
1924
|
function via(stream, pipeline) {
|
|
1925
|
+
if (isFusionEnabled()) {
|
|
1926
|
+
const p = pipeline;
|
|
1927
|
+
if (p._fusedSteps || p[PURE_PIPELINE_TAG]) {
|
|
1928
|
+
let fusedRepr = p._cachedFusedRepr;
|
|
1929
|
+
if (!fusedRepr) {
|
|
1930
|
+
fusedRepr = fuse(pipeline);
|
|
1931
|
+
if (fusedRepr) p._cachedFusedRepr = fusedRepr;
|
|
1932
|
+
}
|
|
1933
|
+
if (fusedRepr) {
|
|
1934
|
+
return applyFused(stream, fusedRepr);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
596
1938
|
return pipeline(stream);
|
|
597
1939
|
}
|
|
598
|
-
function
|
|
1940
|
+
function andThen2(p1, p2) {
|
|
1941
|
+
const fused = tryFuse(p1, p2);
|
|
1942
|
+
if (fused) return fused;
|
|
599
1943
|
return ((input) => p2(p1(input)));
|
|
600
1944
|
}
|
|
601
|
-
function
|
|
602
|
-
|
|
1945
|
+
function collectPureMetas(pipeline) {
|
|
1946
|
+
const p = pipeline;
|
|
1947
|
+
if (p._fusedSteps && Array.isArray(p._fusedSteps)) {
|
|
1948
|
+
return p._fusedSteps;
|
|
1949
|
+
}
|
|
1950
|
+
const tag = p[PURE_PIPELINE_TAG];
|
|
1951
|
+
if (tag) {
|
|
1952
|
+
return [tag];
|
|
1953
|
+
}
|
|
1954
|
+
return null;
|
|
1955
|
+
}
|
|
1956
|
+
function tryFuse(p1, p2) {
|
|
1957
|
+
if (!isFusionEnabled()) {
|
|
1958
|
+
if (isFusionVerbose()) {
|
|
1959
|
+
console.log("[FusionEngine] andThen: fusion globally disabled, skipping");
|
|
1960
|
+
}
|
|
1961
|
+
return null;
|
|
1962
|
+
}
|
|
1963
|
+
const metas1 = collectPureMetas(p1);
|
|
1964
|
+
const metas2 = collectPureMetas(p2);
|
|
1965
|
+
if (!metas1 || !metas2) {
|
|
1966
|
+
if (isFusionVerbose()) {
|
|
1967
|
+
const reason = !metas1 && !metas2 ? "neither operand is pure" : !metas1 ? "left operand is not pure" : "right operand is not pure";
|
|
1968
|
+
console.log(`[FusionEngine] andThen: cannot fuse \u2014 ${reason}`);
|
|
1969
|
+
}
|
|
1970
|
+
return null;
|
|
1971
|
+
}
|
|
1972
|
+
const combinedMetas = [...metas1, ...metas2];
|
|
1973
|
+
const fusedRepr = fuse(
|
|
1974
|
+
createMetadataCarrier(combinedMetas)
|
|
1975
|
+
);
|
|
1976
|
+
if (!fusedRepr) {
|
|
1977
|
+
return null;
|
|
1978
|
+
}
|
|
1979
|
+
if (isFusionVerbose()) {
|
|
1980
|
+
console.log(
|
|
1981
|
+
`[FusionEngine] andThen: fused ${combinedMetas.length} steps: ${combinedMetas.map((m) => m.kind).join(" \u2192 ")}`
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
const fusedPipeline = ((input) => {
|
|
1985
|
+
return applyFused(input, fusedRepr);
|
|
1986
|
+
});
|
|
1987
|
+
fusedPipeline._fusedSteps = combinedMetas;
|
|
1988
|
+
return fusedPipeline;
|
|
1989
|
+
}
|
|
1990
|
+
function createMetadataCarrier(metas) {
|
|
1991
|
+
const carrier = (() => {
|
|
1992
|
+
});
|
|
1993
|
+
carrier._fusedSteps = metas;
|
|
1994
|
+
return carrier;
|
|
1995
|
+
}
|
|
1996
|
+
function compose2(p2, p1) {
|
|
1997
|
+
return andThen2(p1, p2);
|
|
603
1998
|
}
|
|
604
1999
|
function identity() {
|
|
605
2000
|
return ((input) => input);
|
|
606
2001
|
}
|
|
607
2002
|
function mapP(f) {
|
|
608
|
-
|
|
2003
|
+
const pipeline = ((input) => {
|
|
609
2004
|
const onError = (opt) => asyncFail(opt);
|
|
610
2005
|
const onSuccess = ([a, tail]) => asyncSucceed([f(a), loop(tail)]);
|
|
611
2006
|
const loop = (cur) => fromPull(
|
|
@@ -613,15 +2008,19 @@ function mapP(f) {
|
|
|
613
2008
|
);
|
|
614
2009
|
return loop(input);
|
|
615
2010
|
});
|
|
2011
|
+
pipeline[PURE_PIPELINE_TAG] = { kind: "map", fn: f };
|
|
2012
|
+
return pipeline;
|
|
616
2013
|
}
|
|
617
2014
|
function filterP(pred) {
|
|
618
|
-
|
|
2015
|
+
const pipeline = ((input) => {
|
|
619
2016
|
const onError = (opt) => asyncFail(opt);
|
|
620
2017
|
const onSuccess = ([a, tail]) => pred(a) ? asyncSucceed([a, loop(tail)]) : next(tail);
|
|
621
2018
|
const next = (cur) => asyncFold(uncons(cur), onError, onSuccess);
|
|
622
2019
|
const loop = (cur) => fromPull(next(cur));
|
|
623
2020
|
return loop(input);
|
|
624
2021
|
});
|
|
2022
|
+
pipeline[PURE_PIPELINE_TAG] = { kind: "filter", pred };
|
|
2023
|
+
return pipeline;
|
|
625
2024
|
}
|
|
626
2025
|
function filterMapP(f) {
|
|
627
2026
|
return ((input) => {
|
|
@@ -640,7 +2039,7 @@ function filterMapP(f) {
|
|
|
640
2039
|
}
|
|
641
2040
|
function takeP(n) {
|
|
642
2041
|
const m = Math.max(0, n | 0);
|
|
643
|
-
|
|
2042
|
+
const pipeline = ((input) => {
|
|
644
2043
|
const loop = (cur, remaining) => {
|
|
645
2044
|
if (remaining <= 0) return emptyStream();
|
|
646
2045
|
return fromPull(
|
|
@@ -653,10 +2052,12 @@ function takeP(n) {
|
|
|
653
2052
|
};
|
|
654
2053
|
return loop(input, m);
|
|
655
2054
|
});
|
|
2055
|
+
pipeline[PURE_PIPELINE_TAG] = { kind: "take", n: m };
|
|
2056
|
+
return pipeline;
|
|
656
2057
|
}
|
|
657
2058
|
function dropP(n) {
|
|
658
2059
|
const m = Math.max(0, n | 0);
|
|
659
|
-
|
|
2060
|
+
const pipeline = ((input) => {
|
|
660
2061
|
const skip = (cur, remaining) => {
|
|
661
2062
|
if (remaining <= 0) return cur;
|
|
662
2063
|
return fromPull(
|
|
@@ -669,6 +2070,8 @@ function dropP(n) {
|
|
|
669
2070
|
};
|
|
670
2071
|
return skip(input, m);
|
|
671
2072
|
});
|
|
2073
|
+
pipeline[PURE_PIPELINE_TAG] = { kind: "drop", n: m };
|
|
2074
|
+
return pipeline;
|
|
672
2075
|
}
|
|
673
2076
|
function mapEffectP(f) {
|
|
674
2077
|
return ((input) => {
|
|
@@ -731,25 +2134,187 @@ function groupedP(n) {
|
|
|
731
2134
|
});
|
|
732
2135
|
}
|
|
733
2136
|
|
|
2137
|
+
// src/core/stream/operators.ts
|
|
2138
|
+
function throttle(stream, intervalMs) {
|
|
2139
|
+
let lastEmitTime = 0;
|
|
2140
|
+
const loop = (cur) => fromPull(
|
|
2141
|
+
asyncFold(
|
|
2142
|
+
uncons(cur),
|
|
2143
|
+
(opt) => asyncFail(opt),
|
|
2144
|
+
([a, tail]) => {
|
|
2145
|
+
const now = Date.now();
|
|
2146
|
+
if (now - lastEmitTime >= intervalMs) {
|
|
2147
|
+
lastEmitTime = now;
|
|
2148
|
+
return asyncSucceed([a, loop(tail)]);
|
|
2149
|
+
}
|
|
2150
|
+
return uncons(loop(tail));
|
|
2151
|
+
}
|
|
2152
|
+
)
|
|
2153
|
+
);
|
|
2154
|
+
return loop(stream);
|
|
2155
|
+
}
|
|
2156
|
+
function debounce(stream, delayMs) {
|
|
2157
|
+
return fromPull(
|
|
2158
|
+
async((_env, cb) => {
|
|
2159
|
+
let lastValue;
|
|
2160
|
+
let hasValue = false;
|
|
2161
|
+
let timerId;
|
|
2162
|
+
let done = false;
|
|
2163
|
+
let tail = stream;
|
|
2164
|
+
const pullNext = () => {
|
|
2165
|
+
if (done) return;
|
|
2166
|
+
const pull = uncons(tail);
|
|
2167
|
+
pull(_env, (exit) => {
|
|
2168
|
+
if (done) return;
|
|
2169
|
+
if (exit._tag === "Failure") {
|
|
2170
|
+
if (hasValue) {
|
|
2171
|
+
const value = lastValue;
|
|
2172
|
+
hasValue = false;
|
|
2173
|
+
clearTimeout(timerId);
|
|
2174
|
+
cb({ _tag: "Success", value: [value, emptyStream()] });
|
|
2175
|
+
} else {
|
|
2176
|
+
cb(exit);
|
|
2177
|
+
}
|
|
2178
|
+
return;
|
|
2179
|
+
}
|
|
2180
|
+
const [a, nextTail] = exit.value;
|
|
2181
|
+
tail = nextTail;
|
|
2182
|
+
lastValue = a;
|
|
2183
|
+
hasValue = true;
|
|
2184
|
+
clearTimeout(timerId);
|
|
2185
|
+
timerId = setTimeout(() => {
|
|
2186
|
+
if (done) return;
|
|
2187
|
+
const value = lastValue;
|
|
2188
|
+
hasValue = false;
|
|
2189
|
+
done = true;
|
|
2190
|
+
cb({ _tag: "Success", value: [value, debounce(tail, delayMs)] });
|
|
2191
|
+
}, delayMs);
|
|
2192
|
+
pullNext();
|
|
2193
|
+
});
|
|
2194
|
+
};
|
|
2195
|
+
pullNext();
|
|
2196
|
+
return () => {
|
|
2197
|
+
done = true;
|
|
2198
|
+
clearTimeout(timerId);
|
|
2199
|
+
};
|
|
2200
|
+
})
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2203
|
+
function zip2(left, right) {
|
|
2204
|
+
const loop = (l, r) => fromPull(
|
|
2205
|
+
asyncFold(
|
|
2206
|
+
uncons(l),
|
|
2207
|
+
(opt) => asyncFail(opt),
|
|
2208
|
+
([a, lTail]) => asyncFold(
|
|
2209
|
+
uncons(r),
|
|
2210
|
+
(opt) => asyncFail(opt),
|
|
2211
|
+
([b, rTail]) => asyncSucceed([[a, b], loop(lTail, rTail)])
|
|
2212
|
+
)
|
|
2213
|
+
)
|
|
2214
|
+
);
|
|
2215
|
+
return loop(left, right);
|
|
2216
|
+
}
|
|
2217
|
+
function zipWith(left, right, f) {
|
|
2218
|
+
const loop = (l, r) => fromPull(
|
|
2219
|
+
asyncFold(
|
|
2220
|
+
uncons(l),
|
|
2221
|
+
(opt) => asyncFail(opt),
|
|
2222
|
+
([a, lTail]) => asyncFold(
|
|
2223
|
+
uncons(r),
|
|
2224
|
+
(opt) => asyncFail(opt),
|
|
2225
|
+
([b, rTail]) => asyncSucceed([f(a, b), loop(lTail, rTail)])
|
|
2226
|
+
)
|
|
2227
|
+
)
|
|
2228
|
+
);
|
|
2229
|
+
return loop(left, right);
|
|
2230
|
+
}
|
|
2231
|
+
function scan(stream, initial, f) {
|
|
2232
|
+
const loop = (cur, acc) => fromPull(
|
|
2233
|
+
asyncFold(
|
|
2234
|
+
uncons(cur),
|
|
2235
|
+
(opt) => asyncFail(opt),
|
|
2236
|
+
([a, tail]) => {
|
|
2237
|
+
const next = f(acc, a);
|
|
2238
|
+
return asyncSucceed([next, loop(tail, next)]);
|
|
2239
|
+
}
|
|
2240
|
+
)
|
|
2241
|
+
);
|
|
2242
|
+
return concatStream(
|
|
2243
|
+
emitStream(succeed(initial)),
|
|
2244
|
+
loop(stream, initial)
|
|
2245
|
+
);
|
|
2246
|
+
}
|
|
2247
|
+
function interleave(left, right) {
|
|
2248
|
+
const loop = (l, r, pickLeft) => fromPull(
|
|
2249
|
+
asyncFold(
|
|
2250
|
+
uncons(pickLeft ? l : r),
|
|
2251
|
+
// Current stream ended — drain the other
|
|
2252
|
+
(_opt) => uncons(pickLeft ? r : l),
|
|
2253
|
+
([a, tail]) => {
|
|
2254
|
+
const nextL = pickLeft ? tail : l;
|
|
2255
|
+
const nextR = pickLeft ? r : tail;
|
|
2256
|
+
return asyncSucceed([a, loop(nextL, nextR, !pickLeft)]);
|
|
2257
|
+
}
|
|
2258
|
+
)
|
|
2259
|
+
);
|
|
2260
|
+
return loop(left, right, true);
|
|
2261
|
+
}
|
|
2262
|
+
function take2(stream, n) {
|
|
2263
|
+
if (n <= 0) return emptyStream();
|
|
2264
|
+
const loop = (cur, remaining) => {
|
|
2265
|
+
if (remaining <= 0) return emptyStream();
|
|
2266
|
+
return fromPull(
|
|
2267
|
+
asyncFold(
|
|
2268
|
+
uncons(cur),
|
|
2269
|
+
(opt) => asyncFail(opt),
|
|
2270
|
+
([a, tail]) => asyncSucceed([a, loop(tail, remaining - 1)])
|
|
2271
|
+
)
|
|
2272
|
+
);
|
|
2273
|
+
};
|
|
2274
|
+
return loop(stream, n);
|
|
2275
|
+
}
|
|
2276
|
+
function drop(stream, n) {
|
|
2277
|
+
if (n <= 0) return stream;
|
|
2278
|
+
const skip = (cur, remaining) => {
|
|
2279
|
+
if (remaining <= 0) return cur;
|
|
2280
|
+
return fromPull(
|
|
2281
|
+
asyncFold(
|
|
2282
|
+
uncons(cur),
|
|
2283
|
+
(opt) => asyncFail(opt),
|
|
2284
|
+
([_a, tail]) => uncons(skip(tail, remaining - 1))
|
|
2285
|
+
)
|
|
2286
|
+
);
|
|
2287
|
+
};
|
|
2288
|
+
return skip(stream, n);
|
|
2289
|
+
}
|
|
2290
|
+
|
|
734
2291
|
// src/core/runtime/engineStats.ts
|
|
735
|
-
function engineStats(engine, data
|
|
736
|
-
return { engine, data, fallbackUsed };
|
|
2292
|
+
function engineStats(engine, data) {
|
|
2293
|
+
return { engine, data, fallbackUsed: false };
|
|
737
2294
|
}
|
|
738
2295
|
function selectedEngineStats(requested, engine, data) {
|
|
739
|
-
|
|
2296
|
+
if (requested !== engine) {
|
|
2297
|
+
throw new Error(`brass-runtime strict engine mismatch: requested '${requested}', got '${engine}'`);
|
|
2298
|
+
}
|
|
2299
|
+
return { requested, engine, data, fallbackUsed: false };
|
|
740
2300
|
}
|
|
741
2301
|
export {
|
|
2302
|
+
ABI_VERSION,
|
|
742
2303
|
Async,
|
|
743
2304
|
Cause,
|
|
744
2305
|
DefaultHostExecutor,
|
|
2306
|
+
EVENT_WORDS,
|
|
745
2307
|
EngineFiberHandle,
|
|
2308
|
+
EventKindCode,
|
|
746
2309
|
Exit,
|
|
747
2310
|
HostRegistry,
|
|
748
2311
|
JsFiberEngine,
|
|
2312
|
+
NONE_U32,
|
|
749
2313
|
NoopHooks,
|
|
2314
|
+
OpcodeTagCode,
|
|
2315
|
+
PURE_PIPELINE_TAG,
|
|
750
2316
|
ProgramBuilder,
|
|
751
2317
|
PushStatus,
|
|
752
|
-
ReferenceWasmBridge,
|
|
753
2318
|
RingBuffer,
|
|
754
2319
|
Runtime,
|
|
755
2320
|
RuntimeFiber,
|
|
@@ -758,9 +2323,16 @@ export {
|
|
|
758
2323
|
WasmFiberEngine,
|
|
759
2324
|
WasmFiberRegistryBridge,
|
|
760
2325
|
WasmPackFiberBridge,
|
|
2326
|
+
abortablePromiseStats,
|
|
761
2327
|
acquireRelease,
|
|
762
|
-
andThen,
|
|
2328
|
+
andThen2 as andThen,
|
|
2329
|
+
andThen as andThenSchedule,
|
|
2330
|
+
applyFused,
|
|
2331
|
+
assertCompletesWithin,
|
|
2332
|
+
assertFails,
|
|
2333
|
+
assertFailsWith,
|
|
763
2334
|
assertNever,
|
|
2335
|
+
assertSucceeds,
|
|
764
2336
|
async,
|
|
765
2337
|
asyncCatchAll,
|
|
766
2338
|
asyncFail,
|
|
@@ -773,25 +2345,43 @@ export {
|
|
|
773
2345
|
asyncSync,
|
|
774
2346
|
asyncTotal,
|
|
775
2347
|
bounded,
|
|
2348
|
+
bracket,
|
|
776
2349
|
broadcast,
|
|
777
2350
|
broadcastToHub,
|
|
778
2351
|
buffer,
|
|
779
2352
|
bufferP,
|
|
780
2353
|
catchAll,
|
|
2354
|
+
catchTag,
|
|
2355
|
+
catchTags,
|
|
781
2356
|
chunks,
|
|
782
2357
|
chunksP,
|
|
783
2358
|
collectAllPar,
|
|
784
2359
|
collectStream,
|
|
785
|
-
compose,
|
|
2360
|
+
compose2 as compose,
|
|
2361
|
+
compose as composeLayer,
|
|
786
2362
|
concatStream,
|
|
2363
|
+
debounce,
|
|
2364
|
+
decodeEvent,
|
|
2365
|
+
decodeEventBatch,
|
|
2366
|
+
delayedEffect,
|
|
2367
|
+
derivedRef,
|
|
2368
|
+
deserializeFusedPipeline,
|
|
787
2369
|
dropP,
|
|
2370
|
+
drop as dropStream,
|
|
2371
|
+
elapsed,
|
|
788
2372
|
emitStream,
|
|
789
2373
|
emptyStream,
|
|
2374
|
+
encodeOpcodeNodes,
|
|
2375
|
+
encodeOpcodeProgram,
|
|
790
2376
|
end,
|
|
791
2377
|
engineStats,
|
|
2378
|
+
ensuring,
|
|
2379
|
+
exponential,
|
|
792
2380
|
fail,
|
|
793
2381
|
filterMapP,
|
|
794
2382
|
filterP,
|
|
2383
|
+
fixed,
|
|
2384
|
+
flakyEffect,
|
|
795
2385
|
flatMap,
|
|
796
2386
|
flattenStream,
|
|
797
2387
|
foreachStream,
|
|
@@ -800,16 +2390,41 @@ export {
|
|
|
800
2390
|
fromHub,
|
|
801
2391
|
fromPromiseAbortable,
|
|
802
2392
|
fromPull,
|
|
2393
|
+
fuse,
|
|
803
2394
|
getBenchmarkBudget,
|
|
804
2395
|
getCurrentFiber,
|
|
2396
|
+
getStats,
|
|
805
2397
|
globalScheduler,
|
|
2398
|
+
gracefulShutdown,
|
|
806
2399
|
groupedP,
|
|
807
2400
|
identity,
|
|
2401
|
+
inferCallerLaneFromStack,
|
|
2402
|
+
initState,
|
|
2403
|
+
interleave,
|
|
2404
|
+
intersect,
|
|
2405
|
+
isFusionEnabled,
|
|
2406
|
+
isFusionVerbose,
|
|
2407
|
+
jittered,
|
|
2408
|
+
laneTag,
|
|
2409
|
+
layer,
|
|
2410
|
+
layerFail,
|
|
2411
|
+
layerFrom,
|
|
2412
|
+
layerSucceed,
|
|
808
2413
|
linkAbortController,
|
|
809
2414
|
makeBoundedRingBuffer,
|
|
810
2415
|
makeCancelToken,
|
|
2416
|
+
makeCircuitBreaker,
|
|
2417
|
+
makeFiberReadyQueue,
|
|
811
2418
|
makeHub,
|
|
2419
|
+
makeMetrics,
|
|
2420
|
+
makeRef,
|
|
2421
|
+
makeSemaphore,
|
|
812
2422
|
makeStreamChunker,
|
|
2423
|
+
makeTestRuntime,
|
|
2424
|
+
makeTracer,
|
|
2425
|
+
makeWorkerPool,
|
|
2426
|
+
managed,
|
|
2427
|
+
managedAll,
|
|
813
2428
|
managedStream,
|
|
814
2429
|
map,
|
|
815
2430
|
mapAsync,
|
|
@@ -818,38 +2433,71 @@ export {
|
|
|
818
2433
|
mapChunksEffectP,
|
|
819
2434
|
mapEffectP,
|
|
820
2435
|
mapError,
|
|
2436
|
+
mapError2 as mapErrorTyped,
|
|
2437
|
+
mapLayer,
|
|
821
2438
|
mapP,
|
|
822
2439
|
mapStream,
|
|
823
2440
|
mapTryAsync,
|
|
824
2441
|
merge,
|
|
2442
|
+
merge2 as mergeLayer,
|
|
825
2443
|
mergeStream,
|
|
2444
|
+
neverEffect,
|
|
826
2445
|
none,
|
|
2446
|
+
orElse,
|
|
827
2447
|
orElseOptional,
|
|
2448
|
+
provideLayer,
|
|
828
2449
|
race,
|
|
829
2450
|
raceWith,
|
|
830
2451
|
rangeStream,
|
|
2452
|
+
recurs,
|
|
2453
|
+
registerShutdownHooks,
|
|
2454
|
+
repeatWithSchedule,
|
|
2455
|
+
resetAbortablePromiseStats,
|
|
2456
|
+
retry,
|
|
2457
|
+
retryN,
|
|
2458
|
+
retryWithBackoff,
|
|
2459
|
+
retryWithSchedule,
|
|
2460
|
+
runFusedArray,
|
|
831
2461
|
runtimeCapabilities,
|
|
2462
|
+
runtimeForCaller,
|
|
2463
|
+
sanitizeLaneKey,
|
|
2464
|
+
scan,
|
|
832
2465
|
selectedEngineStats,
|
|
2466
|
+
serializeFusedPipeline,
|
|
833
2467
|
setBenchmarkBudget,
|
|
2468
|
+
setFusionEnabled,
|
|
2469
|
+
setFusionVerbose,
|
|
2470
|
+
sleep,
|
|
834
2471
|
some,
|
|
835
2472
|
streamFromReadableStream,
|
|
836
2473
|
succeed,
|
|
837
2474
|
sync,
|
|
2475
|
+
tagError,
|
|
838
2476
|
takeP,
|
|
2477
|
+
take as takeSchedule,
|
|
2478
|
+
take2 as takeStream,
|
|
839
2479
|
tapEffectP,
|
|
2480
|
+
throttle,
|
|
2481
|
+
timeout,
|
|
840
2482
|
toPromise,
|
|
2483
|
+
toPromiseByCaller,
|
|
841
2484
|
uncons,
|
|
2485
|
+
union,
|
|
842
2486
|
unit,
|
|
843
2487
|
unsafeGetCurrentRuntime,
|
|
844
2488
|
unsafeRunAsync,
|
|
845
2489
|
unsafeRunFoldWithEnv,
|
|
846
2490
|
unwrapScoped,
|
|
2491
|
+
useManaged,
|
|
847
2492
|
via,
|
|
2493
|
+
whileInput,
|
|
848
2494
|
widenOpt,
|
|
849
2495
|
withAsyncPromise,
|
|
850
2496
|
withCurrentFiber,
|
|
851
2497
|
withScope,
|
|
852
2498
|
withScopeAsync,
|
|
853
2499
|
zip,
|
|
854
|
-
zipPar
|
|
2500
|
+
zipPar,
|
|
2501
|
+
zip2 as zipStream,
|
|
2502
|
+
zipWith
|
|
855
2503
|
};
|