@agentuity/runtime 0.0.103 → 0.0.105
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 +61 -35
- package/dist/_config.d.ts.map +1 -1
- package/dist/_config.js +9 -2
- package/dist/_config.js.map +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +6 -0
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts +5 -2
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js.map +1 -1
- package/dist/eval.d.ts +2 -0
- package/dist/eval.d.ts.map +1 -1
- package/dist/handlers/cron.d.ts +47 -0
- package/dist/handlers/cron.d.ts.map +1 -0
- package/dist/handlers/cron.js +49 -0
- package/dist/handlers/cron.js.map +1 -0
- package/dist/handlers/index.d.ts +5 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +5 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/sse.d.ts +74 -0
- package/dist/handlers/sse.d.ts.map +1 -0
- package/dist/handlers/sse.js +70 -0
- package/dist/handlers/sse.js.map +1 -0
- package/dist/handlers/stream.d.ts +52 -0
- package/dist/handlers/stream.d.ts.map +1 -0
- package/dist/handlers/stream.js +75 -0
- package/dist/handlers/stream.js.map +1 -0
- package/dist/handlers/websocket.d.ts +49 -0
- package/dist/handlers/websocket.d.ts.map +1 -0
- package/dist/handlers/websocket.js +130 -0
- package/dist/handlers/websocket.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/otel/logger.d.ts +1 -4
- package/dist/otel/logger.d.ts.map +1 -1
- package/dist/otel/logger.js +11 -2
- package/dist/otel/logger.js.map +1 -1
- package/dist/router.d.ts +46 -236
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +82 -349
- package/dist/router.js.map +1 -1
- package/dist/workbench.d.ts +6 -2
- package/dist/workbench.d.ts.map +1 -1
- package/dist/workbench.js +29 -26
- package/dist/workbench.js.map +1 -1
- package/package.json +5 -7
- package/src/_config.ts +9 -2
- package/src/agent.ts +6 -0
- package/src/app.ts +7 -2
- package/src/eval.ts +2 -0
- package/src/handlers/cron.ts +70 -0
- package/src/handlers/index.ts +4 -0
- package/src/handlers/sse.ts +118 -0
- package/src/handlers/stream.ts +86 -0
- package/src/handlers/websocket.ts +153 -0
- package/src/index.ts +16 -3
- package/src/otel/logger.ts +13 -2
- package/src/router.ts +110 -597
- package/src/workbench.ts +30 -27
- package/dist/io/email.d.ts +0 -77
- package/dist/io/email.d.ts.map +0 -1
- package/dist/io/email.js +0 -162
- package/dist/io/email.js.map +0 -1
- package/src/io/email.ts +0 -191
package/src/router.ts
CHANGED
|
@@ -1,300 +1,77 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
type Context,
|
|
5
|
-
Hono,
|
|
6
|
-
type Input,
|
|
7
|
-
type MiddlewareHandler,
|
|
8
|
-
type Schema,
|
|
9
|
-
type Env as HonoEnv,
|
|
10
|
-
} from 'hono';
|
|
11
|
-
import { stream as honoStream, streamSSE as honoStreamSSE } from 'hono/streaming';
|
|
12
|
-
import { upgradeWebSocket } from 'hono/bun';
|
|
13
|
-
import { hash, returnResponse } from './_util';
|
|
2
|
+
import { type Context, Hono, type Schema, type Env as HonoEnv } from 'hono';
|
|
3
|
+
import { returnResponse } from './_util';
|
|
14
4
|
import type { Env } from './app';
|
|
15
|
-
import { getAgentAsyncLocalStorage } from './_context';
|
|
16
|
-
import { parseEmail, type Email } from './io/email';
|
|
17
5
|
|
|
18
6
|
// Re-export both Env types
|
|
19
7
|
export type { Env };
|
|
20
8
|
export type { HonoEnv };
|
|
21
9
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
) => any | Promise<any>;
|
|
10
|
+
// Re-export WebSocketConnection from handlers
|
|
11
|
+
export type { WebSocketConnection } from './handlers/websocket';
|
|
25
12
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
c: Context<E, P, I>
|
|
29
|
-
) => any | Promise<any>;
|
|
30
|
-
|
|
31
|
-
type StreamHandler<E extends Env = Env, P extends string = string, I extends Input = {}> = (
|
|
32
|
-
c: Context<E, P, I>
|
|
33
|
-
) => ReadableStream<any> | Promise<ReadableStream<any>>;
|
|
34
|
-
|
|
35
|
-
export interface WebSocketConnection {
|
|
36
|
-
onOpen: (handler: (event: any) => void | Promise<void>) => void;
|
|
37
|
-
onMessage: (handler: (event: any) => void | Promise<void>) => void;
|
|
38
|
-
onClose: (handler: (event: any) => void | Promise<void>) => void;
|
|
39
|
-
send: (data: string | ArrayBuffer | Uint8Array) => void;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
type WebSocketHandler<E extends Env = Env, P extends string = string, I extends Input = {}> = (
|
|
43
|
-
c: Context<E, P, I>
|
|
44
|
-
) => (ws: WebSocketConnection) => void | Promise<void>;
|
|
45
|
-
|
|
46
|
-
type SSEHandler<E extends Env = Env, P extends string = string, I extends Input = {}> = (
|
|
47
|
-
c: Context<E, P, I>
|
|
48
|
-
) => (stream: any) => void | Promise<void>;
|
|
49
|
-
|
|
50
|
-
// Module augmentation to add custom methods to Hono
|
|
51
|
-
// This avoids wrapper types and type instantiation depth issues
|
|
52
|
-
// Use simplified signatures to avoid type instantiation depth issues
|
|
13
|
+
// Module augmentation to add deprecated methods to Hono
|
|
14
|
+
// These stubs throw errors with migration instructions
|
|
53
15
|
declare module 'hono' {
|
|
54
16
|
interface Hono {
|
|
55
17
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* @param address - The email address to handle (e.g., 'support@example.com')
|
|
59
|
-
* @param handler - Handler function receiving parsed email and context
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* ```typescript
|
|
63
|
-
* router.email('support@example.com', (email, c) => {
|
|
64
|
-
* console.log('From:', email.fromEmail());
|
|
65
|
-
* console.log('Subject:', email.subject());
|
|
66
|
-
* console.log('Body:', email.text());
|
|
67
|
-
* return c.text('Email received');
|
|
68
|
-
* });
|
|
69
|
-
* ```
|
|
70
|
-
*/
|
|
71
|
-
email(address: string, handler: (email: Email, c: Context) => any): this;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Register a route to handle incoming emails with middleware.
|
|
75
|
-
*
|
|
76
|
-
* @param address - The email address to handle
|
|
77
|
-
* @param middleware - Middleware to run before the handler
|
|
78
|
-
* @param handler - Handler function receiving parsed email and context
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* ```typescript
|
|
82
|
-
* router.email('support@example.com', authMiddleware, (email, c) => {
|
|
83
|
-
* return c.json({ received: email.subject() });
|
|
84
|
-
* });
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
email(
|
|
88
|
-
address: string,
|
|
89
|
-
middleware: MiddlewareHandler,
|
|
90
|
-
handler: (email: Email, c: Context) => any
|
|
91
|
-
): this;
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Register a route to handle incoming SMS messages to a phone number.
|
|
95
|
-
*
|
|
96
|
-
* @param params - Configuration object with phone number
|
|
97
|
-
* @param params.number - Phone number to handle (e.g., '+1234567890')
|
|
98
|
-
* @param handler - Handler function receiving context
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* ```typescript
|
|
102
|
-
* router.sms({ number: '+1234567890' }, (c) => {
|
|
103
|
-
* const message = c.req.query('message');
|
|
104
|
-
* console.log('SMS received:', message);
|
|
105
|
-
* return c.text('SMS received');
|
|
106
|
-
* });
|
|
107
|
-
* ```
|
|
108
|
-
*/
|
|
109
|
-
sms(params: { number: string }, handler: (c: Context) => any): this;
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Schedule a handler to run at specific intervals using cron syntax.
|
|
113
|
-
*
|
|
114
|
-
* @param schedule - Cron expression (e.g., '0 0 * * *' for daily at midnight)
|
|
115
|
-
* @param handler - Handler function to run on schedule
|
|
116
|
-
*
|
|
117
|
-
* @example
|
|
118
|
-
* ```typescript
|
|
119
|
-
* // Run daily at midnight
|
|
120
|
-
* router.cron('0 0 * * *', (c) => {
|
|
121
|
-
* console.log('Daily cleanup running');
|
|
122
|
-
* return c.text('Cleanup complete');
|
|
123
|
-
* });
|
|
124
|
-
*
|
|
125
|
-
* // Run every hour
|
|
126
|
-
* router.cron('0 * * * *', (c) => {
|
|
127
|
-
* console.log('Hourly health check');
|
|
128
|
-
* return c.text('OK');
|
|
129
|
-
* });
|
|
130
|
-
* ```
|
|
131
|
-
*/
|
|
132
|
-
cron(schedule: string, handler: (c: Context) => any): this;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Create a streaming route that returns a ReadableStream.
|
|
136
|
-
*
|
|
137
|
-
* @param path - The route path
|
|
138
|
-
* @param handler - Handler returning a ReadableStream
|
|
139
|
-
*
|
|
140
|
-
* @example
|
|
18
|
+
* @deprecated Use the `websocket` middleware instead:
|
|
141
19
|
* ```typescript
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* start(controller) {
|
|
145
|
-
* controller.enqueue('event 1\n');
|
|
146
|
-
* controller.enqueue('event 2\n');
|
|
147
|
-
* controller.close();
|
|
148
|
-
* }
|
|
149
|
-
* });
|
|
150
|
-
* });
|
|
20
|
+
* import { websocket } from '@agentuity/runtime';
|
|
21
|
+
* router.get('/ws', websocket((c, ws) => { ... }));
|
|
151
22
|
* ```
|
|
152
23
|
*/
|
|
153
|
-
|
|
154
|
-
path: string,
|
|
155
|
-
handler: (c: Context) => ReadableStream<any> | Promise<ReadableStream<any>>
|
|
156
|
-
): this;
|
|
24
|
+
websocket(path: string, ...args: any[]): this;
|
|
157
25
|
|
|
158
26
|
/**
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* @param path - The route path
|
|
162
|
-
* @param middleware - Middleware to run before streaming
|
|
163
|
-
* @param handler - Handler returning a ReadableStream
|
|
164
|
-
*
|
|
165
|
-
* @example
|
|
27
|
+
* @deprecated Use the `sse` middleware instead:
|
|
166
28
|
* ```typescript
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* start(controller) {
|
|
170
|
-
* controller.enqueue('secure data\n');
|
|
171
|
-
* controller.close();
|
|
172
|
-
* }
|
|
173
|
-
* });
|
|
174
|
-
* });
|
|
29
|
+
* import { sse } from '@agentuity/runtime';
|
|
30
|
+
* router.get('/events', sse((c, stream) => { ... }));
|
|
175
31
|
* ```
|
|
176
32
|
*/
|
|
177
|
-
|
|
178
|
-
path: string,
|
|
179
|
-
middleware: MiddlewareHandler,
|
|
180
|
-
handler: (c: Context) => ReadableStream<any> | Promise<ReadableStream<any>>
|
|
181
|
-
): this;
|
|
33
|
+
sse(path: string, ...args: any[]): this;
|
|
182
34
|
|
|
183
35
|
/**
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* @param path - The route path
|
|
187
|
-
* @param handler - Setup function that registers WebSocket event handlers
|
|
188
|
-
*
|
|
189
|
-
* @example
|
|
36
|
+
* @deprecated Use the `stream` middleware instead:
|
|
190
37
|
* ```typescript
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* console.log('WebSocket opened');
|
|
194
|
-
* ws.send('Welcome!');
|
|
195
|
-
* });
|
|
196
|
-
*
|
|
197
|
-
* ws.onMessage((event) => {
|
|
198
|
-
* console.log('Received:', event.data);
|
|
199
|
-
* ws.send('Echo: ' + event.data);
|
|
200
|
-
* });
|
|
201
|
-
*
|
|
202
|
-
* ws.onClose((event) => {
|
|
203
|
-
* console.log('WebSocket closed');
|
|
204
|
-
* });
|
|
205
|
-
* });
|
|
38
|
+
* import { stream } from '@agentuity/runtime';
|
|
39
|
+
* router.post('/data', stream((c) => new ReadableStream({ ... })));
|
|
206
40
|
* ```
|
|
207
41
|
*/
|
|
208
|
-
|
|
42
|
+
stream(path: string, ...args: any[]): this;
|
|
209
43
|
|
|
210
44
|
/**
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* @param path - The route path
|
|
214
|
-
* @param middleware - Middleware to run before WebSocket upgrade
|
|
215
|
-
* @param handler - Setup function that registers WebSocket event handlers
|
|
216
|
-
*
|
|
217
|
-
* @example
|
|
45
|
+
* @deprecated Use the `cron` middleware instead:
|
|
218
46
|
* ```typescript
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* ws.send('Authenticated echo: ' + event.data);
|
|
222
|
-
* });
|
|
223
|
-
* });
|
|
47
|
+
* import { cron } from '@agentuity/runtime';
|
|
48
|
+
* router.post('/job', cron('0 0 * * *', (c) => { ... }));
|
|
224
49
|
* ```
|
|
225
50
|
*/
|
|
226
|
-
|
|
227
|
-
path: string,
|
|
228
|
-
middleware: MiddlewareHandler,
|
|
229
|
-
handler: (c: Context) => (ws: WebSocketConnection) => void
|
|
230
|
-
): this;
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Create a Server-Sent Events (SSE) route for streaming updates to clients.
|
|
234
|
-
*
|
|
235
|
-
* @param path - The route path
|
|
236
|
-
* @param handler - Handler receiving SSE stream writer
|
|
237
|
-
*
|
|
238
|
-
* @example
|
|
239
|
-
* ```typescript
|
|
240
|
-
* router.sse('/notifications', (c) => async (stream) => {
|
|
241
|
-
* let count = 0;
|
|
242
|
-
* const interval = setInterval(() => {
|
|
243
|
-
* stream.writeSSE({
|
|
244
|
-
* data: `Notification ${++count}`,
|
|
245
|
-
* event: 'notification'
|
|
246
|
-
* });
|
|
247
|
-
* if (count >= 10) {
|
|
248
|
-
* clearInterval(interval);
|
|
249
|
-
* stream.close();
|
|
250
|
-
* }
|
|
251
|
-
* }, 1000);
|
|
252
|
-
* });
|
|
253
|
-
* ```
|
|
254
|
-
*/
|
|
255
|
-
sse(path: string, handler: (c: Context) => (stream: any) => void): this;
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Create an SSE route with middleware.
|
|
259
|
-
*
|
|
260
|
-
* @param path - The route path
|
|
261
|
-
* @param middleware - Middleware to run before SSE streaming
|
|
262
|
-
* @param handler - Handler receiving SSE stream writer
|
|
263
|
-
*
|
|
264
|
-
* @example
|
|
265
|
-
* ```typescript
|
|
266
|
-
* router.sse('/protected-events', authMiddleware, (c) => async (stream) => {
|
|
267
|
-
* stream.writeSSE({ data: 'Secure event', event: 'update' });
|
|
268
|
-
* stream.close();
|
|
269
|
-
* });
|
|
270
|
-
* ```
|
|
271
|
-
*/
|
|
272
|
-
sse(
|
|
273
|
-
path: string,
|
|
274
|
-
middleware: MiddlewareHandler,
|
|
275
|
-
handler: (c: Context) => (stream: any) => void
|
|
276
|
-
): this;
|
|
51
|
+
cron(schedule: string, ...args: any[]): this;
|
|
277
52
|
}
|
|
278
53
|
}
|
|
279
54
|
|
|
280
55
|
/**
|
|
281
56
|
* Creates a Hono router with extended methods for Agentuity-specific routing patterns.
|
|
282
57
|
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
* - **
|
|
287
|
-
* - **
|
|
288
|
-
* - **
|
|
289
|
-
* - **cron()** - Scheduled
|
|
58
|
+
* Standard HTTP methods (get, post, put, delete, patch) are available, plus middleware
|
|
59
|
+
* functions for specialized protocols:
|
|
60
|
+
*
|
|
61
|
+
* - **websocket()** - WebSocket connections (import { websocket } from '@agentuity/runtime')
|
|
62
|
+
* - **sse()** - Server-Sent Events (import { sse } from '@agentuity/runtime')
|
|
63
|
+
* - **stream()** - Streaming responses (import { stream } from '@agentuity/runtime')
|
|
64
|
+
* - **cron()** - Scheduled tasks (import { cron } from '@agentuity/runtime')
|
|
290
65
|
*
|
|
291
66
|
* @template E - Environment type (Hono Env)
|
|
292
67
|
* @template S - Schema type for route definitions
|
|
293
68
|
*
|
|
294
|
-
* @returns Extended Hono router
|
|
69
|
+
* @returns Extended Hono router
|
|
295
70
|
*
|
|
296
71
|
* @example
|
|
297
72
|
* ```typescript
|
|
73
|
+
* import { createRouter, websocket, sse, stream, cron } from '@agentuity/runtime';
|
|
74
|
+
*
|
|
298
75
|
* const router = createRouter();
|
|
299
76
|
*
|
|
300
77
|
* // Standard HTTP routes
|
|
@@ -304,54 +81,32 @@ declare module 'hono' {
|
|
|
304
81
|
* return c.json({ received: body });
|
|
305
82
|
* });
|
|
306
83
|
*
|
|
307
|
-
* // Streaming response
|
|
308
|
-
* router.stream('/events', (c) => {
|
|
309
|
-
* return new ReadableStream({
|
|
310
|
-
* start(controller) {
|
|
311
|
-
* controller.enqueue('event 1\n');
|
|
312
|
-
* controller.enqueue('event 2\n');
|
|
313
|
-
* controller.close();
|
|
314
|
-
* }
|
|
315
|
-
* });
|
|
316
|
-
* });
|
|
317
|
-
*
|
|
318
84
|
* // WebSocket connection
|
|
319
|
-
* router.
|
|
85
|
+
* router.get('/ws', websocket((c, ws) => {
|
|
320
86
|
* ws.onMessage((event) => {
|
|
321
|
-
* console.log('Received:', event.data);
|
|
322
87
|
* ws.send('Echo: ' + event.data);
|
|
323
88
|
* });
|
|
324
|
-
* });
|
|
89
|
+
* }));
|
|
325
90
|
*
|
|
326
91
|
* // Server-Sent Events
|
|
327
|
-
* router.
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
* stream.writeSSE({ data: `Message ${++count}` });
|
|
331
|
-
* if (count >= 10) {
|
|
332
|
-
* clearInterval(interval);
|
|
333
|
-
* stream.close();
|
|
334
|
-
* }
|
|
335
|
-
* }, 1000);
|
|
336
|
-
* });
|
|
92
|
+
* router.get('/events', sse((c, stream) => {
|
|
93
|
+
* stream.writeSSE({ data: 'Hello', event: 'message' });
|
|
94
|
+
* }));
|
|
337
95
|
*
|
|
338
|
-
* //
|
|
339
|
-
* router.
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
* return c.text('SMS received');
|
|
348
|
-
* });
|
|
96
|
+
* // Streaming response
|
|
97
|
+
* router.post('/stream', stream((c) => {
|
|
98
|
+
* return new ReadableStream({
|
|
99
|
+
* start(controller) {
|
|
100
|
+
* controller.enqueue('data\n');
|
|
101
|
+
* controller.close();
|
|
102
|
+
* }
|
|
103
|
+
* });
|
|
104
|
+
* }));
|
|
349
105
|
*
|
|
350
|
-
* //
|
|
351
|
-
* router.cron('0 0 * * *', (c) => {
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
* });
|
|
106
|
+
* // Cron job
|
|
107
|
+
* router.post('/daily', cron('0 0 * * *', (c) => {
|
|
108
|
+
* return { status: 'complete' };
|
|
109
|
+
* }));
|
|
355
110
|
* ```
|
|
356
111
|
*/
|
|
357
112
|
export const createRouter = <E extends Env = Env, S extends Schema = Schema>(): Hono<E, S> => {
|
|
@@ -405,314 +160,72 @@ export const createRouter = <E extends Env = Env, S extends Schema = Schema>():
|
|
|
405
160
|
};
|
|
406
161
|
}
|
|
407
162
|
|
|
408
|
-
//
|
|
409
|
-
_router.
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
const contentType = (c.req.header('content-type') || '').trim().toLowerCase();
|
|
425
|
-
if (!contentType.includes('message/rfc822')) {
|
|
426
|
-
return c.text('Bad Request: Content-Type must be message/rfc822', 400);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const arrayBuffer = await c.req.arrayBuffer();
|
|
430
|
-
const buffer = Buffer.from(arrayBuffer);
|
|
431
|
-
|
|
432
|
-
const email = await parseEmail(buffer);
|
|
433
|
-
|
|
434
|
-
let result = handler(email, c);
|
|
435
|
-
if (result instanceof Promise) result = await result;
|
|
436
|
-
|
|
437
|
-
if (result === undefined) {
|
|
438
|
-
return c.text('OK', 200);
|
|
439
|
-
}
|
|
440
|
-
return returnResponse(c, result);
|
|
441
|
-
};
|
|
442
|
-
|
|
443
|
-
if (middleware) {
|
|
444
|
-
return router.post(path, middleware, wrapper);
|
|
445
|
-
} else {
|
|
446
|
-
return router.post(path, wrapper);
|
|
447
|
-
}
|
|
163
|
+
// Deprecated stubs that throw errors with migration instructions
|
|
164
|
+
_router.websocket = (path: string, ..._args: any[]) => {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`router.websocket() is deprecated and has been removed.\n\n` +
|
|
167
|
+
`Migration: Use the websocket middleware instead:\n\n` +
|
|
168
|
+
` import { createRouter, websocket } from '@agentuity/runtime';\n\n` +
|
|
169
|
+
` const router = createRouter();\n\n` +
|
|
170
|
+
` // Before (deprecated):\n` +
|
|
171
|
+
` // router.websocket('${path}', (c) => (ws) => { ... });\n\n` +
|
|
172
|
+
` // After:\n` +
|
|
173
|
+
` router.get('${path}', websocket((c, ws) => {\n` +
|
|
174
|
+
` ws.onMessage((event) => {\n` +
|
|
175
|
+
` ws.send('Echo: ' + event.data);\n` +
|
|
176
|
+
` });\n` +
|
|
177
|
+
` }));`
|
|
178
|
+
);
|
|
448
179
|
};
|
|
449
180
|
|
|
450
|
-
_router.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
181
|
+
_router.sse = (path: string, ..._args: any[]) => {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`router.sse() is deprecated and has been removed.\n\n` +
|
|
184
|
+
`Migration: Use the sse middleware instead:\n\n` +
|
|
185
|
+
` import { createRouter, sse } from '@agentuity/runtime';\n\n` +
|
|
186
|
+
` const router = createRouter();\n\n` +
|
|
187
|
+
` // Before (deprecated):\n` +
|
|
188
|
+
` // router.sse('${path}', (c) => async (stream) => { ... });\n\n` +
|
|
189
|
+
` // After:\n` +
|
|
190
|
+
` router.get('${path}', sse((c, stream) => {\n` +
|
|
191
|
+
` stream.writeSSE({ data: 'Hello', event: 'message' });\n` +
|
|
192
|
+
` }));`
|
|
193
|
+
);
|
|
460
194
|
};
|
|
461
195
|
|
|
462
|
-
_router.
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
196
|
+
_router.stream = (path: string, ..._args: any[]) => {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`router.stream() is deprecated and has been removed.\n\n` +
|
|
199
|
+
`Migration: Use the stream middleware instead:\n\n` +
|
|
200
|
+
` import { createRouter, stream } from '@agentuity/runtime';\n\n` +
|
|
201
|
+
` const router = createRouter();\n\n` +
|
|
202
|
+
` // Before (deprecated):\n` +
|
|
203
|
+
` // router.stream('${path}', (c) => new ReadableStream({ ... }));\n\n` +
|
|
204
|
+
` // After:\n` +
|
|
205
|
+
` router.post('${path}', stream((c) => {\n` +
|
|
206
|
+
` return new ReadableStream({\n` +
|
|
207
|
+
` start(controller) {\n` +
|
|
208
|
+
` controller.enqueue('data\\n');\n` +
|
|
209
|
+
` controller.close();\n` +
|
|
210
|
+
` }\n` +
|
|
211
|
+
` });\n` +
|
|
212
|
+
` }));`
|
|
213
|
+
);
|
|
472
214
|
};
|
|
473
215
|
|
|
474
|
-
_router.
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
const asyncLocalStorage = getAgentAsyncLocalStorage();
|
|
488
|
-
const capturedContext = asyncLocalStorage.getStore();
|
|
489
|
-
|
|
490
|
-
// Set Content-Type header for streaming response detection by clients
|
|
491
|
-
c.header('Content-Type', 'application/octet-stream');
|
|
492
|
-
|
|
493
|
-
return honoStream(c, async (s: any) => {
|
|
494
|
-
const runInContext = async () => {
|
|
495
|
-
try {
|
|
496
|
-
let streamResult = handler(c);
|
|
497
|
-
if (streamResult instanceof Promise) streamResult = await streamResult;
|
|
498
|
-
await s.pipe(streamResult);
|
|
499
|
-
} catch (err) {
|
|
500
|
-
c.var.logger.error('Stream error:', err);
|
|
501
|
-
throw err;
|
|
502
|
-
}
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
if (capturedContext) {
|
|
506
|
-
await asyncLocalStorage.run(capturedContext, runInContext);
|
|
507
|
-
} else {
|
|
508
|
-
await runInContext();
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
// Use POST for stream routes - allows accepting request body
|
|
514
|
-
// (validators will handle input validation if present)
|
|
515
|
-
if (middleware) {
|
|
516
|
-
return router.post(path, middleware, wrapper);
|
|
517
|
-
} else {
|
|
518
|
-
return router.post(path, wrapper);
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
_router.websocket = (path: string, ...args: any[]) => {
|
|
523
|
-
let middleware: MiddlewareHandler | undefined;
|
|
524
|
-
let handler: WebSocketHandler;
|
|
525
|
-
|
|
526
|
-
if (args.length === 1) {
|
|
527
|
-
handler = args[0];
|
|
528
|
-
} else {
|
|
529
|
-
middleware = args[0];
|
|
530
|
-
handler = args[1];
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Use upgradeWebSocket directly from hono/bun
|
|
534
|
-
const wrapper = upgradeWebSocket((c: Context) => {
|
|
535
|
-
let openHandler: ((event: any) => void | Promise<void>) | undefined;
|
|
536
|
-
let messageHandler: ((event: any) => void | Promise<void>) | undefined;
|
|
537
|
-
let closeHandler: ((event: any) => void | Promise<void>) | undefined;
|
|
538
|
-
let initialized = false;
|
|
539
|
-
|
|
540
|
-
// Capture the AgentContext from the upgrade request
|
|
541
|
-
const asyncLocalStorage = getAgentAsyncLocalStorage();
|
|
542
|
-
const capturedContext = asyncLocalStorage.getStore();
|
|
543
|
-
|
|
544
|
-
const wsConnection: WebSocketConnection = {
|
|
545
|
-
onOpen: (h) => {
|
|
546
|
-
openHandler = h;
|
|
547
|
-
},
|
|
548
|
-
onMessage: (h) => {
|
|
549
|
-
messageHandler = h;
|
|
550
|
-
},
|
|
551
|
-
onClose: (h) => {
|
|
552
|
-
closeHandler = h;
|
|
553
|
-
},
|
|
554
|
-
send: (_data: string | ArrayBuffer | Uint8Array) => {
|
|
555
|
-
// This will be bound to the actual ws in the handlers
|
|
556
|
-
},
|
|
557
|
-
};
|
|
558
|
-
|
|
559
|
-
const setupResult = handler(c);
|
|
560
|
-
const setupFn = typeof setupResult === 'function' ? setupResult : null;
|
|
561
|
-
|
|
562
|
-
// Call setup IMMEDIATELY during upgrade, not in onOpen
|
|
563
|
-
// This allows the user's code to register handlers before events fire
|
|
564
|
-
if (setupFn) {
|
|
565
|
-
if (capturedContext) {
|
|
566
|
-
asyncLocalStorage.run(capturedContext, () => setupFn(wsConnection));
|
|
567
|
-
} else {
|
|
568
|
-
setupFn(wsConnection);
|
|
569
|
-
}
|
|
570
|
-
initialized = true;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
return {
|
|
574
|
-
onOpen: async (event: any, ws: any) => {
|
|
575
|
-
try {
|
|
576
|
-
// Bind the real ws.send now that we have the actual websocket
|
|
577
|
-
wsConnection.send = (data) => ws.send(data);
|
|
578
|
-
|
|
579
|
-
if (openHandler) {
|
|
580
|
-
// Run handler in captured context
|
|
581
|
-
const handler = openHandler;
|
|
582
|
-
if (capturedContext) {
|
|
583
|
-
await asyncLocalStorage.run(capturedContext, () => handler(event));
|
|
584
|
-
} else {
|
|
585
|
-
await handler(event);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
} catch (err) {
|
|
589
|
-
c.var.logger?.error('WebSocket onOpen error:', err);
|
|
590
|
-
throw err;
|
|
591
|
-
}
|
|
592
|
-
},
|
|
593
|
-
onMessage: async (event: any, ws: any) => {
|
|
594
|
-
try {
|
|
595
|
-
// Lazy initialization fallback (shouldn't normally happen)
|
|
596
|
-
if (!initialized && setupFn) {
|
|
597
|
-
wsConnection.send = (data) => ws.send(data);
|
|
598
|
-
if (capturedContext) {
|
|
599
|
-
await asyncLocalStorage.run(capturedContext, async () => {
|
|
600
|
-
const result = setupFn(wsConnection);
|
|
601
|
-
if (result instanceof Promise) await result;
|
|
602
|
-
});
|
|
603
|
-
} else {
|
|
604
|
-
const result = setupFn(wsConnection);
|
|
605
|
-
if (result instanceof Promise) await result;
|
|
606
|
-
}
|
|
607
|
-
initialized = true;
|
|
608
|
-
}
|
|
609
|
-
if (messageHandler) {
|
|
610
|
-
// Run handler in captured context
|
|
611
|
-
const handler = messageHandler;
|
|
612
|
-
if (capturedContext) {
|
|
613
|
-
await asyncLocalStorage.run(capturedContext, () => handler(event));
|
|
614
|
-
} else {
|
|
615
|
-
await handler(event);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
} catch (err) {
|
|
619
|
-
c.var.logger?.error('WebSocket onMessage error:', err);
|
|
620
|
-
throw err;
|
|
621
|
-
}
|
|
622
|
-
},
|
|
623
|
-
onClose: async (event: any, _ws: any) => {
|
|
624
|
-
try {
|
|
625
|
-
if (closeHandler) {
|
|
626
|
-
// Run handler in captured context
|
|
627
|
-
const handler = closeHandler;
|
|
628
|
-
if (capturedContext) {
|
|
629
|
-
await asyncLocalStorage.run(capturedContext, () => handler(event));
|
|
630
|
-
} else {
|
|
631
|
-
await handler(event);
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
} catch (err) {
|
|
635
|
-
c.var.logger?.error('WebSocket onClose error:', err);
|
|
636
|
-
}
|
|
637
|
-
},
|
|
638
|
-
};
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
// wrapper is what upgradeWebSocket(...) returned. Force arity=2 so our get shim
|
|
642
|
-
// recognizes it as middleware and does not wrap/convert undefined -> 200.
|
|
643
|
-
const wsMiddleware: MiddlewareHandler = (c, next) =>
|
|
644
|
-
(wrapper as unknown as MiddlewareHandler)(c, next);
|
|
645
|
-
|
|
646
|
-
if (middleware) {
|
|
647
|
-
// Compose into a single middleware to avoid the 3-arg route which treats the
|
|
648
|
-
// second function as a handler and wraps it.
|
|
649
|
-
const composed: MiddlewareHandler = async (c, next) => {
|
|
650
|
-
return middleware(c, async () => {
|
|
651
|
-
await wsMiddleware(c, next);
|
|
652
|
-
});
|
|
653
|
-
};
|
|
654
|
-
return router.get(path, composed);
|
|
655
|
-
} else {
|
|
656
|
-
return router.get(path, wsMiddleware);
|
|
657
|
-
}
|
|
658
|
-
};
|
|
659
|
-
|
|
660
|
-
_router.sse = (path: string, ...args: any[]) => {
|
|
661
|
-
let middleware: MiddlewareHandler | undefined;
|
|
662
|
-
let handler: SSEHandler;
|
|
663
|
-
|
|
664
|
-
if (args.length === 1) {
|
|
665
|
-
handler = args[0];
|
|
666
|
-
} else {
|
|
667
|
-
middleware = args[0];
|
|
668
|
-
handler = args[1];
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
const wrapper = (c: Context) => {
|
|
672
|
-
// Capture the AgentContext from the request
|
|
673
|
-
const asyncLocalStorage = getAgentAsyncLocalStorage();
|
|
674
|
-
const capturedContext = asyncLocalStorage.getStore();
|
|
675
|
-
|
|
676
|
-
return honoStreamSSE(c, async (stream: any) => {
|
|
677
|
-
// Wrap the stream to intercept write() calls
|
|
678
|
-
const wrappedStream = {
|
|
679
|
-
...stream,
|
|
680
|
-
write: async (data: any) => {
|
|
681
|
-
// Convert simple write to writeSSE format
|
|
682
|
-
if (
|
|
683
|
-
typeof data === 'string' ||
|
|
684
|
-
typeof data === 'number' ||
|
|
685
|
-
typeof data === 'boolean'
|
|
686
|
-
) {
|
|
687
|
-
return stream.writeSSE({ data: String(data) });
|
|
688
|
-
} else if (typeof data === 'object' && data !== null) {
|
|
689
|
-
// If it's already an SSE message object, pass it through
|
|
690
|
-
return stream.writeSSE(data);
|
|
691
|
-
}
|
|
692
|
-
return stream.writeSSE({ data: String(data) });
|
|
693
|
-
},
|
|
694
|
-
writeSSE: stream.writeSSE.bind(stream),
|
|
695
|
-
onAbort: stream.onAbort.bind(stream),
|
|
696
|
-
close: stream.close?.bind(stream),
|
|
697
|
-
};
|
|
698
|
-
|
|
699
|
-
const runInContext = async () => {
|
|
700
|
-
await handler(c)(wrappedStream);
|
|
701
|
-
};
|
|
702
|
-
|
|
703
|
-
if (capturedContext) {
|
|
704
|
-
await asyncLocalStorage.run(capturedContext, runInContext);
|
|
705
|
-
} else {
|
|
706
|
-
await runInContext();
|
|
707
|
-
}
|
|
708
|
-
});
|
|
709
|
-
};
|
|
710
|
-
|
|
711
|
-
if (middleware) {
|
|
712
|
-
return router.get(path, middleware, wrapper);
|
|
713
|
-
} else {
|
|
714
|
-
return router.get(path, wrapper);
|
|
715
|
-
}
|
|
216
|
+
_router.cron = (schedule: string, ..._args: any[]) => {
|
|
217
|
+
throw new Error(
|
|
218
|
+
`router.cron() is deprecated and has been removed.\n\n` +
|
|
219
|
+
`Migration: Use the cron middleware instead:\n\n` +
|
|
220
|
+
` import { createRouter, cron } from '@agentuity/runtime';\n\n` +
|
|
221
|
+
` const router = createRouter();\n\n` +
|
|
222
|
+
` // Before (deprecated):\n` +
|
|
223
|
+
` // router.cron('${schedule}', (c) => { ... });\n\n` +
|
|
224
|
+
` // After:\n` +
|
|
225
|
+
` router.post('/your-cron-path', cron('${schedule}', (c) => {\n` +
|
|
226
|
+
` return { status: 'complete' };\n` +
|
|
227
|
+
` }));`
|
|
228
|
+
);
|
|
716
229
|
};
|
|
717
230
|
|
|
718
231
|
return router;
|