rajt 0.0.71 → 0.0.72

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,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.71",
4
+ "version": "0.0.72",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
@@ -25,7 +25,6 @@
25
25
  "src"
26
26
  ],
27
27
  "scripts": {
28
- "rajt": "./src/bin/rajt.js",
29
28
  "aws:local": "bun run --silent aws:build && bun run --silent sam:local",
30
29
  "aws:package": "bun run --silent aws:build && bun run --silent sam:package",
31
30
  "aws:deploy": "bun run --silent aws:build && bun run --silent sam:package && bun run --silent sam:deploy",
@@ -34,11 +33,7 @@
34
33
  "sam:package": "sam package --template-file ../../template-prod.yaml --output-template-file ../../packaged.yaml",
35
34
  "sam:deploy": "sam deploy --template-file ../../packaged.yaml --stack-name rajt-llrt --capabilities CAPABILITY_IAM",
36
35
  "sam:update": "source ../../.env.prod && aws lambda update-function-code --function-name $AWS_NAME --zip-file fileb://../../lambda.zip --region $AWS_REGION --no-cli-pager 2>&1 >/dev/null",
37
- "clean": "rm -rf ../../dist ../../tmp",
38
- "clean:build": "rm -rf ../../dist",
39
- "clean:temp": "rm -rf ../../tmp",
40
- "zip": "zip -j ../../lambda.zip ../../dist/index.js",
41
- "start": "node ../../dist/index.js"
36
+ "zip": "zip -j ../../lambda.zip ../../dist/index.js"
42
37
  },
43
38
  "dependencies": {
44
39
  "cripta": "^0.1",
@@ -97,8 +92,11 @@
97
92
  "application",
98
93
  "framework",
99
94
  "router",
95
+ "serverless",
96
+ "typescript",
100
97
  "cloudflare",
101
98
  "workers",
99
+ "vercel",
102
100
  "deno",
103
101
  "bun",
104
102
  "nodejs"
@@ -1,7 +1,7 @@
1
1
  import { defineCommand } from 'citty'
2
2
  import { gray } from '../../utils/colors'
3
3
  import { build, normalizePlatform, platformError } from './utils'
4
- import { wait, error } from '../../utils/log'
4
+ import { wait, error, rn } from '../../utils/log'
5
5
 
6
6
  import { platforms } from './constants'
7
7
 
@@ -27,11 +27,11 @@ export default defineCommand({
27
27
 
28
28
  try {
29
29
  await build(platform)
30
- } catch (e) {
31
- error('Build failed:', e)
30
+ } catch (e: any) {
31
+ error('Build failed:', e?.message || e)
32
32
  process.exit(0)
33
33
  } finally {
34
- console.log('\t')
34
+ rn()
35
35
  }
36
36
  },
37
37
  })
