@arki/event-sourcing 0.1.4 → 0.2.1

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/README.md CHANGED
@@ -22,20 +22,105 @@ Peer-installs:
22
22
 
23
23
  - **Event store** — `getEventStore(connectionString, options)` opens a PostgreSQL event store with a clean `close()` that releases the pool.
24
24
  - **Message bus** — `eventSourcingFeatures.initMessageBus(eventStore, handlers)` builds an in-memory message bus, registers command handlers, and wraps each handler with stream-name resolution + logging.
25
+ - **DOT adapter** — `eventSourcing()` opens the store, publishes `eventStore` + `messageBus`, collects feature-local ES bundles, and registers the `event-catalog` projection.
25
26
  - **Process managers** — `createProcessManager` (per-batch), `createStatefulProcessManager` (per-batch with state), and `createSimpleProcessManager` (per-message with a pre-bound context).
26
- - **Builders** — fluent `defineCommand`, `defineEvent`, `defineDecider`, `defineProjection`, `defineCommandHandler`, `defineProcessManager`, `defineStatefulProcessManager` for type-safe authoring.
27
+ - **Builders** — `defineCommand`, `defineEvent`, `defineDecider`, `defineProjection`, `defineCommandHandler`, `defineProcessManager`, `defineStatefulProcessManager` for type-safe authoring.
27
28
  - **Drizzle projection helpers** — `drizzleProjection` / `drizzleWithRepoProjection` so projection handlers receive a typed Drizzle database (or repository registry) instead of a raw client.
28
29
 
29
30
  ## Quick start
30
31
 
31
- ### 1. Bootstrap an event store and message bus
32
+ ### DOT app setup
33
+
34
+ ```ts
35
+ import { z } from '@arki/contracts';
36
+ import { defineApp, pip, provide, token } from '@arki/dot';
37
+ import { eventSourcing, es, type EsBundle } from '@arki/event-sourcing/dot';
38
+ import { defineCommand, defineCommandHandler, defineEvent } from '@arki/event-sourcing/builders';
39
+
40
+ const placeOrder = defineCommand({
41
+ type: 'PlaceOrder',
42
+ inputSchema: z.object({ orderId: z.string(), total: z.number() }),
43
+ });
44
+
45
+ const orderPlaced = defineEvent({
46
+ type: 'OrderPlaced',
47
+ dataSchema: z.object({ orderId: z.string(), total: z.number() }),
48
+ });
49
+
50
+ const placeOrderHandler = defineCommandHandler({
51
+ initialState: () => ({ placed: false }),
52
+ evolve: (state, event) => (event.type === 'OrderPlaced' ? { placed: true } : state),
53
+ decide: (command, state) => {
54
+ if (state.placed) throw new Error('Order already placed');
55
+ return [orderPlaced({ orderId: command.data.orderId, total: command.data.total })];
56
+ },
57
+ });
58
+
59
+ export const OrdersEs = token<EsBundle>()('orders.es');
60
+
61
+ export const ordersEsPip = pip({
62
+ name: 'orders-es',
63
+ actions: [placeOrder, orderPlaced],
64
+ boot: () =>
65
+ provide(
66
+ OrdersEs,
67
+ es.bundle({
68
+ handlers: [es.handle(placeOrder, placeOrderHandler, command => `order-${command.data.orderId}`)],
69
+ readModels: [],
70
+ }),
71
+ ),
72
+ });
73
+
74
+ export const app = defineApp('shop-api')
75
+ .use(ordersEsPip)
76
+ .use(eventSourcing({ bundles: [OrdersEs], dbUrl: process.env.DB_URL }));
77
+ ```
78
+
79
+ `eventSourcing()` may be mounted with no options for append-only mode. It resolves the store URL from `EVENT_STORE_URL`, `EVENTSTORE_URL`, or `EVENT_DB_URL`; apps that use a different env name should pass `dbUrl` explicitly.
80
+
81
+ Commands and events produced by `defineCommand` / `defineEvent` contribute DOT actions. `dot explain --as event-catalog` renders their JSON Schemas without booting the app. Deprecated dynamic `commandHandlers` still run, but are intentionally absent from the manifest and catalog.
82
+
83
+ ### Composition order
84
+
85
+ Feature pips that handle commands publish ES bundles. Feature pips that send commands need the `messageBus` service. Mount them in this order:
86
+
87
+ ```text
88
+ es-feature pips -> eventSourcing() -> http/queue feature pips that need messageBus -> http()/queue runtime
89
+ ```
90
+
91
+ A feature that both handles `PlaceOrder` and exposes `POST /orders` should be split into two pips: `orders-es` publishes `OrdersEs`; `orders-http` needs `messageBus` and binds the HTTP route.
92
+
93
+ ### HTTP and queue recipes
94
+
95
+ Expose a command over HTTP explicitly:
96
+
97
+ ```ts
98
+ routes().bind(placeOrderRoute, async ({ body }, { messageBus }) => {
99
+ await messageBus.send(placeOrder(body));
100
+ return { ok: true };
101
+ });
102
+ ```
103
+
104
+ Use `@arki/queue` for durable/async command transport:
105
+
106
+ ```ts
107
+ jobs.worker('orders.place', async ({ payload }, { messageBus }) => {
108
+ await messageBus.send(placeOrder(payload));
109
+ });
110
+ ```
111
+
112
+ The message bus published by this package is strictly in-process synchronous dispatch. It is not durable, does not distribute work across instances, and does not survive restarts or rolling deploys.
113
+
114
+ ### Programmatic bootstrap
115
+
116
+ Non-DOT composition roots can still use the lower-level helpers:
32
117
 
