vector-framework 1.2.0 → 1.2.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 +19 -0
- package/dist/auth/protected.d.ts +1 -0
- package/dist/auth/protected.d.ts.map +1 -1
- package/dist/auth/protected.js +3 -0
- package/dist/auth/protected.js.map +1 -1
- package/dist/cache/manager.d.ts +1 -0
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +3 -0
- package/dist/cache/manager.js.map +1 -1
- package/dist/cli/graceful-shutdown.d.ts +15 -0
- package/dist/cli/graceful-shutdown.d.ts.map +1 -0
- package/dist/cli/graceful-shutdown.js +42 -0
- package/dist/cli/graceful-shutdown.js.map +1 -0
- package/dist/cli/index.js +37 -43
- package/dist/cli/index.js.map +1 -1
- package/dist/cli.js +967 -222
- package/dist/core/config-loader.d.ts.map +1 -1
- package/dist/core/config-loader.js +5 -2
- package/dist/core/config-loader.js.map +1 -1
- package/dist/core/server.d.ts +4 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +240 -9
- package/dist/core/server.js.map +1 -1
- package/dist/core/vector.d.ts +4 -2
- package/dist/core/vector.d.ts.map +1 -1
- package/dist/core/vector.js +32 -2
- package/dist/core/vector.js.map +1 -1
- package/dist/errors/index.cjs +2 -0
- package/dist/index.cjs +1434 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1327
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +153 -46
- package/dist/openapi/docs-ui.d.ts +1 -1
- package/dist/openapi/docs-ui.d.ts.map +1 -1
- package/dist/openapi/docs-ui.js +147 -35
- package/dist/openapi/docs-ui.js.map +1 -1
- package/dist/openapi/generator.d.ts.map +1 -1
- package/dist/openapi/generator.js +318 -6
- package/dist/openapi/generator.js.map +1 -1
- package/dist/start-vector.d.ts +3 -0
- package/dist/start-vector.d.ts.map +1 -0
- package/dist/start-vector.js +38 -0
- package/dist/start-vector.js.map +1 -0
- package/dist/types/index.d.ts +25 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/logger.js +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +2 -0
- package/dist/utils/validation.js.map +1 -1
- package/package.json +10 -14
- package/src/auth/protected.ts +4 -0
- package/src/cache/manager.ts +4 -0
- package/src/cli/graceful-shutdown.ts +60 -0
- package/src/cli/index.ts +42 -49
- package/src/core/config-loader.ts +5 -2
- package/src/core/server.ts +304 -9
- package/src/core/vector.ts +38 -4
- package/src/index.ts +4 -3
- package/src/openapi/assets/favicon/android-chrome-192x192.png +0 -0
- package/src/openapi/assets/favicon/android-chrome-512x512.png +0 -0
- package/src/openapi/assets/favicon/apple-touch-icon.png +0 -0
- package/src/openapi/assets/favicon/favicon-16x16.png +0 -0
- package/src/openapi/assets/favicon/favicon-32x32.png +0 -0
- package/src/openapi/assets/favicon/favicon.ico +0 -0
- package/src/openapi/assets/favicon/site.webmanifest +11 -0
- package/src/openapi/assets/logo.svg +12 -0
- package/src/openapi/assets/logo_dark.svg +6 -0
- package/src/openapi/assets/logo_icon.png +0 -0
- package/src/openapi/assets/logo_white.svg +6 -0
- package/src/openapi/docs-ui.ts +153 -35
- package/src/openapi/generator.ts +341 -6
- package/src/start-vector.ts +50 -0
- package/src/types/index.ts +34 -0
- package/src/utils/logger.ts +1 -1
- package/src/utils/validation.ts +2 -0
package/package.json
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vector-framework",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"author": "webhie-com",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/webhie-com/vector.git"
|
|
8
8
|
},
|
|
9
|
-
"main": "./dist/index.
|
|
9
|
+
"main": "./dist/index.cjs",
|
|
10
10
|
"module": "./dist/index.mjs",
|
|
11
11
|
"dependencies": {},
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"@biomejs/biome": "^2.4.6",
|
|
14
14
|
"@biomejs/cli-darwin-arm64": "^2.4.6",
|
|
15
15
|
"@types/bun": "latest",
|
|
16
|
+
"arktype": "^2.2.0",
|
|
16
17
|
"oxlint": "^1.15.0",
|
|
17
18
|
"typescript": "^5.0.0",
|
|
19
|
+
"valibot": "^1.2.0",
|
|
18
20
|
"zod": "^4.3.6"
|
|
19
21
|
},
|
|
20
22
|
"peerDependencies": {
|
|
@@ -24,22 +26,16 @@
|
|
|
24
26
|
".": {
|
|
25
27
|
"types": "./dist/index.d.ts",
|
|
26
28
|
"import": "./dist/index.mjs",
|
|
27
|
-
"require": "./dist/index.
|
|
28
|
-
},
|
|
29
|
-
"./middleware": {
|
|
30
|
-
"types": "./dist/middleware/index.d.ts",
|
|
31
|
-
"import": "./dist/middleware/index.mjs",
|
|
32
|
-
"require": "./dist/middleware/index.js"
|
|
29
|
+
"require": "./dist/index.cjs"
|
|
33
30
|
},
|
|
34
31
|
"./types": {
|
|
35
32
|
"types": "./dist/types/index.d.ts",
|
|
36
|
-
"
|
|
37
|
-
"require": "./dist/types/index.js"
|
|
33
|
+
"default": "./dist/types/index.js"
|
|
38
34
|
},
|
|
39
35
|
"./errors": {
|
|
40
36
|
"types": "./dist/errors/index.d.ts",
|
|
41
|
-
"import": "./dist/errors/index.
|
|
42
|
-
"require": "./dist/errors/index.
|
|
37
|
+
"import": "./dist/errors/index.js",
|
|
38
|
+
"require": "./dist/errors/index.cjs"
|
|
43
39
|
}
|
|
44
40
|
},
|
|
45
41
|
"bin": {
|
|
@@ -79,7 +75,7 @@
|
|
|
79
75
|
"build:lib": "bun run build:clean && bun run build:ts && bun run build:bundle && bun run build:cli",
|
|
80
76
|
"build:clean": "rm -rf dist",
|
|
81
77
|
"build:ts": "tsc",
|
|
82
|
-
"build:bundle": "bun build src/index.ts --format esm --minify --outfile dist/index.mjs && bun build src/index.ts --format cjs --minify --outfile dist/index.
|
|
78
|
+
"build:bundle": "bun build src/index.ts --target bun --format esm --minify --outfile dist/index.mjs && bun build src/index.ts --target bun --format cjs --minify --outfile dist/index.cjs && bun build src/errors/index.ts --target bun --format cjs --minify --outfile dist/errors/index.cjs",
|
|
83
79
|
"build:cli": "bun build src/cli/index.ts --target bun --outfile dist/cli.js",
|
|
84
80
|
"local:cli:build": "bun run build:lib",
|
|
85
81
|
"local:cli:dev": "bun run dist/cli.js dev --config ./vector.config.ts",
|
|
@@ -88,7 +84,7 @@
|
|
|
88
84
|
"test:unit": "bun test tests/*.test.ts",
|
|
89
85
|
"test:watch": "bun test --watch tests/*.test.ts",
|
|
90
86
|
"test:coverage": "bun test --coverage tests/*.test.ts",
|
|
91
|
-
"test:e2e": "bun test --max-concurrency 1 tests/e2e/e2e.test.ts tests/e2e/zod-io.e2e.test.ts",
|
|
87
|
+
"test:e2e": "bun test --max-concurrency 1 tests/e2e/e2e.test.ts tests/e2e/zod-io.e2e.test.ts tests/e2e/package-exports.test.ts",
|
|
92
88
|
"test:load": "bun run tests/e2e/load.test.ts",
|
|
93
89
|
"test:soak": "bun run tests/e2e/soak.test.ts",
|
|
94
90
|
"test:benchmark": "bun run tests/e2e/benchmark.test.ts",
|
package/src/auth/protected.ts
CHANGED
|
@@ -7,6 +7,10 @@ export class AuthManager<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
7
7
|
this.protectedHandler = handler;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
clearProtectedHandler() {
|
|
11
|
+
this.protectedHandler = null;
|
|
12
|
+
}
|
|
13
|
+
|
|
10
14
|
async authenticate(request: VectorRequest<TTypes>): Promise<GetAuthType<TTypes> | null> {
|
|
11
15
|
if (!this.protectedHandler) {
|
|
12
16
|
throw new Error('Protected handler not configured. Use vector.protected() to set authentication handler.');
|
package/src/cache/manager.ts
CHANGED
|
@@ -16,6 +16,10 @@ export class CacheManager<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
16
16
|
this.cacheHandler = handler;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
clearCacheHandler() {
|
|
20
|
+
this.cacheHandler = null;
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
async get<T = GetCacheType<TTypes>>(
|
|
20
24
|
key: string,
|
|
21
25
|
factory: () => Promise<T>,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
type SignalEvent = 'SIGINT' | 'SIGTERM';
|
|
2
|
+
|
|
3
|
+
interface ShutdownTarget {
|
|
4
|
+
shutdown?: () => Promise<void> | void;
|
|
5
|
+
stop?: () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface GracefulShutdownOptions {
|
|
9
|
+
getTarget: () => ShutdownTarget | null | undefined;
|
|
10
|
+
on?: (event: SignalEvent, listener: () => void) => void;
|
|
11
|
+
off?: (event: SignalEvent, listener: () => void) => void;
|
|
12
|
+
exit?: (code: number) => void;
|
|
13
|
+
logError?: (message?: any, ...optionalParams: any[]) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function installGracefulShutdownHandlers(options: GracefulShutdownOptions): () => void {
|
|
17
|
+
const on = options.on ?? ((event: SignalEvent, listener: () => void) => process.on(event, listener));
|
|
18
|
+
const off = options.off ?? ((event: SignalEvent, listener: () => void) => process.off(event, listener));
|
|
19
|
+
const exit = options.exit ?? ((code: number) => process.exit(code));
|
|
20
|
+
const logError = options.logError ?? console.error;
|
|
21
|
+
let shuttingDown = false;
|
|
22
|
+
|
|
23
|
+
const handleSignal = async (signal: SignalEvent): Promise<void> => {
|
|
24
|
+
if (shuttingDown) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
shuttingDown = true;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const target = options.getTarget();
|
|
31
|
+
if (target) {
|
|
32
|
+
if (typeof target.shutdown === 'function') {
|
|
33
|
+
await target.shutdown();
|
|
34
|
+
} else if (typeof target.stop === 'function') {
|
|
35
|
+
target.stop();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exit(0);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
logError(`[vector] Graceful shutdown failed after ${signal}:`, error);
|
|
41
|
+
exit(1);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const onSigint = () => {
|
|
46
|
+
void handleSignal('SIGINT');
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const onSigterm = () => {
|
|
50
|
+
void handleSignal('SIGTERM');
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
on('SIGINT', onSigint);
|
|
54
|
+
on('SIGTERM', onSigterm);
|
|
55
|
+
|
|
56
|
+
return () => {
|
|
57
|
+
off('SIGINT', onSigint);
|
|
58
|
+
off('SIGTERM', onSigterm);
|
|
59
|
+
};
|
|
60
|
+
}
|
package/src/cli/index.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { watch } from 'node:fs';
|
|
4
4
|
import { parseArgs } from 'node:util';
|
|
5
|
-
import { getVectorInstance } from '../core/vector';
|
|
6
|
-
import { ConfigLoader } from '../core/config-loader';
|
|
7
5
|
import { resolveHost, resolvePort, resolveRoutesDir } from './option-resolution';
|
|
6
|
+
import { installGracefulShutdownHandlers } from './graceful-shutdown';
|
|
7
|
+
import { startVector } from '../start-vector';
|
|
8
|
+
import type { StartedVectorApp } from '../types';
|
|
8
9
|
|
|
9
10
|
// Compatibility layer for both Node and Bun
|
|
10
11
|
const args = typeof Bun !== 'undefined' ? Bun.argv.slice(2) : process.argv.slice(2);
|
|
@@ -54,9 +55,10 @@ async function runDev() {
|
|
|
54
55
|
const isDev = command === 'dev';
|
|
55
56
|
|
|
56
57
|
let server: any = null;
|
|
57
|
-
let
|
|
58
|
+
let app: StartedVectorApp<any> | null = null;
|
|
59
|
+
let removeShutdownHandlers: (() => void) | null = null;
|
|
58
60
|
|
|
59
|
-
async function startServer(): Promise<{ server: any;
|
|
61
|
+
async function startServer(): Promise<{ server: any; app: StartedVectorApp<any>; config: any }> {
|
|
60
62
|
// Create a timeout promise that rejects after 10 seconds
|
|
61
63
|
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
62
64
|
setTimeout(() => {
|
|
@@ -65,50 +67,35 @@ async function runDev() {
|
|
|
65
67
|
});
|
|
66
68
|
|
|
67
69
|
// Create the actual server start promise
|
|
68
|
-
const serverStartPromise = (async (): Promise<{ server: any;
|
|
70
|
+
const serverStartPromise = (async (): Promise<{ server: any; app: StartedVectorApp<any>; config: any }> => {
|
|
69
71
|
const explicitConfigPath = values.config as string | undefined;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
exposeHeaders: 'Authorization',
|
|
91
|
-
maxAge: 86400,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Get Vector instance and configure handlers
|
|
96
|
-
vector = getVectorInstance();
|
|
97
|
-
|
|
98
|
-
// Load and set auth handler if configured
|
|
99
|
-
const authHandler = await configLoader.loadAuthHandler();
|
|
100
|
-
if (authHandler) {
|
|
101
|
-
vector.setProtectedHandler(authHandler);
|
|
102
|
-
}
|
|
72
|
+
app = await startVector({
|
|
73
|
+
configPath: explicitConfigPath,
|
|
74
|
+
mutateConfig: (loadedConfig) => {
|
|
75
|
+
const config = { ...loadedConfig } as Record<string, any>;
|
|
76
|
+
config.port = resolvePort(config.port, hasPortOption, values.port as string);
|
|
77
|
+
config.hostname = resolveHost(config.hostname, hasHostOption, values.host as string);
|
|
78
|
+
config.routesDir = resolveRoutesDir(config.routesDir, hasRoutesOption, values.routes as string);
|
|
79
|
+
config.development = config.development ?? isDev;
|
|
80
|
+
config.autoDiscover = true; // Always auto-discover routes
|
|
81
|
+
|
|
82
|
+
if (config.cors === undefined && values.cors) {
|
|
83
|
+
config.cors = {
|
|
84
|
+
origin: '*',
|
|
85
|
+
credentials: true,
|
|
86
|
+
allowHeaders: 'Content-Type, Authorization',
|
|
87
|
+
allowMethods: 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
|
|
88
|
+
exposeHeaders: 'Authorization',
|
|
89
|
+
maxAge: 86400,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
103
92
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
vector.setCacheHandler(cacheHandler);
|
|
108
|
-
}
|
|
93
|
+
return config;
|
|
94
|
+
},
|
|
95
|
+
});
|
|
109
96
|
|
|
110
|
-
|
|
111
|
-
|
|
97
|
+
server = app.server;
|
|
98
|
+
const config = app.config as Record<string, any>;
|
|
112
99
|
|
|
113
100
|
// Verify the server is actually running
|
|
114
101
|
if (!server || !server.port) {
|
|
@@ -120,7 +107,7 @@ async function runDev() {
|
|
|
120
107
|
|
|
121
108
|
console.log(`\nListening on ${cyan}http://${config.hostname}:${config.port}${reset}\n`);
|
|
122
109
|
|
|
123
|
-
return { server,
|
|
110
|
+
return { server, app, config };
|
|
124
111
|
})();
|
|
125
112
|
|
|
126
113
|
// Race between server startup and timeout
|
|
@@ -132,6 +119,12 @@ async function runDev() {
|
|
|
132
119
|
const result = await startServer();
|
|
133
120
|
server = result.server;
|
|
134
121
|
|
|
122
|
+
if (!removeShutdownHandlers) {
|
|
123
|
+
removeShutdownHandlers = installGracefulShutdownHandlers({
|
|
124
|
+
getTarget: () => app,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
135
128
|
// Setup file watching for hot reload
|
|
136
129
|
if (isDev && values.watch) {
|
|
137
130
|
try {
|
|
@@ -173,8 +166,8 @@ async function runDev() {
|
|
|
173
166
|
changedFiles.clear();
|
|
174
167
|
|
|
175
168
|
// Stop the current server
|
|
176
|
-
if (
|
|
177
|
-
|
|
169
|
+
if (app) {
|
|
170
|
+
app.stop();
|
|
178
171
|
}
|
|
179
172
|
|
|
180
173
|
// Small delay to ensure file system operations complete
|
|
@@ -184,7 +177,7 @@ async function runDev() {
|
|
|
184
177
|
try {
|
|
185
178
|
const result = await startServer();
|
|
186
179
|
server = result.server;
|
|
187
|
-
|
|
180
|
+
app = result.app;
|
|
188
181
|
} catch (error: any) {
|
|
189
182
|
console.error('\n[Reload Error]', error.message || error);
|
|
190
183
|
// Don't exit the process on reload failures, just continue watching
|
|
@@ -35,8 +35,8 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
35
35
|
this.configSource = 'user';
|
|
36
36
|
} catch (error: any) {
|
|
37
37
|
const msg = error instanceof Error ? error.message : String(error);
|
|
38
|
-
console.error(`[
|
|
39
|
-
console.error('[
|
|
38
|
+
console.error(`[vector] Failed to load config from ${this.configPath}: ${msg}`);
|
|
39
|
+
console.error('[vector] Server is using default configuration. Fix your config file and restart.');
|
|
40
40
|
this.config = {};
|
|
41
41
|
}
|
|
42
42
|
} else {
|
|
@@ -62,9 +62,12 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
|
|
|
62
62
|
config.reusePort = this.config.reusePort;
|
|
63
63
|
config.development = this.config.development;
|
|
64
64
|
config.routesDir = this.config.routesDir || './routes';
|
|
65
|
+
config.routeExcludePatterns = this.config.routeExcludePatterns;
|
|
65
66
|
config.idleTimeout = this.config.idleTimeout;
|
|
66
67
|
config.defaults = this.config.defaults;
|
|
67
68
|
config.openapi = this.config.openapi;
|
|
69
|
+
config.startup = this.config.startup;
|
|
70
|
+
config.shutdown = this.config.shutdown;
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
// Always auto-discover routes
|