hono 4.12.17 → 4.12.19
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/bun/serve-static.js +1 -1
- package/dist/adapter/cloudflare-workers/serve-static.js +1 -1
- package/dist/adapter/deno/serve-static.js +1 -1
- package/dist/cjs/adapter/bun/serve-static.js +1 -1
- package/dist/cjs/adapter/cloudflare-workers/serve-static.js +1 -1
- package/dist/cjs/adapter/deno/serve-static.js +1 -1
- package/dist/cjs/jsx/utils.js +95 -5
- package/dist/cjs/middleware/cache/index.js +34 -26
- package/dist/cjs/request.js +15 -0
- package/dist/cjs/utils/cookie.js +3 -3
- package/dist/cjs/utils/jwt/jwt.js +12 -6
- package/dist/cjs/utils/stream.js +4 -2
- package/dist/jsx/utils.js +95 -5
- package/dist/middleware/cache/index.js +34 -26
- package/dist/request.js +15 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/adapter/bun/serve-static.d.ts +1 -1
- package/dist/types/adapter/cloudflare-workers/serve-static.d.ts +2 -2
- package/dist/types/adapter/deno/serve-static.d.ts +1 -1
- package/dist/types/jsx/utils.d.ts +1 -1
- package/dist/types/middleware/bearer-auth/index.d.ts +6 -5
- package/dist/types/middleware/cache/index.d.ts +1 -1
- package/dist/types/request.d.ts +13 -0
- package/dist/utils/cookie.js +3 -3
- package/dist/utils/jwt/jwt.js +12 -6
- package/dist/utils/stream.js +4 -2
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { stat } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { serveStatic as baseServeStatic } from "../../middleware/serve-static/index.js";
|
|
5
|
-
var serveStatic = (options) => {
|
|
5
|
+
var serveStatic = (options = {}) => {
|
|
6
6
|
return async function serveStatic2(c, next) {
|
|
7
7
|
const getContent = async (path) => {
|
|
8
8
|
const file = Bun.file(path);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/adapter/cloudflare-workers/serve-static.ts
|
|
2
2
|
import { serveStatic as baseServeStatic } from "../../middleware/serve-static/index.js";
|
|
3
3
|
import { getContentFromKVAsset } from "./utils.js";
|
|
4
|
-
var serveStatic = (options) => {
|
|
4
|
+
var serveStatic = (options = {}) => {
|
|
5
5
|
return async function serveStatic2(c, next) {
|
|
6
6
|
const getContent = async (path) => {
|
|
7
7
|
return getContentFromKVAsset(path, {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { serveStatic as baseServeStatic } from "../../middleware/serve-static/index.js";
|
|
4
4
|
var { open, lstatSync, errors } = Deno;
|
|
5
|
-
var serveStatic = (options) => {
|
|
5
|
+
var serveStatic = (options = {}) => {
|
|
6
6
|
return async function serveStatic2(c, next) {
|
|
7
7
|
const getContent = async (path) => {
|
|
8
8
|
try {
|
|
@@ -23,7 +23,7 @@ module.exports = __toCommonJS(serve_static_exports);
|
|
|
23
23
|
var import_promises = require("node:fs/promises");
|
|
24
24
|
var import_node_path = require("node:path");
|
|
25
25
|
var import_serve_static = require("../../middleware/serve-static");
|
|
26
|
-
const serveStatic = (options) => {
|
|
26
|
+
const serveStatic = (options = {}) => {
|
|
27
27
|
return async function serveStatic2(c, next) {
|
|
28
28
|
const getContent = async (path) => {
|
|
29
29
|
const file = Bun.file(path);
|
|
@@ -22,7 +22,7 @@ __export(serve_static_exports, {
|
|
|
22
22
|
module.exports = __toCommonJS(serve_static_exports);
|
|
23
23
|
var import_serve_static = require("../../middleware/serve-static");
|
|
24
24
|
var import_utils = require("./utils");
|
|
25
|
-
const serveStatic = (options) => {
|
|
25
|
+
const serveStatic = (options = {}) => {
|
|
26
26
|
return async function serveStatic2(c, next) {
|
|
27
27
|
const getContent = async (path) => {
|
|
28
28
|
return (0, import_utils.getContentFromKVAsset)(path, {
|
|
@@ -23,7 +23,7 @@ module.exports = __toCommonJS(serve_static_exports);
|
|
|
23
23
|
var import_node_path = require("node:path");
|
|
24
24
|
var import_serve_static = require("../../middleware/serve-static");
|
|
25
25
|
const { open, lstatSync, errors } = Deno;
|
|
26
|
-
const serveStatic = (options) => {
|
|
26
|
+
const serveStatic = (options = {}) => {
|
|
27
27
|
return async function serveStatic2(c, next) {
|
|
28
28
|
const getContent = async (path) => {
|
|
29
29
|
try {
|
package/dist/cjs/jsx/utils.js
CHANGED
|
@@ -90,15 +90,105 @@ const isValidAttributeName = (name) => {
|
|
|
90
90
|
cacheValidName(validAttributeNameCache, validAttributeNameCacheMax, name);
|
|
91
91
|
return true;
|
|
92
92
|
};
|
|
93
|
+
const invalidStylePropertyNameCharRe = /[\s"'():;\\/\[\]{}\x00-\x1f\x7f-\x9f]/;
|
|
94
|
+
const validStylePropertyNameCache = /* @__PURE__ */ new Set();
|
|
95
|
+
const validStylePropertyNameCacheMax = 1024;
|
|
96
|
+
const isValidStylePropertyName = (name) => {
|
|
97
|
+
if (validStylePropertyNameCache.has(name)) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
const len = name.length;
|
|
101
|
+
if (len === 0) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
for (let i = 0; i < len; i++) {
|
|
105
|
+
const c = name.charCodeAt(i);
|
|
106
|
+
if (!(c >= 97 && c <= 122 || // a-z
|
|
107
|
+
c >= 65 && c <= 90 || // A-Z
|
|
108
|
+
c >= 48 && c <= 57 || // 0-9
|
|
109
|
+
c === 45 || // -
|
|
110
|
+
c === 95)) {
|
|
111
|
+
if (!invalidStylePropertyNameCharRe.test(name)) {
|
|
112
|
+
cacheValidName(validStylePropertyNameCache, validStylePropertyNameCacheMax, name);
|
|
113
|
+
return true;
|
|
114
|
+
} else {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
cacheValidName(validStylePropertyNameCache, validStylePropertyNameCacheMax, name);
|
|
120
|
+
return true;
|
|
121
|
+
};
|
|
122
|
+
const unsafeStyleValueCharRe = /[;"'\\/\[\](){}]/;
|
|
123
|
+
const hasUnsafeStyleValue = (value) => {
|
|
124
|
+
if (!unsafeStyleValueCharRe.test(value)) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
let quote = 0;
|
|
128
|
+
const blockStack = [];
|
|
129
|
+
for (let i = 0, len = value.length; i < len; i++) {
|
|
130
|
+
const c = value.charCodeAt(i);
|
|
131
|
+
if (c === 92) {
|
|
132
|
+
if (i === len - 1) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
i++;
|
|
136
|
+
} else if (quote !== 0) {
|
|
137
|
+
if (c === 10 || c === 12 || c === 13) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
if (c === quote) {
|
|
141
|
+
quote = 0;
|
|
142
|
+
}
|
|
143
|
+
} else if (c === 47 && value.charCodeAt(i + 1) === 42) {
|
|
144
|
+
const end = value.indexOf("*/", i + 2);
|
|
145
|
+
if (end === -1) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
i = end + 1;
|
|
149
|
+
} else if (c === 34 || c === 39) {
|
|
150
|
+
quote = c;
|
|
151
|
+
} else if (c === 40) {
|
|
152
|
+
blockStack.push(41);
|
|
153
|
+
} else if (c === 91) {
|
|
154
|
+
blockStack.push(93);
|
|
155
|
+
} else if (c === 123 || c === 125) {
|
|
156
|
+
return true;
|
|
157
|
+
} else if (c === 41 || c === 93) {
|
|
158
|
+
if (blockStack[blockStack.length - 1] !== c) {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
blockStack.pop();
|
|
162
|
+
} else if (c === 59 && blockStack.length === 0) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return quote !== 0 || blockStack.length !== 0;
|
|
167
|
+
};
|
|
93
168
|
const styleObjectForEach = (style, fn) => {
|
|
94
169
|
for (const [k, v] of Object.entries(style)) {
|
|
95
170
|
const key = k[0] === "-" || !/[A-Z]/.test(k) ? k : k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
171
|
+
if (!isValidStylePropertyName(key)) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (v == null) {
|
|
175
|
+
fn(key, null);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
let value;
|
|
179
|
+
if (typeof v === "number") {
|
|
180
|
+
value = !key.match(
|
|
99
181
|
/^(?:a|border-im|column(?:-c|s)|flex(?:$|-[^b])|grid-(?:ar|[^a])|font-w|li|or|sca|st|ta|wido|z)|ty$/
|
|
100
|
-
) ? `${v}px` : `${v}
|
|
101
|
-
)
|
|
182
|
+
) ? `${v}px` : `${v}`;
|
|
183
|
+
} else if (typeof v === "string") {
|
|
184
|
+
if (hasUnsafeStyleValue(v)) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
value = v;
|
|
188
|
+
} else {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
fn(key, value);
|
|
102
192
|
}
|
|
103
193
|
};
|
|
104
194
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -21,20 +21,14 @@ __export(cache_exports, {
|
|
|
21
21
|
});
|
|
22
22
|
module.exports = __toCommonJS(cache_exports);
|
|
23
23
|
const defaultCacheableStatusCodes = [200];
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
if (vary
|
|
27
|
-
return
|
|
24
|
+
const shouldSkipCacheControl = (cacheControl) => !!cacheControl && /(?:^|,\s*)(?:private|no-(?:store|cache))(?:\s*(?:=|,|$))/i.test(cacheControl);
|
|
25
|
+
const parseVaryDirectives = (vary) => {
|
|
26
|
+
if (vary == null) {
|
|
27
|
+
return [];
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
if (cacheControl && /(?:^|,\s*)(?:private|no-(?:store|cache))(?:\s*(?:=|,|$))/i.test(cacheControl)) {
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
if (res.headers.has("Set-Cookie")) {
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
return false;
|
|
29
|
+
return (Array.isArray(vary) ? vary : vary.split(",")).map((directive) => directive.trim().toLowerCase()).filter(Boolean);
|
|
37
30
|
};
|
|
31
|
+
const shouldSkipCache = (res, optionsVaryDirectives, responseVary) => responseVary.length && (!optionsVaryDirectives || responseVary.some((name) => !optionsVaryDirectives.has(name))) || shouldSkipCacheControl(res.headers.get("Cache-Control")) || res.headers.has("Set-Cookie");
|
|
38
32
|
const cache = (options) => {
|
|
39
33
|
if (!globalThis.caches) {
|
|
40
34
|
if (options.onCacheNotAvailable === false) {
|
|
@@ -49,8 +43,9 @@ const cache = (options) => {
|
|
|
49
43
|
options.wait = false;
|
|
50
44
|
}
|
|
51
45
|
const cacheControlDirectives = options.cacheControl?.split(",").map((directive) => directive.toLowerCase());
|
|
52
|
-
const
|
|
53
|
-
|
|
46
|
+
const optionsVaryList = parseVaryDirectives(options.vary);
|
|
47
|
+
const varyDirectives = optionsVaryList.length ? new Set(optionsVaryList) : void 0;
|
|
48
|
+
if (varyDirectives?.has("*")) {
|
|
54
49
|
throw new Error(
|
|
55
50
|
'Middleware vary configuration cannot include "*", as it disallows effective caching.'
|
|
56
51
|
);
|
|
@@ -58,7 +53,7 @@ const cache = (options) => {
|
|
|
58
53
|
const cacheableStatusCodes = new Set(
|
|
59
54
|
options.cacheableStatusCodes ?? defaultCacheableStatusCodes
|
|
60
55
|
);
|
|
61
|
-
const addHeader = (c) => {
|
|
56
|
+
const addHeader = (c, responseVary) => {
|
|
62
57
|
if (cacheControlDirectives) {
|
|
63
58
|
const existingDirectives = c.res.headers.get("Cache-Control")?.split(",").map((d) => d.trim().split("=", 1)[0]) ?? [];
|
|
64
59
|
for (const directive of cacheControlDirectives) {
|
|
@@ -70,24 +65,36 @@ const cache = (options) => {
|
|
|
70
65
|
}
|
|
71
66
|
}
|
|
72
67
|
if (varyDirectives) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
new Set(
|
|
76
|
-
[...existingDirectives, ...varyDirectives].map((directive) => directive.toLowerCase())
|
|
77
|
-
)
|
|
78
|
-
).sort();
|
|
79
|
-
if (vary.includes("*")) {
|
|
80
|
-
c.header("Vary", "*");
|
|
68
|
+
if (responseVary.length === 0) {
|
|
69
|
+
c.header("Vary", Array.from(varyDirectives).join(", "));
|
|
81
70
|
} else {
|
|
82
|
-
|
|
71
|
+
const merged = new Set(varyDirectives);
|
|
72
|
+
for (const directive of responseVary) {
|
|
73
|
+
merged.add(directive);
|
|
74
|
+
}
|
|
75
|
+
if (merged.has("*")) {
|
|
76
|
+
c.header("Vary", "*");
|
|
77
|
+
} else {
|
|
78
|
+
c.header("Vary", Array.from(merged).join(", "));
|
|
79
|
+
}
|
|
83
80
|
}
|
|
84
81
|
}
|
|
85
82
|
};
|
|
86
83
|
return async function cache2(c, next) {
|
|
84
|
+
if (c.req.method !== "GET" || c.req.raw.headers.has("Authorization")) {
|
|
85
|
+
await next();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
87
88
|
let key = c.req.url;
|
|
88
89
|
if (options.keyGenerator) {
|
|
89
90
|
key = await options.keyGenerator(c);
|
|
90
91
|
}
|
|
92
|
+
if (varyDirectives) {
|
|
93
|
+
for (const directive of varyDirectives) {
|
|
94
|
+
const value = c.req.raw.headers.get(directive) ?? "";
|
|
95
|
+
key += `::${directive}=${encodeURIComponent(value)}`;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
91
98
|
const cacheName = typeof options.cacheName === "function" ? await options.cacheName(c) : options.cacheName;
|
|
92
99
|
const cache3 = await caches.open(cacheName);
|
|
93
100
|
const response = await cache3.match(key);
|
|
@@ -98,8 +105,9 @@ const cache = (options) => {
|
|
|
98
105
|
if (!cacheableStatusCodes.has(c.res.status)) {
|
|
99
106
|
return;
|
|
100
107
|
}
|
|
101
|
-
|
|
102
|
-
|
|
108
|
+
const responseVary = parseVaryDirectives(c.res.headers.get("Vary"));
|
|
109
|
+
addHeader(c, responseVary);
|
|
110
|
+
if (shouldSkipCache(c.res, varyDirectives, responseVary)) {
|
|
103
111
|
return;
|
|
104
112
|
}
|
|
105
113
|
const res = c.res.clone();
|
package/dist/cjs/request.js
CHANGED
|
@@ -169,6 +169,21 @@ class HonoRequest {
|
|
|
169
169
|
arrayBuffer() {
|
|
170
170
|
return this.#cachedBody("arrayBuffer");
|
|
171
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* `.bytes()` parses the request body as a `Uint8Array`.
|
|
174
|
+
*
|
|
175
|
+
* @see {@link https://hono.dev/docs/api/request#bytes}
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* app.post('/entry', async (c) => {
|
|
180
|
+
* const body = await c.req.bytes()
|
|
181
|
+
* })
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
bytes() {
|
|
185
|
+
return this.#cachedBody("arrayBuffer").then((buffer) => new Uint8Array(buffer));
|
|
186
|
+
}
|
|
172
187
|
/**
|
|
173
188
|
* Parses the request body as a `Blob`.
|
|
174
189
|
* @example
|
package/dist/cjs/utils/cookie.js
CHANGED
|
@@ -72,14 +72,14 @@ const parse = (cookie, name) => {
|
|
|
72
72
|
return {};
|
|
73
73
|
}
|
|
74
74
|
const pairs = cookie.split(";");
|
|
75
|
-
const parsedCookie =
|
|
75
|
+
const parsedCookie = /* @__PURE__ */ Object.create(null);
|
|
76
76
|
for (const pairStr of pairs) {
|
|
77
77
|
const valueStartPos = pairStr.indexOf("=");
|
|
78
78
|
if (valueStartPos === -1) {
|
|
79
79
|
continue;
|
|
80
80
|
}
|
|
81
81
|
const cookieName = trimCookieWhitespace(pairStr.substring(0, valueStartPos));
|
|
82
|
-
if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName)) {
|
|
82
|
+
if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName) || cookieName in parsedCookie) {
|
|
83
83
|
continue;
|
|
84
84
|
}
|
|
85
85
|
let cookieValue = trimCookieWhitespace(pairStr.substring(valueStartPos + 1));
|
|
@@ -96,7 +96,7 @@ const parse = (cookie, name) => {
|
|
|
96
96
|
return parsedCookie;
|
|
97
97
|
};
|
|
98
98
|
const parseSigned = async (cookie, secret, name) => {
|
|
99
|
-
const parsedCookie =
|
|
99
|
+
const parsedCookie = /* @__PURE__ */ Object.create(null);
|
|
100
100
|
const secretKey = await getCryptoKey(secret);
|
|
101
101
|
for (const [key, value] of Object.entries(parse(cookie, name))) {
|
|
102
102
|
const signatureStartPos = value.lastIndexOf(".");
|
|
@@ -81,14 +81,20 @@ const verify = async (token, publicKey, algOrOptions) => {
|
|
|
81
81
|
throw new import_types.JwtAlgorithmMismatch(alg, header.alg);
|
|
82
82
|
}
|
|
83
83
|
const now = Math.floor(Date.now() / 1e3);
|
|
84
|
-
if (nbf && payload.nbf
|
|
85
|
-
|
|
84
|
+
if (nbf && payload.nbf !== void 0) {
|
|
85
|
+
if (typeof payload.nbf !== "number" || !Number.isFinite(payload.nbf) || payload.nbf > now) {
|
|
86
|
+
throw new import_types.JwtTokenNotBefore(token);
|
|
87
|
+
}
|
|
86
88
|
}
|
|
87
|
-
if (exp && payload.exp
|
|
88
|
-
|
|
89
|
+
if (exp && payload.exp !== void 0) {
|
|
90
|
+
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp) || payload.exp <= now) {
|
|
91
|
+
throw new import_types.JwtTokenExpired(token);
|
|
92
|
+
}
|
|
89
93
|
}
|
|
90
|
-
if (iat && payload.iat
|
|
91
|
-
|
|
94
|
+
if (iat && payload.iat !== void 0) {
|
|
95
|
+
if (typeof payload.iat !== "number" || !Number.isFinite(payload.iat) || now < payload.iat) {
|
|
96
|
+
throw new import_types.JwtTokenIssuedAt(now, payload.iat);
|
|
97
|
+
}
|
|
92
98
|
}
|
|
93
99
|
if (iss) {
|
|
94
100
|
if (!payload.iss) {
|
package/dist/cjs/utils/stream.js
CHANGED
|
@@ -48,7 +48,9 @@ class StreamingApi {
|
|
|
48
48
|
done ? controller.close() : controller.enqueue(value);
|
|
49
49
|
},
|
|
50
50
|
cancel: () => {
|
|
51
|
-
this.
|
|
51
|
+
if (!this.closed) {
|
|
52
|
+
this.abort();
|
|
53
|
+
}
|
|
52
54
|
}
|
|
53
55
|
});
|
|
54
56
|
}
|
|
@@ -70,11 +72,11 @@ class StreamingApi {
|
|
|
70
72
|
return new Promise((res) => setTimeout(res, ms));
|
|
71
73
|
}
|
|
72
74
|
async close() {
|
|
75
|
+
this.closed = true;
|
|
73
76
|
try {
|
|
74
77
|
await this.writer.close();
|
|
75
78
|
} catch {
|
|
76
79
|
}
|
|
77
|
-
this.closed = true;
|
|
78
80
|
}
|
|
79
81
|
async pipe(body) {
|
|
80
82
|
this.writer.releaseLock();
|
package/dist/jsx/utils.js
CHANGED
|
@@ -66,15 +66,105 @@ var isValidAttributeName = (name) => {
|
|
|
66
66
|
cacheValidName(validAttributeNameCache, validAttributeNameCacheMax, name);
|
|
67
67
|
return true;
|
|
68
68
|
};
|
|
69
|
+
var invalidStylePropertyNameCharRe = /[\s"'():;\\/\[\]{}\x00-\x1f\x7f-\x9f]/;
|
|
70
|
+
var validStylePropertyNameCache = /* @__PURE__ */ new Set();
|
|
71
|
+
var validStylePropertyNameCacheMax = 1024;
|
|
72
|
+
var isValidStylePropertyName = (name) => {
|
|
73
|
+
if (validStylePropertyNameCache.has(name)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
const len = name.length;
|
|
77
|
+
if (len === 0) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
for (let i = 0; i < len; i++) {
|
|
81
|
+
const c = name.charCodeAt(i);
|
|
82
|
+
if (!(c >= 97 && c <= 122 || // a-z
|
|
83
|
+
c >= 65 && c <= 90 || // A-Z
|
|
84
|
+
c >= 48 && c <= 57 || // 0-9
|
|
85
|
+
c === 45 || // -
|
|
86
|
+
c === 95)) {
|
|
87
|
+
if (!invalidStylePropertyNameCharRe.test(name)) {
|
|
88
|
+
cacheValidName(validStylePropertyNameCache, validStylePropertyNameCacheMax, name);
|
|
89
|
+
return true;
|
|
90
|
+
} else {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
cacheValidName(validStylePropertyNameCache, validStylePropertyNameCacheMax, name);
|
|
96
|
+
return true;
|
|
97
|
+
};
|
|
98
|
+
var unsafeStyleValueCharRe = /[;"'\\/\[\](){}]/;
|
|
99
|
+
var hasUnsafeStyleValue = (value) => {
|
|
100
|
+
if (!unsafeStyleValueCharRe.test(value)) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
let quote = 0;
|
|
104
|
+
const blockStack = [];
|
|
105
|
+
for (let i = 0, len = value.length; i < len; i++) {
|
|
106
|
+
const c = value.charCodeAt(i);
|
|
107
|
+
if (c === 92) {
|
|
108
|
+
if (i === len - 1) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
i++;
|
|
112
|
+
} else if (quote !== 0) {
|
|
113
|
+
if (c === 10 || c === 12 || c === 13) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
if (c === quote) {
|
|
117
|
+
quote = 0;
|
|
118
|
+
}
|
|
119
|
+
} else if (c === 47 && value.charCodeAt(i + 1) === 42) {
|
|
120
|
+
const end = value.indexOf("*/", i + 2);
|
|
121
|
+
if (end === -1) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
i = end + 1;
|
|
125
|
+
} else if (c === 34 || c === 39) {
|
|
126
|
+
quote = c;
|
|
127
|
+
} else if (c === 40) {
|
|
128
|
+
blockStack.push(41);
|
|
129
|
+
} else if (c === 91) {
|
|
130
|
+
blockStack.push(93);
|
|
131
|
+
} else if (c === 123 || c === 125) {
|
|
132
|
+
return true;
|
|
133
|
+
} else if (c === 41 || c === 93) {
|
|
134
|
+
if (blockStack[blockStack.length - 1] !== c) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
blockStack.pop();
|
|
138
|
+
} else if (c === 59 && blockStack.length === 0) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return quote !== 0 || blockStack.length !== 0;
|
|
143
|
+
};
|
|
69
144
|
var styleObjectForEach = (style, fn) => {
|
|
70
145
|
for (const [k, v] of Object.entries(style)) {
|
|
71
146
|
const key = k[0] === "-" || !/[A-Z]/.test(k) ? k : k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
147
|
+
if (!isValidStylePropertyName(key)) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (v == null) {
|
|
151
|
+
fn(key, null);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
let value;
|
|
155
|
+
if (typeof v === "number") {
|
|
156
|
+
value = !key.match(
|
|
75
157
|
/^(?:a|border-im|column(?:-c|s)|flex(?:$|-[^b])|grid-(?:ar|[^a])|font-w|li|or|sca|st|ta|wido|z)|ty$/
|
|
76
|
-
) ? `${v}px` : `${v}
|
|
77
|
-
)
|
|
158
|
+
) ? `${v}px` : `${v}`;
|
|
159
|
+
} else if (typeof v === "string") {
|
|
160
|
+
if (hasUnsafeStyleValue(v)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
value = v;
|
|
164
|
+
} else {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
fn(key, value);
|
|
78
168
|
}
|
|
79
169
|
};
|
|
80
170
|
export {
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
// src/middleware/cache/index.ts
|
|
2
2
|
var defaultCacheableStatusCodes = [200];
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
if (vary
|
|
6
|
-
return
|
|
3
|
+
var shouldSkipCacheControl = (cacheControl) => !!cacheControl && /(?:^|,\s*)(?:private|no-(?:store|cache))(?:\s*(?:=|,|$))/i.test(cacheControl);
|
|
4
|
+
var parseVaryDirectives = (vary) => {
|
|
5
|
+
if (vary == null) {
|
|
6
|
+
return [];
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
if (cacheControl && /(?:^|,\s*)(?:private|no-(?:store|cache))(?:\s*(?:=|,|$))/i.test(cacheControl)) {
|
|
10
|
-
return true;
|
|
11
|
-
}
|
|
12
|
-
if (res.headers.has("Set-Cookie")) {
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
return false;
|
|
8
|
+
return (Array.isArray(vary) ? vary : vary.split(",")).map((directive) => directive.trim().toLowerCase()).filter(Boolean);
|
|
16
9
|
};
|
|
10
|
+
var shouldSkipCache = (res, optionsVaryDirectives, responseVary) => responseVary.length && (!optionsVaryDirectives || responseVary.some((name) => !optionsVaryDirectives.has(name))) || shouldSkipCacheControl(res.headers.get("Cache-Control")) || res.headers.has("Set-Cookie");
|
|
17
11
|
var cache = (options) => {
|
|
18
12
|
if (!globalThis.caches) {
|
|
19
13
|
if (options.onCacheNotAvailable === false) {
|
|
@@ -28,8 +22,9 @@ var cache = (options) => {
|
|
|
28
22
|
options.wait = false;
|
|
29
23
|
}
|
|
30
24
|
const cacheControlDirectives = options.cacheControl?.split(",").map((directive) => directive.toLowerCase());
|
|
31
|
-
const
|
|
32
|
-
|
|
25
|
+
const optionsVaryList = parseVaryDirectives(options.vary);
|
|
26
|
+
const varyDirectives = optionsVaryList.length ? new Set(optionsVaryList) : void 0;
|
|
27
|
+
if (varyDirectives?.has("*")) {
|
|
33
28
|
throw new Error(
|
|
34
29
|
'Middleware vary configuration cannot include "*", as it disallows effective caching.'
|
|
35
30
|
);
|
|
@@ -37,7 +32,7 @@ var cache = (options) => {
|
|
|
37
32
|
const cacheableStatusCodes = new Set(
|
|
38
33
|
options.cacheableStatusCodes ?? defaultCacheableStatusCodes
|
|
39
34
|
);
|
|
40
|
-
const addHeader = (c) => {
|
|
35
|
+
const addHeader = (c, responseVary) => {
|
|
41
36
|
if (cacheControlDirectives) {
|
|
42
37
|
const existingDirectives = c.res.headers.get("Cache-Control")?.split(",").map((d) => d.trim().split("=", 1)[0]) ?? [];
|
|
43
38
|
for (const directive of cacheControlDirectives) {
|
|
@@ -49,24 +44,36 @@ var cache = (options) => {
|
|
|
49
44
|
}
|
|
50
45
|
}
|
|
51
46
|
if (varyDirectives) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
new Set(
|
|
55
|
-
[...existingDirectives, ...varyDirectives].map((directive) => directive.toLowerCase())
|
|
56
|
-
)
|
|
57
|
-
).sort();
|
|
58
|
-
if (vary.includes("*")) {
|
|
59
|
-
c.header("Vary", "*");
|
|
47
|
+
if (responseVary.length === 0) {
|
|
48
|
+
c.header("Vary", Array.from(varyDirectives).join(", "));
|
|
60
49
|
} else {
|
|
61
|
-
|
|
50
|
+
const merged = new Set(varyDirectives);
|
|
51
|
+
for (const directive of responseVary) {
|
|
52
|
+
merged.add(directive);
|
|
53
|
+
}
|
|
54
|
+
if (merged.has("*")) {
|
|
55
|
+
c.header("Vary", "*");
|
|
56
|
+
} else {
|
|
57
|
+
c.header("Vary", Array.from(merged).join(", "));
|
|
58
|
+
}
|
|
62
59
|
}
|
|
63
60
|
}
|
|
64
61
|
};
|
|
65
62
|
return async function cache2(c, next) {
|
|
63
|
+
if (c.req.method !== "GET" || c.req.raw.headers.has("Authorization")) {
|
|
64
|
+
await next();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
66
67
|
let key = c.req.url;
|
|
67
68
|
if (options.keyGenerator) {
|
|
68
69
|
key = await options.keyGenerator(c);
|
|
69
70
|
}
|
|
71
|
+
if (varyDirectives) {
|
|
72
|
+
for (const directive of varyDirectives) {
|
|
73
|
+
const value = c.req.raw.headers.get(directive) ?? "";
|
|
74
|
+
key += `::${directive}=${encodeURIComponent(value)}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
70
77
|
const cacheName = typeof options.cacheName === "function" ? await options.cacheName(c) : options.cacheName;
|
|
71
78
|
const cache3 = await caches.open(cacheName);
|
|
72
79
|
const response = await cache3.match(key);
|
|
@@ -77,8 +84,9 @@ var cache = (options) => {
|
|
|
77
84
|
if (!cacheableStatusCodes.has(c.res.status)) {
|
|
78
85
|
return;
|
|
79
86
|
}
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
const responseVary = parseVaryDirectives(c.res.headers.get("Vary"));
|
|
88
|
+
addHeader(c, responseVary);
|
|
89
|
+
if (shouldSkipCache(c.res, varyDirectives, responseVary)) {
|
|
82
90
|
return;
|
|
83
91
|
}
|
|
84
92
|
const res = c.res.clone();
|
package/dist/request.js
CHANGED
|
@@ -147,6 +147,21 @@ var HonoRequest = class {
|
|
|
147
147
|
arrayBuffer() {
|
|
148
148
|
return this.#cachedBody("arrayBuffer");
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* `.bytes()` parses the request body as a `Uint8Array`.
|
|
152
|
+
*
|
|
153
|
+
* @see {@link https://hono.dev/docs/api/request#bytes}
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* app.post('/entry', async (c) => {
|
|
158
|
+
* const body = await c.req.bytes()
|
|
159
|
+
* })
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
bytes() {
|
|
163
|
+
return this.#cachedBody("arrayBuffer").then((buffer) => new Uint8Array(buffer));
|
|
164
|
+
}
|
|
150
165
|
/**
|
|
151
166
|
* Parses the request body as a `Blob`.
|
|
152
167
|
* @example
|