rajt 0.0.97 → 0.0.99

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 CHANGED
@@ -1,9 +1,10 @@
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.97",
4
+ "version": "0.0.99",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
7
+ "files": ["bin", "src"],
7
8
  "bin": {
8
9
  "rajt": "./bin/rajt.js"
9
10
  },
@@ -22,10 +23,6 @@
22
23
  "./env": "./src/utils/environment.ts",
23
24
  "./length": "./src/utils/length.ts"
24
25
  },
25
- "files": [
26
- "bin",
27
- "src"
28
- ],
29
26
  "scripts": {
30
27
  "aws:local": "bun run --silent aws:build && bun run --silent sam:local",
31
28
  "aws:package": "bun run --silent aws:build && bun run --silent sam:package",
@@ -38,51 +35,44 @@
38
35
  "zip": "zip -j ../../lambda.zip ../../.rajt/dist/index.js"
39
36
  },
40
37
  "dependencies": {
41
- "cripta": "^0.1",
42
- "forj": "0.1.7",
43
- "t0n": "^0.1",
44
38
  "@hono/node-server": "^1.19.9",
45
39
  "@hono/standard-validator": "^0.2.2",
40
+ "@hono/zod-validator": "^0.7.6",
46
41
  "@scalar/hono-api-reference": "^0.9.40",
47
42
  "chokidar": "^3.5.2",
48
43
  "citty": "^0.1.6",
49
44
  "consola": "^3.4.2",
45
+ "cripta": "^0.1.10",
50
46
  "dotenv": "^16.5.0",
51
47
  "esbuild": "^0.25.2",
48
+ "forj": "^0.1.8",
52
49
  "hono": "^4.11.7",
53
- "hono-openapi": "^1.2.0",
50
+ "hono-openapi": "^1.3.0",
54
51
  "localflare-api": "^0.4.2",
55
52
  "localflare-core": "^0.4.2",
56
- "miniflare": "^4.20251217.0",
53
+ "miniflare": "^4.20260301.1",
57
54
  "pathe": "^2.0",
58
55
  "quansync": "^0.2.11",
56
+ "t0n": "^0.1.12",
59
57
  "tiny-glob": "^0.2",
60
- "tsx": "^4.19.3",
61
- "ua-parser-js": "^2.0.8",
58
+ "tsx": "^4.19.4",
62
59
  "wrangler": "^4.61.0",
63
60
  "zod": "^4.3.6",
64
- "zod-openapi": "4"
61
+ "zod-openapi": "^5.4.6"
65
62
  },
66
63
  "devDependencies": {
67
- "@cloudflare/workers-types": "^4.20251230.0",
68
- "@miniflare/core": "^2.14.4",
69
- "@miniflare/d1": "^2.14.4",
70
- "@miniflare/durable-objects": "^2.14.4",
71
- "@miniflare/kv": "^2.14.4",
72
- "@miniflare/r2": "^2.14.4",
73
- "@miniflare/scheduler": "^2.14.4",
74
- "@miniflare/sites": "^2.14.4",
75
- "@miniflare/storage-file": "^2.14.4",
76
- "@miniflare/web-sockets": "^2.14.4",
64
+ "@cloudflare/workers-types": "^4.20260113.0",
77
65
  "@types/node": "^25.1.0",
78
66
  "bun-types": "^1.3.8",
79
67
  "typescript": "^5.9.3"
80
68
  },
69
+ "packageManager": "bun@1.3.10",
81
70
  "engines": {
82
71
  "node": ">=18.0.0"
83
72
  },
84
73
  "resolutions": {
85
- "@smithy/types": "^4.3.0"
74
+ "@smithy/types": "^4.3.0",
75
+ "zod": "^4.3.6"
86
76
  },
87
77
  "publishConfig": {
88
78
  "registry": "https://registry.npmjs.org"
@@ -111,4 +101,4 @@
111
101
  "bun",
112
102
  "nodejs"
113
103
  ]
114
- }
104
+ }
package/src/auth/token.ts CHANGED
@@ -1,8 +1,37 @@
1
- import { Envir } from 't0n'
2
- import { Token as Factory } from 'cripta'
3
- import { UAParser } from 'ua-parser-js'
1
+ import { Envir, parseUA } from 't0n'
2
+ import { Token as Factory, sha256 } from 'cripta'
4
3
  import type { IRequest } from '@/types'
