vitek-plugin 0.1.0-beta
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/LICENSE +21 -0
- package/README.md +908 -0
- package/dist/adapters/vite/dev-server.d.ts +23 -0
- package/dist/adapters/vite/dev-server.d.ts.map +1 -0
- package/dist/adapters/vite/dev-server.js +428 -0
- package/dist/adapters/vite/logger.d.ts +33 -0
- package/dist/adapters/vite/logger.d.ts.map +1 -0
- package/dist/adapters/vite/logger.js +112 -0
- package/dist/core/context/create-context.d.ts +39 -0
- package/dist/core/context/create-context.d.ts.map +1 -0
- package/dist/core/context/create-context.js +34 -0
- package/dist/core/file-system/scan-api-dir.d.ts +26 -0
- package/dist/core/file-system/scan-api-dir.d.ts.map +1 -0
- package/dist/core/file-system/scan-api-dir.js +83 -0
- package/dist/core/file-system/watch-api-dir.d.ts +18 -0
- package/dist/core/file-system/watch-api-dir.d.ts.map +1 -0
- package/dist/core/file-system/watch-api-dir.js +40 -0
- package/dist/core/middleware/compose.d.ts +12 -0
- package/dist/core/middleware/compose.d.ts.map +1 -0
- package/dist/core/middleware/compose.js +27 -0
- package/dist/core/middleware/get-applicable-middlewares.d.ts +17 -0
- package/dist/core/middleware/get-applicable-middlewares.d.ts.map +1 -0
- package/dist/core/middleware/get-applicable-middlewares.js +47 -0
- package/dist/core/middleware/load-global.d.ts +13 -0
- package/dist/core/middleware/load-global.d.ts.map +1 -0
- package/dist/core/middleware/load-global.js +37 -0
- package/dist/core/normalize/normalize-path.d.ts +25 -0
- package/dist/core/normalize/normalize-path.d.ts.map +1 -0
- package/dist/core/normalize/normalize-path.js +76 -0
- package/dist/core/routing/route-matcher.d.ts +10 -0
- package/dist/core/routing/route-matcher.d.ts.map +1 -0
- package/dist/core/routing/route-matcher.js +32 -0
- package/dist/core/routing/route-parser.d.ts +28 -0
- package/dist/core/routing/route-parser.d.ts.map +1 -0
- package/dist/core/routing/route-parser.js +52 -0
- package/dist/core/routing/route-types.d.ts +43 -0
- package/dist/core/routing/route-types.d.ts.map +1 -0
- package/dist/core/routing/route-types.js +5 -0
- package/dist/core/types/extract-ast.d.ts +18 -0
- package/dist/core/types/extract-ast.d.ts.map +1 -0
- package/dist/core/types/extract-ast.js +26 -0
- package/dist/core/types/generate.d.ts +22 -0
- package/dist/core/types/generate.d.ts.map +1 -0
- package/dist/core/types/generate.js +576 -0
- package/dist/core/types/schema.d.ts +21 -0
- package/dist/core/types/schema.d.ts.map +1 -0
- package/dist/core/types/schema.js +17 -0
- package/dist/core/validation/types.d.ts +27 -0
- package/dist/core/validation/types.d.ts.map +1 -0
- package/dist/core/validation/types.js +5 -0
- package/dist/core/validation/validator.d.ts +22 -0
- package/dist/core/validation/validator.d.ts.map +1 -0
- package/dist/core/validation/validator.js +131 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/plugin.d.ts +27 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +54 -0
- package/dist/shared/constants.d.ts +13 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +12 -0
- package/dist/shared/errors.d.ts +75 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +118 -0
- package/dist/shared/response-helpers.d.ts +61 -0
- package/dist/shared/response-helpers.d.ts.map +1 -0
- package/dist/shared/response-helpers.js +100 -0
- package/dist/shared/utils.d.ts +17 -0
- package/dist/shared/utils.d.ts.map +1 -0
- package/dist/shared/utils.js +27 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,908 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="./src/assets/logo.webp" alt="Vitek Plugin Logo" width="200" height="200" />
|
|
3
|
+
|
|
4
|
+
# Vitek Plugin
|
|
5
|
+
|
|
6
|
+
**File-based HTTP API generation for Vite**
|
|
7
|
+
|
|
8
|
+
[](https://github.com/yourusername/vitek-plugin)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](https://vitejs.dev/)
|
|
11
|
+
|
|
12
|
+
> ⚠️ **Beta Version**: This project is currently in beta/testing phase. APIs may change in future releases.
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 🎯 About the Name "Vitek"
|
|
18
|
+
|
|
19
|
+
**Vitek** is a portmanteau combining **"Vite"** (the build tool) and **"tek"** (a suffix suggesting technology/toolkit). The name reflects the plugin's core purpose: bringing powerful API generation capabilities to the Vite ecosystem.
|
|
20
|
+
|
|
21
|
+
The "tek" suffix is commonly used in technology naming to denote tools and frameworks (similar to "kit" or "toolkit"), making "Vitek" a natural fit for a plugin that extends Vite's functionality with file-based API routing and type generation.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 📖 Overview
|
|
26
|
+
|
|
27
|
+
**Vitek** is a powerful Vite plugin that enables automatic file-based HTTP API generation. Write your API endpoints as simple TypeScript/JavaScript files, and Vitek handles all the configuration, type generation, and integration with the Vite development server.
|
|
28
|
+
|
|
29
|
+
### Why Vitek?
|
|
30
|
+
|
|
31
|
+
- 🚀 **Zero Configuration**: Works out of the box with Vite - no separate server setup needed
|
|
32
|
+
- 📁 **File-Based Routing**: Organize your API like your file system - intuitive and scalable
|
|
33
|
+
- 🔥 **Hot Reload**: Automatic reloading of routes and middlewares on file changes
|
|
34
|
+
- 💪 **Type-Safe**: Full TypeScript support with auto-generated types and client helpers
|
|
35
|
+
- 🎯 **Developer Experience**: Generated client helpers for seamless frontend integration
|
|
36
|
+
- 🏗️ **Modular Architecture**: Core logic is runtime-agnostic, ready for other environments
|
|
37
|
+
- ⚡ **Lightweight**: Minimal overhead, runs directly in Vite's dev server
|
|
38
|
+
- 🔄 **Unified Development**: Same server for frontend and backend during development
|
|
39
|
+
- 📦 **No Dependencies**: Works with your existing Vite setup without additional runtime dependencies
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 🆚 Vitek vs. Other Solutions
|
|
44
|
+
|
|
45
|
+
### Comparison with Framework-Specific Solutions
|
|
46
|
+
|
|
47
|
+
#### **Next.js API Routes**
|
|
48
|
+
|
|
49
|
+
- **Next.js**: Requires Next.js framework, tightly coupled to React ecosystem
|
|
50
|
+
- **Vitek**: Framework-agnostic, works with any frontend (React, Vue, Svelte, vanilla JS)
|
|
51
|
+
- **Vitek Advantage**: More flexible, lighter weight, not tied to a specific framework
|
|
52
|
+
|
|
53
|
+
#### **SvelteKit API Routes**
|
|
54
|
+
|
|
55
|
+
- **SvelteKit**: Requires SvelteKit framework, Svelte-specific
|
|
56
|
+
- **Vitek**: Works with any frontend framework or no framework at all
|
|
57
|
+
- **Vitek Advantage**: Universal solution, not limited to Svelte projects
|
|
58
|
+
|
|
59
|
+
#### **Nuxt.js Server Routes**
|
|
60
|
+
|
|
61
|
+
- **Nuxt.js**: Vue.js-specific, requires Nuxt framework
|
|
62
|
+
- **Vitek**: Framework-independent, works with any stack
|
|
63
|
+
- **Vitek Advantage**: More versatile, can be used in any Vite project
|
|
64
|
+
|
|
65
|
+
### Comparison with Standalone Backend Solutions
|
|
66
|
+
|
|
67
|
+
#### **Express.js / Fastify**
|
|
68
|
+
|
|
69
|
+
- **Express/Fastify**: Separate Node.js server, requires server setup and configuration
|
|
70
|
+
- **Vitek**: Integrated with Vite dev server, no separate server needed
|
|
71
|
+
- **Vitek Advantage**: Simpler setup, unified development environment, automatic hot reload
|
|
72
|
+
|
|
73
|
+
#### **Hono**
|
|
74
|
+
|
|
75
|
+
- **Hono**: Fast web framework, but still requires separate server setup
|
|
76
|
+
- **Vitek**: File-based routing with automatic type generation, integrated with Vite
|
|
77
|
+
- **Vitek Advantage**: Better DX with file-based routing, automatic client generation
|
|
78
|
+
|
|
79
|
+
#### **tRPC**
|
|
80
|
+
|
|
81
|
+
- **tRPC**: Type-safe RPC framework, requires separate server setup
|
|
82
|
+
- **Vitek**: File-based REST API with automatic type generation, integrated with Vite
|
|
83
|
+
- **Vitek Advantage**: Simpler setup, standard REST API, works with any HTTP client
|
|
84
|
+
|
|
85
|
+
### Comparison with Full-Stack Frameworks
|
|
86
|
+
|
|
87
|
+
#### **Remix**
|
|
88
|
+
|
|
89
|
+
- **Remix**: Full-stack React framework with server-side rendering
|
|
90
|
+
- **Vitek**: Lightweight API layer, works with any frontend
|
|
91
|
+
- **Vitek Advantage**: More flexible, lighter, not tied to React or SSR
|
|
92
|
+
|
|
93
|
+
### Why Choose Vitek?
|
|
94
|
+
|
|
95
|
+
**Choose Vitek if you:**
|
|
96
|
+
|
|
97
|
+
- ✅ Want to add API routes to an existing Vite project
|
|
98
|
+
- ✅ Prefer file-based routing over manual route registration
|
|
99
|
+
- ✅ Want automatic type generation for your API
|
|
100
|
+
- ✅ Need a lightweight solution without framework lock-in
|
|
101
|
+
- ✅ Want unified development (frontend + backend in one server)
|
|
102
|
+
- ✅ Prefer REST APIs over RPC or GraphQL
|
|
103
|
+
- ✅ Want zero configuration and minimal setup
|
|
104
|
+
|
|
105
|
+
**Consider alternatives if you:**
|
|
106
|
+
|
|
107
|
+
- Need server-side rendering (use Next.js, Remix, or SvelteKit)
|
|
108
|
+
- Want GraphQL (use Apollo Server or similar)
|
|
109
|
+
- Need advanced features like WebSockets out of the box (use Express/Fastify with Socket.io)
|
|
110
|
+
- Are building a full-stack framework from scratch (use Hono, Express, or Fastify)
|
|
111
|
+
- Need production-ready server features (use Express, Fastify, or Hono with proper setup)
|
|
112
|
+
|
|
113
|
+
**Vitek's sweet spot**: Adding API routes to Vite projects with minimal configuration, automatic type safety, and excellent developer experience.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## ✨ Features
|
|
118
|
+
|
|
119
|
+
- ✅ **File-based routing**: Automatic routes based on file structure
|
|
120
|
+
- ✅ **Zero config**: Works automatically with the Vite server
|
|
121
|
+
- ✅ **Hot reload**: Automatically reloads routes and middlewares on save
|
|
122
|
+
- ✅ **Type-safe**: Automatically generates TypeScript types for all routes
|
|
123
|
+
- ✅ **Client helpers**: Generates typed functions to call the API from the frontend
|
|
124
|
+
- ✅ **Hierarchical middleware**: Middlewares per folder/subfolder
|
|
125
|
+
- ✅ **All HTTP methods**: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
|
|
126
|
+
- ✅ **Dynamic parameters**: Support for `[id]` and `[...ids]` (catch-all)
|
|
127
|
+
- ✅ **Typed query params**: Define types for query parameters
|
|
128
|
+
- ✅ **Typed body**: Define types for request body
|
|
129
|
+
- ✅ **JavaScript support**: Works with both TypeScript and JavaScript projects
|
|
130
|
+
- ✅ **Isolated core**: Modular architecture, ready for other runtimes
|
|
131
|
+
- ✅ **Response control**: Custom status codes and headers via response helpers
|
|
132
|
+
- ✅ **HTTP error classes**: Built-in error classes with automatic status code mapping
|
|
133
|
+
- ✅ **Request validation**: Optional runtime validation for body and query parameters
|
|
134
|
+
- ✅ **Enhanced logging**: Configurable log levels and request/response logging
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 📦 Installation
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm install vitek-plugin
|
|
142
|
+
# or
|
|
143
|
+
pnpm add vitek-plugin
|
|
144
|
+
# or
|
|
145
|
+
yarn add vitek-plugin
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Requirements:**
|
|
149
|
+
|
|
150
|
+
- Vite ^5.0.0
|
|
151
|
+
- Node.js 18+ (for development)
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## ⚡ Quick Start
|
|
156
|
+
|
|
157
|
+
### 1. Configure the Plugin
|
|
158
|
+
|
|
159
|
+
Add Vitek to your `vite.config.ts`:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { defineConfig } from "vite";
|
|
163
|
+
import { vitek } from "vitek-plugin";
|
|
164
|
+
|
|
165
|
+
export default defineConfig({
|
|
166
|
+
plugins: [vitek()],
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 2. Create Your First Route
|
|
171
|
+
|
|
172
|
+
Create `src/api/health.get.ts`:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import type { VitekContext } from "vitek-plugin";
|
|
176
|
+
|
|
177
|
+
export default function handler(context: VitekContext) {
|
|
178
|
+
return {
|
|
179
|
+
status: "ok",
|
|
180
|
+
timestamp: new Date().toISOString(),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 3. Start the Development Server
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npm run dev
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Visit: `http://localhost:5173/api/health` 🎉
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 📁 File Structure
|
|
196
|
+
|
|
197
|
+
### Naming Convention
|
|
198
|
+
|
|
199
|
+
Files follow the pattern: `[name].[method].ts` or `[name].[method].js`
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
src/api/
|
|
203
|
+
├── middleware.ts # Global middleware (optional)
|
|
204
|
+
├── health.get.ts # GET /api/health
|
|
205
|
+
├── users/
|
|
206
|
+
│ ├── middleware.ts # Middleware for /api/users/*
|
|
207
|
+
│ ├── [id].get.ts # GET /api/users/:id
|
|
208
|
+
│ ├── [id].put.ts # PUT /api/users/:id
|
|
209
|
+
│ └── [id]/
|
|
210
|
+
│ ├── middleware.ts # Middleware for /api/users/:id/*
|
|
211
|
+
│ └── posts.get.ts # GET /api/users/:id/posts
|
|
212
|
+
└── posts/
|
|
213
|
+
├── index.get.ts # GET /api/posts
|
|
214
|
+
├── index.post.ts # POST /api/posts
|
|
215
|
+
├── [id].get.ts # GET /api/posts/:id
|
|
216
|
+
└── [...ids].get.ts # GET /api/posts/*ids (catch-all)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Dynamic Parameters
|
|
220
|
+
|
|
221
|
+
- **Single parameter**: `[id].get.ts` → `:id`
|
|
222
|
+
- Example: `users/[id].get.ts` → `/api/users/:id`
|
|
223
|
+
- **Catch-all**: `[...ids].get.ts` → `*ids`
|
|
224
|
+
- Example: `posts/[...ids].get.ts` → `/api/posts/*ids`
|
|
225
|
+
- Captures: `/api/posts/1/2/3` → `params.ids = "1/2/3"`
|
|
226
|
+
|
|
227
|
+
### Supported HTTP Methods
|
|
228
|
+
|
|
229
|
+
All HTTP methods are supported through file extension:
|
|
230
|
+
|
|
231
|
+
- `.get.ts` → GET
|
|
232
|
+
- `.post.ts` → POST
|
|
233
|
+
- `.put.ts` → PUT
|
|
234
|
+
- `.patch.ts` → PATCH
|
|
235
|
+
- `.delete.ts` → DELETE
|
|
236
|
+
- `.head.ts` → HEAD
|
|
237
|
+
- `.options.ts` → OPTIONS
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 🎯 Usage Examples
|
|
242
|
+
|
|
243
|
+
### Example 1: Simple GET Route
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// src/api/health.get.ts
|
|
247
|
+
import type { VitekContext } from "vitek-plugin";
|
|
248
|
+
|
|
249
|
+
export default function handler(context: VitekContext) {
|
|
250
|
+
return {
|
|
251
|
+
status: "ok",
|
|
252
|
+
timestamp: new Date().toISOString(),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Example 2: Route with Dynamic Parameter
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// src/api/users/[id].get.ts
|
|
261
|
+
import type { VitekContext } from "vitek-plugin";
|
|
262
|
+
|
|
263
|
+
export default async function handler(context: VitekContext) {
|
|
264
|
+
const { params } = context;
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
id: params.id,
|
|
268
|
+
name: `User ${params.id}`,
|
|
269
|
+
email: `user${params.id}@example.com`,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Example 3: POST Route with Typed Body
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
// src/api/posts/index.post.ts
|
|
278
|
+
import type { VitekContext } from "vitek-plugin";
|
|
279
|
+
|
|
280
|
+
export type Body = {
|
|
281
|
+
title: string;
|
|
282
|
+
content: string;
|
|
283
|
+
authorId: number;
|
|
284
|
+
tags?: string[];
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
export default async function handler(context: VitekContext) {
|
|
288
|
+
const { body } = context;
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
message: "Post created",
|
|
292
|
+
post: {
|
|
293
|
+
id: Math.random(),
|
|
294
|
+
...body,
|
|
295
|
+
createdAt: new Date().toISOString(),
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Example 4: Route with Query Parameters
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
// src/api/posts/index.get.ts
|
|
305
|
+
import type { VitekContext } from "vitek-plugin";
|
|
306
|
+
|
|
307
|
+
export type Query = {
|
|
308
|
+
limit?: number;
|
|
309
|
+
offset?: number;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export default async function handler(context: VitekContext) {
|
|
313
|
+
const { query } = context;
|
|
314
|
+
|
|
315
|
+
const limit = query.limit ? Number(query.limit) : 10;
|
|
316
|
+
const offset = query.offset ? Number(query.offset) : 0;
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
posts: [],
|
|
320
|
+
pagination: { limit, offset },
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Example 5: Complete Route (Params + Body + Query)
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
// src/api/posts/[id]/comments.post.ts
|
|
329
|
+
import type { VitekContext } from "vitek-plugin";
|
|
330
|
+
|
|
331
|
+
export type Body = {
|
|
332
|
+
text: string;
|
|
333
|
+
authorId: number;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
export type Query = {
|
|
337
|
+
notify?: boolean;
|
|
338
|
+
sendEmail?: boolean;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export default async function handler(context: VitekContext) {
|
|
342
|
+
const { params, body, query } = context;
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
message: "Comment created",
|
|
346
|
+
postId: params.id,
|
|
347
|
+
comment: {
|
|
348
|
+
id: Math.random(),
|
|
349
|
+
...body,
|
|
350
|
+
postId: params.id,
|
|
351
|
+
notify: query.notify || false,
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Example 6: Catch-All Route
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
// src/api/posts/[...ids].get.ts
|
|
361
|
+
import type { VitekContext } from "vitek-plugin";
|
|
362
|
+
|
|
363
|
+
export default async function handler(context: VitekContext) {
|
|
364
|
+
const { params } = context;
|
|
365
|
+
|
|
366
|
+
// params.ids contains all segments: "1/2/3" for /api/posts/1/2/3
|
|
367
|
+
const ids = params.ids.split("/");
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
ids,
|
|
371
|
+
message: "Multiple posts requested",
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## 🔌 Middlewares
|
|
379
|
+
|
|
380
|
+
### Global Middleware
|
|
381
|
+
|
|
382
|
+
Create `src/api/middleware.ts` to apply middlewares to all routes:
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
// src/api/middleware.ts
|
|
386
|
+
import type { Middleware } from "vitek-plugin";
|
|
387
|
+
|
|
388
|
+
export default [
|
|
389
|
+
async (context, next) => {
|
|
390
|
+
// Executes before the route
|
|
391
|
+
console.log(`[Global] ${context.method} ${context.path}`);
|
|
392
|
+
|
|
393
|
+
await next(); // Continues to next middleware/handler
|
|
394
|
+
|
|
395
|
+
// Executes after the route
|
|
396
|
+
console.log(`[Global] Completed ${context.path}`);
|
|
397
|
+
},
|
|
398
|
+
] satisfies Middleware[];
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Hierarchical Middleware by Folder
|
|
402
|
+
|
|
403
|
+
Middlewares are applied hierarchically based on folder structure:
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
// src/api/posts/middleware.ts
|
|
407
|
+
// Applies to: /api/posts, /api/posts/:id, /api/posts/:id/comments, etc.
|
|
408
|
+
|
|
409
|
+
import type { Middleware } from "vitek-plugin";
|
|
410
|
+
|
|
411
|
+
export default [
|
|
412
|
+
async (context, next) => {
|
|
413
|
+
console.log(`[Posts Middleware] ${context.method} ${context.path}`);
|
|
414
|
+
await next();
|
|
415
|
+
},
|
|
416
|
+
] satisfies Middleware[];
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
// src/api/posts/[id]/middleware.ts
|
|
421
|
+
// Applies to: /api/posts/:id/comments, but NOT /api/posts
|
|
422
|
+
|
|
423
|
+
import type { Middleware } from "vitek-plugin";
|
|
424
|
+
|
|
425
|
+
export default [
|
|
426
|
+
async (context, next) => {
|
|
427
|
+
// Validate post exists
|
|
428
|
+
const postId = context.params.id;
|
|
429
|
+
console.log(`[Post ID Middleware] Validating post ${postId}`);
|
|
430
|
+
await next();
|
|
431
|
+
},
|
|
432
|
+
] satisfies Middleware[];
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Middleware execution order:**
|
|
436
|
+
|
|
437
|
+
1. Global middleware (`src/api/middleware.ts`)
|
|
438
|
+
2. Folder-specific middleware (e.g., `src/api/posts/middleware.ts`)
|
|
439
|
+
3. Nested folder middleware (e.g., `src/api/posts/[id]/middleware.ts`)
|
|
440
|
+
4. Route handler
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## 🎯 Response Handling
|
|
445
|
+
|
|
446
|
+
Vitek provides flexible response handling with support for custom status codes and headers.
|
|
447
|
+
|
|
448
|
+
### Basic Response (Backward Compatible)
|
|
449
|
+
|
|
450
|
+
Returning a plain object automatically creates a 200 OK JSON response:
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
export default function handler(context: VitekContext) {
|
|
454
|
+
return { message: "Success" }; // Status 200, JSON
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Custom Status Codes and Headers
|
|
459
|
+
|
|
460
|
+
Use response helpers for full control over HTTP responses:
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
import { created, notFound, json } from "vitek-plugin";
|
|
464
|
+
|
|
465
|
+
export default function handler(context: VitekContext) {
|
|
466
|
+
// 201 Created
|
|
467
|
+
return created({ id: 123, message: "Resource created" });
|
|
468
|
+
|
|
469
|
+
// 404 Not Found
|
|
470
|
+
return notFound({ error: "Resource not found" });
|
|
471
|
+
|
|
472
|
+
// Custom status and headers
|
|
473
|
+
return json(
|
|
474
|
+
{ data: "custom" },
|
|
475
|
+
{
|
|
476
|
+
status: 201,
|
|
477
|
+
headers: { "X-Custom-Header": "value" },
|
|
478
|
+
}
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Available Response Helpers
|
|
484
|
+
|
|
485
|
+
- `ok(body, headers?)` - 200 OK
|
|
486
|
+
- `created(body, headers?)` - 201 Created
|
|
487
|
+
- `noContent(headers?)` - 204 No Content
|
|
488
|
+
- `badRequest(body, headers?)` - 400 Bad Request
|
|
489
|
+
- `unauthorized(body, headers?)` - 401 Unauthorized
|
|
490
|
+
- `forbidden(body, headers?)` - 403 Forbidden
|
|
491
|
+
- `notFound(body, headers?)` - 404 Not Found
|
|
492
|
+
- `conflict(body, headers?)` - 409 Conflict
|
|
493
|
+
- `unprocessableEntity(body, headers?)` - 422 Validation Error
|
|
494
|
+
- `tooManyRequests(body, headers?)` - 429 Too Many Requests
|
|
495
|
+
- `internalServerError(body, headers?)` - 500 Internal Server Error
|
|
496
|
+
- `redirect(url, permanent?, preserveMethod?)` - 301/302/307/308 Redirect
|
|
497
|
+
- `json(body, options?)` - Custom JSON response with status and headers
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## ⚠️ Error Handling
|
|
502
|
+
|
|
503
|
+
Vitek provides HTTP error classes for better error handling with automatic status code mapping.
|
|
504
|
+
|
|
505
|
+
### HTTP Error Classes
|
|
506
|
+
|
|
507
|
+
```typescript
|
|
508
|
+
import {
|
|
509
|
+
BadRequestError,
|
|
510
|
+
NotFoundError,
|
|
511
|
+
UnauthorizedError,
|
|
512
|
+
ValidationError,
|
|
513
|
+
} from "vitek-plugin";
|
|
514
|
+
|
|
515
|
+
export default function handler(context: VitekContext) {
|
|
516
|
+
const { params } = context;
|
|
517
|
+
|
|
518
|
+
if (!params.id) {
|
|
519
|
+
throw new BadRequestError("ID is required"); // Returns 400
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const resource = findResource(params.id);
|
|
523
|
+
if (!resource) {
|
|
524
|
+
throw new NotFoundError("Resource not found"); // Returns 404
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Validation errors with field details
|
|
528
|
+
throw new ValidationError("Validation failed", {
|
|
529
|
+
email: ["Invalid email format"],
|
|
530
|
+
age: ["Must be 18 or older"],
|
|
531
|
+
}); // Returns 422
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### Available Error Classes
|
|
536
|
+
|
|
537
|
+
- `BadRequestError` - 400 Bad Request
|
|
538
|
+
- `UnauthorizedError` - 401 Unauthorized
|
|
539
|
+
- `ForbiddenError` - 403 Forbidden
|
|
540
|
+
- `NotFoundError` - 404 Not Found
|
|
541
|
+
- `ConflictError` - 409 Conflict
|
|
542
|
+
- `ValidationError` - 422 Unprocessable Entity (with field errors)
|
|
543
|
+
- `TooManyRequestsError` - 429 Too Many Requests
|
|
544
|
+
- `InternalServerError` - 500 Internal Server Error
|
|
545
|
+
|
|
546
|
+
All errors automatically return the appropriate HTTP status code and JSON error response.
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## ✅ Request Validation
|
|
551
|
+
|
|
552
|
+
Vitek provides optional runtime validation for request body and query parameters.
|
|
553
|
+
|
|
554
|
+
### Manual Validation
|
|
555
|
+
|
|
556
|
+
Use validation helpers in your handlers:
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
import { validateBody, validateQuery, ValidationError } from "vitek-plugin";
|
|
560
|
+
import type { ValidationSchema } from "vitek-plugin";
|
|
561
|
+
|
|
562
|
+
export type Body = {
|
|
563
|
+
title: string;
|
|
564
|
+
content: string;
|
|
565
|
+
authorId: number;
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
export default function handler(context: VitekContext) {
|
|
569
|
+
// Validate body
|
|
570
|
+
const body = validateBody(context.body, {
|
|
571
|
+
title: { type: "string", required: true, min: 1, max: 200 },
|
|
572
|
+
content: { type: "string", required: true, min: 10 },
|
|
573
|
+
authorId: { type: "number", required: true, min: 1 },
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
// Validate query
|
|
577
|
+
const query = validateQuery(context.query, {
|
|
578
|
+
limit: { type: "number", min: 1, max: 100 },
|
|
579
|
+
offset: { type: "number", min: 0 },
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// If validation fails, ValidationError (422) is thrown automatically
|
|
583
|
+
return { message: "Validated successfully", body, query };
|
|
584
|
+
}
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
### Validation Rules
|
|
588
|
+
|
|
589
|
+
```typescript
|
|
590
|
+
type ValidationRule = {
|
|
591
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
592
|
+
required?: boolean;
|
|
593
|
+
min?: number; // For strings: min length, for numbers: min value, for arrays: min items
|
|
594
|
+
max?: number; // For strings: max length, for numbers: max value, for arrays: max items
|
|
595
|
+
pattern?: string | RegExp; // For strings: regex pattern
|
|
596
|
+
custom?: (value: any) => boolean | string; // Custom validator
|
|
597
|
+
};
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### Validation Functions
|
|
601
|
+
|
|
602
|
+
- `validate(data, schema)` - Returns validation result without throwing
|
|
603
|
+
- `validateOrThrow(data, schema)` - Throws `ValidationError` if invalid
|
|
604
|
+
- `validateBody(body, schema)` - Validates request body
|
|
605
|
+
- `validateQuery(query, schema)` - Validates query parameters
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## 📝 Type Generation
|
|
610
|
+
|
|
611
|
+
Vitek automatically generates TypeScript types for all your routes.
|
|
612
|
+
|
|
613
|
+
### `src/api.types.ts`
|
|
614
|
+
|
|
615
|
+
Contains all route types and parameter definitions:
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
// Auto-generated by Vitek - DO NOT EDIT
|
|
619
|
+
|
|
620
|
+
export type VitekParams = Record<string, string>;
|
|
621
|
+
export type VitekQuery = Record<string, string | string[]>;
|
|
622
|
+
|
|
623
|
+
export interface UsersIdGetParams extends VitekParams {
|
|
624
|
+
id: string;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
export type PostsPostBody = {
|
|
628
|
+
title: string;
|
|
629
|
+
content: string;
|
|
630
|
+
authorId: number;
|
|
631
|
+
tags?: string[];
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
export type PostsIndexGetQuery = {
|
|
635
|
+
limit?: number;
|
|
636
|
+
offset?: number;
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// Union type with all routes
|
|
640
|
+
export type VitekRoute =
|
|
641
|
+
| { pattern: "users/:id"; method: "get"; params: UsersIdGetParams }
|
|
642
|
+
| { pattern: "posts"; method: "post"; params: PostsPostBody };
|
|
643
|
+
// ...
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### `src/api.services.ts` (TypeScript) or `src/api.services.js` (JavaScript)
|
|
647
|
+
|
|
648
|
+
Contains typed helper functions to call the API from the frontend:
|
|
649
|
+
|
|
650
|
+
```typescript
|
|
651
|
+
import { getUsersById, postPosts, getPostsIdComments } from "./api.services";
|
|
652
|
+
|
|
653
|
+
// GET /api/users/:id
|
|
654
|
+
const user = await getUsersById({ id: "123" });
|
|
655
|
+
|
|
656
|
+
// POST /api/posts (with body)
|
|
657
|
+
const post = await postPosts({
|
|
658
|
+
title: "Hello",
|
|
659
|
+
content: "World",
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
// GET /api/posts/:id/comments (with params + query)
|
|
663
|
+
const comments = await getPostsIdComments(
|
|
664
|
+
{ id: "123" }, // params
|
|
665
|
+
{ limit: 10, offset: 0 } // query
|
|
666
|
+
);
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
**Generated services features:**
|
|
670
|
+
|
|
671
|
+
- ✅ Only necessary parameters are included (`params`, `body`, `query` only appear if defined)
|
|
672
|
+
- ✅ Unique function names automatically generated
|
|
673
|
+
- ✅ Complete types for autocomplete and type-checking (TypeScript projects)
|
|
674
|
+
- ✅ Last parameter is always `options?: RequestInit` for fetch customization
|
|
675
|
+
|
|
676
|
+
**Note:** For JavaScript projects, Vitek generates `api.services.js` without TypeScript types. For TypeScript projects, it generates both `api.types.ts` and `api.services.ts`.
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
## ⚙️ Configuration
|
|
681
|
+
|
|
682
|
+
### Plugin Options
|
|
683
|
+
|
|
684
|
+
```typescript
|
|
685
|
+
import { vitek } from "vitek-plugin";
|
|
686
|
+
|
|
687
|
+
export default defineConfig({
|
|
688
|
+
plugins: [
|
|
689
|
+
vitek({
|
|
690
|
+
apiDir: "src/api", // API directory (default: 'src/api')
|
|
691
|
+
apiBasePath: "/api", // API base path (default: '/api')
|
|
692
|
+
enableValidation: false, // Enable automatic validation (default: false)
|
|
693
|
+
logging: {
|
|
694
|
+
level: "info", // Log level: 'debug' | 'info' | 'warn' | 'error'
|
|
695
|
+
enableRequestLogging: false, // Log all requests/responses (default: false)
|
|
696
|
+
enableRouteLogging: true, // Log route matches (default: true)
|
|
697
|
+
},
|
|
698
|
+
}),
|
|
699
|
+
],
|
|
700
|
+
});
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
### Options
|
|
704
|
+
|
|
705
|
+
| Option | Type | Default | Description |
|
|
706
|
+
| ------------------------------ | ---------------------------------------- | ----------- | ------------------------------------------------------------------------------------------ |
|
|
707
|
+
| `apiDir` | `string` | `'src/api'` | Directory where API route files are located |
|
|
708
|
+
| `apiBasePath` | `string` | `'/api'` | Base path for all API routes |
|
|
709
|
+
| `enableValidation` | `boolean` | `false` | Enable automatic request validation (currently manual validation is available via helpers) |
|
|
710
|
+
| `logging` | `object` | `undefined` | Logging configuration |
|
|
711
|
+
| `logging.level` | `'debug' \| 'info' \| 'warn' \| 'error'` | `'info'` | Minimum log level to display |
|
|
712
|
+
| `logging.enableRequestLogging` | `boolean` | `false` | Log all HTTP requests with method, path, status code, and duration |
|
|
713
|
+
| `logging.enableRouteLogging` | `boolean` | `true` | Log route matches when requests are handled |
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
## 📖 Examples
|
|
718
|
+
|
|
719
|
+
This repository includes three complete examples demonstrating different use cases:
|
|
720
|
+
|
|
721
|
+
### [basic-js](./examples/basic-js/)
|
|
722
|
+
|
|
723
|
+
**Pure JavaScript, no frameworks**
|
|
724
|
+
|
|
725
|
+
- Minimal example with pure JavaScript
|
|
726
|
+
- No TypeScript, no React
|
|
727
|
+
- Simple HTML page with fetch API
|
|
728
|
+
- Perfect for understanding the basics
|
|
729
|
+
|
|
730
|
+
**When to use**: Start here if you want to learn the fundamentals without any framework overhead.
|
|
731
|
+
|
|
732
|
+
### [js-react](./examples/js-react/)
|
|
733
|
+
|
|
734
|
+
**JavaScript with React (no TypeScript)**
|
|
735
|
+
|
|
736
|
+
- React application in JavaScript
|
|
737
|
+
- Uses generated services (without TypeScript types)
|
|
738
|
+
- Demonstrates Vitek integration with React
|
|
739
|
+
- Intermediate complexity
|
|
740
|
+
|
|
741
|
+
**When to use**: Perfect for React projects that prefer JavaScript over TypeScript.
|
|
742
|
+
|
|
743
|
+
### [typescript-react](./examples/typescript-react/)
|
|
744
|
+
|
|
745
|
+
**Complete TypeScript with React**
|
|
746
|
+
|
|
747
|
+
- Full-featured example with TypeScript and React
|
|
748
|
+
- Complete type-safety with generated types
|
|
749
|
+
- Hierarchical middlewares
|
|
750
|
+
- All HTTP methods and advanced features
|
|
751
|
+
- Most comprehensive example
|
|
752
|
+
|
|
753
|
+
**When to use**: Reference implementation showing all Vitek features with full type-safety.
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
## 🏗️ Architecture
|
|
758
|
+
|
|
759
|
+
Vitek follows a modular architecture:
|
|
760
|
+
|
|
761
|
+
- **Core**: Logic independent of Vite (reusable for other runtimes)
|
|
762
|
+
- **Adapters**: Integration with different runtimes (currently Vite)
|
|
763
|
+
- **Plugin**: Thin layer that registers the plugin in Vite
|
|
764
|
+
|
|
765
|
+
This allows the core to be used in other contexts (standalone Node.js, other bundlers, etc).
|
|
766
|
+
|
|
767
|
+
```
|
|
768
|
+
vitek-plugin/
|
|
769
|
+
├── src/
|
|
770
|
+
│ ├── core/ # Runtime-agnostic core logic
|
|
771
|
+
│ │ ├── context/ # Context creation
|
|
772
|
+
│ │ ├── file-system/ # File scanning and watching
|
|
773
|
+
│ │ ├── middleware/ # Middleware composition
|
|
774
|
+
│ │ ├── normalize/ # Path normalization
|
|
775
|
+
│ │ ├── routing/ # Route parsing and matching
|
|
776
|
+
│ │ ├── types/ # Type generation
|
|
777
|
+
│ │ └── validation/ # Request validation
|
|
778
|
+
│ ├── adapters/ # Runtime-specific adapters
|
|
779
|
+
│ │ └── vite/ # Vite integration
|
|
780
|
+
│ ├── shared/ # Shared utilities
|
|
781
|
+
│ │ ├── errors.ts # Error classes
|
|
782
|
+
│ │ └── response-helpers.ts # Response helper functions
|
|
783
|
+
│ └── plugin.ts # Vite plugin entry point
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
---
|
|
787
|
+
|
|
788
|
+
## 🔍 How It Works
|
|
789
|
+
|
|
790
|
+
1. **Scan**: The plugin scans `src/api` looking for route files and middlewares
|
|
791
|
+
2. **Loading**: Loads handlers and middlewares using Vite's module system
|
|
792
|
+
3. **Type Generation**: Analyzes files and automatically generates TypeScript types (for TS projects)
|
|
793
|
+
4. **Service Generation**: Creates typed helper functions for the frontend
|
|
794
|
+
5. **Integration**: Registers middleware in the Vite server to intercept `/api/*` requests
|
|
795
|
+
6. **Hot Reload**: Watches for file changes and automatically reloads
|
|
796
|
+
|
|
797
|
+
---
|
|
798
|
+
|
|
799
|
+
## 🛠️ Development
|
|
800
|
+
|
|
801
|
+
### Building the Plugin
|
|
802
|
+
|
|
803
|
+
```bash
|
|
804
|
+
npm run build
|
|
805
|
+
# or
|
|
806
|
+
pnpm build
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
### Development Mode
|
|
810
|
+
|
|
811
|
+
```bash
|
|
812
|
+
npm run dev
|
|
813
|
+
# or
|
|
814
|
+
pnpm dev
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
This runs TypeScript compiler in watch mode.
|
|
818
|
+
|
|
819
|
+
---
|
|
820
|
+
|
|
821
|
+
## 🤝 Contributing
|
|
822
|
+
|
|
823
|
+
To contribute, make sure to follow the steps below:
|
|
824
|
+
|
|
825
|
+
1. Create a new branch:
|
|
826
|
+
|
|
827
|
+
```shell
|
|
828
|
+
git checkout -b feat/your-new-feature
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
2. Make your changes, add unit tests (if applicable) and test with `npm link`
|
|
832
|
+
|
|
833
|
+
On vitek-plugin project:
|
|
834
|
+
|
|
835
|
+
```shell
|
|
836
|
+
npm link
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
On your app/project:
|
|
840
|
+
|
|
841
|
+
```shell
|
|
842
|
+
npm link vitek-plugin
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
This will create a symlink into your `node_modules` app, and you can test iteratively. You can check more about npm-link [here](https://docs.npmjs.com/cli/v9/commands/npm-link)
|
|
846
|
+
|
|
847
|
+
3. Before to push your changes to origin, open your pull request and fill all required fields.
|
|
848
|
+
1. Make sure to fill the **Release** section with what your pull request changes. **This section is required to merge pull request.**
|
|
849
|
+
4. Set a _required_ `semver` label according to your change:
|
|
850
|
+
1. `semver:patch`: used when you submit a fix to a bug, enhance performance, etc;
|
|
851
|
+
2. `semver:minor`: used when you submit a new component, new feature, etc;
|
|
852
|
+
3. `semver:major`: used when you submit some breaking change, etc;
|
|
853
|
+
4. `semver:prerelease`: used when you submit a prerelease (ex: `0.1.0-beta.1`);
|
|
854
|
+
5. `semver:bypass`: used to update docs, or something that doesn't affect the build.
|
|
855
|
+
|
|
856
|
+
> Info: Once you have merged your pull request, with all required fields, GitHub Actions will be responsible to create a new build and publish.
|
|
857
|
+
|
|
858
|
+
---
|
|
859
|
+
|
|
860
|
+
## 📄 License
|
|
861
|
+
|
|
862
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
863
|
+
|
|
864
|
+
**MIT License** means:
|
|
865
|
+
|
|
866
|
+
- ✅ Free to use for personal and commercial projects
|
|
867
|
+
- ✅ Free to modify
|
|
868
|
+
- ✅ Free to distribute
|
|
869
|
+
- ✅ Free to use privately
|
|
870
|
+
- ✅ No warranty or liability
|
|
871
|
+
|
|
872
|
+
---
|
|
873
|
+
|
|
874
|
+
## ⚠️ Beta Status
|
|
875
|
+
|
|
876
|
+
**This project is currently in beta/testing phase.**
|
|
877
|
+
|
|
878
|
+
- Version: `0.1.0-beta`
|
|
879
|
+
- APIs may change in future releases
|
|
880
|
+
- Some features may be experimental
|
|
881
|
+
- Feedback and bug reports are welcome!
|
|
882
|
+
|
|
883
|
+
---
|
|
884
|
+
|
|
885
|
+
## 🙏 Acknowledgments
|
|
886
|
+
|
|
887
|
+
- Built with [Vite](https://vitejs.dev/)
|
|
888
|
+
- Inspired by file-based routing patterns from Next.js and SvelteKit
|
|
889
|
+
- Type generation powered by TypeScript
|
|
890
|
+
|
|
891
|
+
---
|
|
892
|
+
|
|
893
|
+
## 📞 Support
|
|
894
|
+
|
|
895
|
+
- 🐛 **Found a bug?** [Open an issue](https://github.com/yourusername/vitek-plugin/issues)
|
|
896
|
+
- 💡 **Have a suggestion?** [Open a discussion](https://github.com/yourusername/vitek-plugin/discussions)
|
|
897
|
+
- 📖 **Need help?** Check the [examples](./examples/) directory
|
|
898
|
+
|
|
899
|
+
---
|
|
900
|
+
|
|
901
|
+
<div align="center">
|
|
902
|
+
<p>Made with ❤️ for the Vite community</p>
|
|
903
|
+
<p>
|
|
904
|
+
<a href="https://github.com/yourusername/vitek-plugin">GitHub</a> •
|
|
905
|
+
<a href="https://npmjs.com/package/vitek-plugin">NPM</a> •
|
|
906
|
+
<a href="LICENSE">License</a>
|
|
907
|
+
</p>
|
|
908
|
+
</div>
|