33
118
  ```ts
34
119
  import { eventSourcingFeatures } from '@arki/event-sourcing';
35
120
 
36
121
  const { eventStore, close } = eventSourcingFeatures.initEventSourcing(
37
122
  [
38
- /* projections produced by defineProjection / drizzleProjection / postgreSQLProjection */
123
+ /* read-model projections produced by defineProjection / drizzleProjection / postgreSQLProjection */
39
124
  ],
40
125
  process.env.EVENT_STORE_URL,
41
126
  );
@@ -44,46 +129,10 @@ const messageBus = eventSourcingFeatures.initMessageBus(eventStore, [
44
129
  /* { commandType, handler, getStreamName } registrations */
45
130
  ]);
46
131
 
47
- // Later, on shutdown:
48
132
  await close();
49
133
  ```
50
134
 
51
- `initEventSourcing` throws a descriptive error if the connection string is undefined, naming `EVENT_STORE_URL`, `EVENTSTORE_URL`, and `EVENT_DB_URL` as the recognised env var names.
52
-
53
- ### 2. Define a command, a decider, and a handler
54
-
55
- ```ts
56
- import { defineCommand, defineEvent, defineDecider, defineCommandHandler, z } from '@arki/event-sourcing';
57
- // (or import each builder from '@arki/event-sourcing/builders')
58
-
59
- const PlaceOrder = defineCommand({
60
- type: 'PlaceOrder',
61
- inputSchema: z.object({ orderId: z.string(), total: z.number() }),
62
- metadataSchema: z.object({ userId: z.string() }),
63
- });
64
-
65
- const OrderPlaced = defineEvent({
66
- type: 'OrderPlaced',
67
- inputSchema: z.object({ orderId: z.string(), total: z.number() }),
68
- metadataSchema: z.object({ userId: z.string(), at: z.string() }),
69
- });
70
-
71
- const orderDecider = defineDecider()
72
- .initialState(() => ({ placed: false }))
73
- .evolve((state, event) => (event.type === 'OrderPlaced' ? { placed: true } : state))
74
- .decide((command, state) => {
75
- if (state.placed) throw new Error('Order already placed');
76
- return OrderPlaced({ orderId: command.data.orderId, total: command.data.total }, {
77
- userId: command.metadata.userId,
78
- at: new Date().toISOString(),
79
- });
80
- })
81
- .build();
82
-
83
- export const placeOrderHandler = defineCommandHandler(orderDecider);
84
- ```
85
-
86
- ### 3. Define a process manager
135
+ ### Process managers
87
136
 
88
137
  Use `createProcessManager` for batch processing, or `createSimpleProcessManager` when the handler closes over a fixed context and processes one event at a time:
89
138
 
@@ -114,6 +163,8 @@ await eventSourcingFeatures.setupProcessManagers(eventStore, [sendOrderEmails]);
114
163
  - `@arki/event-sourcing/builders` — fluent builders only.
115
164
  - `@arki/event-sourcing/store` — `getEventStore`, `drizzleProjection`, `postgreSQLProjection`, projection context types.
116
165
  - `@arki/event-sourcing/bus` — `getInMemoryMessageBus` and message bus types re-exported from Emmett.
166
+ - `@arki/event-sourcing/dot` — DOT pip, ES bundle helpers, and ES pip error codes.
167
+ - `@arki/event-sourcing/projection` — pure `event-catalog` projection for DOT.
117
168
 
118
169
  ## Documentation
119
170
 
@@ -1,5 +1,6 @@
1
1
  import type { z } from '@arki/contracts';
2
2
  import type { Command, DefaultCommandMetadata } from '../command.js';
3
+ import type { EventSourcingActionDeclaration } from '../dot-action.js';
3
4
  import type { DefaultRecord } from '../types.js';
4
5
  /**
5
6
  * Configuration for defining a domain command factory.
@@ -12,6 +13,12 @@ export type CommandConfig<TType extends string, TInput extends DefaultRecord, TM
12
13
  /** Optional Zod schema for validating command metadata */
13
14
  metadataSchema?: z.ZodType<TMetadata>;
14
15
  };
16
+ export type CommandFactory<TType extends string, TInput extends DefaultRecord, TMetadata extends DefaultCommandMetadata | undefined = undefined> = ((input: TInput, metadata?: TMetadata) => Command<TType, TInput, TMetadata>) & EventSourcingActionDeclaration & {
17
+ readonly type: TType;
18
+ readonly inputSchema: z.ZodType<TInput>;
19
+ readonly metadataSchema?: z.ZodType<TMetadata>;
20
+ toDotAction(): EventSourcingActionDeclaration;
21
+ };
15
22
  /**
16
23
  * Creates a strongly-typed command factory function.
17
24
  *
@@ -35,5 +42,5 @@ export type CommandConfig<TType extends string, TInput extends DefaultRecord, TM
35
42
  * );
36
43
  * ```
37
44
  */
