@lunora/cli 1.0.0-alpha.8 → 1.0.0-alpha.80

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.
Files changed (59) hide show
  1. package/LICENSE.md +6 -0
  2. package/__assets__/package-og.svg +1 -1
  3. package/dist/bin.mjs +1 -1
  4. package/dist/index.d.mts +290 -117
  5. package/dist/index.d.ts +290 -117
  6. package/dist/index.mjs +8 -8
  7. package/dist/packem_chunks/handler.mjs +87 -6
  8. package/dist/packem_chunks/handler10.mjs +8 -14
  9. package/dist/packem_chunks/handler11.mjs +19 -189
  10. package/dist/packem_chunks/handler12.mjs +176 -115
  11. package/dist/packem_chunks/handler13.mjs +118 -52
  12. package/dist/packem_chunks/handler14.mjs +50 -43
  13. package/dist/packem_chunks/handler15.mjs +48 -67
  14. package/dist/packem_chunks/handler16.mjs +85 -37
  15. package/dist/packem_chunks/handler17.mjs +39 -100
  16. package/dist/packem_chunks/handler18.mjs +87 -152
  17. package/dist/packem_chunks/handler19.mjs +148 -67
  18. package/dist/packem_chunks/handler2.mjs +6 -4
  19. package/dist/packem_chunks/handler20.mjs +77 -75
  20. package/dist/packem_chunks/handler21.mjs +71 -288
  21. package/dist/packem_chunks/handler3.mjs +6 -3
  22. package/dist/packem_chunks/handler4.mjs +2 -2
  23. package/dist/packem_chunks/handler5.mjs +7 -4
  24. package/dist/packem_chunks/handler6.mjs +10 -7
  25. package/dist/packem_chunks/handler7.mjs +2 -2
  26. package/dist/packem_chunks/handler8.mjs +1 -1
  27. package/dist/packem_chunks/handler9.mjs +315 -12
  28. package/dist/packem_chunks/planDevCommand.mjs +758 -81
  29. package/dist/packem_chunks/runCodegenCommand.mjs +5 -4
  30. package/dist/packem_chunks/runDeployCommand.mjs +126 -20
  31. package/dist/packem_chunks/runInitCommand.mjs +1661 -179
  32. package/dist/packem_chunks/runMigrateGenerateCommand.mjs +5 -4
  33. package/dist/packem_chunks/runResetCommand.mjs +2 -2
  34. package/dist/packem_chunks/runRpcCommand.mjs +3 -2
  35. package/dist/packem_shared/{COMMANDS-Bn8luojF.mjs → COMMANDS-DW8lQmuW.mjs} +85 -23
  36. package/dist/packem_shared/{DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs → DEFAULT_IMPORT_BATCH_SIZE-CRQmmBZM.mjs} +3 -2
  37. package/dist/packem_shared/{api-spec-CtA6ilu4.mjs → api-spec-Bx0iKbxA.mjs} +3 -1
  38. package/dist/packem_shared/{buildRegistryIndex-BcYe607_.mjs → buildRegistryIndex-BS5ig822.mjs} +1 -1
  39. package/dist/packem_shared/codegen-error-DJG-ghs_.mjs +31 -0
  40. package/dist/packem_shared/{command-BDXcJCCJ.mjs → command-lYnl4QyF.mjs} +6 -1
  41. package/dist/packem_shared/{commands-DqsEzojt.mjs → commands-ClEvcz3V.mjs} +224 -18
  42. package/dist/packem_shared/{createLogger-CHPNjFw2.mjs → createLogger-CIWSHrTL.mjs} +40 -8
  43. package/dist/packem_shared/{createRecordingSpawner-DxI3mebw.mjs → createRecordingSpawner-Cw5Iu73G.mjs} +12 -2
  44. package/dist/packem_shared/{detect-package-manager-DYp7n3mJ.mjs → detect-package-manager-DvEthdCw.mjs} +26 -30
  45. package/dist/packem_shared/{insertSchemaExtension-BuzF6-t2.mjs → insertSchemaExtension-DAqbfr9Z.mjs} +15 -10
  46. package/dist/packem_shared/{open-url-Dfq6fAyT.mjs → open-url-4PBLY9X0.mjs} +3 -2
  47. package/dist/packem_shared/{output-format-7gyGR3h8.mjs → output-format-B4642rjE.mjs} +1 -1
  48. package/dist/packem_shared/{parseManifest--vZf2FY1.mjs → parseManifest-Dbp-Q2q3.mjs} +36 -9
  49. package/dist/packem_shared/prompt-cancelled-APzX1Im-.mjs +9 -0
  50. package/dist/packem_shared/runAddCommand-DGjFXGqa.mjs +4 -0
  51. package/dist/packem_shared/storage-DEXpJkXh.mjs +84 -0
  52. package/dist/packem_shared/tui-prompts-BjEN8XgP.mjs +658 -0
  53. package/dist/packem_shared/wrangler-secrets-Dq_Fkbm-.mjs +49 -0
  54. package/package.json +16 -13
  55. package/skills/lunora-quickstart/SKILL.md +25 -5
  56. package/skills/lunora-setup-storage/SKILL.md +7 -3
  57. package/dist/packem_shared/features-ocSSpZtS.mjs +0 -24
  58. package/dist/packem_shared/runAddCommand-G544_v6e.mjs +0 -4
  59. package/dist/packem_shared/tui-prompts-XHFxlOg5.mjs +0 -269
