vafast 0.1.17

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 ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Vafast Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,237 @@
1
+ # Vafast
2
+ ![Cloudflare Workers](https://img.shields.io/badge/Runtime-Workers-F38020?logo=cloudflare&logoColor=white)
3
+ ![bun](https://img.shields.io/badge/Runtime-Bun-%23000000?logo=bun\&logoColor=white)
4
+ ![version](https://img.shields.io/npm/v/vafast)
5
+ ![license](https://img.shields.io/npm/l/vafast)
6
+ ![stars](https://img.shields.io/github/stars/vafast/vafast?style=social)
7
+
8
+
9
+ > Vafast — 在一个文件中编写高性能API。
10
+ 专为Bun构建。设计上类型安全。冷启动时间低于1ms。
11
+
12
+ ---
13
+
14
+ [![文档](https://img.shields.io/badge/docs-vafast.dev-blue?logo=readthedocs)](https://vafast.dev)
15
+
16
+ ## 📚 Vafast 文档
17
+
18
+ 探索Vafast的完整指南 — 一个专为速度、结构和零样板代码而构建的Bun和Edge原生Web框架。
19
+
20
+ 👉 [https://vafast.dev](https://vafast.dev)
21
+
22
+ ---
23
+
24
+ > ⚡ 亚毫秒级API。一流的副作用控制。
25
+ > 👉 [在GitHub上给Vafast加星标](https://github.com/vafast/vafast)
26
+ Vafast是一个声明式、类型安全的Bun框架 — 旨在使副作用显式化,性能可预测。
27
+
28
+ ---
29
+
30
+ ## 🚀 快速开始
31
+
32
+ ```bash
33
+ npx create-vafast-app
34
+ ```
35
+
36
+ <p align="center"> <img src="./assets/スクリーンショット 2025-06-17 21.58.05.png" width="500" alt="Vafast设置终端截图"> </p>
37
+
38
+ 选择您的环境:
39
+
40
+ * **Bun**
41
+ * **Cloudflare Workers**
42
+
43
+ 此命令在几秒钟内设置一个可立即运行的Vafast项目。
44
+
45
+ 📣 **喜欢不碍事的极简工具?**
46
+ 给主Vafast仓库加星标:[https://github.com/vafast/vafast](https://github.com/vafast/vafast)
47
+
48
+ ---
49
+
50
+ ## 📁 您将获得什么
51
+
52
+ 一个零样板项目,专为您的运行时定制:
53
+
54
+ * 带有工作路由器和`/`端点的`index.ts`
55
+ * 运行时配置文件(`bunfig.toml`、`wrangler.toml`)
56
+ * 带有最小脚本和依赖项的`package.json`
57
+
58
+ 示例输出:
59
+
60
+ ```bash
61
+ ✔ 选择您的目标环境: › Bun
62
+ ✔ 项目文件夹: › my-vafast-app
63
+
64
+ ✅ Vafast应用已在'my-vafast-app'中创建
65
+
66
+ 下一步:
67
+
68
+ cd my-vafast-app
69
+ bun install # 或 npm install
70
+ npm run dev (Bun) # 或 wrangler dev
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 🔧 设计理念
76
+
77
+ Vafast建立在5个核心原则之上:
78
+
79
+ 1. **代码即结构** — 路由、中间件和逻辑是配置,而不是行为。代码是清单,而不是脚本。
80
+ 2. **错误即值** — VafastError携带类型、状态和意图。它们被抛出,但不被隐藏。
81
+ 3. **组合优于约定** — 中间件被显式组合,顺序是契约的一部分。
82
+ 4. **类型塑造行为** — 您的API的结构和安全性由其类型定义,而不是文档。
83
+ 5. **专为边缘设计** — 为Bun构建,为fetch优化,诞生于毫秒时代。
84
+
85
+ ---
86
+
87
+ ## ✨ 特性
88
+
89
+ * ✅ **结构优先路由** — 将整个API定义为单个声明式结构
90
+ * ✅ **可组合中间件** — 显式`compose()`流程,无装饰器或全局作用域
91
+ * ✅ **结构化错误** — 抛出带有类型、状态和可见性的`VafastError`
92
+ * ✅ **内置响应助手** — `json()`、`html()`、`text()`、`error()`等 — 干净且一致
93
+ * ✅ **边缘原生执行** — 在Bun、Workers和Deno上即时冷启动和亚毫秒响应
94
+ * ✅ **无样板代码** — 无CLI、无配置、无目录规则。只有纯代码。
95
+ * ✅ **设计上类型安全** — 路由、处理器、错误,全部由TypeScript塑造
96
+
97
+ ---
98
+
99
+ ## ⚡️ 性能基准测试
100
+
101
+ 所有测试均使用Bun v1.1.0在M2 Pro芯片(macOS)上进行,模拟边缘运行时条件。
102
+
103
+ | 指标 | 结果 | 解释 |
104
+ |--------------------|--------------------|----------------|
105
+ | ❄️ 冷启动 | `0.02 ms` | 🧊 基本上无法测量 — 完美适用于边缘/fetch基础运行时 |
106
+ | ⚡️ 首次请求 | `0.79 ms` | 🚀 突破1ms障碍。适用于延迟关键型API |
107
+ | 🔁 请求/秒 | `90,489 rps` | 🔥 与Hono相当,超过Express 10倍+ |
108
+ | 📉 平均延迟 | `0.96 ms` | ⚡ 负载下亚毫秒 — 适用于交互式应用 |
109
+ | 📦 吞吐量 | `10.9 MB/sec` | 📈 轻松处理大型JSON负载 |
110
+ | 🎯 总请求数 | `905,000 in 10s` | 💪 经过真实世界负载的实战测试 |
111
+
112
+ > ✨ Vafast专为边缘优先、零预热环境而设计 — 这些数字证明了这一点。
113
+
114
+ ---
115
+
116
+ ## 🧱 Cookie示例
117
+
118
+ ```ts
119
+ import { Server,json,setCookie,requireAuth } from "vafast";
120
+ import type { Route } from "vafast";
121
+
122
+ const routes: Route[] = [
123
+ {
124
+ method: "GET",
125
+ path: "/login",
126
+ handler: () => {
127
+ const headers = new Headers();
128
+ headers.append("Set-Cookie", setCookie("auth", "valid-token", {
129
+ httpOnly: true,
130
+ path: "/",
131
+ maxAge: 3600,
132
+ }));
133
+ return json({ message: "已登录" }, 200, headers);
134
+ },
135
+ middleware: [],
136
+ },
137
+ {
138
+ method: "GET",
139
+ path: "/private",
140
+ handler: () => json({ message: "仅限认证用户的秘密数据" }),
141
+ middleware: [requireAuth],
142
+ },
143
+ ];
144
+
145
+ const server = new Server(routes);
146
+
147
+ export default {
148
+ fetch: (req: Request) => server.fetch(req),
149
+ };
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 🔥 Vafast哲学 – 结构化简洁性的5大法则
155
+
156
+ 后端应该是透明的、快速的,并且像架构一样设计 — 而不是像魔法。Vafast建立在五个现代原则之上:
157
+
158
+ 1. **结构是真理之源**
159
+ API被定义为代码,而不是行为。无装饰器,无约定 — 只有您可以阅读的配置。
160
+
161
+ 2. **错误是数据,不是混乱**
162
+ 异常携带类型、状态和可见性。您不捕获它们 — 您设计它们。
163
+
164
+ 3. **组合就是一切**
165
+ 中间件被显式组合。无全局状态,无来自地狱的堆栈跟踪。
166
+
167
+ 4. **专为边缘构建,由类型塑造**
168
+ Vafast在Bun、Workers和Deno上即时运行。您的类型塑造运行的内容 — 而不是您的文档。
169
+
170
+ 5. **无引导、无样板、无废话**
171
+ 一个文件。无CLI。无隐藏魔法。您写的就是您部署的。
172
+
173
+ ---
174
+
175
+ ## 🔍 Vafast vs Hono vs Elysia — 关键差异
176
+
177
+ ## 🔍 Vafast vs Hono vs Elysia — 2025年重新审视
178
+
179
+ | 维度 | **Vafast ✨** | **Hono 🌿** | **Elysia 🧠** |
180
+ |-----------------|--------------------------------------------------|--------------------------------------------------|----------------------------------------------|
181
+ | **哲学** | 结构和副作用控制 | 简洁性和熟悉性 | 类型最大化和装饰器DSL |
182
+ | **路由** | 声明式`Route[]`结构 | 链式风格`app.get("/foo")` | 宏增强的处理器声明 |
183
+ | **中间件** | 显式`compose([...])`,每个路由作用域 | 全局`app.use()`和嵌套路由器 | 插件+生命周期钩子+装饰器 |
184
+ | **错误模型** | `VafastError`:带有元数据的结构化错误 | `throw`或`return c.text()` | `set.status()`,插件驱动处理 |
185
+ | **类型安全** | 类型驱动的配置和处理器(`Route<T>`) | 中等(上下文特定类型) | 极其强大,但与工具紧密耦合 |
186
+ | **响应API**| `json()`、`error()`作为纯返回值 | `c.json()`、`c.text()`方法 | `set.response()`副作用注入 |
187
+ | **可扩展性**| 中间件和组合原语 | 带有共享上下文的插件 | 插件+宏+装饰器 |
188
+ | **依赖项**| 🟢 零外部运行时依赖 | 🟡 轻量级 | 🔴 重量级:valibot、宏、SWC等 |
189
+ | **运行时支持** | ✅ Bun / Workers               | ✅ Bun / Node / Workers/ Deno | ❌ 仅限Bun,限于SWC宏管道 |
190
+ | **理想用户** | API设计师、类型感知极简主义者、边缘开发者| 想要熟悉DX的Express/Deno用户 | 热爱宏和装饰器的TS高级用户 |
191
+
192
+ > **Vafast**不仅仅是极简 — 它是架构性的。它让您完全控制结构、类型和执行,无需固执己见的工具或隐藏行为。
193
+
194
+ ---
195
+
196
+ ## 📦 安装
197
+
198
+ ```bash
199
+ bun add vafast
200
+ ```
201
+
202
+ 在Workers中使用:
203
+
204
+ ```bash
205
+ npm install vafast
206
+ ```
207
+
208
+ ---
209
+
210
+ ## 🤍 使用场景
211
+
212
+ Vafast适用于:
213
+ * ⚡️ 需要边缘速度API — 在Bun、Workers和Deno上亚毫秒响应时间。
214
+
215
+ * 📦 想要类型驱动可靠性 — 由类型塑造的API,而不是运行时猜测。
216
+
217
+ * 🌐 部署在现代运行时 — 以fetch优先运行,随处工作:Bun、Node、Workers、Deno。
218
+
219
+ * 🧪 考虑副作用设计 — 有意识地控制cookie、头部和认证。
220
+
221
+ ---
222
+
223
+ ## 💥 准备好再次编写真实代码了吗?
224
+
225
+ > 🚀 如果您厌倦了魔法、宏和单体 — 试试Vafast。
226
+ >
227
+ > 👉 **[⭐️ 在GitHub上加星标](https://github.com/vafast/vafast)** 加入这场运动。
228
+
229
+ [![GitHub Stars](https://img.shields.io/github/stars/vafast/vafast?style=social)](https://github.com/vafast/vafast)
230
+
231
+ ---
232
+
233
+ ## 📜 许可证
234
+
235
+ Apache 2.0
236
+
237
+
@@ -0,0 +1,3 @@
1
+ /** 生成令牌 */
2
+ export declare function generateToken(payload: Record<string, any>, secret: string): Promise<string>;
3
+ export declare function verifyToken(token: string, secret: string): Promise<Record<string, any> | null>;
@@ -0,0 +1,8 @@
1
+ export declare function getCookie(req: Request, key: string): string | null;
2
+ /** 生成 Set-Cookie 头 */
3
+ export declare function setCookie(key: string, value: string, options?: {
4
+ path?: string;
5
+ httpOnly?: boolean;
6
+ maxAge?: number;
7
+ secure?: boolean;
8
+ }): string;
@@ -0,0 +1,2 @@
1
+ import type { Route } from "./types";
2
+ export declare function defineRoutes(routes: Route[]): Route[];
@@ -0,0 +1,13 @@
1
+ export * from "./server";
2
+ export * from "./middleware";
3
+ export * from "./util";
4
+ export * from "./cookie";
5
+ export * from "./router";
6
+ export * from "./middleware/authMiddleware";
7
+ export * from "./middleware/rateLimit";
8
+ export * from "./middleware/cors";
9
+ export * from "./auth/token";
10
+ export * from "./middleware/auth";
11
+ export * from "./utils/base64url";
12
+ export * from "./defineRoute";
13
+ export * from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,323 @@
1
+ // @bun
2
+ // src/router.ts
3
+ function matchPath(pattern, path) {
4
+ const patternParts = pattern.split("/").filter(Boolean);
5
+ const pathParts = path.split("/").filter(Boolean);
6
+ const params = {};
7
+ for (let i = 0;i < patternParts.length; i++) {
8
+ const pat = patternParts[i];
9
+ const part = pathParts[i];
10
+ if (pat === "*") {
11
+ params["*"] = pathParts.slice(i).join("/");
12
+ return { matched: true, params };
13
+ }
14
+ if (pat.startsWith(":")) {
15
+ if (!part)
16
+ return { matched: false, params: {} };
17
+ params[pat.slice(1)] = part;
18
+ continue;
19
+ }
20
+ if (pat !== part)
21
+ return { matched: false, params: {} };
22
+ }
23
+ if (patternParts.length !== pathParts.length)
24
+ return { matched: false, params: {} };
25
+ return { matched: true, params };
26
+ }
27
+
28
+ // src/util.ts
29
+ function json(data, status = 200, headers = {}) {
30
+ const h = new Headers({
31
+ "Content-Type": "application/json",
32
+ ...headers
33
+ });
34
+ return new Response(JSON.stringify(data), {
35
+ status,
36
+ headers: h
37
+ });
38
+ }
39
+ function redirect(location, status = 302) {
40
+ return new Response(null, {
41
+ status,
42
+ headers: {
43
+ Location: location
44
+ }
45
+ });
46
+ }
47
+ function parseQuery(req) {
48
+ return new URL(req.url).searchParams;
49
+ }
50
+ async function parseBody(req) {
51
+ const contentType = req.headers.get("content-type") || "";
52
+ if (contentType.includes("application/json")) {
53
+ return await req.json();
54
+ }
55
+ if (contentType.includes("application/x-www-form-urlencoded")) {
56
+ const text = await req.text();
57
+ return Object.fromEntries(new URLSearchParams(text));
58
+ }
59
+ return await req.text();
60
+ }
61
+
62
+ // src/middleware.ts
63
+ class VafastError extends Error {
64
+ status;
65
+ type;
66
+ expose;
67
+ constructor(message, options = {}) {
68
+ super(message);
69
+ this.name = "VafastError";
70
+ this.status = options.status ?? 500;
71
+ this.type = options.type ?? "internal_error";
72
+ this.expose = options.expose ?? false;
73
+ if (options.cause)
74
+ this.cause = options.cause;
75
+ }
76
+ }
77
+ function composeMiddleware(middleware, finalHandler) {
78
+ const all = [errorHandler, ...middleware];
79
+ return function composedHandler(req) {
80
+ let i = -1;
81
+ const dispatch = (index) => {
82
+ if (index <= i)
83
+ return Promise.reject(new Error("next() called multiple times"));
84
+ i = index;
85
+ const fn = index < all.length ? all[index] : finalHandler;
86
+ return Promise.resolve(fn(req, () => dispatch(index + 1)));
87
+ };
88
+ return dispatch(0);
89
+ };
90
+ }
91
+ var errorHandler = async (req, next) => {
92
+ try {
93
+ return await next();
94
+ } catch (err) {
95
+ console.error("\u672A\u5904\u7406\u7684\u9519\u8BEF:", err);
96
+ if (err instanceof VafastError) {
97
+ return json({
98
+ error: err.type,
99
+ message: err.expose ? err.message : "\u53D1\u751F\u4E86\u4E00\u4E2A\u9519\u8BEF"
100
+ }, err.status);
101
+ }
102
+ return json({ error: "internal_error", message: "\u51FA\u73B0\u4E86\u4E00\u4E9B\u95EE\u9898" }, 500);
103
+ }
104
+ };
105
+
106
+ // src/server.ts
107
+ class Server {
108
+ routes;
109
+ globalMiddleware = [];
110
+ constructor(routes) {
111
+ this.routes = routes;
112
+ }
113
+ use(mw) {
114
+ this.globalMiddleware.push(mw);
115
+ }
116
+ fetch = async (req) => {
117
+ const { pathname } = new URL(req.url);
118
+ const method = req.method;
119
+ let matched;
120
+ let params = {};
121
+ for (const route of this.routes) {
122
+ if (route.method !== method)
123
+ continue;
124
+ const result = matchPath(route.path, pathname);
125
+ if (result.matched) {
126
+ matched = route;
127
+ params = result.params;
128
+ break;
129
+ }
130
+ }
131
+ const handler = async (req2) => {
132
+ if (matched) {
133
+ req2.params = params;
134
+ return await matched.handler(req2, params);
135
+ } else {
136
+ return new Response("Not Found", { status: 404 });
137
+ }
138
+ };
139
+ const middlewareChain = matched?.middleware ? [...this.globalMiddleware, ...matched.middleware] : this.globalMiddleware;
140
+ const composedHandler = composeMiddleware(middlewareChain, handler);
141
+ return await composedHandler(req);
142
+ };
143
+ }
144
+ // src/cookie.ts
145
+ function getCookie(req, key) {
146
+ const cookie = req.headers.get("cookie");
147
+ console.log("[Vafast] \u63A5\u6536\u5230\u7684 Cookie:", cookie);
148
+ if (!cookie)
149
+ return null;
150
+ const pairs = cookie.split(";").map((c) => c.trim().split("="));
151
+ for (const [k, v] of pairs) {
152
+ if (k === key) {
153
+ console.log(`[Vafast] \u5339\u914D\u7684 Cookie: ${k}=${v}`);
154
+ return decodeURIComponent(v);
155
+ }
156
+ }
157
+ console.log("[Vafast] \u6CA1\u6709\u5339\u914D\u7684 cookie \u952E:", key);
158
+ return null;
159
+ }
160
+ function setCookie(key, value, options = {}) {
161
+ let cookie = `${key}=${encodeURIComponent(value)}`;
162
+ if (options.path)
163
+ cookie += `; Path=${options.path}`;
164
+ if (options.httpOnly)
165
+ cookie += `; HttpOnly`;
166
+ if (options.secure)
167
+ cookie += `; Secure`;
168
+ if (options.maxAge)
169
+ cookie += `; Max-Age=${options.maxAge}`;
170
+ return cookie;
171
+ }
172
+ // src/middleware/authMiddleware.ts
173
+ var requireAuth = async (req, next) => {
174
+ const token = getCookie(req, "auth");
175
+ if (!token || token !== "valid-token") {
176
+ throw new VafastError("Unauthorized", {
177
+ status: 401,
178
+ type: "unauthorized",
179
+ expose: true
180
+ });
181
+ }
182
+ return next();
183
+ };
184
+ // src/middleware/rateLimit.ts
185
+ var store = new Map;
186
+ function rateLimit(options = {}) {
187
+ const windowMs = options.windowMs ?? 60000;
188
+ const max = options.max ?? 30;
189
+ const keyFn = options.keyFn ?? getIP;
190
+ return async (req, next) => {
191
+ const key = keyFn(req);
192
+ const now = Date.now();
193
+ const entry = store.get(key);
194
+ if (entry && entry.expires > now) {
195
+ if (entry.count >= max) {
196
+ throw new VafastError("Too many requests", {
197
+ status: 429,
198
+ type: "rate_limit",
199
+ expose: true
200
+ });
201
+ }
202
+ entry.count += 1;
203
+ } else {
204
+ store.set(key, { count: 1, expires: now + windowMs });
205
+ }
206
+ return next();
207
+ };
208
+ }
209
+ function getIP(req) {
210
+ return req.headers.get("cf-connecting-ip") || req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || "unknown";
211
+ }
212
+ // src/middleware/cors.ts
213
+ function createCORS(options = {}) {
214
+ const {
215
+ origin = [],
216
+ methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
217
+ headers = [],
218
+ credentials = false,
219
+ maxAge
220
+ } = options;
221
+ return async (req, next) => {
222
+ const reqOrigin = req.headers.get("Origin") || "";
223
+ const isAllowedOrigin = origin === "*" || origin.includes(reqOrigin);
224
+ if (req.method === "OPTIONS") {
225
+ const resHeaders = new Headers;
226
+ if (isAllowedOrigin) {
227
+ resHeaders.set("Access-Control-Allow-Origin", origin === "*" ? "*" : reqOrigin);
228
+ resHeaders.set("Access-Control-Allow-Methods", methods.join(","));
229
+ resHeaders.set("Access-Control-Allow-Headers", headers.join(","));
230
+ if (credentials)
231
+ resHeaders.set("Access-Control-Allow-Credentials", "true");
232
+ if (maxAge)
233
+ resHeaders.set("Access-Control-Max-Age", maxAge.toString());
234
+ }
235
+ return new Response(null, { status: 204, headers: resHeaders });
236
+ }
237
+ const res = await next();
238
+ if (isAllowedOrigin) {
239
+ res.headers.set("Access-Control-Allow-Origin", origin === "*" ? "*" : reqOrigin);
240
+ if (credentials)
241
+ res.headers.set("Access-Control-Allow-Credentials", "true");
242
+ }
243
+ return res;
244
+ };
245
+ }
246
+ // src/utils/base64url.ts
247
+ function base64urlEncode(str) {
248
+ return btoa(str).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
249
+ }
250
+ function base64urlDecode(str) {
251
+ const pad = str.length % 4 === 0 ? "" : "=".repeat(4 - str.length % 4);
252
+ const base64 = str.replace(/-/g, "+").replace(/_/g, "/") + pad;
253
+ return atob(base64);
254
+ }
255
+
256
+ // src/auth/token.ts
257
+ var encoder = new TextEncoder;
258
+ async function sign(data, secret) {
259
+ const key = await crypto.subtle.importKey("raw", encoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
260
+ const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(data));
261
+ return btoa(String.fromCharCode(...new Uint8Array(signature)));
262
+ }
263
+ async function generateToken(payload, secret) {
264
+ const data = base64urlEncode(JSON.stringify(payload));
265
+ const sig = await sign(data, secret);
266
+ return `${data}.${base64urlEncode(sig)}`;
267
+ }
268
+ async function verifyToken(token, secret) {
269
+ const [data, sig] = token.split(".");
270
+ if (!data || !sig)
271
+ return null;
272
+ const expectedSig = await sign(data, secret);
273
+ const expected = base64urlEncode(expectedSig);
274
+ if (sig !== expected)
275
+ return null;
276
+ try {
277
+ return JSON.parse(base64urlDecode(data));
278
+ } catch {
279
+ return null;
280
+ }
281
+ }
282
+ // src/middleware/auth.ts
283
+ function createAuth(options) {
284
+ const { secret, cookieName = "auth", headerName = "authorization" } = options;
285
+ return async (req, next) => {
286
+ const token = getCookie(req, cookieName) || req.headers.get(headerName)?.replace("Bearer ", "") || "";
287
+ const user = await verifyToken(token, secret);
288
+ if (!user) {
289
+ throw new VafastError("Unauthorized", {
290
+ status: 401,
291
+ type: "unauthorized",
292
+ expose: true
293
+ });
294
+ }
295
+ req.user = user;
296
+ return next();
297
+ };
298
+ }
299
+ // src/defineRoute.ts
300
+ function defineRoutes(routes) {
301
+ return routes;
302
+ }
303
+ export {
304
+ verifyToken,
305
+ setCookie,
306
+ requireAuth,
307
+ redirect,
308
+ rateLimit,
309
+ parseQuery,
310
+ parseBody,
311
+ matchPath,
312
+ json,
313
+ getCookie,
314
+ generateToken,
315
+ defineRoutes,
316
+ createCORS,
317
+ createAuth,
318
+ composeMiddleware,
319
+ base64urlEncode,
320
+ base64urlDecode,
321
+ VafastError,
322
+ Server
323
+ };
@@ -0,0 +1,8 @@
1
+ import type { Middleware } from "../types";
2
+ interface AuthOptions {
3
+ secret: string;
4
+ cookieName?: string;
5
+ headerName?: string;
6
+ }
7
+ export declare function createAuth(options: AuthOptions): Middleware;
8
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { Middleware } from "../types";
2
+ export declare const requireAuth: Middleware;
@@ -0,0 +1,9 @@
1
+ import type { Middleware } from "../types";
2
+ export interface CORSOptions {
3
+ origin?: string[] | "*";
4
+ methods?: string[];
5
+ headers?: string[];
6
+ credentials?: boolean;
7
+ maxAge?: number;
8
+ }
9
+ export declare function createCORS(options?: CORSOptions): Middleware;
@@ -0,0 +1,8 @@
1
+ import type { Middleware } from "../types";
2
+ interface RateLimitOptions {
3
+ windowMs?: number;
4
+ max?: number;
5
+ keyFn?: (req: Request) => string;
6
+ }
7
+ export declare function rateLimit(options?: RateLimitOptions): Middleware;
8
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { Handler, Middleware } from "./types";
2
+ /** 中间件类型:使用 next() 传递给下一个处理 */
3
+ /** Vafast 自定义错误类型 */
4
+ export declare class VafastError extends Error {
5
+ status: number;
6
+ type: string;
7
+ expose: boolean;
8
+ constructor(message: string, options?: {
9
+ status?: number;
10
+ type?: string;
11
+ expose?: boolean;
12
+ cause?: unknown;
13
+ });
14
+ }
15
+ /**
16
+ * 组合类型: 自动注入错误处理器进行中间件组合
17
+ */
18
+ export declare function composeMiddleware(middleware: Middleware[], finalHandler: Handler): Handler;
@@ -0,0 +1,8 @@
1
+ export interface MatchResult {
2
+ matched: boolean;
3
+ params: Record<string, string>;
4
+ }
5
+ /**
6
+ * 匹配函数:支持动态路由
7
+ */
8
+ export declare function matchPath(pattern: string, path: string): MatchResult;
@@ -0,0 +1,9 @@
1
+ import type { Middleware } from "./types";
2
+ import type { Route } from "./types";
3
+ export declare class Server {
4
+ private routes;
5
+ private globalMiddleware;
6
+ constructor(routes: Route[]);
7
+ use(mw: Middleware): void;
8
+ fetch: (req: Request) => Promise<Response>;
9
+ }
@@ -0,0 +1,9 @@
1
+ export type Method = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
2
+ export type Handler = (req: Request, params?: Record<string, string>, user?: Record<string, any>) => Response | Promise<Response>;
3
+ export type Middleware = (req: Request, next: () => Promise<Response>) => Promise<Response>;
4
+ export interface Route {
5
+ method: Method;
6
+ path: string;
7
+ handler: Handler;
8
+ middleware?: Middleware[];
9
+ }
package/dist/util.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export declare function json(data: unknown, status?: number, headers?: HeadersInit): Response;
2
+ /** 生成重定向响应 */
3
+ export declare function redirect(location: string, status?: 301 | 302): Response;
4
+ /** 获取查询字符串 */
5
+ export declare function parseQuery(req: Request): URLSearchParams;
6
+ /** 解析请求体(JSON / URL编码) */
7
+ export declare function parseBody(req: Request): Promise<unknown>;
@@ -0,0 +1,2 @@
1
+ export declare function base64urlEncode(str: string): string;
2
+ export declare function base64urlDecode(str: string): string;
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "vafast",
3
+ "version": "0.1.17",
4
+ "description": "专为Bun构建的极简结构化Web框架。Go风格,函数优先。",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/vafast/vafast.git"
9
+ },
10
+ "homepage": "https://github.com/vafast/vafast#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/vafast/vafast/issues"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "import": "./dist/index.js",
17
+ "types": "./dist/index.d.ts"
18
+ },
19
+ "./mod": {
20
+ "import": "./dist/index.js",
21
+ "types": "./dist/index.d.ts"
22
+ }
23
+ },
24
+ "types": "./dist/index.d.ts",
25
+ "main": "./dist/index.js",
26
+ "scripts": {
27
+ "build": "bun build src/index.ts --outdir dist --target bun",
28
+ "dev": "bun --watch index.ts",
29
+ "example": "bun run example/basic/hello-world.ts",
30
+ "example:schema": "bun run example/advanced/schema.ts",
31
+ "test": "bun test",
32
+ "benchmark": "bun run benchmarks/performance.ts",
33
+ "postbuild": "rimraf src/**/*.d.ts",
34
+ "release": "bumpp && npm publish"
35
+ },
36
+ "keywords": [
37
+ "bun",
38
+ "framework",
39
+ "minimal",
40
+ "router",
41
+ "go",
42
+ "web",
43
+ "edge",
44
+ "typescript",
45
+ "fast"
46
+ ],
47
+ "files": [
48
+ "dist",
49
+ "README.md",
50
+ "LICENSE"
51
+ ],
52
+ "author": "Vafast Team",
53
+ "license": "MIT",
54
+ "devDependencies": {
55
+ "@types/node": "^22.15.30",
56
+ "bumpp": "^10.2.3",
57
+ "bun-types": "^1.2.20",
58
+ "rimraf": "^6.0.1"
59
+ },
60
+ "dependencies": {
61
+ "@sinclair/typebox": "^0.34.39",
62
+ "bun": "^1.2.15"
63
+ }
64
+ }