vector-framework 0.8.1 → 0.8.2
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 +78 -56
- package/dist/cache/manager.d.ts +1 -1
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +8 -3
- package/dist/cache/manager.js.map +1 -1
- package/dist/cli/index.js +76 -47
- package/dist/cli/index.js.map +1 -1
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +2 -1
- package/dist/core/router.js.map +1 -1
- package/dist/core/vector.d.ts.map +1 -1
- package/dist/core/vector.js +1 -6
- package/dist/core/vector.js.map +1 -1
- package/dist/dev/route-generator.js +3 -3
- package/dist/dev/route-generator.js.map +1 -1
- package/dist/dev/route-scanner.js +3 -3
- package/dist/dev/route-scanner.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/package.json +3 -3
- package/src/cache/manager.ts +15 -5
- package/src/cli/index.ts +92 -48
- package/src/core/router.ts +2 -1
- package/src/core/vector.ts +1 -7
- package/src/dev/route-generator.ts +3 -3
- package/src/dev/route-scanner.ts +3 -3
- package/src/types/index.ts +1 -1
package/src/cli/index.ts
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
3
|
+
import { watch } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { parseArgs } from "node:util";
|
|
6
|
+
import vector from "../core/vector";
|
|
6
7
|
|
|
7
8
|
const { values, positionals } = parseArgs({
|
|
8
9
|
args: Bun.argv.slice(2),
|
|
9
10
|
options: {
|
|
10
11
|
port: {
|
|
11
|
-
type:
|
|
12
|
-
short:
|
|
13
|
-
default:
|
|
12
|
+
type: "string",
|
|
13
|
+
short: "p",
|
|
14
|
+
default: "3000",
|
|
14
15
|
},
|
|
15
16
|
host: {
|
|
16
|
-
type:
|
|
17
|
-
short:
|
|
18
|
-
default:
|
|
17
|
+
type: "string",
|
|
18
|
+
short: "h",
|
|
19
|
+
default: "localhost",
|
|
19
20
|
},
|
|
20
21
|
routes: {
|
|
21
|
-
type:
|
|
22
|
-
short:
|
|
23
|
-
default:
|
|
22
|
+
type: "string",
|
|
23
|
+
short: "r",
|
|
24
|
+
default: "./routes",
|
|
24
25
|
},
|
|
25
26
|
watch: {
|
|
26
|
-
type:
|
|
27
|
-
short:
|
|
27
|
+
type: "boolean",
|
|
28
|
+
short: "w",
|
|
28
29
|
default: true,
|
|
29
30
|
},
|
|
30
31
|
cors: {
|
|
31
|
-
type:
|
|
32
|
+
type: "boolean",
|
|
32
33
|
default: true,
|
|
33
34
|
},
|
|
34
35
|
},
|
|
@@ -36,13 +37,15 @@ const { values, positionals } = parseArgs({
|
|
|
36
37
|
allowPositionals: true,
|
|
37
38
|
});
|
|
38
39
|
|
|
39
|
-
const command = positionals[0] ||
|
|
40
|
+
const command = positionals[0] || "dev";
|
|
40
41
|
|
|
41
42
|
async function runDev() {
|
|
42
|
-
const isDev = command ===
|
|
43
|
-
console.log(
|
|
43
|
+
const isDev = command === "dev";
|
|
44
|
+
console.log(
|
|
45
|
+
`\n→ Starting Vector ${isDev ? "development" : "production"} server\n`
|
|
46
|
+
);
|
|
44
47
|
|
|
45
|
-
const config = {
|
|
48
|
+
const config: any = {
|
|
46
49
|
port: Number.parseInt(values.port as string),
|
|
47
50
|
hostname: values.host as string,
|
|
48
51
|
routesDir: values.routes as string,
|
|
@@ -50,22 +53,39 @@ async function runDev() {
|
|
|
50
53
|
autoDiscover: true,
|
|
51
54
|
cors: values.cors
|
|
52
55
|
? {
|
|
53
|
-
origin:
|
|
56
|
+
origin: "*",
|
|
54
57
|
credentials: true,
|
|
55
|
-
allowHeaders:
|
|
56
|
-
allowMethods:
|
|
57
|
-
exposeHeaders:
|
|
58
|
+
allowHeaders: "Content-Type, Authorization",
|
|
59
|
+
allowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
60
|
+
exposeHeaders: "Authorization",
|
|
58
61
|
maxAge: 86400,
|
|
59
62
|
}
|
|
60
63
|
: undefined,
|
|
61
64
|
};
|
|
62
65
|
|
|
63
66
|
try {
|
|
64
|
-
const userConfigPath = join(process.cwd(),
|
|
67
|
+
const userConfigPath = join(process.cwd(), "vector.config.ts");
|
|
65
68
|
try {
|
|
66
69
|
const userConfig = await import(userConfigPath);
|
|
67
70
|
if (userConfig.default) {
|
|
68
|
-
|
|
71
|
+
// Properly merge config, preserving middleware arrays
|
|
72
|
+
const {
|
|
73
|
+
before,
|
|
74
|
+
finally: finallyMiddleware,
|
|
75
|
+
...otherConfig
|
|
76
|
+
} = userConfig.default;
|
|
77
|
+
|
|
78
|
+
// Merge non-middleware config
|
|
79
|
+
Object.assign(config, otherConfig);
|
|
80
|
+
|
|
81
|
+
// Handle middleware arrays properly - these need to be set after Object.assign
|
|
82
|
+
// to avoid being overwritten
|
|
83
|
+
if (before) {
|
|
84
|
+
config.before = before;
|
|
85
|
+
}
|
|
86
|
+
if (finallyMiddleware) {
|
|
87
|
+
config.finally = finallyMiddleware;
|
|
88
|
+
}
|
|
69
89
|
}
|
|
70
90
|
} catch {
|
|
71
91
|
// No user config file, use defaults
|
|
@@ -73,32 +93,56 @@ async function runDev() {
|
|
|
73
93
|
|
|
74
94
|
await vector.serve(config);
|
|
75
95
|
|
|
76
|
-
const gray =
|
|
77
|
-
const reset =
|
|
78
|
-
const cyan =
|
|
79
|
-
const green =
|
|
96
|
+
const gray = "\x1b[90m";
|
|
97
|
+
const reset = "\x1b[0m";
|
|
98
|
+
const cyan = "\x1b[36m";
|
|
99
|
+
const green = "\x1b[32m";
|
|
80
100
|
|
|
81
101
|
console.log(` ${gray}Routes${reset} ${config.routesDir}`);
|
|
82
102
|
if (isDev && values.watch) {
|
|
83
|
-
console.log(` ${gray}Watching${reset}
|
|
103
|
+
console.log(` ${gray}Watching${reset} All project files`);
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
// Watch entire project directory for changes
|
|
107
|
+
watch(process.cwd(), { recursive: true }, async (_, filename) => {
|
|
108
|
+
if (
|
|
109
|
+
filename &&
|
|
110
|
+
(filename.endsWith(".ts") ||
|
|
111
|
+
filename.endsWith(".js") ||
|
|
112
|
+
filename.endsWith(".json"))
|
|
113
|
+
) {
|
|
114
|
+
console.log(`\n 🔄 File changed: ${filename}`);
|
|
115
|
+
console.log(" 🔄 Restarting server...\n");
|
|
116
|
+
|
|
117
|
+
// Exit the current process, which will trigger a restart if using --watch flag
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.warn(" ⚠️ File watching not available");
|
|
123
|
+
}
|
|
84
124
|
}
|
|
85
|
-
console.log(
|
|
86
|
-
|
|
125
|
+
console.log(
|
|
126
|
+
` ${gray}CORS${reset} ${values.cors ? "Enabled" : "Disabled"}`
|
|
127
|
+
);
|
|
128
|
+
console.log(
|
|
129
|
+
` ${gray}Mode${reset} ${isDev ? "Development" : "Production"}\n`
|
|
130
|
+
);
|
|
87
131
|
console.log(
|
|
88
132
|
` ${green}Ready${reset} → ${cyan}http://${config.hostname}:${config.port}${reset}\n`
|
|
89
133
|
);
|
|
90
134
|
} catch (error) {
|
|
91
|
-
console.error(
|
|
135
|
+
console.error("[ERROR] Failed to start server:", error);
|
|
92
136
|
process.exit(1);
|
|
93
137
|
}
|
|
94
138
|
}
|
|
95
139
|
|
|
96
140
|
async function runBuild() {
|
|
97
|
-
console.log(
|
|
141
|
+
console.log("\n→ Building Vector application\n");
|
|
98
142
|
|
|
99
143
|
try {
|
|
100
|
-
const { RouteScanner } = await import(
|
|
101
|
-
const { RouteGenerator } = await import(
|
|
144
|
+
const { RouteScanner } = await import("../dev/route-scanner");
|
|
145
|
+
const { RouteGenerator } = await import("../dev/route-generator");
|
|
102
146
|
|
|
103
147
|
const scanner = new RouteScanner(values.routes as string);
|
|
104
148
|
const generator = new RouteGenerator();
|
|
@@ -109,31 +153,31 @@ async function runBuild() {
|
|
|
109
153
|
console.log(` Generated ${routes.length} routes`);
|
|
110
154
|
|
|
111
155
|
const buildProcess = Bun.spawn([
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
156
|
+
"bun",
|
|
157
|
+
"build",
|
|
158
|
+
"src/index.ts",
|
|
159
|
+
"--outdir",
|
|
160
|
+
"dist",
|
|
161
|
+
"--minify",
|
|
118
162
|
]);
|
|
119
163
|
await buildProcess.exited;
|
|
120
164
|
|
|
121
|
-
console.log(
|
|
165
|
+
console.log("\n ✓ Build complete\n");
|
|
122
166
|
} catch (error) {
|
|
123
|
-
console.error(
|
|
167
|
+
console.error("[ERROR] Build failed:", error);
|
|
124
168
|
process.exit(1);
|
|
125
169
|
}
|
|
126
170
|
}
|
|
127
171
|
|
|
128
172
|
switch (command) {
|
|
129
|
-
case
|
|
173
|
+
case "dev":
|
|
130
174
|
await runDev();
|
|
131
175
|
break;
|
|
132
|
-
case
|
|
176
|
+
case "build":
|
|
133
177
|
await runBuild();
|
|
134
178
|
break;
|
|
135
|
-
case
|
|
136
|
-
process.env.NODE_ENV =
|
|
179
|
+
case "start":
|
|
180
|
+
process.env.NODE_ENV = "production";
|
|
137
181
|
await runDev();
|
|
138
182
|
break;
|
|
139
183
|
default:
|
package/src/core/router.ts
CHANGED
|
@@ -140,7 +140,8 @@ export class VectorRouter<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
140
140
|
|
|
141
141
|
request = vectorRequest;
|
|
142
142
|
try {
|
|
143
|
-
|
|
143
|
+
// Default expose to true if not specified
|
|
144
|
+
if (options.expose === false) {
|
|
144
145
|
return APIError.forbidden('Forbidden');
|
|
145
146
|
}
|
|
146
147
|
|
package/src/core/vector.ts
CHANGED
|
@@ -105,12 +105,6 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
105
105
|
this.server = new VectorServer<TTypes>(this.router, this.config);
|
|
106
106
|
const bunServer = await this.server.start();
|
|
107
107
|
|
|
108
|
-
if (this.config.development && this.routeScanner) {
|
|
109
|
-
this.routeScanner.enableWatch(async () => {
|
|
110
|
-
await this.discoverRoutes();
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
108
|
return bunServer;
|
|
115
109
|
}
|
|
116
110
|
|
|
@@ -163,7 +157,7 @@ export class Vector<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
163
157
|
console.log(`✅ Loaded ${routes.length} routes from ${routesDir}`);
|
|
164
158
|
}
|
|
165
159
|
} catch (error) {
|
|
166
|
-
if ((error as any).code !== 'ENOENT') {
|
|
160
|
+
if ((error as any).code !== 'ENOENT' && (error as any).code !== 'ENOTDIR') {
|
|
167
161
|
console.error('Failed to discover routes:', error);
|
|
168
162
|
}
|
|
169
163
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
2
|
import { dirname, relative } from 'node:path';
|
|
3
3
|
import type { GeneratedRoute } from '../types';
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ export class RouteGenerator {
|
|
|
11
11
|
|
|
12
12
|
async generate(routes: GeneratedRoute[]): Promise<void> {
|
|
13
13
|
const outputDir = dirname(this.outputPath);
|
|
14
|
-
await mkdir(outputDir, { recursive: true });
|
|
14
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
15
15
|
|
|
16
16
|
const imports: string[] = [];
|
|
17
17
|
const groupedByFile = new Map<string, GeneratedRoute[]>();
|
|
@@ -64,7 +64,7 @@ ${routeEntries.join('\n')}
|
|
|
64
64
|
export default routes;
|
|
65
65
|
`;
|
|
66
66
|
|
|
67
|
-
await writeFile(this.outputPath, content, 'utf-8');
|
|
67
|
+
await fs.writeFile(this.outputPath, content, 'utf-8');
|
|
68
68
|
console.log(`Generated routes file: ${this.outputPath}`);
|
|
69
69
|
}
|
|
70
70
|
|
package/src/dev/route-scanner.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
2
|
import { join, relative, resolve, sep } from 'node:path';
|
|
3
3
|
import type { GeneratedRoute } from '../types';
|
|
4
4
|
|
|
@@ -26,11 +26,11 @@ export class RouteScanner {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
private async scanDirectory(dir: string, routes: GeneratedRoute[], basePath = ''): Promise<void> {
|
|
29
|
-
const entries = await readdir(dir);
|
|
29
|
+
const entries = await fs.readdir(dir);
|
|
30
30
|
|
|
31
31
|
for (const entry of entries) {
|
|
32
32
|
const fullPath = join(dir, entry);
|
|
33
|
-
const stats = await stat(fullPath);
|
|
33
|
+
const stats = await fs.stat(fullPath);
|
|
34
34
|
|
|
35
35
|
if (stats.isDirectory()) {
|
|
36
36
|
const newBasePath = basePath ? `${basePath}/${entry}` : entry;
|
package/src/types/index.ts
CHANGED
|
@@ -64,7 +64,7 @@ export interface RouteOptions<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
64
64
|
method: string;
|
|
65
65
|
path: string;
|
|
66
66
|
auth?: boolean;
|
|
67
|
-
expose?: boolean;
|
|
67
|
+
expose?: boolean; // defaults to true
|
|
68
68
|
cache?: CacheOptions | number;
|
|
69
69
|
rawRequest?: boolean;
|
|
70
70
|
rawResponse?: boolean;
|