vector-framework 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +99 -628
  2. package/dist/auth/protected.d.ts +1 -0
  3. package/dist/auth/protected.d.ts.map +1 -1
  4. package/dist/auth/protected.js +3 -0
  5. package/dist/auth/protected.js.map +1 -1
  6. package/dist/cache/manager.d.ts +1 -0
  7. package/dist/cache/manager.d.ts.map +1 -1
  8. package/dist/cache/manager.js +5 -7
  9. package/dist/cache/manager.js.map +1 -1
  10. package/dist/cli/graceful-shutdown.d.ts +15 -0
  11. package/dist/cli/graceful-shutdown.d.ts.map +1 -0
  12. package/dist/cli/graceful-shutdown.js +42 -0
  13. package/dist/cli/graceful-shutdown.js.map +1 -0
  14. package/dist/cli/index.js +46 -97
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/option-resolution.d.ts +4 -0
  17. package/dist/cli/option-resolution.d.ts.map +1 -0
  18. package/dist/cli/option-resolution.js +28 -0
  19. package/dist/cli/option-resolution.js.map +1 -0
  20. package/dist/cli.js +3423 -660
  21. package/dist/constants/index.d.ts +3 -0
  22. package/dist/constants/index.d.ts.map +1 -1
  23. package/dist/constants/index.js +6 -0
  24. package/dist/constants/index.js.map +1 -1
  25. package/dist/core/config-loader.d.ts.map +1 -1
  26. package/dist/core/config-loader.js +7 -2
  27. package/dist/core/config-loader.js.map +1 -1
  28. package/dist/core/router.d.ts +41 -17
  29. package/dist/core/router.d.ts.map +1 -1
  30. package/dist/core/router.js +432 -153
  31. package/dist/core/router.js.map +1 -1
  32. package/dist/core/server.d.ts +17 -1
  33. package/dist/core/server.d.ts.map +1 -1
  34. package/dist/core/server.js +471 -31
  35. package/dist/core/server.js.map +1 -1
  36. package/dist/core/vector.d.ts +8 -5
  37. package/dist/core/vector.d.ts.map +1 -1
  38. package/dist/core/vector.js +53 -14
  39. package/dist/core/vector.js.map +1 -1
  40. package/dist/dev/route-generator.d.ts.map +1 -1
  41. package/dist/dev/route-generator.js.map +1 -1
  42. package/dist/dev/route-scanner.d.ts.map +1 -1
  43. package/dist/dev/route-scanner.js +1 -5
  44. package/dist/dev/route-scanner.js.map +1 -1
  45. package/dist/http.d.ts +14 -14
  46. package/dist/http.d.ts.map +1 -1
  47. package/dist/http.js +34 -41
  48. package/dist/http.js.map +1 -1
  49. package/dist/index.d.ts +2 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +1420 -8
  52. package/dist/index.js.map +1 -1
  53. package/dist/index.mjs +1420 -8
  54. package/dist/middleware/manager.d.ts.map +1 -1
  55. package/dist/middleware/manager.js +4 -0
  56. package/dist/middleware/manager.js.map +1 -1
  57. package/dist/openapi/docs-ui.d.ts +2 -0
  58. package/dist/openapi/docs-ui.d.ts.map +1 -0
  59. package/dist/openapi/docs-ui.js +1425 -0
  60. package/dist/openapi/docs-ui.js.map +1 -0
  61. package/dist/openapi/generator.d.ts +12 -0
  62. package/dist/openapi/generator.d.ts.map +1 -0
  63. package/dist/openapi/generator.js +502 -0
  64. package/dist/openapi/generator.js.map +1 -0
  65. package/dist/start-vector.d.ts +3 -0
  66. package/dist/start-vector.d.ts.map +1 -0
  67. package/dist/start-vector.js +38 -0
  68. package/dist/start-vector.js.map +1 -0
  69. package/dist/types/index.d.ts +95 -11
  70. package/dist/types/index.d.ts.map +1 -1
  71. package/dist/types/standard-schema.d.ts +118 -0
  72. package/dist/types/standard-schema.d.ts.map +1 -0
  73. package/dist/types/standard-schema.js +2 -0
  74. package/dist/types/standard-schema.js.map +1 -0
  75. package/dist/utils/cors.d.ts +13 -0
  76. package/dist/utils/cors.d.ts.map +1 -0
  77. package/dist/utils/cors.js +89 -0
  78. package/dist/utils/cors.js.map +1 -0
  79. package/dist/utils/logger.js +1 -1
  80. package/dist/utils/path.d.ts +6 -0
  81. package/dist/utils/path.d.ts.map +1 -1
  82. package/dist/utils/path.js +5 -0
  83. package/dist/utils/path.js.map +1 -1
  84. package/dist/utils/schema-validation.d.ts +31 -0
  85. package/dist/utils/schema-validation.d.ts.map +1 -0
  86. package/dist/utils/schema-validation.js +77 -0
  87. package/dist/utils/schema-validation.js.map +1 -0
  88. package/dist/utils/validation.d.ts.map +1 -1
  89. package/dist/utils/validation.js +3 -0
  90. package/dist/utils/validation.js.map +1 -1
  91. package/package.json +15 -12
  92. package/src/auth/protected.ts +7 -13
  93. package/src/cache/manager.ts +8 -18
  94. package/src/cli/graceful-shutdown.ts +60 -0
  95. package/src/cli/index.ts +52 -115
  96. package/src/cli/option-resolution.ts +40 -0
  97. package/src/constants/index.ts +7 -0
  98. package/src/core/config-loader.ts +7 -4
  99. package/src/core/router.ts +502 -156
  100. package/src/core/server.ts +610 -33
  101. package/src/core/vector.ts +87 -33
  102. package/src/dev/route-generator.ts +1 -3
  103. package/src/dev/route-scanner.ts +2 -9
  104. package/src/http.ts +85 -125
  105. package/src/index.ts +4 -3
  106. package/src/middleware/manager.ts +4 -0
  107. package/src/openapi/assets/favicon/android-chrome-192x192.png +0 -0
  108. package/src/openapi/assets/favicon/android-chrome-512x512.png +0 -0
  109. package/src/openapi/assets/favicon/apple-touch-icon.png +0 -0
  110. package/src/openapi/assets/favicon/favicon-16x16.png +0 -0
  111. package/src/openapi/assets/favicon/favicon-32x32.png +0 -0
  112. package/src/openapi/assets/favicon/favicon.ico +0 -0
  113. package/src/openapi/assets/favicon/site.webmanifest +11 -0
  114. package/src/openapi/assets/logo.svg +12 -0
  115. package/src/openapi/assets/logo_dark.svg +6 -0
  116. package/src/openapi/assets/logo_icon.png +0 -0
  117. package/src/openapi/assets/logo_white.svg +6 -0
  118. package/src/openapi/assets/tailwindcdn.js +83 -0
  119. package/src/openapi/docs-ui.ts +1435 -0
  120. package/src/openapi/generator.ts +586 -0
  121. package/src/start-vector.ts +50 -0
  122. package/src/types/index.ts +138 -17
  123. package/src/types/standard-schema.ts +147 -0
  124. package/src/utils/cors.ts +101 -0
  125. package/src/utils/logger.ts +1 -1
  126. package/src/utils/path.ts +6 -0
  127. package/src/utils/schema-validation.ts +123 -0
  128. package/src/utils/validation.ts +3 -0
