@decaf-ts/core 0.20.0 → 0.21.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 (138) hide show
  1. package/lib/cjs/index.cjs +1 -1
  2. package/lib/esm/index.js +1 -1
  3. package/lib/types/auth/constants.d.ts +5 -0
  4. package/lib/types/auth/decorators.d.ts +5 -0
  5. package/lib/types/auth/index.d.ts +2 -0
  6. package/lib/types/fs/FilesystemAdapter.d.ts +70 -0
  7. package/lib/types/fs/FsDispatch.d.ts +7 -0
  8. package/lib/types/fs/helpers.d.ts +17 -0
  9. package/lib/types/fs/index.d.ts +4 -0
  10. package/lib/types/fs/indexStore.d.ts +28 -0
  11. package/lib/types/fs/locks/FilesystemLock.d.ts +13 -0
  12. package/lib/types/fs/locks/FilesystemMultiLock.d.ts +8 -0
  13. package/lib/types/fs/types.d.ts +40 -0
  14. package/lib/types/identity/decorators.d.ts +72 -0
  15. package/lib/types/identity/index.d.ts +6 -0
  16. package/lib/types/index.d.cts +1 -1
  17. package/lib/types/index.d.mts +1 -1
  18. package/lib/types/index.d.ts +34 -0
  19. package/lib/types/interfaces/ContextuallyLogged.d.ts +8 -0
  20. package/lib/types/interfaces/ErrorParser.d.ts +16 -0
  21. package/lib/types/interfaces/Executor.d.ts +16 -0
  22. package/lib/types/interfaces/Observable.d.ts +33 -0
  23. package/lib/types/interfaces/Observer.d.ts +15 -0
  24. package/lib/types/interfaces/Paginatable.d.ts +20 -0
  25. package/lib/types/interfaces/Queriable.d.ts +47 -0
  26. package/lib/types/interfaces/RawExecutor.d.ts +28 -0
  27. package/lib/types/interfaces/SequenceOptions.d.ts +79 -0
  28. package/lib/types/interfaces/index.d.ts +12 -0
  29. package/lib/types/migrations/Migration.d.ts +19 -0
  30. package/lib/types/migrations/MigrationService.d.ts +63 -0
  31. package/lib/types/migrations/MigrationTaskBuilder.d.ts +10 -0
  32. package/lib/types/migrations/MigrationTasks.d.ts +9 -0
  33. package/lib/types/migrations/MigrationVersioning.d.ts +7 -0
  34. package/lib/types/migrations/SemverMigrationVersioning.d.ts +10 -0
  35. package/lib/types/migrations/StandardMigrationVersioning.d.ts +12 -0
  36. package/lib/types/migrations/constants.d.ts +2 -0
  37. package/lib/types/migrations/decorators.d.ts +12 -0
  38. package/lib/types/migrations/index.d.ts +15 -0
  39. package/lib/types/migrations/types.d.ts +46 -0
  40. package/lib/types/model/BaseModel.d.ts +37 -0
  41. package/lib/types/model/SequenceModel.d.ts +32 -0
  42. package/lib/types/model/construction.d.ts +455 -0
  43. package/lib/types/model/decorators.d.ts +237 -0
  44. package/lib/types/model/index.d.ts +11 -0
  45. package/lib/types/model/indexing.d.ts +20 -0
  46. package/lib/types/model/types.d.ts +60 -0
  47. package/lib/types/overrides/Metadata.d.ts +22 -0
  48. package/lib/types/overrides/Model.d.ts +94 -0
  49. package/lib/types/overrides/ModelBuilder.d.ts +31 -0
  50. package/lib/types/overrides/index.d.ts +11 -0
  51. package/lib/types/overrides/injectables.d.ts +10 -0
  52. package/lib/types/overrides/overrides.d.ts +1 -0
  53. package/lib/types/persistence/Adapter.d.ts +469 -0
  54. package/lib/types/persistence/Context.d.ts +16 -0
  55. package/lib/types/persistence/ContextLock.d.ts +18 -0
  56. package/lib/types/persistence/Dispatch.d.ts +128 -0
  57. package/lib/types/persistence/ObserverHandler.d.ts +111 -0
  58. package/lib/types/persistence/Sequence.d.ts +126 -0
  59. package/lib/types/persistence/constants.d.ts +74 -0
  60. package/lib/types/persistence/decorators.d.ts +28 -0
  61. package/lib/types/persistence/errors.d.ts +33 -0
  62. package/lib/types/persistence/event-filters.d.ts +20 -0
  63. package/lib/types/persistence/generators.d.ts +14 -0
  64. package/lib/types/persistence/index.d.ts +18 -0
  65. package/lib/types/persistence/transactions.d.ts +4 -0
  66. package/lib/types/persistence/types.d.ts +86 -0
  67. package/lib/types/query/Condition.d.ts +131 -0
  68. package/lib/types/query/MethodQueryBuilder.d.ts +185 -0
  69. package/lib/types/query/Paginator.d.ts +105 -0
  70. package/lib/types/query/Statement.d.ts +136 -0
  71. package/lib/types/query/constants.d.ts +69 -0
  72. package/lib/types/query/decorators.d.ts +8 -0
  73. package/lib/types/query/errors.d.ts +21 -0
  74. package/lib/types/query/index.d.ts +16 -0
  75. package/lib/types/query/options.d.ts +393 -0
  76. package/lib/types/query/selectors.d.ts +39 -0
  77. package/lib/types/query/types.d.ts +158 -0
  78. package/lib/types/query/utils.d.ts +40 -0
  79. package/lib/types/ram/RamAdapter.d.ts +341 -0
  80. package/lib/types/ram/RamPaginator.d.ts +54 -0
  81. package/lib/types/ram/RamStatement.d.ts +92 -0
  82. package/lib/types/ram/constants.d.ts +8 -0
  83. package/lib/types/ram/handlers.d.ts +24 -0
  84. package/lib/types/ram/index.d.ts +12 -0
  85. package/lib/types/ram/types.d.ts +50 -0
  86. package/lib/types/repository/Repository.d.ts +501 -0
  87. package/lib/types/repository/constants.d.ts +36 -0
  88. package/lib/types/repository/decorators.d.ts +30 -0
  89. package/lib/types/repository/errors.d.ts +19 -0
  90. package/lib/types/repository/index.d.ts +12 -0
  91. package/lib/types/repository/injectables.d.ts +95 -0
  92. package/lib/types/repository/types.d.ts +28 -0
  93. package/lib/types/repository/utils.d.ts +36 -0
  94. package/lib/types/services/ModelService.d.ts +45 -0
  95. package/lib/types/services/PersistenceService.d.ts +17 -0
  96. package/lib/types/services/index.d.ts +8 -0
  97. package/lib/types/services/services.d.ts +96 -0
  98. package/lib/types/tasks/CleanUpTask.d.ts +15 -0
  99. package/lib/types/tasks/TaskContext.d.ts +30 -0
  100. package/lib/types/tasks/TaskEngine.d.ts +97 -0
  101. package/lib/types/tasks/TaskErrors.d.ts +65 -0
  102. package/lib/types/tasks/TaskEventBus.d.ts +17 -0
  103. package/lib/types/tasks/TaskEventService.d.ts +7 -0
  104. package/lib/types/tasks/TaskHandler.d.ts +12 -0
  105. package/lib/types/tasks/TaskHandlerRegistry.d.ts +8 -0
  106. package/lib/types/tasks/TaskService.d.ts +65 -0
  107. package/lib/types/tasks/TaskStateChangeError.d.ts +11 -0
  108. package/lib/types/tasks/TaskTracker.d.ts +47 -0
  109. package/lib/types/tasks/builder.d.ts +72 -0
  110. package/lib/types/tasks/constants.d.ts +31 -0
  111. package/lib/types/tasks/decorators.d.ts +4 -0
  112. package/lib/types/tasks/index.d.ts +23 -0
  113. package/lib/types/tasks/logging.d.ts +31 -0
  114. package/lib/types/tasks/models/TaskBackoffModel.d.ts +9 -0
  115. package/lib/types/tasks/models/TaskErrorModel.d.ts +8 -0
  116. package/lib/types/tasks/models/TaskEventModel.d.ts +11 -0
  117. package/lib/types/tasks/models/TaskIOSerializer.d.ts +33 -0
  118. package/lib/types/tasks/models/TaskLogEntryModel.d.ts +10 -0
  119. package/lib/types/tasks/models/TaskModel.d.ts +43 -0
  120. package/lib/types/tasks/models/TaskStepResultModel.d.ts +9 -0
  121. package/lib/types/tasks/models/TaskStepSpecModel.d.ts +9 -0
  122. package/lib/types/tasks/models/index.d.ts +8 -0
  123. package/lib/types/tasks/types.d.ts +71 -0
  124. package/lib/types/tasks/utils.d.ts +5 -0
  125. package/lib/types/utils/ContextualLoggedClass.d.ts +37 -0
  126. package/lib/types/utils/decorators.d.ts +27 -0
  127. package/lib/types/utils/errors.d.ts +56 -0
  128. package/lib/types/utils/index.d.ts +11 -0
  129. package/lib/types/utils/throttling.d.ts +9 -0
  130. package/lib/types/utils/types.d.ts +23 -0
  131. package/lib/types/utils/utils.d.ts +22 -0
  132. package/lib/types/workers/TaskEngine.d.ts +40 -0
  133. package/lib/types/workers/WorkThreadEnvironment.d.ts +35 -0
  134. package/lib/types/workers/index.d.ts +5 -0
  135. package/lib/types/workers/messages.d.ts +69 -0
  136. package/lib/types/workers/types.d.ts +41 -0
  137. package/lib/types/workers/workerThread.d.ts +1 -0
  138. package/package.json +1 -1