@@ -1,10 +1,11 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { findWranglerFile } from '@lunora/config';
3
- import { join } from '@visulima/path';
4
- import { d as defineHandler } from '../packem_shared/command-BDXcJCCJ.mjs';
5
- import { t as tuiSelect } from '../packem_shared/tui-prompts-XHFxlOg5.mjs';
6
- import { n as normalizeFeature, E as EMAIL_ITEM, D as DEFAULT_AUTH_ITEM, p as promptAuthProvider, A as AUTH_PROVIDER_OPTIONS } from '../packem_shared/features-ocSSpZtS.mjs';
7
- import { r as runAddCommand } from '../packem_shared/commands-DqsEzojt.mjs';
3
+ import { join, basename } from '@visulima/path';
4
+ import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
5
+ import { v as validateOutputFormat, i as isJsonFormat, p as printJson, l as loggerForFormat } from '../packem_shared/output-format-B4642rjE.mjs';
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';
8
9
 
9
10
  const providerToItem = (provider) => {
10
11
  const value = provider.trim().toLowerCase();
@@ -28,6 +29,51 @@ const resolveAuthItem = async (options) => {
28
29
  const select = options.promptSelect ?? ((message, choices, settings) => tuiSelect(message, choices, settings));
29
30
  return promptAuthProvider(select);
30
31
  };
32
+ const textPrompt = (options) => options.promptText ?? ((message, settings) => tuiText(message, settings));
33
+ const resolveStorageBucketName = async (options) => {
34
+ const projectName = basename(options.cwd ?? process.cwd());
35
+ if (options.bucket !== void 0 && options.bucket !== "") {
36
+ const sanitized = sanitizeBucketName(options.bucket);
37
+ if (sanitized !== void 0) {
38
+ return sanitized;
39
+ }
40
+ const fallback = deriveBucketName(projectName);
41
+ options.logger.warn(`add: "${options.bucket}" isn't a valid R2 bucket name (lowercase alphanumeric + hyphens, 3–63 chars) — using "${fallback}".`);
42
+ return fallback;
43
+ }
44
+ if (options.yes === true) {
45
+ return deriveBucketName(projectName);
46
+ }
47
+ return promptBucketName(textPrompt(options), projectName);
48
+ };
49
+ const resolveMailDestination = async (options) => {
50
+ const warn = (message) => {
51
+ options.logger.warn(`add: ${message}`);
52
+ };
53
+ if (options.mailTo !== void 0 && options.mailTo !== "") {
54
+ return resolveTypedDestination(options.mailTo, warn);
55
+ }
56
+ if (options.yes === true) {
57
+ return void 0;
58
+ }
59
+ return resolveTypedDestination(await textPrompt(options)(MAIL_DESTINATION_PROMPT, { placeholder: "you@yourdomain.com" }), warn);
60
+ };
61
+ const resolveAuthDatabaseName = async (options) => {
62
+ const projectName = basename(options.cwd ?? process.cwd());
63
+ if (options.db !== void 0 && options.db !== "") {
64
+ const sanitized = sanitizeDatabaseName(options.db);
65
+ if (sanitized !== void 0) {
66
+ return sanitized;
67
+ }
68
+ const fallback = deriveDatabaseName(projectName);
69
+ options.logger.warn(`add: "${options.db}" isn't a usable D1 database name — using "${fallback}".`);
70
+ return fallback;
71
+ }
72
+ if (options.yes === true) {
73
+ return deriveDatabaseName(projectName);
74
+ }
75
+ return promptDatabaseName(textPrompt(options), projectName);
76
+ };
31
77
  const resolveFeatureItems = async (feature, options) => {
32
78
  if (feature.kind === "auth") {
33
79
  return [await resolveAuthItem(options)];
@@ -49,6 +95,28 @@ const runAddFeature = async (options) => {
49
95
  return { code: 1, items: [] };
50
96
  }
51
97
  const items = await resolveFeatureItems(feature, options);
98
+ const transforms = [];
99
+ if (items.includes("storage")) {
100
+ const bucketName = await resolveStorageBucketName(options);
101
+ transforms.push((manifest) => withStorageBucketName(manifest, bucketName));
102
+ }
103
+ if (items.includes("mail")) {
104
+ const destination = await resolveMailDestination(options);
105
+ if (destination !== void 0) {
106
+ transforms.push((manifest) => withMailDestination(manifest, destination));
107
+ }
108
+ }
109
+ if (items.some((name) => name === "auth" || name.startsWith("auth-"))) {
110
+ const databaseName = await resolveAuthDatabaseName(options);
111
+ transforms.push((manifest) => withAuthDatabaseName(manifest, databaseName));
112
+ }
113
+ const transformManifest = transforms.length > 0 ? (manifest) => {
114
+ let result2 = manifest;
115
+ for (const transform of transforms) {
116
+ result2 = transform(result2);
117
+ }
118
+ return result2;
119
+ } : void 0;
52
120
  const result = await runAddCommand({
53
121
  allowUnsafeSource: options.allowUnsafeSource,
54
122
  cwd,
@@ -57,22 +125,35 @@ const runAddFeature = async (options) => {
57
125
  names: [...items],
58
126
  ref: options.ref,
59
127
  source: options.source,
128
+ transformManifest,
60
129
  yes: true
61
130
  });
62
131
  return { code: result.code, items };
63
132
  };
64
133
  const execute = defineHandler(async ({ argument, cwd, logger, options }) => {
134
+ const formatError = validateOutputFormat("add", options.format);
135
+ if (formatError !== void 0) {
136
+ logger.error(formatError);
137
+ return { code: 1 };
138
+ }
139
+ const effectiveLogger = loggerForFormat(options.format, logger);
65
140
  const result = await runAddFeature({
66
141
  allowUnsafeSource: options.allowUnsafeSource === true,
142
+ bucket: options.bucket,
67
143
  cwd,
144
+ db: options.db,
68
145
  feature: argument[0],
69
146
  from: options.from,
70
- logger,
147
+ logger: effectiveLogger,
148
+ mailTo: options.mailTo,
71
149
  provider: options.provider,
72
150
  ref: options.ref,
73
151
  source: options.source,
74
152
  yes: options.yes === true
75
153
  });
154
+ if (isJsonFormat(options.format)) {
155
+ printJson({ code: result.code, items: result.items });
156
+ }
76
157
  return { code: result.code };
77
158
  });
78
159
 
@@ -1,22 +1,16 @@
1
- import { d as defineHandler } from '../packem_shared/command-BDXcJCCJ.mjs';
1
+ import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
2
2
  import { a as resolveProductionWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
3
- import { runImportCommand } from '../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs';
3
+ import { runExportCommand } from '../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-CRQmmBZM.mjs';
4
4
 
5
- const execute = defineHandler(({ argument, cwd, logger, options }) => {
6
- const file = argument[0];
7
- if (!file) {
8
- logger.error("import requires a file. Usage: lunora import <path> [--table <name>]");
9
- return { code: 1 };
10
- }
11
- return runImportCommand({
12
- batchSize: options.batchSize,
13
- file,
5
+ const execute = defineHandler(
6
+ ({ argument, cwd, logger, options }) => runExportCommand({
14
7
  logger,
8
+ out: argument[0] ?? options.out,
15
9
  prod: options.prod === true,
16
- table: options.table,
10
+ tables: options.tables,
17
11
  token: options.token,
18
12
  url: resolveProductionWorkerUrl({ cwd, prod: options.prod === true, url: options.url })
19
- });
20
- });
13
+ })
14
+ );
21
15
 
22
16
  export { execute };
@@ -1,192 +1,22 @@
1
- import { readFileSync, existsSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { discoverSchema } from '@lunora/codegen';
4
- import { readLinkedProject } from '@lunora/config';
5
- import { parse } from 'jsonc-parser';
6
- import { Project } from 'ts-morph';
7
- import { d as defineHandler } from '../packem_shared/command-BDXcJCCJ.mjs';
1
+ import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
2
+ import { a as resolveProductionWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
3
+ import { runImportCommand } from '../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-CRQmmBZM.mjs';
8
4
 
9
- const findWranglerFile = (projectRoot) => {
10
- for (const candidate of ["wrangler.jsonc", "wrangler.json"]) {
11
- const fullPath = join(projectRoot, candidate);
12
- if (existsSync(fullPath)) {
13
- return fullPath;
14
- }
15
- }
16
- return void 0;
17
- };
18
- const stringField = (record, key) => {
19
- if (record === null || typeof record !== "object") {
20
- return void 0;
21
- }
22
- const value = record[key];
23
- return typeof value === "string" && value.length > 0 ? value : void 0;
24
- };
25
- const arrayField = (record, key) => {
26
- if (record === null || typeof record !== "object") {
27
- return [];
28
- }
29
- const value = record[key];
30
- return Array.isArray(value) ? value : [];
31
- };
32
- const summariseWrangler = (raw) => {
33
- const durableObjectBindings = arrayField(raw.durable_objects ?? {}, "bindings");
34
- const d1 = arrayField(raw, "d1_databases");
35
- const vectorize = arrayField(raw, "vectorize");
36
- return {
37
- bindings: {
38
- d1: d1.map((entry) => stringField(entry, "binding") ?? "<unnamed>"),
39
- durableObjects: durableObjectBindings.map((entry) => stringField(entry, "name") ?? "<unnamed>"),
40
- vectorize: vectorize.map((entry) => stringField(entry, "binding") ?? "<unnamed>")
41
- },
42
- compatibilityDate: stringField(raw, "compatibility_date"),
43
- compatibilityFlags: arrayField(raw, "compatibility_flags").filter((entry) => typeof entry === "string"),
44
- main: stringField(raw, "main"),
45
- name: stringField(raw, "name")
46
- };
47
- };
48
- const summariseSchema = (schema) => {
49
- return {
50
- tables: schema.tables.map((table) => {
51
- let shard = "root";
52
- if (table.shardMode === "global") {
53
- shard = "global";
54
- } else if (typeof table.shardMode === "object") {
55
- shard = `shardBy(${table.shardMode.field})`;
56
- }
57
- return {
58
- indexes: table.indexes.length,
59
- name: table.name,
60
- shard
61
- };
62
- }),
63
- vectorIndexes: schema.vectorIndexes.length
64
- };
65
- };
66
- const collectLunoraPackages = (projectRoot) => {
67
- const pkgPath = join(projectRoot, "package.json");
68
- if (!existsSync(pkgPath)) {
69
- return [];
70
- }
71
- let pkg;
72
- try {
73
- pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
74
- } catch {
75
- return [];
76
- }
77
- if (pkg === null || typeof pkg !== "object") {
78
- return [];
79
- }
80
- const sections = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
81
- const seen = /* @__PURE__ */ new Map();
82
- for (const section of sections) {
83
- const block = pkg[section];
84
- if (block === null || typeof block !== "object") {
85
- continue;
86
- }
87
- for (const [name, version] of Object.entries(block)) {
88
- if (!name.startsWith("@lunora/")) {
89
- continue;
90
- }
91
- if (typeof version === "string" && !seen.has(name)) {
92
- seen.set(name, version);
93
- }
94
- }
95
- }
96
- return [...seen.entries()].toSorted(([a], [b]) => a.localeCompare(b)).map(([name, version]) => {
97
- return { name, version };
5
+ const execute = defineHandler(({ argument, cwd, logger, options }) => {
6
+ const file = argument[0];
7
+ if (!file) {
8
+ logger.error("import requires a file. Usage: lunora import <path> [--table <name>]");
9
+ return { code: 1 };
10
+ }
11
+ return runImportCommand({
12
+ batchSize: options.batchSize,
13
+ file,
14
+ logger,
15
+ prod: options.prod === true,
16
+ table: options.table,
17
+ token: options.token,
18
+ url: resolveProductionWorkerUrl({ cwd, prod: options.prod === true, url: options.url })
98
19
  });
99
- };
100
- const collectInfo = (projectRoot) => {
101
- const lunoraPackages = collectLunoraPackages(projectRoot);
102
- const wranglerPath = findWranglerFile(projectRoot);
103
- let wrangler;
104
- if (wranglerPath) {
105
- try {
106
- wrangler = summariseWrangler(parse(readFileSync(wranglerPath, "utf8")));
107
- } catch {
108
- wrangler = void 0;
109
- }
110
- }
111
- const schemaPath = join(projectRoot, "lunora", "schema.ts");
112
- let schema;
113
- let schemaError;
114
- if (existsSync(schemaPath)) {
115
- try {
116
- const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
117
- schema = summariseSchema(discoverSchema(project, schemaPath));
118
- } catch (error) {
119
- schemaError = error instanceof Error ? error.message : String(error);
120
- }
121
- }
122
- return {
123
- link: readLinkedProject(projectRoot),
124
- lunoraPackages,
125
- projectRoot,
126
- schema,
127
- schemaError,
128
- wrangler,
129
- wranglerPath
130
- };
131
- };
132
- const renderText = (snapshot, logger) => {
133
- logger.info(`project: ${snapshot.projectRoot}`);
134
- logger.info("");
135
- logger.info("@lunora/* packages:");
136
- if (snapshot.lunoraPackages.length === 0) {
137
- logger.info(" (none found in package.json)");
138
- } else {
139
- for (const pkg of snapshot.lunoraPackages) {
140
- logger.info(` ${pkg.name}@${pkg.version}`);
141
- }
142
- }
143
- logger.info("");
144
- if (snapshot.wrangler) {
145
- logger.info(`wrangler: ${snapshot.wranglerPath ?? ""}`);
146
- logger.info(` name: ${snapshot.wrangler.name ?? "<unset>"}`);
147
- logger.info(` main: ${snapshot.wrangler.main ?? "<unset>"}`);
148
- logger.info(` compatibility_date: ${snapshot.wrangler.compatibilityDate ?? "<unset>"}`);
149
- logger.info(` compatibility_flags: ${snapshot.wrangler.compatibilityFlags.join(", ") || "<none>"}`);
150
- logger.info(` durable objects: ${snapshot.wrangler.bindings.durableObjects.join(", ") || "<none>"}`);
151
- logger.info(` d1 databases: ${snapshot.wrangler.bindings.d1.join(", ") || "<none>"}`);
152
- logger.info(` vectorize indexes: ${snapshot.wrangler.bindings.vectorize.join(", ") || "<none>"}`);
153
- } else {
154
- logger.info("wrangler: (not found)");
155
- }
156
- logger.info("");
157
- if (snapshot.link) {
158
- logger.info(`link: ${snapshot.link.workerName ?? "(unnamed)"} -> ${snapshot.link.workerUrl ?? "<no url>"}`);
159
- if (snapshot.link.env !== void 0) {
160
- logger.info(` env: ${snapshot.link.env}`);
161
- }
162
- } else {
163
- logger.info("link: (not linked — run `lunora link --url <https://your-worker>`)");
164
- }
165
- logger.info("");
166
- if (snapshot.schemaError !== void 0) {
167
- logger.warn(`schema: parse error — ${snapshot.schemaError}`);
168
- } else if (snapshot.schema) {
169
- logger.info(`schema: ${String(snapshot.schema.tables.length)} table(s), ${String(snapshot.schema.vectorIndexes)} vector index(es)`);
170
- for (const table of snapshot.schema.tables) {
171
- logger.info(` ${table.name} [${table.shard}, ${String(table.indexes)} index(es)]`);
172
- }
173
- } else {
174
- logger.info("schema: (no lunora/schema.ts)");
175
- }
176
- };
177
- const runInfoCommand = (options) => {
178
- const cwd = options.cwd ?? process.cwd();
179
- const snapshot = collectInfo(cwd);
180
- if (options.json) {
181
- process.stdout.write(`${JSON.stringify(snapshot, void 0, 2)}
182
- `);
183
- } else {
184
- renderText(snapshot, options.logger);
185
- }
186
- return { code: 0, snapshot };
187
- };
188
- const execute = defineHandler(
189
- ({ cwd, logger, options }) => runInfoCommand({ cwd, json: options.json === true, logger })
190
- );
20
+ });
191
21
 
192
- export { collectInfo, execute, runInfoCommand };
22
+ export { execute };