5
4
 
5
+ const STABLE_HEADERS = [
6
+ 'host',
7
+ 'connection',
8
+ 'sec-ch-ua',
9
+ 'sec-ch-ua-mobile',
10
+ 'sec-ch-ua-platform',
11
+ 'upgrade-insecure-requests',
12
+ 'user-agent',
13
+ 'accept',
14
+ 'sec-fetch-site',
15
+ 'sec-fetch-mode',
16
+ 'sec-fetch-user',
17
+ 'sec-fetch-dest',
18
+ 'accept-encoding',
19
+ 'accept-language',
20
+ ]
21
+
22
+ function headerOrdering(headers: Record<string, string>) {
23
+ const order: string[] = []
24
+
25
+ for (const name in headers) {
26
+ const key = name.toLowerCase()
27
+
28
+ if (STABLE_HEADERS.includes(key))
29
+ order.push(key)
30
+ }
31
+
32
+ return order
33
+ }
34
+
6
35
  export class Token {
7
36
  static #cookieName: string = '__auth_'
8
37
  static #name: string = 'Authorization'
@@ -48,8 +77,7 @@ export class Token {
48
77
  return Factory.parse(token)
49
78
  .issuedBy(serveHost)
50
79
  .permittedFor(host)
51
- .withClaim('u', this.userAgent(req))
52
- .withClaim('i', this.ip(req))
80
+ .withClaim('_', this.fingerprint(req))
53
81
  }
54
82
 
55
83
  static create(req: IRequest, user: any, exp: number = 7200) {
@@ -61,8 +89,7 @@ export class Token {
61
89
  .permittedFor(host)
62
90
  .issuedAt(time)
63
91
  .expiresAt(time + exp)
64
- .withClaim('u', this.userAgent(req))
65
- .withClaim('i', this.ip(req))
92
+ .withClaim('_', this.fingerprint(req))
66
93
  .body(user)
67
94
  }
68
95
 
@@ -90,11 +117,18 @@ export class Token {
90
117
  }
91
118
  }
92
119
 
93
- static userAgent(req: IRequest) {
94
- const ua = req?.userAgent
95
- if (!ua) return 0
96
- const { browser, device, os } = UAParser(ua)
97
- return (browser?.name || '') + (browser?.major || '') + (device?.model || '') + (os?.name || '')
120
+ static fingerprint(req: IRequest) {
121
+ const ua = parseUA(req.header('user-agent'))
122
+
123
+ const id = sha256(
124
+ // (req.header('accept-language') || '')
125
+ this.ip(req)
126
+ + ua.browser.name + ua.browser.version.split('.')[0]
127
+ + ua.os.type + ua.os.name
128
+ + headerOrdering(req.header()).join('')
129
+ )
130
+
131
+ return id.substring(0, 8) + id.substring(56, 64)
98
132
  }
99
133
 
100
134
  static ip(req: IRequest) {
@@ -1,5 +1,5 @@
1
1
  import { defineCommand } from 'citty'
2
- import { gray } from '../../utils/colors'
2
+ import { gray } from 't0n/color'
3
3
  import { build, normalizePlatform, platformError } from '../utils'
4
4
  import { wait, error, rn } from '../../utils/log'
5
5
 
@@ -4,7 +4,7 @@ import { Migrator } from 'forj'
4
4
  import { makeFile, hasExt, camelCase, kebabCase } from '../utils'
5
5
  import { _root } from '../../utils/paths'
6
6
  import { event, error } from '../../utils/log'
7
- import { dim } from '../../utils/colors'
7
+ import { dim } from 't0n/color'
8
8
  import * as stub from '../stubs'
9
9
 
10
10
  export default defineCommand({
@@ -2,7 +2,7 @@ import { defineCommand } from 'citty'
2
2
  import { spawn } from 'node:child_process'
3
3
  import { join } from 'pathe'
4
4
  import { Migrator } from 'forj'
5
- import { gray } from '../../utils/colors'
5
+ import { gray } from 't0n/color'
6
6
  import { getRuntime, cleanDB, cleanDir } from '../utils'
7
7
  import { _root } from '../../utils/paths'
8
8
  import { wait, info, event, rn, error, log } from '../../utils/log'
package/src/cli/index.ts CHANGED
@@ -2,7 +2,7 @@ import { defineCommand, runMain, renderUsage } from 'citty'
2
2
  import type { ArgsDef, CommandDef } from 'citty'
3
3
  import { createConsola } from 'consola'
4
4
  import { logo } from '../utils/log'
5
- import { isColorSupported, gray } from '../utils/colors'
5
+ import { isColorSupported, gray } from 't0n/color'
6
6
  import { version as rajtVersion } from '../../package.json'
7
7
 
8
8
  import dev from './commands/dev'
package/src/cli/utils.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import esbuild from 'esbuild'
2
2
  import { Miniflare } from 'miniflare'
3
- import { mkdirSync, existsSync, statSync, readdirSync, rmSync, unlinkSync, copyFileSync, writeFileSync, readFileSync } from 'node:fs'
3
+ import { mkdirSync, existsSync, statSync, readdirSync, rmSync, unlinkSync, copyFileSync, writeFileSync } from 'node:fs'
4
4
  import { readFile, stat, writeFile } from 'node:fs/promises'
5
5
  import { basename, dirname, join, relative } from 'pathe'
6
6
  import { createHash, createHmac } from 'node:crypto'
@@ -9,7 +9,7 @@ import { findWranglerConfig, parseWranglerConfig, WRANGLER_CONFIG_FILES } from '
9
9
  import type { WranglerConfig, LocalflareManifest } from 'localflare-core'
10
10
 
11
11
  import chokidar from 'chokidar'
12
- import { gray, bold, italic, purple, yellow, red } from '../utils/colors'
12
+ import { gray, bold, italic, purple, yellow, red } from 't0n/color'
13
13
  import type { ChokidarEventName, Platform } from './types'
14
14
 
15
15
  import { cacheRoutes } from '../routes'
package/src/config.ts CHANGED
@@ -39,6 +39,7 @@ export default class Config {
39
39
  this.#c.clear()
40
40
  }
41
41
 
42
+ // @ts-ignore
42
43
  static get length(): number {
43
44
  return this.#c.length
44
45
  }
package/src/create-app.ts CHANGED
@@ -1,19 +1,19 @@
1
1
  import { Hono } from 'hono'
2
2
  import { logger } from 'hono/logger'
3
3
  import { matchedRoutes } from 'hono/route'
4
- import { describeRoute } from 'hono-openapi'
5
4
  import { Envir, Datte } from 't0n'
6
5
  import type {
7
6
  Env, Context, Next,
8
7
  HTTPResponseError,
9
8
  ServerOptions,
10
9
  } from './types'
11
- import { resolve, resolveMiddleware } from './utils/resolve'
10
+ import { resolve, resolveMiddleware, mw } from './utils/resolve'
12
11
  import { getMiddlewares, getHandler } from './register'
13
12
  import request, { GET_REQUEST } from './request'
14
13
  import response from './response'
15
14
  import { isDev } from './utils/environment'
16
- import { gray } from './utils/colors'
15
+ import { gray } from 't0n/color'
16
+ import { Route } from './types'
17
17
 
18
18
  const NFHandler = () => response.notFound()
19
19
  const EHandler = async (e: Error | HTTPResponseError) => {
@@ -108,24 +108,19 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
108
108
 
109
109
  if (options?.init) options.init(app)
110
110
 
111
- const routes = options?.routes || []
112
- for (const route of routes) {
111
+ const routes = options?.routes || [] // @ts-ignore
112
+ const routeRegister = options?.routeRegister ? options.routeRegister : (_: Hono, route: Route) => { // @ts0ignore
113
113
  if (Array.isArray(route)) { // @ts-ignore
114
- app[route[0]](route[1], ...mw(route[2], route[3]), ...resolve(getHandler(route[3]), route[3]))
114
+ _[route[0]](route[1], ...mw(route[2], route[3]), ...resolve(getHandler(route[3]), route[3]))
115
115
  } else { // @ts-ignore
116
- app[route.method](route.path, describeRoute(route.desc), ...mw(route.middlewares, route.name), ...resolve(route.handle, route.name))
116
+ _[route.method](route.path, ...mw(route.middlewares, route.name), ...resolve(route.handle, route.name))
117
117
  }
118
118
  }
119
119
 
120
- return app
121
- }
120
+ for (const route of routes)
121
+ routeRegister(app, route)
122
122
 
123
- function mw(...objs: string[]): Function[] {
124
- return objs.flatMap(obj => {
125
- if (typeof obj != 'string') return null
126
- // @ts-ignore
127
- return getHandler(obj)?.mw || null
128
- }).flat().filter(Boolean)
123
+ return app
129
124
  }
130
125
 
131
126
  export default createApp
package/src/dev.ts CHANGED
@@ -3,7 +3,7 @@ import { config } from 'dotenv'
3
3
  import { getRoutes, getMiddlewares, getConfigs } from './routes'
4
4
  import { registerHandler, registerMiddleware } from './register'
5
5
  import Config from './config'
6
- import OAS from './oas'
6
+ 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'
@@ -28,6 +28,6 @@ Ability.roles = Config.get('roles', {})
28
28
 
29
29
  // @ts-ignore
30
30
  const app = createApp({ routes })
31
- OAS.register(app, Config.get('rajt', {}))
31
+ registerOpenAPI(app, Config.get('rajt', {}))
32
32
 
33
33
  export default app
@@ -0,0 +1,67 @@
1
+ import { basicAuth } from 'hono/basic-auth'
2
+ import { Scalar } from '@scalar/hono-api-reference'
3
+ import { Envir } from 't0n'
4
+ import response from '../response'
5
+ import { getHandler } from '../register'
6
+ import type { Hono } from '../types'
7
+
8
+ export function config(opts: any) {
9
+ const docs = opts?.docs ?? {}
10
+
11
+ const appName = Envir.get('APP_NAME', 'API Docs')
12
+ const appVersion = Envir.get('APP_VERSION') || Envir.get('VERSION_HASH') || '1.0.0'
13
+
14
+ return {
15
+ ...docs,
16
+ disable: !!docs?.disable,
17
+ path: docs?.path || '/docs',
18
+ auth: docs?.auth || {},
19
+ agent: !docs?.agent,
20
+ appName, appVersion,
21
+ }
22
+ }
23
+
24
+ export function registerOpenAPI(app: Hono, conf: any) {
25
+ const opts = config(conf)
26
+ if (opts.disable) return
27
+
28
+ if (opts?.auth?.username && opts?.auth?.password) {
29
+ app.use(opts.path +'/*', async (c, next) => {
30
+ const realm = opts.auth?.realm || 'Docs'
31
+ const unauthorized = response.unauthorized(
32
+ null,
33
+ {'WWW-Authenticate': `Basic realm="${realm.replace(/"/g, '\\"')}", charset="UTF-8"`}
34
+ )
35
+ if (!c.req.raw.headers.get('Authorization')) return unauthorized
36
+ const auth = basicAuth({ username: opts.auth.username, password: opts.auth.password, realm })
37
+
38
+ try {
39
+ await auth(c, next)
40
+ } catch {
41
+ return unauthorized
42
+ }
43
+ })
44
+ }
45
+
46
+ app.get(opts.path + '/openapi', async () => response.json(getHandler('RAJT_OPENAPI')))
47
+
48
+ app.get(
49
+ opts.path,
50
+ Scalar({
51
+ theme: 'saturn',
52
+ url: opts.path +'/openapi',
53
+ showDeveloperTools: 'never',
54
+ telemetry: false,
55
+ documentDownloadType: 'json', //'direct',
56
+ isLoading: true,
57
+ persistAuth: true,
58
+ hideClientButton: true,
59
+ pageTitle: opts.appName,
60
+ agent: { disabled: opts.agent },
61
+ slug: opts.appName?.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^\w\s_-]/g, '').replace(/[\s_-]+/g, '_').replace(/[^\x00-\x7F]/g, '') +'_'+ opts.appVersion,
62
+ // hideDownloadButton: true,
63
+ // onLoaded: () => document?.querySelectorAll('[href="https://www.scalar.com"]')?.forEach(el => el.remove()),
64
+ customCss: `[href="https://www.scalar.com"]{display:none}`,
65
+ })
66
+ )
67
+ }
@@ -0,0 +1,41 @@
1
+ import { STATUS_CODES } from 'node:http'
2
+ import { generateSpecs, resolver } from 'hono-openapi'
3
+ import { array, object, string } from 'zod/mini'
4
+ import { Envir } from 't0n'
5
+ import type { Hono } from '../types'
6
+ import { config } from './register'
7
+
8
+ export async function generateOpenAPI(app: Hono, conf: any) {
9
+ const opts = config(conf)
10
+ if (opts.disable) return {}
11
+
12
+ return await generateSpecs(app, {
13
+ documentation: {
14
+ info: {
15
+ title: opts.appName,
16
+ version: opts.appVersion,
17
+ description: Envir.get('APP_DESCRIPTION', ''),
18
+ },
19
+ components: {
20
+ securitySchemes: {
21
+ JWT: {
22
+ type: 'http',
23
+ scheme: 'bearer',
24
+ bearerFormat: 'JWT',
25
+ },
26
+ },
27
+ responses: {
28
+ 500: {
29
+ description: STATUS_CODES[500],
30
+ content: { // @ts-ignore
31
+ 'application/json': await resolver(object({
32
+ m: array(string()),
33
+ })).toOpenAPISchema(),
34
+ },
35
+ },
36
+ ...opts?.responses,
37
+ },
38
+ },
39
+ },
40
+ })
41
+ }
package/src/prod.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import Config from './config'
2
- import OAS from './oas'
2
+ import { registerOpenAPI } from './open-api/register'
3
3
  import { Ability } from './auth'
4
4
  import createApp from './create-app'
5
5
 
@@ -14,6 +14,6 @@ Ability.roles = Config.get('roles', {})
14
14
 
15
15
  // @ts-ignore
16
16
  const app = createApp({ routes })
17
- OAS.register(app, Config.get('rajt', {}))
17
+ registerOpenAPI(app, Config.get('rajt', {}))
18
18
 
19
19
  export { app }
package/src/request.ts CHANGED
@@ -78,11 +78,13 @@ export default class $Request {
78
78
  }
79
79
 
80
80
  get ip(): string | undefined {
81
- return this.#c.req.header('cf-connecting-ip')
82
- || this.#c.req.header('x-forwarded-for')?.split(',')[0]?.trim()
81
+ return this.#c.req.header('cf-connecting-ip') // cf
82
+ || this.#c.req.header('x-forwarded-for')?.split(',').at(-1)?.trim() // aws lambda
83
83
  || this.#c.env?.aws?.lambda?.event?.requestContext?.identity?.sourceIp
84
- || this.#c.req.header('x-real-ip')
85
- || this.#c.env?.remoteAddr?.hostname
84
+ || this.#c.env?.event?.Records[0]?.cf?.request?.clientIp // aws lambda@edge
85
+ || this.#c.req.header('x-real-ip') // vercel
86
+ || this.#c.env?.context?.ip // netlify
87
+ || this.#c.env?.remoteAddr?.hostname // deno
86
88
  }
87
89
 
88
90
  get userAgent(): string | undefined {
package/src/routes.ts CHANGED
@@ -13,12 +13,12 @@ import versionSHA from './utils/version-sha'
13
13
  import type { Routes, StandardSchemaV1 } from './types'
14
14
  import { rn, substep, warn } from './utils/log'
15
15
  import { _root } from './utils/paths'
16
-
17
- import OAS from './oas'
18
- import z from 'zod'
19
- import { resolver } from 'hono-openapi'
16
+ import { generateOpenAPI } from './open-api/spec'
17
+ import type * as z from 'zod'
18
+ import { describeRoute, resolver } from 'hono-openapi'
20
19
  import { mimes } from 'hono/utils/mime'
21
20
  import { STATUS_CODES } from 'node:http'
21
+ import { mw, resolve as _resolve } from './utils/resolve'
22
22
 
23
23
  import { highlightedMethod, highlightedURI } from './cli/utils'
24
24
 
@@ -344,7 +344,9 @@ export async function cacheRoutes() {
344
344
  middlewares.forEach(mw => registerMiddleware(mw.handle))
345
345
 
346
346
  // @ts-ignore
347
- const openApi = await OAS.generateSpecs(createApp({ routes }), configs?.rajt || {})
347
+ const openApi = await generateOpenAPI(createApp({ routes, routeRegister: (app: Hono, route: Route) => {
348
+ app[route.method](route.path, describeRoute(route.desc), ...mw(route.middlewares, route.name), ..._resolve(route.handle, route.name))
349
+ } }), configs?.rajt || {})
348
350
 
349
351
  const iPath = join(_root, '.rajt/imports.mjs')
350
352
  ensureDir(iPath)
package/src/types.ts CHANGED
@@ -10,7 +10,7 @@ import { mimes, type BaseMime } from 'hono/utils/mime'
10
10
  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
- import z from 'zod'
13
+ import type * as z from 'zod'
14
14
  import Action from './action'
15
15
  import request from './request'
16
16
  import response from './response'
package/src/utils/log.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { blue, bold, gray, green, magenta, red, yellow, white } from './colors'
1
+ import { blue, bold, gray, green, magenta, red, yellow, white } from 't0n/color'
2
2
 
3
3
  const _step = (color: Function, ...msg: any[]) => {
4
4
  const length = msg.length
@@ -1,3 +1,5 @@
1
+ import { getHandler } from '../register'
2
+
1
3
  export function resolve(obj: any, id: string) {
2
4
  if (typeof obj == 'function' && obj?.length == 2)
3
5
  return [obj]
@@ -33,3 +35,11 @@ export function resolveMiddleware(obj: any) {
33
35
 
34
36
  throw new Error('Invalid middleware provided. Must be a Hono middleware function or MiddlewareClass instance/constructor')
35
37
  }
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,5 +1,5 @@
1
- import { ZodObject } from 'zod'
2
- import { validator } from 'hono-openapi'
1
+ import type * as z from 'zod'
2
+ import { zValidator } from '@hono/zod-validator'
3
3
  import response from './response'
4
4
  import type {
5
5
  Rule, Rules,
@@ -7,11 +7,11 @@ import type {
7
7
  } from './types'
8
8
 
9
9
  export default class $Validator {
10
- private static cache = new Map<string, (schema: ZodObject<any>) => Rule>()
10
+ private static cache = new Map<string, (schema: z.ZodObject<any>) => Rule>()
11
11
 
12
12
  private static createRule<T extends keyof ValidationTargets>(
13
13
  target: T,
14
- schema: ZodObject<any>
14
+ schema: z.ZodObject<any>
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: ZodObject<any>) => this.createRule(target, schema)
27
+ const fn = (schema: z.ZodObject<any>) => this.createRule(target, schema)
28
28
  this.cache.set(target, fn)
29
29
  return fn
30
30
  }
@@ -38,9 +38,9 @@ export default class $Validator {
38
38
 
39
39
  static parse(rules: Rules): Function[] {
40
40
  return (Array.isArray(rules) ? rules : [rules]) // @ts-ignore
41
- .flatMap(rule => validator(rule.target, rule.schema, (result, c) => {
41
+ .flatMap(rule => zValidator(rule.target, rule.schema, (result, c) => {
42
42
  if (!result.success) // @ts-ignore
43
- return response.badRequest(result.error)
43
+ return response.badRequest({ ...result.error.flatten()[rule.eTarget] })
44
44
  }))
45
45
  }
46
46
  }
package/src/oas.ts DELETED
@@ -1,110 +0,0 @@
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 TODO: remove dependency of 'package.json'...
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
- }
@@ -1,102 +0,0 @@
1
- // ISC License
2
-
3
- // Copyright (c) 2021 Alexey Raspopov, Kostiantyn Denysov, Anton Verinov
4
-
5
- // Permission to use, copy, modify, and/or distribute this software for any
6
- // purpose with or without fee is hereby granted, provided that the above
7
- // copyright notice and this permission notice appear in all copies.
8
-
9
- // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
- // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
- // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
- // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
- // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
- // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
- // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
- //
17
- // https://github.com/alexeyraspopov/picocolors/commit/6f0a4638348ed20633d623ee973f9c9a96f65104
18
-
19
- import { getColorEnabledAsync } from 'hono/utils/color'
20
-
21
- export const enabled = await getColorEnabledAsync()
22
- export const isColorSupported = enabled
23
-
24
- // const { env, stdout } = globalThis?.process ?? {}
25
- // const enabled =
26
- // env &&
27
- // !env.NO_COLOR &&
28
- // (env.FORCE_COLOR || (stdout?.isTTY && !env.CI && env.TERM !== 'dumb'))
29
-
30
- const replaceClose = (
31
- str: string,
32
- close: string,
33
- replace: string,
34
- index: number
35
- ): string => {
36
- const start = str.substring(0, index) + replace
37
- const end = str.substring(index + close.length)
38
- const nextIndex = end.indexOf(close)
39
- return ~nextIndex
40
- ? start + replaceClose(end, close, replace, nextIndex)
41
- : start + end
42
- }
43
-
44
- const formatter = (open: string, close: string, replace = open) => {
45
- if (!enabled) return String
46
- return (input: string) => {
47
- const string = '' + input
48
- const index = string.indexOf(close, open.length)
49
- return ~index
50
- ? open + replaceClose(string, close, replace, index) + close
51
- : open + string + close
52
- }
53
- }
54
-
55
- export const reset = enabled ? (s: string) => `\x1b[0m${s}\x1b[0m` : String
56
- export const bold = formatter('\x1b[1m', '\x1b[22m', '\x1b[22m\x1b[1m')
57
- export const dim = formatter('\x1b[2m', '\x1b[22m', '\x1b[22m\x1b[2m')
58
- export const italic = formatter('\x1b[3m', '\x1b[23m')
59
- export const underline = formatter('\x1b[4m', '\x1b[24m')
60
- export const inverse = formatter('\x1b[7m', '\x1b[27m')
61
- export const hidden = formatter('\x1b[8m', '\x1b[28m')
62
- export const strikethrough = formatter('\x1b[9m', '\x1b[29m')
63
-
64
- const endText = '\x1b[39m'
65
- export const black = formatter('\x1b[30m', endText)
66
- export const red = formatter('\x1b[31m', endText)
67
- export const green = formatter('\x1b[32m', endText)
68
- export const yellow = formatter('\x1b[33m', endText)
69
- export const blue = formatter('\x1b[34m', endText)
70
- export const magenta = formatter('\x1b[35m', endText)
71
- export const purple = formatter('\x1b[38;2;173;127;168m', endText)
72
- export const cyan = formatter('\x1b[36m', endText)
73
- export const white = formatter('\x1b[37m', endText)
74
- export const gray = formatter('\x1b[90m', endText)
75
-
76
- const endBg = '\x1b[49m'
77
- export const bgBlack = formatter('\x1b[40m', endBg)
78
- export const bgRed = formatter('\x1b[41m', endBg)
79
- export const bgGreen = formatter('\x1b[42m', endBg)
80
- export const bgYellow = formatter('\x1b[43m', endBg)
81
- export const bgBlue = formatter('\x1b[44m', endBg)
82
- export const bgMagenta = formatter('\x1b[45m', endBg)
83
- export const bgCyan = formatter('\x1b[46m', endBg)
84
- export const bgWhite = formatter('\x1b[47m', endBg)
85
-
86
- export const blackBright = formatter("\x1b[90m", endText)
87
- export const redBright = formatter("\x1b[91m", endText)
88
- export const greenBright = formatter("\x1b[92m", endText)
89
- export const yellowBright = formatter("\x1b[93m", endText)
90
- export const blueBright = formatter("\x1b[94m", endText)
91
- export const magentaBright = formatter("\x1b[95m", endText)
92
- export const cyanBright = formatter("\x1b[96m", endText)
93
- export const whiteBright = formatter("\x1b[97m", endText)
94
-
95
- export const bgBlackBright = formatter("\x1b[100m", endBg)
96
- export const bgRedBright = formatter("\x1b[101m", endBg)
97
- export const bgGreenBright = formatter("\x1b[102m", endBg)
98
- export const bgYellowBright = formatter("\x1b[103m", endBg)
99
- export const bgBlueBright = formatter("\x1b[104m", endBg)
100
- export const bgMagentaBright = formatter("\x1b[105m", endBg)
101
- export const bgCyanBright = formatter("\x1b[106m", endBg)
102
- export const bgWhiteBright = formatter("\x1b[107m", endBg)