@crossdelta/cloudevents 0.3.1 → 0.3.3
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
|
@@ -35,15 +35,23 @@ bun add @crossdelta/cloudevents zod@4
|
|
|
35
35
|
import { handleEvent } from '@crossdelta/cloudevents'
|
|
36
36
|
import { z } from 'zod'
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
orderId: z.string(),
|
|
42
|
-
total: z.number(),
|
|
43
|
-
}),
|
|
44
|
-
}, async (data) => {
|
|
45
|
-
console.log(`New order: ${data.orderId}, total: ${data.total}`)
|
|
38
|
+
const OrderCreatedSchema = z.object({
|
|
39
|
+
orderId: z.string(),
|
|
40
|
+
total: z.number(),
|
|
46
41
|
})
|
|
42
|
+
|
|
43
|
+
// Export type for use in use-cases
|
|
44
|
+
export type OrderCreatedEvent = z.infer<typeof OrderCreatedSchema>
|
|
45
|
+
|
|
46
|
+
export default handleEvent(
|
|
47
|
+
{
|
|
48
|
+
schema: OrderCreatedSchema,
|
|
49
|
+
type: 'orders.created',
|
|
50
|
+
},
|
|
51
|
+
async (data) => {
|
|
52
|
+
console.log(`New order: ${data.orderId}, total: ${data.total}`)
|
|
53
|
+
},
|
|
54
|
+
)
|
|
47
55
|
```
|
|
48
56
|
|
|
49
57
|
**2. Start consuming:**
|
|
@@ -84,18 +92,52 @@ That's it. Handlers are auto-discovered, validated with Zod, and messages persis
|
|
|
84
92
|
|
|
85
93
|
## Core Concepts
|
|
86
94
|
|
|
95
|
+
### Event Type vs. Event Data
|
|
96
|
+
|
|
97
|
+
**Important distinction:**
|
|
98
|
+
|
|
99
|
+
- **Event Type** (`orders.created`): Lives in the CloudEvent **envelope** (`ce.type`). Used for routing and handler matching.
|
|
100
|
+
- **Event Data** (`{ orderId, total }`): The actual payload. Does **not** include the type.
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const Schema = z.object({
|
|
104
|
+
orderId: z.string(),
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
export default handleEvent(
|
|
108
|
+
{
|
|
109
|
+
schema: Schema,
|
|
110
|
+
type: 'orders.created',
|
|
111
|
+
},
|
|
112
|
+
async (data) => { ... }
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
87
116
|
### Handlers
|
|
88
117
|
|
|
89
118
|
Drop a `*.event.ts` file anywhere — it's auto-registered:
|
|
90
119
|
|
|
91
120
|
```typescript
|
|
92
121
|
// src/handlers/user-signup.event.ts
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
122
|
+
import { z } from 'zod'
|
|
123
|
+
|
|
124
|
+
const UserSignupSchema = z.object({
|
|
125
|
+
email: z.string().email(),
|
|
126
|
+
name: z.string(),
|
|
98
127
|
})
|
|
128
|
+
|
|
129
|
+
// Export type for use in use-cases
|
|
130
|
+
export type UserSignupEvent = z.infer<typeof UserSignupSchema>
|
|
131
|
+
|
|
132
|
+
export default handleEvent(
|
|
133
|
+
{
|
|
134
|
+
schema: UserSignupSchema,
|
|
135
|
+
type: 'users.signup',
|
|
136
|
+
},
|
|
137
|
+
async (data) => {
|
|
138
|
+
await sendWelcomeEmail(data.email)
|
|
139
|
+
},
|
|
140
|
+
)
|
|
99
141
|
```
|
|
100
142
|
|
|
101
143
|
### Publishing
|
|
@@ -19,6 +19,23 @@ export const quarantineMessage = async (processingContext, reason, options, erro
|
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
try {
|
|
22
|
+
// Serialize error properly - handle ValidationError specially
|
|
23
|
+
let serializedError;
|
|
24
|
+
if (error) {
|
|
25
|
+
if (typeof error === 'object' && error !== null && 'type' in error && error.type === 'ValidationError') {
|
|
26
|
+
serializedError = JSON.stringify(error, null, 2);
|
|
27
|
+
}
|
|
28
|
+
else if (error instanceof Error) {
|
|
29
|
+
serializedError = JSON.stringify({
|
|
30
|
+
name: error.name,
|
|
31
|
+
message: error.message,
|
|
32
|
+
stack: error.stack,
|
|
33
|
+
}, null, 2);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
serializedError = JSON.stringify(error, null, 2);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
22
39
|
const quarantineData = {
|
|
23
40
|
originalMessageId: processingContext.messageId,
|
|
24
41
|
originalEventType: processingContext.eventType,
|
|
@@ -27,7 +44,7 @@ export const quarantineMessage = async (processingContext, reason, options, erro
|
|
|
27
44
|
originalCloudEvent: processingContext.originalCloudEvent,
|
|
28
45
|
quarantinedAt: new Date().toISOString(),
|
|
29
46
|
quarantineReason: reason,
|
|
30
|
-
error:
|
|
47
|
+
error: serializedError,
|
|
31
48
|
};
|
|
32
49
|
await publishRawEvent(options.quarantineTopic, 'hono.cloudevents.quarantined', quarantineData, {
|
|
33
50
|
projectId: options.projectId,
|
|
@@ -40,6 +40,8 @@ export function createBaseMessageProcessor(deps) {
|
|
|
40
40
|
return { handled: true, shouldAck: true };
|
|
41
41
|
};
|
|
42
42
|
const handleValidationFailure = async (validationResult, handler, context) => {
|
|
43
|
+
// Log validation errors with full details for debugging
|
|
44
|
+
logger.error(`[${name}] validation failed for handler ${handler.name}`, JSON.stringify(validationResult.error, null, 2));
|
|
43
45
|
if (dlqEnabled) {
|
|
44
46
|
await quarantineMessage(context, 'validation_error', options, validationResult.error);
|
|
45
47
|
return { handled: true, shouldAck: true };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossdelta/cloudevents",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "CloudEvents toolkit for TypeScript - Zod validation, handler discovery, NATS JetStream",
|
|
5
5
|
"author": "crossdelta",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"prepublishOnly": "bun run build"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"cloudevents": "
|
|
44
|
+
"cloudevents": "^10.0.0",
|
|
45
45
|
"glob": "11.0.0",
|
|
46
46
|
"nats": "^2.29.3"
|
|
47
47
|
},
|