rajt 0.0.100 → 0.0.102

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/bin/rajt.js CHANGED
@@ -1,15 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from 'node:child_process';
3
- import { join, dirname } from 'node:path';
3
+ import { join, dirname, resolve } from 'node:path';
4
4
  import { existsSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
5
6
 
6
- const __dirname = dirname(new URL(import.meta.url).pathname);
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
8
 
8
9
  const ERR_NODE_VERSION = '18.0.0';
9
10
  const MIN_NODE_VERSION = '18.0.0';
10
11
 
11
- let rajtProcess;
12
-
13
12
  function runRajt() {
14
13
  if (process?.versions?.node && semiver(process.versions.node, ERR_NODE_VERSION) < 0) {
15
14
  console.error(
@@ -21,58 +20,70 @@ Consider using a Node.js version manager such as https://volta.sh or https://git
21
20
  return;
22
21
  }
23
22
 
24
- const isBun = process?.isBun || typeof Bun != 'undefined';
25
- let tsxPath;
26
-
27
- if (!isBun) {
28
- const _tsxPath = 'node_modules/.bin/tsx'
29
- const tsxPaths = [
30
- // join(__dirname, '../node_modules/.bin/tsx'),
31
- // join(__dirname, '../../.bin/tsx'),
32
- join(__dirname, '../'+ _tsxPath),
33
- join(__dirname, '../../'+ _tsxPath),
34
- join(process.cwd(), _tsxPath),
35
- 'tsx',
36
- ];
37
-
38
- for (const pathOption of tsxPaths) {
39
- if (pathOption == 'tsx' || existsSync(pathOption)) {
40
- tsxPath = pathOption;
41
- break;
42
- }
43
- }
23
+ const isBun = process?.isBun || typeof Bun !== 'undefined';
24
+ const targetScript = resolve(__dirname, '../src/cli/index.ts');
25
+
26
+ let executor = process.execPath;
27
+ let args = [];
28
+
29
+ if (isBun) {
30
+ args = [targetScript, ...process.argv.slice(2)];
31
+ } else {
32
+ const tsxBin = findTsx();
44
33
 
45
- if (!tsxPath) {
46
- console.error('TypeScript file found but tsx is not available. Please install tsx:');
34
+ if (!tsxBin) {
35
+ console.error('Error: "tsx" is not available. Please install tsx:');
47
36
  console.error(' npm i -D tsx');
48
37
  console.error(' or');
49
38
  console.error(' bun i -D tsx');
50
39
  process.exit(1);
51
- return;
52
40
  }
53
- }
54
41
 
55
- return spawn(
56
- process.execPath,
57
- [
42
+ args = [
58
43
  '--no-warnings',
59
- ...process.execArgv,
60
- tsxPath,
61
- join(__dirname, '../src/cli/index.ts').replace(/^\\/, ''),
62
- ...process.argv.slice(2),
63
- ].filter(arg => arg && !arg.includes('experimental-vm-modules') && !arg.includes('loader')),
64
- {
65
- stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
66
- env: {
67
- ...process.env,
68
- NODE_ENV: process.env.NODE_ENV || 'development',
69
- TSX_DISABLE_CACHE: process.env.TSX_DISABLE_CACHE || '1',
70
- }
44
+ tsxBin,
45
+ targetScript,
46
+ ...process.argv.slice(2)
47
+ ].filter(arg => !arg.includes('experimental-vm-modules') && !arg.includes('loader'));
48
+ }
49
+
50
+ return execute(executor, args)
51
+ }
52
+
53
+ function findTsx() {
54
+ const relativePaths = [
55
+ join(__dirname, '../node_modules/tsx/dist/cli.mjs'),
56
+ join(process.cwd(), 'node_modules/tsx/dist/cli.mjs'),
57
+ join(__dirname, '../node_modules/.bin/tsx'),
58
+ join(process.cwd(), 'node_modules/.bin/tsx'),
59
+ ];
60
+
61
+ for (const p of relativePaths) {
62
+ if (existsSync(p)) return p;
63
+ if (existsSync(`${p}.exe`)) return `${p}.exe`;
64
+ if (existsSync(`${p}.cmd`)) return `${p}.cmd`;
65
+ }
66
+
67
+ return null
68
+ }
69
+
70
+ function execute(command, args) {
71
+ const child = spawn(command, args, {
72
+ stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
73
+ env: {
74
+ ...process.env,
75
+ NODE_ENV: process.env.NODE_ENV || 'development',
76
+ TSX_DISABLE_CACHE: '1',
71
77
  }
72
- )
73
- .on('exit', code => process.exit(code == null ? 0 : code))
74
- .on('message', message => process.send && process.send(message))
75
- .on('disconnect', () => process.disconnect && process.disconnect());
78
+ });
79
+
80
+ process.on('SIGINT', () => child.kill('SIGINT'))
81
+ .on('SIGTERM', () => child.kill('SIGTERM'));
82
+
83
+ return child
84
+ .on('exit', code => process.exit(code ?? 0))
85
+ .on('message', msg => process.send?.(msg))
86
+ .on('disconnect', () => process.disconnect?.())
76
87
  }
77
88
 
78
89
  var fn = new Intl.Collator(0, { numeric: 1 }).compare;
@@ -101,7 +112,5 @@ function directly() {
101
112
  }
102
113
 
103
114
  if (directly()) {
104
- rajtProcess = runRajt();
105
- process.on('SIGINT', () => rajtProcess && rajtProcess.kill())
106
- .on('SIGTERM', () => rajtProcess && rajtProcess.kill());
115
+ runRajt()
107
116
  }
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.100",
4
+ "version": "0.0.102",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
7
7
  "files": ["bin", "src"],
@@ -35,25 +35,25 @@
35
35
  "zip": "zip -j ../../lambda.zip ../../.rajt/dist/index.js"
36
36
  },
37
37
  "dependencies": {
38
- "@hono/node-server": "^1.19.9",
38
+ "@hono/node-server": "^1.19.11",
39
39
  "@hono/standard-validator": "^0.2.2",
40
40
  "@hono/zod-validator": "^0.7.6",
41
- "@scalar/hono-api-reference": "^0.9.40",
41
+ "@scalar/hono-api-reference": "^0.10.3",
42
42
  "chokidar": "^3.5.2",
43
43
  "citty": "^0.1.6",
44
44
  "consola": "^3.4.2",
45
- "cripta": "^0.1.11",
45
+ "cripta": "^0.1.12",
46
46
  "dotenv": "^16.5.0",
47
47
  "esbuild": "^0.25.2",
48
- "forj": "^0.1.8",
49
- "hono": "^4.11.7",
48
+ "forj": "^0.1.10",
49
+ "hono": "^4.12.8",
50
50
  "hono-openapi": "^1.3.0",
51
- "localflare-api": "^0.4.2",
52
- "localflare-core": "^0.4.2",
53
- "miniflare": "^4.20260301.1",
51
+ "localflare-api": "^0.5.0",
52
+ "localflare-core": "^0.5.0",
53
+ "miniflare": "^4.20260312.0",
54
54
  "pathe": "^2.0",
55
55
  "quansync": "^0.2.11",
56
- "t0n": "^0.1.12",
56
+ "t0n": "^0.1.13",
57
57
  "tiny-glob": "^0.2",
58
58
  "tsx": "^4.19.4",
59
59
  "wrangler": "^4.61.0",
@@ -19,11 +19,11 @@ export class Ability {
19
19
  }
20
20
 
21
21
  static fromAction(target: any): string {
22
- return !target ? '' : this.format(typeof target == 'string' ? target : (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) {
26
- return path == '/'
26
+ return path === '/'
27
27
  ? 'index'
28
28
  : path.normalize('NFD')
29
29
  .replace(/[\u0300-\u036f]/g, '')
@@ -28,7 +28,7 @@ export default defineCommand({
28
28
 
29
29
  // @ts-ignore
30
30
  await build.run({ args: { platform } })
31
- const isBun = getRuntime() == 'bun'
31
+ const isBun = getRuntime() === 'bun'
32
32
 
33
33
  switch (platform) {
34
34
  case 'aws':
@@ -54,7 +54,7 @@ export default defineCommand({
54
54
  event('Building..')
55
55
  }
56
56
  const fn = async () => {
57
- building && await build(platform)
57
+ building && await build(platform, 'dev')
58
58
  await start()
59
59
  }
60
60
 
@@ -109,7 +109,7 @@ export default defineCommand({
109
109
 
110
110
  const started = (port: number) => {
111
111
  log(`Starting API on http://${host}:${port}`)
112
- if (platform == 'cf')
112
+ if (platform === 'cf')
113
113
  log(`Localflare on https://studio.localflare.dev`)
114
114
  rn()
115
115
  }
@@ -136,7 +136,7 @@ export default defineCommand({
136
136
  {
137
137
  stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
138
138
  // stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
139
- shell: process.platform == 'win32',
139
+ shell: process.platform === 'win32',
140
140
  env: {...process.env, DOCKER_HOST: getDockerHost()},
141
141
  }
142
142
  )
@@ -202,8 +202,8 @@ export default defineCommand({
202
202
  case 'node':
203
203
  return withPort(desiredPort, async (port) => {
204
204
  started(port)
205
- const isBun = getRuntime() == 'bun'
206
- const isWin32 = process.platform == 'win32'
205
+ const isBun = getRuntime() === 'bun'
206
+ const isWin32 = process.platform === 'win32'
207
207
  const params = isBun
208
208
  ? ['run', '--port=' + port, '--hot', '--silent', '--no-clear-screen', '--no-summary', join(_root, 'node_modules/rajt/src/dev.ts')]
209
209
  : [join(_root, 'node_modules/.bin/tsx' + (isWin32 ? '.exe' : '')), 'watch', join(_root, 'node_modules/rajt/src/dev-node.ts')]
@@ -19,13 +19,13 @@ export default defineCommand({
19
19
  },
20
20
  },
21
21
  async run({ args }) {
22
- if (args._.length != 2) {
22
+ if (args._.length !== 2) {
23
23
  error('Invalid args: '+ gray('[ACTION] [DATABASE]'))
24
24
  return rn()
25
25
  }
26
26
 
27
27
  const [action, database] = args._
28
- const isBun = getRuntime() == 'bun'
28
+ const isBun = getRuntime() === 'bun'
29
29
  const isRemote = !!args?.remote
30
30
 
31
31
  try {
@@ -46,15 +46,15 @@ export default defineCommand({
46
46
  keys.add(key)
47
47
 
48
48
  let mLength = method.length
49
- if (method == 'GET') mLength += 5
49
+ if (method === 'GET') mLength += 5
50
50
 
51
51
  maxMethodLength = Math.max(maxMethodLength, mLength)
52
52
  maxPathLength = Math.max(maxPathLength, path.length)
53
53
 
54
54
  return [
55
- isMiddleware && method != 'ALL' || !isMiddleware,
55
+ isMiddleware && method !== 'ALL' || !isMiddleware,
56
56
  opts.path ? path.startsWith(opts.path) : true,
57
- opts.method ? method == opts.method : true,
57
+ opts.method ? method === opts.method : true,
58
58
  ].every(Boolean)
59
59
  })
60
60
 
@@ -68,7 +68,7 @@ export default defineCommand({
68
68
  let mLength = method.length
69
69
  let str = highlightedMethod(method, null, true)
70
70
 
71
- if (method == 'GET')
71
+ if (method === 'GET')
72
72
  mLength += 5
73
73
 
74
74
  console.log(str + ' '.repeat(maxMethodLength - mLength) +' '+ highlightedURI(path, method))
package/src/cli/index.ts CHANGED
@@ -19,8 +19,8 @@ import make from './commands/make'
19
19
  const directly = () => {
20
20
  try {
21
21
  // @ts-ignore
22
- return typeof vitest == 'undefined'
23
- && import.meta.url == `file://${process.argv[1].replace(/\\/g, '/')}`
22
+ return typeof vitest === 'undefined'
23
+ && import.meta.url?.endsWith(process.argv[1].replace(/\\/g, '/'))
24
24
  } catch {
25
25
  return false
26
26
  }
@@ -32,7 +32,7 @@ const version = [name, isColorSupported ? gray('v'+rajtVersion) : rajtVersion].j
32
32
  if (directly()) {
33
33
  const _args = process.argv.slice(2)
34
34
  const length = _args.length
35
- if (!length || (length == 1 && ['-v', '--version', '--v', '-version'].includes(_args[0]))) {
35
+ if (!length || (length === 1 && ['-v', '--version', '--v', '-version'].includes(_args[0]))) {
36
36
  console.log(version)
37
37
  process.exit(0)
38
38
  }
package/src/cli/stubs.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  export const replace = (str: string, map: Record<string, string>) => {
2
- if (!str || typeof str != 'string' || !map || typeof map != 'object') return str
2
+ if (!str || typeof str !== 'string' || !map || typeof map !== 'object') return str
3
3
  const entries = Object.entries(map)
4
4
  const length = entries?.length || 0
5
5
  if (!length) return str
6
6
 
7
7
  str = str.trimStart()
8
- if (length == 1)
8
+ if (length === 1)
9
9
  return str.replaceAll(entries[0][0], entries[0][1])
10
10
 
11
11
  return entries.reduce(
package/src/cli/utils.ts CHANGED
@@ -44,7 +44,7 @@ export const platformError = () => error(`Provide a valid platform: ${formatArgs
44
44
 
45
45
  export function getRuntime() {
46
46
  try {
47
- return process?.isBun || typeof Bun != 'undefined' ? 'bun' : 'node'
47
+ return process?.isBun || typeof Bun !== 'undefined' ? 'bun' : 'node'
48
48
  } catch {
49
49
  return 'node'
50
50
  }
@@ -117,10 +117,10 @@ function stripDecorators(source: string) {
117
117
  }
118
118
 
119
119
  const dist = '.rajt/dist'
120
- export const build = async (platform: Platform) => {
120
+ export const build = async (platform: Platform, env: string = 'prd') => {
121
121
  const startTime = Date.now()
122
122
 
123
- const isCF = platform == 'cf'
123
+ const isCF = platform === 'cf'
124
124
  cleanDir(join(_root, dist))
125
125
 
126
126
  if (isCF) {
@@ -138,7 +138,7 @@ export const build = async (platform: Platform) => {
138
138
  const encoder = new TextEncoder()
139
139
 
140
140
  // @ts-ignore
141
- platform = platform != 'node' ? '-'+ platform : ''
141
+ platform = platform !== 'node' ? '-'+ platform : ''
142
142
  const opts = {
143
143
  entryPoints: [join(_rajt, `prod${platform}.ts`)],
144
144
  bundle: true,
@@ -160,9 +160,10 @@ export const build = async (platform: Platform) => {
160
160
  ],
161
161
  metafile: true,
162
162
  write: false,
163
- // define: {
164
- // 'process.env.NODE_ENV': '"development"'
165
- // },
163
+ define: {
164
+ 'process.env.RAJT_ENV': env,
165
+ // 'process.env.NODE_ENV': '"development"',
166
+ },
166
167
  // tsconfig: join(_root, 'tsconfig.json'),
167
168
  // sourcemap: true,
168
169
  // logLevel: 'info',
@@ -257,7 +258,7 @@ export function cleanDB(key: string, config?: WranglerConfig) {
257
258
  config ??= wranglerConfig()
258
259
  if (!config?.d1_databases) return
259
260
  for (const db of config.d1_databases) {
260
- if (key == db.database_name || key == db.binding) {
261
+ if (key === db.database_name || key === db.binding) {
261
262
  const ns = 'miniflare-D1DatabaseObject'
262
263
  const fileName = join(ns, durableObjectNamespace(db.preview_database_id || db.database_id || db.binding, ns) +'.sqlite')
263
264
 
@@ -462,7 +463,7 @@ export async function wait(ms: number) {
462
463
  export function getDockerHost() {
463
464
  const platform = process.platform
464
465
 
465
- if (platform == 'darwin') {
466
+ if (platform === 'darwin') {
466
467
  for (const socket of [
467
468
  '/Users/'+ process.env.USER +'/.docker/run/docker.sock',
468
469
  '/var/run/docker.sock',
@@ -475,7 +476,7 @@ export function getDockerHost() {
475
476
  return 'tcp://localhost:2375'
476
477
  }
477
478
 
478
- return process.env.DOCKER_HOST || (platform == 'win32' ? 'tcp://localhost:2375' : 'unix:///var/run/docker.sock')
479
+ return process.env.DOCKER_HOST || (platform === 'win32' ? 'tcp://localhost:2375' : 'unix:///var/run/docker.sock')
479
480
  }
480
481
 
481
482
  export function makeFile(path: string, content: string) {
package/src/create-app.ts CHANGED
@@ -21,10 +21,10 @@ const EHandler = async (e: Error | HTTPResponseError) => {
21
21
  console.error(e)
22
22
 
23
23
  switch (true) {
24
- case 'status' in e && e.status == 401:
24
+ case 'status' in e && e.status === 401:
25
25
  return response.unauthorized()
26
26
 
27
- case 'status' in e && e.status == 400: // @ts-ignore
27
+ case 'status' in e && e.status === 400: // @ts-ignore
28
28
  return response.badRequest(null, e?.message)
29
29
 
30
30
  default:
@@ -69,13 +69,13 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
69
69
  if (isDev()) {
70
70
  app.use('*', async function (c: Context, next: Next) {
71
71
  const method = c.req.method
72
- const route = matchedRoutes(c).find(route => route.method == method)?.path
72
+ const route = matchedRoutes(c).find(route => route.method === method)?.path
73
73
  const logWithRoute = (args: string[]) => {
74
74
  if (!route || !args.length) return args
75
75
  return args.map(arg => {
76
76
  if (!arg) return arg
77
77
  const split = arg?.split(' ')
78
- if (split.length < 3 || split[2] == route)
78
+ if (split.length < 3 || split[2] === route)
79
79
  return arg
80
80
 
81
81
  split.splice(Math.min(3, split.length), 0, gray(route))
@@ -113,11 +113,11 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
113
113
  if (options?.init) options.init(app)
114
114
 
115
115
  const routes = options?.routes || [] // @ts-ignore
116
- const routeRegister = options?.routeRegister ? options.routeRegister : (_: Hono, route: Route) => { // @ts0ignore
116
+ const routeRegister = options?.routeRegister ? options.routeRegister : (_: Hono, route: Route) => {
117
117
  if (Array.isArray(route)) { // @ts-ignore
118
118
  _[getVerb[route[0]]](route[1], ...resolve(...route[2], route[3]))
119
119
  } else { // @ts-ignore
120
- _[route.method](route.path, ...resolve(...route.middlewares), route.handle)
120
+ _[route.method](route.path, ...resolve(...route.middlewares, route.handle))
121
121
  }
122
122
  }
123
123
 
package/src/http.ts CHANGED
@@ -29,10 +29,10 @@ export const getVerb = [
29
29
  ]
30
30
 
31
31
  function method(method: string, ...args: any[]): void | ClassDecorator {
32
- if (args.length == 1 && typeof args[0] == 'function')
32
+ if (args.length === 1 && typeof args[0] === 'function')
33
33
  return _method(method, '/', args[0])
34
34
 
35
- const path = typeof args[0] == 'string' ? args[0] : '/'
35
+ const path = typeof args[0] === 'string' ? args[0] : '/'
36
36
  return (target: Function) => _method(method, path, target)
37
37
  }
38
38
 
@@ -117,7 +117,7 @@ export function Middlewares(...handlers: MiddlewareType[]) {
117
117
  export function Auth(target: Function): void
118
118
  export function Auth(): ClassDecorator
119
119
  export function Auth(...args: any[]): void | ClassDecorator {
120
- if (args.length == 1 && typeof args[0] == 'function')
120
+ if (args.length === 1 && typeof args[0] === 'function')
121
121
  return _auth(args[0])
122
122
 
123
123
  return (target: any) => _auth(target)
@@ -61,7 +61,8 @@ export function registerOpenAPI(app: Hono, conf: any) {
61
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
62
  // hideDownloadButton: true,
63
63
  // onLoaded: () => document?.querySelectorAll('[href="https://www.scalar.com"]')?.forEach(el => el.remove()),
64
- customCss: `[href="https://www.scalar.com"]{display:none}`,
64
+ customCss: `[href="https://www.scalar.com"],.scalar-mcp-layer{display:none!important}`,
65
+ // favicon: 'https://example.com/favicon.png',
65
66
  })
66
67
  )
67
68
  }
package/src/request.ts CHANGED
@@ -27,6 +27,7 @@ export default class $Request {
27
27
  #u: Authnz<any> | null = null
28
28
 
29
29
  #host: string
30
+ #protocol: string
30
31
  #routePath?: string
31
32
  #matchedRoutes: RouterRoute[]
32
33
 
@@ -37,6 +38,7 @@ export default class $Request {
37
38
 
38
39
  const url = new URL(c.req.raw.url)
39
40
  this.#host = url.protocol +'//'+ url.host
41
+ this.#protocol = url.protocol
40
42
 
41
43
  this.#matchedRoutes = matchedRoutes(c)
42
44
  }
@@ -68,6 +70,13 @@ export default class $Request {
68
70
  return this.has(prop, value)
69
71
  }
70
72
 
73
+ createToken(data: any, exp: number) {
74
+ return Token.create(this, data, exp)
75
+ }
76
+ parseToken(token: string) {
77
+ return Token.parse(this, token)
78
+ }
79
+
71
80
  get cx() {
72
81
  return this.#c
73
82
  }
@@ -90,6 +99,10 @@ export default class $Request {
90
99
  return this.#c.req.header('user-agent')
91
100
  }
92
101
 
102
+ get protocol() {
103
+ return this.#protocol
104
+ }
105
+
93
106
  get url() {
94
107
  return this.#c.req.raw.url
95
108
  }
package/src/response.ts CHANGED
@@ -58,7 +58,7 @@ export default class $Response {
58
58
  headers?: HeaderRecord
59
59
  ): Response | Promise<Response> {
60
60
  const res = (html: string) => this.raw(status, html, 'text/html; charset=UTF-8' as BaseMime, headers)
61
- return typeof html == 'string'
61
+ return typeof html === 'string'
62
62
  ? res(html)
63
63
  : resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res)
64
64
  }
package/src/routes.ts CHANGED
@@ -4,11 +4,13 @@ import { join, resolve, relative } from 'pathe'
4
4
  import { IMPORT } from 't0n'
5
5
  import glob from 'tiny-glob'
6
6
  import { config } from 'dotenv'
7
- import { describeRoute, resolver } from 'hono-openapi'
7
+ import { describeRoute, resolver, validator } from 'hono-openapi'
8
8
  import { mimes } from 'hono/utils/mime'
9
9
  import { STATUS_CODES } from 'node:http'
10
10
  import { registerHandler, registerMiddleware } from './register'
11
11
  import createApp from './create-app'
12
+ import _response from './response'
13
+ import _validator from './validator'
12
14
  import { isAnonFn } from './utils/func'
13
15
  import ensureDir from './utils/ensuredir'
14
16
  import versionSHA from './utils/version-sha'
@@ -20,7 +22,7 @@ import { resolve as _resolve } from './utils/resolve'
20
22
  import { highlightedMethod, highlightedURI } from './cli/utils'
21
23
 
22
24
  import type * as z from 'zod'
23
- import type { Routes, StandardSchemaV1 } from './types'
25
+ import type { Routes, Rule, StandardSchemaV1 } from './types'
24
26
 
25
27
  const importName = (name?: string) => (name || 'Fn'+ Math.random().toString(36).substring(2)).replace(/\.ts$/, '')
26
28
  const walk = async (dir: string, baseDir: string, fn: Function, parentMw: string[] = []): Promise<void> => {
@@ -44,7 +46,7 @@ const walk = async (dir: string, baseDir: string, fn: Function, parentMw: string
44
46
 
45
47
  if (stat.isDirectory()) {
46
48
  await walk(fullPath, baseDir, fn, currentMw)
47
- } else if (file != 'index.ts' && file.endsWith('.ts') && !file.endsWith('.d.ts')) {
49
+ } else if (file !== 'index.ts' && file.endsWith('.ts') && !file.endsWith('.d.ts')) {
48
50
  const mod = await IMPORT(fullPath)
49
51
  fn(fullPath, baseDir, mod.default, currentMw)
50
52
  }
@@ -54,18 +56,18 @@ const walk = async (dir: string, baseDir: string, fn: Function, parentMw: string
54
56
  function isZodSchema(obj: any): obj is z.ZodType {
55
57
  return (
56
58
  obj &&
57
- typeof obj == 'object' &&
59
+ typeof obj === 'object' &&
58
60
  ('_def' in obj || '_type' in obj) &&
59
61
  (obj.safeParse !== undefined || obj.parse !== undefined)
60
62
  )
61
63
  }
62
64
 
63
65
  function ResolveDescribeSchema(obj: any, deep: boolean = false) {
64
- if (!obj || typeof obj != 'object') return obj
66
+ if (!obj || typeof obj !== 'object') return obj
65
67
  if (isZodSchema(obj))
66
68
  return { content: {'application/json': { schema: resolver(obj as unknown as StandardSchemaV1) }} }
67
69
 
68
- if (obj.content && typeof obj.content == 'object') {
70
+ if (obj.content && typeof obj.content === 'object') {
69
71
  for (const mediaType in obj.content) {
70
72
  const contentItem = obj.content[mediaType]
71
73
  if (contentItem?.schema && isZodSchema(contentItem.schema))
@@ -81,7 +83,7 @@ function ResolveDescribeSchema(obj: any, deep: boolean = false) {
81
83
  }
82
84
 
83
85
  for (const key in obj) {
84
- if (obj[key] && typeof obj[key] == 'object') {
86
+ if (obj[key] && typeof obj[key] === 'object') {
85
87
  obj[key] = ResolveDescribeSchema(obj[key], true)
86
88
 
87
89
  if (!deep && !obj[key]?.description) {
@@ -135,7 +137,7 @@ export async function getRoutes(
135
137
  }
136
138
 
137
139
  const mw = (handle.mw?.length ? [...handle.mw, ...middlewares] : middlewares).flatMap(obj => {
138
- return typeof obj == 'string' ? obj : obj?.name || null
140
+ return typeof obj === 'string' ? obj : obj?.name || null
139
141
  }).filter(Boolean) as Function[]
140
142
 
141
143
  routes.push({
@@ -191,7 +193,7 @@ function extractHttpPath(file: string) {
191
193
  .map(part => part.startsWith('[') && part.endsWith(']') ? ':'+ part.slice(1, -1) : part)
192
194
  .join('/')
193
195
 
194
- return route == '/' ? '/' : route.replace(/\/$/, '')
196
+ return route === '/' ? '/' : route.replace(/\/$/, '')
195
197
  }
196
198
 
197
199
  export function sortRoutes(routes: Routes) {
@@ -210,7 +212,7 @@ export function sortRoutes(routes: Routes) {
210
212
  return metaB.score - metaA.score
211
213
  })
212
214
 
213
- while (list.length && list.at(-1)?.path == '/') {
215
+ while (list.length && list.at(-1)?.path === '/') {
214
216
  const last = list.pop()
215
217
  last && list.unshift(last)
216
218
  }
@@ -275,9 +277,9 @@ export async function getConfigs(
275
277
  const keyPath = extractName(file).split('.')
276
278
 
277
279
  keyPath.reduce((acc, key, index) => {
278
- if (index == keyPath.length - 1) {
280
+ if (index === keyPath.length - 1) {
279
281
  acc[key] = mod.default
280
- } else if (!acc[key] || typeof acc[key] != 'object') {
282
+ } else if (!acc[key] || typeof acc[key] !== 'object') {
281
283
  acc[key] = {}
282
284
  }
283
285
 
@@ -295,15 +297,15 @@ function stringifyToJS(value: unknown): string {
295
297
 
296
298
  const type = typeof value
297
299
 
298
- if (type == 'string') return JSON.stringify(value)
299
- if (type == 'number' || type == 'boolean') return String(value)
300
- if (type == 'bigint') return `${value}n`
301
- if (type == 'function') return value.toString()
300
+ if (type === 'string') return JSON.stringify(value)
301
+ if (type === 'number' || type === 'boolean') return String(value)
302
+ if (type === 'bigint') return `${value}n`
303
+ if (type === 'function') return value.toString()
302
304
 
303
305
  if (Array.isArray(value))
304
306
  return `[${value.map(stringifyToJS).join(',')}]`
305
307
 
306
- if (type == 'object') {
308
+ if (type === 'object') {
307
309
  const entries = Object.entries(value as Record<string, unknown>)
308
310
  .map(([key, val]) => `${IDENTIFIER_RE.test(key) ? key : JSON.stringify(key)}:${stringifyToJS(val)}`)
309
311
 
@@ -326,7 +328,7 @@ async function dependencyPath(lib: string) {
326
328
  export async function cacheRoutes() {
327
329
  const env = Object.entries(
328
330
  config({ path: join(_root, '.env.prod') })?.parsed || {}
329
- ).filter(([key, val]) => key?.toLowerCase().indexOf('aws') != 0) // prevent AWS credentials
331
+ ).filter(([key, val]) => key?.toLowerCase().startsWith('aws')) // prevent AWS credentials
330
332
 
331
333
  const version = versionSHA('../../.git') // @ts-ignore
332
334
  env.push(['VERSION_SHA', process.env['VERSION_SHA'] = version]) // @ts-ignore
@@ -358,9 +360,13 @@ export async function cacheRoutes() {
358
360
  registerHandler(h[1], mod[h[1]])
359
361
  }
360
362
 
363
+ _validator.setParser((rule: Rule) => validator(rule.target, rule.schema, (result, c) => {
364
+ if (!result.success) // @ts-ignore
365
+ return _response.badRequest(result.error)
366
+ }))
361
367
  // @ts-ignore
362
368
  const openApi = await generateOpenAPI(createApp({ routes, routeRegister: (app: Hono, route: Route) => {
363
- app[route.method](route.path, describeRoute(route.desc), ..._resolve(...route.middlewares), route.handle)
369
+ app[route.method](route.path, describeRoute(route.desc), ..._resolve(...route.middlewares, route.handle))
364
370
  } }), configs?.rajt || {})
365
371
 
366
372
  const iPath = join(_root, '.rajt/imports.mjs')
@@ -374,7 +380,7 @@ export async function cacheRoutes() {
374
380
  stringifyToJS(Object.fromEntries(routes.map(r => ([r.path + r.method, r.name]))))
375
381
 
376
382
  writeFileSync(iPath, `// AUTO-GENERATED FILE - DO NOT EDIT
377
- ${env?.length ? `import { Envir } from '${await dependencyPath('t0n')}/dist/index'\nEnvir.add({${env.map(([key, val]) => key +':'+ stringifyToJS(val)).join(',')}})` : ''}
383
+ ${env?.length ? `import { Envir } from '${await dependencyPath('t0n')}/src/envir'\nEnvir.add({${env.map(([key, val]) => key +':'+ stringifyToJS(val)).join(',')}})` : ''}
378
384
  ${Object.entries(configs)?.length ? `import Config from '${_rajtDir}/src/config'\nConfig.add(${stringifyToJS(configs)})` : ''}
379
385
 
380
386
  import { registerHandler, registerMiddleware } from '${_rajtDir}/src/register'
@@ -1,16 +1,17 @@
1
1
  const prd = Symbol('prd')
2
2
  const dev = Symbol('dev')
3
3
 
4
- let env = prd
4
+ // @ts-ignore
5
+ let env = process.env.RAJT_ENV || detectEnvironment()
5
6
 
6
- export const getEnv = () => env
7
+ export const getEnv = () => env // @ts-ignore
7
8
  export const setEnv = (e: symbol) => env = e
8
9
 
9
- export function detectEnvironment() {
10
+ export function detectEnvironment(): symbol {
10
11
  try {
11
12
  if (
12
- process.env?.npm_lifecycle_event == 'dev'
13
- || process.env?.npm_lifecycle_script == 'rajt'
13
+ process.env?.npm_lifecycle_event === 'dev'
14
+ || process.env?.npm_lifecycle_script === 'rajt'
14
15
  || process.env?.AWS_SAM_LOCAL
15
16
  // || process?.argv?.includes('--dev')
16
17
  || process?.argv?.some(arg => ['-port', '-platform', '--dev', '--development', '--watch'].includes(arg))
@@ -24,10 +25,11 @@ export function detectEnvironment() {
24
25
  return prd
25
26
  }
26
27
 
27
- export const isEnv = (e: symbol) => env == e
28
+ export const isEnv = (e: symbol) => env === e
28
29
 
29
- export const isDev = () => env == dev
30
- export const isProd = () => env == prd
30
+ // @ts-ignore
31
+ export const isDev = () => env === dev
32
+ export const isProd = () => env === prd
31
33
 
32
34
  export const isDevelopment = isDev
33
35
  export const isProduction = isProd
package/src/utils/func.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  export const isAsyncFn = (fn: any) => {
2
- return fn?.constructor?.name == 'AsyncFunction'
2
+ return fn?.constructor?.name === 'AsyncFunction'
3
3
  || fn.toString().toLowerCase().trim().startsWith('async')
4
4
  }
5
5
 
6
6
  export const isAnonFn = (fn: any) => {
7
- return fn?.name == '' || fn?.name == 'anonymous'
7
+ return fn?.name === '' || fn?.name === 'anonymous'
8
8
  }
package/src/utils/log.ts CHANGED
@@ -54,7 +54,7 @@ const LOGGING_METHOD = {
54
54
 
55
55
  function prefixedLog(prefixType: keyof typeof prefixes, ...msg: any[]) {
56
56
  const length = msg.length
57
- if ((msg[0] === '' || msg[0] === undefined) && length == 1)
57
+ if ((msg[0] === '' || msg[0] === undefined) && length === 1)
58
58
  msg.shift()
59
59
 
60
60
  const consoleMethod: keyof typeof LOGGING_METHOD =
@@ -64,12 +64,12 @@ function prefixedLog(prefixType: keyof typeof prefixes, ...msg: any[]) {
64
64
 
65
65
  const prefix = prefixes[prefixType]
66
66
  // If there's no message, don't print the prefix but a new line
67
- if (length == 0) {
67
+ if (length === 0) {
68
68
  console[consoleMethod]('')
69
69
  } else {
70
70
  // Ensure if there's ANSI escape codes it's concatenated into one string.
71
71
  // Chrome DevTool can only handle color if it's in one string.
72
- if (length == 1 && typeof msg[0] == 'string') {
72
+ if (length === 1 && typeof msg[0] === 'string') {
73
73
  console[consoleMethod](prefix +' '+ msg[0])
74
74
  } else {
75
75
  console[consoleMethod](prefix, ...msg)
package/src/utils/port.ts CHANGED
@@ -5,7 +5,7 @@ import { error, warn } from './log'
5
5
  export function withPort(desiredPort: number, cb: (port: number) => void, maxAttempts = 10) {
6
6
  getAvailablePort(desiredPort)
7
7
  .then(([port, pid]) => {
8
- if (port != desiredPort)
8
+ if (port !== desiredPort)
9
9
  warn(
10
10
  `Port ${desiredPort} is in use by ${pid ? 'process '+ pid : 'an unknown process'}, using available port ${port} instead`
11
11
  )
@@ -3,10 +3,10 @@ import { getHandler } from '../register'
3
3
  export function resolve(...objs: any[]) {
4
4
  const _ = []
5
5
  for (let obj of objs) {
6
- if (typeof obj == 'string')
6
+ if (typeof obj === 'string')
7
7
  obj = getHandler(obj)
8
8
 
9
- if (typeof obj == 'function' && obj?.length == 2) {
9
+ if (typeof obj === 'function' && obj?.length === 2) {
10
10
 
11
11
  } else if (obj?.run) {
12
12
  _.push(...obj.run())
@@ -34,7 +34,7 @@ export function resolve(...objs: any[]) {
34
34
  }
35
35
 
36
36
  export function resolveMiddleware(obj: any) {
37
- if (typeof obj == 'function' && obj.length == 2)
37
+ if (typeof obj === 'function' && obj.length === 2)
38
38
  return obj
39
39
 
40
40
  if (obj?.factory)
package/src/validator.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { zValidator } from '@hono/zod-validator'
2
2
  import response from './response'
3
+ import type * as z from 'zod'
3
4
  import type {
4
5
  Rule, Rules, RuleFn,
5
6
  ValidationTargets,
6
7
  zObject,
8
+ MiddlewareHandler,
7
9
  } from './types'
8
10
 
9
11
  export default class $Validator {
@@ -36,11 +38,33 @@ export default class $Validator {
36
38
  static readonly header = $Validator.fn('header')!
37
39
  static readonly cookie = $Validator.fn('cookie')!
38
40
 
41
+ static #parser = (rule: Rule) => zValidator(rule.target, rule.schema, (result, c) => {
42
+ if (!result.success) // @ts-ignore
43
+ return response.badRequest(formatZodErrors(result.error.issues || []))
44
+ })
45
+
46
+ static setParser(parser: (rule: Rule) => MiddlewareHandler) {
47
+ this.#parser = parser
48
+ }
49
+
39
50
  static parse(rules: Rules): Function[] {
40
51
  return (Array.isArray(rules) ? rules : [rules]) // @ts-ignore
41
- .flatMap(rule => zValidator(rule.target, rule.schema, (result, c) => {
42
- if (!result.success) // @ts-ignore
43
- return response.badRequest({ ...result.error.flatten()[rule.eTarget] })
44
- }))
52
+ .flatMap(this.#parser)
53
+ }
54
+ }
55
+
56
+ function formatZodErrors(issues: z.ZodIssue[]): Record<string, string[]> {
57
+ const result: Record<string, string[]> = {}
58
+
59
+ for (const issue of issues) {
60
+ const path = issue.path.join('.')
61
+ const key = path || 'root'
62
+
63
+ if (!result[key])
64
+ result[key] = []
65
+
66
+ result[key].push(issue.message)
45
67
  }
68
+
69
+ return result
46
70
  }