diff --git a/packages/cli/plugin-bff/src/runtime/hono/adapter.ts b/packages/cli/plugin-bff/src/runtime/hono/adapter.ts index 707032e40f52..64d216d00f3a 100644 --- a/packages/cli/plugin-bff/src/runtime/hono/adapter.ts +++ b/packages/cli/plugin-bff/src/runtime/hono/adapter.ts @@ -64,6 +64,8 @@ export class HonoAdapter { if (result instanceof Response) { return result; } + } else { + logger.error(err); } } catch (configError) { logger.error(`Error in serverConfig.onError handler: ${configError}`); @@ -104,11 +106,7 @@ export class HonoAdapter { before, handler: async (c: Context, next: Next) => { if (this.apiServer) { - const response = await this.apiServer.fetch( - c.req as unknown as Request, - c.env, - ); - + const response = await this.apiServer.fetch(c.req.raw, c.env); if (response.status !== 404) { return new Response(response.body, response); } diff --git a/packages/cli/plugin-bff/src/utils/createHonoRoutes.ts b/packages/cli/plugin-bff/src/utils/createHonoRoutes.ts index 356309d564eb..057080f1a91c 100644 --- a/packages/cli/plugin-bff/src/utils/createHonoRoutes.ts +++ b/packages/cli/plugin-bff/src/utils/createHonoRoutes.ts @@ -44,7 +44,7 @@ const handleResponseMeta = (c: Context, handler: Handler) => { case ResponseMetaType.Redirect: return c.redirect(meta.value as string); case ResponseMetaType.StatusCode: - c.status(meta.value as number); + c.status(meta.value as any); break; default: break; diff --git a/packages/document/main-doc/docs/en/guides/advanced-features/bff/extend-server.mdx b/packages/document/main-doc/docs/en/guides/advanced-features/bff/extend-server.mdx index bf8f4ab19c5d..a29aa46984f6 100644 --- a/packages/document/main-doc/docs/en/guides/advanced-features/bff/extend-server.mdx +++ b/packages/document/main-doc/docs/en/guides/advanced-features/bff/extend-server.mdx @@ -12,11 +12,12 @@ Developers can use middleware by configuring middlewares in `server/modern.serve import { type MiddlewareHandler, defineServerConfig, + getCookie } from '@modern-js/server-runtime'; const requireAuthForApi: MiddlewareHandler = async (c, next) => { if (c.req.path.startsWith('/api') && c.req.path !== '/api/login') { - const sid = c.req.cookie('sid'); + const sid = getCookie(c, 'sid'); if (!sid) { return c.json({ code: -1, message: 'need login' }, 400); } diff --git a/packages/document/main-doc/docs/en/guides/advanced-features/web-server.mdx b/packages/document/main-doc/docs/en/guides/advanced-features/web-server.mdx index e9ede5eff8c1..db67c33ee732 100644 --- a/packages/document/main-doc/docs/en/guides/advanced-features/web-server.mdx +++ b/packages/document/main-doc/docs/en/guides/advanced-features/web-server.mdx @@ -406,7 +406,7 @@ type MiddlewareContext = { Differences between Middleware `Context` and Hono `Context`: | UnstableMiddleware | Hono | Description | | :----------------------- | :---------------------------- | :--------------------------------------------------------------------------- | -| `c.request.cookie` | `c.req.cookie()` | Refer to [Hono Cookie Helper](https://hono.dev/docs/helpers/cookie) documentation | +| `c.request.cookie` | `getCookie()` | Refer to [Hono Cookie Helper](https://hono.dev/docs/helpers/cookie) documentation | | `c.request.pathname` | `c.req.path` | Refer to [HonoRequest path](https://hono.dev/docs/api/request#path) documentation | | `c.request.url` | - | Hono `c.req.url` provides the full request URL, calculate manually from URL | | `c.request.host` | `c.req.header('Host')` | Obtain host through header | diff --git a/packages/document/main-doc/docs/zh/guides/advanced-features/bff/extend-server.mdx b/packages/document/main-doc/docs/zh/guides/advanced-features/bff/extend-server.mdx index 180b8cad582b..65a2e1a64356 100644 --- a/packages/document/main-doc/docs/zh/guides/advanced-features/bff/extend-server.mdx +++ b/packages/document/main-doc/docs/zh/guides/advanced-features/bff/extend-server.mdx @@ -14,11 +14,12 @@ Modern.js 支持用户通过 [Middleware](/guides/advanced-features/web-server.h import { type MiddlewareHandler, defineServerConfig, + getCookie } from '@modern-js/server-runtime'; const requireAuthForApi: MiddlewareHandler = async (c, next) => { if (c.req.path.startsWith('/api') && c.req.path !== '/api/login') { - const sid = c.req.cookie('sid'); + const sid = getCookie(c, 'sid'); if (!sid) { return c.json({ code: -1, message: 'need login' }, 400); } diff --git a/packages/document/main-doc/docs/zh/guides/advanced-features/web-server.mdx b/packages/document/main-doc/docs/zh/guides/advanced-features/web-server.mdx index b8d9be97d911..40d397e12cda 100644 --- a/packages/document/main-doc/docs/zh/guides/advanced-features/web-server.mdx +++ b/packages/document/main-doc/docs/zh/guides/advanced-features/web-server.mdx @@ -400,7 +400,7 @@ Middleware `Context` 和 Hono `Context` 的具体差异: | UnstableMiddleware | Hono | 说明 | | :------------------- | :--------------------- | :----------------------------------------------------------------------- | -| `c.request.cookie` | `c.req.cookie()` | 参考 [Hono Cookie Helper](https://hono.dev/docs/helpers/cookie) 文档 | +| `c.request.cookie` | `getCookie()` | 参考 [Hono Cookie Helper](https://hono.dev/docs/helpers/cookie) 文档 | | `c.request.pathname` | `c.req.path` | 参考 [HonoRequest path](https://hono.dev/docs/api/request#path) 文档 | | `c.request.url` | - | Hono `c.req.url` 为完整请求路径,自行通过 url 计算 | | `c.request.host` | `c.req.header('Host')` | 通过 header 获取 host | diff --git a/packages/runtime/plugin-i18n/src/server/index.ts b/packages/runtime/plugin-i18n/src/server/index.ts index 181429c51838..f43f5c3d5263 100644 --- a/packages/runtime/plugin-i18n/src/server/index.ts +++ b/packages/runtime/plugin-i18n/src/server/index.ts @@ -13,7 +13,7 @@ const getLanguageFromPath = ( urlPath: string, languages: string[], ): string | null => { - const url = new URL(req.url, `http://${req.headers.host}`); + const url = new URL(req.url, `http://${req.header().host}`); const pathname = url.pathname; // Remove urlPath prefix to get remaining path diff --git a/packages/server/core/package.json b/packages/server/core/package.json index 0d47bd924d1b..a59cb9989243 100644 --- a/packages/server/core/package.json +++ b/packages/server/core/package.json @@ -32,6 +32,12 @@ "jsnext:source": "./src/adapters/node/index.ts", "import": "./dist/esm-node/adapters/node/index.js", "default": "./dist/cjs/adapters/node/index.js" + }, + "./hono": { + "types": "./dist/types/hono.d.ts", + "jsnext:source": "./src/hono.ts", + "import": "./dist/esm-node/hono.js", + "default": "./dist/cjs/hono.js" } }, "typesVersions": { @@ -41,6 +47,9 @@ ], "node": [ "./dist/types/adapters/node/index.d.ts" + ], + "hono": [ + "./dist/types/hono.d.ts" ] } }, @@ -64,7 +73,7 @@ "@web-std/stream": "^1.0.3", "cloneable-readable": "^3.0.0", "flatted": "^3.3.3", - "hono": "^3.12.2", + "hono": "^4.10.4", "ts-deepmerge": "7.0.3" }, "devDependencies": { @@ -95,6 +104,11 @@ "types": "./dist/types/adapters/node/index.d.ts", "import": "./dist/esm-node/adapters/node/index.js", "default": "./dist/cjs/adapters/node/index.js" + }, + "./hono": { + "types": "./dist/types/hono.d.ts", + "import": "./dist/esm-node/hono.js", + "default": "./dist/cjs/hono.js" } } } diff --git a/packages/server/core/src/adapters/node/hono.ts b/packages/server/core/src/adapters/node/hono.ts index 2bd927d26f7a..a8ea4b078a0e 100644 --- a/packages/server/core/src/adapters/node/hono.ts +++ b/packages/server/core/src/adapters/node/hono.ts @@ -42,6 +42,9 @@ export const httpCallBack2HonoMid = (handler: Handler) => { } if (isResFinalized(res)) { + // Fix: ensure context.res is initialized before setting finalized + // This prevents c.#res from being undefined in Hono + const _ = context.res; context.finalized = true; } else { await next(); @@ -92,6 +95,9 @@ export const connectMockMid2HonoMid = ( // The function lenth < 3 means the handler is not a function with next if (handler.length < 3) { res.once('finish', () => { + // Fix: ensure context.res is initialized before setting finalized + // This prevents c.#res from being undefined in Hono + const _ = context.res; context.finalized = true; resolve(); }); diff --git a/packages/server/core/src/hono.ts b/packages/server/core/src/hono.ts new file mode 100644 index 000000000000..69db601412c1 --- /dev/null +++ b/packages/server/core/src/hono.ts @@ -0,0 +1,17 @@ +// === Export Hono.js Core Types and APIs === + +// Core types from Hono +export type { + Context, + Next, + MiddlewareHandler, + MiddlewareHandler as Middleware, + HonoRequest, +} from 'hono'; + +// Hono utilities +export { + setCookie, + getCookie, + deleteCookie, +} from 'hono/cookie'; diff --git a/packages/server/core/src/plugins/render/index.ts b/packages/server/core/src/plugins/render/index.ts index 63b16a963384..9d6ca9d74617 100644 --- a/packages/server/core/src/plugins/render/index.ts +++ b/packages/server/core/src/plugins/render/index.ts @@ -1,4 +1,5 @@ import type { ServerRoute } from '@modern-js/types'; +import type { ContentfulStatusCode } from 'hono/utils/http-status'; import type { ServerNodeEnv } from '../../adapters/node/hono'; import { getLoaderCtx } from '../../helper'; import type { @@ -114,6 +115,6 @@ function createRenderHandler( headersData[k] = v; }); - return c.body(body, status, headersData); + return c.body(body!, status as ContentfulStatusCode, headersData); }; } diff --git a/packages/server/server-runtime/src/index.ts b/packages/server/server-runtime/src/index.ts index f704ed4cbf2c..052327c4cd5f 100644 --- a/packages/server/server-runtime/src/index.ts +++ b/packages/server/server-runtime/src/index.ts @@ -10,6 +10,8 @@ export { type ServerConfig, } from '@modern-js/server-core'; +export * from '@modern-js/server-core/hono'; + export type { Container, CacheControl, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e94b54ee97bd..7f6284f7135d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1613,8 +1613,8 @@ importers: specifier: ^3.3.3 version: 3.3.3 hono: - specifier: ^3.12.2 - version: 3.12.12 + specifier: ^4.10.4 + version: 4.10.4 ts-deepmerge: specifier: 7.0.3 version: 7.0.3 @@ -3327,8 +3327,8 @@ importers: specifier: workspace:* version: link:../../../packages/server/server-runtime hono: - specifier: ^3.12.2 - version: 3.12.12 + specifier: ^4.10.4 + version: 4.10.4 react: specifier: ^19.2.0 version: 19.2.0 @@ -12140,9 +12140,9 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} - hono@3.12.12: - resolution: {integrity: sha512-5IAMJOXfpA5nT+K0MNjClchzz0IhBHs2Szl7WFAhrFOsbtQsYmNynFyJRg/a3IPsmCfxcrf8txUGiNShXpK5Rg==} - engines: {node: '>=16.0.0'} + hono@4.10.4: + resolution: {integrity: sha512-YG/fo7zlU3KwrBL5vDpWKisLYiM+nVstBQqfr7gCPbSYURnNEP9BDxEMz8KfsDR9JX0lJWDRNc6nXX31v7ZEyg==} + engines: {node: '>=16.9.0'} hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -24572,7 +24572,7 @@ snapshots: dependencies: parse-passwd: 1.0.0 - hono@3.12.12: {} + hono@4.10.4: {} hookable@5.5.3: {} diff --git a/tests/integration/bff-hono/package.json b/tests/integration/bff-hono/package.json index f3e220e633d4..4e923e3fc50f 100644 --- a/tests/integration/bff-hono/package.json +++ b/tests/integration/bff-hono/package.json @@ -14,7 +14,7 @@ "@modern-js/plugin-bff": "workspace:*", "@modern-js/runtime": "workspace:*", "@modern-js/server-runtime": "workspace:*", - "hono": "^3.12.2", + "hono": "^4.10.4", "react": "^19.2.0", "react-dom": "^19.2.0", "ts-node": "^10.9.2", diff --git a/tests/integration/ssg/fixtures/web-server/server/modern.server.ts b/tests/integration/ssg/fixtures/web-server/server/modern.server.ts index b6a4f2a27bb2..a8ef3b5e4eba 100644 --- a/tests/integration/ssg/fixtures/web-server/server/modern.server.ts +++ b/tests/integration/ssg/fixtures/web-server/server/modern.server.ts @@ -11,7 +11,8 @@ const timing: MiddlewareHandler = async (c, next) => { const text = await res.text(); const newText = text.replace('', 'bytedance'); - c.res = c.body(newText, { + + c.res = new Response(newText, { status: res.status, headers: res.headers, });