package/README.md CHANGED
@@ -1,706 +1,177 @@
1
- # Vector Framework
1
+ # vector
2
2
 
3
- **Blazing fast, secure, and developer-friendly API framework for Bun**
3
+ <img width="1640" height="664" alt="vector-bw-banner" src="https://github.com/user-attachments/assets/afeb8c6e-0729-4fea-9054-7972f8af9365" />
4
4
 
5
- - **100,000+ requests/second** - Optimized for extreme performance
6
- - **Single dependency** - Only itty-router, minimizing security risks
7
- - **Zero build step** - Native TypeScript execution with Bun
8
- - **Encore-like DX** - Declarative, type-safe APIs you'll love
5
+ Blazing fast, secure, and developer-friendly API framework for Bun.
9
6
 
10
- ## Quick Start
7
+ Vector is a Bun-first framework for building HTTP APIs with declarative route files, strong TypeScript inference, and zero runtime dependencies.
8
+
9
+ - **Zero Dependencies**: No runtime routing dependency
10
+ - **Bun Native**: TypeScript-first workflow with the Bun runtime
11
+ - **Type Safe**: Typed request/auth/context with schema-driven validation
12
+ - **Built In**: Middleware, auth hooks, caching, CORS, OpenAPI generation
11
13
 
12
- ### Installation
14
+ ## Installation
13
15
 
14
16
  ```bash
15
17
  bun add vector-framework
16
18
  ```
17
19
 
