@lunora/cli 1.0.0-alpha.9 → 1.0.0-alpha.91
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/LICENSE.md +6 -0
- package/__assets__/package-og.svg +1 -1
- package/dist/bin.mjs +1 -1
- package/dist/index.d.mts +358 -300
- package/dist/index.d.ts +358 -300
- package/dist/index.mjs +8 -9
- package/dist/packem_chunks/handler.mjs +15 -5
- package/dist/packem_chunks/handler10.mjs +8 -14
- package/dist/packem_chunks/handler11.mjs +20 -189
- package/dist/packem_chunks/handler12.mjs +176 -115
- package/dist/packem_chunks/handler13.mjs +118 -52
- package/dist/packem_chunks/handler14.mjs +50 -43
- package/dist/packem_chunks/handler15.mjs +48 -67
- package/dist/packem_chunks/handler16.mjs +94 -37
- package/dist/packem_chunks/handler17.mjs +39 -100
- package/dist/packem_chunks/handler18.mjs +87 -152
- package/dist/packem_chunks/handler19.mjs +148 -67
- package/dist/packem_chunks/handler2.mjs +6 -4
- package/dist/packem_chunks/handler20.mjs +77 -75
- package/dist/packem_chunks/handler21.mjs +71 -288
- package/dist/packem_chunks/handler3.mjs +8 -4
- package/dist/packem_chunks/handler4.mjs +2 -2
- package/dist/packem_chunks/handler5.mjs +7 -4
- package/dist/packem_chunks/handler6.mjs +10 -7
- package/dist/packem_chunks/handler7.mjs +2 -2
- package/dist/packem_chunks/handler8.mjs +1 -1
- package/dist/packem_chunks/handler9.mjs +330 -12
- package/dist/packem_chunks/planDevCommand.mjs +762 -81
- package/dist/packem_chunks/runCodegenCommand.mjs +5 -4
- package/dist/packem_chunks/runDeployCommand.mjs +137 -22
- package/dist/packem_chunks/runInitCommand.mjs +1648 -188
- package/dist/packem_chunks/runMigrateGenerateCommand.mjs +94 -47
- package/dist/packem_chunks/runResetCommand.mjs +2 -2
- package/dist/packem_chunks/runRpcCommand.mjs +3 -2
- package/dist/packem_shared/{COMMANDS-Dh0bSERi.mjs → COMMANDS-DZ0NnuqI.mjs} +103 -27
- package/dist/packem_shared/{DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs → DEFAULT_IMPORT_BATCH_SIZE-D0VOTerB.mjs} +7 -2
- package/dist/packem_shared/{api-spec-CtA6ilu4.mjs → api-spec-Bx0iKbxA.mjs} +3 -1
- package/dist/packem_shared/{buildRegistryIndex-BcYe607_.mjs → buildRegistryIndex-BS5ig822.mjs} +1 -1
- package/dist/packem_shared/codegen-error-DJG-ghs_.mjs +31 -0
- package/dist/packem_shared/{command-BDXcJCCJ.mjs → command-lYnl4QyF.mjs} +6 -1
- package/dist/packem_shared/{commands-CkkATMMx.mjs → commands-D5Yxt9VY.mjs} +199 -20
- package/dist/packem_shared/{createLogger-CHPNjFw2.mjs → createLogger-CIWSHrTL.mjs} +40 -8
- package/dist/packem_shared/{createRecordingSpawner-DxI3mebw.mjs → createRecordingSpawner-WuSn20kb.mjs} +23 -2
- package/dist/packem_shared/detect-package-manager-v4hHpQd0.mjs +62 -0
- package/dist/packem_shared/{insertSchemaExtension-BuzF6-t2.mjs → insertSchemaExtension-DAqbfr9Z.mjs} +15 -10
- package/dist/packem_shared/{open-url-Dfq6fAyT.mjs → open-url-4PBLY9X0.mjs} +3 -2
- package/dist/packem_shared/{output-format-7gyGR3h8.mjs → output-format-B4642rjE.mjs} +1 -1
- package/dist/packem_shared/{parseManifest--vZf2FY1.mjs → parseManifest-Dbp-Q2q3.mjs} +36 -9
- package/dist/packem_shared/prompt-cancelled-APzX1Im-.mjs +9 -0
- package/dist/packem_shared/runAddCommand-D1hgfqFQ.mjs +4 -0
- package/dist/packem_shared/{storage-Bjo35hPa.mjs → storage-BXU4ax4O.mjs} +1 -1
- package/dist/packem_shared/tui-prompts-BjEN8XgP.mjs +658 -0
- package/dist/packem_shared/wrangler-secrets-Coni-mER.mjs +49 -0
- package/package.json +17 -14
- package/skills/lunora-quickstart/SKILL.md +26 -5
- package/dist/packem_shared/detect-package-manager-DYp7n3mJ.mjs +0 -61
- package/dist/packem_shared/parseArgs-YXFuKdEk.mjs +0 -56
- package/dist/packem_shared/runAddCommand-DepS9W9W.mjs +0 -4
- package/dist/packem_shared/tui-prompts-CA9lngSS.mjs +0 -269
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { runCodegen } from '@lunora/codegen';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { collectWranglerSecretVariables } from '@lunora/config';
|
|
3
|
+
import { p as parseApiSpec } from '../packem_shared/api-spec-Bx0iKbxA.mjs';
|
|
4
|
+
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
5
|
+
import { v as validateOutputFormat, p as printJson, l as loggerForFormat, i as isJsonFormat } from '../packem_shared/output-format-B4642rjE.mjs';
|
|
5
6
|
|
|
6
7
|
const CRON_TRIGGER_LIMIT = 3;
|
|
7
8
|
const runCodegenCommand = (options) => {
|
|
@@ -13,7 +14,7 @@ const runCodegenCommand = (options) => {
|
|
|
13
14
|
options.logger.error(formatError);
|
|
14
15
|
return { advisories: [], cronTriggers: [], error: formatError, outputDirectory: "" };
|
|
15
16
|
}
|
|
16
|
-
const result = runCodegen({ apiSpec: options.apiSpec, projectRoot });
|
|
17
|
+
const result = runCodegen({ apiSpec: options.apiSpec, projectRoot, wranglerVariables: collectWranglerSecretVariables(projectRoot) });
|
|
17
18
|
const commandResult = {
|
|
18
19
|
advisories: result.advisories.map((advisory) => {
|
|
19
20
|
return {
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { runCodegen, discoverMigrations } from '@lunora/codegen';
|
|
3
|
-
import { readLinkedProject, writeLinkedProject, validateWranglerProject, inferLunoraBindings, reconcileWranglerBindings, DEV_VARS_FILE, parseDevVariableEntries, findWranglerFile, readWranglerJsonc, discoverContainerInfo } from '@lunora/config';
|
|
3
|
+
import { readLinkedProject, writeLinkedProject, validateWranglerProject, inferLunoraBindings, reconcileWranglerBindings, reconcileWranglerCompatibilityDate, reconcileWranglerCrons, DEV_VARS_FILE, parseDevVariableEntries, isMintableSecretKey, findWranglerFile, readWranglerJsonc, discoverContainerInfo, packageNamesFromBindings, requiredSecrets, generateSecretValue } from '@lunora/config';
|
|
4
4
|
import { join } from '@visulima/path';
|
|
5
5
|
import { Spinner } from '@visulima/spinner';
|
|
6
6
|
import { Project } from 'ts-morph';
|
|
7
|
-
import { p as parseApiSpec } from '../packem_shared/api-spec-
|
|
7
|
+
import { p as parseApiSpec } from '../packem_shared/api-spec-Bx0iKbxA.mjs';
|
|
8
8
|
import { r as readWranglerName } from '../packem_shared/wrangler-name-cy4yhm9j.mjs';
|
|
9
|
-
import { d as defineHandler } from '../packem_shared/command-
|
|
9
|
+
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
10
|
+
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-v4hHpQd0.mjs';
|
|
10
11
|
import { a as isRailpackAvailable, i as isDockerAvailable } from '../packem_shared/docker-hMQ97KSQ.mjs';
|
|
11
|
-
import { v as validateOutputFormat, i as isJsonFormat, p as printJson, l as loggerForFormat } from '../packem_shared/output-format-
|
|
12
|
+
import { v as validateOutputFormat, i as isJsonFormat, p as printJson, l as loggerForFormat } from '../packem_shared/output-format-B4642rjE.mjs';
|
|
12
13
|
import { containerBuildTag } from '@lunora/container';
|
|
13
|
-
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-
|
|
14
|
+
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-WuSn20kb.mjs';
|
|
14
15
|
import { r as resolveWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
|
|
15
16
|
import { r as runSchemaDriftGate } from '../packem_shared/schema-drift-gate-BtBt0as0.mjs';
|
|
17
|
+
import { c as createTuiConfirm } from '../packem_shared/tui-prompts-BjEN8XgP.mjs';
|
|
18
|
+
import { l as listRemoteSecrets } from '../packem_shared/wrangler-secrets-Coni-mER.mjs';
|
|
16
19
|
import { runMigrateDataCommand } from './runMigrateGenerateCommand.mjs';
|
|
17
20
|
|
|
18
21
|
const WORKERS_DEV_URL = /https?:\/\/[^\s"'<>]+\.workers\.dev[^\s"'<>]*/u;
|
|
@@ -78,7 +81,8 @@ const buildRailpackImages = async (options) => {
|
|
|
78
81
|
for (const target of options.targets) {
|
|
79
82
|
const tag = containerBuildTag(target.exportName);
|
|
80
83
|
const build = { args: ["build", target.buildDir, "--name", tag], command: "railpack", cwd: options.cwd };
|
|
81
|
-
const
|
|
84
|
+
const pushExec = execArgsFor(detectPackageManager(options.cwd), "wrangler", ["containers", "push", tag]);
|
|
85
|
+
const push = { args: pushExec.args, command: pushExec.command, cwd: options.cwd };
|
|
82
86
|
options.logger.info(`railpack: building "${target.exportName}" → ${tag} from ${target.buildDir}`);
|
|
83
87
|
const buildResult = await spawner(build);
|
|
84
88
|
if (buildResult.code !== 0) {
|
|
@@ -177,7 +181,7 @@ const buildContainerImages = async (cwd, options) => {
|
|
|
177
181
|
});
|
|
178
182
|
return result.code === 0 ? void 0 : result.error ?? "railpack build failed";
|
|
179
183
|
};
|
|
180
|
-
const provisionBindings = async (cwd, logger) => {
|
|
184
|
+
const provisionBindings = async (cwd, logger, cronTriggers = []) => {
|
|
181
185
|
try {
|
|
182
186
|
const inferred = await inferLunoraBindings({ projectRoot: cwd });
|
|
183
187
|
const reconciled = reconcileWranglerBindings(cwd, inferred);
|
|
@@ -191,6 +195,26 @@ const provisionBindings = async (cwd, logger) => {
|
|
|
191
195
|
const message = error instanceof Error ? error.message : String(error);
|
|
192
196
|
logger.warn(`binding inference skipped: ${message}`);
|
|
193
197
|
}
|
|
198
|
+
try {
|
|
199
|
+
const reconciled = reconcileWranglerCompatibilityDate(cwd);
|
|
200
|
+
if (reconciled.changed) {
|
|
201
|
+
logger.success(
|
|
202
|
+
`bumped compatibility_date to ${reconciled.date ?? "unknown"} (Workers Cache enabled) → ${reconciled.wranglerPath ?? "wrangler.jsonc"}`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
} catch (error) {
|
|
206
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
207
|
+
logger.warn(`compatibility date sync skipped: ${message}`);
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
const reconciled = reconcileWranglerCrons(cwd, cronTriggers);
|
|
211
|
+
if (reconciled.changed) {
|
|
212
|
+
logger.success(`synced ${String(cronTriggers.length)} cron trigger(s) → ${reconciled.wranglerPath ?? "wrangler.jsonc"}`);
|
|
213
|
+
}
|
|
214
|
+
} catch (error) {
|
|
215
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
216
|
+
logger.warn(`cron trigger sync skipped: ${message}`);
|
|
217
|
+
}
|
|
194
218
|
};
|
|
195
219
|
const warnDevVariablesNotPushed = (cwd, logger) => {
|
|
196
220
|
const devVariablesPath = join(cwd, DEV_VARS_FILE);
|
|
@@ -210,6 +234,90 @@ const warnDevVariablesNotPushed = (cwd, logger) => {
|
|
|
210
234
|
`Note: \`lunora deploy\` does not push secrets. ${DEV_VARS_FILE} has ${String(keyCount)} key(s); if you changed them, run \`lunora env push --yes\` to update the deployed secrets.`
|
|
211
235
|
);
|
|
212
236
|
};
|
|
237
|
+
const SECRET_LIKE_KEY = /(?:KEY|PASSWORD|SECRET|TOKEN)$/u;
|
|
238
|
+
const resolveRequiredSecretKeys = async (cwd) => {
|
|
239
|
+
let packages = [];
|
|
240
|
+
try {
|
|
241
|
+
packages = packageNamesFromBindings(await inferLunoraBindings({ projectRoot: cwd }));
|
|
242
|
+
} catch {
|
|
243
|
+
}
|
|
244
|
+
const fromPackages = requiredSecrets(packages).map((entry) => entry.key);
|
|
245
|
+
let fromLocal = [];
|
|
246
|
+
try {
|
|
247
|
+
const devVariablesPath = join(cwd, DEV_VARS_FILE);
|
|
248
|
+
if (existsSync(devVariablesPath)) {
|
|
249
|
+
fromLocal = parseDevVariableEntries(readFileSync(devVariablesPath, "utf8")).map((entry) => entry.key).filter((key) => SECRET_LIKE_KEY.test(key));
|
|
250
|
+
}
|
|
251
|
+
} catch {
|
|
252
|
+
}
|
|
253
|
+
return [.../* @__PURE__ */ new Set([...fromPackages, ...fromLocal])];
|
|
254
|
+
};
|
|
255
|
+
const pushMintableSecrets = async (cwd, options, keys) => {
|
|
256
|
+
const { logger } = options;
|
|
257
|
+
const spawner = options.spawner ?? defaultSpawner;
|
|
258
|
+
const manager = detectPackageManager(cwd);
|
|
259
|
+
const environmentFlag = options.env === void 0 ? "" : ` --env ${options.env}`;
|
|
260
|
+
for (const key of keys) {
|
|
261
|
+
const args = ["secret", "put", key];
|
|
262
|
+
if (options.env !== void 0) {
|
|
263
|
+
args.push("--env", options.env);
|
|
264
|
+
}
|
|
265
|
+
if (options.temporary === true) {
|
|
266
|
+
args.push("--temporary");
|
|
267
|
+
}
|
|
268
|
+
const exec = execArgsFor(manager, "wrangler", args);
|
|
269
|
+
const pushResult = await spawner({ args: exec.args, command: exec.command, cwd, input: generateSecretValue() });
|
|
270
|
+
if (pushResult.code !== 0) {
|
|
271
|
+
logger.error(
|
|
272
|
+
`failed to push secret ${key} (exit ${String(pushResult.code)}); set it manually with \`wrangler secret put ${key}${environmentFlag}\`.`
|
|
273
|
+
);
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
logger.success(`generated + pushed ${key}`);
|
|
277
|
+
}
|
|
278
|
+
return true;
|
|
279
|
+
};
|
|
280
|
+
const offerMissingSecrets = async (cwd, options, interactive) => {
|
|
281
|
+
if (options.dryRun === true || options.preview === true) {
|
|
282
|
+
return void 0;
|
|
283
|
+
}
|
|
284
|
+
const { logger } = options;
|
|
285
|
+
const environmentFlag = options.env === void 0 ? "" : ` --env ${options.env}`;
|
|
286
|
+
let remote;
|
|
287
|
+
try {
|
|
288
|
+
remote = await (options.secretLister ?? listRemoteSecrets)({ cwd, env: options.env, temporary: options.temporary });
|
|
289
|
+
} catch {
|
|
290
|
+
return void 0;
|
|
291
|
+
}
|
|
292
|
+
if (!remote.ok) {
|
|
293
|
+
return void 0;
|
|
294
|
+
}
|
|
295
|
+
const remoteNames = new Set(remote.names);
|
|
296
|
+
const required = await resolveRequiredSecretKeys(cwd);
|
|
297
|
+
const missing = required.filter((key) => !remoteNames.has(key));
|
|
298
|
+
if (missing.length === 0) {
|
|
299
|
+
return void 0;
|
|
300
|
+
}
|
|
301
|
+
if (!interactive) {
|
|
302
|
+
return `missing required secret(s) on the deploy target: ${missing.join(", ")}. Set them with \`wrangler secret put <KEY>${environmentFlag}\` (or \`lunora env generate --set\` then \`lunora env push --yes${options.env === void 0 ? "" : " --prod"}\`), then re-deploy.`;
|
|
303
|
+
}
|
|
304
|
+
for (const key of missing.filter((name) => !isMintableSecretKey(name))) {
|
|
305
|
+
logger.warn(`required secret ${key} is not set on the target — set it with: wrangler secret put ${key}${environmentFlag}`);
|
|
306
|
+
}
|
|
307
|
+
const mintable = missing.filter((key) => isMintableSecretKey(key));
|
|
308
|
+
if (mintable.length === 0) {
|
|
309
|
+
return void 0;
|
|
310
|
+
}
|
|
311
|
+
const confirm = options.secretConfirm ?? createTuiConfirm();
|
|
312
|
+
if (await confirm(`${String(mintable.length)} required secret(s) not set on the target (${mintable.join(", ")}). Generate strong values and push them now?`)) {
|
|
313
|
+
await pushMintableSecrets(cwd, options, mintable);
|
|
314
|
+
return void 0;
|
|
315
|
+
}
|
|
316
|
+
logger.warn(
|
|
317
|
+
`${String(mintable.length)} required secret(s) not set on the target: ${mintable.join(", ")}. Generate + push with \`lunora env generate --set\` then \`lunora env push --yes${options.env === void 0 ? "" : " --prod"}\`.`
|
|
318
|
+
);
|
|
319
|
+
return void 0;
|
|
320
|
+
};
|
|
213
321
|
const runPostDeployMigrations = async (options, cwd) => {
|
|
214
322
|
const project = new Project({ skipAddingFilesFromTsConfig: true });
|
|
215
323
|
const lunoraDirectory = join(cwd, "lunora");
|
|
@@ -352,7 +460,7 @@ const runPreDeployGates = async (cwd, options) => {
|
|
|
352
460
|
return buildContainerImages(cwd, options);
|
|
353
461
|
};
|
|
354
462
|
const buildWranglerDeployArgs = (cwd, options) => {
|
|
355
|
-
const args = options.preview ? ["
|
|
463
|
+
const args = options.preview ? ["versions", "upload"] : ["deploy"];
|
|
356
464
|
const composedEntry = resolveComposedWorkerEntry(cwd);
|
|
357
465
|
if (composedEntry !== void 0) {
|
|
358
466
|
args.push(composedEntry);
|
|
@@ -375,6 +483,16 @@ const buildWranglerDeployArgs = (cwd, options) => {
|
|
|
375
483
|
}
|
|
376
484
|
return args;
|
|
377
485
|
};
|
|
486
|
+
const reportWranglerProblems = (validation, logger) => {
|
|
487
|
+
if (validation.problems.length === 0) {
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
logger.error("wrangler.jsonc validation failed:");
|
|
491
|
+
for (const problem of validation.problems) {
|
|
492
|
+
logger.error(` - ${problem}`);
|
|
493
|
+
}
|
|
494
|
+
return true;
|
|
495
|
+
};
|
|
378
496
|
const executeDeploy = async (options) => {
|
|
379
497
|
const cwd = options.cwd ?? process.cwd();
|
|
380
498
|
const interactive = isInteractive(options);
|
|
@@ -410,7 +528,7 @@ const executeDeploy = async (options) => {
|
|
|
410
528
|
}
|
|
411
529
|
reblessSchemaBaseline = gate.rebless;
|
|
412
530
|
}
|
|
413
|
-
await provisionBindings(cwd, options.logger);
|
|
531
|
+
await provisionBindings(cwd, options.logger, codegen?.cronTriggers ?? []);
|
|
414
532
|
const migratePreflightError = validateMigrateDeployPreflight(options);
|
|
415
533
|
if (migratePreflightError !== void 0) {
|
|
416
534
|
return { code: 1, descriptor: void 0, error: migratePreflightError, validation: { problems: [], wranglerPath: void 0 } };
|
|
@@ -420,24 +538,21 @@ const executeDeploy = async (options) => {
|
|
|
420
538
|
return { code: 1, descriptor: void 0, error: preflightError, validation: { problems: [], wranglerPath: void 0 } };
|
|
421
539
|
}
|
|
422
540
|
const validation = validateWranglerProject({ projectRoot: cwd });
|
|
423
|
-
if (validation.
|
|
424
|
-
|
|
425
|
-
for (const problem of validation.problems) {
|
|
426
|
-
options.logger.error(` - ${problem}`);
|
|
427
|
-
}
|
|
428
|
-
return {
|
|
429
|
-
code: 1,
|
|
430
|
-
descriptor: void 0,
|
|
431
|
-
error: "wrangler validation failed",
|
|
432
|
-
validation
|
|
433
|
-
};
|
|
541
|
+
if (reportWranglerProblems(validation, options.logger)) {
|
|
542
|
+
return { code: 1, descriptor: void 0, error: "wrangler validation failed", validation };
|
|
434
543
|
}
|
|
435
544
|
warnDevVariablesNotPushed(cwd, options.logger);
|
|
545
|
+
const secretAbort = await offerMissingSecrets(cwd, options, interactive);
|
|
546
|
+
if (secretAbort !== void 0) {
|
|
547
|
+
options.logger.error(secretAbort);
|
|
548
|
+
return { code: 1, descriptor: void 0, error: secretAbort, validation };
|
|
549
|
+
}
|
|
436
550
|
const shouldAutoLink = !isJsonFormat(options.format) && options.dryRun !== true && options.preview !== true && readLinkedProject(cwd) === void 0;
|
|
551
|
+
const exec = execArgsFor(detectPackageManager(cwd), "wrangler", buildWranglerDeployArgs(cwd, options));
|
|
437
552
|
const descriptor = {
|
|
438
|
-
args:
|
|
553
|
+
args: exec.args,
|
|
439
554
|
captureStdout: shouldAutoLink,
|
|
440
|
-
command:
|
|
555
|
+
command: exec.command,
|
|
441
556
|
cwd,
|
|
442
557
|
// In `--format json` mode stdout is reserved for the single JSON document,
|
|
443
558
|
// so route wrangler's progress + deployed-URL output to stderr instead.
|