38
- export declare function defineCommand<TType extends string, TInput extends DefaultRecord, TMetadata extends DefaultCommandMetadata | undefined = undefined>(config: CommandConfig<TType, TInput, TMetadata>): (input: TInput, metadata?: TMetadata) => Command<TType, TInput, TMetadata>;
45
+ export declare function defineCommand<TType extends string, TInput extends DefaultRecord, TMetadata extends DefaultCommandMetadata | undefined = undefined>(config: CommandConfig<TType, TInput, TMetadata>): CommandFactory<TType, TInput, TMetadata>;
39
46
  //# sourceMappingURL=command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/builders/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,aAAa,CACvB,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,aAAa,EAC5B,SAAS,SAAS,sBAAsB,GAAG,SAAS,GAAG,SAAS,IAC9D;IACF,mDAAmD;IACnD,IAAI,EAAE,KAAK,CAAC;IACZ,8CAA8C;IAC9C,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAC3B,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,aAAa,EAC5B,SAAS,SAAS,sBAAsB,GAAG,SAAS,GAAG,SAAS,EAEhE,MAAM,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,GAC9C,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAqB5E"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/builders/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,KAAK,EAAE,8BAA8B,EAAc,MAAM,kBAAkB,CAAC;AAEnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,aAAa,CACvB,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,aAAa,EAC5B,SAAS,SAAS,sBAAsB,GAAG,SAAS,GAAG,SAAS,IAC9D;IACF,mDAAmD;IACnD,IAAI,EAAE,KAAK,CAAC;IACZ,8CAA8C;IAC9C,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,cAAc,CACxB,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,aAAa,EAC5B,SAAS,SAAS,sBAAsB,GAAG,SAAS,GAAG,SAAS,IAC9D,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,GAC9E,8BAA8B,GAAG;IAC/B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/C,WAAW,IAAI,8BAA8B,CAAC;CAC/C,CAAC;AAmBJ;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAC3B,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,aAAa,EAC5B,SAAS,SAAS,sBAAsB,GAAG,SAAS,GAAG,SAAS,EAEhE,MAAM,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,GAC9C,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CA+C1C"}
@@ -1,3 +1,17 @@
1
+ import { EVENT_SOURCING_ACTION_META_SCHEMA, schemaToJsonObject } from '../dot-action.js';
2
+ function commandAction(type, inputSchema) {
3
+ return {
4
+ id: type,
5
+ binding: 'es',
6
+ direction: 'in',
7
+ address: type,
8
+ metaSchema: EVENT_SOURCING_ACTION_META_SCHEMA,
9
+ meta: {
10
+ kind: 'command',
11
+ input: schemaToJsonObject(inputSchema, `command "${type}" input`),
12
+ },
13
+ };
14
+ }
1
15
  /**
2
16
  * Creates a strongly-typed command factory function.
3
17
  *
@@ -23,7 +37,8 @@
23
37
  */
24
38
  export function defineCommand(config) {
25
39
  const { type, inputSchema, metadataSchema } = config;
26
- return (input, metadata) => {
40
+ let cachedAction;
41
+ const factory = (input, metadata) => {
27
42
  const validatedInput = inputSchema.parse(input);
28
43
  const validatedMetadata = metadataSchema ? metadataSchema.parse(metadata) : metadata;
29
44
  // Conditionally construct the command object based on whether metadata is provided
@@ -40,5 +55,27 @@ export function defineCommand(config) {
40
55
  kind: 'Command',
41
56
  });
42
57
  };
58
+ const getAction = () => {
59
+ cachedAction ??= commandAction(type, inputSchema);
60
+ return cachedAction;
61
+ };
62
+ Object.defineProperties(factory, {
63
+ type: { value: type, enumerable: true },
64
+ inputSchema: { value: inputSchema },
65
+ ...(metadataSchema === undefined ? {} : { metadataSchema: { value: metadataSchema } }),
66
+ id: { value: type, enumerable: true },
67
+ binding: { value: 'es', enumerable: true },
68
+ direction: { value: 'in', enumerable: true },
69
+ address: { value: type, enumerable: true },
70
+ metaSchema: { value: EVENT_SOURCING_ACTION_META_SCHEMA, enumerable: true },
71
+ meta: {
72
+ enumerable: true,
73
+ get() {
74
+ return getAction().meta;
75
+ },
76
+ },
77
+ toDotAction: { value: getAction },
78
+ });
79
+ return factory;
43
80
  }
