UNPKG

@lunora/cli

Version:

The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands

193 lines (190 loc) 6.68 kB
import { readFileSync, existsSync } from 'node:fs'; import { join } from 'node:path'; import { discoverSchema } from '@lunora/codegen'; import { readLinkedProject } from '@lunora/config'; import { parse } from 'jsonc-parser'; import { Project } from 'ts-morph'; import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs'; const findWranglerFile = (projectRoot) => { for (const candidate of ["wrangler.jsonc", "wrangler.json"]) { const fullPath = join(projectRoot, candidate); if (existsSync(fullPath)) { return fullPath; } } return void 0; }; const stringField = (record, key) => { if (record === null || typeof record !== "object") { return void 0; } const value = record[key]; return typeof value === "string" && value.length > 0 ? value : void 0; }; const arrayField = (record, key) => { if (record === null || typeof record !== "object") { return []; } const value = record[key]; return Array.isArray(value) ? value : []; }; const summariseWrangler = (raw) => { const durableObjectBindings = arrayField(raw.durable_objects ?? {}, "bindings"); const d1 = arrayField(raw, "d1_databases"); const vectorize = arrayField(raw, "vectorize"); return { bindings: { d1: d1.map((entry) => stringField(entry, "binding") ?? "<unnamed>"), durableObjects: durableObjectBindings.map((entry) => stringField(entry, "name") ?? "<unnamed>"), vectorize: vectorize.map((entry) => stringField(entry, "binding") ?? "<unnamed>") }, compatibilityDate: stringField(raw, "compatibility_date"), compatibilityFlags: arrayField(raw, "compatibility_flags").filter((entry) => typeof entry === "string"), main: stringField(raw, "main"), name: stringField(raw, "name") }; }; const summariseSchema = (schema) => { return { tables: schema.tables.map((table) => { let shard = "root"; if (table.shardMode === "global") { shard = "global"; } else if (typeof table.shardMode === "object") { shard = `shardBy(${table.shardMode.field})`; } return { indexes: table.indexes.length, name: table.name, shard }; }), vectorIndexes: schema.vectorIndexes.length }; }; const collectLunoraPackages = (projectRoot) => { const pkgPath = join(projectRoot, "package.json"); if (!existsSync(pkgPath)) { return []; } let pkg; try { pkg = JSON.parse(readFileSync(pkgPath, "utf8")); } catch { return []; } if (pkg === null || typeof pkg !== "object") { return []; } const sections = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]; const seen = /* @__PURE__ */ new Map(); for (const section of sections) { const block = pkg[section]; if (block === null || typeof block !== "object") { continue; } for (const [name, version] of Object.entries(block)) { if (!name.startsWith("@lunora/")) { continue; } if (typeof version === "string" && !seen.has(name)) { seen.set(name, version); } } } return [...seen.entries()].toSorted(([a], [b]) => a.localeCompare(b)).map(([name, version]) => { return { name, version }; }); }; const collectInfo = (projectRoot) => { const lunoraPackages = collectLunoraPackages(projectRoot); const wranglerPath = findWranglerFile(projectRoot); let wrangler; if (wranglerPath) { try { wrangler = summariseWrangler(parse(readFileSync(wranglerPath, "utf8"))); } catch { wrangler = void 0; } } const schemaPath = join(projectRoot, "lunora", "schema.ts"); let schema; let schemaError; if (existsSync(schemaPath)) { try { const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false }); schema = summariseSchema(discoverSchema(project, schemaPath)); } catch (error) { schemaError = error instanceof Error ? error.message : String(error); } } return { link: readLinkedProject(projectRoot), lunoraPackages, projectRoot, schema, schemaError, wrangler, wranglerPath }; }; const renderText = (snapshot, logger) => { logger.info(`project: ${snapshot.projectRoot}`); logger.info(""); logger.info("@lunora/* packages:"); if (snapshot.lunoraPackages.length === 0) { logger.info(" (none found in package.json)"); } else { for (const pkg of snapshot.lunoraPackages) { logger.info(` ${pkg.name}@${pkg.version}`); } } logger.info(""); if (snapshot.wrangler) { logger.info(`wrangler: ${snapshot.wranglerPath ?? ""}`); logger.info(` name: ${snapshot.wrangler.name ?? "<unset>"}`); logger.info(` main: ${snapshot.wrangler.main ?? "<unset>"}`); logger.info(` compatibility_date: ${snapshot.wrangler.compatibilityDate ?? "<unset>"}`); logger.info(` compatibility_flags: ${snapshot.wrangler.compatibilityFlags.join(", ") || "<none>"}`); logger.info(` durable objects: ${snapshot.wrangler.bindings.durableObjects.join(", ") || "<none>"}`); logger.info(` d1 databases: ${snapshot.wrangler.bindings.d1.join(", ") || "<none>"}`); logger.info(` vectorize indexes: ${snapshot.wrangler.bindings.vectorize.join(", ") || "<none>"}`); } else { logger.info("wrangler: (not found)"); } logger.info(""); if (snapshot.link) { logger.info(`link: ${snapshot.link.workerName ?? "(unnamed)"} -> ${snapshot.link.workerUrl ?? "<no url>"}`); if (snapshot.link.env !== void 0) { logger.info(` env: ${snapshot.link.env}`); } } else { logger.info("link: (not linked — run `lunora link --url <https://your-worker>`)"); } logger.info(""); if (snapshot.schemaError !== void 0) { logger.warn(`schema: parse error — ${snapshot.schemaError}`); } else if (snapshot.schema) { logger.info(`schema: ${String(snapshot.schema.tables.length)} table(s), ${String(snapshot.schema.vectorIndexes)} vector index(es)`); for (const table of snapshot.schema.tables) { logger.info(` ${table.name} [${table.shard}, ${String(table.indexes)} index(es)]`); } } else { logger.info("schema: (no lunora/schema.ts)"); } }; const runInfoCommand = (options) => { const cwd = options.cwd ?? process.cwd(); const snapshot = collectInfo(cwd); if (options.json) { process.stdout.write(`${JSON.stringify(snapshot, void 0, 2)} `); } else { renderText(snapshot, options.logger); } return { code: 0, snapshot }; }; const execute = defineHandler( ({ cwd, logger, options }) => runInfoCommand({ cwd, json: options.json === true, logger }) ); export { collectInfo, execute, runInfoCommand };