@hono/node-server
Advanced tools
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| //#region src/early-hints.ts | ||
| /** | ||
| * Early Hints middleware for Node.js | ||
| * Automatically sends a 103 Early Hints informational response with the specified Link header(s). | ||
| * | ||
| * @param options EarlyHintsOptions | ||
| * @returns MiddlewareHandler | ||
| */ | ||
| const earlyHints = (options) => { | ||
| let warned = false; | ||
| return async (c, next) => { | ||
| const mode = c.req.header("Sec-Fetch-Mode"); | ||
| const dest = c.req.header("Sec-Fetch-Dest"); | ||
| if (mode && mode !== "navigate" || dest && dest !== "document") return next(); | ||
| const env = c.env || {}; | ||
| const outgoing = (env.server ? env.server : env)?.outgoing; | ||
| if (typeof outgoing?.writeEarlyHints !== "function") { | ||
| if (!warned) { | ||
| console.warn("Early Hints Middleware is not supported because writeEarlyHints is not defined."); | ||
| warned = true; | ||
| } | ||
| return await next(); | ||
| } | ||
| if (!outgoing.headersSent) { | ||
| const link = typeof options.link === "function" ? options.link(c) : options.link; | ||
| if (link !== void 0 && (Array.isArray(link) ? link.length > 0 : Boolean(link))) outgoing.writeEarlyHints({ link }); | ||
| } | ||
| await next(); | ||
| }; | ||
| }; | ||
| //#endregion | ||
| exports.earlyHints = earlyHints; |
| import { Context, Env, MiddlewareHandler } from "hono"; | ||
| //#region src/early-hints.d.ts | ||
| type EarlyHintsOptions<E extends Env = Env> = { | ||
| link: string | string[] | ((c: Context<E>) => string | string[] | undefined); | ||
| }; | ||
| /** | ||
| * Early Hints middleware for Node.js | ||
| * Automatically sends a 103 Early Hints informational response with the specified Link header(s). | ||
| * | ||
| * @param options EarlyHintsOptions | ||
| * @returns MiddlewareHandler | ||
| */ | ||
| declare const earlyHints: <E extends Env = any>(options: EarlyHintsOptions<E>) => MiddlewareHandler<E>; | ||
| //#endregion | ||
| export { EarlyHintsOptions, earlyHints }; |
| import { Context, Env, MiddlewareHandler } from "hono"; | ||
| //#region src/early-hints.d.ts | ||
| type EarlyHintsOptions<E extends Env = Env> = { | ||
| link: string | string[] | ((c: Context<E>) => string | string[] | undefined); | ||
| }; | ||
| /** | ||
| * Early Hints middleware for Node.js | ||
| * Automatically sends a 103 Early Hints informational response with the specified Link header(s). | ||
| * | ||
| * @param options EarlyHintsOptions | ||
| * @returns MiddlewareHandler | ||
| */ | ||
| declare const earlyHints: <E extends Env = any>(options: EarlyHintsOptions<E>) => MiddlewareHandler<E>; | ||
| //#endregion | ||
| export { EarlyHintsOptions, earlyHints }; |
| //#region src/early-hints.ts | ||
| /** | ||
| * Early Hints middleware for Node.js | ||
| * Automatically sends a 103 Early Hints informational response with the specified Link header(s). | ||
| * | ||
| * @param options EarlyHintsOptions | ||
| * @returns MiddlewareHandler | ||
| */ | ||
| const earlyHints = (options) => { | ||
| let warned = false; | ||
| return async (c, next) => { | ||
| const mode = c.req.header("Sec-Fetch-Mode"); | ||
| const dest = c.req.header("Sec-Fetch-Dest"); | ||
| if (mode && mode !== "navigate" || dest && dest !== "document") return next(); | ||
| const env = c.env || {}; | ||
| const outgoing = (env.server ? env.server : env)?.outgoing; | ||
| if (typeof outgoing?.writeEarlyHints !== "function") { | ||
| if (!warned) { | ||
| console.warn("Early Hints Middleware is not supported because writeEarlyHints is not defined."); | ||
| warned = true; | ||
| } | ||
| return await next(); | ||
| } | ||
| if (!outgoing.headersSent) { | ||
| const link = typeof options.link === "function" ? options.link(c) : options.link; | ||
| if (link !== void 0 && (Array.isArray(link) ? link.length > 0 : Boolean(link))) outgoing.writeEarlyHints({ link }); | ||
| } | ||
| await next(); | ||
| }; | ||
| }; | ||
| //#endregion | ||
| export { earlyHints }; |
+4
-1
@@ -687,3 +687,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const socket = incoming.socket; | ||
| if (socket && !socket.destroyed) socket.destroySoon(); | ||
| if (socket && !socket.destroyed) { | ||
| if (typeof socket.destroySoon === "function") socket.destroySoon(); | ||
| else if (typeof socket.destroy === "function") socket.destroy(); | ||
| } | ||
| }; | ||
@@ -690,0 +693,0 @@ const timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS); |
+4
-1
@@ -686,3 +686,6 @@ import { t as X_ALREADY_SENT } from "./constants-BLSFu_RU.mjs"; | ||
| const socket = incoming.socket; | ||
| if (socket && !socket.destroyed) socket.destroySoon(); | ||
| if (socket && !socket.destroyed) { | ||
| if (typeof socket.destroySoon === "function") socket.destroySoon(); | ||
| else if (typeof socket.destroy === "function") socket.destroy(); | ||
| } | ||
| }; | ||
@@ -689,0 +692,0 @@ const timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS); |
+14
-1
| { | ||
| "name": "@hono/node-server", | ||
| "version": "2.0.12", | ||
| "version": "2.1.0", | ||
| "description": "Node.js Adapter for Hono", | ||
@@ -51,2 +51,12 @@ "main": "dist/index.mjs", | ||
| } | ||
| }, | ||
| "./early-hints": { | ||
| "import": { | ||
| "types": "./dist/early-hints.d.mts", | ||
| "default": "./dist/early-hints.mjs" | ||
| }, | ||
| "require": { | ||
| "types": "./dist/early-hints.d.cts", | ||
| "default": "./dist/early-hints.cjs" | ||
| } | ||
| } | ||
@@ -67,2 +77,5 @@ }, | ||
| "./dist/conninfo.d.mts" | ||
| ], | ||
| "early-hints": [ | ||
| "./dist/early-hints.d.mts" | ||
| ] | ||
@@ -69,0 +82,0 @@ } |
+47
-1
@@ -89,3 +89,3 @@ # Node.js Adapter for Hono | ||
| const wss = new WebSocketServer({ noServer: true }) // important to create with `noServer: true` | ||
| const wss = new WebSocketServer({ noServer: true }) | ||
| serve({ | ||
@@ -336,2 +336,48 @@ fetch: app.fetch, | ||
| ## Early Hints Middleware | ||
| You can send HTTP 103 Early Hints to instruct browsers to preload or preconnect resources before the final response is prepared. The middleware is supported under Node.js bindings (HTTP/1.1 and HTTP/2). | ||
| ### Usage | ||
| Import `earlyHints` from `@hono/node-server/early-hints`: | ||
| #### Static links | ||
| ```ts | ||
| import { serve } from '@hono/node-server' | ||
| import { earlyHints } from '@hono/node-server/early-hints' | ||
| import { Hono } from 'hono' | ||
| const app = new Hono() | ||
| app.use( | ||
| earlyHints({ | ||
| link: '</styles.css>; rel=preload; as=style', | ||
| }) | ||
| ) | ||
| app.get('/', (c) => { | ||
| return c.html('<!DOCTYPE html><html><body><h1>Hello Hono!</h1></body></html>') | ||
| }) | ||
| serve(app) | ||
| ``` | ||
| #### Dynamic links | ||
| ```ts | ||
| app.use( | ||
| earlyHints({ | ||
| link: (c) => | ||
| c.req.query('theme') === 'dark' | ||
| ? '</dark.css>; rel=preload; as=style' | ||
| : '</light.css>; rel=preload; as=style', | ||
| }) | ||
| ) | ||
| ``` | ||
| > [!NOTE] | ||
| > Early Hints are sent only for requests that look like document navigations. If `Sec-Fetch-Mode` or `Sec-Fetch-Dest` is present with a value other than `navigate` or `document`, for example a `fetch()` or XHR call from a browser, a subresource request, or an iframe navigation, the middleware skips the hints and continues to the handler. Requests without these headers, such as `curl` or `fetch()` from a JavaScript runtime, are treated as navigations and do receive Early Hints. | ||
| ## Direct response from Node.js API | ||
@@ -338,0 +384,0 @@ |
125761
4.49%29
16%2869
2.46%438
11.73%