44
81
  //# sourceMappingURL=command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/builders/command.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,aAAa,CAK3B,MAA+C;IAE/C,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC;IAErD,OAAO,CAAC,KAAa,EAAE,QAAoB,EAAE,EAAE;QAC7C,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,iBAAiB,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAErF,mFAAmF;QACnF,OAAO,CAAC,iBAAiB,KAAK,SAAS;YACrC,CAAC,CAAC;gBACE,IAAI;gBACJ,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,SAAkB;aACzB;YACH,CAAC,CAAC;gBACE,IAAI;gBACJ,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,iBAAiB;gBAC3B,IAAI,EAAE,SAAkB;aACzB,CAAiD,CAAC;IACzD,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/builders/command.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iCAAiC,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AA+BzF,SAAS,aAAa,CACpB,IAAW,EACX,WAAsB;IAEtB,OAAO;QACL,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,iCAAiC;QAC7C,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,kBAAkB,CAAC,WAAW,EAAE,YAAY,IAAI,SAAS,CAAC;SAClE;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,aAAa,CAK3B,MAA+C;IAE/C,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC;IACrD,IAAI,YAAwD,CAAC;IAE7D,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,QAAoB,EAAE,EAAE;QACtD,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,iBAAiB,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAErF,mFAAmF;QACnF,OAAO,CAAC,iBAAiB,KAAK,SAAS;YACrC,CAAC,CAAC;gBACE,IAAI;gBACJ,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,SAAkB;aACzB;YACH,CAAC,CAAC;gBACE,IAAI;gBACJ,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,iBAAiB;gBAC3B,IAAI,EAAE,SAAkB;aACzB,CAAiD,CAAC;IACzD,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,GAAmC,EAAE;QACrD,YAAY,KAAK,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAClD,OAAO,YAAY,CAAC;IACtB,CAAC,CAAC;IAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE;QAC/B,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QACvC,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE;QACnC,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,CAAC;QACtF,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QACrC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QAC1C,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QAC5C,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QAC1C,UAAU,EAAE,EAAE,KAAK,EAAE,iCAAiC,EAAE,UAAU,EAAE,IAAI,EAAE;QAC1E,IAAI,EAAE;YACJ,UAAU,EAAE,IAAI;YAChB,GAAG;gBACD,OAAO,SAAS,EAAE,CAAC,IAAI,CAAC;YAC1B,CAAC;SACF;QACD,WAAW,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE;KAClC,CAAC,CAAC;IAEH,OAAO,OAAmD,CAAC;AAC7D,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import type { z } from '@arki/contracts';
2
2
  import type { Event } from '../event.js';
3
+ import type { EventSourcingActionDeclaration } from '../dot-action.js';
3
4
  import type { DefaultRecord } from '../types.js';
4
5
  /**
5
6
  * Configuration for defining a domain event factory.
@@ -12,6 +13,12 @@ export type EventConfig<TType extends string, TData extends DefaultRecord, TMeta
12
13
  /** Optional Zod schema for validating event metadata */
13
14
  metadataSchema?: z.ZodType<TMetadata>;
14
15
  };
16
+ export type EventFactory<TType extends string, TData extends DefaultRecord, TMetadata extends DefaultRecord | undefined = undefined> = ((data: TData, metadata?: TMetadata) => Event<TType, TData, TMetadata>) & EventSourcingActionDeclaration & {
17
+ readonly type: TType;
18
+ readonly dataSchema: z.ZodType<TData>;
19
+ readonly metadataSchema?: z.ZodType<TMetadata>;
20
+ toDotAction(): EventSourcingActionDeclaration;
21
+ };
15
22
  /**
16
23
  * Creates a strongly-typed event factory function.
17
24
  *
@@ -35,5 +42,5 @@ export type EventConfig<TType extends string, TData extends DefaultRecord, TMeta
35
42
  * );
36
43
  * ```
37
44
  */
38
- export declare function defineEvent<TType extends string, TData extends DefaultRecord, TMetadata extends DefaultRecord | undefined = undefined>(config: EventConfig<TType, TData, TMetadata>): (data: TData, metadata?: TMetadata) => Event<TType, TData, TMetadata>;
45
+ export declare function defineEvent<TType extends string, TData extends DefaultRecord, TMetadata extends DefaultRecord | undefined = undefined>(config: EventConfig<TType, TData, TMetadata>): EventFactory<TType, TData, TMetadata>;
39
46
  //# sourceMappingURL=event.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/builders/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,WAAW,CACrB,KAAK,SAAS,MAAM,EACpB,KAAK,SAAS,aAAa,EAC3B,SAAS,SAAS,aAAa,GAAG,SAAS,GAAG,SAAS,IACrD;IACF,kDAAkD;IAClD,IAAI,EAAE,KAAK,CAAC;IACZ,2CAA2C;IAC3C,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,wDAAwD;IACxD,cAAc,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CACzB,KAAK,SAAS,MAAM,EACpB,KAAK,SAAS,aAAa,EAC3B,SAAS,SAAS,aAAa,GAAG,SAAS,GAAG,SAAS,EACvD,MAAM,EAAE,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAmBrH"}
