@demlik/tea 0.14.0 → 0.16.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 +30 -7
- package/dist/agent/index.d.ts +49 -36
- package/dist/agent/index.js +12 -8
- package/dist/chunk-4LPY67E4.js +18 -0
- package/dist/chunk-4LPY67E4.js.map +1 -0
- package/dist/chunk-5XU6ZJO2.js +533 -0
- package/dist/chunk-5XU6ZJO2.js.map +1 -0
- package/dist/{chunk-AQ6ZIMEA.js → chunk-6NG4V5SB.js} +89 -115
- package/dist/chunk-6NG4V5SB.js.map +1 -0
- package/dist/{chunk-HYDWG35Q.js → chunk-7MGXQZPW.js} +11 -9
- package/dist/chunk-7MGXQZPW.js.map +1 -0
- package/dist/{chunk-BLJ2JQSH.js → chunk-BCTEOVOU.js} +3 -3
- package/dist/{chunk-BLJ2JQSH.js.map → chunk-BCTEOVOU.js.map} +1 -1
- package/dist/chunk-CH5KTOEZ.js +710 -0
- package/dist/chunk-CH5KTOEZ.js.map +1 -0
- package/dist/chunk-CIHSHLQX.js +64 -0
- package/dist/chunk-CIHSHLQX.js.map +1 -0
- package/dist/{chunk-Z2L3LSNV.js → chunk-EHUDXAKC.js} +246 -210
- package/dist/chunk-EHUDXAKC.js.map +1 -0
- package/dist/chunk-GOX2CYIM.js +380 -0
- package/dist/chunk-GOX2CYIM.js.map +1 -0
- package/dist/chunk-IVJP3GKJ.js +104 -0
- package/dist/chunk-IVJP3GKJ.js.map +1 -0
- package/dist/{chunk-F7FMAWLA.js → chunk-MVZS5FDM.js} +13 -6
- package/dist/chunk-MVZS5FDM.js.map +1 -0
- package/dist/{chunk-LYLTKJWM.js → chunk-MYNLY3HP.js} +9 -8
- package/dist/chunk-MYNLY3HP.js.map +1 -0
- package/dist/{chunk-I5MQMJDW.js → chunk-NSIAORRY.js} +20 -30
- package/dist/chunk-NSIAORRY.js.map +1 -0
- package/dist/{chunk-MYXFNWAJ.js → chunk-QNGYQMZB.js} +4 -4
- package/dist/chunk-QNGYQMZB.js.map +1 -0
- package/dist/chunk-WT5PBPLB.js +98 -0
- package/dist/chunk-WT5PBPLB.js.map +1 -0
- package/dist/{core-CTzMJ82M.d.ts → core-BbgtiXdg.d.ts} +231 -139
- package/dist/do/index.d.ts +37 -32
- package/dist/do/index.js +21 -14
- package/dist/do/index.js.map +1 -1
- package/dist/{durable-effects-B0-qGQDy.d.ts → durable-effects-7MTK_jnj.d.ts} +1 -1
- package/dist/effect/index.d.ts +151 -0
- package/dist/effect/index.js +98 -0
- package/dist/effect/index.js.map +1 -0
- package/dist/extension/index.d.ts +6 -7
- package/dist/extension/index.js +3 -2
- package/dist/extension/index.js.map +1 -1
- package/dist/flow/index.d.ts +68 -70
- package/dist/flow/index.js +32 -27
- package/dist/flow/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +6 -7
- package/dist/idempotency/index.js +4 -2
- package/dist/{index-DJWIER_3.d.ts → index-7vV8xmsD.d.ts} +1 -1
- package/dist/{index-NjrT3fL2.d.ts → index-Bz5Rh9Ga.d.ts} +19 -96
- package/dist/index-CjFDUBeq.d.ts +207 -0
- package/dist/{index-6A7dB8f6.d.ts → index-CkFYA9Y6.d.ts} +14 -16
- package/dist/{index-B5BZ-_cT.d.ts → index-Cou86-GX.d.ts} +189 -108
- package/dist/{index-TvRb1KVf.d.ts → index-DU6JpQ8G.d.ts} +1 -1
- package/dist/{index-q0hXFeZ0.d.ts → index-Xufl55W8.d.ts} +286 -215
- package/dist/{index-4vZzljCD.d.ts → index-_dOR3xqA.d.ts} +57 -45
- package/dist/index.d.ts +181 -385
- package/dist/index.js +2 -1
- package/dist/jev/index.d.ts +147 -99
- package/dist/jev/index.js +329 -233
- package/dist/jev/index.js.map +1 -1
- package/dist/{machine-CdIcN2Xm.d.ts → machine-BQzTV8On.d.ts} +171 -280
- package/dist/machine-viz/index.d.ts +5 -5
- package/dist/machine-viz/index.js +8 -4
- package/dist/machine-viz/index.js.map +1 -1
- package/dist/mem/index.d.ts +3 -4
- package/dist/mem/index.js +2 -1
- package/dist/mem/index.js.map +1 -1
- package/dist/node/index.d.ts +119 -78
- package/dist/node/index.js +52 -38
- package/dist/node/index.js.map +1 -1
- package/dist/paginate/index.d.ts +27 -33
- package/dist/paginate/index.js +6 -4
- package/dist/parity/index.d.ts +4 -5
- package/dist/parity/index.js +3 -2
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/index.d.ts +2 -2
- package/dist/pbt/index.js +2 -1
- package/dist/pbt/index.js.map +1 -1
- package/dist/persistence/index.d.ts +6 -7
- package/dist/persistence/index.js +5 -3
- package/dist/promise/index.d.ts +186 -0
- package/dist/promise/index.js +5 -0
- package/dist/promise/index.js.map +1 -0
- package/dist/protocol-ClRZBhHQ.d.ts +53 -0
- package/dist/react/index.d.ts +36 -17
- package/dist/react/index.js +27 -4
- package/dist/react/index.js.map +1 -1
- package/dist/resilience/index.d.ts +63 -455
- package/dist/resilience/index.js +37 -483
- package/dist/resilience/index.js.map +1 -1
- package/dist/{runtime-types-LWDoi943.d.ts → runtime-types-CiVpC0HN.d.ts} +131 -388
- package/dist/testing/index.d.ts +165 -15
- package/dist/testing/index.js +104 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/timing/index.d.ts +25 -22
- package/dist/timing/index.js +4 -3
- package/dist/timing/index.js.map +1 -1
- package/dist/{types-DP3f5NIl.d.ts → types-LxZxGYda.d.ts} +2 -2
- package/dist/work-queue/index.d.ts +5 -6
- package/package.json +18 -5
- package/dist/chunk-AQ6ZIMEA.js.map +0 -1
- package/dist/chunk-F2US5BW6.js +0 -72
- package/dist/chunk-F2US5BW6.js.map +0 -1
- package/dist/chunk-F7FMAWLA.js.map +0 -1
- package/dist/chunk-HUKZQX6U.js +0 -97
- package/dist/chunk-HUKZQX6U.js.map +0 -1
- package/dist/chunk-HYDWG35Q.js.map +0 -1
- package/dist/chunk-I5MQMJDW.js.map +0 -1
- package/dist/chunk-LYLTKJWM.js.map +0 -1
- package/dist/chunk-MYXFNWAJ.js.map +0 -1
- package/dist/chunk-RQULHGYH.js +0 -1804
- package/dist/chunk-RQULHGYH.js.map +0 -1
- package/dist/chunk-Z2L3LSNV.js.map +0 -1
- package/dist/index-DMCeMPMJ.d.ts +0 -272
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @demlik/tea — pure-core leaf (ADR 0006).
|
|
@@ -9,40 +9,48 @@ import { z } from 'zod';
|
|
|
9
9
|
* `Reducer`, `Transitions`, `Cmd`, `Sub`, `Port`, …).
|
|
10
10
|
*
|
|
11
11
|
* **Dependency direction (the actual decoupling):** this module imports
|
|
12
|
-
* NOTHING from the runtime — no `
|
|
12
|
+
* NOTHING from the runtime — no `run`/host/`Store`. The
|
|
13
13
|
* runtime (`run`, the host, interpret, `Store`, subscribe — all in
|
|
14
14
|
* `../index.ts`) imports *from* here; never the reverse. The root door
|
|
15
15
|
* re-exports this surface through `./index.ts`, and
|
|
16
16
|
* `pure/import-graph.test.ts` is the regression fence asserting the pure
|
|
17
17
|
* entrypoint's import graph never reaches `run`.
|
|
18
18
|
*
|
|
19
|
-
* The one external name it reaches for is
|
|
20
|
-
* erased at compile time —
|
|
21
|
-
*
|
|
19
|
+
* The one external name it reaches for is the Standard Schema TYPE surface
|
|
20
|
+
* (`import type` from `@standard-schema/spec`), erased at compile time —
|
|
21
|
+
* `Cmd.define` accepts any Standard Schema (zod, Effect Schema through
|
|
22
|
+
* `Schema.toStandardSchemaV1`, …), and it imports no schema library.
|
|
22
23
|
*/
|
|
23
24
|
|
|
24
|
-
type RequirementsOf<C> = C extends {
|
|
25
|
-
readonly __r?: infer R;
|
|
26
|
-
} ? R : unknown;
|
|
27
25
|
/** The `E` union one Cmd can settle with; `unknown` for an untyped Cmd. */
|
|
28
26
|
type ErrorsOf<C> = C extends {
|
|
29
27
|
readonly __e?: infer E;
|
|
30
28
|
} ? E : unknown;
|
|
31
|
-
type UnionToIntersection<U> = (U extends unknown ? (u: U) => void : never) extends (u: infer I) => void ? I : never;
|
|
32
|
-
type RequirementsBoxed<C> = C extends unknown ? [RequirementsOf<C>] : never;
|
|
33
|
-
type KnownRequirements<B> = B extends [infer R] ? unknown extends R ? never : R : never;
|
|
34
29
|
/**
|
|
35
|
-
* The
|
|
36
|
-
* `
|
|
37
|
-
*
|
|
38
|
-
* that requires nothing — untyped, or `Cmd.define`d without `requirements` — leaves
|
|
39
|
-
* the demand of its siblings intact (#56).
|
|
40
|
-
*
|
|
41
|
-
* This is the requirement. `provide` is what satisfies it: hand `run` a
|
|
42
|
-
* `provide({ … })` graph in place of the object and the same `Ctx` is built once
|
|
43
|
-
* at boot, in dependency order, and released in reverse when the run ends.
|
|
30
|
+
* The two builders the Promise engine hands a `Cmd.define`d handler on its
|
|
31
|
+
* ctx: `ok(value)` and `err({ _tag })`, with `err` typed to the def's declared
|
|
32
|
+
* tags.
|
|
44
33
|
*/
|
|
45
|
-
|
|
34
|
+
interface OutcomeHelpers<Ok, E> {
|
|
35
|
+
readonly ok: (value: Ok) => Outcome<Ok, never>;
|
|
36
|
+
readonly err: (error: E) => Outcome<never, E>;
|
|
37
|
+
}
|
|
38
|
+
/** The result a `Cmd.define`d handler returns: its value, or a declared failure. */
|
|
39
|
+
type Outcome<Ok, E> = {
|
|
40
|
+
readonly _tag: "Ok";
|
|
41
|
+
readonly value: Ok;
|
|
42
|
+
} | {
|
|
43
|
+
readonly _tag: "Err";
|
|
44
|
+
readonly error: E;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Build an {@link Outcome} outside a handler's helpers — in a test that calls a
|
|
48
|
+
* handler directly, or in an adapter converting another result type.
|
|
49
|
+
*/
|
|
50
|
+
declare const Outcome: {
|
|
51
|
+
readonly ok: <Ok>(value: Ok) => Outcome<Ok, never>;
|
|
52
|
+
readonly err: <E>(error: E) => Outcome<never, E>;
|
|
53
|
+
};
|
|
46
54
|
/** The shape every settled failure has (ADR 0011): a plain `_tag` record. */
|
|
47
55
|
type Tagged = {
|
|
48
56
|
readonly _tag: string;
|
|
@@ -57,9 +65,9 @@ type TaggedError<Tag extends string> = Tag extends string ? {
|
|
|
57
65
|
readonly [detail: string]: unknown;
|
|
58
66
|
} : never;
|
|
59
67
|
/**
|
|
60
|
-
* The kernel-minted failure: a handler returned
|
|
68
|
+
* The kernel-minted failure: a handler returned an `Ok` value the Cmd's `ok`
|
|
61
69
|
* schema rejects. Plain data, so it folds into Model like any settled error;
|
|
62
|
-
* `issues` is
|
|
70
|
+
* `issues` is the schema's issue list flattened to `path` + `message` strings.
|
|
63
71
|
*/
|
|
64
72
|
type MalformedResult = {
|
|
65
73
|
readonly _tag: "malformed_result";
|
|
@@ -68,6 +76,50 @@ type MalformedResult = {
|
|
|
68
76
|
readonly message: string;
|
|
69
77
|
}>;
|
|
70
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* A schema whose `validate` returned a Promise where the kernel needs an answer
|
|
81
|
+
* now — the `ok` check at the interpret edge, the `args` check in a reducer.
|
|
82
|
+
* A contract breach (ADR 0021 §5): it goes to the error sink.
|
|
83
|
+
*/
|
|
84
|
+
declare class AsyncSchemaError extends Error {
|
|
85
|
+
/** What the schema was checking, e.g. `the "fetch" Cmd's ok schema`. */
|
|
86
|
+
readonly where: string;
|
|
87
|
+
readonly name = "AsyncSchemaError";
|
|
88
|
+
readonly _tag: "AsyncSchemaError";
|
|
89
|
+
constructor(
|
|
90
|
+
/** What the schema was checking, e.g. `the "fetch" Cmd's ok schema`. */
|
|
91
|
+
where: string);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* A `Cmd.define`d handler failed outside its declared channel: its `Err` carried
|
|
95
|
+
* no `_tag`, or a tag the def does not declare. A contract breach (ADR 0011,
|
|
96
|
+
* 0021 §4): it goes to the error sink, never to `<name>_err`.
|
|
97
|
+
*/
|
|
98
|
+
declare class UndeclaredFailureError extends Error {
|
|
99
|
+
readonly cmdType: string;
|
|
100
|
+
/** The `error` the handler's `Err` carried, verbatim. */
|
|
101
|
+
readonly failure: unknown;
|
|
102
|
+
/** The tags the def declares. */
|
|
103
|
+
readonly declared: readonly string[];
|
|
104
|
+
readonly name = "UndeclaredFailureError";
|
|
105
|
+
readonly _tag: "UndeclaredFailureError";
|
|
106
|
+
constructor(cmdType: string,
|
|
107
|
+
/** The `error` the handler's `Err` carried, verbatim. */
|
|
108
|
+
failure: unknown,
|
|
109
|
+
/** The tags the def declares. */
|
|
110
|
+
declared: readonly string[]);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* A `Cmd.define`d handler returned something the engine cannot settle: any Msg
|
|
114
|
+
* (the engine mints the Cmd's `<name>_ok` / `<name>_err`, never the handler —
|
|
115
|
+
* ADR 0021), or any other value that is neither an {@link Outcome} nor nothing.
|
|
116
|
+
*/
|
|
117
|
+
declare class OutcomeContractError extends Error {
|
|
118
|
+
readonly cmdType: string;
|
|
119
|
+
readonly name = "OutcomeContractError";
|
|
120
|
+
readonly _tag: "OutcomeContractError";
|
|
121
|
+
constructor(cmdType: string, detail: string);
|
|
122
|
+
}
|
|
71
123
|
/**
|
|
72
124
|
* The payload a constructor accepts: a plain record spread beside `type`. A
|
|
73
125
|
* `type` key is refused at the type level — it would overwrite the discriminant.
|
|
@@ -75,16 +127,8 @@ type MalformedResult = {
|
|
|
75
127
|
type CmdInput = {
|
|
76
128
|
readonly type?: never;
|
|
77
129
|
} & Record<string, unknown>;
|
|
78
|
-
/**
|
|
79
|
-
* Phantom carrier for a Cmd's `R`. `Cmd.requirements<{ http: Http }>()` is how a
|
|
80
|
-
* declaration names the `Ctx` slice its handler reads — a type, not a value, so
|
|
81
|
-
* nothing is constructed and nothing is checked at runtime.
|
|
82
|
-
*/
|
|
83
|
-
type Requirements<R> = {
|
|
84
|
-
readonly __r?: R;
|
|
85
|
-
};
|
|
86
130
|
/** The value `Cmd.define("fetch", …)` builds: `{ type: "fetch", ...input }`. */
|
|
87
|
-
type CmdValue<Name extends string, Input extends CmdInput, E extends Tagged
|
|
131
|
+
type CmdValue<Name extends string, Input extends CmdInput, Ok, E extends Tagged> = Cmd<Name, Ok, E | MalformedResult> & Readonly<Input>;
|
|
88
132
|
type SettledOk<Name extends string, C, Ok> = {
|
|
89
133
|
readonly type: `${Name}_ok`;
|
|
90
134
|
readonly cmd: C;
|
|
@@ -104,37 +148,39 @@ type SettledErr<Name extends string, C, E extends Tagged> = {
|
|
|
104
148
|
* the minted Msg builders and the declaration hung on it. `E` here is the
|
|
105
149
|
* DECLARED tag union; the settled `_err` arm widens it by `MalformedResult`.
|
|
106
150
|
*
|
|
107
|
-
* `ok` / `err`
|
|
108
|
-
*
|
|
109
|
-
*
|
|
151
|
+
* `ok` / `err` mint a settled Msg OUTSIDE the runtime (a `replay` log, a unit
|
|
152
|
+
* test) and take an optional `at`. A handler never calls them: it returns an
|
|
153
|
+
* {@link Outcome}, and inside `run` the interpret edge mints and stamps.
|
|
110
154
|
*/
|
|
111
|
-
interface CmdDef<Name extends string, Input extends CmdInput, Ok, E extends Tagged
|
|
112
|
-
(input: Input): CmdValue<Name, Input,
|
|
155
|
+
interface CmdDef<Name extends string, Input extends CmdInput, Ok, E extends Tagged> {
|
|
156
|
+
(input: Input): CmdValue<Name, Input, Ok, E>;
|
|
113
157
|
/** The `type` discriminant of every Cmd this builds. */
|
|
114
158
|
readonly cmdType: Name;
|
|
115
159
|
readonly okType: `${Name}_ok`;
|
|
116
160
|
readonly errType: `${Name}_err`;
|
|
117
|
-
readonly ok: (cmd: CmdValue<Name, Input,
|
|
118
|
-
readonly err: (cmd: CmdValue<Name, Input,
|
|
161
|
+
readonly ok: (cmd: CmdValue<Name, Input, Ok, E>, value: Ok, at?: number) => SettledOk<Name, CmdValue<Name, Input, Ok, E>, Ok>;
|
|
162
|
+
readonly err: (cmd: CmdValue<Name, Input, Ok, E>, error: E, at?: number) => SettledErr<Name, CmdValue<Name, Input, Ok, E>, E>;
|
|
119
163
|
readonly schema: {
|
|
120
|
-
readonly input:
|
|
121
|
-
readonly ok:
|
|
164
|
+
readonly input: StandardSchemaV1<unknown, Input>;
|
|
165
|
+
readonly ok: StandardSchemaV1<unknown, Ok>;
|
|
122
166
|
};
|
|
123
167
|
/** The declared `_tag` list, verbatim. */
|
|
124
168
|
readonly errTags: ReadonlyArray<E["_tag"]>;
|
|
125
169
|
}
|
|
126
170
|
/**
|
|
127
171
|
* The declaration-erased view the runtime reads: which `type` a def builds,
|
|
128
|
-
* which two Msg types it settles with,
|
|
129
|
-
*
|
|
172
|
+
* which two Msg types it settles with, the `ok` schema the edge parses against
|
|
173
|
+
* and the tags an `Err` may carry. Every `CmdDef<…>` is one of these
|
|
174
|
+
* structurally.
|
|
130
175
|
*/
|
|
131
176
|
type AnyCmdDef = {
|
|
132
177
|
readonly cmdType: string;
|
|
133
178
|
readonly okType: string;
|
|
134
179
|
readonly errType: string;
|
|
135
180
|
readonly schema: {
|
|
136
|
-
readonly ok:
|
|
181
|
+
readonly ok: StandardSchemaV1;
|
|
137
182
|
};
|
|
183
|
+
readonly errTags: ReadonlyArray<string>;
|
|
138
184
|
};
|
|
139
185
|
/** The Cmd value a def (or a union of defs) builds. */
|
|
140
186
|
type CmdOf<D extends AnyCmdDef> = D extends ((input: never) => infer C extends Cmd) ? C : never;
|
|
@@ -143,17 +189,16 @@ type CmdOf<D extends AnyCmdDef> = D extends ((input: never) => infer C extends C
|
|
|
143
189
|
* `value`, `<name>_err` carrying `error`. `defineMachine({ cmds })` folds this
|
|
144
190
|
* into the machine's `M` so the user never spells the effect half of it.
|
|
145
191
|
*/
|
|
146
|
-
type Settled<D extends AnyCmdDef> = D extends CmdDef<infer Name, infer Input, infer Ok, infer E
|
|
192
|
+
type Settled<D extends AnyCmdDef> = D extends CmdDef<infer Name, infer Input, infer Ok, infer E> ? SettledOk<Name, CmdValue<Name, Input, Ok, E>, Ok> | SettledErr<Name, CmdValue<Name, Input, Ok, E>, E> : never;
|
|
147
193
|
/** The `Ok` a def's handler must produce. */
|
|
148
|
-
type OkOf<D extends AnyCmdDef> = D extends CmdDef<infer _Name, infer _Input, infer Ok, infer _E
|
|
194
|
+
type OkOf<D extends AnyCmdDef> = D extends CmdDef<infer _Name, infer _Input, infer Ok, infer _E> ? Ok : never;
|
|
149
195
|
/** The DECLARED failure union a def's handler may settle with. */
|
|
150
|
-
type ErrOf<D extends AnyCmdDef> = D extends CmdDef<infer _Name, infer _Input, infer _Ok, infer E
|
|
151
|
-
declare function defineCmd<const Name extends string, Input extends CmdInput, Ok, const Tags extends readonly string[]
|
|
152
|
-
readonly input:
|
|
153
|
-
readonly ok:
|
|
196
|
+
type ErrOf<D extends AnyCmdDef> = D extends CmdDef<infer _Name, infer _Input, infer _Ok, infer E> ? E : never;
|
|
197
|
+
declare function defineCmd<const Name extends string, Input extends CmdInput, Ok, const Tags extends readonly string[]>(name: Name, spec: {
|
|
198
|
+
readonly input: StandardSchemaV1<unknown, Input>;
|
|
199
|
+
readonly ok: StandardSchemaV1<unknown, Ok>;
|
|
154
200
|
readonly err: Tags;
|
|
155
|
-
|
|
156
|
-
}): CmdDef<Name, Input, Ok, TaggedError<Tags[number]>, R>;
|
|
201
|
+
}): CmdDef<Name, Input, Ok, TaggedError<Tags[number]>>;
|
|
157
202
|
type SyncReturn<S, C extends Cmd> = readonly [S, readonly C[]] & {
|
|
158
203
|
readonly then?: never;
|
|
159
204
|
};
|
|
@@ -265,51 +310,50 @@ type ExhaustiveTransitions<S extends {
|
|
|
265
310
|
/**
|
|
266
311
|
* A tagged-union, one-shot effect — JSON-plain, hashable, replayable.
|
|
267
312
|
*
|
|
268
|
-
* `T` is the tag. `
|
|
269
|
-
*
|
|
270
|
-
* Cmd
|
|
271
|
-
*
|
|
272
|
-
* handed to `run`, built by hand or by a `provide` graph that acquires each
|
|
273
|
-
* dependency once and releases it when the run ends.
|
|
274
|
-
*
|
|
275
|
-
* @see {@link RequiredCtx} — every Cmd's `R`, intersected: what `run` demands.
|
|
276
|
-
* @see `provide` — the host-side graph that builds a `ctx` satisfying `R`.
|
|
313
|
+
* `T` is the tag. `Ok` and `E` are phantom type parameters (ADR 0014): `Ok` is
|
|
314
|
+
* the value this Cmd settles with, and `E` is the `_tag` union it can fail
|
|
315
|
+
* with. A Cmd carries no requirements (ADR 0020) — its handler gets its
|
|
316
|
+
* services from the plain `ctx` handed to `run`.
|
|
277
317
|
*/
|
|
278
|
-
type Cmd<T extends string = string,
|
|
318
|
+
type Cmd<T extends string = string, Ok = unknown, E = unknown> = {
|
|
279
319
|
readonly type: T;
|
|
320
|
+
/** Phantom — the value this Cmd settles with. Never assigned. */
|
|
321
|
+
readonly __ok?: Ok;
|
|
280
322
|
/** Phantom — the `_tag` union this Cmd can settle with. Never assigned. */
|
|
281
323
|
readonly __e?: E;
|
|
282
|
-
/** Phantom — the `Ctx` slice this Cmd's handler needs. Never assigned. */
|
|
283
|
-
readonly __r?: R;
|
|
284
324
|
};
|
|
285
325
|
declare const Cmd: {
|
|
286
326
|
/**
|
|
287
|
-
* Declare a typed Cmd constructor (ADR 0014). Returns the builder —
|
|
327
|
+
* Declare a typed Cmd constructor (ADR 0014, 0021). Returns the builder —
|
|
288
328
|
* `fetch({ url })` yields `{ type: "fetch", url }` — carrying the minted Msg
|
|
289
|
-
* builders `fetch.ok(cmd, value)` / `fetch.err(cmd, error)`
|
|
290
|
-
* declaration the runtime edge parses against.
|
|
291
|
-
* the two-arm Msg union it settles with;
|
|
292
|
-
* folds that union into the machine's `M`.
|
|
329
|
+
* builders `fetch.ok(cmd, value)` / `fetch.err(cmd, error)` (for replay
|
|
330
|
+
* logs and tests) and the declaration the runtime edge parses against.
|
|
331
|
+
* `Settled<typeof fetch>` is the two-arm Msg union it settles with;
|
|
332
|
+
* `defineMachine({ cmds: [fetch] })` folds that union into the machine's `M`.
|
|
293
333
|
*
|
|
294
334
|
* const fetch = Cmd.define("fetch", {
|
|
295
335
|
* input: z.object({ url: z.string() }),
|
|
296
336
|
* ok: z.object({ status: z.number(), body: z.string() }),
|
|
297
337
|
* err: ["not_found", "timeout"],
|
|
298
|
-
* requirements: Cmd.requirements<{ http: Http }>(),
|
|
299
338
|
* });
|
|
300
339
|
*
|
|
301
|
-
* `
|
|
302
|
-
*
|
|
303
|
-
*
|
|
340
|
+
* `input` and `ok` take any Standard Schema whose `validate` is synchronous:
|
|
341
|
+
* zod directly, Effect Schema through `Schema.toStandardSchemaV1(...)`. `err`
|
|
342
|
+
* is the `_tag` list the handler may fail with; the runtime adds
|
|
343
|
+
* `malformed_result` for an `Ok` value the `ok` schema rejects.
|
|
344
|
+
*
|
|
345
|
+
* The handler returns an outcome and the engine mints the Msg:
|
|
346
|
+
*
|
|
347
|
+
* fetch: async (cmd, { ok, err }) =>
|
|
348
|
+
* res.status === 404 ? err({ _tag: "not_found" }) : ok(await res.json()),
|
|
349
|
+
*
|
|
350
|
+
* A throw or an undeclared tag goes to the error sink, never to `fetch_err`.
|
|
351
|
+
* The handler reads its services off the plain `ctx` handed to `run` (ADR
|
|
352
|
+
* 0020).
|
|
304
353
|
*
|
|
305
354
|
* A Cmd must not wait; see `DepKeyedSub` for anything that watches.
|
|
306
355
|
*/
|
|
307
356
|
readonly define: typeof defineCmd;
|
|
308
|
-
/**
|
|
309
|
-
* Name a Cmd's `R` — the `Ctx` slice its handler reads. A phantom: nothing
|
|
310
|
-
* is built, nothing is checked at runtime; the type is what `run` reads.
|
|
311
|
-
*/
|
|
312
|
-
readonly requirements: <R>() => Requirements<R>;
|
|
313
357
|
/**
|
|
314
358
|
* The empty Cmd array. Typed `readonly never[]` so it's assignable to any
|
|
315
359
|
* `readonly C[]` for any `C extends Cmd`. Use in `init` returns and
|
|
@@ -375,40 +419,40 @@ type SubId = string & {
|
|
|
375
419
|
* Strengthens invariant 7 (identity is explicit).
|
|
376
420
|
*/
|
|
377
421
|
declare function subId(s: string): SubId;
|
|
378
|
-
type Sub<T extends string = string> = {
|
|
422
|
+
type Sub<T extends string = string, D = unknown> = {
|
|
379
423
|
readonly id: SubId;
|
|
380
424
|
readonly type: T;
|
|
425
|
+
readonly deps: D;
|
|
381
426
|
};
|
|
382
427
|
type Dispose = () => void | Promise<void>;
|
|
428
|
+
/** The `deps` a `timer` Sub declares: fire `msg` once, `ms` after it starts. */
|
|
429
|
+
type TimerDeps<M> = {
|
|
430
|
+
readonly ms: number;
|
|
431
|
+
readonly msg: M;
|
|
432
|
+
};
|
|
433
|
+
/** The built-in `timer` Sub, as its runner sees it. */
|
|
434
|
+
type TimerSub<M> = Sub<"timer", TimerDeps<M>>;
|
|
435
|
+
/** The Sub types every engine ships a runner for. */
|
|
436
|
+
type BuiltinSubType = "timer";
|
|
437
|
+
/** The built-in Subs a machine over `M` may declare without declaring them. */
|
|
438
|
+
type BuiltinSub<M> = TimerSub<M>;
|
|
439
|
+
/**
|
|
440
|
+
* The one `id` of a Sub: a structural hash of its `type` and its `deps`
|
|
441
|
+
* value. Same type and same deps → same id → the running Sub is left alone.
|
|
442
|
+
*/
|
|
443
|
+
declare function subIdOf(type: string, deps: unknown): SubId;
|
|
383
444
|
declare function structuralHash(deps: unknown): string;
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
* The slice of state this Sub depends on. `null` OR `undefined` ⇒ the Sub is
|
|
387
|
-
* inactive in this state (the substrate disposes it if it was running) — see
|
|
388
|
-
* `depsInactive`, so `(s) => s.optionalRunId` gates correctly. Otherwise the
|
|
389
|
-
* Sub is active, keyed on `structuralHash(deps)`.
|
|
390
|
-
*
|
|
391
|
-
* Pure (invariant 2). Plain JSON-compatible data only (invariant 1) — the
|
|
392
|
-
* structural hash walks it deterministically and THROWS on a `Date`, `Map`,
|
|
393
|
-
* `Set`, `Error` or class instance rather than collapsing them all onto one
|
|
394
|
-
* id. Project such a value first (`startedAt.toISOString()`).
|
|
395
|
-
*/
|
|
396
|
-
readonly deps: (state: S) => unknown;
|
|
445
|
+
type DepKeyedSub<S, U extends Sub = Sub> = U extends Sub<infer T, infer D> ? {
|
|
446
|
+
readonly type: T;
|
|
397
447
|
/**
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
* cleanup.
|
|
404
|
-
*
|
|
405
|
-
* `source` takes `state` (not the deps slice) so the slice type `D` never
|
|
406
|
-
* escapes the entry — each battery's `.depKeyed` closes over its own typed
|
|
407
|
-
* deps internally (cast-free existential: the entry that produced the deps
|
|
408
|
-
* is the entry that consumes them).
|
|
448
|
+
* The slice of state this Sub depends on. `null` or `undefined` ⇒ off in
|
|
449
|
+
* this state (see `depsInactive`), so `(s) => s.optionalRunId` gates
|
|
450
|
+
* correctly. Pure (invariant 2). Plain JSON-compatible data only
|
|
451
|
+
* (invariant 1): the structural hash THROWS on a `Date`, `Map`, `Set`,
|
|
452
|
+
* `Error` or class instance rather than collapsing them onto one id.
|
|
409
453
|
*/
|
|
410
|
-
readonly
|
|
411
|
-
}
|
|
454
|
+
readonly deps: (state: S) => D | null | undefined;
|
|
455
|
+
} : never;
|
|
412
456
|
interface Identity<S, M> {
|
|
413
457
|
/** The identity THIS instance owns. Pure (invariant 2); plain value. */
|
|
414
458
|
readonly ofState: (state: S) => unknown;
|
|
@@ -439,12 +483,24 @@ type NoCtx = Readonly<Record<never, never>>;
|
|
|
439
483
|
type Interpret<M extends {
|
|
440
484
|
type: string;
|
|
441
485
|
}, C extends Cmd, Ctx> = {
|
|
442
|
-
[K in C["type"]]:
|
|
486
|
+
[K in C["type"]]: InterpretCell<M, Extract<C, {
|
|
443
487
|
type: K;
|
|
444
|
-
}>,
|
|
445
|
-
type: K;
|
|
446
|
-
}>> & PortEmitter, dispatch?: (msg: M) => void) => Promise<M | void>;
|
|
488
|
+
}>, Ctx>;
|
|
447
489
|
};
|
|
490
|
+
/**
|
|
491
|
+
* One cell of {@link Interpret}: the outcome-returning form for a
|
|
492
|
+
* `Cmd.define`d Cmd, the Msg-returning form for a hand-written one. A Cmd is
|
|
493
|
+
* `Cmd.define`d exactly when its `E` phantom is declared (not `unknown`).
|
|
494
|
+
*/
|
|
495
|
+
type InterpretCell<M extends {
|
|
496
|
+
type: string;
|
|
497
|
+
}, C extends Cmd, Ctx> = unknown extends ErrorsOf<C> ? (cmd: C, ctx: Ctx & PortEmitter, dispatch?: (msg: M) => void) => Promise<M | void> : (cmd: C, ctx: Ctx & PortEmitter & OutcomeHelpers<OkOfCmd<C>, DeclaredErrorsOf<C>>, dispatch?: (msg: M) => void) => Promise<Outcome<OkOfCmd<C>, DeclaredErrorsOf<C>> | void>;
|
|
498
|
+
/** The value a Cmd settles with; `unknown` for a hand-written Cmd. */
|
|
499
|
+
type OkOfCmd<C> = C extends {
|
|
500
|
+
readonly __ok?: infer Ok;
|
|
501
|
+
} ? Ok : unknown;
|
|
502
|
+
/** The failures a `Cmd.define`d Cmd's handler may return: its declared tags. */
|
|
503
|
+
type DeclaredErrorsOf<C> = Exclude<ErrorsOf<C>, MalformedResult>;
|
|
448
504
|
type InterpretDetached<C extends Cmd, Allowed extends {
|
|
449
505
|
type: string;
|
|
450
506
|
}, Ctx> = (cmd: C, ctx: Ctx & PortEmitter, dispatch: (msg: Allowed) => void) => Promise<void>;
|
|
@@ -455,6 +511,54 @@ type Subscribe<M extends {
|
|
|
455
511
|
type: K;
|
|
456
512
|
}>, ctx: Ctx, dispatch: (msg: M) => void) => Dispose;
|
|
457
513
|
};
|
|
514
|
+
/**
|
|
515
|
+
* The `interpret` option of an engine's `run`: optional for a machine that
|
|
516
|
+
* emits no Cmd, required — one handler per Cmd variant — for one that does.
|
|
517
|
+
*/
|
|
518
|
+
type InterpretArg<M extends {
|
|
519
|
+
type: string;
|
|
520
|
+
}, C extends Cmd, Ctx> = [
|
|
521
|
+
C
|
|
522
|
+
] extends [Cmd<never>] ? {
|
|
523
|
+
interpret?: Interpret<M, C, Ctx>;
|
|
524
|
+
} : {
|
|
525
|
+
interpret: Interpret<M, C, Ctx>;
|
|
526
|
+
};
|
|
527
|
+
/**
|
|
528
|
+
* The `subscribe` option of an engine's `run`: one runner per Sub type the
|
|
529
|
+
* machine declares, except the built-ins (`timer`) the engine already ships.
|
|
530
|
+
* Optional when every declared type is a built-in. An entry named after a
|
|
531
|
+
* built-in replaces it (#270 R2.1), which is how a test drives time.
|
|
532
|
+
*/
|
|
533
|
+
type SubscribeArg<M extends {
|
|
534
|
+
type: string;
|
|
535
|
+
}, U extends Sub, Ctx> = [
|
|
536
|
+
Exclude<U["type"], BuiltinSubType>
|
|
537
|
+
] extends [never] ? {
|
|
538
|
+
readonly subscribe?: Partial<Subscribe<M, Exclude<U, Sub<never>> | BuiltinSub<M>, Ctx>>;
|
|
539
|
+
} : {
|
|
540
|
+
readonly subscribe: Subscribe<M, Exclude<U, {
|
|
541
|
+
readonly type: BuiltinSubType;
|
|
542
|
+
}>, Ctx> & Partial<Subscribe<M, BuiltinSub<M>, Ctx>>;
|
|
543
|
+
};
|
|
544
|
+
/**
|
|
545
|
+
* The handlers an engine is handed beside a machine: the {@link InterpretArg}
|
|
546
|
+
* Cmd handlers and the {@link SubscribeArg} sub runners. A machine carries
|
|
547
|
+
* neither — it is data, and one machine file runs under any engine.
|
|
548
|
+
*/
|
|
549
|
+
type RunHandlers<M extends {
|
|
550
|
+
type: string;
|
|
551
|
+
}, C extends Cmd, U extends Sub, Ctx> = InterpretArg<M, C, Ctx> & SubscribeArg<M, U, Ctx>;
|
|
552
|
+
/**
|
|
553
|
+
* A machine beside the handlers it runs under — what a wrapper, a battery's
|
|
554
|
+
* `toMachine` or an agent host hands around, and what an engine takes apart:
|
|
555
|
+
* `run(wired.machine, { ...wired, ctx })`.
|
|
556
|
+
*/
|
|
557
|
+
type Wired<S, M extends {
|
|
558
|
+
type: string;
|
|
559
|
+
}, C extends Cmd, U extends Sub, Ctx> = {
|
|
560
|
+
readonly machine: Machine<S, M, C, U, Ctx>;
|
|
561
|
+
} & RunHandlers<M, C, U, Ctx>;
|
|
458
562
|
type Machine<S, M extends {
|
|
459
563
|
type: string;
|
|
460
564
|
}, C extends Cmd, U extends Sub, Ctx> = {
|
|
@@ -487,24 +591,27 @@ type Machine<S, M extends {
|
|
|
487
591
|
type: string;
|
|
488
592
|
}] ? Transitions<S, M, C> : never);
|
|
489
593
|
/**
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
* a new phase can't silently forget to arm it.
|
|
496
|
-
*
|
|
497
|
-
* The deps slice type is erased to `unknown` per entry — each Sub's slice
|
|
498
|
-
* differs, but the slice type never crosses this field (the kernel only needs
|
|
499
|
-
* to hash it and pass `state` back to that same entry's `source`).
|
|
594
|
+
* The machine's Subs, as data: each entry names a Sub `type` and the state
|
|
595
|
+
* slice it depends on (`deps`). The engine derives the id
|
|
596
|
+
* (`structuralHash({ type, deps })`) and the gate (`deps` non-null), starts
|
|
597
|
+
* the runner for `type` when an entry turns on, leaves it alone while the id
|
|
598
|
+
* holds, restarts it when the id changes, and stops it on `null` or `stop()`.
|
|
500
599
|
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
600
|
+
* `U` is the machine's own Sub union (`types.sub`); the built-in `timer`
|
|
601
|
+
* (`{ type: "timer", deps: (s) => ({ ms, msg }) }`) is always available.
|
|
503
602
|
*
|
|
504
603
|
* Strengthens invariant 4 (lifecycle owned by the substrate) and invariant 7
|
|
505
604
|
* (identity derived, not hand-authored).
|
|
506
605
|
*/
|
|
507
|
-
subs?: ReadonlyArray<DepKeyedSub<S, M
|
|
606
|
+
readonly subs?: ReadonlyArray<DepKeyedSub<S, U | BuiltinSub<M>>>;
|
|
607
|
+
/**
|
|
608
|
+
* Phantom — never assigned, never read. `subs` reaches `U` only through a
|
|
609
|
+
* conditional type, which is no inference site, so this is the slot a caller
|
|
610
|
+
* like `run(machine, …)` infers the Sub union from (and so what types its
|
|
611
|
+
* `subscribe` runners). Same device as `Cmd`'s `__ok`. Tuple-wrapped so an
|
|
612
|
+
* empty union (`never`) is still a candidate rather than `undefined`.
|
|
613
|
+
*/
|
|
614
|
+
readonly __sub?: readonly [U];
|
|
508
615
|
/**
|
|
509
616
|
* Instance-identity filter. Declares THIS instance's identity once; the
|
|
510
617
|
* substrate drops any message addressed to a DIFFERENT identity before it
|
|
@@ -522,14 +629,6 @@ type Machine<S, M extends {
|
|
|
522
629
|
* observable point, not per cell).
|
|
523
630
|
*/
|
|
524
631
|
identity?: Identity<S, M>;
|
|
525
|
-
/**
|
|
526
|
-
* Manual Sub aggregate — the documented escape hatch, KEPT alongside `subs`.
|
|
527
|
-
* The machine that needs cross-Sub logic the per-Sub `deps` fold can't
|
|
528
|
-
* express lists Subs here; the substrate reconciles them via `subscribe`.
|
|
529
|
-
* Both paths feed ONE reconcile pass.
|
|
530
|
-
*/
|
|
531
|
-
subscriptions?: (state: S) => readonly U[];
|
|
532
|
-
subscribe?: Subscribe<M, U, Ctx>;
|
|
533
632
|
/**
|
|
534
633
|
* The update form ("reducer" | "transitions"), stamped non-enumerably by
|
|
535
634
|
* `defineMachine` at construction (see `UpdateForm` / `formOf`). Optional in
|
|
@@ -538,14 +637,7 @@ type Machine<S, M extends {
|
|
|
538
637
|
* `detectUpdateForm` when the tag is absent. Never written by hand.
|
|
539
638
|
*/
|
|
540
639
|
readonly __form?: UpdateForm;
|
|
541
|
-
}
|
|
542
|
-
interpret?: Interpret<M, C, Ctx>;
|
|
543
|
-
} : {
|
|
544
|
-
interpret: Interpret<M, C, Ctx>;
|
|
545
|
-
}) & ([U] extends [Sub<never>] ? unknown : {
|
|
546
|
-
subscriptions: (state: S) => readonly U[];
|
|
547
|
-
subscribe: Subscribe<M, U, Ctx>;
|
|
548
|
-
});
|
|
640
|
+
};
|
|
549
641
|
declare function foldUpdates<S, M extends {
|
|
550
642
|
type: string;
|
|
551
643
|
}, C extends Cmd>(machine: {
|
|
@@ -559,4 +651,4 @@ declare function foldMsgs<S, M extends {
|
|
|
559
651
|
type: string;
|
|
560
652
|
}, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, base: S, msgs: readonly M[]): S;
|
|
561
653
|
|
|
562
|
-
export { type AnyCmdDef as A,
|
|
654
|
+
export { applyCellChecked as $, type AnyCmdDef as A, type BuiltinSubType as B, Cmd as C, type DeclaredErrorsOf as D, type ErrorsOf as E, type InterpretArg as F, type InterpretCell as G, type MachineShape as H, type InterpretDetached as I, type NoCtx as J, OutcomeContractError as K, type OutcomeHelpers as L, type Machine as M, NoCellError as N, type OkOfCmd as O, type Port as P, type SubscribeArg as Q, type RunHandlers as R, type Sub as S, type TimerDeps as T, type UpdateForm as U, type SyncReturn as V, type Wired as W, UndeclaredFailureError as X, acceptedTypes as Y, acceptsOf as Z, applyCell as _, type BuiltinSub as a, describeMachine as a0, detectUpdateForm as a1, foldMsgs as a2, foldUpdates as a3, formOf as a4, msgKeysOf as a5, structuralHash as a6, subId as a7, subIdOf as a8, type CmdDef as b, type CmdOf as c, type Subscribe as d, type SettledOk as e, type SettledErr as f, type TaggedError as g, type Dispose as h, type Reducer as i, type Settled as j, type Transitions as k, Outcome as l, type PortEmitter as m, type SubId as n, type DepKeyedSub as o, type Interpret as p, type TimerSub as q, type MalformedResult as r, type Tagged as s, type OkOf as t, type ErrOf as u, type CmdValue as v, AsyncSchemaError as w, type CmdInput as x, type ExhaustiveTransitions as y, type Identity as z };
|