@lunora/cli 1.0.0-alpha.86 → 1.0.0-alpha.88

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/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { runCli } from './packem_shared/COMMANDS-D0tmnAwr.mjs';
2
+ import { runCli } from './packem_shared/COMMANDS-DZ0NnuqI.mjs';
3
3
 
4
4
  try {
5
5
  const code = await runCli();
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { COMMANDS, VERSION, runCli } from './packem_shared/COMMANDS-D0tmnAwr.mjs';
1
+ export { COMMANDS, VERSION, runCli } from './packem_shared/COMMANDS-DZ0NnuqI.mjs';
2
2
  export { runCodegenCommand } from './packem_chunks/runCodegenCommand.mjs';
3
3
  export { DEFAULT_IMPORT_BATCH_SIZE, runExportCommand, runImportCommand } from './packem_shared/DEFAULT_IMPORT_BATCH_SIZE-D0VOTerB.mjs';
4
4
  export { runDeployCommand } from './packem_chunks/runDeployCommand.mjs';
@@ -15,4 +15,4 @@ export { createRecordingSpawner, defaultSpawner } from './packem_shared/createRe
15
15
  export { default as parseManifest } from './packem_shared/parseManifest-Dbp-Q2q3.mjs';
16
16
  export { REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, validateWranglerProject as validateWrangler, validateWranglerConfig } from '@lunora/config';
17
17
  export { buildRegistryIndex } from './packem_shared/buildRegistryIndex-BS5ig822.mjs';
18
- export { r as runAddCommand, a as runBuildIndexCommand, b as runRegistryViewCommand } from './packem_shared/commands-ClEvcz3V.mjs';
18
+ export { r as runAddCommand, a as runBuildIndexCommand, b as runRegistryViewCommand } from './packem_shared/commands-CKg6zztp.mjs';
@@ -4,8 +4,8 @@ import { join, basename } from '@visulima/path';
4
4
  import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
5
5
  import { v as validateOutputFormat, i as isJsonFormat, p as printJson, l as loggerForFormat } from '../packem_shared/output-format-B4642rjE.mjs';
6
6
  import { t as tuiText, a as tuiSelect } from '../packem_shared/tui-prompts-BjEN8XgP.mjs';
7
- 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-DEXpJkXh.mjs';
8
- import { r as runAddCommand } from '../packem_shared/commands-ClEvcz3V.mjs';
7
+ 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-BDaKEAHr.mjs';
8
+ import { r as runAddCommand } from '../packem_shared/commands-CKg6zztp.mjs';
9
9
 
10
10
  const providerToItem = (provider) => {
11
11
  const value = provider.trim().toLowerCase();
@@ -1,5 +1,5 @@
1
1
  import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
2
- import { r as runAddCommand, b as runRegistryViewCommand, a as runBuildIndexCommand } from '../packem_shared/commands-ClEvcz3V.mjs';
2
+ import { r as runAddCommand, b as runRegistryViewCommand, a as runBuildIndexCommand } from '../packem_shared/commands-CKg6zztp.mjs';
3
3
 
4
4
  const execute = defineHandler(({ argument, cwd, logger, options }) => {
5
5
  const subcommand = argument[0];
@@ -11,11 +11,11 @@ import { d as detectPackageManager, a as detectInstalledManagers, i as installAr
11
11
  import MagicString from 'magic-string';
12
12
  import { Project, SyntaxKind } from 'ts-morph';
13
13
  import { P as PromptCancelledError } from '../packem_shared/prompt-cancelled-APzX1Im-.mjs';
14
- import { c as resolveTagVersions, d as resolveSourceRef, e as resolvePinnedSourceRef, f as resolveDistTag, r as runAddCommand } from '../packem_shared/commands-ClEvcz3V.mjs';
14
+ import { c as resolveTagVersions, d as resolveSourceRef, e as resolvePinnedSourceRef, f as resolveDistTag, r as runAddCommand } from '../packem_shared/commands-CKg6zztp.mjs';
15
15
  import { defaultSpawner } from '../packem_shared/createRecordingSpawner-WuSn20kb.mjs';
16
16
  import { d as tuiMascot, e as tuiStep, f as tuiMoonrise, t as tuiText, g as tuiHeadline, h as tuiInfo, a as tuiSelect, b as tuiConfirm, w as withTuiSpinner, i as tuiNextSteps, j as tuiTasks, k as tuiMultiSelect, l as withTuiBadgeProgress } from '../packem_shared/tui-prompts-BjEN8XgP.mjs';
17
17
  import { logStep } from '../packem_shared/createLogger-CIWSHrTL.mjs';
18
- import { E as EMAIL_ITEM, p as promptBucketName, w as withStorageBucketName, M as MAIL_DESTINATION_PROMPT, r as resolveTypedDestination, f as withMailDestination, e as promptAuthProvider, c as promptDatabaseName, g as withAuthDatabaseName } from '../packem_shared/storage-DEXpJkXh.mjs';
18
+ import { E as EMAIL_ITEM, p as promptBucketName, w as withStorageBucketName, M as MAIL_DESTINATION_PROMPT, r as resolveTypedDestination, f as withMailDestination, e as promptAuthProvider, c as promptDatabaseName, g as withAuthDatabaseName } from '../packem_shared/storage-BDaKEAHr.mjs';
19
19
  import dns from 'node:dns/promises';
20
20
 
21
21
  const GITHUB_CONTENT = `name: Deploy
@@ -2386,6 +2386,7 @@ const FRAMEWORK_CHOICES = [
2386
2386
  { description: "Vue SPA — create-vite base + Lunora", label: "Vue", value: "vue" },
2387
2387
  { description: "Solid SPA — create-vite base + Lunora", label: "Solid", value: "solid" },
2388
2388
  { description: "Svelte SPA — create-vite base + Lunora", label: "Svelte", value: "svelte" },
2389
+ { description: "Next.js (App Router) — OpenNext on Cloudflare + a standalone Lunora worker", label: "Next.js", value: "next" },
2389
2390
  { description: "TanStack Start (React) — SSR with live-loader routes", label: "TanStack Start · React", value: "tanstack-start-react" },
2390
2391
  { description: "TanStack Start (Solid)", label: "TanStack Start · Solid", value: "tanstack-start-solid" },
2391
2392
  { description: "React Router (v7, framework mode) — SSR composed into the Lunora worker", label: "React Router", value: "react-router" },
@@ -2439,10 +2440,6 @@ const scaffoldOverlayPath = async (options, framework, name, target) => {
2439
2440
  return scaffoldViteOverlay({ framework, logger: options.logger, name, overlayBaseFrom: options.overlayBaseFrom, target });
2440
2441
  };
2441
2442
  const scaffoldTemplatePath = async (options, templateType, name, target) => {
2442
- if (templateType === "next") {
2443
- options.logger.warn('template "next" is not yet available — re-run with `--vite react` or `-t standalone`.');
2444
- return { code: 1, files: [], target };
2445
- }
2446
2443
  if (options.from !== void 0) {
2447
2444
  return await scaffoldFromLocal(options.from, templateType, target, name, options.logger);
2448
2445
  }
@@ -1,6 +1,7 @@
1
1
  import { existsSync, mkdirSync, writeFileSync, mkdtempSync, rmSync, readFileSync } from 'node:fs';
2
2
  import { tmpdir } from 'node:os';
3
3
  import { discoverSchema, discoverMigrations } from '@lunora/codegen';
4
+ import { isInteractive, promptSelect, promptText } from '@lunora/config';
4
5
  import { LunoraError } from '@lunora/errors';
5
6
  import { join } from '@visulima/path';
6
7
  import { Project } from 'ts-morph';
@@ -152,7 +153,47 @@ const camelCase = (slug) => slug.split("-").filter((part) => part.length > 0).ma
152
153
  }
153
154
  return part.charAt(0).toUpperCase() + part.slice(1);
154
155
  }).join("");
155
- const runMigrateCreateCommand = (options) => {
156
+ const discoverKnownTables = (cwd) => {
157
+ const schemaPath = join(cwd, "lunora", "schema.ts");
158
+ if (!existsSync(schemaPath)) {
159
+ return [];
160
+ }
161
+ try {
162
+ const project = new Project({ skipAddingFilesFromTsConfig: true });
163
+ return discoverSchema(project, schemaPath).tables.map((table) => table.name);
164
+ } catch {
165
+ return [];
166
+ }
167
+ };
168
+ const promptForTable = async (tables) => {
169
+ if (tables.length > 0) {
170
+ return promptSelect(
171
+ "Which table does this migration iterate?",
172
+ tables.map((name) => {
173
+ return { label: name, value: name };
174
+ })
175
+ );
176
+ }
177
+ return promptText("Target table for the migration: ");
178
+ };
179
+ const resolveCreateTable = async (cwd, options) => {
180
+ if (options.table !== void 0) {
181
+ return options.table;
182
+ }
183
+ const prompt = options.promptTable ?? (isInteractive() ? promptForTable : void 0);
184
+ if (prompt === void 0) {
185
+ options.logger.error("migrate create requires a target table when not running interactively — re-run with --table <table>");
186
+ return void 0;
187
+ }
188
+ const answer = await prompt(discoverKnownTables(cwd));
189
+ const table = answer?.trim();
190
+ if (table === void 0 || table === "") {
191
+ options.logger.error("no table selected — re-run with --table <table>");
192
+ return void 0;
193
+ }
194
+ return table;
195
+ };
196
+ const runMigrateCreateCommand = async (options) => {
156
197
  const cwd = options.cwd ?? process.cwd();
157
198
  const slug = kebabCase(options.name);
158
199
  if (slug === "") {
@@ -166,9 +207,12 @@ const runMigrateCreateCommand = (options) => {
166
207
  );
167
208
  return { code: 1, file: "" };
168
209
  }
169
- const table = options.table ?? "TODO_table";
210
+ const table = await resolveCreateTable(cwd, options);
211
+ if (table === void 0) {
212
+ return { code: 1, file: "" };
213
+ }
170
214
  if (!IDENTIFIER_PATTERN.test(table)) {
171
- options.logger.error(`invalid --table: "${table}" — must be a valid identifier ([A-Za-z_][A-Za-z0-9_]*)`);
215
+ options.logger.error(`invalid table: "${table}" — must be a valid identifier ([A-Za-z_][A-Za-z0-9_]*)`);
172
216
  return { code: 1, file: "" };
173
217
  }
174
218
  const lunoraDirectory = join(cwd, "lunora");
@@ -196,9 +240,6 @@ ${content}`;
196
240
  ${block}
197
241
  `, "utf8");
198
242
  options.logger.success(`scaffolded migration "${slug}" in ${file}`);
199
- if (options.table === void 0) {
200
- options.logger.warn(`set the \`table\` field on "${slug}" — it defaults to "${table}"`);
201
- }
202
243
  return { code: 0, file };
203
244
  };
204
245
  const resolveMigrationTable = (cwd, id) => {
@@ -380,6 +380,7 @@ const initCommand = {
380
380
  description: "Scaffold a new Lunora project",
381
381
  examples: [
382
382
  ["lunora init my-app", "Scaffold with the default (vite) template"],
383
+ ["lunora init my-app -t next", "Scaffold a Next.js app"],
383
384
  ["lunora init my-app -t tanstack-start-react", "Scaffold a TanStack Start (React) app"],
384
385
  ["lunora init my-app -t tanstack-start-solid", "Scaffold a TanStack Start (Solid) app"],
385
386
  ["lunora init my-app --ref alpha", "Scaffold from the alpha branch's templates"],
@@ -399,7 +400,7 @@ const initCommand = {
399
400
  // picker (default React overlay) and a non-interactive run errors.
400
401
  // For React/Vue/Solid/Svelte SPAs use `--vite <framework>` (overlay);
401
402
  // `-t` selects a bespoke template.
402
- description: "Bespoke template (standalone | astro | nuxt | sveltekit | tanstack-start-react | tanstack-start-solid). For an SPA use --vite react|vue|solid|svelte.",
403
+ description: "Bespoke template (standalone | astro | next | nuxt | sveltekit | tanstack-start-react | tanstack-start-solid). For an SPA use --vite react|vue|solid|svelte.",
403
404
  name: "template",
404
405
  type: String
405
406
  },
@@ -544,7 +545,7 @@ const migrateCommand = {
544
545
  name: "migrate",
545
546
  options: [
546
547
  { description: "Migration name slug (e.g. add_users_email)", name: "name", type: String },
547
- { description: "Target table for `create`", name: "table", type: String },
548
+ { description: "Target table for `create` (prompted for interactively when omitted)", name: "table", type: String },
548
549
  { description: "Preview a data migration without rewriting rows", name: "dry-run", type: Boolean },
549
550
  { description: "Rows per batch for a data migration", name: "batch-size", type: Number },
550
551
  { description: "Cap batches processed this run (maps to the runner's maxBatches)", name: "steps", type: Number },
@@ -100,8 +100,8 @@ const resolvePinnedSourceRef = async (ref, logger) => {
100
100
  return sha;
101
101
  };
102
102
  const STABLE_DIST_TAG = "latest";
103
- const resolveDistTag = () => {
104
- const ref = resolveVersionRef(resolveCliVersion());
103
+ const resolveDistTag = (version = resolveCliVersion()) => {
104
+ const ref = resolveVersionRef(version);
105
105
  return ref === STABLE_BRANCH ? STABLE_DIST_TAG : ref;
106
106
  };
107
107
  const DEFAULT_REGISTRY = "https://registry.npmjs.org";
@@ -112,7 +112,7 @@ const registryBase = () => {
112
112
  };
113
113
  const resolveTagVersion = async (packageName, tag) => {
114
114
  try {
115
- const response = await fetch(`${registryBase()}/${packageName.replace("/", "%2F")}`, {
115
+ const response = await fetch(`${registryBase()}/${packageName.replaceAll("/", "%2F")}`, {
116
116
  headers: { accept: "application/vnd.npm.install-v1+json" },
117
117
  signal: AbortSignal.timeout(1e4)
118
118
  });
@@ -1,4 +1,4 @@
1
1
  import 'node:fs';
2
2
  import '@visulima/path';
3
- export { r as runAddCommand, a as runBuildIndexCommand, g as runListCommand, b as runRegistryViewCommand } from './commands-ClEvcz3V.mjs';
3
+ export { r as runAddCommand, a as runBuildIndexCommand, g as runListCommand, b as runRegistryViewCommand } from './commands-CKg6zztp.mjs';
4
4
  import './buildRegistryIndex-BS5ig822.mjs';
@@ -1,4 +1,4 @@
1
- import { s as setBindingField } from './commands-ClEvcz3V.mjs';
1
+ import { s as setBindingField } from './commands-CKg6zztp.mjs';
2
2
 
3
3
  const INVALID_SLUG_CHARS = /[^a-z0-9]+/u;
4
4
  const toKebabSlug = (input, min, max) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/cli",
3
- "version": "1.0.0-alpha.86",
3
+ "version": "1.0.0-alpha.88",
4
4
  "description": "The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands",
5
5
  "keywords": [
6
6
  "agent-skills",
@@ -52,12 +52,12 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@bomb.sh/tab": "0.0.18",
55
- "@lunora/codegen": "1.0.0-alpha.43",
56
- "@lunora/config": "1.0.0-alpha.67",
57
- "@lunora/container": "1.0.0-alpha.11",
58
- "@lunora/d1": "1.0.0-alpha.29",
59
- "@lunora/errors": "1.0.0-alpha.4",
60
- "@lunora/seed": "1.0.0-alpha.23",
55
+ "@lunora/codegen": "1.0.0-alpha.45",
56
+ "@lunora/config": "1.0.0-alpha.69",
57
+ "@lunora/container": "1.0.0-alpha.12",
58
+ "@lunora/d1": "1.0.0-alpha.31",
59
+ "@lunora/errors": "1.0.0-alpha.5",
60
+ "@lunora/seed": "1.0.0-alpha.25",
61
61
  "@visulima/cerebro": "3.0.0",
62
62
  "@visulima/error": "6.0.0",
63
63
  "@visulima/fs": "5.0.0",
@@ -57,6 +57,7 @@ pnpm install
57
57
  | `vite` | React + Vite (the simplest full-stack starter) |
58
58
  | `standalone` | Worker-only Lunora backend, no frontend |
59
59
  | `astro` | Astro integration |
60
+ | `next` | Next.js (App Router, OpenNext on Cloudflare) |
60
61
  | `nuxt` | Nuxt (Vue) |
61
62
  | `sveltekit` | SvelteKit |
62
63
  | `tanstack-start-react` | TanStack Start (React) |