1
+ {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/builders/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,8BAA8B,EAAc,MAAM,kBAAkB,CAAC;AAEnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,WAAW,CACrB,KAAK,SAAS,MAAM,EACpB,KAAK,SAAS,aAAa,EAC3B,SAAS,SAAS,aAAa,GAAG,SAAS,GAAG,SAAS,IACrD;IACF,kDAAkD;IAClD,IAAI,EAAE,KAAK,CAAC;IACZ,2CAA2C;IAC3C,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,wDAAwD;IACxD,cAAc,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,YAAY,CACtB,KAAK,SAAS,MAAM,EACpB,KAAK,SAAS,aAAa,EAC3B,SAAS,SAAS,aAAa,GAAG,SAAS,GAAG,SAAS,IACrD,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,GACzE,8BAA8B,GAAG;IAC/B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/C,WAAW,IAAI,8BAA8B,CAAC;CAC/C,CAAC;AAmBJ;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CACzB,KAAK,SAAS,MAAM,EACpB,KAAK,SAAS,aAAa,EAC3B,SAAS,SAAS,aAAa,GAAG,SAAS,GAAG,SAAS,EACvD,MAAM,EAAE,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CA6CrF"}
@@ -1,3 +1,17 @@
1
+ import { EVENT_SOURCING_ACTION_META_SCHEMA, schemaToJsonObject } from '../dot-action.js';
2
+ function eventAction(type, dataSchema) {
3
+ return {
4
+ id: type,
5
+ binding: 'es',
6
+ direction: 'out',
7
+ address: type,
8
+ metaSchema: EVENT_SOURCING_ACTION_META_SCHEMA,
9
+ meta: {
10
+ kind: 'event',
11
+ data: schemaToJsonObject(dataSchema, `event "${type}" data`),
12
+ },
13
+ };
14
+ }
1
15
  /**
2
16
  * Creates a strongly-typed event factory function.
3
17
  *
@@ -23,7 +37,8 @@
23
37
  */
24
38
  export function defineEvent(config) {
25
39
  const { type, dataSchema, metadataSchema } = config;
26
- return (data, metadata) => {
40
+ let cachedAction;
41
+ const factory = (data, metadata) => {
27
42
  const validatedData = dataSchema.parse(data);
28
43
  const validatedMetadata = metadataSchema ? metadataSchema.parse(metadata) : metadata;
29
44
  // Conditionally construct the event object based on whether metadata is provided
@@ -38,5 +53,27 @@ export function defineEvent(config) {
38
53
  metadata: validatedMetadata,
39
54
  });
40
55
  };
56
+ const getAction = () => {
57
+ cachedAction ??= eventAction(type, dataSchema);
58
+ return cachedAction;
59
+ };
60
+ Object.defineProperties(factory, {
61
+ type: { value: type, enumerable: true },
62
+ dataSchema: { value: dataSchema },
63
+ ...(metadataSchema === undefined ? {} : { metadataSchema: { value: metadataSchema } }),
64
+ id: { value: type, enumerable: true },
65
+ binding: { value: 'es', enumerable: true },
66
+ direction: { value: 'out', enumerable: true },
67
+ address: { value: type, enumerable: true },
68
+ metaSchema: { value: EVENT_SOURCING_ACTION_META_SCHEMA, enumerable: true },
69
+ meta: {
70
+ enumerable: true,
71
+ get() {
72
+ return getAction().meta;
73
+ },
74
+ },
75
+ toDotAction: { value: getAction },
76
+ });
77
+ return factory;
41
78
  }
42
79
  //# sourceMappingURL=event.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/builders/event.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,WAAW,CAIzB,MAA4C;IAC5C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC;IAEpD,OAAO,CAAC,IAAW,EAAE,QAAoB,EAAE,EAAE;QAC3C,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,iBAAiB,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAErF,iFAAiF;QACjF,OAAO,CAAC,iBAAiB,KAAK,SAAS;YACrC,CAAC,CAAC;gBACE,IAAI;gBACJ,IAAI,EAAE,aAAa;aACpB;YACH,CAAC,CAAC;gBACE,IAAI;gBACJ,IAAI,EAAE,aAAa;gBACnB,QAAQ,EAAE,iBAAiB;aAC5B,CAA8C,CAAC;IACtD,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/builders/event.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iCAAiC,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AA+BzF,SAAS,WAAW,CAClB,IAAW,EACX,UAAqB;IAErB,OAAO;QACL,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,iCAAiC;QAC7C,IAAI,EAAE;YACJ,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,kBAAkB,CAAC,UAAU,EAAE,UAAU,IAAI,QAAQ,CAAC;SAC7D;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,WAAW,CAIzB,MAA4C;IAC5C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC;IACpD,IAAI,YAAwD,CAAC;IAE7D,MAAM,OAAO,GAAG,CAAC,IAAW,EAAE,QAAoB,EAAE,EAAE;QACpD,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,iBAAiB,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAErF,iFAAiF;QACjF,OAAO,CAAC,iBAAiB,KAAK,SAAS;YACrC,CAAC,CAAC;gBACE,IAAI;gBACJ,IAAI,EAAE,aAAa;aACpB;YACH,CAAC,CAAC;gBACE,IAAI;gBACJ,IAAI,EAAE,aAAa;gBACnB,QAAQ,EAAE,iBAAiB;aAC5B,CAA8C,CAAC;IACtD,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,GAAmC,EAAE;QACrD,YAAY,KAAK,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC/C,OAAO,YAAY,CAAC;IACtB,CAAC,CAAC;IAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE;QAC/B,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QACvC,UAAU,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE;QACjC,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,CAAC;QACtF,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QACrC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QAC1C,SAAS,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE;QAC7C,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QAC1C,UAAU,EAAE,EAAE,KAAK,EAAE,iCAAiC,EAAE,UAAU,EAAE,IAAI,EAAE;QAC1E,IAAI,EAAE;YACJ,UAAU,EAAE,IAAI;YAChB,GAAG;gBACD,OAAO,SAAS,EAAE,CAAC,IAAI,CAAC;YAC1B,CAAC;SACF;QACD,WAAW,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE;KAClC,CAAC,CAAC;IAEH,OAAO,OAAgD,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { z } from '@arki/contracts';
2
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
3
+ [key: string]: JsonValue;
4
+ };
5
+ export type JsonObject = {
6
+ [key: string]: JsonValue;
7
+ };
8
+ export declare const EVENT_SOURCING_ACTION_META_SCHEMA = "@arki/event-sourcing/action-meta@1";
9
+ export declare const EVENT_SOURCING_SCHEMA_REJECTED_CODE = "EVENT_SOURCING_PLUGIN_E007";
10
+ export type EventSourcingActionMeta = {
11
+ readonly kind: 'command';
12
+ readonly input: JsonObject;
13
+ } | {
14
+ readonly kind: 'event';
15
+ readonly data: JsonObject;
16
+ };
17
+ export type EventSourcingActionDeclaration = {
18
+ readonly id: string;
19
+ readonly binding: 'es';
20
+ readonly direction: 'in' | 'out';
21
+ readonly address: string;
22
+ readonly metaSchema: typeof EVENT_SOURCING_ACTION_META_SCHEMA;
23
+ readonly meta: EventSourcingActionMeta;
24
+ };
25
+ export declare class EventSourcingActionError extends Error {
26
+ readonly code = "EVENT_SOURCING_PLUGIN_E007";
27
+ constructor(message: string, cause: unknown);
28
+ }
29
+ export declare function isJsonObject(value: unknown): value is JsonObject;
30
+ export declare function schemaToJsonObject(schema: z.ZodType, label: string): JsonObject;
31
+ //# sourceMappingURL=dot-action.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dot-action.d.ts","sourceRoot":"","sources":["../src/dot-action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAEpC,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AACtG,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD,eAAO,MAAM,iCAAiC,uCAAuC,CAAC;AACtF,eAAO,MAAM,mCAAmC,+BAA+B,CAAC;AAEhF,MAAM,MAAM,uBAAuB,GAC/B;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B,CAAC;AAEN,MAAM,MAAM,8BAA8B,GAAG;IAC3C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,GAAG,KAAK,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,iCAAiC,CAAC;IAC9D,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;CACxC,CAAC;AAEF,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,gCAAuC;gBAExC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAI5C;AAmBD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AA4BD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAY/E"}
@@ -0,0 +1,73 @@
1
+ import { z } from '@arki/contracts';
2
+ export const EVENT_SOURCING_ACTION_META_SCHEMA = '@arki/event-sourcing/action-meta@1';
3
+ export const EVENT_SOURCING_SCHEMA_REJECTED_CODE = 'EVENT_SOURCING_PLUGIN_E007';
4
+ export class EventSourcingActionError extends Error {
5
+ code = EVENT_SOURCING_SCHEMA_REJECTED_CODE;
6
+ constructor(message, cause) {
7
+ super(message, { cause });
8
+ this.name = 'EventSourcingActionError';
9
+ }
10
+ }
11
+ function isJsonPrimitive(value) {
12
+ return value === null || typeof value === 'string' || typeof value === 'boolean' || typeof value === 'number';
13
+ }
14
+ function isPlainObject(value) {
15
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
16
+ return false;
17
+ const prototype = Object.getPrototypeOf(value);
18
+ return prototype === Object.prototype || prototype === null;
19
+ }
20
+ function isJsonValue(value) {
21
+ if (isJsonPrimitive(value))
22
+ return typeof value !== 'number' || Number.isFinite(value);
23
+ if (Array.isArray(value))
24
+ return value.every(isJsonValue);
25
+ if (!isPlainObject(value))
26
+ return false;
27
+ return Object.values(value).every(isJsonValue);
28
+ }
29
+ export function isJsonObject(value) {
30
+ return isPlainObject(value) && Object.values(value).every(isJsonValue);
31
+ }
32
+ function jsonDeepEqual(left, right) {
33
+ if (isJsonPrimitive(left) || isJsonPrimitive(right))
34
+ return Object.is(left, right);
35
+ if (Array.isArray(left) || Array.isArray(right)) {
36
+ if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length)
37
+ return false;
38
+ return left.every((value, index) => jsonDeepEqual(value, right[index]));
39
+ }
40
+ if (!isPlainObject(left) || !isPlainObject(right))
41
+ return false;
42
+ const leftEntries = Object.entries(left);
43
+ const rightEntries = Object.entries(right);
44
+ if (leftEntries.length !== rightEntries.length)
45
+ return false;
46
+ for (const [key, value] of leftEntries) {
47
+ if (!Object.hasOwn(right, key) || !jsonDeepEqual(value, right[key]))
48
+ return false;
49
+ }
50
+ return true;
51
+ }
52
+ function toJsonObject(value) {
53
+ const serialized = JSON.stringify(value);
54
+ if (serialized === undefined)
55
+ throw new TypeError('Value must be a JSON-serializable object.');
56
+ const parsed = JSON.parse(serialized);
57
+ if (!isJsonObject(parsed) || !jsonDeepEqual(value, parsed)) {
58
+ throw new TypeError('Value must be a JSON-serializable object without lossy coercions.');
59
+ }
60
+ return parsed;
61
+ }
62
+ export function schemaToJsonObject(schema, label) {
63
+ try {
64
+ const json = z.toJSONSchema(schema);
65
+ const rest = { ...json };
66
+ delete rest['$schema'];
67
+ return toJsonObject(rest);
68
+ }
69
+ catch (error) {
70
+ throw new EventSourcingActionError(`[event-sourcing] ${label} schema could not be converted to JSON Schema.`, error);
71
+ }
72
+ }
73
+ //# sourceMappingURL=dot-action.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dot-action.js","sourceRoot":"","sources":["../src/dot-action.ts"],"names":[],"mappings":"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"}
package/dist/dot.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * DOT adapter for `@arki/event-sourcing`.
3
3
  *
