hono 4.5.3 → 4.5.5

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.
@@ -1,5 +1,6 @@
1
1
  // src/adapter/bun/serve-static.ts
2
2
  import { serveStatic as baseServeStatic } from "../../middleware/serve-static/index.js";
3
+ import { stat } from "node:fs/promises";
3
4
  var serveStatic = (options) => {
4
5
  return async function serveStatic2(c, next) {
5
6
  const getContent = async (path) => {
@@ -10,10 +11,20 @@ var serveStatic = (options) => {
10
11
  const pathResolve = (path) => {
11
12
  return `./${path}`;
12
13
  };
14
+ const isDir = async (path) => {
15
+ let isDir2;
16
+ try {
17
+ const stats = await stat(path);
18
+ isDir2 = stats.isDirectory();
19
+ } catch {
20
+ }
21
+ return isDir2;
22
+ };
13
23
  return baseServeStatic({
14
24
  ...options,
15
25
  getContent,
16
- pathResolve
26
+ pathResolve,
27
+ isDir
17
28
  })(c, next);
18
29
  };
19
30
  };
@@ -1,6 +1,6 @@
1
1
  // src/adapter/deno/serve-static.ts
2
2
  import { serveStatic as baseServeStatic } from "../../middleware/serve-static/index.js";
3
- var { open } = Deno;
3
+ var { open, lstatSync } = Deno;
4
4
  var serveStatic = (options) => {
5
5
  return async function serveStatic2(c, next) {
6
6
  const getContent = async (path) => {
@@ -14,10 +14,20 @@ var serveStatic = (options) => {
14
14
  const pathResolve = (path) => {
15
15
  return `./${path}`;
16
16
  };
17
+ const isDir = (path) => {
18
+ let isDir2;
19
+ try {
20
+ const stat = lstatSync(path);
21
+ isDir2 = stat.isDirectory;
22
+ } catch {
23
+ }
24
+ return isDir2;
25
+ };
17
26
  return baseServeStatic({
18
27
  ...options,
19
28
  getContent,
20
- pathResolve
29
+ pathResolve,
30
+ isDir
21
31
  })(c, next);
22
32
  };
23
33
  };
@@ -22,6 +22,7 @@ __export(serve_static_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(serve_static_exports);
24
24
  var import_serve_static = require("../../middleware/serve-static");
25
+ var import_promises = require("node:fs/promises");
25
26
  const serveStatic = (options) => {
26
27
  return async function serveStatic2(c, next) {
27
28
  const getContent = async (path) => {
@@ -32,10 +33,20 @@ const serveStatic = (options) => {
32
33
  const pathResolve = (path) => {
33
34
  return `./${path}`;
34
35
  };
36
+ const isDir = async (path) => {
37
+ let isDir2;
38
+ try {
39
+ const stats = await (0, import_promises.stat)(path);
40
+ isDir2 = stats.isDirectory();
41
+ } catch {
42
+ }
43
+ return isDir2;
44
+ };
35
45
  return (0, import_serve_static.serveStatic)({
36
46
  ...options,
37
47
  getContent,
38
- pathResolve
48
+ pathResolve,
49
+ isDir
39
50
  })(c, next);
40
51
  };
41
52
  };
@@ -22,7 +22,7 @@ __export(serve_static_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(serve_static_exports);
24
24
  var import_serve_static = require("../../middleware/serve-static");
25
- const { open } = Deno;
25
+ const { open, lstatSync } = Deno;
26
26
  const serveStatic = (options) => {
27
27
  return async function serveStatic2(c, next) {
28
28
  const getContent = async (path) => {
@@ -36,10 +36,20 @@ const serveStatic = (options) => {
36
36
  const pathResolve = (path) => {
37
37
  return `./${path}`;
38
38
  };
39
+ const isDir = (path) => {
40
+ let isDir2;
41
+ try {
42
+ const stat = lstatSync(path);
43
+ isDir2 = stat.isDirectory;
44
+ } catch {
45
+ }
46
+ return isDir2;
47
+ };
39
48
  return (0, import_serve_static.serveStatic)({
40
49
  ...options,
41
50
  getContent,
42
- pathResolve
51
+ pathResolve,
52
+ isDir
43
53
  })(c, next);
44
54
  };
45
55
  };
@@ -167,7 +167,13 @@ const hc = (baseUrl, options) => createProxy(function proxyCallback(opts) {
167
167
  }
168
168
  });
169
169
  }
170
- return new WebSocket(targetUrl.toString());
170
+ const establishWebSocket = (...args) => {
171
+ if (options?.webSocket !== void 0 && typeof options.webSocket === "function") {
172
+ return options.webSocket(...args);
173
+ }
174
+ return new WebSocket(...args);
175
+ };
176
+ return establishWebSocket(targetUrl.toString());
171
177
  }
172
178
  const req = new ClientRequestImpl(url, method);
173
179
  if (method) {
@@ -208,7 +208,9 @@ class JSXFunctionNode extends JSXNode {
208
208
  ...this.props,
209
209
  children: children.length <= 1 ? children[0] : children
210
210
  });
211
- if (res instanceof Promise) {
211
+ if (typeof res === "boolean" || res == null) {
212
+ return;
213
+ } else if (res instanceof Promise) {
212
214
  if (import_context.globalContexts.length === 0) {
213
215
  buffer.unshift("", res);
214
216
  } else {
@@ -303,11 +305,11 @@ const shallowEqual = (a, b) => {
303
305
  return true;
304
306
  };
305
307
  const memo = (component, propsAreEqual = shallowEqual) => {
306
- let computed = void 0;
308
+ let computed = null;
307
309
  let prevProps = void 0;
308
310
  return (props) => {
309
311
  if (prevProps && !propsAreEqual(prevProps, props)) {
310
- computed = void 0;
312
+ computed = null;
311
313
  }
312
314
  prevProps = props;
313
315
  return computed ||= component(props);
@@ -34,6 +34,15 @@ const serveStatic = (options) => {
34
34
  let filename = options.path ?? decodeURI(c.req.path);
35
35
  filename = options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename;
36
36
  const root = options.root;
37
+ if (!filename.endsWith("/") && options.isDir) {
38
+ const path2 = (0, import_filepath.getFilePathWithoutDefaultDocument)({
39
+ filename,
40
+ root
41
+ });
42
+ if (path2 && await options.isDir(path2)) {
43
+ filename = filename + "/";
44
+ }
45
+ }
37
46
  let path = (0, import_filepath.getFilePath)({
38
47
  filename,
39
48
  root,
@@ -151,7 +151,13 @@ var hc = (baseUrl, options) => createProxy(function proxyCallback(opts) {
151
151
  }
152
152
  });
153
153
  }
154
- return new WebSocket(targetUrl.toString());
154
+ const establishWebSocket = (...args) => {
155
+ if (options?.webSocket !== void 0 && typeof options.webSocket === "function") {
156
+ return options.webSocket(...args);
157
+ }
158
+ return new WebSocket(...args);
159
+ };
160
+ return establishWebSocket(targetUrl.toString());
155
161
  }
156
162
  const req = new ClientRequestImpl(url, method);
157
163
  if (method) {
package/dist/jsx/base.js CHANGED
@@ -171,7 +171,9 @@ var JSXFunctionNode = class extends JSXNode {
171
171
  ...this.props,
172
172
  children: children.length <= 1 ? children[0] : children
173
173
  });
174
- if (res instanceof Promise) {
174
+ if (typeof res === "boolean" || res == null) {
175
+ return;
176
+ } else if (res instanceof Promise) {
175
177
  if (globalContexts.length === 0) {
176
178
  buffer.unshift("", res);
177
179
  } else {
@@ -266,11 +268,11 @@ var shallowEqual = (a, b) => {
266
268
  return true;
267
269
  };
268
270
  var memo = (component, propsAreEqual = shallowEqual) => {
269
- let computed = void 0;
271
+ let computed = null;
270
272
  let prevProps = void 0;
271
273
  return (props) => {
272
274
  if (prevProps && !propsAreEqual(prevProps, props)) {
273
- computed = void 0;
275
+ computed = null;
274
276
  }
275
277
  prevProps = props;
276
278
  return computed ||= component(props);
@@ -12,6 +12,15 @@ var serveStatic = (options) => {
12
12
  let filename = options.path ?? decodeURI(c.req.path);
13
13
  filename = options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename;
14
14
  const root = options.root;
15
+ if (!filename.endsWith("/") && options.isDir) {
16
+ const path2 = getFilePathWithoutDefaultDocument({
17
+ filename,
18
+ root
19
+ });
20
+ if (path2 && await options.isDir(path2)) {
21
+ filename = filename + "/";
22
+ }
23
+ }
15
24
  let path = getFilePath({
16
25
  filename,
17
26
  root,
@@ -5,6 +5,7 @@ import type { HasRequiredKeys } from '../utils/types';
5
5
  type HonoRequest = (typeof Hono.prototype)['request'];
6
6
  export type ClientRequestOptions<T = unknown> = {
7
7
  fetch?: typeof fetch | HonoRequest;
8
+ webSocket?: (...args: ConstructorParameters<typeof WebSocket>) => WebSocket;
8
9
  /**
9
10
  * Standard `RequestInit`, caution that this take highest priority
10
11
  * and could be used to overwrite things that Hono sets for you, like `body | method | headers`.
@@ -3,7 +3,8 @@ import type { Result } from './router';
3
3
  import type { Env, FetchEventLike, H, Input, NotFoundHandler, RouterRoute, TypedResponse } from './types';
4
4
  import type { RedirectStatusCode, StatusCode } from './utils/http-status';
5
5
  import type { InvalidJSONValue, IsAny, JSONParsed, JSONValue, SimplifyDeepArray } from './utils/types';
6
- type HeaderRecord = Record<string, string | string[]>;
6
+ import type { BaseMime } from './utils/mime';
7
+ type HeaderRecord = Record<'Content-Type', BaseMime> | Record<ResponseHeader, string | string[]> | Record<string, string | string[]>;
7
8
  /**
8
9
  * Data type can be a string, ArrayBuffer, or ReadableStream.
9
10
  */
@@ -158,6 +159,21 @@ type ContextOptions<E extends Env> = {
158
159
  matchResult?: Result<[H, RouterRoute]>;
159
160
  path?: string;
160
161
  };
162
+ interface SetHeadersOptions {
163
+ append?: boolean;
164
+ }
165
+ type ResponseHeader = 'Access-Control-Allow-Credentials' | 'Access-Control-Allow-Headers' | 'Access-Control-Allow-Methods' | 'Access-Control-Allow-Origin' | 'Access-Control-Expose-Headers' | 'Access-Control-Max-Age' | 'Age' | 'Allow' | 'Cache-Control' | 'Clear-Site-Data' | 'Content-Disposition' | 'Content-Encoding' | 'Content-Language' | 'Content-Length' | 'Content-Location' | 'Content-Range' | 'Content-Security-Policy' | 'Content-Security-Policy-Report-Only' | 'Content-Type' | 'Cookie' | 'Cross-Origin-Embedder-Policy' | 'Cross-Origin-Opener-Policy' | 'Cross-Origin-Resource-Policy' | 'Date' | 'ETag' | 'Expires' | 'Last-Modified' | 'Location' | 'Permissions-Policy' | 'Pragma' | 'Retry-After' | 'Save-Data' | 'Sec-CH-Prefers-Color-Scheme' | 'Sec-CH-Prefers-Reduced-Motion' | 'Sec-CH-UA' | 'Sec-CH-UA-Arch' | 'Sec-CH-UA-Bitness' | 'Sec-CH-UA-Form-Factor' | 'Sec-CH-UA-Full-Version' | 'Sec-CH-UA-Full-Version-List' | 'Sec-CH-UA-Mobile' | 'Sec-CH-UA-Model' | 'Sec-CH-UA-Platform' | 'Sec-CH-UA-Platform-Version' | 'Sec-CH-UA-WoW64' | 'Sec-Fetch-Dest' | 'Sec-Fetch-Mode' | 'Sec-Fetch-Site' | 'Sec-Fetch-User' | 'Sec-GPC' | 'Server' | 'Server-Timing' | 'Service-Worker-Navigation-Preload' | 'Set-Cookie' | 'Strict-Transport-Security' | 'Timing-Allow-Origin' | 'Trailer' | 'Transfer-Encoding' | 'Upgrade' | 'Vary' | 'WWW-Authenticate' | 'Warning' | 'X-Content-Type-Options' | 'X-DNS-Prefetch-Control' | 'X-Frame-Options' | 'X-Permitted-Cross-Domain-Policies' | 'X-Powered-By' | 'X-Robots-Tag' | 'X-XSS-Protection';
166
+ interface SetHeaders {
167
+ (name: 'Content-Type', value?: BaseMime, options?: SetHeadersOptions): void;
168
+ (name: ResponseHeader, value?: string, options?: SetHeadersOptions): void;
169
+ (name: string, value?: string, options?: SetHeadersOptions): void;
170
+ }
171
+ type ResponseHeadersInit = [string, string][] | Record<'Content-Type', BaseMime> | Record<ResponseHeader, string> | Record<string, string> | Headers;
172
+ interface ResponseInit {
173
+ headers?: ResponseHeadersInit;
174
+ status?: number;
175
+ statusText?: string;
176
+ }
161
177
  export declare const TEXT_PLAIN = "text/plain; charset=UTF-8";
162
178
  export declare class Context<E extends Env = any, P extends string = any, I extends Input = {}> {
163
179
  #private;
@@ -298,9 +314,7 @@ export declare class Context<E extends Env = any, P extends string = any, I exte
298
314
  * })
299
315
  * ```
300
316
  */
301
- header: (name: string, value: string | undefined, options?: {
302
- append?: boolean;
303
- }) => void;
317
+ header: SetHeaders;
304
318
  status: (status: StatusCode) => void;
305
319
  /**
306
320
  * `.set()` can set the value specified by the key.
@@ -3,7 +3,7 @@ import type { Context } from './context';
3
3
  import type { JSX as HonoJSX, IntrinsicElements as IntrinsicElementsDefined } from './intrinsic-elements';
4
4
  export type Props = Record<string, any>;
5
5
  export type FC<P = Props> = {
6
- (props: P): HtmlEscapedString | Promise<HtmlEscapedString>;
6
+ (props: P): HtmlEscapedString | Promise<HtmlEscapedString> | null;
7
7
  defaultProps?: Partial<P> | undefined;
8
8
  displayName?: string | undefined;
9
9
  };
@@ -6,7 +6,9 @@
6
6
  */
7
7
  export declare namespace JSX {
8
8
  export type CrossOrigin = 'anonymous' | 'use-credentials' | '' | undefined;
9
- export type CSSProperties = {};
9
+ export interface CSSProperties {
10
+ [propertyKey: string]: unknown;
11
+ }
10
12
  type AnyAttributes = {
11
13
  [attributeName: string]: any;
12
14
  };
@@ -147,7 +149,7 @@ export declare namespace JSX {
147
149
  contenteditable?: boolean | 'inherit' | undefined;
148
150
  contextmenu?: string | undefined;
149
151
  dir?: string | undefined;
150
- draggable?: boolean | undefined;
152
+ draggable?: 'true' | 'false' | boolean | undefined;
151
153
  enterkeyhint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send' | undefined;
152
154
  hidden?: boolean | undefined;
153
155
  id?: string | undefined;
@@ -165,7 +167,7 @@ export declare namespace JSX {
165
167
  popover?: string | undefined;
166
168
  slot?: string | undefined;
167
169
  spellcheck?: boolean | undefined;
168
- style?: CSSProperties | undefined;
170
+ style?: CSSProperties | string | undefined;
169
171
  tabindex?: number | undefined;
170
172
  title?: string | undefined;
171
173
  translate?: 'yes' | 'no' | undefined;
@@ -17,4 +17,5 @@ export type ServeStaticOptions<E extends Env = Env> = {
17
17
  export declare const serveStatic: <E extends Env = Env>(options: ServeStaticOptions<E> & {
18
18
  getContent: (path: string, c: Context<E, any, {}>) => Promise<Data | Response | null>;
19
19
  pathResolve?: ((path: string) => string) | undefined;
20
+ isDir?: ((path: string) => boolean | undefined | Promise<boolean | undefined>) | undefined;
20
21
  }) => MiddlewareHandler;
@@ -458,7 +458,7 @@ type ChangePathOfSchema<S extends Schema, Path extends string> = keyof S extends
458
458
  [K in keyof S as Path]: S[K];
459
459
  };
460
460
  export type Endpoint = {
461
- input: Partial<ValidationTargets>;
461
+ input: any;
462
462
  output: any;
463
463
  outputFormat: ResponseFormat;
464
464
  status: StatusCode;
@@ -514,11 +514,11 @@ export type TypedResponse<T = unknown, U extends StatusCode = StatusCode, F exte
514
514
  type MergeTypedResponse<T> = T extends Promise<infer T2> ? T2 extends TypedResponse ? T2 : TypedResponse : T extends TypedResponse ? T : TypedResponse;
515
515
  export type FormValue = string | Blob;
516
516
  export type ParsedFormValue = string | File;
517
- export type ValidationTargets<T extends FormValue = ParsedFormValue> = {
517
+ export type ValidationTargets<T extends FormValue = ParsedFormValue, P extends string = string> = {
518
518
  json: any;
519
519
  form: Record<string, T | T[]>;
520
520
  query: Record<string, string | string[]>;
521
- param: Record<string, string> | Record<string, string | undefined>;
521
+ param: Record<P, P extends `${infer _}?` ? string | undefined : string>;
522
522
  header: Record<string, string>;
523
523
  cookie: Record<string, string>;
524
524
  };
@@ -5,4 +5,8 @@
5
5
  export declare const getMimeType: (filename: string, mimes?: Record<string, string>) => string | undefined;
6
6
  export declare const getExtension: (mimeType: string) => string | undefined;
7
7
  export { baseMimes as mimes };
8
- declare const baseMimes: Record<string, string>;
8
+ /**
9
+ * Union types for BaseMime
10
+ */
11
+ export type BaseMime = 'audio/aac' | 'video/x-msvideo' | 'image/avif' | 'video/av1' | 'application/octet-stream' | 'image/bmp' | 'text/css' | 'text/csv' | 'application/vnd.ms-fontobject' | 'application/epub+zip' | 'image/gif' | 'application/gzip' | 'text/html' | 'image/x-icon' | 'text/calendar' | 'image/jpeg' | 'text/javascript' | 'application/json' | 'application/ld+json' | 'audio/x-midi' | 'audio/mpeg' | 'video/mp4' | 'video/mpeg' | 'audio/ogg' | 'video/ogg' | 'application/ogg' | 'audio/opus' | 'font/otf' | 'application/pdf' | 'image/png' | 'application/rtf' | 'image/svg+xml' | 'image/tiff' | 'video/mp2t' | 'font/ttf' | 'text/plain' | 'application/wasm' | 'video/webm' | 'audio/webm' | 'image/webp' | 'font/woff' | 'font/woff2' | 'application/xhtml+xml' | 'application/xml' | 'application/zip' | 'video/3gpp' | 'video/3gpp2' | 'model/gltf+json' | 'model/gltf-binary';
12
+ declare const baseMimes: Record<string, BaseMime>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "4.5.3",
3
+ "version": "4.5.5",
4
4
  "description": "Web framework built on Web Standards",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",