From aa6642bd63c0904dbc95ff57e4988aa5ff2019d5 Mon Sep 17 00:00:00 2001 From: sor4chi Date: Wed, 27 Dec 2023 05:21:08 +0000 Subject: [PATCH 1/5] feat: pass context to onNotFound callback in serveStatic --- src/adapter/bun/serve-static.ts | 10 +++++----- src/adapter/cloudflare-workers/serve-static.ts | 5 +++-- src/adapter/deno/serve-static.ts | 10 +++++----- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/adapter/bun/serve-static.ts b/src/adapter/bun/serve-static.ts index 084277a77..bacd257dd 100644 --- a/src/adapter/bun/serve-static.ts +++ b/src/adapter/bun/serve-static.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { existsSync } from 'fs' import type { Context } from '../../context' -import type { Next } from '../../types' +import type { MiddlewareHandler } from '../../types' import { getFilePath } from '../../utils/filepath' import { getMimeType } from '../../utils/mime' @@ -13,13 +13,13 @@ export type ServeStaticOptions = { root?: string path?: string rewriteRequestPath?: (path: string) => string - onNotFound?: (path: string) => void | Promise + onNotFound?: (path: string, c: Context) => void | Promise } const DEFAULT_DOCUMENT = 'index.html' -export const serveStatic = (options: ServeStaticOptions = { root: '' }) => { - return async (c: Context, next: Next) => { +export const serveStatic = (options: ServeStaticOptions = { root: '' }): MiddlewareHandler => { + return async (c, next) => { // Do nothing if Response is already set if (c.finalized) { await next() @@ -50,7 +50,7 @@ export const serveStatic = (options: ServeStaticOptions = { root: '' }) => { } } - await options.onNotFound?.(path) + await options.onNotFound?.(path, c) await next() return } diff --git a/src/adapter/cloudflare-workers/serve-static.ts b/src/adapter/cloudflare-workers/serve-static.ts index 2bcbd1a27..9676e7d3d 100644 --- a/src/adapter/cloudflare-workers/serve-static.ts +++ b/src/adapter/cloudflare-workers/serve-static.ts @@ -1,5 +1,6 @@ // @denoify-ignore import type { KVNamespace } from '@cloudflare/workers-types' +import type { Context } from '../../context' import type { MiddlewareHandler } from '../../types' import { getFilePath } from '../../utils/filepath' import { getMimeType } from '../../utils/mime' @@ -11,7 +12,7 @@ export type ServeStaticOptions = { manifest?: object | string namespace?: KVNamespace rewriteRequestPath?: (path: string) => string - onNotFound?: (path: string) => void | Promise + onNotFound?: (path: string, c: Context) => void | Promise } const DEFAULT_DOCUMENT = 'index.html' @@ -51,7 +52,7 @@ export const serveStatic = (options: ServeStaticOptions = { root: '' }): Middlew return c.body(content) } - await options.onNotFound?.(path) + await options.onNotFound?.(path, c) await next() return } diff --git a/src/adapter/deno/serve-static.ts b/src/adapter/deno/serve-static.ts index ccf9d4b91..d828d7396 100644 --- a/src/adapter/deno/serve-static.ts +++ b/src/adapter/deno/serve-static.ts @@ -1,5 +1,5 @@ import type { Context } from '../../context' -import type { Next } from '../../types' +import type { MiddlewareHandler } from '../../types' import { getFilePath } from '../../utils/filepath' import { getMimeType } from '../../utils/mime' @@ -11,13 +11,13 @@ export type ServeStaticOptions = { root?: string path?: string rewriteRequestPath?: (path: string) => string - onNotFound?: (path: string) => void | Promise + onNotFound?: (path: string, c: Context) => void | Promise } const DEFAULT_DOCUMENT = 'index.html' -export const serveStatic = (options: ServeStaticOptions = { root: '' }) => { - return async (c: Context, next: Next) => { +export const serveStatic = (options: ServeStaticOptions = { root: '' }): MiddlewareHandler => { + return async (c, next) => { // Do nothing if Response is already set if (c.finalized) { await next() @@ -53,7 +53,7 @@ export const serveStatic = (options: ServeStaticOptions = { root: '' }) => { return c.body(file.readable) } - await options.onNotFound?.(path) + await options.onNotFound?.(path, c) await next() return } From dc5ad1dcc656846d132ffbd6f5b96cfe5d1a08c3 Mon Sep 17 00:00:00 2001 From: sor4chi Date: Wed, 27 Dec 2023 05:36:42 +0000 Subject: [PATCH 2/5] chore: denoify --- deno_dist/adapter/deno/serve-static.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/deno_dist/adapter/deno/serve-static.ts b/deno_dist/adapter/deno/serve-static.ts index 8536bcd62..680decc0b 100644 --- a/deno_dist/adapter/deno/serve-static.ts +++ b/deno_dist/adapter/deno/serve-static.ts @@ -1,5 +1,5 @@ import type { Context } from '../../context.ts' -import type { Next } from '../../types.ts' +import type { MiddlewareHandler } from '../../types.ts' import { getFilePath } from '../../utils/filepath.ts' import { getMimeType } from '../../utils/mime.ts' @@ -11,13 +11,13 @@ export type ServeStaticOptions = { root?: string path?: string rewriteRequestPath?: (path: string) => string - onNotFound?: (path: string) => void | Promise + onNotFound?: (path: string, c: Context) => void | Promise } const DEFAULT_DOCUMENT = 'index.html' -export const serveStatic = (options: ServeStaticOptions = { root: '' }) => { - return async (c: Context, next: Next) => { +export const serveStatic = (options: ServeStaticOptions = { root: '' }): MiddlewareHandler => { + return async (c, next) => { // Do nothing if Response is already set if (c.finalized) { await next() @@ -53,7 +53,7 @@ export const serveStatic = (options: ServeStaticOptions = { root: '' }) => { return c.body(file.readable) } - await options.onNotFound?.(path) + await options.onNotFound?.(path, c) await next() return } From dfe060a4736580248f9ab9863ad877a9e91b255c Mon Sep 17 00:00:00 2001 From: sor4chi Date: Wed, 27 Dec 2023 16:15:52 +0900 Subject: [PATCH 3/5] test: update notFoundHandler's callback expect --- runtime_tests/bun/index.test.tsx | 5 ++++- runtime_tests/deno/middleware.test.tsx | 4 +--- src/adapter/cloudflare-workers/serve-static.test.ts | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/runtime_tests/bun/index.test.tsx b/runtime_tests/bun/index.test.tsx index 9264623ac..6a58a6bad 100644 --- a/runtime_tests/bun/index.test.tsx +++ b/runtime_tests/bun/index.test.tsx @@ -114,7 +114,10 @@ describe('Serve Static Middleware', () => { const res = await app.request(new Request('http://localhost/favicon-notfound.ico')) expect(res.status).toBe(404) expect(res.headers.get('X-Custom')).toBe('Bun') - expect(onNotFound).toHaveBeenCalledWith('./runtime_tests/bun/favicon-notfound.ico') + expect(onNotFound).toHaveBeenCalledWith( + './runtime_tests/bun/favicon-notfound.ico', + expect.anything() + ) }) it('Should return 200 response - /static/plain.txt', async () => { diff --git a/runtime_tests/deno/middleware.test.tsx b/runtime_tests/deno/middleware.test.tsx index 8dd5d6909..d1d1ce5c2 100644 --- a/runtime_tests/deno/middleware.test.tsx +++ b/runtime_tests/deno/middleware.test.tsx @@ -102,9 +102,7 @@ Deno.test('Serve Static middleware', async () => { assertEquals(res.status, 404) assertMatch(res.headers.get('Content-Type') || '', /^text\/plain/) assertEquals(res.headers.get('X-Custom'), 'Deno') - assertSpyCall(onNotFound, 0, { - args: ['./runtime_tests/deno/favicon-notfound.ico'], - }) + assertSpyCall(onNotFound, 0) res = await app.request('http://localhost/static/plain.txt') assertEquals(res.status, 200) diff --git a/src/adapter/cloudflare-workers/serve-static.test.ts b/src/adapter/cloudflare-workers/serve-static.test.ts index 2d1306850..dd19fa5ab 100644 --- a/src/adapter/cloudflare-workers/serve-static.test.ts +++ b/src/adapter/cloudflare-workers/serve-static.test.ts @@ -63,7 +63,7 @@ describe('ServeStatic Middleware', () => { it('Should return 404 response', async () => { const res = await app.request('http://localhost/static/not-found.html') expect(res.status).toBe(404) - expect(onNotFound).toHaveBeenCalledWith('assets/static/not-found.html') + expect(onNotFound).toHaveBeenCalledWith('assets/static/not-found.html', expect.anything()) }) it('Should return plan.txt', async () => { From a9436f5d08e1c5ddd6df25a799e123a6dcb3187c Mon Sep 17 00:00:00 2001 From: Sor4chi <80559385+sor4chi@users.noreply.github.com> Date: Tue, 2 Jan 2024 01:35:18 +0900 Subject: [PATCH 4/5] feat: add Env generics for serveStatic to support `c.env` type in callback handler --- deno_dist/adapter/deno/serve-static.ts | 10 ++++++---- src/adapter/bun/serve-static.ts | 10 ++++++---- .../cloudflare-workers/serve-static.test.ts | 20 +++++++++++++++++++ .../cloudflare-workers/serve-static.ts | 10 ++++++---- src/adapter/deno/serve-static.ts | 10 ++++++---- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/deno_dist/adapter/deno/serve-static.ts b/deno_dist/adapter/deno/serve-static.ts index 680decc0b..8cecd4fc5 100644 --- a/deno_dist/adapter/deno/serve-static.ts +++ b/deno_dist/adapter/deno/serve-static.ts @@ -1,5 +1,5 @@ import type { Context } from '../../context.ts' -import type { MiddlewareHandler } from '../../types.ts' +import type { Env, MiddlewareHandler } from '../../types.ts' import { getFilePath } from '../../utils/filepath.ts' import { getMimeType } from '../../utils/mime.ts' @@ -7,16 +7,18 @@ import { getMimeType } from '../../utils/mime.ts' // @ts-ignore const { open } = Deno -export type ServeStaticOptions = { +export type ServeStaticOptions = { root?: string path?: string rewriteRequestPath?: (path: string) => string - onNotFound?: (path: string, c: Context) => void | Promise + onNotFound?: (path: string, c: Context) => void | Promise } const DEFAULT_DOCUMENT = 'index.html' -export const serveStatic = (options: ServeStaticOptions = { root: '' }): MiddlewareHandler => { +export const serveStatic = ( + options: ServeStaticOptions = { root: '' } +): MiddlewareHandler => { return async (c, next) => { // Do nothing if Response is already set if (c.finalized) { diff --git a/src/adapter/bun/serve-static.ts b/src/adapter/bun/serve-static.ts index bacd257dd..479718f9a 100644 --- a/src/adapter/bun/serve-static.ts +++ b/src/adapter/bun/serve-static.ts @@ -2,23 +2,25 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { existsSync } from 'fs' import type { Context } from '../../context' -import type { MiddlewareHandler } from '../../types' +import type { Env, MiddlewareHandler } from '../../types' import { getFilePath } from '../../utils/filepath' import { getMimeType } from '../../utils/mime' // @ts-ignore const { file } = Bun -export type ServeStaticOptions = { +export type ServeStaticOptions = { root?: string path?: string rewriteRequestPath?: (path: string) => string - onNotFound?: (path: string, c: Context) => void | Promise + onNotFound?: (path: string, c: Context) => void | Promise } const DEFAULT_DOCUMENT = 'index.html' -export const serveStatic = (options: ServeStaticOptions = { root: '' }): MiddlewareHandler => { +export const serveStatic = ( + options: ServeStaticOptions = { root: '' } +): MiddlewareHandler => { return async (c, next) => { // Do nothing if Response is already set if (c.finalized) { diff --git a/src/adapter/cloudflare-workers/serve-static.test.ts b/src/adapter/cloudflare-workers/serve-static.test.ts index dd19fa5ab..a1474760e 100644 --- a/src/adapter/cloudflare-workers/serve-static.test.ts +++ b/src/adapter/cloudflare-workers/serve-static.test.ts @@ -155,3 +155,23 @@ describe('With middleware', () => { expect(await res.text()).toBe('bar') }) }) + +describe('Types of middleware', () => { + it('Should pass env type from generics of serveStatic', async () => { + type Env = { + Bindings: { + HOGE: string + } + } + const app = new Hono() + app.use( + '/static/*', + serveStatic({ + root: './assets', + onNotFound: (_, c) => { + expectTypeOf(c.env).toEqualTypeOf() + }, + }) + ) + }) +}) diff --git a/src/adapter/cloudflare-workers/serve-static.ts b/src/adapter/cloudflare-workers/serve-static.ts index 9676e7d3d..91cec143f 100644 --- a/src/adapter/cloudflare-workers/serve-static.ts +++ b/src/adapter/cloudflare-workers/serve-static.ts @@ -1,24 +1,26 @@ // @denoify-ignore import type { KVNamespace } from '@cloudflare/workers-types' import type { Context } from '../../context' -import type { MiddlewareHandler } from '../../types' +import type { Env, MiddlewareHandler } from '../../types' import { getFilePath } from '../../utils/filepath' import { getMimeType } from '../../utils/mime' import { getContentFromKVAsset } from './utils' -export type ServeStaticOptions = { +export type ServeStaticOptions = { root?: string path?: string manifest?: object | string namespace?: KVNamespace rewriteRequestPath?: (path: string) => string - onNotFound?: (path: string, c: Context) => void | Promise + onNotFound?: (path: string, c: Context) => void | Promise } const DEFAULT_DOCUMENT = 'index.html' // This middleware is available only on Cloudflare Workers. -export const serveStatic = (options: ServeStaticOptions = { root: '' }): MiddlewareHandler => { +export const serveStatic = ( + options: ServeStaticOptions = { root: '' } +): MiddlewareHandler => { return async (c, next) => { // Do nothing if Response is already set if (c.finalized) { diff --git a/src/adapter/deno/serve-static.ts b/src/adapter/deno/serve-static.ts index d828d7396..8add7e715 100644 --- a/src/adapter/deno/serve-static.ts +++ b/src/adapter/deno/serve-static.ts @@ -1,5 +1,5 @@ import type { Context } from '../../context' -import type { MiddlewareHandler } from '../../types' +import type { Env, MiddlewareHandler } from '../../types' import { getFilePath } from '../../utils/filepath' import { getMimeType } from '../../utils/mime' @@ -7,16 +7,18 @@ import { getMimeType } from '../../utils/mime' // @ts-ignore const { open } = Deno -export type ServeStaticOptions = { +export type ServeStaticOptions = { root?: string path?: string rewriteRequestPath?: (path: string) => string - onNotFound?: (path: string, c: Context) => void | Promise + onNotFound?: (path: string, c: Context) => void | Promise } const DEFAULT_DOCUMENT = 'index.html' -export const serveStatic = (options: ServeStaticOptions = { root: '' }): MiddlewareHandler => { +export const serveStatic = ( + options: ServeStaticOptions = { root: '' } +): MiddlewareHandler => { return async (c, next) => { // Do nothing if Response is already set if (c.finalized) { From 0943cf74dbda0c6abbe0234dcee6d22a5b54bf69 Mon Sep 17 00:00:00 2001 From: Sor4chi <80559385+sor4chi@users.noreply.github.com> Date: Tue, 2 Jan 2024 22:22:32 +0900 Subject: [PATCH 5/5] feat: add Env generics for serveStatic to support c.env type in cloudflare workers module's callback handler --- src/adapter/cloudflare-workers/server-static-module.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/adapter/cloudflare-workers/server-static-module.ts b/src/adapter/cloudflare-workers/server-static-module.ts index 1eed8ab90..3d7fd6ca7 100644 --- a/src/adapter/cloudflare-workers/server-static-module.ts +++ b/src/adapter/cloudflare-workers/server-static-module.ts @@ -3,11 +3,12 @@ // @ts-ignore // For ES module mode import manifest from '__STATIC_CONTENT_MANIFEST' +import type { Env } from '../../types' import type { ServeStaticOptions } from './serve-static' import { serveStatic } from './serve-static' -const module = (options: ServeStaticOptions = { root: '' }) => { - return serveStatic({ +const module = (options: ServeStaticOptions = { root: '' }) => { + return serveStatic({ root: options.root, path: options.path, manifest: options.manifest ? options.manifest : manifest,