@kerebron/extension-server-hono 0.4.28 → 0.4.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/esm/HonoYjsMemAdapter.js +1 -0
  2. package/esm/HonoYjsMemAdapter.js.map +1 -0
  3. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/compose.js +1 -0
  4. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/compose.js.map +1 -0
  5. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/context.js +1 -0
  6. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/context.js.map +1 -0
  7. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/helper/websocket/index.js +1 -0
  8. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/helper/websocket/index.js.map +1 -0
  9. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/hono-base.js +1 -0
  10. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/hono-base.js.map +1 -0
  11. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/http-exception.js +1 -0
  12. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/http-exception.js.map +1 -0
  13. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request/constants.js +1 -0
  14. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request/constants.js.map +1 -0
  15. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request.js +1 -0
  16. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request.js.map +1 -0
  17. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/router.js +1 -0
  18. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/router.js.map +1 -0
  19. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/types.js +1 -0
  20. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/types.js.map +1 -0
  21. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/body.js +1 -0
  22. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/body.js.map +1 -0
  23. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/constants.js +1 -0
  24. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/constants.js.map +1 -0
  25. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/headers.js +1 -0
  26. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/headers.js.map +1 -0
  27. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/html.js +1 -0
  28. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/html.js.map +1 -0
  29. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/http-status.js +1 -0
  30. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/http-status.js.map +1 -0
  31. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/mime.js +1 -0
  32. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/mime.js.map +1 -0
  33. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/types.js +1 -0
  34. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/types.js.map +1 -0
  35. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/url.js +1 -0
  36. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/url.js.map +1 -0
  37. package/esm/mod.js +1 -0
  38. package/esm/mod.js.map +1 -0
  39. package/package.json +5 -1
  40. package/src/HonoYjsMemAdapter.ts +264 -0
  41. package/src/deps/jsr.io/@hono/hono/4.11.3/src/compose.ts +73 -0
  42. package/src/deps/jsr.io/@hono/hono/4.11.3/src/context.ts +770 -0
  43. package/src/deps/jsr.io/@hono/hono/4.11.3/src/helper/websocket/index.ts +140 -0
  44. package/src/deps/jsr.io/@hono/hono/4.11.3/src/hono-base.ts +539 -0
  45. package/src/deps/jsr.io/@hono/hono/4.11.3/src/http-exception.ts +78 -0
  46. package/src/deps/jsr.io/@hono/hono/4.11.3/src/request/constants.ts +1 -0
  47. package/src/deps/jsr.io/@hono/hono/4.11.3/src/request.ts +487 -0
  48. package/src/deps/jsr.io/@hono/hono/4.11.3/src/router.ts +103 -0
  49. package/src/deps/jsr.io/@hono/hono/4.11.3/src/types.ts +2489 -0
  50. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/body.ts +229 -0
  51. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/constants.ts +4 -0
  52. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/headers.ts +333 -0
  53. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/html.ts +182 -0
  54. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/http-status.ts +72 -0
  55. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/mime.ts +96 -0
  56. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/types.ts +116 -0
  57. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/url.ts +310 -0
  58. package/src/mod.ts +5 -0
