@agentuity/runtime 1.0.48 → 2.0.0-beta.0

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.
Files changed (104) hide show
  1. package/dist/_globals.d.ts +58 -0
  2. package/dist/_globals.d.ts.map +1 -0
  3. package/dist/_globals.js +71 -0
  4. package/dist/_globals.js.map +1 -0
  5. package/dist/_metadata.d.ts.map +1 -1
  6. package/dist/_metadata.js +14 -0
  7. package/dist/_metadata.js.map +1 -1
  8. package/dist/_process-protection.d.ts +2 -0
  9. package/dist/_process-protection.d.ts.map +1 -1
  10. package/dist/_process-protection.js +14 -23
  11. package/dist/_process-protection.js.map +1 -1
  12. package/dist/_server.d.ts +4 -0
  13. package/dist/_server.d.ts.map +1 -1
  14. package/dist/_server.js +4 -0
  15. package/dist/_server.js.map +1 -1
  16. package/dist/_services.d.ts +1 -1
  17. package/dist/_services.d.ts.map +1 -1
  18. package/dist/_services.js +5 -1
  19. package/dist/_services.js.map +1 -1
  20. package/dist/_standalone.d.ts.map +1 -1
  21. package/dist/_standalone.js +3 -9
  22. package/dist/_standalone.js.map +1 -1
  23. package/dist/agent.d.ts.map +1 -1
  24. package/dist/agent.js +1 -0
  25. package/dist/agent.js.map +1 -1
  26. package/dist/app.d.ts +149 -71
  27. package/dist/app.d.ts.map +1 -1
  28. package/dist/app.js +121 -156
  29. package/dist/app.js.map +1 -1
  30. package/dist/bootstrap.d.ts +44 -0
  31. package/dist/bootstrap.d.ts.map +1 -0
  32. package/dist/bootstrap.js +256 -0
  33. package/dist/bootstrap.js.map +1 -0
  34. package/dist/dev-patches/aisdk.d.ts.map +1 -1
  35. package/dist/dev-patches/aisdk.js +6 -8
  36. package/dist/dev-patches/aisdk.js.map +1 -1
  37. package/dist/dev-patches/gateway.d.ts.map +1 -1
  38. package/dist/dev-patches/gateway.js +7 -8
  39. package/dist/dev-patches/gateway.js.map +1 -1
  40. package/dist/handlers/_route-meta.d.ts +20 -0
  41. package/dist/handlers/_route-meta.d.ts.map +1 -0
  42. package/dist/handlers/_route-meta.js +25 -0
  43. package/dist/handlers/_route-meta.js.map +1 -0
  44. package/dist/handlers/cron.d.ts.map +1 -1
  45. package/dist/handlers/cron.js +3 -1
  46. package/dist/handlers/cron.js.map +1 -1
  47. package/dist/handlers/sse.d.ts +3 -3
  48. package/dist/handlers/sse.d.ts.map +1 -1
  49. package/dist/handlers/sse.js +4 -16
  50. package/dist/handlers/sse.js.map +1 -1
  51. package/dist/handlers/stream.d.ts.map +1 -1
  52. package/dist/handlers/stream.js +4 -12
  53. package/dist/handlers/stream.js.map +1 -1
  54. package/dist/handlers/websocket.d.ts +3 -1
  55. package/dist/handlers/websocket.d.ts.map +1 -1
  56. package/dist/handlers/websocket.js +6 -37
  57. package/dist/handlers/websocket.js.map +1 -1
  58. package/dist/index.d.ts +1 -1
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +1 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/middleware.d.ts +1 -8
  63. package/dist/middleware.d.ts.map +1 -1
  64. package/dist/middleware.js +29 -71
  65. package/dist/middleware.js.map +1 -1
  66. package/dist/otel/logger.d.ts.map +1 -1
  67. package/dist/otel/logger.js +4 -7
  68. package/dist/otel/logger.js.map +1 -1
  69. package/dist/otel/otel.d.ts +4 -1
  70. package/dist/otel/otel.d.ts.map +1 -1
  71. package/dist/otel/otel.js +13 -2
  72. package/dist/otel/otel.js.map +1 -1
  73. package/dist/router.d.ts +10 -62
  74. package/dist/router.d.ts.map +1 -1
  75. package/dist/router.js +9 -146
  76. package/dist/router.js.map +1 -1
  77. package/dist/workbench.d.ts +1 -1
  78. package/dist/workbench.d.ts.map +1 -1
  79. package/dist/workbench.js +120 -12
  80. package/dist/workbench.js.map +1 -1
  81. package/package.json +7 -7
  82. package/src/_globals.ts +92 -0
  83. package/src/_metadata.ts +14 -0
  84. package/src/_process-protection.ts +17 -28
  85. package/src/_server.ts +4 -0
  86. package/src/_services.ts +6 -2
  87. package/src/_standalone.ts +4 -9
  88. package/src/agent.ts +1 -0
  89. package/src/app.ts +294 -195
  90. package/src/bootstrap.ts +316 -0
  91. package/src/dev-patches/aisdk.ts +8 -11
  92. package/src/dev-patches/gateway.ts +9 -11
  93. package/src/globals.d.ts +28 -0
  94. package/src/handlers/_route-meta.ts +31 -0
  95. package/src/handlers/cron.ts +4 -1
  96. package/src/handlers/sse.ts +8 -19
  97. package/src/handlers/stream.ts +5 -12
  98. package/src/handlers/websocket.ts +11 -37
  99. package/src/index.ts +2 -3
  100. package/src/middleware.ts +40 -99
  101. package/src/otel/logger.ts +5 -8
  102. package/src/otel/otel.ts +14 -2
  103. package/src/router.ts +12 -216
  104. package/src/workbench.ts +135 -12
