@bluelibs/runner 3.3.2 → 3.4.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 +437 -33
- package/dist/define.d.ts +5 -5
- package/dist/define.js +22 -2
- package/dist/define.js.map +1 -1
- package/dist/defs.d.ts +55 -21
- package/dist/defs.js.map +1 -1
- package/dist/defs.returnTag.d.ts +36 -0
- package/dist/defs.returnTag.js +4 -0
- package/dist/defs.returnTag.js.map +1 -0
- package/dist/errors.d.ts +60 -10
- package/dist/errors.js +103 -12
- package/dist/errors.js.map +1 -1
- package/dist/globals/globalMiddleware.d.ts +4 -4
- package/dist/globals/globalResources.d.ts +28 -10
- package/dist/globals/middleware/cache.middleware.d.ts +9 -9
- package/dist/globals/resources/queue.resource.d.ts +5 -2
- package/dist/index.d.ts +33 -14
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/models/DependencyProcessor.js +4 -4
- package/dist/models/DependencyProcessor.js.map +1 -1
- package/dist/models/EventManager.js +10 -1
- package/dist/models/EventManager.js.map +1 -1
- package/dist/models/Logger.d.ts +8 -0
- package/dist/models/Logger.js +24 -0
- package/dist/models/Logger.js.map +1 -1
- package/dist/models/OverrideManager.js +1 -1
- package/dist/models/OverrideManager.js.map +1 -1
- package/dist/models/ResourceInitializer.d.ts +2 -2
- package/dist/models/ResourceInitializer.js.map +1 -1
- package/dist/models/Store.d.ts +2 -2
- package/dist/models/Store.js +1 -1
- package/dist/models/Store.js.map +1 -1
- package/dist/models/StoreConstants.d.ts +6 -3
- package/dist/models/StoreRegistry.d.ts +2 -2
- package/dist/models/StoreRegistry.js +1 -1
- package/dist/models/StoreRegistry.js.map +1 -1
- package/dist/models/StoreTypes.d.ts +1 -1
- package/dist/models/StoreValidator.js +5 -5
- package/dist/models/StoreValidator.js.map +1 -1
- package/dist/models/TaskRunner.js +10 -0
- package/dist/models/TaskRunner.js.map +1 -1
- package/dist/run.d.ts +3 -3
- package/dist/run.js +1 -1
- package/dist/run.js.map +1 -1
- package/dist/t1.d.ts +1 -0
- package/dist/t1.js +13 -0
- package/dist/t1.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/package.json +2 -2
- package/src/__tests__/errors.test.ts +92 -11
- package/src/__tests__/models/EventManager.test.ts +0 -1
- package/src/__tests__/models/Logger.test.ts +82 -5
- package/src/__tests__/recursion/c.resource.ts +1 -1
- package/src/__tests__/run.overrides.test.ts +3 -3
- package/src/__tests__/typesafety.test.ts +112 -9
- package/src/__tests__/validation-edge-cases.test.ts +111 -0
- package/src/__tests__/validation-interface.test.ts +428 -0
- package/src/define.ts +47 -15
- package/src/defs.returnTag.ts +91 -0
- package/src/defs.ts +84 -27
- package/src/errors.ts +95 -23
- package/src/index.ts +1 -0
- package/src/models/DependencyProcessor.ts +9 -5
- package/src/models/EventManager.ts +12 -3
- package/src/models/Logger.ts +28 -0
- package/src/models/OverrideManager.ts +2 -7
- package/src/models/ResourceInitializer.ts +8 -3
- package/src/models/Store.ts +3 -3
- package/src/models/StoreRegistry.ts +2 -2
- package/src/models/StoreTypes.ts +1 -1
- package/src/models/StoreValidator.ts +6 -6
- package/src/models/TaskRunner.ts +10 -1
- package/src/run.ts +8 -5
- package/src/testing.ts +1 -1
package/src/defs.ts
CHANGED
|
@@ -15,6 +15,23 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { MiddlewareEverywhereOptions } from "./define";
|
|
18
|
+
import {
|
|
19
|
+
EnsureResponseSatisfiesContracts,
|
|
20
|
+
HasContracts,
|
|
21
|
+
} from "./defs.returnTag";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Generic validation schema interface that can be implemented by any validation library.
|
|
25
|
+
* Compatible with Zod, Yup, Joi, and other validation libraries.
|
|
26
|
+
*/
|
|
27
|
+
export interface IValidationSchema<T = any> {
|
|
28
|
+
/**
|
|
29
|
+
* Parse and validate the input data.
|
|
30
|
+
* Should throw an error if validation fails.
|
|
31
|
+
* Can transform the data if the schema supports transformations.
|
|
32
|
+
*/
|
|
33
|
+
parse(input: unknown): T;
|
|
34
|
+
}
|
|
18
35
|
|
|
19
36
|
// Re-export public cache type so consumers don’t import from internals.
|
|
20
37
|
export { ICacheInstance } from "./globals/middleware/cache.middleware";
|
|
@@ -57,17 +74,17 @@ export const symbolIndexResource: unique symbol = Symbol(
|
|
|
57
74
|
"runner.indexResource"
|
|
58
75
|
);
|
|
59
76
|
|
|
60
|
-
export interface ITagDefinition<TConfig = void> {
|
|
77
|
+
export interface ITagDefinition<TConfig = void, TEnforceContract = void> {
|
|
61
78
|
id: string | symbol;
|
|
62
79
|
}
|
|
63
80
|
|
|
64
81
|
/**
|
|
65
82
|
* A configured instance of a tag as produced by `ITag.with()`.
|
|
66
83
|
*/
|
|
67
|
-
export interface ITagWithConfig<TConfig = void> {
|
|
84
|
+
export interface ITagWithConfig<TConfig = void, TEnforceContract = void> {
|
|
68
85
|
id: string | symbol;
|
|
69
86
|
/** The tag definition used to produce this configured instance. */
|
|
70
|
-
tag: ITag<TConfig>;
|
|
87
|
+
tag: ITag<TConfig, TEnforceContract>;
|
|
71
88
|
/** The configuration captured for this tag instance. */
|
|
72
89
|
config: TConfig;
|
|
73
90
|
}
|
|
@@ -76,16 +93,19 @@ export interface ITagWithConfig<TConfig = void> {
|
|
|
76
93
|
* A tag definition (builder). Use `.with(config)` to obtain configured instances,
|
|
77
94
|
* and `.extract(tags)` to find either a configured instance or the bare tag in a list.
|
|
78
95
|
*/
|
|
79
|
-
export interface ITag<TConfig = void
|
|
96
|
+
export interface ITag<TConfig = void, TEnforceContract = void>
|
|
97
|
+
extends ITagDefinition<TConfig, TEnforceContract> {
|
|
80
98
|
/**
|
|
81
99
|
* Creates a configured instance of the tag.
|
|
82
100
|
*/
|
|
83
|
-
with(config: TConfig): ITagWithConfig<TConfig>;
|
|
101
|
+
with(config: TConfig): ITagWithConfig<TConfig, TEnforceContract>;
|
|
84
102
|
/**
|
|
85
103
|
* Extracts either a configured instance or the bare tag from a list of tags
|
|
86
104
|
* or from a taggable object (`{ meta: { tags?: [] } }`).
|
|
87
105
|
*/
|
|
88
|
-
extract(
|
|
106
|
+
extract(
|
|
107
|
+
target: TagType[] | ITaggable
|
|
108
|
+
): ExtractedTagResult<TConfig, TEnforceContract> | null;
|
|
89
109
|
[symbolFilePath]: string;
|
|
90
110
|
}
|
|
91
111
|
|
|
@@ -96,9 +116,9 @@ export interface ITag<TConfig = void> extends ITagDefinition<TConfig> {
|
|
|
96
116
|
*/
|
|
97
117
|
export type TagType =
|
|
98
118
|
| string
|
|
99
|
-
| ITag<void>
|
|
100
|
-
| ITag<{ [K in any]?: any }>
|
|
101
|
-
| ITagWithConfig<any>;
|
|
119
|
+
| ITag<void, any>
|
|
120
|
+
| ITag<{ [K in any]?: any }, any>
|
|
121
|
+
| ITagWithConfig<any, any>;
|
|
102
122
|
|
|
103
123
|
/**
|
|
104
124
|
* Conditional result type for `ITag.extract`:
|
|
@@ -106,7 +126,7 @@ export type TagType =
|
|
|
106
126
|
* - For optional object config → identifier with optional config
|
|
107
127
|
* - For required config → identifier with required config
|
|
108
128
|
*/
|
|
109
|
-
export type ExtractedTagResult<TConfig> = {} extends TConfig
|
|
129
|
+
export type ExtractedTagResult<TConfig, TEnforceContract> = {} extends TConfig
|
|
110
130
|
? { id: string | symbol; config?: TConfig }
|
|
111
131
|
: { id: string | symbol; config: TConfig };
|
|
112
132
|
|
|
@@ -119,7 +139,6 @@ export interface ITaggable {
|
|
|
119
139
|
tags?: TagType[];
|
|
120
140
|
};
|
|
121
141
|
}
|
|
122
|
-
|
|
123
142
|
/**
|
|
124
143
|
* Common metadata you can attach to tasks/resources/events/middleware.
|
|
125
144
|
* Useful for docs, filtering and middleware decisions.
|
|
@@ -149,7 +168,9 @@ export type DependencyMapType = Record<
|
|
|
149
168
|
type ExtractTaskInput<T> = T extends ITask<infer I, any, infer D> ? I : never;
|
|
150
169
|
type ExtractTaskOutput<T> = T extends ITask<any, infer O, infer D> ? O : never;
|
|
151
170
|
type ExtractResourceValue<T> = T extends IResource<any, infer V, infer D>
|
|
152
|
-
? V
|
|
171
|
+
? V extends Promise<infer U>
|
|
172
|
+
? U
|
|
173
|
+
: V
|
|
153
174
|
: never;
|
|
154
175
|
|
|
155
176
|
type ExtractEventParams<T> = T extends IEvent<infer P> ? P : never;
|
|
@@ -213,7 +234,8 @@ export interface ITaskDefinition<
|
|
|
213
234
|
TInput = any,
|
|
214
235
|
TOutput extends Promise<any> = any,
|
|
215
236
|
TDependencies extends DependencyMapType = {},
|
|
216
|
-
TOn extends "*" | IEventDefinition<any> | undefined = undefined // Adding a generic to track 'on' type
|
|
237
|
+
TOn extends "*" | IEventDefinition<any> | undefined = undefined, // Adding a generic to track 'on' type,
|
|
238
|
+
TMeta extends ITaskMeta = any
|
|
217
239
|
> {
|
|
218
240
|
/**
|
|
219
241
|
* Stable identifier. If omitted, an anonymous id is generated from file path
|
|
@@ -237,7 +259,12 @@ export interface ITaskDefinition<
|
|
|
237
259
|
*/
|
|
238
260
|
listenerOrder?: number;
|
|
239
261
|
/** Optional metadata used for docs, filtering and tooling. */
|
|
240
|
-
meta?:
|
|
262
|
+
meta?: TMeta;
|
|
263
|
+
/**
|
|
264
|
+
* Optional validation schema for runtime input validation.
|
|
265
|
+
* When provided, task input will be validated before execution.
|
|
266
|
+
*/
|
|
267
|
+
inputSchema?: IValidationSchema<TInput>;
|
|
241
268
|
/**
|
|
242
269
|
* The task body. If `on` is set, the input is an `IEventEmission`. Otherwise,
|
|
243
270
|
* it's the declared input type.
|
|
@@ -247,7 +274,9 @@ export interface ITaskDefinition<
|
|
|
247
274
|
? TInput
|
|
248
275
|
: IEventEmission<TOn extends "*" ? any : ExtractEventParams<TOn>>,
|
|
249
276
|
dependencies: DependencyValuesType<TDependencies>
|
|
250
|
-
) =>
|
|
277
|
+
) => HasContracts<TMeta> extends true
|
|
278
|
+
? EnsureResponseSatisfiesContracts<TMeta, TOutput>
|
|
279
|
+
: TOutput;
|
|
251
280
|
}
|
|
252
281
|
|
|
253
282
|
export type BeforeRunEventPayload<TInput> = {
|
|
@@ -284,8 +313,9 @@ export interface ITask<
|
|
|
284
313
|
TInput = any,
|
|
285
314
|
TOutput extends Promise<any> = any,
|
|
286
315
|
TDependencies extends DependencyMapType = {},
|
|
287
|
-
TOn extends "*" | IEventDefinition<any> | undefined = undefined
|
|
288
|
-
|
|
316
|
+
TOn extends "*" | IEventDefinition<any> | undefined = undefined,
|
|
317
|
+
TMeta extends ITaskMeta = any
|
|
318
|
+
> extends ITaskDefinition<TInput, TOutput, TDependencies, TOn, TMeta> {
|
|
289
319
|
id: string | symbol;
|
|
290
320
|
dependencies: TDependencies | (() => TDependencies);
|
|
291
321
|
computedDependencies?: DependencyValuesType<TDependencies>;
|
|
@@ -304,11 +334,12 @@ export interface ITask<
|
|
|
304
334
|
|
|
305
335
|
export interface IResourceDefinition<
|
|
306
336
|
TConfig = any,
|
|
307
|
-
TValue =
|
|
337
|
+
TValue extends Promise<any> = Promise<any>,
|
|
308
338
|
TDependencies extends DependencyMapType = {},
|
|
309
339
|
TContext = any,
|
|
310
340
|
THooks = any,
|
|
311
|
-
TRegisterableItems = any
|
|
341
|
+
TRegisterableItems = any,
|
|
342
|
+
TMeta extends IResourceMeta = any
|
|
312
343
|
> {
|
|
313
344
|
/** Stable identifier. Omit to get an anonymous id. */
|
|
314
345
|
id?: string | symbol;
|
|
@@ -329,7 +360,9 @@ export interface IResourceDefinition<
|
|
|
329
360
|
config: TConfig,
|
|
330
361
|
dependencies: DependencyValuesType<TDependencies>,
|
|
331
362
|
context: TContext
|
|
332
|
-
) =>
|
|
363
|
+
) => HasContracts<TMeta> extends true
|
|
364
|
+
? EnsureResponseSatisfiesContracts<TMeta, TValue>
|
|
365
|
+
: TValue;
|
|
333
366
|
/**
|
|
334
367
|
* Clean-up function for the resource. This is called when the resource is no longer needed.
|
|
335
368
|
*
|
|
@@ -340,12 +373,17 @@ export interface IResourceDefinition<
|
|
|
340
373
|
*/
|
|
341
374
|
dispose?: (
|
|
342
375
|
this: any,
|
|
343
|
-
value: TValue,
|
|
376
|
+
value: TValue extends Promise<infer U> ? U : TValue,
|
|
344
377
|
config: TConfig,
|
|
345
378
|
dependencies: DependencyValuesType<TDependencies>,
|
|
346
379
|
context: TContext
|
|
347
380
|
) => Promise<void>;
|
|
348
|
-
meta?:
|
|
381
|
+
meta?: TMeta;
|
|
382
|
+
/**
|
|
383
|
+
* Optional validation schema for runtime config validation.
|
|
384
|
+
* When provided, resource config will be validated when .with() is called.
|
|
385
|
+
*/
|
|
386
|
+
configSchema?: IValidationSchema<TConfig>;
|
|
349
387
|
/**
|
|
350
388
|
* Safe overrides to swap behavior while preserving identities. See
|
|
351
389
|
* README: Overrides.
|
|
@@ -370,10 +408,19 @@ export interface IResourceDefinition<
|
|
|
370
408
|
|
|
371
409
|
export interface IResource<
|
|
372
410
|
TConfig = void,
|
|
373
|
-
TValue = any
|
|
411
|
+
TValue extends Promise<any> = Promise<any>,
|
|
374
412
|
TDependencies extends DependencyMapType = any,
|
|
375
|
-
TContext = any
|
|
376
|
-
|
|
413
|
+
TContext = any,
|
|
414
|
+
TMeta extends IResourceMeta = any
|
|
415
|
+
> extends IResourceDefinition<
|
|
416
|
+
TConfig,
|
|
417
|
+
TValue,
|
|
418
|
+
TDependencies,
|
|
419
|
+
TContext,
|
|
420
|
+
any,
|
|
421
|
+
any,
|
|
422
|
+
TMeta
|
|
423
|
+
> {
|
|
377
424
|
id: string | symbol;
|
|
378
425
|
with(config: TConfig): IResourceWithConfig<TConfig, TValue, TDependencies>;
|
|
379
426
|
register:
|
|
@@ -396,7 +443,7 @@ export interface IResource<
|
|
|
396
443
|
|
|
397
444
|
export interface IResourceWithConfig<
|
|
398
445
|
TConfig = any,
|
|
399
|
-
TValue = any
|
|
446
|
+
TValue extends Promise<any> = Promise<any>,
|
|
400
447
|
TDependencies extends DependencyMapType = any
|
|
401
448
|
> {
|
|
402
449
|
/** The id of the underlying resource. */
|
|
@@ -415,6 +462,11 @@ export interface IEventDefinition<TPayload = void> {
|
|
|
415
462
|
/** Stable identifier. Omit to get an anonymous id. */
|
|
416
463
|
id?: string | symbol;
|
|
417
464
|
meta?: IEventMeta;
|
|
465
|
+
/**
|
|
466
|
+
* Optional validation schema for runtime payload validation.
|
|
467
|
+
* When provided, event payload will be validated when emitted.
|
|
468
|
+
*/
|
|
469
|
+
payloadSchema?: IValidationSchema<TPayload>;
|
|
418
470
|
}
|
|
419
471
|
|
|
420
472
|
export interface IEvent<TPayload = any> extends IEventDefinition<TPayload> {
|
|
@@ -469,6 +521,11 @@ export interface IMiddlewareDefinition<
|
|
|
469
521
|
id?: string | symbol;
|
|
470
522
|
/** Static or lazy dependency map. */
|
|
471
523
|
dependencies?: TDependencies | ((config: TConfig) => TDependencies);
|
|
524
|
+
/**
|
|
525
|
+
* Optional validation schema for runtime config validation.
|
|
526
|
+
* When provided, middleware config will be validated when .with() is called.
|
|
527
|
+
*/
|
|
528
|
+
configSchema?: IValidationSchema<TConfig>;
|
|
472
529
|
/**
|
|
473
530
|
* The middleware body, called with task/resource execution input.
|
|
474
531
|
*/
|
|
@@ -530,7 +587,7 @@ export interface IMiddlewareExecutionInput<
|
|
|
530
587
|
};
|
|
531
588
|
/** Resource hook: present when wrapping init/dispose. */
|
|
532
589
|
resource?: {
|
|
533
|
-
definition: IResource<TResourceConfig>;
|
|
590
|
+
definition: IResource<TResourceConfig, any, any, any, any>;
|
|
534
591
|
config: TResourceConfig;
|
|
535
592
|
};
|
|
536
593
|
next: (
|
package/src/errors.ts
CHANGED
|
@@ -1,33 +1,105 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all BlueLibs Runner errors
|
|
3
|
+
*/
|
|
4
|
+
export class RuntimeError extends Error {
|
|
5
|
+
constructor(message: string) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "RuntimeError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
2
10
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Error thrown when attempting to register a component with a duplicate ID
|
|
13
|
+
*/
|
|
14
|
+
export class DuplicateRegistrationError extends RuntimeError {
|
|
15
|
+
constructor(type: string, id: string | symbol) {
|
|
16
|
+
super(`${type} "${id.toString()}" already registered`);
|
|
17
|
+
this.name = "DuplicateRegistrationError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
6
20
|
|
|
7
|
-
|
|
8
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Error thrown when a dependency is not found in the registry
|
|
23
|
+
*/
|
|
24
|
+
export class DependencyNotFoundError extends RuntimeError {
|
|
25
|
+
constructor(key: string | symbol) {
|
|
26
|
+
super(
|
|
9
27
|
`Dependency ${key.toString()} not found. Did you forget to register it through a resource?`
|
|
10
|
-
)
|
|
28
|
+
);
|
|
29
|
+
this.name = "DependencyNotFoundError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
11
32
|
|
|
12
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Error thrown when an unknown item type is encountered
|
|
35
|
+
*/
|
|
36
|
+
export class UnknownItemTypeError extends RuntimeError {
|
|
37
|
+
constructor(item: any) {
|
|
38
|
+
super(`Unknown item type: ${item}`);
|
|
39
|
+
this.name = "UnknownItemTypeError";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
13
42
|
|
|
14
|
-
|
|
15
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Error thrown when circular dependencies are detected
|
|
45
|
+
*/
|
|
46
|
+
export class CircularDependenciesError extends RuntimeError {
|
|
47
|
+
constructor(cycles: string[]) {
|
|
48
|
+
super(`Circular dependencies detected: ${cycles.join(", ")}`);
|
|
49
|
+
this.name = "CircularDependenciesError";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
16
52
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Error thrown when an event is not found in the registry
|
|
55
|
+
*/
|
|
56
|
+
export class EventNotFoundError extends RuntimeError {
|
|
57
|
+
constructor(id: string | symbol) {
|
|
58
|
+
super(`Event "${id.toString()}" not found. Did you forget to register it?`);
|
|
59
|
+
this.name = "EventNotFoundError";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
21
62
|
|
|
22
|
-
|
|
23
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Error thrown when attempting to make a middleware global when it's already global
|
|
65
|
+
*/
|
|
66
|
+
export class MiddlewareAlreadyGlobalError extends RuntimeError {
|
|
67
|
+
constructor(id: string | symbol) {
|
|
68
|
+
super(
|
|
24
69
|
"Cannot call .everywhere() on an already global middleware: " +
|
|
25
|
-
id.toString
|
|
26
|
-
)
|
|
70
|
+
id.toString()
|
|
71
|
+
);
|
|
72
|
+
this.name = "MiddlewareAlreadyGlobalError";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
27
75
|
|
|
28
|
-
|
|
29
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Error thrown when attempting to modify a locked component
|
|
78
|
+
*/
|
|
79
|
+
export class LockedError extends RuntimeError {
|
|
80
|
+
constructor(what: string | symbol) {
|
|
81
|
+
super(`Cannot modify the ${what.toString()} when it is locked.`);
|
|
82
|
+
this.name = "LockedError";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
30
85
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Error thrown when attempting to initialize a store that's already initialized
|
|
88
|
+
*/
|
|
89
|
+
export class StoreAlreadyInitializedError extends RuntimeError {
|
|
90
|
+
constructor() {
|
|
91
|
+
super("Store already initialized. Cannot reinitialize.");
|
|
92
|
+
this.name = "StoreAlreadyInitializedError";
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Error thrown when validation fails for task input, resource config, middleware config, or event payload
|
|
98
|
+
*/
|
|
99
|
+
export class ValidationError extends RuntimeError {
|
|
100
|
+
constructor(type: string, id: string | symbol, originalError: Error | string) {
|
|
101
|
+
const errorMessage = originalError instanceof Error ? originalError.message : String(originalError);
|
|
102
|
+
super(`${type} validation failed for ${id.toString()}: ${errorMessage}`);
|
|
103
|
+
this.name = "ValidationError";
|
|
104
|
+
}
|
|
105
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -13,7 +13,11 @@ import * as utils from "../define";
|
|
|
13
13
|
import { EventManager } from "./EventManager";
|
|
14
14
|
import { ResourceInitializer } from "./ResourceInitializer";
|
|
15
15
|
import { TaskRunner } from "./TaskRunner";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
DependencyNotFoundError,
|
|
18
|
+
EventNotFoundError,
|
|
19
|
+
UnknownItemTypeError,
|
|
20
|
+
} from "../errors";
|
|
17
21
|
import { Logger } from "./Logger";
|
|
18
22
|
|
|
19
23
|
/**
|
|
@@ -148,7 +152,7 @@ export class DependencyProcessor {
|
|
|
148
152
|
});
|
|
149
153
|
} else {
|
|
150
154
|
if (this.store.events.get(eventDefinition.id) === undefined) {
|
|
151
|
-
throw
|
|
155
|
+
throw new EventNotFoundError(eventDefinition.id);
|
|
152
156
|
}
|
|
153
157
|
this.eventManager.addListener(eventDefinition, handler, {
|
|
154
158
|
order: task.task.listenerOrder || 0,
|
|
@@ -179,7 +183,7 @@ export class DependencyProcessor {
|
|
|
179
183
|
} else if (utils.isEvent(object)) {
|
|
180
184
|
return this.extractEventDependency(object, source);
|
|
181
185
|
} else {
|
|
182
|
-
throw
|
|
186
|
+
throw new UnknownItemTypeError(object);
|
|
183
187
|
}
|
|
184
188
|
}
|
|
185
189
|
|
|
@@ -197,7 +201,7 @@ export class DependencyProcessor {
|
|
|
197
201
|
async extractTaskDependency(object: ITask<any, any, {}>) {
|
|
198
202
|
const storeTask = this.store.tasks.get(object.id);
|
|
199
203
|
if (storeTask === undefined) {
|
|
200
|
-
throw
|
|
204
|
+
throw new DependencyNotFoundError(`Task ${object.id.toString()}`);
|
|
201
205
|
}
|
|
202
206
|
|
|
203
207
|
if (!storeTask.isInitialized) {
|
|
@@ -221,7 +225,7 @@ export class DependencyProcessor {
|
|
|
221
225
|
// check if it exists in the store with the value
|
|
222
226
|
const storeResource = this.store.resources.get(object.id);
|
|
223
227
|
if (storeResource === undefined) {
|
|
224
|
-
throw
|
|
228
|
+
throw new DependencyNotFoundError(`Resource ${object.id.toString()}`);
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
const { resource, config } = storeResource;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
IEventDefinition,
|
|
5
5
|
IEventEmission,
|
|
6
6
|
} from "../defs";
|
|
7
|
-
import {
|
|
7
|
+
import { LockedError, ValidationError } from "../errors";
|
|
8
8
|
import { Logger } from "./Logger";
|
|
9
9
|
|
|
10
10
|
const HandlerOptionsDefaults = { order: 0 };
|
|
@@ -42,7 +42,7 @@ export class EventManager {
|
|
|
42
42
|
|
|
43
43
|
checkLock() {
|
|
44
44
|
if (this.#isLocked) {
|
|
45
|
-
throw
|
|
45
|
+
throw new LockedError("EventManager");
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -106,6 +106,15 @@ export class EventManager {
|
|
|
106
106
|
data: TInput,
|
|
107
107
|
source: string | symbol
|
|
108
108
|
): Promise<void> {
|
|
109
|
+
// Validate payload with schema if provided
|
|
110
|
+
if (eventDefinition.payloadSchema) {
|
|
111
|
+
try {
|
|
112
|
+
data = eventDefinition.payloadSchema.parse(data);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw new ValidationError("Event payload", eventDefinition.id, error instanceof Error ? error : new Error(String(error)));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
109
118
|
const allListeners = this.getCachedMergedListeners(eventDefinition.id);
|
|
110
119
|
|
|
111
120
|
if (allListeners.length === 0) {
|
|
@@ -130,7 +139,7 @@ export class EventManager {
|
|
|
130
139
|
if (propagationStopped) {
|
|
131
140
|
break;
|
|
132
141
|
}
|
|
133
|
-
|
|
142
|
+
|
|
134
143
|
if (!listener.filter || listener.filter(event)) {
|
|
135
144
|
await listener.handler(event);
|
|
136
145
|
}
|
package/src/models/Logger.ts
CHANGED
|
@@ -48,6 +48,34 @@ export class Logger {
|
|
|
48
48
|
boundContext: Record<string, any> = {}
|
|
49
49
|
) {
|
|
50
50
|
this.boundContext = { ...boundContext };
|
|
51
|
+
this.printThreshold = this.getDefaultPrintThreshold();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Determines the default print threshold based on environment variables
|
|
56
|
+
*/
|
|
57
|
+
private getDefaultPrintThreshold(): LogLevels | null {
|
|
58
|
+
// Check if logging is explicitly disabled
|
|
59
|
+
const disableLogs = process.env.RUNNER_DISABLE_LOGS;
|
|
60
|
+
if (disableLogs === "true" || disableLogs === "1") {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check for specific log level override
|
|
65
|
+
const logLevel = process.env.RUNNER_LOG_LEVEL;
|
|
66
|
+
if (logLevel && this.isValidLogLevel(logLevel)) {
|
|
67
|
+
return logLevel as LogLevels;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Default to 'info' level for better developer experience
|
|
71
|
+
return "info";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Validates if a string is a valid log level
|
|
76
|
+
*/
|
|
77
|
+
private isValidLogLevel(level: string): boolean {
|
|
78
|
+
return Object.keys(Logger.Severity).includes(level);
|
|
51
79
|
}
|
|
52
80
|
|
|
53
81
|
/**
|
|
@@ -6,12 +6,7 @@ import {
|
|
|
6
6
|
RegisterableItems,
|
|
7
7
|
} from "../defs";
|
|
8
8
|
import * as utils from "../define";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
TaskStoreElementType,
|
|
12
|
-
MiddlewareStoreElementType,
|
|
13
|
-
ResourceStoreElementType,
|
|
14
|
-
} from "./StoreTypes";
|
|
9
|
+
import { DependencyNotFoundError } from "../errors";
|
|
15
10
|
import { StoreRegistry } from "./StoreRegistry";
|
|
16
11
|
|
|
17
12
|
export class OverrideManager {
|
|
@@ -65,7 +60,7 @@ export class OverrideManager {
|
|
|
65
60
|
? override.resource.id
|
|
66
61
|
: override.id;
|
|
67
62
|
|
|
68
|
-
throw
|
|
63
|
+
throw new DependencyNotFoundError(id);
|
|
69
64
|
}
|
|
70
65
|
}
|
|
71
66
|
|
|
@@ -23,7 +23,7 @@ export class ResourceInitializer {
|
|
|
23
23
|
*/
|
|
24
24
|
public async initializeResource<
|
|
25
25
|
TConfig = null,
|
|
26
|
-
TValue = any
|
|
26
|
+
TValue extends Promise<any> = Promise<any>,
|
|
27
27
|
TDeps extends DependencyMapType = {},
|
|
28
28
|
TContext = any
|
|
29
29
|
>(
|
|
@@ -109,11 +109,16 @@ export class ResourceInitializer {
|
|
|
109
109
|
|
|
110
110
|
if (!isSuppressed) throw e;
|
|
111
111
|
|
|
112
|
-
return { value: undefined as TValue, context: {} as TContext };
|
|
112
|
+
return { value: undefined as unknown as TValue, context: {} as TContext };
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
public async initWithMiddleware<
|
|
116
|
+
public async initWithMiddleware<
|
|
117
|
+
C,
|
|
118
|
+
V extends Promise<any>,
|
|
119
|
+
D extends DependencyMapType,
|
|
120
|
+
TContext
|
|
121
|
+
>(
|
|
117
122
|
resource: IResource<C, V, D, TContext>,
|
|
118
123
|
config: C,
|
|
119
124
|
dependencies: DependencyValuesType<D>,
|
package/src/models/Store.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "../defs";
|
|
7
7
|
import { IDependentNode } from "../tools/findCircularDependencies";
|
|
8
8
|
import { globalEventsArray } from "../globals/globalEvents";
|
|
9
|
-
import {
|
|
9
|
+
import { StoreAlreadyInitializedError } from "../errors";
|
|
10
10
|
import { EventManager } from "./EventManager";
|
|
11
11
|
import { Logger } from "./Logger";
|
|
12
12
|
import { StoreRegistry } from "./StoreRegistry";
|
|
@@ -125,9 +125,9 @@ export class Store {
|
|
|
125
125
|
this.registry.resources.set(root.id, this.root);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
initializeStore(root: IResource<any>, config: any) {
|
|
128
|
+
initializeStore(root: IResource<any, any, any, any, any>, config: any) {
|
|
129
129
|
if (this.#isInitialized) {
|
|
130
|
-
throw
|
|
130
|
+
throw new StoreAlreadyInitializedError();
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
this.registerGlobalComponents();
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
IEvent,
|
|
13
13
|
} from "../defs";
|
|
14
14
|
import * as utils from "../define";
|
|
15
|
-
import {
|
|
15
|
+
import { UnknownItemTypeError } from "../errors";
|
|
16
16
|
import {
|
|
17
17
|
TaskStoreElementType,
|
|
18
18
|
MiddlewareStoreElementType,
|
|
@@ -55,7 +55,7 @@ export class StoreRegistry {
|
|
|
55
55
|
} else if (utils.isResourceWithConfig(item)) {
|
|
56
56
|
this.storeResourceWithConfig<C>(item);
|
|
57
57
|
} else {
|
|
58
|
-
throw
|
|
58
|
+
throw new UnknownItemTypeError(item);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
package/src/models/StoreTypes.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DependencyNotFoundError, DuplicateRegistrationError } from "../errors";
|
|
2
2
|
import {
|
|
3
3
|
TaskStoreElementType,
|
|
4
4
|
MiddlewareStoreElementType,
|
|
@@ -16,16 +16,16 @@ export class StoreValidator {
|
|
|
16
16
|
|
|
17
17
|
checkIfIDExists(id: string | symbol): void | never {
|
|
18
18
|
if (this.tasks.has(id)) {
|
|
19
|
-
throw
|
|
19
|
+
throw new DuplicateRegistrationError("Task", id);
|
|
20
20
|
}
|
|
21
21
|
if (this.resources.has(id)) {
|
|
22
|
-
throw
|
|
22
|
+
throw new DuplicateRegistrationError("Resource", id);
|
|
23
23
|
}
|
|
24
24
|
if (this.events.has(id)) {
|
|
25
|
-
throw
|
|
25
|
+
throw new DuplicateRegistrationError("Event", id);
|
|
26
26
|
}
|
|
27
27
|
if (this.middlewares.has(id)) {
|
|
28
|
-
throw
|
|
28
|
+
throw new DuplicateRegistrationError("Middleware", id);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -33,7 +33,7 @@ export class StoreValidator {
|
|
|
33
33
|
for (const task of this.tasks.values()) {
|
|
34
34
|
task.task.middleware.forEach((middleware) => {
|
|
35
35
|
if (!this.middlewares.has(middleware.id)) {
|
|
36
|
-
throw
|
|
36
|
+
throw new DependencyNotFoundError(
|
|
37
37
|
`Middleware ${middleware.id.toString()} in Task ${task.task.id.toString()}`
|
|
38
38
|
);
|
|
39
39
|
}
|