rajt 0.0.77 → 0.0.79
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/cli/commands/utils.ts +9 -2
- package/src/create-app.ts +2 -96
- package/src/dev.ts +5 -2
- package/src/oas.ts +110 -0
- package/src/prod.ts +5 -1
- package/src/routes.ts +65 -4
- package/src/types.ts +26 -4
- package/src/validator.ts +1 -1
package/package.json
CHANGED
|
@@ -58,6 +58,14 @@ export const formatTime = (ms: number) => {
|
|
|
58
58
|
return `${(ms / 1000).toFixed(2)}s`
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
const nodeModules = [
|
|
62
|
+
'crypto', 'buffer', 'http', 'fs', 'path', 'events', 'stream', 'util',
|
|
63
|
+
'url', 'querystring', 'os', 'child_process', 'cluster', 'dns', 'net',
|
|
64
|
+
'tls', 'https', 'zlib', 'readline', 'repl', 'vm', 'module', 'assert',
|
|
65
|
+
'timers', 'string_decoder', 'punycode', 'perf_hooks', 'dgram', 'tty',
|
|
66
|
+
'worker_threads', 'wasi'
|
|
67
|
+
].flatMap(lib => ['node:'+ lib, lib])
|
|
68
|
+
|
|
61
69
|
const dist = '.rajt/dist'
|
|
62
70
|
export const build = async (platform: Platform) => {
|
|
63
71
|
const startTime = Date.now()
|
|
@@ -99,8 +107,7 @@ export const build = async (platform: Platform) => {
|
|
|
99
107
|
'@aws-sdk', '@smithy',
|
|
100
108
|
...(isCF ? [
|
|
101
109
|
'cloudflare:workers',
|
|
102
|
-
|
|
103
|
-
'node:buffer', 'buffer',
|
|
110
|
+
...nodeModules,
|
|
104
111
|
] : []),
|
|
105
112
|
],
|
|
106
113
|
metafile: true,
|
package/src/create-app.ts
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { Hono } from 'hono'
|
|
2
2
|
import { logger } from 'hono/logger'
|
|
3
3
|
import { matchedRoutes } from 'hono/route'
|
|
4
|
-
import {
|
|
5
|
-
import { openAPIRouteHandler, describeRoute, resolver } from 'hono-openapi'
|
|
6
|
-
import { Scalar } from '@scalar/hono-api-reference'
|
|
4
|
+
import { describeRoute } from 'hono-openapi'
|
|
7
5
|
import { Envir, Datte } from 't0n'
|
|
8
6
|
import type {
|
|
9
7
|
Env, Context, Next,
|
|
10
8
|
HTTPResponseError,
|
|
11
9
|
ServerOptions,
|
|
12
|
-
DescribeRouteOptions,
|
|
13
10
|
} from './types'
|
|
14
11
|
import { resolve, resolveMiddleware } from './utils/resolve'
|
|
15
12
|
import { getMiddlewares, getHandler } from './register'
|
|
@@ -17,7 +14,6 @@ import request, { GET_REQUEST } from './request'
|
|
|
17
14
|
import response from './response'
|
|
18
15
|
import { isDev } from './utils/environment'
|
|
19
16
|
import { gray } from './utils/colors'
|
|
20
|
-
import packageJson from '../../../package.json'
|
|
21
17
|
|
|
22
18
|
const NFHandler = () => response.notFound()
|
|
23
19
|
const EHandler = async (e: Error | HTTPResponseError) => {
|
|
@@ -65,7 +61,7 @@ const EHandler = async (e: Error | HTTPResponseError) => {
|
|
|
65
61
|
// stack: isDev (? e.stack : undefined
|
|
66
62
|
}
|
|
67
63
|
|
|
68
|
-
export const createApp = <E extends Env>(options?: ServerOptions<E>
|
|
64
|
+
export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
69
65
|
// const root = options?.root ?? '/'
|
|
70
66
|
const app = options?.app ?? new Hono<E>()
|
|
71
67
|
|
|
@@ -121,96 +117,6 @@ export const createApp = <E extends Env>(options?: ServerOptions<E> & { configs:
|
|
|
121
117
|
}
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
const _docs = options?.configs?.docs ?? {}
|
|
125
|
-
const docs = {
|
|
126
|
-
..._docs,
|
|
127
|
-
disable: !!_docs?.disable,
|
|
128
|
-
path: _docs?.path || '/docs',
|
|
129
|
-
auth: _docs?.auth || {},
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (docs.disable) return app
|
|
133
|
-
|
|
134
|
-
if (docs?.auth?.username && docs?.auth?.password) {
|
|
135
|
-
app.use(docs.path +'/*', async (c, next) => {
|
|
136
|
-
const realm = docs.auth?.realm || 'Docs'
|
|
137
|
-
const unauthorized = response.unauthorized(
|
|
138
|
-
null,
|
|
139
|
-
{'WWW-Authenticate': `Basic realm="${realm.replace(/"/g, '\\"')}", charset="UTF-8"`}
|
|
140
|
-
)
|
|
141
|
-
if (!c.req.raw.headers.get('Authorization')) return unauthorized
|
|
142
|
-
const auth = basicAuth({ username: docs.auth.username, password: docs.auth.password, realm })
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
await auth(c, next)
|
|
146
|
-
} catch {
|
|
147
|
-
return unauthorized
|
|
148
|
-
}
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const appName = Envir.get('APP_NAME', packageJson?.name || 'API Docs')
|
|
153
|
-
const appVersion = Envir.get('APP_VERSION', packageJson?.version || '1.0.0')
|
|
154
|
-
|
|
155
|
-
app.get(
|
|
156
|
-
docs.path +'/openapi',
|
|
157
|
-
openAPIRouteHandler(app, {
|
|
158
|
-
documentation: {
|
|
159
|
-
info: {
|
|
160
|
-
title: appName,
|
|
161
|
-
version: appVersion,
|
|
162
|
-
description: Envir.get('APP_DESCRIPTION', packageJson?.description || ''),
|
|
163
|
-
},
|
|
164
|
-
components: {
|
|
165
|
-
securitySchemes: {
|
|
166
|
-
JWT: {
|
|
167
|
-
type: 'http',
|
|
168
|
-
scheme: 'bearer',
|
|
169
|
-
bearerFormat: 'JWT',
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
responses: {
|
|
173
|
-
500: {
|
|
174
|
-
description: 'Internal Server Error',
|
|
175
|
-
content: {
|
|
176
|
-
'application/json': {
|
|
177
|
-
schema: {
|
|
178
|
-
type: 'object',
|
|
179
|
-
properties: {
|
|
180
|
-
m: {
|
|
181
|
-
type: 'array',
|
|
182
|
-
items: { type: 'string' },
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
...docs?.responses,
|
|
190
|
-
},
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
})
|
|
194
|
-
)
|
|
195
|
-
|
|
196
|
-
app.get(
|
|
197
|
-
docs.path,
|
|
198
|
-
Scalar({
|
|
199
|
-
theme: 'saturn',
|
|
200
|
-
url: docs.path +'/openapi',
|
|
201
|
-
showDeveloperTools: 'never',
|
|
202
|
-
telemetry: false,
|
|
203
|
-
documentDownloadType: 'json', //'direct',
|
|
204
|
-
isLoading: true,
|
|
205
|
-
persistAuth: true,
|
|
206
|
-
hideClientButton: true,
|
|
207
|
-
slug: appName.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^\w\s_-]/g, '').replace(/[\s_-]+/g, '_').replace(/[^\x00-\x7F]/g, '') +'_'+ appVersion,
|
|
208
|
-
// hideDownloadButton: true,
|
|
209
|
-
// onLoaded: () => document?.querySelectorAll('[href="https://www.scalar.com"]')?.forEach(el => el.remove()),
|
|
210
|
-
customCss: `[href="https://www.scalar.com"]{display:none}`,
|
|
211
|
-
})
|
|
212
|
-
)
|
|
213
|
-
|
|
214
120
|
return app
|
|
215
121
|
}
|
|
216
122
|
|
package/src/dev.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { dirname, join } from 'node:path'
|
|
2
2
|
import { config } from 'dotenv'
|
|
3
|
-
import createApp from './create-app'
|
|
4
3
|
import { getRoutes, getMiddlewares, getConfigs } from './routes'
|
|
5
4
|
import { registerHandler, registerMiddleware } from './register'
|
|
6
5
|
import Config from './config'
|
|
6
|
+
import OAS from './oas'
|
|
7
|
+
import createApp from './create-app'
|
|
7
8
|
import { Ability } from 'rajt/auth'
|
|
8
9
|
import { setEnv, detectEnvironment } from 'rajt/env'
|
|
9
10
|
|
|
@@ -25,6 +26,8 @@ middlewares.forEach(mw => registerMiddleware(mw.handle))
|
|
|
25
26
|
Ability.fromRoutes(routes)
|
|
26
27
|
Ability.roles = Config.get('roles', {})
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
const app = createApp({ routes })
|
|
31
|
+
OAS.register(app, Config.get('rajt', {}))
|
|
29
32
|
|
|
30
33
|
export default app
|
package/src/oas.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { STATUS_CODES } from 'node:http'
|
|
2
|
+
import { basicAuth } from 'hono/basic-auth'
|
|
3
|
+
import { Scalar } from '@scalar/hono-api-reference'
|
|
4
|
+
import { generateSpecs, resolver } from 'hono-openapi'
|
|
5
|
+
import { Envir } from 't0n'
|
|
6
|
+
import z from 'zod'
|
|
7
|
+
import response from './response'
|
|
8
|
+
import { getHandler } from './register'
|
|
9
|
+
import type { Hono } from './types'
|
|
10
|
+
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
import packageJson from '../../../package.json'
|
|
13
|
+
|
|
14
|
+
export default class OAS {
|
|
15
|
+
static #config(config: any) {
|
|
16
|
+
const docs = config?.docs ?? {}
|
|
17
|
+
|
|
18
|
+
const appName = Envir.get('APP_NAME', packageJson?.name || 'API Docs')
|
|
19
|
+
const appVersion = Envir.get('APP_VERSION', packageJson?.version || '1.0.0')
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
...docs,
|
|
23
|
+
disable: !!docs?.disable,
|
|
24
|
+
path: docs?.path || '/docs',
|
|
25
|
+
auth: docs?.auth || {},
|
|
26
|
+
agent: !docs?.agent,
|
|
27
|
+
appName, appVersion,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static register(app: Hono, config: any) {
|
|
32
|
+
const opts = this.#config(config)
|
|
33
|
+
if (opts.disable) return
|
|
34
|
+
|
|
35
|
+
if (opts?.auth?.username && opts?.auth?.password) {
|
|
36
|
+
app.use(opts.path +'/*', async (c, next) => {
|
|
37
|
+
const realm = opts.auth?.realm || 'Docs'
|
|
38
|
+
const unauthorized = response.unauthorized(
|
|
39
|
+
null,
|
|
40
|
+
{'WWW-Authenticate': `Basic realm="${realm.replace(/"/g, '\\"')}", charset="UTF-8"`}
|
|
41
|
+
)
|
|
42
|
+
if (!c.req.raw.headers.get('Authorization')) return unauthorized
|
|
43
|
+
const auth = basicAuth({ username: opts.auth.username, password: opts.auth.password, realm })
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
await auth(c, next)
|
|
47
|
+
} catch {
|
|
48
|
+
return unauthorized
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
app.get(opts.path + '/openapi', async () => response.json(getHandler('RAJT_OPENAPI')))
|
|
54
|
+
|
|
55
|
+
app.get(
|
|
56
|
+
opts.path,
|
|
57
|
+
Scalar({
|
|
58
|
+
theme: 'saturn',
|
|
59
|
+
url: opts.path +'/openapi',
|
|
60
|
+
showDeveloperTools: 'never',
|
|
61
|
+
telemetry: false,
|
|
62
|
+
documentDownloadType: 'json', //'direct',
|
|
63
|
+
isLoading: true,
|
|
64
|
+
persistAuth: true,
|
|
65
|
+
hideClientButton: true,
|
|
66
|
+
pageTitle: opts.appName,
|
|
67
|
+
agent: { disabled: opts.agent },
|
|
68
|
+
slug: opts.appName?.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^\w\s_-]/g, '').replace(/[\s_-]+/g, '_').replace(/[^\x00-\x7F]/g, '') +'_'+ opts.appVersion,
|
|
69
|
+
// hideDownloadButton: true,
|
|
70
|
+
// onLoaded: () => document?.querySelectorAll('[href="https://www.scalar.com"]')?.forEach(el => el.remove()),
|
|
71
|
+
customCss: `[href="https://www.scalar.com"]{display:none}`,
|
|
72
|
+
})
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static async generateSpecs(app: Hono, config: any) {
|
|
77
|
+
const opts = this.#config(config)
|
|
78
|
+
if (opts.disable) return {}
|
|
79
|
+
|
|
80
|
+
return await generateSpecs(app, {
|
|
81
|
+
documentation: {
|
|
82
|
+
info: {
|
|
83
|
+
title: opts.appName,
|
|
84
|
+
version: opts.appVersion,
|
|
85
|
+
description: Envir.get('APP_DESCRIPTION', packageJson?.description || ''),
|
|
86
|
+
},
|
|
87
|
+
components: {
|
|
88
|
+
securitySchemes: {
|
|
89
|
+
JWT: {
|
|
90
|
+
type: 'http',
|
|
91
|
+
scheme: 'bearer',
|
|
92
|
+
bearerFormat: 'JWT',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
responses: {
|
|
96
|
+
500: {
|
|
97
|
+
description: STATUS_CODES[500],
|
|
98
|
+
content: { // @ts-ignore
|
|
99
|
+
'application/json': await resolver(z.object({
|
|
100
|
+
m: z.array(z.string()),
|
|
101
|
+
})).toOpenAPISchema(),
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
...opts?.responses,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
}
|
package/src/prod.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Config from './config'
|
|
2
|
+
import OAS from './oas'
|
|
2
3
|
import { Ability } from './auth'
|
|
3
4
|
import createApp from './create-app'
|
|
4
5
|
|
|
@@ -12,4 +13,7 @@ Ability.fromRoutes(routes)
|
|
|
12
13
|
Ability.roles = Config.get('roles', {})
|
|
13
14
|
|
|
14
15
|
// @ts-ignore
|
|
15
|
-
|
|
16
|
+
const app = createApp({ routes })
|
|
17
|
+
OAS.register(app, Config.get('rajt', {}))
|
|
18
|
+
|
|
19
|
+
export { app }
|
package/src/routes.ts
CHANGED
|
@@ -5,12 +5,20 @@ import glob from 'tiny-glob'
|
|
|
5
5
|
import { config } from 'dotenv'
|
|
6
6
|
|
|
7
7
|
import { IMPORT } from 't0n'
|
|
8
|
+
import { registerHandler, registerMiddleware } from './register'
|
|
9
|
+
import createApp from './create-app'
|
|
8
10
|
import { isAnonFn } from './utils/func'
|
|
9
11
|
import ensureDir from './utils/ensuredir'
|
|
10
12
|
import versionSHA from './utils/version-sha'
|
|
11
|
-
import type { Routes } from './types'
|
|
13
|
+
import type { Routes, StandardSchemaV1 } from './types'
|
|
12
14
|
import { substep, warn } from './utils/log'
|
|
13
15
|
|
|
16
|
+
import OAS from './oas'
|
|
17
|
+
import z from 'zod'
|
|
18
|
+
import { resolver } from 'hono-openapi'
|
|
19
|
+
import { mimes } from 'hono/utils/mime'
|
|
20
|
+
import { STATUS_CODES } from 'node:http'
|
|
21
|
+
|
|
14
22
|
const __filename = new URL(import.meta.url).pathname
|
|
15
23
|
const __root = resolve(dirname(__filename), '../../..')
|
|
16
24
|
|
|
@@ -43,6 +51,50 @@ const walk = async (dir: string, baseDir: string, fn: Function, parentMw: string
|
|
|
43
51
|
}
|
|
44
52
|
}
|
|
45
53
|
|
|
54
|
+
function isZodSchema(obj: any): obj is z.ZodType {
|
|
55
|
+
return (
|
|
56
|
+
obj &&
|
|
57
|
+
typeof obj == 'object' &&
|
|
58
|
+
('_def' in obj || '_type' in obj) &&
|
|
59
|
+
(obj.safeParse !== undefined || obj.parse !== undefined)
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function ResolveDescribeSchema(obj: any, deep: boolean = false) {
|
|
64
|
+
if (!obj || typeof obj !== 'object') return obj
|
|
65
|
+
if (isZodSchema(obj))
|
|
66
|
+
return { content: {'application/json': { schema: resolver(obj as unknown as StandardSchemaV1) }} }
|
|
67
|
+
|
|
68
|
+
if (obj.content && typeof obj.content == 'object') {
|
|
69
|
+
for (const mediaType in obj.content) {
|
|
70
|
+
const contentItem = obj.content[mediaType]
|
|
71
|
+
if (contentItem?.schema && isZodSchema(contentItem.schema))
|
|
72
|
+
contentItem.schema = resolver(contentItem.schema)
|
|
73
|
+
|
|
74
|
+
if (mediaType in mimes) {
|
|
75
|
+
obj.content[mimes[mediaType]] = contentItem
|
|
76
|
+
delete obj.content[mediaType]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return obj
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (const key in obj) {
|
|
84
|
+
if (obj[key] && typeof obj[key] == 'object') {
|
|
85
|
+
obj[key] = ResolveDescribeSchema(obj[key], true)
|
|
86
|
+
|
|
87
|
+
if (!deep && !obj[key]?.description) {
|
|
88
|
+
const desription = (new Response(null, { status: Number(key) })).statusText || STATUS_CODES[key]
|
|
89
|
+
if (desription) obj[key].description = desription
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return obj
|
|
96
|
+
}
|
|
97
|
+
|
|
46
98
|
let hasDuplicatedRoutes = false
|
|
47
99
|
export async function getRoutes(
|
|
48
100
|
dirs: string[] = ['actions', 'features', 'routes']
|
|
@@ -70,9 +122,10 @@ export async function getRoutes(
|
|
|
70
122
|
...d,
|
|
71
123
|
responses: {
|
|
72
124
|
500: {$ref: '#/components/responses/500'},
|
|
73
|
-
...d?.responses,
|
|
125
|
+
...ResolveDescribeSchema(d?.responses),
|
|
74
126
|
}
|
|
75
127
|
}
|
|
128
|
+
|
|
76
129
|
routes.push({
|
|
77
130
|
method, path: uri,
|
|
78
131
|
name,
|
|
@@ -261,16 +314,24 @@ export async function cacheRoutes() {
|
|
|
261
314
|
throw new Error("The app can't build with duplicate routes")
|
|
262
315
|
|
|
263
316
|
const middlewares = await getMiddlewares()
|
|
264
|
-
const configs =
|
|
317
|
+
const configs = await getConfigs()
|
|
318
|
+
|
|
319
|
+
routes.forEach(r => registerHandler(r.name, r.handle))
|
|
320
|
+
middlewares.forEach(mw => registerMiddleware(mw.handle))
|
|
321
|
+
|
|
322
|
+
// @ts-ignore
|
|
323
|
+
const openApi = await OAS.generateSpecs(createApp({ routes }), configs?.rajt || {})
|
|
265
324
|
|
|
266
325
|
const iPath = join(__root, '.rajt/import-routes.mjs')
|
|
267
326
|
ensureDir(iPath)
|
|
268
327
|
writeFileSync(iPath, `// AUTO-GENERATED FILE - DO NOT EDIT
|
|
269
328
|
${env?.length ? `import { Envir } from '../node_modules/t0n/dist/index'\nEnvir.add({${env.map(([key, val]) => key +':'+ stringifyToJS(val)).join(',')}})` : ''}
|
|
270
|
-
${configs?.length ? `import Config from '../node_modules/rajt/src/config'\nConfig.add(
|
|
329
|
+
${Object.entries(configs)?.length ? `import Config from '../node_modules/rajt/src/config'\nConfig.add(${stringifyToJS(configs)})` : ''}
|
|
271
330
|
|
|
272
331
|
import { registerHandler, registerMiddleware } from '../node_modules/rajt/src/register'
|
|
273
332
|
|
|
333
|
+
${Object.entries(openApi)?.length ? `registerHandler('RAJT_OPENAPI', ${stringifyToJS(openApi)})` : ''}
|
|
334
|
+
|
|
274
335
|
${routes.map(r => `import ${r.name} from '../${normalizeImportPath(r.file)}'`).join('\n')}
|
|
275
336
|
${middlewares.map(r => `import ${r.name} from '../${normalizeImportPath(r.file)}'`).join('\n')}
|
|
276
337
|
|
package/src/types.ts
CHANGED
|
@@ -6,17 +6,19 @@ import type {
|
|
|
6
6
|
} from 'hono'
|
|
7
7
|
import type { ResponseHeader } from 'hono/utils/headers'
|
|
8
8
|
// import type { StatusCode } from 'hono/utils/http-status'
|
|
9
|
-
import type
|
|
10
|
-
import type {
|
|
9
|
+
import { mimes, type BaseMime } from 'hono/utils/mime'
|
|
10
|
+
import type { OpenAPIV3_1, OpenAPIV3 } from 'openapi-types'
|
|
11
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec'
|
|
12
|
+
import type { DescribeRouteOptions as RawDescribeRouteOptions, ResolverReturnType } from 'hono-openapi'
|
|
11
13
|
import z from 'zod'
|
|
12
14
|
import Action from './action'
|
|
13
15
|
import request from './request'
|
|
14
16
|
import response from './response'
|
|
15
17
|
import validator from './validator'
|
|
16
18
|
|
|
17
|
-
|
|
18
19
|
// export type { H, Handler, HandlerResponse } from 'hono/types'
|
|
19
20
|
export type {
|
|
21
|
+
Hono,
|
|
20
22
|
Env, Context, Next,
|
|
21
23
|
// ErrorHandler, NotFoundHandler,
|
|
22
24
|
MiddlewareHandler, // TODO: remove..
|
|
@@ -29,7 +31,7 @@ export type {
|
|
|
29
31
|
RedirectStatusCode,
|
|
30
32
|
StatusCode,
|
|
31
33
|
} from 'hono/utils/http-status'
|
|
32
|
-
export type { BaseMime,
|
|
34
|
+
export type { BaseMime, StandardSchemaV1 }
|
|
33
35
|
|
|
34
36
|
type PublicMethods<T> = {
|
|
35
37
|
[K in keyof T]: K extends `#${string}` | `$${string}` | symbol | 'prototype' ? never : K
|
|
@@ -46,6 +48,26 @@ export type Rule = {
|
|
|
46
48
|
}
|
|
47
49
|
export type Rules = Rule[] | Rule | null
|
|
48
50
|
|
|
51
|
+
export type StandardSchema = StandardSchemaV1 | OpenAPIV3_1.ReferenceObject
|
|
52
|
+
export type DescribeRouteOptions = Omit<RawDescribeRouteOptions, 'responses'> & {
|
|
53
|
+
responses?: {
|
|
54
|
+
[key: string | number]: (Omit<OpenAPIV3.ResponseObject, 'description' | 'headers' | 'content' | 'links'> & {
|
|
55
|
+
description?: string,
|
|
56
|
+
headers?: { // TODO maybe dont accept ResolverReturnType
|
|
57
|
+
[header: string]: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.HeaderObject
|
|
58
|
+
},
|
|
59
|
+
content?: {
|
|
60
|
+
[key: BaseMime | keyof typeof mimes]: Omit<OpenAPIV3_1.MediaTypeObject, 'schema'> & {
|
|
61
|
+
schema?: StandardSchema | OpenAPIV3_1.SchemaObject | ResolverReturnType,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
links?: { // TODO maybe dont accept ResolverReturnType
|
|
65
|
+
[link: string]: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.LinkObject
|
|
66
|
+
},
|
|
67
|
+
}) | StandardSchema,
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
|
|
49
71
|
export type Route = {
|
|
50
72
|
method: string,
|
|
51
73
|
path: string,
|
package/src/validator.ts
CHANGED
|
@@ -40,7 +40,7 @@ export default class $Validator {
|
|
|
40
40
|
return (Array.isArray(rules) ? rules : [rules]) // @ts-ignore
|
|
41
41
|
.flatMap(rule => validator(rule.target, rule.schema, (result, c) => {
|
|
42
42
|
if (!result.success) // @ts-ignore
|
|
43
|
-
return response.badRequest(
|
|
43
|
+
return response.badRequest(result.error)
|
|
44
44
|
}))
|
|
45
45
|
}
|
|
46
46
|
}
|