@geekmidas/cli 10.0.0-alpha.46 → 10.0.0-alpha.47

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/index.cjs CHANGED
@@ -6,10 +6,11 @@ const require_config = require("./config-CsYSyUya.cjs");
6
6
  const require_workspace = require("./workspace-DEibcoBe.cjs");
7
7
  const require_storage = require("./storage-CSGoC3bK.cjs");
8
8
  const require_store = require("./store-DQgxT_WR.cjs");
9
- const require_workspace$1 = require("./workspace-D9z2ymBW.cjs");
9
+ const require_workspace$1 = require("./workspace-vafrzZTC.cjs");
10
10
  const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-BN0PIZxd.cjs");
11
11
  const require_openapi = require("./openapi.cjs");
12
- const require_ready = require("./ready-L7I68yXf.cjs");
12
+ const require_ready = require("./ready-lr2Fm-ep.cjs");
13
+ const require_backends = require("./backends-B9V2XD2M.cjs");
13
14
  const require_emit = require("./emit-Dmc1nvdS.cjs");
14
15
  let commander = require("commander");
15
16
  let node_process = require("node:process");
@@ -28,6 +29,7 @@ let chokidar = require("chokidar");
28
29
  chokidar = require_rolldown_runtime.__toESM(chokidar, 1);
29
30
  let node_crypto = require("node:crypto");
30
31
  let node_url = require("node:url");
32
+ let _geekmidas_constructs_encryption = require("@geekmidas/constructs/encryption");
31
33
  let _geekmidas_db_pg_roles = require("@geekmidas/db/pg/roles");
32
34
  let pg = require("pg");
33
35
  let yaml = require("yaml");
@@ -46,7 +48,7 @@ let _geekmidas_constructs_queue = require("@geekmidas/constructs/queue");
46
48
  let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
47
49
  let node_dns_promises = require("node:dns/promises");
48
50
  //#region package.json
49
- var version = "10.0.0-alpha.46";
51
+ var version = "10.0.0-alpha.47";
50
52
  //#endregion
51
53
  //#region src/auth/credentials.ts
52
54
  /**
@@ -1184,7 +1186,7 @@ async function devCommand(options) {
1184
1186
  appRoot,
1185
1187
  target: "server",
1186
1188
  enableOpenApi,
1187
- cacheBackend: require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(workspace ?? config)),
1189
+ cacheBackend: require_backends.cacheBackendFor(require_backends.providerOf(workspace ?? config)),
1188
1190
  telescope,
1189
1191
  studio,
1190
1192
  hooks,
@@ -1202,9 +1204,9 @@ async function devCommand(options) {
1202
1204
  stage: workspace.stages.local,
1203
1205
  ...options.fake ? { fake: true } : {}
1204
1206
  });
1205
- if (reconciled.changed && reconciled.plan.containers.length > 0) {
1206
- logger$9.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
1207
- for (const [container, address] of Object.entries(reconciled.addresses)) logger$9.log(` ${container}: ${address}`);
1207
+ if (reconciled.services.length > 0) {
1208
+ logger$9.log("🐳 Services");
1209
+ for (const line of require_workspace$1.describeServices(reconciled.services)) logger$9.log(line);
1208
1210
  }
1209
1211
  Object.assign(appSecrets, reconciled.env);
1210
1212
  const own = reconciled.plan.resources.find((r) => (r.kind === "rest-api" || r.kind === "site") && require_config.appKey(r.id) === workspaceAppName);
@@ -1485,9 +1487,9 @@ async function workspaceDevCommand(workspace, options) {
1485
1487
  stage: workspace.stages.local,
1486
1488
  ...options.fake ? { fake: true } : {}
1487
1489
  });
1488
- if (reconciled.changed && reconciled.plan.containers.length > 0) {
1489
- logger$9.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
1490
- for (const [container, address] of Object.entries(reconciled.addresses)) logger$9.log(` ${container}: ${address}`);
1490
+ if (reconciled.services.length > 0) {
1491
+ logger$9.log("🐳 Services");
1492
+ for (const line of require_workspace$1.describeServices(reconciled.services)) logger$9.log(line);
1491
1493
  }
1492
1494
  const secretsEnv = {
1493
1495
  ...rawSecrets,
@@ -1496,9 +1498,9 @@ async function workspaceDevCommand(workspace, options) {
1496
1498
  const fakes = options.fake ? await serveFakes(reconciled.fakes, reconciled.ports) : [];
1497
1499
  for (const { id, port } of fakes) logger$9.log(`🎭 ${id} fake: http://localhost:${port}`);
1498
1500
  if (options.migrate || options.seed) {
1499
- const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
1501
+ const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
1500
1502
  await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
1501
- } else await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1503
+ } else await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1502
1504
  logger$9.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
1503
1505
  });
1504
1506
  const appUrls = {};
@@ -2633,7 +2635,7 @@ async function buildCommand(options) {
2633
2635
  }
2634
2636
  }
2635
2637
  const config = loadedConfig.type !== "workspace" ? await require_config.loadConfig() : (0, node_path.resolve)(process.cwd()) === (0, node_path.resolve)(loadedConfig.workspace.root) ? rootGkmConfig(loadedConfig.workspace) : (await require_config.loadAppConfig()).gkmConfig;
2636
- const target = options.provider ?? require_workspace$1.providerOf(loadedConfig.workspace);
2638
+ const target = options.provider ?? require_backends.providerOf(loadedConfig.workspace);
2637
2639
  const workspaceRoot = loadedConfig.workspace.root;
2638
2640
  const appRoot = process.cwd();
2639
2641
  const output = await buildOneApp({
@@ -2665,14 +2667,14 @@ async function declaredIn(config, cwd) {
2665
2667
  */
