@ontrails/core 1.0.0-beta.11 → 1.0.0-beta.13
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/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +67 -30
- package/README.md +19 -19
- package/dist/context.d.ts +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +5 -4
- package/dist/context.js.map +1 -1
- package/dist/derive.d.ts +8 -3
- package/dist/derive.d.ts.map +1 -1
- package/dist/derive.js +7 -7
- package/dist/derive.js.map +1 -1
- package/dist/event.d.ts +4 -41
- package/dist/event.d.ts.map +1 -1
- package/dist/event.js +4 -14
- package/dist/event.js.map +1 -1
- package/dist/execute.d.ts +11 -9
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +34 -151
- package/dist/execute.js.map +1 -1
- package/dist/gate.d.ts +17 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +21 -0
- package/dist/gate.js.map +1 -0
- package/dist/index.d.ts +10 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -7
- package/dist/index.js.map +1 -1
- package/dist/layer.d.ts +5 -16
- package/dist/layer.d.ts.map +1 -1
- package/dist/layer.js +3 -20
- package/dist/layer.js.map +1 -1
- package/dist/provision-config.d.ts +22 -0
- package/dist/provision-config.d.ts.map +1 -0
- package/dist/provision-config.js +210 -0
- package/dist/provision-config.js.map +1 -0
- package/dist/provision.d.ts +71 -0
- package/dist/provision.d.ts.map +1 -0
- package/dist/provision.js +56 -0
- package/dist/provision.js.map +1 -0
- package/dist/run.d.ts +27 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +34 -0
- package/dist/run.js.map +1 -0
- package/dist/service-config.d.ts +22 -0
- package/dist/service-config.d.ts.map +1 -0
- package/dist/service-config.js +210 -0
- package/dist/service-config.js.map +1 -0
- package/dist/service.d.ts +39 -37
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +21 -21
- package/dist/service.js.map +1 -1
- package/dist/signal.d.ts +33 -0
- package/dist/signal.d.ts.map +1 -0
- package/dist/signal.js +17 -0
- package/dist/signal.js.map +1 -0
- package/dist/topo.d.ts +10 -10
- package/dist/topo.d.ts.map +1 -1
- package/dist/topo.js +48 -35
- package/dist/topo.js.map +1 -1
- package/dist/trail.d.ts +19 -17
- package/dist/trail.d.ts.map +1 -1
- package/dist/trail.js +5 -4
- package/dist/trail.js.map +1 -1
- package/dist/types.d.ts +26 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -1
- package/dist/types.js.map +1 -1
- package/dist/validate-topo.d.ts +2 -2
- package/dist/validate-topo.js +31 -31
- package/dist/validate-topo.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/context.test.ts +8 -8
- package/src/__tests__/execute.test.ts +124 -122
- package/src/__tests__/{layer.test.ts → gate.test.ts} +26 -26
- package/src/__tests__/{dispatch.test.ts → run.test.ts} +39 -39
- package/src/__tests__/service-config.test.ts +228 -0
- package/src/__tests__/service.test.ts +71 -71
- package/src/__tests__/{event.test.ts → signal.test.ts} +15 -15
- package/src/__tests__/topo.test.ts +54 -54
- package/src/__tests__/trail-permit.test.ts +60 -0
- package/src/__tests__/trail.test.ts +58 -58
- package/src/__tests__/type-utils.test.ts +3 -3
- package/src/__tests__/validate-topo.test.ts +38 -38
- package/src/context.ts +5 -4
- package/src/derive.ts +8 -8
- package/src/event.ts +11 -73
- package/src/execute.ts +59 -238
- package/src/{layer.ts → gate.ts} +13 -13
- package/src/index.ts +26 -21
- package/src/provision-config.ts +373 -0
- package/src/provision.ts +148 -0
- package/src/{dispatch.ts → run.ts} +8 -8
- package/src/signal.ts +65 -0
- package/src/topo.ts +74 -52
- package/src/trail.ts +30 -23
- package/src/types.ts +30 -10
- package/src/validate-topo.ts +33 -33
- package/tsconfig.tsbuildinfo +1 -1
- package/src/service.ts +0 -139
package/src/execute.ts
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Centralized trail execution pipeline.
|
|
3
3
|
*
|
|
4
|
-
* Validates input, builds context, composes
|
|
4
|
+
* Validates input, builds context, composes gates, and runs the
|
|
5
5
|
* implementation. Surfaces (CLI, MCP, HTTP) delegate here instead
|
|
6
6
|
* of reimplementing the pipeline.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { AnyTrail } from './trail.js';
|
|
10
|
-
import type {
|
|
11
|
-
import type {
|
|
12
|
-
AnyService,
|
|
13
|
-
ServiceContext,
|
|
14
|
-
ServiceOverrideMap,
|
|
15
|
-
} from './service.js';
|
|
10
|
+
import type { Gate } from './gate.js';
|
|
11
|
+
import type { ProvisionOverrideMap } from './provision.js';
|
|
16
12
|
import type { TrailContext, TrailContextInit } from './types.js';
|
|
17
13
|
|
|
18
|
-
import {
|
|
14
|
+
import { composeGates } from './gate.js';
|
|
19
15
|
import { createTrailContext } from './context.js';
|
|
20
16
|
import { InternalError } from './errors.js';
|
|
21
17
|
import { Result } from './result.js';
|
|
22
|
-
import {
|
|
18
|
+
import { createProvisionLookup } from './provision.js';
|
|
19
|
+
import { resolveProvisions } from './provision-config.js';
|
|
23
20
|
import { validateInput } from './validation.js';
|
|
24
21
|
|
|
25
22
|
type MutableTrailContext = {
|
|
@@ -35,36 +32,29 @@ export interface ExecuteTrailOptions {
|
|
|
35
32
|
/** Partial context overrides merged on top of the base context. */
|
|
36
33
|
readonly ctx?: Partial<TrailContextInit> | undefined;
|
|
37
34
|
/** AbortSignal override (takes final precedence over ctx and factory). */
|
|
38
|
-
readonly
|
|
39
|
-
/**
|
|
40
|
-
readonly
|
|
35
|
+
readonly abortSignal?: AbortSignal | undefined;
|
|
36
|
+
/** Gates to compose around the implementation. */
|
|
37
|
+
readonly gates?: readonly Gate[] | undefined;
|
|
41
38
|
/** Factory that produces a base TrailContext (takes precedence over defaults). */
|
|
42
39
|
readonly createContext?:
|
|
43
40
|
| (() => TrailContextInit | Promise<TrailContextInit>)
|
|
44
41
|
| undefined;
|
|
45
|
-
/** Explicit
|
|
46
|
-
readonly
|
|
42
|
+
/** Explicit provision instance overrides keyed by provision ID. */
|
|
43
|
+
readonly provisions?: ProvisionOverrideMap | undefined;
|
|
44
|
+
/** Config values for provisions that declare a `config` schema, keyed by provision ID. */
|
|
45
|
+
readonly configValues?:
|
|
46
|
+
| Readonly<Record<string, Record<string, unknown>>>
|
|
47
|
+
| undefined;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
// ---------------------------------------------------------------------------
|
|
50
51
|
// Context resolution
|
|
51
52
|
// ---------------------------------------------------------------------------
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
*
|
|
56
|
-
* Resolution order:
|
|
57
|
-
* 1. Factory (`createContext`) or `createTrailContext()` defaults.
|
|
58
|
-
* 2. Partial `ctx` overrides merged on top.
|
|
59
|
-
* 3. `signal` override takes final precedence.
|
|
60
|
-
*/
|
|
61
|
-
const resolveContext = async (
|
|
54
|
+
const applyContextOverrides = (
|
|
55
|
+
base: TrailContextInit,
|
|
62
56
|
options?: ExecuteTrailOptions
|
|
63
|
-
):
|
|
64
|
-
const seed = options?.createContext
|
|
65
|
-
? await options.createContext()
|
|
66
|
-
: createTrailContext();
|
|
67
|
-
const base = seed.service ? seed : createTrailContext(seed);
|
|
57
|
+
): TrailContextInit => {
|
|
68
58
|
const withOverrides = options?.ctx
|
|
69
59
|
? {
|
|
70
60
|
...base,
|
|
@@ -72,220 +62,46 @@ const resolveContext = async (
|
|
|
72
62
|
extensions: { ...base.extensions, ...options.ctx.extensions },
|
|
73
63
|
}
|
|
74
64
|
: base;
|
|
75
|
-
const resolved = options?.signal
|
|
76
|
-
? { ...withOverrides, signal: options.signal }
|
|
77
|
-
: withOverrides;
|
|
78
|
-
if (
|
|
79
|
-
options?.ctx?.extensions !== undefined ||
|
|
80
|
-
resolved.service === undefined
|
|
81
|
-
) {
|
|
82
|
-
const bound = { ...resolved } as MutableTrailContext;
|
|
83
|
-
bound.service = createServiceLookup(() => bound);
|
|
84
|
-
return bound;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return resolved as TrailContext;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const singletonServices = new WeakMap<AnyService, Map<string, unknown>>();
|
|
91
|
-
|
|
92
|
-
/** In-flight service creation promises, keyed by service × context. */
|
|
93
|
-
const pendingCreations = new WeakMap<
|
|
94
|
-
AnyService,
|
|
95
|
-
Map<string, Promise<Result<unknown, Error>>>
|
|
96
|
-
>();
|
|
97
|
-
|
|
98
|
-
const hasOwnServiceOverride = (
|
|
99
|
-
overrides: ServiceOverrideMap | undefined,
|
|
100
|
-
id: string
|
|
101
|
-
): overrides is ServiceOverrideMap =>
|
|
102
|
-
overrides !== undefined && Object.hasOwn(overrides, id);
|
|
103
|
-
|
|
104
|
-
const toServiceContext = (ctx: TrailContext): ServiceContext => ({
|
|
105
|
-
cwd: ctx.cwd,
|
|
106
|
-
env: ctx.env,
|
|
107
|
-
workspaceRoot: ctx.workspaceRoot,
|
|
108
|
-
});
|
|
109
65
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
env: Object.entries(ctx.env ?? {}).toSorted(([left], [right]) =>
|
|
114
|
-
left.localeCompare(right)
|
|
115
|
-
),
|
|
116
|
-
workspaceRoot: ctx.workspaceRoot,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const toInternalServiceError = (id: string, error: unknown): InternalError => {
|
|
120
|
-
const cause = error instanceof Error ? error : undefined;
|
|
121
|
-
const message = cause?.message ?? String(error);
|
|
122
|
-
return new InternalError(`Service "${id}" failed to resolve: ${message}`, {
|
|
123
|
-
...(cause ? { cause } : {}),
|
|
124
|
-
context: { serviceId: id },
|
|
125
|
-
});
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const getCachedSingletonService = (
|
|
129
|
-
declaredService: AnyService,
|
|
130
|
-
serviceContext: ServiceContext
|
|
131
|
-
): { readonly found: boolean; readonly value: unknown } => {
|
|
132
|
-
const scopedCache = singletonServices.get(declaredService);
|
|
133
|
-
if (scopedCache === undefined) {
|
|
134
|
-
return { found: false, value: undefined };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const key = toServiceContextKey(serviceContext);
|
|
138
|
-
if (!scopedCache.has(key)) {
|
|
139
|
-
return { found: false, value: undefined };
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
found: true,
|
|
144
|
-
value: scopedCache.get(key),
|
|
145
|
-
};
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const getProvidedService = (
|
|
149
|
-
ctx: TrailContext,
|
|
150
|
-
overrides: ServiceOverrideMap | undefined,
|
|
151
|
-
declaredService: AnyService,
|
|
152
|
-
serviceContext: ServiceContext
|
|
153
|
-
): Result<unknown, Error> | undefined => {
|
|
154
|
-
const { id } = declaredService;
|
|
155
|
-
if (hasOwnServiceOverride(overrides, id)) {
|
|
156
|
-
return Result.ok(overrides[id]);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (Object.hasOwn(ctx.extensions ?? {}, id)) {
|
|
160
|
-
return Result.ok(ctx.extensions?.[id]);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const cached = getCachedSingletonService(declaredService, serviceContext);
|
|
164
|
-
if (cached.found) {
|
|
165
|
-
return Result.ok(cached.value);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return undefined;
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const getSingletonServiceCache = (
|
|
172
|
-
declaredService: AnyService
|
|
173
|
-
): Map<string, unknown> => {
|
|
174
|
-
const existing = singletonServices.get(declaredService);
|
|
175
|
-
if (existing !== undefined) {
|
|
176
|
-
return existing;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const created = new Map<string, unknown>();
|
|
180
|
-
singletonServices.set(declaredService, created);
|
|
181
|
-
return created;
|
|
66
|
+
return options?.abortSignal
|
|
67
|
+
? { ...withOverrides, abortSignal: options.abortSignal }
|
|
68
|
+
: withOverrides;
|
|
182
69
|
};
|
|
183
70
|
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
):
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const instance = created.unwrap();
|
|
195
|
-
getSingletonServiceCache(declaredService).set(
|
|
196
|
-
toServiceContextKey(serviceContext),
|
|
197
|
-
instance
|
|
198
|
-
);
|
|
199
|
-
return Result.ok(instance);
|
|
200
|
-
} catch (error: unknown) {
|
|
201
|
-
return Result.err(toInternalServiceError(declaredService.id, error));
|
|
71
|
+
const bindProvisionLookup = (
|
|
72
|
+
resolved: TrailContextInit,
|
|
73
|
+
options?: ExecuteTrailOptions
|
|
74
|
+
): TrailContext => {
|
|
75
|
+
if (
|
|
76
|
+
options?.ctx?.extensions === undefined &&
|
|
77
|
+
resolved.provision !== undefined
|
|
78
|
+
) {
|
|
79
|
+
return resolved as TrailContext;
|
|
202
80
|
}
|
|
203
|
-
};
|
|
204
81
|
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
): void => {
|
|
210
|
-
const pending = pendingCreations.get(declaredService);
|
|
211
|
-
if (pending) {
|
|
212
|
-
pending.set(key, promise);
|
|
213
|
-
} else {
|
|
214
|
-
pendingCreations.set(declaredService, new Map([[key, promise]]));
|
|
215
|
-
}
|
|
82
|
+
const bound = { ...resolved } as MutableTrailContext;
|
|
83
|
+
const lookup = createProvisionLookup(() => bound);
|
|
84
|
+
bound.provision = lookup;
|
|
85
|
+
return bound;
|
|
216
86
|
};
|
|
217
87
|
|
|
218
88
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
89
|
+
* Build a TrailContext from options.
|
|
90
|
+
*
|
|
91
|
+
* Resolution order:
|
|
92
|
+
* 1. Factory (`createContext`) or `createTrailContext()` defaults.
|
|
93
|
+
* 2. Partial `ctx` overrides merged on top.
|
|
94
|
+
* 3. `abortSignal` override takes final precedence.
|
|
222
95
|
*/
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const promise = doCreateServiceInstance(declaredService, serviceContext);
|
|
234
|
-
trackPendingCreation(declaredService, key, promise);
|
|
235
|
-
|
|
236
|
-
try {
|
|
237
|
-
return await promise;
|
|
238
|
-
} finally {
|
|
239
|
-
pendingCreations.get(declaredService)?.delete(key);
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
const resolveServiceInstance = async (
|
|
244
|
-
declaredService: AnyService,
|
|
245
|
-
ctx: TrailContext,
|
|
246
|
-
serviceContext: ServiceContext,
|
|
247
|
-
overrides?: ServiceOverrideMap
|
|
248
|
-
): Promise<Result<unknown, Error>> =>
|
|
249
|
-
getProvidedService(ctx, overrides, declaredService, serviceContext) ??
|
|
250
|
-
(await createServiceInstance(declaredService, serviceContext));
|
|
251
|
-
|
|
252
|
-
const withResolvedServices = (
|
|
253
|
-
ctx: TrailContext,
|
|
254
|
-
resolvedServices: Record<string, unknown>
|
|
255
|
-
): TrailContext => {
|
|
256
|
-
const extensions = { ...ctx.extensions, ...resolvedServices };
|
|
257
|
-
const resolvedCtx = { ...ctx, extensions } as MutableTrailContext;
|
|
258
|
-
resolvedCtx.service = createServiceLookup(() => resolvedCtx);
|
|
259
|
-
return resolvedCtx;
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
const resolveServices = async (
|
|
263
|
-
trail: AnyTrail,
|
|
264
|
-
ctx: TrailContext,
|
|
265
|
-
overrides?: ServiceOverrideMap
|
|
266
|
-
): Promise<Result<TrailContext, Error>> => {
|
|
267
|
-
if (trail.services.length === 0) {
|
|
268
|
-
return Result.ok(ctx);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const resolvedServices: Record<string, unknown> = {};
|
|
272
|
-
const serviceContext = toServiceContext(ctx);
|
|
273
|
-
|
|
274
|
-
for (const declaredService of trail.services) {
|
|
275
|
-
const resolved = await resolveServiceInstance(
|
|
276
|
-
declaredService,
|
|
277
|
-
ctx,
|
|
278
|
-
serviceContext,
|
|
279
|
-
overrides
|
|
280
|
-
);
|
|
281
|
-
if (resolved.isErr()) {
|
|
282
|
-
return resolved;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
resolvedServices[declaredService.id] = resolved.unwrap();
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
return Result.ok(withResolvedServices(ctx, resolvedServices));
|
|
96
|
+
const resolveContext = async (
|
|
97
|
+
options?: ExecuteTrailOptions
|
|
98
|
+
): Promise<TrailContext> => {
|
|
99
|
+
const seed = options?.createContext
|
|
100
|
+
? await options.createContext()
|
|
101
|
+
: createTrailContext();
|
|
102
|
+
const base = seed.provision ? seed : createTrailContext(seed);
|
|
103
|
+
const resolved = applyContextOverrides(base, options);
|
|
104
|
+
return bindProvisionLookup(resolved, options);
|
|
289
105
|
};
|
|
290
106
|
|
|
291
107
|
const prepareContext = async (
|
|
@@ -293,16 +109,21 @@ const prepareContext = async (
|
|
|
293
109
|
options?: ExecuteTrailOptions
|
|
294
110
|
): Promise<Result<TrailContext, Error>> => {
|
|
295
111
|
const baseCtx = await resolveContext(options);
|
|
296
|
-
return await
|
|
112
|
+
return await resolveProvisions(
|
|
113
|
+
trail,
|
|
114
|
+
baseCtx,
|
|
115
|
+
options?.provisions,
|
|
116
|
+
options?.configValues
|
|
117
|
+
);
|
|
297
118
|
};
|
|
298
119
|
|
|
299
120
|
const runTrail = async (
|
|
300
121
|
trail: AnyTrail,
|
|
301
122
|
input: unknown,
|
|
302
123
|
ctx: TrailContext,
|
|
303
|
-
|
|
124
|
+
gates: readonly Gate[]
|
|
304
125
|
): Promise<Result<unknown, Error>> => {
|
|
305
|
-
const impl =
|
|
126
|
+
const impl = composeGates([...gates], trail, trail.blaze);
|
|
306
127
|
return await impl(input, ctx);
|
|
307
128
|
};
|
|
308
129
|
|
|
@@ -311,7 +132,7 @@ const runTrail = async (
|
|
|
311
132
|
// ---------------------------------------------------------------------------
|
|
312
133
|
|
|
313
134
|
/**
|
|
314
|
-
* Execute a trail through the standard validate-context-
|
|
135
|
+
* Execute a trail through the standard validate-context-gates-run pipeline.
|
|
315
136
|
*
|
|
316
137
|
* The function never throws -- unexpected exceptions are caught and
|
|
317
138
|
* returned as `Result.err(InternalError)`.
|
|
@@ -336,7 +157,7 @@ export const executeTrail = async (
|
|
|
336
157
|
trail,
|
|
337
158
|
validated.value,
|
|
338
159
|
resolvedCtx.value,
|
|
339
|
-
options?.
|
|
160
|
+
options?.gates ?? []
|
|
340
161
|
);
|
|
341
162
|
} catch (error: unknown) {
|
|
342
163
|
const message = error instanceof Error ? error.message : String(error);
|
package/src/{layer.ts → gate.ts}
RENAMED
|
@@ -2,15 +2,15 @@ import type { Trail } from './trail.js';
|
|
|
2
2
|
import type { Implementation } from './types.js';
|
|
3
3
|
|
|
4
4
|
// ---------------------------------------------------------------------------
|
|
5
|
-
//
|
|
5
|
+
// Gate interface
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
7
|
|
|
8
|
-
/** A composable
|
|
9
|
-
export interface
|
|
8
|
+
/** A composable gate that wraps trail implementations. */
|
|
9
|
+
export interface Gate {
|
|
10
10
|
readonly name: string;
|
|
11
11
|
readonly description?: string | undefined;
|
|
12
12
|
|
|
13
|
-
/** Wrap a trail's implementation, returning a new implementation */
|
|
13
|
+
/** Wrap a trail's implementation, returning a new implementation. */
|
|
14
14
|
wrap<I, O>(
|
|
15
15
|
trail: Trail<I, O>,
|
|
16
16
|
implementation: Implementation<I, O>
|
|
@@ -22,22 +22,22 @@ export interface Layer {
|
|
|
22
22
|
// ---------------------------------------------------------------------------
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Apply
|
|
25
|
+
* Apply gates outermost-first: gates[0] wraps gates[1] wraps ... wraps
|
|
26
26
|
* the base implementation.
|
|
27
27
|
*
|
|
28
|
-
* An empty
|
|
28
|
+
* An empty gates array returns the implementation unchanged.
|
|
29
29
|
*/
|
|
30
|
-
export const
|
|
31
|
-
|
|
30
|
+
export const composeGates = <I, O>(
|
|
31
|
+
gates: readonly Gate[],
|
|
32
32
|
trail: Trail<I, O>,
|
|
33
33
|
implementation: Implementation<I, O>
|
|
34
34
|
): Implementation<I, O> => {
|
|
35
|
-
// Fold right so
|
|
35
|
+
// Fold right so gates[0] is the outermost wrapper.
|
|
36
36
|
let result = implementation;
|
|
37
|
-
for (let i =
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
40
|
-
result =
|
|
37
|
+
for (let i = gates.length - 1; i >= 0; i -= 1) {
|
|
38
|
+
const gate = gates[i];
|
|
39
|
+
if (gate) {
|
|
40
|
+
result = gate.wrap(trail, result);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
return result;
|
package/src/index.ts
CHANGED
|
@@ -31,30 +31,33 @@ export type {
|
|
|
31
31
|
Implementation,
|
|
32
32
|
TrailContext,
|
|
33
33
|
TrailContextInit,
|
|
34
|
-
|
|
34
|
+
CrossFn,
|
|
35
|
+
BasePermit,
|
|
36
|
+
PermitRequirement,
|
|
35
37
|
ProgressCallback,
|
|
36
38
|
ProgressEvent,
|
|
37
39
|
Logger,
|
|
38
|
-
|
|
40
|
+
ProvisionLookup,
|
|
39
41
|
} from './types.js';
|
|
42
|
+
export { TRAILHEAD_KEY } from './types.js';
|
|
40
43
|
|
|
41
44
|
// Context factory
|
|
42
45
|
export { createTrailContext } from './context.js';
|
|
43
46
|
|
|
44
|
-
//
|
|
47
|
+
// Provision
|
|
45
48
|
export {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
} from './
|
|
49
|
+
createProvisionLookup,
|
|
50
|
+
findDuplicateProvisionId,
|
|
51
|
+
isProvision,
|
|
52
|
+
provision,
|
|
53
|
+
} from './provision.js';
|
|
51
54
|
export type {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
} from './
|
|
55
|
+
AnyProvision,
|
|
56
|
+
Provision,
|
|
57
|
+
ProvisionContext,
|
|
58
|
+
ProvisionOverrideMap,
|
|
59
|
+
ProvisionSpec,
|
|
60
|
+
} from './provision.js';
|
|
58
61
|
|
|
59
62
|
// Trail
|
|
60
63
|
export { trail } from './trail.js';
|
|
@@ -70,7 +73,9 @@ export type {
|
|
|
70
73
|
export type { TrailInput, TrailOutput, TrailResult } from './type-utils.js';
|
|
71
74
|
export { inputOf, outputOf } from './type-utils.js';
|
|
72
75
|
|
|
73
|
-
//
|
|
76
|
+
// Signal
|
|
77
|
+
export { signal } from './signal.js';
|
|
78
|
+
export type { AnySignal, Signal, SignalSpec } from './signal.js';
|
|
74
79
|
export { event } from './event.js';
|
|
75
80
|
export type { AnyEvent, Event, EventSpec } from './event.js';
|
|
76
81
|
|
|
@@ -82,9 +87,9 @@ export type { Topo } from './topo.js';
|
|
|
82
87
|
export { validateTopo } from './validate-topo.js';
|
|
83
88
|
export type { TopoIssue } from './validate-topo.js';
|
|
84
89
|
|
|
85
|
-
//
|
|
86
|
-
export {
|
|
87
|
-
export type {
|
|
90
|
+
// Gate
|
|
91
|
+
export { composeGates } from './gate.js';
|
|
92
|
+
export type { Gate } from './gate.js';
|
|
88
93
|
|
|
89
94
|
// Derive
|
|
90
95
|
export { deriveFields } from './derive.js';
|
|
@@ -94,9 +99,9 @@ export type { Field, FieldOverride } from './derive.js';
|
|
|
94
99
|
export { executeTrail } from './execute.js';
|
|
95
100
|
export type { ExecuteTrailOptions } from './execute.js';
|
|
96
101
|
|
|
97
|
-
//
|
|
98
|
-
export {
|
|
99
|
-
export type {
|
|
102
|
+
// Run
|
|
103
|
+
export { run } from './run.js';
|
|
104
|
+
export type { RunOptions } from './run.js';
|
|
100
105
|
|
|
101
106
|
// Validation
|
|
102
107
|
export {
|