@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.
Files changed (75) hide show
  1. package/README.md +437 -33
  2. package/dist/define.d.ts +5 -5
  3. package/dist/define.js +22 -2
  4. package/dist/define.js.map +1 -1
  5. package/dist/defs.d.ts +55 -21
  6. package/dist/defs.js.map +1 -1
  7. package/dist/defs.returnTag.d.ts +36 -0
  8. package/dist/defs.returnTag.js +4 -0
  9. package/dist/defs.returnTag.js.map +1 -0
  10. package/dist/errors.d.ts +60 -10
  11. package/dist/errors.js +103 -12
  12. package/dist/errors.js.map +1 -1
  13. package/dist/globals/globalMiddleware.d.ts +4 -4
  14. package/dist/globals/globalResources.d.ts +28 -10
  15. package/dist/globals/middleware/cache.middleware.d.ts +9 -9
  16. package/dist/globals/resources/queue.resource.d.ts +5 -2
  17. package/dist/index.d.ts +33 -14
  18. package/dist/index.js +2 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/models/DependencyProcessor.js +4 -4
  21. package/dist/models/DependencyProcessor.js.map +1 -1
  22. package/dist/models/EventManager.js +10 -1
  23. package/dist/models/EventManager.js.map +1 -1
  24. package/dist/models/Logger.d.ts +8 -0
  25. package/dist/models/Logger.js +24 -0
  26. package/dist/models/Logger.js.map +1 -1
  27. package/dist/models/OverrideManager.js +1 -1
  28. package/dist/models/OverrideManager.js.map +1 -1
  29. package/dist/models/ResourceInitializer.d.ts +2 -2
  30. package/dist/models/ResourceInitializer.js.map +1 -1
  31. package/dist/models/Store.d.ts +2 -2
  32. package/dist/models/Store.js +1 -1
  33. package/dist/models/Store.js.map +1 -1
  34. package/dist/models/StoreConstants.d.ts +6 -3
  35. package/dist/models/StoreRegistry.d.ts +2 -2
  36. package/dist/models/StoreRegistry.js +1 -1
  37. package/dist/models/StoreRegistry.js.map +1 -1
  38. package/dist/models/StoreTypes.d.ts +1 -1
  39. package/dist/models/StoreValidator.js +5 -5
  40. package/dist/models/StoreValidator.js.map +1 -1
  41. package/dist/models/TaskRunner.js +10 -0
  42. package/dist/models/TaskRunner.js.map +1 -1
  43. package/dist/run.d.ts +3 -3
  44. package/dist/run.js +1 -1
  45. package/dist/run.js.map +1 -1
  46. package/dist/t1.d.ts +1 -0
  47. package/dist/t1.js +13 -0
  48. package/dist/t1.js.map +1 -0
  49. package/dist/testing.d.ts +1 -1
  50. package/package.json +2 -2
  51. package/src/__tests__/errors.test.ts +92 -11
  52. package/src/__tests__/models/EventManager.test.ts +0 -1
  53. package/src/__tests__/models/Logger.test.ts +82 -5
  54. package/src/__tests__/recursion/c.resource.ts +1 -1
  55. package/src/__tests__/run.overrides.test.ts +3 -3
  56. package/src/__tests__/typesafety.test.ts +112 -9
  57. package/src/__tests__/validation-edge-cases.test.ts +111 -0
  58. package/src/__tests__/validation-interface.test.ts +428 -0
  59. package/src/define.ts +47 -15
  60. package/src/defs.returnTag.ts +91 -0
  61. package/src/defs.ts +84 -27
  62. package/src/errors.ts +95 -23
  63. package/src/index.ts +1 -0
  64. package/src/models/DependencyProcessor.ts +9 -5
  65. package/src/models/EventManager.ts +12 -3
  66. package/src/models/Logger.ts +28 -0
  67. package/src/models/OverrideManager.ts +2 -7
  68. package/src/models/ResourceInitializer.ts +8 -3
  69. package/src/models/Store.ts +3 -3
  70. package/src/models/StoreRegistry.ts +2 -2
  71. package/src/models/StoreTypes.ts +1 -1
  72. package/src/models/StoreValidator.ts +6 -6
  73. package/src/models/TaskRunner.ts +10 -1
  74. package/src/run.ts +8 -5
  75. 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> extends ITagDefinition<TConfig> {
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(target: TagType[] | ITaggable): ExtractedTagResult<TConfig> | null;
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?: ITaskMeta;
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
- ) => TOutput;
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
- > extends ITaskDefinition<TInput, TOutput, TDependencies, TOn> {
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 = unknown,
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
- ) => Promise<TValue>;
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?: IResourceMeta;
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
- > extends IResourceDefinition<TConfig, TValue, TDependencies, TContext> {
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
- import { ITask, IResource } from "./defs";
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
- export const Errors = {
4
- duplicateRegistration: (type: string, id: string | symbol) =>
5
- new Error(`${type} "${id.toString()}" already registered`),
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
- dependencyNotFound: (key: string | symbol) =>
8
- new Error(
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
- unknownItemType: (item: any) => new Error(`Unknown item type: ${item}`),
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
- circularDependencies: (cycles: string[]) =>
15
- new Error(`Circular dependencies detected: ${cycles.join(", ")}`),
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
- eventNotFound: (id: string | symbol) =>
18
- new Error(
19
- `Event "${id.toString()}" not found. Did you forget to register it?`
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
- middlewareAlreadyGlobal: (id: string | symbol) =>
23
- new Error(
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
- locked: (what: string | symbol) =>
29
- new Error(`Cannot modify the ${what.toString()} when it is locked.`),
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
- storeAlreadyInitialized: () =>
32
- new Error("Store already initialized. Cannot reinitialize."),
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
@@ -36,3 +36,4 @@ export {
36
36
 
37
37
  export * as definitions from "./defs";
38
38
  export { Semaphore, Store, EventManager, TaskRunner, Queue } from "./models";
39
+ export * as Errors from "./errors";
@@ -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 { Errors } from "../errors";
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 Errors.eventNotFound(eventDefinition.id);
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 Errors.unknownItemType(object);
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 Errors.dependencyNotFound(`Task ${object.id.toString()}`);
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 Errors.dependencyNotFound(`Resource ${object.id.toString()}`);
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 { Errors } from "../errors";
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 Errors.locked("EventManager");
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
  }
@@ -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 { Errors } from "../errors";
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 Errors.dependencyNotFound(id);
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<C, V, D extends DependencyMapType, TContext>(
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>,
@@ -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 { Errors } from "../errors";
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 Errors.storeAlreadyInitialized();
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 { Errors } from "../errors";
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 Errors.unknownItemType(item);
58
+ throw new UnknownItemTypeError(item);
59
59
  }
60
60
  }
61
61
 
@@ -13,7 +13,7 @@ import {
13
13
 
14
14
  export type ResourceStoreElementType<
15
15
  C = any,
16
- V = any,
16
+ V extends Promise<any> = any,
17
17
  D extends DependencyMapType = {},
18
18
  TContext = any
19
19
  > = {
@@ -1,4 +1,4 @@
1
- import { Errors } from "../errors";
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 Errors.duplicateRegistration("Task", id);
19
+ throw new DuplicateRegistrationError("Task", id);
20
20
  }
21
21
  if (this.resources.has(id)) {
22
- throw Errors.duplicateRegistration("Resource", id);
22
+ throw new DuplicateRegistrationError("Resource", id);
23
23
  }
24
24
  if (this.events.has(id)) {
25
- throw Errors.duplicateRegistration("Event", id);
25
+ throw new DuplicateRegistrationError("Event", id);
26
26
  }
27
27
  if (this.middlewares.has(id)) {
28
- throw Errors.duplicateRegistration("Middleware", id);
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 Errors.dependencyNotFound(
36
+ throw new DependencyNotFoundError(
37
37
  `Middleware ${middleware.id.toString()} in Task ${task.task.id.toString()}`
38
38
  );
39
39
  }