4
4
  * Wraps `eventSourcingFeatures.initEventSourcing` + `initMessageBus` as a
5
- * single `DotPip`. The pip opens the PostgreSQL event store in
5
+ * single `DotPlugin`. The plugin opens the PostgreSQL event store in
6
6
  * `boot`, attaches command handlers to an in-memory message bus, publishes
7
7
  * both as `services.eventStore` and `services.messageBus`, and closes the
8
8
  * event store pool in `dispose` (reverse declaration order).
@@ -36,31 +36,98 @@
36
36
  * Importing this adapter without `@arki/dot` installed will fail at module
37
37
  * load — that is intentional: the adapter only makes sense in a DOT app.
38
38
  */
39
- import type { EventStore, MessageBus } from '@event-driven-io/emmett';
40
- import type { EmptyShape, Pip } from '@arki/dot/pip';
39
+ import type { Command, Event, EventStore, MessageBus } from '@event-driven-io/emmett';
40
+ import type { Plugin, Token } from '@arki/dot/plugin';
41
41
  import type { CommandHandlerRegistration } from './command.js';
42
42
  import type { PostgreSQLProjectionInput } from './event-sourcing-features.js';
43
+ import type { CommandHandler } from './builders/command-handler.js';
43
44
  /**
44
- * Stable error codes thrown by the event-sourcing pip. Exported so consumers
45
+ * Stable error codes thrown by the event-sourcing plugin. Exported so consumers
45
46
  * and coding agents can match against them — never parse the message.
46
47
  *
47
48
  * @see packages/dot/docs/principles.md — principle 1.3 ("errors are part
48
49
  * of the API") and principle 4 ("agent-discoverable everywhere").
49
50
  */