@@ -0,0 +1,95 @@
1
+ import { InjectableRegistryImp } from "@decaf-ts/injectable-decorators";
2
+ import { Logger } from "@decaf-ts/logging";
3
+ import { Constructor } from "@decaf-ts/decoration";
4
+ /**
5
+ * @description Registry for injectable repositories with auto-resolution.
6
+ * @summary Provides an InjectableRegistry implementation that resolves repositories by model name or constructor. If a repository
7
+ * is not explicitly registered, it attempts to infer the correct repository using model metadata and the active or specified adapter flavour.
8
+ * @param {void} [constructor] No constructor parameters required; the superclass handles internal state.
9
+ * @class InjectablesRegistry
10
+ * @example
11
+ * // Basic usage: retrieve a repository by model name
12
+ * const registry = new InjectablesRegistry();
13
+ * const userRepo = registry.get<UserRepository>('User');
14
+ * // If UserRepository is registered, it will be returned. Otherwise, a repository will be created if a User model exists.
15
+ *
16
+ * // Retrieve by constructor and specify adapter flavour
17
+ * const repoByCtor = registry.get<UserRepository>(UserModel, 'ram');
18
+ *
19
+ * // Retrieve by symbol (e.g., injectable token)
20
+ * const token = Symbol.for('UserRepository');
21
+ * const byToken = registry.get<UserRepository>(token);
22
+ * @mermaid
23
+ * sequenceDiagram
24
+ * participant C as Consumer
25
+ * participant R as InjectablesRegistry
26
+ * participant B as BaseRegistry
27
+ * participant M as Model
28
+ * participant A as Adapter
29
+ * participant RP as Repository
30
+ * C->>R: get(name, flavour?)
31
+ * activate R
32
+ * R->>B: super.get(name)
33
+ * alt Found in base registry
34
+ * B-->>R: injectable
35
+ * R-->>C: injectable
36
+ * else Not found
37
+ * R->>M: Model.get(name)
38
+ * alt Model found
39
+ * R->>A: resolve flavour (from arg/metadata/current)
40
+ * R->>RP: Repository.forModel(modelCtor, alias)
41
+ * alt Repository instance
42
+ * RP-->>R: repository instance
43
+ * R-->>C: repository instance
44
+ * else Repository ctor
45
+ * R->>A: Adapter.get(resolvedFlavour) or Adapter.current
46
+ * A-->>R: adapter instance
47
+ * R->>RP: new repoCtor(adapter, modelCtor)
48
+ * R-->>C: repository instance
49
+ * end
50
+ * else Model not found
51
+ * R-->>C: undefined
52
+ * end
53
+ * end
54
+ */
55
+ export declare class InjectablesRegistry extends InjectableRegistryImp {
56
+ private logger?;
57
+ protected get log(): Logger;
58
+ constructor();
59
+ /**
60
+ * @description Retrieve an injectable with repository auto-resolution.
61
+ * @summary Attempts to get an injectable from the base registry; if not found and the name refers to a known model, it
62
+ * resolves the appropriate repository using the specified flavour or model metadata, falling back to the current adapter when needed.
63
+ * @template T The injectable type to be returned.
64
+ * @param {string | symbol | Constructor<T>} name Token, model name, or constructor associated with the injectable or model.
65
+ * @param {string} [flavour] Optional adapter flavour (e.g., "ram"). If omitted, derives from metadata or current adapter.
66
+ * @return {T | undefined} The located or auto-created injectable instance; otherwise undefined if it cannot be resolved.
67
+ * @mermaid
68
+ * sequenceDiagram
69
+ * participant G as get(name, flavour?)
70
+ * participant BR as BaseRegistry
71
+ * participant M as Model
72
+ * participant A as Adapter
73
+ * participant RP as Repository
74
+ * G->>BR: super.get(name)
75
+ * alt Found
76
+ * BR-->>G: injectable
77
+ * else Not found
78
+ * G->>M: derive modelCtor from name
79
+ * alt modelCtor resolved
80
+ * G->>A: resolve flavour (arg | metadata | current)
81
+ * G->>RP: Repository.forModel(modelCtor, alias)
82
+ * alt returns instance
83
+ * RP-->>G: Repository instance
84
+ * else returns ctor
85
+ * G->>A: Adapter.get(flavour) | Adapter.current
86
+ * A-->>G: adapter instance
87
+ * G->>RP: new repoCtor(adapter, modelCtor)
88
+ * end
89
+ * else no modelCtor
90
+ * G-->>G: return undefined
91
+ * end
92
+ * end
93
+ */
94
+ get<T>(name: symbol | Constructor<T> | string, flavour?: string): T | undefined;
95
+ }
@@ -0,0 +1,28 @@
1
+ import { Cascade, OrderDirection } from "./constants";
2
+ /**
3
+ * @description Metadata for cascade operations on related entities.
4
+ * @summary Defines how update and delete operations should cascade to related entities.
5
+ * @typedef CascadeMetadata
6
+ * @property {Cascade} update - Determines cascade behavior for update operations.
7
+ * @property {Cascade} delete - Determines cascade behavior for delete operations.
8
+ * @memberOf module:core
9
+ */
10
+ export type CascadeMetadata = {
11
+ update: Cascade;
12
+ delete: Cascade;
13
+ };
14
+ export type IndexMetadata = {
15
+ name?: string;
16
+ directions?: OrderDirection[2];
17
+ compositions?: string[];
18
+ };
19
+ /**
20
+ * @description Metadata for a named index that extends IndexMetadata.
21
+ * @summary Extends IndexMetadata with a suffix to identify the index.
22
+ * @typedef NamedIndexMetadata
23
+ * @property {string} suffix - The suffix to append to the index name.
24
+ * @memberOf module:core
25
+ */
26
+ export type NamedIndexMetadata = IndexMetadata & {
27
+ suffix: string;
28
+ };
@@ -0,0 +1,36 @@
1
+ import { Model } from "@decaf-ts/decorator-validation";
2
+ import { Constructor } from "@decaf-ts/decoration";
3
+ /**
4
+ * @description Generates a unique injectable name for a repository.
5
+ * @summary Creates a standardized injectable token for repositories using the adapter flavour and model table name.
6
+ * This helps the DI system register and resolve repository instances consistently across adapters.
7
+ * @template T The model type that extends Model.
8
+ * @param {Constructor<T> | T} model The model constructor or instance from which to derive the table name.
9
+ * @param {string} [flavour] Optional adapter flavour/alias. If omitted, it is read from model metadata.
10
+ * @return {string} A namespaced injectable token for the repository (e.g., "db:repo:ram:users").
11
+ * @throws {InternalError} If the flavour cannot be determined from arguments or metadata.
12
+ * @function generateInjectableNameForRepository
13
+ * @mermaid
14
+ * sequenceDiagram
15
+ * participant C as Caller
16
+ * participant U as generateInjectableNameForRepository
17
+ * participant R as Reflect Metadata
18
+ * participant A as Adapter
19
+ * participant S as String Formatter
20
+ * C->>U: call(model, flavour?)
21
+ * alt flavour provided
22
+ * U-->>U: use provided flavour
23
+ * else flavour not provided
24
+ * U->>A: ADAPTER
25
+ * U->>R: getMetadata(key, model|model.ctor)
26
+ * alt metadata present
27
+ * R-->>U: flavour
28
+ * else missing
29
+ * U-->>C: throw InternalError
30
+ * end
31
+ * end
32
+ * U->>S: sf(INJECTABLE, flavour, Model.tableName(model))
33
+ * S-->>C: token string
34
+ * @memberOf module:core
35
+ */
36
+ export declare function generateInjectableNameForRepository<T extends Model>(model: Constructor<T> | T, flavour?: string): string;
@@ -0,0 +1,45 @@
1
+ import { type Constructor } from "@decaf-ts/decoration";
2
+ import { Model, type ModelConstructor } from "@decaf-ts/decorator-validation";
3
+ import { type Repo } from "../repository/Repository";
4
+ import { Service } from "./services";
5
+ import type { AllOperationKeys, ContextOf, EventIds, ObserverFilter, PersistenceObservable, PersistenceObserver } from "../persistence/types";
6
+ import { type IRepository, type PrimaryKeyType } from "@decaf-ts/db-decorators";
7
+ import type { ContextualArgs, ContextualizedArgs, MaybeContextualArg, MethodOrOperation } from "../utils/ContextualLoggedClass";
8
+ import { OrderDirection } from "../repository/constants";
9
+ import { type DirectionLimitOffset } from "../query/types";
10
+ import { type Observer } from "../interfaces";
11
+ import { SelectSelector, WhereOption } from "../query/index";
12
+ export type ArrayMode = "one" | "many";
13
+ export declare class ModelService<M extends Model<boolean>, R extends Repo<M> = Repo<M>> extends Service implements IRepository<M, ContextOf<R>>, PersistenceObservable<ContextOf<R>>, PersistenceObserver<ContextOf<R>> {
14
+ private readonly clazz;
15
+ protected _repository: R;
16
+ get class(): Constructor<M>;
17
+ get repo(): R;
18
+ constructor(clazz: Constructor<M>, name?: string);
19
+ static getService<M extends Model<boolean>, S extends ModelService<M>>(name: string | symbol | Constructor<M>): S;
20
+ create(model: M, ...args: MaybeContextualArg<ContextOf<R>>): Promise<M>;
21
+ createAll(models: M[], ...args: MaybeContextualArg<ContextOf<R>>): Promise<M[]>;
22
+ delete(key: PrimaryKeyType, ...args: MaybeContextualArg<ContextOf<R>>): Promise<M>;
23
+ deleteAll(keys: PrimaryKeyType[], ...args: MaybeContextualArg<ContextOf<R>>): Promise<M[]>;
24
+ read(key: PrimaryKeyType, ...args: MaybeContextualArg<ContextOf<R>>): Promise<M>;
25
+ readAll(keys: PrimaryKeyType[], ...args: MaybeContextualArg<ContextOf<R>>): Promise<M[]>;
26
+ query<M, R extends ArrayMode = "one">(methodName: string, ...args: unknown[]): Promise<R extends "one" ? M : M[]>;
27
+ update(model: M, ...args: MaybeContextualArg<ContextOf<R>>): Promise<M>;
28
+ updateAll(models: M[], ...args: any[]): Promise<M[]>;
29
+ select<S extends readonly SelectSelector<M>[]>(): WhereOption<M, M[]>;
30
+ select<S extends readonly SelectSelector<M>[]>(selector: readonly [...S]): WhereOption<M, Pick<M, S[number]>[]>;
31
+ listBy(key: keyof M, order: OrderDirection, ...args: MaybeContextualArg<ContextOf<R>>): Promise<M[]>;
32
+ paginateBy(key: keyof M, order: OrderDirection, ref: Omit<DirectionLimitOffset, "direction">, ...args: MaybeContextualArg<ContextOf<R>>): Promise<import("..").SerializedPage<M>>;
33
+ findOneBy(key: keyof M, value: any, ...args: MaybeContextualArg<ContextOf<R>>): Promise<M>;
34
+ findBy(key: keyof M, value: any, ...args: MaybeContextualArg<ContextOf<R>>): Promise<M[]>;
35
+ findByPaginate(key: keyof M, value: any, ref: DirectionLimitOffset, ...args: MaybeContextualArg<ContextOf<R>>): Promise<import("..").SerializedPage<M>>;
36
+ statement(name: string, ...args: MaybeContextualArg<ContextOf<R>>): Promise<any>;
37
+ static forModel<M extends Model<boolean>, S extends ModelService<M>>(this: new (model: ModelConstructor<M>) => S, model: ModelConstructor<M>, alias?: string | symbol): S;
38
+ refresh(table: Constructor<M>, event: AllOperationKeys, id: EventIds, ...args: ContextualArgs<ContextOf<R>>): Promise<void>;
39
+ observe(observer: Observer, filter?: ObserverFilter): () => void;
40
+ unObserve(observer: Observer): void;
41
+ updateObservers(model: Constructor, operation: AllOperationKeys, ids: EventIds, ...args: ContextualArgs<ContextOf<R>>): Promise<void>;
42
+ protected logCtx<ARGS extends any[] = any[], METHOD extends MethodOrOperation = MethodOrOperation>(args: MaybeContextualArg<ContextOf<this["repo"]>, ARGS>, operation: METHOD): ContextualizedArgs<ContextOf<this["repo"]>, ARGS, METHOD extends string ? true : false>;
43
+ protected logCtx<ARGS extends any[] = any[], METHOD extends MethodOrOperation = MethodOrOperation>(args: MaybeContextualArg<ContextOf<this["repo"]>, ARGS>, operation: METHOD, allowCreate: false): ContextualizedArgs<ContextOf<this["repo"]>, ARGS, METHOD extends string ? true : false>;
44
+ protected logCtx<ARGS extends any[] = any[], METHOD extends MethodOrOperation = MethodOrOperation>(args: MaybeContextualArg<ContextOf<this["repo"]>, ARGS>, operation: METHOD, allowCreate: true): Promise<ContextualizedArgs<ContextOf<this["repo"]>, ARGS, METHOD extends string ? true : false>>;
45
+ }
@@ -0,0 +1,17 @@
1
+ import { ClientBasedService } from "./services";
2
+ import { Adapter } from "../persistence/Adapter";
3
+ import { ConfigOf, ContextOf } from "../persistence/types";
4
+ import { MaybeContextualArg } from "../utils/ContextualLoggedClass";
5
+ import { Constructor } from "@decaf-ts/decoration";
6
+ export declare class PersistenceService<A extends Adapter<any, any, any, any>> extends ClientBasedService<A[], [
7
+ Constructor<A>,
8
+ ConfigOf<A>,
9
+ ...args: any[]
10
+ ][], ContextOf<A>> {
11
+ constructor();
12
+ for(conf: any, ...args: any[]): this;
13
+ initialize(...args: MaybeContextualArg<ContextOf<A>>): Promise<{
14
+ config: [Constructor<A>, ConfigOf<A>, ...args: any[]][];
15
+ client: A[];
16
+ }>;
17
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @description Exports for the services module.
3
+ * @summary This file exports all the necessary components for the services functionality, including ModelService, PersistenceService, and services.
4
+ * @module core/services
5
+ */
6
+ export * from "./ModelService";
7
+ export * from "./PersistenceService";
8
+ export * from "./services";
@@ -0,0 +1,96 @@
1
+ import type { AllOperationKeys, ContextFlags, EventIds, FlagsOf, ObserverFilter, PersistenceObservable, PersistenceObserver } from "../persistence/types";
2
+ import { Context } from "../persistence/Context";
3
+ import { ContextualArgs, ContextualizedArgs, ContextualLoggedClass, MaybeContextualArg, MethodOrOperation } from "../utils/ContextualLoggedClass";
4
+ import { Constructor } from "@decaf-ts/decoration";
5
+ import type { Observer } from "../interfaces/Observer";
6
+ import { ObserverHandler } from "../persistence/ObserverHandler";
7
+ export declare abstract class Service<C extends Context<ContextFlags<any>> = Context<ContextFlags<any>>> extends ContextualLoggedClass<C> implements PersistenceObservable<C>, PersistenceObserver<C> {
8
+ readonly name?: string | undefined;
9
+ protected observers: Observer[];
10
+ protected observerHandler?: ObserverHandler;
11
+ protected constructor(name?: string | undefined);
12
+ for(conf: any, ...args: any[]): this;
13
+ override(conf: any, ...args: any[]): this;
14
+ /**
15
+ * @description Registers an observer for this repository.
16
+ * @summary Adds an observer that will be notified of changes to models in this repository.
17
+ * @param {Observer} observer - The observer to register.
18
+ * @param {ObserverFilter} [filter] - Optional filter to limit which events the observer receives.
19
+ * @return {void}
20
+ * @see {Observable#observe}
21
+ */
22
+ observe(observer: Observer, filter?: ObserverFilter): () => void;
23
+ /**
24
+ * @description Unregisters an observer from this repository.
25
+ * @summary Removes an observer so it will no longer receive notifications of changes.
26
+ * @param {Observer} observer - The observer to unregister.
27
+ * @return {void}
28
+ * @throws {InternalError} If the observer handler is not initialized.
29
+ * @see {Observable#unObserve}
30
+ */
31
+ unObserve(observer: Observer): void;
32
+ /**
33
+ * @description Notifies all observers of an event.
34
+ * @summary Updates all registered observers with information about a database event.
35
+ * @param {string} table - The table name where the event occurred.
36
+ * @param {OperationKeys|BulkCrudOperationKeys|string} event - The type of event that occurred.
37
+ * @param {EventIds} id - The ID or IDs of the affected records.
38
+ * @param {...any[]} args - Additional arguments.
39
+ * @return {Promise<void>} A promise that resolves when all observers have been notified.
40
+ * @throws {InternalError} If the observer handler is not initialized.
41
+ */
42
+ updateObservers(table: Constructor<any> | string, event: AllOperationKeys, id: EventIds, ...args: ContextualArgs<C>): Promise<void>;
43
+ /**
44
+ * @description Creates repository flags for an operation
45
+ * @summary Generates a set of flags that describe a database operation, combining default flags with overrides
46
+ * @template F - The Repository Flags type
47
+ * @template M - The model type
48
+ * @param {OperationKeys} operation - The type of operation being performed
49
+ * @param {Partial<F>} flags - Custom flag overrides
50
+ * @param {...any[]} args - Additional arguments
51
+ * @return {Promise<F>} The complete set of flags
52
+ */
53
+ protected flags(operation: string, flags: Partial<FlagsOf<C>>, ...args: any[]): Promise<FlagsOf<C>>;
54
+ /**
55
+ * @description Alias for updateObservers.
56
+ * @summary Notifies all observers of an event (alias for updateObservers).
57
+ * @param {string} table - The table name where the event occurred.
58
+ * @param {OperationKeys|BulkCrudOperationKeys|string} event - The type of event that occurred.
59
+ * @param {EventIds} id - The ID or IDs of the affected records.
60
+ * @param {...any[]} args - Additional arguments.
61
+ * @return {Promise<void>} A promise that resolves when all observers have been notified.
62
+ */
63
+ refresh(table: Constructor<any> | string, event: AllOperationKeys, id: EventIds, ...args: ContextualArgs<C>): Promise<void>;
64
+ /**
65
+ * @description The context constructor for this adapter
66
+ * @summary Reference to the context class constructor used by this adapter
67
+ */
68
+ protected readonly Context: Constructor<C>;
69
+ context(operation: ((...args: any[]) => any) | string, overrides: Partial<FlagsOf<C>>, ...args: MaybeContextualArg<Context<any>>): Promise<C>;
70
+ protected logCtx<CONTEXT extends Context<any> = C, ARGS extends any[] = any[], METHOD extends MethodOrOperation = MethodOrOperation>(args: MaybeContextualArg<CONTEXT, ARGS>, operation: METHOD): ContextualizedArgs<CONTEXT, ARGS, METHOD extends string ? true : false>;
71
+ protected logCtx<CONTEXT extends Context<any> = C, ARGS extends any[] = any[], METHOD extends MethodOrOperation = MethodOrOperation>(args: MaybeContextualArg<CONTEXT, ARGS>, operation: METHOD, allowCreate: false, overrides?: Partial<FlagsOf<CONTEXT>>): ContextualizedArgs<CONTEXT, ARGS, METHOD extends string ? true : false>;
72
+ protected logCtx<CONTEXT extends Context<any> = C, ARGS extends any[] = any[], METHOD extends MethodOrOperation = MethodOrOperation>(args: MaybeContextualArg<CONTEXT, ARGS>, operation: METHOD, allowCreate: true, overrides?: Partial<FlagsOf<CONTEXT>>): Promise<ContextualizedArgs<CONTEXT, ARGS, METHOD extends string ? true : false>>;
73
+ /**
74
+ * @description Retrieves a Service instance by name/class
75
+ * @summary Looks up and returns a cached API instance by its name or constructor
76
+ * @template A Type extending Api
77
+ * @param {string | Constructor<A>} name - Name of the API or its constructor
78
+ * @return {A} The requested API instance
79
+ */
80
+ static get<A extends Service>(name: string | symbol | Constructor<A>): A;
81
+ static boot<C extends Context<any> = any>(...args: MaybeContextualArg<C>): Promise<void>;
82
+ static shutdown<C extends Context<any> = any>(...args: MaybeContextualArg<C>): Promise<void>;
83
+ }
84
+ export declare abstract class ClientBasedService<CLIENT, CONF, C extends Context<any> = any> extends Service {
85
+ protected _client?: CLIENT;
86
+ protected _config?: CONF;
87
+ protected constructor();
88
+ boot(...args: MaybeContextualArg<C>): Promise<void>;
89
+ abstract initialize(...args: ContextualArgs<C>): Promise<{
90
+ config: CONF;
91
+ client: CLIENT;
92
+ }>;
93
+ protected get config(): CONF;
94
+ get client(): CLIENT;
95
+ shutdown(...args: MaybeContextualArg<C>): Promise<void>;
96
+ }
@@ -0,0 +1,15 @@
1
+ import { TaskHandler } from "./TaskHandler";
2
+ import { TaskContext } from "./TaskContext";
3
+ import { type Repo } from "../repository/Repository";
4
+ import { TaskModel } from "./models/TaskModel";
5
+ import { Condition } from "../query/Condition";
6
+ export type CleanUpTaskInput = {
7
+ successfulExpiry: Date;
8
+ failedExpiry: Date;
9
+ cancelledExpiry: Date;
10
+ } | Condition<TaskModel>;
11
+ export declare class CleanUpTask extends TaskHandler<CleanUpTaskInput, TaskModel[]> {
12
+ protected tasks: Repo<TaskModel>;
13
+ constructor();
14
+ run(input: CleanUpTaskInput, ctx: TaskContext): Promise<TaskModel[]>;
15
+ }
@@ -0,0 +1,30 @@
1
+ import { Context } from "../persistence/Context";
2
+ import { TaskFlags } from "./types";
3
+ import { TaskLogger } from "./logging";
4
+ import { DateTarget } from "@decaf-ts/decorator-validation";
5
+ import { TaskErrorModel } from "./models/TaskErrorModel";
6
+ import { TaskStatus } from "./constants";
7
+ import { TaskStateChangeRequest } from "./TaskStateChangeError";
8
+ import { TaskStepSpecModel } from "./models/TaskStepSpecModel";
9
+ export declare class TaskContext extends Context<TaskFlags> {
10
+ get taskId(): string;
11
+ get logger(): TaskLogger<any>;
12
+ get step(): number | undefined;
13
+ setStep(step?: number): void;
14
+ get pipe(): TaskFlags["pipe"];
15
+ flush(): Promise<void>;
16
+ get attempt(): number;
17
+ get progress(): (data: any) => Promise<void>;
18
+ get heartbeat(): () => Promise<void>;
19
+ cacheResult(taskId: string, payload: any): void;
20
+ protected changeState(status: TaskStatus, payload?: Partial<TaskStateChangeRequest>): never;
21
+ cancel(reason?: string | Error | TaskErrorModel, details?: any): never;
22
+ retry(reason?: string | Error | TaskErrorModel): never;
23
+ reschedule(when: DateTarget, reason?: string | Error | TaskErrorModel): never;
24
+ private toTaskError;
25
+ get resultCache(): Record<string, any> | undefined;
26
+ scheduleSteps(...steps: (TaskStepSpecModel | Partial<TaskStepSpecModel>)[]): {
27
+ afterCurrent: () => Promise<void>;
28
+ };
29
+ constructor(ctx?: Context<any>);
30
+ }
@@ -0,0 +1,97 @@
1
+ import { TaskModel } from "./models/TaskModel";
2
+ import { Repo } from "../repository/Repository";
3
+ import { TaskEventModel } from "./models/TaskEventModel";
4
+ import { TaskHandlerRegistry } from "./TaskHandlerRegistry";
5
+ import { TaskEventBus } from "./TaskEventBus";
6
+ import { TaskStepResultModel } from "./models/TaskStepResultModel";
7
+ import { TaskLogEntryModel } from "./models/TaskLogEntryModel";
8
+ import { TaskBackoffModel } from "./models/TaskBackoffModel";
9
+ import { TaskStepSpecModel } from "./models/TaskStepSpecModel";
10
+ import { TaskEventType, TaskStatus } from "./constants";
11
+ import { Adapter } from "../persistence/Adapter";
12
+ import { Context } from "../persistence/Context";
13
+ import { ContextOf, FlagsOf } from "../persistence/types";
14
+ import { LogLevel } from "@decaf-ts/logging";
15
+ import { AbsContextual, ContextualArgs, MaybeContextualArg } from "../utils/ContextualLoggedClass";
16
+ import { OperationKeys } from "@decaf-ts/db-decorators";
17
+ import { TaskContext } from "./TaskContext";
18
+ import { TaskStateChangeRequest } from "./TaskStateChangeError";
19
+ import { DateTarget } from "@decaf-ts/decorator-validation";
20
+ import { Constructor } from "@decaf-ts/decoration";
21
+ import { TaskEngineConfig, TaskFlags } from "./types";
22
+ import { TaskTracker } from "./TaskTracker";
23
+ import { Lock } from "@decaf-ts/transactional-decorators";
24
+ type ParsedTaskDependency = {
25
+ taskId: string;
26
+ stepRef?: string;
27
+ };
28
+ export declare class TaskEngine<A extends Adapter<any, any, any, any>, C extends TaskEngineConfig<A> = TaskEngineConfig<A>> extends AbsContextual<ContextOf<A>> {
29
+ protected config: C;
30
+ private _tasks?;
31
+ private _events?;
32
+ private _adapter?;
33
+ protected lock: Lock;
34
+ protected get Context(): Constructor<ContextOf<A>>;
35
+ protected get adapter(): A;
36
+ protected get registry(): TaskHandlerRegistry;
37
+ protected get bus(): TaskEventBus;
38
+ protected get tasks(): Repo<TaskModel>;
39
+ protected get events(): Repo<TaskEventModel>;
40
+ protected running: boolean;
41
+ private idleDelayMs;
42
+ static createTaskContext(base?: Context<any>, overrides?: Partial<TaskFlags>): TaskContext;
43
+ constructor(config: C);
44
+ push<I, O>(task: TaskModel<I, O>, ...args: MaybeContextualArg<any>): Promise<TaskModel<I, O>>;
45
+ push<I, O>(task: TaskModel<I, O>, track: false, ...args: MaybeContextualArg<any>): Promise<TaskModel<I, O>>;
46
+ push<I, O>(task: TaskModel<I, O>, track: true, ...args: MaybeContextualArg<any>): Promise<{
47
+ task: TaskModel<I, O>;
48
+ tracker: TaskTracker<(typeof task)["output"]>;
49
+ }>;
50
+ schedule<I, O>(task: TaskModel<I, O>, ...args: MaybeContextualArg<any>): {
51
+ for: (when: DateTarget) => Promise<TaskModel<I, O>>;
52
+ };
53
+ schedule<I, O>(task: TaskModel<I, O>, track: false, ...args: MaybeContextualArg<any>): {
54
+ for: (when: DateTarget) => Promise<TaskModel<I, O>>;
55
+ };
56
+ schedule<I, O>(task: TaskModel<I, O>, track: true, ...args: MaybeContextualArg<any>): {
57
+ for: (when: DateTarget) => Promise<{
58
+ task: TaskModel<I, O>;
59
+ tracker: TaskTracker<O>;
60
+ }>;
61
+ };
62
+ track(id: string, ...args: MaybeContextualArg<any>): Promise<{
63
+ task: TaskModel<any, any>;
64
+ tracker: TaskTracker<any>;
65
+ }>;
66
+ protected ensureTaskError(task: TaskModel, ctx: Context): Promise<TaskModel>;
67
+ cancel(id: string, ...args: MaybeContextualArg<any>): Promise<TaskModel>;
68
+ isRunning(): Promise<boolean>;
69
+ start(...args: MaybeContextualArg<any>): Promise<void>;
70
+ stop(...args: MaybeContextualArg<any>): Promise<void>;
71
+ protected loop(...args: ContextualArgs<any>): Promise<void>;
72
+ protected claimBatch(ctx: Context<any>): Promise<TaskModel[]>;
73
+ protected tryClaim(task: TaskModel, ctx: Context): Promise<TaskModel | null>;
74
+ protected isTaskFinished(status?: TaskStatus): boolean;
75
+ protected parseTaskDependency(value: string): ParsedTaskDependency | undefined;
76
+ protected normalizeDependencies(deps: string[] | string | undefined): ParsedTaskDependency[];
77
+ protected resolveDependencyStepIndex(task: TaskModel, stepRef: string): number | undefined;
78
+ protected areDependenciesSatisfied(dependencies: ParsedTaskDependency[], ctx: Context): Promise<boolean>;
79
+ protected getStepLock(task: TaskModel, stepIndex: number | undefined): string | undefined;
80
+ protected hasLockConflict(task: TaskModel, stepIndex: number | undefined, ctx: Context): Promise<boolean>;
81
+ protected isRunnable(task: TaskModel, ctx: Context): Promise<boolean>;
82
+ protected executeClaimed(task: TaskModel): Promise<void>;
83
+ protected handleTaskStateChange(request: TaskStateChangeRequest, task: TaskModel, ctx: TaskContext): Promise<void>;
84
+ protected runComposite(task: TaskModel, context: TaskContext): Promise<any>;
85
+ protected normalizeBackoff(backoff: TaskBackoffModel | string | object | any): TaskBackoffModel;
86
+ protected normalizeSteps(steps: TaskStepSpecModel[] | string | undefined): TaskStepSpecModel[];
87
+ protected normalizeStepResults(results: TaskStepResultModel[] | string | undefined): TaskStepResultModel[];
88
+ protected appendLog(ctx: TaskContext | Context, task: TaskModel, logEntries: [LogLevel, string] | [LogLevel, string, any] | ([LogLevel, string] | [LogLevel, string, any])[]): Promise<[TaskModel, TaskLogEntryModel[]]>;
89
+ protected emitStatus(ctx: TaskContext | Context, task: TaskModel, status: TaskStatus, outputOrError?: any | Error, originalError?: Error): Promise<void>;
90
+ protected emitLog(ctx: TaskContext | Context, taskId: string, entries: TaskLogEntryModel[]): Promise<void>;
91
+ protected normalizePipeArgs(args: any[]): ([LogLevel, string] | [LogLevel, string, any])[];
92
+ protected emitProgress(ctx: TaskContext | Context, taskId: string, data: any): Promise<void>;
93
+ protected persistEvent(ctx: TaskContext | Context, taskId: string, type: TaskEventType, payload: any): Promise<TaskEventModel>;
94
+ toString(): string;
95
+ context(operation: ((...args: any[]) => any) | OperationKeys.CREATE | OperationKeys.READ | OperationKeys.UPDATE | OperationKeys.DELETE | string, overrides: Partial<FlagsOf<ContextOf<A>>>, ...args: any[]): Promise<ContextOf<A>>;
96
+ }
97
+ export {};
@@ -0,0 +1,65 @@
1
+ import { BaseError } from "@decaf-ts/db-decorators";
2
+ import { TaskErrorModel } from "./models/TaskErrorModel";
3
+ import { TaskStatus } from "./constants";
4
+ /**
5
+ * Represents the next action to take after a task error.
6
+ * Used to identify the appropriate response to task failures.
7
+ */
8
+ export type TaskNextAction = TaskStatus.CANCELED | TaskStatus.WAITING_RETRY | TaskStatus.SCHEDULED | TaskStatus.FAILED;
9
+ /**
10
+ * Additional properties added to errors from TaskTracker.resolve() and TaskTracker.wait()
11
+ */
12
+ export type TaskErrorProps = {
13
+ /** The next action to take in response to this error */
14
+ nextAction: TaskNextAction;
15
+ /** The task ID this error relates to (optional, present on TaskControlError) */
16
+ taskId?: string;
17
+ /** Additional error details (optional, present on TaskControlError) */
18
+ details?: TaskErrorModel;
19
+ /** Additional metadata (optional, present on TaskControlError) */
20
+ meta?: Record<string, any>;
21
+ };
22
+ /**
23
+ * Generic type that preserves the original error type while adding task-specific properties.
24
+ * Use this to type errors from TaskTracker.resolve() and TaskTracker.wait().
25
+ *
26
+ * The original error is preserved (e.g., ValidationError stays ValidationError),
27
+ * with the nextAction property added to identify the appropriate response:
28
+ * - `TaskStatus.CANCELED`: Task was explicitly canceled
29
+ * - `TaskStatus.SCHEDULED`: Task was rescheduled
30
+ * - `TaskStatus.WAITING_RETRY`: Task is waiting for retry
31
+ * - `TaskStatus.FAILED`: Task has permanently failed
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * try {
36
+ * await tracker.resolve();
37
+ * } catch (error: unknown) {
38
+ * if (isTaskError<ValidationError>(error, ValidationError)) {
39
+ * // error is typed as TaskErrorFrom<ValidationError>
40
+ * console.log(error.nextAction); // TaskNextAction
41
+ * console.log(error.code); // ValidationError's code property
42
+ * }
43
+ * }
44
+ * ```
45
+ */
46
+ export type TaskErrorFrom<E extends Error> = E & TaskErrorProps;
47
+ export declare function isTaskError<E extends Error = Error>(error: unknown, ErrorClass?: new (...args: any[]) => E): error is TaskErrorFrom<E>;
48
+ export declare class TaskControlError extends BaseError {
49
+ readonly taskId: string;
50
+ readonly details?: TaskErrorModel;
51
+ readonly meta?: Record<string, any>;
52
+ constructor(name: string, taskId: string, message: string, details?: TaskErrorModel, meta?: Record<string, any>, code?: number);
53
+ }
54
+ export declare class TaskFailError extends TaskControlError {
55
+ constructor(taskId: string, details?: TaskErrorModel, meta?: Record<string, any>);
56
+ }
57
+ export declare class TaskRetryError extends TaskControlError {
58
+ constructor(taskId: string, details?: TaskErrorModel, meta?: Record<string, any>);
59
+ }
60
+ export declare class TaskCancelError extends TaskControlError {
61
+ constructor(taskId: string, details?: TaskErrorModel, meta?: Record<string, any>);
62
+ }
63
+ export declare class TaskRescheduleError extends TaskControlError {
64
+ constructor(taskId: string, details?: TaskErrorModel, meta?: Record<string, any>);
65
+ }
@@ -0,0 +1,17 @@
1
+ import { TaskEventModel } from "./models/TaskEventModel";
2
+ import { Context } from "../persistence/Context";
3
+ import { ObserverHandler } from "../persistence/ObserverHandler";
4
+ import { EventIds, ObserverFilter } from "../persistence/types";
5
+ import { TaskContext } from "./TaskContext";
6
+ import { Observer } from "../interfaces/Observer";
7
+ import { Constructor } from "@decaf-ts/decoration";
8
+ import { BulkCrudOperationKeys, OperationKeys } from "@decaf-ts/db-decorators";
9
+ import { ContextualArgs } from "../utils/index";
10
+ import { Model } from "@decaf-ts/decorator-validation";
11
+ export declare class TaskEventBus extends ObserverHandler<TaskContext> {
12
+ protected readonly listeners: Set<(evt: TaskEventModel) => void>;
13
+ observe(observer: Observer, filter?: ObserverFilter): () => void;
14
+ unObserve(observer: Observer): void;
15
+ emit(evt: TaskEventModel, ctx: Context): void;
16
+ updateObservers<M extends Model>(model: Constructor<M> | string, event: OperationKeys | BulkCrudOperationKeys | string, id: EventIds, evt: TaskEventModel, ...args: ContextualArgs<any>): Promise<void>;
17
+ }
@@ -0,0 +1,7 @@
1
+ import { type Repo } from "../repository/Repository";
2
+ import { ModelService } from "../services/ModelService";
3
+ import { TaskEventModel } from "./models/TaskEventModel";
4
+ export declare class TaskEventService extends ModelService<TaskEventModel> {
5
+ constructor();
6
+ get repo(): Repo<TaskEventModel>;
7
+ }
@@ -0,0 +1,12 @@
1
+ import { ITaskHandler } from "./types";
2
+ import { AbsContextual, ContextualArgs } from "../utils/ContextualLoggedClass";
3
+ import { TaskContext } from "./TaskContext";
4
+ export declare abstract class TaskHandler<I, O> extends AbsContextual<TaskContext> implements ITaskHandler<I, O> {
5
+ private _type?;
6
+ get type(): string;
7
+ protected constructor();
8
+ protected runPrefix(input: I, ...args: ContextualArgs<TaskContext>): Promise<any[]>;
9
+ protected runSuffix(output: O, ctx: TaskContext): O;
10
+ catch(input: I, error: unknown, ctx: TaskContext): Promise<void>;
11
+ abstract run(input: I, ctx: TaskContext): Promise<O>;
12
+ }
@@ -0,0 +1,8 @@
1
+ import { ITaskHandler } from "./types";
2
+ export declare class TaskHandlerRegistry {
3
+ private readonly handlers;
4
+ constructor();
5
+ protected initialize(): void;
6
+ register(handler: ITaskHandler): void;
7
+ get(type: string): ITaskHandler | undefined;
8
+ }