@ontrails/core 1.0.0-beta.12 → 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.
Files changed (98) hide show
  1. package/CHANGELOG.md +59 -35
  2. package/README.md +19 -19
  3. package/dist/context.d.ts +1 -1
  4. package/dist/context.d.ts.map +1 -1
  5. package/dist/context.js +5 -4
  6. package/dist/context.js.map +1 -1
  7. package/dist/derive.d.ts +8 -3
  8. package/dist/derive.d.ts.map +1 -1
  9. package/dist/derive.js +7 -7
  10. package/dist/derive.js.map +1 -1
  11. package/dist/event.d.ts +4 -41
  12. package/dist/event.d.ts.map +1 -1
  13. package/dist/event.js +4 -14
  14. package/dist/event.js.map +1 -1
  15. package/dist/execute.d.ts +10 -10
  16. package/dist/execute.d.ts.map +1 -1
  17. package/dist/execute.js +35 -28
  18. package/dist/execute.js.map +1 -1
  19. package/dist/gate.d.ts +17 -0
  20. package/dist/gate.d.ts.map +1 -0
  21. package/dist/gate.js +21 -0
  22. package/dist/gate.js.map +1 -0
  23. package/dist/index.d.ts +10 -8
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +9 -8
  26. package/dist/index.js.map +1 -1
  27. package/dist/layer.d.ts +5 -16
  28. package/dist/layer.d.ts.map +1 -1
  29. package/dist/layer.js +3 -20
  30. package/dist/layer.js.map +1 -1
  31. package/dist/provision-config.d.ts +22 -0
  32. package/dist/provision-config.d.ts.map +1 -0
  33. package/dist/provision-config.js +210 -0
  34. package/dist/provision-config.js.map +1 -0
  35. package/dist/provision.d.ts +71 -0
  36. package/dist/provision.d.ts.map +1 -0
  37. package/dist/provision.js +56 -0
  38. package/dist/provision.js.map +1 -0
  39. package/dist/run.d.ts +27 -0
  40. package/dist/run.d.ts.map +1 -0
  41. package/dist/run.js +34 -0
  42. package/dist/run.js.map +1 -0
  43. package/dist/service-config.d.ts +7 -7
  44. package/dist/service-config.d.ts.map +1 -1
  45. package/dist/service-config.js +75 -73
  46. package/dist/service-config.js.map +1 -1
  47. package/dist/service.d.ts +32 -36
  48. package/dist/service.d.ts.map +1 -1
  49. package/dist/service.js +21 -21
  50. package/dist/service.js.map +1 -1
  51. package/dist/signal.d.ts +33 -0
  52. package/dist/signal.d.ts.map +1 -0
  53. package/dist/signal.js +17 -0
  54. package/dist/signal.js.map +1 -0
  55. package/dist/topo.d.ts +10 -10
  56. package/dist/topo.d.ts.map +1 -1
  57. package/dist/topo.js +48 -35
  58. package/dist/topo.js.map +1 -1
  59. package/dist/trail.d.ts +16 -16
  60. package/dist/trail.d.ts.map +1 -1
  61. package/dist/trail.js +5 -4
  62. package/dist/trail.js.map +1 -1
  63. package/dist/types.d.ts +10 -10
  64. package/dist/types.d.ts.map +1 -1
  65. package/dist/types.js +2 -2
  66. package/dist/types.js.map +1 -1
  67. package/dist/validate-topo.d.ts +2 -2
  68. package/dist/validate-topo.js +31 -31
  69. package/dist/validate-topo.js.map +1 -1
  70. package/package.json +1 -1
  71. package/src/__tests__/context.test.ts +8 -8
  72. package/src/__tests__/execute.test.ts +124 -122
  73. package/src/__tests__/{layer.test.ts → gate.test.ts} +26 -26
  74. package/src/__tests__/{dispatch.test.ts → run.test.ts} +39 -39
  75. package/src/__tests__/service-config.test.ts +41 -37
  76. package/src/__tests__/service.test.ts +71 -71
  77. package/src/__tests__/{event.test.ts → signal.test.ts} +15 -15
  78. package/src/__tests__/topo.test.ts +54 -54
  79. package/src/__tests__/trail-permit.test.ts +4 -4
  80. package/src/__tests__/trail.test.ts +58 -58
  81. package/src/__tests__/type-utils.test.ts +3 -3
  82. package/src/__tests__/validate-topo.test.ts +38 -38
  83. package/src/context.ts +5 -4
  84. package/src/derive.ts +8 -8
  85. package/src/event.ts +11 -73
  86. package/src/execute.ts +56 -40
  87. package/src/{layer.ts → gate.ts} +13 -13
  88. package/src/index.ts +24 -22
  89. package/src/{service-config.ts → provision-config.ts} +124 -105
  90. package/src/provision.ts +148 -0
  91. package/src/{dispatch.ts → run.ts} +8 -8
  92. package/src/signal.ts +65 -0
  93. package/src/topo.ts +74 -52
  94. package/src/trail.ts +23 -22
  95. package/src/types.ts +11 -11
  96. package/src/validate-topo.ts +33 -33
  97. package/tsconfig.tsbuildinfo +1 -1
  98. package/src/service.ts +0 -145
