@crossdelta/platform-sdk 0.3.38 → 0.3.40
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
|
@@ -156,7 +156,7 @@ my-platform/
|
|
|
156
156
|
|
|
157
157
|
## ⚡ Event-Driven Architecture
|
|
158
158
|
|
|
159
|
-
Every workspace includes **NATS + JetStream** for event-driven microservices communication using **[`@crossdelta/cloudevents`](https://
|
|
159
|
+
Every workspace includes **NATS + JetStream** for event-driven microservices communication using **[`@crossdelta/cloudevents`](https://www.npmjs.com/package/@crossdelta/cloudevents)**:
|
|
160
160
|
|
|
161
161
|
- 🎯 **Type-safe event handlers** with Zod schemas
|
|
162
162
|
- 🔄 **Auto-discovery** of event handlers (`*.event.ts` files)
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## Architecture Overview
|
|
4
4
|
|
|
5
|
-
Bun-based **monorepo** (
|
|
5
|
+
Bun-based **monorepo** (Tu }).optional(),
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
// Export type for use in use-cases
|
|
9
|
+
export type OrderCreatedEvent = z.infer<typeof OrderCreatedSchema>
|
|
10
|
+
|
|
11
|
+
export default handleEvent() with event-driven microservices:
|
|
6
12
|
|
|
7
13
|
| Directory | Stack | Purpose |
|
|
8
14
|
|-----------|-------|---------|
|
|
@@ -86,7 +92,6 @@ import { z } from 'zod'
|
|
|
86
92
|
import { sendNotification } from '../use-cases/send-notification.use-case'
|
|
87
93
|
|
|
88
94
|
const OrderCreatedSchema = z.object({
|
|
89
|
-
type: z.literal('orders.created'),
|
|
90
95
|
orderId: z.string(),
|
|
91
96
|
customerId: z.string(),
|
|
92
97
|
total: z.number(),
|
|
@@ -99,12 +104,30 @@ const OrderCreatedSchema = z.object({
|
|
|
99
104
|
).optional(),
|
|
100
105
|
})
|
|
101
106
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
// Export type for reuse in other services
|
|
108
|
+
export type OrderCreatedEvent = z.infer<typeof OrderCreatedSchema>
|
|
109
|
+
|
|
110
|
+
export default handleEvent(
|
|
111
|
+
{
|
|
112
|
+
schema: OrderCreatedSchema,
|
|
113
|
+
type: 'orders.created',
|
|
114
|
+
},
|
|
115
|
+
async (data) => {
|
|
116
|
+
await sendNotification(data)
|
|
117
|
+
},
|
|
118
|
+
)
|
|
105
119
|
```
|
|
106
120
|
|
|
107
|
-
**
|
|
121
|
+
**Important:**
|
|
122
|
+
- **Schema** validates only the event data payload (without `type` field)
|
|
123
|
+
- **Event type** is declared in the options object, not in the schema
|
|
124
|
+
- Event type matches the first parameter of `publish()` (e.g., `'orders.created'`)
|
|
125
|
+
- Do NOT include `type: z.literal('...')` in the schema - it's redundant and causes validation errors
|
|
126
|
+
- **Always export the inferred type** using `export type EventName = z.infer<typeof EventSchema>` for use in use-cases
|
|
127
|
+
|
|
128
|
+
**Naming conventions:**
|
|
129
|
+
- Schema constants: PascalCase with `Schema` suffix (e.g., `OrderCreatedSchema`, `UserUpdatedSchema`)
|
|
130
|
+
- Exported types: PascalCase with `Event` suffix (e.g., `OrderCreatedEvent`, `UserUpdatedEvent`)
|
|
108
131
|
|
|
109
132
|
### Service Folder Structure
|
|
110
133
|
|
|
@@ -249,12 +272,46 @@ Format source files with path headers. Paths are relative to the service directo
|
|
|
249
272
|
|
|
250
273
|
#### `src/handlers/event-name.event.ts`
|
|
251
274
|
```typescript
|
|
252
|
-
|
|
275
|
+
import { handleEvent } from '@crossdelta/cloudevents'
|
|
276
|
+
import { z } from 'zod'
|
|
277
|
+
import { businessLogic } from '../use-cases/business-logic.use-case'
|
|
278
|
+
|
|
279
|
+
const EventDataSchema = z.object({
|
|
280
|
+
id: z.string(),
|
|
281
|
+
// ... other fields
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
// Export type for use in use-cases
|
|
285
|
+
export type EventDataType = z.infer<typeof EventDataSchema>
|
|
286
|
+
|
|
287
|
+
export default handleEvent(
|
|
288
|
+
{
|
|
289
|
+
schema: EventDataSchema,
|
|
290
|
+
type: 'resource.action', // e.g., 'orders.created', 'users.updated'
|
|
291
|
+
},
|
|
292
|
+
async (data) => {
|
|
293
|
+
await businessLogic(data)
|
|
294
|
+
},
|
|
295
|
+
)
|
|
253
296
|
```
|
|
254
297
|
|
|
255
298
|
#### `src/use-cases/business-logic.use-case.ts`
|
|
256
299
|
```typescript
|
|
257
|
-
|
|
300
|
+
import type { EventDataType } from '../handlers/event-name.event'
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Business logic that processes the event data.
|
|
304
|
+
* Uses the exported type from the handler for type safety.
|
|
305
|
+
*/
|
|
306
|
+
export async function businessLogic(data: EventDataType): Promise<void> {
|
|
307
|
+
// Full type inference from the handler schema
|
|
308
|
+
console.log('Processing:', data.id)
|
|
309
|
+
|
|
310
|
+
// All business logic here
|
|
311
|
+
// - Validation
|
|
312
|
+
// - External API calls
|
|
313
|
+
// - Database operations
|
|
314
|
+
}
|
|
258
315
|
```
|
|
259
316
|
|
|
260
317
|
### Tests
|