18
- ### 1. Configure Your App
20
+ Requirements:
21
+
22
+ - Bun `>= 1.0.0`
23
+
24
+ ## Quick Start
19
25
 
20
- Create `vector.config.ts` in your project root:
26
+ ### 1. Create `vector.config.ts`
21
27
 
22
- ```typescript
23
- // vector.config.ts
28
+ ```ts
24
29
  import type { VectorConfigSchema } from "vector-framework";
25
30
 
26
31
  const config: VectorConfigSchema = {
27
- // Server configuration
28
32
  port: 3000,
29
33
  hostname: "localhost",
30
34
  development: process.env.NODE_ENV !== "production",
31
- routesDir: "./routes", // Auto-discovers routes here
32
-
33
- // CORS configuration
34
- cors: {
35
- origin: "*",
36
- credentials: true,
37
- allowHeaders: ["Content-Type", "Authorization"],
38
- allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
39
- },
40
-
41
- // Authentication handler
42
- auth: async (request) => {
43
- const token = request.headers.get("Authorization")?.replace("Bearer ", "");
44
- if (token === "valid-token") {
45
- return { id: "user-123", email: "user@example.com" };
46
- }
47
- throw new Error("Invalid token");
48
- },
49
-
50
- // Optional: Cache handler (Redis example)
51
- cache: async (key, factory, ttl) => {
52
- // Your caching logic here
53
- const cached = await redis.get(key);
54
- if (cached) return JSON.parse(cached);
55
-
56
- const value = await factory();
57
- await redis.setex(key, ttl, JSON.stringify(value));
58
- return value;
35
+ routesDir: "./routes",
36
+ defaults: {
37
+ route: {
38
+ expose: true,
39
+ auth: false,
40
+ },
59
41
  },
60
-
61
- // Optional: Middleware
62
- before: [
63
- async (request) => {
64
- console.log(`${request.method} ${request.url}`);
65
- return request;
66
- }
67
- ],
68
- after: [
69
- async (response, request) => {
70
- const duration = Date.now() - (request.startTime || Date.now());
71
- response.headers.set("X-Response-Time", `${duration}ms`);
72
- return response;
73
- }
74
- ],
75
42
  };
76
43
 
77
44
  export default config;
78
45
  ```
79
46
 
80
- ### 2. Create Your First Route
47
+ ### 2. Create a route file
81
48
 
82
- ```typescript
49
+ ```ts
83
50
  // routes/hello.ts
84
51
  import { route } from "vector-framework";
85
52
 
86
- // Simple public endpoint
87
53
  export const hello = route(
88
- {
89
- method: "GET",
90
- path: "/hello/:name",
91
- expose: true, // Public endpoint (default: true)
92
- },
93
- async (req) => {
94
- return { message: `Hello ${req.params.name}!` };
95
- }
96
- );
97
-
98
- // Protected endpoint - uses auth from config
99
- export const getProfile = route(
100
- {
101
- method: "GET",
102
- path: "/profile",
103
- auth: true, // Requires authentication
104
- expose: true,
105
- },
54
+ { method: "GET", path: "/hello/:name", expose: true },
106
55
  async (req) => {
107
- return {
108
- user: req.authUser, // Typed from your auth handler
109
- timestamp: new Date(),
110
- };
111
- }
112
- );
113
-
114
- // Cached endpoint
115
- export const getUsers = route(
116
- {
117
- method: "GET",
118
- path: "/users",
119
- cache: 300, // Cache for 5 minutes
120
- expose: true,
56
+ return { message: `Hello ${req.params.name}` };
121
57
  },
122
- async () => {
123
- // Expensive operation, will be cached
124
- const users = await db.users.findMany();
125
- return { users };
126
- }
127
58
  );
128
59
  ```
129
60
 
130
- ### 3. Start Your Server
61
+ ### 3. Run the server
131
62
 
132
63
  ```bash
133
- # Development mode with hot reload
134
64
  bun vector dev
135
-
136
- # Production mode
137
- bun vector start
138
-
139
- # With custom options
140
- bun vector dev --port 4000 --routes ./api
141
65
  ```
142
66
 
143
- That's it! Your API is running at `http://localhost:3000` 🎉
144
-
145
- ## TypeScript Type Safety
146
-
147
- Vector provides full type safety with customizable types. Define your types in the config and use them in routes:
148
-
149
- ```typescript
150
- // vector.config.ts
151
- import type { VectorConfigSchema, VectorTypes } from "vector-framework";
67
+ Your API will be available at `http://localhost:3000`.
152
68
 
153
- // Define your custom user type
154
- interface MyUser {
155
- id: string;
156
- email: string;
157
- role: "admin" | "user";
158
- permissions: string[];
159
- }
160
-
161
- // Extend Vector types
162
- interface MyAppTypes extends VectorTypes {
163
- auth: MyUser;
164
- }
165
-
166
- // Use in config with type parameter
167
- const config: VectorConfigSchema<MyAppTypes> = {
168
- port: 3000,
69
+ ## Production Start
169
70
 
170
- // Auth handler returns your custom type
171
- auth: async (request): Promise<MyUser> => {
172
- // Your auth logic
173
- return {
174
- id: "user-123",
175
- email: "user@example.com",
176
- role: "admin",
177
- permissions: ["read", "write"],
178
- };
179
- },
180
- };
181
-
182
- export default config;
183
- export type { MyAppTypes }; // Export for use in routes
184
- ```
185
-
186
- ```typescript
187
- // routes/admin.ts
188
- import { route, APIError } from "vector-framework";
189
- import type { MyAppTypes } from "../vector.config";
190
-
191
- // Use type parameter to get fully typed request
192
- export const adminOnly = route<MyAppTypes>(
193
- {
194
- method: "GET",
195
- path: "/admin/data",
196
- auth: true,
197
- expose: true,
198
- },
199
- async (req) => {
200
- // req.authUser is now typed as MyUser
201
- if (req.authUser?.role !== "admin") {
202
- throw APIError.forbidden("Admin access required");
203
- }
204
-
205
- // TypeScript knows these properties exist
206
- return {
207
- user: req.authUser.email,
208
- permissions: req.authUser.permissions,
209
- };
210
- }
211
- );
212
- ```
213
-
214
- ## Core Features
215
-
216
- ### Route Options
217
-
218
- ```typescript
219
- interface RouteOptions {
220
- method: string; // HTTP method (GET, POST, etc.)
221
- path: string; // Route path with params (/users/:id)
222
- expose?: boolean; // Make route accessible (default: true)
223
- auth?: boolean; // Require authentication
224
- cache?: number | { // Cache configuration
225
- ttl: number; // Time to live in seconds
226
- key?: string; // Custom cache key
227
- };
228
- rawRequest?: boolean; // Skip body parsing
229
- rawResponse?: boolean; // Return raw response
230
- responseContentType?: string; // Response content type
231
- }
71
+ ```bash
72
+ bun vector start --config ./vector.config.ts --routes ./routes --port 8080 --host 0.0.0.0
232
73
  ```
233
74
 
234
- ### Request Object
235
-
236
- Every route handler receives a typed request object:
75
+ Notes:
237
76
 
238
- ```typescript
239
- export const example = route(
240
- { method: "POST", path: "/example/:id" },
241
- async (req) => {
242
- // All available request properties:
243
- req.params.id; // URL parameters
244
- req.query.search; // Query parameters
245
- req.headers; // Request headers
246
- req.cookies; // Parsed cookies
247
- req.content; // Parsed body (JSON/form data)
248
- req.authUser; // Authenticated user (when auth: true)
249
- req.context; // Request context
250
- req.metadata; // Route metadata
251
- }
252
- );
253
- ```
77
+ - `start` uses the same config and route options as `dev`.
78
+ - `start` sets `NODE_ENV=production`.
79
+ - File watching is only enabled for `dev`.
254
80
 
255
- ### Error Handling
81
+ ## Programmatic Start
256
82
 
257
- Vector provides comprehensive error responses. Requests with a malformed URL are automatically rejected with a `400 Bad Request` before reaching your handler. Unhandled exceptions in handlers return a `500 Internal Server Error`.
83
+ ```ts
84
+ import { startVector } from "vector-framework";
258
85
 
259
- ```typescript
260
- import { APIError } from "vector-framework";
86
+ const app = await startVector({
87
+ configPath: "./vector.config.ts",
88
+ });
261
89
 
262
- export const example = route(
263
- { method: "GET", path: "/data/:id" },
264
- async (req) => {
265
- // Client errors (4xx)
266
- if (!req.params.id) {
267
- throw APIError.badRequest("ID is required");
268
- }
269
-
270
- const data = await findData(req.params.id);
271
- if (!data) {
272
- throw APIError.notFound("Data not found");
273
- }
274
-
275
- if (!canAccess(req.authUser, data)) {
276
- throw APIError.forbidden("Access denied");
277
- }
278
-
279
- // Rate limiting
280
- if (await isRateLimited(req)) {
281
- throw APIError.tooManyRequests("Please wait before trying again");
282
- }
283
-
284
- // Server errors (5xx)
285
- try {
286
- return await processData(data);
287
- } catch (error) {
288
- throw APIError.internalServerError("Processing failed");
289
- }
290
- }
291
- );
90
+ console.log(`Listening on ${app.server.hostname}:${app.server.port}`);
292
91
  ```
293
92
 
294
- ## Configuration Reference
93
+ Notes:
295
94
 
296
- ### VectorConfigSchema
95
+ - `startVector()` does not enable file watching.
96
+ - `app.stop()` stops immediately (used for dev reload flows).
97
+ - `await app.shutdown()` performs graceful shutdown and runs config `shutdown` hook.
297
98
 
298
- ```typescript
299
- interface VectorConfigSchema {
300
- // Server
301
- port?: number; // Server port (default: 3000)
302
- hostname?: string; // Server hostname (default: localhost)
303
- reusePort?: boolean; // Reuse port (default: true)
304
- development?: boolean; // Development mode
305
- routesDir?: string; // Routes directory (default: ./routes)
306
- routeExcludePatterns?: string[]; // Patterns to exclude from route scanning
307
- idleTimeout?: number; // Idle timeout in seconds
99
+ ## Optional: Validation + OpenAPI
308
100
 
309
- // CORS
310
- cors?: CorsOptions | boolean;
311
-
312
- // Handlers
313
- auth?: ProtectedHandler; // Authentication handler
314
- cache?: CacheHandler; // Cache handler
315
-
316
- // Middleware
317
- before?: BeforeMiddleware[]; // Pre-request middleware
318
- after?: AfterMiddleware[]; // Post-response middleware
319
- }
101
+ ```bash
102
+ bun add -d zod
320
103
  ```
321
104
 
322
- ### Example: Full Configuration
105
+ Vector is not tied to Zod. It supports any validation library that implements the
106
+ `StandardSchemaV1` interface (`~standard` v1).
323
107
 
324
- ```typescript
325
- // vector.config.ts
326
- import type { VectorConfigSchema } from "vector-framework";
327
- import { verifyJWT } from "./lib/auth";
328
- import { redis } from "./lib/redis";
108
+ Common compatible choices include:
329
109
 
330
- const config: VectorConfigSchema = {
331
- port: process.env.PORT || 3000,
332
- hostname: "0.0.0.0",
333
- development: process.env.NODE_ENV !== "production",
334
- routesDir: "./api/routes",
335
- routeExcludePatterns: ["*.test.ts", "*.spec.ts"], // Optional: custom exclusions
336
- idleTimeout: 60,
337
-
338
- cors: {
339
- origin: ["https://example.com", "https://app.example.com"],
340
- credentials: true,
341
- allowHeaders: ["Content-Type", "Authorization", "X-Request-ID"],
342
- allowMethods: ["GET", "POST", "PUT", "DELETE"],
343
- maxAge: 86400,
344
- },
110
+ - Zod (v4+)
111
+ - Valibot
112
+ - ArkType
345
113
 
346
- auth: async (request) => {
347
- const token = request.headers.get("Authorization")?.replace("Bearer ", "");
348
- if (!token) throw new Error("No token provided");
114
+ For OpenAPI schema conversion, your library also needs `StandardJSONSchemaV1`
115
+ (`~standard.jsonSchema.input/output`). If those converters are missing, runtime
116
+ validation still works, but schema conversion is skipped.
349
117
 
350
- const user = await verifyJWT(token);
351
- if (!user) throw new Error("Invalid token");
118
+ ```ts
119
+ import { route } from "vector-framework";
120
+ import { z } from "zod";
352
121
 
353
- return user;
354
- },
122
+ const CreateUserInput = z.object({
123
+ body: z.object({
124
+ email: z.string().email(),
125
+ name: z.string().min(1),
126
+ }),
127
+ });
355
128
 
