hono 4.6.19 → 4.7.0
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/dist/adapter/lambda-edge/handler.js +6 -2
- package/dist/cjs/adapter/lambda-edge/handler.js +6 -2
- package/dist/cjs/helper/accepts/accepts.js +4 -26
- package/dist/cjs/helper/factory/index.js +6 -2
- package/dist/cjs/helper/proxy/index.js +75 -0
- package/dist/cjs/helper/streaming/sse.js +8 -5
- package/dist/cjs/helper/streaming/stream.js +8 -5
- package/dist/cjs/helper/streaming/utils.js +36 -0
- package/dist/cjs/middleware/etag/digest.js +2 -7
- package/dist/cjs/middleware/etag/index.js +7 -2
- package/dist/cjs/middleware/jwk/index.js +28 -0
- package/dist/cjs/middleware/jwk/jwk.js +124 -0
- package/dist/cjs/middleware/language/index.js +36 -0
- package/dist/cjs/middleware/language/language.js +210 -0
- package/dist/cjs/middleware/logger/index.js +2 -3
- package/dist/cjs/request.js +1 -1
- package/dist/cjs/router/linear-router/router.js +3 -1
- package/dist/cjs/router/trie-router/node.js +24 -11
- package/dist/cjs/utils/accept.js +86 -0
- package/dist/cjs/utils/jwt/index.js +1 -1
- package/dist/cjs/utils/jwt/jwt.js +56 -3
- package/dist/cjs/utils/jwt/types.js +8 -0
- package/dist/cjs/utils/url.js +6 -5
- package/dist/helper/accepts/accepts.js +2 -23
- package/dist/helper/factory/index.js +6 -2
- package/dist/helper/proxy/index.js +52 -0
- package/dist/helper/streaming/sse.js +8 -5
- package/dist/helper/streaming/stream.js +8 -5
- package/dist/helper/streaming/utils.js +13 -0
- package/dist/middleware/etag/digest.js +2 -7
- package/dist/middleware/etag/index.js +7 -2
- package/dist/middleware/jwk/index.js +5 -0
- package/dist/middleware/jwk/jwk.js +101 -0
- package/dist/middleware/language/index.js +15 -0
- package/dist/middleware/language/language.js +178 -0
- package/dist/middleware/logger/index.js +2 -3
- package/dist/request.js +1 -1
- package/dist/router/linear-router/router.js +3 -1
- package/dist/router/trie-router/node.js +24 -11
- package/dist/types/client/types.d.ts +1 -2
- package/dist/types/context.d.ts +2 -2
- package/dist/types/helper/accepts/accepts.d.ts +0 -1
- package/dist/types/helper/adapter/index.d.ts +1 -1
- package/dist/types/helper/factory/index.d.ts +4 -1
- package/dist/types/helper/proxy/index.d.ts +54 -0
- package/dist/types/helper/streaming/utils.d.ts +1 -0
- package/dist/types/middleware/etag/digest.d.ts +1 -1
- package/dist/types/middleware/etag/index.d.ts +4 -0
- package/dist/types/middleware/jwk/index.d.ts +1 -0
- package/dist/types/middleware/jwk/jwk.d.ts +40 -0
- package/dist/types/middleware/language/index.d.ts +7 -0
- package/dist/types/middleware/language/language.d.ts +102 -0
- package/dist/types/utils/accept.d.ts +11 -0
- package/dist/types/utils/jwt/index.d.ts +4 -0
- package/dist/types/utils/jwt/jws.d.ts +4 -1
- package/dist/types/utils/jwt/jwt.d.ts +7 -1
- package/dist/types/utils/jwt/types.d.ts +4 -0
- package/dist/types/utils/url.d.ts +1 -1
- package/dist/utils/accept.js +63 -0
- package/dist/utils/jwt/index.js +2 -2
- package/dist/utils/jwt/jwt.js +54 -2
- package/dist/utils/jwt/types.js +7 -0
- package/dist/utils/url.js +6 -5
- package/package.json +26 -5
- package/perf-measures/bundle-check/generated/.gitkeep +0 -0
- package/perf-measures/type-check/generated/.gitkeep +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/helper/streaming/sse.ts
|
|
2
2
|
import { HtmlEscapedCallbackPhase, resolveCallback } from "../../utils/html.js";
|
|
3
3
|
import { StreamingApi } from "../../utils/stream.js";
|
|
4
|
+
import { isOldBunVersion } from "./utils.js";
|
|
4
5
|
var SSEStreamingApi = class extends StreamingApi {
|
|
5
6
|
constructor(writable, readable) {
|
|
6
7
|
super(writable, readable);
|
|
@@ -40,11 +41,13 @@ var contextStash = /* @__PURE__ */ new WeakMap();
|
|
|
40
41
|
var streamSSE = (c, cb, onError) => {
|
|
41
42
|
const { readable, writable } = new TransformStream();
|
|
42
43
|
const stream = new SSEStreamingApi(writable, readable);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
stream.
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
if (isOldBunVersion()) {
|
|
45
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
46
|
+
if (!stream.closed) {
|
|
47
|
+
stream.abort();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
48
51
|
contextStash.set(stream.responseReadable, c);
|
|
49
52
|
c.header("Transfer-Encoding", "chunked");
|
|
50
53
|
c.header("Content-Type", "text/event-stream");
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
// src/helper/streaming/stream.ts
|
|
2
2
|
import { StreamingApi } from "../../utils/stream.js";
|
|
3
|
+
import { isOldBunVersion } from "./utils.js";
|
|
3
4
|
var contextStash = /* @__PURE__ */ new WeakMap();
|
|
4
5
|
var stream = (c, cb, onError) => {
|
|
5
6
|
const { readable, writable } = new TransformStream();
|
|
6
7
|
const stream2 = new StreamingApi(writable, readable);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
stream2.
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
if (isOldBunVersion()) {
|
|
9
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
10
|
+
if (!stream2.closed) {
|
|
11
|
+
stream2.abort();
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
12
15
|
contextStash.set(stream2.responseReadable, c);
|
|
13
16
|
(async () => {
|
|
14
17
|
try {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// src/helper/streaming/utils.ts
|
|
2
|
+
var isOldBunVersion = () => {
|
|
3
|
+
const version = typeof Bun !== "undefined" ? Bun.version : void 0;
|
|
4
|
+
if (version === void 0) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
const result = version.startsWith("1.1") || version.startsWith("1.0") || version.startsWith("0.");
|
|
8
|
+
isOldBunVersion = () => result;
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
export {
|
|
12
|
+
isOldBunVersion
|
|
13
|
+
};
|
|
@@ -8,7 +8,7 @@ var mergeBuffers = (buffer1, buffer2) => {
|
|
|
8
8
|
merged.set(buffer2, buffer1.byteLength);
|
|
9
9
|
return merged;
|
|
10
10
|
};
|
|
11
|
-
var generateDigest = async (stream) => {
|
|
11
|
+
var generateDigest = async (stream, generator) => {
|
|
12
12
|
if (!stream || !crypto || !crypto.subtle) {
|
|
13
13
|
return null;
|
|
14
14
|
}
|
|
@@ -19,12 +19,7 @@ var generateDigest = async (stream) => {
|
|
|
19
19
|
if (done) {
|
|
20
20
|
break;
|
|
21
21
|
}
|
|
22
|
-
result = await
|
|
23
|
-
{
|
|
24
|
-
name: "SHA-1"
|
|
25
|
-
},
|
|
26
|
-
mergeBuffers(result, value)
|
|
27
|
-
);
|
|
22
|
+
result = await generator(mergeBuffers(result, value));
|
|
28
23
|
}
|
|
29
24
|
if (!result) {
|
|
30
25
|
return null;
|
|
@@ -14,20 +14,25 @@ function etagMatches(etag2, ifNoneMatch) {
|
|
|
14
14
|
var etag = (options) => {
|
|
15
15
|
const retainedHeaders = options?.retainedHeaders ?? RETAINED_304_HEADERS;
|
|
16
16
|
const weak = options?.weak ?? false;
|
|
17
|
+
const generator = options?.generateDigest ?? ((body) => crypto.subtle.digest(
|
|
18
|
+
{
|
|
19
|
+
name: "SHA-1"
|
|
20
|
+
},
|
|
21
|
+
body
|
|
22
|
+
));
|
|
17
23
|
return async function etag2(c, next) {
|
|
18
24
|
const ifNoneMatch = c.req.header("If-None-Match") ?? null;
|
|
19
25
|
await next();
|
|
20
26
|
const res = c.res;
|
|
21
27
|
let etag3 = res.headers.get("ETag");
|
|
22
28
|
if (!etag3) {
|
|
23
|
-
const hash = await generateDigest(res.clone().body);
|
|
29
|
+
const hash = await generateDigest(res.clone().body, generator);
|
|
24
30
|
if (hash === null) {
|
|
25
31
|
return;
|
|
26
32
|
}
|
|
27
33
|
etag3 = weak ? `W/"${hash}"` : `"${hash}"`;
|
|
28
34
|
}
|
|
29
35
|
if (etagMatches(etag3, ifNoneMatch)) {
|
|
30
|
-
await c.res.blob();
|
|
31
36
|
c.res = new Response(null, {
|
|
32
37
|
status: 304,
|
|
33
38
|
statusText: "Not Modified",
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// src/middleware/jwk/jwk.ts
|
|
2
|
+
import { getCookie, getSignedCookie } from "../../helper/cookie/index.js";
|
|
3
|
+
import { HTTPException } from "../../http-exception.js";
|
|
4
|
+
import { Jwt } from "../../utils/jwt/index.js";
|
|
5
|
+
import "../../context.js";
|
|
6
|
+
var jwk = (options, init) => {
|
|
7
|
+
if (!options || !(options.keys || options.jwks_uri)) {
|
|
8
|
+
throw new Error('JWK auth middleware requires options for either "keys" or "jwks_uri" or both');
|
|
9
|
+
}
|
|
10
|
+
if (!crypto.subtle || !crypto.subtle.importKey) {
|
|
11
|
+
throw new Error("`crypto.subtle.importKey` is undefined. JWK auth middleware requires it.");
|
|
12
|
+
}
|
|
13
|
+
return async function jwk2(ctx, next) {
|
|
14
|
+
const credentials = ctx.req.raw.headers.get("Authorization");
|
|
15
|
+
let token;
|
|
16
|
+
if (credentials) {
|
|
17
|
+
const parts = credentials.split(/\s+/);
|
|
18
|
+
if (parts.length !== 2) {
|
|
19
|
+
const errDescription = "invalid credentials structure";
|
|
20
|
+
throw new HTTPException(401, {
|
|
21
|
+
message: errDescription,
|
|
22
|
+
res: unauthorizedResponse({
|
|
23
|
+
ctx,
|
|
24
|
+
error: "invalid_request",
|
|
25
|
+
errDescription
|
|
26
|
+
})
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
token = parts[1];
|
|
30
|
+
}
|
|
31
|
+
} else if (options.cookie) {
|
|
32
|
+
if (typeof options.cookie == "string") {
|
|
33
|
+
token = getCookie(ctx, options.cookie);
|
|
34
|
+
} else if (options.cookie.secret) {
|
|
35
|
+
if (options.cookie.prefixOptions) {
|
|
36
|
+
token = await getSignedCookie(
|
|
37
|
+
ctx,
|
|
38
|
+
options.cookie.secret,
|
|
39
|
+
options.cookie.key,
|
|
40
|
+
options.cookie.prefixOptions
|
|
41
|
+
);
|
|
42
|
+
} else {
|
|
43
|
+
token = await getSignedCookie(ctx, options.cookie.secret, options.cookie.key);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
if (options.cookie.prefixOptions) {
|
|
47
|
+
token = getCookie(ctx, options.cookie.key, options.cookie.prefixOptions);
|
|
48
|
+
} else {
|
|
49
|
+
token = getCookie(ctx, options.cookie.key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!token) {
|
|
54
|
+
const errDescription = "no authorization included in request";
|
|
55
|
+
throw new HTTPException(401, {
|
|
56
|
+
message: errDescription,
|
|
57
|
+
res: unauthorizedResponse({
|
|
58
|
+
ctx,
|
|
59
|
+
error: "invalid_request",
|
|
60
|
+
errDescription
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
let payload;
|
|
65
|
+
let cause;
|
|
66
|
+
try {
|
|
67
|
+
payload = await Jwt.verifyFromJwks(token, options, init);
|
|
68
|
+
} catch (e) {
|
|
69
|
+
cause = e;
|
|
70
|
+
}
|
|
71
|
+
if (!payload) {
|
|
72
|
+
if (cause instanceof Error && cause.constructor === Error) {
|
|
73
|
+
throw cause;
|
|
74
|
+
}
|
|
75
|
+
throw new HTTPException(401, {
|
|
76
|
+
message: "Unauthorized",
|
|
77
|
+
res: unauthorizedResponse({
|
|
78
|
+
ctx,
|
|
79
|
+
error: "invalid_token",
|
|
80
|
+
statusText: "Unauthorized",
|
|
81
|
+
errDescription: "token verification failure"
|
|
82
|
+
}),
|
|
83
|
+
cause
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
ctx.set("jwtPayload", payload);
|
|
87
|
+
await next();
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
function unauthorizedResponse(opts) {
|
|
91
|
+
return new Response("Unauthorized", {
|
|
92
|
+
status: 401,
|
|
93
|
+
statusText: opts.statusText,
|
|
94
|
+
headers: {
|
|
95
|
+
"WWW-Authenticate": `Bearer realm="${opts.ctx.req.url}",error="${opts.error}",error_description="${opts.errDescription}"`
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
jwk
|
|
101
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/middleware/language/index.ts
|
|
2
|
+
import {
|
|
3
|
+
languageDetector,
|
|
4
|
+
detectFromCookie,
|
|
5
|
+
detectFromHeader,
|
|
6
|
+
detectFromPath,
|
|
7
|
+
detectFromQuery
|
|
8
|
+
} from "./language.js";
|
|
9
|
+
export {
|
|
10
|
+
detectFromCookie,
|
|
11
|
+
detectFromHeader,
|
|
12
|
+
detectFromPath,
|
|
13
|
+
detectFromQuery,
|
|
14
|
+
languageDetector
|
|
15
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// src/middleware/language/language.ts
|
|
2
|
+
import { setCookie, getCookie } from "../../helper/cookie/index.js";
|
|
3
|
+
import { parseAccept } from "../../utils/accept.js";
|
|
4
|
+
var DEFAULT_OPTIONS = {
|
|
5
|
+
order: ["querystring", "cookie", "header"],
|
|
6
|
+
lookupQueryString: "lang",
|
|
7
|
+
lookupCookie: "language",
|
|
8
|
+
lookupFromHeaderKey: "accept-language",
|
|
9
|
+
lookupFromPathIndex: 0,
|
|
10
|
+
caches: ["cookie"],
|
|
11
|
+
ignoreCase: true,
|
|
12
|
+
fallbackLanguage: "en",
|
|
13
|
+
supportedLanguages: ["en"],
|
|
14
|
+
cookieOptions: {
|
|
15
|
+
sameSite: "Strict",
|
|
16
|
+
secure: true,
|
|
17
|
+
maxAge: 365 * 24 * 60 * 60,
|
|
18
|
+
httpOnly: true
|
|
19
|
+
},
|
|
20
|
+
debug: false
|
|
21
|
+
};
|
|
22
|
+
function parseAcceptLanguage(header) {
|
|
23
|
+
return parseAccept(header).map(({ type, q }) => ({ lang: type, q }));
|
|
24
|
+
}
|
|
25
|
+
var normalizeLanguage = (lang, options) => {
|
|
26
|
+
if (!lang) {
|
|
27
|
+
return void 0;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
let normalizedLang = lang.trim();
|
|
31
|
+
if (options.convertDetectedLanguage) {
|
|
32
|
+
normalizedLang = options.convertDetectedLanguage(normalizedLang);
|
|
33
|
+
}
|
|
34
|
+
const compLang = options.ignoreCase ? normalizedLang.toLowerCase() : normalizedLang;
|
|
35
|
+
const compSupported = options.supportedLanguages.map(
|
|
36
|
+
(l) => options.ignoreCase ? l.toLowerCase() : l
|
|
37
|
+
);
|
|
38
|
+
const matchedLang = compSupported.find((l) => l === compLang);
|
|
39
|
+
return matchedLang ? options.supportedLanguages[compSupported.indexOf(matchedLang)] : void 0;
|
|
40
|
+
} catch {
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var detectFromQuery = (c, options) => {
|
|
45
|
+
try {
|
|
46
|
+
const query = c.req.query(options.lookupQueryString);
|
|
47
|
+
return normalizeLanguage(query, options);
|
|
48
|
+
} catch {
|
|
49
|
+
return void 0;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var detectFromCookie = (c, options) => {
|
|
53
|
+
try {
|
|
54
|
+
const cookie = getCookie(c, options.lookupCookie);
|
|
55
|
+
return normalizeLanguage(cookie, options);
|
|
56
|
+
} catch {
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
function detectFromHeader(c, options) {
|
|
61
|
+
try {
|
|
62
|
+
const acceptLanguage = c.req.header(options.lookupFromHeaderKey);
|
|
63
|
+
if (!acceptLanguage) {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
const languages = parseAcceptLanguage(acceptLanguage);
|
|
67
|
+
for (const { lang } of languages) {
|
|
68
|
+
const normalizedLang = normalizeLanguage(lang, options);
|
|
69
|
+
if (normalizedLang) {
|
|
70
|
+
return normalizedLang;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return void 0;
|
|
74
|
+
} catch {
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function detectFromPath(c, options) {
|
|
79
|
+
try {
|
|
80
|
+
const pathSegments = c.req.path.split("/").filter(Boolean);
|
|
81
|
+
const langSegment = pathSegments[options.lookupFromPathIndex];
|
|
82
|
+
return normalizeLanguage(langSegment, options);
|
|
83
|
+
} catch {
|
|
84
|
+
return void 0;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
var detectors = {
|
|
88
|
+
querystring: detectFromQuery,
|
|
89
|
+
cookie: detectFromCookie,
|
|
90
|
+
header: detectFromHeader,
|
|
91
|
+
path: detectFromPath
|
|
92
|
+
};
|
|
93
|
+
function validateOptions(options) {
|
|
94
|
+
if (!options.supportedLanguages.includes(options.fallbackLanguage)) {
|
|
95
|
+
throw new Error("Fallback language must be included in supported languages");
|
|
96
|
+
}
|
|
97
|
+
if (options.lookupFromPathIndex < 0) {
|
|
98
|
+
throw new Error("Path index must be non-negative");
|
|
99
|
+
}
|
|
100
|
+
if (!options.order.every((detector) => Object.keys(detectors).includes(detector))) {
|
|
101
|
+
throw new Error("Invalid detector type in order array");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function cacheLanguage(c, language, options) {
|
|
105
|
+
if (!Array.isArray(options.caches) || !options.caches.includes("cookie")) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
setCookie(c, options.lookupCookie, language, options.cookieOptions);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (options.debug) {
|
|
112
|
+
console.error("Failed to cache language:", error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
var detectLanguage = (c, options) => {
|
|
117
|
+
let detectedLang;
|
|
118
|
+
for (const detectorName of options.order) {
|
|
119
|
+
const detector = detectors[detectorName];
|
|
120
|
+
if (!detector) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
detectedLang = detector(c, options);
|
|
125
|
+
if (detectedLang) {
|
|
126
|
+
if (options.debug) {
|
|
127
|
+
console.log(`Language detected from ${detectorName}: ${detectedLang}`);
|
|
128
|
+
}
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
if (options.debug) {
|
|
133
|
+
console.error(`Error in ${detectorName} detector:`, error);
|
|
134
|
+
}
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const finalLang = detectedLang || options.fallbackLanguage;
|
|
139
|
+
if (detectedLang && options.caches) {
|
|
140
|
+
cacheLanguage(c, finalLang, options);
|
|
141
|
+
}
|
|
142
|
+
return finalLang;
|
|
143
|
+
};
|
|
144
|
+
var languageDetector = (userOptions) => {
|
|
145
|
+
const options = {
|
|
146
|
+
...DEFAULT_OPTIONS,
|
|
147
|
+
...userOptions,
|
|
148
|
+
cookieOptions: {
|
|
149
|
+
...DEFAULT_OPTIONS.cookieOptions,
|
|
150
|
+
...userOptions.cookieOptions
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
validateOptions(options);
|
|
154
|
+
return async function languageDetector2(ctx, next) {
|
|
155
|
+
try {
|
|
156
|
+
const lang = detectLanguage(ctx, options);
|
|
157
|
+
ctx.set("language", lang);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (options.debug) {
|
|
160
|
+
console.error("Language detection failed:", error);
|
|
161
|
+
}
|
|
162
|
+
ctx.set("language", options.fallbackLanguage);
|
|
163
|
+
}
|
|
164
|
+
await next();
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
export {
|
|
168
|
+
DEFAULT_OPTIONS,
|
|
169
|
+
detectFromCookie,
|
|
170
|
+
detectFromHeader,
|
|
171
|
+
detectFromPath,
|
|
172
|
+
detectFromQuery,
|
|
173
|
+
detectors,
|
|
174
|
+
languageDetector,
|
|
175
|
+
normalizeLanguage,
|
|
176
|
+
parseAcceptLanguage,
|
|
177
|
+
validateOptions
|
|
178
|
+
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// src/middleware/logger/index.ts
|
|
2
2
|
import { getColorEnabled } from "../../utils/color.js";
|
|
3
|
-
import { getPath } from "../../utils/url.js";
|
|
4
3
|
var humanize = (times) => {
|
|
5
4
|
const [delimiter, separator] = [",", "."];
|
|
6
5
|
const orderTimes = times.map((v) => v.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter));
|
|
@@ -32,8 +31,8 @@ function log(fn, prefix, method, path, status = 0, elapsed) {
|
|
|
32
31
|
}
|
|
33
32
|
var logger = (fn = console.log) => {
|
|
34
33
|
return async function logger2(c, next) {
|
|
35
|
-
const { method } = c.req;
|
|
36
|
-
const path =
|
|
34
|
+
const { method, url } = c.req;
|
|
35
|
+
const path = url.slice(url.indexOf("/", 8));
|
|
37
36
|
log(fn, "<--" /* Incoming */, method, path);
|
|
38
37
|
const start = Date.now();
|
|
39
38
|
await next();
|
package/dist/request.js
CHANGED
|
@@ -66,7 +66,9 @@ var LinearRouter = class {
|
|
|
66
66
|
let value;
|
|
67
67
|
if (name.charCodeAt(name.length - 1) === 125) {
|
|
68
68
|
const openBracePos = name.indexOf("{");
|
|
69
|
-
const
|
|
69
|
+
const next = parts[j + 1];
|
|
70
|
+
const lookahead = next && next[1] !== ":" && next[1] !== "*" ? `(?=${next})` : "";
|
|
71
|
+
const pattern = name.slice(openBracePos + 1, -1) + lookahead;
|
|
70
72
|
const restPath = path.slice(pos + 1);
|
|
71
73
|
const match = new RegExp(pattern, "d").exec(restPath);
|
|
72
74
|
if (!match || match.indices[0][0] !== 0 || match.indices[0][1] === 0) {
|
|
@@ -25,21 +25,23 @@ var Node = class {
|
|
|
25
25
|
const possibleKeys = [];
|
|
26
26
|
for (let i = 0, len = parts.length; i < len; i++) {
|
|
27
27
|
const p = parts[i];
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const nextP = parts[i + 1];
|
|
29
|
+
const pattern = getPattern(p, nextP);
|
|
30
|
+
const key = Array.isArray(pattern) ? pattern[0] : p;
|
|
31
|
+
if (Object.keys(curNode.#children).includes(key)) {
|
|
32
|
+
curNode = curNode.#children[key];
|
|
33
|
+
const pattern2 = getPattern(p, nextP);
|
|
31
34
|
if (pattern2) {
|
|
32
35
|
possibleKeys.push(pattern2[1]);
|
|
33
36
|
}
|
|
34
37
|
continue;
|
|
35
38
|
}
|
|
36
|
-
curNode.#children[
|
|
37
|
-
const pattern = getPattern(p);
|
|
39
|
+
curNode.#children[key] = new Node();
|
|
38
40
|
if (pattern) {
|
|
39
41
|
curNode.#patterns.push(pattern);
|
|
40
42
|
possibleKeys.push(pattern[1]);
|
|
41
43
|
}
|
|
42
|
-
curNode = curNode.#children[
|
|
44
|
+
curNode = curNode.#children[key];
|
|
43
45
|
}
|
|
44
46
|
const m = /* @__PURE__ */ Object.create(null);
|
|
45
47
|
const handlerSet = {
|
|
@@ -78,6 +80,7 @@ var Node = class {
|
|
|
78
80
|
const curNode = this;
|
|
79
81
|
let curNodes = [curNode];
|
|
80
82
|
const parts = splitPath(path);
|
|
83
|
+
const curNodesQueue = [];
|
|
81
84
|
for (let i = 0, len = parts.length; i < len; i++) {
|
|
82
85
|
const part = parts[i];
|
|
83
86
|
const isLast = i === len - 1;
|
|
@@ -105,6 +108,7 @@ var Node = class {
|
|
|
105
108
|
const astNode = node.#children["*"];
|
|
106
109
|
if (astNode) {
|
|
107
110
|
handlerSets.push(...this.#getHandlerSets(astNode, method, node.#params));
|
|
111
|
+
astNode.#params = params;
|
|
108
112
|
tempNodes.push(astNode);
|
|
109
113
|
}
|
|
110
114
|
continue;
|
|
@@ -115,10 +119,19 @@ var Node = class {
|
|
|
115
119
|
const [key, name, matcher] = pattern;
|
|
116
120
|
const child = node.#children[key];
|
|
117
121
|
const restPathString = parts.slice(i).join("/");
|
|
118
|
-
if (matcher instanceof RegExp
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
if (matcher instanceof RegExp) {
|
|
123
|
+
const m = matcher.exec(restPathString);
|
|
124
|
+
if (m) {
|
|
125
|
+
params[name] = m[0];
|
|
126
|
+
handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params));
|
|
127
|
+
if (Object.keys(child.#children).length) {
|
|
128
|
+
child.#params = params;
|
|
129
|
+
const componentCount = m[0].match(/\//)?.length ?? 0;
|
|
130
|
+
const targetCurNodes = curNodesQueue[componentCount] ||= [];
|
|
131
|
+
targetCurNodes.push(child);
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
122
135
|
}
|
|
123
136
|
if (matcher === true || matcher.test(part)) {
|
|
124
137
|
params[name] = part;
|
|
@@ -136,7 +149,7 @@ var Node = class {
|
|
|
136
149
|
}
|
|
137
150
|
}
|
|
138
151
|
}
|
|
139
|
-
curNodes = tempNodes;
|
|
152
|
+
curNodes = tempNodes.concat(curNodesQueue.shift() ?? []);
|
|
140
153
|
}
|
|
141
154
|
if (handlerSets.length > 1) {
|
|
142
155
|
handlerSets.sort((a, b) => {
|
|
@@ -47,7 +47,6 @@ export type ClientRequest<S extends Schema> = {
|
|
|
47
47
|
} ? {
|
|
48
48
|
$ws: (args?: I) => WebSocket;
|
|
49
49
|
} : {} : {});
|
|
50
|
-
type BlankRecordToNever<T> = T extends any ? T extends null ? null : keyof T extends never ? never : T : never;
|
|
51
50
|
type ClientResponseOfEndpoint<T extends Endpoint = Endpoint> = T extends {
|
|
52
51
|
output: infer O;
|
|
53
52
|
outputFormat: infer F;
|
|
@@ -63,7 +62,7 @@ export interface ClientResponse<T, U extends number = StatusCode, F extends Resp
|
|
|
63
62
|
url: string;
|
|
64
63
|
redirect(url: string, status: number): Response;
|
|
65
64
|
clone(): Response;
|
|
66
|
-
json(): F extends "text" ? Promise<never> : F extends "json" ? Promise<
|
|
65
|
+
json(): F extends "text" ? Promise<never> : F extends "json" ? Promise<T> : Promise<unknown>;
|
|
67
66
|
text(): F extends "text" ? (T extends string ? Promise<T> : Promise<never>) : Promise<string>;
|
|
68
67
|
blob(): Promise<Blob>;
|
|
69
68
|
formData(): Promise<FormData>;
|
package/dist/types/context.d.ts
CHANGED
|
@@ -7,9 +7,9 @@ import type { BaseMime } from './utils/mime';
|
|
|
7
7
|
import type { InvalidJSONValue, IsAny, JSONParsed, JSONValue, SimplifyDeepArray } from './utils/types';
|
|
8
8
|
type HeaderRecord = Record<"Content-Type", BaseMime> | Record<ResponseHeader, string | string[]> | Record<string, string | string[]>;
|
|
9
9
|
/**
|
|
10
|
-
* Data type can be a string, ArrayBuffer, or ReadableStream.
|
|
10
|
+
* Data type can be a string, ArrayBuffer, Uint8Array (buffer), or ReadableStream.
|
|
11
11
|
*/
|
|
12
|
-
export type Data = string | ArrayBuffer | ReadableStream;
|
|
12
|
+
export type Data = string | ArrayBuffer | ReadableStream | Uint8Array;
|
|
13
13
|
/**
|
|
14
14
|
* Interface for the execution context in a web worker or similar environment.
|
|
15
15
|
*/
|
|
@@ -13,7 +13,6 @@ export interface acceptsConfig {
|
|
|
13
13
|
export interface acceptsOptions extends acceptsConfig {
|
|
14
14
|
match?: (accepts: Accept[], config: acceptsConfig) => string;
|
|
15
15
|
}
|
|
16
|
-
export declare const parseAccept: (acceptHeader: string) => Accept[];
|
|
17
16
|
export declare const defaultMatch: (accepts: Accept[], config: acceptsConfig) => string;
|
|
18
17
|
/**
|
|
19
18
|
* Match the accept header with the given options.
|
|
@@ -6,7 +6,7 @@ import type { Context } from '../../context';
|
|
|
6
6
|
export type Runtime = "node" | "deno" | "bun" | "workerd" | "fastly" | "edge-light" | "other";
|
|
7
7
|
export declare const env: <T extends Record<string, unknown>, C extends Context = Context<{
|
|
8
8
|
Bindings: T;
|
|
9
|
-
}, any, {}>>(c: C, runtime?: Runtime) => T & C["env"];
|
|
9
|
+
}, any, {}>>(c: T extends Record<string, unknown> ? Context : C, runtime?: Runtime) => T & C["env"];
|
|
10
10
|
export declare const knownUserAgents: Partial<Record<Runtime, string>>;
|
|
11
11
|
export declare const getRuntimeKey: () => Runtime;
|
|
12
12
|
export declare const checkUserAgentEquals: (platform: string) => boolean;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Factory Helper for Hono.
|
|
4
4
|
*/
|
|
5
5
|
import { Hono } from '../../hono';
|
|
6
|
+
import type { HonoOptions } from '../../hono-base';
|
|
6
7
|
import type { Env, H, HandlerResponse, Input, IntersectNonAnyTypes, MiddlewareHandler } from '../../types';
|
|
7
8
|
type InitApp<E extends Env = Env> = (app: Hono<E>) => void;
|
|
8
9
|
export interface CreateHandlersInterface<E extends Env, P extends string> {
|
|
@@ -340,13 +341,15 @@ export interface CreateHandlersInterface<E extends Env, P extends string> {
|
|
|
340
341
|
export declare class Factory<E extends Env = Env, P extends string = string> {
|
|
341
342
|
constructor(init?: {
|
|
342
343
|
initApp?: InitApp<E>;
|
|
344
|
+
defaultAppOptions?: HonoOptions<E>;
|
|
343
345
|
});
|
|
344
|
-
createApp: () => Hono<E>;
|
|
346
|
+
createApp: (options?: HonoOptions<E>) => Hono<E>;
|
|
345
347
|
createMiddleware: <I extends Input = {}>(middleware: MiddlewareHandler<E, P, I>) => MiddlewareHandler<E, P, I>;
|
|
346
348
|
createHandlers: CreateHandlersInterface<E, P>;
|
|
347
349
|
}
|
|
348
350
|
export declare const createFactory: <E extends Env = Env, P extends string = string>(init?: {
|
|
349
351
|
initApp?: InitApp<E>;
|
|
352
|
+
defaultAppOptions?: HonoOptions<E>;
|
|
350
353
|
}) => Factory<E, P>;
|
|
351
354
|
export declare const createMiddleware: <E extends Env = any, P extends string = string, I extends Input = {}>(middleware: MiddlewareHandler<E, P, I>) => MiddlewareHandler<E, P, I>;
|
|
352
355
|
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* Proxy Helper for Hono.
|
|
4
|
+
*/
|
|
5
|
+
import type { RequestHeader } from '../../utils/headers';
|
|
6
|
+
interface ProxyRequestInit extends Omit<RequestInit, "headers"> {
|
|
7
|
+
raw?: Request;
|
|
8
|
+
headers?: HeadersInit | [
|
|
9
|
+
string,
|
|
10
|
+
string
|
|
11
|
+
][] | Record<RequestHeader, string | undefined> | Record<string, string | undefined>;
|
|
12
|
+
}
|
|
13
|
+
interface ProxyFetch {
|
|
14
|
+
(input: string | URL | Request, init?: ProxyRequestInit): Promise<Response>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Fetch API wrapper for proxy.
|
|
18
|
+
* The parameters and return value are the same as for `fetch` (except for the proxy-specific options).
|
|
19
|
+
*
|
|
20
|
+
* The “Accept-Encoding” header is replaced with an encoding that the current runtime can handle.
|
|
21
|
+
* Unnecessary response headers are deleted and a Response object is returned that can be returned
|
|
22
|
+
* as is as a response from the handler.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* app.get('/proxy/:path', (c) => {
|
|
27
|
+
* return proxy(`http://${originServer}/${c.req.param('path')}`, {
|
|
28
|
+
* headers: {
|
|
29
|
+
* ...c.req.header(), // optional, specify only when forwarding all the request data (including credentials) is necessary.
|
|
30
|
+
* 'X-Forwarded-For': '127.0.0.1',
|
|
31
|
+
* 'X-Forwarded-Host': c.req.header('host'),
|
|
32
|
+
* Authorization: undefined, // do not propagate request headers contained in c.req.header('Authorization')
|
|
33
|
+
* },
|
|
34
|
+
* }).then((res) => {
|
|
35
|
+
* res.headers.delete('Set-Cookie')
|
|
36
|
+
* return res
|
|
37
|
+
* })
|
|
38
|
+
* })
|
|
39
|
+
*
|
|
40
|
+
* app.all('/proxy/:path', (c) => {
|
|
41
|
+
* return proxy(`http://${originServer}/${c.req.param('path')}`, {
|
|
42
|
+
* ...c.req, // optional, specify only when forwarding all the request data (including credentials) is necessary.
|
|
43
|
+
* headers: {
|
|
44
|
+
* ...c.req.header(),
|
|
45
|
+
* 'X-Forwarded-For': '127.0.0.1',
|
|
46
|
+
* 'X-Forwarded-Host': c.req.header('host'),
|
|
47
|
+
* Authorization: undefined, // do not propagate request headers contained in c.req.header('Authorization')
|
|
48
|
+
* },
|
|
49
|
+
* })
|
|
50
|
+
* })
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare const proxy: ProxyFetch;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare let isOldBunVersion: () => boolean;
|