rajt 0.0.60 → 0.0.62
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/README.md +9 -1
- package/bin/rajt.js +120 -0
- package/package.json +6 -4
- package/src/action.ts +2 -1
- package/src/cli/commands/dev/index.ts +34 -28
- package/src/cli/commands/dev/utils.ts +2 -3
- package/src/cli/index.ts +3 -5
- package/src/config.ts +76 -0
- package/src/create-app.ts +7 -4
- package/src/db/dynamodb.d.ts +1 -0
- package/src/db/dynamodb.ts +1 -0
- package/src/dev-node.ts +16 -0
- package/src/dev.ts +11 -21
- package/src/esbuild.mjs +2 -3
- package/src/http.ts +2 -1
- package/src/index.ts +4 -1
- package/src/prod.ts +5 -6
- package/src/request.ts +2 -0
- package/src/routes.ts +103 -21
- package/src/utils/import.ts +3 -0
- package/src/utils/json-import.ts +1 -3
- package/src/utils/logger.ts +10 -3
- package/src/bin/rajt.js +0 -123
package/README.md
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
<h1 align="left">λ Rajt<br/><a href="https://pr.new/attla/rajt"><img align="right" src="https://developer.stackblitz.com/img/start_pr_dark_small.svg" alt="Start new PR in StackBlitz Codeflow"></a><a href="https://npmjs.com/package/rajt"><img align="right" src="https://img.shields.io/npm/v/rajt.svg" alt="npm package"></a></h1>
|
|
2
|
+
|
|
3
|
+
> *Runtime-Agnostic for Javascript and TypeScript*.
|
|
4
|
+
|
|
5
|
+
> *From Hungarian **`[ˈrɒjt]`** (meaning "start") and Russian **`Райт`** (meaning "wright").*
|
|
6
|
+
|
|
7
|
+
<br/>
|
|
8
|
+
|
|
9
|
+
> ⚠️ Rajt is under ALFA development — expect updates, rough edges, and occasional breack changes.
|
|
2
10
|
<br/>
|
|
3
11
|
|
|
4
|
-
|
|
12
|
+
This framework is fully geared towards the serverless world, specifically AWS Lambda (Node.js, Bun and LLRT runtime) / Cloudflare Workers.
|
|
5
13
|
|
|
6
14
|
- 💡 Instant Server Start
|
|
7
15
|
- ⚡️ Fast Cold Start
|
package/bin/rajt.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(new URL(import.meta.url).pathname);
|
|
7
|
+
|
|
8
|
+
const ERR_NODE_VERSION = "18.0.0";
|
|
9
|
+
const MIN_NODE_VERSION = "18.0.0";
|
|
10
|
+
|
|
11
|
+
let rajtProcess;
|
|
12
|
+
|
|
13
|
+
function runRajt() {
|
|
14
|
+
if (process?.versions?.node && semiver(process.versions.node, ERR_NODE_VERSION) < 0) {
|
|
15
|
+
console.error(
|
|
16
|
+
`Rajt requires at least Node.js v${MIN_NODE_VERSION}. You are using v${process.versions.node}. Please update your version of Node.js.
|
|
17
|
+
|
|
18
|
+
Consider using a Node.js version manager such as https://volta.sh or https://github.com/nvm-sh/nvm.`
|
|
19
|
+
);
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const isBun = process?.isBun || typeof Bun != 'undefined';
|
|
25
|
+
let tsxPath;
|
|
26
|
+
// const params = isBun ? bunParams() : nodeParams();
|
|
27
|
+
|
|
28
|
+
if (!isBun) {
|
|
29
|
+
const tsxPaths = [
|
|
30
|
+
// join(__dirname, "../node_modules/.bin/tsx"),
|
|
31
|
+
// join(__dirname, "../../.bin/tsx"),
|
|
32
|
+
join(__dirname, "../node_modules/.bin/tsx"),
|
|
33
|
+
join(__dirname, "../../node_modules/.bin/tsx"),
|
|
34
|
+
join(process.cwd(), "node_modules/.bin/tsx"),
|
|
35
|
+
"tsx",
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
for (const pathOption of tsxPaths) {
|
|
39
|
+
if (pathOption == "tsx" || existsSync(pathOption)) {
|
|
40
|
+
tsxPath = pathOption;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!tsxPath) {
|
|
46
|
+
console.error("TypeScript file found but tsx is not available. Please install tsx:");
|
|
47
|
+
console.error(" npm i -D tsx");
|
|
48
|
+
console.error(" or");
|
|
49
|
+
console.error(" bun i -D tsx");
|
|
50
|
+
process.exit(1);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return spawn(
|
|
56
|
+
process.execPath,
|
|
57
|
+
[
|
|
58
|
+
"--no-warnings",
|
|
59
|
+
...process.execArgv,
|
|
60
|
+
tsxPath,
|
|
61
|
+
join(__dirname, "../src/cli/index.ts"),
|
|
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
|
+
}
|
|
71
|
+
}
|
|
72
|
+
).on("exit", (code) =>
|
|
73
|
+
process.exit(code == null ? 0 : code)
|
|
74
|
+
).on("message", (message) => {
|
|
75
|
+
if (process.send) {
|
|
76
|
+
process.send(message);
|
|
77
|
+
}
|
|
78
|
+
}).on("disconnect", () => {
|
|
79
|
+
if (process.disconnect) {
|
|
80
|
+
process.disconnect();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
var fn = new Intl.Collator(0, { numeric: 1 }).compare;
|
|
86
|
+
|
|
87
|
+
function semiver(a, b, bool) {
|
|
88
|
+
a = a.split(".");
|
|
89
|
+
b = b.split(".");
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
fn(a[0], b[0]) ||
|
|
93
|
+
fn(a[1], b[1]) ||
|
|
94
|
+
((b[2] = b.slice(2).join(".")),
|
|
95
|
+
(bool = /[.-]/.test((a[2] = a.slice(2).join(".")))),
|
|
96
|
+
bool == /[.-]/.test(b[2]) ? fn(a[2], b[2]) : bool ? -1 : 1)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function directly() {
|
|
101
|
+
try {
|
|
102
|
+
return process.env?.npm_lifecycle_script == 'rajt'
|
|
103
|
+
&& (
|
|
104
|
+
process.argv[1]?.endsWith('node_modules/.bin/rajt')
|
|
105
|
+
|| process.argv[1]?.endsWith('node_modules/rajt/bin/rajt.js')
|
|
106
|
+
)
|
|
107
|
+
} catch {
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (directly()) {
|
|
113
|
+
rajtProcess = runRajt();
|
|
114
|
+
process.on("SIGINT", () => {
|
|
115
|
+
rajtProcess && rajtProcess.kill();
|
|
116
|
+
});
|
|
117
|
+
process.on("SIGTERM", () => {
|
|
118
|
+
rajtProcess && rajtProcess.kill();
|
|
119
|
+
});
|
|
120
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
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.
|
|
4
|
+
"version": "0.0.62",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"rajt": "./
|
|
8
|
+
"rajt": "./bin/rajt.js"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./src/index.ts",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"./length": "./src/utils/length.ts"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
|
+
"bin",
|
|
24
25
|
"src"
|
|
25
26
|
],
|
|
26
27
|
"scripts": {
|
|
@@ -53,9 +54,10 @@
|
|
|
53
54
|
"dependencies": {
|
|
54
55
|
"@hono/zod-validator": "^0.4.3",
|
|
55
56
|
"cripta": "^0.1",
|
|
56
|
-
"forj": "^0.0.
|
|
57
|
+
"forj": "^0.0.4",
|
|
57
58
|
"hono": "^4.7.6",
|
|
58
|
-
"t0n": "^0.1
|
|
59
|
+
"t0n": "^0.1",
|
|
60
|
+
"tiny-glob": "^0.2",
|
|
59
61
|
"ua-parser-js": "^2.0.4"
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
package/src/action.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import response from './response'
|
|
2
2
|
import validator from './validator'
|
|
3
|
+
import { GET_REQUEST } from './request'
|
|
3
4
|
import type { Context, IRequest, IResponse, IValidator, Rules } from './types'
|
|
4
5
|
|
|
5
6
|
export default class Action {
|
|
6
7
|
static run() {
|
|
7
8
|
const rules = this.rules(validator)
|
|
8
|
-
const h = async (c: Context) => await this.handle(c.get(
|
|
9
|
+
const h = async (c: Context) => await this.handle(c.get(GET_REQUEST as unknown as string), response)
|
|
9
10
|
if (!rules) return [h]
|
|
10
11
|
|
|
11
12
|
const pipe = validator.parse(rules)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
|
-
import { fileURLToPath } from 'node:url'
|
|
3
2
|
import { dirname, join, relative } from 'node:path'
|
|
4
3
|
import { spawn, type ChildProcess } from 'node:child_process'
|
|
5
4
|
|
|
6
5
|
import chokidar from 'chokidar'
|
|
7
|
-
import colors from 'picocolors'
|
|
6
|
+
// import colors from 'picocolors'
|
|
8
7
|
import { defineCommand } from 'citty'
|
|
9
8
|
import type { ChokidarEventName } from '../../types'
|
|
10
9
|
|
|
@@ -13,7 +12,7 @@ import { build, createMiniflare } from './utils'
|
|
|
13
12
|
import { getAvailablePort } from '../../../utils/port'
|
|
14
13
|
import shutdown from '../../../utils/shutdown'
|
|
15
14
|
|
|
16
|
-
const __dirname = join(dirname(
|
|
15
|
+
const __dirname = join(dirname(new URL(import.meta.url).pathname), '../../../../../../')
|
|
17
16
|
|
|
18
17
|
export default defineCommand({
|
|
19
18
|
meta: {
|
|
@@ -36,7 +35,7 @@ export default defineCommand({
|
|
|
36
35
|
description: 'Environment platform',
|
|
37
36
|
type: 'enum',
|
|
38
37
|
options: ['aws', 'cf', 'node'] as const,
|
|
39
|
-
required: true,
|
|
38
|
+
// required: true,
|
|
40
39
|
},
|
|
41
40
|
},
|
|
42
41
|
async run({ args }) {
|
|
@@ -93,7 +92,7 @@ export default defineCommand({
|
|
|
93
92
|
'local', 'start-api',
|
|
94
93
|
'--warm-containers', 'LAZY',
|
|
95
94
|
'--debug', '--template-file', join(__dirname, 'template-dev.yaml'),
|
|
96
|
-
'--port',
|
|
95
|
+
'--port', String(port),
|
|
97
96
|
],
|
|
98
97
|
{
|
|
99
98
|
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
|
@@ -168,30 +167,43 @@ export default defineCommand({
|
|
|
168
167
|
logger.step('Server restarted')
|
|
169
168
|
})
|
|
170
169
|
})
|
|
170
|
+
default:
|
|
171
171
|
case 'node':
|
|
172
172
|
return withPort(desiredPort, async (port) => {
|
|
173
173
|
logger.step(`API running on http://${host}:${port}`)
|
|
174
|
+
const isBun = process?.isBun || typeof Bun != 'undefined'
|
|
175
|
+
const params = isBun
|
|
176
|
+
? ['run', '--port='+ port, '--hot', '--silent', '--no-clear-screen', '--no-summary', join(__dirname, 'node_modules/rajt/src/dev.ts')]
|
|
177
|
+
: [join(__dirname, 'node_modules/.bin/tsx'), 'watch', join(__dirname, 'node_modules/rajt/src/dev-node.ts')]
|
|
174
178
|
|
|
175
|
-
spawn(
|
|
179
|
+
const child = spawn(
|
|
176
180
|
process.execPath,
|
|
177
|
-
|
|
178
|
-
join(__dirname, 'node_modules/.bin/tsx'), 'watch', join(__dirname, 'node_modules/rajt/src/dev.ts'),
|
|
179
|
-
],
|
|
181
|
+
params,
|
|
180
182
|
{
|
|
181
|
-
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
|
182
|
-
env: {...process.env, PORT:
|
|
183
|
+
stdio: ['inherit', isBun ? 'pipe' : 'inherit', 'inherit', 'ipc'],
|
|
184
|
+
env: {...process.env, PORT: port},
|
|
183
185
|
}
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
if (isBun && child?.stdout) {
|
|
189
|
+
child.stdout?.on('data', data => {
|
|
190
|
+
const output = data.toString()
|
|
191
|
+
if (!output.includes('Started development server'))
|
|
192
|
+
process.stdout.write(output)
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
child.on('exit', code => process.exit(code ?? 0))
|
|
197
|
+
.on('message', msg => {
|
|
198
|
+
if (process.send) process.send(msg)
|
|
199
|
+
}).on('disconnect', () => {
|
|
200
|
+
if (process.disconnect) process.disconnect()
|
|
201
|
+
})
|
|
190
202
|
})
|
|
191
|
-
default:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
203
|
+
// default:
|
|
204
|
+
// return logger.warn(
|
|
205
|
+
// `🟠 Provide a valid platform: ${['aws', 'cf', 'node'].map(p => colors.blue(p)).join(', ')}.\n`
|
|
206
|
+
// )
|
|
195
207
|
}
|
|
196
208
|
},
|
|
197
209
|
})
|
|
@@ -228,13 +240,7 @@ function getAssetChangeMessage(
|
|
|
228
240
|
|
|
229
241
|
async function watch(cb: (e: ChokidarEventName | string, file: string) => Promise<void>) {
|
|
230
242
|
const codeWatcher = chokidar.watch([
|
|
231
|
-
join(__dirname, 'actions/**/*.ts'),
|
|
232
|
-
join(__dirname, 'configs/**/*.ts'),
|
|
233
|
-
join(__dirname, 'enums/**/*.ts'),
|
|
234
|
-
join(__dirname, 'locales/**/*.ts'),
|
|
235
|
-
join(__dirname, 'middlewares/**/*.ts'),
|
|
236
|
-
join(__dirname, 'models/**/*.ts'),
|
|
237
|
-
join(__dirname, 'utils/**/*.ts'),
|
|
243
|
+
join(__dirname, '{actions,features,routes,configs,enums,locales,middlewares,models,utils}/**/*.ts'),
|
|
238
244
|
join(__dirname, '.env.dev'),
|
|
239
245
|
join(__dirname, '.env.prod'),
|
|
240
246
|
join(__dirname, 'package.json'),
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import esbuild from 'esbuild'
|
|
2
2
|
import TOML from '@iarna/toml'
|
|
3
3
|
import { Miniflare } from 'miniflare'
|
|
4
|
-
import { fileURLToPath } from 'node:url'
|
|
5
4
|
import { mkdirSync, existsSync, readdirSync, rmSync, copyFileSync } from 'node:fs'
|
|
6
5
|
import { readFile, stat, writeFile } from 'node:fs/promises'
|
|
7
6
|
import { basename, dirname, join, relative } from 'node:path'
|
|
8
7
|
|
|
9
8
|
import { cacheRoutes } from '../../../routes'
|
|
10
9
|
|
|
11
|
-
const __dirname = join(dirname(
|
|
10
|
+
const __dirname = join(dirname(new URL(import.meta.url).pathname), '../../../../../../')
|
|
12
11
|
const __rajt = join(__dirname, 'node_modules/rajt/src')
|
|
13
12
|
|
|
14
13
|
export const formatSize = (bytes: number) => {
|
|
@@ -79,7 +78,7 @@ export const build = async (platform: 'aws' | 'cf' | 'node') => {
|
|
|
79
78
|
name: 'preserve-class-names',
|
|
80
79
|
setup(build) {
|
|
81
80
|
build.onLoad(
|
|
82
|
-
{ filter: /(actions|features)\/.*\.ts$/ },
|
|
81
|
+
{ filter: /(actions|features|routes)\/.*\.ts$/ },
|
|
83
82
|
async (args) => {
|
|
84
83
|
const contents = await readFile(args.path, 'utf8')
|
|
85
84
|
const result = await esbuild.transform(contents, {
|
package/src/cli/index.ts
CHANGED
|
@@ -25,11 +25,9 @@ console.error = () => {}
|
|
|
25
25
|
const directly = () => {
|
|
26
26
|
try {
|
|
27
27
|
// @ts-ignore
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|| import.meta.url == `file://${process.argv[1]}`
|
|
32
|
-
)
|
|
28
|
+
return typeof vitest == 'undefined'
|
|
29
|
+
&& process.env?.npm_lifecycle_script == 'rajt'
|
|
30
|
+
&& import.meta.url == `file://${process.argv[1]}`
|
|
33
31
|
} catch {
|
|
34
32
|
return false
|
|
35
33
|
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { DataBag } from 't0n'
|
|
2
|
+
|
|
3
|
+
export default class Config {
|
|
4
|
+
static #c: DataBag
|
|
5
|
+
|
|
6
|
+
static {
|
|
7
|
+
this.#c = new DataBag()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static all<T = any>(): Record<string, T> {
|
|
11
|
+
return this.#c.all()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static has(key: string): boolean {
|
|
15
|
+
return this.#c.has(key)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static add<T = any>(data: Record<string, T> = {}) {
|
|
19
|
+
this.#c.add(data)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static replace<T = any>(data: Record<string, T> = {}) {
|
|
23
|
+
this.#c.replace(data)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static get<T = any>(key: string, defaultValue?: T): T {
|
|
27
|
+
return this.#c.get(key, defaultValue)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static set<T = any>(key: string, value: T) {
|
|
31
|
+
this.#c.set(key, value)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static remove(key: string) {
|
|
35
|
+
this.#c.remove(key)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static clear() {
|
|
39
|
+
this.#c.clear()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static get length(): number {
|
|
43
|
+
return this.#c.length
|
|
44
|
+
}
|
|
45
|
+
static get size(): number {
|
|
46
|
+
return this.#c.length
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static keys(): string[] {
|
|
50
|
+
return this.#c.keys()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static values<T = any>(): T[] {
|
|
54
|
+
return this.#c.values()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static entries<T = any>(): [string, T][] {
|
|
58
|
+
return this.#c.entries()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static toArray<T = any>(): [string, T][] {
|
|
62
|
+
return this.#c.entries()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static jsonSerialize<T = any>(): Record<string, T> {
|
|
66
|
+
return this.#c.all()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static toJson(options: number = 0): string {
|
|
70
|
+
return this.#c.toJson(options)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static [Symbol.iterator](): IterableIterator<[string, any]> {
|
|
74
|
+
return this.#c[Symbol.iterator]()
|
|
75
|
+
}
|
|
76
|
+
}
|
package/src/create-app.ts
CHANGED
|
@@ -6,7 +6,8 @@ import type { Env, Context, ErrorHandler, NotFoundHandler, Next } from 'hono'
|
|
|
6
6
|
// import { createMiddleware } from 'hono/factory'
|
|
7
7
|
// import type { H, Handler, HandlerResponse } from 'hono/types'
|
|
8
8
|
import type { HTTPResponseError } from 'hono/types'
|
|
9
|
-
import
|
|
9
|
+
import { createColors } from 'picocolors'
|
|
10
|
+
import { getColorEnabledAsync } from 'hono/utils/color'
|
|
10
11
|
import { Envir } from 't0n'
|
|
11
12
|
import type { Routes } from './types'
|
|
12
13
|
import { BadRequest, Unauthorized } from './exceptions'
|
|
@@ -14,9 +15,11 @@ import { resolve, resolveMiddleware } from './utils/resolve'
|
|
|
14
15
|
import { getMiddlewares, getHandler } from './register'
|
|
15
16
|
import { isDev } from './utils/environment'
|
|
16
17
|
import localDate from './utils/local-date'
|
|
17
|
-
import request from './request'
|
|
18
|
+
import request, { GET_REQUEST } from './request'
|
|
18
19
|
import response from './response'
|
|
19
20
|
|
|
21
|
+
const colors = createColors(await getColorEnabledAsync())
|
|
22
|
+
|
|
20
23
|
type InitFunction<E extends Env = Env> = (app: Hono<E>) => void
|
|
21
24
|
|
|
22
25
|
export type ServerOptions<E extends Env = Env> = Partial<{
|
|
@@ -85,12 +88,12 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
|
85
88
|
app.use('*', logger((...args: any[]) => console.log(colors.gray(localDate()), ...args)))
|
|
86
89
|
|
|
87
90
|
app.use(async (c: Context, next: Next) => {
|
|
88
|
-
c.set(
|
|
91
|
+
c.set(GET_REQUEST as unknown as string, new request(c))
|
|
89
92
|
if (c.env) Envir.add(c.env)
|
|
90
93
|
await next()
|
|
91
94
|
})
|
|
92
95
|
getMiddlewares().forEach(mw => {
|
|
93
|
-
const h = async (c: Context, next: Next) => await resolveMiddleware(mw)(c.get(
|
|
96
|
+
const h = async (c: Context, next: Next) => await resolveMiddleware(mw)(c.get(GET_REQUEST as unknown as string), next)
|
|
94
97
|
// @ts-ignore
|
|
95
98
|
mw?.path ? app.use(String(mw.path), h) : app.use(h)
|
|
96
99
|
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'forj/dynamodb/types'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'forj/dynamodb'
|
package/src/dev-node.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { serve, type ServerType } from '@hono/node-server'
|
|
2
|
+
import app from './dev'
|
|
3
|
+
import shutdown from './utils/shutdown'
|
|
4
|
+
|
|
5
|
+
const fetch = app.fetch
|
|
6
|
+
|
|
7
|
+
const port = process.env?.PORT ? Number(process.env.PORT) : 3000
|
|
8
|
+
|
|
9
|
+
let server: ServerType | null = serve({ fetch, port })
|
|
10
|
+
|
|
11
|
+
shutdown(() => {
|
|
12
|
+
if (server) {
|
|
13
|
+
server?.close()
|
|
14
|
+
server = null
|
|
15
|
+
}
|
|
16
|
+
})
|
package/src/dev.ts
CHANGED
|
@@ -1,40 +1,30 @@
|
|
|
1
|
-
import { fileURLToPath } from 'node:url'
|
|
2
1
|
import { dirname, join } from 'node:path'
|
|
3
2
|
import { config } from 'dotenv'
|
|
4
|
-
import { serve, type ServerType } from '@hono/node-server'
|
|
5
3
|
import createApp from './create-app'
|
|
6
|
-
import { getRoutes, getMiddlewares } from './routes'
|
|
4
|
+
import { getRoutes, getMiddlewares, getConfigs } from './routes'
|
|
7
5
|
import { registerHandler, registerMiddleware } from './register'
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import { setEnv, detectEnvironment } from '
|
|
11
|
-
import shutdown from './utils/shutdown'
|
|
6
|
+
import Config from './config'
|
|
7
|
+
import { Ability } from 'rajt/auth'
|
|
8
|
+
import { setEnv, detectEnvironment } from 'rajt/env'
|
|
12
9
|
|
|
13
10
|
setEnv(detectEnvironment())
|
|
14
11
|
|
|
15
|
-
const __dirname = join(dirname(
|
|
12
|
+
const __dirname = join(dirname(new URL(import.meta.url).pathname), '../../../')
|
|
16
13
|
|
|
17
14
|
config({ path: join(__dirname, '.env.dev') })
|
|
18
15
|
|
|
16
|
+
Config.add(await getConfigs())
|
|
17
|
+
|
|
19
18
|
let routes = await getRoutes()
|
|
20
19
|
routes.forEach(r => registerHandler(r.name, r.handle))
|
|
21
|
-
routes = routes.filter(r => r?.path)
|
|
20
|
+
routes = routes.filter(r => r?.method && r?.path)
|
|
22
21
|
|
|
23
22
|
const middlewares = await getMiddlewares()
|
|
24
23
|
middlewares.forEach(mw => registerMiddleware(mw.handle))
|
|
25
24
|
|
|
26
25
|
Ability.fromRoutes(routes)
|
|
27
|
-
Ability.roles =
|
|
28
|
-
|
|
29
|
-
const fetch = createApp({ routes }).fetch
|
|
30
|
-
|
|
31
|
-
const port = process.env?.PORT ? Number(process.env.PORT) : 3000
|
|
26
|
+
Ability.roles = Config.get('roles', {})
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
const app = createApp({ routes })
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
if (server) {
|
|
37
|
-
server?.close()
|
|
38
|
-
server = null
|
|
39
|
-
}
|
|
40
|
-
})
|
|
30
|
+
export default app
|
package/src/esbuild.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import esbuild from 'esbuild'
|
|
2
2
|
import { basename, dirname, join, relative } from 'node:path'
|
|
3
|
-
import { fileURLToPath } from 'node:url'
|
|
4
3
|
import { mkdirSync, existsSync, readdirSync, rmSync, copyFileSync } from 'node:fs'
|
|
5
4
|
import { readFile, stat, writeFile } from 'node:fs/promises'
|
|
6
5
|
|
|
@@ -16,7 +15,7 @@ const platforms = ['aws', 'cf']
|
|
|
16
15
|
if (!platform || !platforms.includes(platform))
|
|
17
16
|
fail()
|
|
18
17
|
|
|
19
|
-
const __dirname = dirname(
|
|
18
|
+
const __dirname = dirname(new URL(import.meta.url).pathname)
|
|
20
19
|
|
|
21
20
|
const formatSize = (bytes) => {
|
|
22
21
|
if (bytes < 1024) return `${bytes}b`
|
|
@@ -55,7 +54,7 @@ const buildOptions = {
|
|
|
55
54
|
name: 'preserve-class-names',
|
|
56
55
|
setup(build) {
|
|
57
56
|
build.onLoad(
|
|
58
|
-
{ filter: /(actions|features)\/.*\.ts$/ },
|
|
57
|
+
{ filter: /(actions|features|routes)\/.*\.ts$/ },
|
|
59
58
|
async (args) => {
|
|
60
59
|
const contents = await readFile(args.path, 'utf8')
|
|
61
60
|
const result = await esbuild.transform(contents, {
|
package/src/http.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Context, Next } from 'hono'
|
|
2
2
|
import { MiddlewareType } from './middleware'
|
|
3
3
|
import response from './response'
|
|
4
|
+
import { GET_REQUEST } from './request'
|
|
4
5
|
import { Ability } from './auth'
|
|
5
6
|
import mergeMiddleware from './utils/merge-middleware'
|
|
6
7
|
import { IRequest } from './types'
|
|
@@ -102,7 +103,7 @@ export function Auth(...args: any[]): void | ClassDecorator {
|
|
|
102
103
|
|
|
103
104
|
function _auth(target: Function | any) {
|
|
104
105
|
mergeMiddleware(target, async (c: Context, next: Next) => {
|
|
105
|
-
const req = c.get(
|
|
106
|
+
const req = c.get(GET_REQUEST as unknown as string) as IRequest
|
|
106
107
|
const ability = Ability.fromAction(target)
|
|
107
108
|
|
|
108
109
|
if (!req?.user || !ability || req.cant(ability))
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { default as Action } from './action'
|
|
2
2
|
export { default as Middleware } from './middleware'
|
|
3
3
|
export { default as Response } from './response'
|
|
4
|
-
export {
|
|
4
|
+
export { default as Config } from './config'
|
|
5
|
+
|
|
6
|
+
export { Enum, Envir } from 't0n'
|
|
7
|
+
export type { EnumStatic, EnumValue, EnumType } from 't0n'
|
package/src/prod.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Config from './config'
|
|
2
2
|
import { Ability } from './auth'
|
|
3
|
+
import createApp from './create-app'
|
|
3
4
|
|
|
4
5
|
// @ts-ignore
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
import '../../../tmp/import-routes.mjs'
|
|
7
7
|
// @ts-ignore
|
|
8
|
-
|
|
8
|
+
import routes from '../../../tmp/routes.json'
|
|
9
9
|
|
|
10
|
-
// @ts-ignore
|
|
11
|
-
Ability.roles = (await import('../../../roles.json')).default
|
|
12
10
|
// @ts-ignore
|
|
13
11
|
Ability.fromRoutes(routes)
|
|
12
|
+
Ability.roles = Config.get('roles', {})
|
|
14
13
|
|
|
15
14
|
// @ts-ignore
|
|
16
15
|
export const app = createApp({ routes })
|
package/src/request.ts
CHANGED
|
@@ -17,6 +17,8 @@ const cookieWrapper = (c: Context) => ({
|
|
|
17
17
|
delete: (name: string, opt?: CookieOptions) => deleteCookie(c, name, opt)
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
+
export const GET_REQUEST: unique symbol = Symbol()
|
|
21
|
+
|
|
20
22
|
export default class $Request {
|
|
21
23
|
#c!: Context
|
|
22
24
|
#cookie: ReturnType<typeof cookieWrapper>
|
package/src/routes.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { existsSync, readdirSync, statSync } from 'node:fs'
|
|
1
|
+
import { existsSync, readdirSync, statSync, writeFileSync } from 'node:fs'
|
|
2
2
|
import { dirname, join, resolve } from 'node:path'
|
|
3
|
-
import { fileURLToPath } from 'node:url'
|
|
4
|
-
import { Route } from './types'
|
|
5
|
-
import { isAnonFn } from './utils/func'
|
|
6
3
|
|
|
7
|
-
import
|
|
4
|
+
import glob from 'tiny-glob'
|
|
8
5
|
import { config } from 'dotenv'
|
|
6
|
+
|
|
7
|
+
import IMPORT from './utils/import'
|
|
8
|
+
import { isAnonFn } from './utils/func'
|
|
9
9
|
import ensureDir from './utils/ensuredir'
|
|
10
10
|
import versionSHA from './utils/version-sha'
|
|
11
|
+
import type { Route } from './types'
|
|
11
12
|
|
|
12
|
-
const __filename =
|
|
13
|
-
const
|
|
13
|
+
const __filename = new URL(import.meta.url).pathname
|
|
14
|
+
const __root = resolve(dirname(__filename), '../../..')
|
|
14
15
|
|
|
15
16
|
const importName = (name?: string) => (name || 'Fn'+ Math.random().toString(36).substring(2)).replace(/\.ts$/, '')
|
|
16
17
|
const walk = async (dir: string, baseDir: string, fn: Function, parentMw: string[] = []): Promise<void> => {
|
|
@@ -21,7 +22,7 @@ const walk = async (dir: string, baseDir: string, fn: Function, parentMw: string
|
|
|
21
22
|
const indexFile = join(dir, 'index.ts')
|
|
22
23
|
|
|
23
24
|
if (existsSync(indexFile)) {
|
|
24
|
-
const mod = await
|
|
25
|
+
const mod = await IMPORT(indexFile)
|
|
25
26
|
const group = mod.default
|
|
26
27
|
|
|
27
28
|
!isAnonFn(group) && group?.mw?.length && currentMw.push(group?.name)
|
|
@@ -35,28 +36,30 @@ const walk = async (dir: string, baseDir: string, fn: Function, parentMw: string
|
|
|
35
36
|
if (stat.isDirectory()) {
|
|
36
37
|
await walk(fullPath, baseDir, fn, currentMw)
|
|
37
38
|
} else if (file != 'index.ts' && file.endsWith('.ts') && !file.endsWith('.d.ts')) {
|
|
38
|
-
const mod = await
|
|
39
|
+
const mod = await IMPORT(fullPath)
|
|
39
40
|
fn(fullPath, baseDir, mod.default, currentMw)
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
export async function getRoutes(
|
|
45
|
-
dirs: string[] = ['actions', 'features']
|
|
46
|
+
dirs: string[] = ['actions', 'features', 'routes']
|
|
46
47
|
): Promise<Route[]> {
|
|
47
48
|
const routes: Route[] = []
|
|
48
49
|
let mw: string[] = []
|
|
49
50
|
|
|
50
51
|
await Promise.all(dirs.map(dir => walk(
|
|
51
|
-
resolve(
|
|
52
|
+
resolve(__root, dir),
|
|
52
53
|
dir,
|
|
53
|
-
(
|
|
54
|
+
(path: string, baseDir: string, handle: any, middlewares: string[]) => {
|
|
54
55
|
const name = importName(handle?.name)
|
|
55
|
-
|
|
56
|
+
path = path.split(baseDir)[1]
|
|
57
|
+
const file = baseDir + path
|
|
56
58
|
|
|
59
|
+
const m = handle?.m?.toLowerCase()
|
|
60
|
+
const [method, uri] = m ? [m, handle?.p] : [extractHttpVerb(path), extractHttpPath(path)]
|
|
57
61
|
routes.push({
|
|
58
|
-
method:
|
|
59
|
-
path: handle?.p || '',
|
|
62
|
+
method, path: uri,
|
|
60
63
|
name,
|
|
61
64
|
file,
|
|
62
65
|
// @ts-ignore
|
|
@@ -69,6 +72,27 @@ export async function getRoutes(
|
|
|
69
72
|
return sortRoutes(routes)
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
function extractHttpVerb(file: string) {
|
|
76
|
+
if (!file) return 'get'
|
|
77
|
+
const match = file.match(/\.(get|post|put|patch|delete|head|options)\.(?=[jt]s$)/i)
|
|
78
|
+
return match && match[1] ? match[1].toLowerCase() : 'get'
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function extractHttpPath(file: string) {
|
|
82
|
+
const route = '/'+ file.replace(/\\/g, '/')
|
|
83
|
+
// .replace(/^(actions|features|routes)\//, '')
|
|
84
|
+
.replace(/\.[jt]s$/, '')
|
|
85
|
+
.replace(/\.(get|post|put|patch|delete|head|options)$/i, '')
|
|
86
|
+
.replace(/\/index$/, '')
|
|
87
|
+
.split('/')
|
|
88
|
+
.filter(Boolean)
|
|
89
|
+
.filter(part => !(part.startsWith('(') && part.endsWith(')')))
|
|
90
|
+
.map(part => part.startsWith('[') && part.endsWith(']') ? ':'+ part.slice(1, -1) : part)
|
|
91
|
+
.join('/')
|
|
92
|
+
|
|
93
|
+
return route == '/' ? '/' : route.replace(/\/$/, '')
|
|
94
|
+
}
|
|
95
|
+
|
|
72
96
|
function sortRoutes(routes: Route[]) {
|
|
73
97
|
const metas = new Map<string, { score: number, segmentsCount: number }>()
|
|
74
98
|
|
|
@@ -109,7 +133,7 @@ export async function getMiddlewares(
|
|
|
109
133
|
const mw: Route[] = []
|
|
110
134
|
|
|
111
135
|
await Promise.all(dirs.map(dir => walk(
|
|
112
|
-
resolve(
|
|
136
|
+
resolve(__root, dir),
|
|
113
137
|
dir,
|
|
114
138
|
(fullPath: string, baseDir: string, handle: any) => {
|
|
115
139
|
// @ts-ignore
|
|
@@ -124,6 +148,36 @@ export async function getMiddlewares(
|
|
|
124
148
|
return mw
|
|
125
149
|
}
|
|
126
150
|
|
|
151
|
+
function extractName(file: string) {
|
|
152
|
+
return file.replace(/\.[^/.]+$/, '').split('/').slice(1).join('.')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function getConfigs(
|
|
156
|
+
dirs: string[] = ['configs']
|
|
157
|
+
): Promise<Record<string, any>> {
|
|
158
|
+
if (!dirs?.length) return {}
|
|
159
|
+
const configs: Record<string, any> = {}
|
|
160
|
+
|
|
161
|
+
const files = await glob(join(__root, dirs?.length > 1 ? `{${dirs.join(',')}}` : dirs[0], '/**/*.{ts,js,json}'))
|
|
162
|
+
|
|
163
|
+
for (const file of files) {
|
|
164
|
+
const mod = await IMPORT(join(__root, file))
|
|
165
|
+
const keyPath = extractName(file).split('.')
|
|
166
|
+
|
|
167
|
+
keyPath.reduce((acc, key, index) => {
|
|
168
|
+
if (index == keyPath.length - 1) {
|
|
169
|
+
acc[key] = mod.default
|
|
170
|
+
} else if (!acc[key] || typeof acc[key] != 'object') {
|
|
171
|
+
acc[key] = {}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return acc[key]
|
|
175
|
+
}, configs)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return configs
|
|
179
|
+
}
|
|
180
|
+
|
|
127
181
|
const env = Object.entries(
|
|
128
182
|
config({ path: '../../.env.prod' })?.parsed || {}
|
|
129
183
|
).filter(([key, val]) => key?.toLowerCase().indexOf('aws') != 0) // prevent AWS credentials
|
|
@@ -132,18 +186,46 @@ const version = versionSHA('../../.git') // @ts-ignore
|
|
|
132
186
|
env.push(['VERSION_SHA', process.env['VERSION_SHA'] = version]) // @ts-ignore
|
|
133
187
|
env.push(['VERSION_HASH', process.env['VERSION_HASH'] = version?.substring(0, 7)])
|
|
134
188
|
|
|
189
|
+
const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u
|
|
190
|
+
function stringifyToJS(value: unknown): string {
|
|
191
|
+
if (value === null) return 'null'
|
|
192
|
+
if (value === undefined) return 'undefined'
|
|
193
|
+
|
|
194
|
+
const type = typeof value
|
|
195
|
+
|
|
196
|
+
if (type == 'string') return JSON.stringify(value)
|
|
197
|
+
if (type == 'number' || type == 'boolean') return String(value)
|
|
198
|
+
if (type == 'bigint') return `${value}n`
|
|
199
|
+
if (type == 'function') return value.toString()
|
|
200
|
+
|
|
201
|
+
if (Array.isArray(value))
|
|
202
|
+
return `[${value.map(stringifyToJS).join(',')}]`
|
|
203
|
+
|
|
204
|
+
if (type == 'object') {
|
|
205
|
+
const entries = Object.entries(value as Record<string, unknown>)
|
|
206
|
+
.map(([key, val]) => `${IDENTIFIER_RE.test(key) ? key : JSON.stringify(key)}:${stringifyToJS(val)}`)
|
|
207
|
+
|
|
208
|
+
return `{${entries.join(',')}}`
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return 'undefined'
|
|
212
|
+
}
|
|
213
|
+
|
|
135
214
|
export async function cacheRoutes() {
|
|
136
|
-
const rolePath = join(
|
|
215
|
+
const rolePath = join(__root, 'configs/roles.ts')
|
|
216
|
+
ensureDir(rolePath)
|
|
137
217
|
if (!existsSync(rolePath))
|
|
138
|
-
writeFileSync(rolePath,
|
|
218
|
+
writeFileSync(rolePath, `export default {\n\n}`)
|
|
139
219
|
|
|
140
220
|
const routes = await getRoutes()
|
|
141
221
|
const middlewares = await getMiddlewares()
|
|
222
|
+
const configs = Object.entries(await getConfigs())
|
|
142
223
|
|
|
143
|
-
const iPath = join(
|
|
224
|
+
const iPath = join(__root, 'tmp/import-routes.mjs')
|
|
144
225
|
ensureDir(iPath)
|
|
145
226
|
writeFileSync(iPath, `// AUTO-GENERATED FILE - DO NOT EDIT
|
|
146
|
-
${env?.length ? `import { Envir } from '../node_modules/t0n/dist/index'\nEnvir.add({${env.map(([key, val]) => key +
|
|
227
|
+
${env?.length ? `import { Envir } from '../node_modules/t0n/dist/index'\nEnvir.add({${env.map(([key, val]) => key +':'+ stringifyToJS(val)).join(',')}})` : ''}
|
|
228
|
+
${configs?.length ? `import Config from '../node_modules/rajt/src/config'\nConfig.add({${configs.map(([key, val]) => key +':'+ stringifyToJS(val)).join(',')}})` : ''}
|
|
147
229
|
|
|
148
230
|
import { registerHandler, registerMiddleware } from '../node_modules/rajt/src/register'
|
|
149
231
|
|
|
@@ -169,7 +251,7 @@ try {
|
|
|
169
251
|
}
|
|
170
252
|
`)
|
|
171
253
|
|
|
172
|
-
const rPath = join(
|
|
254
|
+
const rPath = join(__root, 'tmp/routes.json')
|
|
173
255
|
ensureDir(rPath)
|
|
174
256
|
writeFileSync(rPath, JSON.stringify(routes.filter(r => r.method && r.path).map(route => [
|
|
175
257
|
route.method,
|
package/src/utils/json-import.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs'
|
|
2
2
|
import { dirname, join } from 'node:path'
|
|
3
|
-
import { fileURLToPath } from 'node:url'
|
|
4
3
|
|
|
5
4
|
export default function jsonImport<T = any>(filePath: string, defaultValue: T = {} as T): T {
|
|
6
|
-
const
|
|
7
|
-
const __dirname = dirname(__filename)
|
|
5
|
+
const __dirname = dirname(new URL(import.meta.url).pathname)
|
|
8
6
|
|
|
9
7
|
try {
|
|
10
8
|
const fullPath = join(__dirname, filePath)
|
package/src/utils/logger.ts
CHANGED
|
@@ -13,17 +13,18 @@ export interface ILogger {
|
|
|
13
13
|
// custom
|
|
14
14
|
step(...data: any[]): void;
|
|
15
15
|
substep(...data: any[]): void;
|
|
16
|
+
stepWarn(...data: any[]): void;
|
|
16
17
|
ln(): void;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export const logger = {
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
$step(color: Function, ...args: any[]) {
|
|
22
|
+
if (args?.length && args.length < 2) return _console.log(color('⁕') +` ${args[0]}\n`)
|
|
22
23
|
const length = args.length - 1
|
|
23
24
|
args.forEach((arg, index) => {
|
|
24
25
|
switch (index) {
|
|
25
26
|
case 0:
|
|
26
|
-
return _console.log(
|
|
27
|
+
return _console.log(color('⁕') + ' ' + arg)
|
|
27
28
|
// return _console.log(colors.blue('⁕') +` ${arg} \n`)
|
|
28
29
|
case length:
|
|
29
30
|
return _console.log(` ${colors.gray('⁕')} ${arg}\n`)
|
|
@@ -31,6 +32,12 @@ export const logger = {
|
|
|
31
32
|
return _console.log(` ${colors.gray('⁕')} ` + arg)
|
|
32
33
|
}
|
|
33
34
|
})
|
|
35
|
+
},
|
|
36
|
+
step(...args: any[]) {
|
|
37
|
+
this.$step(colors.blue, ...args)
|
|
38
|
+
},
|
|
39
|
+
stepWarn(...args: any[]) {
|
|
40
|
+
this.$step(colors.yellow, ...args)
|
|
34
41
|
},
|
|
35
42
|
substep(...args: any[]) {
|
|
36
43
|
args.forEach(arg => _console.log(` ${colors.gray('⁕')} ` + arg))
|
package/src/bin/rajt.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
|
-
import { join, dirname } from "node:path";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = dirname(__filename);
|
|
9
|
-
|
|
10
|
-
const ERR_NODE_VERSION = "18.0.0";
|
|
11
|
-
const MIN_NODE_VERSION = "18.0.0";
|
|
12
|
-
|
|
13
|
-
let rajtProcess;
|
|
14
|
-
|
|
15
|
-
// Executes ../src/cli/index.ts
|
|
16
|
-
function runRajt() {
|
|
17
|
-
if (semiver(process.versions.node, ERR_NODE_VERSION) < 0) {
|
|
18
|
-
console.error(
|
|
19
|
-
`Rajt requires at least Node.js v${MIN_NODE_VERSION}. You are using v${process.versions.node}. Please update your version of Node.js.
|
|
20
|
-
|
|
21
|
-
Consider using a Node.js version manager such as https://volta.sh or https://github.com/nvm-sh/nvm.`
|
|
22
|
-
);
|
|
23
|
-
process.exitCode = 1;
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const tsxPaths = [
|
|
28
|
-
// join(__dirname, "../node_modules/.bin/tsx"),
|
|
29
|
-
// join(__dirname, "../../.bin/tsx"),
|
|
30
|
-
join(__dirname, "../node_modules/.bin/tsx"),
|
|
31
|
-
join(__dirname, "../../node_modules/.bin/tsx"),
|
|
32
|
-
join(process.cwd(), "node_modules/.bin/tsx"),
|
|
33
|
-
"tsx",
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
let tsxPath;
|
|
37
|
-
for (const pathOption of tsxPaths) {
|
|
38
|
-
if (pathOption == "tsx" || existsSync(pathOption)) {
|
|
39
|
-
tsxPath = pathOption;
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!tsxPath) {
|
|
45
|
-
console.error("TypeScript file found but tsx is not available. Please install tsx:");
|
|
46
|
-
console.error(" npm i -D tsx");
|
|
47
|
-
console.error(" or");
|
|
48
|
-
console.error(" bun i -D tsx");
|
|
49
|
-
process.exit(1);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return spawn(
|
|
54
|
-
process.execPath,
|
|
55
|
-
[
|
|
56
|
-
"--no-warnings",
|
|
57
|
-
...process.execArgv,
|
|
58
|
-
tsxPath,
|
|
59
|
-
join(__dirname, "../rajt/src/cli/index.ts"),
|
|
60
|
-
...process.argv.slice(2),
|
|
61
|
-
].filter(arg =>
|
|
62
|
-
!arg.includes('experimental-vm-modules') &&
|
|
63
|
-
!arg.includes('loader')
|
|
64
|
-
),
|
|
65
|
-
{
|
|
66
|
-
stdio: ["inherit", "inherit", "inherit", "ipc"],
|
|
67
|
-
env: {
|
|
68
|
-
...process.env,
|
|
69
|
-
NODE_ENV: process.env.NODE_ENV || 'development',
|
|
70
|
-
TSX_DISABLE_CACHE: process.env.TSX_DISABLE_CACHE || '1',
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
)
|
|
74
|
-
.on("exit", (code) =>
|
|
75
|
-
process.exit(code == null ? 0 : code)
|
|
76
|
-
)
|
|
77
|
-
.on("message", (message) => {
|
|
78
|
-
if (process.send) {
|
|
79
|
-
process.send(message);
|
|
80
|
-
}
|
|
81
|
-
})
|
|
82
|
-
.on("disconnect", () => {
|
|
83
|
-
if (process.disconnect) {
|
|
84
|
-
process.disconnect();
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
var fn = new Intl.Collator(0, { numeric: 1 }).compare;
|
|
90
|
-
|
|
91
|
-
function semiver(a, b, bool) {
|
|
92
|
-
a = a.split(".");
|
|
93
|
-
b = b.split(".");
|
|
94
|
-
|
|
95
|
-
return (
|
|
96
|
-
fn(a[0], b[0]) ||
|
|
97
|
-
fn(a[1], b[1]) ||
|
|
98
|
-
((b[2] = b.slice(2).join(".")),
|
|
99
|
-
(bool = /[.-]/.test((a[2] = a.slice(2).join(".")))),
|
|
100
|
-
bool == /[.-]/.test(b[2]) ? fn(a[2], b[2]) : bool ? -1 : 1)
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function directly() {
|
|
105
|
-
try {
|
|
106
|
-
return ![typeof require, typeof module].includes('undefined') && require.main == module
|
|
107
|
-
|| import.meta.url == `file://${process.argv[1]}`
|
|
108
|
-
|| process.argv[1].endsWith(process.env?.npm_package_bin_rajt)
|
|
109
|
-
|| import.meta?.url?.endsWith(process.env?.npm_package_bin_rajt)
|
|
110
|
-
} catch {
|
|
111
|
-
return false
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (directly()) {
|
|
116
|
-
rajtProcess = runRajt();
|
|
117
|
-
process.on("SIGINT", () => {
|
|
118
|
-
rajtProcess && rajtProcess.kill();
|
|
119
|
-
});
|
|
120
|
-
process.on("SIGTERM", () => {
|
|
121
|
-
rajtProcess && rajtProcess.kill();
|
|
122
|
-
});
|
|
123
|
-
}
|