From 9bcd09f13105192ce603b8e17590a8a101731624 Mon Sep 17 00:00:00 2001 From: miyaji255 <84168445+miyaji255@users.noreply.github.com> Date: Sat, 11 Jan 2025 21:42:15 +0900 Subject: [PATCH] feat(types): Add DefaultEnv for zero runtime factory with interface merging --- jsr.json | 3 + package.json | 24 ++++++ src/adapter/aws-lambda/alb.ts | 24 ++++++ src/adapter/aws-lambda/api-gateway-v2.ts | 24 ++++++ src/adapter/aws-lambda/api-gateway.ts | 24 ++++++ src/adapter/aws-lambda/handler.ts | 10 ++- src/adapter/bun/serve-static.ts | 8 +- src/adapter/cloudflare-pages/handler.test.ts | 2 +- src/adapter/cloudflare-pages/handler.ts | 6 +- src/adapter/cloudflare-pages/index.ts | 12 +++ .../cloudflare-workers/serve-static-module.ts | 6 +- .../cloudflare-workers/serve-static.ts | 13 ++-- src/adapter/deno/serve-static.ts | 8 +- src/adapter/lambda-edge/index.ts | 25 +++++++ src/context.ts | 4 +- src/hono-base.ts | 33 +++++---- src/hono.ts | 4 +- src/index.ts | 3 + src/middleware/combine/index.ts | 4 +- src/middleware/serve-static/index.ts | 6 +- src/preset/quick.ts | 4 +- src/preset/tiny.ts | 4 +- src/request.ts | 2 +- src/types.ts | 73 +++++++++++++++---- 24 files changed, 259 insertions(+), 67 deletions(-) create mode 100644 src/adapter/aws-lambda/alb.ts create mode 100644 src/adapter/aws-lambda/api-gateway-v2.ts create mode 100644 src/adapter/aws-lambda/api-gateway.ts diff --git a/jsr.json b/jsr.json index c3b3559a6..953c900d8 100644 --- a/jsr.json +++ b/jsr.json @@ -73,6 +73,9 @@ "./deno": "./src/adapter/deno/index.ts", "./bun": "./src/adapter/bun/index.ts", "./aws-lambda": "./src/adapter/aws-lambda/index.ts", + "./aws-lambda/alb": "./src/adapter/aws-lambda/alb.ts", + "./aws-lambda/api-gateway":"./src/adapter/aws-lambda/api-gateway.ts", + "./aws-lambda/api-gateway-v2":"./src/adapter/aws-lambda/api-gateway-v2.ts", "./vercel": "./src/adapter/vercel/index.ts", "./netlify": "./src/adapter/netlify/index.ts", "./lambda-edge": "./src/adapter/lambda-edge/index.ts", diff --git a/package.json b/package.json index b3a6cfefa..fac01e102 100644 --- a/package.json +++ b/package.json @@ -349,6 +349,21 @@ "import": "./dist/adapter/aws-lambda/index.js", "require": "./dist/cjs/adapter/aws-lambda/index.js" }, + "./aws-lambda/alb": { + "types": "./dist/types/adapter/aws-lambda/alb.d.ts", + "import": "./dist/adapter/aws-lambda/alb.js", + "require": "./dist/cjs/adapter/aws-lambda/alb.js" + }, + "./aws-lambda/api-gateway": { + "types": "./dist/types/adapter/aws-lambda/api-gateway.d.ts", + "import": "./dist/adapter/aws-lambda/api-gateway.js", + "require": "./dist/cjs/adapter/aws-lambda/api-gateway.js" + }, + "./aws-lambda/api-gateway-v2": { + "types": "./dist/types/adapter/aws-lambda/api-gateway-v2.d.ts", + "import": "./dist/adapter/aws-lambda/api-gateway-v2.js", + "require": "./dist/cjs/adapter/aws-lambda/api-gateway-v2.js" + }, "./vercel": { "types": "./dist/types/adapter/vercel/index.d.ts", "import": "./dist/adapter/vercel/index.js", @@ -575,6 +590,15 @@ "aws-lambda": [ "./dist/types/adapter/aws-lambda" ], + "aws-lambda/alb": [ + "./dist/types/adapter/aws-lambda/alb.d.ts" + ], + "aws-lambda/api-gateway":[ + "./dist/types/adapter/aws-lambda/api-gateway.d.ts" + ], + "aws-lambda/api-gateway-v2":[ + "./dist/types/adapter/aws-lambda/api-gateway-v2.d.ts" + ], "vercel": [ "./dist/types/adapter/vercel" ], diff --git a/src/adapter/aws-lambda/alb.ts b/src/adapter/aws-lambda/alb.ts new file mode 100644 index 000000000..4fd309aff --- /dev/null +++ b/src/adapter/aws-lambda/alb.ts @@ -0,0 +1,24 @@ +/** + * @module + * AWS Lambda Adapter for Hono. Invoked by ALB Event. + */ + +export { handle, streamHandle } from './handler' +export type { APIGatewayProxyResult, ALBProxyEvent } from './handler' +export type { ALBRequestContext, LambdaContext } from './types' + +import type { ALBProxyEvent } from './handler' +import type { LambdaContext } from './types' + +declare module '../../types' { + interface DefaultEnv { + Bindings: DefaultBindings + } + + interface DefaultBindings { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore On development, this line will raise an error because of interface merging. + event: ALBProxyEvent + lambdaContext: LambdaContext + } +} diff --git a/src/adapter/aws-lambda/api-gateway-v2.ts b/src/adapter/aws-lambda/api-gateway-v2.ts new file mode 100644 index 000000000..0acd0a2e7 --- /dev/null +++ b/src/adapter/aws-lambda/api-gateway-v2.ts @@ -0,0 +1,24 @@ +/** + * @module + * AWS Lambda Adapter for Hono. Invoked by AWS API Gateway Proxy Event V2. + */ + +export { handle, streamHandle } from './handler' +export type { APIGatewayProxyResult, APIGatewayProxyEventV2 } from './handler' +export type { ApiGatewayRequestContext, LambdaContext } from './types' + +import type { APIGatewayProxyEventV2 } from './handler' +import type { LambdaContext } from './types' + +declare module '../../types' { + interface DefaultEnv { + Bindings: DefaultBindings + } + + interface DefaultBindings { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore On development, this line will raise an error because of interface merging. + event: APIGatewayProxyEventV2 + lambdaContext: LambdaContext + } +} diff --git a/src/adapter/aws-lambda/api-gateway.ts b/src/adapter/aws-lambda/api-gateway.ts new file mode 100644 index 000000000..2d448412c --- /dev/null +++ b/src/adapter/aws-lambda/api-gateway.ts @@ -0,0 +1,24 @@ +/** + * @module + * AWS Lambda Adapter for Hono. Invoked by AWS API Gateway Proxy Event. + */ + +export { handle, streamHandle } from './handler' +export type { APIGatewayProxyResult, APIGatewayProxyEvent } from './handler' +export type { ApiGatewayRequestContextV2, LambdaContext } from './types' + +import type { APIGatewayProxyEvent } from './handler' +import type { LambdaContext } from './types' + +declare module '../../types' { + interface DefaultEnv { + Bindings: DefaultBindings + } + + interface DefaultBindings { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore On development, this line will raise an error because of interface merging. + event: APIGatewayProxyEvent + lambdaContext: LambdaContext + } +} diff --git a/src/adapter/aws-lambda/handler.ts b/src/adapter/aws-lambda/handler.ts index a8bb83461..f4987d9e3 100644 --- a/src/adapter/aws-lambda/handler.ts +++ b/src/adapter/aws-lambda/handler.ts @@ -1,6 +1,6 @@ import crypto from 'node:crypto' import type { Hono } from '../../hono' -import type { Env, Schema } from '../../types' +import type { DefaultEnv, Env, Schema } from '../../types' import { decodeBase64, encodeBase64 } from '../../utils/encode' import type { ALBRequestContext, @@ -106,7 +106,7 @@ const streamToNodeStream = async ( } export const streamHandle = < - E extends Env = Env, + E extends Env = DefaultEnv, S extends Schema = {}, BasePath extends string = '/' >( @@ -165,7 +165,11 @@ export const streamHandle = < /** * Accepts events from API Gateway/ELB(`APIGatewayProxyEvent`) and directly through Function Url(`APIGatewayProxyEventV2`) */ -export const handle = ( +export const handle = < + E extends Env = DefaultEnv, + S extends Schema = {}, + BasePath extends string = '/' +>( app: Hono ): ((event: LambdaEvent, lambdaContext?: LambdaContext) => Promise) => { return async (event, lambdaContext?) => { diff --git a/src/adapter/bun/serve-static.ts b/src/adapter/bun/serve-static.ts index c5be32e6c..52e7b97db 100644 --- a/src/adapter/bun/serve-static.ts +++ b/src/adapter/bun/serve-static.ts @@ -2,11 +2,11 @@ import { stat } from 'node:fs/promises' import { serveStatic as baseServeStatic } from '../../middleware/serve-static' import type { ServeStaticOptions } from '../../middleware/serve-static' -import type { Env, MiddlewareHandler } from '../../types' +import type { DefaultEnv, Env, MiddlewareHandler } from '../../types' -export const serveStatic = ( +export const serveStatic = ( options: ServeStaticOptions -): MiddlewareHandler => { +): MiddlewareHandler => { return async function serveStatic(c, next) { const getContent = async (path: string) => { path = path.startsWith('/') ? path : `./${path}` @@ -25,7 +25,7 @@ export const serveStatic = ( } catch {} return isDir } - return baseServeStatic({ + return baseServeStatic({ ...options, getContent, pathResolve, diff --git a/src/adapter/cloudflare-pages/handler.test.ts b/src/adapter/cloudflare-pages/handler.test.ts index 747d11e07..52cd9b8a1 100644 --- a/src/adapter/cloudflare-pages/handler.test.ts +++ b/src/adapter/cloudflare-pages/handler.test.ts @@ -67,7 +67,7 @@ describe('Adapter for Cloudflare Pages', () => { it('Should not use `basePath()` if path argument is not passed', async () => { const request = new Request('http://localhost/api/error') const eventContext = createEventContext({ request }) - const app = new Hono().basePath('/api') + const app = new Hono().basePath('/api') app.onError((e) => { throw e diff --git a/src/adapter/cloudflare-pages/handler.ts b/src/adapter/cloudflare-pages/handler.ts index 6eb7df406..0aba1952e 100644 --- a/src/adapter/cloudflare-pages/handler.ts +++ b/src/adapter/cloudflare-pages/handler.ts @@ -1,7 +1,7 @@ import { Context } from '../../context' import type { Hono } from '../../hono' import { HTTPException } from '../../http-exception' -import type { BlankSchema, Env, Input, MiddlewareHandler, Schema } from '../../types' +import type { BlankSchema, DefaultEnv, Env, Input, MiddlewareHandler, Schema } from '../../types' // Ref: https://github.com/cloudflare/workerd/blob/main/types/defines/pages.d.ts @@ -28,7 +28,7 @@ declare type PagesFunction< > = (context: EventContext) => Response | Promise export const handle = - ( + ( app: Hono ): PagesFunction => (eventContext) => { @@ -110,7 +110,7 @@ declare abstract class FetcherLike { */ export const serveStatic = (): MiddlewareHandler => { return async (c) => { - const env = c.env as { ASSETS: FetcherLike } + const env = c.env as unknown as { ASSETS: FetcherLike } const res = await env.ASSETS.fetch(c.req.raw) if (res.status === 404) { return c.notFound() diff --git a/src/adapter/cloudflare-pages/index.ts b/src/adapter/cloudflare-pages/index.ts index 0bbeb2a37..d967c4b56 100644 --- a/src/adapter/cloudflare-pages/index.ts +++ b/src/adapter/cloudflare-pages/index.ts @@ -5,3 +5,15 @@ export { handle, handleMiddleware, serveStatic } from './handler' export type { EventContext } from './handler' +import type { EventContext } from './handler' + +declare module '../../types' { + interface DefaultEnv { + Bindings: DefaultBindings + } + + interface DefaultBindings { + eventContext: EventContext + ASSETS: { fetch: typeof fetch } + } +} diff --git a/src/adapter/cloudflare-workers/serve-static-module.ts b/src/adapter/cloudflare-workers/serve-static-module.ts index bbd8c01e6..020e90c60 100644 --- a/src/adapter/cloudflare-workers/serve-static-module.ts +++ b/src/adapter/cloudflare-workers/serve-static-module.ts @@ -1,11 +1,11 @@ // For ES module mode -import type { Env, MiddlewareHandler } from '../../types' +import type { DefaultEnv, Env, MiddlewareHandler } from '../../types' import type { ServeStaticOptions } from './serve-static' import { serveStatic } from './serve-static' -const module = ( +const module = ( options: Omit, 'namespace'> -): MiddlewareHandler => { +): MiddlewareHandler => { return serveStatic(options) } diff --git a/src/adapter/cloudflare-workers/serve-static.ts b/src/adapter/cloudflare-workers/serve-static.ts index 453db7e13..ea00b7462 100644 --- a/src/adapter/cloudflare-workers/serve-static.ts +++ b/src/adapter/cloudflare-workers/serve-static.ts @@ -1,9 +1,9 @@ import { serveStatic as baseServeStatic } from '../../middleware/serve-static' import type { ServeStaticOptions as BaseServeStaticOptions } from '../../middleware/serve-static' -import type { Env, MiddlewareHandler } from '../../types' +import type { DefaultEnv, Env, MiddlewareHandler } from '../../types' import { getContentFromKVAsset } from './utils' -export type ServeStaticOptions = BaseServeStaticOptions & { +export type ServeStaticOptions = BaseServeStaticOptions & { // namespace is KVNamespace namespace?: unknown manifest: object | string @@ -18,9 +18,9 @@ export type ServeStaticOptions = BaseServeStaticOptions * please consider using Cloudflare Pages. You can start to create the Cloudflare Pages * application with the `npm create hono@latest` command. */ -export const serveStatic = ( +export const serveStatic = ( options: ServeStaticOptions -): MiddlewareHandler => { +): MiddlewareHandler => { return async function serveStatic(c, next) { const getContent = async (path: string) => { return getContentFromKVAsset(path, { @@ -30,11 +30,12 @@ export const serveStatic = ( namespace: options.namespace ? options.namespace : c.env - ? c.env.__STATIC_CONTENT + ? // eslint-disable-next-line @typescript-eslint/no-explicit-any + (c.env as any).__STATIC_CONTENT : undefined, }) } - return baseServeStatic({ + return baseServeStatic({ ...options, getContent, })(c, next) diff --git a/src/adapter/deno/serve-static.ts b/src/adapter/deno/serve-static.ts index 867f6f9ea..b32e4b3f3 100644 --- a/src/adapter/deno/serve-static.ts +++ b/src/adapter/deno/serve-static.ts @@ -1,12 +1,12 @@ import type { ServeStaticOptions } from '../../middleware/serve-static' import { serveStatic as baseServeStatic } from '../../middleware/serve-static' -import type { Env, MiddlewareHandler } from '../../types' +import type { DefaultEnv, Env, MiddlewareHandler } from '../../types' const { open, lstatSync, errors } = Deno -export const serveStatic = ( +export const serveStatic = ( options: ServeStaticOptions -): MiddlewareHandler => { +): MiddlewareHandler => { return async function serveStatic(c, next) { const getContent = async (path: string) => { try { @@ -35,7 +35,7 @@ export const serveStatic = ( return isDir } - return baseServeStatic({ + return baseServeStatic({ ...options, getContent, pathResolve, diff --git a/src/adapter/lambda-edge/index.ts b/src/adapter/lambda-edge/index.ts index b8b2aada1..4ca3722c1 100644 --- a/src/adapter/lambda-edge/index.ts +++ b/src/adapter/lambda-edge/index.ts @@ -12,3 +12,28 @@ export type { CloudFrontResponse, CloudFrontEdgeEvent, } from './handler' + +import type { + Callback, + CloudFrontConfig, + CloudFrontRequest, + CloudFrontResponse, + CloudFrontEdgeEvent, +} from './handler' + +declare module '../../types' { + interface DefaultEnv { + Bindings: DefaultBindings + } + + interface DefaultBindings { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore On development, this line will raise an error because of interface merging. + event: CloudFrontEdgeEvent + context?: {} + callback: Callback + config: CloudFrontConfig + request: CloudFrontRequest + response?: CloudFrontResponse + } +} diff --git a/src/context.ts b/src/context.ts index a5f6b4c6a..a37abeee7 100644 --- a/src/context.ts +++ b/src/context.ts @@ -242,7 +242,7 @@ type ContextOptions = { * Handler for not found responses. */ notFoundHandler?: NotFoundHandler - matchResult?: Result<[H, RouterRoute]> + matchResult?: Result<[H, RouterRoute]> path?: string } @@ -339,7 +339,7 @@ export class Context< #renderer: Renderer | undefined #notFoundHandler: NotFoundHandler | undefined - #matchResult: Result<[H, RouterRoute]> | undefined + #matchResult: Result<[H, RouterRoute]> | undefined #path: string | undefined /** diff --git a/src/hono-base.ts b/src/hono-base.ts index c141a0db6..3fb91fd16 100644 --- a/src/hono-base.ts +++ b/src/hono-base.ts @@ -10,12 +10,13 @@ import type { ExecutionContext } from './context' import type { Router } from './router' import { METHODS, METHOD_NAME_ALL, METHOD_NAME_ALL_LOWERCASE } from './router' import type { + DefaultEnv, Env, ErrorHandler, FetchEventLike, H, - HTTPResponseError, HandlerInterface, + HTTPResponseError, MergePath, MergeSchemaPath, MiddlewareHandler, @@ -62,7 +63,7 @@ export type HonoOptions = { * const app = new Hono({ router: new RegExpRouter() }) * ``` */ - router?: Router<[H, RouterRoute]> + router?: Router<[H, RouterRoute]> /** * `getPath` can handle the host header value. * @@ -95,7 +96,7 @@ type MountOptions = replaceRequest?: MountReplaceRequest } -class Hono { +class Hono { get!: HandlerInterface post!: HandlerInterface put!: HandlerInterface @@ -110,19 +111,19 @@ class Hono + router!: Router<[H, RouterRoute]> readonly getPath: GetPath // Cannot use `#` because it requires visibility at JavaScript runtime. private _basePath: string = '/' #path: string = '/' - routes: RouterRoute[] = [] + routes: RouterRoute[] = [] constructor(options: HonoOptions = {}) { // Implementation of app.get(...handlers[]) or app.get(path, ...handlers[]) const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE] allMethods.forEach((method) => { - this[method] = (args1: string | H, ...args: H[]) => { + this[method] = (args1: string | H, ...args: H[]) => { if (typeof args1 === 'string') { this.#path = args1 } else { @@ -136,7 +137,7 @@ class Hono { + this.on = (method: string | string[], path: string | string[], ...handlers: H[]) => { for (const p of [path].flat()) { this.#path = p for (const m of [method].flat()) { @@ -177,9 +178,9 @@ class Hono = notFoundHandler // Cannot use `#` because it requires visibility at JavaScript runtime. - private errorHandler: ErrorHandler = errorHandler + private errorHandler: ErrorHandler = errorHandler /** * `.route()` allows grouping other Hono instance in routes. @@ -215,11 +216,11 @@ class Hono - (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res + (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res ;(handler as any)[COMPOSED_HANDLER] = r.handler } - subApp.#addRoute(r.method, r.path, handler) + subApp.#addRoute(r.method, r.path, handler as any) }) return this } @@ -334,7 +335,7 @@ class Hono unknown[] = optionHandler + const getOptions: (c: Context) => unknown[] = optionHandler ? (c) => { const options = optionHandler!(c) return Array.isArray(options) ? options : [options] @@ -356,7 +357,7 @@ class Hono { + const handler: MiddlewareHandler = async (c, next) => { const res = await applicationHandler(replaceRequest!(c.req.raw), ...getOptions(c)) if (res) { @@ -369,10 +370,10 @@ class Hono) { method = method.toUpperCase() path = mergePath(this._basePath, path) - const r: RouterRoute = { path, method, handler } + const r: RouterRoute = { path, method, handler } this.router.add(method, path, [handler, r]) this.routes.push(r) } @@ -428,7 +429,7 @@ class Hono(matchResult[0], this.errorHandler, this.#notFoundHandler) + const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler) return (async () => { try { diff --git a/src/hono.ts b/src/hono.ts index d15a8e304..a5072dff0 100644 --- a/src/hono.ts +++ b/src/hono.ts @@ -3,7 +3,7 @@ import type { HonoOptions } from './hono-base' import { RegExpRouter } from './router/reg-exp-router' import { SmartRouter } from './router/smart-router' import { TrieRouter } from './router/trie-router' -import type { BlankEnv, BlankSchema, Env, Schema } from './types' +import type { BlankSchema, DefaultEnv, Env, Schema } from './types' /** * The Hono class extends the functionality of the HonoBase class. @@ -14,7 +14,7 @@ import type { BlankEnv, BlankSchema, Env, Schema } from './types' * @template BasePath - The base path type. */ export class Hono< - E extends Env = BlankEnv, + E extends Env = DefaultEnv, S extends Schema = BlankSchema, BasePath extends string = '/' > extends HonoBase { diff --git a/src/index.ts b/src/index.ts index ba20118b9..baab0d687 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,6 +21,9 @@ import { Hono } from './hono' */ export type { Env, + DefaultEnv, + DefaultBindings, + DefaultVariables, ErrorHandler, Handler, MiddlewareHandler, diff --git a/src/middleware/combine/index.ts b/src/middleware/combine/index.ts index 2a258bc35..d38bdcad3 100644 --- a/src/middleware/combine/index.ts +++ b/src/middleware/combine/index.ts @@ -7,9 +7,9 @@ import { compose } from '../../compose' import type { Context } from '../../context' import { METHOD_NAME_ALL } from '../../router' import { TrieRouter } from '../../router/trie-router' -import type { MiddlewareHandler, Next } from '../../types' +import type { DefaultEnv, Env, MiddlewareHandler, Next } from '../../types' -type Condition = (c: Context) => boolean +type Condition = (c: Context) => boolean /** * Create a composed middleware that runs the first middleware that returns true. diff --git a/src/middleware/serve-static/index.ts b/src/middleware/serve-static/index.ts index 0f1837f22..bad38d188 100644 --- a/src/middleware/serve-static/index.ts +++ b/src/middleware/serve-static/index.ts @@ -4,7 +4,7 @@ */ import type { Context, Data } from '../../context' -import type { Env, MiddlewareHandler } from '../../types' +import type { DefaultEnv, Env, MiddlewareHandler } from '../../types' import { COMPRESSIBLE_CONTENT_TYPE_REGEX } from '../../utils/compress' import { getFilePath, getFilePathWithoutDefaultDocument } from '../../utils/filepath' import { getMimeType } from '../../utils/mime' @@ -32,13 +32,13 @@ const defaultPathResolve = (path: string) => path /** * This middleware is not directly used by the user. Create a wrapper specifying `getContent()` by the environment such as Deno or Bun. */ -export const serveStatic = ( +export const serveStatic = ( options: ServeStaticOptions & { getContent: (path: string, c: Context) => Promise pathResolve?: (path: string) => string isDir?: (path: string) => boolean | undefined | Promise } -): MiddlewareHandler => { +): MiddlewareHandler => { let isAbsoluteRoot = false let root: string diff --git a/src/preset/quick.ts b/src/preset/quick.ts index 06e89344e..bd9e4bdd6 100644 --- a/src/preset/quick.ts +++ b/src/preset/quick.ts @@ -8,10 +8,10 @@ import type { HonoOptions } from '../hono-base' import { LinearRouter } from '../router/linear-router' import { SmartRouter } from '../router/smart-router' import { TrieRouter } from '../router/trie-router' -import type { BlankEnv, BlankSchema, Env, Schema } from '../types' +import type { BlankSchema, DefaultEnv, Env, Schema } from '../types' export class Hono< - E extends Env = BlankEnv, + E extends Env = DefaultEnv, S extends Schema = BlankSchema, BasePath extends string = '/' > extends HonoBase { diff --git a/src/preset/tiny.ts b/src/preset/tiny.ts index f23f1a11a..85595c7e0 100644 --- a/src/preset/tiny.ts +++ b/src/preset/tiny.ts @@ -6,10 +6,10 @@ import { HonoBase } from '../hono-base' import type { HonoOptions } from '../hono-base' import { PatternRouter } from '../router/pattern-router' -import type { BlankEnv, BlankSchema, Env, Schema } from '../types' +import type { BlankSchema, DefaultEnv, Env, Schema } from '../types' export class Hono< - E extends Env = BlankEnv, + E extends Env = DefaultEnv, S extends Schema = BlankSchema, BasePath extends string = '/' > extends HonoBase { diff --git a/src/request.ts b/src/request.ts index 68c710c35..0e10d31be 100644 --- a/src/request.ts +++ b/src/request.ts @@ -64,7 +64,7 @@ export class HonoRequest

{ constructor( request: Request, path: string = '/', - matchResult: Result<[unknown, RouterRoute]> = [[]] + matchResult: Result<[unknown, RouterRoute]> = [[]] ) { this.raw = request this.path = path diff --git a/src/types.ts b/src/types.ts index bfa96a260..b4236237f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -32,6 +32,51 @@ export type Env = { Bindings?: Bindings Variables?: Variables } +/** + * Default `Env` type. This type is designed to be used with interface merging. + * + * @see {Env} + * @example + * declare module 'hono' { + * interface DefaultEnv { + * Bindings: DefaultBindings + * Variables: DefaultVariables + * } + * } + */ +export interface DefaultEnv {} +/** + * Default `Bindings` type. This type is designed to be used with interface merging. + * + * @see {Bindings} + * @example + * declare module 'hono' { + * interface DefaultEnv { + * Bindings: DefaultBindings + * } + * + * interface DefaultBindings { + * lambdaContext: LambdaContext + * } + * } + */ +export interface DefaultBindings {} +/** + * Default `Variables` type. This type is designed to be used with interface merging. + * + * @see {Variables} + * @example + * declare module 'hono' { + * interface DefaultEnv { + * Variables: DefaultVariables + * } + * + * interface DefaultVariables { + * foo: () => string + * } + * } + */ +export interface DefaultVariables {} export type Next = () => Promise @@ -55,10 +100,10 @@ export type BlankInput = {} ////// ////// //////////////////////////////////////// -export interface RouterRoute { +export interface RouterRoute { path: string method: string - handler: H + handler: H } //////////////////////////////////////// @@ -70,31 +115,33 @@ export interface RouterRoute { export type HandlerResponse = Response | TypedResponse | Promise> export type Handler< - E extends Env = any, + E extends Env = DefaultEnv, P extends string = any, I extends Input = BlankInput, R extends HandlerResponse = any > = (c: Context, next: Next) => R export type MiddlewareHandler< - E extends Env = any, + E extends Env = DefaultEnv, P extends string = string, I extends Input = {} > = (c: Context, next: Next) => Promise export type H< - E extends Env = any, + E extends Env = DefaultEnv, P extends string = any, I extends Input = BlankInput, R extends HandlerResponse = any > = Handler | MiddlewareHandler -export type NotFoundHandler = (c: Context) => Response | Promise +export type NotFoundHandler = ( + c: Context +) => Response | Promise export interface HTTPResponseError extends Error { getResponse: () => Response } -export type ErrorHandler = ( +export type ErrorHandler = ( err: Error | HTTPResponseError, c: Context ) => Response | Promise @@ -680,11 +727,6 @@ export interface MiddlewareHandlerInterface< S extends Schema = BlankSchema, BasePath extends string = '/' > { - //// app.use(...handlers[]) - ( - ...handlers: MiddlewareHandler>>[] - ): HonoBase, S, BasePath> - // app.use(handler) ( handler: MiddlewareHandler>> @@ -1058,7 +1100,12 @@ export interface MiddlewareHandlerInterface< BasePath > - //// app.use(path, ...handlers[]) + // app.use(...handlers[]) + ( + ...handlers: MiddlewareHandler>>[] + ): HonoBase, S, BasePath> + + // app.use(path, ...handlers[])

( path: P, ...handlers: MiddlewareHandler>[]