@nimbus-cqrs/core 2.1.1 → 2.1.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/README.md +31 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Refer to the [Nimbus main repository](https://github.com/overlap-dev/Nimbus) or
|
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
15
|
# Deno
|
|
16
|
-
deno add
|
|
16
|
+
deno add npm:@nimbus-cqrs/core
|
|
17
17
|
|
|
18
18
|
# NPM
|
|
19
19
|
npm install @nimbus-cqrs/core
|
|
@@ -30,17 +30,13 @@ For detailed documentation, please refer to the [Nimbus documentation](https://n
|
|
|
30
30
|
|
|
31
31
|
## Command
|
|
32
32
|
|
|
33
|
-
A **Command** asks the system to
|
|
33
|
+
A **Command** asks the system to _do_ something (a write). You declare a [Zod](https://zod.dev/) schema that extends Nimbus' built-in `commandSchema`, write a handler, and register both on the router. Incoming messages are validated against the schema before they reach your handler.
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
createCommand,
|
|
39
|
-
getRouter,
|
|
40
|
-
} from '@nimbus-cqrs/core';
|
|
41
|
-
import { z } from 'zod';
|
|
36
|
+
import { commandSchema, createCommand, getRouter } from "@nimbus-cqrs/core";
|
|
37
|
+
import { z } from "zod";
|
|
42
38
|
|
|
43
|
-
const ADD_TODO =
|
|
39
|
+
const ADD_TODO = "com.example.todo.add";
|
|
44
40
|
|
|
45
41
|
const addTodoSchema = commandSchema.extend({
|
|
46
42
|
type: z.literal(ADD_TODO),
|
|
@@ -52,7 +48,7 @@ type AddTodoCommand = z.infer<typeof addTodoSchema>;
|
|
|
52
48
|
|
|
53
49
|
const handleAddTodo = async (cmd: AddTodoCommand) => {
|
|
54
50
|
// ...persist the todo here...
|
|
55
|
-
return { id:
|
|
51
|
+
return { id: "todo-1", title: cmd.data.title, status: "open" };
|
|
56
52
|
};
|
|
57
53
|
|
|
58
54
|
const router = getRouter();
|
|
@@ -61,9 +57,9 @@ router.register(ADD_TODO, handleAddTodo, addTodoSchema);
|
|
|
61
57
|
const result = await router.route(
|
|
62
58
|
createCommand<AddTodoCommand>({
|
|
63
59
|
type: ADD_TODO,
|
|
64
|
-
source:
|
|
65
|
-
data: { title:
|
|
66
|
-
})
|
|
60
|
+
source: "https://app.example.com",
|
|
61
|
+
data: { title: "Write the README" },
|
|
62
|
+
})
|
|
67
63
|
);
|
|
68
64
|
|
|
69
65
|
console.log(result);
|
|
@@ -74,13 +70,13 @@ console.log(result);
|
|
|
74
70
|
|
|
75
71
|
## Query
|
|
76
72
|
|
|
77
|
-
A **Query** asks the system to
|
|
73
|
+
A **Query** asks the system to _read_ something. Mechanically it is identical to a Command — same router, same validation, same shape — only the intent differs.
|
|
78
74
|
|
|
79
75
|
```typescript
|
|
80
|
-
import { createQuery, getRouter, querySchema } from
|
|
81
|
-
import { z } from
|
|
76
|
+
import { createQuery, getRouter, querySchema } from "@nimbus-cqrs/core";
|
|
77
|
+
import { z } from "zod";
|
|
82
78
|
|
|
83
|
-
const GET_TODO =
|
|
79
|
+
const GET_TODO = "com.example.todo.get";
|
|
84
80
|
|
|
85
81
|
const getTodoSchema = querySchema.extend({
|
|
86
82
|
type: z.literal(GET_TODO),
|
|
@@ -90,7 +86,7 @@ type GetTodoQuery = z.infer<typeof getTodoSchema>;
|
|
|
90
86
|
|
|
91
87
|
const handleGetTodo = async (q: GetTodoQuery) => {
|
|
92
88
|
// ...load the todo from your read model...
|
|
93
|
-
return { id: q.data.id, title:
|
|
89
|
+
return { id: q.data.id, title: "Write the README", status: "open" };
|
|
94
90
|
};
|
|
95
91
|
|
|
96
92
|
const router = getRouter();
|
|
@@ -99,25 +95,21 @@ router.register(GET_TODO, handleGetTodo, getTodoSchema);
|
|
|
99
95
|
const todo = await router.route(
|
|
100
96
|
createQuery<GetTodoQuery>({
|
|
101
97
|
type: GET_TODO,
|
|
102
|
-
source:
|
|
103
|
-
data: { id:
|
|
104
|
-
})
|
|
98
|
+
source: "https://app.example.com",
|
|
99
|
+
data: { id: "todo-1" },
|
|
100
|
+
})
|
|
105
101
|
);
|
|
106
102
|
```
|
|
107
103
|
|
|
108
104
|
## Event
|
|
109
105
|
|
|
110
|
-
An **Event** announces that something
|
|
106
|
+
An **Event** announces that something _has happened_. Events are published to the in-process EventBus, which delivers them to every matching subscriber asynchronously, with exponential-backoff retries on handler errors and built-in OpenTelemetry traces and metrics.
|
|
111
107
|
|
|
112
108
|
```typescript
|
|
113
|
-
import {
|
|
114
|
-
|
|
115
|
-
eventSchema,
|
|
116
|
-
getEventBus,
|
|
117
|
-
} from '@nimbus-cqrs/core';
|
|
118
|
-
import { z } from 'zod';
|
|
109
|
+
import { createEvent, eventSchema, getEventBus } from "@nimbus-cqrs/core";
|
|
110
|
+
import { z } from "zod";
|
|
119
111
|
|
|
120
|
-
const TODO_ADDED =
|
|
112
|
+
const TODO_ADDED = "com.example.todo.added";
|
|
121
113
|
|
|
122
114
|
const todoAddedSchema = eventSchema.extend({
|
|
123
115
|
type: z.literal(TODO_ADDED),
|
|
@@ -143,10 +135,10 @@ eventBus.subscribeEvent<TodoAddedEvent>({
|
|
|
143
135
|
eventBus.putEvent(
|
|
144
136
|
createEvent<TodoAddedEvent>({
|
|
145
137
|
type: TODO_ADDED,
|
|
146
|
-
source:
|
|
147
|
-
subject:
|
|
148
|
-
data: { id:
|
|
149
|
-
})
|
|
138
|
+
source: "https://app.example.com",
|
|
139
|
+
subject: "/todos/todo-1",
|
|
140
|
+
data: { id: "todo-1", title: "Write the README" },
|
|
141
|
+
})
|
|
150
142
|
);
|
|
151
143
|
```
|
|
152
144
|
|
|
@@ -157,27 +149,27 @@ A typical flow is to publish an event from inside a command handler once the wri
|
|
|
157
149
|
A typical app configures a single named router at startup with cross-cutting concerns (logging, correlation IDs, …) and then resolves it from anywhere via `getRouter()`.
|
|
158
150
|
|
|
159
151
|
```typescript
|
|
160
|
-
import { getLogger, getRouter, setupRouter } from
|
|
152
|
+
import { getLogger, getRouter, setupRouter } from "@nimbus-cqrs/core";
|
|
161
153
|
|
|
162
|
-
setupRouter(
|
|
154
|
+
setupRouter("default", {
|
|
163
155
|
logInput: (input) => {
|
|
164
156
|
getLogger().debug({
|
|
165
|
-
category:
|
|
157
|
+
category: "Router",
|
|
166
158
|
message: `Routing ${input.type}`,
|
|
167
159
|
correlationId: input.correlationid,
|
|
168
160
|
});
|
|
169
161
|
},
|
|
170
162
|
logOutput: (output) => {
|
|
171
163
|
getLogger().debug({
|
|
172
|
-
category:
|
|
173
|
-
message:
|
|
164
|
+
category: "Router",
|
|
165
|
+
message: "Handler completed",
|
|
174
166
|
data: { output },
|
|
175
167
|
});
|
|
176
168
|
},
|
|
177
169
|
});
|
|
178
170
|
|
|
179
171
|
// Anywhere else in your app:
|
|
180
|
-
const router = getRouter(
|
|
172
|
+
const router = getRouter("default");
|
|
181
173
|
router.register(/* type, handler, schema */);
|
|
182
174
|
await router.route(/* command or query */);
|
|
183
175
|
```
|