@agentuity/cli 1.0.59 → 2.0.0-beta.1
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/bin/cli.ts +2 -3
- package/dist/cmd/build/app-config-extractor.d.ts +27 -0
- package/dist/cmd/build/app-config-extractor.d.ts.map +1 -0
- package/dist/cmd/build/app-config-extractor.js +152 -0
- package/dist/cmd/build/app-config-extractor.js.map +1 -0
- package/dist/cmd/build/app-router-detector.d.ts +2 -5
- package/dist/cmd/build/app-router-detector.d.ts.map +1 -1
- package/dist/cmd/build/app-router-detector.js +130 -154
- package/dist/cmd/build/app-router-detector.js.map +1 -1
- package/dist/cmd/build/ci.d.ts.map +1 -1
- package/dist/cmd/build/ci.js +5 -21
- package/dist/cmd/build/ci.js.map +1 -1
- package/dist/cmd/build/ids.d.ts +11 -0
- package/dist/cmd/build/ids.d.ts.map +1 -0
- package/dist/cmd/build/ids.js +18 -0
- package/dist/cmd/build/ids.js.map +1 -0
- package/dist/cmd/build/index.d.ts.map +1 -1
- package/dist/cmd/build/index.js +8 -0
- package/dist/cmd/build/index.js.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts +8 -4
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +166 -487
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts +43 -14
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +290 -129
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
- package/dist/cmd/build/vite/config-loader.d.ts +15 -20
- package/dist/cmd/build/vite/config-loader.d.ts.map +1 -1
- package/dist/cmd/build/vite/config-loader.js +41 -74
- package/dist/cmd/build/vite/config-loader.js.map +1 -1
- package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/docs-generator.js +0 -2
- package/dist/cmd/build/vite/docs-generator.js.map +1 -1
- package/dist/cmd/build/vite/index.d.ts.map +1 -1
- package/dist/cmd/build/vite/index.js +0 -36
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.d.ts +10 -2
- package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.js +302 -23
- package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
- package/dist/cmd/build/vite/route-discovery.d.ts +11 -38
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/route-discovery.js +97 -177
- package/dist/cmd/build/vite/route-discovery.js.map +1 -1
- package/dist/cmd/build/vite/server-bundler.js +1 -1
- package/dist/cmd/build/vite/server-bundler.js.map +1 -1
- package/dist/cmd/build/vite/static-renderer.d.ts +0 -2
- package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
- package/dist/cmd/build/vite/static-renderer.js +19 -13
- package/dist/cmd/build/vite/static-renderer.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts +6 -3
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js +175 -69
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.d.ts +8 -3
- package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.js +14 -13
- package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +42 -190
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/build/vite/ws-proxy.d.ts +53 -0
- package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -0
- package/dist/cmd/build/vite/ws-proxy.js +95 -0
- package/dist/cmd/build/vite/ws-proxy.js.map +1 -0
- package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
- package/dist/cmd/build/vite-bundler.js +0 -3
- package/dist/cmd/build/vite-bundler.js.map +1 -1
- package/dist/cmd/cloud/deploy-fork.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy-fork.js +15 -36
- package/dist/cmd/cloud/deploy-fork.js.map +1 -1
- package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/exec.js +28 -86
- package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
- package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/run.js +2 -9
- package/dist/cmd/cloud/sandbox/run.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/build.js +2 -2
- package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
- package/dist/cmd/coder/hub-url.d.ts.map +1 -1
- package/dist/cmd/coder/hub-url.js +1 -3
- package/dist/cmd/coder/hub-url.js.map +1 -1
- package/dist/cmd/coder/start.js +6 -6
- package/dist/cmd/coder/start.js.map +1 -1
- package/dist/cmd/coder/tui-init.d.ts +2 -2
- package/dist/cmd/coder/tui-init.js +2 -2
- package/dist/cmd/coder/tui-init.js.map +1 -1
- package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
- package/dist/cmd/dev/file-watcher.js +2 -8
- package/dist/cmd/dev/file-watcher.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +432 -752
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/process-manager.d.ts +104 -0
- package/dist/cmd/dev/process-manager.d.ts.map +1 -0
- package/dist/cmd/dev/process-manager.js +204 -0
- package/dist/cmd/dev/process-manager.js.map +1 -0
- package/dist/errors.d.ts +10 -24
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +12 -42
- package/dist/errors.js.map +1 -1
- package/dist/schema-generator.d.ts.map +1 -1
- package/dist/schema-generator.js +12 -2
- package/dist/schema-generator.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +5 -19
- package/dist/tui.js.map +1 -1
- package/dist/utils/version-mismatch.d.ts +39 -0
- package/dist/utils/version-mismatch.d.ts.map +1 -0
- package/dist/utils/version-mismatch.js +161 -0
- package/dist/utils/version-mismatch.js.map +1 -0
- package/package.json +6 -6
- package/src/cmd/ai/prompt/agent.md +0 -1
- package/src/cmd/ai/prompt/api.md +0 -7
- package/src/cmd/ai/prompt/web.md +51 -213
- package/src/cmd/build/app-config-extractor.ts +186 -0
- package/src/cmd/build/app-router-detector.ts +152 -182
- package/src/cmd/build/ci.ts +5 -21
- package/src/cmd/build/ids.ts +19 -0
- package/src/cmd/build/index.ts +10 -0
- package/src/cmd/build/vite/agent-discovery.ts +208 -679
- package/src/cmd/build/vite/bun-dev-server.ts +383 -146
- package/src/cmd/build/vite/config-loader.ts +45 -77
- package/src/cmd/build/vite/docs-generator.ts +0 -2
- package/src/cmd/build/vite/index.ts +1 -42
- package/src/cmd/build/vite/lifecycle-generator.ts +345 -21
- package/src/cmd/build/vite/route-discovery.ts +116 -274
- package/src/cmd/build/vite/server-bundler.ts +1 -1
- package/src/cmd/build/vite/static-renderer.ts +23 -15
- package/src/cmd/build/vite/vite-asset-server-config.ts +200 -70
- package/src/cmd/build/vite/vite-asset-server.ts +25 -15
- package/src/cmd/build/vite/vite-builder.ts +49 -220
- package/src/cmd/build/vite/ws-proxy.ts +126 -0
- package/src/cmd/build/vite-bundler.ts +0 -4
- package/src/cmd/cloud/deploy-fork.ts +16 -39
- package/src/cmd/cloud/sandbox/exec.ts +23 -130
- package/src/cmd/cloud/sandbox/run.ts +2 -9
- package/src/cmd/cloud/sandbox/snapshot/build.ts +2 -2
- package/src/cmd/coder/hub-url.ts +1 -3
- package/src/cmd/coder/start.ts +6 -6
- package/src/cmd/coder/tui-init.ts +4 -4
- package/src/cmd/dev/file-watcher.ts +2 -9
- package/src/cmd/dev/index.ts +476 -859
- package/src/cmd/dev/process-manager.ts +261 -0
- package/src/errors.ts +12 -44
- package/src/schema-generator.ts +12 -2
- package/src/tui.ts +5 -18
- package/src/utils/version-mismatch.ts +204 -0
- package/dist/cmd/build/ast.d.ts +0 -78
- package/dist/cmd/build/ast.d.ts.map +0 -1
- package/dist/cmd/build/ast.js +0 -2703
- package/dist/cmd/build/ast.js.map +0 -1
- package/dist/cmd/build/entry-generator.d.ts +0 -25
- package/dist/cmd/build/entry-generator.d.ts.map +0 -1
- package/dist/cmd/build/entry-generator.js +0 -695
- package/dist/cmd/build/entry-generator.js.map +0 -1
- package/dist/cmd/build/vite/api-mount-path.d.ts +0 -61
- package/dist/cmd/build/vite/api-mount-path.d.ts.map +0 -1
- package/dist/cmd/build/vite/api-mount-path.js +0 -83
- package/dist/cmd/build/vite/api-mount-path.js.map +0 -1
- package/dist/cmd/build/vite/registry-generator.d.ts +0 -19
- package/dist/cmd/build/vite/registry-generator.d.ts.map +0 -1
- package/dist/cmd/build/vite/registry-generator.js +0 -1108
- package/dist/cmd/build/vite/registry-generator.js.map +0 -1
- package/dist/cmd/build/webanalytics-generator.d.ts +0 -16
- package/dist/cmd/build/webanalytics-generator.d.ts.map +0 -1
- package/dist/cmd/build/webanalytics-generator.js +0 -178
- package/dist/cmd/build/webanalytics-generator.js.map +0 -1
- package/dist/cmd/build/workbench.d.ts +0 -7
- package/dist/cmd/build/workbench.d.ts.map +0 -1
- package/dist/cmd/build/workbench.js +0 -55
- package/dist/cmd/build/workbench.js.map +0 -1
- package/dist/utils/route-migration.d.ts +0 -62
- package/dist/utils/route-migration.d.ts.map +0 -1
- package/dist/utils/route-migration.js +0 -630
- package/dist/utils/route-migration.js.map +0 -1
- package/dist/utils/stream-capture.d.ts +0 -9
- package/dist/utils/stream-capture.d.ts.map +0 -1
- package/dist/utils/stream-capture.js +0 -34
- package/dist/utils/stream-capture.js.map +0 -1
- package/src/cmd/build/ast.ts +0 -3529
- package/src/cmd/build/entry-generator.ts +0 -760
- package/src/cmd/build/vite/api-mount-path.ts +0 -87
- package/src/cmd/build/vite/registry-generator.ts +0 -1267
- package/src/cmd/build/webanalytics-generator.ts +0 -197
- package/src/cmd/build/workbench.ts +0 -58
- package/src/utils/route-migration.ts +0 -757
- package/src/utils/stream-capture.ts +0 -39
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Route Discovery
|
|
2
|
+
* Route Discovery — Explicit Routing Only
|
|
3
3
|
*
|
|
4
|
-
* Discovers routes
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Discovers routes from `createApp({ router })` by importing the router
|
|
5
|
+
* module at build time and reading `router.routes` from the Hono instance.
|
|
6
|
+
*
|
|
7
|
+
* File-based routing (scanning src/api/**) is no longer supported.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import { join, relative } from 'node:path';
|
|
10
|
-
import {
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
11
12
|
import type { Logger } from '../../../types';
|
|
12
|
-
import { parseRoute } from '../ast';
|
|
13
13
|
import { toForwardSlash } from '../../../utils/normalize-path';
|
|
14
14
|
import { detectExplicitRouter, type AppRouterDetection } from '../app-router-detector';
|
|
15
15
|
|
|
@@ -28,34 +28,6 @@ export interface RouteMetadata {
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export interface RouteInfo {
|
|
32
|
-
method: string;
|
|
33
|
-
path: string;
|
|
34
|
-
filename: string;
|
|
35
|
-
hasValidator: boolean;
|
|
36
|
-
routeType: 'api' | 'sms' | 'email' | 'cron' | 'websocket' | 'sse' | 'stream';
|
|
37
|
-
agentVariable?: string;
|
|
38
|
-
agentImportPath?: string;
|
|
39
|
-
agentName?: string;
|
|
40
|
-
agentDescription?: string;
|
|
41
|
-
inputSchemaVariable?: string;
|
|
42
|
-
outputSchemaVariable?: string;
|
|
43
|
-
inputSchemaImportPath?: string;
|
|
44
|
-
inputSchemaImportedName?: string;
|
|
45
|
-
outputSchemaImportPath?: string;
|
|
46
|
-
outputSchemaImportedName?: string;
|
|
47
|
-
inputSchemaCode?: string;
|
|
48
|
-
outputSchemaCode?: string;
|
|
49
|
-
stream?: boolean;
|
|
50
|
-
pathParams?: string[];
|
|
51
|
-
/**
|
|
52
|
-
* When a route is mounted via .route(), its filename is set to the parent file
|
|
53
|
-
* (for dedup filtering). schemaSourceFile preserves the actual file where the
|
|
54
|
-
* route's schema variables are defined/exported, so registry imports resolve correctly.
|
|
55
|
-
*/
|
|
56
|
-
schemaSourceFile?: string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
31
|
/**
|
|
60
32
|
* Extract path parameters from a route path.
|
|
61
33
|
* Matches patterns like :id, :userId, :id?, *path, etc.
|
|
@@ -74,283 +46,154 @@ export function extractPathParams(path: string): string[] {
|
|
|
74
46
|
}
|
|
75
47
|
|
|
76
48
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* When `createApp({ router })` is detected in app.ts, routes are discovered by
|
|
80
|
-
* following the router imports with code-derived mount paths. Otherwise, falls back
|
|
81
|
-
* to scanning src/api/**\/*.ts with filesystem-derived paths.
|
|
49
|
+
* Generate a deterministic route ID from project/deployment/path/method.
|
|
82
50
|
*/
|
|
83
|
-
|
|
84
|
-
srcDir: string,
|
|
51
|
+
function generateRouteId(
|
|
85
52
|
projectId: string,
|
|
86
53
|
deploymentId: string,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
54
|
+
path: string,
|
|
55
|
+
method: string
|
|
56
|
+
): string {
|
|
57
|
+
const hash = createHash('sha256')
|
|
58
|
+
.update(`${projectId}:${deploymentId}:${path}:${method}`)
|
|
59
|
+
.digest('hex')
|
|
60
|
+
.substring(0, 16);
|
|
61
|
+
return `routeid_${hash}`;
|
|
62
|
+
}
|
|
95
63
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
srcDir,
|
|
106
|
-
projectId,
|
|
107
|
-
deploymentId,
|
|
108
|
-
detection,
|
|
109
|
-
logger
|
|
110
|
-
);
|
|
111
|
-
return { ...result, explicitRouter: detection };
|
|
64
|
+
/**
|
|
65
|
+
* Generate a version hash from file contents.
|
|
66
|
+
*/
|
|
67
|
+
async function generateFileVersion(filePath: string): Promise<string> {
|
|
68
|
+
try {
|
|
69
|
+
const content = await Bun.file(filePath).text();
|
|
70
|
+
return createHash('sha256').update(content).digest('hex').substring(0, 16);
|
|
71
|
+
} catch {
|
|
72
|
+
return 'unknown';
|
|
112
73
|
}
|
|
113
|
-
|
|
114
|
-
// Fall back to file-based discovery
|
|
115
|
-
return discoverFileBasedRoutes(srcDir, projectId, deploymentId, logger);
|
|
116
74
|
}
|
|
117
75
|
|
|
118
76
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
77
|
+
* Detect route type from handler metadata or method.
|
|
78
|
+
* Checks for route-meta symbol stamped by handler wrappers (websocket, sse, stream, cron).
|
|
121
79
|
*/
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
logger: Logger
|
|
129
|
-
): Promise<{ routes: RouteMetadata[]; routeInfoList: RouteInfo[] }> {
|
|
130
|
-
const routes: RouteMetadata[] = [];
|
|
131
|
-
const routeInfoList: RouteInfo[] = [];
|
|
132
|
-
const visited = new Set<string>();
|
|
133
|
-
const mountedSubrouters = new Set<string>();
|
|
134
|
-
|
|
135
|
-
for (const mount of detection.mounts) {
|
|
136
|
-
try {
|
|
137
|
-
const parsedRoutes = await parseRoute(rootDir, mount.routerFile, projectId, deploymentId, {
|
|
138
|
-
visitedFiles: visited,
|
|
139
|
-
mountedSubrouters,
|
|
140
|
-
mountPrefix: mount.path,
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
if (parsedRoutes.length > 0) {
|
|
144
|
-
const relFile = './' + toForwardSlash(relative(srcDir, mount.routerFile));
|
|
145
|
-
logger.trace(
|
|
146
|
-
'Discovered %d route(s) from explicit mount at %s (%s)',
|
|
147
|
-
parsedRoutes.length,
|
|
148
|
-
mount.path,
|
|
149
|
-
relFile
|
|
150
|
-
);
|
|
151
|
-
routes.push(...parsedRoutes);
|
|
152
|
-
|
|
153
|
-
for (const route of parsedRoutes) {
|
|
154
|
-
const pathParams = extractPathParams(route.path);
|
|
155
|
-
routeInfoList.push({
|
|
156
|
-
method: route.method.toUpperCase(),
|
|
157
|
-
path: route.path,
|
|
158
|
-
filename: route.filename,
|
|
159
|
-
hasValidator: route.config?.hasValidator === true,
|
|
160
|
-
routeType: route.type || 'api',
|
|
161
|
-
agentVariable: route.config?.agentVariable as string | undefined,
|
|
162
|
-
agentImportPath: route.config?.agentImportPath as string | undefined,
|
|
163
|
-
inputSchemaVariable: route.config?.inputSchemaVariable as string | undefined,
|
|
164
|
-
outputSchemaVariable: route.config?.outputSchemaVariable as string | undefined,
|
|
165
|
-
inputSchemaImportPath: route.config?.inputSchemaImportPath as string | undefined,
|
|
166
|
-
inputSchemaImportedName: route.config?.inputSchemaImportedName as
|
|
167
|
-
| string
|
|
168
|
-
| undefined,
|
|
169
|
-
outputSchemaImportPath: route.config?.outputSchemaImportPath as
|
|
170
|
-
| string
|
|
171
|
-
| undefined,
|
|
172
|
-
outputSchemaImportedName: route.config?.outputSchemaImportedName as
|
|
173
|
-
| string
|
|
174
|
-
| undefined,
|
|
175
|
-
stream:
|
|
176
|
-
route.config?.stream !== undefined && route.config.stream !== null
|
|
177
|
-
? Boolean(route.config.stream)
|
|
178
|
-
: route.type === 'stream'
|
|
179
|
-
? true
|
|
180
|
-
: undefined,
|
|
181
|
-
pathParams: pathParams.length > 0 ? pathParams : undefined,
|
|
182
|
-
schemaSourceFile: route.config?.schemaSourceFile as string | undefined,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
} catch (error) {
|
|
187
|
-
logger.warn(
|
|
188
|
-
'Failed to parse explicit router at %s: %s',
|
|
189
|
-
mount.routerFile,
|
|
190
|
-
error instanceof Error ? error.message : String(error)
|
|
191
|
-
);
|
|
80
|
+
function detectRouteType(handler: unknown): 'api' | 'websocket' | 'sse' | 'stream' | 'cron' {
|
|
81
|
+
// Check for route-meta symbol (future: handler wrappers will tag this)
|
|
82
|
+
if (typeof handler === 'function') {
|
|
83
|
+
const meta = (handler as any)[Symbol.for('agentuity:route-meta')];
|
|
84
|
+
if (meta?.type) {
|
|
85
|
+
return meta.type;
|
|
192
86
|
}
|
|
193
87
|
}
|
|
194
88
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const conflicts = detectRouteConflicts(routeInfoList);
|
|
199
|
-
if (conflicts.length > 0) {
|
|
200
|
-
logger.error('Route conflicts detected:');
|
|
201
|
-
for (const conflict of conflicts) {
|
|
202
|
-
logger.error(' %s', conflict.message);
|
|
203
|
-
for (const route of conflict.routes) {
|
|
204
|
-
logger.error(' - %s %s in %s', route.method, route.path, route.filename);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
throw new Error(
|
|
208
|
-
`Found ${conflicts.length} route conflict(s). Fix the conflicts and try again.`
|
|
209
|
-
);
|
|
89
|
+
// Heuristic: upgradeWebSocket handler has a specific name
|
|
90
|
+
if (typeof handler === 'function' && handler.name === 'upgradeWebSocket') {
|
|
91
|
+
return 'websocket';
|
|
210
92
|
}
|
|
211
93
|
|
|
212
|
-
return
|
|
94
|
+
return 'api';
|
|
213
95
|
}
|
|
214
96
|
|
|
215
97
|
/**
|
|
216
|
-
* Discover routes
|
|
98
|
+
* Discover all routes from explicit router mounts in createApp({ router }).
|
|
99
|
+
*
|
|
100
|
+
* Imports each router module at build time and reads `router.routes` from
|
|
101
|
+
* the Hono instance to extract method, path, and route type.
|
|
102
|
+
*
|
|
103
|
+
* @throws If no explicit router is detected in app.ts
|
|
217
104
|
*/
|
|
218
|
-
async function
|
|
105
|
+
export async function discoverRoutes(
|
|
219
106
|
srcDir: string,
|
|
220
107
|
projectId: string,
|
|
221
108
|
deploymentId: string,
|
|
222
109
|
logger: Logger
|
|
223
|
-
): Promise<{
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
110
|
+
): Promise<{
|
|
111
|
+
routes: RouteMetadata[];
|
|
112
|
+
explicitRouter?: AppRouterDetection;
|
|
113
|
+
}> {
|
|
114
|
+
const rootDir = join(srcDir, '..');
|
|
227
115
|
|
|
228
|
-
|
|
229
|
-
if (!
|
|
230
|
-
logger.
|
|
231
|
-
return { routes
|
|
116
|
+
const detection = await detectExplicitRouter(rootDir, logger);
|
|
117
|
+
if (!detection.detected || detection.mounts.length === 0) {
|
|
118
|
+
logger.debug('No explicit router detected in createApp() — no routes to discover');
|
|
119
|
+
return { routes: [] };
|
|
232
120
|
}
|
|
233
121
|
|
|
234
|
-
|
|
122
|
+
logger.debug(
|
|
123
|
+
'Using explicit router detection (%d mount(s) from createApp)',
|
|
124
|
+
detection.mounts.length
|
|
125
|
+
);
|
|
235
126
|
|
|
236
|
-
|
|
237
|
-
// These files will be parsed standalone AND via .route() — we need to deduplicate
|
|
238
|
-
const mountedSubrouters = new Set<string>();
|
|
127
|
+
const routes: RouteMetadata[] = [];
|
|
239
128
|
|
|
240
|
-
|
|
241
|
-
const glob = new Bun.Glob('**/*.ts');
|
|
242
|
-
for await (const file of glob.scan(apiDir)) {
|
|
243
|
-
const filePath = join(apiDir, file);
|
|
129
|
+
const seenRoutes = new Set<string>();
|
|
244
130
|
|
|
131
|
+
for (const mount of detection.mounts) {
|
|
245
132
|
try {
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
133
|
+
// Import the router module at build time
|
|
134
|
+
const routerModule = await import(mount.routerFile);
|
|
135
|
+
const router = routerModule.default ?? routerModule;
|
|
136
|
+
|
|
137
|
+
// Validate it's a Hono instance with routes
|
|
138
|
+
if (!router || !Array.isArray(router.routes)) {
|
|
139
|
+
logger.warn(
|
|
140
|
+
'Router module at %s does not export a Hono instance with routes',
|
|
141
|
+
mount.routerFile
|
|
142
|
+
);
|
|
252
143
|
continue;
|
|
253
144
|
}
|
|
254
145
|
|
|
255
|
-
const
|
|
256
|
-
const
|
|
146
|
+
const relFile = './' + toForwardSlash(relative(srcDir, mount.routerFile));
|
|
147
|
+
const version = await generateFileVersion(mount.routerFile);
|
|
257
148
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
projectId,
|
|
263
|
-
deploymentId,
|
|
264
|
-
undefined,
|
|
265
|
-
mountedSubrouters
|
|
266
|
-
);
|
|
267
|
-
|
|
268
|
-
if (parsedRoutes.length > 0) {
|
|
269
|
-
logger.trace('Discovered %d route(s) in %s', parsedRoutes.length, relativeFilename);
|
|
270
|
-
routes.push(...parsedRoutes);
|
|
149
|
+
// Filter to actual route handlers (not middleware — middleware uses '*' or ALL method)
|
|
150
|
+
const routeEntries = router.routes.filter(
|
|
151
|
+
(r: any) => r.method !== 'ALL' && r.path !== '*'
|
|
152
|
+
);
|
|
271
153
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
filename: route.filename,
|
|
279
|
-
hasValidator: route.config?.hasValidator === true,
|
|
280
|
-
routeType: route.type || 'api',
|
|
281
|
-
agentVariable: route.config?.agentVariable as string | undefined,
|
|
282
|
-
agentImportPath: route.config?.agentImportPath as string | undefined,
|
|
283
|
-
inputSchemaVariable: route.config?.inputSchemaVariable as string | undefined,
|
|
284
|
-
outputSchemaVariable: route.config?.outputSchemaVariable as string | undefined,
|
|
285
|
-
inputSchemaImportPath: route.config?.inputSchemaImportPath as
|
|
286
|
-
| string
|
|
287
|
-
| undefined,
|
|
288
|
-
inputSchemaImportedName: route.config?.inputSchemaImportedName as
|
|
289
|
-
| string
|
|
290
|
-
| undefined,
|
|
291
|
-
outputSchemaImportPath: route.config?.outputSchemaImportPath as
|
|
292
|
-
| string
|
|
293
|
-
| undefined,
|
|
294
|
-
outputSchemaImportedName: route.config?.outputSchemaImportedName as
|
|
295
|
-
| string
|
|
296
|
-
| undefined,
|
|
297
|
-
stream:
|
|
298
|
-
route.config?.stream !== undefined && route.config.stream !== null
|
|
299
|
-
? Boolean(route.config.stream)
|
|
300
|
-
: route.type === 'stream'
|
|
301
|
-
? true
|
|
302
|
-
: undefined,
|
|
303
|
-
pathParams: pathParams.length > 0 ? pathParams : undefined,
|
|
304
|
-
schemaSourceFile: route.config?.schemaSourceFile as string | undefined,
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
} catch (error) {
|
|
309
|
-
// Skip files that don't have proper router setup
|
|
310
|
-
if (error instanceof Error) {
|
|
311
|
-
if (
|
|
312
|
-
error.message.includes('could not find default export') ||
|
|
313
|
-
error.message.includes('could not find an proper createRouter')
|
|
314
|
-
) {
|
|
315
|
-
logger.trace('Skipping %s: %s', file, error.message);
|
|
316
|
-
} else {
|
|
317
|
-
throw error;
|
|
318
|
-
}
|
|
319
|
-
} else {
|
|
320
|
-
throw error;
|
|
154
|
+
for (const route of routeEntries) {
|
|
155
|
+
const method = String(route.method).toUpperCase();
|
|
156
|
+
// Combine mount path with route path
|
|
157
|
+
let fullPath = route.path;
|
|
158
|
+
if (mount.path !== '/' && !fullPath.startsWith(mount.path)) {
|
|
159
|
+
fullPath = mount.path + (fullPath.startsWith('/') ? fullPath : '/' + fullPath);
|
|
321
160
|
}
|
|
161
|
+
|
|
162
|
+
// Deduplicate (Hono may register same route multiple times for middleware)
|
|
163
|
+
const routeKey = `${method} ${fullPath}`;
|
|
164
|
+
if (seenRoutes.has(routeKey)) continue;
|
|
165
|
+
seenRoutes.add(routeKey);
|
|
166
|
+
|
|
167
|
+
const routeType = detectRouteType(route.handler);
|
|
168
|
+
const id = generateRouteId(projectId, deploymentId, fullPath, method);
|
|
169
|
+
|
|
170
|
+
routes.push({
|
|
171
|
+
id,
|
|
172
|
+
filename: toForwardSlash(relative(rootDir, mount.routerFile)),
|
|
173
|
+
path: fullPath,
|
|
174
|
+
method: method.toLowerCase(),
|
|
175
|
+
version,
|
|
176
|
+
type: routeType,
|
|
177
|
+
});
|
|
322
178
|
}
|
|
323
|
-
} catch (error) {
|
|
324
|
-
logger.warn(`Failed to parse route file ${filePath}: ${error}`);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
179
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
180
|
+
logger.trace(
|
|
181
|
+
'Discovered %d route(s) from explicit mount at %s (%s)',
|
|
182
|
+
routeEntries.length,
|
|
183
|
+
mount.path,
|
|
184
|
+
relFile
|
|
185
|
+
);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
logger.warn(
|
|
188
|
+
'Failed to import router at %s: %s',
|
|
189
|
+
mount.routerFile,
|
|
190
|
+
error instanceof Error ? error.message : String(error)
|
|
191
|
+
);
|
|
336
192
|
}
|
|
337
|
-
|
|
338
|
-
// Remove routes whose filename matches a sub-router file
|
|
339
|
-
// (these are the incorrectly-prefixed standalone routes)
|
|
340
|
-
const filteredRoutes = routes.filter((r) => !subrouterRelPaths.has(r.filename));
|
|
341
|
-
const filteredRouteInfoList = routeInfoList.filter((r) => !subrouterRelPaths.has(r.filename));
|
|
342
|
-
|
|
343
|
-
// Replace arrays in-place
|
|
344
|
-
routes.length = 0;
|
|
345
|
-
routes.push(...filteredRoutes);
|
|
346
|
-
routeInfoList.length = 0;
|
|
347
|
-
routeInfoList.push(...filteredRouteInfoList);
|
|
348
193
|
}
|
|
349
194
|
|
|
350
|
-
logger.debug('Discovered %d route(s)', routes.length);
|
|
351
|
-
|
|
352
195
|
// Check for route conflicts
|
|
353
|
-
const conflicts = detectRouteConflicts(
|
|
196
|
+
const conflicts = detectRouteConflicts(routes);
|
|
354
197
|
if (conflicts.length > 0) {
|
|
355
198
|
logger.error('Route conflicts detected:');
|
|
356
199
|
for (const conflict of conflicts) {
|
|
@@ -364,7 +207,8 @@ async function discoverFileBasedRoutes(
|
|
|
364
207
|
);
|
|
365
208
|
}
|
|
366
209
|
|
|
367
|
-
|
|
210
|
+
logger.debug('Discovered %d route(s) via explicit router detection', routes.length);
|
|
211
|
+
return { routes, explicitRouter: detection };
|
|
368
212
|
}
|
|
369
213
|
|
|
370
214
|
export interface RouteConflict {
|
|
@@ -374,14 +218,13 @@ export interface RouteConflict {
|
|
|
374
218
|
}
|
|
375
219
|
|
|
376
220
|
/**
|
|
377
|
-
* Detect conflicts between routes
|
|
221
|
+
* Detect conflicts between routes.
|
|
378
222
|
*/
|
|
379
223
|
export function detectRouteConflicts(
|
|
380
224
|
routes: Array<{ method: string; path: string; filename: string }>
|
|
381
225
|
): RouteConflict[] {
|
|
382
226
|
const conflicts: RouteConflict[] = [];
|
|
383
227
|
|
|
384
|
-
// Group routes by method+path
|
|
385
228
|
const methodPathMap = new Map<string, Array<{ path: string; filename: string }>>();
|
|
386
229
|
|
|
387
230
|
for (const route of routes) {
|
|
@@ -392,7 +235,6 @@ export function detectRouteConflicts(
|
|
|
392
235
|
methodPathMap.get(key)!.push({ path: route.path, filename: route.filename });
|
|
393
236
|
}
|
|
394
237
|
|
|
395
|
-
// Check for exact duplicates
|
|
396
238
|
for (const [methodPath, routeList] of methodPathMap.entries()) {
|
|
397
239
|
if (routeList.length > 1) {
|
|
398
240
|
const [method = 'UNKNOWN'] = methodPath.split(' ', 2);
|
|
@@ -56,7 +56,7 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
|
|
|
56
56
|
|
|
57
57
|
logger.debug('[server-bundler] Starting server bundle process');
|
|
58
58
|
|
|
59
|
-
const entryPath = join(rootDir, '
|
|
59
|
+
const entryPath = join(rootDir, 'app.ts');
|
|
60
60
|
const outDir = join(rootDir, '.agentuity');
|
|
61
61
|
|
|
62
62
|
logger.debug(`[server-bundler] Entry: ${entryPath}, OutDir: ${outDir}`);
|
|
@@ -17,7 +17,6 @@ import { join } from 'node:path';
|
|
|
17
17
|
import { createRequire } from 'node:module';
|
|
18
18
|
import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from 'node:fs';
|
|
19
19
|
import type { Logger } from '../../../types';
|
|
20
|
-
import { hasFrameworkPlugin } from './config-loader';
|
|
21
20
|
|
|
22
21
|
/** Minimal shape of a TanStack Router route tree node. */
|
|
23
22
|
interface RouteTreeNode {
|
|
@@ -75,8 +74,6 @@ function extractRoutePaths(node: RouteTreeNode): string[] {
|
|
|
75
74
|
export interface StaticRenderOptions {
|
|
76
75
|
rootDir: string;
|
|
77
76
|
logger: Logger;
|
|
78
|
-
/** User plugins from agentuity.config.ts */
|
|
79
|
-
userPlugins: import('vite').PluginOption[];
|
|
80
77
|
}
|
|
81
78
|
|
|
82
79
|
export interface StaticRenderResult {
|
|
@@ -85,7 +82,7 @@ export interface StaticRenderResult {
|
|
|
85
82
|
}
|
|
86
83
|
|
|
87
84
|
export async function runStaticRender(options: StaticRenderOptions): Promise<StaticRenderResult> {
|
|
88
|
-
const { rootDir, logger
|
|
85
|
+
const { rootDir, logger } = options;
|
|
89
86
|
const started = Date.now();
|
|
90
87
|
|
|
91
88
|
const clientDir = join(rootDir, '.agentuity/client');
|
|
@@ -125,27 +122,36 @@ export async function runStaticRender(options: StaticRenderOptions): Promise<Sta
|
|
|
125
122
|
|
|
126
123
|
const projectRequire = createRequire(join(rootDir, 'package.json'));
|
|
127
124
|
let vitePath = 'vite';
|
|
128
|
-
let reactPluginPath = '@vitejs/plugin-react';
|
|
129
125
|
try {
|
|
130
126
|
vitePath = projectRequire.resolve('vite');
|
|
131
|
-
reactPluginPath = projectRequire.resolve('@vitejs/plugin-react');
|
|
132
127
|
} catch {
|
|
133
128
|
// Use CLI's bundled version
|
|
134
129
|
}
|
|
135
130
|
|
|
136
|
-
const { build: viteBuild } = await import(vitePath);
|
|
137
|
-
const reactModule = await import(reactPluginPath);
|
|
138
|
-
const react = reactModule.default;
|
|
131
|
+
const { build: viteBuild, loadConfigFromFile, mergeConfig } = await import(vitePath);
|
|
139
132
|
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
133
|
+
// Load vite.config.ts if it exists (v2 approach)
|
|
134
|
+
let userConfig: import('vite').InlineConfig = {};
|
|
135
|
+
const viteConfigPath = join(rootDir, 'vite.config.ts');
|
|
136
|
+
|
|
137
|
+
if (await Bun.file(viteConfigPath).exists()) {
|
|
138
|
+
try {
|
|
139
|
+
const loaded = await loadConfigFromFile(
|
|
140
|
+
{ command: 'build', mode: 'production' },
|
|
141
|
+
viteConfigPath
|
|
142
|
+
);
|
|
143
|
+
if (loaded?.config) {
|
|
144
|
+
userConfig = loaded.config as import('vite').InlineConfig;
|
|
145
|
+
logger.debug('Loaded vite.config.ts for SSR build');
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
logger.warn('Failed to load vite.config.ts: %s', error);
|
|
149
|
+
}
|
|
144
150
|
}
|
|
145
151
|
|
|
146
|
-
|
|
152
|
+
// Merge user config with SSR build settings
|
|
153
|
+
const ssrConfig = mergeConfig(userConfig, {
|
|
147
154
|
root: rootDir,
|
|
148
|
-
plugins,
|
|
149
155
|
build: {
|
|
150
156
|
ssr: entryServerPath,
|
|
151
157
|
outDir: ssrOutDir,
|
|
@@ -163,6 +169,8 @@ export async function runStaticRender(options: StaticRenderOptions): Promise<Sta
|
|
|
163
169
|
logLevel: isViteDebug ? 'info' : 'warn',
|
|
164
170
|
});
|
|
165
171
|
|
|
172
|
+
await viteBuild(ssrConfig);
|
|
173
|
+
|
|
166
174
|
// Steps 2–4: wrapped in try-finally so SSR artifacts are always cleaned up,
|
|
167
175
|
// even if an exception is thrown during module import, validation, or rendering.
|
|
168
176
|
let routeCount = 0;
|