@decocms/runtime 1.0.0-alpha.35 → 1.0.0-alpha.37
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 +2 -2
- package/src/events.ts +58 -22
- package/src/tools.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/runtime",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.37",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"check": "tsc --noEmit"
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@cloudflare/workers-types": "^4.20250617.0",
|
|
10
10
|
"@deco/mcp": "npm:@jsr/deco__mcp@0.7.8",
|
|
11
|
-
"@decocms/bindings": "1.0.1-alpha.
|
|
11
|
+
"@decocms/bindings": "1.0.1-alpha.21",
|
|
12
12
|
"@modelcontextprotocol/sdk": "1.20.2",
|
|
13
13
|
"@ai-sdk/provider": "^2.0.0",
|
|
14
14
|
"hono": "^4.10.7",
|
package/src/events.ts
CHANGED
|
@@ -60,10 +60,18 @@ export interface BatchHandler<TEnv> {
|
|
|
60
60
|
* { handler: fn, events: ["order.created", "order.updated"] }
|
|
61
61
|
* ```
|
|
62
62
|
*/
|
|
63
|
-
export type BindingHandlers<TEnv> =
|
|
63
|
+
export type BindingHandlers<TEnv, Binding = unknown> =
|
|
64
64
|
| BatchHandler<TEnv>
|
|
65
|
-
| Record<string, PerEventHandler<TEnv
|
|
65
|
+
| (Record<string, PerEventHandler<TEnv>> & CronHandlers<Binding, TEnv>);
|
|
66
66
|
|
|
67
|
+
export type CronHandlers<Binding, Env = unknown> = Binding extends {
|
|
68
|
+
__type: "@deco/event-bus";
|
|
69
|
+
value: string;
|
|
70
|
+
}
|
|
71
|
+
? {
|
|
72
|
+
[key in `cron/${string}`]: (env: Env) => Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
: {};
|
|
67
75
|
/**
|
|
68
76
|
* EventHandlers type supports three granularity levels:
|
|
69
77
|
*
|
|
@@ -82,9 +90,10 @@ export type BindingHandlers<TEnv> =
|
|
|
82
90
|
* { DATABASE: { "order.created": (ctx, env) => result } }
|
|
83
91
|
* ```
|
|
84
92
|
*/
|
|
85
|
-
export type EventHandlers<
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
export type EventHandlers<
|
|
94
|
+
Env = unknown,
|
|
95
|
+
TSchema extends z.ZodTypeAny = never,
|
|
96
|
+
> = [TSchema] extends [never]
|
|
88
97
|
? Record<string, never>
|
|
89
98
|
:
|
|
90
99
|
| BatchHandler<z.infer<TSchema>> // Global handler with events
|
|
@@ -94,7 +103,7 @@ export type EventHandlers<TSchema extends z.ZodTypeAny = never> = [
|
|
|
94
103
|
value: string;
|
|
95
104
|
}
|
|
96
105
|
? K
|
|
97
|
-
: never]?: BindingHandlers<z.infer<TSchema
|
|
106
|
+
: never]?: BindingHandlers<Env, z.infer<TSchema>[K]>;
|
|
98
107
|
};
|
|
99
108
|
|
|
100
109
|
/**
|
|
@@ -124,7 +133,7 @@ const isBinding = (v: unknown): v is Binding => {
|
|
|
124
133
|
* Check if handlers is a global batch handler (has handler + events at top level)
|
|
125
134
|
*/
|
|
126
135
|
const isGlobalHandler = <TEnv>(
|
|
127
|
-
handlers: EventHandlers<z.ZodTypeAny>,
|
|
136
|
+
handlers: EventHandlers<TEnv, z.ZodTypeAny>,
|
|
128
137
|
): handlers is BatchHandler<TEnv> => {
|
|
129
138
|
return (
|
|
130
139
|
typeof handlers === "object" &&
|
|
@@ -159,10 +168,10 @@ const isBatchHandler = <TEnv>(
|
|
|
159
168
|
/**
|
|
160
169
|
* Get binding keys from event handlers object
|
|
161
170
|
*/
|
|
162
|
-
const getBindingKeys = <TSchema extends z.ZodTypeAny>(
|
|
163
|
-
handlers: EventHandlers<TSchema>,
|
|
171
|
+
const getBindingKeys = <TEnv, TSchema extends z.ZodTypeAny>(
|
|
172
|
+
handlers: EventHandlers<TEnv, TSchema>,
|
|
164
173
|
): string[] => {
|
|
165
|
-
if (isGlobalHandler(handlers)) {
|
|
174
|
+
if (isGlobalHandler<TEnv>(handlers)) {
|
|
166
175
|
return [];
|
|
167
176
|
}
|
|
168
177
|
return Object.keys(handlers);
|
|
@@ -171,11 +180,11 @@ const getBindingKeys = <TSchema extends z.ZodTypeAny>(
|
|
|
171
180
|
/**
|
|
172
181
|
* Get event types for a binding from handlers
|
|
173
182
|
*/
|
|
174
|
-
const getEventTypesForBinding = <TSchema extends z.ZodTypeAny>(
|
|
175
|
-
handlers: EventHandlers<TSchema>,
|
|
183
|
+
const getEventTypesForBinding = <TEnv, TSchema extends z.ZodTypeAny>(
|
|
184
|
+
handlers: EventHandlers<TEnv, TSchema>,
|
|
176
185
|
binding: string,
|
|
177
186
|
): string[] => {
|
|
178
|
-
if (isGlobalHandler(handlers)) {
|
|
187
|
+
if (isGlobalHandler<TEnv>(handlers)) {
|
|
179
188
|
return handlers.events;
|
|
180
189
|
}
|
|
181
190
|
const bindingHandler = handlers[binding as keyof typeof handlers];
|
|
@@ -193,10 +202,10 @@ const getEventTypesForBinding = <TSchema extends z.ZodTypeAny>(
|
|
|
193
202
|
/**
|
|
194
203
|
* Get scopes from event handlers for subscription
|
|
195
204
|
*/
|
|
196
|
-
const scopesFromEvents = <TSchema extends z.ZodTypeAny = never>(
|
|
197
|
-
handlers: EventHandlers<TSchema>,
|
|
205
|
+
const scopesFromEvents = <TEnv, TSchema extends z.ZodTypeAny = never>(
|
|
206
|
+
handlers: EventHandlers<TEnv, TSchema>,
|
|
198
207
|
): string[] => {
|
|
199
|
-
if (isGlobalHandler(handlers)) {
|
|
208
|
+
if (isGlobalHandler<TEnv>(handlers)) {
|
|
200
209
|
// Global handler - scopes are based on explicit events array
|
|
201
210
|
// Note: "*" binding means all bindings
|
|
202
211
|
return handlers.events.map((event) => `*::event@${event}`);
|
|
@@ -216,11 +225,11 @@ const scopesFromEvents = <TSchema extends z.ZodTypeAny = never>(
|
|
|
216
225
|
* Get subscriptions from event handlers and state
|
|
217
226
|
* Returns flat array of { eventType, publisher } for EVENT_SYNC_SUBSCRIPTIONS
|
|
218
227
|
*/
|
|
219
|
-
const eventsSubscriptions = <TSchema extends z.ZodTypeAny = never>(
|
|
220
|
-
handlers: EventHandlers<TSchema>,
|
|
228
|
+
const eventsSubscriptions = <TEnv, TSchema extends z.ZodTypeAny = never>(
|
|
229
|
+
handlers: EventHandlers<TEnv, TSchema>,
|
|
221
230
|
state: z.infer<TSchema>,
|
|
222
231
|
): EventSubscription[] => {
|
|
223
|
-
if (isGlobalHandler(handlers)) {
|
|
232
|
+
if (isGlobalHandler<TEnv>(handlers)) {
|
|
224
233
|
// Global handler - subscribe to all bindings with the explicit events
|
|
225
234
|
const subscriptions: EventSubscription[] = [];
|
|
226
235
|
for (const [, value] of Object.entries(state)) {
|
|
@@ -343,14 +352,14 @@ const mergeResults = (results: OnEventsOutput[]): OnEventsOutput => {
|
|
|
343
352
|
* 2. Per-binding: `{ BINDING: (context, env) => result }` - handles all events from binding
|
|
344
353
|
* 3. Per-event: `{ BINDING: { "event.type": (context, env) => result } }` - handles specific events
|
|
345
354
|
*/
|
|
346
|
-
const executeEventHandlers = async <TSchema extends z.ZodTypeAny>(
|
|
347
|
-
handlers: EventHandlers<TSchema>,
|
|
355
|
+
const executeEventHandlers = async <TEnv, TSchema extends z.ZodTypeAny>(
|
|
356
|
+
handlers: EventHandlers<TEnv, TSchema>,
|
|
348
357
|
events: CloudEvent[],
|
|
349
358
|
env: z.infer<TSchema>,
|
|
350
359
|
state: z.infer<TSchema>,
|
|
351
360
|
): Promise<OnEventsOutput> => {
|
|
352
361
|
// Case 1: Global handler
|
|
353
|
-
if (isGlobalHandler(handlers)) {
|
|
362
|
+
if (isGlobalHandler<TEnv>(handlers)) {
|
|
354
363
|
try {
|
|
355
364
|
return await handlers.handler({ events }, env);
|
|
356
365
|
} catch (error) {
|
|
@@ -422,6 +431,33 @@ const executeEventHandlers = async <TSchema extends z.ZodTypeAny>(
|
|
|
422
431
|
continue;
|
|
423
432
|
}
|
|
424
433
|
|
|
434
|
+
// Case 3a: Cron handlers (event type starts with "cron/")
|
|
435
|
+
// - Handler signature: (env) => Promise<void>
|
|
436
|
+
// - Fire and forget (don't await)
|
|
437
|
+
// - Always return success immediately
|
|
438
|
+
if (eventType.startsWith("cron/")) {
|
|
439
|
+
const cronHandler = eventHandler as unknown as (
|
|
440
|
+
env: z.infer<TSchema>,
|
|
441
|
+
) => Promise<void>;
|
|
442
|
+
|
|
443
|
+
// Fire and forget - don't await, just log errors
|
|
444
|
+
cronHandler(env).catch((error) => {
|
|
445
|
+
console.error(
|
|
446
|
+
`[Event] Cron handler error for ${eventType}:`,
|
|
447
|
+
error instanceof Error ? error.message : String(error),
|
|
448
|
+
);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// Immediately return success for all cron events
|
|
452
|
+
const results: Record<string, EventResult> = {};
|
|
453
|
+
for (const event of typedEvents) {
|
|
454
|
+
results[event.id] = { success: true };
|
|
455
|
+
}
|
|
456
|
+
promises.push(Promise.resolve({ results }));
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Case 3b: Regular per-event handlers
|
|
425
461
|
// Call handler for each event type (handler receives all events of that type)
|
|
426
462
|
promises.push(
|
|
427
463
|
(async () => {
|
package/src/tools.ts
CHANGED
|
@@ -237,7 +237,7 @@ export interface CreateMCPServerOptions<
|
|
|
237
237
|
oauth?: OAuthConfig;
|
|
238
238
|
events?: {
|
|
239
239
|
bus?: keyof PickByType<Env & DefaultEnv<TSchema>, EventBusBindingClient>;
|
|
240
|
-
handlers?: EventHandlers<TSchema>;
|
|
240
|
+
handlers?: EventHandlers<Env & DefaultEnv<TSchema>, TSchema>;
|
|
241
241
|
};
|
|
242
242
|
configuration?: {
|
|
243
243
|
onChange?: (
|