@lunora/cli 1.0.0-alpha.49 → 1.0.0-alpha.490

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 (147) hide show
  1. package/LICENSE.md +234 -104
  2. package/README.md +6 -4
  3. package/dist/bin.mjs +3 -10
  4. package/dist/cli.d.mts +31 -0
  5. package/dist/cli.d.ts +31 -0
  6. package/dist/cli.mjs +1 -0
  7. package/dist/index.d.mts +1181 -427
  8. package/dist/index.d.ts +1181 -427
  9. package/dist/index.mjs +1 -19
  10. package/dist/packem_chunks/cli.mjs +2 -0
  11. package/dist/packem_chunks/dispatch.mjs +1 -0
  12. package/dist/packem_chunks/handler.mjs +61 -157
  13. package/dist/packem_chunks/handler10.mjs +1 -16
  14. package/dist/packem_chunks/handler11.mjs +1 -22
  15. package/dist/packem_chunks/handler12.mjs +1 -192
  16. package/dist/packem_chunks/handler13.mjs +3 -131
  17. package/dist/packem_chunks/handler14.mjs +1 -65
  18. package/dist/packem_chunks/handler15.mjs +1 -58
  19. package/dist/packem_chunks/handler16.mjs +1 -80
  20. package/dist/packem_chunks/handler17.mjs +1 -43
  21. package/dist/packem_chunks/handler18.mjs +1 -105
  22. package/dist/packem_chunks/handler19.mjs +1 -170
  23. package/dist/packem_chunks/handler2.mjs +1 -114
  24. package/dist/packem_chunks/handler20.mjs +1 -94
  25. package/dist/packem_chunks/handler21.mjs +7 -94
  26. package/dist/packem_chunks/handler22.mjs +1 -0
  27. package/dist/packem_chunks/handler23.mjs +3 -0
  28. package/dist/packem_chunks/handler24.mjs +3 -0
  29. package/dist/packem_chunks/handler25.mjs +2 -0
  30. package/dist/packem_chunks/handler26.mjs +1 -0
  31. package/dist/packem_chunks/handler27.mjs +2 -0
  32. package/dist/packem_chunks/handler28.mjs +99 -0
  33. package/dist/packem_chunks/handler29.mjs +3 -0
  34. package/dist/packem_chunks/handler3.mjs +1 -204
  35. package/dist/packem_chunks/handler30.mjs +15 -0
  36. package/dist/packem_chunks/handler31.mjs +1 -0
  37. package/dist/packem_chunks/handler32.mjs +1 -0
  38. package/dist/packem_chunks/handler4.mjs +1 -33
  39. package/dist/packem_chunks/handler5.mjs +3 -49
  40. package/dist/packem_chunks/handler6.mjs +1 -91
  41. package/dist/packem_chunks/handler7.mjs +1 -42
  42. package/dist/packem_chunks/handler8.mjs +1 -174
  43. package/dist/packem_chunks/handler9.mjs +2 -315
  44. package/dist/packem_chunks/runCodegenCommand.mjs +4 -52
  45. package/dist/packem_chunks/runDevCommand.mjs +8 -0
  46. package/dist/packem_chunks/runInitCommand.mjs +423 -1452
  47. package/dist/packem_chunks/runResetCommand.mjs +1 -41
  48. package/dist/packem_chunks/runRpcCommand.mjs +1 -68
  49. package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck9tABfr.mjs +1 -0
  50. package/dist/packem_shared/EXIT_CODE-DQVhSE-1.mjs +1 -0
  51. package/dist/packem_shared/admin-token-VdUnvnKW.mjs +1 -0
  52. package/dist/packem_shared/admin-url-DJB8P6Jh.mjs +1 -0
  53. package/dist/packem_shared/api-spec-lYyq4vL6.mjs +1 -0
  54. package/dist/packem_shared/binding-manifest-file-BZyQFSTF.mjs +2 -0
  55. package/dist/packem_shared/buildRegistryIndex-Dc8D8AR6.mjs +1 -0
  56. package/dist/packem_shared/cap-error-body-YBKO32BF.mjs +1 -0
  57. package/dist/packem_shared/catalog-CahzmDLV.mjs +1 -0
  58. package/dist/packem_shared/cli-manifest-DoQ_3bzs.mjs +1 -0
  59. package/dist/packem_shared/cloudflare-credentials-BVmZnDZk.mjs +1 -0
  60. package/dist/packem_shared/codegen-error-AmH54ofi.mjs +3 -0
  61. package/dist/packem_shared/command-BpMv2n0o.mjs +1 -0
  62. package/dist/packem_shared/commands-CkuCMUP_.mjs +13 -0
  63. package/dist/packem_shared/createLogger-4TujevyB.mjs +2 -0
  64. package/dist/packem_shared/createRecordingSpawner-DchLi0gR.mjs +1 -0
  65. package/dist/packem_shared/deploy-target-resolve-BTCW1Iv4.mjs +1 -0
  66. package/dist/packem_shared/diffSnapshots-DcE-jQUz.mjs +9 -0
  67. package/dist/packem_shared/docker-DpVxvYpL.mjs +1 -0
  68. package/dist/packem_shared/export-rows-EzdNDYpa.mjs +3 -0
  69. package/dist/packem_shared/free-port-DjbFhaaT.mjs +1 -0
  70. package/dist/packem_shared/health-probe-By9T5x2y.mjs +13 -0
  71. package/dist/packem_shared/import-3Y59Ry9F.mjs +13 -0
  72. package/dist/packem_shared/index-oHZBGBwB.mjs +1 -0
  73. package/dist/packem_shared/insertSchemaExtension-CbTH3lCQ.mjs +10 -0
  74. package/dist/packem_shared/js-literal-FWLi94Lh.mjs +1 -0
  75. package/dist/packem_shared/lint-ignore-report-DKZagpqk.mjs +2 -0
  76. package/dist/packem_shared/mcp-config-file-GR1Y_CVw.mjs +2 -0
  77. package/dist/packem_shared/open-url-EnKy--w-.mjs +1 -0
  78. package/dist/packem_shared/output-format-DWe_tkTR.mjs +2 -0
  79. package/dist/packem_shared/parseManifest-CwPTKdtS.mjs +1 -0
  80. package/dist/packem_shared/path-containment-CgxYZggb.mjs +1 -0
  81. package/dist/packem_shared/plan-BF2E-dq4.mjs +5 -0
  82. package/dist/packem_shared/planDevCommand-C8QHZzEJ.mjs +1 -0
  83. package/dist/packem_shared/platform-diagnostics-Cn2g6Jh-.mjs +4 -0
  84. package/dist/packem_shared/prompt-cancelled-BvsNxg_Q.mjs +1 -0
  85. package/dist/packem_shared/render-lunora-error-JsLelWwR.mjs +2 -0
  86. package/dist/packem_shared/resolve-Bdc9KEUv.mjs +5 -0
  87. package/dist/packem_shared/resolve-target-C_ZloTvd.mjs +1 -0
  88. package/dist/packem_shared/runAddCommand-gThKW-ZB.mjs +1 -0
  89. package/dist/packem_shared/runDeployCommand-DhgZz8Sj.mjs +1 -0
  90. package/dist/packem_shared/runExportCommand-_PtkJJDT.mjs +5 -0
  91. package/dist/packem_shared/runMigrateGenerateCommand-DHdSMKbu.mjs +11 -0
  92. package/dist/packem_shared/schemaIrToSnapshot-CbWOjany.mjs +1 -0
  93. package/dist/packem_shared/shared-CV7ESvuj.mjs +2 -0
  94. package/dist/packem_shared/sql-u1MSmopg.mjs +3 -0
  95. package/dist/packem_shared/storage-3GOIFVZm.mjs +1 -0
  96. package/dist/packem_shared/tui-prompts-B3YwUhGw.mjs +4 -0
  97. package/dist/packem_shared/variables-CPYyJtsL.mjs +1 -0
  98. package/dist/packem_shared/vectorize-metadata-DK61NmVx.mjs +2 -0
  99. package/dist/packem_shared/wrangler-name-Dsk5K1f-.mjs +1 -0
  100. package/dist/packem_shared/wrangler-secrets-C9siMBwN.mjs +1 -0
  101. package/package.json +46 -20
  102. package/skills/README.md +36 -17
  103. package/skills/lunora/SKILL.md +158 -65
  104. package/skills/lunora-cloudflare-audit/SKILL.md +164 -0
  105. package/skills/lunora-create-package/SKILL.md +98 -84
  106. package/skills/lunora-deploy/SKILL.md +212 -102
  107. package/skills/lunora-functions/SKILL.md +367 -60
  108. package/skills/lunora-migration-helper/SKILL.md +194 -149
  109. package/skills/lunora-performance-audit/SKILL.md +137 -95
  110. package/skills/lunora-quickstart/SKILL.md +136 -136
  111. package/skills/lunora-realtime/SKILL.md +219 -97
  112. package/skills/lunora-setup-auth/SKILL.md +203 -101
  113. package/skills/lunora-setup-hyperdrive/SKILL.md +153 -110
  114. package/skills/lunora-setup-hyperdrive-global/SKILL.md +152 -94
  115. package/skills/lunora-setup-mail/SKILL.md +97 -113
  116. package/skills/lunora-setup-scheduler/SKILL.md +133 -97
  117. package/skills/lunora-setup-storage/SKILL.md +189 -95
  118. package/dist/packem_chunks/planDevCommand.mjs +0 -541
  119. package/dist/packem_chunks/runDeployCommand.mjs +0 -594
  120. package/dist/packem_chunks/runMigrateGenerateCommand.mjs +0 -397
  121. package/dist/packem_shared/COMMANDS-B0ftFD_3.mjs +0 -948
  122. package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs +0 -244
  123. package/dist/packem_shared/admin-url-4UzT-CI4.mjs +0 -19
  124. package/dist/packem_shared/api-spec-CtA6ilu4.mjs +0 -13
  125. package/dist/packem_shared/buildRegistryIndex-BcYe607_.mjs +0 -38
  126. package/dist/packem_shared/codegen-error-DJG-ghs_.mjs +0 -31
  127. package/dist/packem_shared/command-D3lB_4Az.mjs +0 -19
  128. package/dist/packem_shared/commands-B-gR09Z_.mjs +0 -845
  129. package/dist/packem_shared/createLogger-B40gPzQo.mjs +0 -78
  130. package/dist/packem_shared/createRecordingSpawner-DxI3mebw.mjs +0 -43
  131. package/dist/packem_shared/detect-package-manager-DYp7n3mJ.mjs +0 -61
  132. package/dist/packem_shared/diffSnapshots-BeDvvNiF.mjs +0 -161
  133. package/dist/packem_shared/docker-hMQ97KSQ.mjs +0 -21
  134. package/dist/packem_shared/insertSchemaExtension-DAqbfr9Z.mjs +0 -64
  135. package/dist/packem_shared/open-url-Dfq6fAyT.mjs +0 -41
  136. package/dist/packem_shared/output-format-wUvAN6AL.mjs +0 -17
  137. package/dist/packem_shared/parseArgs-YXFuKdEk.mjs +0 -56
  138. package/dist/packem_shared/parseManifest--vZf2FY1.mjs +0 -94
  139. package/dist/packem_shared/prompt-cancelled-APzX1Im-.mjs +0 -9
  140. package/dist/packem_shared/resolve-target-qbsJ_5sF.mjs +0 -16
  141. package/dist/packem_shared/runAddCommand-bnY6-HKb.mjs +0 -4
  142. package/dist/packem_shared/schema-drift-gate-BtBt0as0.mjs +0 -79
  143. package/dist/packem_shared/schemaIrToSnapshot-DdsljJT-.mjs +0 -43
  144. package/dist/packem_shared/storage-BIsph-Vk.mjs +0 -84
  145. package/dist/packem_shared/tui-prompts-BjEN8XgP.mjs +0 -658
  146. package/dist/packem_shared/wrangler-name-cy4yhm9j.mjs +0 -12
  147. package/dist/packem_shared/wrangler-secrets-P2_ZUR-k.mjs +0 -47