@@ -53,8 +53,8 @@ export default defineCommand({
53
53
  try {
54
54
  await build(platform)
55
55
  if (!lambda) await startLambda()
56
- } catch (e) {
57
- error('Build failed:', e)
56
+ } catch (e: any) {
57
+ error('Build failed:', e?.message || e)
58
58
  process.exit(0)
59
59
  } finally {
60
60
  isBuilding = false
@@ -141,8 +141,8 @@ export default defineCommand({
141
141
  try {
142
142
  await build(platform)
143
143
  await startWorker()
144
- } catch (e) {
145
- error('Build failed:', e)
144
+ } catch (e: any) {
145
+ error('Build failed:', e?.message || e)
146
146
  process.exit(0)
147
147
  } finally {
148
148
  isBuilding = false
@@ -0,0 +1,106 @@
1
+ import { join } from 'node:path'
2
+ import { defineCommand } from 'citty'
3
+ import { inspectRoutes } from 'hono/dev'
4
+ import { gray, purple, red, yellow } from '../../utils/colors'
5
+ import { __rajt } from './utils'
6
+ import { rn } from '../../utils/log'
7
+ import IMPORT from '../../utils/import'
8
+
9
+ export default defineCommand({
10
+ meta: {
11
+ name: 'routes',
12
+ description: '📒 Displays all registered routes\n',
13
+ },
14
+ args: {
15
+ path: {
16
+ description: 'Filter the routes by path',
17
+ type: 'string',
18
+ },
19
+ method: {
20
+ description: 'Filter the routes by method',
21
+ type: 'string',
22
+ },
23
+ reverse: {
24
+ description: 'Reverse the ordering of the routes',
25
+ type: 'boolean',
26
+ },
27
+ },
28
+ async run({ args }) {
29
+ const mod = await IMPORT(join(__rajt, 'dev.ts'))
30
+ const app = mod.default
31
+
32
+ const opts = {
33
+ path: args?.path || '',
34
+ method: args?.method?.toUpperCase() || '',
35
+ reverse: !!args?.reverse,
36
+ }
37
+
38
+ const keys: Set<string> = new Set()
39
+ let maxMethodLength = 0
40
+ let maxPathLength = 0
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
+ let routes = inspectRoutes(app)
65
+ .filter(({ method, path, isMiddleware }) => {
66
+ const key = method + '-' + path
67
+ if (keys.has(key)) return false
68
+ keys.add(key)
69
+
70
+ let mLength = method.length
71
+ if (method == 'GET') mLength += 5
72
+
73
+ maxMethodLength = Math.max(maxMethodLength, mLength)
74
+ maxPathLength = Math.max(maxPathLength, path.length)
75
+
76
+ return [
77
+ !isMiddleware,
78
+ opts.path ? path.startsWith(opts.path) : true,
79
+ opts.method ? method == opts.method : true,
80
+ ].every(Boolean)
81
+ })
82
+
83
+ if (opts.reverse)
84
+ routes = routes.reverse()
85
+
86
+ routes.forEach(route => {
87
+ if (!route) return
88
+ const { method, path } = route
89
+
90
+ let mLength = method.length
91
+ let str = colorMethod(method)
92
+
93
+ if (method == 'GET') {
94
+ mLength += 5
95
+ str += gray('|') + colorMethod('HEAD')
96
+ }
97
+
98
+ console.log(str + ' '.repeat(maxMethodLength - mLength) +' '+ path.replace(
99
+ /(?::([a-zA-Z_][a-zA-Z0-9_]*)(\{[^}]+\})?|\*)/g,
100
+ _ => colorMethod(method, _)
101
+ ))
102
+ })
103
+
104
+ rn()
105
+ },
106
+ })
@@ -14,7 +14,7 @@ import { step, substep, event, error, warn } from '../../utils/log'
14
14
  import { platforms } from './constants'
15
15
 
16
16
  export const _root = join(dirname(new URL(import.meta.url).pathname), '../../../../../')
17
- const __rajt = join(_root, 'node_modules/rajt/src')
17
+ export const __rajt = join(_root, 'node_modules/rajt/src')
18
18
 
19
19
  export function normalizePlatform(platform: Platform) {
20
20
  platform = platform?.toLowerCase() as Platform
package/src/cli/index.ts CHANGED
@@ -5,10 +5,10 @@ import { logo } from '../utils/log'
5
5
  import { isColorSupported, gray } from '../utils/colors'
6
6
  import { version as rajtVersion } from '../../package.json'
7
7
 
8
-
9
8
  import dev from './commands/dev'
10
9
  import build from './commands/build'
11
10
  import deploy from './commands/deploy'
11
+ import routes from './commands/routes'
12
12
 
13
13
  /**
14
14
  * The main entrypoint for the CLI.
@@ -56,6 +56,8 @@ if (directly()) {
56
56
  dev,
57
57
  build,
58
58
  deploy,
59
+ routes,
60
+ endpoints: routes,
59
61
  },
60
62
  })
61
63
 
package/src/create-app.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Hono } from 'hono'
2
2
  import { logger } from 'hono/logger'
3
+ import { matchedRoutes } from 'hono/route'
3
4
  import { Envir } from 't0n'
4
5
  import type {
5
6
  Env, Context, Next,
@@ -64,8 +65,31 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
64
65
  // const root = options?.root ?? '/'
65
66
  const app = options?.app ?? new Hono<E>()
66
67
 
67
- if (isDev())
68
- app.use('*', logger((...args: any[]) => console.log(gray(localDate()), ...args)))
68
+ if (isDev()) {
69
+ app.use('*', async function (c: Context, next: Next) {
70
+ const method = c.req.method
71
+ const route = matchedRoutes(c).find(route => route.method == method)?.path
72
+ const logWithRoute = (args: string[]) => {
73
+ if (!route || !args.length) return args
74
+ return args.map(arg => {
75
+ if (!arg) return arg
76
+ const split = arg?.split(' ')
77
+ if (split.length < 3 || split[2] == route)
78
+ return arg
79
+
80
+ split.splice(Math.min(3, split.length), 0, gray(route))
81
+ return split.join(' ')
82
+ })
83
+ }
84
+
85
+ const devLogger = logger((...args: any[]) => {
86
+ const timestamp = gray(localDate())
87
+ console.log(timestamp, ...logWithRoute(args))
88
+ })
89
+
90
+ await devLogger(c, next)
91
+ })
92
+ }
69
93
 
70
94
  app.use(async (c: Context, next: Next) => {
71
95
  c.set(GET_REQUEST as unknown as string, new request(c))
package/src/register.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  export const handlers: Record<string, Function> = {}
2
2
 
3
3
  export function registerHandler(id: string, handler: any) {
4
- if (id in handlers)
5
- console.warn(`🟠 Handler "${id}" has already been registered`)
4
+ // if (id in handlers)
5
+ // console.warn(`Handler "${id}" has already been registered`)
6
6
 
7
7
  handlers[id] = handler
8
8
  }
package/src/request.ts CHANGED
@@ -3,6 +3,8 @@ import { HTTPException } from 'hono/http-exception'
3
3
  import { Authnz, Token } from './auth'
4
4
 
5
5
  import type { Context } from 'hono'
6
+ import { routePath, matchedRoutes } from 'hono/route'
7
+ import type { RouterRoute } from 'hono/types'
6
8
  import type { CookieOptions, CookiePrefixOptions } from 'hono/utils/cookie'
7
9
  import type { CustomHeader, RequestHeader } from 'hono/utils/headers'
8
10
  import type { BodyData, ParseBodyOptions } from 'hono/utils/body'
@@ -25,6 +27,8 @@ export default class $Request {
25
27
  #u: Authnz<any> | null = null
26
28
 
27
29
  #host: string
30
+ #routePath: string
31
+ #matchedRoutes: RouterRoute[]
28
32
 
29
33
  constructor(c: Context) {
30
34
  this.#c = c
@@ -33,6 +37,9 @@ export default class $Request {
33
37
 
34
38
  const url = new URL(c.req.raw.url)
35
39
  this.#host = url.protocol +'//'+ url.host
40
+
41
+ this.#routePath = routePath(c)
42
+ this.#matchedRoutes = matchedRoutes(c)
36
43
  }
37
44
 
38
45
  get user() {
@@ -83,7 +90,7 @@ export default class $Request {
83
90
  }
84
91
 
85
92
  get routePath() {
86
- return this.#c.req.routePath
93
+ return this.#routePath
87
94
  }
88
95
 
89
96
  get url() {
@@ -98,12 +105,17 @@ export default class $Request {
98
105
  return this.#c.req.path
99
106
  }
100
107
 
108
+ get fullPath() {
109
+ const url = this.url
110
+ return url.slice(url.indexOf('/', 8))
111
+ }
112
+
101
113
  get method() {
102
114
  return this.#c.req.raw.method
103
115
  }
104
116
 
105
117
  get matchedRoutes() {
106
- return this.#c.req.matchedRoutes
118
+ return this.#matchedRoutes
107
119
  }
108
120
 
109
121
  get raw() {
package/src/routes.ts CHANGED
@@ -9,6 +9,7 @@ import { isAnonFn } from './utils/func'
9
9
  import ensureDir from './utils/ensuredir'
10
10
  import versionSHA from './utils/version-sha'
11
11
  import type { Route } from './types'
12
+ import { error, substep, warn } from './utils/log'
12
13
 
13
14
  const __filename = new URL(import.meta.url).pathname
14
15
  const __root = resolve(dirname(__filename), '../../..')
@@ -42,11 +43,16 @@ const walk = async (dir: string, baseDir: string, fn: Function, parentMw: string
42
43
  }
43
44
  }
44
45
 
46
+ let hasDuplicatedRoutes = false
45
47
  export async function getRoutes(
46
48
  dirs: string[] = ['actions', 'features', 'routes']
47
49
  ): Promise<Route[]> {
50
+ hasDuplicatedRoutes = false
48
51
  const routes: Route[] = []
49
- let mw: string[] = []
52
+
53
+ let length = 0
54
+ const keys: Set<string> = new Set()
55
+ const bag: Record<string, string[]> = {}
50
56
 
51
57
  await Promise.all(dirs.map(dir => walk(
52
58
  resolve(__root, dir),
@@ -66,9 +72,24 @@ export async function getRoutes(
66
72
  middlewares,
67
73
  handle,
68
74
  })
75
+
76
+ if (!keys.has(name)) {
77
+ keys.add(name)
78
+ } else {
79
+ ;(bag[name] ||= []).push(file)
80
+ length++
81
+ }
69
82
  }
70
83
  )))
71
84
 
85
+ if (length) {
86
+ hasDuplicatedRoutes = true
87
+ Object.entries(bag).forEach(([name, paths]) => {
88
+ warn(`Route "${name}" has `+ (paths.length > 1 ? `registered ${paths.length} times:` : 'already been registered:'))
89
+ substep(...paths)
90
+ })
91
+ }
92
+
72
93
  return sortRoutes(routes)
73
94
  }
74
95
 
@@ -93,13 +114,13 @@ function extractHttpPath(file: string) {
93
114
  return route == '/' ? '/' : route.replace(/\/$/, '')
94
115
  }
95
116
 
96
- function sortRoutes(routes: Route[]) {
117
+ export function sortRoutes(routes: Route[]) {
97
118
  const metas = new Map<string, { score: number, segmentsCount: number }>()
98
119
 
99
120
  for (const route of routes)
100
121
  metas.set(route.path, computeRouteMeta(route.path))
101
122
 
102
- return routes.sort((a, b) => {
123
+ const list = routes.sort((a, b) => {
103
124
  const metaA = metas.get(a.path)!
104
125
  const metaB = metas.get(b.path)!
105
126
 
@@ -108,6 +129,13 @@ function sortRoutes(routes: Route[]) {
108
129
 
109
130
  return metaB.score - metaA.score
110
131
  })
132
+
133
+ while (list.length && list.at(-1)?.path == '/') {
134
+ const last = list.pop()
135
+ last && list.unshift(last)
136
+ }
137
+
138
+ return list
111
139
  }
112
140
 
113
141
  function computeRouteMeta(path: string) {
@@ -116,7 +144,7 @@ function computeRouteMeta(path: string) {
116
144
  let score = 0
117
145
  for (const segment of segments) {
118
146
  if (segment === '*') {
119
- score += 0
147
+ continue
120
148
  } else if (segment.startsWith(':')) {
121
149
  score += 1
122
150
  } else {
@@ -219,6 +247,9 @@ export async function cacheRoutes() {
219
247
  writeFileSync(rolePath, `export default {\n\n}`)
220
248
 
221
249
  const routes = await getRoutes()
250
+ if (hasDuplicatedRoutes)
251
+ throw new Error("The app can't build with duplicate routes")
252
+
222
253
  const middlewares = await getMiddlewares()
223
254
  const configs = Object.entries(await getConfigs())
224
255