UNPKG

@lunora/cli

Version:

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

161 lines (158 loc) 6.71 kB
import { existsSync } from 'node:fs'; import { findWranglerFile } from '@lunora/config'; import { join, basename } from '@visulima/path'; import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs'; import { v as validateOutputFormat, i as isJsonFormat, p as printJson, l as loggerForFormat } from '../packem_shared/output-format-B4642rjE.mjs'; import { t as tuiText, a as tuiSelect } from '../packem_shared/tui-prompts-BjEN8XgP.mjs'; import { n as normalizeFeature, E as EMAIL_ITEM, s as sanitizeBucketName, d as deriveBucketName, p as promptBucketName, r as resolveTypedDestination, M as MAIL_DESTINATION_PROMPT, a as sanitizeDatabaseName, b as deriveDatabaseName, c as promptDatabaseName, D as DEFAULT_AUTH_ITEM, e as promptAuthProvider, A as AUTH_PROVIDER_OPTIONS, w as withStorageBucketName, f as withMailDestination, g as withAuthDatabaseName } from '../packem_shared/storage-BXU4ax4O.mjs'; import { r as runAddCommand } from '../packem_shared/commands-D5Yxt9VY.mjs'; const providerToItem = (provider) => { const value = provider.trim().toLowerCase(); const match = AUTH_PROVIDER_OPTIONS.find( (option) => option.value === value || option.label.toLowerCase() === value || value === "auth0" && option.value === "auth-auth0" || value === "clerk" && option.value === "auth-clerk" ); return match?.value; }; const resolveAuthItem = async (options) => { if (options.provider !== void 0 && options.provider !== "") { const item = providerToItem(options.provider); if (item === void 0) { options.logger.warn(`add: unknown --provider "${options.provider}" — using "${DEFAULT_AUTH_ITEM}" (email & password).`); return DEFAULT_AUTH_ITEM; } return item; } if (options.yes === true) { return DEFAULT_AUTH_ITEM; } const select = options.promptSelect ?? ((message, choices, settings) => tuiSelect(message, choices, settings)); return promptAuthProvider(select); }; const textPrompt = (options) => options.promptText ?? ((message, settings) => tuiText(message, settings)); const resolveStorageBucketName = async (options) => { const projectName = basename(options.cwd ?? process.cwd()); if (options.bucket !== void 0 && options.bucket !== "") { const sanitized = sanitizeBucketName(options.bucket); if (sanitized !== void 0) { return sanitized; } const fallback = deriveBucketName(projectName); options.logger.warn(`add: "${options.bucket}" isn't a valid R2 bucket name (lowercase alphanumeric + hyphens, 3–63 chars) — using "${fallback}".`); return fallback; } if (options.yes === true) { return deriveBucketName(projectName); } return promptBucketName(textPrompt(options), projectName); }; const resolveMailDestination = async (options) => { const warn = (message) => { options.logger.warn(`add: ${message}`); }; if (options.mailTo !== void 0 && options.mailTo !== "") { return resolveTypedDestination(options.mailTo, warn); } if (options.yes === true) { return void 0; } return resolveTypedDestination(await textPrompt(options)(MAIL_DESTINATION_PROMPT, { placeholder: "you@yourdomain.com" }), warn); }; const resolveAuthDatabaseName = async (options) => { const projectName = basename(options.cwd ?? process.cwd()); if (options.db !== void 0 && options.db !== "") { const sanitized = sanitizeDatabaseName(options.db); if (sanitized !== void 0) { return sanitized; } const fallback = deriveDatabaseName(projectName); options.logger.warn(`add: "${options.db}" isn't a usable D1 database name — using "${fallback}".`); return fallback; } if (options.yes === true) { return deriveDatabaseName(projectName); } return promptDatabaseName(textPrompt(options), projectName); }; const resolveFeatureItems = async (feature, options) => { if (feature.kind === "auth") { return [await resolveAuthItem(options)]; } if (feature.kind === "email") { return [EMAIL_ITEM]; } return [feature.item]; }; const runAddFeature = async (options) => { const cwd = options.cwd ?? process.cwd(); const feature = options.feature === void 0 ? void 0 : normalizeFeature(options.feature); if (feature === void 0) { options.logger.error("add requires a feature or registry item. Usage: lunora add <auth|email|storage|crons|presence|…>"); return { code: 1, items: [] }; } if (!existsSync(join(cwd, "lunora")) || findWranglerFile(cwd) === void 0) { options.logger.error("add: not a Lunora project here (need a lunora/ directory and a wrangler.jsonc). Run `lunora init` first."); return { code: 1, items: [] }; } const items = await resolveFeatureItems(feature, options); const transforms = []; if (items.includes("storage")) { const bucketName = await resolveStorageBucketName(options); transforms.push((manifest) => withStorageBucketName(manifest, bucketName)); } if (items.includes("mail")) { const destination = await resolveMailDestination(options); if (destination !== void 0) { transforms.push((manifest) => withMailDestination(manifest, destination)); } } if (items.some((name) => name === "auth" || name.startsWith("auth-"))) { const databaseName = await resolveAuthDatabaseName(options); transforms.push((manifest) => withAuthDatabaseName(manifest, databaseName)); } const transformManifest = transforms.length > 0 ? (manifest) => { let result2 = manifest; for (const transform of transforms) { result2 = transform(result2); } return result2; } : void 0; const result = await runAddCommand({ allowUnsafeSource: options.allowUnsafeSource, cwd, from: options.from, logger: options.logger, names: [...items], ref: options.ref, source: options.source, transformManifest, yes: true }); return { code: result.code, items }; }; const execute = defineHandler(async ({ argument, cwd, logger, options }) => { const formatError = validateOutputFormat("add", options.format); if (formatError !== void 0) { logger.error(formatError); return { code: 1 }; } const effectiveLogger = loggerForFormat(options.format, logger); const result = await runAddFeature({ allowUnsafeSource: options.allowUnsafeSource === true, bucket: options.bucket, cwd, db: options.db, feature: argument[0], from: options.from, logger: effectiveLogger, mailTo: options.mailTo, provider: options.provider, ref: options.ref, source: options.source, yes: options.yes === true }); if (isJsonFormat(options.format)) { printJson({ code: result.code, items: result.items }); } return { code: result.code }; }); export { execute, runAddFeature };