@suveren/gateway 0.6.4 → 0.6.7
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/bin/suveren-gateway.js +19 -2
- package/content/integrations/deploy-github.json +2 -2
- package/dist/mcp-server/http.mjs +6 -1
- package/lib/autostart-templates.d.mts +2 -0
- package/lib/autostart-templates.mjs +16 -3
- package/node_modules/@hono/node-server/README.md +47 -1
- package/node_modules/@hono/node-server/dist/early-hints.cjs +35 -0
- package/node_modules/@hono/node-server/dist/early-hints.d.cts +16 -0
- package/node_modules/@hono/node-server/dist/early-hints.d.mts +16 -0
- package/node_modules/@hono/node-server/dist/early-hints.mjs +33 -0
- package/node_modules/@hono/node-server/dist/index.cjs +4 -1
- package/node_modules/@hono/node-server/dist/index.mjs +4 -1
- package/node_modules/@hono/node-server/package.json +14 -1
- package/node_modules/express-rate-limit/dist/index.cjs +6 -1
- package/node_modules/express-rate-limit/dist/index.mjs +6 -1
- package/node_modules/express-rate-limit/package.json +6 -6
- package/node_modules/hono/dist/cjs/context.js +28 -13
- package/node_modules/hono/dist/cjs/hono-base.js +3 -2
- package/node_modules/hono/dist/cjs/jsx/base.js +26 -14
- package/node_modules/hono/dist/cjs/jsx/hooks/index.js +2 -2
- package/node_modules/hono/dist/cjs/middleware/cache/index.js +103 -8
- package/node_modules/hono/dist/cjs/middleware/compress/index.js +5 -0
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/etag/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/jwk/jwk.js +9 -4
- package/node_modules/hono/dist/cjs/middleware/jwt/jwt.js +9 -4
- package/node_modules/hono/dist/cjs/middleware/method-not-allowed/index.js +90 -0
- package/node_modules/hono/dist/cjs/request.js +6 -8
- package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +55 -56
- package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +64 -85
- package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +13 -5
- package/node_modules/hono/dist/cjs/router.js +1 -1
- package/node_modules/hono/dist/cjs/utils/cookie.js +1 -1
- package/node_modules/hono/dist/cjs/utils/url.js +7 -7
- package/node_modules/hono/dist/context.js +28 -13
- package/node_modules/hono/dist/hono-base.js +3 -2
- package/node_modules/hono/dist/jsx/base.js +26 -14
- package/node_modules/hono/dist/jsx/hooks/index.js +2 -2
- package/node_modules/hono/dist/middleware/cache/index.js +103 -8
- package/node_modules/hono/dist/middleware/compress/index.js +5 -0
- package/node_modules/hono/dist/middleware/cors/index.js +1 -1
- package/node_modules/hono/dist/middleware/etag/index.js +1 -1
- package/node_modules/hono/dist/middleware/jwk/jwk.js +9 -4
- package/node_modules/hono/dist/middleware/jwt/jwt.js +9 -4
- package/node_modules/hono/dist/middleware/method-not-allowed/index.js +68 -0
- package/node_modules/hono/dist/request.js +7 -9
- package/node_modules/hono/dist/router/reg-exp-router/node.js +55 -56
- package/node_modules/hono/dist/router/reg-exp-router/router.js +64 -85
- package/node_modules/hono/dist/router/reg-exp-router/trie.js +13 -5
- package/node_modules/hono/dist/router.js +1 -1
- package/node_modules/hono/dist/types/client/types.d.ts +1 -1
- package/node_modules/hono/dist/types/hono-base.d.ts +4 -3
- package/node_modules/hono/dist/types/jsx/base.d.ts +4 -2
- package/node_modules/hono/dist/types/jsx/dom/index.d.ts +5 -5
- package/node_modules/hono/dist/types/jsx/dom/intrinsic-element/components.d.ts +2 -2
- package/node_modules/hono/dist/types/jsx/dom/server.d.ts +5 -5
- package/node_modules/hono/dist/types/jsx/hooks/index.d.ts +8 -6
- package/node_modules/hono/dist/types/jsx/index.d.ts +5 -5
- package/node_modules/hono/dist/types/middleware/cache/index.d.ts +6 -4
- package/node_modules/hono/dist/types/middleware/cors/index.d.ts +1 -1
- package/node_modules/hono/dist/types/middleware/jsx-renderer/index.d.ts +2 -2
- package/node_modules/hono/dist/types/middleware/jwk/jwk.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/jwt/jwt.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/method-not-allowed/index.d.ts +49 -0
- package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +1 -1
- package/node_modules/hono/dist/types/router/reg-exp-router/trie.d.ts +2 -1
- package/node_modules/hono/dist/types/router.d.ts +1 -1
- package/node_modules/hono/dist/types/utils/headers.d.ts +2 -2
- package/node_modules/hono/dist/types/utils/url.d.ts +1 -0
- package/node_modules/hono/dist/utils/cookie.js +2 -2
- package/node_modules/hono/dist/utils/url.js +5 -6
- package/node_modules/hono/package.json +9 -1
- package/package.json +1 -1
- package/profiles/deploy/0.8.profile.json +170 -0
- package/profiles/index.json +2 -1
|
@@ -48,7 +48,7 @@ var etag = (options) => {
|
|
|
48
48
|
}
|
|
49
49
|
etag3 = weak ? `W/"${hash}"` : `"${hash}"`;
|
|
50
50
|
}
|
|
51
|
-
const matched = ifNoneMatch === "*" ? (c.req.method === "GET" || c.req.method === "HEAD") && res.ok : etagMatches(etag3, ifNoneMatch);
|
|
51
|
+
const matched = ifNoneMatch === "*" ? (c.req.method === "GET" || c.req.method === "HEAD" || c.req.method === "QUERY") && res.ok : etagMatches(etag3, ifNoneMatch);
|
|
52
52
|
if (matched) {
|
|
53
53
|
c.res = new Response(null, {
|
|
54
54
|
status: 304,
|
|
@@ -24,7 +24,8 @@ var jwk = (options, init) => {
|
|
|
24
24
|
res: unauthorizedResponse({
|
|
25
25
|
ctx,
|
|
26
26
|
error: "invalid_request",
|
|
27
|
-
errDescription
|
|
27
|
+
errDescription,
|
|
28
|
+
realm: options.realm
|
|
28
29
|
})
|
|
29
30
|
});
|
|
30
31
|
} else {
|
|
@@ -62,7 +63,8 @@ var jwk = (options, init) => {
|
|
|
62
63
|
res: unauthorizedResponse({
|
|
63
64
|
ctx,
|
|
64
65
|
error: "invalid_request",
|
|
65
|
-
errDescription
|
|
66
|
+
errDescription,
|
|
67
|
+
realm: options.realm
|
|
66
68
|
})
|
|
67
69
|
});
|
|
68
70
|
}
|
|
@@ -89,7 +91,8 @@ var jwk = (options, init) => {
|
|
|
89
91
|
ctx,
|
|
90
92
|
error: "invalid_token",
|
|
91
93
|
statusText: "Unauthorized",
|
|
92
|
-
errDescription: "token verification failure"
|
|
94
|
+
errDescription: "token verification failure",
|
|
95
|
+
realm: options.realm
|
|
93
96
|
}),
|
|
94
97
|
cause
|
|
95
98
|
});
|
|
@@ -99,11 +102,13 @@ var jwk = (options, init) => {
|
|
|
99
102
|
};
|
|
100
103
|
};
|
|
101
104
|
function unauthorizedResponse(opts) {
|
|
105
|
+
const realm = (opts.realm ?? opts.ctx.req.url).replace(/"/g, '\\"');
|
|
106
|
+
const errDescription = opts.errDescription.replace(/"/g, '\\"');
|
|
102
107
|
return new Response("Unauthorized", {
|
|
103
108
|
status: 401,
|
|
104
109
|
statusText: opts.statusText,
|
|
105
110
|
headers: {
|
|
106
|
-
"WWW-Authenticate": `Bearer realm="${
|
|
111
|
+
"WWW-Authenticate": `Bearer realm="${realm}",error="${opts.error}",error_description="${errDescription}"`
|
|
107
112
|
}
|
|
108
113
|
});
|
|
109
114
|
}
|
|
@@ -27,7 +27,8 @@ var jwt = (options) => {
|
|
|
27
27
|
res: unauthorizedResponse({
|
|
28
28
|
ctx,
|
|
29
29
|
error: "invalid_request",
|
|
30
|
-
errDescription
|
|
30
|
+
errDescription,
|
|
31
|
+
realm: options.realm
|
|
31
32
|
})
|
|
32
33
|
});
|
|
33
34
|
} else {
|
|
@@ -62,7 +63,8 @@ var jwt = (options) => {
|
|
|
62
63
|
res: unauthorizedResponse({
|
|
63
64
|
ctx,
|
|
64
65
|
error: "invalid_request",
|
|
65
|
-
errDescription
|
|
66
|
+
errDescription,
|
|
67
|
+
realm: options.realm
|
|
66
68
|
})
|
|
67
69
|
});
|
|
68
70
|
}
|
|
@@ -83,7 +85,8 @@ var jwt = (options) => {
|
|
|
83
85
|
ctx,
|
|
84
86
|
error: "invalid_token",
|
|
85
87
|
statusText: "Unauthorized",
|
|
86
|
-
errDescription: "token verification failure"
|
|
88
|
+
errDescription: "token verification failure",
|
|
89
|
+
realm: options.realm
|
|
87
90
|
}),
|
|
88
91
|
cause
|
|
89
92
|
});
|
|
@@ -93,11 +96,13 @@ var jwt = (options) => {
|
|
|
93
96
|
};
|
|
94
97
|
};
|
|
95
98
|
function unauthorizedResponse(opts) {
|
|
99
|
+
const realm = (opts.realm ?? opts.ctx.req.url).replace(/"/g, '\\"');
|
|
100
|
+
const errDescription = opts.errDescription.replace(/"/g, '\\"');
|
|
96
101
|
return new Response("Unauthorized", {
|
|
97
102
|
status: 401,
|
|
98
103
|
statusText: opts.statusText,
|
|
99
104
|
headers: {
|
|
100
|
-
"WWW-Authenticate": `Bearer realm="${
|
|
105
|
+
"WWW-Authenticate": `Bearer realm="${realm}",error="${opts.error}",error_description="${errDescription}"`
|
|
101
106
|
}
|
|
102
107
|
});
|
|
103
108
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/middleware/method-not-allowed/index.ts
|
|
2
|
+
import { basePath, matchedRoutes } from "../../helper/route/index.js";
|
|
3
|
+
import { METHOD_NAME_ALL } from "../../router.js";
|
|
4
|
+
import { TrieRouter } from "../../router/trie-router/index.js";
|
|
5
|
+
var methodNotAllowed = (options) => {
|
|
6
|
+
let methodRouter;
|
|
7
|
+
return async function methodNotAllowed2(c, next) {
|
|
8
|
+
const routeIndex = c.req.routeIndex;
|
|
9
|
+
await next();
|
|
10
|
+
if (c.res.status !== 404) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (c.error) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!methodRouter) {
|
|
17
|
+
const methodsByPath = /* @__PURE__ */ new Map();
|
|
18
|
+
for (const route of options.app.routes) {
|
|
19
|
+
if (route.method === METHOD_NAME_ALL || route.method === "HEAD") {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const methods2 = methodsByPath.get(route.path) ?? /* @__PURE__ */ new Set();
|
|
23
|
+
methods2.add(route.method);
|
|
24
|
+
if (route.method === "GET") {
|
|
25
|
+
methods2.add("HEAD");
|
|
26
|
+
}
|
|
27
|
+
methodsByPath.set(route.path, methods2);
|
|
28
|
+
}
|
|
29
|
+
methodRouter = new TrieRouter();
|
|
30
|
+
for (const [path, methods2] of methodsByPath) {
|
|
31
|
+
methodRouter.add(METHOD_NAME_ALL, path, [...methods2]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
let requestPath = c.req.path;
|
|
35
|
+
const routes = matchedRoutes(c);
|
|
36
|
+
const currentRoute = routes[routeIndex];
|
|
37
|
+
const sourceRoute = options.app.routes.find((route) => route.handler === methodNotAllowed2);
|
|
38
|
+
if (currentRoute && sourceRoute) {
|
|
39
|
+
const currentBasePathParts = basePath(c, routeIndex).split("/").filter(Boolean);
|
|
40
|
+
const sourceBasePathLength = sourceRoute.basePath.split("/").filter(Boolean).length;
|
|
41
|
+
const mountBasePathParts = currentBasePathParts.slice(
|
|
42
|
+
0,
|
|
43
|
+
currentBasePathParts.length - sourceBasePathLength
|
|
44
|
+
);
|
|
45
|
+
if (mountBasePathParts.length > 0) {
|
|
46
|
+
const mountBasePath = `/${mountBasePathParts.join("/")}`;
|
|
47
|
+
requestPath = c.req.path.slice(mountBasePath.length) || "/";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const allowedMethods = /* @__PURE__ */ new Set();
|
|
51
|
+
for (const [methods2] of methodRouter.match(METHOD_NAME_ALL, requestPath)[0]) {
|
|
52
|
+
for (const method of methods2) {
|
|
53
|
+
allowedMethods.add(method);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (allowedMethods.size === 0 || allowedMethods.has(c.req.method)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
c.res.headers.delete("Allow");
|
|
60
|
+
c.res.headers.delete("Content-Length");
|
|
61
|
+
const methods = [...allowedMethods];
|
|
62
|
+
const allow = methods.join(", ");
|
|
63
|
+
c.res = options.onMethodNotAllowed ? await options.onMethodNotAllowed(c, methods) : c.text("Method Not Allowed", 405, { Allow: allow });
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
export {
|
|
67
|
+
methodNotAllowed
|
|
68
|
+
};
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
import { HTTPException } from "./http-exception.js";
|
|
3
3
|
import { GET_MATCH_RESULT } from "./request/constants.js";
|
|
4
4
|
import { parseBody } from "./utils/body.js";
|
|
5
|
-
import {
|
|
6
|
-
var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
|
|
5
|
+
import { getQueryParam, getQueryParams, tryDecodeURIComponent } from "./utils/url.js";
|
|
7
6
|
var HonoRequest = class {
|
|
8
7
|
/**
|
|
9
8
|
* `.raw` can get the raw Request object.
|
|
@@ -42,7 +41,6 @@ var HonoRequest = class {
|
|
|
42
41
|
this.raw = request;
|
|
43
42
|
this.path = path;
|
|
44
43
|
this.#matchResult = matchResult;
|
|
45
|
-
this.#validatedData = {};
|
|
46
44
|
}
|
|
47
45
|
param(key) {
|
|
48
46
|
return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
|
|
@@ -50,7 +48,7 @@ var HonoRequest = class {
|
|
|
50
48
|
#getDecodedParam(key) {
|
|
51
49
|
const paramKey = this.#matchResult[0][this.routeIndex][1][key];
|
|
52
50
|
const param = this.#getParamValue(paramKey);
|
|
53
|
-
return param &&
|
|
51
|
+
return param && tryDecodeURIComponent(param);
|
|
54
52
|
}
|
|
55
53
|
#getAllDecodedParams() {
|
|
56
54
|
const decoded = {};
|
|
@@ -58,7 +56,7 @@ var HonoRequest = class {
|
|
|
58
56
|
for (const key of keys) {
|
|
59
57
|
const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
|
|
60
58
|
if (value !== void 0) {
|
|
61
|
-
decoded[key] =
|
|
59
|
+
decoded[key] = tryDecodeURIComponent(value);
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
return decoded;
|
|
@@ -91,8 +89,7 @@ var HonoRequest = class {
|
|
|
91
89
|
if (cachedBody) {
|
|
92
90
|
return cachedBody;
|
|
93
91
|
}
|
|
94
|
-
const anyCachedKey
|
|
95
|
-
if (anyCachedKey) {
|
|
92
|
+
for (const anyCachedKey in bodyCache) {
|
|
96
93
|
return bodyCache[anyCachedKey].then((body) => {
|
|
97
94
|
if (anyCachedKey === "json") {
|
|
98
95
|
body = JSON.stringify(body);
|
|
@@ -195,10 +192,11 @@ var HonoRequest = class {
|
|
|
195
192
|
* @param data - The validated data to add.
|
|
196
193
|
*/
|
|
197
194
|
addValidatedData(target, data) {
|
|
198
|
-
|
|
195
|
+
;
|
|
196
|
+
(this.#validatedData ??= {})[target] = data;
|
|
199
197
|
}
|
|
200
198
|
valid(target) {
|
|
201
|
-
return this.#validatedData[target];
|
|
199
|
+
return this.#validatedData?.[target];
|
|
202
200
|
}
|
|
203
201
|
/**
|
|
204
202
|
* `.url()` can get the request url strings.
|
|
@@ -12,7 +12,7 @@ function compareKey(a, b) {
|
|
|
12
12
|
return 1;
|
|
13
13
|
}
|
|
14
14
|
if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) {
|
|
15
|
-
return 1;
|
|
15
|
+
return b === TAIL_WILDCARD_REG_EXP_STR ? -1 : 1;
|
|
16
16
|
} else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) {
|
|
17
17
|
return -1;
|
|
18
18
|
}
|
|
@@ -24,76 +24,75 @@ function compareKey(a, b) {
|
|
|
24
24
|
return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
|
|
25
25
|
}
|
|
26
26
|
var Node = class _Node {
|
|
27
|
+
// handler index of a dynamic path, or -1 for a static path terminal
|
|
27
28
|
#index;
|
|
28
29
|
#varIndex;
|
|
29
30
|
#children = /* @__PURE__ */ Object.create(null);
|
|
30
|
-
insert(tokens, index, paramMap, context,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
|
|
52
|
-
if (/\((?!\?:)/.test(regexpStr)) {
|
|
53
|
-
throw PATH_ERROR;
|
|
31
|
+
insert(tokens, index, paramMap, context, isStatic) {
|
|
32
|
+
let node = this;
|
|
33
|
+
for (let i = 0, len = tokens.length; i < len; i++) {
|
|
34
|
+
const token = tokens[i];
|
|
35
|
+
const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : null : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
36
|
+
let nextNode;
|
|
37
|
+
if (pattern) {
|
|
38
|
+
const name = pattern[1];
|
|
39
|
+
let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
|
|
40
|
+
if (name && pattern[2]) {
|
|
41
|
+
if (regexpStr === ".*") {
|
|
42
|
+
throw PATH_ERROR;
|
|
43
|
+
}
|
|
44
|
+
regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
|
|
45
|
+
if (/\((?!\?:)/.test(regexpStr)) {
|
|
46
|
+
throw PATH_ERROR;
|
|
47
|
+
}
|
|
48
|
+
if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) {
|
|
49
|
+
throw PATH_ERROR;
|
|
50
|
+
}
|
|
54
51
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
nextNode = node.#children[regexpStr];
|
|
53
|
+
if (!nextNode) {
|
|
54
|
+
if (regexpStr !== ONLY_WILDCARD_REG_EXP_STR && regexpStr !== TAIL_WILDCARD_REG_EXP_STR) {
|
|
55
|
+
for (const k in node.#children) {
|
|
56
|
+
if (
|
|
57
|
+
// a single-char pattern coexists with single-char literals as a literal does
|
|
58
|
+
(regexpStr.length > 1 || k.length > 1) && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
|
59
|
+
) {
|
|
60
|
+
throw PATH_ERROR;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
nextNode = node.#children[regexpStr] = new _Node();
|
|
62
65
|
}
|
|
63
|
-
if (pathErrorCheckOnly) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
node = this.#children[regexpStr] = new _Node();
|
|
67
66
|
if (name !== "") {
|
|
68
|
-
|
|
67
|
+
nextNode.#varIndex ??= context.varIndex++;
|
|
68
|
+
paramMap.push([name, nextNode.#varIndex]);
|
|
69
69
|
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
)) {
|
|
80
|
-
throw PATH_ERROR;
|
|
70
|
+
} else {
|
|
71
|
+
nextNode = node.#children[token];
|
|
72
|
+
if (!nextNode) {
|
|
73
|
+
for (const k in node.#children) {
|
|
74
|
+
if (k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR) {
|
|
75
|
+
throw PATH_ERROR;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
nextNode = node.#children[token] = new _Node();
|
|
81
79
|
}
|
|
82
|
-
if (pathErrorCheckOnly) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
node = this.#children[token] = new _Node();
|
|
86
80
|
}
|
|
81
|
+
node = nextNode;
|
|
82
|
+
}
|
|
83
|
+
if (node.#index !== void 0) {
|
|
84
|
+
throw PATH_ERROR;
|
|
87
85
|
}
|
|
88
|
-
node
|
|
86
|
+
node.#index = isStatic ? -1 : index;
|
|
89
87
|
}
|
|
90
88
|
buildRegExpStr() {
|
|
91
89
|
const childKeys = Object.keys(this.#children).sort(compareKey);
|
|
92
90
|
const strList = childKeys.map((k) => {
|
|
93
91
|
const c = this.#children[k];
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
const childStr = c.buildRegExpStr();
|
|
93
|
+
return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + childStr;
|
|
94
|
+
}).filter(Boolean);
|
|
95
|
+
if (typeof this.#index === "number" && this.#index !== -1) {
|
|
97
96
|
strList.unshift(`#${this.#index}`);
|
|
98
97
|
}
|
|
99
98
|
if (strList.length === 0) {
|
|
@@ -8,7 +8,6 @@ import { checkOptionalParameter } from "../../utils/url.js";
|
|
|
8
8
|
import { match, emptyParam } from "./matcher.js";
|
|
9
9
|
import { PATH_ERROR } from "./node.js";
|
|
10
10
|
import { Trie } from "./trie.js";
|
|
11
|
-
var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
|
|
12
11
|
var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
13
12
|
function buildWildcardRegExp(path) {
|
|
14
13
|
return wildcardRegExpCache[path] ??= new RegExp(
|
|
@@ -21,63 +20,6 @@ function buildWildcardRegExp(path) {
|
|
|
21
20
|
function clearWildcardRegExpCache() {
|
|
22
21
|
wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
23
22
|
}
|
|
24
|
-
function buildMatcherFromPreprocessedRoutes(routes) {
|
|
25
|
-
const trie = new Trie();
|
|
26
|
-
const handlerData = [];
|
|
27
|
-
if (routes.length === 0) {
|
|
28
|
-
return nullMatcher;
|
|
29
|
-
}
|
|
30
|
-
const routesWithStaticPathFlag = routes.map(
|
|
31
|
-
(route) => [!/\*|\/:/.test(route[0]), ...route]
|
|
32
|
-
).sort(
|
|
33
|
-
([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
|
|
34
|
-
);
|
|
35
|
-
const staticMap = /* @__PURE__ */ Object.create(null);
|
|
36
|
-
for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
|
|
37
|
-
const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i];
|
|
38
|
-
if (pathErrorCheckOnly) {
|
|
39
|
-
staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
|
|
40
|
-
} else {
|
|
41
|
-
j++;
|
|
42
|
-
}
|
|
43
|
-
let paramAssoc;
|
|
44
|
-
try {
|
|
45
|
-
paramAssoc = trie.insert(path, j, pathErrorCheckOnly);
|
|
46
|
-
} catch (e) {
|
|
47
|
-
throw e === PATH_ERROR ? new UnsupportedPathError(path) : e;
|
|
48
|
-
}
|
|
49
|
-
if (pathErrorCheckOnly) {
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
handlerData[j] = handlers.map(([h, paramCount]) => {
|
|
53
|
-
const paramIndexMap = /* @__PURE__ */ Object.create(null);
|
|
54
|
-
paramCount -= 1;
|
|
55
|
-
for (; paramCount >= 0; paramCount--) {
|
|
56
|
-
const [key, value] = paramAssoc[paramCount];
|
|
57
|
-
paramIndexMap[key] = value;
|
|
58
|
-
}
|
|
59
|
-
return [h, paramIndexMap];
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
|
|
63
|
-
for (let i = 0, len = handlerData.length; i < len; i++) {
|
|
64
|
-
for (let j = 0, len2 = handlerData[i].length; j < len2; j++) {
|
|
65
|
-
const map = handlerData[i][j]?.[1];
|
|
66
|
-
if (!map) {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const keys = Object.keys(map);
|
|
70
|
-
for (let k = 0, len3 = keys.length; k < len3; k++) {
|
|
71
|
-
map[keys[k]] = paramReplacementMap[map[keys[k]]];
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const handlerMap = [];
|
|
76
|
-
for (const i in indexReplacementMap) {
|
|
77
|
-
handlerMap[i] = handlerData[indexReplacementMap[i]];
|
|
78
|
-
}
|
|
79
|
-
return [regexp, handlerMap, staticMap];
|
|
80
|
-
}
|
|
81
23
|
function findMiddleware(middleware, path) {
|
|
82
24
|
if (!middleware) {
|
|
83
25
|
return void 0;
|
|
@@ -93,9 +35,18 @@ var RegExpRouter = class {
|
|
|
93
35
|
name = "RegExpRouter";
|
|
94
36
|
#middleware;
|
|
95
37
|
#routes;
|
|
38
|
+
#tries;
|
|
96
39
|
constructor() {
|
|
97
40
|
this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
98
41
|
this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
42
|
+
this.#tries = { [METHOD_NAME_ALL]: new Trie() };
|
|
43
|
+
}
|
|
44
|
+
#insertPath(method, path) {
|
|
45
|
+
try {
|
|
46
|
+
this.#tries[method].insert(path, !/\*|\/:/.test(path));
|
|
47
|
+
} catch (e) {
|
|
48
|
+
throw e === PATH_ERROR ? new UnsupportedPathError(path) : e;
|
|
49
|
+
}
|
|
99
50
|
}
|
|
100
51
|
add(method, path, handler) {
|
|
101
52
|
const middleware = this.#middleware;
|
|
@@ -104,11 +55,12 @@ var RegExpRouter = class {
|
|
|
104
55
|
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
105
56
|
}
|
|
106
57
|
if (!middleware[method]) {
|
|
107
|
-
;
|
|
58
|
+
this.#tries[method] = new Trie();
|
|
108
59
|
[middleware, routes].forEach((handlerMap) => {
|
|
109
60
|
handlerMap[method] = /* @__PURE__ */ Object.create(null);
|
|
110
61
|
Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => {
|
|
111
62
|
handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]];
|
|
63
|
+
this.#insertPath(method, p);
|
|
112
64
|
});
|
|
113
65
|
});
|
|
114
66
|
}
|
|
@@ -118,13 +70,12 @@ var RegExpRouter = class {
|
|
|
118
70
|
const paramCount = (path.match(/\/:/g) || []).length;
|
|
119
71
|
if (/\*$/.test(path)) {
|
|
120
72
|
const re = buildWildcardRegExp(path);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
73
|
+
Object.keys(middleware).forEach((m) => {
|
|
74
|
+
if ((method === METHOD_NAME_ALL || method === m) && !middleware[m][path]) {
|
|
75
|
+
this.#insertPath(m, path);
|
|
76
|
+
middleware[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || [];
|
|
77
|
+
}
|
|
78
|
+
});
|
|
128
79
|
Object.keys(middleware).forEach((m) => {
|
|
129
80
|
if (method === METHOD_NAME_ALL || method === m) {
|
|
130
81
|
Object.keys(middleware[m]).forEach((p) => {
|
|
@@ -146,9 +97,12 @@ var RegExpRouter = class {
|
|
|
146
97
|
const path2 = paths[i];
|
|
147
98
|
Object.keys(routes).forEach((m) => {
|
|
148
99
|
if (method === METHOD_NAME_ALL || method === m) {
|
|
149
|
-
routes[m][path2]
|
|
150
|
-
|
|
151
|
-
|
|
100
|
+
if (!routes[m][path2]) {
|
|
101
|
+
this.#insertPath(m, path2);
|
|
102
|
+
routes[m][path2] = [
|
|
103
|
+
...findMiddleware(middleware[m], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || []
|
|
104
|
+
];
|
|
105
|
+
}
|
|
152
106
|
routes[m][path2].push([handler, paramCount - len + i + 1]);
|
|
153
107
|
}
|
|
154
108
|
});
|
|
@@ -160,29 +114,54 @@ var RegExpRouter = class {
|
|
|
160
114
|
Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
|
|
161
115
|
matchers[method] ||= this.#buildMatcher(method);
|
|
162
116
|
});
|
|
163
|
-
this.#middleware = this.#routes = void 0;
|
|
117
|
+
this.#middleware = this.#routes = this.#tries = void 0;
|
|
164
118
|
clearWildcardRegExpCache();
|
|
165
119
|
return matchers;
|
|
166
120
|
}
|
|
167
121
|
#buildMatcher(method) {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
122
|
+
const middleware = this.#middleware[method];
|
|
123
|
+
const routes = this.#routes[method];
|
|
124
|
+
const trie = this.#tries[method];
|
|
125
|
+
const staticMap = /* @__PURE__ */ Object.create(null);
|
|
126
|
+
const handlerData = [];
|
|
127
|
+
[middleware, routes].forEach((r) => {
|
|
128
|
+
for (const path in r) {
|
|
129
|
+
const handlers = r[path];
|
|
130
|
+
const pathData = trie.paths[path];
|
|
131
|
+
if (!pathData) {
|
|
132
|
+
staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const paramAssoc = pathData[1];
|
|
136
|
+
handlerData[pathData[0]] = handlers.map(([h, paramCount]) => {
|
|
137
|
+
const paramIndexMap = /* @__PURE__ */ Object.create(null);
|
|
138
|
+
paramCount -= 1;
|
|
139
|
+
for (; paramCount >= 0; paramCount--) {
|
|
140
|
+
const [key, value] = paramAssoc[paramCount];
|
|
141
|
+
paramIndexMap[key] = value;
|
|
142
|
+
}
|
|
143
|
+
return [h, paramIndexMap];
|
|
144
|
+
});
|
|
179
145
|
}
|
|
180
146
|
});
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
147
|
+
const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
|
|
148
|
+
for (let i = 0, len = handlerData.length; i < len; i++) {
|
|
149
|
+
for (let j = 0, len2 = handlerData[i].length; j < len2; j++) {
|
|
150
|
+
const map = handlerData[i][j]?.[1];
|
|
151
|
+
if (!map) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const keys = Object.keys(map);
|
|
155
|
+
for (let k = 0, len3 = keys.length; k < len3; k++) {
|
|
156
|
+
map[keys[k]] = paramReplacementMap[map[keys[k]]];
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const handlerMap = [];
|
|
161
|
+
for (const i in indexReplacementMap) {
|
|
162
|
+
handlerMap[i] = handlerData[indexReplacementMap[i]];
|
|
185
163
|
}
|
|
164
|
+
return [regexp, handlerMap, staticMap];
|
|
186
165
|
}
|
|
187
166
|
};
|
|
188
167
|
export {
|
|
@@ -3,12 +3,20 @@ import { Node } from "./node.js";
|
|
|
3
3
|
var Trie = class {
|
|
4
4
|
#context = { varIndex: 0 };
|
|
5
5
|
#root = new Node();
|
|
6
|
-
|
|
6
|
+
#index = 0;
|
|
7
|
+
// dynamic path -> [handler index, param assoc]; static paths are not registered
|
|
8
|
+
paths = /* @__PURE__ */ Object.create(null);
|
|
9
|
+
insert(path, isStatic) {
|
|
10
|
+
if (isStatic) {
|
|
11
|
+
this.#root.insert(path.split(""), 0, [], this.#context, true);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
7
14
|
const paramAssoc = [];
|
|
8
15
|
const groups = [];
|
|
16
|
+
let markedPath = path;
|
|
9
17
|
for (let i = 0; ; ) {
|
|
10
18
|
let replaced = false;
|
|
11
|
-
|
|
19
|
+
markedPath = markedPath.replace(/\{[^}]+\}/g, (m) => {
|
|
12
20
|
const mark = `@\\${i}`;
|
|
13
21
|
groups[i] = [mark, m];
|
|
14
22
|
i++;
|
|
@@ -19,7 +27,7 @@ var Trie = class {
|
|
|
19
27
|
break;
|
|
20
28
|
}
|
|
21
29
|
}
|
|
22
|
-
const tokens =
|
|
30
|
+
const tokens = markedPath.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
|
|
23
31
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
24
32
|
const [mark] = groups[i];
|
|
25
33
|
for (let j = tokens.length - 1; j >= 0; j--) {
|
|
@@ -29,8 +37,8 @@ var Trie = class {
|
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
}
|
|
32
|
-
this.#root.insert(tokens, index, paramAssoc, this.#context,
|
|
33
|
-
|
|
40
|
+
this.#root.insert(tokens, this.#index, paramAssoc, this.#context, false);
|
|
41
|
+
this.paths[path] = [this.#index++, paramAssoc];
|
|
34
42
|
}
|
|
35
43
|
buildRegExp() {
|
|
36
44
|
let regexp = this.#root.buildRegExpStr();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/router.ts
|
|
2
2
|
var METHOD_NAME_ALL = "ALL";
|
|
3
3
|
var METHOD_NAME_ALL_LOWERCASE = "all";
|
|
4
|
-
var METHODS = ["get", "post", "put", "delete", "options", "patch"];
|
|
4
|
+
var METHODS = ["get", "post", "put", "delete", "options", "patch", "query"];
|
|
5
5
|
var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
|
|
6
6
|
var UnsupportedPathError = class extends Error {
|
|
7
7
|
};
|
|
@@ -10,7 +10,7 @@ import type { HasRequiredKeys } from '../utils/types';
|
|
|
10
10
|
type MethodNameAll = `$${typeof METHOD_NAME_ALL_LOWERCASE}`;
|
|
11
11
|
/**
|
|
12
12
|
* Type representing all standard HTTP methods prefixed with '$'
|
|
13
|
-
* e.g., '$get' | '$post' | '$put' | '$delete' | '$options' | '$patch'
|
|
13
|
+
* e.g., '$get' | '$post' | '$put' | '$delete' | '$options' | '$patch' | '$query'
|
|
14
14
|
*/
|
|
15
15
|
type StandardMethods = `$${(typeof METHODS)[number]}`;
|
|
16
16
|
/**
|
|
@@ -65,6 +65,7 @@ declare class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends
|
|
|
65
65
|
delete: HandlerInterface<E, 'delete', S, BasePath, CurrentPath>;
|
|
66
66
|
options: HandlerInterface<E, 'options', S, BasePath, CurrentPath>;
|
|
67
67
|
patch: HandlerInterface<E, 'patch', S, BasePath, CurrentPath>;
|
|
68
|
+
query: HandlerInterface<E, 'query', S, BasePath, CurrentPath>;
|
|
68
69
|
all: HandlerInterface<E, 'all', S, BasePath, CurrentPath>;
|
|
69
70
|
on: OnHandlerInterface<E, S, BasePath>;
|
|
70
71
|
use: MiddlewareHandlerInterface<E, S, BasePath>;
|
|
@@ -179,12 +180,12 @@ declare class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends
|
|
|
179
180
|
* @see {@link https://hono.dev/docs/api/hono#fetch}
|
|
180
181
|
*
|
|
181
182
|
* @param {Request} request - request Object of request
|
|
182
|
-
* @param {Env}
|
|
183
|
-
* @param {ExecutionContext} - context of execution
|
|
183
|
+
* @param {Env} env - env Object
|
|
184
|
+
* @param {ExecutionContext} executionCtx - context of execution
|
|
184
185
|
* @returns {Response | Promise<Response>} response of request
|
|
185
186
|
*
|
|
186
187
|
*/
|
|
187
|
-
fetch: (request: Request,
|
|
188
|
+
fetch: (request: Request, env?: E['Bindings'] | {}, executionCtx?: ExecutionContext) => Response | Promise<Response>;
|
|
188
189
|
/**
|
|
189
190
|
* `.request()` is a useful method for testing.
|
|
190
191
|
* You can pass a URL or pathname to send a GET request.
|