rajt 0.0.28 → 0.0.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.
- package/package.json +1 -1
- package/src/action.ts +34 -28
- package/src/create-app.ts +12 -26
- package/src/register.ts +5 -16
- package/src/response.ts +31 -39
- package/src/utils/resolve.ts +4 -4
package/package.json
CHANGED
package/src/action.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Context, Handler, HonoRequest, MiddlewareHandler, Next, ValidationTargets } from 'hono'
|
|
2
|
-
import { z, ZodObject, ZodRawShape } from 'zod'
|
|
3
|
-
import { zValidator } from '@hono/zod-validator'
|
|
1
|
+
// import { Context, Handler, HonoRequest, MiddlewareHandler, Next, ValidationTargets } from 'hono'
|
|
4
2
|
// import { JSONValue } from 'hono/utils/types'
|
|
3
|
+
import { Context, Handler, ValidationTargets } from 'hono'
|
|
4
|
+
import { z, ZodObject } from 'zod'
|
|
5
|
+
import { zValidator } from '@hono/zod-validator'
|
|
5
6
|
import JsonResponse from './response'
|
|
6
7
|
import { bufferToFormData } from 'hono/utils/buffer'
|
|
7
8
|
import { HTTPException } from 'hono/http-exception'
|
|
@@ -16,15 +17,8 @@ type RuleDefinition = {
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export default abstract class Action {
|
|
19
|
-
protected context!: Context
|
|
20
|
-
protected errorTarget!: string
|
|
21
|
-
protected rules(): RuleDefinition[] | RuleDefinition | null {
|
|
22
|
-
return null
|
|
23
|
-
}
|
|
24
|
-
|
|
25
20
|
rule<T extends keyof ValidationTargets>(target: T): { schema: (schema: ZodObject<any>) => RuleDefinition }
|
|
26
21
|
rule<T extends keyof ValidationTargets>(target: T, schema: ZodObject<any>): RuleDefinition
|
|
27
|
-
|
|
28
22
|
rule<T extends keyof ValidationTargets>(target: T, schema?: ZodObject<any>):
|
|
29
23
|
| { schema: (schema: ZodObject<any>) => RuleDefinition }
|
|
30
24
|
| RuleDefinition
|
|
@@ -47,26 +41,26 @@ export default abstract class Action {
|
|
|
47
41
|
}
|
|
48
42
|
|
|
49
43
|
param(key: string) {
|
|
50
|
-
return this.
|
|
44
|
+
return this.cx.req.param(key)
|
|
51
45
|
}
|
|
52
46
|
|
|
53
47
|
query() {
|
|
54
|
-
return this.
|
|
48
|
+
return this.cx.req.query()
|
|
55
49
|
}
|
|
56
50
|
|
|
57
51
|
async form(cType?: string) {
|
|
58
|
-
cType ??= this.
|
|
52
|
+
cType ??= this.cx.req.header('Content-Type')
|
|
59
53
|
if (!cType) return {}
|
|
60
54
|
|
|
61
55
|
let formData: FormData
|
|
62
56
|
|
|
63
|
-
if (this.
|
|
64
|
-
formData = await this.
|
|
57
|
+
if (this.cx.req.bodyCache.formData) {
|
|
58
|
+
formData = await this.cx.req.bodyCache.formData
|
|
65
59
|
} else {
|
|
66
60
|
try {
|
|
67
|
-
const arrayBuffer = await this.
|
|
61
|
+
const arrayBuffer = await this.cx.req.arrayBuffer()
|
|
68
62
|
formData = await bufferToFormData(arrayBuffer, cType)
|
|
69
|
-
this.
|
|
63
|
+
this.cx.req.bodyCache.formData = formData
|
|
70
64
|
} catch (e) {
|
|
71
65
|
throw new HTTPException(400, {
|
|
72
66
|
message: 'Malformed FormData request.'
|
|
@@ -93,14 +87,14 @@ export default abstract class Action {
|
|
|
93
87
|
|
|
94
88
|
async json<E>() {
|
|
95
89
|
try {
|
|
96
|
-
return await this.
|
|
90
|
+
return await this.cx.req.json<E>()
|
|
97
91
|
} catch {
|
|
98
92
|
throw new HTTPException(400, { message: 'Malformed JSON in request body' })
|
|
99
93
|
}
|
|
100
94
|
}
|
|
101
95
|
|
|
102
96
|
async body<E>() {
|
|
103
|
-
const cType = this.
|
|
97
|
+
const cType = this.cx.req.header('Content-Type')
|
|
104
98
|
if (!cType) return {} as E
|
|
105
99
|
|
|
106
100
|
if (/^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/.test(cType)) {
|
|
@@ -118,14 +112,21 @@ export default abstract class Action {
|
|
|
118
112
|
}
|
|
119
113
|
|
|
120
114
|
get response() {
|
|
121
|
-
return
|
|
115
|
+
return JsonResponse
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get cx() {
|
|
119
|
+
return JsonResponse.cx
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
get cookie() {
|
|
123
|
+
return JsonResponse.cookie
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
validate() {
|
|
125
127
|
const rules = this.rules()
|
|
126
128
|
const h = async (c: Context) => {
|
|
127
|
-
this.
|
|
128
|
-
return await this.handle(c)
|
|
129
|
+
return await this.handle(this.cx)
|
|
129
130
|
}
|
|
130
131
|
if (!rules) return [h]
|
|
131
132
|
|
|
@@ -138,17 +139,22 @@ export default abstract class Action {
|
|
|
138
139
|
}))
|
|
139
140
|
|
|
140
141
|
rulesArray.push(h)
|
|
141
|
-
|
|
142
142
|
return rulesArray
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
run() {
|
|
146
|
+
return this.validate()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// PUBLIC API
|
|
150
|
+
|
|
145
151
|
get auth() {
|
|
146
|
-
const auth = this.
|
|
152
|
+
const auth = this.cx.get('#auth')
|
|
147
153
|
return auth ? auth?.data : null
|
|
148
154
|
}
|
|
149
155
|
|
|
150
156
|
can(...abilities: string[]): boolean {
|
|
151
|
-
const auth = this.
|
|
157
|
+
const auth = this.cx.get('#auth')
|
|
152
158
|
return auth ? auth.can(...abilities) : false
|
|
153
159
|
}
|
|
154
160
|
|
|
@@ -157,12 +163,12 @@ export default abstract class Action {
|
|
|
157
163
|
}
|
|
158
164
|
|
|
159
165
|
hasRole(...roles: string[]): boolean {
|
|
160
|
-
const auth = this.
|
|
166
|
+
const auth = this.cx.get('#auth')
|
|
161
167
|
return auth ? auth.hasRole(...roles) : false
|
|
162
168
|
}
|
|
163
169
|
|
|
164
|
-
|
|
165
|
-
return
|
|
170
|
+
rules(): RuleDefinition[] | RuleDefinition | null {
|
|
171
|
+
return null
|
|
166
172
|
}
|
|
167
173
|
|
|
168
174
|
abstract handle(c: Context): Promise<Response>
|
package/src/create-app.ts
CHANGED
|
@@ -38,11 +38,6 @@ const EHandler = async (e: Error | HTTPResponseError) => {
|
|
|
38
38
|
// @ts-ignore
|
|
39
39
|
return response.badRequest(undefined, e?.message)
|
|
40
40
|
|
|
41
|
-
// case e.message.includes('Not Found'):
|
|
42
|
-
// // @ts-ignore
|
|
43
|
-
// case e?.status === 404:
|
|
44
|
-
// return json.notFound();
|
|
45
|
-
|
|
46
41
|
default:
|
|
47
42
|
return response.internalError(
|
|
48
43
|
// @ts-ignore
|
|
@@ -54,14 +49,11 @@ const EHandler = async (e: Error | HTTPResponseError) => {
|
|
|
54
49
|
if (!path) return match
|
|
55
50
|
|
|
56
51
|
const nodeModulesIndex = path.indexOf('node_modules')
|
|
57
|
-
if (nodeModulesIndex > -1)
|
|
52
|
+
if (nodeModulesIndex > -1)
|
|
58
53
|
return `${method || ''}(node_modules${path.slice(nodeModulesIndex + 'node_modules'.length)})`
|
|
59
|
-
}
|
|
60
54
|
|
|
61
55
|
const projectRoot = process.cwd()
|
|
62
|
-
const relativePath = path.startsWith(projectRoot)
|
|
63
|
-
? path.slice(projectRoot.length + 1)
|
|
64
|
-
: path
|
|
56
|
+
const relativePath = path.startsWith(projectRoot) ? path.slice(projectRoot.length + 1) : path
|
|
65
57
|
return `${method || ''}(${relativePath})`
|
|
66
58
|
}
|
|
67
59
|
).trim()
|
|
@@ -77,7 +69,7 @@ const EHandler = async (e: Error | HTTPResponseError) => {
|
|
|
77
69
|
// e.message || 'Internal Error'
|
|
78
70
|
// )
|
|
79
71
|
// error: e.message,
|
|
80
|
-
// cause: e.cause || '
|
|
72
|
+
// cause: e.cause || '???',
|
|
81
73
|
// stack: isDev ? e.stack : undefined
|
|
82
74
|
}
|
|
83
75
|
|
|
@@ -85,16 +77,12 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
|
85
77
|
// const root = options?.root ?? '/'
|
|
86
78
|
const app = options?.app ?? new Hono<E>()
|
|
87
79
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
]
|
|
95
|
-
middlewares.forEach(mw => {
|
|
96
|
-
// @ts-ignore
|
|
97
|
-
const h = resolveMiddleware(mw)
|
|
80
|
+
app.use(async (c: Context, next: Next) => {
|
|
81
|
+
response.setContext(c)
|
|
82
|
+
await next()
|
|
83
|
+
})
|
|
84
|
+
getMiddlewares().forEach(mw => {
|
|
85
|
+
const h = async (c: Context, next: Next) => await resolveMiddleware(mw)(response.cx, next)
|
|
98
86
|
// @ts-ignore
|
|
99
87
|
mw?.path ? app.use(String(mw.path), h) : app.use(h)
|
|
100
88
|
})
|
|
@@ -102,18 +90,16 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
|
102
90
|
app.onError(options?.onError || EHandler)
|
|
103
91
|
app.notFound(options?.notFound || NFHandler)
|
|
104
92
|
|
|
105
|
-
if (options?.init)
|
|
106
|
-
options.init(app)
|
|
93
|
+
if (options?.init) options.init(app)
|
|
107
94
|
|
|
108
95
|
const routes = options?.routes || []
|
|
109
96
|
for (const route of routes) {
|
|
110
97
|
if (Array.isArray(route)) {
|
|
111
|
-
const handle = getHandler(route[3])
|
|
112
98
|
// @ts-ignore
|
|
113
|
-
app[route[0]](route[1], ...mw(route[2], route[3]), ...resolve(
|
|
99
|
+
app[route[0]](route[1], ...mw(route[2], route[3]), ...resolve(getHandler(route[3]), route[3]))
|
|
114
100
|
} else {
|
|
115
101
|
// @ts-ignore
|
|
116
|
-
app[route.method](route.path, ...mw(route.middlewares, route.name), ...resolve(route.handle))
|
|
102
|
+
app[route.method](route.path, ...mw(route.middlewares, route.name), ...resolve(route.handle, route.name))
|
|
117
103
|
}
|
|
118
104
|
}
|
|
119
105
|
|
package/src/register.ts
CHANGED
|
@@ -1,24 +1,13 @@
|
|
|
1
|
-
export const handlers = {}
|
|
1
|
+
export const handlers: Record<string, Function> = {}
|
|
2
2
|
|
|
3
3
|
export function registerHandler(id: string, handler: any) {
|
|
4
|
-
if (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const instance = new handler()
|
|
9
|
-
// @ts-ignore
|
|
10
|
-
handlers[id] = instance.handle.bind(instance)
|
|
11
|
-
} else if (handler.run) {
|
|
12
|
-
const instance = new handler()
|
|
13
|
-
// @ts-ignore
|
|
14
|
-
handlers[id] = instance.run.bind(instance)
|
|
15
|
-
} else {
|
|
16
|
-
console.warn(`Handler ${id} could not be registered - unsupported type`)
|
|
17
|
-
}
|
|
4
|
+
if (id in handlers)
|
|
5
|
+
console.warn(`Handler "${id}" has already been registered`)
|
|
6
|
+
|
|
7
|
+
handlers[id] = handler
|
|
18
8
|
}
|
|
19
9
|
|
|
20
10
|
export function getHandler(id: string): Function {
|
|
21
|
-
// @ts-ignore
|
|
22
11
|
const handler = handlers[id] || null
|
|
23
12
|
if (!handler) throw new Error(`Handler ${id} not registered`)
|
|
24
13
|
return handler
|
package/src/response.ts
CHANGED
|
@@ -1,43 +1,39 @@
|
|
|
1
1
|
import { Context } from 'hono'
|
|
2
|
-
import { ContentfulStatusCode, StatusCode } from 'hono/utils/http-status'
|
|
3
|
-
import { ErrorResponse, Errors
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// newResponse(body?: any, init?: ResponseOrInit<StatusCode>): Response {
|
|
17
|
-
// return new Response(body ?? null, typeof init === 'number' ? {status: init} : init ?? {status: 500})
|
|
18
|
-
// }
|
|
19
|
-
// json(json: JSONValue | {} | InvalidJSONValue, status: ContentfulStatusCode = 500): Response {
|
|
20
|
-
// return new Response(JSON.stringify(json), {
|
|
21
|
-
// status,
|
|
22
|
-
// headers: { 'Content-Type': 'application/json' }
|
|
23
|
-
// })
|
|
24
|
-
// }
|
|
25
|
-
}
|
|
2
|
+
import type { ContentfulStatusCode, StatusCode } from 'hono/utils/http-status'
|
|
3
|
+
import { ErrorResponse, Errors } from './types'
|
|
4
|
+
import { getCookie, getSignedCookie, setCookie, setSignedCookie, deleteCookie } from 'hono/cookie'
|
|
5
|
+
import type { CookieOptions, CookiePrefixOptions } from 'hono/utils/cookie'
|
|
6
|
+
|
|
7
|
+
const cookieWrapper = (c: Context) => ({
|
|
8
|
+
all: () => getCookie(c),
|
|
9
|
+
allSigned: (secret: string) => getSignedCookie(c, secret),
|
|
10
|
+
get: (name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getCookie(c, name, prefixOptions) : getCookie(c, name),
|
|
11
|
+
getSigned: (secret: string, name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getSignedCookie(c, secret, name, prefixOptions) : getSignedCookie(c, secret, name),
|
|
12
|
+
set: (name: string, value: string, opt?: CookieOptions) => setCookie(c, name, value, opt),
|
|
13
|
+
setSigned: (name: string, value: string, secret: string, opt?: CookieOptions) => setSignedCookie(c, name, value, secret, opt),
|
|
14
|
+
delete: (name: string, opt?: CookieOptions) => deleteCookie(c, name, opt)
|
|
15
|
+
})
|
|
26
16
|
|
|
27
17
|
export default class JsonResponse {
|
|
28
|
-
static #c
|
|
18
|
+
static #c: Context
|
|
19
|
+
static #cookie: ReturnType<typeof cookieWrapper>
|
|
29
20
|
|
|
30
21
|
static setContext(c: Context) {
|
|
31
22
|
this.#c = c
|
|
23
|
+
this.#cookie = cookieWrapper(c)
|
|
32
24
|
return this
|
|
33
25
|
}
|
|
34
26
|
|
|
35
|
-
static
|
|
36
|
-
return this.#c
|
|
27
|
+
static get cx(): Context {
|
|
28
|
+
return this.#c
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static get cookie() {
|
|
32
|
+
return this.#cookie
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
static raw(status?: StatusCode, body?: string) {
|
|
40
|
-
return this
|
|
36
|
+
return this.cx.newResponse(body ? body : null, { status })
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
static ok(): Response
|
|
@@ -46,7 +42,7 @@ export default class JsonResponse {
|
|
|
46
42
|
if (data === undefined)
|
|
47
43
|
return this.raw(200)
|
|
48
44
|
|
|
49
|
-
return this
|
|
45
|
+
return this.cx.json(data, 200)
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
static created(): Response
|
|
@@ -55,7 +51,7 @@ export default class JsonResponse {
|
|
|
55
51
|
if (data === undefined)
|
|
56
52
|
return this.raw(201)
|
|
57
53
|
|
|
58
|
-
return this
|
|
54
|
+
return this.cx.json(data, 201)
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
static accepted(): Response
|
|
@@ -64,12 +60,10 @@ export default class JsonResponse {
|
|
|
64
60
|
if (data === undefined)
|
|
65
61
|
return this.raw(202)
|
|
66
62
|
|
|
67
|
-
return this
|
|
63
|
+
return this.cx.json(data, 202)
|
|
68
64
|
}
|
|
69
65
|
|
|
70
|
-
static deleted()
|
|
71
|
-
static deleted<T>(data: T): Response
|
|
72
|
-
static deleted<T>(data?: T) {
|
|
66
|
+
static deleted() {
|
|
73
67
|
return this.noContent()
|
|
74
68
|
}
|
|
75
69
|
|
|
@@ -88,7 +82,7 @@ export default class JsonResponse {
|
|
|
88
82
|
if (data === undefined)
|
|
89
83
|
return this.raw(401)
|
|
90
84
|
|
|
91
|
-
return this
|
|
85
|
+
return this.cx.json(data, 401)
|
|
92
86
|
}
|
|
93
87
|
|
|
94
88
|
static forbidden(): Response
|
|
@@ -97,7 +91,7 @@ export default class JsonResponse {
|
|
|
97
91
|
if (data === undefined)
|
|
98
92
|
return this.raw(403)
|
|
99
93
|
|
|
100
|
-
return this
|
|
94
|
+
return this.cx.json(data, 403)
|
|
101
95
|
}
|
|
102
96
|
|
|
103
97
|
static notFound(): Response
|
|
@@ -122,9 +116,7 @@ export default class JsonResponse {
|
|
|
122
116
|
}
|
|
123
117
|
|
|
124
118
|
static error(errors?: Errors, msg?: string, status?: ContentfulStatusCode) {
|
|
125
|
-
const context = this.#context()
|
|
126
119
|
status ??= 500
|
|
127
|
-
|
|
128
120
|
if (!errors && !msg)
|
|
129
121
|
return this.raw(status, msg)
|
|
130
122
|
|
|
@@ -132,6 +124,6 @@ export default class JsonResponse {
|
|
|
132
124
|
if (msg) resp.m = msg
|
|
133
125
|
if (errors) resp.e = errors
|
|
134
126
|
|
|
135
|
-
return
|
|
127
|
+
return this.cx.json(resp, status)
|
|
136
128
|
}
|
|
137
129
|
}
|
package/src/utils/resolve.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import Action, { ActionType } from '../action'
|
|
2
2
|
import { MiddlewareType } from '../middleware'
|
|
3
3
|
|
|
4
|
-
export function resolve(obj: ActionType) {
|
|
4
|
+
export function resolve(obj: ActionType, id: string) {
|
|
5
5
|
if (typeof obj === 'function' && obj?.length === 2)
|
|
6
6
|
return [obj]
|
|
7
7
|
|
|
8
|
-
if (obj
|
|
8
|
+
if (obj?.run)
|
|
9
9
|
return obj.run()
|
|
10
10
|
|
|
11
11
|
const instance = new (obj as new () => Action)()
|
|
12
|
-
if (
|
|
12
|
+
if (obj?.prototype?.run)
|
|
13
13
|
return instance.run()
|
|
14
14
|
|
|
15
15
|
if (obj?.prototype?.handle)
|
|
16
16
|
return [instance.handle]
|
|
17
17
|
|
|
18
|
-
throw new Error(
|
|
18
|
+
throw new Error(`Invalid action "${id}" - unsupported type`)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function resolveMiddleware(obj: MiddlewareType) {
|