rajt 0.0.58 → 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.
- package/package.json +7 -7
- package/src/action-old.ts +72 -0
- package/src/action.ts +12 -61
- package/src/auth/ability.ts +2 -2
- package/src/auth/authnz.ts +3 -0
- package/src/auth/index.ts +0 -1
- package/src/auth/token.ts +27 -24
- package/src/bin/rajt.js +2 -2
- package/src/cli/commands/dev/index.ts +2 -2
- package/src/cli/commands/dev/utils.ts +12 -3
- package/src/create-app.ts +7 -7
- package/src/db/d1.d.ts +1 -0
- package/src/db/d1.ts +1 -0
- package/src/enum.ts +2 -0
- package/src/http.ts +6 -5
- package/src/index.ts +0 -2
- package/src/request-old.ts +98 -0
- package/src/request.ts +152 -71
- package/src/response.ts +71 -26
- package/src/routes.ts +66 -2
- package/src/scripts/cache-routes.ts +1 -64
- package/src/types.ts +24 -4
- package/src/utils/func.ts +1 -1
- package/src/utils/resolve.ts +2 -1
- package/src/validator.ts +68 -0
- package/src/auth/auth.ts +0 -33
- package/src/dynamodb/client.ts +0 -125
- package/src/dynamodb/compact.ts +0 -205
- package/src/dynamodb/decorators.ts +0 -126
- package/src/dynamodb/index.ts +0 -4
- package/src/dynamodb/model.ts +0 -258
- package/src/dynamodb/query-builder.ts +0 -174
- package/src/dynamodb/repository.ts +0 -31
- package/src/dynamodb/schema.ts +0 -107
- package/src/dynamodb/types.ts +0 -32
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rajt",
|
|
3
3
|
"description": "A serverless bundler layer, fully typed for AWS Lambda (Node.js and LLRT) and Cloudflare Workers.",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.59",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./src/index.ts",
|
|
12
12
|
"./auth": "./src/auth/index.ts",
|
|
13
|
-
"./
|
|
14
|
-
"./
|
|
13
|
+
"./d1": "./src/db/d1.ts",
|
|
14
|
+
"./d1/types": "./src/db.d.ts",
|
|
15
|
+
"./dynamodb": "./src/db/dynamodb.ts",
|
|
16
|
+
"./dynamodb/types": "./src/db/dynamodb.d.ts",
|
|
17
|
+
"./enum": "./src/enum.ts",
|
|
15
18
|
"./http": "./src/http.ts",
|
|
16
19
|
"./types": "./src/types.ts",
|
|
17
20
|
"./env": "./src/utils/environment.ts",
|
|
@@ -48,12 +51,10 @@
|
|
|
48
51
|
"start": "node ../../dist/index.js"
|
|
49
52
|
},
|
|
50
53
|
"dependencies": {
|
|
51
|
-
"@aws-sdk/client-dynamodb": "3.817.0",
|
|
52
|
-
"@aws-sdk/lib-dynamodb": "3.817.0",
|
|
53
54
|
"@hono/zod-validator": "^0.4.3",
|
|
54
55
|
"cripta": "^0.1",
|
|
56
|
+
"forj": "^0.0.2",
|
|
55
57
|
"hono": "^4.7.6",
|
|
56
|
-
"pluralize": "^8.0",
|
|
57
58
|
"t0n": "^0.1.5",
|
|
58
59
|
"ua-parser-js": "^2.0.4"
|
|
59
60
|
},
|
|
@@ -71,7 +72,6 @@
|
|
|
71
72
|
"@miniflare/storage-file": "^2.14.4",
|
|
72
73
|
"@miniflare/web-sockets": "^2.14.4",
|
|
73
74
|
"@types/node": "^20.11.0",
|
|
74
|
-
"@types/pluralize": "^0.0.33",
|
|
75
75
|
"bun-types": "^1.2.14",
|
|
76
76
|
"chokidar-cli": "^3.0.0",
|
|
77
77
|
"citty": "^0.1.6",
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// import { Context, Handler, HonoRequest, MiddlewareHandler, Next, ValidationTargets } from 'hono'
|
|
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'
|
|
6
|
+
import response from './response'
|
|
7
|
+
import cx from './context'
|
|
8
|
+
|
|
9
|
+
export type ActionType = Function | Handler | Action | (new () => Action)
|
|
10
|
+
|
|
11
|
+
type RuleDefinition = {
|
|
12
|
+
schema: z.ZodObject<any>
|
|
13
|
+
target: keyof ValidationTargets
|
|
14
|
+
eTarget?: 'fieldErrors' | 'formErrors'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default class Action {
|
|
18
|
+
static rule<T extends keyof ValidationTargets>(target: T): { schema: (schema: ZodObject<any>) => RuleDefinition }
|
|
19
|
+
static rule<T extends keyof ValidationTargets>(target: T, schema: ZodObject<any>): RuleDefinition
|
|
20
|
+
static rule<T extends keyof ValidationTargets>(target: T, schema?: ZodObject<any>):
|
|
21
|
+
| { schema: (schema: ZodObject<any>) => RuleDefinition }
|
|
22
|
+
| RuleDefinition
|
|
23
|
+
{
|
|
24
|
+
if (schema !== undefined) {
|
|
25
|
+
return {
|
|
26
|
+
target,
|
|
27
|
+
schema,
|
|
28
|
+
eTarget: 'fieldErrors' // | 'formErrors'
|
|
29
|
+
} satisfies RuleDefinition
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
schema: (schema: ZodObject<any>) => ({
|
|
34
|
+
target,
|
|
35
|
+
schema,
|
|
36
|
+
eTarget: 'fieldErrors' // | 'formErrors'
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static validate() {
|
|
42
|
+
const rules = this.rules()
|
|
43
|
+
const h = async (c: Context) => {
|
|
44
|
+
return await this.handle(cx.cx)
|
|
45
|
+
}
|
|
46
|
+
if (!rules) return [h]
|
|
47
|
+
|
|
48
|
+
const rulesArray: Function[] = (Array.isArray(rules) ? rules : [rules])
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
.map(rule => zValidator(rule.target, rule.schema, (result, c) => {
|
|
51
|
+
if (!result.success) {
|
|
52
|
+
// @ts-ignore
|
|
53
|
+
return response.badRequest({ ...result.error.flatten()[rule.eTarget] })
|
|
54
|
+
}
|
|
55
|
+
}))
|
|
56
|
+
|
|
57
|
+
rulesArray.push(h)
|
|
58
|
+
return rulesArray
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static run() {
|
|
62
|
+
return this.validate()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static rules(): RuleDefinition[] | RuleDefinition | null {
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static async handle(c: Context): Promise<Response> {
|
|
70
|
+
return Promise.resolve(response.raw(200, 'Action handle not implemented'))
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/action.ts
CHANGED
|
@@ -1,72 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { Context,
|
|
4
|
-
import { z, ZodObject } from 'zod'
|
|
5
|
-
import { zValidator } from '@hono/zod-validator'
|
|
6
|
-
import Response from './response'
|
|
7
|
-
import cx from './context'
|
|
8
|
-
|
|
9
|
-
export type ActionType = Function | Handler | Action | (new () => Action)
|
|
10
|
-
|
|
11
|
-
type RuleDefinition = {
|
|
12
|
-
schema: z.ZodObject<any>
|
|
13
|
-
target: keyof ValidationTargets
|
|
14
|
-
eTarget?: 'fieldErrors' | 'formErrors'
|
|
15
|
-
}
|
|
1
|
+
import response from './response'
|
|
2
|
+
import validator from './validator'
|
|
3
|
+
import type { Context, IRequest, IResponse, IValidator, Rules } from './types'
|
|
16
4
|
|
|
17
5
|
export default class Action {
|
|
18
|
-
static
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
| { schema: (schema: ZodObject<any>) => RuleDefinition }
|
|
22
|
-
| RuleDefinition
|
|
23
|
-
{
|
|
24
|
-
if (schema !== undefined) {
|
|
25
|
-
return {
|
|
26
|
-
target,
|
|
27
|
-
schema,
|
|
28
|
-
eTarget: 'fieldErrors' // | 'formErrors'
|
|
29
|
-
} satisfies RuleDefinition
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
schema: (schema: ZodObject<any>) => ({
|
|
34
|
-
target,
|
|
35
|
-
schema,
|
|
36
|
-
eTarget: 'fieldErrors' // | 'formErrors'
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
static validate() {
|
|
42
|
-
const rules = this.rules()
|
|
43
|
-
const h = async (c: Context) => {
|
|
44
|
-
return await this.handle(cx.cx)
|
|
45
|
-
}
|
|
6
|
+
static run() {
|
|
7
|
+
const rules = this.rules(validator)
|
|
8
|
+
const h = async (c: Context) => await this.handle(c.get('_'), response)
|
|
46
9
|
if (!rules) return [h]
|
|
47
10
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (!result.success) {
|
|
52
|
-
// @ts-ignore
|
|
53
|
-
return Response.badRequest({ ...result.error.flatten()[rule.eTarget] })
|
|
54
|
-
}
|
|
55
|
-
}))
|
|
56
|
-
|
|
57
|
-
rulesArray.push(h)
|
|
58
|
-
return rulesArray
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
static run() {
|
|
62
|
-
return this.validate()
|
|
11
|
+
const pipe = validator.parse(rules)
|
|
12
|
+
pipe.push(h)
|
|
13
|
+
return pipe
|
|
63
14
|
}
|
|
64
15
|
|
|
65
|
-
static rules():
|
|
16
|
+
static rules(v: IValidator): Rules {
|
|
66
17
|
return null
|
|
67
18
|
}
|
|
68
19
|
|
|
69
|
-
static async handle(
|
|
70
|
-
return Promise.resolve(
|
|
20
|
+
static async handle(req: IRequest, res: IResponse): Promise<Response> {
|
|
21
|
+
return Promise.resolve(res.raw(200, 'Action handle not implemented'))
|
|
71
22
|
}
|
|
72
23
|
}
|
package/src/auth/ability.ts
CHANGED
|
@@ -16,8 +16,8 @@ export class Ability {
|
|
|
16
16
|
const paths = actions?.map(a => Array.isArray(a) ? a[0] + a[1] : a.method + a.path) || []
|
|
17
17
|
const items = new Set(paths)
|
|
18
18
|
|
|
19
|
-
if (items.size
|
|
20
|
-
throw new Error(`Duplicate routes detected: "${paths.filter((path, index) => paths.indexOf(path)
|
|
19
|
+
if (items.size != actions.length)
|
|
20
|
+
throw new Error(`Duplicate routes detected: "${paths.filter((path, index) => paths.indexOf(path) != index).join('", "')}"`)
|
|
21
21
|
|
|
22
22
|
this.#abilities = Array.from(new Set(actions?.map(a => Array.isArray(a) ? a[3] : a.name) || []))
|
|
23
23
|
.map(a => this.format(a))
|
package/src/auth/authnz.ts
CHANGED
package/src/auth/index.ts
CHANGED
package/src/auth/token.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { Envir } from 't0n'
|
|
2
2
|
import { Token as Factory } from 'cripta'
|
|
3
3
|
import { UAParser } from 'ua-parser-js'
|
|
4
|
-
import
|
|
4
|
+
import type { IRequest } from '@/types'
|
|
5
5
|
|
|
6
6
|
export class Token {
|
|
7
|
+
static #cookieName: string = '__auth_'
|
|
7
8
|
static #name: string = 'Authorization'
|
|
8
9
|
static #prefix: string = 'bearer'
|
|
9
10
|
|
|
10
|
-
static fromRequest() {
|
|
11
|
-
const token = this.fromCookie() || this.fromHeader()
|
|
12
|
-
return token ? this.parse(token) : null
|
|
11
|
+
static fromRequest(req: IRequest) {
|
|
12
|
+
const token = this.fromCookie(req) || this.fromHeader(req)
|
|
13
|
+
return token ? this.parse(req, token) : null
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
static fromHeader(): string | null {
|
|
16
|
-
const header =
|
|
16
|
+
static fromHeader(req: IRequest): string | null {
|
|
17
|
+
const header = req.header(this.#name) || req.header('HTTP_AUTHORIZATION') || req.header('REDIRECT_HTTP_AUTHORIZATION') || null
|
|
17
18
|
|
|
18
19
|
if (header) {
|
|
19
20
|
const pos = header.toLowerCase().indexOf(this.#prefix.toLowerCase())
|
|
@@ -29,39 +30,39 @@ export class Token {
|
|
|
29
30
|
return null
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
static fromCookie(): string | null {
|
|
33
|
-
const uid =
|
|
33
|
+
static fromCookie(req: IRequest): string | null {
|
|
34
|
+
const uid = req.header('uid')
|
|
34
35
|
|
|
35
36
|
if (uid) {
|
|
36
|
-
const auth =
|
|
37
|
+
const auth = req.cookie.get(this.#cookieName + uid)
|
|
37
38
|
return auth ? auth : null
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
return null
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
static parse(token: string) {
|
|
44
|
-
const host = this.host()
|
|
44
|
+
static parse(req: IRequest, token: string) {
|
|
45
|
+
const host = this.host(req)
|
|
45
46
|
const serveHost = Envir.get('FLOW_SERVER', host) as string
|
|
46
47
|
|
|
47
48
|
return Factory.parse(token)
|
|
48
49
|
.issuedBy(serveHost)
|
|
49
50
|
.permittedFor(host)
|
|
50
|
-
.withClaim('u', this.userAgent())
|
|
51
|
-
.withClaim('i', this.ip())
|
|
51
|
+
.withClaim('u', this.userAgent(req))
|
|
52
|
+
.withClaim('i', this.ip(req))
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
static create(user: any, exp: number = 7200) {
|
|
55
|
+
static create(req: IRequest, user: any, exp: number = 7200) {
|
|
55
56
|
const time = Math.floor(Date.now() / 1000)
|
|
56
|
-
const host = this.host(
|
|
57
|
+
const host = this.host(req)
|
|
57
58
|
|
|
58
59
|
return Factory.create()
|
|
59
60
|
.issuedBy(host)
|
|
60
61
|
.permittedFor(host)
|
|
61
62
|
.issuedAt(time)
|
|
62
63
|
.expiresAt(time + exp)
|
|
63
|
-
.withClaim('u', this.userAgent())
|
|
64
|
-
.withClaim('i', this.ip())
|
|
64
|
+
.withClaim('u', this.userAgent(req))
|
|
65
|
+
.withClaim('i', this.ip(req))
|
|
65
66
|
.body(user)
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -73,8 +74,9 @@ export class Token {
|
|
|
73
74
|
this.#name = name
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
static host(
|
|
77
|
-
|
|
77
|
+
static host(req: IRequest): string {
|
|
78
|
+
const url = req.url || req.header('host')
|
|
79
|
+
if (!url) return ''
|
|
78
80
|
|
|
79
81
|
let formattedUrl = String(url)
|
|
80
82
|
if (!formattedUrl.startsWith('http'))
|
|
@@ -88,13 +90,14 @@ export class Token {
|
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
92
|
|
|
91
|
-
static userAgent() {
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
static userAgent(req: IRequest) {
|
|
94
|
+
const ua = req?.userAgent
|
|
95
|
+
if (!ua) return 0
|
|
96
|
+
const { browser, device, os } = UAParser(ua)
|
|
94
97
|
return (browser?.name || '') + (browser?.major || '') + (device?.model || '') + (os?.name || '')
|
|
95
98
|
}
|
|
96
99
|
|
|
97
|
-
static ip() {
|
|
98
|
-
return
|
|
100
|
+
static ip(req: IRequest) {
|
|
101
|
+
return req?.ip || 0
|
|
99
102
|
}
|
|
100
103
|
}
|
package/src/bin/rajt.js
CHANGED
|
@@ -35,7 +35,7 @@ Consider using a Node.js version manager such as https://volta.sh or https://git
|
|
|
35
35
|
|
|
36
36
|
let tsxPath;
|
|
37
37
|
for (const pathOption of tsxPaths) {
|
|
38
|
-
if (pathOption
|
|
38
|
+
if (pathOption == "tsx" || existsSync(pathOption)) {
|
|
39
39
|
tsxPath = pathOption;
|
|
40
40
|
break;
|
|
41
41
|
}
|
|
@@ -72,7 +72,7 @@ Consider using a Node.js version manager such as https://volta.sh or https://git
|
|
|
72
72
|
}
|
|
73
73
|
)
|
|
74
74
|
.on("exit", (code) =>
|
|
75
|
-
process.exit(code
|
|
75
|
+
process.exit(code == null ? 0 : code)
|
|
76
76
|
)
|
|
77
77
|
.on("message", (message) => {
|
|
78
78
|
if (process.send) {
|
|
@@ -103,7 +103,7 @@ export default defineCommand({
|
|
|
103
103
|
}
|
|
104
104
|
).on('exit', code => {
|
|
105
105
|
logger.step(`Lambda process exited with code ${code ?? 0}`)
|
|
106
|
-
if (code
|
|
106
|
+
if (code != 0 && code != null)
|
|
107
107
|
logger.error('Lambda process crashed, waiting for restart...')
|
|
108
108
|
|
|
109
109
|
lambda = null
|
|
@@ -277,7 +277,7 @@ async function wait(ms: number) {
|
|
|
277
277
|
function getDockerHost() {
|
|
278
278
|
const platform = process.platform
|
|
279
279
|
|
|
280
|
-
if (platform
|
|
280
|
+
if (platform == 'darwin') {
|
|
281
281
|
for (const socket of [
|
|
282
282
|
'/Users/'+ process.env.USER +'/.docker/run/docker.sock',
|
|
283
283
|
'/var/run/docker.sock',
|
|
@@ -6,6 +6,8 @@ import { mkdirSync, existsSync, readdirSync, rmSync, copyFileSync } from 'node:f
|
|
|
6
6
|
import { readFile, stat, writeFile } from 'node:fs/promises'
|
|
7
7
|
import { basename, dirname, join, relative } from 'node:path'
|
|
8
8
|
|
|
9
|
+
import { cacheRoutes } from '../../../routes'
|
|
10
|
+
|
|
9
11
|
const __dirname = join(dirname(fileURLToPath(import.meta.url)), '../../../../../../')
|
|
10
12
|
const __rajt = join(__dirname, 'node_modules/rajt/src')
|
|
11
13
|
|
|
@@ -113,6 +115,10 @@ export const build = async (platform: 'aws' | 'cf' | 'node') => {
|
|
|
113
115
|
],
|
|
114
116
|
}
|
|
115
117
|
|
|
118
|
+
await cacheRoutes()
|
|
119
|
+
|
|
120
|
+
logger.step('Routes cached')
|
|
121
|
+
|
|
116
122
|
const result = await esbuild.build(opts)
|
|
117
123
|
if (!result?.metafile) throw Error('build fail')
|
|
118
124
|
|
|
@@ -164,10 +170,13 @@ export async function createMiniflare(options = {}, configPath = 'wrangler.toml'
|
|
|
164
170
|
|
|
165
171
|
d1Databases: Object.fromEntries(config.d1_databases.map(db => [db.binding, db.database_id])),
|
|
166
172
|
|
|
167
|
-
modules:
|
|
168
|
-
|
|
169
|
-
{ type: 'ESModule', include: ['**/*.js', '**/*.ts'] },
|
|
173
|
+
modules: [
|
|
174
|
+
{ type: "ESModule", path: "dist/index.js" },
|
|
170
175
|
],
|
|
176
|
+
// modules: true,
|
|
177
|
+
// modulesRules: [
|
|
178
|
+
// { type: 'ESModule', include: ['**/*.js', '**/*.ts'] },
|
|
179
|
+
// ],
|
|
171
180
|
|
|
172
181
|
kvPersist: join(__dirname, '.wrangler/state/v3/kv'),
|
|
173
182
|
cachePersist: join(__dirname, '.wrangler/state/v3/cache'),
|
package/src/create-app.ts
CHANGED
|
@@ -7,15 +7,15 @@ import type { Env, Context, ErrorHandler, NotFoundHandler, Next } from 'hono'
|
|
|
7
7
|
// import type { H, Handler, HandlerResponse } from 'hono/types'
|
|
8
8
|
import type { HTTPResponseError } from 'hono/types'
|
|
9
9
|
import colors from 'picocolors'
|
|
10
|
+
import { Envir } from 't0n'
|
|
10
11
|
import type { Routes } from './types'
|
|
11
12
|
import { BadRequest, Unauthorized } from './exceptions'
|
|
12
13
|
import { resolve, resolveMiddleware } from './utils/resolve'
|
|
13
14
|
import { getMiddlewares, getHandler } from './register'
|
|
14
15
|
import { isDev } from './utils/environment'
|
|
15
16
|
import localDate from './utils/local-date'
|
|
16
|
-
import
|
|
17
|
+
import request from './request'
|
|
17
18
|
import response from './response'
|
|
18
|
-
import cx from './context'
|
|
19
19
|
|
|
20
20
|
type InitFunction<E extends Env = Env> = (app: Hono<E>) => void
|
|
21
21
|
|
|
@@ -40,7 +40,7 @@ const EHandler = async (e: Error | HTTPResponseError) => {
|
|
|
40
40
|
case e instanceof BadRequest:
|
|
41
41
|
case 'status' in e && e.status == 400:
|
|
42
42
|
// @ts-ignore
|
|
43
|
-
return response.badRequest(
|
|
43
|
+
return response.badRequest(null, e?.message)
|
|
44
44
|
|
|
45
45
|
default:
|
|
46
46
|
return response.internalError(
|
|
@@ -85,12 +85,12 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
|
85
85
|
app.use('*', logger((...args: any[]) => console.log(colors.gray(localDate()), ...args)))
|
|
86
86
|
|
|
87
87
|
app.use(async (c: Context, next: Next) => {
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
c.set('_', new request(c))
|
|
89
|
+
if (c.env) Envir.add(c.env)
|
|
90
90
|
await next()
|
|
91
91
|
})
|
|
92
92
|
getMiddlewares().forEach(mw => {
|
|
93
|
-
const h = async (c: Context, next: Next) => await resolveMiddleware(mw)(
|
|
93
|
+
const h = async (c: Context, next: Next) => await resolveMiddleware(mw)(c.get('_'), next)
|
|
94
94
|
// @ts-ignore
|
|
95
95
|
mw?.path ? app.use(String(mw.path), h) : app.use(h)
|
|
96
96
|
})
|
|
@@ -117,7 +117,7 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
|
117
117
|
|
|
118
118
|
function mw(...objs: string[]): Function[] {
|
|
119
119
|
return objs.flatMap(obj => {
|
|
120
|
-
if (typeof obj
|
|
120
|
+
if (typeof obj != 'string') return null
|
|
121
121
|
// @ts-ignore
|
|
122
122
|
return getHandler(obj)?.mw || null
|
|
123
123
|
}).flat().filter(Boolean)
|
package/src/db/d1.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'forj/d1/types'
|
package/src/db/d1.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'forj/d1'
|
package/src/enum.ts
ADDED
package/src/http.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Context, Next } from 'hono'
|
|
2
2
|
import { MiddlewareType } from './middleware'
|
|
3
|
-
import
|
|
4
|
-
import { Ability
|
|
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
9
|
if (args.length == 1 && typeof args[0] == 'function')
|
|
@@ -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
|
|
105
|
+
const req = c.get('_') as IRequest
|
|
105
106
|
const ability = Ability.fromAction(target)
|
|
106
107
|
|
|
107
|
-
if (!user || !ability ||
|
|
108
|
-
return
|
|
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
4
|
export { Enum } from 't0n'
|
|
@@ -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
|
+
}
|