2666
2668
  function backendsOf(workspace) {
2667
2669
  return {
2668
- cache: require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(workspace)),
2670
+ cache: require_backends.cacheBackendFor(require_backends.providerOf(workspace)),
2669
2671
  email: "ses"
2670
2672
  };
2671
2673
  }
2672
2674
  /** One app's build, from its config and the command's options. */
2673
2675
  async function buildOneApp(input) {
2674
2676
  const { config, options, workspace, appRoot, target } = input;
2675
- const cacheBackend = require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(workspace));
2677
+ const cacheBackend = require_backends.cacheBackendFor(require_backends.providerOf(workspace));
2676
2678
  const production = normalizeProductionConfig(options.production ?? false);
2677
2679
  if (production) logger$8.log(`🏭 Building for PRODUCTION`);
2678
2680
  logger$8.log(`Building for ${target}`);
@@ -2975,7 +2977,7 @@ async function workspaceBuildCommand(workspace, options) {
2975
2977
  const buildOrder = require_workspace.getAppBuildOrder(workspace);
2976
2978
  logger$8.log(` Build order: ${buildOrder.join(" → ")}`);
2977
2979
  try {
2978
- const target = options.provider ?? require_workspace$1.providerOf(workspace);
2980
+ const target = options.provider ?? require_backends.providerOf(workspace);
2979
2981
  const builds = [];
2980
2982
  for (const appName of buildOrder) {
2981
2983
  const app = workspace.apps[appName];
@@ -3376,6 +3378,19 @@ const PROVISIONERS = {
3376
3378
  return { provides: { [key]: supplied(declaration.id, key, context) } };
3377
3379
  },
3378
3380
  /**
3381
+ * The keyring the stage keeps in its secrets.
3382
+ *
3383
+ * Generated on the first deploy (`withGeneratedSecrets`) and rotated only
3384
+ * by `gkm encryption:rotate`, so a redeploy never changes a key and nothing
3385
+ * written becomes unreadable. Nothing is created in Dokploy: the process
3386
+ * holds the keyring.
3387
+ */
3388
+ encryption: async (declaration, context) => {
3389
+ if (declaration.kind !== "encryption") throw new WrongKind(declaration.kind);
3390
+ const key = (0, _geekmidas_manifest.provideKey)(declaration.id, "url");
3391
+ return { provides: { [key]: supplied(declaration.id, key, context) } };
3392
+ },
3393
+ /**
3379
3394
  * A third party's credentials, as the stage was given them.
3380
3395
  *
3381
3396
  * Nothing is created and nothing derived: the value was issued by somebody
@@ -3745,9 +3760,9 @@ async function provisionDeclared(options) {
3745
3760
  environmentId: options.environmentId,
3746
3761
  stage: options.stage,
3747
3762
  project: workspace.name,
3748
- cache: require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(workspace)),
3749
- events: require_workspace$1.eventsBackendFor(require_workspace$1.providerOf(workspace)),
3750
- storage: require_workspace$1.storageBackendFor(require_workspace$1.providerOf(workspace)),
3763
+ cache: require_backends.cacheBackendFor(require_backends.providerOf(workspace)),
3764
+ events: require_backends.eventsBackendFor(require_backends.providerOf(workspace)),
3765
+ storage: require_backends.storageBackendFor(require_backends.providerOf(workspace)),
3751
3766
  addresses: surfaceAddresses(workspace, manifest, options.appUrls),
3752
3767
  seed: options.seed,
3753
3768
  ...options.supplied ? { supplied: options.supplied } : {},
@@ -6385,6 +6400,8 @@ function validateEnvVars(requiredVars, context) {
6385
6400
  * who could read the repo.
6386
6401
  * - **Each `secret` construct's value** — an auth server's signing secret —
6387
6402
  * random, rather than derived.
6403
+ * - **Each `encryption` construct's keyring** — one random key and an index
6404
+ * key. Later keys are added by `gkm encryption:rotate`, never by a deploy.
6388
6405
  *
6389
6406
  * Both are generated on the first deploy that needs them and written to the
6390
6407
  * stage's store, so every later deploy reads the same values: sessions survive
@@ -6400,10 +6417,10 @@ function withGeneratedSecrets(secrets, manifest) {
6400
6417
  const generated = [];
6401
6418
  const custom = { ...secrets.custom };
6402
6419
  for (const declaration of Object.values(manifest)) {
6403
- if (declaration?.kind !== "secret") continue;
6420
+ if (declaration?.kind !== "secret" && declaration?.kind !== "encryption") continue;
6404
6421
  const key = declaration.provides?.[0];
6405
6422
  if (!key || custom[key]) continue;
6406
- custom[key] = random();
6423
+ custom[key] = declaration.kind === "encryption" ? (0, _geekmidas_constructs_encryption.generateKeyring)() : random();
6407
6424
  generated.push(key);
6408
6425
  }
6409
6426
  const seed = secrets.seed ?? random();
@@ -9077,26 +9094,26 @@ function loadPackageJson() {
9077
9094
  * Run: pnpm --filter @geekmidas/cli sync-versions
9078
9095
  */
9079
9096
  const GEEKMIDAS_VERSIONS = {
9080
- "@geekmidas/audit": "~10.0.0-alpha.46",
9081
- "@geekmidas/auth": "~10.0.0-alpha.46",
9082
- "@geekmidas/cache": "~10.0.0-alpha.46",
9083
- "@geekmidas/client": "~10.0.0-alpha.46",
9084
- "@geekmidas/cloud": "~10.0.0-alpha.46",
9085
- "@geekmidas/constructs": "~10.0.0-alpha.46",
9086
- "@geekmidas/db": "~10.0.0-alpha.46",
9087
- "@geekmidas/emailkit": "~10.0.0-alpha.46",
9088
- "@geekmidas/envkit": "~10.0.0-alpha.46",
9089
- "@geekmidas/errors": "~10.0.0-alpha.46",
9090
- "@geekmidas/events": "~10.0.0-alpha.46",
9091
- "@geekmidas/logger": "~10.0.0-alpha.46",
9092
- "@geekmidas/manifest": "~10.0.0-alpha.46",
9093
- "@geekmidas/rate-limit": "~10.0.0-alpha.46",
9094
- "@geekmidas/schema": "~10.0.0-alpha.46",
9095
- "@geekmidas/services": "~10.0.0-alpha.46",
9096
- "@geekmidas/storage": "~10.0.0-alpha.46",
9097
- "@geekmidas/studio": "~10.0.0-alpha.46",
9098
- "@geekmidas/telescope": "~10.0.0-alpha.46",
9099
- "@geekmidas/testkit": "~10.0.0-alpha.46",
9097
+ "@geekmidas/audit": "~10.0.0-alpha.47",
9098
+ "@geekmidas/auth": "~10.0.0-alpha.47",
9099
+ "@geekmidas/cache": "~10.0.0-alpha.47",
9100
+ "@geekmidas/client": "~10.0.0-alpha.47",
9101
+ "@geekmidas/cloud": "~10.0.0-alpha.47",
9102
+ "@geekmidas/constructs": "~10.0.0-alpha.47",
9103
+ "@geekmidas/db": "~10.0.0-alpha.47",
9104
+ "@geekmidas/emailkit": "~10.0.0-alpha.47",
9105
+ "@geekmidas/envkit": "~10.0.0-alpha.47",
9106
+ "@geekmidas/errors": "~10.0.0-alpha.47",
9107
+ "@geekmidas/events": "~10.0.0-alpha.47",
9108
+ "@geekmidas/logger": "~10.0.0-alpha.47",
9109
+ "@geekmidas/manifest": "~10.0.0-alpha.47",
9110
+ "@geekmidas/rate-limit": "~10.0.0-alpha.47",
9111
+ "@geekmidas/schema": "~10.0.0-alpha.47",
9112
+ "@geekmidas/services": "~10.0.0-alpha.47",
9113
+ "@geekmidas/storage": "~10.0.0-alpha.47",
9114
+ "@geekmidas/studio": "~10.0.0-alpha.47",
9115
+ "@geekmidas/telescope": "~10.0.0-alpha.47",
9116
+ "@geekmidas/testkit": "~10.0.0-alpha.47",
9100
9117
  "@geekmidas/cli": `~${loadPackageJson().version}`
9101
9118
  };
9102
9119
  //#endregion
@@ -15505,8 +15522,8 @@ async function reconcileLocal(workspace, stage, options) {
15505
15522
  logger$1.log("🐳 Services already up to date");
15506
15523
  return;
15507
15524
  }
15508
- logger$1.log(`🐳 Services: ${result.plan.containers.join(", ")}`);
15509
- for (const [container, address] of Object.entries(result.addresses)) logger$1.log(` ${container}: ${address}`);
15525
+ logger$1.log("🐳 Services");
15526
+ for (const line of require_workspace$1.describeServices(result.services)) logger$1.log(line);
15510
15527
  const url = result.plan.resources.filter((r) => r.kind === "rest-api" || r.kind === "site" || r.kind === "file-server").map((r) => result.env[r.envKey]).find((address) => address?.startsWith("https://"));
15511
15528
  if (url) await ensureTrusted(workspace.root, url, { ...options.yes ? { assumeYes: true } : {} });
15512
15529
  }
@@ -15853,7 +15870,7 @@ function testDatabases(reconciled) {
15853
15870
  * starts without the reference data the app needs.
15854
15871
  */
15855
15872
  async function migrateTestStage(workspace, env) {
15856
- const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
15873
+ const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
15857
15874
  const { discover } = await Promise.resolve().then(() => require("./discover-DXNviAh-.cjs")).then((n) => n.discover_exports);
15858
15875
  const sources = {};
15859
15876
  const manifest = await discover({
@@ -16284,7 +16301,7 @@ program.command("migrate").description("Apply each database construct's migratio
16284
16301
  try {
16285
16302
  const globalOptions = program.opts();
16286
16303
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16287
- const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
16304
+ const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
16288
16305
  await migrateCommand({
16289
16306
  ...options,
16290
16307
  ...construct ? { construct } : {}
@@ -16298,7 +16315,7 @@ program.command("seed").description("Migrate, then run each database construct's
16298
16315
  try {
16299
16316
  const globalOptions = program.opts();
16300
16317
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16301
- const { seedCommand } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
16318
+ const { seedCommand } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
16302
16319
  await seedCommand({
16303
16320
  ...options,
16304
16321
  ...construct ? { construct } : {}
@@ -16312,7 +16329,7 @@ program.command("migration").description("Write a construct's next migration: an
16312
16329
  try {
16313
16330
  const globalOptions = program.opts();
16314
16331
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16315
- const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
16332
+ const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
16316
16333
  await migrationCommand({
16317
16334
  construct,
16318
16335
  ...name ? { name } : {}
@@ -16406,6 +16423,28 @@ program.command("secrets:set").description("Set a custom secret for a stage").ar
16406
16423
  process.exit(1);
16407
16424
  }
16408
16425
  });
16426
+ program.command("encryption:rotate").description("Add a new current key to an Encryption construct's keyring on a server stage").argument("<construct>", "The Encryption construct (e.g. Pii)").requiredOption("--stage <stage>", "A deployed stage").action(async (construct, options) => {
16427
+ try {
16428
+ const globalOptions = program.opts();
16429
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16430
+ const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-C7OGMve_.cjs"));
16431
+ await encryptionRotateCommand(construct, options);
16432
+ } catch (error) {
16433
+ console.error(formatError(error));
16434
+ process.exit(1);
16435
+ }
16436
+ });
16437
+ program.command("encryption:retire").description("Remove an old key from an Encryption construct's keyring, once nothing is under it").argument("<construct>", "The Encryption construct (e.g. Pii)").argument("<key>", "The key to retire (e.g. k1)").requiredOption("--stage <stage>", "A deployed stage").action(async (construct, key, options) => {
16438
+ try {
16439
+ const globalOptions = program.opts();
16440
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16441
+ const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-C7OGMve_.cjs"));
16442
+ await encryptionRetireCommand(construct, key, options);
16443
+ } catch (error) {
16444
+ console.error(formatError(error));
16445
+ process.exit(1);
16446
+ }
16447
+ });
16409
16448
  program.command("secrets:show").description("Show secrets for a stage").requiredOption("--stage <stage>", "Stage name").option("--reveal", "Show actual secret values (not masked)").action(async (options) => {
16410
16449
  try {
16411
16450
  const globalOptions = program.opts();
@@ -16451,7 +16490,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
16451
16490
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
16452
16491
  process.exit(1);
16453
16492
  }
16454
- const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-D9z2ymBW.cjs")).then((n) => n.workspace_exports);
16493
+ const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-vafrzZTC.cjs")).then((n) => n.workspace_exports);
16455
16494
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
16456
16495
  if (!result) {
16457
16496
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);