@vibecheckai/cli 3.2.6 → 3.3.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.
- package/bin/registry.js +192 -5
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
- package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
- package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
- package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
- package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
- package/bin/runners/lib/agent-firewall/logger.js +141 -0
- package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
- package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
- package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
- package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
- package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
- package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
- package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
- package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
- package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
- package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
- package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
- package/bin/runners/lib/analyzers.js +81 -18
- package/bin/runners/lib/authority-badge.js +425 -0
- package/bin/runners/lib/cli-output.js +7 -1
- package/bin/runners/lib/error-handler.js +16 -9
- package/bin/runners/lib/exit-codes.js +275 -0
- package/bin/runners/lib/global-flags.js +37 -0
- package/bin/runners/lib/help-formatter.js +413 -0
- package/bin/runners/lib/logger.js +38 -0
- package/bin/runners/lib/unified-cli-output.js +604 -0
- package/bin/runners/lib/upsell.js +148 -0
- package/bin/runners/runApprove.js +1200 -0
- package/bin/runners/runAuth.js +324 -95
- package/bin/runners/runCheckpoint.js +39 -21
- package/bin/runners/runClassify.js +859 -0
- package/bin/runners/runContext.js +136 -24
- package/bin/runners/runDoctor.js +108 -68
- package/bin/runners/runFix.js +6 -5
- package/bin/runners/runGuard.js +212 -118
- package/bin/runners/runInit.js +3 -2
- package/bin/runners/runMcp.js +130 -52
- package/bin/runners/runPolish.js +43 -20
- package/bin/runners/runProve.js +1 -2
- package/bin/runners/runReport.js +3 -2
- package/bin/runners/runScan.js +63 -44
- package/bin/runners/runShip.js +3 -4
- package/bin/runners/runValidate.js +19 -2
- package/bin/runners/runWatch.js +104 -53
- package/bin/vibecheck.js +106 -19
- package/mcp-server/HARDENING_SUMMARY.md +299 -0
- package/mcp-server/agent-firewall-interceptor.js +367 -31
- package/mcp-server/authority-tools.js +569 -0
- package/mcp-server/conductor/conflict-resolver.js +588 -0
- package/mcp-server/conductor/execution-planner.js +544 -0
- package/mcp-server/conductor/index.js +377 -0
- package/mcp-server/conductor/lock-manager.js +615 -0
- package/mcp-server/conductor/request-queue.js +550 -0
- package/mcp-server/conductor/session-manager.js +500 -0
- package/mcp-server/conductor/tools.js +510 -0
- package/mcp-server/index.js +1149 -243
- package/mcp-server/lib/{api-client.js → api-client.cjs} +40 -4
- package/mcp-server/lib/logger.cjs +30 -0
- package/mcp-server/logger.js +173 -0
- package/mcp-server/package.json +2 -2
- package/mcp-server/premium-tools.js +2 -2
- package/mcp-server/tier-auth.js +245 -35
- package/mcp-server/truth-firewall-tools.js +145 -15
- package/mcp-server/vibecheck-tools.js +2 -2
- package/package.json +2 -3
- package/mcp-server/index.old.js +0 -4137
- package/mcp-server/package-lock.json +0 -165
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates route definitions after simulated changes.
|
|
5
|
+
* Checks for orphaned routes, duplicate routes, and broken route handlers.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
const path = require("path");
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Extract route definitions from source code
|
|
14
|
+
* @param {string} content - File content
|
|
15
|
+
* @param {string} filePath - File path for context
|
|
16
|
+
* @returns {Array} Array of route objects
|
|
17
|
+
*/
|
|
18
|
+
function extractRoutes(content, filePath) {
|
|
19
|
+
const routes = [];
|
|
20
|
+
const fileType = detectFileType(filePath, content);
|
|
21
|
+
|
|
22
|
+
switch (fileType) {
|
|
23
|
+
case "fastify":
|
|
24
|
+
routes.push(...extractFastifyRoutes(content, filePath));
|
|
25
|
+
break;
|
|
26
|
+
case "express":
|
|
27
|
+
routes.push(...extractExpressRoutes(content, filePath));
|
|
28
|
+
break;
|
|
29
|
+
case "nextjs-api":
|
|
30
|
+
routes.push(...extractNextJsApiRoutes(content, filePath));
|
|
31
|
+
break;
|
|
32
|
+
case "nextjs-app":
|
|
33
|
+
routes.push(...extractNextJsAppRoutes(content, filePath));
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
// Try all extractors
|
|
37
|
+
routes.push(...extractGenericRoutes(content, filePath));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return routes;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Detect the type of routing framework used
|
|
45
|
+
*/
|
|
46
|
+
function detectFileType(filePath, content) {
|
|
47
|
+
const lowerPath = filePath.toLowerCase();
|
|
48
|
+
|
|
49
|
+
// Next.js App Router
|
|
50
|
+
if (lowerPath.includes("/app/") && (lowerPath.endsWith("route.ts") || lowerPath.endsWith("route.js"))) {
|
|
51
|
+
return "nextjs-app";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Next.js Pages API
|
|
55
|
+
if (lowerPath.includes("/pages/api/") || lowerPath.includes("/api/")) {
|
|
56
|
+
return "nextjs-api";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Fastify
|
|
60
|
+
if (content.includes("fastify.") || content.includes("app.register") || content.includes(".route({")) {
|
|
61
|
+
return "fastify";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Express
|
|
65
|
+
if (content.includes("express.Router") || content.includes("router.get") || content.includes("app.use")) {
|
|
66
|
+
return "express";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return "unknown";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Extract Fastify routes
|
|
74
|
+
*/
|
|
75
|
+
function extractFastifyRoutes(content, filePath) {
|
|
76
|
+
const routes = [];
|
|
77
|
+
const methods = ["get", "post", "put", "patch", "delete", "head", "options"];
|
|
78
|
+
|
|
79
|
+
for (const method of methods) {
|
|
80
|
+
// Pattern: fastify.get('/path', handler) or app.get('/path', handler)
|
|
81
|
+
const regex = new RegExp(`(?:fastify|app|server)\\.${method}\\s*\\(\\s*['"\`]([^'"\`]+)['"\`]`, "gi");
|
|
82
|
+
let match;
|
|
83
|
+
|
|
84
|
+
while ((match = regex.exec(content)) !== null) {
|
|
85
|
+
routes.push({
|
|
86
|
+
method: method.toUpperCase(),
|
|
87
|
+
path: match[1],
|
|
88
|
+
file: filePath,
|
|
89
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
90
|
+
type: "fastify",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Pattern: .route({ method: 'GET', url: '/path' })
|
|
96
|
+
const routeObjRegex = /\.route\s*\(\s*\{[^}]*method:\s*['"](\w+)['"][^}]*url:\s*['"]([^'"]+)['"][^}]*\}/gi;
|
|
97
|
+
let match;
|
|
98
|
+
|
|
99
|
+
while ((match = routeObjRegex.exec(content)) !== null) {
|
|
100
|
+
routes.push({
|
|
101
|
+
method: match[1].toUpperCase(),
|
|
102
|
+
path: match[2],
|
|
103
|
+
file: filePath,
|
|
104
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
105
|
+
type: "fastify",
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return routes;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Extract Express routes
|
|
114
|
+
*/
|
|
115
|
+
function extractExpressRoutes(content, filePath) {
|
|
116
|
+
const routes = [];
|
|
117
|
+
const methods = ["get", "post", "put", "patch", "delete", "head", "options", "all"];
|
|
118
|
+
|
|
119
|
+
for (const method of methods) {
|
|
120
|
+
// Pattern: router.get('/path', handler) or app.get('/path', handler)
|
|
121
|
+
const regex = new RegExp(`(?:router|app)\\.${method}\\s*\\(\\s*['"\`]([^'"\`]+)['"\`]`, "gi");
|
|
122
|
+
let match;
|
|
123
|
+
|
|
124
|
+
while ((match = regex.exec(content)) !== null) {
|
|
125
|
+
routes.push({
|
|
126
|
+
method: method.toUpperCase(),
|
|
127
|
+
path: match[1],
|
|
128
|
+
file: filePath,
|
|
129
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
130
|
+
type: "express",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Pattern: app.use('/prefix', router)
|
|
136
|
+
const useRegex = /(?:router|app)\.use\s*\(\s*['"]([^'"]+)['"]\s*,/g;
|
|
137
|
+
let match;
|
|
138
|
+
|
|
139
|
+
while ((match = useRegex.exec(content)) !== null) {
|
|
140
|
+
routes.push({
|
|
141
|
+
method: "USE",
|
|
142
|
+
path: match[1],
|
|
143
|
+
file: filePath,
|
|
144
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
145
|
+
type: "express-middleware",
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return routes;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Extract Next.js API routes
|
|
154
|
+
*/
|
|
155
|
+
function extractNextJsApiRoutes(content, filePath) {
|
|
156
|
+
const routes = [];
|
|
157
|
+
|
|
158
|
+
// Derive route path from file path
|
|
159
|
+
const apiMatch = filePath.match(/(?:pages\/api|app)\/(.+?)\.(ts|js|tsx|jsx)$/);
|
|
160
|
+
if (apiMatch) {
|
|
161
|
+
let routePath = "/" + apiMatch[1].replace(/\\/g, "/");
|
|
162
|
+
|
|
163
|
+
// Handle index files
|
|
164
|
+
if (routePath.endsWith("/index")) {
|
|
165
|
+
routePath = routePath.slice(0, -6) || "/";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Handle dynamic routes
|
|
169
|
+
routePath = routePath.replace(/\[([^\]]+)\]/g, ":$1");
|
|
170
|
+
|
|
171
|
+
// Check for exported methods
|
|
172
|
+
const methods = [];
|
|
173
|
+
if (content.includes("export default") || content.includes("export async function handler")) {
|
|
174
|
+
methods.push("GET", "POST", "PUT", "DELETE", "PATCH");
|
|
175
|
+
}
|
|
176
|
+
if (content.match(/export\s+(?:async\s+)?function\s+GET/)) methods.push("GET");
|
|
177
|
+
if (content.match(/export\s+(?:async\s+)?function\s+POST/)) methods.push("POST");
|
|
178
|
+
if (content.match(/export\s+(?:async\s+)?function\s+PUT/)) methods.push("PUT");
|
|
179
|
+
if (content.match(/export\s+(?:async\s+)?function\s+DELETE/)) methods.push("DELETE");
|
|
180
|
+
if (content.match(/export\s+(?:async\s+)?function\s+PATCH/)) methods.push("PATCH");
|
|
181
|
+
|
|
182
|
+
// Default to GET if no explicit methods found
|
|
183
|
+
if (methods.length === 0) {
|
|
184
|
+
methods.push("ALL");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
for (const method of [...new Set(methods)]) {
|
|
188
|
+
routes.push({
|
|
189
|
+
method,
|
|
190
|
+
path: `/api${routePath}`,
|
|
191
|
+
file: filePath,
|
|
192
|
+
line: 1,
|
|
193
|
+
type: "nextjs-api",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return routes;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Extract Next.js App Router routes
|
|
203
|
+
*/
|
|
204
|
+
function extractNextJsAppRoutes(content, filePath) {
|
|
205
|
+
const routes = [];
|
|
206
|
+
|
|
207
|
+
// Derive route path from file path
|
|
208
|
+
const appMatch = filePath.match(/app\/(.+?)\/route\.(ts|js)$/);
|
|
209
|
+
if (appMatch) {
|
|
210
|
+
let routePath = "/" + appMatch[1].replace(/\\/g, "/");
|
|
211
|
+
|
|
212
|
+
// Handle dynamic routes
|
|
213
|
+
routePath = routePath.replace(/\[([^\]]+)\]/g, ":$1");
|
|
214
|
+
|
|
215
|
+
// Check for exported methods
|
|
216
|
+
const methods = [];
|
|
217
|
+
if (content.match(/export\s+(?:async\s+)?function\s+GET/)) methods.push("GET");
|
|
218
|
+
if (content.match(/export\s+(?:async\s+)?function\s+POST/)) methods.push("POST");
|
|
219
|
+
if (content.match(/export\s+(?:async\s+)?function\s+PUT/)) methods.push("PUT");
|
|
220
|
+
if (content.match(/export\s+(?:async\s+)?function\s+DELETE/)) methods.push("DELETE");
|
|
221
|
+
if (content.match(/export\s+(?:async\s+)?function\s+PATCH/)) methods.push("PATCH");
|
|
222
|
+
if (content.match(/export\s+(?:async\s+)?function\s+HEAD/)) methods.push("HEAD");
|
|
223
|
+
if (content.match(/export\s+(?:async\s+)?function\s+OPTIONS/)) methods.push("OPTIONS");
|
|
224
|
+
|
|
225
|
+
for (const method of methods) {
|
|
226
|
+
routes.push({
|
|
227
|
+
method,
|
|
228
|
+
path: routePath,
|
|
229
|
+
file: filePath,
|
|
230
|
+
line: 1,
|
|
231
|
+
type: "nextjs-app",
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return routes;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Extract generic routes
|
|
241
|
+
*/
|
|
242
|
+
function extractGenericRoutes(content, filePath) {
|
|
243
|
+
const routes = [];
|
|
244
|
+
const methods = ["get", "post", "put", "patch", "delete"];
|
|
245
|
+
|
|
246
|
+
for (const method of methods) {
|
|
247
|
+
// Generic pattern: .method('path' or .method('/path'
|
|
248
|
+
const regex = new RegExp(`\\.${method}\\s*\\(\\s*['"\`](/[^'"\`]*|[^'"\`]+)['"\`]`, "gi");
|
|
249
|
+
let match;
|
|
250
|
+
|
|
251
|
+
while ((match = regex.exec(content)) !== null) {
|
|
252
|
+
const routePath = match[1];
|
|
253
|
+
if (routePath.startsWith("/") || routePath.includes("api")) {
|
|
254
|
+
routes.push({
|
|
255
|
+
method: method.toUpperCase(),
|
|
256
|
+
path: routePath,
|
|
257
|
+
file: filePath,
|
|
258
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
259
|
+
type: "generic",
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return routes;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Validate routes after changes
|
|
270
|
+
* @param {Array} originalRoutes - Original routes
|
|
271
|
+
* @param {Map} changedFiles - Changed files (path -> content)
|
|
272
|
+
* @param {Set} deletedFiles - Deleted files
|
|
273
|
+
* @returns {Object} Validation result
|
|
274
|
+
*/
|
|
275
|
+
function validateRoutes(originalRoutes, changedFiles, deletedFiles) {
|
|
276
|
+
const issues = [];
|
|
277
|
+
const newRoutes = [];
|
|
278
|
+
const orphanedRoutes = [];
|
|
279
|
+
const duplicates = [];
|
|
280
|
+
|
|
281
|
+
// Extract routes from changed files
|
|
282
|
+
for (const [filePath, content] of changedFiles) {
|
|
283
|
+
const routes = extractRoutes(content, filePath);
|
|
284
|
+
newRoutes.push(...routes);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Check for orphaned routes (routes whose handlers are deleted)
|
|
288
|
+
for (const route of originalRoutes) {
|
|
289
|
+
if (deletedFiles.has(route.file)) {
|
|
290
|
+
orphanedRoutes.push({
|
|
291
|
+
route,
|
|
292
|
+
issue: "Route handler file was deleted",
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Check for duplicates
|
|
298
|
+
const routeMap = new Map();
|
|
299
|
+
for (const route of newRoutes) {
|
|
300
|
+
const key = `${route.method}:${route.path}`;
|
|
301
|
+
if (routeMap.has(key)) {
|
|
302
|
+
duplicates.push({
|
|
303
|
+
route,
|
|
304
|
+
existingRoute: routeMap.get(key),
|
|
305
|
+
issue: "Duplicate route definition",
|
|
306
|
+
});
|
|
307
|
+
} else {
|
|
308
|
+
routeMap.set(key, route);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Build issues list
|
|
313
|
+
for (const orphan of orphanedRoutes) {
|
|
314
|
+
issues.push({
|
|
315
|
+
type: "orphaned_route",
|
|
316
|
+
severity: "error",
|
|
317
|
+
message: `Route ${orphan.route.method} ${orphan.route.path} is orphaned - handler file '${orphan.route.file}' was deleted`,
|
|
318
|
+
route: orphan.route,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
for (const dup of duplicates) {
|
|
323
|
+
issues.push({
|
|
324
|
+
type: "duplicate_route",
|
|
325
|
+
severity: "warning",
|
|
326
|
+
message: `Duplicate route ${dup.route.method} ${dup.route.path} in '${dup.route.file}' (already defined in '${dup.existingRoute.file}')`,
|
|
327
|
+
route: dup.route,
|
|
328
|
+
existingRoute: dup.existingRoute,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
valid: issues.filter(i => i.severity === "error").length === 0,
|
|
334
|
+
issues,
|
|
335
|
+
newRoutes,
|
|
336
|
+
orphanedRoutes,
|
|
337
|
+
duplicates,
|
|
338
|
+
summary: {
|
|
339
|
+
totalRoutes: newRoutes.length,
|
|
340
|
+
orphanedCount: orphanedRoutes.length,
|
|
341
|
+
duplicateCount: duplicates.length,
|
|
342
|
+
errorCount: issues.filter(i => i.severity === "error").length,
|
|
343
|
+
warningCount: issues.filter(i => i.severity === "warning").length,
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Check if a route is referenced somewhere
|
|
350
|
+
* @param {Object} route - Route to check
|
|
351
|
+
* @param {Map} files - All files
|
|
352
|
+
* @returns {Array} References found
|
|
353
|
+
*/
|
|
354
|
+
function findRouteReferences(route, files) {
|
|
355
|
+
const references = [];
|
|
356
|
+
const pathPattern = route.path.replace(/:[^/]+/g, "[^/]+");
|
|
357
|
+
const regex = new RegExp(`['"\`]${pathPattern}['"\`]|fetch\\s*\\([^)]*${pathPattern}`);
|
|
358
|
+
|
|
359
|
+
for (const [filePath, content] of files) {
|
|
360
|
+
if (regex.test(content)) {
|
|
361
|
+
references.push({
|
|
362
|
+
file: filePath,
|
|
363
|
+
route,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return references;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
module.exports = {
|
|
372
|
+
extractRoutes,
|
|
373
|
+
validateRoutes,
|
|
374
|
+
findRouteReferences,
|
|
375
|
+
detectFileType,
|
|
376
|
+
extractFastifyRoutes,
|
|
377
|
+
extractExpressRoutes,
|
|
378
|
+
extractNextJsApiRoutes,
|
|
379
|
+
extractNextJsAppRoutes,
|
|
380
|
+
};
|