package/src/index.ts CHANGED
@@ -31,33 +31,33 @@ export type {
31
31
  Implementation,
32
32
  TrailContext,
33
33
  TrailContextInit,
34
- FollowFn,
34
+ CrossFn,
35
35
  BasePermit,
36
36
  PermitRequirement,
37
37
  ProgressCallback,
38
38
  ProgressEvent,
39
39
  Logger,
40
- ServiceLookup,
40
+ ProvisionLookup,
41
41
  } from './types.js';
42
- export { SURFACE_KEY } from './types.js';
42
+ export { TRAILHEAD_KEY } from './types.js';
43
43
 
44
44
  // Context factory
45
45
  export { createTrailContext } from './context.js';
46
46
 
47
- // Service
47
+ // Provision
48
48
  export {
49
- createServiceLookup,
50
- findDuplicateServiceId,
51
- isService,
52
- service,
53
- } from './service.js';
49
+ createProvisionLookup,
50
+ findDuplicateProvisionId,
51
+ isProvision,
52
+ provision,
53
+ } from './provision.js';
54
54
  export type {
55
- AnyService,
56
- Service,
57
- ServiceContext,
58
- ServiceOverrideMap,
59
- ServiceSpec,
60
- } from './service.js';
55
+ AnyProvision,
56
+ Provision,
57
+ ProvisionContext,
58
+ ProvisionOverrideMap,
59
+ ProvisionSpec,
60
+ } from './provision.js';
61
61
 
62
62
  // Trail
63
63
  export { trail } from './trail.js';
