@auto-engineer/pipeline 1.65.0 → 1.67.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +6 -6
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +135 -0
- package/dist/src/builder/define-v2.d.ts +101 -0
- package/dist/src/builder/define-v2.d.ts.map +1 -0
- package/dist/src/builder/define-v2.js +209 -0
- package/dist/src/builder/define-v2.js.map +1 -0
- package/dist/src/engine/command-dispatcher.d.ts +31 -0
- package/dist/src/engine/command-dispatcher.d.ts.map +1 -0
- package/dist/src/engine/command-dispatcher.js +26 -0
- package/dist/src/engine/command-dispatcher.js.map +1 -0
- package/dist/src/engine/event-router.d.ts +21 -0
- package/dist/src/engine/event-router.d.ts.map +1 -0
- package/dist/src/engine/event-router.js +22 -0
- package/dist/src/engine/event-router.js.map +1 -0
- package/dist/src/engine/index.d.ts +15 -0
- package/dist/src/engine/index.d.ts.map +1 -0
- package/dist/src/engine/index.js +15 -0
- package/dist/src/engine/index.js.map +1 -0
- package/dist/src/engine/pipeline-engine.d.ts +37 -0
- package/dist/src/engine/pipeline-engine.d.ts.map +1 -0
- package/dist/src/engine/pipeline-engine.js +53 -0
- package/dist/src/engine/pipeline-engine.js.map +1 -0
- package/dist/src/engine/projections/item-status.d.ts +9 -0
- package/dist/src/engine/projections/item-status.d.ts.map +1 -0
- package/dist/src/engine/projections/item-status.js +9 -0
- package/dist/src/engine/projections/item-status.js.map +1 -0
- package/dist/src/engine/projections/latest-run.d.ts +9 -0
- package/dist/src/engine/projections/latest-run.d.ts.map +1 -0
- package/dist/src/engine/projections/latest-run.js +9 -0
- package/dist/src/engine/projections/latest-run.js.map +1 -0
- package/dist/src/engine/projections/message-log.d.ts +9 -0
- package/dist/src/engine/projections/message-log.d.ts.map +1 -0
- package/dist/src/engine/projections/message-log.js +10 -0
- package/dist/src/engine/projections/message-log.js.map +1 -0
- package/dist/src/engine/projections/node-status.d.ts +9 -0
- package/dist/src/engine/projections/node-status.d.ts.map +1 -0
- package/dist/src/engine/projections/node-status.js +9 -0
- package/dist/src/engine/projections/node-status.js.map +1 -0
- package/dist/src/engine/projections/stats.d.ts +9 -0
- package/dist/src/engine/projections/stats.d.ts.map +1 -0
- package/dist/src/engine/projections/stats.js +9 -0
- package/dist/src/engine/projections/stats.js.map +1 -0
- package/dist/src/engine/sqlite-consumer.d.ts +11 -0
- package/dist/src/engine/sqlite-consumer.d.ts.map +1 -0
- package/dist/src/engine/sqlite-consumer.js +27 -0
- package/dist/src/engine/sqlite-consumer.js.map +1 -0
- package/dist/src/engine/sqlite-store.d.ts +10 -0
- package/dist/src/engine/sqlite-store.d.ts.map +1 -0
- package/dist/src/engine/sqlite-store.js +14 -0
- package/dist/src/engine/sqlite-store.js.map +1 -0
- package/dist/src/engine/workflow-processor.d.ts +20 -0
- package/dist/src/engine/workflow-processor.d.ts.map +1 -0
- package/dist/src/engine/workflow-processor.js +36 -0
- package/dist/src/engine/workflow-processor.js.map +1 -0
- package/dist/src/engine/workflows/await-workflow.d.ts +33 -0
- package/dist/src/engine/workflows/await-workflow.d.ts.map +1 -0
- package/dist/src/engine/workflows/await-workflow.js +45 -0
- package/dist/src/engine/workflows/await-workflow.js.map +1 -0
- package/dist/src/engine/workflows/phased-workflow.d.ts +64 -0
- package/dist/src/engine/workflows/phased-workflow.d.ts.map +1 -0
- package/dist/src/engine/workflows/phased-workflow.js +103 -0
- package/dist/src/engine/workflows/phased-workflow.js.map +1 -0
- package/dist/src/engine/workflows/settled-workflow.d.ts +62 -0
- package/dist/src/engine/workflows/settled-workflow.d.ts.map +1 -0
- package/dist/src/engine/workflows/settled-workflow.js +92 -0
- package/dist/src/engine/workflows/settled-workflow.js.map +1 -0
- package/dist/src/graph/types.d.ts +1 -1
- package/dist/src/graph/types.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/server/pipeline-server-v2.d.ts +48 -0
- package/dist/src/server/pipeline-server-v2.d.ts.map +1 -0
- package/dist/src/server/pipeline-server-v2.js +61 -0
- package/dist/src/server/pipeline-server-v2.js.map +1 -0
- package/dist/src/server/pipeline-server.d.ts +5 -1
- package/dist/src/server/pipeline-server.d.ts.map +1 -1
- package/dist/src/server/pipeline-server.js +71 -10
- package/dist/src/server/pipeline-server.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/ketchup-plan.md +13 -0
- package/package.json +3 -3
- package/src/builder/define-v2.specs.ts +236 -0
- package/src/builder/define-v2.ts +351 -0
- package/src/engine/command-dispatcher.specs.ts +62 -0
- package/src/engine/command-dispatcher.ts +46 -0
- package/src/engine/event-router.specs.ts +75 -0
- package/src/engine/event-router.ts +36 -0
- package/src/engine/index.ts +39 -0
- package/src/engine/pipeline-engine-e2e.specs.ts +776 -0
- package/src/engine/pipeline-engine.integration.specs.ts +126 -0
- package/src/engine/pipeline-engine.specs.ts +70 -0
- package/src/engine/pipeline-engine.ts +82 -0
- package/src/engine/projections/item-status.ts +11 -0
- package/src/engine/projections/latest-run.ts +10 -0
- package/src/engine/projections/message-log.ts +11 -0
- package/src/engine/projections/node-status.ts +10 -0
- package/src/engine/projections/projections.specs.ts +176 -0
- package/src/engine/projections/stats.ts +10 -0
- package/src/engine/sqlite-consumer.specs.ts +42 -0
- package/src/engine/sqlite-consumer.ts +34 -0
- package/src/engine/sqlite-store.specs.ts +46 -0
- package/src/engine/sqlite-store.ts +21 -0
- package/src/engine/workflow-processor.specs.ts +37 -0
- package/src/engine/workflow-processor.ts +57 -0
- package/src/engine/workflows/await-workflow.specs.ts +104 -0
- package/src/engine/workflows/await-workflow.ts +66 -0
- package/src/engine/workflows/phased-workflow.specs.ts +383 -0
- package/src/engine/workflows/phased-workflow.ts +153 -0
- package/src/engine/workflows/settled-workflow.specs.ts +364 -0
- package/src/engine/workflows/settled-workflow.ts +139 -0
- package/src/graph/types.ts +1 -1
- package/src/index.ts +2 -0
- package/src/server/pipeline-server-v2.specs.ts +91 -0
- package/src/server/pipeline-server-v2.ts +70 -0
- package/src/server/pipeline-server.specs.ts +327 -134
- package/src/server/pipeline-server.ts +77 -11
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SQLiteEventStore } from '@event-driven-io/emmett-sqlite';
|
|
2
|
+
|
|
3
|
+
type CommandHandler = (command: {
|
|
4
|
+
type: string;
|
|
5
|
+
data: Record<string, unknown>;
|
|
6
|
+
}) =>
|
|
7
|
+
| Array<{ type: string; data: Record<string, unknown> }>
|
|
8
|
+
| Promise<Array<{ type: string; data: Record<string, unknown> }>>;
|
|
9
|
+
|
|
10
|
+
export function createCommandDispatcher() {
|
|
11
|
+
const handlers = new Map<string, CommandHandler>();
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
register(commandType: string, handler: CommandHandler): void {
|
|
15
|
+
handlers.set(commandType, handler);
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
registeredTypes(): string[] {
|
|
19
|
+
return [...handlers.keys()];
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
async dispatch(command: {
|
|
23
|
+
type: string;
|
|
24
|
+
data: Record<string, unknown>;
|
|
25
|
+
}): Promise<Array<{ type: string; data: Record<string, unknown> }>> {
|
|
26
|
+
const handler = handlers.get(command.type);
|
|
27
|
+
if (!handler) {
|
|
28
|
+
throw new Error(`No handler registered for command type: ${command.type}`);
|
|
29
|
+
}
|
|
30
|
+
return handler(command);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function dispatchAndStore(
|
|
36
|
+
dispatcher: ReturnType<typeof createCommandDispatcher>,
|
|
37
|
+
eventStore: SQLiteEventStore,
|
|
38
|
+
streamName: string,
|
|
39
|
+
command: { type: string; data: Record<string, unknown> },
|
|
40
|
+
): Promise<Array<{ type: string; data: Record<string, unknown> }>> {
|
|
41
|
+
const results = await dispatcher.dispatch(command);
|
|
42
|
+
if (results.length > 0) {
|
|
43
|
+
await eventStore.appendToStream(streamName, results);
|
|
44
|
+
}
|
|
45
|
+
return results;
|
|
46
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createCommandDispatcher } from './command-dispatcher.js';
|
|
2
|
+
import { createEventRouter } from './event-router.js';
|
|
3
|
+
|
|
4
|
+
describe('EventRouter', () => {
|
|
5
|
+
it('dispatches commands when matching event is routed', async () => {
|
|
6
|
+
const dispatcher = createCommandDispatcher();
|
|
7
|
+
const dispatched: Array<{ type: string; data: Record<string, unknown> }> = [];
|
|
8
|
+
dispatcher.register('ProcessPayment', (cmd) => {
|
|
9
|
+
dispatched.push(cmd);
|
|
10
|
+
return [{ type: 'PaymentProcessed', data: { amount: cmd.data.amount } }];
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const router = createEventRouter(dispatcher);
|
|
14
|
+
router.register({
|
|
15
|
+
eventType: 'OrderCreated',
|
|
16
|
+
commands: [{ commandType: 'ProcessPayment', data: { amount: 100 } }],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const results = await router.route({ type: 'OrderCreated', data: { orderId: '1' } });
|
|
20
|
+
|
|
21
|
+
expect(dispatched).toEqual([{ type: 'ProcessPayment', data: { amount: 100 } }]);
|
|
22
|
+
expect(results).toEqual([{ type: 'PaymentProcessed', data: { amount: 100 } }]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('dispatches multiple commands for single event', async () => {
|
|
26
|
+
const dispatcher = createCommandDispatcher();
|
|
27
|
+
dispatcher.register('ProcessPayment', () => [{ type: 'PaymentProcessed', data: {} }]);
|
|
28
|
+
dispatcher.register('SendEmail', () => [{ type: 'EmailSent', data: {} }]);
|
|
29
|
+
|
|
30
|
+
const router = createEventRouter(dispatcher);
|
|
31
|
+
router.register({
|
|
32
|
+
eventType: 'OrderCreated',
|
|
33
|
+
commands: [
|
|
34
|
+
{ commandType: 'ProcessPayment', data: { amount: 100 } },
|
|
35
|
+
{ commandType: 'SendEmail', data: { template: 'order' } },
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const results = await router.route({ type: 'OrderCreated', data: {} });
|
|
40
|
+
|
|
41
|
+
expect(results).toEqual([
|
|
42
|
+
{ type: 'PaymentProcessed', data: {} },
|
|
43
|
+
{ type: 'EmailSent', data: {} },
|
|
44
|
+
]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('returns empty array for unregistered event type', async () => {
|
|
48
|
+
const dispatcher = createCommandDispatcher();
|
|
49
|
+
const router = createEventRouter(dispatcher);
|
|
50
|
+
|
|
51
|
+
const results = await router.route({ type: 'Unknown', data: {} });
|
|
52
|
+
|
|
53
|
+
expect(results).toEqual([]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('resolves factory data functions with the event', async () => {
|
|
57
|
+
const dispatcher = createCommandDispatcher();
|
|
58
|
+
dispatcher.register('ProcessPayment', (cmd) => [{ type: 'Processed', data: cmd.data }]);
|
|
59
|
+
|
|
60
|
+
const router = createEventRouter(dispatcher);
|
|
61
|
+
router.register({
|
|
62
|
+
eventType: 'OrderCreated',
|
|
63
|
+
commands: [
|
|
64
|
+
{
|
|
65
|
+
commandType: 'ProcessPayment',
|
|
66
|
+
data: (event) => ({ orderId: event.data.orderId }),
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const results = await router.route({ type: 'OrderCreated', data: { orderId: '42' } });
|
|
72
|
+
|
|
73
|
+
expect(results).toEqual([{ type: 'Processed', data: { orderId: '42' } }]);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { createCommandDispatcher } from './command-dispatcher.js';
|
|
2
|
+
|
|
3
|
+
type Event = { type: string; data: Record<string, unknown> };
|
|
4
|
+
|
|
5
|
+
type EmitMapping = {
|
|
6
|
+
eventType: string;
|
|
7
|
+
commands: Array<{
|
|
8
|
+
commandType: string;
|
|
9
|
+
data: Record<string, unknown> | ((event: Event) => Record<string, unknown>);
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function createEventRouter(dispatcher: ReturnType<typeof createCommandDispatcher>) {
|
|
14
|
+
const mappings = new Map<string, EmitMapping['commands']>();
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
register(mapping: EmitMapping): void {
|
|
18
|
+
const existing = mappings.get(mapping.eventType) ?? [];
|
|
19
|
+
mappings.set(mapping.eventType, [...existing, ...mapping.commands]);
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
async route(event: Event): Promise<Array<{ type: string; data: Record<string, unknown> }>> {
|
|
23
|
+
const commands = mappings.get(event.type);
|
|
24
|
+
if (!commands) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const commandPromises = commands.map((command) => {
|
|
29
|
+
const data = typeof command.data === 'function' ? command.data(event) : command.data;
|
|
30
|
+
return dispatcher.dispatch({ type: command.commandType, data });
|
|
31
|
+
});
|
|
32
|
+
const resultArrays = await Promise.all(commandPromises);
|
|
33
|
+
return resultArrays.flat();
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export { createCommandDispatcher, dispatchAndStore } from './command-dispatcher';
|
|
2
|
+
export { createEventRouter } from './event-router';
|
|
3
|
+
export { createPipelineEngine } from './pipeline-engine';
|
|
4
|
+
export { itemStatusProjection } from './projections/item-status';
|
|
5
|
+
export { latestRunProjection } from './projections/latest-run';
|
|
6
|
+
export { messageLogProjection } from './projections/message-log';
|
|
7
|
+
export { nodeStatusProjection } from './projections/node-status';
|
|
8
|
+
export { statsProjection } from './projections/stats';
|
|
9
|
+
export { createConsumer } from './sqlite-consumer';
|
|
10
|
+
export { createPipelineStore, type PipelineStore } from './sqlite-store';
|
|
11
|
+
export { createWorkflowProcessor, type WorkflowRegistration } from './workflow-processor';
|
|
12
|
+
export {
|
|
13
|
+
type AwaitInput,
|
|
14
|
+
type AwaitOutput,
|
|
15
|
+
type AwaitState,
|
|
16
|
+
createAwaitWorkflow,
|
|
17
|
+
decide as awaitDecide,
|
|
18
|
+
evolve as awaitEvolve,
|
|
19
|
+
initialState as awaitInitialState,
|
|
20
|
+
} from './workflows/await-workflow';
|
|
21
|
+
export {
|
|
22
|
+
createPhasedWorkflow,
|
|
23
|
+
decide as phasedDecide,
|
|
24
|
+
evolve as phasedEvolve,
|
|
25
|
+
initialState as phasedInitialState,
|
|
26
|
+
type PhasedInput,
|
|
27
|
+
type PhasedItem,
|
|
28
|
+
type PhasedOutput,
|
|
29
|
+
type PhasedState,
|
|
30
|
+
} from './workflows/phased-workflow';
|
|
31
|
+
export {
|
|
32
|
+
createSettledWorkflow,
|
|
33
|
+
decide as settledDecide,
|
|
34
|
+
evolve as settledEvolve,
|
|
35
|
+
initialState as settledInitialState,
|
|
36
|
+
type SettledInput,
|
|
37
|
+
type SettledOutput,
|
|
38
|
+
type SettledState,
|
|
39
|
+
} from './workflows/settled-workflow';
|