rajt 0.0.99 → 0.0.100
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 +2 -2
- package/src/auth/ability.ts +1 -1
- package/src/auth/index.ts +1 -0
- package/src/auth/middlewares.ts +23 -0
- package/src/cli/commands/dev.ts +21 -14
- package/src/cli/commands/migrate.ts +1 -1
- package/src/cli/utils.ts +82 -40
- package/src/create-app.ts +10 -6
- package/src/dev.ts +2 -3
- package/src/http.ts +27 -16
- package/src/middleware.ts +4 -0
- package/src/register.ts +0 -3
- package/src/request.ts +10 -6
- package/src/routes.ts +37 -19
- package/src/types.ts +4 -1
- package/src/utils/resolve.ts +31 -26
- package/src/validator.ts +5 -5
- package/src/utils/json-import.ts +0 -14
- package/src/utils/merge-middleware.ts +0 -9
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.100",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
7
7
|
"files": ["bin", "src"],
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"chokidar": "^3.5.2",
|
|
43
43
|
"citty": "^0.1.6",
|
|
44
44
|
"consola": "^3.4.2",
|
|
45
|
-
"cripta": "^0.1.
|
|
45
|
+
"cripta": "^0.1.11",
|
|
46
46
|
"dotenv": "^16.5.0",
|
|
47
47
|
"esbuild": "^0.25.2",
|
|
48
48
|
"forj": "^0.1.8",
|
package/src/auth/ability.ts
CHANGED
|
@@ -19,7 +19,7 @@ export class Ability {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
static fromAction(target: any): string {
|
|
22
|
-
return !target ? '' : this.format(target.name.length > 3 ? target.name : (target?.p || ''))
|
|
22
|
+
return !target ? '' : this.format(typeof target == 'string' ? target : (target.name.length > 3 ? target.name : (target?.p || '')))
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
static format(path: string) {
|
package/src/auth/index.ts
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Ability } from './ability'
|
|
2
|
+
import response from '../response'
|
|
3
|
+
import { GET_REQUEST } from '../request'
|
|
4
|
+
import Config from '../config'
|
|
5
|
+
import { verbAlias } from '../http'
|
|
6
|
+
import type {
|
|
7
|
+
Context, Next,
|
|
8
|
+
IRequest,
|
|
9
|
+
} from '../types'
|
|
10
|
+
|
|
11
|
+
export async function Autorized(c: Context, next: Next) {
|
|
12
|
+
const req = c.get(GET_REQUEST as unknown as string) as IRequest
|
|
13
|
+
const ability = Ability.fromAction(Config.get(`routes.${req.routePath}$`+ verbAlias[req.method.toLowerCase()]))
|
|
14
|
+
|
|
15
|
+
if (!req?.user || !ability || req.cant(ability))
|
|
16
|
+
return response.unauthorized()
|
|
17
|
+
|
|
18
|
+
await next()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// export function Unautorized() {
|
|
22
|
+
|
|
23
|
+
// }
|
package/src/cli/commands/dev.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { spawn, type ChildProcess } from 'node:child_process'
|
|
|
3
3
|
|
|
4
4
|
import { defineCommand } from 'citty'
|
|
5
5
|
import type { Miniflare } from 'miniflare'
|
|
6
|
+
import type { WranglerConfig } from 'localflare-core'
|
|
6
7
|
import {
|
|
7
8
|
build, wait, watch, normalizePlatform, platformError, getRuntime,
|
|
8
9
|
wranglerConfig, createMiniflare, localflareManifest,
|
|
@@ -161,21 +162,12 @@ export default defineCommand({
|
|
|
161
162
|
})
|
|
162
163
|
case 'cf':
|
|
163
164
|
return withPort(desiredPort, async (port) => {
|
|
164
|
-
|
|
165
|
-
let worker: Miniflare | null = null
|
|
166
|
-
let localflare: Miniflare | null = null
|
|
167
|
-
const startWorker = async () => {
|
|
168
|
-
if (worker) await worker.dispose()
|
|
169
|
-
if (localflare) await localflare.dispose()
|
|
165
|
+
started(port)
|
|
170
166
|
|
|
171
|
-
|
|
167
|
+
let localflare: Miniflare | null = null
|
|
168
|
+
const startLocalflare = async (workerConfig: WranglerConfig) => {
|
|
169
|
+
if (localflare) return
|
|
172
170
|
|
|
173
|
-
const workerConfig = await wranglerConfig()
|
|
174
|
-
workerConfig.host = host
|
|
175
|
-
workerConfig.liveReload = false
|
|
176
|
-
|
|
177
|
-
worker = createMiniflare({ ...workerConfig, port })
|
|
178
|
-
await worker.ready
|
|
179
171
|
localflare = createMiniflare({
|
|
180
172
|
...workerConfig,
|
|
181
173
|
vars: {
|
|
@@ -185,8 +177,23 @@ export default defineCommand({
|
|
|
185
177
|
main: '.rajt/localfire.js',
|
|
186
178
|
port: 8788,
|
|
187
179
|
inspectorPort: 9230,
|
|
188
|
-
|
|
180
|
+
})
|
|
181
|
+
|
|
189
182
|
await localflare.ready
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let worker: Miniflare | null = null
|
|
186
|
+
const startWorker = async () => {
|
|
187
|
+
if (worker) await worker.dispose()
|
|
188
|
+
|
|
189
|
+
const workerConfig = await wranglerConfig() // @ts-ignore
|
|
190
|
+
workerConfig.host = host // @ts-ignore
|
|
191
|
+
workerConfig.liveReload = false
|
|
192
|
+
|
|
193
|
+
worker = createMiniflare({ ...workerConfig, port })
|
|
194
|
+
await worker.ready
|
|
195
|
+
|
|
196
|
+
if (!localflare) await startLocalflare(workerConfig)
|
|
190
197
|
}
|
|
191
198
|
|
|
192
199
|
await startApp(startWorker)
|
package/src/cli/utils.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import ts from 'typescript'
|
|
1
2
|
import esbuild from 'esbuild'
|
|
2
3
|
import { Miniflare } from 'miniflare'
|
|
3
4
|
import { mkdirSync, existsSync, statSync, readdirSync, rmSync, unlinkSync, copyFileSync, writeFileSync } from 'node:fs'
|
|
@@ -69,6 +70,52 @@ const nodeModules = [
|
|
|
69
70
|
'async_hooks', 'console', 'fsevents',
|
|
70
71
|
].flatMap(lib => ['node:'+ lib, lib])
|
|
71
72
|
|
|
73
|
+
const printer = ts.createPrinter()
|
|
74
|
+
function stripDecorators(source: string) {
|
|
75
|
+
const sourceFile = ts.createSourceFile(
|
|
76
|
+
'tmp.ts', source, ts.ScriptTarget.ESNext, false
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const transformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
|
|
80
|
+
const visit: ts.Visitor = (node) => {
|
|
81
|
+
if (ts.isClassDeclaration(node) && node.modifiers?.length) {
|
|
82
|
+
let hasDecorator = false
|
|
83
|
+
const modifiers = []
|
|
84
|
+
|
|
85
|
+
for (const m of node.modifiers) {
|
|
86
|
+
if (m.kind === ts.SyntaxKind.Decorator) {
|
|
87
|
+
hasDecorator = true
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
modifiers.push(m)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (hasDecorator) {
|
|
94
|
+
return ts.factory.updateClassDeclaration(
|
|
95
|
+
node,
|
|
96
|
+
modifiers.length ? modifiers : undefined,
|
|
97
|
+
node.name,
|
|
98
|
+
node.typeParameters,
|
|
99
|
+
node.heritageClauses,
|
|
100
|
+
node.members
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return ts.visitEachChild(node, visit, context)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return (node) => ts.visitNode(node, visit) as ts.SourceFile
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const result = ts.transform(sourceFile, [transformer])
|
|
112
|
+
const code = printer.printFile(result.transformed[0])
|
|
113
|
+
|
|
114
|
+
result.dispose()
|
|
115
|
+
|
|
116
|
+
return code
|
|
117
|
+
}
|
|
118
|
+
|
|
72
119
|
const dist = '.rajt/dist'
|
|
73
120
|
export const build = async (platform: Platform) => {
|
|
74
121
|
const startTime = Date.now()
|
|
@@ -86,6 +133,10 @@ export const build = async (platform: Platform) => {
|
|
|
86
133
|
|
|
87
134
|
if (['bun', 'vercel'].includes(platform)) platform = 'cf'
|
|
88
135
|
|
|
136
|
+
const USE_STRICT_RE = /(["'`])\s*use strict\s*\1;?/g
|
|
137
|
+
const decoder = new TextDecoder()
|
|
138
|
+
const encoder = new TextEncoder()
|
|
139
|
+
|
|
89
140
|
// @ts-ignore
|
|
90
141
|
platform = platform != 'node' ? '-'+ platform : ''
|
|
91
142
|
const opts = {
|
|
@@ -112,54 +163,45 @@ export const build = async (platform: Platform) => {
|
|
|
112
163
|
// define: {
|
|
113
164
|
// 'process.env.NODE_ENV': '"development"'
|
|
114
165
|
// },
|
|
115
|
-
// loader: {
|
|
116
|
-
// '.ts': 'ts',
|
|
117
|
-
// '.js': 'js'
|
|
118
|
-
// },
|
|
119
166
|
// tsconfig: join(_root, 'tsconfig.json'),
|
|
120
167
|
// sourcemap: true,
|
|
121
168
|
// logLevel: 'info',
|
|
122
169
|
plugins: [
|
|
123
170
|
{
|
|
124
|
-
name: 'rajt
|
|
171
|
+
name: 'rajt',
|
|
125
172
|
setup(build) {
|
|
126
173
|
build.onResolve({ filter: /\.rajt[\/\\]/ }, args => ({ path: join(_root, args.path) }))
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const result = await esbuild.transform(contents, {
|
|
137
|
-
loader: 'ts',
|
|
138
|
-
minify: true,
|
|
139
|
-
keepNames: true
|
|
140
|
-
})
|
|
141
|
-
return { contents: result.code, loader: 'ts' }
|
|
142
|
-
}
|
|
143
|
-
)
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: 'remove-use-strict',
|
|
148
|
-
setup(build) {
|
|
174
|
+
|
|
175
|
+
// strip decorators
|
|
176
|
+
build.onLoad({ filter: /\.ts$/ }, async (args) => {
|
|
177
|
+
const source = await readFile(args.path, 'utf8')
|
|
178
|
+
return { contents: stripDecorators(source), loader: 'ts' }
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
// remove "use strict"
|
|
182
|
+
const write = build.initialOptions.write
|
|
149
183
|
build.onEnd(async (result) => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
184
|
+
const files = result.outputFiles
|
|
185
|
+
if (!files) return
|
|
186
|
+
|
|
187
|
+
const tasks: Promise<void>[] = []
|
|
188
|
+
|
|
189
|
+
for (const file of files) {
|
|
190
|
+
if (!file.path.endsWith('.js')) continue
|
|
191
|
+
|
|
192
|
+
let code = decoder.decode(file.contents)
|
|
193
|
+
|
|
194
|
+
if (USE_STRICT_RE.test(code))
|
|
195
|
+
code = code.replace(USE_STRICT_RE, '')
|
|
196
|
+
|
|
197
|
+
if (write) {
|
|
198
|
+
file.contents = encoder.encode(code)
|
|
199
|
+
} else {
|
|
200
|
+
tasks.push(writeFile(file.path, code))
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (tasks.length) await Promise.all(tasks)
|
|
163
205
|
})
|
|
164
206
|
}
|
|
165
207
|
},
|
package/src/create-app.ts
CHANGED
|
@@ -7,13 +7,14 @@ import type {
|
|
|
7
7
|
HTTPResponseError,
|
|
8
8
|
ServerOptions,
|
|
9
9
|
} from './types'
|
|
10
|
-
import { resolve, resolveMiddleware
|
|
11
|
-
import { getMiddlewares
|
|
10
|
+
import { resolve, resolveMiddleware } from './utils/resolve'
|
|
11
|
+
import { getMiddlewares } from './register'
|
|
12
12
|
import request, { GET_REQUEST } from './request'
|
|
13
13
|
import response from './response'
|
|
14
14
|
import { isDev } from './utils/environment'
|
|
15
15
|
import { gray } from 't0n/color'
|
|
16
16
|
import { Route } from './types'
|
|
17
|
+
import { getVerb } from './http'
|
|
17
18
|
|
|
18
19
|
const NFHandler = () => response.notFound()
|
|
19
20
|
const EHandler = async (e: Error | HTTPResponseError) => {
|
|
@@ -96,11 +97,14 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
|
96
97
|
if (c.env) Envir.add(c.env)
|
|
97
98
|
await next()
|
|
98
99
|
})
|
|
99
|
-
|
|
100
|
+
|
|
101
|
+
const middlewares = getMiddlewares()
|
|
102
|
+
for (const mw of middlewares) {
|
|
100
103
|
const h = async (c: Context, next: Next) => await resolveMiddleware(mw)(c.get(GET_REQUEST as unknown as string), next)
|
|
101
104
|
// @ts-ignore
|
|
102
105
|
mw?.path ? app.use(String(mw.path), h) : app.use(h)
|
|
103
|
-
}
|
|
106
|
+
}
|
|
107
|
+
|
|
104
108
|
// @ts-ignore
|
|
105
109
|
app.onError(options?.onError || EHandler)
|
|
106
110
|
// @ts-ignore
|
|
@@ -111,9 +115,9 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
|
111
115
|
const routes = options?.routes || [] // @ts-ignore
|
|
112
116
|
const routeRegister = options?.routeRegister ? options.routeRegister : (_: Hono, route: Route) => { // @ts0ignore
|
|
113
117
|
if (Array.isArray(route)) { // @ts-ignore
|
|
114
|
-
_[route[0]](route[1], ...
|
|
118
|
+
_[getVerb[route[0]]](route[1], ...resolve(...route[2], route[3]))
|
|
115
119
|
} else { // @ts-ignore
|
|
116
|
-
_[route.method](route.path, ...
|
|
120
|
+
_[route.method](route.path, ...resolve(...route.middlewares), route.handle)
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
|
package/src/dev.ts
CHANGED
|
@@ -7,12 +7,11 @@ import { registerOpenAPI } from './open-api/register'
|
|
|
7
7
|
import createApp from './create-app'
|
|
8
8
|
import { Ability } from 'rajt/auth'
|
|
9
9
|
import { setEnv, detectEnvironment } from 'rajt/env'
|
|
10
|
+
import { _root } from './utils/paths'
|
|
10
11
|
|
|
11
12
|
setEnv(detectEnvironment())
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
config({ path: join(__dirname, '.env.dev') })
|
|
14
|
+
config({ path: join(_root, '.env.dev') })
|
|
16
15
|
|
|
17
16
|
Config.add(await getConfigs())
|
|
18
17
|
|
package/src/http.ts
CHANGED
|
@@ -1,14 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { GET_REQUEST } from './request'
|
|
4
|
-
import { Ability } from './auth'
|
|
5
|
-
import mergeMiddleware from './utils/merge-middleware'
|
|
1
|
+
import { Autorized } from './auth'
|
|
2
|
+
import { type MiddlewareType, mergeMiddleware } from './middleware'
|
|
6
3
|
import type {
|
|
7
|
-
Context, Next,
|
|
8
|
-
IRequest,
|
|
9
4
|
DescribeRouteOptions,
|
|
10
5
|
} from './types'
|
|
11
6
|
|
|
7
|
+
export const verbAlias = {
|
|
8
|
+
get: 0,
|
|
9
|
+
post: 1,
|
|
10
|
+
put: 2,
|
|
11
|
+
patch: 3,
|
|
12
|
+
delete: 4,
|
|
13
|
+
head: 5,
|
|
14
|
+
options: 6,
|
|
15
|
+
connect: 7,
|
|
16
|
+
trace: 8,
|
|
17
|
+
} as Record<string, number>
|
|
18
|
+
|
|
19
|
+
export const getVerb = [
|
|
20
|
+
'get',
|
|
21
|
+
'post',
|
|
22
|
+
'put',
|
|
23
|
+
'patch',
|
|
24
|
+
'delete',
|
|
25
|
+
'head',
|
|
26
|
+
'options',
|
|
27
|
+
'connect',
|
|
28
|
+
'trace',
|
|
29
|
+
]
|
|
30
|
+
|
|
12
31
|
function method(method: string, ...args: any[]): void | ClassDecorator {
|
|
13
32
|
if (args.length == 1 && typeof args[0] == 'function')
|
|
14
33
|
return _method(method, '/', args[0])
|
|
@@ -112,15 +131,7 @@ function _auth(target: Function | any) {
|
|
|
112
131
|
if (!target.d?.responses) target.d.responses = {}
|
|
113
132
|
target.d.responses[401] = {description: 'Unauthorized'}
|
|
114
133
|
|
|
115
|
-
mergeMiddleware(target,
|
|
116
|
-
const req = c.get(GET_REQUEST as unknown as string) as IRequest
|
|
117
|
-
const ability = Ability.fromAction(target)
|
|
118
|
-
|
|
119
|
-
if (!req?.user || !ability || req.cant(ability))
|
|
120
|
-
return response.unauthorized()
|
|
121
|
-
|
|
122
|
-
await next()
|
|
123
|
-
})
|
|
134
|
+
mergeMiddleware(target, Autorized)
|
|
124
135
|
}
|
|
125
136
|
|
|
126
137
|
function _describe(spec: DescribeRouteOptions): ClassDecorator{
|
package/src/middleware.ts
CHANGED
|
@@ -15,3 +15,7 @@ export class Middleware {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export const toHonoMiddleware = (mw: MiddlewareHandler) => async (req: IRequest, next: Next) => await mw(req.cx, next)
|
|
18
|
+
|
|
19
|
+
export function mergeMiddleware(target: Function | any, ...handlers: MiddlewareType[]) {
|
|
20
|
+
target.mw = [...target?.mw, ...handlers.flat()]
|
|
21
|
+
}
|
package/src/register.ts
CHANGED
package/src/request.ts
CHANGED
|
@@ -27,7 +27,7 @@ export default class $Request {
|
|
|
27
27
|
#u: Authnz<any> | null = null
|
|
28
28
|
|
|
29
29
|
#host: string
|
|
30
|
-
#routePath
|
|
30
|
+
#routePath?: string
|
|
31
31
|
#matchedRoutes: RouterRoute[]
|
|
32
32
|
|
|
33
33
|
constructor(c: Context) {
|
|
@@ -38,7 +38,6 @@ export default class $Request {
|
|
|
38
38
|
const url = new URL(c.req.raw.url)
|
|
39
39
|
this.#host = url.protocol +'//'+ url.host
|
|
40
40
|
|
|
41
|
-
this.#routePath = routePath(c)
|
|
42
41
|
this.#matchedRoutes = matchedRoutes(c)
|
|
43
42
|
}
|
|
44
43
|
|
|
@@ -91,10 +90,6 @@ export default class $Request {
|
|
|
91
90
|
return this.#c.req.header('user-agent')
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
get routePath() {
|
|
95
|
-
return this.#routePath
|
|
96
|
-
}
|
|
97
|
-
|
|
98
93
|
get url() {
|
|
99
94
|
return this.#c.req.raw.url
|
|
100
95
|
}
|
|
@@ -116,6 +111,15 @@ export default class $Request {
|
|
|
116
111
|
return this.#c.req.raw.method
|
|
117
112
|
}
|
|
118
113
|
|
|
114
|
+
get routePath() {
|
|
115
|
+
this.#routePath ??= routePath(this.#c)
|
|
116
|
+
return this.#routePath
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get routeIndex() {
|
|
120
|
+
return this.#c.req.routeIndex
|
|
121
|
+
}
|
|
122
|
+
|
|
119
123
|
get matchedRoutes() {
|
|
120
124
|
return this.#matchedRoutes
|
|
121
125
|
}
|
package/src/routes.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readdirSync, statSync, writeFileSync } from 'node:fs'
|
|
2
2
|
import { join, resolve, relative } from 'pathe'
|
|
3
3
|
|
|
4
|
+
import { IMPORT } from 't0n'
|
|
4
5
|
import glob from 'tiny-glob'
|
|
5
6
|
import { config } from 'dotenv'
|
|
6
|
-
|
|
7
|
-
import {
|
|
7
|
+
import { describeRoute, resolver } from 'hono-openapi'
|
|
8
|
+
import { mimes } from 'hono/utils/mime'
|
|
9
|
+
import { STATUS_CODES } from 'node:http'
|
|
8
10
|
import { registerHandler, registerMiddleware } from './register'
|
|
9
11
|
import createApp from './create-app'
|
|
10
12
|
import { isAnonFn } from './utils/func'
|
|
11
13
|
import ensureDir from './utils/ensuredir'
|
|
12
14
|
import versionSHA from './utils/version-sha'
|
|
13
|
-
import type { Routes, StandardSchemaV1 } from './types'
|
|
14
15
|
import { rn, substep, warn } from './utils/log'
|
|
15
|
-
import { _root } from './utils/paths'
|
|
16
|
+
import { _root, _rajt } from './utils/paths'
|
|
16
17
|
import { generateOpenAPI } from './open-api/spec'
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
import { mimes } from 'hono/utils/mime'
|
|
20
|
-
import { STATUS_CODES } from 'node:http'
|
|
21
|
-
import { mw, resolve as _resolve } from './utils/resolve'
|
|
22
|
-
|
|
18
|
+
import { verbAlias } from './http'
|
|
19
|
+
import { resolve as _resolve } from './utils/resolve'
|
|
23
20
|
import { highlightedMethod, highlightedURI } from './cli/utils'
|
|
24
21
|
|
|
22
|
+
import type * as z from 'zod'
|
|
23
|
+
import type { Routes, StandardSchemaV1 } from './types'
|
|
24
|
+
|
|
25
25
|
const importName = (name?: string) => (name || 'Fn'+ Math.random().toString(36).substring(2)).replace(/\.ts$/, '')
|
|
26
26
|
const walk = async (dir: string, baseDir: string, fn: Function, parentMw: string[] = []): Promise<void> => {
|
|
27
27
|
if (!existsSync(dir)) return
|
|
@@ -61,7 +61,7 @@ function isZodSchema(obj: any): obj is z.ZodType {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
function ResolveDescribeSchema(obj: any, deep: boolean = false) {
|
|
64
|
-
if (!obj || typeof obj
|
|
64
|
+
if (!obj || typeof obj != 'object') return obj
|
|
65
65
|
if (isZodSchema(obj))
|
|
66
66
|
return { content: {'application/json': { schema: resolver(obj as unknown as StandardSchemaV1) }} }
|
|
67
67
|
|
|
@@ -134,12 +134,16 @@ export async function getRoutes(
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
const mw = (handle.mw?.length ? [...handle.mw, ...middlewares] : middlewares).flatMap(obj => {
|
|
138
|
+
return typeof obj == 'string' ? obj : obj?.name || null
|
|
139
|
+
}).filter(Boolean) as Function[]
|
|
140
|
+
|
|
137
141
|
routes.push({
|
|
138
142
|
method, path: uri,
|
|
139
143
|
name,
|
|
140
144
|
file,
|
|
141
145
|
// @ts-ignore
|
|
142
|
-
middlewares,
|
|
146
|
+
middlewares: mw,
|
|
143
147
|
handle,
|
|
144
148
|
desc,
|
|
145
149
|
})
|
|
@@ -339,13 +343,24 @@ export async function cacheRoutes() {
|
|
|
339
343
|
|
|
340
344
|
const middlewares = await getMiddlewares()
|
|
341
345
|
const configs = await getConfigs()
|
|
346
|
+
const handlers = [
|
|
347
|
+
['auth/middlewares', 'Autorized', 'Autorized'],
|
|
348
|
+
]
|
|
349
|
+
|
|
350
|
+
for (const r of routes)
|
|
351
|
+
registerHandler(r.name, r.handle)
|
|
342
352
|
|
|
343
|
-
|
|
344
|
-
|
|
353
|
+
for (const mw of middlewares)
|
|
354
|
+
registerMiddleware(mw.handle)
|
|
355
|
+
|
|
356
|
+
for (const h of handlers) {
|
|
357
|
+
const mod = await IMPORT(join(_rajt, h[0]))
|
|
358
|
+
registerHandler(h[1], mod[h[1]])
|
|
359
|
+
}
|
|
345
360
|
|
|
346
361
|
// @ts-ignore
|
|
347
362
|
const openApi = await generateOpenAPI(createApp({ routes, routeRegister: (app: Hono, route: Route) => {
|
|
348
|
-
app[route.method](route.path, describeRoute(route.desc), ...
|
|
363
|
+
app[route.method](route.path, describeRoute(route.desc), ..._resolve(...route.middlewares), route.handle)
|
|
349
364
|
} }), configs?.rajt || {})
|
|
350
365
|
|
|
351
366
|
const iPath = join(_root, '.rajt/imports.mjs')
|
|
@@ -355,13 +370,18 @@ export async function cacheRoutes() {
|
|
|
355
370
|
copyFileSync(localfireEntry, join(_root, '.rajt/localfire.js'))
|
|
356
371
|
|
|
357
372
|
const _rajtDir = await dependencyPath('rajt')
|
|
373
|
+
|
|
374
|
+
stringifyToJS(Object.fromEntries(routes.map(r => ([r.path + r.method, r.name]))))
|
|
375
|
+
|
|
358
376
|
writeFileSync(iPath, `// AUTO-GENERATED FILE - DO NOT EDIT
|
|
359
377
|
${env?.length ? `import { Envir } from '${await dependencyPath('t0n')}/dist/index'\nEnvir.add({${env.map(([key, val]) => key +':'+ stringifyToJS(val)).join(',')}})` : ''}
|
|
360
378
|
${Object.entries(configs)?.length ? `import Config from '${_rajtDir}/src/config'\nConfig.add(${stringifyToJS(configs)})` : ''}
|
|
361
379
|
|
|
362
380
|
import { registerHandler, registerMiddleware } from '${_rajtDir}/src/register'
|
|
381
|
+
${handlers.map(([file, name, _export]) => `\nimport ${_export ? `{ ${name} }` : name} from '${_rajtDir}/src/${file}'\nregisterHandler('${name}', ${name})`).join('\n')}
|
|
363
382
|
|
|
364
383
|
${Object.entries(openApi)?.length ? `registerHandler('RAJT_OPENAPI', ${stringifyToJS(openApi)})` : ''}
|
|
384
|
+
Config.set('routes', ${stringifyToJS(Object.fromEntries(routes.map(r => ([r.path+'$'+verbAlias[r.method], r.name]))))})
|
|
365
385
|
|
|
366
386
|
${routes.map(r => `import ${r.name} from '../${normalizeImportPath(r.file)}'`).join('\n')}
|
|
367
387
|
${middlewares.map(r => `import ${r.name} from '../${normalizeImportPath(r.file)}'`).join('\n')}
|
|
@@ -370,9 +390,7 @@ try {
|
|
|
370
390
|
const handlers = {${routes.map(r => r.name).join()}}
|
|
371
391
|
|
|
372
392
|
for (const [name, handler] of Object.entries(handlers)) {
|
|
373
|
-
|
|
374
|
-
registerHandler(name, handler)
|
|
375
|
-
}
|
|
393
|
+
registerHandler(name, handler)
|
|
376
394
|
}
|
|
377
395
|
|
|
378
396
|
const middlewares = {${middlewares.map(r => r.name).join()}}
|
|
@@ -388,7 +406,7 @@ try {
|
|
|
388
406
|
const rPath = join(_root, '.rajt/routes.json')
|
|
389
407
|
ensureDir(rPath)
|
|
390
408
|
writeFileSync(rPath, JSON.stringify(routes.filter(r => r.method && r.path).map(route => [
|
|
391
|
-
route.method,
|
|
409
|
+
verbAlias[route.method],
|
|
392
410
|
route.path,
|
|
393
411
|
route.middlewares,
|
|
394
412
|
route.name,
|
package/src/types.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { OpenAPIV3_1, OpenAPIV3 } from 'openapi-types'
|
|
|
11
11
|
import type { StandardSchemaV1 } from '@standard-schema/spec'
|
|
12
12
|
import type { DescribeRouteOptions as RawDescribeRouteOptions, ResolverReturnType } from 'hono-openapi'
|
|
13
13
|
import type * as z from 'zod'
|
|
14
|
+
import type zm from 'zod/mini'
|
|
14
15
|
import Action from './action'
|
|
15
16
|
import request from './request'
|
|
16
17
|
import response from './response'
|
|
@@ -33,6 +34,7 @@ export type {
|
|
|
33
34
|
} from 'hono/utils/http-status'
|
|
34
35
|
export type { BaseMime, StandardSchemaV1 }
|
|
35
36
|
|
|
37
|
+
export type zObject = z.ZodTypeAny | zm.ZodMiniObject
|
|
36
38
|
type PublicMethods<T> = {
|
|
37
39
|
[K in keyof T]: K extends `#${string}` | `$${string}` | symbol | 'prototype' ? never : K
|
|
38
40
|
}[keyof T]
|
|
@@ -42,11 +44,12 @@ export type IResponse = Pick<typeof response, PublicMethods<typeof response>>
|
|
|
42
44
|
|
|
43
45
|
export type IValidator = Pick<typeof validator, PublicMethods<typeof validator>>
|
|
44
46
|
export type Rule = {
|
|
45
|
-
schema:
|
|
47
|
+
schema: zObject
|
|
46
48
|
target: keyof ValidationTargets
|
|
47
49
|
eTarget?: 'fieldErrors' | 'formErrors'
|
|
48
50
|
}
|
|
49
51
|
export type Rules = Rule[] | Rule | null
|
|
52
|
+
export type RuleFn = (schema: zObject) => Rule
|
|
50
53
|
|
|
51
54
|
export type StandardSchema = StandardSchemaV1 | OpenAPIV3_1.ReferenceObject
|
|
52
55
|
export type DescribeRouteOptions = Omit<RawDescribeRouteOptions, 'responses'> & {
|
package/src/utils/resolve.ts
CHANGED
|
@@ -1,23 +1,36 @@
|
|
|
1
1
|
import { getHandler } from '../register'
|
|
2
2
|
|
|
3
|
-
export function resolve(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
3
|
+
export function resolve(...objs: any[]) {
|
|
4
|
+
const _ = []
|
|
5
|
+
for (let obj of objs) {
|
|
6
|
+
if (typeof obj == 'string')
|
|
7
|
+
obj = getHandler(obj)
|
|
8
|
+
|
|
9
|
+
if (typeof obj == 'function' && obj?.length == 2) {
|
|
10
|
+
|
|
11
|
+
} else if (obj?.run) {
|
|
12
|
+
_.push(...obj.run())
|
|
13
|
+
continue
|
|
14
|
+
} else if (obj?.handle) {
|
|
15
|
+
obj = obj.handle
|
|
16
|
+
} else if (obj?.factory) {
|
|
17
|
+
obj = obj?.opts ? obj.factory(...Array.isArray(obj.opts) ? obj.opts : [obj.opts]) : obj.factory()
|
|
18
|
+
} else {
|
|
19
|
+
const instance = new obj()
|
|
20
|
+
if (obj?.prototype?.run) {
|
|
21
|
+
_.push(...instance.run())
|
|
22
|
+
continue
|
|
23
|
+
} else if (obj?.prototype?.handle) {
|
|
24
|
+
obj = instance.handle
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
throw new Error(`Invalid action "${obj?.name || String(obj)}" - unsupported type`)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
obj && _.push(obj)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return _
|
|
21
34
|
}
|
|
22
35
|
|
|
23
36
|
export function resolveMiddleware(obj: any) {
|
|
@@ -35,11 +48,3 @@ export function resolveMiddleware(obj: any) {
|
|
|
35
48
|
|
|
36
49
|
throw new Error('Invalid middleware provided. Must be a Hono middleware function or MiddlewareClass instance/constructor')
|
|
37
50
|
}
|
|
38
|
-
|
|
39
|
-
export function mw(...objs: string[]): Function[] {
|
|
40
|
-
return objs.flatMap(obj => {
|
|
41
|
-
if (typeof obj != 'string') return null
|
|
42
|
-
// @ts-ignore
|
|
43
|
-
return getHandler(obj)?.mw || null
|
|
44
|
-
}).flat().filter(Boolean)
|
|
45
|
-
}
|
package/src/validator.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type * as z from 'zod'
|
|
2
1
|
import { zValidator } from '@hono/zod-validator'
|
|
3
2
|
import response from './response'
|
|
4
3
|
import type {
|
|
5
|
-
Rule, Rules,
|
|
4
|
+
Rule, Rules, RuleFn,
|
|
6
5
|
ValidationTargets,
|
|
6
|
+
zObject,
|
|
7
7
|
} from './types'
|
|
8
8
|
|
|
9
9
|
export default class $Validator {
|
|
10
|
-
private static cache = new Map<string,
|
|
10
|
+
private static cache = new Map<string, RuleFn>()
|
|
11
11
|
|
|
12
12
|
private static createRule<T extends keyof ValidationTargets>(
|
|
13
13
|
target: T,
|
|
14
|
-
schema:
|
|
14
|
+
schema: zObject
|
|
15
15
|
): Rule {
|
|
16
16
|
return {
|
|
17
17
|
target,
|
|
@@ -24,7 +24,7 @@ export default class $Validator {
|
|
|
24
24
|
if (this.cache.has(target))
|
|
25
25
|
return this.cache.get(target)
|
|
26
26
|
|
|
27
|
-
const fn = (schema:
|
|
27
|
+
const fn = (schema: zObject) => this.createRule(target, schema)
|
|
28
28
|
this.cache.set(target, fn)
|
|
29
29
|
return fn
|
|
30
30
|
}
|
package/src/utils/json-import.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs'
|
|
2
|
-
import { dirname, join } from 'pathe'
|
|
3
|
-
|
|
4
|
-
export default function jsonImport<T = any>(filePath: string, defaultValue: T = {} as T): T {
|
|
5
|
-
const __dirname = dirname(new URL(import.meta.url).pathname)
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
const fullPath = join(__dirname, filePath)
|
|
9
|
-
const fileContent = readFileSync(fullPath, 'utf-8')
|
|
10
|
-
return JSON.parse(fileContent) as T
|
|
11
|
-
} catch (error) {
|
|
12
|
-
return defaultValue
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { MiddlewareHandler } from 'hono'
|
|
2
|
-
import { MiddlewareType } from '../middleware'
|
|
3
|
-
import { resolveMiddleware } from './resolve'
|
|
4
|
-
|
|
5
|
-
export default function mergeMiddleware(target: Function | any, ...handlers: MiddlewareType[]) {
|
|
6
|
-
const existingMiddlewares: MiddlewareHandler[] = target?.mw || []
|
|
7
|
-
const allMiddlewares = [...existingMiddlewares, ...handlers.flat().map(handler => resolveMiddleware(handler))]
|
|
8
|
-
target.mw = allMiddlewares
|
|
9
|
-
}
|