Skip to content

Commit 614c8aa

Browse files
committed
feat(types): Add DefaultEnv for zero runtime factory with interface merging
1 parent e7fbc3e commit 614c8aa

24 files changed

+259
-67
lines changed

jsr.json

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
"./deno": "./src/adapter/deno/index.ts",
7676
"./bun": "./src/adapter/bun/index.ts",
7777
"./aws-lambda": "./src/adapter/aws-lambda/index.ts",
78+
"./aws-lambda/alb": "./src/adapter/aws-lambda/alb.ts",
79+
"./aws-lambda/api-gateway":"./src/adapter/aws-lambda/api-gateway.ts",
80+
"./aws-lambda/api-gateway-v2":"./src/adapter/aws-lambda/api-gateway-v2.ts",
7881
"./vercel": "./src/adapter/vercel/index.ts",
7982
"./netlify": "./src/adapter/netlify/index.ts",
8083
"./lambda-edge": "./src/adapter/lambda-edge/index.ts",

package.json

+24
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,21 @@
359359
"import": "./dist/adapter/aws-lambda/index.js",
360360
"require": "./dist/cjs/adapter/aws-lambda/index.js"
361361
},
362+
"./aws-lambda/alb": {
363+
"types": "./dist/types/adapter/aws-lambda/alb.d.ts",
364+
"import": "./dist/adapter/aws-lambda/alb.js",
365+
"require": "./dist/cjs/adapter/aws-lambda/alb.js"
366+
},
367+
"./aws-lambda/api-gateway": {
368+
"types": "./dist/types/adapter/aws-lambda/api-gateway.d.ts",
369+
"import": "./dist/adapter/aws-lambda/api-gateway.js",
370+
"require": "./dist/cjs/adapter/aws-lambda/api-gateway.js"
371+
},
372+
"./aws-lambda/api-gateway-v2": {
373+
"types": "./dist/types/adapter/aws-lambda/api-gateway-v2.d.ts",
374+
"import": "./dist/adapter/aws-lambda/api-gateway-v2.js",
375+
"require": "./dist/cjs/adapter/aws-lambda/api-gateway-v2.js"
376+
},
362377
"./vercel": {
363378
"types": "./dist/types/adapter/vercel/index.d.ts",
364379
"import": "./dist/adapter/vercel/index.js",
@@ -593,6 +608,15 @@
593608
"aws-lambda": [
594609
"./dist/types/adapter/aws-lambda"
595610
],
611+
"aws-lambda/alb": [
612+
"./dist/types/adapter/aws-lambda/alb.d.ts"
613+
],
614+
"aws-lambda/api-gateway":[
615+
"./dist/types/adapter/aws-lambda/api-gateway.d.ts"
616+
],
617+
"aws-lambda/api-gateway-v2":[
618+
"./dist/types/adapter/aws-lambda/api-gateway-v2.d.ts"
619+
],
596620
"vercel": [
597621
"./dist/types/adapter/vercel"
598622
],

src/adapter/aws-lambda/alb.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @module
3+
* AWS Lambda Adapter for Hono. Invoked by ALB Event.
4+
*/
5+
6+
export { handle, streamHandle } from './handler'
7+
export type { APIGatewayProxyResult, ALBProxyEvent } from './handler'
8+
export type { ALBRequestContext, LambdaContext } from './types'
9+
10+
import type { ALBProxyEvent } from './handler'
11+
import type { LambdaContext } from './types'
12+
13+
declare module '../../types' {
14+
interface DefaultEnv {
15+
Bindings: DefaultBindings
16+
}
17+
18+
interface DefaultBindings {
19+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
20+
// @ts-ignore On development, this line will raise an error because of interface merging.
21+
event: ALBProxyEvent
22+
lambdaContext: LambdaContext
23+
}
24+
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @module
3+
* AWS Lambda Adapter for Hono. Invoked by AWS API Gateway Proxy Event V2.
4+
*/
5+
6+
export { handle, streamHandle } from './handler'
7+
export type { APIGatewayProxyResult, APIGatewayProxyEventV2 } from './handler'
8+
export type { ApiGatewayRequestContext, LambdaContext } from './types'
9+
10+
import type { APIGatewayProxyEventV2 } from './handler'
11+
import type { LambdaContext } from './types'
12+
13+
declare module '../../types' {
14+
interface DefaultEnv {
15+
Bindings: DefaultBindings
16+
}
17+
18+
interface DefaultBindings {
19+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
20+
// @ts-ignore On development, this line will raise an error because of interface merging.
21+
event: APIGatewayProxyEventV2
22+
lambdaContext: LambdaContext
23+
}
24+
}

src/adapter/aws-lambda/api-gateway.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @module
3+
* AWS Lambda Adapter for Hono. Invoked by AWS API Gateway Proxy Event.
4+
*/
5+
6+
export { handle, streamHandle } from './handler'
7+
export type { APIGatewayProxyResult, APIGatewayProxyEvent } from './handler'
8+
export type { ApiGatewayRequestContextV2, LambdaContext } from './types'
9+
10+
import type { APIGatewayProxyEvent } from './handler'
11+
import type { LambdaContext } from './types'
12+
13+
declare module '../../types' {
14+
interface DefaultEnv {
15+
Bindings: DefaultBindings
16+
}
17+
18+
interface DefaultBindings {
19+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
20+
// @ts-ignore On development, this line will raise an error because of interface merging.
21+
event: APIGatewayProxyEvent
22+
lambdaContext: LambdaContext
23+
}
24+
}

src/adapter/aws-lambda/handler.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Hono } from '../../hono'
2-
import type { Env, Schema } from '../../types'
2+
import type { DefaultEnv, Env, Schema } from '../../types'
33
import { decodeBase64, encodeBase64 } from '../../utils/encode'
44
import type {
55
ALBRequestContext,
@@ -101,7 +101,7 @@ const streamToNodeStream = async (
101101
}
102102

103103
export const streamHandle = <
104-
E extends Env = Env,
104+
E extends Env = DefaultEnv,
105105
S extends Schema = {},
106106
BasePath extends string = '/'
107107
>(
@@ -160,7 +160,11 @@ export const streamHandle = <
160160
/**
161161
* Accepts events from API Gateway/ELB(`APIGatewayProxyEvent`) and directly through Function Url(`APIGatewayProxyEventV2`)
162162
*/
163-
export const handle = <E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'>(
163+
export const handle = <
164+
E extends Env = DefaultEnv,
165+
S extends Schema = {},
166+
BasePath extends string = '/'
167+
>(
164168
app: Hono<E, S, BasePath>
165169
): ((event: LambdaEvent, lambdaContext?: LambdaContext) => Promise<APIGatewayProxyResult>) => {
166170
return async (event, lambdaContext?) => {

src/adapter/bun/serve-static.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
import { stat } from 'node:fs/promises'
33
import { serveStatic as baseServeStatic } from '../../middleware/serve-static'
44
import type { ServeStaticOptions } from '../../middleware/serve-static'
5-
import type { Env, MiddlewareHandler } from '../../types'
5+
import type { DefaultEnv, Env, MiddlewareHandler } from '../../types'
66

7-
export const serveStatic = <E extends Env = Env>(
7+
export const serveStatic = <E extends Env = DefaultEnv>(
88
options: ServeStaticOptions<E>
9-
): MiddlewareHandler => {
9+
): MiddlewareHandler<E> => {
1010
return async function serveStatic(c, next) {
1111
const getContent = async (path: string) => {
1212
path = path.startsWith('/') ? path : `./${path}`
@@ -25,7 +25,7 @@ export const serveStatic = <E extends Env = Env>(
2525
} catch {}
2626
return isDir
2727
}
28-
return baseServeStatic({
28+
return baseServeStatic<E>({
2929
...options,
3030
getContent,
3131
pathResolve,

src/adapter/cloudflare-pages/handler.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ describe('Adapter for Cloudflare Pages', () => {
6767
it('Should not use `basePath()` if path argument is not passed', async () => {
6868
const request = new Request('http://localhost/api/error')
6969
const eventContext = createEventContext({ request })
70-
const app = new Hono().basePath('/api')
70+
const app = new Hono<Env>().basePath('/api')
7171

7272
app.onError((e) => {
7373
throw e

src/adapter/cloudflare-pages/handler.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Context } from '../../context'
22
import type { Hono } from '../../hono'
33
import { HTTPException } from '../../http-exception'
4-
import type { BlankSchema, Env, Input, MiddlewareHandler, Schema } from '../../types'
4+
import type { BlankSchema, DefaultEnv, Env, Input, MiddlewareHandler, Schema } from '../../types'
55

66
// Ref: https://github.com/cloudflare/workerd/blob/main/types/defines/pages.d.ts
77

@@ -28,7 +28,7 @@ declare type PagesFunction<
2828
> = (context: EventContext<Env, Params, Data>) => Response | Promise<Response>
2929

3030
export const handle =
31-
<E extends Env = Env, S extends Schema = BlankSchema, BasePath extends string = '/'>(
31+
<E extends Env = DefaultEnv, S extends Schema = BlankSchema, BasePath extends string = '/'>(
3232
app: Hono<E, S, BasePath>
3333
): PagesFunction<E['Bindings']> =>
3434
(eventContext) => {
@@ -110,7 +110,7 @@ declare abstract class FetcherLike {
110110
*/
111111
export const serveStatic = (): MiddlewareHandler => {
112112
return async (c) => {
113-
const env = c.env as { ASSETS: FetcherLike }
113+
const env = c.env as unknown as { ASSETS: FetcherLike }
114114
const res = await env.ASSETS.fetch(c.req.raw)
115115
if (res.status === 404) {
116116
return c.notFound()

src/adapter/cloudflare-pages/index.ts

+12
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,15 @@
55

66
export { handle, handleMiddleware, serveStatic } from './handler'
77
export type { EventContext } from './handler'
8+
import type { EventContext } from './handler'
9+
10+
declare module '../../types' {
11+
interface DefaultEnv {
12+
Bindings: DefaultBindings
13+
}
14+
15+
interface DefaultBindings {
16+
eventContext: EventContext<DefaultEnv>
17+
ASSETS: { fetch: typeof fetch }
18+
}
19+
}

src/adapter/cloudflare-workers/serve-static-module.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// For ES module mode
2-
import type { Env, MiddlewareHandler } from '../../types'
2+
import type { DefaultEnv, Env, MiddlewareHandler } from '../../types'
33
import type { ServeStaticOptions } from './serve-static'
44
import { serveStatic } from './serve-static'
55

6-
const module = <E extends Env = Env>(
6+
const module = <E extends Env = DefaultEnv>(
77
options: Omit<ServeStaticOptions<E>, 'namespace'>
8-
): MiddlewareHandler => {
8+
): MiddlewareHandler<E> => {
99
return serveStatic<E>(options)
1010
}
1111

src/adapter/cloudflare-workers/serve-static.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { serveStatic as baseServeStatic } from '../../middleware/serve-static'
22
import type { ServeStaticOptions as BaseServeStaticOptions } from '../../middleware/serve-static'
3-
import type { Env, MiddlewareHandler } from '../../types'
3+
import type { DefaultEnv, Env, MiddlewareHandler } from '../../types'
44
import { getContentFromKVAsset } from './utils'
55

6-
export type ServeStaticOptions<E extends Env = Env> = BaseServeStaticOptions<E> & {
6+
export type ServeStaticOptions<E extends Env = DefaultEnv> = BaseServeStaticOptions<E> & {
77
// namespace is KVNamespace
88
namespace?: unknown
99
manifest: object | string
@@ -18,9 +18,9 @@ export type ServeStaticOptions<E extends Env = Env> = BaseServeStaticOptions<E>
1818
* please consider using Cloudflare Pages. You can start to create the Cloudflare Pages
1919
* application with the `npm create hono@latest` command.
2020
*/
21-
export const serveStatic = <E extends Env = Env>(
21+
export const serveStatic = <E extends Env = DefaultEnv>(
2222
options: ServeStaticOptions<E>
23-
): MiddlewareHandler => {
23+
): MiddlewareHandler<E> => {
2424
return async function serveStatic(c, next) {
2525
const getContent = async (path: string) => {
2626
return getContentFromKVAsset(path, {
@@ -30,11 +30,12 @@ export const serveStatic = <E extends Env = Env>(
3030
namespace: options.namespace
3131
? options.namespace
3232
: c.env
33-
? c.env.__STATIC_CONTENT
33+
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
34+
(c.env as any).__STATIC_CONTENT
3435
: undefined,
3536
})
3637
}
37-
return baseServeStatic({
38+
return baseServeStatic<E>({
3839
...options,
3940
getContent,
4041
})(c, next)

src/adapter/deno/serve-static.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import type { ServeStaticOptions } from '../../middleware/serve-static'
22
import { serveStatic as baseServeStatic } from '../../middleware/serve-static'
3-
import type { Env, MiddlewareHandler } from '../../types'
3+
import type { DefaultEnv, Env, MiddlewareHandler } from '../../types'
44

55
const { open, lstatSync, errors } = Deno
66

7-
export const serveStatic = <E extends Env = Env>(
7+
export const serveStatic = <E extends Env = DefaultEnv>(
88
options: ServeStaticOptions<E>
9-
): MiddlewareHandler => {
9+
): MiddlewareHandler<E> => {
1010
return async function serveStatic(c, next) {
1111
const getContent = async (path: string) => {
1212
try {
@@ -35,7 +35,7 @@ export const serveStatic = <E extends Env = Env>(
3535
return isDir
3636
}
3737

38-
return baseServeStatic({
38+
return baseServeStatic<E>({
3939
...options,
4040
getContent,
4141
pathResolve,

src/adapter/lambda-edge/index.ts

+25
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,28 @@ export type {
1212
CloudFrontResponse,
1313
CloudFrontEdgeEvent,
1414
} from './handler'
15+
16+
import type {
17+
Callback,
18+
CloudFrontConfig,
19+
CloudFrontRequest,
20+
CloudFrontResponse,
21+
CloudFrontEdgeEvent,
22+
} from './handler'
23+
24+
declare module '../../types' {
25+
interface DefaultEnv {
26+
Bindings: DefaultBindings
27+
}
28+
29+
interface DefaultBindings {
30+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
31+
// @ts-ignore On development, this line will raise an error because of interface merging.
32+
event: CloudFrontEdgeEvent
33+
context?: {}
34+
callback: Callback
35+
config: CloudFrontConfig
36+
request: CloudFrontRequest
37+
response?: CloudFrontResponse
38+
}
39+
}

src/context.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ type ContextOptions<E extends Env> = {
242242
* Handler for not found responses.
243243
*/
244244
notFoundHandler?: NotFoundHandler<E>
245-
matchResult?: Result<[H, RouterRoute]>
245+
matchResult?: Result<[H<E>, RouterRoute<E>]>
246246
path?: string
247247
}
248248

@@ -339,7 +339,7 @@ export class Context<
339339
#renderer: Renderer | undefined
340340
#notFoundHandler: NotFoundHandler<E> | undefined
341341

342-
#matchResult: Result<[H, RouterRoute]> | undefined
342+
#matchResult: Result<[H<E>, RouterRoute<E>]> | undefined
343343
#path: string | undefined
344344

345345
/**

0 commit comments

Comments
 (0)