vector-framework 0.9.7 → 0.9.9
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 +516 -346
- package/dist/cli/index.js +63 -64
- package/dist/cli/index.js.map +1 -1
- package/dist/cli.js +480 -424
- package/dist/core/router.d.ts +1 -0
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +73 -25
- package/dist/core/router.js.map +1 -1
- package/dist/core/vector.d.ts.map +1 -1
- package/dist/core/vector.js +8 -4
- package/dist/core/vector.js.map +1 -1
- package/dist/dev/route-scanner.d.ts +5 -2
- package/dist/dev/route-scanner.d.ts.map +1 -1
- package/dist/dev/route-scanner.js +63 -16
- package/dist/dev/route-scanner.js.map +1 -1
- package/dist/http.d.ts +2 -2
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +3 -4
- package/dist/http.js.map +1 -1
- package/dist/index.js +7 -7
- package/dist/index.mjs +7 -7
- package/dist/middleware/manager.d.ts.map +1 -1
- package/dist/middleware/manager.js +8 -1
- package/dist/middleware/manager.js.map +1 -1
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -2
- package/src/cli/index.ts +78 -78
- package/src/core/router.ts +85 -27
- package/src/core/vector.ts +9 -4
- package/src/dev/route-scanner.ts +76 -18
- package/src/http.ts +8 -13
- package/src/middleware/manager.ts +7 -1
- package/src/types/index.ts +5 -0
package/dist/cli.js
CHANGED
|
@@ -28,6 +28,222 @@ var __export = (target, all) => {
|
|
|
28
28
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
29
29
|
var __require = import.meta.require;
|
|
30
30
|
|
|
31
|
+
// src/dev/route-generator.ts
|
|
32
|
+
var exports_route_generator = {};
|
|
33
|
+
__export(exports_route_generator, {
|
|
34
|
+
RouteGenerator: () => RouteGenerator
|
|
35
|
+
});
|
|
36
|
+
import { promises as fs } from "fs";
|
|
37
|
+
import { dirname, relative } from "path";
|
|
38
|
+
|
|
39
|
+
class RouteGenerator {
|
|
40
|
+
outputPath;
|
|
41
|
+
constructor(outputPath = "./.vector/routes.generated.ts") {
|
|
42
|
+
this.outputPath = outputPath;
|
|
43
|
+
}
|
|
44
|
+
async generate(routes) {
|
|
45
|
+
const outputDir = dirname(this.outputPath);
|
|
46
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
47
|
+
const imports = [];
|
|
48
|
+
const groupedByFile = new Map;
|
|
49
|
+
for (const route of routes) {
|
|
50
|
+
if (!groupedByFile.has(route.path)) {
|
|
51
|
+
groupedByFile.set(route.path, []);
|
|
52
|
+
}
|
|
53
|
+
groupedByFile.get(route.path).push(route);
|
|
54
|
+
}
|
|
55
|
+
let importIndex = 0;
|
|
56
|
+
const routeEntries = [];
|
|
57
|
+
for (const [filePath, fileRoutes] of groupedByFile) {
|
|
58
|
+
const relativePath = relative(dirname(this.outputPath), filePath).replace(/\\/g, "/").replace(/\.(ts|js)$/, "");
|
|
59
|
+
const importName = `route_${importIndex++}`;
|
|
60
|
+
const namedImports = fileRoutes.filter((r) => r.name !== "default").map((r) => r.name);
|
|
61
|
+
if (fileRoutes.some((r) => r.name === "default")) {
|
|
62
|
+
if (namedImports.length > 0) {
|
|
63
|
+
imports.push(`import ${importName}, { ${namedImports.join(", ")} } from '${relativePath}';`);
|
|
64
|
+
} else {
|
|
65
|
+
imports.push(`import ${importName} from '${relativePath}';`);
|
|
66
|
+
}
|
|
67
|
+
} else if (namedImports.length > 0) {
|
|
68
|
+
imports.push(`import { ${namedImports.join(", ")} } from '${relativePath}';`);
|
|
69
|
+
}
|
|
70
|
+
for (const route of fileRoutes) {
|
|
71
|
+
const routeVar = route.name === "default" ? importName : route.name;
|
|
72
|
+
routeEntries.push(` ${routeVar},`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const content = `// This file is auto-generated. Do not edit manually.
|
|
76
|
+
// Generated at: ${new Date().toISOString()}
|
|
77
|
+
|
|
78
|
+
${imports.join(`
|
|
79
|
+
`)}
|
|
80
|
+
|
|
81
|
+
export const routes = [
|
|
82
|
+
${routeEntries.join(`
|
|
83
|
+
`)}
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
export default routes;
|
|
87
|
+
`;
|
|
88
|
+
await fs.writeFile(this.outputPath, content, "utf-8");
|
|
89
|
+
}
|
|
90
|
+
async generateDynamic(routes) {
|
|
91
|
+
const routeEntries = [];
|
|
92
|
+
for (const route of routes) {
|
|
93
|
+
const routeObj = JSON.stringify({
|
|
94
|
+
method: route.method,
|
|
95
|
+
path: route.options.path,
|
|
96
|
+
options: route.options
|
|
97
|
+
});
|
|
98
|
+
routeEntries.push(` await import('${route.path}').then(m => ({
|
|
99
|
+
...${routeObj},
|
|
100
|
+
handler: m.${route.name === "default" ? "default" : route.name}
|
|
101
|
+
}))`);
|
|
102
|
+
}
|
|
103
|
+
return `export const loadRoutes = async () => {
|
|
104
|
+
return Promise.all([
|
|
105
|
+
${routeEntries.join(`,
|
|
106
|
+
`)}
|
|
107
|
+
]);
|
|
108
|
+
};`;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
var init_route_generator = () => {};
|
|
112
|
+
|
|
113
|
+
// src/dev/route-scanner.ts
|
|
114
|
+
var exports_route_scanner = {};
|
|
115
|
+
__export(exports_route_scanner, {
|
|
116
|
+
RouteScanner: () => RouteScanner
|
|
117
|
+
});
|
|
118
|
+
import { existsSync, promises as fs2 } from "fs";
|
|
119
|
+
import { join, relative as relative2, resolve, sep } from "path";
|
|
120
|
+
var RouteScanner;
|
|
121
|
+
var init_route_scanner = __esm(() => {
|
|
122
|
+
RouteScanner = class RouteScanner {
|
|
123
|
+
routesDir;
|
|
124
|
+
excludePatterns;
|
|
125
|
+
static DEFAULT_EXCLUDE_PATTERNS = [
|
|
126
|
+
"*.test.ts",
|
|
127
|
+
"*.test.js",
|
|
128
|
+
"*.test.tsx",
|
|
129
|
+
"*.test.jsx",
|
|
130
|
+
"*.spec.ts",
|
|
131
|
+
"*.spec.js",
|
|
132
|
+
"*.spec.tsx",
|
|
133
|
+
"*.spec.jsx",
|
|
134
|
+
"*.tests.ts",
|
|
135
|
+
"*.tests.js",
|
|
136
|
+
"**/__tests__/**",
|
|
137
|
+
"*.interface.ts",
|
|
138
|
+
"*.type.ts",
|
|
139
|
+
"*.d.ts"
|
|
140
|
+
];
|
|
141
|
+
constructor(routesDir = "./routes", excludePatterns) {
|
|
142
|
+
this.routesDir = resolve(process.cwd(), routesDir);
|
|
143
|
+
this.excludePatterns = excludePatterns || RouteScanner.DEFAULT_EXCLUDE_PATTERNS;
|
|
144
|
+
}
|
|
145
|
+
async scan() {
|
|
146
|
+
const routes = [];
|
|
147
|
+
if (!existsSync(this.routesDir)) {
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
await this.scanDirectory(this.routesDir, routes);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error.code === "ENOENT") {
|
|
154
|
+
console.warn(` \u2717 Routes directory not accessible: ${this.routesDir}`);
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
return routes;
|
|
160
|
+
}
|
|
161
|
+
isExcluded(filePath) {
|
|
162
|
+
const relativePath = relative2(this.routesDir, filePath);
|
|
163
|
+
for (const pattern of this.excludePatterns) {
|
|
164
|
+
const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, "[^/]*").replace(/\*\*/g, ".*").replace(/\?/g, ".");
|
|
165
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
166
|
+
const filename = relativePath.split(sep).pop() || "";
|
|
167
|
+
if (regex.test(relativePath) || regex.test(filename)) {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
async scanDirectory(dir, routes, basePath = "") {
|
|
174
|
+
const entries = await fs2.readdir(dir);
|
|
175
|
+
for (const entry of entries) {
|
|
176
|
+
const fullPath = join(dir, entry);
|
|
177
|
+
const stats = await fs2.stat(fullPath);
|
|
178
|
+
if (stats.isDirectory()) {
|
|
179
|
+
const newBasePath = basePath ? `${basePath}/${entry}` : entry;
|
|
180
|
+
await this.scanDirectory(fullPath, routes, newBasePath);
|
|
181
|
+
} else if (entry.endsWith(".ts") || entry.endsWith(".js")) {
|
|
182
|
+
if (this.isExcluded(fullPath)) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const routePath = relative2(this.routesDir, fullPath).replace(/\.(ts|js)$/, "").split(sep).join("/");
|
|
186
|
+
try {
|
|
187
|
+
const importPath = process.platform === "win32" ? `file:///${fullPath.replace(/\\/g, "/")}` : fullPath;
|
|
188
|
+
const module = await import(importPath);
|
|
189
|
+
if (module.default && typeof module.default === "function") {
|
|
190
|
+
routes.push({
|
|
191
|
+
name: "default",
|
|
192
|
+
path: fullPath,
|
|
193
|
+
method: "GET",
|
|
194
|
+
options: {
|
|
195
|
+
method: "GET",
|
|
196
|
+
path: `/${routePath}`,
|
|
197
|
+
expose: true
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
for (const [name, value] of Object.entries(module)) {
|
|
202
|
+
if (name === "default")
|
|
203
|
+
continue;
|
|
204
|
+
if (value && typeof value === "object" && "entry" in value && "options" in value && "handler" in value) {
|
|
205
|
+
const routeDef = value;
|
|
206
|
+
routes.push({
|
|
207
|
+
name,
|
|
208
|
+
path: fullPath,
|
|
209
|
+
method: routeDef.options.method,
|
|
210
|
+
options: routeDef.options
|
|
211
|
+
});
|
|
212
|
+
} else if (Array.isArray(value) && value.length >= 4) {
|
|
213
|
+
const [method, , , path] = value;
|
|
214
|
+
routes.push({
|
|
215
|
+
name,
|
|
216
|
+
path: fullPath,
|
|
217
|
+
method,
|
|
218
|
+
options: {
|
|
219
|
+
method,
|
|
220
|
+
path,
|
|
221
|
+
expose: true
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.error(`Failed to load route from ${fullPath}:`, error);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
enableWatch(callback) {
|
|
233
|
+
if (typeof Bun !== "undefined" && Bun.env.NODE_ENV === "development") {
|
|
234
|
+
console.log(`Watching for route changes in ${this.routesDir}`);
|
|
235
|
+
setInterval(async () => {
|
|
236
|
+
await callback();
|
|
237
|
+
}, 1000);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// src/cli/index.ts
|
|
244
|
+
import { watch } from "fs";
|
|
245
|
+
import { parseArgs } from "util";
|
|
246
|
+
|
|
31
247
|
// src/auth/protected.ts
|
|
32
248
|
class AuthManager {
|
|
33
249
|
protectedHandler = null;
|
|
@@ -55,83 +271,80 @@ class AuthManager {
|
|
|
55
271
|
}
|
|
56
272
|
|
|
57
273
|
// src/constants/index.ts
|
|
58
|
-
var HTTP_STATUS
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
MULTIPART: "multipart/form-data"
|
|
133
|
-
};
|
|
134
|
-
});
|
|
274
|
+
var HTTP_STATUS = {
|
|
275
|
+
OK: 200,
|
|
276
|
+
CREATED: 201,
|
|
277
|
+
ACCEPTED: 202,
|
|
278
|
+
NON_AUTHORITATIVE_INFORMATION: 203,
|
|
279
|
+
NO_CONTENT: 204,
|
|
280
|
+
RESET_CONTENT: 205,
|
|
281
|
+
PARTIAL_CONTENT: 206,
|
|
282
|
+
MULTI_STATUS: 207,
|
|
283
|
+
ALREADY_REPORTED: 208,
|
|
284
|
+
IM_USED: 226,
|
|
285
|
+
MULTIPLE_CHOICES: 300,
|
|
286
|
+
MOVED_PERMANENTLY: 301,
|
|
287
|
+
FOUND: 302,
|
|
288
|
+
SEE_OTHER: 303,
|
|
289
|
+
NOT_MODIFIED: 304,
|
|
290
|
+
USE_PROXY: 305,
|
|
291
|
+
TEMPORARY_REDIRECT: 307,
|
|
292
|
+
PERMANENT_REDIRECT: 308,
|
|
293
|
+
BAD_REQUEST: 400,
|
|
294
|
+
UNAUTHORIZED: 401,
|
|
295
|
+
PAYMENT_REQUIRED: 402,
|
|
296
|
+
FORBIDDEN: 403,
|
|
297
|
+
NOT_FOUND: 404,
|
|
298
|
+
METHOD_NOT_ALLOWED: 405,
|
|
299
|
+
NOT_ACCEPTABLE: 406,
|
|
300
|
+
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
301
|
+
REQUEST_TIMEOUT: 408,
|
|
302
|
+
CONFLICT: 409,
|
|
303
|
+
GONE: 410,
|
|
304
|
+
LENGTH_REQUIRED: 411,
|
|
305
|
+
PRECONDITION_FAILED: 412,
|
|
306
|
+
PAYLOAD_TOO_LARGE: 413,
|
|
307
|
+
URI_TOO_LONG: 414,
|
|
308
|
+
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
309
|
+
RANGE_NOT_SATISFIABLE: 416,
|
|
310
|
+
EXPECTATION_FAILED: 417,
|
|
311
|
+
IM_A_TEAPOT: 418,
|
|
312
|
+
MISDIRECTED_REQUEST: 421,
|
|
313
|
+
UNPROCESSABLE_ENTITY: 422,
|
|
314
|
+
LOCKED: 423,
|
|
315
|
+
FAILED_DEPENDENCY: 424,
|
|
316
|
+
TOO_EARLY: 425,
|
|
317
|
+
UPGRADE_REQUIRED: 426,
|
|
318
|
+
PRECONDITION_REQUIRED: 428,
|
|
319
|
+
TOO_MANY_REQUESTS: 429,
|
|
320
|
+
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
|
321
|
+
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
|
|
322
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
323
|
+
NOT_IMPLEMENTED: 501,
|
|
324
|
+
BAD_GATEWAY: 502,
|
|
325
|
+
SERVICE_UNAVAILABLE: 503,
|
|
326
|
+
GATEWAY_TIMEOUT: 504,
|
|
327
|
+
HTTP_VERSION_NOT_SUPPORTED: 505,
|
|
328
|
+
VARIANT_ALSO_NEGOTIATES: 506,
|
|
329
|
+
INSUFFICIENT_STORAGE: 507,
|
|
330
|
+
LOOP_DETECTED: 508,
|
|
331
|
+
NOT_EXTENDED: 510,
|
|
332
|
+
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
333
|
+
};
|
|
334
|
+
var DEFAULT_CONFIG = {
|
|
335
|
+
PORT: 3000,
|
|
336
|
+
HOSTNAME: "localhost",
|
|
337
|
+
ROUTES_DIR: "./routes",
|
|
338
|
+
CACHE_TTL: 0,
|
|
339
|
+
CORS_MAX_AGE: 86400
|
|
340
|
+
};
|
|
341
|
+
var CONTENT_TYPES = {
|
|
342
|
+
JSON: "application/json",
|
|
343
|
+
TEXT: "text/plain",
|
|
344
|
+
HTML: "text/html",
|
|
345
|
+
FORM_URLENCODED: "application/x-www-form-urlencoded",
|
|
346
|
+
MULTIPART: "multipart/form-data"
|
|
347
|
+
};
|
|
135
348
|
|
|
136
349
|
// src/cache/manager.ts
|
|
137
350
|
class CacheManager {
|
|
@@ -228,187 +441,10 @@ class CacheManager {
|
|
|
228
441
|
return parts.join(":");
|
|
229
442
|
}
|
|
230
443
|
}
|
|
231
|
-
var init_manager = __esm(() => {
|
|
232
|
-
init_constants();
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
// src/dev/route-generator.ts
|
|
236
|
-
var exports_route_generator = {};
|
|
237
|
-
__export(exports_route_generator, {
|
|
238
|
-
RouteGenerator: () => RouteGenerator
|
|
239
|
-
});
|
|
240
|
-
import { promises as fs } from "fs";
|
|
241
|
-
import { dirname, relative } from "path";
|
|
242
|
-
|
|
243
|
-
class RouteGenerator {
|
|
244
|
-
outputPath;
|
|
245
|
-
constructor(outputPath = "./.vector/routes.generated.ts") {
|
|
246
|
-
this.outputPath = outputPath;
|
|
247
|
-
}
|
|
248
|
-
async generate(routes) {
|
|
249
|
-
const outputDir = dirname(this.outputPath);
|
|
250
|
-
await fs.mkdir(outputDir, { recursive: true });
|
|
251
|
-
const imports = [];
|
|
252
|
-
const groupedByFile = new Map;
|
|
253
|
-
for (const route of routes) {
|
|
254
|
-
if (!groupedByFile.has(route.path)) {
|
|
255
|
-
groupedByFile.set(route.path, []);
|
|
256
|
-
}
|
|
257
|
-
groupedByFile.get(route.path).push(route);
|
|
258
|
-
}
|
|
259
|
-
let importIndex = 0;
|
|
260
|
-
const routeEntries = [];
|
|
261
|
-
for (const [filePath, fileRoutes] of groupedByFile) {
|
|
262
|
-
const relativePath = relative(dirname(this.outputPath), filePath).replace(/\\/g, "/").replace(/\.(ts|js)$/, "");
|
|
263
|
-
const importName = `route_${importIndex++}`;
|
|
264
|
-
const namedImports = fileRoutes.filter((r) => r.name !== "default").map((r) => r.name);
|
|
265
|
-
if (fileRoutes.some((r) => r.name === "default")) {
|
|
266
|
-
if (namedImports.length > 0) {
|
|
267
|
-
imports.push(`import ${importName}, { ${namedImports.join(", ")} } from '${relativePath}';`);
|
|
268
|
-
} else {
|
|
269
|
-
imports.push(`import ${importName} from '${relativePath}';`);
|
|
270
|
-
}
|
|
271
|
-
} else if (namedImports.length > 0) {
|
|
272
|
-
imports.push(`import { ${namedImports.join(", ")} } from '${relativePath}';`);
|
|
273
|
-
}
|
|
274
|
-
for (const route of fileRoutes) {
|
|
275
|
-
const routeVar = route.name === "default" ? importName : route.name;
|
|
276
|
-
routeEntries.push(` ${routeVar},`);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
const content = `// This file is auto-generated. Do not edit manually.
|
|
280
|
-
// Generated at: ${new Date().toISOString()}
|
|
281
|
-
|
|
282
|
-
${imports.join(`
|
|
283
|
-
`)}
|
|
284
|
-
|
|
285
|
-
export const routes = [
|
|
286
|
-
${routeEntries.join(`
|
|
287
|
-
`)}
|
|
288
|
-
];
|
|
289
|
-
|
|
290
|
-
export default routes;
|
|
291
|
-
`;
|
|
292
|
-
await fs.writeFile(this.outputPath, content, "utf-8");
|
|
293
|
-
}
|
|
294
|
-
async generateDynamic(routes) {
|
|
295
|
-
const routeEntries = [];
|
|
296
|
-
for (const route of routes) {
|
|
297
|
-
const routeObj = JSON.stringify({
|
|
298
|
-
method: route.method,
|
|
299
|
-
path: route.options.path,
|
|
300
|
-
options: route.options
|
|
301
|
-
});
|
|
302
|
-
routeEntries.push(` await import('${route.path}').then(m => ({
|
|
303
|
-
...${routeObj},
|
|
304
|
-
handler: m.${route.name === "default" ? "default" : route.name}
|
|
305
|
-
}))`);
|
|
306
|
-
}
|
|
307
|
-
return `export const loadRoutes = async () => {
|
|
308
|
-
return Promise.all([
|
|
309
|
-
${routeEntries.join(`,
|
|
310
|
-
`)}
|
|
311
|
-
]);
|
|
312
|
-
};`;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
var init_route_generator = () => {};
|
|
316
|
-
|
|
317
|
-
// src/dev/route-scanner.ts
|
|
318
|
-
var exports_route_scanner = {};
|
|
319
|
-
__export(exports_route_scanner, {
|
|
320
|
-
RouteScanner: () => RouteScanner
|
|
321
|
-
});
|
|
322
|
-
import { existsSync, promises as fs2 } from "fs";
|
|
323
|
-
import { join, relative as relative2, resolve, sep } from "path";
|
|
324
444
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
this.routesDir = resolve(process.cwd(), routesDir);
|
|
329
|
-
}
|
|
330
|
-
async scan() {
|
|
331
|
-
const routes = [];
|
|
332
|
-
if (!existsSync(this.routesDir)) {
|
|
333
|
-
return [];
|
|
334
|
-
}
|
|
335
|
-
try {
|
|
336
|
-
await this.scanDirectory(this.routesDir, routes);
|
|
337
|
-
} catch (error) {
|
|
338
|
-
if (error.code === "ENOENT") {
|
|
339
|
-
console.warn(` \u2717 Routes directory not accessible: ${this.routesDir}`);
|
|
340
|
-
return [];
|
|
341
|
-
}
|
|
342
|
-
throw error;
|
|
343
|
-
}
|
|
344
|
-
return routes;
|
|
345
|
-
}
|
|
346
|
-
async scanDirectory(dir, routes, basePath = "") {
|
|
347
|
-
const entries = await fs2.readdir(dir);
|
|
348
|
-
for (const entry of entries) {
|
|
349
|
-
const fullPath = join(dir, entry);
|
|
350
|
-
const stats = await fs2.stat(fullPath);
|
|
351
|
-
if (stats.isDirectory()) {
|
|
352
|
-
const newBasePath = basePath ? `${basePath}/${entry}` : entry;
|
|
353
|
-
await this.scanDirectory(fullPath, routes, newBasePath);
|
|
354
|
-
} else if (entry.endsWith(".ts") || entry.endsWith(".js")) {
|
|
355
|
-
const routePath = relative2(this.routesDir, fullPath).replace(/\.(ts|js)$/, "").split(sep).join("/");
|
|
356
|
-
try {
|
|
357
|
-
const importPath = process.platform === "win32" ? `file:///${fullPath.replace(/\\/g, "/")}` : fullPath;
|
|
358
|
-
const module = await import(importPath);
|
|
359
|
-
if (module.default && typeof module.default === "function") {
|
|
360
|
-
routes.push({
|
|
361
|
-
name: "default",
|
|
362
|
-
path: fullPath,
|
|
363
|
-
method: "GET",
|
|
364
|
-
options: {
|
|
365
|
-
method: "GET",
|
|
366
|
-
path: `/${routePath}`,
|
|
367
|
-
expose: true
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
for (const [name, value] of Object.entries(module)) {
|
|
372
|
-
if (name === "default")
|
|
373
|
-
continue;
|
|
374
|
-
if (value && typeof value === "object" && "entry" in value && "options" in value && "handler" in value) {
|
|
375
|
-
const routeDef = value;
|
|
376
|
-
routes.push({
|
|
377
|
-
name,
|
|
378
|
-
path: fullPath,
|
|
379
|
-
method: routeDef.options.method,
|
|
380
|
-
options: routeDef.options
|
|
381
|
-
});
|
|
382
|
-
} else if (Array.isArray(value) && value.length >= 4) {
|
|
383
|
-
const [method, , , path] = value;
|
|
384
|
-
routes.push({
|
|
385
|
-
name,
|
|
386
|
-
path: fullPath,
|
|
387
|
-
method,
|
|
388
|
-
options: {
|
|
389
|
-
method,
|
|
390
|
-
path,
|
|
391
|
-
expose: true
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
} catch (error) {
|
|
397
|
-
console.error(`Failed to load route from ${fullPath}:`, error);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
enableWatch(callback) {
|
|
403
|
-
if (typeof Bun !== "undefined" && Bun.env.NODE_ENV === "development") {
|
|
404
|
-
console.log(`Watching for route changes in ${this.routesDir}`);
|
|
405
|
-
setInterval(async () => {
|
|
406
|
-
await callback();
|
|
407
|
-
}, 1000);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
var init_route_scanner = () => {};
|
|
445
|
+
// src/core/vector.ts
|
|
446
|
+
init_route_generator();
|
|
447
|
+
init_route_scanner();
|
|
412
448
|
|
|
413
449
|
// src/middleware/manager.ts
|
|
414
450
|
class MiddlewareManager {
|
|
@@ -434,7 +470,11 @@ class MiddlewareManager {
|
|
|
434
470
|
async executeFinally(response, request) {
|
|
435
471
|
let currentResponse = response;
|
|
436
472
|
for (const handler of this.finallyHandlers) {
|
|
437
|
-
|
|
473
|
+
try {
|
|
474
|
+
currentResponse = await handler(currentResponse, request);
|
|
475
|
+
} catch (error) {
|
|
476
|
+
console.error("After middleware error:", error);
|
|
477
|
+
}
|
|
438
478
|
}
|
|
439
479
|
return currentResponse;
|
|
440
480
|
}
|
|
@@ -461,7 +501,17 @@ var r = (e = "text/plain; charset=utf-8", t) => (r2, o = {}) => {
|
|
|
461
501
|
return r2;
|
|
462
502
|
const a = new Response(t?.(r2) ?? r2, o.url ? undefined : o);
|
|
463
503
|
return a.headers.set("content-type", e), a;
|
|
464
|
-
}
|
|
504
|
+
};
|
|
505
|
+
var o = r("application/json; charset=utf-8", JSON.stringify);
|
|
506
|
+
var p = r("text/plain; charset=utf-8", String);
|
|
507
|
+
var f = r("text/html");
|
|
508
|
+
var u = r("image/jpeg");
|
|
509
|
+
var h = r("image/png");
|
|
510
|
+
var g = r("image/webp");
|
|
511
|
+
var w = (e) => {
|
|
512
|
+
e.cookies = (e.headers.get("Cookie") || "").split(/;\s*/).map((e2) => e2.split(/=(.+)/)).reduce((e2, [t, r2]) => r2 ? (e2[t] = r2, e2) : e2, {});
|
|
513
|
+
};
|
|
514
|
+
var y = (e = {}) => {
|
|
465
515
|
const { origin: t = "*", credentials: r2 = false, allowMethods: o2 = "*", allowHeaders: a, exposeHeaders: s, maxAge: c } = e, n = (e2) => {
|
|
466
516
|
const o3 = e2?.headers.get("origin");
|
|
467
517
|
return t === true ? o3 : t instanceof RegExp ? t.test(o3) ? o3 : undefined : Array.isArray(t) ? t.includes(o3) ? o3 : undefined : t instanceof Function ? t(o3) : t == "*" && r2 ? o3 : t;
|
|
@@ -477,16 +527,16 @@ var r = (e = "text/plain; charset=utf-8", t) => (r2, o = {}) => {
|
|
|
477
527
|
}
|
|
478
528
|
} };
|
|
479
529
|
};
|
|
480
|
-
var init_itty_router = __esm(() => {
|
|
481
|
-
o = r("application/json; charset=utf-8", JSON.stringify);
|
|
482
|
-
p = r("text/plain; charset=utf-8", String);
|
|
483
|
-
f = r("text/html");
|
|
484
|
-
u = r("image/jpeg");
|
|
485
|
-
h = r("image/png");
|
|
486
|
-
g = r("image/webp");
|
|
487
|
-
});
|
|
488
530
|
|
|
489
531
|
// src/http.ts
|
|
532
|
+
var { preflight, corsify } = y({
|
|
533
|
+
origin: "*",
|
|
534
|
+
credentials: true,
|
|
535
|
+
allowHeaders: "Content-Type, Authorization",
|
|
536
|
+
allowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
537
|
+
exposeHeaders: "Authorization",
|
|
538
|
+
maxAge: 86400
|
|
539
|
+
});
|
|
490
540
|
function stringifyData(data) {
|
|
491
541
|
return JSON.stringify(data ?? null, (_key, value) => typeof value === "bigint" ? value.toString() : value);
|
|
492
542
|
}
|
|
@@ -499,6 +549,51 @@ function createErrorResponse(code, message, contentType) {
|
|
|
499
549
|
};
|
|
500
550
|
return createResponse(code, errorBody, contentType);
|
|
501
551
|
}
|
|
552
|
+
var APIError = {
|
|
553
|
+
badRequest: (msg = "Bad Request", contentType) => createErrorResponse(HTTP_STATUS.BAD_REQUEST, msg, contentType),
|
|
554
|
+
unauthorized: (msg = "Unauthorized", contentType) => createErrorResponse(HTTP_STATUS.UNAUTHORIZED, msg, contentType),
|
|
555
|
+
paymentRequired: (msg = "Payment Required", contentType) => createErrorResponse(402, msg, contentType),
|
|
556
|
+
forbidden: (msg = "Forbidden", contentType) => createErrorResponse(HTTP_STATUS.FORBIDDEN, msg, contentType),
|
|
557
|
+
notFound: (msg = "Not Found", contentType) => createErrorResponse(HTTP_STATUS.NOT_FOUND, msg, contentType),
|
|
558
|
+
methodNotAllowed: (msg = "Method Not Allowed", contentType) => createErrorResponse(405, msg, contentType),
|
|
559
|
+
notAcceptable: (msg = "Not Acceptable", contentType) => createErrorResponse(406, msg, contentType),
|
|
560
|
+
requestTimeout: (msg = "Request Timeout", contentType) => createErrorResponse(408, msg, contentType),
|
|
561
|
+
conflict: (msg = "Conflict", contentType) => createErrorResponse(HTTP_STATUS.CONFLICT, msg, contentType),
|
|
562
|
+
gone: (msg = "Gone", contentType) => createErrorResponse(410, msg, contentType),
|
|
563
|
+
lengthRequired: (msg = "Length Required", contentType) => createErrorResponse(411, msg, contentType),
|
|
564
|
+
preconditionFailed: (msg = "Precondition Failed", contentType) => createErrorResponse(412, msg, contentType),
|
|
565
|
+
payloadTooLarge: (msg = "Payload Too Large", contentType) => createErrorResponse(413, msg, contentType),
|
|
566
|
+
uriTooLong: (msg = "URI Too Long", contentType) => createErrorResponse(414, msg, contentType),
|
|
567
|
+
unsupportedMediaType: (msg = "Unsupported Media Type", contentType) => createErrorResponse(415, msg, contentType),
|
|
568
|
+
rangeNotSatisfiable: (msg = "Range Not Satisfiable", contentType) => createErrorResponse(416, msg, contentType),
|
|
569
|
+
expectationFailed: (msg = "Expectation Failed", contentType) => createErrorResponse(417, msg, contentType),
|
|
570
|
+
imATeapot: (msg = "I'm a teapot", contentType) => createErrorResponse(418, msg, contentType),
|
|
571
|
+
misdirectedRequest: (msg = "Misdirected Request", contentType) => createErrorResponse(421, msg, contentType),
|
|
572
|
+
unprocessableEntity: (msg = "Unprocessable Entity", contentType) => createErrorResponse(HTTP_STATUS.UNPROCESSABLE_ENTITY, msg, contentType),
|
|
573
|
+
locked: (msg = "Locked", contentType) => createErrorResponse(423, msg, contentType),
|
|
574
|
+
failedDependency: (msg = "Failed Dependency", contentType) => createErrorResponse(424, msg, contentType),
|
|
575
|
+
tooEarly: (msg = "Too Early", contentType) => createErrorResponse(425, msg, contentType),
|
|
576
|
+
upgradeRequired: (msg = "Upgrade Required", contentType) => createErrorResponse(426, msg, contentType),
|
|
577
|
+
preconditionRequired: (msg = "Precondition Required", contentType) => createErrorResponse(428, msg, contentType),
|
|
578
|
+
tooManyRequests: (msg = "Too Many Requests", contentType) => createErrorResponse(429, msg, contentType),
|
|
579
|
+
requestHeaderFieldsTooLarge: (msg = "Request Header Fields Too Large", contentType) => createErrorResponse(431, msg, contentType),
|
|
580
|
+
unavailableForLegalReasons: (msg = "Unavailable For Legal Reasons", contentType) => createErrorResponse(451, msg, contentType),
|
|
581
|
+
internalServerError: (msg = "Internal Server Error", contentType) => createErrorResponse(HTTP_STATUS.INTERNAL_SERVER_ERROR, msg, contentType),
|
|
582
|
+
notImplemented: (msg = "Not Implemented", contentType) => createErrorResponse(501, msg, contentType),
|
|
583
|
+
badGateway: (msg = "Bad Gateway", contentType) => createErrorResponse(502, msg, contentType),
|
|
584
|
+
serviceUnavailable: (msg = "Service Unavailable", contentType) => createErrorResponse(503, msg, contentType),
|
|
585
|
+
gatewayTimeout: (msg = "Gateway Timeout", contentType) => createErrorResponse(504, msg, contentType),
|
|
586
|
+
httpVersionNotSupported: (msg = "HTTP Version Not Supported", contentType) => createErrorResponse(505, msg, contentType),
|
|
587
|
+
variantAlsoNegotiates: (msg = "Variant Also Negotiates", contentType) => createErrorResponse(506, msg, contentType),
|
|
588
|
+
insufficientStorage: (msg = "Insufficient Storage", contentType) => createErrorResponse(507, msg, contentType),
|
|
589
|
+
loopDetected: (msg = "Loop Detected", contentType) => createErrorResponse(508, msg, contentType),
|
|
590
|
+
notExtended: (msg = "Not Extended", contentType) => createErrorResponse(510, msg, contentType),
|
|
591
|
+
networkAuthenticationRequired: (msg = "Network Authentication Required", contentType) => createErrorResponse(511, msg, contentType),
|
|
592
|
+
invalidArgument: (msg = "Invalid Argument", contentType) => createErrorResponse(HTTP_STATUS.UNPROCESSABLE_ENTITY, msg, contentType),
|
|
593
|
+
rateLimitExceeded: (msg = "Rate Limit Exceeded", contentType) => createErrorResponse(429, msg, contentType),
|
|
594
|
+
maintenance: (msg = "Service Under Maintenance", contentType) => createErrorResponse(503, msg, contentType),
|
|
595
|
+
custom: (statusCode, msg, contentType) => createErrorResponse(statusCode, msg, contentType)
|
|
596
|
+
};
|
|
502
597
|
function createResponse(statusCode, data, contentType = CONTENT_TYPES.JSON) {
|
|
503
598
|
const body = contentType === CONTENT_TYPES.JSON ? stringifyData(data) : data;
|
|
504
599
|
return new Response(body, {
|
|
@@ -506,64 +601,6 @@ function createResponse(statusCode, data, contentType = CONTENT_TYPES.JSON) {
|
|
|
506
601
|
headers: { "content-type": contentType }
|
|
507
602
|
});
|
|
508
603
|
}
|
|
509
|
-
var preflight, corsify, APIError;
|
|
510
|
-
var init_http = __esm(() => {
|
|
511
|
-
init_itty_router();
|
|
512
|
-
init_constants();
|
|
513
|
-
({ preflight, corsify } = y({
|
|
514
|
-
origin: "*",
|
|
515
|
-
credentials: true,
|
|
516
|
-
allowHeaders: "Content-Type, Authorization",
|
|
517
|
-
allowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
518
|
-
exposeHeaders: "Authorization",
|
|
519
|
-
maxAge: 86400
|
|
520
|
-
}));
|
|
521
|
-
APIError = {
|
|
522
|
-
badRequest: (msg = "Bad Request", contentType) => createErrorResponse(HTTP_STATUS.BAD_REQUEST, msg, contentType),
|
|
523
|
-
unauthorized: (msg = "Unauthorized", contentType) => createErrorResponse(HTTP_STATUS.UNAUTHORIZED, msg, contentType),
|
|
524
|
-
paymentRequired: (msg = "Payment Required", contentType) => createErrorResponse(402, msg, contentType),
|
|
525
|
-
forbidden: (msg = "Forbidden", contentType) => createErrorResponse(HTTP_STATUS.FORBIDDEN, msg, contentType),
|
|
526
|
-
notFound: (msg = "Not Found", contentType) => createErrorResponse(HTTP_STATUS.NOT_FOUND, msg, contentType),
|
|
527
|
-
methodNotAllowed: (msg = "Method Not Allowed", contentType) => createErrorResponse(405, msg, contentType),
|
|
528
|
-
notAcceptable: (msg = "Not Acceptable", contentType) => createErrorResponse(406, msg, contentType),
|
|
529
|
-
requestTimeout: (msg = "Request Timeout", contentType) => createErrorResponse(408, msg, contentType),
|
|
530
|
-
conflict: (msg = "Conflict", contentType) => createErrorResponse(HTTP_STATUS.CONFLICT, msg, contentType),
|
|
531
|
-
gone: (msg = "Gone", contentType) => createErrorResponse(410, msg, contentType),
|
|
532
|
-
lengthRequired: (msg = "Length Required", contentType) => createErrorResponse(411, msg, contentType),
|
|
533
|
-
preconditionFailed: (msg = "Precondition Failed", contentType) => createErrorResponse(412, msg, contentType),
|
|
534
|
-
payloadTooLarge: (msg = "Payload Too Large", contentType) => createErrorResponse(413, msg, contentType),
|
|
535
|
-
uriTooLong: (msg = "URI Too Long", contentType) => createErrorResponse(414, msg, contentType),
|
|
536
|
-
unsupportedMediaType: (msg = "Unsupported Media Type", contentType) => createErrorResponse(415, msg, contentType),
|
|
537
|
-
rangeNotSatisfiable: (msg = "Range Not Satisfiable", contentType) => createErrorResponse(416, msg, contentType),
|
|
538
|
-
expectationFailed: (msg = "Expectation Failed", contentType) => createErrorResponse(417, msg, contentType),
|
|
539
|
-
imATeapot: (msg = "I'm a teapot", contentType) => createErrorResponse(418, msg, contentType),
|
|
540
|
-
misdirectedRequest: (msg = "Misdirected Request", contentType) => createErrorResponse(421, msg, contentType),
|
|
541
|
-
unprocessableEntity: (msg = "Unprocessable Entity", contentType) => createErrorResponse(HTTP_STATUS.UNPROCESSABLE_ENTITY, msg, contentType),
|
|
542
|
-
locked: (msg = "Locked", contentType) => createErrorResponse(423, msg, contentType),
|
|
543
|
-
failedDependency: (msg = "Failed Dependency", contentType) => createErrorResponse(424, msg, contentType),
|
|
544
|
-
tooEarly: (msg = "Too Early", contentType) => createErrorResponse(425, msg, contentType),
|
|
545
|
-
upgradeRequired: (msg = "Upgrade Required", contentType) => createErrorResponse(426, msg, contentType),
|
|
546
|
-
preconditionRequired: (msg = "Precondition Required", contentType) => createErrorResponse(428, msg, contentType),
|
|
547
|
-
tooManyRequests: (msg = "Too Many Requests", contentType) => createErrorResponse(429, msg, contentType),
|
|
548
|
-
requestHeaderFieldsTooLarge: (msg = "Request Header Fields Too Large", contentType) => createErrorResponse(431, msg, contentType),
|
|
549
|
-
unavailableForLegalReasons: (msg = "Unavailable For Legal Reasons", contentType) => createErrorResponse(451, msg, contentType),
|
|
550
|
-
internalServerError: (msg = "Internal Server Error", contentType) => createErrorResponse(HTTP_STATUS.INTERNAL_SERVER_ERROR, msg, contentType),
|
|
551
|
-
notImplemented: (msg = "Not Implemented", contentType) => createErrorResponse(501, msg, contentType),
|
|
552
|
-
badGateway: (msg = "Bad Gateway", contentType) => createErrorResponse(502, msg, contentType),
|
|
553
|
-
serviceUnavailable: (msg = "Service Unavailable", contentType) => createErrorResponse(503, msg, contentType),
|
|
554
|
-
gatewayTimeout: (msg = "Gateway Timeout", contentType) => createErrorResponse(504, msg, contentType),
|
|
555
|
-
httpVersionNotSupported: (msg = "HTTP Version Not Supported", contentType) => createErrorResponse(505, msg, contentType),
|
|
556
|
-
variantAlsoNegotiates: (msg = "Variant Also Negotiates", contentType) => createErrorResponse(506, msg, contentType),
|
|
557
|
-
insufficientStorage: (msg = "Insufficient Storage", contentType) => createErrorResponse(507, msg, contentType),
|
|
558
|
-
loopDetected: (msg = "Loop Detected", contentType) => createErrorResponse(508, msg, contentType),
|
|
559
|
-
notExtended: (msg = "Not Extended", contentType) => createErrorResponse(510, msg, contentType),
|
|
560
|
-
networkAuthenticationRequired: (msg = "Network Authentication Required", contentType) => createErrorResponse(511, msg, contentType),
|
|
561
|
-
invalidArgument: (msg = "Invalid Argument", contentType) => createErrorResponse(HTTP_STATUS.UNPROCESSABLE_ENTITY, msg, contentType),
|
|
562
|
-
rateLimitExceeded: (msg = "Rate Limit Exceeded", contentType) => createErrorResponse(429, msg, contentType),
|
|
563
|
-
maintenance: (msg = "Service Under Maintenance", contentType) => createErrorResponse(503, msg, contentType),
|
|
564
|
-
custom: (statusCode, msg, contentType) => createErrorResponse(statusCode, msg, contentType)
|
|
565
|
-
};
|
|
566
|
-
});
|
|
567
604
|
|
|
568
605
|
// src/core/router.ts
|
|
569
606
|
class VectorRouter {
|
|
@@ -638,23 +675,45 @@ class VectorRouter {
|
|
|
638
675
|
createRouteRegex(path) {
|
|
639
676
|
return RegExp(`^${path.replace(/\/+(\/|$)/g, "$1").replace(/(\/?\.?):(\w+)\+/g, "($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g, "($1(?<$2>[^$1/]+?))").replace(/\./g, "\\.").replace(/(\/?)\*/g, "($1.*)?")}/*$`);
|
|
640
677
|
}
|
|
678
|
+
prepareRequest(request, options) {
|
|
679
|
+
if (!request.context) {
|
|
680
|
+
request.context = {};
|
|
681
|
+
}
|
|
682
|
+
if (options?.params !== undefined) {
|
|
683
|
+
request.params = options.params;
|
|
684
|
+
}
|
|
685
|
+
if (options?.route !== undefined) {
|
|
686
|
+
request.route = options.route;
|
|
687
|
+
}
|
|
688
|
+
if (options?.metadata !== undefined) {
|
|
689
|
+
request.metadata = options.metadata;
|
|
690
|
+
}
|
|
691
|
+
if (!request.query && request.url) {
|
|
692
|
+
const url = new URL(request.url);
|
|
693
|
+
const query = {};
|
|
694
|
+
for (const [key, value] of url.searchParams) {
|
|
695
|
+
if (key in query) {
|
|
696
|
+
if (Array.isArray(query[key])) {
|
|
697
|
+
query[key].push(value);
|
|
698
|
+
} else {
|
|
699
|
+
query[key] = [query[key], value];
|
|
700
|
+
}
|
|
701
|
+
} else {
|
|
702
|
+
query[key] = value;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
request.query = query;
|
|
706
|
+
}
|
|
707
|
+
if (!request.cookies) {
|
|
708
|
+
w(request);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
641
711
|
wrapHandler(options, handler) {
|
|
642
712
|
return async (request) => {
|
|
643
713
|
const vectorRequest = request;
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
}
|
|
647
|
-
if (!vectorRequest.query && vectorRequest.url) {
|
|
648
|
-
const url = new URL(vectorRequest.url);
|
|
649
|
-
const query = {};
|
|
650
|
-
for (let [k, v] of url.searchParams) {
|
|
651
|
-
query[k] = query[k] ? [].concat(query[k], v) : v;
|
|
652
|
-
}
|
|
653
|
-
vectorRequest.query = query;
|
|
654
|
-
}
|
|
655
|
-
if (options.metadata) {
|
|
656
|
-
vectorRequest.metadata = options.metadata;
|
|
657
|
-
}
|
|
714
|
+
this.prepareRequest(vectorRequest, {
|
|
715
|
+
metadata: options.metadata
|
|
716
|
+
});
|
|
658
717
|
request = vectorRequest;
|
|
659
718
|
try {
|
|
660
719
|
if (options.expose === false) {
|
|
@@ -690,19 +749,37 @@ class VectorRouter {
|
|
|
690
749
|
}
|
|
691
750
|
let result;
|
|
692
751
|
const cacheOptions = options.cache;
|
|
752
|
+
const cacheFactory = async () => {
|
|
753
|
+
const res = await handler(request);
|
|
754
|
+
if (res instanceof Response) {
|
|
755
|
+
return {
|
|
756
|
+
_isResponse: true,
|
|
757
|
+
body: await res.text(),
|
|
758
|
+
status: res.status,
|
|
759
|
+
headers: Object.fromEntries(res.headers.entries())
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
return res;
|
|
763
|
+
};
|
|
693
764
|
if (cacheOptions && typeof cacheOptions === "number" && cacheOptions > 0) {
|
|
694
765
|
const cacheKey = this.cacheManager.generateKey(request, {
|
|
695
766
|
authUser: request.authUser
|
|
696
767
|
});
|
|
697
|
-
result = await this.cacheManager.get(cacheKey,
|
|
768
|
+
result = await this.cacheManager.get(cacheKey, cacheFactory, cacheOptions);
|
|
698
769
|
} else if (cacheOptions && typeof cacheOptions === "object" && cacheOptions.ttl) {
|
|
699
770
|
const cacheKey = cacheOptions.key || this.cacheManager.generateKey(request, {
|
|
700
771
|
authUser: request.authUser
|
|
701
772
|
});
|
|
702
|
-
result = await this.cacheManager.get(cacheKey,
|
|
773
|
+
result = await this.cacheManager.get(cacheKey, cacheFactory, cacheOptions.ttl);
|
|
703
774
|
} else {
|
|
704
775
|
result = await handler(request);
|
|
705
776
|
}
|
|
777
|
+
if (result && typeof result === "object" && result._isResponse === true) {
|
|
778
|
+
result = new Response(result.body, {
|
|
779
|
+
status: result.status,
|
|
780
|
+
headers: result.headers
|
|
781
|
+
});
|
|
782
|
+
}
|
|
706
783
|
let response;
|
|
707
784
|
if (options.rawResponse || result instanceof Response) {
|
|
708
785
|
response = result instanceof Response ? result : new Response(result);
|
|
@@ -730,15 +807,15 @@ class VectorRouter {
|
|
|
730
807
|
async handle(request) {
|
|
731
808
|
const url = new URL(request.url);
|
|
732
809
|
const pathname = url.pathname;
|
|
733
|
-
for (const [method, regex, handlers] of this.routes) {
|
|
810
|
+
for (const [method, regex, handlers, path] of this.routes) {
|
|
734
811
|
if (request.method === "OPTIONS" || request.method === method) {
|
|
735
812
|
const match = pathname.match(regex);
|
|
736
813
|
if (match) {
|
|
737
814
|
const req = request;
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
815
|
+
this.prepareRequest(req, {
|
|
816
|
+
params: match.groups || {},
|
|
817
|
+
route: path || pathname
|
|
818
|
+
});
|
|
742
819
|
for (const handler of handlers) {
|
|
743
820
|
const response = await handler(req);
|
|
744
821
|
if (response)
|
|
@@ -753,9 +830,6 @@ class VectorRouter {
|
|
|
753
830
|
this.routes = [];
|
|
754
831
|
}
|
|
755
832
|
}
|
|
756
|
-
var init_router = __esm(() => {
|
|
757
|
-
init_http();
|
|
758
|
-
});
|
|
759
833
|
|
|
760
834
|
// src/core/server.ts
|
|
761
835
|
class VectorServer {
|
|
@@ -852,9 +926,6 @@ class VectorServer {
|
|
|
852
926
|
return `http://${hostname}:${port}`;
|
|
853
927
|
}
|
|
854
928
|
}
|
|
855
|
-
var init_server = __esm(() => {
|
|
856
|
-
init_itty_router();
|
|
857
|
-
});
|
|
858
929
|
|
|
859
930
|
// src/core/vector.ts
|
|
860
931
|
class Vector {
|
|
@@ -901,6 +972,9 @@ class Vector {
|
|
|
901
972
|
async startServer(config) {
|
|
902
973
|
this.config = { ...this.config, ...config };
|
|
903
974
|
this.middlewareManager.clear();
|
|
975
|
+
if (this.config.autoDiscover !== false) {
|
|
976
|
+
this.router.clearRoutes();
|
|
977
|
+
}
|
|
904
978
|
if (config?.before) {
|
|
905
979
|
this.middlewareManager.addBefore(...config.before);
|
|
906
980
|
}
|
|
@@ -916,7 +990,8 @@ class Vector {
|
|
|
916
990
|
}
|
|
917
991
|
async discoverRoutes() {
|
|
918
992
|
const routesDir = this.config.routesDir || "./routes";
|
|
919
|
-
|
|
993
|
+
const excludePatterns = this.config.routeExcludePatterns;
|
|
994
|
+
this.routeScanner = new RouteScanner(routesDir, excludePatterns);
|
|
920
995
|
if (!this.routeGenerator) {
|
|
921
996
|
this.routeGenerator = new RouteGenerator;
|
|
922
997
|
}
|
|
@@ -985,7 +1060,6 @@ class Vector {
|
|
|
985
1060
|
this.server.stop();
|
|
986
1061
|
this.server = null;
|
|
987
1062
|
}
|
|
988
|
-
this.router.clearRoutes();
|
|
989
1063
|
}
|
|
990
1064
|
getServer() {
|
|
991
1065
|
return this.server;
|
|
@@ -1003,25 +1077,11 @@ class Vector {
|
|
|
1003
1077
|
Vector.instance = null;
|
|
1004
1078
|
}
|
|
1005
1079
|
}
|
|
1006
|
-
var getVectorInstance;
|
|
1007
|
-
var init_vector = __esm(() => {
|
|
1008
|
-
init_manager();
|
|
1009
|
-
init_route_generator();
|
|
1010
|
-
init_route_scanner();
|
|
1011
|
-
init_router();
|
|
1012
|
-
init_server();
|
|
1013
|
-
getVectorInstance = Vector.getInstance;
|
|
1014
|
-
});
|
|
1015
|
-
|
|
1016
|
-
// src/cli/index.ts
|
|
1017
|
-
init_vector();
|
|
1018
|
-
import { watch } from "fs";
|
|
1019
|
-
import { parseArgs } from "util";
|
|
1080
|
+
var getVectorInstance = Vector.getInstance;
|
|
1020
1081
|
|
|
1021
1082
|
// src/core/config-loader.ts
|
|
1022
1083
|
import { existsSync as existsSync2 } from "fs";
|
|
1023
1084
|
import { resolve as resolve2, isAbsolute } from "path";
|
|
1024
|
-
|
|
1025
1085
|
class ConfigLoader {
|
|
1026
1086
|
configPath;
|
|
1027
1087
|
config = null;
|
|
@@ -1150,56 +1210,52 @@ async function runDev() {
|
|
|
1150
1210
|
}, 1e4);
|
|
1151
1211
|
});
|
|
1152
1212
|
const serverStartPromise = (async () => {
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
console.log(` ${gray}Mode${reset} ${config.development ? "Development" : "Production"}
|
|
1213
|
+
const configLoader = new ConfigLoader(values.config);
|
|
1214
|
+
const config = await configLoader.load();
|
|
1215
|
+
const configSource = configLoader.getConfigSource();
|
|
1216
|
+
config.port = config.port ?? Number.parseInt(values.port);
|
|
1217
|
+
config.hostname = config.hostname ?? values.host;
|
|
1218
|
+
config.routesDir = config.routesDir ?? values.routes;
|
|
1219
|
+
config.development = config.development ?? isDev;
|
|
1220
|
+
config.autoDiscover = true;
|
|
1221
|
+
if (config.cors === undefined && values.cors) {
|
|
1222
|
+
config.cors = {
|
|
1223
|
+
origin: "*",
|
|
1224
|
+
credentials: true,
|
|
1225
|
+
allowHeaders: "Content-Type, Authorization",
|
|
1226
|
+
allowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
1227
|
+
exposeHeaders: "Authorization",
|
|
1228
|
+
maxAge: 86400
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
vector = getVectorInstance();
|
|
1232
|
+
const authHandler = await configLoader.loadAuthHandler();
|
|
1233
|
+
if (authHandler) {
|
|
1234
|
+
vector.setProtectedHandler(authHandler);
|
|
1235
|
+
}
|
|
1236
|
+
const cacheHandler = await configLoader.loadCacheHandler();
|
|
1237
|
+
if (cacheHandler) {
|
|
1238
|
+
vector.setCacheHandler(cacheHandler);
|
|
1239
|
+
}
|
|
1240
|
+
server = await vector.startServer(config);
|
|
1241
|
+
if (!server || !server.port) {
|
|
1242
|
+
throw new Error("Server started but is not responding correctly");
|
|
1243
|
+
}
|
|
1244
|
+
const gray = "\x1B[90m";
|
|
1245
|
+
const reset = "\x1B[0m";
|
|
1246
|
+
const cyan = "\x1B[36m";
|
|
1247
|
+
const green = "\x1B[32m";
|
|
1248
|
+
console.log(` ${gray}Config${reset} ${configSource === "user" ? "User config loaded" : "Using defaults"}`);
|
|
1249
|
+
console.log(` ${gray}Routes${reset} ${config.routesDir}`);
|
|
1250
|
+
if (isDev && values.watch) {
|
|
1251
|
+
console.log(` ${gray}Watching${reset} All project files`);
|
|
1252
|
+
}
|
|
1253
|
+
console.log(` ${gray}CORS${reset} ${config.cors ? "Enabled" : "Disabled"}`);
|
|
1254
|
+
console.log(` ${gray}Mode${reset} ${config.development ? "Development" : "Production"}
|
|
1196
1255
|
`);
|
|
1197
|
-
|
|
1256
|
+
console.log(` ${green}Ready${reset} \u2192 ${cyan}http://${config.hostname}:${config.port}${reset}
|
|
1198
1257
|
`);
|
|
1199
|
-
|
|
1200
|
-
} catch (error) {
|
|
1201
|
-
throw error;
|
|
1202
|
-
}
|
|
1258
|
+
return { server, vector, config };
|
|
1203
1259
|
})();
|
|
1204
1260
|
return await Promise.race([serverStartPromise, timeoutPromise]);
|
|
1205
1261
|
}
|
|
@@ -1231,9 +1287,11 @@ async function runDev() {
|
|
|
1231
1287
|
vector.stop();
|
|
1232
1288
|
}
|
|
1233
1289
|
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1290
|
+
if (__require.cache) {
|
|
1291
|
+
for (const key in __require.cache) {
|
|
1292
|
+
if (!key.includes("node_modules")) {
|
|
1293
|
+
delete __require.cache[key];
|
|
1294
|
+
}
|
|
1237
1295
|
}
|
|
1238
1296
|
}
|
|
1239
1297
|
try {
|
|
@@ -1244,14 +1302,12 @@ async function runDev() {
|
|
|
1244
1302
|
console.error(`
|
|
1245
1303
|
[Reload Error]`, error.message || error);
|
|
1246
1304
|
} finally {
|
|
1247
|
-
|
|
1248
|
-
isReloading = false;
|
|
1249
|
-
}, 2000);
|
|
1305
|
+
isReloading = false;
|
|
1250
1306
|
}
|
|
1251
1307
|
}, 500);
|
|
1252
1308
|
}
|
|
1253
1309
|
});
|
|
1254
|
-
} catch
|
|
1310
|
+
} catch {
|
|
1255
1311
|
console.warn(" \u26A0\uFE0F File watching not available");
|
|
1256
1312
|
}
|
|
1257
1313
|
}
|