brass-runtime 1.16.0 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +283 -18
- package/dist/agent/cli/main.cjs +38 -38
- package/dist/agent/cli/main.js +6 -6
- package/dist/agent/cli/main.mjs +6 -6
- package/dist/agent/index.cjs +7 -7
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +6 -6
- package/dist/agent/index.mjs +6 -6
- package/dist/chunk-2HQTDLHF.mjs +683 -0
- package/dist/chunk-36I3M4UC.mjs +370 -0
- package/dist/{chunk-QY5FKYEQ.js → chunk-3AYM6WPJ.js} +570 -51
- package/dist/chunk-3LOYJFRR.cjs +300 -0
- package/dist/chunk-3Y2RIUMM.js +300 -0
- package/dist/{chunk-N6VHMOWB.cjs → chunk-4ROBZFL6.cjs} +128 -128
- package/dist/{chunk-NC5SDRYE.js → chunk-52OB2ROS.js} +4 -4
- package/dist/{chunk-JX3LZQJH.cjs → chunk-52PPNNI4.cjs} +82 -20
- package/dist/{chunk-5YOQOXEQ.cjs → chunk-5EC274J5.cjs} +676 -293
- package/dist/chunk-5QC7LRZ3.js +229 -0
- package/dist/{chunk-7TL2LHQJ.js → chunk-5VRJNBLZ.mjs} +524 -141
- package/dist/chunk-62AZW6UT.cjs +313 -0
- package/dist/chunk-6IXXWIUM.js +683 -0
- package/dist/chunk-74ZTY6CP.js +2871 -0
- package/dist/chunk-76YMRMH2.cjs +777 -0
- package/dist/chunk-7CMJS3QE.mjs +2871 -0
- package/dist/{chunk-2WC63LJK.mjs → chunk-7JIJOVCT.js} +20 -10
- package/dist/{chunk-FM4W4QPL.js → chunk-A2OM6NEH.mjs} +5 -4
- package/dist/chunk-AGR5B2BC.cjs +683 -0
- package/dist/chunk-AVNQLJ5V.js +777 -0
- package/dist/chunk-B33ICAKP.js +313 -0
- package/dist/{chunk-J3H54ZRV.mjs → chunk-B5JD23U7.mjs} +1 -1
- package/dist/chunk-BABBZK4Y.js +2024 -0
- package/dist/{chunk-U5KWK3PX.mjs → chunk-C3MDXTRZ.js} +11 -0
- package/dist/{chunk-F5EUMJL7.mjs → chunk-CIZFIMK5.js} +55 -5
- package/dist/{chunk-SPUEME2B.cjs → chunk-CZIVE6NT.cjs} +12 -1
- package/dist/{chunk-TDVMADDN.js → chunk-DNFJLJMW.mjs} +11 -0
- package/dist/chunk-DNFO2EIZ.mjs +777 -0
- package/dist/{chunk-XDZOO4L5.js → chunk-EJ6BPYVR.mjs} +79 -17
- package/dist/{chunk-JNFRRJYH.cjs → chunk-ENKODRU3.cjs} +242 -192
- package/dist/chunk-EOC4UHBS.mjs +229 -0
- package/dist/{chunk-7LVI2GIN.js → chunk-FH2X7BVP.js} +507 -72
- package/dist/{chunk-OOGJ73B6.js → chunk-FHQGHPMO.mjs} +20 -10
- package/dist/{chunk-WQ5QNU5R.cjs → chunk-GLE2WY7Z.cjs} +652 -217
- package/dist/{chunk-G6IQOE4P.mjs → chunk-GYM3LLGS.mjs} +507 -72
- package/dist/chunk-HLWLMW2F.mjs +2024 -0
- package/dist/{chunk-TVN5I4U6.cjs → chunk-JF5WGYJJ.cjs} +25 -24
- package/dist/{chunk-CY33PGEX.mjs → chunk-KH4SYAOS.mjs} +570 -51
- package/dist/chunk-KN32XNTH.mjs +313 -0
- package/dist/chunk-KQLYONSE.cjs +2871 -0
- package/dist/{chunk-7HUOJA4W.cjs → chunk-KZJQ723N.cjs} +90 -80
- package/dist/{chunk-CCKHV5BT.mjs → chunk-L2SYFEBS.js} +5 -4
- package/dist/{chunk-IJT6RRQ5.cjs → chunk-L6VB5N7Q.cjs} +20 -9
- package/dist/{chunk-ZGLD4TVZ.mjs → chunk-MBEJI5HF.mjs} +4 -4
- package/dist/{chunk-PRWCB3QL.mjs → chunk-MIIYDLGM.js} +524 -141
- package/dist/{chunk-H55LI6WY.js → chunk-MOO4L7F4.mjs} +15 -4
- package/dist/{chunk-7XOPAB5Q.js → chunk-MT3OWDPC.mjs} +55 -5
- package/dist/chunk-MVGUEJ5Z.cjs +370 -0
- package/dist/chunk-PD4EJTQC.cjs +229 -0
- package/dist/chunk-PWC3RBQE.mjs +300 -0
- package/dist/{chunk-MWXMNYJS.cjs → chunk-Q2I37RP3.cjs} +643 -124
- package/dist/{chunk-VFIUZG7J.mjs → chunk-RKGKFN2A.js} +79 -17
- package/dist/{chunk-NYL4D7SK.cjs → chunk-SA6HUJVI.cjs} +5 -5
- package/dist/{chunk-K2T3DV26.mjs → chunk-TRM4JUZQ.js} +15 -4
- package/dist/chunk-UB4B6OFY.js +370 -0
- package/dist/{chunk-G3XGCZDQ.js → chunk-UCUBNWM2.js} +1 -1
- package/dist/chunk-VN44DYYT.cjs +2024 -0
- package/dist/{client-CtFmoDvM.d.ts → client-CZHU674n.d.ts} +211 -36
- package/dist/core/index.cjs +135 -9
- package/dist/core/index.d.ts +238 -33
- package/dist/core/index.js +155 -29
- package/dist/core/index.mjs +155 -29
- package/dist/{effect-CGNl5Rqp.d.ts → effect-DIUHZ9IN.d.ts} +89 -1
- package/dist/effectRunner-CFLC32IK.cjs +8 -0
- package/dist/{effectRunner-A4CHJXJI.js → effectRunner-L4S7IPT3.js} +2 -2
- package/dist/{effectRunner-OPUF6QRN.mjs → effectRunner-NNGG75QA.mjs} +2 -2
- package/dist/http/index.cjs +324 -2986
- package/dist/http/index.d.ts +54 -68
- package/dist/http/index.js +238 -2900
- package/dist/http/index.mjs +238 -2900
- package/dist/http/testing.cjs +14 -12
- package/dist/http/testing.d.ts +5 -4
- package/dist/http/testing.js +10 -8
- package/dist/http/testing.mjs +10 -8
- package/dist/index.cjs +423 -255
- package/dist/index.d.ts +87 -69
- package/dist/index.js +301 -133
- package/dist/index.mjs +301 -133
- package/dist/observability/index.cjs +16 -531
- package/dist/observability/index.d.ts +81 -8
- package/dist/observability/index.js +23 -538
- package/dist/observability/index.mjs +23 -538
- package/dist/perf/cli.cjs +401 -0
- package/dist/perf/cli.d.ts +1 -0
- package/dist/perf/cli.js +401 -0
- package/dist/perf/cli.mjs +401 -0
- package/dist/perf/index.cjs +141 -0
- package/dist/perf/index.d.ts +483 -0
- package/dist/perf/index.js +141 -0
- package/dist/perf/index.mjs +141 -0
- package/dist/schedule-CK3Ml_7p.d.ts +259 -0
- package/dist/schema/index.cjs +6 -2
- package/dist/schema/index.d.ts +3 -1
- package/dist/schema/index.js +5 -1
- package/dist/schema/index.mjs +5 -1
- package/dist/{server-C8hDXA74.d.ts → server-GJPg8ZSG.d.ts} +4 -3
- package/dist/{stream-dvSs0QS5.d.ts → stream-B4oK9JFP.d.ts} +1 -1
- package/dist/{tracer-B5tRH9H7.d.ts → tracer-Hwt1cl7h.d.ts} +13 -54
- package/dist/{tracing-Dt9S_6V8.d.ts → tracing-DqbTKGcf.d.ts} +1 -1
- package/docs/ARCHITECTURE.md +292 -0
- package/docs/README.md +63 -0
- package/docs/adr/0001-ai-context-pack.md +32 -0
- package/docs/agent-apply-mode.md +104 -0
- package/docs/agent-approvals.md +110 -0
- package/docs/agent-batch.md +185 -0
- package/docs/agent-boundaries.md +112 -0
- package/docs/agent-chat-sessions.md +160 -0
- package/docs/agent-ci.md +17 -0
- package/docs/agent-cli.md +405 -0
- package/docs/agent-config.md +480 -0
- package/docs/agent-context-discovery.md +159 -0
- package/docs/agent-copilot-like-dx.md +126 -0
- package/docs/agent-declarative-optimized-planning.md +138 -0
- package/docs/agent-dx.md +224 -0
- package/docs/agent-env-files.md +126 -0
- package/docs/agent-follow-up-context.md +43 -0
- package/docs/agent-global-usage.md +180 -0
- package/docs/agent-init.md +109 -0
- package/docs/agent-install-and-configure.md +516 -0
- package/docs/agent-language-workspace-ux.md +99 -0
- package/docs/agent-llm-adapters.md +123 -0
- package/docs/agent-local-install.md +190 -0
- package/docs/agent-local-tests.md +51 -0
- package/docs/agent-observability.md +155 -0
- package/docs/agent-patch-quality-loop.md +162 -0
- package/docs/agent-presets.md +22 -0
- package/docs/agent-project-commands.md +237 -0
- package/docs/agent-project-intelligence.md +156 -0
- package/docs/agent-redaction.md +18 -0
- package/docs/agent-release-readiness.md +76 -0
- package/docs/agent-rollback-safety.md +162 -0
- package/docs/agent-rollback.md +23 -0
- package/docs/agent-run-artifacts.md +16 -0
- package/docs/agent-vscode-auto-discovery.md +137 -0
- package/docs/agent-vscode-batch-runner.md +100 -0
- package/docs/agent-vscode-chat-layout.md +90 -0
- package/docs/agent-vscode-clean-install.md +147 -0
- package/docs/agent-vscode-code-actions.md +70 -0
- package/docs/agent-vscode-diff-preview.md +45 -0
- package/docs/agent-vscode-inline-assist.md +56 -0
- package/docs/agent-vscode-install.md +186 -0
- package/docs/agent-vscode-model-setup.md +97 -0
- package/docs/agent-vscode-patch-preview.md +92 -0
- package/docs/agent-vscode-problems.md +79 -0
- package/docs/agent-vscode-project-dashboard.md +106 -0
- package/docs/agent-vscode-run-history.md +92 -0
- package/docs/agent-vscode-ux.md +73 -0
- package/docs/ai/INVARIANTS.md +84 -0
- package/docs/ai/PROJECT_MAP.md +338 -0
- package/docs/ai/PUBLIC_API.md +336 -0
- package/docs/ai/VALIDATION_MATRIX.md +67 -0
- package/docs/api-polish.md +37 -0
- package/docs/cancellation.md +162 -0
- package/docs/coverage.md +46 -0
- package/docs/getting-started.md +159 -0
- package/docs/guides/README.md +40 -0
- package/docs/guides/circuit-breaker.md +89 -0
- package/docs/guides/error-handling.md +91 -0
- package/docs/guides/getting-started.md +107 -0
- package/docs/guides/layers.md +189 -0
- package/docs/guides/metrics.md +101 -0
- package/docs/guides/resource-management.md +141 -0
- package/docs/guides/retry.md +215 -0
- package/docs/guides/semaphore.md +66 -0
- package/docs/guides/streams.md +117 -0
- package/docs/guides/supervisors.md +98 -0
- package/docs/guides/testing.md +162 -0
- package/docs/guides/tracing.md +71 -0
- package/docs/http-recipes.md +399 -0
- package/docs/http.md +749 -0
- package/docs/modules.md +285 -0
- package/docs/observability-collector-smoke.md +31 -0
- package/docs/observability-framework-examples.md +98 -0
- package/docs/observability.md +542 -0
- package/docs/otel-collector-smoke.yaml +27 -0
- package/docs/performance-profiler.md +199 -0
- package/docs/production-readiness.md +73 -0
- package/docs/recipes/README.md +12 -0
- package/docs/recipes/http-server.md +45 -0
- package/docs/recipes/layers.md +44 -0
- package/docs/recipes/performance.md +47 -0
- package/docs/recipes/runtime.md +41 -0
- package/docs/recipes/testing.md +41 -0
- package/docs/release.md +53 -0
- package/docs/wasm-bounded-queues.md +44 -0
- package/docs/wasm-engine-observability-benchmarks.md +85 -0
- package/docs/wasm-fiber-engine.md +117 -0
- package/docs/wasm-scheduler-state-machine.md +122 -0
- package/docs/wasm-stream-chunks.md +54 -0
- package/package.json +22 -2
- package/dist/chunk-45F7OKGT.cjs +0 -104
- package/dist/chunk-7V4KY4RL.mjs +0 -104
- package/dist/chunk-DJQ7OMMB.cjs +0 -144
- package/dist/chunk-GOV47PPB.mjs +0 -552
- package/dist/chunk-JF4XXPZ5.cjs +0 -552
- package/dist/chunk-KCPT2D6G.js +0 -552
- package/dist/chunk-NOYZIMUJ.mjs +0 -144
- package/dist/chunk-PNVFW245.js +0 -144
- package/dist/chunk-ROJC3NBJ.js +0 -104
- package/dist/effectRunner-3ZHAD3LE.cjs +0 -8
- package/dist/schedule-Fque9Abz.d.ts +0 -70
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ensuring
|
|
3
|
+
} from "./chunk-B33ICAKP.js";
|
|
4
|
+
import {
|
|
5
|
+
makeScheduleDriver
|
|
6
|
+
} from "./chunk-6IXXWIUM.js";
|
|
1
7
|
import {
|
|
2
8
|
makeRuntimeEventRecord
|
|
3
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RKGKFN2A.js";
|
|
4
10
|
import {
|
|
5
11
|
Runtime,
|
|
6
|
-
getCurrentFiber
|
|
7
|
-
|
|
12
|
+
getCurrentFiber,
|
|
13
|
+
liveClock,
|
|
14
|
+
runtimeClockFromEnv,
|
|
15
|
+
toPromise,
|
|
16
|
+
unsafeRunAsync
|
|
17
|
+
} from "./chunk-FH2X7BVP.js";
|
|
8
18
|
import {
|
|
19
|
+
Cause,
|
|
20
|
+
Exit,
|
|
9
21
|
asyncEffect,
|
|
10
22
|
asyncFail,
|
|
11
23
|
asyncFlatMap,
|
|
@@ -14,7 +26,7 @@ import {
|
|
|
14
26
|
asyncSucceed,
|
|
15
27
|
asyncSync,
|
|
16
28
|
unit
|
|
17
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-UB4B6OFY.js";
|
|
18
30
|
|
|
19
31
|
// src/core/types/cancel.ts
|
|
20
32
|
function makeCancelToken() {
|
|
@@ -49,6 +61,25 @@ function linkAbortController(token, ac) {
|
|
|
49
61
|
return token.onCancel(() => ac.abort());
|
|
50
62
|
}
|
|
51
63
|
|
|
64
|
+
// src/core/runtime/dx.ts
|
|
65
|
+
function makeRuntime(env = {}, options = {}) {
|
|
66
|
+
return new Runtime({ ...options, env });
|
|
67
|
+
}
|
|
68
|
+
function runPromise(effect, envOrRuntime) {
|
|
69
|
+
if (envOrRuntime instanceof Runtime) return envOrRuntime.toPromise(effect);
|
|
70
|
+
return toPromise(effect, envOrRuntime);
|
|
71
|
+
}
|
|
72
|
+
function runExit(effect, envOrRuntime) {
|
|
73
|
+
return new Promise((resolve) => {
|
|
74
|
+
if (envOrRuntime instanceof Runtime) {
|
|
75
|
+
envOrRuntime.unsafeRunAsync(effect, resolve);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
unsafeRunAsync(effect, envOrRuntime, resolve);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
var runEffect = runPromise;
|
|
82
|
+
|
|
52
83
|
// src/core/runtime/linkedQueue.ts
|
|
53
84
|
var LinkedQueue = class {
|
|
54
85
|
head = null;
|
|
@@ -267,57 +298,314 @@ function registerShutdownHooks(runtime, config = {}) {
|
|
|
267
298
|
}
|
|
268
299
|
|
|
269
300
|
// src/core/runtime/testing.ts
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
301
|
+
var TestScheduler = class {
|
|
302
|
+
constructor(options = {}) {
|
|
303
|
+
this.options = options;
|
|
304
|
+
this.maxSteps = options.maxSteps ?? 1e4;
|
|
305
|
+
}
|
|
306
|
+
options;
|
|
307
|
+
queue = [];
|
|
308
|
+
maxSteps;
|
|
309
|
+
autoFlushScheduled = false;
|
|
310
|
+
flushing = false;
|
|
311
|
+
enqueuedTasks = 0;
|
|
312
|
+
executedTasks = 0;
|
|
313
|
+
droppedTasks = 0;
|
|
314
|
+
scheduledFlushes = 0;
|
|
315
|
+
completedFlushes = 0;
|
|
316
|
+
schedule(task, tag = "anonymous") {
|
|
317
|
+
if (typeof task !== "function") {
|
|
318
|
+
this.droppedTasks += 1;
|
|
319
|
+
return "dropped";
|
|
320
|
+
}
|
|
321
|
+
this.queue.push({ tag, run: task });
|
|
322
|
+
this.enqueuedTasks += 1;
|
|
323
|
+
this.requestAutoFlush();
|
|
324
|
+
return "accepted";
|
|
325
|
+
}
|
|
326
|
+
scheduleBatch(tasks) {
|
|
327
|
+
return tasks.map(({ fn, tag }) => this.schedule(fn, tag));
|
|
328
|
+
}
|
|
329
|
+
stats() {
|
|
330
|
+
return {
|
|
331
|
+
engine: "ts",
|
|
332
|
+
fallbackUsed: false,
|
|
333
|
+
data: {
|
|
334
|
+
len: this.queue.length,
|
|
335
|
+
phase: this.flushing ? "flushing" : this.autoFlushScheduled ? "scheduled" : "idle",
|
|
336
|
+
scheduledFlushes: this.scheduledFlushes,
|
|
337
|
+
completedFlushes: this.completedFlushes,
|
|
338
|
+
enqueuedTasks: this.enqueuedTasks,
|
|
339
|
+
executedTasks: this.executedTasks,
|
|
340
|
+
droppedTasks: this.droppedTasks,
|
|
341
|
+
yieldedByBudget: 0,
|
|
342
|
+
lanes: [{
|
|
343
|
+
key: "test",
|
|
344
|
+
len: this.queue.length,
|
|
345
|
+
capacity: Number.POSITIVE_INFINITY,
|
|
346
|
+
enqueuedTasks: this.enqueuedTasks,
|
|
347
|
+
executedTasks: this.executedTasks,
|
|
348
|
+
droppedTasks: this.droppedTasks
|
|
349
|
+
}]
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
pending() {
|
|
354
|
+
return this.queue.slice();
|
|
355
|
+
}
|
|
356
|
+
size() {
|
|
357
|
+
return this.queue.length;
|
|
358
|
+
}
|
|
359
|
+
flush(maxTasks = 1) {
|
|
360
|
+
if (this.flushing) return 0;
|
|
361
|
+
this.flushing = true;
|
|
362
|
+
this.autoFlushScheduled = false;
|
|
363
|
+
let ran = 0;
|
|
364
|
+
try {
|
|
365
|
+
while (ran < maxTasks) {
|
|
366
|
+
const next = this.queue.shift();
|
|
367
|
+
if (!next) break;
|
|
368
|
+
ran += 1;
|
|
369
|
+
this.executedTasks += 1;
|
|
370
|
+
try {
|
|
371
|
+
next.run();
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.error(`[TestScheduler] task threw (tag=${next.tag})`, error);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return ran;
|
|
377
|
+
} finally {
|
|
378
|
+
this.flushing = false;
|
|
379
|
+
this.completedFlushes += ran > 0 ? 1 : 0;
|
|
380
|
+
if (this.queue.length > 0) this.requestAutoFlush();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
flushAll(maxSteps = this.maxSteps) {
|
|
384
|
+
let ran = 0;
|
|
385
|
+
while (this.queue.length > 0) {
|
|
386
|
+
if (ran >= maxSteps) {
|
|
387
|
+
throw new Error(`TestScheduler.flushAll exceeded ${maxSteps} steps; possible runaway fiber loop`);
|
|
388
|
+
}
|
|
389
|
+
ran += this.flush(Math.max(1, maxSteps - ran));
|
|
390
|
+
}
|
|
391
|
+
return ran;
|
|
392
|
+
}
|
|
393
|
+
requestAutoFlush() {
|
|
394
|
+
const autoFlush = this.options.autoFlush ?? this.options.synchronous ?? true;
|
|
395
|
+
if (!autoFlush || this.autoFlushScheduled || this.flushing) return;
|
|
396
|
+
this.autoFlushScheduled = true;
|
|
397
|
+
this.scheduledFlushes += 1;
|
|
398
|
+
queueMicrotask(() => {
|
|
399
|
+
if (!this.autoFlushScheduled) return;
|
|
400
|
+
this.flushAll();
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
var TestClock = class {
|
|
405
|
+
constructor(initialTimeMs = 0, flushScheduler = () => void 0, maxSteps = 1e4) {
|
|
406
|
+
this.flushScheduler = flushScheduler;
|
|
407
|
+
this.maxSteps = maxSteps;
|
|
408
|
+
this.nowMs = Math.max(0, Math.floor(initialTimeMs));
|
|
409
|
+
}
|
|
410
|
+
flushScheduler;
|
|
411
|
+
maxSteps;
|
|
412
|
+
nowMs;
|
|
413
|
+
nextId = 1;
|
|
414
|
+
nextSeq = 1;
|
|
415
|
+
timers = /* @__PURE__ */ new Map();
|
|
416
|
+
now() {
|
|
417
|
+
return this.nowMs;
|
|
418
|
+
}
|
|
419
|
+
setTimeout(task, ms) {
|
|
420
|
+
const id = this.nextId++;
|
|
421
|
+
const delay = Math.max(0, Math.floor(ms));
|
|
422
|
+
this.timers.set(id, {
|
|
423
|
+
id,
|
|
424
|
+
dueAt: this.nowMs + delay,
|
|
425
|
+
seq: this.nextSeq++,
|
|
426
|
+
task
|
|
427
|
+
});
|
|
428
|
+
return id;
|
|
429
|
+
}
|
|
430
|
+
clearTimeout(timer) {
|
|
431
|
+
if (typeof timer === "number") this.timers.delete(timer);
|
|
432
|
+
}
|
|
433
|
+
pendingTimers() {
|
|
434
|
+
return Array.from(this.timers.values()).sort(compareTimers).map((timer) => ({
|
|
435
|
+
id: timer.id,
|
|
436
|
+
dueAt: timer.dueAt,
|
|
437
|
+
delayMs: Math.max(0, timer.dueAt - this.nowMs)
|
|
438
|
+
}));
|
|
439
|
+
}
|
|
440
|
+
adjust(ms) {
|
|
441
|
+
return this.advance(ms);
|
|
442
|
+
}
|
|
443
|
+
advance(ms) {
|
|
444
|
+
return this.advanceTo(this.nowMs + Math.max(0, Math.floor(ms)));
|
|
445
|
+
}
|
|
446
|
+
advanceTo(targetMs) {
|
|
447
|
+
const target = Math.max(this.nowMs, Math.floor(targetMs));
|
|
448
|
+
let ran = 0;
|
|
449
|
+
while (true) {
|
|
450
|
+
if (ran >= this.maxSteps) {
|
|
451
|
+
throw new Error(`TestClock.advanceTo exceeded ${this.maxSteps} timers; possible runaway timer loop`);
|
|
452
|
+
}
|
|
453
|
+
const next = this.nextDueTimer(target);
|
|
454
|
+
if (!next) break;
|
|
455
|
+
this.timers.delete(next.id);
|
|
456
|
+
this.nowMs = next.dueAt;
|
|
457
|
+
ran += 1;
|
|
458
|
+
next.task();
|
|
459
|
+
this.flushScheduler();
|
|
460
|
+
}
|
|
461
|
+
this.nowMs = target;
|
|
462
|
+
this.flushScheduler();
|
|
463
|
+
return ran;
|
|
464
|
+
}
|
|
465
|
+
runDue() {
|
|
466
|
+
return this.advanceTo(this.nowMs);
|
|
467
|
+
}
|
|
468
|
+
runAll(maxSteps = this.maxSteps) {
|
|
469
|
+
let ran = 0;
|
|
470
|
+
while (this.timers.size > 0) {
|
|
471
|
+
if (ran >= maxSteps) {
|
|
472
|
+
throw new Error(`TestClock.runAll exceeded ${maxSteps} timers; possible runaway timer loop`);
|
|
473
|
+
}
|
|
474
|
+
const next = this.nextDueTimer(Number.POSITIVE_INFINITY);
|
|
475
|
+
if (!next) break;
|
|
476
|
+
ran += this.advanceTo(next.dueAt);
|
|
477
|
+
}
|
|
478
|
+
return ran;
|
|
479
|
+
}
|
|
480
|
+
clear() {
|
|
481
|
+
this.timers.clear();
|
|
482
|
+
}
|
|
483
|
+
nextDueTimer(targetMs) {
|
|
484
|
+
let selected;
|
|
485
|
+
for (const timer of this.timers.values()) {
|
|
486
|
+
if (timer.dueAt > targetMs) continue;
|
|
487
|
+
if (!selected || compareTimers(timer, selected) < 0) selected = timer;
|
|
488
|
+
}
|
|
489
|
+
return selected;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
function compareTimers(a, b) {
|
|
493
|
+
return a.dueAt === b.dueAt ? a.seq - b.seq : a.dueAt - b.dueAt;
|
|
494
|
+
}
|
|
495
|
+
function makeTestRuntime(env, options = {}) {
|
|
496
|
+
const scheduler = new TestScheduler(options);
|
|
497
|
+
const clock = new TestClock(options.initialTimeMs, () => scheduler.flushAll(options.maxSteps), options.maxSteps);
|
|
498
|
+
const testEnv = withTestClock(env ?? {}, clock);
|
|
499
|
+
const runtime = Runtime.makeWithEngine(testEnv, "ts", { scheduler });
|
|
500
|
+
const flush = (maxTasks) => scheduler.flush(maxTasks);
|
|
501
|
+
const flushAll = (maxSteps) => scheduler.flushAll(maxSteps);
|
|
502
|
+
const advance = (ms) => clock.advance(ms);
|
|
503
|
+
const advanceTo = (targetMs) => clock.advanceTo(targetMs);
|
|
504
|
+
const runDueTimers = () => clock.runDue();
|
|
505
|
+
const runAllTimers = (maxSteps) => clock.runAll(maxSteps);
|
|
506
|
+
const runExit2 = (effect) => {
|
|
507
|
+
const promise = new Promise((resolve) => {
|
|
508
|
+
runtime.unsafeRunAsync(effect, resolve);
|
|
509
|
+
});
|
|
510
|
+
flushAll();
|
|
511
|
+
return promise;
|
|
512
|
+
};
|
|
513
|
+
const run = async (effect) => exitToPromise(await runExit2(effect));
|
|
514
|
+
const fork = (effect) => {
|
|
515
|
+
const fiber = runtime.fork(effect);
|
|
516
|
+
flushAll();
|
|
517
|
+
return fiber;
|
|
518
|
+
};
|
|
519
|
+
return {
|
|
520
|
+
env: testEnv,
|
|
521
|
+
runtime,
|
|
522
|
+
scheduler,
|
|
523
|
+
clock,
|
|
524
|
+
run,
|
|
525
|
+
runExit: runExit2,
|
|
526
|
+
fork,
|
|
527
|
+
flush,
|
|
528
|
+
flushAll,
|
|
529
|
+
advance,
|
|
530
|
+
advanceTo,
|
|
531
|
+
runDueTimers,
|
|
532
|
+
runAllTimers
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function withTestClock(env, clock) {
|
|
536
|
+
const current = env;
|
|
537
|
+
return {
|
|
538
|
+
...env,
|
|
539
|
+
brass: {
|
|
540
|
+
...current.brass ?? {},
|
|
541
|
+
clock
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function exitToPromise(exit) {
|
|
546
|
+
if (exit._tag === "Success") return exit.value;
|
|
547
|
+
const failure = Cause.firstFailure(exit.cause);
|
|
548
|
+
if (failure._tag === "Some") throw failure.value;
|
|
549
|
+
const defect = Cause.firstDefect(exit.cause);
|
|
550
|
+
if (defect._tag === "Some") {
|
|
551
|
+
throw defect.value instanceof Error ? defect.value : new Error(String(defect.value));
|
|
552
|
+
}
|
|
553
|
+
if (Cause.containsInterrupt(exit.cause)) throw new Error("Interrupted");
|
|
554
|
+
throw Cause.toError(exit.cause);
|
|
555
|
+
}
|
|
556
|
+
function runExitWithRuntime(runtime, effect) {
|
|
557
|
+
return new Promise((resolve) => {
|
|
274
558
|
runtime.unsafeRunAsync(effect, resolve);
|
|
275
559
|
});
|
|
276
|
-
|
|
560
|
+
}
|
|
561
|
+
function stableJson(value) {
|
|
562
|
+
return JSON.stringify(value);
|
|
563
|
+
}
|
|
564
|
+
function firstFailureValue(exit) {
|
|
565
|
+
if (exit._tag !== "Failure") return void 0;
|
|
566
|
+
const failure = Cause.firstFailure(exit.cause);
|
|
567
|
+
return failure._tag === "Some" ? failure.value : void 0;
|
|
568
|
+
}
|
|
569
|
+
function makeAssertionRuntime(runtime) {
|
|
570
|
+
return runtime ?? Runtime.make({});
|
|
277
571
|
}
|
|
278
572
|
async function assertSucceeds(effect, expected, runtime) {
|
|
279
|
-
const rt = runtime
|
|
280
|
-
const exit = await
|
|
281
|
-
rt.unsafeRunAsync(effect, resolve);
|
|
282
|
-
});
|
|
573
|
+
const rt = makeAssertionRuntime(runtime);
|
|
574
|
+
const exit = await runExitWithRuntime(rt, effect);
|
|
283
575
|
if (exit._tag !== "Success") {
|
|
284
|
-
throw new Error(`Expected success with ${
|
|
576
|
+
throw new Error(`Expected success with ${stableJson(expected)}, got failure: ${stableJson(exit.cause)}`);
|
|
285
577
|
}
|
|
286
|
-
if (
|
|
287
|
-
throw new Error(`Expected ${
|
|
578
|
+
if (stableJson(exit.value) !== stableJson(expected)) {
|
|
579
|
+
throw new Error(`Expected ${stableJson(expected)}, got ${stableJson(exit.value)}`);
|
|
288
580
|
}
|
|
289
581
|
}
|
|
290
582
|
async function assertFails(effect, expectedError, runtime) {
|
|
291
|
-
const rt = runtime
|
|
292
|
-
const exit = await
|
|
293
|
-
rt.unsafeRunAsync(effect, resolve);
|
|
294
|
-
});
|
|
583
|
+
const rt = makeAssertionRuntime(runtime);
|
|
584
|
+
const exit = await runExitWithRuntime(rt, effect);
|
|
295
585
|
if (exit._tag !== "Failure") {
|
|
296
|
-
throw new Error(`Expected failure with ${
|
|
586
|
+
throw new Error(`Expected failure with ${stableJson(expectedError)}, got success: ${stableJson(exit.value)}`);
|
|
297
587
|
}
|
|
298
|
-
const error = exit
|
|
299
|
-
if (
|
|
300
|
-
throw new Error(`Expected error ${
|
|
588
|
+
const error = firstFailureValue(exit);
|
|
589
|
+
if (stableJson(error) !== stableJson(expectedError)) {
|
|
590
|
+
throw new Error(`Expected error ${stableJson(expectedError)}, got ${stableJson(error)}`);
|
|
301
591
|
}
|
|
302
592
|
}
|
|
303
593
|
async function assertFailsWith(effect, predicate, runtime) {
|
|
304
|
-
const rt = runtime
|
|
305
|
-
const exit = await
|
|
306
|
-
rt.unsafeRunAsync(effect, resolve);
|
|
307
|
-
});
|
|
594
|
+
const rt = makeAssertionRuntime(runtime);
|
|
595
|
+
const exit = await runExitWithRuntime(rt, effect);
|
|
308
596
|
if (exit._tag !== "Failure") {
|
|
309
|
-
throw new Error(`Expected failure, got success: ${
|
|
597
|
+
throw new Error(`Expected failure, got success: ${stableJson(exit.value)}`);
|
|
310
598
|
}
|
|
311
|
-
const error = exit
|
|
312
|
-
if (!predicate(error)) {
|
|
313
|
-
throw new Error(`Error did not match predicate: ${
|
|
599
|
+
const error = firstFailureValue(exit);
|
|
600
|
+
if (error === void 0 || !predicate(error)) {
|
|
601
|
+
throw new Error(`Error did not match predicate: ${stableJson(error)}`);
|
|
314
602
|
}
|
|
315
603
|
}
|
|
316
604
|
async function assertCompletesWithin(effect, maxMs, runtime) {
|
|
317
|
-
const rt = runtime
|
|
318
|
-
const start =
|
|
605
|
+
const rt = makeAssertionRuntime(runtime);
|
|
606
|
+
const start = runtimeClockFromEnv(rt.env).now();
|
|
319
607
|
const result = await rt.toPromise(effect);
|
|
320
|
-
const elapsed =
|
|
608
|
+
const elapsed = runtimeClockFromEnv(rt.env).now() - start;
|
|
321
609
|
if (elapsed > maxMs) {
|
|
322
610
|
throw new Error(`Effect took ${elapsed.toFixed(1)}ms, expected < ${maxMs}ms`);
|
|
323
611
|
}
|
|
@@ -328,16 +616,17 @@ function flakyEffect(failCount, successValue, errorValue) {
|
|
|
328
616
|
return asyncEffect((_env, cb) => {
|
|
329
617
|
calls++;
|
|
330
618
|
if (calls <= failCount) {
|
|
331
|
-
cb(
|
|
619
|
+
cb(Exit.failCause(Cause.fail(errorValue)));
|
|
332
620
|
} else {
|
|
333
|
-
cb(
|
|
621
|
+
cb(Exit.succeed(successValue));
|
|
334
622
|
}
|
|
335
623
|
});
|
|
336
624
|
}
|
|
337
625
|
function delayedEffect(ms, value) {
|
|
338
|
-
return asyncEffect((
|
|
339
|
-
const
|
|
340
|
-
|
|
626
|
+
return asyncEffect((env, cb) => {
|
|
627
|
+
const clock = runtimeClockFromEnv(env);
|
|
628
|
+
const id = clock.setTimeout(() => cb(Exit.succeed(value)), ms);
|
|
629
|
+
return () => clock.clearTimeout(id);
|
|
341
630
|
});
|
|
342
631
|
}
|
|
343
632
|
function neverEffect() {
|
|
@@ -348,6 +637,124 @@ function neverEffect() {
|
|
|
348
637
|
}
|
|
349
638
|
|
|
350
639
|
// src/core/runtime/layer.ts
|
|
640
|
+
var MissingLayerServiceError = class extends Error {
|
|
641
|
+
_tag = "MissingLayerService";
|
|
642
|
+
serviceName;
|
|
643
|
+
constructor(serviceName) {
|
|
644
|
+
super(`Missing layer service '${serviceName}'. Add a layer that provides this ServiceTag or pass a LayerContext containing it.`);
|
|
645
|
+
this.name = "MissingLayerServiceError";
|
|
646
|
+
this.serviceName = serviceName;
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
function formatLayerError(error) {
|
|
650
|
+
if (error instanceof MissingLayerServiceError) return error.message;
|
|
651
|
+
if (isObjectRecord(error) && error._tag === "MissingLayerService" && typeof error.serviceName === "string") {
|
|
652
|
+
return `Missing layer service '${error.serviceName}'. Add the provider layer before using the service.`;
|
|
653
|
+
}
|
|
654
|
+
return error instanceof Error ? error.message : String(error);
|
|
655
|
+
}
|
|
656
|
+
function makeServiceTag(name) {
|
|
657
|
+
return {
|
|
658
|
+
_tag: "ServiceTag",
|
|
659
|
+
key: Symbol(name),
|
|
660
|
+
name
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
var serviceTag = makeServiceTag;
|
|
664
|
+
var defineService = makeServiceTag;
|
|
665
|
+
var LayerContext = class _LayerContext {
|
|
666
|
+
services;
|
|
667
|
+
constructor(entries) {
|
|
668
|
+
if (entries instanceof Map) {
|
|
669
|
+
this.services = new Map(entries);
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
this.services = /* @__PURE__ */ new Map();
|
|
673
|
+
if (!entries) return;
|
|
674
|
+
for (const [tag, service] of entries) this.services.set(tag.key, service);
|
|
675
|
+
}
|
|
676
|
+
static empty() {
|
|
677
|
+
return new _LayerContext();
|
|
678
|
+
}
|
|
679
|
+
get(tag) {
|
|
680
|
+
return this.services.get(tag.key);
|
|
681
|
+
}
|
|
682
|
+
unsafeGet(tag) {
|
|
683
|
+
if (!this.services.has(tag.key)) {
|
|
684
|
+
throw new MissingLayerServiceError(tag.name);
|
|
685
|
+
}
|
|
686
|
+
return this.services.get(tag.key);
|
|
687
|
+
}
|
|
688
|
+
has(tag) {
|
|
689
|
+
return this.services.has(tag.key);
|
|
690
|
+
}
|
|
691
|
+
add(tag, service) {
|
|
692
|
+
const next = new Map(this.services);
|
|
693
|
+
next.set(tag.key, service);
|
|
694
|
+
return new _LayerContext(next);
|
|
695
|
+
}
|
|
696
|
+
merge(other) {
|
|
697
|
+
const next = new Map(this.services);
|
|
698
|
+
for (const [key, service] of other.services) next.set(key, service);
|
|
699
|
+
return new _LayerContext(next);
|
|
700
|
+
}
|
|
701
|
+
size() {
|
|
702
|
+
return this.services.size;
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
function makeLayerScope() {
|
|
706
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
707
|
+
const finalizers = [];
|
|
708
|
+
let closed = false;
|
|
709
|
+
const scope = {
|
|
710
|
+
get: (l, deps) => {
|
|
711
|
+
if (closed) return asyncFail(new Error("LayerScope is closed"));
|
|
712
|
+
if (cache.has(l)) return asyncSucceed(cache.get(l));
|
|
713
|
+
const built = l.buildScoped ? l.buildScoped(deps, scope) : asyncFlatMap(
|
|
714
|
+
l.build(deps),
|
|
715
|
+
({ service, release }) => asyncFlatMap(scope.addFinalizer(release), () => asyncSucceed(service))
|
|
716
|
+
);
|
|
717
|
+
return asyncFlatMap(
|
|
718
|
+
built,
|
|
719
|
+
(service) => asyncSync(() => {
|
|
720
|
+
cache.set(l, service);
|
|
721
|
+
return service;
|
|
722
|
+
})
|
|
723
|
+
);
|
|
724
|
+
},
|
|
725
|
+
close: () => {
|
|
726
|
+
if (closed) return unit();
|
|
727
|
+
closed = true;
|
|
728
|
+
return releaseAll(finalizers);
|
|
729
|
+
},
|
|
730
|
+
size: () => finalizers.length,
|
|
731
|
+
addFinalizer: (release) => asyncSync(() => {
|
|
732
|
+
if (!closed) finalizers.push(release);
|
|
733
|
+
})
|
|
734
|
+
};
|
|
735
|
+
return scope;
|
|
736
|
+
}
|
|
737
|
+
function releaseAll(finalizers) {
|
|
738
|
+
const next = finalizers.pop();
|
|
739
|
+
if (!next) return unit();
|
|
740
|
+
return asyncFold(
|
|
741
|
+
next(),
|
|
742
|
+
() => releaseAll(finalizers),
|
|
743
|
+
() => releaseAll(finalizers)
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
function mergeServices(a, b) {
|
|
747
|
+
if (a instanceof LayerContext && b instanceof LayerContext) {
|
|
748
|
+
return a.merge(b);
|
|
749
|
+
}
|
|
750
|
+
if (isObjectRecord(a) && isObjectRecord(b)) {
|
|
751
|
+
return { ...a, ...b };
|
|
752
|
+
}
|
|
753
|
+
return Object.assign({}, a, b);
|
|
754
|
+
}
|
|
755
|
+
function isObjectRecord(value) {
|
|
756
|
+
return typeof value === "object" && value !== null;
|
|
757
|
+
}
|
|
351
758
|
function layer(acquire, release) {
|
|
352
759
|
return {
|
|
353
760
|
_tag: "Layer",
|
|
@@ -357,6 +764,23 @@ function layer(acquire, release) {
|
|
|
357
764
|
}))
|
|
358
765
|
};
|
|
359
766
|
}
|
|
767
|
+
function layerValue(tag, value) {
|
|
768
|
+
return layerEffect(tag, () => asyncSucceed(value));
|
|
769
|
+
}
|
|
770
|
+
function layerEffect(tag, acquire, release) {
|
|
771
|
+
return {
|
|
772
|
+
_tag: "Layer",
|
|
773
|
+
build: (deps = LayerContext.empty()) => asyncFlatMap(acquire(deps), (service) => asyncSucceed({
|
|
774
|
+
service: deps.add(tag, service),
|
|
775
|
+
release: release ? () => release(service) : () => unit()
|
|
776
|
+
}))
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
var layerFromContext = layerEffect;
|
|
780
|
+
var defineLayer = layerEffect;
|
|
781
|
+
function getService(tag) {
|
|
782
|
+
return asyncSync((context) => context.unsafeGet(tag));
|
|
783
|
+
}
|
|
360
784
|
function layerFrom() {
|
|
361
785
|
return (acquire, release) => ({
|
|
362
786
|
_tag: "Layer",
|
|
@@ -381,6 +805,10 @@ function layerFail(error) {
|
|
|
381
805
|
function compose(from, to) {
|
|
382
806
|
return {
|
|
383
807
|
_tag: "Layer",
|
|
808
|
+
buildScoped: (deps, scope) => asyncFlatMap(
|
|
809
|
+
scope.get(from, deps),
|
|
810
|
+
(mid) => scope.get(to, mid)
|
|
811
|
+
),
|
|
384
812
|
build: (deps) => asyncFlatMap(
|
|
385
813
|
from.build(deps),
|
|
386
814
|
({ service: mid, release: releaseMid }) => asyncFold(
|
|
@@ -397,13 +825,20 @@ function compose(from, to) {
|
|
|
397
825
|
function merge(left, right) {
|
|
398
826
|
return {
|
|
399
827
|
_tag: "Layer",
|
|
828
|
+
buildScoped: (deps, scope) => asyncFlatMap(
|
|
829
|
+
scope.get(left, deps),
|
|
830
|
+
(a) => asyncFlatMap(
|
|
831
|
+
scope.get(right, deps),
|
|
832
|
+
(b) => asyncSucceed(mergeServices(a, b))
|
|
833
|
+
)
|
|
834
|
+
),
|
|
400
835
|
build: (deps) => asyncFlatMap(
|
|
401
836
|
left.build(deps),
|
|
402
837
|
({ service: a, release: releaseA }) => asyncFold(
|
|
403
838
|
right.build(deps),
|
|
404
839
|
(error) => asyncFlatMap(releaseA(), () => asyncFail(error)),
|
|
405
840
|
({ service: b, release: releaseB }) => asyncSucceed({
|
|
406
|
-
service:
|
|
841
|
+
service: mergeServices(a, b),
|
|
407
842
|
release: () => asyncFlatMap(releaseB(), () => releaseA())
|
|
408
843
|
})
|
|
409
844
|
)
|
|
@@ -413,22 +848,63 @@ function merge(left, right) {
|
|
|
413
848
|
function mapLayer(l, f) {
|
|
414
849
|
return {
|
|
415
850
|
_tag: "Layer",
|
|
851
|
+
buildScoped: (deps, scope) => asyncFlatMap(
|
|
852
|
+
scope.get(l, deps),
|
|
853
|
+
(service) => asyncSucceed(f(service))
|
|
854
|
+
),
|
|
416
855
|
build: (deps) => asyncFlatMap(
|
|
417
856
|
l.build(deps),
|
|
418
857
|
({ service, release }) => asyncSucceed({ service: f(service), release })
|
|
419
858
|
)
|
|
420
859
|
};
|
|
421
860
|
}
|
|
861
|
+
function buildLayer(l, deps) {
|
|
862
|
+
const scope = makeLayerScope();
|
|
863
|
+
return asyncFold(
|
|
864
|
+
scope.get(l, deps),
|
|
865
|
+
(error) => asyncFlatMap(scope.close(), () => asyncFail(error)),
|
|
866
|
+
(service) => asyncSucceed({
|
|
867
|
+
service,
|
|
868
|
+
scope,
|
|
869
|
+
close: scope.close,
|
|
870
|
+
use: (body) => body(service)
|
|
871
|
+
})
|
|
872
|
+
);
|
|
873
|
+
}
|
|
422
874
|
function provideLayer(l, use, deps) {
|
|
423
875
|
return asyncFlatMap(
|
|
424
|
-
l
|
|
425
|
-
({ service,
|
|
876
|
+
buildLayer(l, deps ?? {}),
|
|
877
|
+
({ service, close }) => ensuring(
|
|
426
878
|
use(service),
|
|
427
|
-
(
|
|
428
|
-
(value) => asyncFlatMap(release(), () => asyncSucceed(value))
|
|
879
|
+
() => close()
|
|
429
880
|
)
|
|
430
881
|
);
|
|
431
882
|
}
|
|
883
|
+
function provideLayerContext(l, use, deps = LayerContext.empty()) {
|
|
884
|
+
return provideLayer(l, use, deps);
|
|
885
|
+
}
|
|
886
|
+
var provide = provideLayer;
|
|
887
|
+
var provideContext = provideLayerContext;
|
|
888
|
+
var Layer = Object.freeze({
|
|
889
|
+
make: layer,
|
|
890
|
+
from: layerFrom,
|
|
891
|
+
succeed: layerSucceed,
|
|
892
|
+
fail: layerFail,
|
|
893
|
+
value: layerValue,
|
|
894
|
+
effect: layerEffect,
|
|
895
|
+
define: defineLayer,
|
|
896
|
+
fromContext: layerFromContext,
|
|
897
|
+
compose,
|
|
898
|
+
merge,
|
|
899
|
+
map: mapLayer,
|
|
900
|
+
provide: provideLayer,
|
|
901
|
+
provideContext: provideLayerContext,
|
|
902
|
+
build: buildLayer,
|
|
903
|
+
scope: makeLayerScope,
|
|
904
|
+
context: LayerContext.empty,
|
|
905
|
+
tag: makeServiceTag,
|
|
906
|
+
service: getService
|
|
907
|
+
});
|
|
432
908
|
|
|
433
909
|
// src/core/runtime/workerPool.ts
|
|
434
910
|
function makeWorkerPool(config = {}) {
|
|
@@ -653,7 +1129,7 @@ var RuntimeRegistry = class {
|
|
|
653
1129
|
f.runState = "Done";
|
|
654
1130
|
f.lastActiveAt = rec.wallTs;
|
|
655
1131
|
f.status = rec.status === "interrupted" ? "Interrupted" : "Done";
|
|
656
|
-
f.lastEnd = { status: rec.status, error: rec.error };
|
|
1132
|
+
f.lastEnd = { status: rec.status, error: formatRegistryError(rec.error) };
|
|
657
1133
|
}
|
|
658
1134
|
break;
|
|
659
1135
|
}
|
|
@@ -679,6 +1155,17 @@ var RuntimeRegistry = class {
|
|
|
679
1155
|
return this.recent.slice();
|
|
680
1156
|
}
|
|
681
1157
|
};
|
|
1158
|
+
function formatRegistryError(error) {
|
|
1159
|
+
if (error === void 0) return void 0;
|
|
1160
|
+
if (Cause.isCause(error)) return Cause.pretty(error, { singleLine: true });
|
|
1161
|
+
if (error instanceof Error) return error.message;
|
|
1162
|
+
if (typeof error === "string") return error;
|
|
1163
|
+
try {
|
|
1164
|
+
return JSON.stringify(error);
|
|
1165
|
+
} catch {
|
|
1166
|
+
return String(error);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
682
1169
|
|
|
683
1170
|
// src/core/runtime/dump.ts
|
|
684
1171
|
function dumpAllFibers(reg) {
|
|
@@ -943,9 +1430,11 @@ var Supervisor = class {
|
|
|
943
1430
|
}
|
|
944
1431
|
record.restartTimes.push(now);
|
|
945
1432
|
if (record.restart.schedule) {
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1433
|
+
record.scheduleDriver ??= makeScheduleDriver(record.restart.schedule, {
|
|
1434
|
+
name: record.restart.schedule.name ?? "supervisor.restart",
|
|
1435
|
+
clock: this.scheduleClock()
|
|
1436
|
+
});
|
|
1437
|
+
const decision = record.scheduleDriver.next(context);
|
|
949
1438
|
return decision.continue ? Math.max(0, Math.floor(decision.delayMs)) : void 0;
|
|
950
1439
|
}
|
|
951
1440
|
const raw = typeof record.restart.delayMs === "function" ? record.restart.delayMs(context) : record.restart.delayMs ?? 0;
|
|
@@ -988,6 +1477,13 @@ var Supervisor = class {
|
|
|
988
1477
|
this.onEvent?.(event);
|
|
989
1478
|
this.runtime.emit(toRuntimeEvent(event));
|
|
990
1479
|
}
|
|
1480
|
+
scheduleClock() {
|
|
1481
|
+
return {
|
|
1482
|
+
now: this.clock,
|
|
1483
|
+
setTimeout: liveClock.setTimeout,
|
|
1484
|
+
clearTimeout: liveClock.clearTimeout
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
991
1487
|
};
|
|
992
1488
|
function makeSupervisor(runtime, config = {}) {
|
|
993
1489
|
return new Supervisor(runtime, config);
|
|
@@ -1009,14 +1505,14 @@ function resolveRestartPolicy(policy) {
|
|
|
1009
1505
|
};
|
|
1010
1506
|
}
|
|
1011
1507
|
function shouldRestart(mode, exit) {
|
|
1012
|
-
if (exit._tag === "Failure" && exit.cause
|
|
1508
|
+
if (exit._tag === "Failure" && Cause.isInterruptedOnly(exit.cause)) return false;
|
|
1013
1509
|
if (mode === "never") return false;
|
|
1014
1510
|
if (mode === "always") return true;
|
|
1015
1511
|
return exit._tag === "Failure";
|
|
1016
1512
|
}
|
|
1017
1513
|
function statusFromExit(exit) {
|
|
1018
1514
|
if (exit._tag === "Success") return "succeeded";
|
|
1019
|
-
return exit.cause
|
|
1515
|
+
return Cause.isInterruptedOnly(exit.cause) ? "interrupted" : "failed";
|
|
1020
1516
|
}
|
|
1021
1517
|
function toRuntimeEvent(event) {
|
|
1022
1518
|
switch (event.type) {
|
|
@@ -1070,12 +1566,18 @@ function interruptExit() {
|
|
|
1070
1566
|
export {
|
|
1071
1567
|
makeCancelToken,
|
|
1072
1568
|
linkAbortController,
|
|
1569
|
+
makeRuntime,
|
|
1570
|
+
runPromise,
|
|
1571
|
+
runExit,
|
|
1572
|
+
runEffect,
|
|
1073
1573
|
LinkedQueue,
|
|
1074
1574
|
makeSemaphore,
|
|
1075
1575
|
makeRef,
|
|
1076
1576
|
derivedRef,
|
|
1077
1577
|
gracefulShutdown,
|
|
1078
1578
|
registerShutdownHooks,
|
|
1579
|
+
TestScheduler,
|
|
1580
|
+
TestClock,
|
|
1079
1581
|
makeTestRuntime,
|
|
1080
1582
|
assertSucceeds,
|
|
1081
1583
|
assertFails,
|
|
@@ -1084,14 +1586,31 @@ export {
|
|
|
1084
1586
|
flakyEffect,
|
|
1085
1587
|
delayedEffect,
|
|
1086
1588
|
neverEffect,
|
|
1589
|
+
MissingLayerServiceError,
|
|
1590
|
+
formatLayerError,
|
|
1591
|
+
makeServiceTag,
|
|
1592
|
+
serviceTag,
|
|
1593
|
+
defineService,
|
|
1594
|
+
LayerContext,
|
|
1595
|
+
makeLayerScope,
|
|
1087
1596
|
layer,
|
|
1597
|
+
layerValue,
|
|
1598
|
+
layerEffect,
|
|
1599
|
+
layerFromContext,
|
|
1600
|
+
defineLayer,
|
|
1601
|
+
getService,
|
|
1088
1602
|
layerFrom,
|
|
1089
1603
|
layerSucceed,
|
|
1090
1604
|
layerFail,
|
|
1091
1605
|
compose,
|
|
1092
1606
|
merge,
|
|
1093
1607
|
mapLayer,
|
|
1608
|
+
buildLayer,
|
|
1094
1609
|
provideLayer,
|
|
1610
|
+
provideLayerContext,
|
|
1611
|
+
provide,
|
|
1612
|
+
provideContext,
|
|
1613
|
+
Layer,
|
|
1095
1614
|
makeWorkerPool,
|
|
1096
1615
|
makeTracer,
|
|
1097
1616
|
consoleJsonLogger,
|