package/src/index.ts CHANGED
@@ -29,6 +29,8 @@ export {
29
29
  // app.ts exports (all app-related functionality)
30
30
  export {
31
31
  type AppConfig,
32
+ type AnalyticsOptions,
33
+ type WorkbenchOptions,
32
34
  type CompressionConfig,
33
35
  type CorsConfig,
34
36
  type Variables,
@@ -40,9 +42,6 @@ export {
40
42
  type ShutdownHook,
41
43
  createApp,
42
44
  getApp,
43
- getAppState,
44
- getAppConfig,
45
- getUserRouter,
46
45
  runShutdown,
47
46
  registerShutdownHook,
48
47
  fireEvent,
package/src/middleware.ts CHANGED
@@ -10,7 +10,7 @@ import { setSignedCookie } from 'hono/cookie';
10
10
  import type { Env, CompressionConfig, CorsConfig } from './app';
11
11
  import { createTrustedCorsOrigin } from './cors';
12
12
  import type { Logger } from './logger';
13
- import { getAppConfig } from './app';
13
+
14
14
  import { generateId } from './session';
15
15
  import { runInHTTPContext } from './_context';
16
16
  import { DURATION_HEADER, TOKENS_HEADER } from './_tokens';
@@ -111,10 +111,6 @@ export function createBaseMiddleware(config: MiddlewareConfig) {
111
111
 
112
112
  // Import services dynamically to avoid circular deps
113
113
  const { getServices } = await import('./_services');
114
- const { getAppState } = await import('./app');
115
-
116
- c.set('app', getAppState());
117
-
118
114
  const services = getServices();
119
115
  c.set('kv', services.kv);
120
116
  c.set('stream', services.stream);
@@ -201,13 +197,7 @@ export function createBaseMiddleware(config: MiddlewareConfig) {
201
197
  export function createCorsMiddleware(staticOptions?: CorsConfig) {
202
198
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
203
199
  return createMiddleware<Env<any>>(async (c, next) => {
204
- // Lazy resolve: merge app config with static options
205
- const appConfig = getAppConfig();
206
- const appCors = appConfig?.cors;
207
- const corsOptions = {
208
- ...appCors,
209
- ...staticOptions,
210
- };
200
+ const corsOptions = { ...staticOptions };
211
201
 
212
202
  // Extract Agentuity-specific options
213
203
  const { sameOrigin, allowedOrigins, ...honoCorsOptions } = corsOptions;
@@ -689,18 +679,27 @@ export function createOtelMiddleware() {
689
679
  }
690
680
  });
691
681
  } else if (wsDone) {
692
- // WebSocket connectiondefer finalization until onClose fires
682
+ // WebSocket upgradeend the span immediately (short-lived upgrade span)
683
+ // Per OTel conventions, spans should be short-lived. The HTTP upgrade
684
+ // request is a discrete event that completes in milliseconds. Keeping
685
+ // a span open for the entire WS connection lifetime (minutes/hours) is
686
+ // non-standard and causes issues with OTel backends.
693
687
  internal.info(
694
- '[request] %s %s - websocket response, deferring finalization until close (session: %s)',
688
+ '[request] %s %s - websocket upgrade, ending span immediately (session: %s)',
695
689
  method,
696
690
  url.pathname,
697
691
  sessionId
698
692
  );
699
693
 
700
- // For WebSocket, we end the span inside waitUntil after the connection closes
701
- shouldEndSpanInFinally = false;
694
+ // End the upgrade span now with the upgrade duration
695
+ const upgradeDurationNs = Math.round(handlerDurationMs * 1_000_000);
696
+ span.setAttribute('@agentuity/request.duration', upgradeDurationNs);
697
+ span.setAttribute('http.status_code', responseStatus);
698
+ span.setStatus({ code: SpanStatusCode.OK });
699
+ span.end();
700
+ shouldEndSpanInFinally = false; // already ended
702
701
 
703
- // Capture pending promises BEFORE adding finalization waitUntil to avoid deadlock
702
+ // Session finalization still defers until WS close, but without holding a span
704
703
  const pendingPromises = handler.getPendingSnapshot();
705
704
  const hasPendingTasks = pendingPromises.length > 0;
706
705
 
@@ -714,11 +713,6 @@ export function createOtelMiddleware() {
714
713
  );
715
714
  }
716
715
 
717
- // Capture values needed for span attributes
718
- const capturedResponseStatus = responseStatus;
719
- const capturedErrorMessage = errorMessage;
720
-
721
- // Use waitUntil to handle WebSocket close and finalization
722
716
  handler.waitUntil(async () => {
723
717
  let wsError: unknown = undefined;
724
718
 
@@ -741,81 +735,43 @@ export function createOtelMiddleware() {
741
735
  );
742
736
  }
743
737
 
744
- // Record duration now that WebSocket is closed
745
- const wsDurationMs = performance.now() - requestStartTime;
746
- const durationNs = Math.round(wsDurationMs * 1_000_000);
747
- internal.info(
748
- '[request] %s %s - recording websocket duration: %sms (session: %s)',
749
- method,
750
- url.pathname,
751
- wsDurationMs.toFixed(2),
752
- sessionId
753
- );
754
-
755
- // Determine final status
756
- const finalStatus = wsError ? 500 : capturedResponseStatus;
738
+ const finalStatus = wsError ? 500 : responseStatus;
757
739
  const finalErrorMessage = wsError
758
740
  ? wsError instanceof Error
759
741
  ? (wsError.stack ?? wsError.message)
760
742
  : String(wsError)
761
- : capturedErrorMessage;
743
+ : errorMessage;
762
744
 
763
- try {
764
- // Wait for pending tasks captured BEFORE this waitUntil was added
765
- if (hasPendingTasks) {
766
- internal.info(
767
- '[request] %s %s - waiting for %d pending waitUntil tasks (session: %s)',
768
- method,
769
- url.pathname,
770
- pendingPromises.length,
771
- sessionId
772
- );
773
- const logger = c.get('logger');
774
- await handler.waitForPromises(pendingPromises, logger, sessionId);
775
- internal.info(
776
- '[request] %s %s - all waitUntil tasks complete (session: %s)',
777
- method,
778
- url.pathname,
779
- sessionId
780
- );
781
- }
782
-
783
- // Finalize session after WebSocket closes
784
- await finalizeSession(
785
- finalStatus >= 500 ? finalStatus : undefined,
786
- finalErrorMessage
787
- );
745
+ // Wait for pending tasks captured BEFORE this waitUntil was added
746
+ if (hasPendingTasks) {
788
747
  internal.info(
789
- '[request] %s %s - websocket session finalization complete (session: %s)',
748
+ '[request] %s %s - waiting for %d pending waitUntil tasks (session: %s)',
790
749
  method,
791
750
  url.pathname,
751
+ pendingPromises.length,
792
752
  sessionId
793
753
  );
794
- } finally {
795
- // Set span attributes and end span AFTER all work is done
796
- span.setAttribute('@agentuity/request.duration', durationNs);
797
- span.setAttribute('http.status_code', finalStatus);
798
-
799
- if (wsError) {
800
- span.setStatus({
801
- code: SpanStatusCode.ERROR,
802
- message: finalErrorMessage ?? 'WebSocket ended with error',
803
- });
804
- if (wsError instanceof Error) {
805
- span.recordException(wsError);
806
- }
807
- } else {
808
- span.setStatus({ code: SpanStatusCode.OK });
809
- }
810
-
811
- span.end();
754
+ const logger = c.get('logger');
755
+ await handler.waitForPromises(pendingPromises, logger, sessionId);
812
756
  internal.info(
813
- '[request] %s %s - websocket span ended (session: %s)',
757
+ '[request] %s %s - all waitUntil tasks complete (session: %s)',
814
758
  method,
815
759
  url.pathname,
816
760
  sessionId
817
761
  );
818
762
  }
763
+
764
+ // Finalize session after WebSocket closes
765
+ await finalizeSession(
766
+ finalStatus >= 500 ? finalStatus : undefined,
767
+ finalErrorMessage
768
+ );
769
+ internal.info(
770
+ '[request] %s %s - websocket session finalization complete (session: %s)',
771
+ method,
772
+ url.pathname,
773
+ sessionId
774
+ );
819
775
  });
820
776
  } else {
821
777
  // Non-streaming: record duration immediately
@@ -1041,30 +997,15 @@ export function createOtelMiddleware() {
1041
997
  * });
1042
998
  * ```
1043
999
  */
1044
- export function createCompressionMiddleware(
1045
- staticConfig?: CompressionConfig,
1046
- /**
1047
- * Optional config resolver for testing. When provided, this is used instead of getAppConfig().
1048
- * @internal
1049
- */
1050
- configResolver?: () => { compression?: CompressionConfig | false } | undefined
1051
- ) {
1000
+ export function createCompressionMiddleware(staticConfig?: CompressionConfig | false) {
1052
1001
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1053
1002
  return createMiddleware<Env<any>>(async (c, next) => {
1054
- // Lazy resolve: merge app config with static config
1055
- const appConfig = configResolver ? configResolver() : getAppConfig();
1056
- const appCompressionConfig = appConfig?.compression;
1057
-
1058
1003
  // Check if compression is explicitly disabled
1059
- if (appCompressionConfig === false || staticConfig?.enabled === false) {
1004
+ if (staticConfig === false || staticConfig?.enabled === false) {
1060
1005
  return next();
1061
1006
  }
1062
1007
 
1063
- // Merge configs: static config takes precedence over app config
1064
- const config: CompressionConfig = {
1065
- ...(typeof appCompressionConfig === 'object' ? appCompressionConfig : {}),
1066
- ...staticConfig,
1067
- };
1008
+ const config: CompressionConfig = { ...staticConfig };
1068
1009
 
1069
1010
  const { enabled = true, threshold = 1024, filter, honoOptions } = config;
1070
1011
 
@@ -4,20 +4,17 @@ import * as LogsAPI from '@opentelemetry/api-logs';
4
4
  import type { Logger } from '../logger';
5
5
  import ConsoleLogger from '../logger/console';
6
6
 
7
+ import { originalConsole as originalConsoleGlobal } from '../_globals';
8
+
7
9
  /**
8
10
  * Reference to the original console object before patching.
9
- * We use a global symbol to ensure we only capture the original console once,
10
- * preventing double-patching on hot reload.
11
+ * Stored in a Symbol.for() global to survive hot reloads.
11
12
  */
12
- const ORIGINAL_CONSOLE_KEY = Symbol.for('agentuity.originalConsole');
13
-
14
- // Check if we've already saved the original console (prevents double-patching on reload)
15
- const existingOriginal = (globalThis as Record<symbol, Console>)[ORIGINAL_CONSOLE_KEY];
13
+ const existingOriginal = originalConsoleGlobal.get();
16
14
  export const __originalConsole: Console = existingOriginal ?? Object.create(console);
17
15
 
18
- // Save to global if not already saved
19
16
  if (!existingOriginal) {
20
- (globalThis as Record<symbol, Console>)[ORIGINAL_CONSOLE_KEY] = __originalConsole;
17
+ originalConsoleGlobal.set(__originalConsole);
21
18
  }
22
19
 
23
20
  export class OtelLogger implements Logger {
package/src/otel/otel.ts CHANGED
@@ -158,13 +158,23 @@ export const createUserLoggerProvider = ({
158
158
  };
159
159
  };
160
160
 
161
+ import { otel as otelGlobal } from '../_globals';
162
+
161
163
  /**
162
- * Registers and initializes OpenTelemetry with the specified configuration
164
+ * Registers and initializes OpenTelemetry with the specified configuration.
165
+ *
166
+ * Idempotent: if called again (e.g. during bun --hot reload), the previous
167
+ * instance is shut down before creating a new one.
163
168
  *
164
169
  * @param config - The configuration for OpenTelemetry
165
170
  * @returns An object containing the tracer, logger, and shutdown function
166
171
  */
167
172
  export function registerOtel(config: OtelConfig): OtelResponse {
173
+ // Shut down previous instance if this is a hot reload
174
+ const previous = otelGlobal.get();
175
+ if (previous) {
176
+ previous.shutdown().catch(() => {});
177
+ }
168
178
  const {
169
179
  url,
170
180
  name,
@@ -338,5 +348,7 @@ export function registerOtel(config: OtelConfig): OtelResponse {
338
348
  logger.info('connected to Agentuity Agent Cloud');
339
349
  }
340
350
 
341
- return { tracer, meter, logger, shutdown };
351
+ const instance: OtelResponse = { tracer, meter, logger, shutdown };
352
+ otelGlobal.set(instance);
353
+ return instance;
342
354
  }
package/src/router.ts CHANGED
@@ -1,7 +1,5 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { type Context, Hono, type Env as HonoEnv, type Schema } from 'hono';
3
- import { loadBuildMetadata } from './_metadata';
4
- import { returnResponse } from './_util';
1
+ import { Hono, type Env as HonoEnv, type Schema } from 'hono';
2
+ import type { BlankSchema } from 'hono/types';
5
3
  import type { Env } from './app';
6
4
 
7
5
  // Re-export both Env types
@@ -14,7 +12,6 @@ export type { WebSocketConnection } from './handlers/websocket';
14
12
  // Module augmentation to extend Hono types for Agentuity runtime
15
13
  declare module 'hono' {
16
14
  // Extend Context with waitUntil for route handlers
17
- // Note: executionCtx is already provided by Hono's Context class
18
15
  interface Context {
19
16
  /**
20
17
  * Schedule a background task that runs after the response is sent.
@@ -32,63 +29,20 @@ declare module 'hono' {
32
29
  */
33
30
  waitUntil(callback: Promise<void> | (() => void | Promise<void>)): void;
34
31
  }
35
-
36
- // Deprecated router methods (stubs that throw errors with migration instructions)
37
- interface Hono {
38
- /**
39
- * @deprecated Use the `websocket` middleware instead:
40
- * ```typescript
41
- * import { websocket } from '@agentuity/runtime';
42
- * router.get('/ws', websocket((c, ws) => { ... }));
43
- * ```
44
- */
45
- websocket(path: string, ...args: any[]): this;
46
-
47
- /**
48
- * @deprecated Use the `sse` middleware instead:
49
- * ```typescript
50
- * import { sse } from '@agentuity/runtime';
51
- * router.get('/events', sse((c, stream) => { ... }));
52
- * ```
53
- */
54
- sse(path: string, ...args: any[]): this;
55
-
56
- /**
57
- * @deprecated Use the `stream` middleware instead:
58
- * ```typescript
59
- * import { stream } from '@agentuity/runtime';
60
- * router.post('/data', stream((c) => new ReadableStream({ ... })));
61
- * ```
62
- */
63
- stream(path: string, ...args: any[]): this;
64
-
65
- /**
66
- * @deprecated Use the `cron` middleware instead:
67
- * ```typescript
68
- * import { cron } from '@agentuity/runtime';
69
- * router.post('/job', cron('0 0 * * *', (c) => { ... }));
70
- * ```
71
- */
72
- cron(schedule: string, ...args: any[]): this;
73
- }
74
32
  }
75
33
 
76
34
  /**
77
- * Creates a Hono router with extended methods for Agentuity-specific routing patterns.
78
- *
79
- * Standard HTTP methods (get, post, put, delete, patch) are available, plus middleware
80
- * functions for specialized protocols:
35
+ * Creates a Hono router for use with Agentuity.
81
36
  *
82
- * - **websocket()** - WebSocket connections (import { websocket } from '@agentuity/runtime')
83
- * - **sse()** - Server-Sent Events (import { sse } from '@agentuity/runtime')
84
- * - **stream()** - Streaming responses (import { stream } from '@agentuity/runtime')
85
- * - **cron()** - Scheduled tasks (import { cron } from '@agentuity/runtime')
86
- * - **webrtc()** - WebRTC signaling (import { webrtc } from '@agentuity/runtime')
37
+ * This is a thin wrapper around `new Hono()` that provides the correct
38
+ * Agentuity environment types. Hono's full type inference chain is
39
+ * preserved the Schema type parameter accumulates route definitions
40
+ * as you chain `.get()`, `.post()`, etc.
87
41
  *
88
- * @template E - Environment type (Hono Env)
42
+ * @template E - Environment type (defaults to Agentuity's Env)
89
43
  * @template S - Schema type for route definitions
90
44
  *
91
- * @returns Extended Hono router
45
+ * @returns Hono router instance
92
46
  *
93
47
  * @example
94
48
  * ```typescript
@@ -96,7 +50,7 @@ declare module 'hono' {
96
50
  *
97
51
  * const router = createRouter();
98
52
  *
99
- * // Standard HTTP routes
53
+ * // Standard HTTP routes — full type inference
100
54
  * router.get('/hello', (c) => c.text('Hello!'));
101
55
  * router.post('/data', async (c) => {
102
56
  * const body = await c.req.json();
@@ -114,166 +68,8 @@ declare module 'hono' {
114
68
  * router.get('/events', sse((c, stream) => {
115
69
  * stream.writeSSE({ data: 'Hello', event: 'message' });
116
70
  * }));
117
- *
118
- * // Streaming response
119
- * router.post('/stream', stream((c) => {
120
- * return new ReadableStream({
121
- * start(controller) {
122
- * controller.enqueue('data\n');
123
- * controller.close();
124
- * }
125
- * });
126
- * }));
127
- *
128
- * // Cron job
129
- * router.post('/daily', cron('0 0 * * *', (c) => {
130
- * return { status: 'complete' };
131
- * }));
132
71
  * ```
133
72
  */
134
- export const createRouter = <E extends Env = Env, S extends Schema = Schema>(): Hono<E, S> => {
135
- const router = new Hono<E, S>();
136
- // tslint:disable-next-line:no-any no-unused-variable
137
- const _router = router as any;
138
-
139
- for (const method of ['get', 'put', 'post', 'delete', 'options', 'patch']) {
140
- const _originalInvoker = _router[method].bind(router);
141
- _router[method] = (path: string, ...args: any[]) => {
142
- // Pass through to original Hono - it handles all the complex type inference
143
- // We'll only wrap the final handler to add our response handling
144
- if (args.length === 0) {
145
- return _originalInvoker(path);
146
- }
147
-
148
- // Find the last function in args - that's the handler (everything else is middleware)
149
- let handlerIndex = args.length - 1;
150
- while (handlerIndex >= 0 && typeof args[handlerIndex] !== 'function') {
151
- handlerIndex--;
152
- }
153
-
154
- if (handlerIndex < 0) {
155
- // No handler found, pass through as-is
156
- return _originalInvoker(path, ...args);
157
- }
158
-
159
- const handler = args[handlerIndex];
160
-
161
- // Check if this is middleware (2 params: c, next) vs handler (1 param: c)
162
- if (handler.length === 2) {
163
- // This is middleware-only, pass through
164
- return _originalInvoker(path, ...args);
165
- }
166
-
167
- // Wrap the handler to add our response conversion and set routeId
168
- const wrapper = async (c: Context): Promise<Response> => {
169
- // Look up the route ID from build metadata by matching method and path
170
- // Try both the registered path and the actual request path (which may include base path)
171
- const metadata = loadBuildMetadata();
172
- const methodUpper = method.toUpperCase();
173
- const requestPath = c.req.routePath || c.req.path;
174
-
175
- // Try matching by registered path first, then by request path, then by path ending
176
- let route = metadata?.routes?.find(
177
- (r) => r.method.toUpperCase() === methodUpper && r.path === path
178
- );
179
- if (!route) {
180
- route = metadata?.routes?.find(
181
- (r) => r.method.toUpperCase() === methodUpper && r.path === requestPath
182
- );
183
- }
184
- if (!route) {
185
- // Try matching by path ending (handles /api/translate matching /translate)
186
- route = metadata?.routes?.find(
187
- (r) => r.method.toUpperCase() === methodUpper && r.path.endsWith(path)
188
- );
189
- }
190
-
191
- if (route?.id) {
192
- (c as any).set('routeId', route.id);
193
- }
194
-
195
- let result = handler(c);
196
- if (result instanceof Promise) result = await result;
197
- // If handler returns a Response, return it unchanged
198
- if (result instanceof Response) return result;
199
- return returnResponse(c, result);
200
- };
201
-
202
- // Replace the handler with our wrapper
203
- const newArgs = [...args];
204
- newArgs[handlerIndex] = wrapper;
205
-
206
- return _originalInvoker(path, ...newArgs);
207
- };
208
- }
209
-
210
- // Deprecated stubs that throw errors with migration instructions
211
- _router.websocket = (path: string, ..._args: any[]) => {
212
- throw new Error(
213
- 'router.websocket() is deprecated and has been removed.\n\n' +
214
- 'Migration: Use the websocket middleware instead:\n\n' +
215
- ` import { createRouter, websocket } from '@agentuity/runtime';\n\n` +
216
- ' const router = createRouter();\n\n' +
217
- ' // Before (deprecated):\n' +
218
- ` // router.websocket('${path}', (c) => (ws) => { ... });\n\n` +
219
- ' // After:\n' +
220
- ` router.get('${path}', websocket((c, ws) => {\n` +
221
- ' ws.onMessage((event) => {\n' +
222
- ` ws.send('Echo: ' + event.data);\n` +
223
- ' });\n' +
224
- ' }));'
225
- );
226
- };
227
-
228
- _router.sse = (path: string, ..._args: any[]) => {
229
- throw new Error(
230
- 'router.sse() is deprecated and has been removed.\n\n' +
231
- 'Migration: Use the sse middleware instead:\n\n' +
232
- ` import { createRouter, sse } from '@agentuity/runtime';\n\n` +
233
- ' const router = createRouter();\n\n' +
234
- ' // Before (deprecated):\n' +
235
- ` // router.sse('${path}', (c) => async (stream) => { ... });\n\n` +
236
- ' // After:\n' +
237
- ` router.get('${path}', sse((c, stream) => {\n` +
238
- ` stream.writeSSE({ data: 'Hello', event: 'message' });\n` +
239
- ' }));'
240
- );
241
- };
242
-
243
- _router.stream = (path: string, ..._args: any[]) => {
244
- throw new Error(
245
- 'router.stream() is deprecated and has been removed.\n\n' +
246
- 'Migration: Use the stream middleware instead:\n\n' +
247
- ` import { createRouter, stream } from '@agentuity/runtime';\n\n` +
248
- ' const router = createRouter();\n\n' +
249
- ' // Before (deprecated):\n' +
250
- ` // router.stream('${path}', (c) => new ReadableStream({ ... }));\n\n` +
251
- ' // After:\n' +
252
- ` router.post('${path}', stream((c) => {\n` +
253
- ' return new ReadableStream({\n' +
254
- ' start(controller) {\n' +
255
- ` controller.enqueue('data\\n');\n` +
256
- ' controller.close();\n' +
257
- ' }\n' +
258
- ' });\n' +
259
- ' }));'
260
- );
261
- };
262
-
263
- _router.cron = (schedule: string, ..._args: any[]) => {
264
- throw new Error(
265
- 'router.cron() is deprecated and has been removed.\n\n' +
266
- 'Migration: Use the cron middleware instead:\n\n' +
267
- ` import { createRouter, cron } from '@agentuity/runtime';\n\n` +
268
- ' const router = createRouter();\n\n' +
269
- ' // Before (deprecated):\n' +
270
- ` // router.cron('${schedule}', (c) => { ... });\n\n` +
271
- ' // After:\n' +
272
- ` router.post('/your-cron-path', cron('${schedule}', (c) => {\n` +
273
- ` return { status: 'complete' };\n` +
274
- ' }));'
275
- );
276
- };
277
-
278
- return router;
73
+ export const createRouter = <E extends Env = Env, S extends Schema = BlankSchema>(): Hono<E, S> => {
74
+ return new Hono<E, S>();
279
75
  };