@lunora/cli
Version:
The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands
161 lines (158 loc) • 6.71 kB
JavaScript
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 };