rajt 0.0.57 → 0.0.59

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 (49) hide show
  1. package/README.md +10 -7
  2. package/package.json +35 -15
  3. package/src/action-old.ts +72 -0
  4. package/src/action.ts +12 -61
  5. package/src/auth/ability.ts +2 -2
  6. package/src/auth/authnz.ts +3 -0
  7. package/src/auth/index.ts +0 -1
  8. package/src/auth/token.ts +27 -24
  9. package/src/bin/rajt.js +123 -0
  10. package/src/cli/commands/dev/index.ts +294 -0
  11. package/src/cli/commands/dev/utils.ts +215 -0
  12. package/src/cli/index.ts +69 -0
  13. package/src/cli/types.ts +1 -0
  14. package/src/create-app.ts +15 -9
  15. package/src/db/d1.d.ts +1 -0
  16. package/src/db/d1.ts +1 -0
  17. package/src/dev.ts +18 -15
  18. package/src/enum.ts +2 -75
  19. package/src/esbuild.mjs +11 -9
  20. package/src/http.ts +9 -8
  21. package/src/index.ts +1 -3
  22. package/src/prod-aws.ts +2 -17
  23. package/src/prod-cf.ts +1 -18
  24. package/src/prod.ts +16 -0
  25. package/src/request-old.ts +98 -0
  26. package/src/request.ts +152 -71
  27. package/src/response.ts +71 -26
  28. package/src/routes.ts +66 -2
  29. package/src/scripts/cache-routes.ts +1 -64
  30. package/src/types.ts +24 -4
  31. package/src/utils/environment.ts +3 -2
  32. package/src/utils/func.ts +2 -2
  33. package/src/utils/local-date.ts +13 -0
  34. package/src/utils/logger.ts +61 -0
  35. package/src/utils/port.ts +1 -3
  36. package/src/utils/resolve.ts +4 -3
  37. package/src/utils/shutdown.ts +19 -0
  38. package/src/validator.ts +68 -0
  39. package/src/auth/auth.ts +0 -33
  40. package/src/dynamodb/client.ts +0 -125
  41. package/src/dynamodb/compact.ts +0 -205
  42. package/src/dynamodb/decorators.ts +0 -126
  43. package/src/dynamodb/index.ts +0 -4
  44. package/src/dynamodb/model.ts +0 -258
  45. package/src/dynamodb/query-builder.ts +0 -174
  46. package/src/dynamodb/repository.ts +0 -31
  47. package/src/dynamodb/schema.ts +0 -107
  48. package/src/dynamodb/types.ts +0 -32
  49. package/src/utils/lenght.ts +0 -32
package/src/dev.ts CHANGED
@@ -1,16 +1,20 @@
1
+ import { fileURLToPath } from 'node:url'
2
+ import { dirname, join } from 'node:path'
1
3
  import { config } from 'dotenv'
2
- import { serve } from '@hono/node-server'
4
+ import { serve, type ServerType } from '@hono/node-server'
3
5
  import createApp from './create-app'
4
6
  import { getRoutes, getMiddlewares } from './routes'
5
7
  import { registerHandler, registerMiddleware } from './register'
6
8
  import { Ability } from './auth'
7
- import { getAvailablePort } from './utils/port'
8
9
  import jsonImport from './utils/json-import'
9
10
  import { setEnv, detectEnvironment } from './utils/environment'
11
+ import shutdown from './utils/shutdown'
10
12
 
11
13
  setEnv(detectEnvironment())
12
14
 
13
- config({ path: '../../.env.dev' })
15
+ const __dirname = join(dirname(fileURLToPath(import.meta.url)), '../../../')
16
+
17
+ config({ path: join(__dirname, '.env.dev') })
14
18
 
15
19
  let routes = await getRoutes()
16
20
  routes.forEach(r => registerHandler(r.name, r.handle))
@@ -20,18 +24,17 @@ const middlewares = await getMiddlewares()
20
24
  middlewares.forEach(mw => registerMiddleware(mw.handle))
21
25
 
22
26
  Ability.fromRoutes(routes)
23
- Ability.roles = jsonImport('../../../../roles.json')
27
+ Ability.roles = jsonImport(join(__dirname, 'roles.json'))
24
28
 
25
29
  const fetch = createApp({ routes }).fetch
26
30
 
