rajt 0.0.96 → 0.0.97

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
@@ -93,8 +93,8 @@ function semiver(a, b, bool) {
93
93
  function directly() {
94
94
  try {
95
95
  const arg = (process.argv[1] || '')?.replace(/\\/g, '/');
96
- return arg?.endsWith('node_modules/.bin/rajt')
97
- || arg?.endsWith('node_modules/rajt/bin/rajt.js')
96
+ return arg?.endsWith('.bin/rajt')
97
+ || arg?.endsWith('rajt/bin/rajt.js')
98
98
  } catch {
99
99
  return false
100
100
  }
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.96",
4
+ "version": "0.0.97",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
7
7
  "bin": {
@@ -39,13 +39,14 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "cripta": "^0.1",
42
- "forj": "^0.1",
42
+ "forj": "0.1.7",
43
43
  "t0n": "^0.1",
44
44
  "@hono/node-server": "^1.19.9",
45
45
  "@hono/standard-validator": "^0.2.2",
46
46
  "@scalar/hono-api-reference": "^0.9.40",
47
- "chokidar-cli": "^3.0.0",
47
+ "chokidar": "^3.5.2",
48
48
  "citty": "^0.1.6",
49
+ "consola": "^3.4.2",
49
50
  "dotenv": "^16.5.0",
50
51
  "esbuild": "^0.25.2",
51
52
  "hono": "^4.11.7",
@@ -59,6 +60,7 @@
59
60
  "tsx": "^4.19.3",
60
61
  "ua-parser-js": "^2.0.8",
61
62
  "wrangler": "^4.61.0",
63
+ "zod": "^4.3.6",
62
64
  "zod-openapi": "4"
63
65
  },
64
66
  "devDependencies": {
@@ -72,8 +74,8 @@
72
74
  "@miniflare/sites": "^2.14.4",
73
75
  "@miniflare/storage-file": "^2.14.4",
74
76
  "@miniflare/web-sockets": "^2.14.4",
75
- "@types/node": "^20.11.0",
76
- "bun-types": "^1.2.14",
77
+ "@types/node": "^25.1.0",
78
+ "bun-types": "^1.3.8",
77
79
  "typescript": "^5.9.3"
78
80
  },
79
81
  "engines": {
@@ -109,4 +111,4 @@
109
111
  "bun",
110
112
  "nodejs"
111
113
  ]
112
- }
114
+ }
@@ -13,12 +13,6 @@ export class Ability {
13
13
  static fromRoutes(actions: Routes) {
14
14
  if (!actions?.length) return
15
15
 
16
- const paths = actions?.map(a => Array.isArray(a) ? a[0] + a[1] : a.method + a.path) || []
17
- const items = new Set(paths)
18
-
19
- if (items.size != actions.length)
20
- throw new Error(`Duplicate routes detected: "${paths.filter((path, index) => paths.indexOf(path) != index).join('", "')}"`)
21
-
22
16
  this.#abilities = Array.from(new Set(actions?.map(a => Array.isArray(a) ? a[3] : a.name) || []))
23
17
  .map(a => this.format(a))
24
18
  .filter(Boolean)
@@ -1,8 +1,9 @@
1
1
  import { spawn } from 'node:child_process'
2
2
  import { defineCommand } from 'citty'
3
3
 
4
- import { _root, normalizePlatform, platformError, getRuntime } from '../utils'
4
+ import { normalizePlatform, platformError, getRuntime } from '../utils'
5
5
  import { error } from '../../utils/log'
6
+ import { _root } from '../../utils/paths'
6
7
  import { platforms } from '../constants'
7
8
 
8
9
  import build from './build'
@@ -4,11 +4,12 @@ import { spawn, type ChildProcess } from 'node:child_process'
4
4
  import { defineCommand } from 'citty'
5
5
  import type { Miniflare } from 'miniflare'
6
6
  import {
7
- _root, build, wait, watch, normalizePlatform, platformError, getRuntime,
7
+ build, wait, watch, normalizePlatform, platformError, getRuntime,
8
8
  wranglerConfig, createMiniflare, localflareManifest,
9
9
  getDockerHost
10
10
  } from '../utils'
11
11
  import { error, event, log, rn, warn } from '../../utils/log'
12
+ import { _root } from '../../utils/paths'
12
13
  import { withPort } from '../../utils/port'
13
14
  import shutdown from '../../utils/shutdown'
14
15
 
@@ -165,7 +166,9 @@ export default defineCommand({
165
166
  let localflare: Miniflare | null = null
166
167
  const startWorker = async () => {
167
168
  if (worker) await worker.dispose()
168
- if (localflare) await localflare.dispose()
169
+ if (localflare) await localflare.dispose()
170
+
171
+ // await wait(500)
169
172
 
170
173
  const workerConfig = await wranglerConfig()
171
174
  workerConfig.host = host
@@ -179,7 +182,7 @@ export default defineCommand({
179
182
  ...workerConfig.vars,
180
183
  LOCALFLARE_MANIFEST: JSON.stringify(localflareManifest(workerConfig)),
181
184
  },
182
- main: 'node_modules/localflare-api/dist/worker/index.js',
185
+ main: '.rajt/localfire.js',
183
186
  port: 8788,
184
187
  inspectorPort: 9230,
185
188
  })
@@ -1,7 +1,8 @@
1
1
  import { defineCommand } from 'citty'
2
2
  import { join, relative } from 'pathe'
3
3
  import { Migrator } from 'forj'
4
- import { _root, makeFile, hasExt, camelCase, kebabCase } from '../utils'
4
+ import { makeFile, hasExt, camelCase, kebabCase } from '../utils'
5
+ import { _root } from '../../utils/paths'
5
6
  import { event, error } from '../../utils/log'
6
7
  import { dim } from '../../utils/colors'
7
8
  import * as stub from '../stubs'
@@ -3,7 +3,8 @@ import { spawn } from 'node:child_process'
3
3
  import { join } from 'pathe'
4
4
  import { Migrator } from 'forj'
5
5
  import { gray } from '../../utils/colors'
6
- import { _root, getRuntime, cleanDB, cleanDir } from '../utils'
6
+ import { getRuntime, cleanDB, cleanDir } from '../utils'
7
+ import { _root } from '../../utils/paths'
7
8
  import { wait, info, event, rn, error, log } from '../../utils/log'
8
9
 
9
10
  export default defineCommand({
@@ -2,9 +2,9 @@ import { join } from 'pathe'
2
2
  import { defineCommand } from 'citty'
3
3
  import { inspectRoutes } from 'hono/dev'
4
4
  import { IMPORT } from 't0n'
5
- import { gray, purple, red, yellow } from '../../utils/colors'
6
- import { __rajt } from '../utils'
5
+ import { _rajt } from '../../utils/paths'
7
6
  import { rn } from '../../utils/log'
7
+ import { highlightedURI, highlightedMethod } from '../utils'
8
8
 
9
9
  export default defineCommand({
10
10
  meta: {
@@ -26,7 +26,7 @@ export default defineCommand({
26
26
  },
27
27
  },
28
28
  async run({ args }) {
29
- const mod = await IMPORT(join(__rajt, 'dev.ts'))
29
+ const mod = await IMPORT(join(_rajt, 'dev.ts'))
30
30
  const app = mod.default
31
31
 
32
32
  const opts = {
@@ -39,28 +39,6 @@ export default defineCommand({
39
39
  let maxMethodLength = 0
40
40
  let maxPathLength = 0
41
41
 
42
- const colorMethod = (method: string, str?: string) => {
43
- const val = str || method
44
-
45
- switch (method) {
46
- case 'HEAD':
47
- case 'OPTIONS':
48
- case 'CONNECT':
49
- case 'TRACE':
50
- return gray(val)
51
- case 'GET':
52
- return purple(val)
53
- case 'POST':
54
- case 'PUT':
55
- case 'PATCH':
56
- return yellow(val)
57
- case 'DELETE':
58
- return red(val)
59
- }
60
-
61
- return val
62
- }
63
-
64
42
  let routes = inspectRoutes(app)
65
43
  .filter(({ method, path, isMiddleware }) => {
66
44
  const key = method + '-' + path
@@ -88,17 +66,12 @@ export default defineCommand({
88
66
  const { method, path } = route
89
67
 
90
68
  let mLength = method.length
91
- let str = colorMethod(method)
69
+ let str = highlightedMethod(method, null, true)
92
70
 
93
- if (method == 'GET') {
71
+ if (method == 'GET')
94
72
  mLength += 5
95
- str += gray('|') + colorMethod('HEAD')
96
- }
97
73
 
98
- console.log(str + ' '.repeat(maxMethodLength - mLength) +' '+ path.replace(
99
- /(?::([a-zA-Z_][a-zA-Z0-9_]*)(\{[^}]+\})?|\*)/g,
100
- _ => colorMethod(method, _)
101
- ))
74
+ console.log(str + ' '.repeat(maxMethodLength - mLength) +' '+ highlightedURI(path, method))
102
75
  })
103
76
 
104
77
  rn()
package/src/cli/utils.ts CHANGED
@@ -1,23 +1,21 @@
1
1
  import esbuild from 'esbuild'
2
2
  import { Miniflare } from 'miniflare'
3
- import { mkdirSync, existsSync, statSync, readdirSync, rmSync, unlinkSync, copyFileSync, writeFileSync } from 'node:fs'
3
+ import { mkdirSync, existsSync, statSync, readdirSync, rmSync, unlinkSync, copyFileSync, writeFileSync, readFileSync } from 'node:fs'
4
4
  import { readFile, stat, writeFile } from 'node:fs/promises'
5
5
  import { basename, dirname, join, relative } from 'pathe'
6
- import crypto, { createHash } from 'node:crypto'
6
+ import { createHash, createHmac } from 'node:crypto'
7
7
 
8
8
  import { findWranglerConfig, parseWranglerConfig, WRANGLER_CONFIG_FILES } from 'localflare-core'
9
9
  import type { WranglerConfig, LocalflareManifest } from 'localflare-core'
10
10
 
11
11
  import chokidar from 'chokidar'
12
- import { gray, bold, italic } from '../utils/colors'
12
+ import { gray, bold, italic, purple, yellow, red } from '../utils/colors'
13
13
  import type { ChokidarEventName, Platform } from './types'
14
14
 
15
15
  import { cacheRoutes } from '../routes'
16
16
  import { substep, event, error, wait as wwait, warn, log } from '../utils/log'
17
17
  import { platforms } from './constants'
18
-
19
- export const _root = join(dirname(new URL(import.meta.url).pathname), '../../../../')
20
- export const __rajt = join(_root, 'node_modules/rajt/src')
18
+ import { _rajt, _root } from '../utils/paths'
21
19
 
22
20
  export function normalizePlatform(platform: Platform) {
23
21
  platform = platform?.toLowerCase() as Platform
@@ -91,7 +89,7 @@ export const build = async (platform: Platform) => {
91
89
  // @ts-ignore
92
90
  platform = platform != 'node' ? '-'+ platform : ''
93
91
  const opts = {
94
- entryPoints: [join(__rajt, `prod${platform}.ts`)],
92
+ entryPoints: [join(_rajt, `prod${platform}.ts`)],
95
93
  bundle: true,
96
94
  minify: true,
97
95
  outfile: join(_root, dist +'/index.js'),
@@ -122,6 +120,12 @@ export const build = async (platform: Platform) => {
122
120
  // sourcemap: true,
123
121
  // logLevel: 'info',
124
122
  plugins: [
123
+ {
124
+ name: 'rajt-resolver',
125
+ setup(build) {
126
+ build.onResolve({ filter: /\.rajt[\/\\]/ }, args => ({ path: join(_root, args.path) }))
127
+ }
128
+ },
125
129
  {
126
130
  name: 'preserve-class-names',
127
131
  setup(build) {
@@ -199,11 +203,11 @@ export function cleanDir(path: string) {
199
203
  }
200
204
 
201
205
  function durableObjectNamespace(name: string, uniqueKey: string) {
202
- const key = crypto.createHash('sha256').update(uniqueKey).digest()
203
- const nameHmac = crypto.createHmac('sha256', key).update(name).digest().subarray(0, 16)
206
+ const key = createHash('sha256').update(uniqueKey).digest()
207
+ const nameHmac = createHmac('sha256', key).update(name).digest().subarray(0, 16)
204
208
  return Buffer.concat([
205
209
  nameHmac,
206
- crypto.createHmac('sha256', key).update(nameHmac).digest().subarray(0, 16)
210
+ createHmac('sha256', key).update(nameHmac).digest().subarray(0, 16)
207
211
  ]).toString('hex')
208
212
  }
209
213
 
@@ -474,3 +478,30 @@ export const camelCase = (text: string) =>
474
478
  .filter(word => word.length > 0)
475
479
  .map(word => word.charAt(0).toUpperCase() + word.slice(1))
476
480
  .join('')
481
+
482
+ export const highlightedMethod = (method: string, str?: string | null, siblings: boolean = false): string => {
483
+ const val = str || method
484
+
485
+ switch (method) {
486
+ case 'HEAD':
487
+ case 'OPTIONS':
488
+ case 'CONNECT':
489
+ case 'TRACE':
490
+ return gray(val)
491
+ case 'GET':
492
+ return purple(val) + (siblings ? gray('|') + highlightedMethod('HEAD') : '')
493
+ case 'POST':
494
+ case 'PUT':
495
+ case 'PATCH':
496
+ return yellow(val)
497
+ case 'DELETE':
498
+ return red(val)
499
+ }
500
+
501
+ return val
502
+ }
503
+
504
+ export const highlightedURI = (uri: string, method: string) => uri.replace(
505
+ /(?::([a-zA-Z_][a-zA-Z0-9_]*)(\{[^}]+\})?|\*)/g,
506
+ _ => highlightedMethod(method, _)
507
+ )
package/src/prod.ts CHANGED
@@ -4,9 +4,9 @@ import { Ability } from './auth'
4
4
  import createApp from './create-app'
5
5
 
6
6
  // @ts-ignore
7
- import '../../../.rajt/imports.mjs'
7
+ import '.rajt/imports.mjs'
8
8
  // @ts-ignore
9
- import routes from '../../../.rajt/routes.json'
9
+ import routes from '.rajt/routes.json'
10
10
 
11
11
  // @ts-ignore
12
12
  Ability.fromRoutes(routes)
package/src/routes.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { existsSync, readdirSync, statSync, writeFileSync } from 'node:fs'
2
- import { dirname, join, resolve } from 'pathe'
1
+ import { copyFileSync, existsSync, readdirSync, statSync, writeFileSync } from 'node:fs'
2
+ import { join, resolve, relative } from 'pathe'
3
3
 
4
4
  import glob from 'tiny-glob'
5
5
  import { config } from 'dotenv'
@@ -11,7 +11,8 @@ import { isAnonFn } from './utils/func'
11
11
  import ensureDir from './utils/ensuredir'
12
12
  import versionSHA from './utils/version-sha'
13
13
  import type { Routes, StandardSchemaV1 } from './types'
14
- import { substep, warn } from './utils/log'
14
+ import { rn, substep, warn } from './utils/log'
15
+ import { _root } from './utils/paths'
15
16
 
16
17
  import OAS from './oas'
17
18
  import z from 'zod'
@@ -19,8 +20,7 @@ import { resolver } from 'hono-openapi'
19
20
  import { mimes } from 'hono/utils/mime'
20
21
  import { STATUS_CODES } from 'node:http'
21
22
 
22
- const __filename = new URL(import.meta.url).pathname
23
- const __root = resolve(dirname(__filename), '../../..')
23
+ import { highlightedMethod, highlightedURI } from './cli/utils'
24
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> => {
@@ -105,9 +105,17 @@ export async function getRoutes(
105
105
  let length = 0
106
106
  const keys: Set<string> = new Set()
107
107
  const bag: Record<string, string[]> = {}
108
+ const _route = (key: string, _: string) => {
109
+ if (!keys.has(key)) {
110
+ keys.add(key)
111
+ } else {
112
+ ;(bag[key] ||= []).push(_)
113
+ length++
114
+ }
115
+ }
108
116
 
109
117
  await Promise.all(dirs.map(dir => walk(
110
- resolve(__root, dir),
118
+ resolve(_root, dir),
111
119
  dir,
112
120
  (path: string, baseDir: string, handle: any, middlewares: string[]) => {
113
121
  const name = importName(handle?.name)
@@ -136,21 +144,26 @@ export async function getRoutes(
136
144
  desc,
137
145
  })
138
146
 
139
- if (!keys.has(name)) {
140
- keys.add(name)
141
- } else {
142
- ;(bag[name] ||= []).push(file)
143
- length++
144
- }
147
+ const routeKey = method +'|'+ uri
148
+ _route(name, file)
149
+ _route(routeKey, file)
145
150
  }
146
151
  )))
147
152
 
148
153
  if (length) {
149
154
  hasDuplicatedRoutes = true
150
155
  Object.entries(bag).forEach(([name, paths]) => {
151
- warn(`Route "${name}" has `+ (paths.length > 1 ? `registered ${paths.length} times:` : 'already been registered:'))
156
+ if (name.includes('|')) {
157
+ let [method, uri] = name.split('|')
158
+ method = method.toUpperCase()
159
+ name = `${highlightedMethod(method, null, true)} "${highlightedURI(uri, method)}"`
160
+ }
161
+
162
+ warn(`Route ${name} has `+ (paths.length > 1 ? `registered ${paths.length} times:` : 'already been registered:'))
152
163
  substep(...paths)
153
164
  })
165
+
166
+ rn()
154
167
  }
155
168
 
156
169
  return sortRoutes(routes)
@@ -224,7 +237,7 @@ export async function getMiddlewares(
224
237
  const mw: Routes = []
225
238
 
226
239
  await Promise.all(dirs.map(dir => walk(
227
- resolve(__root, dir),
240
+ resolve(_root, dir),
228
241
  dir,
229
242
  (fullPath: string, baseDir: string, handle: any) => {
230
243
  // @ts-ignore
@@ -246,15 +259,15 @@ function extractName(file: string) {
246
259
  export async function getConfigs(
247
260
  dirs: string[] = ['configs']
248
261
  ): Promise<Record<string, any>> {
249
- dirs = dirs.filter(dir => existsSync(join(__root, dir)))
262
+ dirs = dirs.filter(dir => existsSync(join(_root, dir)))
250
263
  if (!dirs?.length) return {}
251
264
  const configs: Record<string, any> = {}
252
265
 
253
- const files = (await glob(join(__root, dirs?.length > 1 ? `{${dirs.join(',')}}` : dirs[0], '/**/*.{ts,js,cjs,mjs,json}')))
266
+ const files = (await glob(join(_root, dirs?.length > 1 ? `{${dirs.join(',')}}` : dirs[0], '/**/*.{ts,js,cjs,mjs,json}')))
254
267
  .filter(file => !file.includes('.d.'))
255
268
 
256
269
  for (const file of files) {
257
- const mod = await IMPORT(join(__root, file))
270
+ const mod = await IMPORT(join(_root, file))
258
271
  const keyPath = extractName(file).split('.')
259
272
 
260
273
  keyPath.reduce((acc, key, index) => {
@@ -296,16 +309,26 @@ function stringifyToJS(value: unknown): string {
296
309
  return 'undefined'
297
310
  }
298
311
 
312
+ export async function dependencyEntry(lib: string, root: string) {
313
+ const path = await import.meta.resolve(lib)
314
+ return relative(root, path.replace('file://', ''))
315
+ }
316
+
317
+ async function dependencyPath(lib: string) {
318
+ const entry = await dependencyEntry(lib, join(_root, '.rajt'))
319
+ return entry.substring(0, entry.lastIndexOf(lib) + lib.length)
320
+ }
321
+
299
322
  export async function cacheRoutes() {
300
323
  const env = Object.entries(
301
- config({ path: '../../.env.prod' })?.parsed || {}
324
+ config({ path: join(_root, '.env.prod') })?.parsed || {}
302
325
  ).filter(([key, val]) => key?.toLowerCase().indexOf('aws') != 0) // prevent AWS credentials
303
326
 
304
327
  const version = versionSHA('../../.git') // @ts-ignore
305
328
  env.push(['VERSION_SHA', process.env['VERSION_SHA'] = version]) // @ts-ignore
306
329
  env.push(['VERSION_HASH', process.env['VERSION_HASH'] = version?.substring(0, 7)])
307
330
 
308
- const rolePath = join(__root, 'configs/roles.ts')
331
+ const rolePath = join(_root, 'configs/roles.ts')
309
332
  ensureDir(rolePath)
310
333
  if (!existsSync(rolePath))
311
334
  writeFileSync(rolePath, `export default {\n\n}`)
@@ -323,13 +346,18 @@ export async function cacheRoutes() {
323
346
  // @ts-ignore
324
347
  const openApi = await OAS.generateSpecs(createApp({ routes }), configs?.rajt || {})
325
348
 
326
- const iPath = join(__root, '.rajt/imports.mjs')
349
+ const iPath = join(_root, '.rajt/imports.mjs')
327
350
  ensureDir(iPath)
351
+
352
+ const localfireEntry = await dependencyEntry('localflare-api', _root)
353
+ copyFileSync(localfireEntry, join(_root, '.rajt/localfire.js'))
354
+
355
+ const _rajtDir = await dependencyPath('rajt')
328
356
  writeFileSync(iPath, `// AUTO-GENERATED FILE - DO NOT EDIT
329
- ${env?.length ? `import { Envir } from '../node_modules/t0n/dist/index'\nEnvir.add({${env.map(([key, val]) => key +':'+ stringifyToJS(val)).join(',')}})` : ''}
330
- ${Object.entries(configs)?.length ? `import Config from '../node_modules/rajt/src/config'\nConfig.add(${stringifyToJS(configs)})` : ''}
357
+ ${env?.length ? `import { Envir } from '${await dependencyPath('t0n')}/dist/index'\nEnvir.add({${env.map(([key, val]) => key +':'+ stringifyToJS(val)).join(',')}})` : ''}
358
+ ${Object.entries(configs)?.length ? `import Config from '${_rajtDir}/src/config'\nConfig.add(${stringifyToJS(configs)})` : ''}
331
359
 
332
- import { registerHandler, registerMiddleware } from '../node_modules/rajt/src/register'
360
+ import { registerHandler, registerMiddleware } from '${_rajtDir}/src/register'
333
361
 
334
362
  ${Object.entries(openApi)?.length ? `registerHandler('RAJT_OPENAPI', ${stringifyToJS(openApi)})` : ''}
335
363
 
@@ -355,7 +383,7 @@ try {
355
383
  }
356
384
  `)
357
385
 
358
- const rPath = join(__root, '.rajt/routes.json')
386
+ const rPath = join(_root, '.rajt/routes.json')
359
387
  ensureDir(rPath)
360
388
  writeFileSync(rPath, JSON.stringify(routes.filter(r => r.method && r.path).map(route => [
361
389
  route.method,
@@ -0,0 +1,5 @@
1
+ import { dirname, join } from 'pathe'
2
+ import { Envir } from 't0n'
3
+
4
+ export const _rajt = join(dirname(new URL(import.meta.url).pathname), '..')
5
+ export const _root = Envir.get('npm_config_local_prefix') || Envir.get('PWD') || join(_rajt, '../../../')