@@ -73,7 +73,9 @@ export type {
73
73
  export type { TrailInput, TrailOutput, TrailResult } from './type-utils.js';
74
74
  export { inputOf, outputOf } from './type-utils.js';
75
75
 
76
- // Event
76
+ // Signal
77
+ export { signal } from './signal.js';
78
+ export type { AnySignal, Signal, SignalSpec } from './signal.js';
77
79
  export { event } from './event.js';
78
80
  export type { AnyEvent, Event, EventSpec } from './event.js';
79
81
 
@@ -85,9 +87,9 @@ export type { Topo } from './topo.js';
85
87
  export { validateTopo } from './validate-topo.js';
86
88
  export type { TopoIssue } from './validate-topo.js';
87
89
 
88
- // Layer
89
- export { composeLayers } from './layer.js';
90
- export type { Layer } from './layer.js';
90
+ // Gate
91
+ export { composeGates } from './gate.js';
92
+ export type { Gate } from './gate.js';
91
93
 
92
94
  // Derive
93
95
  export { deriveFields } from './derive.js';
@@ -97,9 +99,9 @@ export type { Field, FieldOverride } from './derive.js';
97
99
  export { executeTrail } from './execute.js';
98
100
  export type { ExecuteTrailOptions } from './execute.js';
99
101
 
100
- // Dispatch
101
- export { dispatch } from './dispatch.js';
102
- export type { DispatchOptions } from './dispatch.js';
102
+ // Run
103
+ export { run } from './run.js';
104
+ export type { RunOptions } from './run.js';
103
105
 
104
106
  // Validation
105
107
  export {
@@ -1,22 +1,22 @@
1
1
  /**
2
- * Service resolution pipeline.
2
+ * Provision resolution pipeline.
3
3
  *
4
4
  * Extracted from execute.ts to keep both modules under the 400 LOC ceiling.
5
5
  * Handles config validation, singleton caching, concurrent-creation dedup,
6
- * and the full resolve-or-create flow for declared services.
6
+ * and the full resolve-or-create flow for declared provisions.
7
7
  */
8
8
 
9
9
  import type {
10
- AnyService,
11
- ServiceContext,
12
- ServiceOverrideMap,
13
- } from './service.js';
10
+ AnyProvision,
11
+ ProvisionContext,
12
+ ProvisionOverrideMap,
13
+ } from './provision.js';
14
14
  import type { AnyTrail } from './trail.js';
15
15
  import type { TrailContext } from './types.js';
16
16
 
17
17
  import { InternalError, ValidationError } from './errors.js';
18
18
  import { Result } from './result.js';
19
- import { createServiceLookup } from './service.js';
19
+ import { createProvisionLookup } from './provision.js';
20
20
 
21
21
  type MutableTrailContext = {
22
22
  -readonly [K in keyof TrailContext]: TrailContext[K];
@@ -28,11 +28,11 @@ type ConfigValues = Readonly<Record<string, Record<string, unknown>>>;
28
28
  // Singleton caches
29
29
  // ---------------------------------------------------------------------------
30
30
 
31
- const singletonServices = new WeakMap<AnyService, Map<string, unknown>>();
31
+ const singletonProvisions = new WeakMap<AnyProvision, Map<string, unknown>>();
32
32
 
33
- /** In-flight service creation promises, keyed by service x context. */
33
+ /** In-flight provision creation promises, keyed by provision x context. */
34
34
  const pendingCreations = new WeakMap<
35
- AnyService,
35
+ AnyProvision,
36
36
  Map<string, Promise<Result<unknown, Error>>>
37
37
  >();
38
38
 
@@ -40,17 +40,17 @@ const pendingCreations = new WeakMap<
40
40
  // Context helpers
41
41
  // ---------------------------------------------------------------------------
42
42
 
43
- const toServiceContext = (
43
+ const toProvisionContext = (
44
44
  ctx: TrailContext,
45
45
  config?: unknown
46
- ): ServiceContext => ({
46
+ ): ProvisionContext => ({
47
47
  config,
48
48
  cwd: ctx.cwd,
49
49
  env: ctx.env,
50
50
  workspaceRoot: ctx.workspaceRoot,
51
51
  });
52
52
 
53
- const toServiceContextKey = (ctx: ServiceContext): string =>
53
+ const toProvisionContextKey = (ctx: ProvisionContext): string =>
54
54
  JSON.stringify({
55
55
  config: ctx.config,
56
56
  cwd: ctx.cwd,
@@ -64,27 +64,27 @@ const toServiceContextKey = (ctx: ServiceContext): string =>
64
64
  // Config validation
65
65
  // ---------------------------------------------------------------------------
66
66
 
67
- /** Validate and resolve a service's config from the provided configValues map. */
68
- const resolveServiceConfig = (
69
- declaredService: AnyService,
67
+ /** Validate and resolve a provision's config from the provided configValues map. */
68
+ const resolveProvisionConfig = (
69
+ declaredProvision: AnyProvision,
70
70
  configValues?: ConfigValues
71
71
  ): Result<unknown, Error> => {
72
- if (declaredService.config === undefined) {
72
+ if (declaredProvision.config === undefined) {
73
73
  return Result.ok();
74
74
  }
75
- const raw = configValues?.[declaredService.id];
75
+ const raw = configValues?.[declaredProvision.id];
76
76
  if (raw === undefined) {
77
77
  return Result.err(
78
78
  new ValidationError(
79
- `Service "${declaredService.id}" declares a config schema but no config was provided`
79
+ `Provision "${declaredProvision.id}" declares a config schema but no config was provided`
80
80
  )
81
81
  );
82
82
  }
83
- const parsed = declaredService.config.safeParse(raw);
83
+ const parsed = declaredProvision.config.safeParse(raw);
84
84
  if (!parsed.success) {
85
85
  return Result.err(
86
86
  new ValidationError(
87
- `Service "${declaredService.id}" config validation failed: ${parsed.error.message}`
87
+ `Provision "${declaredProvision.id}" config validation failed: ${parsed.error.message}`
88
88
  )
89
89
  );
90
90
  }
@@ -95,22 +95,22 @@ const resolveServiceConfig = (
95
95
  // Override / cache lookups
96
96
  // ---------------------------------------------------------------------------
97
97
 
98
- const hasOwnServiceOverride = (
99
- overrides: ServiceOverrideMap | undefined,
98
+ const hasOwnProvisionOverride = (
99
+ overrides: ProvisionOverrideMap | undefined,
100
100
  id: string
101
- ): overrides is ServiceOverrideMap =>
101
+ ): overrides is ProvisionOverrideMap =>
102
102
  overrides !== undefined && Object.hasOwn(overrides, id);
103
103
 
104
- const getCachedSingletonService = (
105
- declaredService: AnyService,
106
- serviceContext: ServiceContext
104
+ const getCachedSingletonProvision = (
105
+ declaredProvision: AnyProvision,
106
+ provisionContext: ProvisionContext
107
107
  ): { readonly found: boolean; readonly value: unknown } => {
108
- const scopedCache = singletonServices.get(declaredService);
108
+ const scopedCache = singletonProvisions.get(declaredProvision);
109
109
  if (scopedCache === undefined) {
110
110
  return { found: false, value: undefined };
111
111
  }
112
112
 
113
- const key = toServiceContextKey(serviceContext);
113
+ const key = toProvisionContextKey(provisionContext);
114
114
  if (!scopedCache.has(key)) {
115
115
  return { found: false, value: undefined };
116
116
  }
@@ -121,14 +121,14 @@ const getCachedSingletonService = (
121
121
  };
122
122
  };
123
123
 
124
- const getProvidedService = (
124
+ const getProvidedProvision = (
125
125
  ctx: TrailContext,
126
- overrides: ServiceOverrideMap | undefined,
127
- declaredService: AnyService,
128
- serviceContext: ServiceContext
126
+ overrides: ProvisionOverrideMap | undefined,
127
+ declaredProvision: AnyProvision,
128
+ provisionContext: ProvisionContext
129
129
  ): Result<unknown, Error> | undefined => {
130
- const { id } = declaredService;
131
- if (hasOwnServiceOverride(overrides, id)) {
130
+ const { id } = declaredProvision;
131
+ if (hasOwnProvisionOverride(overrides, id)) {
132
132
  return Result.ok(overrides[id]);
133
133
  }
134
134
 
@@ -136,7 +136,10 @@ const getProvidedService = (
136
136
  return Result.ok(ctx.extensions?.[id]);
137
137
  }
138
138
 
139
- const cached = getCachedSingletonService(declaredService, serviceContext);
139
+ const cached = getCachedSingletonProvision(
140
+ declaredProvision,
141
+ provisionContext
142
+ );
140
143
  if (cached.found) {
141
144
  return Result.ok(cached.value);
142
145
  }
@@ -146,200 +149,216 @@ const getProvidedService = (
146
149
 
147
150
  const getOverrideOrExtension = (
148
151
  ctx: TrailContext,
149
- overrides: ServiceOverrideMap | undefined,
150
- declaredService: AnyService
152
+ overrides: ProvisionOverrideMap | undefined,
153
+ declaredProvision: AnyProvision
151
154
  ): Result<unknown, Error> | undefined =>
152
- getProvidedService(ctx, overrides, declaredService, toServiceContext(ctx));
155
+ getProvidedProvision(
156
+ ctx,
157
+ overrides,
158
+ declaredProvision,
159
+ toProvisionContext(ctx)
160
+ );
153
161
 
154
162
  type ConfigAwareResolution =
155
163
  | Result<{ readonly kind: 'provided'; readonly value: unknown }, Error>
156
164
  | Result<
157
- { readonly kind: 'context'; readonly serviceContext: ServiceContext },
165
+ { readonly kind: 'context'; readonly provisionContext: ProvisionContext },
158
166
  Error
159
167
  >;
160
168
 
161
- const resolveConfigAwareProvidedService = (
169
+ const resolveConfigAwareProvidedProvision = (
162
170
  ctx: TrailContext,
163
- declaredService: AnyService,
171
+ declaredProvision: AnyProvision,
164
172
  configValues: ConfigValues | undefined
165
173
  ): ConfigAwareResolution => {
166
- const configResult = resolveServiceConfig(declaredService, configValues);
174
+ const configResult = resolveProvisionConfig(declaredProvision, configValues);
167
175
  if (configResult.isErr()) {
168
176
  return configResult;
169
177
  }
170
178
 
171
- const serviceContext = toServiceContext(ctx, configResult.value);
172
- const provided = getProvidedService(
179
+ const provisionContext = toProvisionContext(ctx, configResult.value);
180
+ const provided = getProvidedProvision(
173
181
  ctx,
174
182
  undefined,
175
- declaredService,
176
- serviceContext
183
+ declaredProvision,
184
+ provisionContext
177
185
  );
178
186
 
179
187
  return provided
180
188
  ? Result.ok({ kind: 'provided', value: provided.unwrap() })
181
- : Result.ok({ kind: 'context', serviceContext });
189
+ : Result.ok({ kind: 'context', provisionContext });
182
190
  };
183
191
 
184
192
  // ---------------------------------------------------------------------------
185
193
  // Instance creation
186
194
  // ---------------------------------------------------------------------------
187
195
 
188
- const toInternalServiceError = (id: string, error: unknown): InternalError => {
196
+ const toInternalProvisionError = (
197
+ id: string,
198
+ error: unknown
199
+ ): InternalError => {
189
200
  const cause = error instanceof Error ? error : undefined;
190
201
  const message = cause?.message ?? String(error);
191
- return new InternalError(`Service "${id}" failed to resolve: ${message}`, {
202
+ return new InternalError(`Provision "${id}" failed to resolve: ${message}`, {
192
203
  ...(cause ? { cause } : {}),
193
- context: { serviceId: id },
204
+ context: { provisionId: id },
194
205
  });
195
206
  };
196
207
 
197
- const getSingletonServiceCache = (
198
- declaredService: AnyService
208
+ const getSingletonProvisionCache = (
209
+ declaredProvision: AnyProvision
199
210
  ): Map<string, unknown> => {
200
- const existing = singletonServices.get(declaredService);
211
+ const existing = singletonProvisions.get(declaredProvision);
201
212
  if (existing !== undefined) {
202
213
  return existing;
203
214
  }
204
215
 
205
216
  const created = new Map<string, unknown>();
206
- singletonServices.set(declaredService, created);
217
+ singletonProvisions.set(declaredProvision, created);
207
218
  return created;
208
219
  };
209
220
 
210
- const doCreateServiceInstance = async (
211
- declaredService: AnyService,
212
- serviceContext: ServiceContext
221
+ const doCreateProvisionInstance = async (
222
+ declaredProvision: AnyProvision,
223
+ provisionContext: ProvisionContext
213
224
  ): Promise<Result<unknown, Error>> => {
214
225
  try {
215
- const created = await declaredService.create(serviceContext);
226
+ const created = await declaredProvision.create(provisionContext);
216
227
  if (created.isErr()) {
217
228
  return Result.err(created.error);
218
229
  }
219
230
 
220
231
  const instance = created.unwrap();
221
- getSingletonServiceCache(declaredService).set(
222
- toServiceContextKey(serviceContext),
232
+ getSingletonProvisionCache(declaredProvision).set(
233
+ toProvisionContextKey(provisionContext),
223
234
  instance
224
235
  );
225
236
  return Result.ok(instance);
226
237
  } catch (error: unknown) {
227
- return Result.err(toInternalServiceError(declaredService.id, error));
238
+ return Result.err(toInternalProvisionError(declaredProvision.id, error));
228
239
  }
229
240
  };
230
241
 
231
242
  const trackPendingCreation = (
232
- declaredService: AnyService,
243
+ declaredProvision: AnyProvision,
233
244
  key: string,
234
245
  promise: Promise<Result<unknown, Error>>
235
246
  ): void => {
236
- const pending = pendingCreations.get(declaredService);
247
+ const pending = pendingCreations.get(declaredProvision);
237
248
  if (pending) {
238
249
  pending.set(key, promise);
239
250
  } else {
240
- pendingCreations.set(declaredService, new Map([[key, promise]]));
251
+ pendingCreations.set(declaredProvision, new Map([[key, promise]]));
241
252
  }
242
253
  };
243
254
 
244
255
  /**
245
- * Deduplicates concurrent creation of the same service singleton.
246
- * If a creation is already in flight for this service x context key,
256
+ * Deduplicates concurrent creation of the same provision singleton.
257
+ * If a creation is already in flight for this provision x context key,
247
258
  * returns the existing promise instead of spawning a second factory call.
248
259
  */
249
- const createServiceInstance = async (
250
- declaredService: AnyService,
251
- serviceContext: ServiceContext
260
+ const createProvisionInstance = async (
261
+ declaredProvision: AnyProvision,
262
+ provisionContext: ProvisionContext
252
263
  ): Promise<Result<unknown, Error>> => {
253
- const key = toServiceContextKey(serviceContext);
254
- const inflight = pendingCreations.get(declaredService)?.get(key);
264
+ const key = toProvisionContextKey(provisionContext);
265
+ const inflight = pendingCreations.get(declaredProvision)?.get(key);
255
266
  if (inflight) {
256
267
  return inflight;
257
268
  }
258
269
 
259
- const promise = doCreateServiceInstance(declaredService, serviceContext);
260
- trackPendingCreation(declaredService, key, promise);
270
+ const promise = doCreateProvisionInstance(
271
+ declaredProvision,
272
+ provisionContext
273
+ );
274
+ trackPendingCreation(declaredProvision, key, promise);
261
275
 
262
276
  try {
263
277
  return await promise;
264
278
  } finally {
265
- pendingCreations.get(declaredService)?.delete(key);
279
+ pendingCreations.get(declaredProvision)?.delete(key);
266
280
  }
267
281
  };
268
282
 
269
- /** Validate config and resolve a single declared service. */
270
- const resolveDeclaredService = async (
271
- declaredService: AnyService,
283
+ /** Validate config and resolve a single declared provision. */
284
+ const resolveDeclaredProvision = async (
285
+ declaredProvision: AnyProvision,
272
286
  ctx: TrailContext,
273
- overrides: ServiceOverrideMap | undefined,
287
+ overrides: ProvisionOverrideMap | undefined,
274
288
  configValues: ConfigValues | undefined
275
289
  ): Promise<Result<unknown, Error>> => {
276
290
  // Check overrides/extensions first — skip config validation entirely when
277
- // a service instance is already provided.
291
+ // a provision instance is already provided.
278
292
  const overrideOrExtension = getOverrideOrExtension(
279
293
  ctx,
280
294
  overrides,
281
- declaredService
295
+ declaredProvision
282
296
  );
283
297
  if (overrideOrExtension !== undefined) {
284
298
  return overrideOrExtension;
285
299
  }
286
300
 
287
301
  // Resolve config before consulting the singleton cache so config-aware
288
- // services use the same canonical context for cache reads and writes.
289
- const configAwareService = resolveConfigAwareProvidedService(
302
+ // provisions use the same canonical context for cache reads and writes.
303
+ const configAwareProvision = resolveConfigAwareProvidedProvision(
290
304
  ctx,
291
- declaredService,
305
+ declaredProvision,
292
306
  configValues
293
307
  );
294
- if (configAwareService.isErr()) {
295
- return configAwareService;
308
+ if (configAwareProvision.isErr()) {
309
+ return configAwareProvision;
296
310
  }
297
311
 
298
312
  // No provided instance — create via factory.
299
- const resolved = configAwareService.unwrap();
313
+ const resolved = configAwareProvision.unwrap();
300
314
  if (resolved.kind === 'provided') {
301
315
  return Result.ok(resolved.value);
302
316
  }
303
317
 
304
- return await createServiceInstance(declaredService, resolved.serviceContext);
318
+ return await createProvisionInstance(
319
+ declaredProvision,
320
+ resolved.provisionContext
321
+ );
305
322
  };
306
323
 
307
324
  // ---------------------------------------------------------------------------
308
- // Full trail service resolution
325
+ // Full trail provision resolution
309
326
  // ---------------------------------------------------------------------------
310
327
 
311
- const withResolvedServices = (
328
+ const withResolvedProvisions = (
312
329
  ctx: TrailContext,
313
- resolvedServices: Record<string, unknown>
330
+ resolvedProvisions: Record<string, unknown>
314
331
  ): TrailContext => {
315
- const extensions = { ...ctx.extensions, ...resolvedServices };
332
+ const extensions = { ...ctx.extensions, ...resolvedProvisions };
316
333
  const resolvedCtx = { ...ctx, extensions } as MutableTrailContext;
317
- resolvedCtx.service = createServiceLookup(() => resolvedCtx);
334
+ const lookup = createProvisionLookup(() => resolvedCtx);
335
+ resolvedCtx.provision = lookup;
318
336
  return resolvedCtx;
319
337
  };
320
338
 
321
339
  /**
322
- * Resolve all declared services for a trail.
340
+ * Resolve all declared provisions for a trail.
323
341
  *
324
- * Validates per-service config, checks overrides and caches, and creates
325
- * new instances as needed. Returns an enriched context with all service
342
+ * Validates per-provision config, checks overrides and caches, and creates
343
+ * new instances as needed. Returns an enriched context with all provision
326
344
  * instances injected into extensions.
327
345
  */
328
- export const resolveServices = async (
346
+ export const resolveProvisions = async (
329
347
  trail: AnyTrail,
330
348
  ctx: TrailContext,
331
- overrides?: ServiceOverrideMap,
349
+ overrides?: ProvisionOverrideMap,
332
350
  configValues?: ConfigValues
333
351
  ): Promise<Result<TrailContext, Error>> => {
334
- if (trail.services.length === 0) {
352
+ const { provisions } = trail;
353
+ if (provisions.length === 0) {
335
354
  return Result.ok(ctx);
336
355
  }
337
356
 
338
- const resolvedServices: Record<string, unknown> = {};
357
+ const resolvedProvisions: Record<string, unknown> = {};
339
358
 
340
- for (const declaredService of trail.services) {
341
- const resolved = await resolveDeclaredService(
342
- declaredService,
359
+ for (const declaredProvision of provisions) {
360
+ const resolved = await resolveDeclaredProvision(
361
+ declaredProvision,
343
362
  ctx,
344
363
  overrides,
345
364
  configValues
@@ -347,8 +366,8 @@ export const resolveServices = async (
347
366
  if (resolved.isErr()) {
348
367
  return resolved;
349
368
  }
350
- resolvedServices[declaredService.id] = resolved.unwrap();
369
+ resolvedProvisions[declaredProvision.id] = resolved.unwrap();
351
370
  }
352
371
 
353
- return Result.ok(withResolvedServices(ctx, resolvedServices));
372
+ return Result.ok(withResolvedProvisions(ctx, resolvedProvisions));
354
373
  };