@auto-engineer/pipeline 1.97.0 → 1.97.2

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/package.json CHANGED
@@ -4,8 +4,9 @@
4
4
  "main": "./dist/src/index.js",
5
5
  "types": "./dist/src/index.d.ts",
6
6
  "dependencies": {
7
- "@event-driven-io/emmett": "^0.38.2",
8
- "@event-driven-io/emmett-sqlite": "^0.38.5",
7
+ "@event-driven-io/dumbo": "0.13.0-beta.31",
8
+ "@event-driven-io/emmett": "0.43.0-beta.5",
9
+ "@event-driven-io/emmett-sqlite": "0.43.0-beta.5",
9
10
  "chokidar": "^3.6.0",
10
11
  "cors": "^2.8.5",
11
12
  "dotenv": "^16.4.5",
@@ -13,8 +14,8 @@
13
14
  "get-port": "^7.1.0",
14
15
  "jose": "^5.9.6",
15
16
  "nanoid": "^5.0.0",
16
- "@auto-engineer/file-store": "1.97.0",
17
- "@auto-engineer/message-bus": "1.97.0"
17
+ "@auto-engineer/message-bus": "1.97.2",
18
+ "@auto-engineer/file-store": "1.97.2"
18
19
  },
19
20
  "devDependencies": {
20
21
  "@types/cors": "^2.8.17",
@@ -23,7 +24,7 @@
23
24
  "publishConfig": {
24
25
  "access": "public"
25
26
  },
26
- "version": "1.97.0",
27
+ "version": "1.97.2",
27
28
  "scripts": {
28
29
  "build": "tsc && tsx ../../scripts/fix-esm-imports.ts",
29
30
  "test": "vitest run --reporter=dot",
@@ -1,4 +1,6 @@
1
- import { readMessagesBatch, sqliteConnection } from '@event-driven-io/emmett-sqlite';
1
+ import { dumbo } from '@event-driven-io/dumbo';
2
+ import { sqlite3DumboDriver } from '@event-driven-io/dumbo/sqlite3';
3
+ import { readMessagesBatch } from '@event-driven-io/emmett-sqlite';
2
4
  import type { PipelineStore } from './sqlite-store.js';
3
5
 
4
6
  type EventHandler = (event: { type: string; data: Record<string, unknown> }) => void;
@@ -6,7 +8,7 @@ type EventHandler = (event: { type: string; data: Record<string, unknown> }) =>
6
8
  export function createConsumer(store: PipelineStore) {
7
9
  const handlers = new Map<string, EventHandler>();
8
10
  let lastPosition = 0n;
9
- const connection = sqliteConnection({ fileName: store.fileName });
11
+ const pool = dumbo({ driver: sqlite3DumboDriver, fileName: store.fileName });
10
12
 
11
13
  return {
12
14
  on(eventType: string, handler: EventHandler): void {
@@ -14,7 +16,7 @@ export function createConsumer(store: PipelineStore) {
14
16
  },
15
17
 
16
18
  async poll(): Promise<void> {
17
- const { messages, currentGlobalPosition } = await readMessagesBatch(connection, {
19
+ const { messages, currentGlobalPosition } = await readMessagesBatch(pool.execute, {
18
20
  after: lastPosition,
19
21
  batchSize: 1000,
20
22
  });
@@ -1,4 +1,5 @@
1
1
  import { getSQLiteEventStore, type SQLiteEventStore } from '@event-driven-io/emmett-sqlite';
2
+ import { sqlite3EventStoreDriver } from '@event-driven-io/emmett-sqlite/sqlite3';
2
3
 
3
4
  export interface PipelineStore {
4
5
  eventStore: SQLiteEventStore;
@@ -9,6 +10,7 @@ export interface PipelineStore {
9
10
  export async function createPipelineStore(options?: { fileName?: string }): Promise<PipelineStore> {
10
11
  const fileName = options?.fileName ?? 'file::memory:?cache=shared';
11
12
  const eventStore = getSQLiteEventStore({
13
+ driver: sqlite3EventStoreDriver,
12
14
  fileName,
13
15
  schema: { autoMigration: 'CreateOrUpdate' },
14
16
  });
@@ -1,7 +1,9 @@
1
1
  import fs from 'node:fs';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
- import { readMessagesBatch, sqliteConnection } from '@event-driven-io/emmett-sqlite';
4
+ import { dumbo } from '@event-driven-io/dumbo';
5
+ import { sqlite3DumboDriver } from '@event-driven-io/dumbo/sqlite3';
6
+ import { readMessagesBatch } from '@event-driven-io/emmett-sqlite';
5
7
  import { nanoid } from 'nanoid';
6
8
  import { define } from '../builder/define';
7
9
  import { PipelineServer } from './pipeline-server';
@@ -2376,16 +2378,15 @@ describe('PipelineServer', () => {
2376
2378
  await new Promise((r) => setTimeout(r, 200));
2377
2379
  await server.stop();
2378
2380
 
2379
- const connection = sqliteConnection({ fileName: tmpFile });
2380
- const { messages } = await readMessagesBatch(connection, {
2381
+ const pool = dumbo({ driver: sqlite3DumboDriver, fileName: tmpFile });
2382
+ const { messages } = await readMessagesBatch(pool.execute, {
2381
2383
  after: 0n,
2382
2384
  batchSize: 1000,
2383
2385
  });
2384
- connection.close();
2386
+ await pool.close();
2385
2387
 
2386
- expect(messages.length).toBeGreaterThan(0);
2387
- expect(messages.some((m) => m.type === 'CommandDispatched')).toBe(true);
2388
- expect(messages.some((m) => m.type === 'PipelineRunStarted')).toBe(true);
2388
+ const types = messages.map((m) => m.type);
2389
+ expect(types).toEqual(expect.arrayContaining(['CommandDispatched', 'PipelineRunStarted']));
2389
2390
 
2390
2391
  fs.unlinkSync(tmpFile);
2391
2392
  });
@@ -6,8 +6,11 @@ import {
6
6
  type Event,
7
7
  type MessageBus,
8
8
  } from '@auto-engineer/message-bus';
9
+ import { dumbo } from '@event-driven-io/dumbo';
10
+ import { sqlite3DumboDriver } from '@event-driven-io/dumbo/sqlite3';
9
11
  import type { EventStore } from '@event-driven-io/emmett';
10
- import { getSQLiteEventStore, readMessagesBatch, sqliteConnection } from '@event-driven-io/emmett-sqlite';
12
+ import { getSQLiteEventStore, readMessagesBatch } from '@event-driven-io/emmett-sqlite';
13
+ import { sqlite3EventStoreDriver } from '@event-driven-io/emmett-sqlite/sqlite3';
11
14
  import cors from 'cors';
12
15
  import express from 'express';
13
16
  import getPort from 'get-port';
@@ -180,6 +183,7 @@ export class PipelineServer {
180
183
 
181
184
  if (this.storeFileName) {
182
185
  this.sqliteEventStore = getSQLiteEventStore({
186
+ driver: sqlite3EventStoreDriver,
183
187
  fileName: this.storeFileName,
184
188
  schema: { autoMigration: 'CreateOrUpdate' },
185
189
  });
@@ -205,12 +209,12 @@ export class PipelineServer {
205
209
  }
206
210
 
207
211
  private async replayEventsFromSQLite(): Promise<void> {
208
- const connection = sqliteConnection({ fileName: this.storeFileName! });
212
+ const pool = dumbo({ driver: sqlite3DumboDriver, fileName: this.storeFileName! });
209
213
  let lastPosition = 0n;
210
214
 
211
215
  try {
212
216
  while (true) {
213
- const { messages, currentGlobalPosition } = await readMessagesBatch(connection, {
217
+ const { messages, currentGlobalPosition } = await readMessagesBatch(pool.execute, {
214
218
  after: lastPosition,
215
219
  batchSize: 1000,
216
220
  });
@@ -229,7 +233,7 @@ export class PipelineServer {
229
233
  const isMissingTable = error instanceof Error && error.message.includes('no such table');
230
234
  if (!isMissingTable) throw error;
231
235
  } finally {
232
- connection.close();
236
+ await pool.close();
233
237
  }
234
238
  }
235
239
 
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import type { ItemStatusDocument } from '../projections/item-status-projection';
3
+ import type { MessageLogDocument } from '../projections/message-log-projection';
3
4
  import type { NodeStatusDocument } from '../projections/node-status-projection';
4
5
  import { createPipelineEventStore } from './pipeline-event-store';
5
6
 
@@ -169,6 +170,72 @@ describe('PipelineEventStore', () => {
169
170
  }
170
171
  });
171
172
 
173
+ it('should append a new message log entry for each NodeStatusChanged even on retry', async () => {
174
+ const { eventStore, readModel, close } = createPipelineEventStore();
175
+ try {
176
+ await eventStore.appendToStream('pipeline-c1', [
177
+ {
178
+ type: 'NodeStatusChanged',
179
+ data: {
180
+ correlationId: 'c1',
181
+ commandName: 'RebuildComponentDB',
182
+ nodeId: 'node-1',
183
+ status: 'running',
184
+ previousStatus: 'idle',
185
+ pendingCount: 1,
186
+ endedCount: 0,
187
+ },
188
+ },
189
+ {
190
+ type: 'NodeStatusChanged',
191
+ data: {
192
+ correlationId: 'c1',
193
+ commandName: 'RebuildComponentDB',
194
+ nodeId: 'node-1',
195
+ status: 'error',
196
+ previousStatus: 'running',
197
+ pendingCount: 0,
198
+ endedCount: 1,
199
+ },
200
+ },
201
+ ]);
202
+
203
+ await eventStore.appendToStream('pipeline-c1', [
204
+ {
205
+ type: 'NodeStatusChanged',
206
+ data: {
207
+ correlationId: 'c1',
208
+ commandName: 'RebuildComponentDB',
209
+ nodeId: 'node-1',
210
+ status: 'running',
211
+ previousStatus: 'error',
212
+ pendingCount: 1,
213
+ endedCount: 0,
214
+ },
215
+ },
216
+ {
217
+ type: 'NodeStatusChanged',
218
+ data: {
219
+ correlationId: 'c1',
220
+ commandName: 'RebuildComponentDB',
221
+ nodeId: 'node-1',
222
+ status: 'success',
223
+ previousStatus: 'running',
224
+ pendingCount: 0,
225
+ endedCount: 1,
226
+ },
227
+ },
228
+ ]);
229
+
230
+ const messages = await readModel.getMessages('c1');
231
+ const statuses = messages.map((m: MessageLogDocument) => (m.messageData as { status: string }).status);
232
+
233
+ expect(statuses).toEqual(['running', 'error', 'running', 'success']);
234
+ } finally {
235
+ await close();
236
+ }
237
+ });
238
+
172
239
  it('should track message stats through CommandDispatched and DomainEventEmitted', async () => {
173
240
  const { eventStore, readModel, close } = createPipelineEventStore();
174
241
  try {
@@ -7,6 +7,7 @@ import {
7
7
  inlineProjections,
8
8
  inMemorySingleStreamProjection,
9
9
  } from '@event-driven-io/emmett';
10
+ import { nanoid } from 'nanoid';
10
11
  import type { AwaitEvent, AwaitTrackerDocument } from '../projections/await-tracker-projection';
11
12
  import { evolve as evolveAwaitTracker } from '../projections/await-tracker-projection';
12
13
  import type { ItemStatusChangedEvent, ItemStatusDocument } from '../projections/item-status-projection';
@@ -59,7 +60,7 @@ function createProjections() {
59
60
  return `prs-${event.data.correlationId}`;
60
61
  }
61
62
  if (event.type === 'NodeStatusChanged') {
62
- return `nsc-${event.data.correlationId}-${event.data.commandName}-${event.data.status}`;
63
+ return `nsc-${nanoid()}`;
63
64
  }
64
65
  if (event.type === 'DomainEventEmitted') {
65
66
  return `dee-${event.data.requestId}-${event.data.eventType}`;
@@ -1,5 +1,6 @@
1
1
  import { getInMemoryDatabase, type InMemoryDatabase } from '@event-driven-io/emmett';
2
2
  import { getSQLiteEventStore, type SQLiteEventStore } from '@event-driven-io/emmett-sqlite';
3
+ import { sqlite3EventStoreDriver } from '@event-driven-io/emmett-sqlite/sqlite3';
3
4
  import { PipelineReadModel } from './pipeline-read-model';
4
5
 
5
6
  export interface SQLitePipelineEventStoreContext {
@@ -19,6 +20,7 @@ export async function createSQLitePipelineEventStore(
19
20
  const database = getInMemoryDatabase();
20
21
 
21
22
  const eventStore = getSQLiteEventStore({
23
+ driver: sqlite3EventStoreDriver,
22
24
  fileName: config.fileName,
23
25
  schema: { autoMigration: 'CreateOrUpdate' },
24
26
  });