rajt 0.0.82 → 0.0.84

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.82",
4
+ "version": "0.0.84",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
7
7
  "bin": {
@@ -39,11 +39,10 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "cripta": "^0.1",
42
- "forj": "^0.0.6",
42
+ "forj": "^0.0.8",
43
43
  "t0n": "^0.1",
44
44
  "@hono/node-server": "^1.19.9",
45
45
  "@hono/standard-validator": "^0.2.2",
46
- "@iarna/toml": "^2.2.5",
47
46
  "@scalar/hono-api-reference": "^0.9.40",
48
47
  "chokidar-cli": "^3.0.0",
49
48
  "citty": "^0.1.6",
@@ -51,6 +50,8 @@
51
50
  "esbuild": "^0.25.2",
52
51
  "hono": "^4.11.7",
53
52
  "hono-openapi": "^1.2.0",
53
+ "localflare-api": "^0.4.2",
54
+ "localflare-core": "^0.4.2",
54
55
  "miniflare": "^4.20251217.0",
55
56
  "quansync": "^0.2.11",
56
57
  "tiny-glob": "^0.2",
@@ -1,9 +1,9 @@
1
1
  import { defineCommand } from 'citty'
2
2
  import { gray } from '../../utils/colors'
3
- import { build, normalizePlatform, platformError } from './utils'
3
+ import { build, normalizePlatform, platformError } from '../utils'
4
4
  import { wait, error, rn } from '../../utils/log'
5
5
 
6
- import { platforms } from './constants'
6
+ import { platforms } from '../constants'
7
7
 
8
8
  export default defineCommand({
9
9
  meta: {
@@ -1,9 +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 { _root, normalizePlatform, platformError, getRuntime } from '../utils'
5
5
  import { error } from '../../utils/log'
6
- import { platforms } from './constants'
6
+ import { platforms } from '../constants'
7
7
 
8
8
  import build from './build'
9
9
 
@@ -3,7 +3,11 @@ import { spawn, type ChildProcess } from 'node:child_process'
3
3
 
4
4
  import { defineCommand } from 'citty'
5
5
  import type { Miniflare } from 'miniflare'
6
- import { _root, build, wait, watch, normalizePlatform, platformError, getRuntime, createMiniflare, getDockerHost } from './utils'
6
+ import {
7
+ _root, build, wait, watch, normalizePlatform, platformError, getRuntime,
8
+ wranglerConfig, createMiniflare, localflareManifest,
9
+ getDockerHost
10
+ } from '../utils'
7
11
  import { error, event, log, rn, warn } from '../../utils/log'
8
12
  import { withPort } from '../../utils/port'
9
13
  import shutdown from '../../utils/shutdown'
@@ -103,6 +107,8 @@ export default defineCommand({
103
107
 
104
108
  const started = (port: number) => {
105
109
  log(`Starting API on http://${host}:${port}`)
110
+ if (platform == 'cf')
111
+ log(`Localflare on https://studio.localflare.dev`)
106
112
  rn()
107
113
  }
108
114
 
@@ -156,9 +162,28 @@ export default defineCommand({
156
162
  return withPort(desiredPort, async (port) => {
157
163
  started(port)
158
164
  let worker: Miniflare | null = null
165
+ let localflare: Miniflare | null = null
159
166
  const startWorker = async () => {
160
167
  if (worker) await worker.dispose()
161
- worker = await createMiniflare({ port, host, liveReload: false })
168
+ if (localflare) await localflare.dispose()
169
+
170
+ const workerConfig = await wranglerConfig()
171
+ workerConfig.host = host
172
+ workerConfig.liveReload = false
173
+
174
+ worker = createMiniflare({ ...workerConfig, port })
175
+ await worker.ready
176
+ localflare = createMiniflare({
177
+ ...workerConfig,
178
+ vars: {
179
+ ...workerConfig.vars,
180
+ LOCALFLARE_MANIFEST: JSON.stringify(localflareManifest(workerConfig)),
181
+ },
182
+ main: 'node_modules/localflare-api/dist/worker/index.js',
183
+ port: 8788,
184
+ inspectorPort: 9230,
185
+ })
186
+ await localflare.ready
162
187
  }
163
188
 
164
189
  await startApp(startWorker)
@@ -1,8 +1,9 @@
1
1
  import { defineCommand } from 'citty'
2
2
  import { join, relative } from 'node:path'
3
3
  import { Migrator } from 'forj'
4
- import { _root, makeFile, hasExt, camelCase, kebabCase } from './utils'
4
+ import { _root, makeFile, hasExt, camelCase, kebabCase } from '../utils'
5
5
  import { event, error } from '../../utils/log'
6
+ import * as stub from '../stubs'
6
7
 
7
8
  export default defineCommand({
8
9
  meta: {
@@ -31,32 +32,20 @@ export default defineCommand({
31
32
  case 'endpoint':
32
33
  fileName = path(kebabCase(name))
33
34
  if (!fileName.endsWith('.ts')) fileName += '.ts'
34
- const className = camelCase(name)
35
- makeFile(fileName, `import { Action } from 'rajt'
36
- import { IRequest, IResponse } from 'rajt/types'
37
-
38
- export default class ${className} extends Action {
39
- static async handle(req: IRequest, res: IResponse) {
40
- return res.ok('${className}')
41
- }
42
- }
43
- `)
35
+ makeFile(fileName, stub.replace(stub.route, { R_NAME: camelCase(name) }))
44
36
  break
45
37
  case 'migrate':
46
38
  case 'migration':
47
- fileName = path(Migrator.fileName(name), 'migration')
39
+ fileName = Migrator.fileName(name)
40
+ const [table, create] = Migrator.guess(fileName)
41
+ fileName = path(fileName, 'migration')
48
42
  if (!fileName.endsWith('.ts')) fileName += '.ts'
49
- makeFile(fileName, `import { Migration, Schema, Blueprint } from 'rajt/db'
50
-
51
- export default class ${Migrator.className(name)} extends Migration {
52
- static async run() {
53
- Schema.${name.includes('create') ? 'create' : 'table'}('users', (table: Blueprint) => {
54
- table.id()
55
- table.timestamps()
56
- })
57
- }
58
- }
59
- `)
43
+ makeFile(fileName, stub.replace(stub.migration, {
44
+ M_NAME: Migrator.className(name),
45
+ S_NAME: create ? 'create' : 'table',
46
+ T_NAME: table || 'TABLE_NAME',
47
+ M_CONTENT: create ? stub.migrationCreate : '//',
48
+ }))
60
49
  break
61
50
  case 'model':
62
51
  error('Action not yet implemented, contact the webmaster')
@@ -2,8 +2,8 @@ import { defineCommand } from 'citty'
2
2
  import { spawn } from 'node:child_process'
3
3
  import { Migrator } from 'forj'
4
4
  import { gray } from '../../utils/colors'
5
- import { _root, getRuntime } from './utils'
6
- import { wait, info, event, rn, error } from '../../utils/log'
5
+ import { _root, getRuntime, cleanDir, d1Path, wait as WAIT } from '../utils'
6
+ import { wait, info, event, rn, error, log } from '../../utils/log'
7
7
 
8
8
  export default defineCommand({
9
9
  meta: {
@@ -34,11 +34,18 @@ export default defineCommand({
34
34
  switch (action) {
35
35
  case 'migrate':
36
36
  case 'apply':
37
- wait('Running migrations')
37
+ case 'fresh':
38
+ case 'refresh':
38
39
  if (!pending?.length)
39
- return info(' Nothing to migrate')
40
+ log('Nothing to compile')
41
+ wait('Running migrations')
42
+
43
+ if (action.includes('fresh')) {
44
+ cleanDir(d1Path)
45
+ await WAIT(2000)
46
+ }
40
47
 
41
- await Migrator.compile(pending)
48
+ await Migrator.compile([...migrated, ...pending])
42
49
 
43
50
  const child = spawn(
44
51
  isBun ? 'bunx' : 'npx',
@@ -50,11 +57,8 @@ export default defineCommand({
50
57
  )
51
58
 
52
59
  child.on('exit', code => process.exit(code ?? 0))
53
- .on('message', msg => {
54
- process.send && process.send(msg)
55
- }).on('disconnect', () => {
56
- process.disconnect && process.disconnect()
57
- })
60
+ .on('message', msg => process.send && process.send(msg))
61
+ .on('disconnect', () => process.disconnect && process.disconnect())
58
62
 
59
63
  pending.forEach(item => event(item.name))
60
64
  break
@@ -3,7 +3,7 @@ import { defineCommand } from 'citty'
3
3
  import { inspectRoutes } from 'hono/dev'
4
4
  import { IMPORT } from 't0n'
5
5
  import { gray, purple, red, yellow } from '../../utils/colors'
6
- import { __rajt } from './utils'
6
+ import { __rajt } from '../utils'
7
7
  import { rn } from '../../utils/log'
8
8
 
9
9
  export default defineCommand({
@@ -0,0 +1,42 @@
1
+ export const replace = (str: string, map: Record<string, string>) => {
2
+ if (!str || typeof str != 'string' || !map || typeof map != 'object') return str
3
+ const entries = Object.entries(map)
4
+ const length = entries?.length || 0
5
+ if (!length) return str
6
+
7
+ str = str.trimStart()
8
+ if (length == 1)
9
+ return str.replaceAll(entries[0][0], entries[0][1])
10
+
11
+ return entries.reduce(
12
+ (acc, entry) => acc.replace(new RegExp(entry[0].replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), entry[1]),
13
+ str
14
+ )
15
+ }
16
+
17
+ export const route = `
18
+ import { Action } from 'rajt'
19
+ import { IRequest, IResponse } from 'rajt/types'
20
+
21
+ export default class R_NAME extends Action {
22
+ static async handle(req: IRequest, res: IResponse) {
23
+ return res.ok('R_NAME')
24
+ }
25
+ }
26
+ `
27
+
28
+ export const migration = `
29
+ import { Migration, Schema, Blueprint } from 'rajt/db'
30
+
31
+ export default class M_NAME extends Migration {
32
+ static async run() {
33
+ Schema.S_NAME('T_NAME', (table: Blueprint) => {
34
+ M_CONTENT
35
+ })
36
+ }
37
+ }
38
+ `
39
+ export const migrationCreate = `
40
+ table.id()
41
+ table.timestamps()
42
+ `.trim()
@@ -1,19 +1,21 @@
1
1
  import esbuild from 'esbuild'
2
- import TOML from '@iarna/toml'
3
2
  import { Miniflare } from 'miniflare'
4
- import { mkdirSync, existsSync, readdirSync, rmSync, copyFileSync, writeFileSync } from 'node:fs'
3
+ import { mkdirSync, existsSync, statSync, readdirSync, rmSync, unlinkSync, copyFileSync, writeFileSync } from 'node:fs'
5
4
  import { readFile, stat, writeFile } from 'node:fs/promises'
6
5
  import { basename, dirname, join, relative } from 'node:path'
7
6
 
7
+ import { findWranglerConfig, parseWranglerConfig, WRANGLER_CONFIG_FILES } from 'localflare-core'
8
+ import type { WranglerConfig, LocalflareManifest } from 'localflare-core'
9
+
8
10
  import chokidar from 'chokidar'
9
- import { gray } from '../../utils/colors'
11
+ import { gray, red } from '../utils/colors'
10
12
  import type { ChokidarEventName, Platform } from './types'
11
13
 
12
- import { cacheRoutes } from '../../routes'
13
- import { step, substep, event, error, wait as wwait, warn, log } from '../../utils/log'
14
+ import { cacheRoutes } from '../routes'
15
+ import { substep, event, error, wait as wwait, warn, log } from '../utils/log'
14
16
  import { platforms } from './constants'
15
17
 
16
- export const _root = join(dirname(new URL(import.meta.url).pathname), '../../../../../')
18
+ export const _root = join(dirname(new URL(import.meta.url).pathname), '../../../../')
17
19
  export const __rajt = join(_root, 'node_modules/rajt/src')
18
20
 
19
21
  export function normalizePlatform(platform: Platform) {
@@ -71,16 +73,10 @@ export const build = async (platform: Platform) => {
71
73
  const startTime = Date.now()
72
74
 
73
75
  const isCF = platform == 'cf'
74
- const distDir = join(_root, dist)
75
-
76
- existsSync(distDir)
77
- ? readdirSync(distDir).forEach(file => rmSync(join(distDir, file), { recursive: true, force: true }))
78
- : mkdirSync(distDir, { recursive: true })
76
+ cleanDir(join(_root, dist))
79
77
 
80
78
  if (isCF) {
81
- for (let file of [
82
- 'wrangler.toml',
83
- ]) {
79
+ for (let file of WRANGLER_CONFIG_FILES) {
84
80
  file = join(_root, file)
85
81
  if (existsSync(file))
86
82
  copyFileSync(file, join(_root, dist, basename(file)))
@@ -181,54 +177,118 @@ export const build = async (platform: Platform) => {
181
177
  )
182
178
  }
183
179
 
184
- async function parseWranglerConfig(file: string) {
180
+ export function cleanDir(path: string) {
181
+ try {
182
+ if (!existsSync(path))
183
+ return mkdirSync(path, {recursive: true})
184
+
185
+ const files = readdirSync(path)
186
+
187
+ for (const file of files) {
188
+ const filePath = join(path, file)
189
+ const stat = statSync(filePath)
190
+
191
+ stat.isDirectory()
192
+ ? rmSync(filePath, {recursive: true, force: true})
193
+ : unlinkSync(filePath)
194
+ }
195
+ } catch {}
196
+ }
197
+
198
+ export function wranglerConfig(file?: string) {
199
+ file ??= findWranglerConfig(_root)
200
+ if (!file) {
201
+ console.log(red(` ✗ Could not find wrangler config file`))
202
+ console.log(red(` Looking for: ${WRANGLER_CONFIG_FILES.join(', ')}`))
203
+ process.exit(1)
204
+ }
205
+
185
206
  try {
186
- return TOML.parse(await readFile(join(_root, file), 'utf-8'))
207
+ return parseWranglerConfig(file)
187
208
  } catch (e) {
188
209
  warn(`Could not parse ${file}, using defaults`)
189
210
  return {}
190
211
  }
191
212
  }
192
213
 
193
- export async function createMiniflare(options = {}, configPath = 'wrangler.toml') {
194
- const config = await parseWranglerConfig(configPath)
214
+ export function localflareManifest(opts: WranglerConfig): LocalflareManifest {
215
+ return {
216
+ name: opts.name || 'worker',
217
+ d1: (opts.d1_databases || []).map((db) => ({
218
+ binding: db.binding,
219
+ database_name: db.database_name,
220
+ })),
221
+ kv: (opts.kv_namespaces || []).map((kv) => ({
222
+ binding: kv.binding,
223
+ })),
224
+ r2: (opts.r2_buckets || []).map((r2) => ({
225
+ binding: r2.binding,
226
+ bucket_name: r2.bucket_name,
227
+ })),
228
+ queues: {
229
+ producers: (opts.queues?.producers || []).map((p) => ({
230
+ binding: p.binding,
231
+ queue: p.queue,
232
+ })),
233
+ consumers: (opts.queues?.consumers || []).map((c) => ({
234
+ queue: c.queue,
235
+ max_batch_size: c.max_batch_size,
236
+ max_batch_timeout: c.max_batch_timeout,
237
+ max_retries: c.max_retries,
238
+ dead_letter_queue: c.dead_letter_queue,
239
+ })),
240
+ },
241
+ do: (opts.durable_objects?.bindings || []).map((d) => ({
242
+ binding: d.name,
243
+ className: d.class_name,
244
+ })),
245
+ vars: Object.entries(opts.vars || {}).map(([key, value]) => ({
246
+ key,
247
+ value,
248
+ isSecret: false,
249
+ // isSecret: looksLikeSecret(key, value),
250
+ })),
251
+ }
252
+ }
253
+
254
+ const wranglerPath = '.wrangler/state/v3'
255
+ export const kvPath = join(_root, wranglerPath, 'kv')
256
+ export const d1Path = join(_root, wranglerPath, 'd1')
257
+ export const r2Path = join(_root, wranglerPath, 'r2')
258
+ export const doPath = join(_root, wranglerPath, 'durable_objects')
195
259
 
260
+ export function createMiniflare(opts = {}) {
261
+ const entry = join(_root, opts?.main || opts?.script)
196
262
  return new Miniflare({
197
- host: options.host || 'localhost',
198
- port: options.port || 8787,
199
- https: options.https || false,
200
- httpsKey: options.httpsKey,
201
- httpsCert: options.httpsCert,
202
- liveReload: options.liveReload !== false,
263
+ host: opts.host || 'localhost',
264
+ port: opts.port || 8787,
265
+ https: opts.https || false,
266
+ httpsKey: opts.httpsKey,
267
+ httpsCert: opts.httpsCert,
268
+ liveReload: opts.liveReload !== false,
203
269
  updateCheck: false,
204
-
205
- scriptPath: join(_root, dist +'/index.js'),
206
- compatibilityDate: config.compatibility_date || '2024-11-01',
207
- compatibilityFlags: config.compatibility_flags || [
270
+ scriptPath: entry,
271
+ modules: [
272
+ {type: 'ESModule', path: entry},
273
+ ],
274
+ compatibilityDate: opts.compatibility_date || '2024-11-01',
275
+ compatibilityFlags: opts.compatibility_flags || [
208
276
  'nodejs_compat',
209
277
  ],
210
-
211
278
  bindings: {
212
- // MY_VARIABLE: 'value',
213
- // ENVIRONMENT: 'development',
214
- ...config.vars,
279
+ ...opts.vars,
215
280
  },
216
281
 
217
- d1Databases: Array.isArray(config.d1_databases) ? Object.fromEntries(config.d1_databases.map(db => [db.binding, db.database_id])) : {},
282
+ d1Databases: Array.isArray(opts.d1_databases) ? Object.fromEntries(opts.d1_databases.map(db => [db.binding, db.database_id])) : {},
283
+ kvNamespaces: Object.fromEntries((opts.kv_namespaces || []).map(ns => [ns.binding, ns.id])),
284
+ // r2Buckets: Object.fromEntries((opts.r2_buckets || []).map(r2 => [r2.binding, r2.bucket_name])),
285
+ // durableObjects: Object.fromEntries((opts.durable_objects?.bindings || []).map(do => [do.name, do.class_name])),
218
286
 
219
- modules: [
220
- { type: 'ESModule', path: dist +'/index.js' },
221
- ],
222
- // modules: true,
223
- // modulesRules: [
224
- // { type: 'ESModule', include: ['**/*.js', '**/*.ts'] },
225
- // ],
226
-
227
- kvPersist: join(_root, '.wrangler/state/v3/kv'),
228
- cachePersist: join(_root, '.wrangler/state/v3/cache'),
229
- d1Persist: join(_root, '.wrangler/state/v3/d1'),
230
- r2Persist: join(_root, '.wrangler/state/v3/r2'),
231
- durablesPersist: join(_root, '.wrangler/state/v3/durable_objects'),
287
+ kvPersist: kvPath,
288
+ cachePersist: join(_root, wranglerPath, 'cache'),
289
+ d1Persist: d1Path,
290
+ r2Persist: r2Path,
291
+ durablesPersist: doPath,
232
292
 
233
293
  verbose: false,
234
294
 
@@ -240,23 +300,21 @@ export async function createMiniflare(options = {}, configPath = 'wrangler.toml'
240
300
  // }),
241
301
 
242
302
  cfFetch: false, // disable cf requests
243
- upstream: config.upstream || 'https://example.com',
303
+ upstream: opts.upstream || 'https://example.com',
244
304
 
245
- sitePath: config.site?.bucket ?
246
- join(_root, config.site.bucket) : undefined,
247
- siteInclude: config.site?.include || ['**/*'],
248
- siteExclude: config.site?.exclude || [],
305
+ sitePath: opts.site?.bucket ?
306
+ join(_root, opts.site.bucket) : undefined,
307
+ siteInclude: opts.site?.include || ['**/*'],
308
+ siteExclude: opts.site?.exclude || [],
249
309
 
250
310
  globalAsyncIO: true,
251
311
  globalTimers: true,
252
312
  globalRandom: true,
253
313
 
254
- inspectorPort: options.inspectorPort || 9229,
314
+ inspectorPort: opts.inspectorPort || 9229,
255
315
 
256
316
  cache: true,
257
317
  cacheWarnUsage: true,
258
-
259
- ...options
260
318
  })
261
319
  }
262
320
 
@@ -285,8 +343,8 @@ export async function watch(cb: (e: ChokidarEventName | string, file: string) =>
285
343
  join(_root, '{actions,features,routes,configs,enums,libs,locales,middlewares,models,utils}/**/*.ts'),
286
344
  join(_root, '.env.dev'),
287
345
  join(_root, '.env.prod'),
288
- join(_root, 'package.json'),
289
- join(_root, 'wrangler.toml'),
346
+ join(_root, 'package.json'),
347
+ ...WRANGLER_CONFIG_FILES.map(f => join(_root, f)),
290
348
  ], {
291
349
  ignored: /(^|[/\\])\../, // ignore hidden files
292
350
  persistent: true,
File without changes
File without changes