27
- const desiredPort = process.env?.PORT ? Number(process.env.PORT) : 3000
28
- getAvailablePort(desiredPort)
29
- .then(port => {
30
- if (port != desiredPort)
31
- console.warn(`🟠 Port ${desiredPort} was in use, using ${port} as a fallback`)
32
-
33
- console.log(`🚀 API running on http://localhost:${port}`)
34
- serve({ fetch, port })
35
- }).catch(err => {
36
- console.error('Error finding available port:', err)
37
- })
31
+ const port = process.env?.PORT ? Number(process.env.PORT) : 3000
32
+
33
+ let server: ServerType | null = serve({ fetch, port })
34
+
35
+ shutdown(() => {
36
+ if (server) {
37
+ server?.close()
38
+ server = null
39
+ }
40
+ })
package/src/enum.ts CHANGED
@@ -1,75 +1,2 @@
1
- type EnumType<T> = T extends string[]
2
- ? { [K in T[number]]: K }
3
- : T extends Record<string, string | number>
4
- ? T
5
- : never
6
-
7
- type EnumValue<T> = T extends string[]
8
- ? T[number]
9
- : T extends Record<string, infer V>
10
- ? V
11
- : never
12
-
13
- type EnumStatic<T> = {
14
- has(search: string | number): boolean
15
- key(search: string | number): string | null
16
- value(search: string | number): EnumValue<T> | null
17
- readonly keys: string[]
18
- readonly values: Array<EnumValue<T>>
19
- toObject(): EnumType<T>
20
- } & EnumType<T>
21
-
22
- export default function Enum<T extends string[] | Record<string, string | number>>(definition: T): EnumStatic<T> {
23
- const enumObj = Array.isArray(definition)
24
- ? Object.fromEntries(definition.map(key => [key, key])) as EnumType<T>
25
- : definition as EnumType<T>
26
-
27
- const keyToValueMap = new Map<string | number, string | number>()
28
- const valueToKeyMap = new Map<string | number, string>()
29
-
30
- Object.entries(enumObj).forEach(([key, value]) => {
31
- keyToValueMap.set(key, value)
32
- valueToKeyMap.set(String(value), key)
33
- if (typeof value === 'number') valueToKeyMap.set(value.toString(), key)
34
- })
35
-
36
- const GeneratedEnum = class {
37
- static has(search: string | number): boolean {
38
- return keyToValueMap.has(search as string) || valueToKeyMap.has(String(search))
39
- }
40
-
41
- static key(search: string | number): string | null {
42
- if (keyToValueMap.has(search as string))
43
- return search as string
44
-
45
- return valueToKeyMap.get(String(search)) || null
46
- }
47
-
48
- static value(search: string | number): EnumValue<T> | null {
49
- if (keyToValueMap.has(search as string))
50
- return keyToValueMap.get(search as string) as EnumValue<T>
51
-
52
- return valueToKeyMap.has(String(search))
53
- ? keyToValueMap.get(valueToKeyMap.get(String(search))!) as EnumValue<T>
54
- : null
55
- }
56
-
57
- static get keys(): string[] {
58
- return Object.keys(enumObj)
59
- }
60
-
61
- static get values(): Array<EnumValue<T>> {
62
- return Object.values(enumObj) as Array<EnumValue<T>>
63
- }
64
-
65
- static toObject(): EnumType<T> {
66
- return { ...enumObj }
67
- }
68
- }
69
-
70
- Object.entries(enumObj).forEach(([key, value]) => {
71
- (GeneratedEnum as any)[key] = value
72
- })
73
-
74
- return GeneratedEnum as unknown as EnumStatic<T>
75
- }
1
+ export { Enum } from 't0n'
2
+ export type { EnumStatic, EnumValue, EnumType } from 't0n'
package/src/esbuild.mjs CHANGED
@@ -34,7 +34,7 @@ const buildOptions = {
34
34
  bundle: true,
35
35
  minify: true,
36
36
  outfile: join(__dirname, '../../../dist/index.js'),
37
- platform: isCF ? 'browser' : 'node20',
37
+ platform: isCF ? 'browser' : 'node',
38
38
  target: isCF ? 'es2022' : 'node20',
39
39
  conditions: isCF ? ['worker', 'browser'] : [],
40
40
  format: 'esm',
@@ -44,8 +44,8 @@ const buildOptions = {
44
44
  '@aws-sdk', '@smithy',
45
45
  ...(isCF ? [
46
46
  'cloudflare:workers',
47
- 'node:crypto',
48
- 'crypto',
47
+ 'node:crypto', 'crypto',
48
+ 'node:buffer', 'buffer',
49
49
  ] : []),
50
50
  ],
51
51
  metafile: true,
@@ -102,12 +102,14 @@ existsSync(distDir)
102
102
  for (const file of await readdirSync(distDir))
103
103
  await rmSync(join(distDir, file))
104
104
 
105
- for (let file of [
106
- 'wrangler.toml',
107
- ]) {
108
- file = join(cwd, file)
109
- if (existsSync(file))
110
- copyFileSync(file, join(cwd, 'dist', basename(file)))
105
+ if (isCF) {
106
+ for (let file of [
107
+ 'wrangler.toml',
108
+ ]) {
109
+ file = join(cwd, file)
110
+ if (existsSync(file))
111
+ copyFileSync(file, join(cwd, 'dist', basename(file)))
112
+ }
111
113
  }
112
114
 
113
115
  esbuild.build(buildOptions)
package/src/http.ts CHANGED
@@ -1,14 +1,15 @@
1
1
  import type { Context, Next } from 'hono'
2
2
  import { MiddlewareType } from './middleware'
3
- import Response from './response'
4
- import { Ability, Auth as Gate } from './auth'
3
+ import response from './response'
4
+ import { Ability } from './auth'
5
5
  import mergeMiddleware from './utils/merge-middleware'
6
+ import { IRequest } from './types'
6
7
 
7
8
  function method(method: string, ...args: any[]): void | ClassDecorator {
8
- if (args.length === 1 && typeof args[0] === 'function')
9
+ if (args.length == 1 && typeof args[0] == 'function')
9
10
  return _method(method, '/', args[0])
10
11
 
11
- const path = typeof args[0] === 'string' ? args[0] : '/'
12
+ const path = typeof args[0] == 'string' ? args[0] : '/'
12
13
  return (target: Function) => _method(method, path, target)
13
14
  }
14
15
 
@@ -93,7 +94,7 @@ export function Middlewares(...handlers: MiddlewareType[]) {
93
94
  export function Auth(target: Function): void
94
95
  export function Auth(): ClassDecorator
95
96
  export function Auth(...args: any[]): void | ClassDecorator {
96
- if (args.length === 1 && typeof args[0] === 'function')
97
+ if (args.length == 1 && typeof args[0] == 'function')
97
98
  return _auth(args[0])
98
99
 
99
100
  return (target: any) => _auth(target)
@@ -101,11 +102,11 @@ export function Auth(...args: any[]): void | ClassDecorator {
101
102
 
102
103
  function _auth(target: Function | any) {
103
104
  mergeMiddleware(target, async (c: Context, next: Next) => {
104
- const user = Gate.user
105
+ const req = c.get('_') as IRequest
105
106
  const ability = Ability.fromAction(target)
106
107
 
107
- if (!user || !ability || Gate.cant(ability))
108
- return Response.unauthorized()
108
+ if (!req?.user || !ability || req.cant(ability))
109
+ return response.unauthorized()
109
110
 
110
111
  await next()
111
112
  })
package/src/index.ts CHANGED
@@ -1,6 +1,4 @@
1
1
  export { default as Action } from './action'
2
- export { Auth, Auth as Gate } from './auth/auth'
3
2
  export { default as Middleware } from './middleware'
4
- export { default as Request } from './request'
5
3
  export { default as Response } from './response'
6
- export { default as Enum } from './enum'
4
+ export { Enum } from 't0n'
package/src/prod-aws.ts CHANGED
@@ -1,19 +1,4 @@
1
1
  import { handle } from 'hono/aws-lambda'
2
- import createApp from './create-app'
3
- import { Ability } from './auth'
2
+ import { app } from './prod'
4
3
 
5
- // @ts-ignore
6
- await import('../../../tmp/import-routes.mjs')
7
-
8
- // @ts-ignore
9
- const routes = (await import('../../../tmp/routes.json')).default
10
-
11
- // @ts-ignore
12
- Ability.roles = (await import('../../../roles.json')).default
13
- // @ts-ignore
14
- Ability.fromRoutes(routes)
15
-
16
- // @ts-ignore
17
- const app = createApp({ routes })
18
-
19
- export const handler = handle(app) // AWS Lambda (LLRT)
4
+ export const handler = handle(app)
package/src/prod-cf.ts CHANGED
@@ -1,18 +1 @@
1
- import createApp from './create-app'
2
- import { Ability } from './auth'
3
-
4
- // @ts-ignore
5
- await import('../../../tmp/import-routes.mjs')
6
-
7
- // @ts-ignore
8
- const routes = (await import('../../../tmp/routes.json')).default
9
-
10
- // @ts-ignore
11
- Ability.roles = (await import('../../../roles.json')).default
12
- // @ts-ignore
13
- Ability.fromRoutes(routes)
14
-
15
- // @ts-ignore
16
- const app = createApp({ routes })
17
-
18
- export default app
1
+ export { app as default } from './prod'
package/src/prod.ts ADDED
@@ -0,0 +1,16 @@
1
+ import createApp from './create-app'
2
+ import { Ability } from './auth'
3
+
4
+ // @ts-ignore
5
+ await import('../../../tmp/import-routes.mjs')
6
+
7
+ // @ts-ignore
8
+ const routes = (await import('../../../tmp/routes.json')).default
9
+
10
+ // @ts-ignore
11
+ Ability.roles = (await import('../../../roles.json')).default
12
+ // @ts-ignore
13
+ Ability.fromRoutes(routes)
14
+
15
+ // @ts-ignore
16
+ export const app = createApp({ routes })
@@ -0,0 +1,98 @@
1
+ import { bufferToFormData } from 'hono/utils/buffer'
2
+ import { HTTPException } from 'hono/http-exception'
3
+ import type { BodyData } from 'hono/utils/body'
4
+ import Response from './response'
5
+ import c from './context'
6
+
7
+ export default class Request {
8
+ static param(key: string) {
9
+ return c.cx.req.param(key)
10
+ }
11
+
12
+ static query() {
13
+ return c.cx.req.query()
14
+ }
15
+
16
+ static async form(cType?: string) {
17
+ cType ??= c.cx.req.header('Content-Type')
18
+ if (!cType) return {}
19
+
20
+ let formData: FormData
21
+
22
+ if (c.cx.req.bodyCache.formData) {
23
+ formData = await c.cx.req.bodyCache.formData
24
+ } else {
25
+ try {
26
+ const arrayBuffer = await c.cx.req.arrayBuffer()
27
+ formData = await bufferToFormData(arrayBuffer, cType)
28
+ c.cx.req.bodyCache.formData = formData
29
+ } catch (e) {
30
+ throw new HTTPException(400, {
31
+ message: 'Malformed FormData request.'
32
+ + (e instanceof Error ? ` ${e.message}` : ` ${String(e)}`)
33
+ })
34
+ }
35
+ }
36
+
37
+ const form: BodyData<{ all: true }> = {}
38
+ formData.forEach((value, key) => {
39
+ if (key.endsWith('[]')) {
40
+ ;((form[key] ??= []) as unknown[]).push(value)
41
+ } else if (Array.isArray(form[key])) {
42
+ ;(form[key] as unknown[]).push(value)
43
+ } else if (key in form) {
44
+ form[key] = [form[key] as string | File, value]
45
+ } else {
46
+ form[key] = value
47
+ }
48
+ })
49
+
50
+ return form
51
+ }
52
+
53
+ static async json<E>() {
54
+ try {
55
+ return await c.cx.req.json<E>()
56
+ } catch {
57
+ throw new HTTPException(400, { message: 'Malformed JSON in request body' })
58
+ }
59
+ }
60
+
61
+ static async body<E>() {
62
+ const cType = c.cx.req.header('Content-Type')
63
+ if (!cType) return {} as E
64
+
65
+ if (/^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/.test(cType)) {
66
+ return await Request.json<E>()
67
+ }
68
+
69
+ if (
70
+ /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/.test(cType)
71
+ && ! /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/.test(cType)
72
+ ) {
73
+ return await Request.form() as E
74
+ }
75
+
76
+ return {} as E
77
+ }
78
+
79
+ static get response() {
80
+ return Response
81
+ }
82
+
83
+ static get cx() {
84
+ return c.cx
85
+ }
86
+
87
+ static get cookie() {
88
+ return c.cookie
89
+ }
90
+
91
+ static get ip() {
92
+ return c.ip
93
+ }
94
+
95
+ static get userAgent() {
96
+ return c.userAgent
97
+ }
98
+ }
package/src/request.ts CHANGED
@@ -1,98 +1,179 @@
1
- import { bufferToFormData } from 'hono/utils/buffer'
1
+ import { getCookie, getSignedCookie, setCookie, setSignedCookie, deleteCookie } from 'hono/cookie'
2
2
  import { HTTPException } from 'hono/http-exception'
3
- import type { BodyData } from 'hono/utils/body'
4
- import Response from './response'
5
- import c from './context'
6
-
7
- export default class Request {
8
- static param(key: string) {
9
- return c.cx.req.param(key)
10
- }
11
-
12
- static query() {
13
- return c.cx.req.query()
14
- }
15
-
16
- static async form(cType?: string) {
17
- cType ??= c.cx.req.header('Content-Type')
18
- if (!cType) return {}
19
-
20
- let formData: FormData
21
-
22
- if (c.cx.req.bodyCache.formData) {
23
- formData = await c.cx.req.bodyCache.formData
24
- } else {
25
- try {
26
- const arrayBuffer = await c.cx.req.arrayBuffer()
27
- formData = await bufferToFormData(arrayBuffer, cType)
28
- c.cx.req.bodyCache.formData = formData
29
- } catch (e) {
30
- throw new HTTPException(400, {
31
- message: 'Malformed FormData request.'
32
- + (e instanceof Error ? ` ${e.message}` : ` ${String(e)}`)
33
- })
34
- }
35
- }
3
+ import { Authnz, Token } from './auth'
4
+
5
+ import type { Context } from 'hono'
6
+ import type { CookieOptions, CookiePrefixOptions } from 'hono/utils/cookie'
7
+ import type { CustomHeader, RequestHeader } from 'hono/utils/headers'
8
+ import type { BodyData, ParseBodyOptions } from 'hono/utils/body'
9
+
10
+ const cookieWrapper = (c: Context) => ({
11
+ all: () => getCookie(c),
12
+ allSigned: (secret: string) => getSignedCookie(c, secret),
13
+ get: (name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getCookie(c, name, prefixOptions) : getCookie(c, name),
14
+ getSigned: (secret: string, name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getSignedCookie(c, secret, name, prefixOptions) : getSignedCookie(c, secret, name),
15
+ set: (name: string, value: string, opt?: CookieOptions) => setCookie(c, name, value, opt),
16
+ setSigned: (name: string, value: string, secret: string, opt?: CookieOptions) => setSignedCookie(c, name, value, secret, opt),
17
+ delete: (name: string, opt?: CookieOptions) => deleteCookie(c, name, opt)
18
+ })
19
+
20
+ export default class $Request {
21
+ #c!: Context
22
+ #cookie: ReturnType<typeof cookieWrapper>
23
+ #u: Authnz<any> | null = null
24
+
25
+ constructor(c: Context) {
26
+ this.#c = c
27
+ this.#cookie = cookieWrapper(c)
28
+ this.#u = Authnz.fromToken(Token.fromRequest(this))
29
+ }
36
30
 
37
- const form: BodyData<{ all: true }> = {}
38
- formData.forEach((value, key) => {
39
- if (key.endsWith('[]')) {
40
- ;((form[key] ??= []) as unknown[]).push(value)
41
- } else if (Array.isArray(form[key])) {
42
- ;(form[key] as unknown[]).push(value)
43
- } else if (key in form) {
44
- form[key] = [form[key] as string | File, value]
45
- } else {
46
- form[key] = value
47
- }
48
- })
31
+ get user() {
32
+ return this.#u ? this.#u?.data : null
33
+ }
49
34
 
50
- return form
35
+ get auth() {
36
+ return this.#u
51
37
  }
52
38
 
53
- static async json<E>() {
54
- try {
55
- return await c.cx.req.json<E>()
56
- } catch {
57
- throw new HTTPException(400, { message: 'Malformed JSON in request body' })
58
- }
39
+ can(...abilities: string[]) {
40
+ return this.#u ? this.#u.can(...abilities) : false
41
+ }
42
+
43
+ cant(...abilities: string[]) {
44
+ return !this.can(...abilities)
45
+ }
46
+
47
+ hasRole(...roles: string[]) {
48
+ return this.#u ? this.#u.hasRole(...roles) : false
49
+ }
50
+
51
+ has(prop: string, value: any = null) {
52
+ return this.#u ? this.#u.has(prop, value) : false
53
+ }
54
+ hasValue(prop: string, value: any = null) {
55
+ return this.has(prop, value)
56
+ }
57
+
58
+ get cx() {
59
+ return this.#c
60
+ }
61
+
62
+ get cookie() {
63
+ return this.#cookie
64
+ }
65
+
66
+ get ip(): string | undefined {
67
+ return this.#c.req.header('cf-connecting-ip')
68
+ || this.#c.req.header('x-forwarded-for')?.split(',')[0]?.trim()
69
+ || this.#c.env?.aws?.lambda?.event?.requestContext?.identity?.sourceIp
70
+ || this.#c.req.header('x-real-ip')
71
+ || this.#c.env?.remoteAddr?.hostname
72
+ }
73
+
74
+ get userAgent(): string | undefined {
75
+ return this.#c.req.header('user-agent')
76
+ }
77
+
78
+ get routePath() {
79
+ return this.#c.req.routePath
80
+ }
81
+
82
+ get path() {
83
+ return this.#c.req.path
59
84
  }
60
85
 
61
- static async body<E>() {
62
- const cType = c.cx.req.header('Content-Type')
86
+ get url() {
87
+ return this.#c.req.raw.url
88
+ }
89
+
90
+ get method() {
91
+ return this.#c.req.raw.method
92
+ }
93
+
94
+ get matchedRoutes() {
95
+ return this.#c.req.matchedRoutes
96
+ }
97
+
98
+ get raw() {
99
+ return this.#c.req.raw
100
+ }
101
+
102
+ header(name: RequestHeader): string | undefined
103
+ header(name: string): string | undefined
104
+ header(): Record<RequestHeader | (string & CustomHeader), string>
105
+ header(name?: string) { // @ts-ignore
106
+ return this.#c.req.header(name)
107
+ }
108
+
109
+ param(key?: string) { // @ts-ignore
110
+ return this.#c.req.param(key)
111
+ }
112
+
113
+ query(): Record<string, string>
114
+ query(key: string): string | undefined
115
+ query(key?: string) { // @ts-ignore
116
+ return this.#c.req.query(key)
117
+ }
118
+
119
+ queries(): Record<string, string[]>
120
+ queries(key: string):string[] | undefined
121
+ queries(key?: string) { // @ts-ignore
122
+ return this.#c.req.queries(key)
123
+ }
124
+
125
+ async body<E>() {
126
+ const cType = this.#c.req.header('Content-Type')
63
127
  if (!cType) return {} as E
64
128
 
65
- if (/^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/.test(cType)) {
66
- return await Request.json<E>()
67
- }
129
+ if (/^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/.test(cType))
130
+ return await this.json<E>()
68
131
 
69
132
  if (
70
- /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/.test(cType)
71
- && ! /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/.test(cType)
133
+ cType?.startsWith('multipart/form-data')
134
+ || cType?.startsWith('application/x-www-form-urlencoded')
72
135
  ) {
73
- return await Request.form() as E
136
+ return await this.parseBody() as E
74
137
  }
75
138
 
76
139
  return {} as E
77
140
  }
78
141
 
79
- static get response() {
80
- return Response
142
+ async parseBody<Options extends Partial<ParseBodyOptions>, T extends BodyData<Options>>(
143
+ options?: Options
144
+ ): Promise<T>
145
+ async parseBody<T extends BodyData>(options?: Partial<ParseBodyOptions>): Promise<T>
146
+ async parseBody(options?: Partial<ParseBodyOptions>) {
147
+ try {
148
+ return await this.#c.req.parseBody(options)
149
+ } catch (e) {
150
+ throw new HTTPException(400, {
151
+ message: 'Malformed FormData request.'+ (e instanceof Error ? ` ${e.message}` : ` ${String(e)}`)
152
+ })
153
+ }
154
+ }
155
+
156
+ async json<E>() {
157
+ try {
158
+ return await this.#c.req.json<E>()
159
+ } catch {
160
+ throw new HTTPException(400, { message: 'Malformed JSON in request body' })
161
+ }
81
162
  }
82
163
 
83
- static get cx() {
84
- return c.cx
164
+ text() {
165
+ return this.#c.req.text()
85
166
  }
86
167
 
87
- static get cookie() {
88
- return c.cookie
168
+ arrayBuffer() {
169
+ return this.#c.req.arrayBuffer()
89
170
  }
90
171
 
91
- static get ip() {
92
- return c.ip
172
+ blob() {
173
+ return this.#c.req.blob()
93
174
  }
94
175
 
95
- static get userAgent() {
96
- return c.userAgent
176
+ formData() {
177
+ return this.#c.req.formData()
97
178
  }
98
179
  }