@barnum/barnum 0.0.0-main-ef6df91f → 0.0.0-main-e8b82cff
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/artifacts/linux-arm64/barnum +0 -0
- package/artifacts/linux-x64/barnum +0 -0
- package/artifacts/macos-arm64/barnum +0 -0
- package/artifacts/macos-x64/barnum +0 -0
- package/artifacts/win-x64/barnum.exe +0 -0
- package/package.json +2 -1
- package/src/all.ts +116 -26
- package/src/ast.ts +262 -454
- package/src/bind.ts +65 -30
- package/src/builtins.ts +222 -123
- package/src/chain.ts +11 -2
- package/src/effect-id.ts +21 -6
- package/src/handler.ts +75 -32
- package/src/index.ts +11 -3
- package/src/pipe.ts +124 -29
- package/src/race.ts +58 -52
- package/src/run.ts +64 -23
- package/src/schema.ts +118 -0
- package/src/try-catch.ts +29 -30
- package/src/worker.ts +10 -1
package/src/handler.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
import type { z } from "zod";
|
|
3
3
|
import { type TypedAction, typedAction } from "./ast.js";
|
|
4
|
+
import { zodToCheckedJsonSchema } from "./schema.js";
|
|
4
5
|
|
|
5
6
|
// ---------------------------------------------------------------------------
|
|
6
7
|
// HandlerDefinition — the user's handle function + optional validators
|
|
@@ -12,6 +13,7 @@ export interface HandlerDefinition<
|
|
|
12
13
|
TStepConfig = unknown,
|
|
13
14
|
> {
|
|
14
15
|
inputValidator?: z.ZodType<TValue>;
|
|
16
|
+
outputValidator?: z.ZodType<TOutput>;
|
|
15
17
|
stepConfigValidator?: z.ZodType<TStepConfig>;
|
|
16
18
|
handle: (context: {
|
|
17
19
|
value: TValue;
|
|
@@ -22,6 +24,7 @@ export interface HandlerDefinition<
|
|
|
22
24
|
/** Runtime-only handler definition shape — erases generic type info. */
|
|
23
25
|
interface UntypedHandlerDefinition {
|
|
24
26
|
inputValidator?: z.ZodType;
|
|
27
|
+
outputValidator?: z.ZodType;
|
|
25
28
|
stepConfigValidator?: z.ZodType;
|
|
26
29
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
30
|
handle: (...args: any[]) => Promise<unknown>;
|
|
@@ -37,7 +40,10 @@ const HANDLER_BRAND = Symbol.for("barnum:handler");
|
|
|
37
40
|
* Opaque handler reference with typed metadata. The `__definition` property
|
|
38
41
|
* is non-enumerable — invisible to `JSON.stringify`, visible to the worker.
|
|
39
42
|
*/
|
|
40
|
-
export type Handler<TValue = unknown, TOutput = unknown> = TypedAction<
|
|
43
|
+
export type Handler<TValue = unknown, TOutput = unknown> = TypedAction<
|
|
44
|
+
TValue,
|
|
45
|
+
TOutput
|
|
46
|
+
> & {
|
|
41
47
|
readonly [HANDLER_BRAND]: true;
|
|
42
48
|
readonly __definition: UntypedHandlerDefinition;
|
|
43
49
|
};
|
|
@@ -88,26 +94,18 @@ function getCallerFilePath(): string {
|
|
|
88
94
|
type HandlerOutput<TOutput> = [TOutput] extends [void] ? never : TOutput;
|
|
89
95
|
|
|
90
96
|
// ---------------------------------------------------------------------------
|
|
91
|
-
// createHandler —
|
|
97
|
+
// createHandler — single overload, validators optional
|
|
92
98
|
// ---------------------------------------------------------------------------
|
|
93
99
|
|
|
94
|
-
|
|
95
|
-
export function createHandler<TValue, TOutput>(
|
|
100
|
+
export function createHandler<TValue = never, TOutput = unknown>(
|
|
96
101
|
definition: {
|
|
97
|
-
inputValidator
|
|
102
|
+
inputValidator?: z.ZodType<TValue>;
|
|
103
|
+
outputValidator?: z.ZodType<NoInfer<TOutput>>;
|
|
98
104
|
handle: (context: { value: TValue }) => Promise<TOutput>;
|
|
99
105
|
},
|
|
100
106
|
exportName?: string,
|
|
101
107
|
): Handler<TValue, HandlerOutput<TOutput>>;
|
|
102
108
|
|
|
103
|
-
// Without inputValidator: handler takes no pipeline input.
|
|
104
|
-
export function createHandler<TOutput>(
|
|
105
|
-
definition: {
|
|
106
|
-
handle: () => Promise<TOutput>;
|
|
107
|
-
},
|
|
108
|
-
exportName?: string,
|
|
109
|
-
): Handler<never, HandlerOutput<TOutput>>;
|
|
110
|
-
|
|
111
109
|
// Implementation
|
|
112
110
|
export function createHandler(
|
|
113
111
|
definition: UntypedHandlerDefinition,
|
|
@@ -117,9 +115,28 @@ export function createHandler(
|
|
|
117
115
|
const filePath = getCallerFilePath();
|
|
118
116
|
const funcName = exportName ?? "default";
|
|
119
117
|
|
|
118
|
+
const inputSchema = definition.inputValidator
|
|
119
|
+
? zodToCheckedJsonSchema(
|
|
120
|
+
definition.inputValidator,
|
|
121
|
+
`${filePath}:${funcName} input`,
|
|
122
|
+
)
|
|
123
|
+
: undefined;
|
|
124
|
+
const outputSchema = definition.outputValidator
|
|
125
|
+
? zodToCheckedJsonSchema(
|
|
126
|
+
definition.outputValidator,
|
|
127
|
+
`${filePath}:${funcName} output`,
|
|
128
|
+
)
|
|
129
|
+
: undefined;
|
|
130
|
+
|
|
120
131
|
const action = typedAction({
|
|
121
132
|
kind: "Invoke",
|
|
122
|
-
handler: {
|
|
133
|
+
handler: {
|
|
134
|
+
kind: "TypeScript",
|
|
135
|
+
module: filePath,
|
|
136
|
+
func: funcName,
|
|
137
|
+
...(inputSchema && { input_schema: inputSchema }),
|
|
138
|
+
...(outputSchema && { output_schema: outputSchema }),
|
|
139
|
+
},
|
|
123
140
|
});
|
|
124
141
|
|
|
125
142
|
// Non-enumerable: invisible to JSON.stringify, visible to the worker
|
|
@@ -136,28 +153,26 @@ export function createHandler(
|
|
|
136
153
|
}
|
|
137
154
|
|
|
138
155
|
// ---------------------------------------------------------------------------
|
|
139
|
-
// createHandlerWithConfig —
|
|
156
|
+
// createHandlerWithConfig — single overload, validators optional
|
|
140
157
|
// ---------------------------------------------------------------------------
|
|
141
158
|
|
|
142
|
-
|
|
143
|
-
|
|
159
|
+
export function createHandlerWithConfig<
|
|
160
|
+
TValue = never,
|
|
161
|
+
TOutput = unknown,
|
|
162
|
+
TStepConfig = unknown,
|
|
163
|
+
>(
|
|
144
164
|
definition: {
|
|
145
|
-
inputValidator
|
|
146
|
-
|
|
147
|
-
|
|
165
|
+
inputValidator?: z.ZodType<TValue>;
|
|
166
|
+
outputValidator?: z.ZodType<NoInfer<TOutput>>;
|
|
167
|
+
stepConfigValidator?: z.ZodType<TStepConfig>;
|
|
168
|
+
handle: (context: {
|
|
169
|
+
value: TValue;
|
|
170
|
+
stepConfig: TStepConfig;
|
|
171
|
+
}) => Promise<TOutput>;
|
|
148
172
|
},
|
|
149
173
|
exportName?: string,
|
|
150
174
|
): (config: TStepConfig) => TypedAction<TValue, HandlerOutput<TOutput>>;
|
|
151
175
|
|
|
152
|
-
// Without inputValidator: handler takes no pipeline input, has config.
|
|
153
|
-
export function createHandlerWithConfig<TOutput, TStepConfig>(
|
|
154
|
-
definition: {
|
|
155
|
-
stepConfigValidator: z.ZodType<TStepConfig>;
|
|
156
|
-
handle: (context: { stepConfig: TStepConfig }) => Promise<TOutput>;
|
|
157
|
-
},
|
|
158
|
-
exportName?: string,
|
|
159
|
-
): (config: TStepConfig) => TypedAction<never, HandlerOutput<TOutput>>;
|
|
160
|
-
|
|
161
176
|
// Implementation
|
|
162
177
|
export function createHandlerWithConfig(
|
|
163
178
|
definition: UntypedHandlerDefinition,
|
|
@@ -167,6 +182,19 @@ export function createHandlerWithConfig(
|
|
|
167
182
|
const filePath = getCallerFilePath();
|
|
168
183
|
const funcName = exportName ?? "default";
|
|
169
184
|
|
|
185
|
+
const inputSchema = definition.inputValidator
|
|
186
|
+
? zodToCheckedJsonSchema(
|
|
187
|
+
definition.inputValidator,
|
|
188
|
+
`${filePath}:${funcName} input`,
|
|
189
|
+
)
|
|
190
|
+
: undefined;
|
|
191
|
+
const outputSchema = definition.outputValidator
|
|
192
|
+
? zodToCheckedJsonSchema(
|
|
193
|
+
definition.outputValidator,
|
|
194
|
+
`${filePath}:${funcName} output`,
|
|
195
|
+
)
|
|
196
|
+
: undefined;
|
|
197
|
+
|
|
170
198
|
// Internal handle that unpacks the [value, config] tuple from All
|
|
171
199
|
const internalDefinition: UntypedHandlerDefinition = {
|
|
172
200
|
handle: ({ value }: { value: unknown }) => {
|
|
@@ -177,7 +205,13 @@ export function createHandlerWithConfig(
|
|
|
177
205
|
|
|
178
206
|
const invokeAction = typedAction({
|
|
179
207
|
kind: "Invoke",
|
|
180
|
-
handler: {
|
|
208
|
+
handler: {
|
|
209
|
+
kind: "TypeScript",
|
|
210
|
+
module: filePath,
|
|
211
|
+
func: funcName,
|
|
212
|
+
...(inputSchema && { input_schema: inputSchema }),
|
|
213
|
+
...(outputSchema && { output_schema: outputSchema }),
|
|
214
|
+
},
|
|
181
215
|
});
|
|
182
216
|
|
|
183
217
|
// Non-enumerable: invisible to JSON.stringify, visible to the worker
|
|
@@ -199,8 +233,17 @@ export function createHandlerWithConfig(
|
|
|
199
233
|
first: {
|
|
200
234
|
kind: "All",
|
|
201
235
|
actions: [
|
|
202
|
-
{
|
|
203
|
-
|
|
236
|
+
{
|
|
237
|
+
kind: "Invoke",
|
|
238
|
+
handler: { kind: "Builtin", builtin: { kind: "Identity" } },
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
kind: "Invoke",
|
|
242
|
+
handler: {
|
|
243
|
+
kind: "Builtin",
|
|
244
|
+
builtin: { kind: "Constant", value: config },
|
|
245
|
+
},
|
|
246
|
+
},
|
|
204
247
|
],
|
|
205
248
|
},
|
|
206
249
|
rest: invokeAction,
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { TaggedUnion, OptionDef, ResultDef } from "./ast.js";
|
|
2
|
+
|
|
1
3
|
export * from "./ast.js";
|
|
2
4
|
export {
|
|
3
5
|
constant,
|
|
@@ -17,6 +19,12 @@ export {
|
|
|
17
19
|
Option,
|
|
18
20
|
Result,
|
|
19
21
|
} from "./builtins.js";
|
|
20
|
-
export
|
|
21
|
-
export
|
|
22
|
-
export {
|
|
22
|
+
export * from "./handler.js";
|
|
23
|
+
export { runPipeline } from "./run.js";
|
|
24
|
+
export { zodToCheckedJsonSchema } from "./schema.js";
|
|
25
|
+
|
|
26
|
+
// Declaration merge: the explicit value exports of Option/Result from builtins
|
|
27
|
+
// shadow the type-only exports from ast's `export *`. Re-declare the generic
|
|
28
|
+
// type aliases here so consumers get both the type and value under one name.
|
|
29
|
+
export type Option<T> = TaggedUnion<OptionDef<T>>;
|
|
30
|
+
export type Result<TValue, TError> = TaggedUnion<ResultDef<TValue, TError>>;
|
package/src/pipe.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type Action,
|
|
3
|
+
type PipeIn,
|
|
4
|
+
type Pipeable,
|
|
5
|
+
type TypedAction,
|
|
6
|
+
typedAction,
|
|
7
|
+
} from "./ast.js";
|
|
2
8
|
import { identity } from "./builtins.js";
|
|
3
9
|
|
|
4
10
|
export function pipe<T1, T2, R1 extends string>(
|
|
@@ -9,16 +15,28 @@ export function pipe<T1, T2, T3, R1 extends string, R2 extends string>(
|
|
|
9
15
|
a2: Pipeable<T2, T3, R2>,
|
|
10
16
|
): TypedAction<PipeIn<T1>, T3, R1 | R2>;
|
|
11
17
|
export function pipe<
|
|
12
|
-
T1,
|
|
13
|
-
|
|
18
|
+
T1,
|
|
19
|
+
T2,
|
|
20
|
+
T3,
|
|
21
|
+
T4,
|
|
22
|
+
R1 extends string,
|
|
23
|
+
R2 extends string,
|
|
24
|
+
R3 extends string,
|
|
14
25
|
>(
|
|
15
26
|
a1: Pipeable<T1, T2, R1>,
|
|
16
27
|
a2: Pipeable<T2, T3, R2>,
|
|
17
28
|
a3: Pipeable<T3, T4, R3>,
|
|
18
29
|
): TypedAction<PipeIn<T1>, T4, R1 | R2 | R3>;
|
|
19
30
|
export function pipe<
|
|
20
|
-
T1,
|
|
21
|
-
|
|
31
|
+
T1,
|
|
32
|
+
T2,
|
|
33
|
+
T3,
|
|
34
|
+
T4,
|
|
35
|
+
T5,
|
|
36
|
+
R1 extends string,
|
|
37
|
+
R2 extends string,
|
|
38
|
+
R3 extends string,
|
|
39
|
+
R4 extends string,
|
|
22
40
|
>(
|
|
23
41
|
a1: Pipeable<T1, T2, R1>,
|
|
24
42
|
a2: Pipeable<T2, T3, R2>,
|
|
@@ -26,9 +44,17 @@ export function pipe<
|
|
|
26
44
|
a4: Pipeable<T4, T5, R4>,
|
|
27
45
|
): TypedAction<PipeIn<T1>, T5, R1 | R2 | R3 | R4>;
|
|
28
46
|
export function pipe<
|
|
29
|
-
T1,
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
T1,
|
|
48
|
+
T2,
|
|
49
|
+
T3,
|
|
50
|
+
T4,
|
|
51
|
+
T5,
|
|
52
|
+
T6,
|
|
53
|
+
R1 extends string,
|
|
54
|
+
R2 extends string,
|
|
55
|
+
R3 extends string,
|
|
56
|
+
R4 extends string,
|
|
57
|
+
R5 extends string,
|
|
32
58
|
>(
|
|
33
59
|
a1: Pipeable<T1, T2, R1>,
|
|
34
60
|
a2: Pipeable<T2, T3, R2>,
|
|
@@ -37,9 +63,19 @@ export function pipe<
|
|
|
37
63
|
a5: Pipeable<T5, T6, R5>,
|
|
38
64
|
): TypedAction<PipeIn<T1>, T6, R1 | R2 | R3 | R4 | R5>;
|
|
39
65
|
export function pipe<
|
|
40
|
-
T1,
|
|
41
|
-
|
|
42
|
-
|
|
66
|
+
T1,
|
|
67
|
+
T2,
|
|
68
|
+
T3,
|
|
69
|
+
T4,
|
|
70
|
+
T5,
|
|
71
|
+
T6,
|
|
72
|
+
T7,
|
|
73
|
+
R1 extends string,
|
|
74
|
+
R2 extends string,
|
|
75
|
+
R3 extends string,
|
|
76
|
+
R4 extends string,
|
|
77
|
+
R5 extends string,
|
|
78
|
+
R6 extends string,
|
|
43
79
|
>(
|
|
44
80
|
a1: Pipeable<T1, T2, R1>,
|
|
45
81
|
a2: Pipeable<T2, T3, R2>,
|
|
@@ -49,9 +85,20 @@ export function pipe<
|
|
|
49
85
|
a6: Pipeable<T6, T7, R6>,
|
|
50
86
|
): TypedAction<PipeIn<T1>, T7, R1 | R2 | R3 | R4 | R5 | R6>;
|
|
51
87
|
export function pipe<
|
|
52
|
-
T1,
|
|
53
|
-
|
|
54
|
-
|
|
88
|
+
T1,
|
|
89
|
+
T2,
|
|
90
|
+
T3,
|
|
91
|
+
T4,
|
|
92
|
+
T5,
|
|
93
|
+
T6,
|
|
94
|
+
T7,
|
|
95
|
+
T8,
|
|
96
|
+
R1 extends string,
|
|
97
|
+
R2 extends string,
|
|
98
|
+
R3 extends string,
|
|
99
|
+
R4 extends string,
|
|
100
|
+
R5 extends string,
|
|
101
|
+
R6 extends string,
|
|
55
102
|
R7 extends string,
|
|
56
103
|
>(
|
|
57
104
|
a1: Pipeable<T1, T2, R1>,
|
|
@@ -63,10 +110,23 @@ export function pipe<
|
|
|
63
110
|
a7: Pipeable<T7, T8, R7>,
|
|
64
111
|
): TypedAction<PipeIn<T1>, T8, R1 | R2 | R3 | R4 | R5 | R6 | R7>;
|
|
65
112
|
export function pipe<
|
|
66
|
-
T1,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
113
|
+
T1,
|
|
114
|
+
T2,
|
|
115
|
+
T3,
|
|
116
|
+
T4,
|
|
117
|
+
T5,
|
|
118
|
+
T6,
|
|
119
|
+
T7,
|
|
120
|
+
T8,
|
|
121
|
+
T9,
|
|
122
|
+
R1 extends string,
|
|
123
|
+
R2 extends string,
|
|
124
|
+
R3 extends string,
|
|
125
|
+
R4 extends string,
|
|
126
|
+
R5 extends string,
|
|
127
|
+
R6 extends string,
|
|
128
|
+
R7 extends string,
|
|
129
|
+
R8 extends string,
|
|
70
130
|
>(
|
|
71
131
|
a1: Pipeable<T1, T2, R1>,
|
|
72
132
|
a2: Pipeable<T2, T3, R2>,
|
|
@@ -78,10 +138,25 @@ export function pipe<
|
|
|
78
138
|
a8: Pipeable<T8, T9, R8>,
|
|
79
139
|
): TypedAction<PipeIn<T1>, T9, R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8>;
|
|
80
140
|
export function pipe<
|
|
81
|
-
T1,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
141
|
+
T1,
|
|
142
|
+
T2,
|
|
143
|
+
T3,
|
|
144
|
+
T4,
|
|
145
|
+
T5,
|
|
146
|
+
T6,
|
|
147
|
+
T7,
|
|
148
|
+
T8,
|
|
149
|
+
T9,
|
|
150
|
+
T10,
|
|
151
|
+
R1 extends string,
|
|
152
|
+
R2 extends string,
|
|
153
|
+
R3 extends string,
|
|
154
|
+
R4 extends string,
|
|
155
|
+
R5 extends string,
|
|
156
|
+
R6 extends string,
|
|
157
|
+
R7 extends string,
|
|
158
|
+
R8 extends string,
|
|
159
|
+
R9 extends string,
|
|
85
160
|
>(
|
|
86
161
|
a1: Pipeable<T1, T2, R1>,
|
|
87
162
|
a2: Pipeable<T2, T3, R2>,
|
|
@@ -94,10 +169,26 @@ export function pipe<
|
|
|
94
169
|
a9: Pipeable<T9, T10, R9>,
|
|
95
170
|
): TypedAction<PipeIn<T1>, T10, R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8 | R9>;
|
|
96
171
|
export function pipe<
|
|
97
|
-
T1,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
172
|
+
T1,
|
|
173
|
+
T2,
|
|
174
|
+
T3,
|
|
175
|
+
T4,
|
|
176
|
+
T5,
|
|
177
|
+
T6,
|
|
178
|
+
T7,
|
|
179
|
+
T8,
|
|
180
|
+
T9,
|
|
181
|
+
T10,
|
|
182
|
+
T11,
|
|
183
|
+
R1 extends string,
|
|
184
|
+
R2 extends string,
|
|
185
|
+
R3 extends string,
|
|
186
|
+
R4 extends string,
|
|
187
|
+
R5 extends string,
|
|
188
|
+
R6 extends string,
|
|
189
|
+
R7 extends string,
|
|
190
|
+
R8 extends string,
|
|
191
|
+
R9 extends string,
|
|
101
192
|
R10 extends string,
|
|
102
193
|
>(
|
|
103
194
|
a1: Pipeable<T1, T2, R1>,
|
|
@@ -110,7 +201,11 @@ export function pipe<
|
|
|
110
201
|
a8: Pipeable<T8, T9, R8>,
|
|
111
202
|
a9: Pipeable<T9, T10, R9>,
|
|
112
203
|
a10: Pipeable<T10, T11, R10>,
|
|
113
|
-
): TypedAction<
|
|
204
|
+
): TypedAction<
|
|
205
|
+
PipeIn<T1>,
|
|
206
|
+
T11,
|
|
207
|
+
R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8 | R9 | R10
|
|
208
|
+
>;
|
|
114
209
|
export function pipe(...actions: Action[]): Action {
|
|
115
210
|
if (actions.length === 0) {
|
|
116
211
|
return identity;
|
|
@@ -118,7 +213,7 @@ export function pipe(...actions: Action[]): Action {
|
|
|
118
213
|
if (actions.length === 1) {
|
|
119
214
|
return actions[0];
|
|
120
215
|
}
|
|
121
|
-
return actions.reduceRight(
|
|
122
|
-
typedAction({ kind: "Chain", first, rest }) as Action,
|
|
216
|
+
return actions.reduceRight(
|
|
217
|
+
(rest, first) => typedAction({ kind: "Chain", first, rest }) as Action,
|
|
123
218
|
);
|
|
124
219
|
}
|
package/src/race.ts
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
type Action,
|
|
3
|
+
type Pipeable,
|
|
4
|
+
type Result,
|
|
5
|
+
type TypedAction,
|
|
6
|
+
typedAction,
|
|
7
|
+
buildRestartBranchAction,
|
|
8
|
+
TAG_BREAK,
|
|
9
|
+
IDENTITY,
|
|
10
|
+
} from "./ast.js";
|
|
11
|
+
import {
|
|
12
|
+
allocateRestartHandlerId,
|
|
13
|
+
type RestartHandlerId,
|
|
14
|
+
} from "./effect-id.js";
|
|
3
15
|
|
|
4
16
|
// ---------------------------------------------------------------------------
|
|
5
17
|
// Shared AST fragments
|
|
6
18
|
// ---------------------------------------------------------------------------
|
|
7
19
|
|
|
8
|
-
const EXTRACT_PAYLOAD: Action = {
|
|
9
|
-
kind: "Invoke",
|
|
10
|
-
handler: { kind: "Builtin", builtin: { kind: "ExtractField", value: "payload" } },
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const TAG_DISCARD: Action = {
|
|
14
|
-
kind: "Invoke",
|
|
15
|
-
handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Discard" } },
|
|
16
|
-
};
|
|
17
|
-
|
|
18
20
|
const TAG_OK: Action = {
|
|
19
21
|
kind: "Invoke",
|
|
20
22
|
handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Ok" } },
|
|
@@ -25,12 +27,18 @@ const TAG_ERR: Action = {
|
|
|
25
27
|
handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Err" } },
|
|
26
28
|
};
|
|
27
29
|
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
/**
|
|
31
|
+
* `Chain(Tag("Break"), RestartPerform(id))` — shared by race branches.
|
|
32
|
+
* The winning branch tags its result as Break, then performs. The handler
|
|
33
|
+
* restarts the body; Branch takes the Break arm (identity), `RestartHandle` exits.
|
|
34
|
+
*/
|
|
35
|
+
function breakPerform(restartHandlerId: RestartHandlerId): Action {
|
|
36
|
+
return {
|
|
37
|
+
kind: "Chain",
|
|
38
|
+
first: TAG_BREAK,
|
|
39
|
+
rest: { kind: "RestartPerform", restart_handler_id: restartHandlerId },
|
|
40
|
+
};
|
|
41
|
+
}
|
|
34
42
|
|
|
35
43
|
// ---------------------------------------------------------------------------
|
|
36
44
|
// race — first branch to complete wins, losers cancelled
|
|
@@ -38,26 +46,27 @@ const RACE_HANDLER: Action = {
|
|
|
38
46
|
|
|
39
47
|
/**
|
|
40
48
|
* Run multiple actions concurrently. The first to complete wins; losers
|
|
41
|
-
* are cancelled during
|
|
49
|
+
* are cancelled during `RestartHandle` frame teardown.
|
|
42
50
|
*
|
|
43
51
|
* All branches must have the same input and output type (since either
|
|
44
52
|
* could win).
|
|
45
53
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
+
* Compiled form (restart+Branch, same substrate as loop/earlyReturn):
|
|
55
|
+
* `Chain(Tag("Continue"),`
|
|
56
|
+
* `RestartHandle(id, ExtractIndex(0),`
|
|
57
|
+
* `Branch({`
|
|
58
|
+
* `Continue: All(Chain(a, breakPerform), Chain(b, breakPerform), ...),`
|
|
59
|
+
* `Break: identity,`
|
|
60
|
+
* `})))`
|
|
61
|
+
*
|
|
62
|
+
* First branch to complete tags Break → `RestartPerform` → handler restarts →
|
|
63
|
+
* Branch takes Break arm → identity → `RestartHandle` exits with winner's value.
|
|
54
64
|
*/
|
|
55
65
|
export function race<TIn, TOut>(
|
|
56
66
|
...actions: Pipeable<TIn, TOut>[]
|
|
57
67
|
): TypedAction<TIn, TOut> {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
const perform: Action = { kind: "Perform", effect_id: effectId };
|
|
68
|
+
const restartHandlerId = allocateRestartHandlerId();
|
|
69
|
+
const perform = breakPerform(restartHandlerId);
|
|
61
70
|
|
|
62
71
|
const branches = actions.map((action) => ({
|
|
63
72
|
kind: "Chain" as const,
|
|
@@ -65,12 +74,11 @@ export function race<TIn, TOut>(
|
|
|
65
74
|
rest: perform,
|
|
66
75
|
}));
|
|
67
76
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
});
|
|
77
|
+
const allAction: Action = { kind: "All", actions: branches };
|
|
78
|
+
|
|
79
|
+
return typedAction(
|
|
80
|
+
buildRestartBranchAction(restartHandlerId, allAction, IDENTITY),
|
|
81
|
+
);
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
// ---------------------------------------------------------------------------
|
|
@@ -129,28 +137,28 @@ Object.defineProperty(sleep, "__definition", {
|
|
|
129
137
|
* that computes a duration from the pipeline input.
|
|
130
138
|
*
|
|
131
139
|
* Built as raw AST rather than through `race()` because each branch wraps
|
|
132
|
-
* its result differently (Ok vs Err) before Perform. `race()`
|
|
133
|
-
* homogeneous output types, but withTimeout needs heterogeneous
|
|
140
|
+
* its result differently (Ok vs Err) before the Break+Perform. `race()`
|
|
141
|
+
* requires homogeneous output types, but withTimeout needs heterogeneous
|
|
142
|
+
* tagging.
|
|
134
143
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
144
|
+
* Same restart+Branch substrate as race: each branch tags Break after
|
|
145
|
+
* wrapping its result as Ok or Err.
|
|
137
146
|
*/
|
|
138
147
|
export function withTimeout<TIn, TOut>(
|
|
139
148
|
ms: Pipeable<TIn, number>,
|
|
140
149
|
body: Pipeable<TIn, TOut>,
|
|
141
150
|
): TypedAction<TIn, Result<TOut, void>> {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
const perform: Action = { kind: "Perform", effect_id: effectId };
|
|
151
|
+
const restartHandlerId = allocateRestartHandlerId();
|
|
152
|
+
const perform = breakPerform(restartHandlerId);
|
|
145
153
|
|
|
146
|
-
// Branch 1: body → Tag("Ok") →
|
|
154
|
+
// Branch 1: body → Tag("Ok") → Tag("Break") → RestartPerform
|
|
147
155
|
const bodyBranch: Action = {
|
|
148
156
|
kind: "Chain",
|
|
149
157
|
first: { kind: "Chain", first: body as Action, rest: TAG_OK },
|
|
150
158
|
rest: perform,
|
|
151
159
|
};
|
|
152
160
|
|
|
153
|
-
// Branch 2: ms → sleep() → Tag("Err") →
|
|
161
|
+
// Branch 2: ms → sleep() → Tag("Err") → Tag("Break") → RestartPerform
|
|
154
162
|
const sleepBranch: Action = {
|
|
155
163
|
kind: "Chain",
|
|
156
164
|
first: {
|
|
@@ -161,11 +169,9 @@ export function withTimeout<TIn, TOut>(
|
|
|
161
169
|
rest: perform,
|
|
162
170
|
};
|
|
163
171
|
|
|
164
|
-
|
|
165
|
-
kind: "Handle",
|
|
166
|
-
effect_id: effectId,
|
|
167
|
-
handler: RACE_HANDLER,
|
|
168
|
-
body: { kind: "All", actions: [bodyBranch, sleepBranch] },
|
|
169
|
-
});
|
|
170
|
-
}
|
|
172
|
+
const allAction: Action = { kind: "All", actions: [bodyBranch, sleepBranch] };
|
|
171
173
|
|
|
174
|
+
return typedAction(
|
|
175
|
+
buildRestartBranchAction(restartHandlerId, allAction, IDENTITY),
|
|
176
|
+
);
|
|
177
|
+
}
|