50
- export declare const EVENT_SOURCING_PIP_ERROR_CODES: {
51
+ export declare const EVENT_SOURCING_PLUGIN_ERROR_CODES: {
51
52
  /** boot was called without a configured event-store URL. */
52
- readonly dbUrlNotConfigured: "EVENT_SOURCING_PIP_E001";
53
+ readonly dbUrlNotConfigured: "EVENT_SOURCING_PLUGIN_E001";
54
+ /** two collected handlers claim the same command type. */
55
+ readonly duplicateCommandHandler: "EVENT_SOURCING_PLUGIN_E002";
56
+ /** a bundle token listed in options.bundles was not provided. */
57
+ readonly bundleMissing: "EVENT_SOURCING_PLUGIN_E003";
58
+ /** a command was dispatched with no registered handler. */
59
+ readonly commandHandlerMissing: "EVENT_SOURCING_PLUGIN_E004";
60
+ /** a command was dispatched after the dispatcher closed. */
61
+ readonly dispatcherClosed: "EVENT_SOURCING_PLUGIN_E005";
62
+ /** reserved for a future declared-action/handler parity diagnostic. */
63
+ readonly declaredActionUnbound: "EVENT_SOURCING_PLUGIN_E006";
64
+ /** command/event schema could not be converted to JSON Schema. */
65
+ readonly schemaRejected: "EVENT_SOURCING_PLUGIN_E007";
66
+ };
67
+ /** A token publishing an {@link EsBundle} — what `options.bundles` lists. */
68
+ export type BundleToken = Token<EsBundle, string>;
69
+ /** Wire-needs record derived from bundle tokens. */
70
+ export type BundleNeeds<TBundles extends readonly BundleToken[]> = {
71
+ readonly [Tok in TBundles[number] as Tok extends Token<EsBundle, infer K> ? K : never]: EsBundle;
72
+ };
73
+ /**
74
+ * A feature token whose slice MAY carry an ES bundle under the `es` key —
75
+ * what `options.features` lists (the feature-plugins slice protocol).
76
+ * Features without an `es` slice contribute nothing, by design.
77
+ */
78
+ export type EsFeatureToken = Token<{
79
+ readonly es?: EsBundle;
80
+ }, string>;
81
+ /** Wire-needs record derived from feature tokens. */
82
+ export type EsFeatureNeeds<TFeatures extends readonly EsFeatureToken[]> = {
83
+ readonly [Tok in TFeatures[number] as Tok extends Token<unknown, infer K> ? K : never]: {
84
+ readonly es?: EsBundle;
85
+ };
86
+ };
87
+ type CommandFactory<C extends Command = Command> = {
88
+ readonly type: C['type'];
89
+ } & ((input: never, metadata?: never) => C);
90
+ /** Feature-local event-sourcing registrations collected by `eventSourcing()`. */
91
+ export type EsBundle = {
92
+ /** Command handlers attached to the in-process message bus at boot. */
93
+ readonly handlers: readonly CommandHandlerRegistration[];
94
+ /** Inline PostgreSQL read-model projections registered on the event store. */
95
+ readonly readModels: readonly PostgreSQLProjectionInput[];
96
+ };
97
+ export type EsBundleInput = {
98
+ readonly handlers?: readonly CommandHandlerRegistration[];
99
+ readonly readModels?: readonly PostgreSQLProjectionInput[];
100
+ };
101
+ declare function bundle(input?: EsBundleInput): EsBundle;
102
+ declare function handle<C extends Command, State, StreamEvent extends Event>(command: CommandFactory<C>, handler: CommandHandler<State, C, StreamEvent>, getStreamName: (command: C) => string): CommandHandlerRegistration<C, State, StreamEvent>;
103
+ /** Namespace for feature-local ES bundle helpers. */
104
+ export declare const es: {
105
+ bundle: typeof bundle;
106
+ handle: typeof handle;
53
107
  };
54
108
  /**
55
109
  * Options for the event-sourcing DOT adapter.
56
110
  */
57
- export type EventSourcingDotOptions = {
111
+ export type EventSourcingDotOptions<TBundles extends readonly BundleToken[] = readonly BundleToken[], TFeatures extends readonly EsFeatureToken[] = readonly EsFeatureToken[]> = {
58
112
  /**
59
113
  * PostgreSQL projection definitions registered inline on the event store.
60
114
  * Accepts the three projection builder patterns documented on
61
115
  * {@link PostgreSQLProjectionInput}.
62
116
  */
63
- readonly projections: readonly PostgreSQLProjectionInput[];
117
+ readonly projections?: readonly PostgreSQLProjectionInput[];
118
+ /**
119
+ * Feature-local bundles to collect. Each token becomes a typed DOT need,
120
+ * so the app builder rejects an `eventSourcing({ bundles })` collector
121
+ * unless an earlier plugin publishes every listed bundle.
122
+ */
123
+ readonly bundles?: TBundles;
124
+ /**
125
+ * Feature-plugin slice tokens to collect (`{ es?: EsBundle }`). Each token
126
+ * becomes a typed DOT need like `bundles`; a feature without an `es`
127
+ * slice contributes nothing (partial features are zero-config — a
128
+ * debug line records the empty contribution).
129
+ */
130
+ readonly features?: TFeatures;
64
131
  /**
65
132
  * Command handlers wired into the in-memory message bus. Each handler's
66
133
  * `getStreamName` callback maps an incoming command to its target stream.
@@ -70,7 +137,7 @@ export type EventSourcingDotOptions = {
70
137
  */
71
138
  readonly commandHandlers?: readonly CommandHandlerRegistration[];
72
139
  /**
73
- * Connection URL for the event store. When omitted, the pip reads
140
+ * Connection URL for the event store. When omitted, the plugin reads
74
141
  * `EVENT_STORE_URL`, `EVENTSTORE_URL`, or `EVENT_DB_URL` from
75
142
  * `process.env`. If none are set, `boot` throws.
76
143
  */
@@ -87,10 +154,11 @@ export type EventSourcingServices = {
87
154
  readonly messageBus: MessageBus;
88
155
  };
89
156
  /**
90
- * Build a DOT pip that opens the event store, wires command handlers
157
+ * Build a DOT plugin that opens the event store, wires command handlers
91
158
  * into an in-memory message bus, and publishes both as services. The
92
159
  * kernel calls `dispose` in reverse declaration order to release the
93
160
  * underlying PG pool.
94
161
  */
95
- export declare function eventSourcing(options: EventSourcingDotOptions): Pip<EmptyShape, EventSourcingServices>;
162
+ export declare function eventSourcing<const TBundles extends readonly BundleToken[] = readonly [], const TFeatures extends readonly EsFeatureToken[] = readonly []>(options?: EventSourcingDotOptions<TBundles, TFeatures>): Plugin<BundleNeeds<TBundles> & EsFeatureNeeds<TFeatures>, EventSourcingServices>;
163
+ export {};
96
164
  //# sourceMappingURL=dot.d.ts.map
package/dist/dot.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../src/dot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAGrD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAG9E;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B;IACzC,4DAA4D;;CAEpD,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAC3D;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAC;IACjE;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,qBAAqB,GAAG;IAClC,mEAAmE;IACnE,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC,CAAC;AAgBF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,uBAAuB,GAAG,GAAG,CAAC,UAAU,EAAE,qBAAqB,CAAC,CA2CtG"}
1
+ {"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../src/dot.ts"],"names":[],"mappings":"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"}