@@ -1,397 +0,0 @@
1
- import { existsSync, mkdirSync, writeFileSync, mkdtempSync, rmSync, readFileSync } from 'node:fs';
2
- import { tmpdir } from 'node:os';
3
- import { discoverSchema, discoverMigrations } from '@lunora/codegen';
4
- import { join } from '@visulima/path';
5
- import { Project } from 'ts-morph';
6
- import { r as resolveAdminBaseUrl } from '../packem_shared/admin-url-4UzT-CI4.mjs';
7
- import { d as defineHandler } from '../packem_shared/command-D3lB_4Az.mjs';
8
- import { diffSnapshots, renderMigrationFile } from '../packem_shared/diffSnapshots-BeDvvNiF.mjs';
9
- import { a as resolveProductionWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
10
- import schemaIrToSnapshot from '../packem_shared/schemaIrToSnapshot-DdsljJT-.mjs';
11
- import { runExportCommand, runImportCommand } from '../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs';
12
-
13
- const SNAPSHOT_FILENAME = ".snapshot.json";
14
- const NON_ALPHANUMERIC = /[^\da-z]+/gu;
15
- const trimChar = (value, char) => {
16
- let start = 0;
17
- let end = value.length;
18
- while (start < end && value[start] === char) {
19
- start += 1;
20
- }
21
- while (end > start && value[end - 1] === char) {
22
- end -= 1;
23
- }
24
- return value.slice(start, end);
25
- };
26
- const slugify = (input) => {
27
- const slug = trimChar(input.toLowerCase().replaceAll(NON_ALPHANUMERIC, "_"), "_");
28
- return slug === "" ? "auto" : slug;
29
- };
30
- const formatTimestamp = (now) => {
31
- const pad = (n, w = 2) => n.toString().padStart(w, "0");
32
- return `${String(now.getUTCFullYear())}${pad(now.getUTCMonth() + 1)}${pad(now.getUTCDate())}${pad(now.getUTCHours())}${pad(
33
- now.getUTCMinutes()
34
- )}${pad(now.getUTCSeconds())}`;
35
- };
36
- const loadSnapshot = (path) => {
37
- if (!existsSync(path)) {
38
- return void 0;
39
- }
40
- try {
41
- const raw = readFileSync(path, "utf8");
42
- const parsed = JSON.parse(raw);
43
- if (parsed.version !== 1) {
44
- throw new Error(`unsupported snapshot version: ${parsed.version}`);
45
- }
46
- return parsed;
47
- } catch (error) {
48
- const message = error instanceof Error ? error.message : String(error);
49
- throw new Error(`failed to read ${path}: ${message}`, { cause: error });
50
- }
51
- };
52
- const runMigrateGenerateCommand = (options) => {
53
- const cwd = options.cwd ?? process.cwd();
54
- const schemaPath = join(cwd, "lunora", "schema.ts");
55
- if (!existsSync(schemaPath)) {
56
- options.logger.error(`schema not found: ${schemaPath} — run \`vis generate lunora-table --name=<name>\` to create one`);
57
- return { code: 1, empty: true, migrationFile: "" };
58
- }
59
- const project = new Project({ skipAddingFilesFromTsConfig: true });
60
- const schemaIr = discoverSchema(project, schemaPath);
61
- const nextSnapshot = schemaIrToSnapshot(schemaIr);
62
- const migrationsDirectory = join(cwd, "lunora", "migrations");
63
- const snapshotPath = join(migrationsDirectory, SNAPSHOT_FILENAME);
64
- let previousSnapshot;
65
- try {
66
- previousSnapshot = loadSnapshot(snapshotPath);
67
- } catch (error) {
68
- options.logger.error(error instanceof Error ? error.message : String(error));
69
- return { code: 1, empty: true, migrationFile: "" };
70
- }
71
- const diff = diffSnapshots(previousSnapshot, nextSnapshot);
72
- if (diff.empty) {
73
- options.logger.info("no schema changes detected — snapshot is already up to date");
74
- return { code: 0, empty: true, migrationFile: "" };
75
- }
76
- const nowFunction = options.now ?? (() => /* @__PURE__ */ new Date());
77
- const now = nowFunction();
78
- const slug = slugify(options.name ?? "auto");
79
- const timestamp = formatTimestamp(now);
80
- const filename = `${timestamp}_${slug}.sql`;
81
- const migrationFile = join(migrationsDirectory, filename);
82
- mkdirSync(migrationsDirectory, { recursive: true });
83
- const body = renderMigrationFile(slug, diff, now.toISOString());
84
- writeFileSync(migrationFile, body, "utf8");
85
- writeFileSync(snapshotPath, `${JSON.stringify(nextSnapshot, void 0, 4)}
86
- `, "utf8");
87
- options.logger.success(`wrote ${migrationFile}`);
88
- if (diff.unsupported.length > 0) {
89
- options.logger.warn(`${String(diff.unsupported.length)} unsupported diff(s) — see the comment block in ${filename} and write the SQL manually`);
90
- }
91
- return { code: 0, empty: false, migrationFile };
92
- };
93
- const DATA_MIGRATIONS_FILENAME = "migrations.ts";
94
- const IDENTIFIER_PATTERN = /^[A-Za-z_]\w*$/u;
95
- const RESERVED_WORDS = /* @__PURE__ */ new Set([
96
- "await",
97
- "break",
98
- "case",
99
- "catch",
100
- "class",
101
- "const",
102
- "continue",
103
- "debugger",
104
- "default",
105
- "delete",
106
- "do",
107
- "else",
108
- "enum",
109
- "export",
110
- "extends",
111
- "false",
112
- "finally",
113
- "for",
114
- "function",
115
- "if",
116
- "implements",
117
- "import",
118
- "in",
119
- "instanceof",
120
- "interface",
121
- "let",
122
- "new",
123
- "null",
124
- "package",
125
- "private",
126
- "protected",
127
- "public",
128
- "return",
129
- "static",
130
- "super",
131
- "switch",
132
- "this",
133
- "throw",
134
- "true",
135
- "try",
136
- "typeof",
137
- "var",
138
- "void",
139
- "while",
140
- "with",
141
- "yield"
142
- ]);
143
- const DEFINE_MIGRATION_IMPORT = `import { defineMigration } from "@lunora/server";`;
144
- const RUN_MIGRATION_OP = "__lunora_admin__:runMigration";
145
- const MIGRATION_STATUS_OP = "__lunora_admin__:migrationStatus";
146
- const MIGRATE_ENDPOINT_PATH = "/_lunora/migrate";
147
- const kebabCase = (input) => trimChar(input.trim().toLowerCase().replaceAll(NON_ALPHANUMERIC, "-"), "-");
148
- const camelCase = (slug) => slug.split("-").filter((part) => part.length > 0).map((part, index) => {
149
- if (index === 0) {
150
- return part;
151
- }
152
- return part.charAt(0).toUpperCase() + part.slice(1);
153
- }).join("");
154
- const runMigrateCreateCommand = (options) => {
155
- const cwd = options.cwd ?? process.cwd();
156
- const slug = kebabCase(options.name);
157
- if (slug === "") {
158
- options.logger.error(`invalid migration name: "${options.name}" — must contain at least one alphanumeric character`);
159
- return { code: 1, file: "" };
160
- }
161
- const exportName = camelCase(slug);
162
- if (!IDENTIFIER_PATTERN.test(exportName) || RESERVED_WORDS.has(exportName)) {
163
- options.logger.error(
164
- `invalid migration name: "${options.name}" derives the export \`${exportName}\`, which is not a valid identifier — pick a name that starts with a letter and isn't a reserved word`
165
- );
166
- return { code: 1, file: "" };
167
- }
168
- const table = options.table ?? "TODO_table";
169
- if (!IDENTIFIER_PATTERN.test(table)) {
170
- options.logger.error(`invalid --table: "${table}" — must be a valid identifier ([A-Za-z_][A-Za-z0-9_]*)`);
171
- return { code: 1, file: "" };
172
- }
173
- const lunoraDirectory = join(cwd, "lunora");
174
- const file = join(lunoraDirectory, DATA_MIGRATIONS_FILENAME);
175
- let content = existsSync(file) ? readFileSync(file, "utf8") : "";
176
- if (content.includes(`id: "${slug}"`) || new RegExp(String.raw`\bexport const ${exportName}\b`, "u").test(content)) {
177
- options.logger.error(`a migration with id "${slug}" (export \`${exportName}\`) already exists in ${file}`);
178
- return { code: 1, file: "" };
179
- }
180
- if (content.trim() === "") {
181
- content = `${DEFINE_MIGRATION_IMPORT}
182
- `;
183
- } else if (!content.includes(DEFINE_MIGRATION_IMPORT)) {
184
- content = `${DEFINE_MIGRATION_IMPORT}
185
- ${content}`;
186
- }
187
- const block = `export const ${exportName} = defineMigration({
188
- id: "${slug}",
189
- table: "${table}",
190
- up: (document) => document,
191
- });`;
192
- mkdirSync(lunoraDirectory, { recursive: true });
193
- writeFileSync(file, `${content.trimEnd()}
194
-
195
- ${block}
196
- `, "utf8");
197
- options.logger.success(`scaffolded migration "${slug}" in ${file}`);
198
- if (options.table === void 0) {
199
- options.logger.warn(`set the \`table\` field on "${slug}" — it defaults to "${table}"`);
200
- }
201
- return { code: 0, file };
202
- };
203
- const resolveMigrationTable = (cwd, id) => {
204
- const project = new Project({ skipAddingFilesFromTsConfig: true });
205
- const migrations = discoverMigrations(project, join(cwd, "lunora"));
206
- return migrations.find((migration) => migration.id === id)?.table;
207
- };
208
- const resolveValidatedTable = (cwd, options) => {
209
- let table;
210
- try {
211
- table = resolveMigrationTable(cwd, options.id);
212
- } catch (error) {
213
- options.logger.error(error instanceof Error ? error.message : String(error));
214
- return void 0;
215
- }
216
- if (table === void 0) {
217
- options.logger.error(`migration "${options.id}" not found under lunora/ — declare it with defineMigration({ id: "${options.id}", ... })`);
218
- return void 0;
219
- }
220
- if (table === "") {
221
- options.logger.error(`migration "${options.id}" must declare \`table\` as a static string literal`);
222
- return void 0;
223
- }
224
- return table;
225
- };
226
- const resolveMigrateDataRequest = (options) => {
227
- const cwd = options.cwd ?? process.cwd();
228
- if (options.prod && options.url === void 0) {
229
- options.logger.error("--prod requires an explicit --url (refusing to migrate the implicit localhost worker)");
230
- return void 0;
231
- }
232
- if (options.prod && (options.subcommand === "up" || options.subcommand === "down") && !options.yes) {
233
- options.logger.error(`migrate ${options.subcommand} --prod runs the migration against production. Re-run with --yes to confirm.`);
234
- return void 0;
235
- }
236
- const token = options.token ?? process.env.LUNORA_ADMIN_TOKEN;
237
- if (!token) {
238
- options.logger.error("admin token required — pass --token or set LUNORA_ADMIN_TOKEN");
239
- return void 0;
240
- }
241
- const table = resolveValidatedTable(cwd, options);
242
- if (table === void 0) {
243
- return void 0;
244
- }
245
- const baseUrl = resolveAdminBaseUrl(options.url, options.logger);
246
- if (baseUrl === void 0) {
247
- return void 0;
248
- }
249
- const fetchImpl = options.fetchImpl ?? globalThis.fetch;
250
- if (typeof fetchImpl !== "function") {
251
- throw new TypeError("no fetch implementation available — pass fetchImpl or run on Node >= 18");
252
- }
253
- return { fetchImpl, requestUrl: `${baseUrl}${MIGRATE_ENDPOINT_PATH}`, table, token };
254
- };
255
- const buildMigrateArgs = (options) => {
256
- const args = { id: options.id };
257
- if (options.subcommand === "status") {
258
- return args;
259
- }
260
- args.direction = options.subcommand;
261
- if (options.dryRun) {
262
- args.dryRun = true;
263
- }
264
- if (options.batchSize !== void 0) {
265
- args.batchSize = options.batchSize;
266
- }
267
- if (options.maxBatches !== void 0) {
268
- args.maxBatches = options.maxBatches;
269
- }
270
- return args;
271
- };
272
- const runMigrateDataCommand = async (options) => {
273
- const request = resolveMigrateDataRequest(options);
274
- if (request === void 0) {
275
- return { body: void 0, code: 1, requestUrl: "" };
276
- }
277
- const { fetchImpl, requestUrl, table, token } = request;
278
- const functionPath = options.subcommand === "status" ? MIGRATION_STATUS_OP : RUN_MIGRATION_OP;
279
- const args = buildMigrateArgs(options);
280
- options.logger.info(`POST ${requestUrl} -> ${options.subcommand} ${options.id} (table "${table}")`);
281
- const response = await fetchImpl(requestUrl, {
282
- body: JSON.stringify({ args, functionPath, table }),
283
- headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
284
- method: "POST"
285
- });
286
- const text = await response.text();
287
- let body;
288
- try {
289
- body = JSON.parse(text);
290
- } catch {
291
- body = text;
292
- }
293
- options.logger.info(JSON.stringify(body, void 0, 2));
294
- return { body, code: response.ok ? 0 : 1, requestUrl };
295
- };
296
- const runMigrateToHyperdriveCommand = async (options) => {
297
- const { logger } = options;
298
- const fromUrl = options.fromUrl ?? options.toUrl;
299
- const toUrl = options.toUrl ?? options.fromUrl;
300
- if (fromUrl !== void 0 && fromUrl === toUrl) {
301
- logger.error(
302
- "source and target are the same deployment — pass distinct --from-url and --to-url so the D1 export and Hyperdrive import don't run against one database"
303
- );
304
- return { code: 1 };
305
- }
306
- const temporaryDirectory = options.out === void 0 ? mkdtempSync(join(tmpdir(), "lunora-d1ps-")) : void 0;
307
- const dumpPath = options.out ?? join(temporaryDirectory, "dump.ndjson");
308
- logger.info(`Exporting .global() data from the D1 source (${fromUrl ?? "http://localhost:8787"}) …`);
309
- const exportResult = await runExportCommand({
310
- fetchImpl: options.fetchImpl,
311
- logger,
312
- out: dumpPath,
313
- prod: options.prod,
314
- tables: options.tables,
315
- token: options.fromToken,
316
- url: fromUrl
317
- });
318
- if (exportResult.code !== 0) {
319
- return { code: exportResult.code };
320
- }
321
- logger.info(`Exported ${String(exportResult.rows)} row(s) (${String(exportResult.bytes)} bytes).`);
322
- logger.info(`Importing into the Hyperdrive target (${toUrl ?? "http://localhost:8787"}) …`);
323
- const importResult = await runImportCommand({
324
- batchSize: options.batchSize,
325
- fetchImpl: options.fetchImpl,
326
- file: dumpPath,
327
- logger,
328
- prod: options.prod,
329
- token: options.toToken,
330
- url: toUrl
331
- });
332
- if (temporaryDirectory !== void 0) {
333
- rmSync(temporaryDirectory, { force: true, recursive: true });
334
- }
335
- if (importResult.code !== 0) {
336
- return { code: importResult.code };
337
- }
338
- if (importResult.inserted === exportResult.rows) {
339
- logger.info(`✓ Migrated ${String(exportResult.rows)} row(s) — counts match. Verify your app reads from Hyperdrive, then decommission the D1 binding.`);
340
- } else {
341
- logger.warn(
342
- `Imported ${String(importResult.inserted)} of ${String(exportResult.rows)} exported row(s) — the remainder likely already existed in the target (see conflicts above). Re-run after resolving, or inspect the dump with --out.`
343
- );
344
- }
345
- return { code: 0 };
346
- };
347
- const execute = defineHandler(({ argument, cwd, logger, options }) => {
348
- const sub = argument[0];
349
- if (sub === "generate") {
350
- return runMigrateGenerateCommand({ cwd, logger, name: argument[1] ?? options.name });
351
- }
352
- if (sub === "d1-to-hyperdrive") {
353
- return runMigrateToHyperdriveCommand({
354
- batchSize: options.batchSize,
355
- fromToken: options.fromToken ?? options.token,
356
- fromUrl: options.fromUrl ?? options.url,
357
- logger,
358
- out: options.out,
359
- prod: options.prod === true,
360
- tables: options.tables,
361
- toToken: options.toToken ?? options.token,
362
- toUrl: options.toUrl ?? options.url
363
- });
364
- }
365
- if (sub === "create") {
366
- const name = argument[1] ?? options.name;
367
- if (!name) {
368
- logger.error("migrate create requires a name. Usage: lunora migrate create <name> [--table <table>]");
369
- return { code: 1 };
370
- }
371
- return runMigrateCreateCommand({ cwd, logger, name, table: options.table });
372
- }
373
- if (sub === "up" || sub === "down" || sub === "status") {
374
- const id = argument[1] ?? options.name;
375
- if (!id) {
376
- logger.error(`migrate ${sub} requires a migration id. Usage: lunora migrate ${sub} <id>`);
377
- return { code: 1 };
378
- }
379
- return runMigrateDataCommand({
380
- batchSize: options.batchSize,
381
- cwd,
382
- dryRun: options.dryRun === true,
383
- id,
384
- logger,
385
- maxBatches: options.steps,
386
- prod: options.prod === true,
387
- subcommand: sub,
388
- token: options.token,
389
- url: resolveProductionWorkerUrl({ cwd, prod: options.prod === true, url: options.url }),
390
- yes: options.yes === true
391
- });
392
- }
393
- logger.error(`unknown migrate subcommand: "${sub ?? ""}" — expected generate | create | up | down | status`);
394
- return { code: 1 };
395
- });
396
-
397
- export { execute, runMigrateCreateCommand, runMigrateDataCommand, runMigrateGenerateCommand, runMigrateToHyperdriveCommand };