vafast 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -10
- package/dist/auth/{token.d.ts → token.d.mts} +21 -19
- package/dist/auth/token.mjs +105 -0
- package/dist/auth/token.mjs.map +1 -0
- package/dist/base-server-Bq4_lJWK.mjs +113 -0
- package/dist/base-server-Bq4_lJWK.mjs.map +1 -0
- package/dist/base-server-Gakrozqk.d.mts +40 -0
- package/dist/base64url-BY-HBSpL.d.mts +6 -0
- package/dist/base64url-DLDOeXsk.mjs +13 -0
- package/dist/base64url-DLDOeXsk.mjs.map +1 -0
- package/dist/chunk-67U6L5Jh.mjs +37 -0
- package/dist/component-route-BYV_X1rA.d.mts +31 -0
- package/dist/component-route-Do2yyYTi.mjs +1 -0
- package/dist/component-router-DXUXLp1R.mjs +33 -0
- package/dist/component-router-DXUXLp1R.mjs.map +1 -0
- package/dist/component-server-ARXvZJUQ.mjs +124 -0
- package/dist/component-server-ARXvZJUQ.mjs.map +1 -0
- package/dist/component-server-BOz4Q-Qt.d.mts +38 -0
- package/dist/create-handler-CbSoroA1.mjs +166 -0
- package/dist/create-handler-CbSoroA1.mjs.map +1 -0
- package/dist/{utils/create-handler.d.ts → create-handler-Dtt0xv6g.d.mts} +24 -24
- package/dist/{defineRoute.d.ts → defineRoute.d.mts} +20 -17
- package/dist/defineRoute.mjs +93 -0
- package/dist/defineRoute.mjs.map +1 -0
- package/dist/dependency-manager-CPkwMI7J.mjs +61 -0
- package/dist/dependency-manager-CPkwMI7J.mjs.map +1 -0
- package/dist/dependency-manager-Dbug5INp.d.mts +27 -0
- package/dist/formats-BSqJWCsG.d.mts +42 -0
- package/dist/go-await-B-KP-K8x.mjs +33 -0
- package/dist/go-await-B-KP-K8x.mjs.map +1 -0
- package/dist/{utils/go-await.d.ts → go-await-CqPx9dVQ.d.mts} +4 -2
- package/dist/handle-BhpqNgGf.mjs +30 -0
- package/dist/handle-BhpqNgGf.mjs.map +1 -0
- package/dist/{utils/handle.d.ts → handle-DOidKTI-.d.mts} +8 -6
- package/dist/html-renderer-C3LKTLme.d.mts +22 -0
- package/dist/{utils/html-renderer.js → html-renderer-CJ3B2Hft.mjs} +34 -29
- package/dist/html-renderer-CJ3B2Hft.mjs.map +1 -0
- package/dist/index-DFsQyT61.d.mts +48 -0
- package/dist/index-DXJd7-2Z.d.mts +1 -0
- package/dist/index.d.mts +35 -0
- package/dist/index.mjs +42 -0
- package/dist/index.mjs.map +1 -0
- package/dist/middleware/{auth.d.ts → auth.d.mts} +12 -8
- package/dist/middleware/auth.mjs +98 -0
- package/dist/middleware/auth.mjs.map +1 -0
- package/dist/middleware/authMiddleware.d.mts +9 -0
- package/dist/middleware/authMiddleware.mjs +19 -0
- package/dist/middleware/authMiddleware.mjs.map +1 -0
- package/dist/middleware/{component-renderer.d.ts → component-renderer.d.mts} +3 -1
- package/dist/middleware/component-renderer.mjs +119 -0
- package/dist/middleware/component-renderer.mjs.map +1 -0
- package/dist/middleware/{component-router.d.ts → component-router.d.mts} +5 -4
- package/dist/middleware/component-router.mjs +4 -0
- package/dist/middleware/cors.d.mts +16 -0
- package/dist/middleware/cors.mjs +38 -0
- package/dist/middleware/cors.mjs.map +1 -0
- package/dist/middleware/rateLimit.d.mts +14 -0
- package/dist/middleware/rateLimit.mjs +34 -0
- package/dist/middleware/rateLimit.mjs.map +1 -0
- package/dist/middleware-3ShRJyd1.mjs +59 -0
- package/dist/middleware-3ShRJyd1.mjs.map +1 -0
- package/dist/middleware.d.mts +25 -0
- package/dist/middleware.mjs +4 -0
- package/dist/monitoring/index.d.mts +33 -0
- package/dist/monitoring/index.mjs +27 -0
- package/dist/monitoring/index.mjs.map +1 -0
- package/dist/monitoring/native-monitor.d.mts +48 -0
- package/dist/monitoring/native-monitor.mjs +154 -0
- package/dist/monitoring/native-monitor.mjs.map +1 -0
- package/dist/monitoring/types.d.mts +150 -0
- package/dist/monitoring/types.mjs +1 -0
- package/dist/node-server/index.d.mts +4 -0
- package/dist/node-server/index.mjs +5 -0
- package/dist/node-server/{request.d.ts → request.d.mts} +4 -6
- package/dist/node-server/request.mjs +3 -0
- package/dist/node-server/{response.d.ts → response.d.mts} +4 -6
- package/dist/node-server/response.mjs +3 -0
- package/dist/node-server/serve.d.mts +2 -0
- package/dist/node-server/serve.mjs +4 -0
- package/dist/{utils/parsers.d.ts → parsers-CodQFP1Z.d.mts} +10 -8
- package/dist/parsers-ROIZWSGI.mjs +168 -0
- package/dist/parsers-ROIZWSGI.mjs.map +1 -0
- package/dist/path-matcher-CXMJ-IrG.mjs +62 -0
- package/dist/path-matcher-CXMJ-IrG.mjs.map +1 -0
- package/dist/radix-tree-BWmhTLhT.mjs +157 -0
- package/dist/radix-tree-BWmhTLhT.mjs.map +1 -0
- package/dist/request-B2BkUecT.mjs +133 -0
- package/dist/request-B2BkUecT.mjs.map +1 -0
- package/dist/request-validator-Dyqng-H_.mjs +77 -0
- package/dist/request-validator-Dyqng-H_.mjs.map +1 -0
- package/dist/request-validator-u2Ccj3_x.d.mts +67 -0
- package/dist/response-BhFKEphr.mjs +72 -0
- package/dist/response-BhFKEphr.mjs.map +1 -0
- package/dist/response-CSKW5hsS.mjs +97 -0
- package/dist/response-CSKW5hsS.mjs.map +1 -0
- package/dist/{utils/response.d.ts → response-CUyV5FIm.d.mts} +4 -2
- package/dist/route-BRR15b-p.mjs +11 -0
- package/dist/route-BRR15b-p.mjs.map +1 -0
- package/dist/route-BqmWCG4e.d.mts +44 -0
- package/dist/route-registry-AlkDgbcE.mjs +225 -0
- package/dist/route-registry-AlkDgbcE.mjs.map +1 -0
- package/dist/route-registry-ykzRmaHB.d.mts +176 -0
- package/dist/router/index.d.mts +5 -0
- package/dist/router/index.mjs +10 -0
- package/dist/router/index.mjs.map +1 -0
- package/dist/router/radix-tree.d.mts +60 -0
- package/dist/router/radix-tree.mjs +4 -0
- package/dist/router-BOeVQrjz.mjs +71 -0
- package/dist/router-BOeVQrjz.mjs.map +1 -0
- package/dist/{router.d.ts → router.d.mts} +6 -7
- package/dist/router.mjs +4 -0
- package/dist/schema-CVuttFSw.d.mts +81 -0
- package/dist/schema-CbAaktsZ.mjs +1 -0
- package/dist/serve-BQQ2JzIH.d.mts +69 -0
- package/dist/serve-MRGGK7-q.mjs +107 -0
- package/dist/serve-MRGGK7-q.mjs.map +1 -0
- package/dist/serve.d.mts +2 -0
- package/dist/serve.mjs +4 -0
- package/dist/server/base-server.d.mts +4 -0
- package/dist/server/base-server.mjs +4 -0
- package/dist/server/component-server.d.mts +5 -0
- package/dist/server/component-server.mjs +5 -0
- package/dist/server/index.d.mts +7 -0
- package/dist/server/index.mjs +8 -0
- package/dist/server/server-factory.d.mts +7 -0
- package/dist/server/server-factory.mjs +6 -0
- package/dist/server/server.d.mts +5 -0
- package/dist/server/server.mjs +4 -0
- package/dist/server-B0nzGCG5.mjs +88 -0
- package/dist/server-B0nzGCG5.mjs.map +1 -0
- package/dist/server-C8WCshmG.mjs +137 -0
- package/dist/server-C8WCshmG.mjs.map +1 -0
- package/dist/server-Drc2kSxp.d.mts +60 -0
- package/dist/sse-BOd2pvUK.d.mts +65 -0
- package/dist/sse-US5D9mgE.mjs +87 -0
- package/dist/sse-US5D9mgE.mjs.map +1 -0
- package/dist/types/component-route.d.mts +2 -0
- package/dist/types/component-route.mjs +1 -0
- package/dist/types/index.d.mts +6 -0
- package/dist/types/index.mjs +3 -0
- package/dist/types/route.d.mts +2 -0
- package/dist/types/route.mjs +3 -0
- package/dist/types/schema.d.mts +2 -0
- package/dist/types/schema.mjs +1 -0
- package/dist/types/types.d.mts +2 -0
- package/dist/types/types.mjs +1 -0
- package/dist/{types/types.d.ts → types-Cb7_2VSt.d.mts} +27 -23
- package/dist/utils/base64url.d.mts +2 -0
- package/dist/utils/base64url.mjs +3 -0
- package/dist/utils/create-handler.d.mts +3 -0
- package/dist/utils/create-handler.mjs +5 -0
- package/dist/utils/dependency-manager.d.mts +2 -0
- package/dist/utils/dependency-manager.mjs +4 -0
- package/dist/utils/formats.d.mts +2 -0
- package/dist/utils/formats.mjs +129 -0
- package/dist/utils/formats.mjs.map +1 -0
- package/dist/utils/go-await.d.mts +2 -0
- package/dist/utils/go-await.mjs +3 -0
- package/dist/utils/handle.d.mts +2 -0
- package/dist/utils/handle.mjs +4 -0
- package/dist/utils/html-renderer.d.mts +2 -0
- package/dist/utils/html-renderer.mjs +4 -0
- package/dist/utils/index.d.mts +16 -0
- package/dist/utils/index.mjs +23 -0
- package/dist/utils/index.mjs.map +1 -0
- package/dist/utils/parsers.d.mts +2 -0
- package/dist/utils/parsers.mjs +3 -0
- package/dist/utils/path-matcher.d.mts +27 -0
- package/dist/utils/path-matcher.mjs +4 -0
- package/dist/utils/request-validator.d.mts +3 -0
- package/dist/utils/request-validator.mjs +5 -0
- package/dist/utils/response.d.mts +2 -0
- package/dist/utils/response.mjs +4 -0
- package/dist/utils/route-registry.d.mts +4 -0
- package/dist/utils/route-registry.mjs +4 -0
- package/dist/utils/sse.d.mts +3 -0
- package/dist/utils/sse.mjs +5 -0
- package/dist/utils/validators/validators.d.mts +2 -0
- package/dist/utils/validators/validators.mjs +3 -0
- package/dist/validators-C0eZyxPh.d.mts +67 -0
- package/dist/validators-CbCLj0Rc.mjs +112 -0
- package/dist/validators-CbCLj0Rc.mjs.map +1 -0
- package/package.json +16 -18
- package/dist/auth/token.js +0 -131
- package/dist/auth/token.js.map +0 -1
- package/dist/defineRoute.js +0 -37
- package/dist/defineRoute.js.map +0 -1
- package/dist/index.d.ts +0 -32
- package/dist/index.js +0 -2575
- package/dist/index.js.map +0 -1
- package/dist/middleware/auth.js +0 -205
- package/dist/middleware/auth.js.map +0 -1
- package/dist/middleware/authMiddleware.d.ts +0 -5
- package/dist/middleware/authMiddleware.js +0 -57
- package/dist/middleware/authMiddleware.js.map +0 -1
- package/dist/middleware/component-renderer.js +0 -139
- package/dist/middleware/component-renderer.js.map +0 -1
- package/dist/middleware/component-router.js +0 -36
- package/dist/middleware/component-router.js.map +0 -1
- package/dist/middleware/cors.d.ts +0 -12
- package/dist/middleware/cors.js +0 -43
- package/dist/middleware/cors.js.map +0 -1
- package/dist/middleware/rateLimit.d.ts +0 -10
- package/dist/middleware/rateLimit.js +0 -49
- package/dist/middleware/rateLimit.js.map +0 -1
- package/dist/middleware.d.ts +0 -21
- package/dist/middleware.js +0 -102
- package/dist/middleware.js.map +0 -1
- package/dist/monitoring/index.d.ts +0 -36
- package/dist/monitoring/index.js +0 -1484
- package/dist/monitoring/index.js.map +0 -1
- package/dist/monitoring/native-monitor.d.ts +0 -44
- package/dist/monitoring/native-monitor.js +0 -1451
- package/dist/monitoring/native-monitor.js.map +0 -1
- package/dist/monitoring/types.d.ts +0 -148
- package/dist/monitoring/types.js +0 -8
- package/dist/monitoring/types.js.map +0 -1
- package/dist/node-server/index.d.ts +0 -4
- package/dist/node-server/index.js +0 -298
- package/dist/node-server/index.js.map +0 -1
- package/dist/node-server/request.js +0 -125
- package/dist/node-server/request.js.map +0 -1
- package/dist/node-server/response.js +0 -76
- package/dist/node-server/response.js.map +0 -1
- package/dist/node-server/serve.d.ts +0 -71
- package/dist/node-server/serve.js +0 -281
- package/dist/node-server/serve.js.map +0 -1
- package/dist/router/index.d.ts +0 -3
- package/dist/router/index.js +0 -229
- package/dist/router/index.js.map +0 -1
- package/dist/router/radix-tree.d.ts +0 -66
- package/dist/router/radix-tree.js +0 -190
- package/dist/router/radix-tree.js.map +0 -1
- package/dist/router.js +0 -41
- package/dist/router.js.map +0 -1
- package/dist/serve.d.ts +0 -2
- package/dist/serve.js +0 -281
- package/dist/serve.js.map +0 -1
- package/dist/server/base-server.d.ts +0 -37
- package/dist/server/base-server.js +0 -134
- package/dist/server/base-server.js.map +0 -1
- package/dist/server/component-server.d.ts +0 -37
- package/dist/server/component-server.js +0 -488
- package/dist/server/component-server.js.map +0 -1
- package/dist/server/index.d.ts +0 -8
- package/dist/server/index.js +0 -1156
- package/dist/server/index.js.map +0 -1
- package/dist/server/server-factory.d.ts +0 -48
- package/dist/server/server-factory.js +0 -1153
- package/dist/server/server-factory.js.map +0 -1
- package/dist/server/server.d.ts +0 -64
- package/dist/server/server.js +0 -734
- package/dist/server/server.js.map +0 -1
- package/dist/types/component-route.d.ts +0 -29
- package/dist/types/component-route.js +0 -1
- package/dist/types/component-route.js.map +0 -1
- package/dist/types/index.d.ts +0 -5
- package/dist/types/index.js +0 -21
- package/dist/types/index.js.map +0 -1
- package/dist/types/route.d.ts +0 -42
- package/dist/types/route.js +0 -12
- package/dist/types/route.js.map +0 -1
- package/dist/types/schema.d.ts +0 -79
- package/dist/types/schema.js +0 -10
- package/dist/types/schema.js.map +0 -1
- package/dist/types/types.js +0 -1
- package/dist/types/types.js.map +0 -1
- package/dist/utils/base64url.d.ts +0 -4
- package/dist/utils/base64url.js +0 -14
- package/dist/utils/base64url.js.map +0 -1
- package/dist/utils/create-handler.js +0 -299
- package/dist/utils/create-handler.js.map +0 -1
- package/dist/utils/dependency-manager.d.ts +0 -25
- package/dist/utils/dependency-manager.js +0 -71
- package/dist/utils/dependency-manager.js.map +0 -1
- package/dist/utils/formats.d.ts +0 -40
- package/dist/utils/formats.js +0 -116
- package/dist/utils/formats.js.map +0 -1
- package/dist/utils/go-await.js +0 -16
- package/dist/utils/go-await.js.map +0 -1
- package/dist/utils/handle.js +0 -48
- package/dist/utils/handle.js.map +0 -1
- package/dist/utils/html-renderer.d.ts +0 -20
- package/dist/utils/html-renderer.js.map +0 -1
- package/dist/utils/index.d.ts +0 -16
- package/dist/utils/index.js +0 -1038
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/parsers.js +0 -160
- package/dist/utils/parsers.js.map +0 -1
- package/dist/utils/path-matcher.d.ts +0 -25
- package/dist/utils/path-matcher.js +0 -73
- package/dist/utils/path-matcher.js.map +0 -1
- package/dist/utils/request-validator.d.ts +0 -66
- package/dist/utils/request-validator.js +0 -158
- package/dist/utils/request-validator.js.map +0 -1
- package/dist/utils/response.js +0 -102
- package/dist/utils/response.js.map +0 -1
- package/dist/utils/route-registry.d.ts +0 -195
- package/dist/utils/route-registry.js +0 -152
- package/dist/utils/route-registry.js.map +0 -1
- package/dist/utils/sse.d.ts +0 -87
- package/dist/utils/sse.js +0 -181
- package/dist/utils/sse.js.map +0 -1
- package/dist/utils/validators/validators.d.ts +0 -76
- package/dist/utils/validators/validators.js +0 -97
- package/dist/utils/validators/validators.js.map +0 -1
package/dist/middleware/auth.js
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
// src/middleware.ts
|
|
2
|
-
var VafastError = class extends Error {
|
|
3
|
-
status;
|
|
4
|
-
type;
|
|
5
|
-
expose;
|
|
6
|
-
constructor(message, options = {}) {
|
|
7
|
-
super(message);
|
|
8
|
-
this.name = "VafastError";
|
|
9
|
-
this.status = options.status ?? 500;
|
|
10
|
-
this.type = options.type ?? "internal_error";
|
|
11
|
-
this.expose = options.expose ?? false;
|
|
12
|
-
if (options.cause) this.cause = options.cause;
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// src/utils/parsers.ts
|
|
17
|
-
import qs from "qs";
|
|
18
|
-
import cookie from "cookie";
|
|
19
|
-
function parseCookies(req) {
|
|
20
|
-
const cookieHeader = req.headers.get("cookie");
|
|
21
|
-
if (!cookieHeader) return {};
|
|
22
|
-
try {
|
|
23
|
-
const parsed = cookie.parse(cookieHeader);
|
|
24
|
-
const result = {};
|
|
25
|
-
for (const [key, value] of Object.entries(parsed)) {
|
|
26
|
-
if (value !== void 0 && value !== null) {
|
|
27
|
-
result[key] = value;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return result;
|
|
31
|
-
} catch {
|
|
32
|
-
return {};
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// src/utils/handle.ts
|
|
37
|
-
function getCookie(req, key) {
|
|
38
|
-
const cookies = parseCookies(req);
|
|
39
|
-
return cookies[key] || null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// src/utils/base64url.ts
|
|
43
|
-
function base64urlEncode(str) {
|
|
44
|
-
return btoa(str).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
45
|
-
}
|
|
46
|
-
function base64urlDecode(str) {
|
|
47
|
-
const pad = str.length % 4 === 0 ? "" : "=".repeat(4 - str.length % 4);
|
|
48
|
-
const base64 = str.replace(/-/g, "+").replace(/_/g, "/") + pad;
|
|
49
|
-
return atob(base64);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/auth/token.ts
|
|
53
|
-
var TokenError = class extends Error {
|
|
54
|
-
constructor(message, code) {
|
|
55
|
-
super(message);
|
|
56
|
-
this.code = code;
|
|
57
|
-
this.name = "TokenError";
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
var encoder = new TextEncoder();
|
|
61
|
-
async function sign(data, secret) {
|
|
62
|
-
const key = await crypto.subtle.importKey(
|
|
63
|
-
"raw",
|
|
64
|
-
encoder.encode(secret),
|
|
65
|
-
{ name: "HMAC", hash: "SHA-256" },
|
|
66
|
-
false,
|
|
67
|
-
["sign"]
|
|
68
|
-
);
|
|
69
|
-
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(data));
|
|
70
|
-
return btoa(
|
|
71
|
-
String.fromCharCode.apply(null, Array.from(new Uint8Array(signature)))
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
async function verifyToken(token, secret) {
|
|
75
|
-
try {
|
|
76
|
-
const [data, sig] = token.split(".");
|
|
77
|
-
if (!data || !sig) {
|
|
78
|
-
throw new TokenError("\u4EE4\u724C\u683C\u5F0F\u65E0\u6548", "MALFORMED_TOKEN");
|
|
79
|
-
}
|
|
80
|
-
const expectedSig = await sign(data, secret);
|
|
81
|
-
const expected = base64urlEncode(expectedSig);
|
|
82
|
-
if (sig !== expected) {
|
|
83
|
-
throw new TokenError("\u4EE4\u724C\u7B7E\u540D\u65E0\u6548", "INVALID_SIGNATURE");
|
|
84
|
-
}
|
|
85
|
-
const payload = JSON.parse(base64urlDecode(data));
|
|
86
|
-
if (payload.exp && Date.now() / 1e3 > payload.exp) {
|
|
87
|
-
throw new TokenError("\u4EE4\u724C\u5DF2\u8FC7\u671F", "EXPIRED_TOKEN");
|
|
88
|
-
}
|
|
89
|
-
return payload;
|
|
90
|
-
} catch (error) {
|
|
91
|
-
if (error instanceof TokenError) {
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
throw new TokenError("\u4EE4\u724C\u9A8C\u8BC1\u5931\u8D25", "INVALID_TOKEN");
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// src/middleware/auth.ts
|
|
99
|
-
function createAuth(options) {
|
|
100
|
-
const {
|
|
101
|
-
secret,
|
|
102
|
-
cookieName = "auth",
|
|
103
|
-
headerName = "authorization",
|
|
104
|
-
required = true,
|
|
105
|
-
roles = [],
|
|
106
|
-
permissions = []
|
|
107
|
-
} = options;
|
|
108
|
-
return async (req, next) => {
|
|
109
|
-
const token = getCookie(req, cookieName) || req.headers.get(headerName)?.replace("Bearer ", "") || "";
|
|
110
|
-
if (!token && required) {
|
|
111
|
-
throw new VafastError("\u7F3A\u5C11\u8BA4\u8BC1\u4EE4\u724C", {
|
|
112
|
-
status: 401,
|
|
113
|
-
type: "unauthorized",
|
|
114
|
-
expose: true
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
if (!token && !required) {
|
|
118
|
-
return next();
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
const user = await verifyToken(token, secret);
|
|
122
|
-
if (!user) {
|
|
123
|
-
throw new VafastError("\u4EE4\u724C\u9A8C\u8BC1\u5931\u8D25", {
|
|
124
|
-
status: 401,
|
|
125
|
-
type: "unauthorized",
|
|
126
|
-
expose: true
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
if (roles.length > 0 && user.role && !roles.includes(user.role)) {
|
|
130
|
-
throw new VafastError("\u6743\u9650\u4E0D\u8DB3", {
|
|
131
|
-
status: 403,
|
|
132
|
-
type: "forbidden",
|
|
133
|
-
expose: true
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
if (permissions.length > 0 && user.permissions) {
|
|
137
|
-
const userPermissions = Array.isArray(user.permissions) ? user.permissions : [user.permissions];
|
|
138
|
-
const hasPermission = permissions.some(
|
|
139
|
-
(permission) => userPermissions.includes(permission)
|
|
140
|
-
);
|
|
141
|
-
if (!hasPermission) {
|
|
142
|
-
throw new VafastError("\u6743\u9650\u4E0D\u8DB3", {
|
|
143
|
-
status: 403,
|
|
144
|
-
type: "forbidden",
|
|
145
|
-
expose: true
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
req.user = user;
|
|
150
|
-
req.token = token;
|
|
151
|
-
return next();
|
|
152
|
-
} catch (error) {
|
|
153
|
-
if (error instanceof TokenError) {
|
|
154
|
-
let status = 401;
|
|
155
|
-
let message = "\u8BA4\u8BC1\u5931\u8D25";
|
|
156
|
-
switch (error.code) {
|
|
157
|
-
case "EXPIRED_TOKEN":
|
|
158
|
-
status = 401;
|
|
159
|
-
message = "\u4EE4\u724C\u5DF2\u8FC7\u671F";
|
|
160
|
-
break;
|
|
161
|
-
case "INVALID_SIGNATURE":
|
|
162
|
-
status = 401;
|
|
163
|
-
message = "\u4EE4\u724C\u7B7E\u540D\u65E0\u6548";
|
|
164
|
-
break;
|
|
165
|
-
case "MALFORMED_TOKEN":
|
|
166
|
-
status = 400;
|
|
167
|
-
message = "\u4EE4\u724C\u683C\u5F0F\u9519\u8BEF";
|
|
168
|
-
break;
|
|
169
|
-
default:
|
|
170
|
-
status = 401;
|
|
171
|
-
message = "\u4EE4\u724C\u9A8C\u8BC1\u5931\u8D25";
|
|
172
|
-
}
|
|
173
|
-
throw new VafastError(message, {
|
|
174
|
-
status,
|
|
175
|
-
type: "unauthorized",
|
|
176
|
-
expose: true
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
if (error instanceof VafastError) {
|
|
180
|
-
throw error;
|
|
181
|
-
}
|
|
182
|
-
throw new VafastError("\u8BA4\u8BC1\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF", {
|
|
183
|
-
status: 500,
|
|
184
|
-
type: "internal_error",
|
|
185
|
-
expose: false
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
function createOptionalAuth(options) {
|
|
191
|
-
return createAuth({ ...options, required: false });
|
|
192
|
-
}
|
|
193
|
-
function createRoleAuth(roles, options) {
|
|
194
|
-
return createAuth({ ...options, roles });
|
|
195
|
-
}
|
|
196
|
-
function createPermissionAuth(permissions, options) {
|
|
197
|
-
return createAuth({ ...options, permissions });
|
|
198
|
-
}
|
|
199
|
-
export {
|
|
200
|
-
createAuth,
|
|
201
|
-
createOptionalAuth,
|
|
202
|
-
createPermissionAuth,
|
|
203
|
-
createRoleAuth
|
|
204
|
-
};
|
|
205
|
-
//# sourceMappingURL=auth.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/middleware.ts","../../src/utils/parsers.ts","../../src/utils/handle.ts","../../src/utils/base64url.ts","../../src/auth/token.ts","../../src/middleware/auth.ts"],"sourcesContent":["// src/middleware.ts\n\nimport { json, mapResponse } from \"./utils/response\";\n\nimport type { Handler, Middleware } from \"./types\";\n/** 中间件类型:使用 next() 传递给下一个处理 */\n\n/** Vafast 自定义错误类型 */\nexport class VafastError extends Error {\n status: number;\n type: string;\n expose: boolean;\n\n constructor(\n message: string,\n options: {\n status?: number;\n type?: string;\n expose?: boolean;\n cause?: unknown;\n } = {},\n ) {\n super(message);\n this.name = \"VafastError\";\n this.status = options.status ?? 500;\n this.type = options.type ?? \"internal_error\";\n this.expose = options.expose ?? false;\n if (options.cause) (this as any).cause = options.cause;\n }\n}\n\n/**\n * 组合类型: 自动注入错误处理器进行中间件组合\n */\nexport function composeMiddleware(\n middleware: Middleware[],\n finalHandler: Handler,\n): (req: Request) => Promise<Response> {\n const all = [errorHandler, ...middleware];\n\n return function composedHandler(req: Request): Promise<Response> {\n let i = -1;\n\n const dispatch = (index: number): Promise<Response> => {\n if (index <= i)\n return Promise.reject(new Error(\"next() called multiple times\"));\n i = index;\n\n // 中间件阶段\n if (index < all.length) {\n const mw = all[index];\n return Promise.resolve(mw(req, () => dispatch(index + 1)));\n }\n\n // 最终 handler - 使用 mapResponse 转换返回值\n return Promise.resolve(finalHandler(req)).then(mapResponse);\n };\n\n return dispatch(0);\n };\n}\n\n/** 默认包含的全局错误处理器 */\nconst errorHandler: Middleware = async (req, next) => {\n try {\n return await next();\n } catch (err) {\n console.error(\"未处理的错误:\", err);\n\n if (err instanceof VafastError) {\n return json(\n {\n error: err.type,\n message: err.expose ? err.message : \"发生了一个错误\",\n },\n err.status,\n );\n }\n\n return json({ error: \"internal_error\", message: \"出现了一些问题\" }, 500);\n }\n};\n","// src/parsers.ts\nimport qs from \"qs\";\nimport cookie from \"cookie\";\n\n// 文件信息接口\nexport interface FileInfo {\n name: string;\n type: string;\n size: number;\n data: ArrayBuffer;\n}\n\n// 表单数据接口\nexport interface FormData {\n fields: Record<string, string>;\n files: Record<string, FileInfo>;\n}\n\n/**\n * 简化的请求体解析函数\n * 优先简洁性,处理最常见的场景\n */\nexport async function parseBody(req: Request): Promise<unknown> {\n const contentType = req.headers.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/json\")) {\n return await req.json();\n }\n if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n const text = await req.text();\n return Object.fromEntries(new URLSearchParams(text));\n }\n return await req.text(); // fallback\n}\n\n/**\n * 解析 multipart/form-data 格式\n * 支持文件上传和普通表单字段\n */\nasync function parseMultipartFormData(req: Request): Promise<FormData> {\n const formData = await req.formData();\n const result: FormData = {\n fields: {},\n files: {},\n };\n\n for (const [key, value] of formData.entries()) {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"name\" in value &&\n \"type\" in value &&\n \"size\" in value\n ) {\n // 处理文件\n const file = value as any;\n const arrayBuffer = await file.arrayBuffer();\n result.files[key] = {\n name: file.name,\n type: file.type,\n size: file.size,\n data: arrayBuffer,\n };\n } else {\n // 处理普通字段\n result.fields[key] = value as string;\n }\n }\n\n return result;\n}\n\n/**\n * 解析请求体为特定类型\n * 提供类型安全的解析方法\n */\nexport async function parseBodyAs<T>(req: Request): Promise<T> {\n const body = await parseBody(req);\n return body as T;\n}\n\n/**\n * 解析请求体为表单数据\n * 专门用于处理 multipart/form-data\n */\nexport async function parseFormData(req: Request): Promise<FormData> {\n const contentType = req.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"multipart/form-data\")) {\n throw new Error(\"请求不是 multipart/form-data 格式\");\n }\n\n return await parseMultipartFormData(req);\n}\n\n/**\n * 解析请求体为文件\n * 专门用于处理文件上传\n */\nexport async function parseFile(req: Request): Promise<FileInfo> {\n const contentType = req.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"multipart/form-data\")) {\n throw new Error(\"请求不是 multipart/form-data 格式\");\n }\n\n const formData = await parseMultipartFormData(req);\n const fileKeys = Object.keys(formData.files);\n\n if (fileKeys.length === 0) {\n throw new Error(\"请求中没有文件\");\n }\n\n if (fileKeys.length > 1) {\n throw new Error(\"请求中包含多个文件,请使用 parseFormData\");\n }\n\n return formData.files[fileKeys[0]];\n}\n\n/**\n * 快速提取 query string(避免创建 URL 对象)\n */\nfunction extractQueryString(url: string): string {\n const qIndex = url.indexOf(\"?\");\n if (qIndex === -1) return \"\";\n\n const hashIndex = url.indexOf(\"#\", qIndex);\n return hashIndex === -1\n ? url.substring(qIndex + 1)\n : url.substring(qIndex + 1, hashIndex);\n}\n\n/** 获取查询字符串,直接返回对象 */\nexport function parseQuery(req: Request): Record<string, unknown> {\n const queryString = extractQueryString(req.url);\n if (!queryString) return {};\n return qs.parse(queryString);\n}\n\n/**\n * 快速解析简单查询字符串(不支持嵌套,但更快)\n * 适用于简单的 key=value&key2=value2 场景\n */\nexport function parseQueryFast(req: Request): Record<string, string> {\n const queryString = extractQueryString(req.url);\n if (!queryString) return {};\n\n const result: Record<string, string> = Object.create(null);\n const pairs = queryString.split(\"&\");\n\n for (const pair of pairs) {\n const eqIndex = pair.indexOf(\"=\");\n if (eqIndex === -1) {\n result[decodeURIComponent(pair)] = \"\";\n } else {\n const key = decodeURIComponent(pair.substring(0, eqIndex));\n const value = decodeURIComponent(pair.substring(eqIndex + 1));\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/** 解析请求头,返回对象 */\nexport function parseHeaders(req: Request): Record<string, string> {\n const headers: Record<string, string> = Object.create(null);\n req.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return headers;\n}\n\n/**\n * 获取单个请求头(避免解析全部)\n */\nexport function getHeader(req: Request, name: string): string | null {\n return req.headers.get(name);\n}\n\n/** 使用cookie库解析Cookie,保证可靠性 */\nexport function parseCookies(req: Request): Record<string, string> {\n const cookieHeader = req.headers.get(\"cookie\");\n if (!cookieHeader) return {};\n\n try {\n const parsed = cookie.parse(cookieHeader);\n // 过滤掉undefined和null值\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(parsed)) {\n if (value !== undefined && value !== null) {\n result[key] = value;\n }\n }\n return result;\n } catch {\n return {};\n }\n}\n\n/**\n * 快速解析 Cookie(简化版,不使用外部库)\n * 适用于简单的 cookie 场景\n */\nexport function parseCookiesFast(req: Request): Record<string, string> {\n const cookieHeader = req.headers.get(\"cookie\");\n if (!cookieHeader) return {};\n\n const result: Record<string, string> = Object.create(null);\n const pairs = cookieHeader.split(\";\");\n\n for (const pair of pairs) {\n const trimmed = pair.trim();\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex > 0) {\n const key = trimmed.substring(0, eqIndex).trim();\n const value = trimmed.substring(eqIndex + 1).trim();\n // 移除引号\n result[key] =\n value.startsWith('\"') && value.endsWith('\"')\n ? value.slice(1, -1)\n : value;\n }\n }\n\n return result;\n}\n\n/**\n * 获取单个 Cookie 值(避免解析全部)\n */\nexport function getCookie(req: Request, name: string): string | null {\n const cookieHeader = req.headers.get(\"cookie\");\n if (!cookieHeader) return null;\n\n const prefix = `${name}=`;\n const pairs = cookieHeader.split(\";\");\n\n for (const pair of pairs) {\n const trimmed = pair.trim();\n if (trimmed.startsWith(prefix)) {\n const value = trimmed.substring(prefix.length).trim();\n return value.startsWith('\"') && value.endsWith('\"')\n ? value.slice(1, -1)\n : value;\n }\n }\n\n return null;\n}\n","import { parseCookies } from \"./parsers\";\n\n/** 获取单个 Cookie 值 */\nexport function getCookie(req: Request, key: string): string | null {\n const cookies = parseCookies(req);\n return cookies[key] || null;\n}\n\n/** 生成 Set-Cookie 头 */\nexport function setCookie(\n key: string,\n value: string,\n options: {\n path?: string;\n httpOnly?: boolean;\n maxAge?: number;\n secure?: boolean;\n } = {},\n): string {\n let cookie = `${key}=${encodeURIComponent(value)}`;\n\n if (options.path) cookie += `; Path=${options.path}`;\n if (options.httpOnly) cookie += `; HttpOnly`;\n if (options.secure) cookie += `; Secure`;\n if (options.maxAge) cookie += `; Max-Age=${options.maxAge}`;\n\n return cookie;\n}\n\n// 提供给中间件写入\"局部上下文\"的工具函数\nexport function setLocals<T extends object>(req: Request, extras: T) {\n const target = req as unknown as Record<string, unknown>;\n target.__locals = { ...((target.__locals as object) ?? {}), ...extras };\n}\n\n// 获取中间件注入的局部上下文\nexport function getLocals<T extends object>(req: Request): T {\n const target = req as unknown as Record<string, unknown>;\n return (target.__locals ?? {}) as T;\n}\n","export function base64urlEncode(str: string): string {\n return btoa(str)\n .replace(/=/g, \"\") // ✅ 删除填充\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\");\n}\n\nexport function base64urlDecode(str: string): string {\n const pad = str.length % 4 === 0 ? \"\" : \"=\".repeat(4 - (str.length % 4));\n const base64 = str.replace(/-/g, \"+\").replace(/_/g, \"/\") + pad;\n return atob(base64);\n}\n","// src/auth/token.ts\nimport { base64urlEncode, base64urlDecode } from \"../utils/base64url\";\n\n// 类型定义\nexport interface TokenPayload {\n [key: string]: any;\n exp?: number; // 过期时间戳\n iat?: number; // 签发时间戳\n sub?: string; // 主题(通常是用户ID)\n aud?: string; // 受众\n iss?: string; // 签发者\n}\n\nexport interface TokenResult {\n payload: TokenPayload;\n token: string;\n expiresAt: number;\n}\n\nexport interface TokenOptions {\n expiresIn?: number; // 过期时间(秒)\n issuer?: string; // 签发者\n audience?: string; // 受众\n subject?: string; // 主题\n}\n\nexport class TokenError extends Error {\n constructor(\n message: string,\n public code:\n | \"INVALID_TOKEN\"\n | \"EXPIRED_TOKEN\"\n | \"INVALID_SIGNATURE\"\n | \"MALFORMED_TOKEN\"\n | \"INVALID_PAYLOAD\",\n ) {\n super(message);\n this.name = \"TokenError\";\n }\n}\n\nconst encoder = new TextEncoder();\n\n/** 使用 HMAC-SHA256 进行签名 */\nasync function sign(data: string, secret: string): Promise<string> {\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n\n const signature = await crypto.subtle.sign(\"HMAC\", key, encoder.encode(data));\n return btoa(\n String.fromCharCode.apply(null, Array.from(new Uint8Array(signature))),\n );\n}\n\n/** 生成令牌 */\nexport async function generateToken(\n payload: TokenPayload,\n secret: string,\n options: TokenOptions = {},\n): Promise<TokenResult> {\n const { expiresIn = 3600, issuer, audience, subject } = options;\n\n // 创建令牌载荷,强制使用当前时间\n const now = Math.floor(Date.now() / 1000);\n const tokenPayload: TokenPayload = {\n ...payload,\n iat: now,\n exp: now + expiresIn,\n };\n\n // 添加可选字段\n if (issuer) tokenPayload.iss = issuer;\n if (audience) tokenPayload.aud = audience;\n if (subject) tokenPayload.sub = subject;\n\n const data = base64urlEncode(JSON.stringify(tokenPayload));\n const sig = await sign(data, secret);\n const token = `${data}.${base64urlEncode(sig)}`;\n\n return {\n payload: tokenPayload,\n token,\n expiresAt: tokenPayload.exp! * 1000, // 转换为毫秒\n };\n}\n\n/** 验证令牌 */\nexport async function verifyToken(\n token: string,\n secret: string,\n): Promise<TokenPayload | null> {\n try {\n const [data, sig] = token.split(\".\");\n if (!data || !sig) {\n throw new TokenError(\"令牌格式无效\", \"MALFORMED_TOKEN\");\n }\n\n const expectedSig = await sign(data, secret);\n const expected = base64urlEncode(expectedSig);\n\n if (sig !== expected) {\n throw new TokenError(\"令牌签名无效\", \"INVALID_SIGNATURE\");\n }\n\n const payload = JSON.parse(base64urlDecode(data)) as TokenPayload;\n\n // 检查过期时间\n if (payload.exp && Date.now() / 1000 > payload.exp) {\n throw new TokenError(\"令牌已过期\", \"EXPIRED_TOKEN\");\n }\n\n return payload;\n } catch (error) {\n if (error instanceof TokenError) {\n throw error;\n }\n throw new TokenError(\"令牌验证失败\", \"INVALID_TOKEN\");\n }\n}\n\n/** 解析令牌(不验证签名) */\nexport function parseToken(token: string): TokenPayload | null {\n try {\n const [data] = token.split(\".\");\n if (!data) return null;\n\n return JSON.parse(base64urlDecode(data));\n } catch {\n return null;\n }\n}\n\n/** 检查令牌是否过期 */\nexport function isTokenExpired(token: string): boolean {\n const payload = parseToken(token);\n if (!payload || !payload.exp) return true;\n\n return Date.now() / 1000 > payload.exp;\n}\n\n/** 获取令牌剩余有效时间(秒) */\nexport function getTokenTimeRemaining(token: string): number {\n const payload = parseToken(token);\n if (!payload || !payload.exp) return 0;\n\n const remaining = payload.exp - Date.now() / 1000;\n return Math.max(0, Math.floor(remaining));\n}\n\n/** 刷新令牌 */\nexport async function refreshToken(\n token: string,\n secret: string,\n options: TokenOptions = {},\n): Promise<TokenResult | null> {\n try {\n const payload = await verifyToken(token, secret);\n if (!payload) return null;\n\n // 移除时间相关字段,重新生成\n const { exp, iat, ...cleanPayload } = payload;\n\n // 添加延迟确保时间戳不同\n await new Promise((resolve) => setTimeout(resolve, 10));\n\n return await generateToken(cleanPayload, secret, options);\n } catch {\n return null;\n }\n}\n\n/** 创建访问令牌和刷新令牌对 */\nexport async function createTokenPair(\n payload: TokenPayload,\n secret: string,\n options: TokenOptions = {},\n): Promise<{\n accessToken: TokenResult;\n refreshToken: TokenResult;\n}> {\n const accessToken = await generateToken(payload, secret, {\n ...options,\n expiresIn: options.expiresIn || 3600, // 1小时\n });\n\n const refreshToken = await generateToken(payload, secret, {\n ...options,\n expiresIn: 7 * 24 * 3600, // 7天\n });\n\n return { accessToken, refreshToken };\n}\n","// src/middleware/auth.ts\n\nimport type { Middleware } from \"../types\";\nimport { VafastError } from \"../middleware\";\nimport { getCookie } from \"../utils/handle\";\nimport { verifyToken, TokenError, type TokenPayload } from \"../auth/token\";\n\ninterface AuthOptions {\n secret: string;\n cookieName?: string;\n headerName?: string;\n required?: boolean; // 是否必需认证\n roles?: string[]; // 允许的角色\n permissions?: string[]; // 允许的权限\n}\n\nexport function createAuth(options: AuthOptions): Middleware {\n const {\n secret,\n cookieName = \"auth\",\n headerName = \"authorization\",\n required = true,\n roles = [],\n permissions = [],\n } = options;\n\n return async (req, next) => {\n const token =\n getCookie(req, cookieName) ||\n req.headers.get(headerName)?.replace(\"Bearer \", \"\") ||\n \"\";\n\n if (!token && required) {\n throw new VafastError(\"缺少认证令牌\", {\n status: 401,\n type: \"unauthorized\",\n expose: true,\n });\n }\n\n if (!token && !required) {\n return next();\n }\n\n try {\n const user = (await verifyToken(token, secret)) as TokenPayload;\n\n if (!user) {\n throw new VafastError(\"令牌验证失败\", {\n status: 401,\n type: \"unauthorized\",\n expose: true,\n });\n }\n\n // 检查角色权限\n if (roles.length > 0 && user.role && !roles.includes(user.role)) {\n throw new VafastError(\"权限不足\", {\n status: 403,\n type: \"forbidden\",\n expose: true,\n });\n }\n\n // 检查具体权限\n if (permissions.length > 0 && user.permissions) {\n const userPermissions = Array.isArray(user.permissions)\n ? user.permissions\n : [user.permissions];\n\n const hasPermission = permissions.some((permission) =>\n userPermissions.includes(permission),\n );\n\n if (!hasPermission) {\n throw new VafastError(\"权限不足\", {\n status: 403,\n type: \"forbidden\",\n expose: true,\n });\n }\n }\n\n // 🪄 在这里扩展 Request 对象\n (req as any).user = user;\n (req as any).token = token;\n\n return next();\n } catch (error) {\n if (error instanceof TokenError) {\n let status = 401;\n let message = \"认证失败\";\n\n switch (error.code) {\n case \"EXPIRED_TOKEN\":\n status = 401;\n message = \"令牌已过期\";\n break;\n case \"INVALID_SIGNATURE\":\n status = 401;\n message = \"令牌签名无效\";\n break;\n case \"MALFORMED_TOKEN\":\n status = 400;\n message = \"令牌格式错误\";\n break;\n default:\n status = 401;\n message = \"令牌验证失败\";\n }\n\n throw new VafastError(message, {\n status,\n type: \"unauthorized\",\n expose: true,\n });\n }\n\n if (error instanceof VafastError) {\n throw error;\n }\n\n throw new VafastError(\"认证过程中发生错误\", {\n status: 500,\n type: \"internal_error\",\n expose: false,\n });\n }\n };\n}\n\n// 可选认证中间件\nexport function createOptionalAuth(\n options: Omit<AuthOptions, \"required\">,\n): Middleware {\n return createAuth({ ...options, required: false });\n}\n\n// 角色验证中间件\nexport function createRoleAuth(\n roles: string[],\n options: Omit<AuthOptions, \"roles\">,\n): Middleware {\n return createAuth({ ...options, roles });\n}\n\n// 权限验证中间件\nexport function createPermissionAuth(\n permissions: string[],\n options: Omit<AuthOptions, \"permissions\">,\n): Middleware {\n return createAuth({ ...options, permissions });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// src/middleware.ts
|
|
2
|
-
var VafastError = class extends Error {
|
|
3
|
-
status;
|
|
4
|
-
type;
|
|
5
|
-
expose;
|
|
6
|
-
constructor(message, options = {}) {
|
|
7
|
-
super(message);
|
|
8
|
-
this.name = "VafastError";
|
|
9
|
-
this.status = options.status ?? 500;
|
|
10
|
-
this.type = options.type ?? "internal_error";
|
|
11
|
-
this.expose = options.expose ?? false;
|
|
12
|
-
if (options.cause) this.cause = options.cause;
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// src/utils/parsers.ts
|
|
17
|
-
import qs from "qs";
|
|
18
|
-
import cookie from "cookie";
|
|
19
|
-
function parseCookies(req) {
|
|
20
|
-
const cookieHeader = req.headers.get("cookie");
|
|
21
|
-
if (!cookieHeader) return {};
|
|
22
|
-
try {
|
|
23
|
-
const parsed = cookie.parse(cookieHeader);
|
|
24
|
-
const result = {};
|
|
25
|
-
for (const [key, value] of Object.entries(parsed)) {
|
|
26
|
-
if (value !== void 0 && value !== null) {
|
|
27
|
-
result[key] = value;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return result;
|
|
31
|
-
} catch {
|
|
32
|
-
return {};
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// src/utils/handle.ts
|
|
37
|
-
function getCookie(req, key) {
|
|
38
|
-
const cookies = parseCookies(req);
|
|
39
|
-
return cookies[key] || null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// src/middleware/authMiddleware.ts
|
|
43
|
-
var requireAuth = async (req, next) => {
|
|
44
|
-
const token = getCookie(req, "auth");
|
|
45
|
-
if (!token || token !== "valid-token") {
|
|
46
|
-
throw new VafastError("Unauthorized", {
|
|
47
|
-
status: 401,
|
|
48
|
-
type: "unauthorized",
|
|
49
|
-
expose: true
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
return next();
|
|
53
|
-
};
|
|
54
|
-
export {
|
|
55
|
-
requireAuth
|
|
56
|
-
};
|
|
57
|
-
//# sourceMappingURL=authMiddleware.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/middleware.ts","../../src/utils/parsers.ts","../../src/utils/handle.ts","../../src/middleware/authMiddleware.ts"],"sourcesContent":["// src/middleware.ts\n\nimport { json, mapResponse } from \"./utils/response\";\n\nimport type { Handler, Middleware } from \"./types\";\n/** 中间件类型:使用 next() 传递给下一个处理 */\n\n/** Vafast 自定义错误类型 */\nexport class VafastError extends Error {\n status: number;\n type: string;\n expose: boolean;\n\n constructor(\n message: string,\n options: {\n status?: number;\n type?: string;\n expose?: boolean;\n cause?: unknown;\n } = {},\n ) {\n super(message);\n this.name = \"VafastError\";\n this.status = options.status ?? 500;\n this.type = options.type ?? \"internal_error\";\n this.expose = options.expose ?? false;\n if (options.cause) (this as any).cause = options.cause;\n }\n}\n\n/**\n * 组合类型: 自动注入错误处理器进行中间件组合\n */\nexport function composeMiddleware(\n middleware: Middleware[],\n finalHandler: Handler,\n): (req: Request) => Promise<Response> {\n const all = [errorHandler, ...middleware];\n\n return function composedHandler(req: Request): Promise<Response> {\n let i = -1;\n\n const dispatch = (index: number): Promise<Response> => {\n if (index <= i)\n return Promise.reject(new Error(\"next() called multiple times\"));\n i = index;\n\n // 中间件阶段\n if (index < all.length) {\n const mw = all[index];\n return Promise.resolve(mw(req, () => dispatch(index + 1)));\n }\n\n // 最终 handler - 使用 mapResponse 转换返回值\n return Promise.resolve(finalHandler(req)).then(mapResponse);\n };\n\n return dispatch(0);\n };\n}\n\n/** 默认包含的全局错误处理器 */\nconst errorHandler: Middleware = async (req, next) => {\n try {\n return await next();\n } catch (err) {\n console.error(\"未处理的错误:\", err);\n\n if (err instanceof VafastError) {\n return json(\n {\n error: err.type,\n message: err.expose ? err.message : \"发生了一个错误\",\n },\n err.status,\n );\n }\n\n return json({ error: \"internal_error\", message: \"出现了一些问题\" }, 500);\n }\n};\n","// src/parsers.ts\nimport qs from \"qs\";\nimport cookie from \"cookie\";\n\n// 文件信息接口\nexport interface FileInfo {\n name: string;\n type: string;\n size: number;\n data: ArrayBuffer;\n}\n\n// 表单数据接口\nexport interface FormData {\n fields: Record<string, string>;\n files: Record<string, FileInfo>;\n}\n\n/**\n * 简化的请求体解析函数\n * 优先简洁性,处理最常见的场景\n */\nexport async function parseBody(req: Request): Promise<unknown> {\n const contentType = req.headers.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/json\")) {\n return await req.json();\n }\n if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n const text = await req.text();\n return Object.fromEntries(new URLSearchParams(text));\n }\n return await req.text(); // fallback\n}\n\n/**\n * 解析 multipart/form-data 格式\n * 支持文件上传和普通表单字段\n */\nasync function parseMultipartFormData(req: Request): Promise<FormData> {\n const formData = await req.formData();\n const result: FormData = {\n fields: {},\n files: {},\n };\n\n for (const [key, value] of formData.entries()) {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"name\" in value &&\n \"type\" in value &&\n \"size\" in value\n ) {\n // 处理文件\n const file = value as any;\n const arrayBuffer = await file.arrayBuffer();\n result.files[key] = {\n name: file.name,\n type: file.type,\n size: file.size,\n data: arrayBuffer,\n };\n } else {\n // 处理普通字段\n result.fields[key] = value as string;\n }\n }\n\n return result;\n}\n\n/**\n * 解析请求体为特定类型\n * 提供类型安全的解析方法\n */\nexport async function parseBodyAs<T>(req: Request): Promise<T> {\n const body = await parseBody(req);\n return body as T;\n}\n\n/**\n * 解析请求体为表单数据\n * 专门用于处理 multipart/form-data\n */\nexport async function parseFormData(req: Request): Promise<FormData> {\n const contentType = req.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"multipart/form-data\")) {\n throw new Error(\"请求不是 multipart/form-data 格式\");\n }\n\n return await parseMultipartFormData(req);\n}\n\n/**\n * 解析请求体为文件\n * 专门用于处理文件上传\n */\nexport async function parseFile(req: Request): Promise<FileInfo> {\n const contentType = req.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"multipart/form-data\")) {\n throw new Error(\"请求不是 multipart/form-data 格式\");\n }\n\n const formData = await parseMultipartFormData(req);\n const fileKeys = Object.keys(formData.files);\n\n if (fileKeys.length === 0) {\n throw new Error(\"请求中没有文件\");\n }\n\n if (fileKeys.length > 1) {\n throw new Error(\"请求中包含多个文件,请使用 parseFormData\");\n }\n\n return formData.files[fileKeys[0]];\n}\n\n/**\n * 快速提取 query string(避免创建 URL 对象)\n */\nfunction extractQueryString(url: string): string {\n const qIndex = url.indexOf(\"?\");\n if (qIndex === -1) return \"\";\n\n const hashIndex = url.indexOf(\"#\", qIndex);\n return hashIndex === -1\n ? url.substring(qIndex + 1)\n : url.substring(qIndex + 1, hashIndex);\n}\n\n/** 获取查询字符串,直接返回对象 */\nexport function parseQuery(req: Request): Record<string, unknown> {\n const queryString = extractQueryString(req.url);\n if (!queryString) return {};\n return qs.parse(queryString);\n}\n\n/**\n * 快速解析简单查询字符串(不支持嵌套,但更快)\n * 适用于简单的 key=value&key2=value2 场景\n */\nexport function parseQueryFast(req: Request): Record<string, string> {\n const queryString = extractQueryString(req.url);\n if (!queryString) return {};\n\n const result: Record<string, string> = Object.create(null);\n const pairs = queryString.split(\"&\");\n\n for (const pair of pairs) {\n const eqIndex = pair.indexOf(\"=\");\n if (eqIndex === -1) {\n result[decodeURIComponent(pair)] = \"\";\n } else {\n const key = decodeURIComponent(pair.substring(0, eqIndex));\n const value = decodeURIComponent(pair.substring(eqIndex + 1));\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/** 解析请求头,返回对象 */\nexport function parseHeaders(req: Request): Record<string, string> {\n const headers: Record<string, string> = Object.create(null);\n req.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return headers;\n}\n\n/**\n * 获取单个请求头(避免解析全部)\n */\nexport function getHeader(req: Request, name: string): string | null {\n return req.headers.get(name);\n}\n\n/** 使用cookie库解析Cookie,保证可靠性 */\nexport function parseCookies(req: Request): Record<string, string> {\n const cookieHeader = req.headers.get(\"cookie\");\n if (!cookieHeader) return {};\n\n try {\n const parsed = cookie.parse(cookieHeader);\n // 过滤掉undefined和null值\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(parsed)) {\n if (value !== undefined && value !== null) {\n result[key] = value;\n }\n }\n return result;\n } catch {\n return {};\n }\n}\n\n/**\n * 快速解析 Cookie(简化版,不使用外部库)\n * 适用于简单的 cookie 场景\n */\nexport function parseCookiesFast(req: Request): Record<string, string> {\n const cookieHeader = req.headers.get(\"cookie\");\n if (!cookieHeader) return {};\n\n const result: Record<string, string> = Object.create(null);\n const pairs = cookieHeader.split(\";\");\n\n for (const pair of pairs) {\n const trimmed = pair.trim();\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex > 0) {\n const key = trimmed.substring(0, eqIndex).trim();\n const value = trimmed.substring(eqIndex + 1).trim();\n // 移除引号\n result[key] =\n value.startsWith('\"') && value.endsWith('\"')\n ? value.slice(1, -1)\n : value;\n }\n }\n\n return result;\n}\n\n/**\n * 获取单个 Cookie 值(避免解析全部)\n */\nexport function getCookie(req: Request, name: string): string | null {\n const cookieHeader = req.headers.get(\"cookie\");\n if (!cookieHeader) return null;\n\n const prefix = `${name}=`;\n const pairs = cookieHeader.split(\";\");\n\n for (const pair of pairs) {\n const trimmed = pair.trim();\n if (trimmed.startsWith(prefix)) {\n const value = trimmed.substring(prefix.length).trim();\n return value.startsWith('\"') && value.endsWith('\"')\n ? value.slice(1, -1)\n : value;\n }\n }\n\n return null;\n}\n","import { parseCookies } from \"./parsers\";\n\n/** 获取单个 Cookie 值 */\nexport function getCookie(req: Request, key: string): string | null {\n const cookies = parseCookies(req);\n return cookies[key] || null;\n}\n\n/** 生成 Set-Cookie 头 */\nexport function setCookie(\n key: string,\n value: string,\n options: {\n path?: string;\n httpOnly?: boolean;\n maxAge?: number;\n secure?: boolean;\n } = {},\n): string {\n let cookie = `${key}=${encodeURIComponent(value)}`;\n\n if (options.path) cookie += `; Path=${options.path}`;\n if (options.httpOnly) cookie += `; HttpOnly`;\n if (options.secure) cookie += `; Secure`;\n if (options.maxAge) cookie += `; Max-Age=${options.maxAge}`;\n\n return cookie;\n}\n\n// 提供给中间件写入\"局部上下文\"的工具函数\nexport function setLocals<T extends object>(req: Request, extras: T) {\n const target = req as unknown as Record<string, unknown>;\n target.__locals = { ...((target.__locals as object) ?? {}), ...extras };\n}\n\n// 获取中间件注入的局部上下文\nexport function getLocals<T extends object>(req: Request): T {\n const target = req as unknown as Record<string, unknown>;\n return (target.__locals ?? {}) as T;\n}\n","// src/middleware/authMiddleware.ts\nimport type { Middleware } from \"../types\";\nimport { VafastError } from \"../middleware\";\nimport { getCookie } from \"../utils/handle\";\n\nexport const requireAuth: Middleware = async (req, next) => {\n const token = getCookie(req, \"auth\");\n\n if (!token || token !== \"valid-token\") {\n throw new VafastError(\"Unauthorized\", {\n status: 401,\n type: \"unauthorized\",\n expose: true,\n });\n }\n\n return next();\n};\n"],"mappings":";AAQO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YACE,SACA,UAKI,CAAC,GACL;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS,QAAQ,UAAU;AAChC,SAAK,OAAO,QAAQ,QAAQ;AAC5B,SAAK,SAAS,QAAQ,UAAU;AAChC,QAAI,QAAQ,MAAO,CAAC,KAAa,QAAQ,QAAQ;AAAA,EACnD;AACF;;;AC5BA,OAAO,QAAQ;AACf,OAAO,YAAY;AAmLZ,SAAS,aAAa,KAAsC;AACjE,QAAM,eAAe,IAAI,QAAQ,IAAI,QAAQ;AAC7C,MAAI,CAAC,aAAc,QAAO,CAAC;AAE3B,MAAI;AACF,UAAM,SAAS,OAAO,MAAM,YAAY;AAExC,UAAM,SAAiC,CAAC;AACxC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,UAAI,UAAU,UAAa,UAAU,MAAM;AACzC,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;;;ACnMO,SAAS,UAAU,KAAc,KAA4B;AAClE,QAAM,UAAU,aAAa,GAAG;AAChC,SAAO,QAAQ,GAAG,KAAK;AACzB;;;ACDO,IAAM,cAA0B,OAAO,KAAK,SAAS;AAC1D,QAAM,QAAQ,UAAU,KAAK,MAAM;AAEnC,MAAI,CAAC,SAAS,UAAU,eAAe;AACrC,UAAM,IAAI,YAAY,gBAAgB;AAAA,MACpC,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,SAAO,KAAK;AACd;","names":[]}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
// src/middleware/component-renderer.ts
|
|
2
|
-
var renderVueSSR = async (componentImport, req, preloadedDeps) => {
|
|
3
|
-
try {
|
|
4
|
-
const { createSSRApp, renderToString } = preloadedDeps || await Promise.all([import("vue"), import("@vue/server-renderer")]).then(
|
|
5
|
-
([vue, renderer]) => ({
|
|
6
|
-
createSSRApp: vue.createSSRApp,
|
|
7
|
-
renderToString: renderer.renderToString
|
|
8
|
-
})
|
|
9
|
-
);
|
|
10
|
-
const componentModule = await componentImport();
|
|
11
|
-
const component = componentModule.default || componentModule;
|
|
12
|
-
const app = createSSRApp(component);
|
|
13
|
-
app.provide("routeInfo", {
|
|
14
|
-
params: req.params || {},
|
|
15
|
-
query: Object.fromEntries(new URL(req.url).searchParams),
|
|
16
|
-
pathname: new URL(req.url).pathname
|
|
17
|
-
});
|
|
18
|
-
const html = await renderToString(app);
|
|
19
|
-
return new Response(
|
|
20
|
-
`
|
|
21
|
-
<!doctype html>
|
|
22
|
-
<html>
|
|
23
|
-
<head>
|
|
24
|
-
<meta charset="utf-8">
|
|
25
|
-
<title>Vue SSR App</title>
|
|
26
|
-
</head>
|
|
27
|
-
<body>
|
|
28
|
-
<div id="app">${html}</div>
|
|
29
|
-
<script>
|
|
30
|
-
window.__ROUTE_INFO__ = {
|
|
31
|
-
params: ${JSON.stringify(req.params || {})},
|
|
32
|
-
query: ${JSON.stringify(Object.fromEntries(new URL(req.url).searchParams))},
|
|
33
|
-
pathname: '${new URL(req.url).pathname}'
|
|
34
|
-
};
|
|
35
|
-
</script>
|
|
36
|
-
<script type="module" src="/client.js"></script>
|
|
37
|
-
</body>
|
|
38
|
-
</html>
|
|
39
|
-
`,
|
|
40
|
-
{
|
|
41
|
-
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
42
|
-
}
|
|
43
|
-
);
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error("Vue SSR \u6E32\u67D3\u5931\u8D25:", error);
|
|
46
|
-
return new Response(
|
|
47
|
-
`
|
|
48
|
-
<!doctype html>
|
|
49
|
-
<html>
|
|
50
|
-
<head><title>\u6E32\u67D3\u9519\u8BEF</title></head>
|
|
51
|
-
<body>
|
|
52
|
-
<h1>Vue SSR \u6E32\u67D3\u5931\u8D25</h1>
|
|
53
|
-
<p>\u9519\u8BEF\u4FE1\u606F: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}</p>
|
|
54
|
-
</body>
|
|
55
|
-
</html>
|
|
56
|
-
`,
|
|
57
|
-
{ status: 500 }
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
var renderReactSSR = async (componentImport, req, preloadedDeps) => {
|
|
62
|
-
try {
|
|
63
|
-
const { createElement, renderToString } = preloadedDeps || await Promise.all([import("react"), import("react-dom/server")]).then(
|
|
64
|
-
([react, renderer]) => ({
|
|
65
|
-
createElement: react.createElement,
|
|
66
|
-
renderToString: renderer.renderToString
|
|
67
|
-
})
|
|
68
|
-
);
|
|
69
|
-
const componentModule = await componentImport();
|
|
70
|
-
const Component = componentModule.default || componentModule;
|
|
71
|
-
const content = createElement(Component, {
|
|
72
|
-
req,
|
|
73
|
-
params: req.params || {},
|
|
74
|
-
query: Object.fromEntries(new URL(req.url).searchParams)
|
|
75
|
-
});
|
|
76
|
-
const html = renderToString(content);
|
|
77
|
-
return new Response(
|
|
78
|
-
`
|
|
79
|
-
<!doctype html>
|
|
80
|
-
<html>
|
|
81
|
-
<head>
|
|
82
|
-
<meta charset="utf-8">
|
|
83
|
-
<title>React SSR App</title>
|
|
84
|
-
</head>
|
|
85
|
-
<body>
|
|
86
|
-
<div id="root">${html}</div>
|
|
87
|
-
<script>
|
|
88
|
-
window.__ROUTE_INFO__ = {
|
|
89
|
-
params: ${JSON.stringify(req.params || {})},
|
|
90
|
-
query: ${JSON.stringify(Object.fromEntries(new URL(req.url).searchParams))},
|
|
91
|
-
pathname: '${new URL(req.url).pathname}'
|
|
92
|
-
};
|
|
93
|
-
</script>
|
|
94
|
-
<script type="module" src="/client.js"></script>
|
|
95
|
-
</body>
|
|
96
|
-
</html>
|
|
97
|
-
`,
|
|
98
|
-
{
|
|
99
|
-
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
100
|
-
}
|
|
101
|
-
);
|
|
102
|
-
} catch (error) {
|
|
103
|
-
console.error("React SSR \u6E32\u67D3\u5931\u8D25:", error);
|
|
104
|
-
return new Response(
|
|
105
|
-
`
|
|
106
|
-
<!doctype html>
|
|
107
|
-
<html>
|
|
108
|
-
<head><title>\u6E32\u67D3\u9519\u8BEF</title></head>
|
|
109
|
-
<body>
|
|
110
|
-
<h1>React SSR \u6E32\u67D3\u5931\u8D25</h1>
|
|
111
|
-
<p>\u9519\u8BEF\u4FE1\u606F: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}</p>
|
|
112
|
-
</body>
|
|
113
|
-
</html>
|
|
114
|
-
`,
|
|
115
|
-
{ status: 500 }
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
var vueRenderer = (preloadedDeps) => {
|
|
120
|
-
return async (req, next) => {
|
|
121
|
-
req.renderVue = async (componentImport) => {
|
|
122
|
-
return await renderVueSSR(componentImport, req, preloadedDeps);
|
|
123
|
-
};
|
|
124
|
-
return next();
|
|
125
|
-
};
|
|
126
|
-
};
|
|
127
|
-
var reactRenderer = (preloadedDeps) => {
|
|
128
|
-
return async (req, next) => {
|
|
129
|
-
req.renderReact = async (componentImport) => {
|
|
130
|
-
return await renderReactSSR(componentImport, req, preloadedDeps);
|
|
131
|
-
};
|
|
132
|
-
return next();
|
|
133
|
-
};
|
|
134
|
-
};
|
|
135
|
-
export {
|
|
136
|
-
reactRenderer,
|
|
137
|
-
vueRenderer
|
|
138
|
-
};
|
|
139
|
-
//# sourceMappingURL=component-renderer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/middleware/component-renderer.ts"],"sourcesContent":["/**\n * 组件渲染中间件 - 专注 SSR\n * 支持 Vue 和 React 的服务端渲染\n */\n\n// Vue SSR 渲染\nconst renderVueSSR = async (\n componentImport: () => Promise<any>,\n req: Request,\n preloadedDeps?: any,\n) => {\n try {\n // 使用预加载的依赖或动态导入\n const { createSSRApp, renderToString } =\n preloadedDeps ||\n (await Promise.all([import(\"vue\"), import(\"@vue/server-renderer\")]).then(\n ([vue, renderer]) => ({\n createSSRApp: vue.createSSRApp,\n renderToString: renderer.renderToString,\n }),\n ));\n\n const componentModule = await componentImport();\n const component = componentModule.default || componentModule;\n\n const app = createSSRApp(component);\n\n // 提供路由信息\n app.provide(\"routeInfo\", {\n params: (req as any).params || {},\n query: Object.fromEntries(new URL(req.url).searchParams),\n pathname: new URL(req.url).pathname,\n });\n\n const html = await renderToString(app);\n\n return new Response(\n `\n <!doctype html>\n <html>\n <head>\n <meta charset=\"utf-8\">\n <title>Vue SSR App</title>\n </head>\n <body>\n <div id=\"app\">${html}</div>\n <script>\n window.__ROUTE_INFO__ = {\n params: ${JSON.stringify((req as any).params || {})},\n query: ${JSON.stringify(Object.fromEntries(new URL(req.url).searchParams))},\n pathname: '${new URL(req.url).pathname}'\n };\n </script>\n <script type=\"module\" src=\"/client.js\"></script>\n </body>\n </html>\n `,\n {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n },\n );\n } catch (error) {\n console.error(\"Vue SSR 渲染失败:\", error);\n return new Response(\n `\n <!doctype html>\n <html>\n <head><title>渲染错误</title></head>\n <body>\n <h1>Vue SSR 渲染失败</h1>\n <p>错误信息: ${error instanceof Error ? error.message : \"未知错误\"}</p>\n </body>\n </html>\n `,\n { status: 500 },\n );\n }\n};\n\n// React SSR 渲染\nconst renderReactSSR = async (\n componentImport: () => Promise<any>,\n req: Request,\n preloadedDeps?: any,\n) => {\n try {\n // 使用预加载的依赖或动态导入\n const { createElement, renderToString } =\n preloadedDeps ||\n (await Promise.all([import(\"react\"), import(\"react-dom/server\")]).then(\n ([react, renderer]) => ({\n createElement: react.createElement,\n renderToString: renderer.renderToString,\n }),\n ));\n\n const componentModule = await componentImport();\n const Component = componentModule.default || componentModule;\n\n const content = createElement(Component, {\n req,\n params: (req as any).params || {},\n query: Object.fromEntries(new URL(req.url).searchParams),\n });\n\n const html = renderToString(content);\n\n return new Response(\n `\n <!doctype html>\n <html>\n <head>\n <meta charset=\"utf-8\">\n <title>React SSR App</title>\n </head>\n <body>\n <div id=\"root\">${html}</div>\n <script>\n window.__ROUTE_INFO__ = {\n params: ${JSON.stringify((req as any).params || {})},\n query: ${JSON.stringify(Object.fromEntries(new URL(req.url).searchParams))},\n pathname: '${new URL(req.url).pathname}'\n };\n </script>\n <script type=\"module\" src=\"/client.js\"></script>\n </body>\n </html>\n `,\n {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n },\n );\n } catch (error) {\n console.error(\"React SSR 渲染失败:\", error);\n return new Response(\n `\n <!doctype html>\n <html>\n <head><title>渲染错误</title></head>\n <body>\n <h1>React SSR 渲染失败</h1>\n <p>错误信息: ${error instanceof Error ? error.message : \"未知错误\"}</p>\n </body>\n </html>\n `,\n { status: 500 },\n );\n }\n};\n\n// Vue 组件渲染器 - 专注 SSR\nexport const vueRenderer = (preloadedDeps?: any) => {\n return async (req: Request, next: () => Promise<Response>) => {\n (req as any).renderVue = async (componentImport: () => Promise<any>) => {\n return await renderVueSSR(componentImport, req, preloadedDeps);\n };\n return next();\n };\n};\n\n// React 组件渲染器 - 专注 SSR\nexport const reactRenderer = (preloadedDeps?: any) => {\n return async (req: Request, next: () => Promise<Response>) => {\n (req as any).renderReact = async (componentImport: () => Promise<any>) => {\n return await renderReactSSR(componentImport, req, preloadedDeps);\n };\n return next();\n };\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// src/middleware/component-router.ts
|
|
2
|
-
function flattenComponentRoutes(routes) {
|
|
3
|
-
const flattened = [];
|
|
4
|
-
function processRoute(route, parentPath = "", parentMiddleware = []) {
|
|
5
|
-
const currentPath = parentPath + route.path;
|
|
6
|
-
const currentMiddleware = [
|
|
7
|
-
...parentMiddleware,
|
|
8
|
-
...route.middleware || []
|
|
9
|
-
];
|
|
10
|
-
if ("component" in route) {
|
|
11
|
-
flattened.push({
|
|
12
|
-
...route,
|
|
13
|
-
fullPath: currentPath,
|
|
14
|
-
middlewareChain: currentMiddleware
|
|
15
|
-
});
|
|
16
|
-
} else if ("children" in route && route.children) {
|
|
17
|
-
for (const child of route.children) {
|
|
18
|
-
processRoute(child, currentPath, currentMiddleware);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
for (const route of routes) {
|
|
23
|
-
processRoute(route);
|
|
24
|
-
}
|
|
25
|
-
return flattened;
|
|
26
|
-
}
|
|
27
|
-
var componentRouter = () => {
|
|
28
|
-
return async (req, next) => {
|
|
29
|
-
return next();
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
export {
|
|
33
|
-
componentRouter,
|
|
34
|
-
flattenComponentRoutes
|
|
35
|
-
};
|
|
36
|
-
//# sourceMappingURL=component-router.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/middleware/component-router.ts"],"sourcesContent":["import type {\n ComponentRoute,\n NestedComponentRoute,\n FlattenedComponentRoute,\n} from \"../types/component-route\";\nimport { vueRenderer, reactRenderer } from \"./component-renderer\";\n\n/**\n * 扁平化嵌套组件路由\n */\nexport function flattenComponentRoutes(\n routes: (ComponentRoute | NestedComponentRoute)[],\n): FlattenedComponentRoute[] {\n const flattened: FlattenedComponentRoute[] = [];\n\n function processRoute(\n route: ComponentRoute | NestedComponentRoute,\n parentPath: string = \"\",\n parentMiddleware: any[] = [],\n ) {\n const currentPath = parentPath + route.path;\n const currentMiddleware = [\n ...parentMiddleware,\n ...(route.middleware || []),\n ];\n\n if (\"component\" in route) {\n // 这是一个组件路由\n flattened.push({\n ...route,\n fullPath: currentPath,\n middlewareChain: currentMiddleware,\n });\n } else if (\"children\" in route && route.children) {\n // 这是一个嵌套路由\n for (const child of route.children) {\n processRoute(child, currentPath, currentMiddleware);\n }\n }\n }\n\n for (const route of routes) {\n processRoute(route);\n }\n\n return flattened;\n}\n\n/**\n * 组件路由处理器中间件\n * 自动检测组件类型并应用相应的渲染器\n */\nexport const componentRouter = () => {\n return async (req: Request, next: () => Promise<Response>) => {\n // 这里可以添加组件路由的自动处理逻辑\n // 比如自动检测组件类型,应用相应的渲染器\n return next();\n };\n};\n"],"mappings":";AAUO,SAAS,uBACd,QAC2B;AAC3B,QAAM,YAAuC,CAAC;AAE9C,WAAS,aACP,OACA,aAAqB,IACrB,mBAA0B,CAAC,GAC3B;AACA,UAAM,cAAc,aAAa,MAAM;AACvC,UAAM,oBAAoB;AAAA,MACxB,GAAG;AAAA,MACH,GAAI,MAAM,cAAc,CAAC;AAAA,IAC3B;AAEA,QAAI,eAAe,OAAO;AAExB,gBAAU,KAAK;AAAA,QACb,GAAG;AAAA,QACH,UAAU;AAAA,QACV,iBAAiB;AAAA,MACnB,CAAC;AAAA,IACH,WAAW,cAAc,SAAS,MAAM,UAAU;AAEhD,iBAAW,SAAS,MAAM,UAAU;AAClC,qBAAa,OAAO,aAAa,iBAAiB;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAEA,aAAW,SAAS,QAAQ;AAC1B,iBAAa,KAAK;AAAA,EACpB;AAEA,SAAO;AACT;AAMO,IAAM,kBAAkB,MAAM;AACnC,SAAO,OAAO,KAAc,SAAkC;AAG5D,WAAO,KAAK;AAAA,EACd;AACF;","names":[]}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Middleware } from '../types/types.js';
|
|
2
|
-
|
|
3
|
-
interface CORSOptions {
|
|
4
|
-
origin?: string[] | "*";
|
|
5
|
-
methods?: string[];
|
|
6
|
-
headers?: string[];
|
|
7
|
-
credentials?: boolean;
|
|
8
|
-
maxAge?: number;
|
|
9
|
-
}
|
|
10
|
-
declare function createCORS(options?: CORSOptions): Middleware;
|
|
11
|
-
|
|
12
|
-
export { type CORSOptions, createCORS };
|
package/dist/middleware/cors.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// src/middleware/cors.ts
|
|
2
|
-
function createCORS(options = {}) {
|
|
3
|
-
const {
|
|
4
|
-
origin = [],
|
|
5
|
-
methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
6
|
-
headers = [],
|
|
7
|
-
credentials = false,
|
|
8
|
-
maxAge
|
|
9
|
-
} = options;
|
|
10
|
-
return async (req, next) => {
|
|
11
|
-
const reqOrigin = req.headers.get("Origin") || "";
|
|
12
|
-
const isAllowedOrigin = origin === "*" || origin.includes(reqOrigin);
|
|
13
|
-
if (req.method === "OPTIONS") {
|
|
14
|
-
const resHeaders = new Headers();
|
|
15
|
-
if (isAllowedOrigin) {
|
|
16
|
-
resHeaders.set(
|
|
17
|
-
"Access-Control-Allow-Origin",
|
|
18
|
-
origin === "*" ? "*" : reqOrigin
|
|
19
|
-
);
|
|
20
|
-
resHeaders.set("Access-Control-Allow-Methods", methods.join(","));
|
|
21
|
-
resHeaders.set("Access-Control-Allow-Headers", headers.join(","));
|
|
22
|
-
if (credentials)
|
|
23
|
-
resHeaders.set("Access-Control-Allow-Credentials", "true");
|
|
24
|
-
if (maxAge) resHeaders.set("Access-Control-Max-Age", maxAge.toString());
|
|
25
|
-
}
|
|
26
|
-
return new Response(null, { status: 204, headers: resHeaders });
|
|
27
|
-
}
|
|
28
|
-
const res = await next();
|
|
29
|
-
if (isAllowedOrigin) {
|
|
30
|
-
res.headers.set(
|
|
31
|
-
"Access-Control-Allow-Origin",
|
|
32
|
-
origin === "*" ? "*" : reqOrigin
|
|
33
|
-
);
|
|
34
|
-
if (credentials)
|
|
35
|
-
res.headers.set("Access-Control-Allow-Credentials", "true");
|
|
36
|
-
}
|
|
37
|
-
return res;
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
export {
|
|
41
|
-
createCORS
|
|
42
|
-
};
|
|
43
|
-
//# sourceMappingURL=cors.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/middleware/cors.ts"],"sourcesContent":["import type { Middleware } from \"../types\";\n\nexport interface CORSOptions {\n origin?: string[] | \"*\";\n methods?: string[];\n headers?: string[];\n credentials?: boolean;\n maxAge?: number;\n}\n\nexport function createCORS(options: CORSOptions = {}): Middleware {\n const {\n origin = [],\n methods = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"OPTIONS\"],\n headers = [],\n credentials = false,\n maxAge,\n } = options;\n\n return async (req, next) => {\n const reqOrigin = req.headers.get(\"Origin\") || \"\";\n\n // 判断:是否为允许的 Origin?\n const isAllowedOrigin = origin === \"*\" || origin.includes(reqOrigin);\n\n // 预检 (OPTIONS) 请求处理\n if (req.method === \"OPTIONS\") {\n const resHeaders = new Headers();\n\n if (isAllowedOrigin) {\n resHeaders.set(\n \"Access-Control-Allow-Origin\",\n origin === \"*\" ? \"*\" : reqOrigin,\n );\n resHeaders.set(\"Access-Control-Allow-Methods\", methods.join(\",\"));\n resHeaders.set(\"Access-Control-Allow-Headers\", headers.join(\",\"));\n if (credentials)\n resHeaders.set(\"Access-Control-Allow-Credentials\", \"true\");\n if (maxAge) resHeaders.set(\"Access-Control-Max-Age\", maxAge.toString());\n }\n\n return new Response(null, { status: 204, headers: resHeaders });\n }\n\n // 正常请求:在 next 后添加头部\n const res = await next();\n\n if (isAllowedOrigin) {\n res.headers.set(\n \"Access-Control-Allow-Origin\",\n origin === \"*\" ? \"*\" : reqOrigin,\n );\n if (credentials)\n res.headers.set(\"Access-Control-Allow-Credentials\", \"true\");\n }\n\n return res;\n };\n}\n"],"mappings":";AAUO,SAAS,WAAW,UAAuB,CAAC,GAAe;AAChE,QAAM;AAAA,IACJ,SAAS,CAAC;AAAA,IACV,UAAU,CAAC,OAAO,QAAQ,OAAO,UAAU,SAAS;AAAA,IACpD,UAAU,CAAC;AAAA,IACX,cAAc;AAAA,IACd;AAAA,EACF,IAAI;AAEJ,SAAO,OAAO,KAAK,SAAS;AAC1B,UAAM,YAAY,IAAI,QAAQ,IAAI,QAAQ,KAAK;AAG/C,UAAM,kBAAkB,WAAW,OAAO,OAAO,SAAS,SAAS;AAGnE,QAAI,IAAI,WAAW,WAAW;AAC5B,YAAM,aAAa,IAAI,QAAQ;AAE/B,UAAI,iBAAiB;AACnB,mBAAW;AAAA,UACT;AAAA,UACA,WAAW,MAAM,MAAM;AAAA,QACzB;AACA,mBAAW,IAAI,gCAAgC,QAAQ,KAAK,GAAG,CAAC;AAChE,mBAAW,IAAI,gCAAgC,QAAQ,KAAK,GAAG,CAAC;AAChE,YAAI;AACF,qBAAW,IAAI,oCAAoC,MAAM;AAC3D,YAAI,OAAQ,YAAW,IAAI,0BAA0B,OAAO,SAAS,CAAC;AAAA,MACxE;AAEA,aAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,KAAK,SAAS,WAAW,CAAC;AAAA,IAChE;AAGA,UAAM,MAAM,MAAM,KAAK;AAEvB,QAAI,iBAAiB;AACnB,UAAI,QAAQ;AAAA,QACV;AAAA,QACA,WAAW,MAAM,MAAM;AAAA,MACzB;AACA,UAAI;AACF,YAAI,QAAQ,IAAI,oCAAoC,MAAM;AAAA,IAC9D;AAEA,WAAO;AAAA,EACT;AACF;","names":[]}
|