rajt 0.0.57 → 0.0.59
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 +10 -7
- package/package.json +35 -15
- package/src/action-old.ts +72 -0
- package/src/action.ts +12 -61
- package/src/auth/ability.ts +2 -2
- package/src/auth/authnz.ts +3 -0
- package/src/auth/index.ts +0 -1
- package/src/auth/token.ts +27 -24
- package/src/bin/rajt.js +123 -0
- package/src/cli/commands/dev/index.ts +294 -0
- package/src/cli/commands/dev/utils.ts +215 -0
- package/src/cli/index.ts +69 -0
- package/src/cli/types.ts +1 -0
- package/src/create-app.ts +15 -9
- package/src/db/d1.d.ts +1 -0
- package/src/db/d1.ts +1 -0
- package/src/dev.ts +18 -15
- package/src/enum.ts +2 -75
- package/src/esbuild.mjs +11 -9
- package/src/http.ts +9 -8
- package/src/index.ts +1 -3
- package/src/prod-aws.ts +2 -17
- package/src/prod-cf.ts +1 -18
- package/src/prod.ts +16 -0
- package/src/request-old.ts +98 -0
- package/src/request.ts +152 -71
- package/src/response.ts +71 -26
- package/src/routes.ts +66 -2
- package/src/scripts/cache-routes.ts +1 -64
- package/src/types.ts +24 -4
- package/src/utils/environment.ts +3 -2
- package/src/utils/func.ts +2 -2
- package/src/utils/local-date.ts +13 -0
- package/src/utils/logger.ts +61 -0
- package/src/utils/port.ts +1 -3
- package/src/utils/resolve.ts +4 -3
- package/src/utils/shutdown.ts +19 -0
- package/src/validator.ts +68 -0
- package/src/auth/auth.ts +0 -33
- package/src/dynamodb/client.ts +0 -125
- package/src/dynamodb/compact.ts +0 -205
- package/src/dynamodb/decorators.ts +0 -126
- package/src/dynamodb/index.ts +0 -4
- package/src/dynamodb/model.ts +0 -258
- package/src/dynamodb/query-builder.ts +0 -174
- package/src/dynamodb/repository.ts +0 -31
- package/src/dynamodb/schema.ts +0 -107
- package/src/dynamodb/types.ts +0 -32
- package/src/utils/lenght.ts +0 -32
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { dirname, join, relative } from 'node:path'
|
|
4
|
+
import { spawn, type ChildProcess } from 'node:child_process'
|
|
5
|
+
|
|
6
|
+
import chokidar from 'chokidar'
|
|
7
|
+
import colors from 'picocolors'
|
|
8
|
+
import { defineCommand } from 'citty'
|
|
9
|
+
import type { ChokidarEventName } from '../../types'
|
|
10
|
+
|
|
11
|
+
import type { Miniflare } from 'miniflare'
|
|
12
|
+
import { build, createMiniflare } from './utils'
|
|
13
|
+
import { getAvailablePort } from '../../../utils/port'
|
|
14
|
+
import shutdown from '../../../utils/shutdown'
|
|
15
|
+
|
|
16
|
+
const __dirname = join(dirname(fileURLToPath(import.meta.url)), '../../../../../../')
|
|
17
|
+
|
|
18
|
+
export default defineCommand({
|
|
19
|
+
meta: {
|
|
20
|
+
name: 'dev',
|
|
21
|
+
description: '💻 Start the localhost server\n',
|
|
22
|
+
},
|
|
23
|
+
args: {
|
|
24
|
+
port: {
|
|
25
|
+
description: 'Port to listen on',
|
|
26
|
+
type: 'number',
|
|
27
|
+
default: 3000,
|
|
28
|
+
},
|
|
29
|
+
host: {
|
|
30
|
+
description: 'Host to forward requests to, defaults to the zone of project',
|
|
31
|
+
type: 'string',
|
|
32
|
+
default: 'localhost',
|
|
33
|
+
},
|
|
34
|
+
platform: {
|
|
35
|
+
alias: 'p',
|
|
36
|
+
description: 'Environment platform',
|
|
37
|
+
type: 'enum',
|
|
38
|
+
options: ['aws', 'cf', 'node'] as const,
|
|
39
|
+
required: true,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
async run({ args }) {
|
|
43
|
+
const platform = args.p || args.platform
|
|
44
|
+
const desiredPort = args.port ? Number(args.port) : 3000
|
|
45
|
+
const host = args.host ? String(args.host) : 'localhost'
|
|
46
|
+
switch (platform) {
|
|
47
|
+
case 'aws':
|
|
48
|
+
return withPort(desiredPort, async (port) => {
|
|
49
|
+
let isBuilding = false
|
|
50
|
+
let lambda: ChildProcess | null = null
|
|
51
|
+
|
|
52
|
+
const buildLambda = async () => {
|
|
53
|
+
if (isBuilding) return
|
|
54
|
+
isBuilding = true
|
|
55
|
+
logger.step('Building lambda')
|
|
56
|
+
try {
|
|
57
|
+
await build(platform)
|
|
58
|
+
if (!lambda) await startLambda()
|
|
59
|
+
} catch (e) {
|
|
60
|
+
logger.error('Build failed:', e)
|
|
61
|
+
process.exit(0)
|
|
62
|
+
} finally {
|
|
63
|
+
isBuilding = false
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const stopLambda = async () => {
|
|
68
|
+
if (!lambda) return
|
|
69
|
+
logger.step('Stopping lambda process...')
|
|
70
|
+
try {
|
|
71
|
+
if (!lambda?.killed) {
|
|
72
|
+
lambda.kill('SIGTERM')
|
|
73
|
+
await wait(1000)
|
|
74
|
+
|
|
75
|
+
if (!lambda?.killed) { // force kill
|
|
76
|
+
lambda.kill('SIGKILL')
|
|
77
|
+
await wait(1000)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
lambda = null
|
|
82
|
+
} catch (e) {
|
|
83
|
+
logger.warn('Error stopping lambda:', e)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const startLambda = async () => {
|
|
88
|
+
await stopLambda()
|
|
89
|
+
|
|
90
|
+
lambda = spawn(
|
|
91
|
+
'sam',
|
|
92
|
+
[
|
|
93
|
+
'local', 'start-api',
|
|
94
|
+
'--warm-containers', 'LAZY',
|
|
95
|
+
'--debug', '--template-file', join(__dirname, 'template-dev.yaml'),
|
|
96
|
+
'--port', args.port,
|
|
97
|
+
],
|
|
98
|
+
{
|
|
99
|
+
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
|
100
|
+
// stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
|
|
101
|
+
shell: process.platform == 'win32',
|
|
102
|
+
env: {...process.env, DOCKER_HOST: getDockerHost()},
|
|
103
|
+
}
|
|
104
|
+
).on('exit', code => {
|
|
105
|
+
logger.step(`Lambda process exited with code ${code ?? 0}`)
|
|
106
|
+
if (code != 0 && code != null)
|
|
107
|
+
logger.error('Lambda process crashed, waiting for restart...')
|
|
108
|
+
|
|
109
|
+
lambda = null
|
|
110
|
+
})
|
|
111
|
+
.on('message', msg => {
|
|
112
|
+
if (process.send) process.send(msg)
|
|
113
|
+
}).on('disconnect', () => {
|
|
114
|
+
if (process.disconnect) process.disconnect()
|
|
115
|
+
}).on('error', e => {
|
|
116
|
+
logger.error('Lambda process error:', e)
|
|
117
|
+
lambda = null
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
await wait(2000)
|
|
121
|
+
|
|
122
|
+
logger.step('Lambda process started successfully')
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await buildLambda()
|
|
126
|
+
logger.step(`API running on http://${host}:${port}`)
|
|
127
|
+
|
|
128
|
+
watch(async () => {
|
|
129
|
+
await buildLambda()
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
shutdown(async () => {
|
|
133
|
+
await stopLambda()
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
case 'cf':
|
|
137
|
+
return withPort(desiredPort, async (port) => {
|
|
138
|
+
let isBuilding = false
|
|
139
|
+
|
|
140
|
+
const buildWorker = async () => {
|
|
141
|
+
if (isBuilding) return
|
|
142
|
+
isBuilding = true
|
|
143
|
+
logger.step('Building worker')
|
|
144
|
+
try {
|
|
145
|
+
await build(platform)
|
|
146
|
+
await startWorker()
|
|
147
|
+
} catch (e) {
|
|
148
|
+
logger.error('Build failed:', e)
|
|
149
|
+
process.exit(0)
|
|
150
|
+
} finally {
|
|
151
|
+
isBuilding = false
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let worker: Miniflare | null = null
|
|
156
|
+
const startWorker = async () => {
|
|
157
|
+
if (worker) await worker.dispose()
|
|
158
|
+
|
|
159
|
+
worker = await createMiniflare({ port, host, liveReload: false })
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
await buildWorker()
|
|
163
|
+
logger.step(`API running on http://${host}:${port}`)
|
|
164
|
+
|
|
165
|
+
watch(async () => {
|
|
166
|
+
logger.step('Restarting server')
|
|
167
|
+
await buildWorker()
|
|
168
|
+
logger.step('Server restarted')
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
case 'node':
|
|
172
|
+
return withPort(desiredPort, async (port) => {
|
|
173
|
+
logger.step(`API running on http://${host}:${port}`)
|
|
174
|
+
|
|
175
|
+
spawn(
|
|
176
|
+
process.execPath,
|
|
177
|
+
[
|
|
178
|
+
join(__dirname, 'node_modules/.bin/tsx'), 'watch', join(__dirname, 'node_modules/rajt/src/dev.ts'),
|
|
179
|
+
],
|
|
180
|
+
{
|
|
181
|
+
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
|
182
|
+
env: {...process.env, PORT: args.port},
|
|
183
|
+
}
|
|
184
|
+
).on('exit', code => process.exit(code ?? 0))
|
|
185
|
+
.on('message', msg => {
|
|
186
|
+
if (process.send) process.send(msg)
|
|
187
|
+
}).on('disconnect', () => {
|
|
188
|
+
if (process.disconnect) process.disconnect()
|
|
189
|
+
})
|
|
190
|
+
})
|
|
191
|
+
default:
|
|
192
|
+
return logger.warn(
|
|
193
|
+
`🟠 Provide a valid platform: ${['aws', 'cf', 'node'].map(p => colors.blue(p)).join(', ')}.\n`
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
function withPort(desiredPort: number, cb: (port: number) => void) {
|
|
200
|
+
getAvailablePort(desiredPort)
|
|
201
|
+
.then((port: number) => {
|
|
202
|
+
if (port != desiredPort)
|
|
203
|
+
logger.warn(`Port ${desiredPort} was in use, using ${port} as a fallback`)
|
|
204
|
+
|
|
205
|
+
cb(port)
|
|
206
|
+
}).catch(e => logger.error('Error finding available port:', e))
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function getAssetChangeMessage(
|
|
210
|
+
e: ChokidarEventName,
|
|
211
|
+
path: string
|
|
212
|
+
): string {
|
|
213
|
+
path = relative(__dirname, path)
|
|
214
|
+
switch (e) {
|
|
215
|
+
case 'add':
|
|
216
|
+
return `File ${path} was added`
|
|
217
|
+
case 'addDir':
|
|
218
|
+
return `Directory ${path} was added`
|
|
219
|
+
case 'unlink':
|
|
220
|
+
return `File ${path} was removed`
|
|
221
|
+
case 'unlinkDir':
|
|
222
|
+
return `Directory ${path} was removed`
|
|
223
|
+
case 'change':
|
|
224
|
+
default:
|
|
225
|
+
return `${path} changed`
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function watch(cb: (e: ChokidarEventName | string, file: string) => Promise<void>) {
|
|
230
|
+
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'),
|
|
238
|
+
join(__dirname, '.env.dev'),
|
|
239
|
+
join(__dirname, '.env.prod'),
|
|
240
|
+
join(__dirname, 'package.json'),
|
|
241
|
+
join(__dirname, 'wrangler.toml'),
|
|
242
|
+
], {
|
|
243
|
+
ignored: /(^|[/\\])\../, // ignore hidden files
|
|
244
|
+
persistent: true,
|
|
245
|
+
ignoreInitial: true,
|
|
246
|
+
awaitWriteFinish: {
|
|
247
|
+
stabilityThreshold: 200,
|
|
248
|
+
pollInterval: 100,
|
|
249
|
+
},
|
|
250
|
+
})
|
|
251
|
+
let restartTimeout: NodeJS.Timeout | null = null
|
|
252
|
+
|
|
253
|
+
const watcher = (e: ChokidarEventName) => async (file: string) => {
|
|
254
|
+
logger.step(getAssetChangeMessage(e, file))
|
|
255
|
+
|
|
256
|
+
if (restartTimeout)
|
|
257
|
+
clearTimeout(restartTimeout)
|
|
258
|
+
|
|
259
|
+
restartTimeout = setTimeout(async () => {
|
|
260
|
+
await cb(e, file)
|
|
261
|
+
}, 300)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
codeWatcher.on('change', watcher('change'))
|
|
265
|
+
codeWatcher.on('add', watcher('add'))
|
|
266
|
+
codeWatcher.on('unlink', watcher('unlink'))
|
|
267
|
+
codeWatcher.on('addDir', watcher('addDir'))
|
|
268
|
+
codeWatcher.on('unlinkDir', watcher('unlinkDir'))
|
|
269
|
+
|
|
270
|
+
logger.step('Watching for file changes')
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async function wait(ms: number) {
|
|
274
|
+
return new Promise(r => setTimeout(r, ms))
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function getDockerHost() {
|
|
278
|
+
const platform = process.platform
|
|
279
|
+
|
|
280
|
+
if (platform == 'darwin') {
|
|
281
|
+
for (const socket of [
|
|
282
|
+
'/Users/'+ process.env.USER +'/.docker/run/docker.sock',
|
|
283
|
+
'/var/run/docker.sock',
|
|
284
|
+
process.env.DOCKER_HOST
|
|
285
|
+
]) {
|
|
286
|
+
if (socket && existsSync(socket.replace(/^unix:\/\//, '')))
|
|
287
|
+
return socket.includes('://') ? socket : `unix://${socket}`
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return 'tcp://localhost:2375'
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return process.env.DOCKER_HOST || (platform == 'win32' ? 'tcp://localhost:2375' : 'unix:///var/run/docker.sock')
|
|
294
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import esbuild from 'esbuild'
|
|
2
|
+
import TOML from '@iarna/toml'
|
|
3
|
+
import { Miniflare } from 'miniflare'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { mkdirSync, existsSync, readdirSync, rmSync, copyFileSync } from 'node:fs'
|
|
6
|
+
import { readFile, stat, writeFile } from 'node:fs/promises'
|
|
7
|
+
import { basename, dirname, join, relative } from 'node:path'
|
|
8
|
+
|
|
9
|
+
import { cacheRoutes } from '../../../routes'
|
|
10
|
+
|
|
11
|
+
const __dirname = join(dirname(fileURLToPath(import.meta.url)), '../../../../../../')
|
|
12
|
+
const __rajt = join(__dirname, 'node_modules/rajt/src')
|
|
13
|
+
|
|
14
|
+
export const formatSize = (bytes: number) => {
|
|
15
|
+
if (bytes < 1024) return `${bytes}b`
|
|
16
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)}kb`
|
|
17
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)}mb`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const formatTime = (ms: number) => {
|
|
21
|
+
if (ms < 1000) return `${ms}ms`
|
|
22
|
+
return `${(ms / 1000).toFixed(2)}s`
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const build = async (platform: 'aws' | 'cf' | 'node') => {
|
|
26
|
+
const startTime = Date.now()
|
|
27
|
+
|
|
28
|
+
const isCF = platform == 'cf'
|
|
29
|
+
const distDir = join(__dirname, 'dist')
|
|
30
|
+
|
|
31
|
+
existsSync(distDir)
|
|
32
|
+
? readdirSync(distDir).forEach(file => rmSync(join(distDir, file), { recursive: true, force: true }))
|
|
33
|
+
: mkdirSync(distDir, { recursive: true })
|
|
34
|
+
|
|
35
|
+
if (isCF) {
|
|
36
|
+
for (let file of [
|
|
37
|
+
'wrangler.toml',
|
|
38
|
+
]) {
|
|
39
|
+
file = join(__dirname, file)
|
|
40
|
+
if (existsSync(file))
|
|
41
|
+
copyFileSync(file, join(__dirname, 'dist', basename(file)))
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const opts = {
|
|
46
|
+
entryPoints: [join(__rajt, `prod-${platform}.ts`)],
|
|
47
|
+
bundle: true,
|
|
48
|
+
minify: false,
|
|
49
|
+
outfile: join(__dirname, 'dist/index.js'),
|
|
50
|
+
format: 'esm',
|
|
51
|
+
target: isCF ? 'es2022' : 'node20',
|
|
52
|
+
// platform: 'neutral',
|
|
53
|
+
platform: isCF ? 'browser' : 'node',
|
|
54
|
+
conditions: isCF ? ['worker', 'browser'] : [],
|
|
55
|
+
treeShaking: true,
|
|
56
|
+
legalComments: 'none',
|
|
57
|
+
external: [
|
|
58
|
+
'@aws-sdk', '@smithy',
|
|
59
|
+
...(isCF ? [
|
|
60
|
+
'cloudflare:workers',
|
|
61
|
+
'node:crypto', 'crypto',
|
|
62
|
+
'node:buffer', 'buffer',
|
|
63
|
+
] : []),
|
|
64
|
+
],
|
|
65
|
+
metafile: true,
|
|
66
|
+
write: false,
|
|
67
|
+
// define: {
|
|
68
|
+
// 'process.env.NODE_ENV': '"development"'
|
|
69
|
+
// },
|
|
70
|
+
// loader: {
|
|
71
|
+
// '.ts': 'ts',
|
|
72
|
+
// '.js': 'js'
|
|
73
|
+
// },
|
|
74
|
+
// tsconfig: join(__dirname, 'tsconfig.json'),
|
|
75
|
+
// sourcemap: true,
|
|
76
|
+
// logLevel: 'info',
|
|
77
|
+
plugins: [
|
|
78
|
+
{
|
|
79
|
+
name: 'preserve-class-names',
|
|
80
|
+
setup(build) {
|
|
81
|
+
build.onLoad(
|
|
82
|
+
{ filter: /(actions|features)\/.*\.ts$/ },
|
|
83
|
+
async (args) => {
|
|
84
|
+
const contents = await readFile(args.path, 'utf8')
|
|
85
|
+
const result = await esbuild.transform(contents, {
|
|
86
|
+
loader: 'ts',
|
|
87
|
+
minify: true,
|
|
88
|
+
keepNames: true
|
|
89
|
+
})
|
|
90
|
+
return { contents: result.code, loader: 'ts' }
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'remove-use-strict',
|
|
97
|
+
setup(build) {
|
|
98
|
+
build.onEnd(async (result) => {
|
|
99
|
+
if (!result.outputFiles) return
|
|
100
|
+
|
|
101
|
+
const files = result.outputFiles.filter(file => file.path.endsWith('.js'))
|
|
102
|
+
await Promise.all(files.map(async file => {
|
|
103
|
+
if (!file.path.endsWith('.js')) return
|
|
104
|
+
|
|
105
|
+
await writeFile(
|
|
106
|
+
file.path,
|
|
107
|
+
new TextDecoder()
|
|
108
|
+
.decode(file.contents)
|
|
109
|
+
.replace(/(["'`])\s*use strict\s*\1;?|`use strict`;?/g, '')
|
|
110
|
+
)
|
|
111
|
+
}))
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
await cacheRoutes()
|
|
119
|
+
|
|
120
|
+
logger.step('Routes cached')
|
|
121
|
+
|
|
122
|
+
const result = await esbuild.build(opts)
|
|
123
|
+
if (!result?.metafile) throw Error('build fail')
|
|
124
|
+
|
|
125
|
+
logger.step('Build completed successfully')
|
|
126
|
+
|
|
127
|
+
const stats = await stat(opts.outfile)
|
|
128
|
+
const size = formatSize(stats.size)
|
|
129
|
+
|
|
130
|
+
logger.step(
|
|
131
|
+
`Build done in ${formatTime(Date.now() - startTime)}`,
|
|
132
|
+
`${relative(join(__dirname, 'node_modules/rajt/src'), opts.entryPoints[0])} → ${relative(__dirname, opts.outfile)}`,
|
|
133
|
+
`Size: ${size}`,
|
|
134
|
+
`Files: ${Object.keys(result.metafile.outputs).length}`
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function parseWranglerConfig(file: string) {
|
|
139
|
+
try {
|
|
140
|
+
return TOML.parse(await readFile(join(__dirname, file), 'utf-8'))
|
|
141
|
+
} catch (e) {
|
|
142
|
+
logger.warn(`Could not parse ${file}, using defaults`)
|
|
143
|
+
return {}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function createMiniflare(options = {}, configPath = 'wrangler.toml') {
|
|
148
|
+
const config = await parseWranglerConfig(configPath)
|
|
149
|
+
|
|
150
|
+
return new Miniflare({
|
|
151
|
+
host: options.host || 'localhost',
|
|
152
|
+
port: options.port || 8787,
|
|
153
|
+
https: options.https || false,
|
|
154
|
+
httpsKey: options.httpsKey,
|
|
155
|
+
httpsCert: options.httpsCert,
|
|
156
|
+
liveReload: options.liveReload !== false,
|
|
157
|
+
updateCheck: false,
|
|
158
|
+
|
|
159
|
+
scriptPath: join(__dirname, 'dist/index.js'),
|
|
160
|
+
compatibilityDate: config.compatibility_date || '2024-11-01',
|
|
161
|
+
compatibilityFlags: config.compatibility_flags || [
|
|
162
|
+
'nodejs_compat',
|
|
163
|
+
],
|
|
164
|
+
|
|
165
|
+
bindings: {
|
|
166
|
+
// MY_VARIABLE: 'value',
|
|
167
|
+
// ENVIRONMENT: 'development',
|
|
168
|
+
...config.vars,
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
d1Databases: Object.fromEntries(config.d1_databases.map(db => [db.binding, db.database_id])),
|
|
172
|
+
|
|
173
|
+
modules: [
|
|
174
|
+
{ type: "ESModule", path: "dist/index.js" },
|
|
175
|
+
],
|
|
176
|
+
// modules: true,
|
|
177
|
+
// modulesRules: [
|
|
178
|
+
// { type: 'ESModule', include: ['**/*.js', '**/*.ts'] },
|
|
179
|
+
// ],
|
|
180
|
+
|
|
181
|
+
kvPersist: join(__dirname, '.wrangler/state/v3/kv'),
|
|
182
|
+
cachePersist: join(__dirname, '.wrangler/state/v3/cache'),
|
|
183
|
+
d1Persist: join(__dirname, '.wrangler/state/v3/d1'),
|
|
184
|
+
r2Persist: join(__dirname, '.wrangler/state/v3/r2'),
|
|
185
|
+
durablesPersist: join(__dirname, '.wrangler/state/v3/durable_objects'),
|
|
186
|
+
|
|
187
|
+
verbose: false,
|
|
188
|
+
|
|
189
|
+
// Logging
|
|
190
|
+
// log: new console.Console({
|
|
191
|
+
// stdout: process.stdout,
|
|
192
|
+
// stderr: process.stderr,
|
|
193
|
+
// inspectOptions: { depth: 3 }
|
|
194
|
+
// }),
|
|
195
|
+
|
|
196
|
+
cfFetch: false, // disable cf requests
|
|
197
|
+
upstream: config.upstream || 'https://example.com',
|
|
198
|
+
|
|
199
|
+
sitePath: config.site?.bucket ?
|
|
200
|
+
join(__dirname, config.site.bucket) : undefined,
|
|
201
|
+
siteInclude: config.site?.include || ['**/*'],
|
|
202
|
+
siteExclude: config.site?.exclude || [],
|
|
203
|
+
|
|
204
|
+
globalAsyncIO: true,
|
|
205
|
+
globalTimers: true,
|
|
206
|
+
globalRandom: true,
|
|
207
|
+
|
|
208
|
+
inspectorPort: options.inspectorPort || 9229,
|
|
209
|
+
|
|
210
|
+
cache: true,
|
|
211
|
+
cacheWarnUsage: true,
|
|
212
|
+
|
|
213
|
+
...options
|
|
214
|
+
})
|
|
215
|
+
}
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defineCommand, runMain, renderUsage } from 'citty'
|
|
2
|
+
import type { ArgsDef, CommandDef } from 'citty'
|
|
3
|
+
import colors from 'picocolors'
|
|
4
|
+
import { createConsola } from 'consola'
|
|
5
|
+
|
|
6
|
+
import { version as rajtVersion } from '../../package.json'
|
|
7
|
+
|
|
8
|
+
import logger, { type ILogger } from '../utils/logger'
|
|
9
|
+
|
|
10
|
+
import dev from './commands/dev'
|
|
11
|
+
|
|
12
|
+
// Prevent non-internal logs
|
|
13
|
+
(globalThis as any).logger = logger // Make it global in Node.js and browser
|
|
14
|
+
declare global { var logger: ILogger }
|
|
15
|
+
|
|
16
|
+
// console.log = () => {}
|
|
17
|
+
console.info = () => {}
|
|
18
|
+
console.warn = () => {}
|
|
19
|
+
console.error = () => {}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The main entrypoint for the CLI.
|
|
23
|
+
* main only gets called when the script is run directly, not when it's imported as a module.
|
|
24
|
+
*/
|
|
25
|
+
const directly = () => {
|
|
26
|
+
try {
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
return typeof vitest == 'undefined'
|
|
29
|
+
&& (
|
|
30
|
+
![typeof require, typeof module].includes('undefined') && require.main == module
|
|
31
|
+
|| import.meta.url == `file://${process.argv[1]}`
|
|
32
|
+
)
|
|
33
|
+
} catch {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const name = 'Rajt CLI'
|
|
39
|
+
const version = [name, colors.isColorSupported ? colors.gray('v'+rajtVersion) : rajtVersion].join(' ')
|
|
40
|
+
|
|
41
|
+
if (directly()) {
|
|
42
|
+
const _args = process.argv.slice(2)
|
|
43
|
+
if (_args.length == 1 && ['-v', '--version', '--v', '-version'].includes(_args[0])) {
|
|
44
|
+
console.log(version)
|
|
45
|
+
process.exit(0)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const consola = createConsola({ formatOptions: {date: false} })
|
|
49
|
+
async function showUsage<T extends ArgsDef = ArgsDef>(cmd: CommandDef<T>, parent?: CommandDef<T>) {
|
|
50
|
+
try {
|
|
51
|
+
consola.log((await renderUsage(cmd, parent)).split('\n').slice(1).join('\n') + '\n')
|
|
52
|
+
} catch (error) {
|
|
53
|
+
consola.error(error)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const main = defineCommand({
|
|
58
|
+
meta: {
|
|
59
|
+
name: 'rajt',
|
|
60
|
+
version: rajtVersion,
|
|
61
|
+
description: name,
|
|
62
|
+
},
|
|
63
|
+
subCommands: {
|
|
64
|
+
dev,
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
runMain(main, { rawArgs: _args?.length ? undefined : ['-h'], showUsage })
|
|
69
|
+
}
|
package/src/cli/types.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ChokidarEventName = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'
|
package/src/create-app.ts
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { Hono } from 'hono'
|
|
3
|
+
import { logger } from 'hono/logger'
|
|
3
4
|
import type { Env, Context, ErrorHandler, NotFoundHandler, Next } from 'hono'
|
|
4
5
|
// import type { MiddlewareHandler } from 'hono'
|
|
5
6
|
// import { createMiddleware } from 'hono/factory'
|
|
6
7
|
// import type { H, Handler, HandlerResponse } from 'hono/types'
|
|
7
8
|
import type { HTTPResponseError } from 'hono/types'
|
|
9
|
+
import colors from 'picocolors'
|
|
10
|
+
import { Envir } from 't0n'
|
|
8
11
|
import type { Routes } from './types'
|
|
9
12
|
import { BadRequest, Unauthorized } from './exceptions'
|
|
10
13
|
import { resolve, resolveMiddleware } from './utils/resolve'
|
|
11
14
|
import { getMiddlewares, getHandler } from './register'
|
|
12
15
|
import { isDev } from './utils/environment'
|
|
13
|
-
import
|
|
16
|
+
import localDate from './utils/local-date'
|
|
17
|
+
import request from './request'
|
|
14
18
|
import response from './response'
|
|
15
|
-
import cx from './context'
|
|
16
19
|
|
|
17
20
|
type InitFunction<E extends Env = Env> = (app: Hono<E>) => void
|
|
18
21
|
|
|
@@ -31,13 +34,13 @@ const EHandler = async (e: Error | HTTPResponseError) => {
|
|
|
31
34
|
|
|
32
35
|
switch (true) {
|
|
33
36
|
case e instanceof Unauthorized:
|
|
34
|
-
case 'status' in e && e.status
|
|
37
|
+
case 'status' in e && e.status == 401:
|
|
35
38
|
return response.unauthorized()
|
|
36
39
|
|
|
37
40
|
case e instanceof BadRequest:
|
|
38
|
-
case 'status' in e && e.status
|
|
41
|
+
case 'status' in e && e.status == 400:
|
|
39
42
|
// @ts-ignore
|
|
40
|
-
return response.badRequest(
|
|
43
|
+
return response.badRequest(null, e?.message)
|
|
41
44
|
|
|
42
45
|
default:
|
|
43
46
|
return response.internalError(
|
|
@@ -78,13 +81,16 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
|
78
81
|
// const root = options?.root ?? '/'
|
|
79
82
|
const app = options?.app ?? new Hono<E>()
|
|
80
83
|
|
|
84
|
+
if (isDev())
|
|
85
|
+
app.use('*', logger((...args: any[]) => console.log(colors.gray(localDate()), ...args)))
|
|
86
|
+
|
|
81
87
|
app.use(async (c: Context, next: Next) => {
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
c.set('_', new request(c))
|
|
89
|
+
if (c.env) Envir.add(c.env)
|
|
84
90
|
await next()
|
|
85
91
|
})
|
|
86
92
|
getMiddlewares().forEach(mw => {
|
|
87
|
-
const h = async (c: Context, next: Next) => await resolveMiddleware(mw)(
|
|
93
|
+
const h = async (c: Context, next: Next) => await resolveMiddleware(mw)(c.get('_'), next)
|
|
88
94
|
// @ts-ignore
|
|
89
95
|
mw?.path ? app.use(String(mw.path), h) : app.use(h)
|
|
90
96
|
})
|
|
@@ -111,7 +117,7 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>) => {
|
|
|
111
117
|
|
|
112
118
|
function mw(...objs: string[]): Function[] {
|
|
113
119
|
return objs.flatMap(obj => {
|
|
114
|
-
if (typeof obj
|
|
120
|
+
if (typeof obj != 'string') return null
|
|
115
121
|
// @ts-ignore
|
|
116
122
|
return getHandler(obj)?.mw || null
|
|
117
123
|
}).flat().filter(Boolean)
|
package/src/db/d1.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'forj/d1/types'
|
package/src/db/d1.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'forj/d1'
|