| import { WorkflowState } from "./workflow"; | ||
| export declare class ComposableWorkflowStep<Input, Output> { | ||
| #private; | ||
| constructor(params: { | ||
| name: string; | ||
| handler: StepHandler<Input, Output>; | ||
| previousStep: PreviousStepHandler<Input>; | ||
| workflowState: WorkflowState<unknown>; | ||
| }); | ||
| addStep<NextOutput>(params: { | ||
| name: string; | ||
| handler: StepHandler<Output, NextOutput>; | ||
| }): ComposableWorkflowStep<Output, NextOutput>; | ||
| execute(repository?: Pick<WorkflowStateRepository, "save">): Promise<Output>; | ||
| results(): Map<string, unknown>; | ||
| status(): "IN_PROGRESS" | "FAILED" | "TODO" | "DONE"; | ||
| get name(): string; | ||
| } | ||
| export type StepHandler<Input, Output> = (input: Input) => Promise<Output>; | ||
| type PreviousStepHandler<Output> = () => Promise<Output>; | ||
| export interface WorkflowStateRepository { | ||
| save: (state: WorkflowState<unknown>) => Promise<void>; | ||
| getById: (id: string) => Promise<WorkflowState<unknown> | undefined>; | ||
| } | ||
| export {}; | ||
| //# sourceMappingURL=composableWorkflowStep.d.ts.map |
| {"version":3,"file":"composableWorkflowStep.d.ts","sourceRoot":"","sources":["../../src/workflows/composableWorkflowStep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,qBAAa,sBAAsB,CAAC,KAAK,EAAE,MAAM;;gBAOnC,MAAM,EAAE;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACpC,YAAY,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACzC,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;KACvC;IASD,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE;QAC1B,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;KAC1C,GAAG,sBAAsB,CAAC,MAAM,EAAE,UAAU,CAAC;IAaxC,OAAO,CACX,UAAU,CAAC,EAAE,IAAI,CAAC,uBAAuB,EAAE,MAAM,CAAC,GACjD,OAAO,CAAC,MAAM,CAAC;IAgElB,OAAO,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAI/B,MAAM;IAIN,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAED,MAAM,MAAM,WAAW,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE3E,KAAK,mBAAmB,CAAC,MAAM,IAAI,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC;CACtE"} |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.ComposableWorkflowStep = void 0; | ||
| class ComposableWorkflowStep { | ||
| #name; | ||
| #handler; | ||
| #previousStep; | ||
| #workflowState; | ||
| #isLast; | ||
| constructor(params) { | ||
| const { name, handler, previousStep, workflowState } = params; | ||
| this.#name = name; | ||
| this.#handler = handler; | ||
| this.#previousStep = previousStep; | ||
| this.#workflowState = workflowState; | ||
| this.#isLast = true; | ||
| } | ||
| addStep(params) { | ||
| const { name, handler } = params; | ||
| this.#isLast = false; | ||
| return new ComposableWorkflowStep({ | ||
| name, | ||
| handler, | ||
| previousStep: () => this.execute(), | ||
| workflowState: this.#workflowState, | ||
| }); | ||
| } | ||
| async execute(repository) { | ||
| this.#workflowState.status = "IN_PROGRESS"; | ||
| // Save initial state | ||
| if (repository) { | ||
| await repository.save(this.#workflowState); | ||
| } | ||
| let result = this.#workflowState.stepResults.get(this.#name); | ||
| if (result !== undefined) { | ||
| return result; | ||
| } | ||
| const input = await this.#previousStep(); | ||
| try { | ||
| const output = await this.#handler(input); | ||
| this.#workflowState.stepResults.set(this.#name, output); | ||
| if (this.#isLast) { | ||
| this.#workflowState.status = "DONE"; | ||
| } | ||
| return output; | ||
| } | ||
| catch (err) { | ||
| const error = this.#handleError(err); | ||
| throw error; | ||
| } | ||
| finally { | ||
| // Save state from either a success or a failure | ||
| if (repository) { | ||
| await repository.save(this.#workflowState); | ||
| } | ||
| } | ||
| } | ||
| #handleError(err) { | ||
| let message = "unknown error"; | ||
| let name = "Unknown Error"; | ||
| if (err instanceof Error) { | ||
| message = err.message; | ||
| name = err.name; | ||
| } | ||
| const error = new Error(`Step: ${this.#name} failed with: ${name} ${message}`, { | ||
| cause: err, | ||
| }); | ||
| this.#workflowState.status = "FAILED"; | ||
| this.#workflowState.error = { | ||
| step: this.#name, | ||
| error: error.message, | ||
| name: error.name, | ||
| }; | ||
| return error; | ||
| } | ||
| results() { | ||
| return this.#workflowState.stepResults; | ||
| } | ||
| status() { | ||
| return this.#workflowState.status; | ||
| } | ||
| get name() { | ||
| return this.#workflowState.name; | ||
| } | ||
| } | ||
| exports.ComposableWorkflowStep = ComposableWorkflowStep; | ||
| //# sourceMappingURL=composableWorkflowStep.js.map |
| {"version":3,"file":"composableWorkflowStep.js","sourceRoot":"","sources":["../../src/workflows/composableWorkflowStep.ts"],"names":[],"mappings":"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"} |
| export { WorkflowBuilder, type WorkflowStep } from "./workflow"; | ||
| export { InMemoryWorkflowStateRepository } from "./repository/inMemoryWorkflowStateRepository"; | ||
| export type { WorkflowStateRepository } from "./composableWorkflowStep"; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workflows/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,+BAA+B,EAAE,MAAM,8CAA8C,CAAC;AAC/F,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC"} |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.InMemoryWorkflowStateRepository = exports.WorkflowBuilder = void 0; | ||
| var workflow_1 = require("./workflow"); | ||
| Object.defineProperty(exports, "WorkflowBuilder", { enumerable: true, get: function () { return workflow_1.WorkflowBuilder; } }); | ||
| var inMemoryWorkflowStateRepository_1 = require("./repository/inMemoryWorkflowStateRepository"); | ||
| Object.defineProperty(exports, "InMemoryWorkflowStateRepository", { enumerable: true, get: function () { return inMemoryWorkflowStateRepository_1.InMemoryWorkflowStateRepository; } }); | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workflows/index.ts"],"names":[],"mappings":";;;AAAA,uCAAgE;AAAvD,2GAAA,eAAe,OAAA;AACxB,gGAA+F;AAAtF,kJAAA,+BAA+B,OAAA"} |
| import { WorkflowStateRepository } from "../composableWorkflowStep"; | ||
| import { WorkflowState } from "../workflow"; | ||
| export declare class InMemoryWorkflowStateRepository implements WorkflowStateRepository { | ||
| #private; | ||
| constructor(); | ||
| save(state: WorkflowState<unknown>): Promise<void>; | ||
| getById(id: string): Promise<WorkflowState<unknown> | undefined>; | ||
| } | ||
| //# sourceMappingURL=inMemoryWorkflowStateRepository.d.ts.map |
| {"version":3,"file":"inMemoryWorkflowStateRepository.d.ts","sourceRoot":"","sources":["../../../src/workflows/repository/inMemoryWorkflowStateRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,qBAAa,+BACX,YAAW,uBAAuB;;;IAQ5B,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;CAIvE"} |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.InMemoryWorkflowStateRepository = void 0; | ||
| class InMemoryWorkflowStateRepository { | ||
| #states; | ||
| constructor() { | ||
| this.#states = new Map(); | ||
| } | ||
| async save(state) { | ||
| this.#states.set(state.id, structuredClone(state)); | ||
| } | ||
| async getById(id) { | ||
| const state = this.#states.get(id); | ||
| return state ? structuredClone(state) : undefined; | ||
| } | ||
| } | ||
| exports.InMemoryWorkflowStateRepository = InMemoryWorkflowStateRepository; | ||
| //# sourceMappingURL=inMemoryWorkflowStateRepository.js.map |
| {"version":3,"file":"inMemoryWorkflowStateRepository.js","sourceRoot":"","sources":["../../../src/workflows/repository/inMemoryWorkflowStateRepository.ts"],"names":[],"mappings":";;;AAGA,MAAa,+BAA+B;IAG1C,OAAO,CAAsC;IAE7C;QACE,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAkC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAA6B;QACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpD,CAAC;CACF;AAjBD,0EAiBC"} |
| import { ComposableWorkflowStep, StepHandler } from "./composableWorkflowStep"; | ||
| export interface WorkflowState<Input> { | ||
| id: string; | ||
| name: string; | ||
| input: Input; | ||
| stepResults: Map<string, unknown>; | ||
| error: { | ||
| step: string; | ||
| error: string; | ||
| name: string; | ||
| } | undefined; | ||
| status: "TODO" | "IN_PROGRESS" | "FAILED" | "DONE"; | ||
| } | ||
| export declare class WorkflowBuilder<Input> { | ||
| #private; | ||
| constructor(params: { | ||
| id: string; | ||
| name: string; | ||
| input: Input; | ||
| stepResult?: Map<string, unknown>; | ||
| }); | ||
| addStep<Output>(step: WorkflowStep<Input, Output>): ComposableWorkflowStep<Input, Output>; | ||
| get name(): string; | ||
| } | ||
| export interface WorkflowStep<Input, Output> { | ||
| name: string; | ||
| handler: StepHandler<Input, Output>; | ||
| } | ||
| //# sourceMappingURL=workflow.d.ts.map |
| {"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/workflows/workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE/E,MAAM,WAAW,aAAa,CAAC,KAAK;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACjE,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAC;CACpD;AAED,qBAAa,eAAe,CAAC,KAAK;;gBAGpB,MAAM,EAAE;QAClB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,KAAK,CAAC;QACb,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC;IAeD,OAAO,CAAC,MAAM,EACZ,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,GAChC,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC;IASxC,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAED,MAAM,WAAW,YAAY,CAAC,KAAK,EAAE,MAAM;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;CACrC"} |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.WorkflowBuilder = void 0; | ||
| const composableWorkflowStep_1 = require("./composableWorkflowStep"); | ||
| class WorkflowBuilder { | ||
| #state; | ||
| constructor(params) { | ||
| const state = { | ||
| status: "TODO", | ||
| name: params.name, | ||
| id: params.id, | ||
| input: params.input, | ||
| stepResults: params.stepResult | ||
| ? params.stepResult | ||
| : new Map(), | ||
| error: undefined, | ||
| }; | ||
| this.#state = state; | ||
| } | ||
| addStep(step) { | ||
| return new composableWorkflowStep_1.ComposableWorkflowStep({ | ||
| name: step.name, | ||
| handler: step.handler, | ||
| workflowState: this.#state, | ||
| previousStep: async () => await Promise.resolve(this.#state.input), | ||
| }); | ||
| } | ||
| get name() { | ||
| return this.#state.name; | ||
| } | ||
| } | ||
| exports.WorkflowBuilder = WorkflowBuilder; | ||
| //# sourceMappingURL=workflow.js.map |
| {"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/workflows/workflow.ts"],"names":[],"mappings":";;;AAAA,qEAA+E;AAW/E,MAAa,eAAe;IAC1B,MAAM,CAAuB;IAE7B,YAAY,MAKX;QACC,MAAM,KAAK,GAAyB;YAClC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,WAAW,EAAE,MAAM,CAAC,UAAU;gBAC5B,CAAC,CAAC,MAAM,CAAC,UAAU;gBACnB,CAAC,CAAC,IAAI,GAAG,EAAmB;YAC9B,KAAK,EAAE,SAAS;SACjB,CAAC;QAEF,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,OAAO,CACL,IAAiC;QAEjC,OAAO,IAAI,+CAAsB,CAAC;YAChC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,aAAa,EAAE,IAAI,CAAC,MAAM;YAC1B,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;SACnE,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAC1B,CAAC;CACF;AArCD,0CAqCC"} |
+3
-2
| { | ||
| "name": "ontologic", | ||
| "version": "1.3.0", | ||
| "version": "1.4.0", | ||
| "description": "", | ||
@@ -30,4 +30,5 @@ "main": "dist/index.js", | ||
| "build": "tsc", | ||
| "build:release": "tsc --project tsconfig-release.json" | ||
| "build:release": "tsc --project tsconfig-release.json", | ||
| "example:sepa": "npx tsx src/examples/workflows/sepaPayment.ts" | ||
| } | ||
| } |
+11
-1
@@ -26,9 +26,19 @@ # Ontologic | ||
| - **Event Bus** — Types event bus that allows to publish and listen to your domain events | ||
| - **Message Relay** — Built-in Outbox Pattern with in-memory component for fast prototyping | ||
| - **Workflows** — Typed, resumable pipelines for multi-step business processes | ||
| ## Examples | ||
| A complete example (entity, invariants, events, use cases) is in the [`examples/`](https://github.com/SachaCR/ontologic/tree/main/examples) directory — a credit balance aggregate with creation, credit, debit, and error handling. | ||
| ### Library Management App | ||
| A full-featured library management application built with NestJS, demonstrating all Ontologic features on a real-world use case: | ||
| **[sachacr/library-examples](https://github.com/sachacr/library-examples)** | ||
| ### Smaller examples | ||
| Focused examples (entity, invariants, events, use cases) are in the [`examples/`](https://github.com/SachaCR/ontologic/tree/main/examples) directory — a credit balance aggregate and an order lifecycle. | ||
| ## License | ||
| MIT |
109185
15.66%139
13.01%1471
16.28%44
29.41%