356
- cache: async (key, factory, ttl) => {
357
- const cached = await redis.get(key);
358
- if (cached) return JSON.parse(cached);
129
+ const CreateUserSchema = { input: CreateUserInput };
359
130
 
360
- const value = await factory();
361
- await redis.setex(key, ttl, JSON.stringify(value));
362
- return value;
131
+ export const createUser = route(
132
+ { method: "POST", path: "/users", expose: true, schema: CreateUserSchema },
133
+ async (req) => {
134
+ return { created: true, email: req.content.email };
363
135
  },
364
-
365
- before: [
366
- // Logging middleware
367
- async (request) => {
368
- request.startTime = Date.now();
369
- console.log(`[${new Date().toISOString()}] ${request.method} ${request.url}`);
370
- return request;
371
- },
372
-
373
- // Request ID middleware
374
- async (request) => {
375
- request.id = crypto.randomUUID();
376
- return request;
377
- },
378
- ],
379
-
380
- after: [
381
- // Response time header
382
- async (response, request) => {
383
- const duration = Date.now() - (request.startTime || Date.now());
384
- response.headers.set("X-Response-Time", `${duration}ms`);
385
- return response;
386
- },
387
-
388
- // Security headers
389
- async (response) => {
390
- response.headers.set("X-Content-Type-Options", "nosniff");
391
- response.headers.set("X-Frame-Options", "DENY");
392
- return response;
393
- },
394
- ],
395
- };
396
-
397
- export default config;
398
- ```
399
-
400
- ## CLI Commands
401
-
402
- ```bash
403
- # Development server with hot reload
404
- bun vector dev
405
-
406
- # Production server
407
- bun vector start
408
-
409
- # Build for production
410
- bun vector build
411
-
412
- # Command options
413
- bun vector dev --port 4000 # Custom port
414
- bun vector dev --host 0.0.0.0 # Custom host
415
- bun vector dev --routes ./api # Custom routes directory
416
- bun vector dev --config ./custom.config.ts # Custom config file
417
- ```
418
-
419
- ## Project Structure
420
-
421
- ```
422
- my-app/
423
- ├── vector.config.ts # Framework configuration
424
- ├── routes/ # Auto-discovered routes
425
- │ ├── users.ts # /users endpoints
426
- │ ├── posts.ts # /posts endpoints
427
- │ ├── users.test.ts # Test file (automatically excluded)
428
- │ └── admin/ # Nested routes
429
- │ └── stats.ts # /admin/stats endpoints
430
- ├── lib/ # Your libraries
431
- │ ├── auth.ts
432
- │ ├── db.ts
433
- │ └── redis.ts
434
- └── package.json
435
- ```
436
-
437
- ## Route Discovery
438
-
439
- Vector automatically discovers and loads route files from your `routesDir` (default: `./routes`). By default, the following file patterns are excluded from route scanning:
440
-
441
- - `*.test.ts`, `*.test.js`, `*.test.tsx`, `*.test.jsx` - Test files
442
- - `*.spec.ts`, `*.spec.js`, `*.spec.tsx`, `*.spec.jsx` - Spec files
443
- - `*.tests.ts`, `*.tests.js` - Test suite files
444
- - `**/__tests__/**` - Test directories
445
- - `*.interface.ts`, `*.type.ts` - Type definition files
446
- - `*.d.ts` - TypeScript declaration files
447
-
448
- You can customize the exclusion patterns using the `routeExcludePatterns` configuration option. Both single-segment (`*`) and multi-segment (`**`) glob patterns are supported:
449
-
450
- ```typescript
451
- // vector.config.ts
452
- const config: VectorConfigSchema = {
453
- routesDir: "./routes",
454
- // Custom exclusion patterns (overrides defaults)
455
- routeExcludePatterns: [
456
- "*.test.ts",
457
- "*.spec.ts",
458
- "*.mock.ts",
459
- "**/__tests__/**", // Exclude any nested __tests__ directory
460
- "_*.ts", // Exclude files starting with underscore
461
- ],
462
- };
136
+ );
463
137
  ```
464
138
 
465
- ## Performance
466
-
467
- Vector achieves exceptional performance through:
468
-
469
- - **Bun Runtime**: Native TypeScript execution without transpilation
470
- - **Minimal Dependencies**: Only itty-router (3KB) as dependency
471
- - **Optimized Routing**: Efficient regex-based route matching
472
- - **Smart Caching**: Built-in response caching with configurable TTL
473
-
474
- Benchmarks show Vector handling **100,000+ requests/second** on standard hardware.
475
-
476
- ## Why Vector?
477
-
478
- ### For Encore Users
479
- Love Encore's declarative API design but need more flexibility? Vector provides the same developer experience with the freedom to deploy anywhere Bun runs.
139
+ Enable OpenAPI in `vector.config.ts`:
480
140
 
481
- ### For Express/Fastify Users
482
- Tired of middleware chains and verbose configurations? Vector's declarative approach makes APIs cleaner and more maintainable.
483
-
484
- ### For New Projects
485
- Starting fresh? Vector gives you production-ready features from day one with minimal configuration.
486
-
487
- ## Error Reference
488
-
489
- Vector provides comprehensive error responses for all HTTP status codes. All errors return a consistent format:
490
-
491
- ```json
492
- {
493
- "error": true,
494
- "message": "Error message",
495
- "statusCode": 400,
496
- "timestamp": "2025-01-01T00:00:00.000Z"
141
+ ```ts
142
+ openapi: {
143
+ enabled: true,
144
+ path: '/openapi.json',
145
+ docs: false,
497
146
  }
498
147
  ```
499
148
 
500
- ### Client Errors (4xx)
501
-
502
- ```typescript
503
- import { APIError } from "vector-framework";
504
-
505
- // 400 Bad Request
506
- APIError.badRequest("Invalid input data");
507
-
508
- // 401 Unauthorized
509
- APIError.unauthorized("Authentication required");
510
-
511
- // 402 Payment Required
512
- APIError.paymentRequired("Subscription expired");
513
-
514
- // 403 Forbidden
515
- APIError.forbidden("Access denied");
516
-
517
- // 404 Not Found
518
- APIError.notFound("Resource not found");
519
-
520
- // 405 Method Not Allowed
521
- APIError.methodNotAllowed("POST not allowed on this endpoint");
522
-
523
- // 406 Not Acceptable
524
- APIError.notAcceptable("Cannot produce requested content type");
525
-
526
- // 408 Request Timeout
527
- APIError.requestTimeout("Request took too long");
528
-
529
- // 409 Conflict
530
- APIError.conflict("Resource already exists");
531
-
532
- // 410 Gone
533
- APIError.gone("Resource permanently deleted");
534
-
535
- // 411 Length Required
536
- APIError.lengthRequired("Content-Length header required");
537
-
538
- // 412 Precondition Failed
539
- APIError.preconditionFailed("ETag mismatch");
540
-
541
- // 413 Payload Too Large
542
- APIError.payloadTooLarge("Request body exceeds limit");
543
-
544
- // 414 URI Too Long
545
- APIError.uriTooLong("URL exceeds maximum length");
149
+ ## Documentation
546
150
 
547
- // 415 Unsupported Media Type
548
- APIError.unsupportedMediaType("Content-Type not supported");
151
+ Start here for deeper guides:
549
152
 
550
- // 416 Range Not Satisfiable
551
- APIError.rangeNotSatisfiable("Requested range cannot be satisfied");
153
+ - [Docs Index](docs/README.md)
154
+ - [Configuration](docs/configuration.md)
155
+ - [Routing and Request API](docs/routing.md)
156
+ - [TypeScript Types](docs/typescript.md)
157
+ - [Schema Validation](docs/schema-validation.md)
158
+ - [OpenAPI and Docs UI](docs/openapi.md)
159
+ - [CLI and Route Discovery](docs/cli-and-discovery.md)
160
+ - [Error Reference](docs/errors.md)
161
+ - [Migration Notes](docs/migration.md)
162
+ - [Performance Notes](docs/performance.md)
552
163
 
553
- // 417 Expectation Failed
554
- APIError.expectationFailed("Expect header requirements not met");
164
+ ## Examples
555
165
 
556
- // 418 I'm a Teapot
557
- APIError.imATeapot("I refuse to brew coffee");
558
-
559
- // 421 Misdirected Request
560
- APIError.misdirectedRequest("Request sent to wrong server");
561
-
562
- // 422 Unprocessable Entity
563
- APIError.unprocessableEntity("Validation failed");
564
-
565
- // 423 Locked
566
- APIError.locked("Resource is locked");
567
-
568
- // 424 Failed Dependency
569
- APIError.failedDependency("Dependent request failed");
570
-
571
- // 425 Too Early
572
- APIError.tooEarly("Request is too early");
573
-
574
- // 426 Upgrade Required
575
- APIError.upgradeRequired("Protocol upgrade required");
576
-
577
- // 428 Precondition Required
578
- APIError.preconditionRequired("Precondition headers required");
579
-
580
- // 429 Too Many Requests
581
- APIError.tooManyRequests("Rate limit exceeded");
582
-
583
- // 431 Request Header Fields Too Large
584
- APIError.requestHeaderFieldsTooLarge("Headers too large");
585
-
586
- // 451 Unavailable For Legal Reasons
587
- APIError.unavailableForLegalReasons("Content blocked for legal reasons");
588
- ```
589
-
590
- ### Server Errors (5xx)
591
-
592
- ```typescript
593
- // 500 Internal Server Error
594
- APIError.internalServerError("Something went wrong");
595
-
596
- // 501 Not Implemented
597
- APIError.notImplemented("Feature not yet available");
598
-
599
- // 502 Bad Gateway
600
- APIError.badGateway("Upstream server error");
601
-
602
- // 503 Service Unavailable
603
- APIError.serviceUnavailable("Service temporarily down");
604
-
605
- // 504 Gateway Timeout
606
- APIError.gatewayTimeout("Upstream server timeout");
607
-
608
- // 505 HTTP Version Not Supported
609
- APIError.httpVersionNotSupported("HTTP/3 not supported");
610
-
611
- // 506 Variant Also Negotiates
612
- APIError.variantAlsoNegotiates("Content negotiation error");
613
-
614
- // 507 Insufficient Storage
615
- APIError.insufficientStorage("Server storage full");
616
-
617
- // 508 Loop Detected
618
- APIError.loopDetected("Infinite loop detected");
619
-
620
- // 510 Not Extended
621
- APIError.notExtended("Extension required");
622
-
623
- // 511 Network Authentication Required
624
- APIError.networkAuthenticationRequired("Network login required");
625
- ```
626
-
627
- ### Convenience Aliases
628
-
629
- ```typescript
630
- // Alias for 422 Unprocessable Entity
631
- APIError.invalidArgument("Field 'email' is required");
632
-
633
- // Alias for 429 Too Many Requests
634
- APIError.rateLimitExceeded("Try again in 60 seconds");
635
-
636
- // Alias for 503 Service Unavailable
637
- APIError.maintenance("Scheduled maintenance in progress");
638
- ```
639
-
640
- ### Custom Errors
641
-
642
- ```typescript
643
- // Create error with any status code
644
- APIError.custom(456, "Custom error message");
645
-
646
- // With custom content type
647
- APIError.custom(400, "Invalid XML", "application/xml");
648
- ```
649
-
650
- ### Usage in Routes
651
-
652
- ```typescript
653
- export const example = route(
654
- { method: "POST", path: "/api/users" },
655
- async (req) => {
656
- // Validation errors
657
- if (!req.content?.email) {
658
- throw APIError.badRequest("Email is required");
659
- }
660
-
661
- if (!isValidEmail(req.content.email)) {
662
- throw APIError.unprocessableEntity("Invalid email format");
663
- }
664
-
665
- // Authentication errors
666
- if (!req.authUser) {
667
- throw APIError.unauthorized("Please login first");
668
- }
669
-
670
- if (req.authUser.role !== "admin") {
671
- throw APIError.forbidden("Admin access required");
672
- }
673
-
674
- // Resource errors
675
- const existingUser = await findUserByEmail(req.content.email);
676
- if (existingUser) {
677
- throw APIError.conflict("Email already registered");
678
- }
679
-
680
- // Rate limiting
681
- if (await checkRateLimit(req.authUser.id)) {
682
- throw APIError.tooManyRequests("Maximum 5 users per hour");
683
- }
684
-
685
- try {
686
- const user = await createUser(req.content);
687
- return { user };
688
- } catch (error) {
689
- // Database errors
690
- if (error.code === "STORAGE_FULL") {
691
- throw APIError.insufficientStorage("Database full");
692
- }
693
-
694
- // Generic server error
695
- throw APIError.internalServerError("Failed to create user");
696
- }
697
- }
698
- );
699
- ```
166
+ - [examples/routes/health.ts](examples/routes/health.ts)
167
+ - [examples/routes/events.ts](examples/routes/events.ts)
168
+ - [examples/routes/commerce.ts](examples/routes/commerce.ts)
169
+ - [tests/e2e/test-routes.ts](tests/e2e/test-routes.ts) (broader endpoint patterns)
170
+ - [tests/e2e/test-zod-routes.ts](tests/e2e/test-zod-routes.ts) (Zod + I/O validation flows)
700
171
 
701
172
  ## Contributing
702
173
 
703
- Contributions are welcome! Please feel free to submit a Pull Request.
174
+ Contributions are welcome. Open an issue or pull request.
704
175
 
705
176
  ## License
706
177