0
0
mirror of https://github.com/honojs/hono.git synced 2024-11-24 11:07:29 +01:00

feat: Introduce Service Worker Adapter (#3062)

* feat: Intoroduce service worker adapter

* test: add test

* chore: format code

* refactor: handler.ts

* chore: remove unused import

* fix: add webworker to jsr.json

* fix: triple slash directives to tsconfig.json

* feat: add types.ts to define worker types
This commit is contained in:
Shotaro Nakamura 2024-07-11 17:16:52 +09:00 committed by GitHub
parent 4a4e851d50
commit c2698fa2e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 118 additions and 0 deletions

View File

@ -71,6 +71,7 @@
"./vercel": "./src/adapter/vercel/index.ts",
"./netlify": "./src/adapter/netlify/index.ts",
"./lambda-edge": "./src/adapter/lambda-edge/index.ts",
"./service-worker": "./src/adapter/service-worker/index.ts",
"./testing": "./src/helper/testing/index.ts",
"./dev": "./src/helper/dev/index.ts",
"./ws": "./src/helper/websocket/index.ts",

View File

@ -343,6 +343,11 @@
"import": "./dist/adapter/lambda-edge/index.js",
"require": "./dist/cjs/adapter/lambda-edge/index.js"
},
"./service-worker": {
"types": "./dist/types/adapter/service-worker/index.d.ts",
"import": "./dist/adapter/service-worker/index.js",
"require": "./dist/cjs/adapter/service-worker/index.js"
},
"./testing": {
"types": "./dist/types/helper/testing/index.d.ts",
"import": "./dist/helper/testing/index.js",
@ -543,6 +548,9 @@
"lambda-edge": [
"./dist/types/adapter/lambda-edge"
],
"service-worker": [
"./dist/types/adapter/service-worker"
],
"testing": [
"./dist/types/helper/testing"
],

View File

@ -0,0 +1,57 @@
import { Hono } from '../../hono'
import { handle } from './handler'
import type { FetchEvent } from './types'
describe('handle', () => {
it('Success to fetch', async () => {
const app = new Hono()
app.get('/', (c) => {
return c.json({ hello: 'world' })
})
const handler = handle(app)
const json = await new Promise<Response>((resolve) => {
handler({
request: new Request('http://localhost/'),
respondWith(res) {
resolve(res)
},
} as FetchEvent)
}).then((res) => res.json())
expect(json).toStrictEqual({ hello: 'world' })
})
it('Fallback 404', async () => {
const app = new Hono()
const handler = handle(app, {
async fetch() {
return new Response('hello world')
},
})
const text = await new Promise<Response>((resolve) => {
handler({
request: new Request('http://localhost/'),
respondWith(res) {
resolve(res)
},
} as FetchEvent)
}).then((res) => res.text())
expect(text).toBe('hello world')
})
it('Do not fallback 404 when fetch is undefined', async () => {
const app = new Hono()
app.get('/', (c) => c.text('Not found', 404))
const handler = handle(app, {
fetch: undefined,
})
const result = await new Promise<Response>((resolve) =>
handler({
request: new Request('https://localhost/'),
respondWith(r) {
resolve(r)
},
} as FetchEvent)
)
expect(result.status).toBe(404)
expect(await result.text()).toBe('Not found')
})
})

View File

@ -0,0 +1,33 @@
/**
* Handler for Service Worker
* @module
*/
import type { Hono } from '../../hono'
import type { FetchEvent } from './types'
type Handler = (evt: FetchEvent) => void
/**
* Adapter for Service Worker
*/
export const handle = (
app: Hono,
opts: {
fetch?: typeof fetch
} = {
fetch: fetch,
}
): Handler => {
return (evt) => {
evt.respondWith(
(async () => {
const res = await app.fetch(evt.request)
if (opts.fetch && res.status === 404) {
return await opts.fetch(evt.request)
}
return res
})()
)
}
}

View File

@ -0,0 +1,5 @@
/**
* Cloudflare Workers Adapter for Hono.
* @module
*/
export { handle } from './handler'

View File

@ -0,0 +1,14 @@
interface ExtendableEvent extends Event {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
waitUntil(f: Promise<any>): void
}
export interface FetchEvent extends ExtendableEvent {
readonly clientId: string
readonly handled: Promise<undefined>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
readonly preloadResponse: Promise<any>
readonly request: Request
readonly resultingClientId: string
respondWith(r: Response | PromiseLike<Response>): void
}