@kerebron/extension-server-hono 0.4.27 → 0.4.29

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 (97) hide show
  1. package/esm/HonoYjsMemAdapter.d.ts +41 -0
  2. package/esm/HonoYjsMemAdapter.d.ts.map +1 -0
  3. package/esm/HonoYjsMemAdapter.js +204 -0
  4. package/esm/HonoYjsMemAdapter.js.map +1 -0
  5. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/compose.d.ts +15 -0
  6. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/compose.d.ts.map +1 -0
  7. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/compose.js +65 -0
  8. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/compose.js.map +1 -0
  9. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/context.d.ts +452 -0
  10. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/context.d.ts.map +1 -0
  11. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/context.js +411 -0
  12. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/context.js.map +1 -0
  13. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/helper/websocket/index.d.ts +70 -0
  14. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/helper/websocket/index.d.ts.map +1 -0
  15. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/helper/websocket/index.js +63 -0
  16. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/helper/websocket/index.js.map +1 -0
  17. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/hono-base.d.ts +221 -0
  18. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/hono-base.d.ts.map +1 -0
  19. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/hono-base.js +392 -0
  20. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/hono-base.js.map +1 -0
  21. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/http-exception.d.ts +60 -0
  22. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/http-exception.d.ts.map +1 -0
  23. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/http-exception.js +62 -0
  24. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/http-exception.js.map +1 -0
  25. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request/constants.d.ts +2 -0
  26. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request/constants.d.ts.map +1 -0
  27. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request/constants.js +2 -0
  28. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request/constants.js.map +1 -0
  29. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request.d.ts +314 -0
  30. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request.d.ts.map +1 -0
  31. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request.js +328 -0
  32. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/request.js.map +1 -0
  33. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/router.d.ts +98 -0
  34. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/router.d.ts.map +1 -0
  35. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/router.js +26 -0
  36. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/router.js.map +1 -0
  37. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/types.d.ts +574 -0
  38. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/types.d.ts.map +1 -0
  39. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/types.js +12 -0
  40. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/types.js.map +1 -0
  41. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/body.d.ts +80 -0
  42. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/body.d.ts.map +1 -0
  43. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/body.js +112 -0
  44. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/body.js.map +1 -0
  45. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/constants.d.ts +5 -0
  46. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/constants.d.ts.map +1 -0
  47. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/constants.js +5 -0
  48. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/constants.js.map +1 -0
  49. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/headers.d.ts +9 -0
  50. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/headers.d.ts.map +1 -0
  51. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/headers.js +6 -0
  52. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/headers.js.map +1 -0
  53. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/html.d.ts +45 -0
  54. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/html.d.ts.map +1 -0
  55. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/html.js +123 -0
  56. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/html.js.map +1 -0
  57. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/http-status.d.ts +33 -0
  58. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/http-status.d.ts.map +1 -0
  59. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/http-status.js +6 -0
  60. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/http-status.js.map +1 -0
  61. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/mime.d.ts +71 -0
  62. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/mime.d.ts.map +1 -0
  63. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/mime.js +84 -0
  64. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/mime.js.map +1 -0
  65. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/types.d.ts +75 -0
  66. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/types.d.ts.map +1 -0
  67. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/types.js +6 -0
  68. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/types.js.map +1 -0
  69. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/url.d.ts +30 -0
  70. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/url.d.ts.map +1 -0
  71. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/url.js +256 -0
  72. package/esm/deps/jsr.io/@hono/hono/4.11.3/src/utils/url.js.map +1 -0
  73. package/esm/mod.d.ts +5 -0
  74. package/esm/mod.d.ts.map +1 -0
  75. package/esm/mod.js +2 -0
  76. package/esm/mod.js.map +1 -0
  77. package/esm/package.json +3 -0
  78. package/package.json +5 -2
  79. package/src/HonoYjsMemAdapter.ts +264 -0
  80. package/src/deps/jsr.io/@hono/hono/4.11.3/src/compose.ts +73 -0
  81. package/src/deps/jsr.io/@hono/hono/4.11.3/src/context.ts +770 -0
  82. package/src/deps/jsr.io/@hono/hono/4.11.3/src/helper/websocket/index.ts +140 -0
  83. package/src/deps/jsr.io/@hono/hono/4.11.3/src/hono-base.ts +539 -0
  84. package/src/deps/jsr.io/@hono/hono/4.11.3/src/http-exception.ts +78 -0
  85. package/src/deps/jsr.io/@hono/hono/4.11.3/src/request/constants.ts +1 -0
  86. package/src/deps/jsr.io/@hono/hono/4.11.3/src/request.ts +487 -0
  87. package/src/deps/jsr.io/@hono/hono/4.11.3/src/router.ts +103 -0
  88. package/src/deps/jsr.io/@hono/hono/4.11.3/src/types.ts +2489 -0
  89. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/body.ts +229 -0
  90. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/constants.ts +4 -0
  91. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/headers.ts +333 -0
  92. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/html.ts +182 -0
  93. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/http-status.ts +72 -0
  94. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/mime.ts +96 -0
  95. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/types.ts +116 -0
  96. package/src/deps/jsr.io/@hono/hono/4.11.3/src/utils/url.ts +310 -0
  97. package/src/mod.ts +5 -0
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @module
3
+ * This module provides the `HTTPException` class.
4
+ */
5
+
6
+ import type { ContentfulStatusCode } from './utils/http-status.js'
7
+
8
+ /**
9
+ * Options for creating an `HTTPException`.
10
+ * @property res - Optional response object to use.
11
+ * @property message - Optional custom error message.
12
+ * @property cause - Optional cause of the error.
13
+ */
14
+ type HTTPExceptionOptions = {
15
+ res?: Response
16
+ message?: string
17
+ cause?: unknown
18
+ }
19
+
20
+ /**
21
+ * `HTTPException` must be used when a fatal error such as authentication failure occurs.
22
+ *
23
+ * @see {@link https://hono.dev/docs/api/exception}
24
+ *
25
+ * @param {StatusCode} status - status code of HTTPException
26
+ * @param {HTTPExceptionOptions} options - options of HTTPException
27
+ * @param {HTTPExceptionOptions["res"]} options.res - response of options of HTTPException
28
+ * @param {HTTPExceptionOptions["message"]} options.message - message of options of HTTPException
29
+ * @param {HTTPExceptionOptions["cause"]} options.cause - cause of options of HTTPException
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { HTTPException } from 'hono/http-exception'
34
+ *
35
+ * // ...
36
+ *
37
+ * app.post('/auth', async (c, next) => {
38
+ * // authentication
39
+ * if (authorized === false) {
40
+ * throw new HTTPException(401, { message: 'Custom error message' })
41
+ * }
42
+ * await next()
43
+ * })
44
+ * ```
45
+ */
46
+ export class HTTPException extends Error {
47
+ readonly res?: Response
48
+ readonly status: ContentfulStatusCode
49
+
50
+ /**
51
+ * Creates an instance of `HTTPException`.
52
+ * @param status - HTTP status code for the exception. Defaults to 500.
53
+ * @param options - Additional options for the exception.
54
+ */
55
+ constructor(status: ContentfulStatusCode = 500, options?: HTTPExceptionOptions) {
56
+ super(options?.message, { cause: options?.cause })
57
+ this.res = options?.res
58
+ this.status = status
59
+ }
60
+
61
+ /**
62
+ * Returns the response object associated with the exception.
63
+ * If a response object is not provided, a new response is created with the error message and status code.
64
+ * @returns The response object.
65
+ */
66
+ getResponse(): Response {
67
+ if (this.res) {
68
+ const newResponse = new Response(this.res.body, {
69
+ status: this.status,
70
+ headers: this.res.headers,
71
+ })
72
+ return newResponse
73
+ }
74
+ return new Response(this.message, {
75
+ status: this.status,
76
+ })
77
+ }
78
+ }
@@ -0,0 +1 @@
1
+ export const GET_MATCH_RESULT: symbol = Symbol()
@@ -0,0 +1,487 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { HTTPException } from './http-exception.js'
3
+ import { GET_MATCH_RESULT } from './request/constants.js'
4
+ import type { Result } from './router.js'
5
+ import type {
6
+ Input,
7
+ InputToDataByTarget,
8
+ ParamKeyToRecord,
9
+ ParamKeys,
10
+ RemoveQuestion,
11
+ RouterRoute,
12
+ ValidationTargets,
13
+ } from './types.js'
14
+ import { parseBody } from './utils/body.js'
15
+ import type { BodyData, ParseBodyOptions } from './utils/body.js'
16
+ import type { CustomHeader, RequestHeader } from './utils/headers.js'
17
+ import type { Simplify, UnionToIntersection } from './utils/types.js'
18
+ import { decodeURIComponent_, getQueryParam, getQueryParams, tryDecode } from './utils/url.js'
19
+
20
+ type Body = {
21
+ json: any
22
+ text: string
23
+ arrayBuffer: ArrayBuffer
24
+ blob: Blob
25
+ formData: FormData
26
+ }
27
+ type BodyCache = Partial<Body & { parsedBody: BodyData }>
28
+
29
+ type OptionalRequestInitProperties = 'window' | 'priority'
30
+ type RequiredRequestInit = Required<Omit<RequestInit, OptionalRequestInitProperties>> & {
31
+ [Key in OptionalRequestInitProperties]?: RequestInit[Key]
32
+ }
33
+
34
+ const tryDecodeURIComponent = (str: string) => tryDecode(str, decodeURIComponent_)
35
+
36
+ export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
37
+ /**
38
+ * `.raw` can get the raw Request object.
39
+ *
40
+ * @see {@link https://hono.dev/docs/api/request#raw}
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * // For Cloudflare Workers
45
+ * app.post('/', async (c) => {
46
+ * const metadata = c.req.raw.cf?.hostMetadata?
47
+ * ...
48
+ * })
49
+ * ```
50
+ */
51
+ raw: Request
52
+
53
+ #validatedData: { [K in keyof ValidationTargets]?: {} } // Short name of validatedData
54
+ #matchResult: Result<[unknown, RouterRoute]>
55
+ routeIndex: number = 0
56
+ /**
57
+ * `.path` can get the pathname of the request.
58
+ *
59
+ * @see {@link https://hono.dev/docs/api/request#path}
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * app.get('/about/me', (c) => {
64
+ * const pathname = c.req.path // `/about/me`
65
+ * })
66
+ * ```
67
+ */
68
+ path: string
69
+ bodyCache: BodyCache = {}
70
+
71
+ constructor(
72
+ request: Request,
73
+ path: string = '/',
74
+ matchResult: Result<[unknown, RouterRoute]> = [[]]
75
+ ) {
76
+ this.raw = request
77
+ this.path = path
78
+ this.#matchResult = matchResult
79
+ this.#validatedData = {}
80
+ }
81
+
82
+ /**
83
+ * `.req.param()` gets the path parameters.
84
+ *
85
+ * @see {@link https://hono.dev/docs/api/routing#path-parameter}
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * const name = c.req.param('name')
90
+ * // or all parameters at once
91
+ * const { id, comment_id } = c.req.param()
92
+ * ```
93
+ */
94
+ param<P2 extends ParamKeys<P> = ParamKeys<P>>(key: P2 extends `${infer _}?` ? never : P2): string
95
+ param<P2 extends RemoveQuestion<ParamKeys<P>> = RemoveQuestion<ParamKeys<P>>>(
96
+ key: P2
97
+ ): string | undefined
98
+ param(key: string): string | undefined
99
+ param<P2 extends string = P>(): Simplify<UnionToIntersection<ParamKeyToRecord<ParamKeys<P2>>>>
100
+ param(key?: string): unknown {
101
+ return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams()
102
+ }
103
+
104
+ #getDecodedParam(key: string): string | undefined {
105
+ const paramKey = this.#matchResult[0][this.routeIndex][1][key]
106
+ const param = this.#getParamValue(paramKey)
107
+ return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param
108
+ }
109
+
110
+ #getAllDecodedParams(): Record<string, string> {
111
+ const decoded: Record<string, string> = {}
112
+
113
+ const keys = Object.keys(this.#matchResult[0][this.routeIndex][1])
114
+ for (const key of keys) {
115
+ const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key])
116
+ if (value !== undefined) {
117
+ decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value
118
+ }
119
+ }
120
+
121
+ return decoded
122
+ }
123
+
124
+ #getParamValue(paramKey: any): string | undefined {
125
+ return this.#matchResult[1] ? this.#matchResult[1][paramKey as any] : paramKey
126
+ }
127
+
128
+ /**
129
+ * `.query()` can get querystring parameters.
130
+ *
131
+ * @see {@link https://hono.dev/docs/api/request#query}
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * // Query params
136
+ * app.get('/search', (c) => {
137
+ * const query = c.req.query('q')
138
+ * })
139
+ *
140
+ * // Get all params at once
141
+ * app.get('/search', (c) => {
142
+ * const { q, limit, offset } = c.req.query()
143
+ * })
144
+ * ```
145
+ */
146
+ query(key: string): string | undefined
147
+ query(): Record<string, string>
148
+ query(key?: string) {
149
+ return getQueryParam(this.url, key)
150
+ }
151
+
152
+ /**
153
+ * `.queries()` can get multiple querystring parameter values, e.g. /search?tags=A&tags=B
154
+ *
155
+ * @see {@link https://hono.dev/docs/api/request#queries}
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * app.get('/search', (c) => {
160
+ * // tags will be string[]
161
+ * const tags = c.req.queries('tags')
162
+ * })
163
+ * ```
164
+ */
165
+ queries(key: string): string[] | undefined
166
+ queries(): Record<string, string[]>
167
+ queries(key?: string) {
168
+ return getQueryParams(this.url, key)
169
+ }
170
+
171
+ /**
172
+ * `.header()` can get the request header value.
173
+ *
174
+ * @see {@link https://hono.dev/docs/api/request#header}
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * app.get('/', (c) => {
179
+ * const userAgent = c.req.header('User-Agent')
180
+ * })
181
+ * ```
182
+ */
183
+ header(name: RequestHeader): string | undefined
184
+ header(name: string): string | undefined
185
+ header(): Record<RequestHeader | (string & CustomHeader), string>
186
+ header(name?: string) {
187
+ if (name) {
188
+ return this.raw.headers.get(name) ?? undefined
189
+ }
190
+
191
+ const headerData: Record<string, string | undefined> = {}
192
+ this.raw.headers.forEach((value, key) => {
193
+ headerData[key] = value
194
+ })
195
+ return headerData
196
+ }
197
+
198
+ /**
199
+ * `.parseBody()` can parse Request body of type `multipart/form-data` or `application/x-www-form-urlencoded`
200
+ *
201
+ * @see {@link https://hono.dev/docs/api/request#parsebody}
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * app.post('/entry', async (c) => {
206
+ * const body = await c.req.parseBody()
207
+ * })
208
+ * ```
209
+ */
210
+ async parseBody<Options extends Partial<ParseBodyOptions>, T extends BodyData<Options>>(
211
+ options?: Options
212
+ ): Promise<T>
213
+ async parseBody<T extends BodyData>(options?: Partial<ParseBodyOptions>): Promise<T>
214
+ async parseBody(options?: Partial<ParseBodyOptions>) {
215
+ return (this.bodyCache.parsedBody ??= await parseBody(this, options))
216
+ }
217
+
218
+ #cachedBody = (key: keyof Body) => {
219
+ const { bodyCache, raw } = this
220
+ const cachedBody = bodyCache[key]
221
+
222
+ if (cachedBody) {
223
+ return cachedBody
224
+ }
225
+
226
+ const anyCachedKey = Object.keys(bodyCache)[0]
227
+ if (anyCachedKey) {
228
+ return (bodyCache[anyCachedKey as keyof Body] as Promise<BodyInit>).then((body) => {
229
+ if (anyCachedKey === 'json') {
230
+ body = JSON.stringify(body)
231
+ }
232
+ return new Response(body)[key]()
233
+ })
234
+ }
235
+
236
+ return (bodyCache[key] = raw[key]())
237
+ }
238
+
239
+ /**
240
+ * `.json()` can parse Request body of type `application/json`
241
+ *
242
+ * @see {@link https://hono.dev/docs/api/request#json}
243
+ *
244
+ * @example
245
+ * ```ts
246
+ * app.post('/entry', async (c) => {
247
+ * const body = await c.req.json()
248
+ * })
249
+ * ```
250
+ */
251
+ json<T = any>(): Promise<T> {
252
+ return this.#cachedBody('text').then((text: string) => JSON.parse(text))
253
+ }
254
+
255
+ /**
256
+ * `.text()` can parse Request body of type `text/plain`
257
+ *
258
+ * @see {@link https://hono.dev/docs/api/request#text}
259
+ *
260
+ * @example
261
+ * ```ts
262
+ * app.post('/entry', async (c) => {
263
+ * const body = await c.req.text()
264
+ * })
265
+ * ```
266
+ */
267
+ text(): Promise<string> {
268
+ return this.#cachedBody('text')
269
+ }
270
+
271
+ /**
272
+ * `.arrayBuffer()` parse Request body as an `ArrayBuffer`
273
+ *
274
+ * @see {@link https://hono.dev/docs/api/request#arraybuffer}
275
+ *
276
+ * @example
277
+ * ```ts
278
+ * app.post('/entry', async (c) => {
279
+ * const body = await c.req.arrayBuffer()
280
+ * })
281
+ * ```
282
+ */
283
+ arrayBuffer(): Promise<ArrayBuffer> {
284
+ return this.#cachedBody('arrayBuffer')
285
+ }
286
+
287
+ /**
288
+ * Parses the request body as a `Blob`.
289
+ * @example
290
+ * ```ts
291
+ * app.post('/entry', async (c) => {
292
+ * const body = await c.req.blob();
293
+ * });
294
+ * ```
295
+ * @see https://hono.dev/docs/api/request#blob
296
+ */
297
+ blob(): Promise<Blob> {
298
+ return this.#cachedBody('blob')
299
+ }
300
+
301
+ /**
302
+ * Parses the request body as `FormData`.
303
+ * @example
304
+ * ```ts
305
+ * app.post('/entry', async (c) => {
306
+ * const body = await c.req.formData();
307
+ * });
308
+ * ```
309
+ * @see https://hono.dev/docs/api/request#formdata
310
+ */
311
+ formData(): Promise<FormData> {
312
+ return this.#cachedBody('formData')
313
+ }
314
+
315
+ /**
316
+ * Adds validated data to the request.
317
+ *
318
+ * @param target - The target of the validation.
319
+ * @param data - The validated data to add.
320
+ */
321
+ addValidatedData(target: keyof ValidationTargets, data: {}) {
322
+ this.#validatedData[target] = data
323
+ }
324
+
325
+ /**
326
+ * Gets validated data from the request.
327
+ *
328
+ * @param target - The target of the validation.
329
+ * @returns The validated data.
330
+ *
331
+ * @see https://hono.dev/docs/api/request#valid
332
+ */
333
+ valid<T extends keyof I & keyof ValidationTargets>(target: T): InputToDataByTarget<I, T>
334
+ valid(target: keyof ValidationTargets) {
335
+ return this.#validatedData[target] as unknown
336
+ }
337
+
338
+ /**
339
+ * `.url()` can get the request url strings.
340
+ *
341
+ * @see {@link https://hono.dev/docs/api/request#url}
342
+ *
343
+ * @example
344
+ * ```ts
345
+ * app.get('/about/me', (c) => {
346
+ * const url = c.req.url // `http://localhost:8787/about/me`
347
+ * ...
348
+ * })
349
+ * ```
350
+ */
351
+ get url(): string {
352
+ return this.raw.url
353
+ }
354
+
355
+ /**
356
+ * `.method()` can get the method name of the request.
357
+ *
358
+ * @see {@link https://hono.dev/docs/api/request#method}
359
+ *
360
+ * @example
361
+ * ```ts
362
+ * app.get('/about/me', (c) => {
363
+ * const method = c.req.method // `GET`
364
+ * })
365
+ * ```
366
+ */
367
+ get method(): string {
368
+ return this.raw.method
369
+ }
370
+
371
+ get [GET_MATCH_RESULT](): Result<[unknown, RouterRoute]> {
372
+ return this.#matchResult
373
+ }
374
+
375
+ /**
376
+ * `.matchedRoutes()` can return a matched route in the handler
377
+ *
378
+ * @deprecated
379
+ *
380
+ * Use matchedRoutes helper defined in "hono/route" instead.
381
+ *
382
+ * @see {@link https://hono.dev/docs/api/request#matchedroutes}
383
+ *
384
+ * @example
385
+ * ```ts
386
+ * app.use('*', async function logger(c, next) {
387
+ * await next()
388
+ * c.req.matchedRoutes.forEach(({ handler, method, path }, i) => {
389
+ * const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]')
390
+ * console.log(
391
+ * method,
392
+ * ' ',
393
+ * path,
394
+ * ' '.repeat(Math.max(10 - path.length, 0)),
395
+ * name,
396
+ * i === c.req.routeIndex ? '<- respond from here' : ''
397
+ * )
398
+ * })
399
+ * })
400
+ * ```
401
+ */
402
+ get matchedRoutes(): RouterRoute[] {
403
+ return this.#matchResult[0].map(([[, route]]) => route)
404
+ }
405
+
406
+ /**
407
+ * `routePath()` can retrieve the path registered within the handler
408
+ *
409
+ * @deprecated
410
+ *
411
+ * Use routePath helper defined in "hono/route" instead.
412
+ *
413
+ * @see {@link https://hono.dev/docs/api/request#routepath}
414
+ *
415
+ * @example
416
+ * ```ts
417
+ * app.get('/posts/:id', (c) => {
418
+ * return c.json({ path: c.req.routePath })
419
+ * })
420
+ * ```
421
+ */
422
+ get routePath(): string {
423
+ return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path
424
+ }
425
+ }
426
+
427
+ /**
428
+ * Clones a HonoRequest's underlying raw Request object.
429
+ *
430
+ * This utility handles both consumed and unconsumed request bodies:
431
+ * - If the request body hasn't been consumed, it uses the native `clone()` method
432
+ * - If the request body has been consumed, it reconstructs a new Request using cached body data
433
+ *
434
+ * This is particularly useful when you need to:
435
+ * - Process the same request body multiple times
436
+ * - Pass requests to external services after validation
437
+ *
438
+ * @param req - The HonoRequest object to clone
439
+ * @returns A Promise that resolves to a new Request object with the same properties
440
+ * @throws {HTTPException} If the request body was consumed directly via `req.raw`
441
+ * without using HonoRequest methods (e.g., `req.json()`, `req.text()`), making it
442
+ * impossible to reconstruct the body from cache
443
+ *
444
+ * @example
445
+ * ```ts
446
+ * // Clone after consuming the body (e.g., after validation)
447
+ * app.post('/forward',
448
+ * validator('json', (data) => data),
449
+ * async (c) => {
450
+ * const validated = c.req.valid('json')
451
+ * // Body has been consumed, but cloneRawRequest still works
452
+ * const clonedReq = await cloneRawRequest(c.req)
453
+ * return fetch('http://backend-service.com', clonedReq)
454
+ * }
455
+ * )
456
+ * ```
457
+ */
458
+ export const cloneRawRequest = async (req: HonoRequest): Promise<Request> => {
459
+ if (!req.raw.bodyUsed) {
460
+ return req.raw.clone()
461
+ }
462
+
463
+ const cacheKey = (Object.keys(req.bodyCache) as Array<keyof Body>)[0]
464
+ if (!cacheKey) {
465
+ throw new HTTPException(500, {
466
+ message:
467
+ 'Cannot clone request: body was already consumed and not cached. Please use HonoRequest methods (e.g., req.json(), req.text()) instead of consuming req.raw directly.',
468
+ })
469
+ }
470
+
471
+ const requestInit: RequiredRequestInit = {
472
+ body: await req[cacheKey](),
473
+ cache: req.raw.cache,
474
+ credentials: req.raw.credentials,
475
+ headers: req.header(),
476
+ integrity: req.raw.integrity,
477
+ keepalive: req.raw.keepalive,
478
+ method: req.method,
479
+ mode: req.raw.mode,
480
+ redirect: req.raw.redirect,
481
+ referrer: req.raw.referrer,
482
+ referrerPolicy: req.raw.referrerPolicy,
483
+ signal: req.raw.signal,
484
+ }
485
+
486
+ return new Request(req.url, requestInit)
487
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @module
3
+ * This module provides types definitions and variables for the routers.
4
+ */
5
+
6
+ /**
7
+ * Constant representing all HTTP methods in uppercase.
8
+ */
9
+ export const METHOD_NAME_ALL = 'ALL' as const
10
+ /**
11
+ * Constant representing all HTTP methods in lowercase.
12
+ */
13
+ export const METHOD_NAME_ALL_LOWERCASE = 'all' as const
14
+ /**
15
+ * Array of supported HTTP methods.
16
+ */
17
+ export const METHODS = ['get', 'post', 'put', 'delete', 'options', 'patch'] as const
18
+ /**
19
+ * Error message indicating that a route cannot be added because the matcher is already built.
20
+ */
21
+ export const MESSAGE_MATCHER_IS_ALREADY_BUILT =
22
+ 'Can not add a route since the matcher is already built.'
23
+
24
+ /**
25
+ * Interface representing a router.
26
+ *
27
+ * @template T - The type of the handler.
28
+ */
29
+ export interface Router<T> {
30
+ /**
31
+ * The name of the router.
32
+ */
33
+ name: string
34
+
35
+ /**
36
+ * Adds a route to the router.
37
+ *
38
+ * @param method - The HTTP method (e.g., 'get', 'post').
39
+ * @param path - The path for the route.
40
+ * @param handler - The handler for the route.
41
+ */
42
+ add(method: string, path: string, handler: T): void
43
+
44
+ /**
45
+ * Matches a route based on the given method and path.
46
+ *
47
+ * @param method - The HTTP method (e.g., 'get', 'post').
48
+ * @param path - The path to match.
49
+ * @returns The result of the match.
50
+ */
51
+ match(method: string, path: string): Result<T>
52
+ }
53
+
54
+ /**
55
+ * Type representing a map of parameter indices.
56
+ */
57
+ export type ParamIndexMap = Record<string, number>
58
+ /**
59
+ * Type representing a stash of parameters.
60
+ */
61
+ export type ParamStash = string[]
62
+ /**
63
+ * Type representing a map of parameters.
64
+ */
65
+ export type Params = Record<string, string>
66
+ /**
67
+ * Type representing the result of a route match.
68
+ *
69
+ * The result can be in one of two formats:
70
+ * 1. An array of handlers with their corresponding parameter index maps, followed by a parameter stash.
71
+ * 2. An array of handlers with their corresponding parameter maps.
72
+ *
73
+ * Example:
74
+ *
75
+ * [[handler, paramIndexMap][], paramArray]
76
+ * ```typescript
77
+ * [
78
+ * [
79
+ * [middlewareA, {}], // '*'
80
+ * [funcA, {'id': 0}], // '/user/:id/*'
81
+ * [funcB, {'id': 0, 'action': 1}], // '/user/:id/:action'
82
+ * ],
83
+ * ['123', 'abc']
84
+ * ]
85
+ * ```
86
+ *
87
+ * [[handler, params][]]
88
+ * ```typescript
89
+ * [
90
+ * [
91
+ * [middlewareA, {}], // '*'
92
+ * [funcA, {'id': '123'}], // '/user/:id/*'
93
+ * [funcB, {'id': '123', 'action': 'abc'}], // '/user/:id/:action'
94
+ * ]
95
+ * ]
96
+ * ```
97
+ */
98
+ export type Result<T> = [[T, ParamIndexMap][], ParamStash] | [[T, Params][]]
99
+
100
+ /**
101
+ * Error class representing an unsupported path error.
102
+ */
103
+ export class UnsupportedPathError extends Error {}