@@ -0,0 +1,140 @@
1
+ /**
2
+ * @module
3
+ * WebSocket Helper for Hono.
4
+ */
5
+
6
+ /* eslint-disable @typescript-eslint/no-explicit-any */
7
+ import type { Context } from '../../context.js'
8
+ import type { MiddlewareHandler, TypedResponse } from '../../types.js'
9
+ import type { StatusCode } from '../../utils/http-status.js'
10
+
11
+ /**
12
+ * WebSocket Event Listeners type
13
+ */
14
+ export interface WSEvents<T = unknown> {
15
+ onOpen?: (evt: Event, ws: WSContext<T>) => void
16
+ onMessage?: (evt: MessageEvent<WSMessageReceive>, ws: WSContext<T>) => void
17
+ onClose?: (evt: CloseEvent, ws: WSContext<T>) => void
18
+ onError?: (evt: Event, ws: WSContext<T>) => void
19
+ }
20
+
21
+ /**
22
+ * Upgrade WebSocket Type
23
+ */
24
+ export interface UpgradeWebSocket<T = unknown, U = any, _WSEvents = WSEvents<T>> {
25
+ (
26
+ createEvents: (c: Context) => _WSEvents | Promise<_WSEvents>,
27
+ options?: U
28
+ ): MiddlewareHandler<
29
+ any,
30
+ string,
31
+ {
32
+ outputFormat: 'ws'
33
+ }
34
+ >
35
+ (
36
+ c: Context,
37
+ events: _WSEvents,
38
+ options?: U
39
+ ): Promise<Response & TypedResponse<{}, StatusCode, 'ws'>>
40
+ }
41
+
42
+ /**
43
+ * ReadyState for WebSocket
44
+ */
45
+ export type WSReadyState = 0 | 1 | 2 | 3
46
+
47
+ /**
48
+ * An argument for WSContext class
49
+ */
50
+ export interface WSContextInit<T = unknown> {
51
+ send(data: string | ArrayBuffer | Uint8Array, options: SendOptions): void
52
+ close(code?: number, reason?: string): void
53
+
54
+ raw?: T
55
+ readyState: WSReadyState
56
+ url?: string | URL | null
57
+ protocol?: string | null
58
+ }
59
+
60
+ /**
61
+ * Options for sending message
62
+ */
63
+ export interface SendOptions {
64
+ compress?: boolean
65
+ }
66
+
67
+ /**
68
+ * A context for controlling WebSockets
69
+ */
70
+ export class WSContext<T = unknown> {
71
+ #init: WSContextInit<T>
72
+ constructor(init: WSContextInit<T>) {
73
+ this.#init = init
74
+ this.raw = init.raw
75
+ this.url = init.url ? new URL(init.url) : null
76
+ this.protocol = init.protocol ?? null
77
+ }
78
+ send(source: string | ArrayBuffer | Uint8Array<ArrayBuffer>, options?: SendOptions): void {
79
+ this.#init.send(source, options ?? {})
80
+ }
81
+ raw?: T
82
+ binaryType: BinaryType = 'arraybuffer'
83
+ get readyState(): WSReadyState {
84
+ return this.#init.readyState
85
+ }
86
+ url: URL | null
87
+ protocol: string | null
88
+ close(code?: number, reason?: string) {
89
+ this.#init.close(code, reason)
90
+ }
91
+ }
92
+
93
+ export type WSMessageReceive = string | Blob | ArrayBufferLike
94
+
95
+ export const createWSMessageEvent = (source: WSMessageReceive): MessageEvent<WSMessageReceive> => {
96
+ return new MessageEvent<WSMessageReceive>('message', {
97
+ data: source,
98
+ })
99
+ }
100
+
101
+ export interface WebSocketHelperDefineContext {}
102
+ export type WebSocketHelperDefineHandler<T, U> = (
103
+ c: Context,
104
+ events: WSEvents<T>,
105
+ options?: U
106
+ ) => Promise<Response | void> | Response | void
107
+
108
+ /**
109
+ * Create a WebSocket adapter/helper
110
+ */
111
+ export const defineWebSocketHelper = <T = unknown, U = any>(
112
+ handler: WebSocketHelperDefineHandler<T, U>
113
+ ): UpgradeWebSocket<T, U> => {
114
+ return ((
115
+ ...args:
116
+ | [createEvents: (c: Context) => WSEvents<T> | Promise<WSEvents<T>>, options?: U]
117
+ | [c: Context, events: WSEvents<T>, options?: U]
118
+ ) => {
119
+ if (typeof args[0] === 'function') {
120
+ const [createEvents, options] = args
121
+ return async function upgradeWebSocket(c, next) {
122
+ const events = await createEvents(c)
123
+ const result = await handler(c, events, options as U)
124
+ if (result) {
125
+ return result
126
+ }
127
+ await next()
128
+ }
129
+ } else {
130
+ const [c, events, options] = args as [c: Context, events: WSEvents<T>, options?: U]
131
+ return (async () => {
132
+ const upgraded = await handler(c, events, options as U)
133
+ if (!upgraded) {
134
+ throw new Error('Failed to upgrade WebSocket')
135
+ }
136
+ return upgraded
137
+ })()
138
+ }
139
+ }) as UpgradeWebSocket<T, U>
140
+ }
@@ -0,0 +1,539 @@
1
+ /**
2
+ * @module
3
+ * This module is the base module for the Hono object.
4
+ */
5
+
6
+ /* eslint-disable @typescript-eslint/no-explicit-any */
7
+ import { compose } from './compose.js'
8
+ import { Context } from './context.js'
9
+ import type { ExecutionContext } from './context.js'
10
+ import type { Router } from './router.js'
11
+ import { METHODS, METHOD_NAME_ALL, METHOD_NAME_ALL_LOWERCASE } from './router.js'
12
+ import type {
13
+ Env,
14
+ ErrorHandler,
15
+ FetchEventLike,
16
+ H,
17
+ HandlerInterface,
18
+ MergePath,
19
+ MergeSchemaPath,
20
+ MiddlewareHandler,
21
+ MiddlewareHandlerInterface,
22
+ Next,
23
+ NotFoundHandler,
24
+ OnHandlerInterface,
25
+ RouterRoute,
26
+ Schema,
27
+ } from './types.js'
28
+ import { COMPOSED_HANDLER } from './utils/constants.js'
29
+ import { getPath, getPathNoStrict, mergePath } from './utils/url.js'
30
+
31
+ const notFoundHandler: NotFoundHandler = (c) => {
32
+ return c.text('404 Not Found', 404)
33
+ }
34
+
35
+ const errorHandler: ErrorHandler = (err, c) => {
36
+ if ('getResponse' in err) {
37
+ const res = err.getResponse()
38
+ return c.newResponse(res.body, res)
39
+ }
40
+ console.error(err)
41
+ return c.text('Internal Server Error', 500)
42
+ }
43
+
44
+ type GetPath<E extends Env> = (request: Request, options?: { env?: E['Bindings'] }) => string
45
+
46
+ export type HonoOptions<E extends Env> = {
47
+ /**
48
+ * `strict` option specifies whether to distinguish whether the last path is a directory or not.
49
+ *
50
+ * @see {@link https://hono.dev/docs/api/hono#strict-mode}
51
+ *
52
+ * @default true
53
+ */
54
+ strict?: boolean
55
+ /**
56
+ * `router` option specifies which router to use.
57
+ *
58
+ * @see {@link https://hono.dev/docs/api/hono#router-option}
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * const app = new Hono({ router: new RegExpRouter() })
63
+ * ```
64
+ */
65
+ router?: Router<[H, RouterRoute]>
66
+ /**
67
+ * `getPath` can handle the host header value.
68
+ *
69
+ * @see {@link https://hono.dev/docs/api/routing#routing-with-host-header-value}
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * const app = new Hono({
74
+ * getPath: (req) =>
75
+ * '/' + req.headers.get('host') + req.url.replace(/^https?:\/\/[^/]+(\/[^?]*)/, '$1'),
76
+ * })
77
+ *
78
+ * app.get('/www1.example.com/hello', () => c.text('hello www1'))
79
+ *
80
+ * // A following request will match the route:
81
+ * // new Request('http://www1.example.com/hello', {
82
+ * // headers: { host: 'www1.example.com' },
83
+ * // })
84
+ * ```
85
+ */
86
+ getPath?: GetPath<E>
87
+ }
88
+
89
+ type MountOptionHandler = (c: Context) => unknown
90
+ type MountReplaceRequest = (originalRequest: Request) => Request
91
+ type MountOptions =
92
+ | MountOptionHandler
93
+ | {
94
+ optionHandler?: MountOptionHandler
95
+ replaceRequest?: MountReplaceRequest | false
96
+ }
97
+
98
+ class Hono<
99
+ E extends Env = Env,
100
+ S extends Schema = {},
101
+ BasePath extends string = '/',
102
+ CurrentPath extends string = BasePath,
103
+ > {
104
+ get!: HandlerInterface<E, 'get', S, BasePath, CurrentPath>
105
+ post!: HandlerInterface<E, 'post', S, BasePath, CurrentPath>
106
+ put!: HandlerInterface<E, 'put', S, BasePath, CurrentPath>
107
+ delete!: HandlerInterface<E, 'delete', S, BasePath, CurrentPath>
108
+ options!: HandlerInterface<E, 'options', S, BasePath, CurrentPath>
109
+ patch!: HandlerInterface<E, 'patch', S, BasePath, CurrentPath>
110
+ all!: HandlerInterface<E, 'all', S, BasePath, CurrentPath>
111
+ on: OnHandlerInterface<E, S, BasePath>
112
+ use: MiddlewareHandlerInterface<E, S, BasePath>
113
+
114
+ /*
115
+ This class is like an abstract class and does not have a router.
116
+ To use it, inherit the class and implement router in the constructor.
117
+ */
118
+ router!: Router<[H, RouterRoute]>
119
+ readonly getPath: GetPath<E>
120
+ // Cannot use `#` because it requires visibility at JavaScript runtime.
121
+ private _basePath: string = '/'
122
+ #path: string = '/'
123
+
124
+ routes: RouterRoute[] = []
125
+
126
+ constructor(options: HonoOptions<E> = {}) {
127
+ // Implementation of app.get(...handlers[]) or app.get(path, ...handlers[])
128
+ const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE]
129
+ allMethods.forEach((method) => {
130
+ this[method] = (args1: string | H, ...args: H[]) => {
131
+ if (typeof args1 === 'string') {
132
+ this.#path = args1
133
+ } else {
134
+ this.#addRoute(method, this.#path, args1)
135
+ }
136
+ args.forEach((handler) => {
137
+ this.#addRoute(method, this.#path, handler)
138
+ })
139
+ return this as any
140
+ }
141
+ })
142
+
143
+ // Implementation of app.on(method, path, ...handlers[])
144
+ this.on = (method: string | string[], path: string | string[], ...handlers: H[]) => {
145
+ for (const p of [path].flat()) {
146
+ this.#path = p
147
+ for (const m of [method].flat()) {
148
+ handlers.map((handler) => {
149
+ this.#addRoute(m.toUpperCase(), this.#path, handler)
150
+ })
151
+ }
152
+ }
153
+ return this as any
154
+ }
155
+
156
+ // Implementation of app.use(...handlers[]) or app.use(path, ...handlers[])
157
+ this.use = (arg1: string | MiddlewareHandler<any>, ...handlers: MiddlewareHandler<any>[]) => {
158
+ if (typeof arg1 === 'string') {
159
+ this.#path = arg1
160
+ } else {
161
+ this.#path = '*'
162
+ handlers.unshift(arg1)
163
+ }
164
+ handlers.forEach((handler) => {
165
+ this.#addRoute(METHOD_NAME_ALL, this.#path, handler)
166
+ })
167
+ return this as any
168
+ }
169
+
170
+ const { strict, ...optionsWithoutStrict } = options
171
+ Object.assign(this, optionsWithoutStrict)
172
+ this.getPath = (strict ?? true) ? (options.getPath ?? getPath) : getPathNoStrict
173
+ }
174
+
175
+ #clone(): Hono<E, S, BasePath, CurrentPath> {
176
+ const clone = new Hono<E, S, BasePath, CurrentPath>({
177
+ router: this.router,
178
+ getPath: this.getPath,
179
+ })
180
+ clone.errorHandler = this.errorHandler
181
+ clone.#notFoundHandler = this.#notFoundHandler
182
+ clone.routes = this.routes
183
+ return clone
184
+ }
185
+
186
+ #notFoundHandler: NotFoundHandler = notFoundHandler
187
+ // Cannot use `#` because it requires visibility at JavaScript runtime.
188
+ private errorHandler: ErrorHandler = errorHandler
189
+
190
+ /**
191
+ * `.route()` allows grouping other Hono instance in routes.
192
+ *
193
+ * @see {@link https://hono.dev/docs/api/routing#grouping}
194
+ *
195
+ * @param {string} path - base Path
196
+ * @param {Hono} app - other Hono instance
197
+ * @returns {Hono} routed Hono instance
198
+ *
199
+ * @example
200
+ * ```ts
201
+ * const app = new Hono()
202
+ * const app2 = new Hono()
203
+ *
204
+ * app2.get("/user", (c) => c.text("user"))
205
+ * app.route("/api", app2) // GET /api/user
206
+ * ```
207
+ */
208
+ route<
209
+ SubPath extends string,
210
+ SubEnv extends Env,
211
+ SubSchema extends Schema,
212
+ SubBasePath extends string,
213
+ SubCurrentPath extends string,
214
+ >(
215
+ path: SubPath,
216
+ app: Hono<SubEnv, SubSchema, SubBasePath, SubCurrentPath>
217
+ ): Hono<E, MergeSchemaPath<SubSchema, MergePath<BasePath, SubPath>> | S, BasePath, CurrentPath> {
218
+ const subApp = this.basePath(path)
219
+ app.routes.map((r) => {
220
+ let handler
221
+ if (app.errorHandler === errorHandler) {
222
+ handler = r.handler
223
+ } else {
224
+ handler = async (c: Context, next: Next) =>
225
+ (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res
226
+ ;(handler as any)[COMPOSED_HANDLER] = r.handler
227
+ }
228
+
229
+ subApp.#addRoute(r.method, r.path, handler)
230
+ })
231
+ return this
232
+ }
233
+
234
+ /**
235
+ * `.basePath()` allows base paths to be specified.
236
+ *
237
+ * @see {@link https://hono.dev/docs/api/routing#base-path}
238
+ *
239
+ * @param {string} path - base Path
240
+ * @returns {Hono} changed Hono instance
241
+ *
242
+ * @example
243
+ * ```ts
244
+ * const api = new Hono().basePath('/api')
245
+ * ```
246
+ */
247
+ basePath<SubPath extends string>(
248
+ path: SubPath
249
+ ): Hono<E, S, MergePath<BasePath, SubPath>, MergePath<BasePath, SubPath>> {
250
+ const subApp = this.#clone()
251
+ subApp._basePath = mergePath(this._basePath, path)
252
+ return subApp
253
+ }
254
+
255
+ /**
256
+ * `.onError()` handles an error and returns a customized Response.
257
+ *
258
+ * @see {@link https://hono.dev/docs/api/hono#error-handling}
259
+ *
260
+ * @param {ErrorHandler} handler - request Handler for error
261
+ * @returns {Hono} changed Hono instance
262
+ *
263
+ * @example
264
+ * ```ts
265
+ * app.onError((err, c) => {
266
+ * console.error(`${err}`)
267
+ * return c.text('Custom Error Message', 500)
268
+ * })
269
+ * ```
270
+ */
271
+ onError = (handler: ErrorHandler<E>): Hono<E, S, BasePath, CurrentPath> => {
272
+ this.errorHandler = handler
273
+ return this
274
+ }
275
+
276
+ /**
277
+ * `.notFound()` allows you to customize a Not Found Response.
278
+ *
279
+ * @see {@link https://hono.dev/docs/api/hono#not-found}
280
+ *
281
+ * @param {NotFoundHandler} handler - request handler for not-found
282
+ * @returns {Hono} changed Hono instance
283
+ *
284
+ * @example
285
+ * ```ts
286
+ * app.notFound((c) => {
287
+ * return c.text('Custom 404 Message', 404)
288
+ * })
289
+ * ```
290
+ */
291
+ notFound = (handler: NotFoundHandler<E>): Hono<E, S, BasePath, CurrentPath> => {
292
+ this.#notFoundHandler = handler
293
+ return this
294
+ }
295
+
296
+ /**
297
+ * `.mount()` allows you to mount applications built with other frameworks into your Hono application.
298
+ *
299
+ * @see {@link https://hono.dev/docs/api/hono#mount}
300
+ *
301
+ * @param {string} path - base Path
302
+ * @param {Function} applicationHandler - other Request Handler
303
+ * @param {MountOptions} [options] - options of `.mount()`
304
+ * @returns {Hono} mounted Hono instance
305
+ *
306
+ * @example
307
+ * ```ts
308
+ * import { Router as IttyRouter } from 'itty-router'
309
+ * import { Hono } from 'hono'
310
+ * // Create itty-router application
311
+ * const ittyRouter = IttyRouter()
312
+ * // GET /itty-router/hello
313
+ * ittyRouter.get('/hello', () => new Response('Hello from itty-router'))
314
+ *
315
+ * const app = new Hono()
316
+ * app.mount('/itty-router', ittyRouter.handle)
317
+ * ```
318
+ *
319
+ * @example
320
+ * ```ts
321
+ * const app = new Hono()
322
+ * // Send the request to another application without modification.
323
+ * app.mount('/app', anotherApp, {
324
+ * replaceRequest: (req) => req,
325
+ * })
326
+ * ```
327
+ */
328
+ mount(
329
+ path: string,
330
+ applicationHandler: (request: Request, ...args: any) => Response | Promise<Response>,
331
+ options?: MountOptions
332
+ ): Hono<E, S, BasePath, CurrentPath> {
333
+ // handle options
334
+ let replaceRequest: MountReplaceRequest | undefined
335
+ let optionHandler: MountOptionHandler | undefined
336
+ if (options) {
337
+ if (typeof options === 'function') {
338
+ optionHandler = options
339
+ } else {
340
+ optionHandler = options.optionHandler
341
+ if (options.replaceRequest === false) {
342
+ replaceRequest = (request) => request
343
+ } else {
344
+ replaceRequest = options.replaceRequest
345
+ }
346
+ }
347
+ }
348
+
349
+ // prepare handlers for request
350
+ const getOptions: (c: Context) => unknown[] = optionHandler
351
+ ? (c) => {
352
+ const options = optionHandler!(c)
353
+ return Array.isArray(options) ? options : [options]
354
+ }
355
+ : (c) => {
356
+ let executionContext: ExecutionContext | undefined = undefined
357
+ try {
358
+ executionContext = c.executionCtx
359
+ } catch {} // Do nothing
360
+ return [c.env, executionContext]
361
+ }
362
+ replaceRequest ||= (() => {
363
+ const mergedPath = mergePath(this._basePath, path)
364
+ const pathPrefixLength = mergedPath === '/' ? 0 : mergedPath.length
365
+ return (request) => {
366
+ const url = new URL(request.url)
367
+ url.pathname = url.pathname.slice(pathPrefixLength) || '/'
368
+ return new Request(url, request)
369
+ }
370
+ })()
371
+
372
+ const handler: MiddlewareHandler = async (c, next) => {
373
+ const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c))
374
+
375
+ if (res) {
376
+ return res
377
+ }
378
+
379
+ await next()
380
+ }
381
+ this.#addRoute(METHOD_NAME_ALL, mergePath(path, '*'), handler)
382
+ return this
383
+ }
384
+
385
+ #addRoute(method: string, path: string, handler: H): void {
386
+ method = method.toUpperCase()
387
+ path = mergePath(this._basePath, path)
388
+ const r: RouterRoute = { basePath: this._basePath, path, method, handler }
389
+ this.router.add(method, path, [handler, r])
390
+ this.routes.push(r)
391
+ }
392
+
393
+ #handleError(err: unknown, c: Context<E>): Response | Promise<Response> {
394
+ if (err instanceof Error) {
395
+ return this.errorHandler(err, c)
396
+ }
397
+ throw err
398
+ }
399
+
400
+ #dispatch(
401
+ request: Request,
402
+ executionCtx: ExecutionContext | FetchEventLike | undefined,
403
+ env: E['Bindings'],
404
+ method: string
405
+ ): Response | Promise<Response> {
406
+ // Handle HEAD method
407
+ if (method === 'HEAD') {
408
+ return (async () =>
409
+ new Response(null, await this.#dispatch(request, executionCtx, env, 'GET')))()
410
+ }
411
+
412
+ const path = this.getPath(request, { env })
413
+ const matchResult = this.router.match(method, path)
414
+
415
+ const c = new Context(request, {
416
+ path,
417
+ matchResult,
418
+ env,
419
+ executionCtx,
420
+ notFoundHandler: this.#notFoundHandler,
421
+ })
422
+
423
+ // Do not `compose` if it has only one handler
424
+ if (matchResult[0].length === 1) {
425
+ let res: ReturnType<H>
426
+ try {
427
+ res = matchResult[0][0][0][0](c, async () => {
428
+ c.res = await this.#notFoundHandler(c)
429
+ })
430
+ } catch (err) {
431
+ return this.#handleError(err, c)
432
+ }
433
+
434
+ return res instanceof Promise
435
+ ? res
436
+ .then(
437
+ (resolved: Response | undefined) =>
438
+ resolved || (c.finalized ? c.res : this.#notFoundHandler(c))
439
+ )
440
+ .catch((err: Error) => this.#handleError(err, c))
441
+ : (res ?? this.#notFoundHandler(c))
442
+ }
443
+
444
+ const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler)
445
+
446
+ return (async () => {
447
+ try {
448
+ const context = await composed(c)
449
+ if (!context.finalized) {
450
+ throw new Error(
451
+ 'Context is not finalized. Did you forget to return a Response object or `await next()`?'
452
+ )
453
+ }
454
+
455
+ return context.res
456
+ } catch (err) {
457
+ return this.#handleError(err, c)
458
+ }
459
+ })()
460
+ }
461
+
462
+ /**
463
+ * `.fetch()` will be entry point of your app.
464
+ *
465
+ * @see {@link https://hono.dev/docs/api/hono#fetch}
466
+ *
467
+ * @param {Request} request - request Object of request
468
+ * @param {Env} Env - env Object
469
+ * @param {ExecutionContext} - context of execution
470
+ * @returns {Response | Promise<Response>} response of request
471
+ *
472
+ */
473
+ fetch: (
474
+ request: Request,
475
+ Env?: E['Bindings'] | {},
476
+ executionCtx?: ExecutionContext
477
+ ) => Response | Promise<Response> = (request, ...rest) => {
478
+ return this.#dispatch(request, rest[1], rest[0], request.method)
479
+ }
480
+
481
+ /**
482
+ * `.request()` is a useful method for testing.
483
+ * You can pass a URL or pathname to send a GET request.
484
+ * app will return a Response object.
485
+ * ```ts
486
+ * test('GET /hello is ok', async () => {
487
+ * const res = await app.request('/hello')
488
+ * expect(res.status).toBe(200)
489
+ * })
490
+ * ```
491
+ * @see https://hono.dev/docs/api/hono#request
492
+ */
493
+ request = (
494
+ input: RequestInfo | URL,
495
+ requestInit?: RequestInit,
496
+ Env?: E['Bindings'] | {},
497
+ executionCtx?: ExecutionContext
498
+ ): Response | Promise<Response> => {
499
+ if (input instanceof Request) {
500
+ return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx)
501
+ }
502
+ input = input.toString()
503
+ return this.fetch(
504
+ new Request(
505
+ /^https?:\/\//.test(input) ? input : `http://localhost${mergePath('/', input)}`,
506
+ requestInit
507
+ ),
508
+ Env,
509
+ executionCtx
510
+ )
511
+ }
512
+
513
+ /**
514
+ * `.fire()` automatically adds a global fetch event listener.
515
+ * This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers.
516
+ * @deprecated
517
+ * Use `fire` from `hono/service-worker` instead.
518
+ * ```ts
519
+ * import { Hono } from 'hono'
520
+ * import { fire } from 'hono/service-worker'
521
+ *
522
+ * const app = new Hono()
523
+ * // ...
524
+ * fire(app)
525
+ * ```
526
+ * @see https://hono.dev/docs/api/hono#fire
527
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
528
+ * @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/
529
+ */
530
+ fire = (): void => {
531
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
532
+ // @ts-ignore
533
+ addEventListener('fetch', (event: FetchEventLike): void => {
534
+ event.respondWith(this.#dispatch(event.request, event, undefined, event.request.method))
535
+ })
536
+ }
537
+ }
538
+
539
+ export { Hono as HonoBase }