Skip to content

Commit

Permalink
feat(serve-static): expose serve-static builder (#2515)
Browse files Browse the repository at this point in the history
* feat: allow to use serve-static builder

* typo

* add stricter type requirement as it is public interface

* allow specifying content-type (and others) from user code

* fix type

* rename the export the `serve-static`

* add a test
  • Loading branch information
cometkim committed Apr 30, 2024
1 parent 9f53dc2 commit 33a7707
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 28 deletions.
2 changes: 1 addition & 1 deletion deno_dist/adapter/deno/serve-static.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const serveStatic = <E extends Env = Env>(
} catch (e) {
console.warn(`${e}`)
}
return file ? file.readable : undefined
return file ? file.readable : null
}
const pathResolve = (path: string) => {
return `./${path}`
Expand Down
2 changes: 1 addition & 1 deletion deno_dist/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { RedirectStatusCode, StatusCode } from './utils/http-status.ts'
import type { JSONValue, InterfaceToType, JSONParsed, IsAny } from './utils/types.ts'

type HeaderRecord = Record<string, string | string[]>
type Data = string | ArrayBuffer | ReadableStream
export type Data = string | ArrayBuffer | ReadableStream

export interface ExecutionContext {
waitUntil(promise: Promise<unknown>): void
Expand Down
13 changes: 8 additions & 5 deletions deno_dist/middleware/serve-static/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Context } from '../../context.ts'
import type { Context, Data } from '../../context.ts'
import type { Env, MiddlewareHandler } from '../../types.ts'
import { getFilePath, getFilePathWithoutDefaultDocument } from '../../utils/filepath.ts'
import { getMimeType } from '../../utils/mime.ts'
Expand All @@ -19,8 +19,7 @@ const defaultPathResolve = (path: string) => path
*/
export const serveStatic = <E extends Env = Env>(
options: ServeStaticOptions<E> & {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getContent: (path: string) => any
getContent: (path: string, c: Context<E>) => Promise<Data | Response | null>
pathResolve?: (path: string) => string
}
): MiddlewareHandler => {
Expand Down Expand Up @@ -49,7 +48,7 @@ export const serveStatic = <E extends Env = Env>(
const pathResolve = options.pathResolve ?? defaultPathResolve

path = pathResolve(path)
let content = await getContent(path)
let content = await getContent(path, c)

if (!content) {
let pathWithOutDefaultDocument = getFilePathWithoutDefaultDocument({
Expand All @@ -60,12 +59,16 @@ export const serveStatic = <E extends Env = Env>(
return await next()
}
pathWithOutDefaultDocument = pathResolve(pathWithOutDefaultDocument)
content = await getContent(pathWithOutDefaultDocument)
content = await getContent(pathWithOutDefaultDocument, c)
if (content) {
path = pathWithOutDefaultDocument
}
}

if (content instanceof Response) {
return c.newResponse(content.body, content)
}

if (content) {
let mimeType: string | undefined
if (options.mimes) {
Expand Down
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@
"import": "./dist/helper/factory/index.js",
"require": "./dist/cjs/helper/factory/index.js"
},
"./serve-static": {
"types": "./dist/types/middleware/serve-static/index.d.ts",
"import": "./dist/middleware/serve-static/index.js",
"require": "./dist/cjs/middleware/serve-static/index.js"
},
"./cloudflare-workers": {
"types": "./dist/types/adapter/cloudflare-workers/index.d.ts",
"import": "./dist/adapter/cloudflare-workers/index.js",
Expand Down Expand Up @@ -475,6 +480,9 @@
"factory": [
"./dist/types/helper/factory/index.d.ts"
],
"serve-static": [
"./dist/types/middleware/serve-static"
],
"cloudflare-workers": [
"./dist/types/adapter/cloudflare-workers"
],
Expand Down
2 changes: 1 addition & 1 deletion src/adapter/deno/serve-static.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const serveStatic = <E extends Env = Env>(
} catch (e) {
console.warn(`${e}`)
}
return file ? file.readable : undefined
return file ? file.readable : null
}
const pathResolve = (path: string) => {
return `./${path}`
Expand Down
2 changes: 1 addition & 1 deletion src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { RedirectStatusCode, StatusCode } from './utils/http-status'
import type { JSONValue, InterfaceToType, JSONParsed, IsAny } from './utils/types'

type HeaderRecord = Record<string, string | string[]>
type Data = string | ArrayBuffer | ReadableStream
export type Data = string | ArrayBuffer | ReadableStream

export interface ExecutionContext {
waitUntil(promise: Promise<unknown>): void
Expand Down
44 changes: 30 additions & 14 deletions src/middleware/serve-static/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import { createMiddleware } from '../../helper'
import { Hono } from '../../hono'
import { serveStatic as baseServeStatic } from '.'

describe('Serve Static Middleware', () => {
const app = new Hono()

const serveStatic = createMiddleware(async (c, next) => {
const mw = baseServeStatic({
getContent: (path) => {
if (path.endsWith('not-found.txt')) {
return undefined
}
return `Hello in ${path}`
},
pathResolve: (path) => {
return `./${path}`
},
})
return await mw(c, next)
const serveStatic = baseServeStatic({
getContent: async (path) => {
if (path.endsWith('not-found.txt')) {
return null
}
return `Hello in ${path}`
},
pathResolve: (path) => {
return `./${path}`
},
})

app.get('/static/*', serveStatic)
Expand Down Expand Up @@ -56,4 +52,24 @@ describe('Serve Static Middleware', () => {
expect(res.status).toBe(404)
expect(await res.text()).toBe('404 Not Found')
})

it('Should return response object content as-is', async () => {
const body = new ReadableStream()
const response = new Response(body)
const app = new Hono().use(
'*',
baseServeStatic({
getContent: async () => {
return response
},
})
)

const res = await app.fetch({
method: 'GET',
url: 'http://localhost',
} as Request)
expect(res.status).toBe(200)
expect(res.body).toBe(body)
})
})
13 changes: 8 additions & 5 deletions src/middleware/serve-static/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Context } from '../../context'
import type { Context, Data } from '../../context'
import type { Env, MiddlewareHandler } from '../../types'
import { getFilePath, getFilePathWithoutDefaultDocument } from '../../utils/filepath'
import { getMimeType } from '../../utils/mime'
Expand All @@ -19,8 +19,7 @@ const defaultPathResolve = (path: string) => path
*/
export const serveStatic = <E extends Env = Env>(
options: ServeStaticOptions<E> & {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getContent: (path: string) => any
getContent: (path: string, c: Context<E>) => Promise<Data | Response | null>
pathResolve?: (path: string) => string
}
): MiddlewareHandler => {
Expand Down Expand Up @@ -49,7 +48,7 @@ export const serveStatic = <E extends Env = Env>(
const pathResolve = options.pathResolve ?? defaultPathResolve

path = pathResolve(path)
let content = await getContent(path)
let content = await getContent(path, c)

if (!content) {
let pathWithOutDefaultDocument = getFilePathWithoutDefaultDocument({
Expand All @@ -60,12 +59,16 @@ export const serveStatic = <E extends Env = Env>(
return await next()
}
pathWithOutDefaultDocument = pathResolve(pathWithOutDefaultDocument)
content = await getContent(pathWithOutDefaultDocument)
content = await getContent(pathWithOutDefaultDocument, c)
if (content) {
path = pathWithOutDefaultDocument
}
}

if (content instanceof Response) {
return c.newResponse(content.body, content)
}

if (content) {
let mimeType: string | undefined
if (options.mimes) {
Expand Down

0 comments on commit 33a7707

Please sign in to comment.