hono 3.12.5 → 3.12.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.
@@ -62,13 +62,7 @@ var createResult = async (event, res) => {
62
62
  const contentEncoding = res.headers.get("content-encoding");
63
63
  isBase64Encoded = isContentEncodingBinary(contentEncoding);
64
64
  }
65
- let body;
66
- if (isBase64Encoded) {
67
- const buffer = await res.arrayBuffer();
68
- body = encodeBase64(buffer);
69
- } else {
70
- body = await res.text();
71
- }
65
+ const body = isBase64Encoded ? encodeBase64(await res.arrayBuffer()) : await res.text();
72
66
  const result = {
73
67
  body,
74
68
  headers: {},
@@ -93,13 +93,7 @@ const createResult = async (event, res) => {
93
93
  const contentEncoding = res.headers.get("content-encoding");
94
94
  isBase64Encoded = isContentEncodingBinary(contentEncoding);
95
95
  }
96
- let body;
97
- if (isBase64Encoded) {
98
- const buffer = await res.arrayBuffer();
99
- body = (0, import_encode.encodeBase64)(buffer);
100
- } else {
101
- body = await res.text();
102
- }
96
+ const body = isBase64Encoded ? (0, import_encode.encodeBase64)(await res.arrayBuffer()) : await res.text();
103
97
  const result = {
104
98
  body,
105
99
  headers: {},
@@ -45,6 +45,10 @@ var import_html = require("./utils/html");
45
45
  var import_stream = require("./utils/stream");
46
46
  var _status, _executionCtx, _headers, _preparedHeaders, _res, _isFresh;
47
47
  const TEXT_PLAIN = "text/plain; charset=UTF-8";
48
+ const setHeaders = (headers, map = {}) => {
49
+ Object.entries(map).forEach(([key, value]) => headers.set(key, value));
50
+ return headers;
51
+ };
48
52
  class Context {
49
53
  constructor(req, options) {
50
54
  this.env = {};
@@ -116,21 +120,21 @@ class Context {
116
120
  });
117
121
  }
118
122
  if (arg && typeof arg !== "number") {
119
- this.res = new Response(data, arg);
123
+ const headers2 = setHeaders(new Headers(arg.headers), __privateGet(this, _preparedHeaders));
124
+ return new Response(data, {
125
+ headers: headers2,
126
+ status: arg.status
127
+ });
120
128
  }
121
- const status = typeof arg === "number" ? arg : arg ? arg.status : __privateGet(this, _status);
129
+ const status = typeof arg === "number" ? arg : __privateGet(this, _status);
122
130
  __privateGet(this, _preparedHeaders) ?? __privateSet(this, _preparedHeaders, {});
123
131
  __privateGet(this, _headers) ?? __privateSet(this, _headers, new Headers());
124
- for (const [k, v] of Object.entries(__privateGet(this, _preparedHeaders))) {
125
- __privateGet(this, _headers).set(k, v);
126
- }
132
+ setHeaders(__privateGet(this, _headers), __privateGet(this, _preparedHeaders));
127
133
  if (__privateGet(this, _res)) {
128
134
  __privateGet(this, _res).headers.forEach((v, k) => {
129
135
  __privateGet(this, _headers)?.set(k, v);
130
136
  });
131
- for (const [k, v] of Object.entries(__privateGet(this, _preparedHeaders))) {
132
- __privateGet(this, _headers).set(k, v);
133
- }
137
+ setHeaders(__privateGet(this, _headers), __privateGet(this, _preparedHeaders));
134
138
  }
135
139
  headers ?? (headers = {});
136
140
  for (const [k, v] of Object.entries(headers)) {
@@ -43,6 +43,9 @@ const inspectRoutes = (hono) => {
43
43
  });
44
44
  };
45
45
  const showRoutes = (hono, opts) => {
46
+ const { process, Deno } = globalThis;
47
+ const isNoColor = typeof process !== "undefined" ? "NO_COLOR" in process?.env : typeof Deno?.noColor === "boolean" ? Deno.noColor : false;
48
+ const colorEnabled = opts?.colorize ?? !isNoColor;
46
49
  const routeData = {};
47
50
  let maxMethodLength = 0;
48
51
  let maxPathLength = 0;
@@ -60,7 +63,7 @@ const showRoutes = (hono, opts) => {
60
63
  return;
61
64
  }
62
65
  const { method, path, routes } = data;
63
- const methodStr = opts?.colorize ?? true ? `\x1B[32m${method}\x1B[0m` : method;
66
+ const methodStr = colorEnabled ? `\x1B[32m${method}\x1B[0m` : method;
64
67
  console.log(`${methodStr} ${" ".repeat(maxMethodLength - method.length)} ${path}`);
65
68
  if (!opts?.verbose) {
66
69
  return;
@@ -248,27 +248,16 @@ const _Hono = class extends defineDynamicClass() {
248
248
  let res;
249
249
  try {
250
250
  res = matchResult[0][0][0][0](c, async () => {
251
+ c.res = await this.notFoundHandler(c);
251
252
  });
252
- if (!res) {
253
- return this.notFoundHandler(c);
254
- }
255
253
  } catch (err) {
256
254
  return this.handleError(err, c);
257
255
  }
258
256
  if (res instanceof Response)
259
257
  return res;
260
- return (async () => {
261
- let awaited;
262
- try {
263
- awaited = await res;
264
- if (!awaited) {
265
- return this.notFoundHandler(c);
266
- }
267
- } catch (err) {
268
- return this.handleError(err, c);
269
- }
270
- return awaited;
271
- })();
258
+ return res.then(
259
+ (resolved) => resolved || (c.finalized ? c.res : this.notFoundHandler(c))
260
+ ).catch((err) => this.handleError(err, c));
272
261
  }
273
262
  const composed = (0, import_compose.compose)(matchResult[0], this.errorHandler, this.notFoundHandler);
274
263
  return (async () => {
@@ -54,16 +54,10 @@ const basicAuth = (options, ...users) => {
54
54
  const requestUser = auth(ctx.req);
55
55
  if (requestUser) {
56
56
  for (const user of users) {
57
- const usernameEqual = await (0, import_buffer.timingSafeEqual)(
58
- user.username,
59
- requestUser.username,
60
- options.hashFunction
61
- );
62
- const passwordEqual = await (0, import_buffer.timingSafeEqual)(
63
- user.password,
64
- requestUser.password,
65
- options.hashFunction
66
- );
57
+ const [usernameEqual, passwordEqual] = await Promise.all([
58
+ (0, import_buffer.timingSafeEqual)(user.username, requestUser.username, options.hashFunction),
59
+ (0, import_buffer.timingSafeEqual)(user.password, requestUser.password, options.hashFunction)
60
+ ]);
67
61
  if (usernameEqual && passwordEqual) {
68
62
  await next();
69
63
  return;
@@ -42,21 +42,20 @@ const cache = (options) => {
42
42
  const key = c.req.url;
43
43
  const cache3 = await caches.open(options.cacheName);
44
44
  const response = await cache3.match(key);
45
- if (!response) {
46
- await next();
47
- if (!c.res.ok) {
48
- return;
49
- }
50
- addHeader(c);
51
- const response2 = c.res.clone();
52
- if (options.wait) {
53
- await cache3.put(key, response2);
54
- } else {
55
- c.executionCtx.waitUntil(cache3.put(key, response2));
56
- }
57
- } else {
45
+ if (response) {
58
46
  return new Response(response.body, response);
59
47
  }
48
+ await next();
49
+ if (!c.res.ok) {
50
+ return;
51
+ }
52
+ addHeader(c);
53
+ const res = c.res.clone();
54
+ if (options.wait) {
55
+ await cache3.put(key, res);
56
+ } else {
57
+ c.executionCtx.waitUntil(cache3.put(key, res));
58
+ }
60
59
  };
61
60
  };
62
61
  // Annotate the CommonJS export names for ESM import in node:
@@ -58,9 +58,7 @@ const cors = (options) => {
58
58
  if (opts.exposeHeaders?.length) {
59
59
  set("Access-Control-Expose-Headers", opts.exposeHeaders.join(","));
60
60
  }
61
- if (c.req.method !== "OPTIONS") {
62
- await next();
63
- } else {
61
+ if (c.req.method === "OPTIONS") {
64
62
  if (opts.maxAge != null) {
65
63
  set("Access-Control-Max-Age", opts.maxAge.toString());
66
64
  }
@@ -86,6 +84,7 @@ const cors = (options) => {
86
84
  statusText: c.res.statusText
87
85
  });
88
86
  }
87
+ await next();
89
88
  };
90
89
  };
91
90
  // Annotate the CommonJS export names for ESM import in node:
@@ -40,13 +40,13 @@ const jwt = (options) => {
40
40
  if (credentials) {
41
41
  const parts = credentials.split(/\s+/);
42
42
  if (parts.length !== 2) {
43
- const res = new Response("Unauthorized", {
44
- status: 401,
45
- headers: {
46
- "WWW-Authenticate": `Bearer realm="${ctx.req.url}",error="invalid_request",error_description="invalid credentials structure"`
47
- }
43
+ throw new import_http_exception.HTTPException(401, {
44
+ res: unauthorizedResponse({
45
+ ctx,
46
+ error: "invalid_request",
47
+ errDescription: "invalid credentials structure"
48
+ })
48
49
  });
49
- throw new import_http_exception.HTTPException(401, { res });
50
50
  } else {
51
51
  token = parts[1];
52
52
  }
@@ -54,13 +54,13 @@ const jwt = (options) => {
54
54
  token = ctx.req.cookie(options.cookie);
55
55
  }
56
56
  if (!token) {
57
- const res = new Response("Unauthorized", {
58
- status: 401,
59
- headers: {
60
- "WWW-Authenticate": `Bearer realm="${ctx.req.url}",error="invalid_request",error_description="no authorization included in request"`
61
- }
57
+ throw new import_http_exception.HTTPException(401, {
58
+ res: unauthorizedResponse({
59
+ ctx,
60
+ error: "invalid_request",
61
+ errDescription: "no authorization included in request"
62
+ })
62
63
  });
63
- throw new import_http_exception.HTTPException(401, { res });
64
64
  }
65
65
  let payload;
66
66
  let msg = "";
@@ -70,19 +70,28 @@ const jwt = (options) => {
70
70
  msg = `${e}`;
71
71
  }
72
72
  if (!payload) {
73
- const res = new Response("Unauthorized", {
74
- status: 401,
75
- statusText: msg,
76
- headers: {
77
- "WWW-Authenticate": `Bearer realm="${ctx.req.url}",error="invalid_token",error_description="token verification failure"`
78
- }
73
+ throw new import_http_exception.HTTPException(401, {
74
+ res: unauthorizedResponse({
75
+ ctx,
76
+ error: "invalid_token",
77
+ statusText: msg,
78
+ errDescription: "token verification failure"
79
+ })
79
80
  });
80
- throw new import_http_exception.HTTPException(401, { res });
81
81
  }
82
82
  ctx.set("jwtPayload", payload);
83
83
  await next();
84
84
  };
85
85
  };
86
+ function unauthorizedResponse(opts) {
87
+ return new Response("Unauthorized", {
88
+ status: 401,
89
+ statusText: opts.statusText,
90
+ headers: {
91
+ "WWW-Authenticate": `Bearer realm="${opts.ctx.req.url}",error="${opts.error}",error_description="${opts.errDescription}"`
92
+ }
93
+ });
94
+ }
86
95
  const verify = import_jwt.Jwt.verify;
87
96
  const decode = import_jwt.Jwt.decode;
88
97
  const sign = import_jwt.Jwt.sign;
@@ -51,38 +51,48 @@ const DEFAULT_OPTIONS = {
51
51
  };
52
52
  const secureHeaders = (customOptions) => {
53
53
  const options = { ...DEFAULT_OPTIONS, ...customOptions };
54
- const headersToSet = Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([key, defaultValue]) => {
55
- const overrideValue = options[key];
56
- if (typeof overrideValue === "string")
57
- return [defaultValue[0], overrideValue];
58
- return defaultValue;
59
- });
54
+ const headersToSet = getFilteredHeaders(options);
60
55
  if (options.contentSecurityPolicy) {
61
- const cspDirectives = Object.entries(options.contentSecurityPolicy).map(([directive, value]) => {
62
- directive = directive.replace(
63
- /[A-Z]+(?![a-z])|[A-Z]/g,
64
- (match, offset) => (offset ? "-" : "") + match.toLowerCase()
65
- );
66
- return `${directive} ${Array.isArray(value) ? value.join(" ") : value}`;
67
- }).join("; ");
68
- headersToSet.push(["Content-Security-Policy", cspDirectives]);
56
+ headersToSet.push(["Content-Security-Policy", getCSPDirectives(options.contentSecurityPolicy)]);
69
57
  }
70
58
  if (options.reportingEndpoints) {
71
- const reportingEndpoints = options.reportingEndpoints.map((endpoint) => `${endpoint.name}="${endpoint.url}"`).join(", ");
72
- headersToSet.push(["Reporting-Endpoints", reportingEndpoints]);
59
+ headersToSet.push(["Reporting-Endpoints", getReportingEndpoints(options.reportingEndpoints)]);
73
60
  }
74
61
  if (options.reportTo) {
75
- const reportToOptions = options.reportTo.map((option) => JSON.stringify(option)).join(", ");
76
- headersToSet.push(["Report-To", reportToOptions]);
62
+ headersToSet.push(["Report-To", getReportToOptions(options.reportTo)]);
77
63
  }
78
64
  return async function secureHeaders2(ctx, next) {
79
65
  await next();
80
- headersToSet.forEach(([header, value]) => {
81
- ctx.res.headers.set(header, value);
82
- });
66
+ setHeaders(ctx, headersToSet);
83
67
  ctx.res.headers.delete("X-Powered-By");
84
68
  };
85
69
  };
70
+ function getFilteredHeaders(options) {
71
+ return Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([key, defaultValue]) => {
72
+ const overrideValue = options[key];
73
+ return typeof overrideValue === "string" ? [defaultValue[0], overrideValue] : defaultValue;
74
+ });
75
+ }
76
+ function getCSPDirectives(contentSecurityPolicy) {
77
+ return Object.entries(contentSecurityPolicy || []).map(([directive, value]) => {
78
+ const kebabCaseDirective = directive.replace(
79
+ /[A-Z]+(?![a-z])|[A-Z]/g,
80
+ (match, offset) => offset ? "-" + match.toLowerCase() : match.toLowerCase()
81
+ );
82
+ return `${kebabCaseDirective} ${Array.isArray(value) ? value.join(" ") : value}`;
83
+ }).join("; ");
84
+ }
85
+ function getReportingEndpoints(reportingEndpoints = []) {
86
+ return reportingEndpoints.map((endpoint) => `${endpoint.name}="${endpoint.url}"`).join(", ");
87
+ }
88
+ function getReportToOptions(reportTo = []) {
89
+ return reportTo.map((option) => JSON.stringify(option)).join(", ");
90
+ }
91
+ function setHeaders(ctx, headersToSet) {
92
+ headersToSet.forEach(([header, value]) => {
93
+ ctx.res.headers.set(header, value);
94
+ });
95
+ }
86
96
  // Annotate the CommonJS export names for ESM import in node:
87
97
  0 && (module.exports = {
88
98
  secureHeaders
@@ -21,39 +21,55 @@ __export(body_exports, {
21
21
  parseBody: () => parseBody
22
22
  });
23
23
  module.exports = __toCommonJS(body_exports);
24
- const isArrayField = (value) => {
25
- return Array.isArray(value);
26
- };
27
- const parseBody = async (request, options = {
28
- all: false
29
- }) => {
30
- let body = {};
24
+ const parseBody = async (request, options = { all: false }) => {
31
25
  const contentType = request.headers.get("Content-Type");
32
- if (contentType && (contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded"))) {
33
- const formData = await request.formData();
34
- if (formData) {
35
- const form = {};
36
- formData.forEach((value, key) => {
37
- const shouldParseAllValues = options.all || key.slice(-2) === "[]";
38
- if (!shouldParseAllValues) {
39
- form[key] = value;
40
- return;
41
- }
42
- if (form[key] && isArrayField(form[key])) {
43
- ;
44
- form[key].push(value);
45
- return;
46
- }
47
- if (form[key]) {
48
- form[key] = [form[key], value];
49
- return;
50
- }
51
- form[key] = value;
52
- });
53
- body = form;
26
+ if (isFormDataContent(contentType)) {
27
+ return parseFormData(request, options);
28
+ }
29
+ return {};
30
+ };
31
+ function isFormDataContent(contentType) {
32
+ if (contentType === null) {
33
+ return false;
34
+ }
35
+ return contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded");
36
+ }
37
+ async function parseFormData(request, options) {
38
+ const formData = await request.formData();
39
+ if (formData) {
40
+ return convertFormDataToBodyData(formData, options);
41
+ }
42
+ return {};
43
+ }
44
+ function convertFormDataToBodyData(formData, options) {
45
+ const form = {};
46
+ formData.forEach((value, key) => {
47
+ const shouldParseAllValues = options.all || key.endsWith("[]");
48
+ if (!shouldParseAllValues) {
49
+ form[key] = value;
50
+ } else {
51
+ handleParsingAllValues(form, key, value);
54
52
  }
53
+ });
54
+ return form;
55
+ }
56
+ const handleParsingAllValues = (form, key, value) => {
57
+ if (form[key] && isArrayField(form[key])) {
58
+ appendToExistingArray(form[key], value);
59
+ } else if (form[key]) {
60
+ convertToNewArray(form, key, value);
61
+ } else {
62
+ form[key] = value;
55
63
  }
56
- return body;
64
+ };
65
+ function isArrayField(field) {
66
+ return Array.isArray(field);
67
+ }
68
+ const appendToExistingArray = (arr, value) => {
69
+ arr.push(value);
70
+ };
71
+ const convertToNewArray = (form, key, value) => {
72
+ form[key] = [form[key], value];
57
73
  };
58
74
  // Annotate the CommonJS export names for ESM import in node:
59
75
  0 && (module.exports = {
@@ -31,11 +31,7 @@ class StreamingApi {
31
31
  this.responseReadable = new ReadableStream({
32
32
  async pull(controller) {
33
33
  const { done, value } = await reader.read();
34
- if (done) {
35
- controller.close();
36
- } else {
37
- controller.enqueue(value);
38
- }
34
+ done ? controller.close() : controller.enqueue(value);
39
35
  },
40
36
  cancel: () => {
41
37
  this.abortSubscribers.forEach((subscriber) => subscriber());
@@ -38,29 +38,25 @@ const splitPath = (path) => {
38
38
  }
39
39
  return paths;
40
40
  };
41
- const splitRoutingPath = (path) => {
41
+ const splitRoutingPath = (routePath) => {
42
+ const { groups, path } = extractGroupsFromPath(routePath);
43
+ const paths = splitPath(path);
44
+ return replaceGroupMarks(paths, groups);
45
+ };
46
+ const extractGroupsFromPath = (path) => {
42
47
  const groups = [];
43
- for (let i = 0; ; ) {
44
- let replaced = false;
45
- path = path.replace(/\{[^}]+\}/g, (m) => {
46
- const mark = `@\\${i}`;
47
- groups[i] = [mark, m];
48
- i++;
49
- replaced = true;
50
- return mark;
51
- });
52
- if (!replaced) {
53
- break;
54
- }
55
- }
56
- const paths = path.split("/");
57
- if (paths[0] === "") {
58
- paths.shift();
59
- }
48
+ path = path.replace(/\{[^}]+\}/g, (match, index) => {
49
+ const mark = `@${index}`;
50
+ groups.push([mark, match]);
51
+ return mark;
52
+ });
53
+ return { groups, path };
54
+ };
55
+ const replaceGroupMarks = (paths, groups) => {
60
56
  for (let i = groups.length - 1; i >= 0; i--) {
61
57
  const [mark] = groups[i];
62
58
  for (let j = paths.length - 1; j >= 0; j--) {
63
- if (paths[j].indexOf(mark) !== -1) {
59
+ if (paths[j].includes(mark)) {
64
60
  paths[j] = paths[j].replace(mark, groups[i][1]);
65
61
  break;
66
62
  }
package/dist/context.js CHANGED
@@ -22,6 +22,10 @@ import { serialize } from "./utils/cookie.js";
22
22
  import { resolveCallback, HtmlEscapedCallbackPhase } from "./utils/html.js";
23
23
  import { StreamingApi } from "./utils/stream.js";
24
24
  var TEXT_PLAIN = "text/plain; charset=UTF-8";
25
+ var setHeaders = (headers, map = {}) => {
26
+ Object.entries(map).forEach(([key, value]) => headers.set(key, value));
27
+ return headers;
28
+ };
25
29
  var _status, _executionCtx, _headers, _preparedHeaders, _res, _isFresh;
26
30
  var Context = class {
27
31
  constructor(req, options) {
@@ -94,21 +98,21 @@ var Context = class {
94
98
  });
95
99
  }
96
100
  if (arg && typeof arg !== "number") {
97
- this.res = new Response(data, arg);
101
+ const headers2 = setHeaders(new Headers(arg.headers), __privateGet(this, _preparedHeaders));
102
+ return new Response(data, {
103
+ headers: headers2,
104
+ status: arg.status
105
+ });
98
106
  }
99
- const status = typeof arg === "number" ? arg : arg ? arg.status : __privateGet(this, _status);
107
+ const status = typeof arg === "number" ? arg : __privateGet(this, _status);
100
108
  __privateGet(this, _preparedHeaders) ?? __privateSet(this, _preparedHeaders, {});
101
109
  __privateGet(this, _headers) ?? __privateSet(this, _headers, new Headers());
102
- for (const [k, v] of Object.entries(__privateGet(this, _preparedHeaders))) {
103
- __privateGet(this, _headers).set(k, v);
104
- }
110
+ setHeaders(__privateGet(this, _headers), __privateGet(this, _preparedHeaders));
105
111
  if (__privateGet(this, _res)) {
106
112
  __privateGet(this, _res).headers.forEach((v, k) => {
107
113
  __privateGet(this, _headers)?.set(k, v);
108
114
  });
109
- for (const [k, v] of Object.entries(__privateGet(this, _preparedHeaders))) {
110
- __privateGet(this, _headers).set(k, v);
111
- }
115
+ setHeaders(__privateGet(this, _headers), __privateGet(this, _preparedHeaders));
112
116
  }
113
117
  headers ?? (headers = {});
114
118
  for (const [k, v] of Object.entries(headers)) {
@@ -19,6 +19,9 @@ var inspectRoutes = (hono) => {
19
19
  });
20
20
  };
21
21
  var showRoutes = (hono, opts) => {
22
+ const { process, Deno } = globalThis;
23
+ const isNoColor = typeof process !== "undefined" ? "NO_COLOR" in process?.env : typeof Deno?.noColor === "boolean" ? Deno.noColor : false;
24
+ const colorEnabled = opts?.colorize ?? !isNoColor;
22
25
  const routeData = {};
23
26
  let maxMethodLength = 0;
24
27
  let maxPathLength = 0;
@@ -36,7 +39,7 @@ var showRoutes = (hono, opts) => {
36
39
  return;
37
40
  }
38
41
  const { method, path, routes } = data;
39
- const methodStr = opts?.colorize ?? true ? `\x1B[32m${method}\x1B[0m` : method;
42
+ const methodStr = colorEnabled ? `\x1B[32m${method}\x1B[0m` : method;
40
43
  console.log(`${methodStr} ${" ".repeat(maxMethodLength - method.length)} ${path}`);
41
44
  if (!opts?.verbose) {
42
45
  return;
package/dist/hono-base.js CHANGED
@@ -226,27 +226,16 @@ var _Hono = class extends defineDynamicClass() {
226
226
  let res;
227
227
  try {
228
228
  res = matchResult[0][0][0][0](c, async () => {
229
+ c.res = await this.notFoundHandler(c);
229
230
  });
230
- if (!res) {
231
- return this.notFoundHandler(c);
232
- }
233
231
  } catch (err) {
234
232
  return this.handleError(err, c);
235
233
  }
236
234
  if (res instanceof Response)
237
235
  return res;
238
- return (async () => {
239
- let awaited;
240
- try {
241
- awaited = await res;
242
- if (!awaited) {
243
- return this.notFoundHandler(c);
244
- }
245
- } catch (err) {
246
- return this.handleError(err, c);
247
- }
248
- return awaited;
249
- })();
236
+ return res.then(
237
+ (resolved) => resolved || (c.finalized ? c.res : this.notFoundHandler(c))
238
+ ).catch((err) => this.handleError(err, c));
250
239
  }
251
240
  const composed = compose(matchResult[0], this.errorHandler, this.notFoundHandler);
252
241
  return (async () => {
@@ -32,16 +32,10 @@ var basicAuth = (options, ...users) => {
32
32
  const requestUser = auth(ctx.req);
33
33
  if (requestUser) {
34
34
  for (const user of users) {
35
- const usernameEqual = await timingSafeEqual(
36
- user.username,
37
- requestUser.username,
38
- options.hashFunction
39
- );
40
- const passwordEqual = await timingSafeEqual(
41
- user.password,
42
- requestUser.password,
43
- options.hashFunction
44
- );
35
+ const [usernameEqual, passwordEqual] = await Promise.all([
36
+ timingSafeEqual(user.username, requestUser.username, options.hashFunction),
37
+ timingSafeEqual(user.password, requestUser.password, options.hashFunction)
38
+ ]);
45
39
  if (usernameEqual && passwordEqual) {
46
40
  await next();
47
41
  return;
@@ -20,21 +20,20 @@ var cache = (options) => {
20
20
  const key = c.req.url;
21
21
  const cache3 = await caches.open(options.cacheName);
22
22
  const response = await cache3.match(key);
23
- if (!response) {
24
- await next();
25
- if (!c.res.ok) {
26
- return;
27
- }
28
- addHeader(c);
29
- const response2 = c.res.clone();
30
- if (options.wait) {
31
- await cache3.put(key, response2);
32
- } else {
33
- c.executionCtx.waitUntil(cache3.put(key, response2));
34
- }
35
- } else {
23
+ if (response) {
36
24
  return new Response(response.body, response);
37
25
  }
26
+ await next();
27
+ if (!c.res.ok) {
28
+ return;
29
+ }
30
+ addHeader(c);
31
+ const res = c.res.clone();
32
+ if (options.wait) {
33
+ await cache3.put(key, res);
34
+ } else {
35
+ c.executionCtx.waitUntil(cache3.put(key, res));
36
+ }
38
37
  };
39
38
  };
40
39
  export {
@@ -36,9 +36,7 @@ var cors = (options) => {
36
36
  if (opts.exposeHeaders?.length) {
37
37
  set("Access-Control-Expose-Headers", opts.exposeHeaders.join(","));
38
38
  }
39
- if (c.req.method !== "OPTIONS") {
40
- await next();
41
- } else {
39
+ if (c.req.method === "OPTIONS") {
42
40
  if (opts.maxAge != null) {
43
41
  set("Access-Control-Max-Age", opts.maxAge.toString());
44
42
  }
@@ -64,6 +62,7 @@ var cors = (options) => {
64
62
  statusText: c.res.statusText
65
63
  });
66
64
  }
65
+ await next();
67
66
  };
68
67
  };
69
68
  export {
@@ -15,13 +15,13 @@ var jwt = (options) => {
15
15
  if (credentials) {
16
16
  const parts = credentials.split(/\s+/);
17
17
  if (parts.length !== 2) {
18
- const res = new Response("Unauthorized", {
19
- status: 401,
20
- headers: {
21
- "WWW-Authenticate": `Bearer realm="${ctx.req.url}",error="invalid_request",error_description="invalid credentials structure"`
22
- }
18
+ throw new HTTPException(401, {
19
+ res: unauthorizedResponse({
20
+ ctx,
21
+ error: "invalid_request",
22
+ errDescription: "invalid credentials structure"
23
+ })
23
24
  });
24
- throw new HTTPException(401, { res });
25
25
  } else {
26
26
  token = parts[1];
27
27
  }
@@ -29,13 +29,13 @@ var jwt = (options) => {
29
29
  token = ctx.req.cookie(options.cookie);
30
30
  }
31
31
  if (!token) {
32
- const res = new Response("Unauthorized", {
33
- status: 401,
34
- headers: {
35
- "WWW-Authenticate": `Bearer realm="${ctx.req.url}",error="invalid_request",error_description="no authorization included in request"`
36
- }
32
+ throw new HTTPException(401, {
33
+ res: unauthorizedResponse({
34
+ ctx,
35
+ error: "invalid_request",
36
+ errDescription: "no authorization included in request"
37
+ })
37
38
  });
38
- throw new HTTPException(401, { res });
39
39
  }
40
40
  let payload;
41
41
  let msg = "";
@@ -45,19 +45,28 @@ var jwt = (options) => {
45
45
  msg = `${e}`;
46
46
  }
47
47
  if (!payload) {
48
- const res = new Response("Unauthorized", {
49
- status: 401,
50
- statusText: msg,
51
- headers: {
52
- "WWW-Authenticate": `Bearer realm="${ctx.req.url}",error="invalid_token",error_description="token verification failure"`
53
- }
48
+ throw new HTTPException(401, {
49
+ res: unauthorizedResponse({
50
+ ctx,
51
+ error: "invalid_token",
52
+ statusText: msg,
53
+ errDescription: "token verification failure"
54
+ })
54
55
  });
55
- throw new HTTPException(401, { res });
56
56
  }
57
57
  ctx.set("jwtPayload", payload);
58
58
  await next();
59
59
  };
60
60
  };
61
+ function unauthorizedResponse(opts) {
62
+ return new Response("Unauthorized", {
63
+ status: 401,
64
+ statusText: opts.statusText,
65
+ headers: {
66
+ "WWW-Authenticate": `Bearer realm="${opts.ctx.req.url}",error="${opts.error}",error_description="${opts.errDescription}"`
67
+ }
68
+ });
69
+ }
61
70
  var verify = Jwt.verify;
62
71
  var decode = Jwt.decode;
63
72
  var sign = Jwt.sign;
@@ -29,38 +29,48 @@ var DEFAULT_OPTIONS = {
29
29
  };
30
30
  var secureHeaders = (customOptions) => {
31
31
  const options = { ...DEFAULT_OPTIONS, ...customOptions };
32
- const headersToSet = Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([key, defaultValue]) => {
33
- const overrideValue = options[key];
34
- if (typeof overrideValue === "string")
35
- return [defaultValue[0], overrideValue];
36
- return defaultValue;
37
- });
32
+ const headersToSet = getFilteredHeaders(options);
38
33
  if (options.contentSecurityPolicy) {
39
- const cspDirectives = Object.entries(options.contentSecurityPolicy).map(([directive, value]) => {
40
- directive = directive.replace(
41
- /[A-Z]+(?![a-z])|[A-Z]/g,
42
- (match, offset) => (offset ? "-" : "") + match.toLowerCase()
43
- );
44
- return `${directive} ${Array.isArray(value) ? value.join(" ") : value}`;
45
- }).join("; ");
46
- headersToSet.push(["Content-Security-Policy", cspDirectives]);
34
+ headersToSet.push(["Content-Security-Policy", getCSPDirectives(options.contentSecurityPolicy)]);
47
35
  }
48
36
  if (options.reportingEndpoints) {
49
- const reportingEndpoints = options.reportingEndpoints.map((endpoint) => `${endpoint.name}="${endpoint.url}"`).join(", ");
50
- headersToSet.push(["Reporting-Endpoints", reportingEndpoints]);
37
+ headersToSet.push(["Reporting-Endpoints", getReportingEndpoints(options.reportingEndpoints)]);
51
38
  }
52
39
  if (options.reportTo) {
53
- const reportToOptions = options.reportTo.map((option) => JSON.stringify(option)).join(", ");
54
- headersToSet.push(["Report-To", reportToOptions]);
40
+ headersToSet.push(["Report-To", getReportToOptions(options.reportTo)]);
55
41
  }
56
42
  return async function secureHeaders2(ctx, next) {
57
43
  await next();
58
- headersToSet.forEach(([header, value]) => {
59
- ctx.res.headers.set(header, value);
60
- });
44
+ setHeaders(ctx, headersToSet);
61
45
  ctx.res.headers.delete("X-Powered-By");
62
46
  };
63
47
  };
48
+ function getFilteredHeaders(options) {
49
+ return Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([key, defaultValue]) => {
50
+ const overrideValue = options[key];
51
+ return typeof overrideValue === "string" ? [defaultValue[0], overrideValue] : defaultValue;
52
+ });
53
+ }
54
+ function getCSPDirectives(contentSecurityPolicy) {
55
+ return Object.entries(contentSecurityPolicy || []).map(([directive, value]) => {
56
+ const kebabCaseDirective = directive.replace(
57
+ /[A-Z]+(?![a-z])|[A-Z]/g,
58
+ (match, offset) => offset ? "-" + match.toLowerCase() : match.toLowerCase()
59
+ );
60
+ return `${kebabCaseDirective} ${Array.isArray(value) ? value.join(" ") : value}`;
61
+ }).join("; ");
62
+ }
63
+ function getReportingEndpoints(reportingEndpoints = []) {
64
+ return reportingEndpoints.map((endpoint) => `${endpoint.name}="${endpoint.url}"`).join(", ");
65
+ }
66
+ function getReportToOptions(reportTo = []) {
67
+ return reportTo.map((option) => JSON.stringify(option)).join(", ");
68
+ }
69
+ function setHeaders(ctx, headersToSet) {
70
+ headersToSet.forEach(([header, value]) => {
71
+ ctx.res.headers.set(header, value);
72
+ });
73
+ }
64
74
  export {
65
75
  secureHeaders
66
76
  };
@@ -16,6 +16,20 @@ interface CloudFrontCustomOrigin {
16
16
  readTimeout: number;
17
17
  sslProtocols: string[];
18
18
  }
19
+ interface CloudFrontS3Origin {
20
+ authMethod: 'origin-access-identity' | 'none';
21
+ customHeaders: CloudFrontHeaders;
22
+ domainName: string;
23
+ path: string;
24
+ region: string;
25
+ }
26
+ type CloudFrontOrigin = {
27
+ s3: CloudFrontS3Origin;
28
+ custom?: never;
29
+ } | {
30
+ custom: CloudFrontCustomOrigin;
31
+ s3?: never;
32
+ };
19
33
  export interface CloudFrontRequest {
20
34
  clientIp: string;
21
35
  headers: CloudFrontHeaders;
@@ -28,9 +42,7 @@ export interface CloudFrontRequest {
28
42
  encoding: string;
29
43
  data: string;
30
44
  };
31
- origin?: {
32
- custom: CloudFrontCustomOrigin;
33
- };
45
+ origin?: CloudFrontOrigin;
34
46
  }
35
47
  export interface CloudFrontResponse {
36
48
  headers: CloudFrontHeaders;
@@ -152,7 +152,73 @@ export interface HandlerInterface<E extends Env = Env, M extends string = string
152
152
  <P extends string, I extends Input = {}, R extends HandlerResponse<any> = any>(path: P, ...handlers: H<E, MergePath<BasePath, P>, I, R>[]): Hono<E, S & ToSchema<M, MergePath<BasePath, P>, I['in'], MergeTypedResponseData<R>>, BasePath>;
153
153
  }
154
154
  export interface MiddlewareHandlerInterface<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'> {
155
- <E2 extends Env = E>(...handlers: MiddlewareHandler<E2, MergePath<BasePath, ExtractKey<S>>>[]): Hono<E, S, BasePath>;
155
+ <E2 extends Env = E>(...handlers: MiddlewareHandler<E2, MergePath<BasePath, ExtractKey<S>>>[]): Hono<IntersectNonAnyTypes<[E, E2]>, S, BasePath>;
156
+ <E2 extends Env = E>(handler: MiddlewareHandler<E2, MergePath<BasePath, ExtractKey<S>>>): Hono<IntersectNonAnyTypes<[E, E2]>, S, BasePath>;
157
+ <E2 extends Env = E, E3 extends Env = IntersectNonAnyTypes<[E, E2]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [MiddlewareHandler<E2, P>, MiddlewareHandler<E3, P>]): Hono<IntersectNonAnyTypes<[E, E2, E3]>, S, BasePath>;
158
+ <E2 extends Env = E, E3 extends Env = E, E4 extends Env = IntersectNonAnyTypes<[E, E2, E3]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [MiddlewareHandler<E2, P>, MiddlewareHandler<E3, P>, MiddlewareHandler<E4, P>]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4]>, S, BasePath>;
159
+ <E2 extends Env = E, E3 extends Env = E, E4 extends Env = E, E5 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [
160
+ MiddlewareHandler<E2, P>,
161
+ MiddlewareHandler<E3, P>,
162
+ MiddlewareHandler<E4, P>,
163
+ MiddlewareHandler<E5, P>
164
+ ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5]>, S, BasePath>;
165
+ <E2 extends Env = E, E3 extends Env = E, E4 extends Env = E, E5 extends Env = E, E6 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [
166
+ MiddlewareHandler<E2, P>,
167
+ MiddlewareHandler<E3, P>,
168
+ MiddlewareHandler<E4, P>,
169
+ MiddlewareHandler<E5, P>,
170
+ MiddlewareHandler<E6, P>
171
+ ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6]>, S, BasePath>;
172
+ <E2 extends Env = E, E3 extends Env = E, E4 extends Env = E, E5 extends Env = E, E6 extends Env = E, E7 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [
173
+ MiddlewareHandler<E2, P>,
174
+ MiddlewareHandler<E3, P>,
175
+ MiddlewareHandler<E4, P>,
176
+ MiddlewareHandler<E5, P>,
177
+ MiddlewareHandler<E6, P>,
178
+ MiddlewareHandler<E7, P>
179
+ ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7]>, S, BasePath>;
180
+ <E2 extends Env = E, E3 extends Env = E, E4 extends Env = E, E5 extends Env = E, E6 extends Env = E, E7 extends Env = E, E8 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [
181
+ MiddlewareHandler<E2, P>,
182
+ MiddlewareHandler<E3, P>,
183
+ MiddlewareHandler<E4, P>,
184
+ MiddlewareHandler<E5, P>,
185
+ MiddlewareHandler<E6, P>,
186
+ MiddlewareHandler<E7, P>,
187
+ MiddlewareHandler<E8, P>
188
+ ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8]>, S, BasePath>;
189
+ <E2 extends Env = E, E3 extends Env = E, E4 extends Env = E, E5 extends Env = E, E6 extends Env = E, E7 extends Env = E, E8 extends Env = E, E9 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [
190
+ MiddlewareHandler<E2, P>,
191
+ MiddlewareHandler<E3, P>,
192
+ MiddlewareHandler<E4, P>,
193
+ MiddlewareHandler<E5, P>,
194
+ MiddlewareHandler<E6, P>,
195
+ MiddlewareHandler<E7, P>,
196
+ MiddlewareHandler<E8, P>,
197
+ MiddlewareHandler<E9, P>
198
+ ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9]>, S, BasePath>;
199
+ <E2 extends Env = E, E3 extends Env = E, E4 extends Env = E, E5 extends Env = E, E6 extends Env = E, E7 extends Env = E, E8 extends Env = E, E9 extends Env = E, E10 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [
200
+ MiddlewareHandler<E2, P>,
201
+ MiddlewareHandler<E3, P>,
202
+ MiddlewareHandler<E4, P>,
203
+ MiddlewareHandler<E5, P>,
204
+ MiddlewareHandler<E6, P>,
205
+ MiddlewareHandler<E7, P>,
206
+ MiddlewareHandler<E8, P>,
207
+ MiddlewareHandler<E9, P>,
208
+ MiddlewareHandler<E10, P>
209
+ ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10]>, S, BasePath>;
210
+ <E2 extends Env = E, E3 extends Env = E, E4 extends Env = E, E5 extends Env = E, E6 extends Env = E, E7 extends Env = E, E8 extends Env = E, E9 extends Env = E, E10 extends Env = E, E11 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10]>, P extends string = MergePath<BasePath, ExtractKey<S>>>(...handlers: [
211
+ MiddlewareHandler<E2, P>,
212
+ MiddlewareHandler<E3, P>,
213
+ MiddlewareHandler<E4, P>,
214
+ MiddlewareHandler<E5, P>,
215
+ MiddlewareHandler<E6, P>,
216
+ MiddlewareHandler<E7, P>,
217
+ MiddlewareHandler<E8, P>,
218
+ MiddlewareHandler<E9, P>,
219
+ MiddlewareHandler<E10, P>,
220
+ MiddlewareHandler<E11, P>
221
+ ]): Hono<IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11]>, S, BasePath>;
156
222
  <P extends string, E2 extends Env = E>(path: P, ...handlers: MiddlewareHandler<E2, MergePath<BasePath, P>>[]): Hono<E, S, BasePath>;
157
223
  }
158
224
  export interface OnHandlerInterface<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'> {
@@ -1,6 +1,6 @@
1
1
  export type Pattern = readonly [string, string, RegExp | true] | '*';
2
2
  export declare const splitPath: (path: string) => string[];
3
- export declare const splitRoutingPath: (path: string) => string[];
3
+ export declare const splitRoutingPath: (routePath: string) => string[];
4
4
  export declare const getPattern: (label: string) => Pattern | null;
5
5
  export declare const getPath: (request: Request) => string;
6
6
  export declare const getQueryStrings: (url: string) => string;
@@ -1,37 +1,53 @@
1
1
  // src/utils/body.ts
2
- var isArrayField = (value) => {
3
- return Array.isArray(value);
4
- };
5
- var parseBody = async (request, options = {
6
- all: false
7
- }) => {
8
- let body = {};
2
+ var parseBody = async (request, options = { all: false }) => {
9
3
  const contentType = request.headers.get("Content-Type");
10
- if (contentType && (contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded"))) {
11
- const formData = await request.formData();
12
- if (formData) {
13
- const form = {};
14
- formData.forEach((value, key) => {
15
- const shouldParseAllValues = options.all || key.slice(-2) === "[]";
16
- if (!shouldParseAllValues) {
17
- form[key] = value;
18
- return;
19
- }
20
- if (form[key] && isArrayField(form[key])) {
21
- ;
22
- form[key].push(value);
23
- return;
24
- }
25
- if (form[key]) {
26
- form[key] = [form[key], value];
27
- return;
28
- }
29
- form[key] = value;
30
- });
31
- body = form;
4
+ if (isFormDataContent(contentType)) {
5
+ return parseFormData(request, options);
6
+ }
7
+ return {};
8
+ };
9
+ function isFormDataContent(contentType) {
10
+ if (contentType === null) {
11
+ return false;
12
+ }
13
+ return contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded");
14
+ }
15
+ async function parseFormData(request, options) {
16
+ const formData = await request.formData();
17
+ if (formData) {
18
+ return convertFormDataToBodyData(formData, options);
19
+ }
20
+ return {};
21
+ }
22
+ function convertFormDataToBodyData(formData, options) {
23
+ const form = {};
24
+ formData.forEach((value, key) => {
25
+ const shouldParseAllValues = options.all || key.endsWith("[]");
26
+ if (!shouldParseAllValues) {
27
+ form[key] = value;
28
+ } else {
29
+ handleParsingAllValues(form, key, value);
32
30
  }
31
+ });
32
+ return form;
33
+ }
34
+ var handleParsingAllValues = (form, key, value) => {
35
+ if (form[key] && isArrayField(form[key])) {
36
+ appendToExistingArray(form[key], value);
37
+ } else if (form[key]) {
38
+ convertToNewArray(form, key, value);
39
+ } else {
40
+ form[key] = value;
33
41
  }
34
- return body;
42
+ };
43
+ function isArrayField(field) {
44
+ return Array.isArray(field);
45
+ }
46
+ var appendToExistingArray = (arr, value) => {
47
+ arr.push(value);
48
+ };
49
+ var convertToNewArray = (form, key, value) => {
50
+ form[key] = [form[key], value];
35
51
  };
36
52
  export {
37
53
  parseBody
@@ -9,11 +9,7 @@ var StreamingApi = class {
9
9
  this.responseReadable = new ReadableStream({
10
10
  async pull(controller) {
11
11
  const { done, value } = await reader.read();
12
- if (done) {
13
- controller.close();
14
- } else {
15
- controller.enqueue(value);
16
- }
12
+ done ? controller.close() : controller.enqueue(value);
17
13
  },
18
14
  cancel: () => {
19
15
  this.abortSubscribers.forEach((subscriber) => subscriber());
package/dist/utils/url.js CHANGED
@@ -6,29 +6,25 @@ var splitPath = (path) => {
6
6
  }
7
7
  return paths;
8
8
  };
9
- var splitRoutingPath = (path) => {
9
+ var splitRoutingPath = (routePath) => {
10
+ const { groups, path } = extractGroupsFromPath(routePath);
11
+ const paths = splitPath(path);
12
+ return replaceGroupMarks(paths, groups);
13
+ };
14
+ var extractGroupsFromPath = (path) => {
10
15
  const groups = [];
11
- for (let i = 0; ; ) {
12
- let replaced = false;
13
- path = path.replace(/\{[^}]+\}/g, (m) => {
14
- const mark = `@\\${i}`;
15
- groups[i] = [mark, m];
16
- i++;
17
- replaced = true;
18
- return mark;
19
- });
20
- if (!replaced) {
21
- break;
22
- }
23
- }
24
- const paths = path.split("/");
25
- if (paths[0] === "") {
26
- paths.shift();
27
- }
16
+ path = path.replace(/\{[^}]+\}/g, (match, index) => {
17
+ const mark = `@${index}`;
18
+ groups.push([mark, match]);
19
+ return mark;
20
+ });
21
+ return { groups, path };
22
+ };
23
+ var replaceGroupMarks = (paths, groups) => {
28
24
  for (let i = groups.length - 1; i >= 0; i--) {
29
25
  const [mark] = groups[i];
30
26
  for (let j = paths.length - 1; j >= 0; j--) {
31
- if (paths[j].indexOf(mark) !== -1) {
27
+ if (paths[j].includes(mark)) {
32
28
  paths[j] = paths[j].replace(mark, groups[i][1]);
33
29
  break;
34
30
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "3.12.5",
3
+ "version": "3.12.7",
4
4
  "description": "Ultrafast web framework for the Edges",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",
@@ -11,14 +11,15 @@
11
11
  ],
12
12
  "scripts": {
13
13
  "test": "tsc --noEmit && vitest --run",
14
- "test:deno": "env NAME=Deno deno test --allow-read --allow-env runtime_tests/deno && deno test --no-lock -c runtime_tests/deno-jsx/deno.precompile.json runtime_tests/deno-jsx && deno test --no-lock -c runtime_tests/deno-jsx/deno.react-jsx.json runtime_tests/deno-jsx",
15
- "test:bun": "env NAME=Bun bun test --jsx-import-source ../../src/jsx runtime_tests/bun/index.test.tsx",
14
+ "test:watch": "vitest --watch",
15
+ "test:deno": "deno test --allow-read --allow-env runtime_tests/deno && deno test --no-lock -c runtime_tests/deno-jsx/deno.precompile.json runtime_tests/deno-jsx && deno test --no-lock -c runtime_tests/deno-jsx/deno.react-jsx.json runtime_tests/deno-jsx",
16
+ "test:bun": "bun test --jsx-import-source ../../src/jsx runtime_tests/bun/index.test.tsx",
16
17
  "test:fastly": "vitest --run --config ./runtime_tests/fastly/vitest.config.ts",
17
18
  "test:lagon": "start-server-and-test \"lagon dev runtime_tests/lagon/index.ts -e runtime_tests/lagon/.env.lagon\" http://127.0.0.1:1234 \"yarn vitest --run runtime_tests/lagon/index.test.ts --config runtime_tests/lagon/vitest.config.ts\"",
18
- "test:node": "env NAME=Node vitest --run --config ./runtime_tests/node/vitest.config.ts",
19
+ "test:node": "vitest --run --config ./runtime_tests/node/vitest.config.ts",
19
20
  "test:wrangler": "vitest --run --config ./runtime_tests/wrangler/vitest.config.ts",
20
- "test:lambda": "env NAME=Node vitest --run --config ./runtime_tests/lambda/vitest.config.ts",
21
- "test:lambda-edge": "env NAME=Node vitest --run --config ./runtime_tests/lambda-edge/vitest.config.ts",
21
+ "test:lambda": "vitest --run --config ./runtime_tests/lambda/vitest.config.ts",
22
+ "test:lambda-edge": "vitest --run --config ./runtime_tests/lambda-edge/vitest.config.ts",
22
23
  "test:all": "yarn test && yarn test:deno && yarn test:bun && yarn test:fastly && yarn test:lagon && yarn test:node && yarn test:wrangler && yarn test:lambda && yarn test:lambda-edge",
23
24
  "lint": "eslint --ext js,ts src runtime_tests",
24
25
  "lint:fix": "eslint --ext js,ts src runtime_tests --fix",