@geekmidas/cli 10.0.0-alpha.75 → 10.0.0-alpha.77

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 (157) hide show
  1. package/dist/{LegacyStateStore-BFnXUFlx.cjs → LegacyStateStore-DwngfJxr.cjs} +2 -2
  2. package/dist/{LegacyStateStore-BFnXUFlx.cjs.map → LegacyStateStore-DwngfJxr.cjs.map} +1 -1
  3. package/dist/{LegacyStateStore-cpt3K1vx.mjs → LegacyStateStore-dyq07_Ir.mjs} +2 -2
  4. package/dist/{LegacyStateStore-cpt3K1vx.mjs.map → LegacyStateStore-dyq07_Ir.mjs.map} +1 -1
  5. package/dist/{LocalStateStore-zQGZ9b4J.cjs → LocalStateStore-B0NCde8Z.cjs} +2 -2
  6. package/dist/{LocalStateStore-zQGZ9b4J.cjs.map → LocalStateStore-B0NCde8Z.cjs.map} +1 -1
  7. package/dist/{LocalStateStore-RH9F2ZEy.mjs → LocalStateStore-DLxCCatI.mjs} +2 -2
  8. package/dist/{LocalStateStore-RH9F2ZEy.mjs.map → LocalStateStore-DLxCCatI.mjs.map} +1 -1
  9. package/dist/{S3StateStore-CT-ZMlQY.cjs → S3StateStore-BOenb-3o.cjs} +2 -2
  10. package/dist/{S3StateStore-CT-ZMlQY.cjs.map → S3StateStore-BOenb-3o.cjs.map} +1 -1
  11. package/dist/{S3StateStore-DBeBc0c0.mjs → S3StateStore-CGK_4hlo.mjs} +2 -2
  12. package/dist/{S3StateStore-DBeBc0c0.mjs.map → S3StateStore-CGK_4hlo.mjs.map} +1 -1
  13. package/dist/{SSMStateStore-rnzNfOaV.mjs → SSMStateStore-B_5_RqY-.mjs} +2 -2
  14. package/dist/{SSMStateStore-rnzNfOaV.mjs.map → SSMStateStore-B_5_RqY-.mjs.map} +1 -1
  15. package/dist/{SSMStateStore-HmsH3c4v.cjs → SSMStateStore-DYeD__7p.cjs} +2 -2
  16. package/dist/{SSMStateStore-HmsH3c4v.cjs.map → SSMStateStore-DYeD__7p.cjs.map} +1 -1
  17. package/dist/{add-CHBin8TF.cjs → add-DCsgtvDk.cjs} +8 -8
  18. package/dist/{add-CHBin8TF.cjs.map → add-DCsgtvDk.cjs.map} +1 -1
  19. package/dist/{add-Cvzdw8cf.mjs → add-EPQO-_dt.mjs} +3 -3
  20. package/dist/{add-Cvzdw8cf.mjs.map → add-EPQO-_dt.mjs.map} +1 -1
  21. package/dist/{aws-DojzQnLd.mjs → aws-Bja4zGSs.mjs} +13 -9
  22. package/dist/aws-Bja4zGSs.mjs.map +1 -0
  23. package/dist/{aws-DkHdTV-p.cjs → aws-CQAuluiu.cjs} +13 -9
  24. package/dist/aws-CQAuluiu.cjs.map +1 -0
  25. package/dist/awsStore-7VmS_cZR.cjs +54 -0
  26. package/dist/awsStore-7VmS_cZR.cjs.map +1 -0
  27. package/dist/awsStore-B529csle.mjs +43 -0
  28. package/dist/awsStore-B529csle.mjs.map +1 -0
  29. package/dist/{bundler-_8AEZhrs.cjs → bundler-5spPyduN.cjs} +5 -5
  30. package/dist/bundler-5spPyduN.cjs.map +1 -0
  31. package/dist/{bundler-xjp5RwRS.mjs → bundler-DgO_EMVs.mjs} +5 -5
  32. package/dist/bundler-DgO_EMVs.mjs.map +1 -0
  33. package/dist/{cli-BTGfA0B7.mjs → cli-B74Ru-V1.mjs} +3 -3
  34. package/dist/{cli-BTGfA0B7.mjs.map → cli-B74Ru-V1.mjs.map} +1 -1
  35. package/dist/{cli-B4ktxAsM.cjs → cli-ZpFTMbGw.cjs} +4 -4
  36. package/dist/{cli-B4ktxAsM.cjs.map → cli-ZpFTMbGw.cjs.map} +1 -1
  37. package/dist/{compose-UKyv_1yU.cjs → compose-CePlrbUw.cjs} +68 -60
  38. package/dist/compose-CePlrbUw.cjs.map +1 -0
  39. package/dist/{compose-DdH2JQJD.mjs → compose-IUuxRW0J.mjs} +18 -10
  40. package/dist/compose-IUuxRW0J.mjs.map +1 -0
  41. package/dist/{config-DA0kRTQe.d.mts → config-Ckmoj56i.d.mts} +3 -3
  42. package/dist/{config-B38YWicj.d.cts.map → config-Ckmoj56i.d.mts.map} +1 -1
  43. package/dist/{config-B38YWicj.d.cts → config-aAeLXH86.d.cts} +3 -3
  44. package/dist/{config-DA0kRTQe.d.mts.map → config-aAeLXH86.d.cts.map} +1 -1
  45. package/dist/config.cjs +1 -1
  46. package/dist/config.d.cts +3 -3
  47. package/dist/config.d.mts +3 -3
  48. package/dist/config.mjs +1 -1
  49. package/dist/deploy/public.cjs +12 -12
  50. package/dist/deploy/public.d.cts +3 -3
  51. package/dist/deploy/public.d.cts.map +1 -1
  52. package/dist/deploy/public.d.mts +3 -3
  53. package/dist/deploy/public.d.mts.map +1 -1
  54. package/dist/deploy/public.mjs +6 -6
  55. package/dist/{deploy-CuSsiFIc.mjs → deploy-Q6X6RXRG.mjs} +5 -5
  56. package/dist/{deploy-CuSsiFIc.mjs.map → deploy-Q6X6RXRG.mjs.map} +1 -1
  57. package/dist/{deploy-XUZoA1us.cjs → deploy-XHXi-_tL.cjs} +11 -11
  58. package/dist/{deploy-XUZoA1us.cjs.map → deploy-XHXi-_tL.cjs.map} +1 -1
  59. package/dist/{dokploy-DZXTQX10.mjs → dokploy-BtP5XSrS.mjs} +2 -2
  60. package/dist/{dokploy-DZXTQX10.mjs.map → dokploy-BtP5XSrS.mjs.map} +1 -1
  61. package/dist/{dokploy-Cvgg_pID.cjs → dokploy-MSsPBO-t.cjs} +2 -2
  62. package/dist/{dokploy-Cvgg_pID.cjs.map → dokploy-MSsPBO-t.cjs.map} +1 -1
  63. package/dist/{encryption-JkeMPugf.mjs → encryption-D4Ykywfr.mjs} +3 -3
  64. package/dist/{encryption-JkeMPugf.mjs.map → encryption-D4Ykywfr.mjs.map} +1 -1
  65. package/dist/{encryption-w-Ehh9DW.cjs → encryption-DY0na43R.cjs} +6 -6
  66. package/dist/{encryption-w-Ehh9DW.cjs.map → encryption-DY0na43R.cjs.map} +1 -1
  67. package/dist/{engine-CmozkHxq.mjs → engine-BI2xjCKt.mjs} +9 -4
  68. package/dist/{engine-CmozkHxq.mjs.map → engine-BI2xjCKt.mjs.map} +1 -1
  69. package/dist/{engine-zpWBMsQq.cjs → engine-y53kE_3H.cjs} +73 -68
  70. package/dist/{engine-zpWBMsQq.cjs.map → engine-y53kE_3H.cjs.map} +1 -1
  71. package/dist/{github-BNngHoId.mjs → github-BBIqk1Jv.mjs} +6 -6
  72. package/dist/github-BBIqk1Jv.mjs.map +1 -0
  73. package/dist/{github-BGdJ-Lnm.cjs → github-Bmb45xUQ.cjs} +10 -10
  74. package/dist/github-Bmb45xUQ.cjs.map +1 -0
  75. package/dist/{index-vMidfqhU.d.cts → index-C7Tma2m1.d.cts} +2 -2
  76. package/dist/{index-B-1lLGzy.d.mts.map → index-C7Tma2m1.d.cts.map} +1 -1
  77. package/dist/{index-B-1lLGzy.d.mts → index-CNdSRwar.d.mts} +2 -2
  78. package/dist/{index-vMidfqhU.d.cts.map → index-CNdSRwar.d.mts.map} +1 -1
  79. package/dist/index.cjs +210 -221
  80. package/dist/index.cjs.map +1 -1
  81. package/dist/index.mjs +141 -152
  82. package/dist/index.mjs.map +1 -1
  83. package/dist/migrate-31JXUOaG.cjs +93 -0
  84. package/dist/migrate-31JXUOaG.cjs.map +1 -0
  85. package/dist/{migrate-BLL1RTAj.mjs → migrate-BUBsUiM3.mjs} +3 -3
  86. package/dist/{migrate-BLL1RTAj.mjs.map → migrate-BUBsUiM3.mjs.map} +1 -1
  87. package/dist/migrate-DWVl5PQK.mjs +93 -0
  88. package/dist/migrate-DWVl5PQK.mjs.map +1 -0
  89. package/dist/{migrate-CgjlYeun.cjs → migrate-sny0NjKe.cjs} +8 -8
  90. package/dist/{migrate-CgjlYeun.cjs.map → migrate-sny0NjKe.cjs.map} +1 -1
  91. package/dist/openapi.cjs +16 -6
  92. package/dist/openapi.cjs.map +1 -1
  93. package/dist/openapi.d.cts +1 -1
  94. package/dist/openapi.d.cts.map +1 -1
  95. package/dist/openapi.d.mts +1 -1
  96. package/dist/openapi.d.mts.map +1 -1
  97. package/dist/openapi.mjs +16 -6
  98. package/dist/openapi.mjs.map +1 -1
  99. package/dist/reconcile/public.d.cts +1 -1
  100. package/dist/reconcile/public.d.mts +1 -1
  101. package/dist/{resolve-DZNx7rLy.mjs → resolve-BF1ICosS.mjs} +3 -3
  102. package/dist/{resolve-DZNx7rLy.mjs.map → resolve-BF1ICosS.mjs.map} +1 -1
  103. package/dist/{resolve-fevXn-wZ.cjs → resolve-DokLtTUb.cjs} +3 -3
  104. package/dist/{resolve-fevXn-wZ.cjs.map → resolve-DokLtTUb.cjs.map} +1 -1
  105. package/dist/{rollback-Dw-FW3X2.cjs → rollback-CpOWRR9H.cjs} +7 -7
  106. package/dist/{rollback-Dw-FW3X2.cjs.map → rollback-CpOWRR9H.cjs.map} +1 -1
  107. package/dist/{rollback-CLi5Pln_.mjs → rollback-sg0ZhKGG.mjs} +5 -5
  108. package/dist/{rollback-CLi5Pln_.mjs.map → rollback-sg0ZhKGG.mjs.map} +1 -1
  109. package/dist/{runtime-BzZD5HHi.d.cts → runtime-B5bYom9w.d.mts} +2 -2
  110. package/dist/{runtime-BzZD5HHi.d.cts.map → runtime-B5bYom9w.d.mts.map} +1 -1
  111. package/dist/{runtime-Cm6J6L7n.d.mts → runtime-BozOkPtG.d.cts} +2 -2
  112. package/dist/{runtime-Cm6J6L7n.d.mts.map → runtime-BozOkPtG.d.cts.map} +1 -1
  113. package/dist/secretsManager-DUXW3fQt.cjs +70 -0
  114. package/dist/secretsManager-DUXW3fQt.cjs.map +1 -0
  115. package/dist/secretsManager-Ti0oZwsS.mjs +70 -0
  116. package/dist/secretsManager-Ti0oZwsS.mjs.map +1 -0
  117. package/dist/{sniffer-BmCvVyhq.mjs → sniffer-DR8AlRCk.mjs} +17 -17
  118. package/dist/sniffer-DR8AlRCk.mjs.map +1 -0
  119. package/dist/{sniffer-bMzrX4cO.cjs → sniffer-Y6GQOCXB.cjs} +17 -17
  120. package/dist/sniffer-Y6GQOCXB.cjs.map +1 -0
  121. package/dist/{state-BrWIOce_.mjs → stale-DGzpiN5S.mjs} +270 -45
  122. package/dist/stale-DGzpiN5S.mjs.map +1 -0
  123. package/dist/{state-kA4Fkufx.cjs → stale-yu2FkH3G.cjs} +293 -44
  124. package/dist/stale-yu2FkH3G.cjs.map +1 -0
  125. package/dist/target/public.cjs +1 -1
  126. package/dist/target/public.d.cts +2 -2
  127. package/dist/target/public.d.mts +2 -2
  128. package/dist/target/public.mjs +1 -1
  129. package/dist/{types-TzCChNrA.d.cts → types-B9yWJAis.d.mts} +59 -9
  130. package/dist/types-B9yWJAis.d.mts.map +1 -0
  131. package/dist/{types-Dp9lgx_S.d.mts → types-ct7pdQRf.d.cts} +60 -8
  132. package/dist/types-ct7pdQRf.d.cts.map +1 -0
  133. package/dist/workspace/index.cjs +1 -1
  134. package/dist/workspace/index.d.cts +2 -2
  135. package/dist/workspace/index.d.mts +2 -2
  136. package/dist/workspace/index.mjs +1 -1
  137. package/dist/{workspace-vdrcRI-m.cjs → workspace-DOm81oUo.cjs} +54 -1
  138. package/dist/workspace-DOm81oUo.cjs.map +1 -0
  139. package/dist/{workspace-C7NqCsQF.mjs → workspace-QUTqYmVy.mjs} +43 -2
  140. package/dist/workspace-QUTqYmVy.mjs.map +1 -0
  141. package/package.json +16 -15
  142. package/dist/aws-DkHdTV-p.cjs.map +0 -1
  143. package/dist/aws-DojzQnLd.mjs.map +0 -1
  144. package/dist/bundler-_8AEZhrs.cjs.map +0 -1
  145. package/dist/bundler-xjp5RwRS.mjs.map +0 -1
  146. package/dist/compose-DdH2JQJD.mjs.map +0 -1
  147. package/dist/compose-UKyv_1yU.cjs.map +0 -1
  148. package/dist/github-BGdJ-Lnm.cjs.map +0 -1
  149. package/dist/github-BNngHoId.mjs.map +0 -1
  150. package/dist/sniffer-BmCvVyhq.mjs.map +0 -1
  151. package/dist/sniffer-bMzrX4cO.cjs.map +0 -1
  152. package/dist/state-BrWIOce_.mjs.map +0 -1
  153. package/dist/state-kA4Fkufx.cjs.map +0 -1
  154. package/dist/types-Dp9lgx_S.d.mts.map +0 -1
  155. package/dist/types-TzCChNrA.d.cts.map +0 -1
  156. package/dist/workspace-C7NqCsQF.mjs.map +0 -1
  157. package/dist/workspace-vdrcRI-m.cjs.map +0 -1
@@ -2,10 +2,10 @@ import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mjs";
2
2
  import { i as run$1, s as gkmHome } from "./run-BJLIerMM.mjs";
3
3
  import { d as output, r as discover, u as ConstructGenerator } from "./discover-BPelzeGW.mjs";
4
4
  import { t as appKey } from "./derive-B4vDpzgP.mjs";
5
- import { O as TEST_STAGE, h as getPublicEnvPrefix, n as allConstructGlobs } from "./workspace-C7NqCsQF.mjs";
5
+ import { F as UnknownSecretsStoreProvider, O as TEST_STAGE, h as getPublicEnvPrefix, m as PUBLIC_ENV_PREFIXES, n as allConstructGlobs } from "./workspace-QUTqYmVy.mjs";
6
6
  import { ConfigNotFound, NotInAnApp, loadWorkspaceAppInfo, loadWorkspaceConfig } from "./config.mjs";
7
7
  import { n as runtimeFor, r as generateTelemetryModule } from "./EndpointGenerator-DftalLYg.mjs";
8
- import { c as runtimeOf } from "./resolve-DZNx7rLy.mjs";
8
+ import { c as runtimeOf } from "./resolve-BF1ICosS.mjs";
9
9
  import { a as DEFAULT_STORAGE, i as DEFAULT_EVENTS$1, n as readFakes, o as holdsEveryCache, r as DEFAULT_CACHE, t as SubscriberGenerator } from "./SubscriberGenerator-5looQ3gB.mjs";
10
10
  import { basename, dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
11
11
  import { constants, existsSync, readFileSync } from "node:fs";
@@ -91,10 +91,6 @@ function toEmbeddableSecrets(secrets) {
91
91
  AWS_SECRET_ACCESS_KEY: secrets.services.localstack.password,
92
92
  AWS_REGION: secrets.services.localstack.region ?? "us-east-1",
93
93
  AWS_ENDPOINT_URL: `http://${secrets.services.localstack.host}:${secrets.services.localstack.port}`
94
- },
95
- ...secrets.services.pgboss && {
96
- PGBOSS_DB_USER: secrets.services.pgboss.username,
97
- PGBOSS_DB_PASSWORD: secrets.services.pgboss.password
98
94
  }
99
95
  };
100
96
  }
@@ -527,7 +523,8 @@ function decrypt(data, keyHex) {
527
523
  var store_exports = /* @__PURE__ */ __exportAll({
528
524
  FileSecretsStore: () => FileSecretsStore,
529
525
  isRemoteStore: () => isRemoteStore,
530
- secretsStoreFor: () => secretsStoreFor
526
+ secretsStoreFor: () => secretsStoreFor,
527
+ storeFromConfig: () => storeFromConfig
531
528
  });
532
529
  /**
533
530
  * The store a stage's secrets are kept in — what every command reads and
@@ -539,13 +536,41 @@ var store_exports = /* @__PURE__ */ __exportAll({
539
536
  async function secretsStoreFor(workspace, stage, options = {}) {
540
537
  const configured = workspace.secrets.store ?? "file";
541
538
  if (stage === workspace.stages.local || configured === "file") return new FileSecretsStore(workspace.root, keystoreProject(workspace, options.home));
542
- if (configured.provider !== "ssm") return configured.provider;
543
- const { AwsSecretsStore } = await import("./aws-DojzQnLd.mjs");
544
- return new AwsSecretsStore({
545
- project: workspace.name,
546
- region: configured.region,
547
- ...options.profile ? { profile: options.profile } : {}
548
- });
539
+ return storeFromConfig(workspace, configured, options);
540
+ }
541
+ /**
542
+ * The store a `secrets.store` value describes, for any stage — what
543
+ * {@link secretsStoreFor} answers for a deployed stage, and what
544
+ * `gkm secrets:migrate` builds for the store it copies to.
545
+ */
546
+ async function storeFromConfig(workspace, config, options = {}) {
547
+ if (config === "file") return new FileSecretsStore(workspace.root, keystoreProject(workspace, options.home));
548
+ const profile = options.profile ? { profile: options.profile } : {};
549
+ switch (config.provider) {
550
+ case "ssm": {
551
+ const { AwsSecretsStore } = await import("./aws-Bja4zGSs.mjs");
552
+ return new AwsSecretsStore({
553
+ project: workspace.name,
554
+ region: config.region,
555
+ ...profile
556
+ });
557
+ }
558
+ case "secrets-manager": {
559
+ const { kmsKeyId } = config;
560
+ const { SecretsManagerSecretsStore } = await import("./secretsManager-Ti0oZwsS.mjs");
561
+ return new SecretsManagerSecretsStore({
562
+ project: workspace.name,
563
+ region: config.region,
564
+ ...kmsKeyId ? { kmsKeyId } : {},
565
+ ...profile
566
+ });
567
+ }
568
+ default: {
569
+ const provider = config.provider;
570
+ if (typeof provider === "object" && provider !== null) return provider;
571
+ throw new UnknownSecretsStoreProvider(provider);
572
+ }
573
+ }
549
574
  }
550
575
  /** Whether a stage's secrets live somewhere other than this machine. */
551
576
  function isRemoteStore(workspace, stage) {
@@ -632,24 +657,18 @@ async function savePortState(workspaceRoot, ports) {
632
657
  await writeFile(join(workspaceRoot, PORT_STATE_PATH), `${JSON.stringify(ports, null, 2)}\n`);
633
658
  }
634
659
  /**
635
- * Load and flatten secrets for an app from encrypted storage.
636
- * For workspace app: maps {APP}_DATABASE_URL → DATABASE_URL.
660
+ * Load and flatten a stage's secrets from its store.
661
+ *
662
+ * Every key as stored — nothing renamed. An app's database URL is its
663
+ * construct's key, derived by reconcile, and never a stored per-app value
664
+ * mapped onto `DATABASE_URL`.
637
665
  * @internal Exported for testing
638
666
  */
639
- async function loadSecretsForApp(store, stage, appName) {
640
- let secrets = {};
667
+ async function loadSecretsForApp(store, stage) {
641
668
  const stageSecrets = await store.read(stage);
642
- if (stageSecrets) {
643
- logger$1.log(`🔐 Loading secrets from stage: ${stage}`);
644
- secrets = toEmbeddableSecrets(stageSecrets);
645
- }
646
- if (Object.keys(secrets).length === 0) return {};
647
- if (!appName) return secrets;
648
- const prefix = appName.toUpperCase();
649
- const mapped = { ...secrets };
650
- const appDbUrl = secrets[`${prefix}_DATABASE_URL`];
651
- if (appDbUrl) mapped.DATABASE_URL = appDbUrl;
652
- return mapped;
669
+ if (!stageSecrets) return {};
670
+ logger$1.log(`🔐 Loading secrets from stage: ${stage}`);
671
+ return toEmbeddableSecrets(stageSecrets);
653
672
  }
654
673
  /**
655
674
  * Walk up the directory tree to find the root containing .gkm/secrets/.
@@ -757,7 +776,7 @@ async function prepareEntryCredentials(options) {
757
776
  const resolvedPort = options.explicitPort ?? workspaceAppPort ?? 3e3;
758
777
  const stage = options.stage ?? workspace?.stages.local;
759
778
  const store = stage ? workspace ? await secretsStoreFor(workspace, stage) : new FileSecretsStore(secretsRoot) : void 0;
760
- const credentials = store && stage ? await loadSecretsForApp(store, stage, appName) : {};
779
+ const credentials = store && stage ? await loadSecretsForApp(store, stage) : {};
761
780
  credentials.PORT = String(resolvedPort);
762
781
  if (appInfo?.app.type === "mobile") credentials.RCT_METRO_PORT = String(resolvedPort);
763
782
  const declaredKeys = [];
@@ -1022,6 +1041,36 @@ function eventsBackendFor(on) {
1022
1041
  return DEFAULT_EVENTS$1[on];
1023
1042
  }
1024
1043
  //#endregion
1044
+ //#region src/exec/imageBuild.ts
1045
+ /**
1046
+ * Set by a site's Dockerfile in its builder stage: this process is building
1047
+ * an image.
1048
+ *
1049
+ * Inside an image there is no stage to load secrets for and no local
1050
+ * container to resolve an address from — the public URLs the bundle inlines
1051
+ * arrived as the Dockerfile's build args, already in the environment. So
1052
+ * `gkm exec -- next build` there injects exactly those, and never the
1053
+ * `localhost` addresses a workspace resolves on a developer's machine.
1054
+ */
1055
+ const IMAGE_BUILD_ENV = "GKM_IMAGE_BUILD";
1056
+ /** Whether this process is building an image. */
1057
+ function isImageBuild(env = process.env) {
1058
+ return env[IMAGE_BUILD_ENV] === "1";
1059
+ }
1060
+ /**
1061
+ * What `gkm exec` injects inside an image build: the public values its build
1062
+ * args set — every `NEXT_PUBLIC_*`, `VITE_*` and `EXPO_PUBLIC_*` — and
1063
+ * nothing read from a secrets store, a file or a container.
1064
+ */
1065
+ function imageBuildCredentials(env = process.env) {
1066
+ const credentials = {};
1067
+ for (const [key, value] of Object.entries(env)) {
1068
+ if (value === void 0) continue;
1069
+ if (PUBLIC_ENV_PREFIXES.some((prefix) => key.startsWith(prefix))) credentials[key] = value;
1070
+ }
1071
+ return credentials;
1072
+ }
1073
+ //#endregion
1025
1074
  //#region src/docker/templates.ts
1026
1075
  /**
1027
1076
  * The turbo every image prunes and builds with when the build root resolves
@@ -1319,7 +1368,48 @@ function binPath(options) {
1319
1368
  * were installed.
1320
1369
  */
1321
1370
  function gkmCommand(args) {
1322
- return `GKM_BIN="$(node -e 'let d=process.cwd();const{existsSync:e}=require("fs"),{dirname:u,join:j}=require("path");for(;;){const p=j(d,"node_modules/@geekmidas/cli/bin/gkm.mjs");if(e(p)){console.log(p);break}if(u(d)===d){console.error("@geekmidas/cli is not installed where the app can resolve it");process.exit(1)}d=u(d)}')" && node "$GKM_BIN" ${args}`;
1371
+ return `GKM_BIN="$(node -e '${FIND_GKM_BIN}')" && node "$GKM_BIN" ${args}`;
1372
+ }
1373
+ /** Prints the `bin/gkm.mjs` Node resolves from the cwd, or fails saying so. */
1374
+ const FIND_GKM_BIN = `let d=process.cwd();const{existsSync:e}=require("fs"),{dirname:u,join:j}=require("path");for(;;){const p=j(d,"node_modules/@geekmidas/cli/bin/gkm.mjs");if(e(p)){console.log(p);break}if(u(d)===d){console.error("@geekmidas/cli is not installed where the app can resolve it");process.exit(1)}d=u(d)}`;
1375
+ /**
1376
+ * What a site's builder does with the gkm workspace it carries, before its
1377
+ * framework builds it — all of it inside the image, nothing from the host:
1378
+ *
1379
+ * - `gkm` on the PATH: the CLI the workspace installs, so a build script that
1380
+ * is `gkm exec -- next build` runs. Resolved from the gkm root rather than
1381
+ * through `node_modules/.bin`, where a CLI that is a workspace package has
1382
+ * no bin linked.
1383
+ * - `GKM_IMAGE_BUILD`, which has `gkm exec` inject the build args above — the
1384
+ * stage's public URLs — and never load a secret or resolve a local address.
1385
+ * - each backend's typed client, generated from its endpoints at the
1386
+ * workspace root's `.gkm/client/`, where the site's tsconfig paths point.
1387
+ */
1388
+ function siteWorkspaceSteps(options) {
1389
+ const { gkmRoot } = layout(options);
1390
+ const root = `/app/${gkmRoot}`.replace(/\/\.$/, "");
1391
+ const clients = options.clients ?? [];
1392
+ const generate = clients.length ? `
1393
+
1394
+ # The typed client of each API this site calls, generated from its endpoints
1395
+ # into ${gkmRoot === "." ? "" : `${gkmRoot}/`}.gkm/client/ — offline, with no secret and no container.
1396
+ RUN ${clients.map(({ app, path }) => `cd /app/${path} && gkm openapi --app ${app}`).join(" && \\\n ")}` : "";
1397
+ return `# The gkm CLI the workspace installs, as \`gkm\`
1398
+ RUN cd ${root} && GKM_BIN="$(node -e '${FIND_GKM_BIN}')" && \\
1399
+ { echo '#!/bin/sh'; echo "exec node \\"$GKM_BIN\\" \\"\\$@\\""; } > /usr/local/bin/gkm && \\
1400
+ chmod +x /usr/local/bin/gkm
1401
+
1402
+ # \`gkm exec\` in this build injects the build args, never a stage's secrets
1403
+ ENV ${IMAGE_BUILD_ENV}=1${generate}`;
1404
+ }
1405
+ /**
1406
+ * Build the site with turbo. Loose env mode, so the task sees what the
1407
+ * Dockerfile set — the build args and `GKM_IMAGE_BUILD` — whatever the
1408
+ * project's turbo.json declares: the image's environment holds nothing else.
1409
+ */
1410
+ function siteBuild(options) {
1411
+ const { turbo } = layout(options);
1412
+ return `RUN ${turbo} run build --filter='${options.turboPackage}' --env-mode=loose`;
1323
1413
  }
1324
1414
  /**
1325
1415
  * The encrypted credentials, from a build secret — never an ARG, which is
@@ -1473,8 +1563,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\
1473
1563
  * @internal Exported for testing
1474
1564
  */
1475
1565
  function generateNextjsDockerfile(options) {
1476
- const { port, appPath, turboPackage, publicUrlArgs = ["NEXT_PUBLIC_API_URL", "NEXT_PUBLIC_AUTH_URL"] } = options;
1477
- const { turbo } = layout(options);
1566
+ const { port, appPath, publicUrlArgs = ["NEXT_PUBLIC_API_URL", "NEXT_PUBLIC_AUTH_URL"] } = options;
1478
1567
  return `# syntax=docker/dockerfile:1
1479
1568
  # Next.js standalone Dockerfile, built from a turbo-pruned slice
1480
1569
 
@@ -1484,13 +1573,15 @@ ${depsStage(options)}
1484
1573
 
1485
1574
  ${builderStage(options, { args: publicUrlArgs })}
1486
1575
 
1576
+ ${siteWorkspaceSteps(options)}
1577
+
1487
1578
  # Ensure public directory exists (may be empty for scaffolded projects)
1488
1579
  RUN mkdir -p ${appPath}/public
1489
1580
 
1490
1581
  ENV NEXT_TELEMETRY_DISABLED=1
1491
1582
 
1492
1583
  # Build the application
1493
- RUN ${turbo} run build --filter='${turboPackage}'
1584
+ ${siteBuild(options)}
1494
1585
 
1495
1586
  # The runner needs the standalone server; without it there is nothing to run.
1496
1587
  RUN if [ ! -d ${appPath}/.next/standalone ]; then \\
@@ -1678,8 +1769,7 @@ CMD ["node", "index.mjs"]
1678
1769
  * @internal Exported for testing
1679
1770
  */
1680
1771
  function generateNodeWebDockerfile(options) {
1681
- const { port, appPath, turboPackage } = options;
1682
- const { turbo } = layout(options);
1772
+ const { port, appPath } = options;
1683
1773
  return `# syntax=docker/dockerfile:1
1684
1774
  # Node SSR web Dockerfile (TanStack Start / Remix), from a turbo-pruned slice
1685
1775
 
@@ -1688,7 +1778,10 @@ ${prunerStage(options)}
1688
1778
  ${depsStage(options)}
1689
1779
 
1690
1780
  ${builderStage(options, { args: options.publicUrlArgs ?? [] })}
1691
- RUN ${turbo} run build --filter='${turboPackage}'
1781
+
1782
+ ${siteWorkspaceSteps(options)}
1783
+
1784
+ ${siteBuild(options)}
1692
1785
 
1693
1786
  FROM ${options.baseImage} AS runner
1694
1787
  WORKDIR /app
@@ -1722,8 +1815,7 @@ CMD ["sh", "-c", "cd ${appPath} && npm start"]
1722
1815
  * @internal Exported for testing
1723
1816
  */
1724
1817
  function generateViteStaticDockerfile(options) {
1725
- const { port, appPath, turboPackage } = options;
1726
- const { turbo } = layout(options);
1818
+ const { port, appPath } = options;
1727
1819
  return `# syntax=docker/dockerfile:1
1728
1820
  # Vite SPA Dockerfile — a turbo-pruned slice built to static files, served by Caddy
1729
1821
 
@@ -1732,7 +1824,10 @@ ${prunerStage(options)}
1732
1824
  ${depsStage(options)}
1733
1825
 
1734
1826
  ${builderStage(options, { args: options.publicUrlArgs ?? [] })}
1735
- RUN ${turbo} run build --filter='${turboPackage}'
1827
+
1828
+ ${siteWorkspaceSteps(options)}
1829
+
1830
+ ${siteBuild(options)}
1736
1831
 
1737
1832
  FROM ${STATIC_SITE_IMAGE} AS runner
1738
1833
 
@@ -1841,7 +1936,7 @@ function fromBuildRoot(layout, path) {
1841
1936
  return joined === "" ? "." : joined;
1842
1937
  }
1843
1938
  /** Everything a template needs about one app, relative to the build root. */
1844
- function appImageOptions(layout, appName, app, workspaceRoot) {
1939
+ function appImageOptions(layout, appName, app, workspaceRoot, apps = {}) {
1845
1940
  const turboPackage = packageName(isAbsolute(app.path) ? app.path : join(workspaceRoot, app.path)) ?? appName;
1846
1941
  return {
1847
1942
  imageName: appName,
@@ -1857,10 +1952,49 @@ function appImageOptions(layout, appName, app, workspaceRoot) {
1857
1952
  ...app.type === "backend" ? {
1858
1953
  gkmPaths: layout.gkmPaths,
1859
1954
  ...layout.workspacePackage && layout.workspacePackage !== turboPackage ? { prunePackages: [layout.workspacePackage] } : {}
1860
- } : {}
1955
+ } : app.type === "web" ? siteWorkspace(layout, app, apps, workspaceRoot, turboPackage) : {}
1861
1956
  };
1862
1957
  }
1863
1958
  /**
1959
+ * What a site's image carries of the gkm workspace: its config and construct
1960
+ * directories, the workspace's own package where it is nested in a monorepo
1961
+ * (it holds the CLI), and each backend the site calls — whose endpoints its
1962
+ * client is generated from, and whose package their imports resolve in.
1963
+ */
1964
+ function siteWorkspace(layout, site, apps, workspaceRoot, turboPackage) {
1965
+ const clients = siteClients(site, apps);
1966
+ const packages = /* @__PURE__ */ new Set();
1967
+ if (layout.workspacePackage) packages.add(layout.workspacePackage);
1968
+ for (const { app } of clients) {
1969
+ const backend = apps[app];
1970
+ const name = packageName(isAbsolute(backend.path) ? backend.path : join(workspaceRoot, backend.path));
1971
+ if (name) packages.add(name);
1972
+ }
1973
+ packages.delete(turboPackage);
1974
+ return {
1975
+ gkmPaths: layout.gkmPaths,
1976
+ ...packages.size > 0 ? { prunePackages: [...packages].sort() } : {},
1977
+ ...clients.length > 0 ? { clients: clients.map(({ app }) => ({
1978
+ app,
1979
+ path: fromBuildRoot(layout, apps[app].path)
1980
+ })) } : {}
1981
+ };
1982
+ }
1983
+ /**
1984
+ * The backends whose clients a site imports: each it depends on that gkm
1985
+ * builds from endpoints — not one with an entry of its own, and not one that
1986
+ * turned OpenAPI off.
1987
+ */
1988
+ function siteClients(site, apps) {
1989
+ return site.dependencies.filter((name) => {
1990
+ const app = apps[name];
1991
+ if (!app || app.type !== "backend" || app.entry) return false;
1992
+ if (app.openapi === false) return false;
1993
+ if (typeof app.openapi === "object" && app.openapi.enabled === false) return false;
1994
+ return true;
1995
+ }).sort().map((app) => ({ app }));
1996
+ }
1997
+ /**
1864
1998
  * The directories the workspace's construct globs start in, relative to its
1865
1999
  * root: `./constructs/**\/*.ts` reads from `constructs`.
1866
2000
  */
@@ -5883,6 +6017,7 @@ async function workspaceDockerCommand(workspace, manifest, imageNames = {}, back
5883
6017
  const dockerfile = appDockerfile(appName, app, {
5884
6018
  layout,
5885
6019
  workspaceRoot: workspace.root,
6020
+ apps: workspace.apps,
5886
6021
  ...manifest ? { manifest } : {}
5887
6022
  });
5888
6023
  const path = dockerfileOf(appName, app.path);
@@ -5938,7 +6073,7 @@ async function workspaceDockerCommand(workspace, manifest, imageNames = {}, back
5938
6073
  * framework. The one choice every builder of images makes.
5939
6074
  */
5940
6075
  function appDockerfile(appName, app, options) {
5941
- const image = appImageOptions(options.layout, appName, app, options.workspaceRoot);
6076
+ const image = appImageOptions(options.layout, appName, app, options.workspaceRoot, options.apps);
5942
6077
  if (app.type === "web") return siteDockerfile(appName, app, {
5943
6078
  image,
5944
6079
  ...options.manifest ? { manifest: options.manifest } : {},
@@ -6352,6 +6487,96 @@ function setPostgresBackupId(state, backupId) {
6352
6487
  if (state.backups) state.backups.postgresBackupId = backupId;
6353
6488
  }
6354
6489
  //#endregion
6355
- export { LOCAL_CA_PATH as $, imageRef as $t, ExternalServicesNotConfigured as A, DEFAULT_IMAGES as At, suppliedOnly as B, loadSecretsForApp as Bt, NoDomainForStage as C, WORKER_PORT as Ct, otelEnv as D, eventsBackendFor as Dt, isOtlpDestination as E, cacheBackendFor as Et, externalServices as F, createCredentialsPreload as Ft, QueueGenerator as G, FileSecretsStore as Gt, WorkerGenerator as H, isRemoteStore as Ht, manifestServiceDeclarations as I, createEntryWrapper as It, backendsOf as J, projectKey as Jt, CronGenerator as K, getKeyPath as Kt, parseDevServices as L, findAvailablePort as Lt, UnknownDevService as M, fakeKey as Mt, assertExternalServices as N, portKeys as Nt, DEV_SERVICES as O, providerOf as Ot, devServicesUsed as P, primaryPortKey as Pt, workspace_exports as Q, imageName as Qt, reportDevServices as R, isPortAvailable as Rt, validateImageRef as S, TURBO_VERSION as St, resolveHost as T, findBuildRoot as Tt, workerBundleName as U, secretsStoreFor as Ut, workerUnits as V, prepareEntryCredentials as Vt, workerEntryDir as W, store_exports as Wt, derivedContainers as X, applicationName as Xt, constructGlobs as Y, readKey as Yt, reconcileWorkspace as Z, deployIdentity as Zt, appDockerfile as _, planFor as _t, recordRelease as a, maskPassword as an, postgresDatabaseNames as at, workerDockerfile as b, composeBuildPaths as bt, setBackupState as c, withCustomSecret as cn, composeFor as ct, setGeneratedSecret as d, appEnvKeys as dt, isOwnedBy as en, forgetState as et, setPostgresBackupId as f, dockerfileOf as ft, DockerPushFailed as g, localRolePassword as gt, DockerBuildFailed as h, envFor as ht, isDnsVerified as i, initStageSecrets as in, bucketPolicies as it, STORAGE_KEY_PAIR as j, describeServices as jt, DevServicesNeedServerTarget as k, storageBackendFor as kt, setDnsRecord as l, bucketClient as lt, withGeneratedSecrets as m, workerEnvKeys as mt, getBackupState as n, ownershipMarker as nn, applyPolicies as nt, recordRollback as o, storage_exports as on, postgresStatements as ot, DeployJournal as p, networkEnv as pt, FAKE_ENV as q, keystoreProject as qt, getGeneratedSecret as r, projectName as rn, applyPostgres as rt, setApplicationId as s, toEmbeddableSecrets as sn, quoteIdentifier as st, createEmptyState as t, markerOf as tn, applyBuckets as tt, setDnsVerification as u, pgClient as ut, dockerCommand as v, resourceName as vt, isMainFrontendApp as w, detectPackageManager as wt, workerDockerfileOf as x, imageLayout as xt, ensureDockerignore as y, hostFor as yt, requiredStageKeys as z, loadEnvFiles as zt };
6490
+ //#region src/secrets/stale.ts
6491
+ /**
6492
+ * Stored secrets an older gkm generated that now shadow a derived value.
6493
+ *
6494
+ * Before constructs, initialising a stage wrote an address for each app into
6495
+ * its custom secrets: `<APP>_DATABASE_URL` as a `postgresql://…@localhost`
6496
+ * URL with a password of its own, and `http://localhost:<port>` for a site or
6497
+ * an auth server. Those keys are now a construct's — `database.schema('AuthDatabase')`
6498
+ * provides `AUTH_DATABASE_URL`, `new BetterAuth('Auth')` provides `AUTH_URL`
6499
+ * — and a deploy derives them. A value the stage holds is a value set by hand,
6500
+ * and set by hand wins: the container is handed `localhost`, where nothing
6501
+ * answers, with a password no role has.
6502
+ *
6503
+ * So a deploy refuses such a stage rather than run it, naming each key and
6504
+ * the command that removes it. Nothing is deleted for the user: the value is
6505
+ * theirs, and only they can say it is stale. A URL that names a real host — a
6506
+ * managed database — is a deliberate choice and still wins.
6507
+ */
6508
+ /** The kinds whose URL an older gkm wrote into a stage's secrets. */
6509
+ const ADDRESSED = /* @__PURE__ */ new Set([
6510
+ "database",
6511
+ "database-reader",
6512
+ "database-schema",
6513
+ "rest-api",
6514
+ "site"
6515
+ ]);
6516
+ /** Hosts that are this machine — never anything, inside a container. */
6517
+ const LOOPBACK = /* @__PURE__ */ new Set([
6518
+ "localhost",
6519
+ "127.0.0.1",
6520
+ "[::1]",
6521
+ "::1"
6522
+ ]);
6523
+ /**
6524
+ * A stage holds a construct's address as a custom secret, pointing at
6525
+ * `localhost` — what an older `gkm secrets:init`, `gkm setup` or `gkm init`
6526
+ * generated. Set by hand wins over derived, so the app would be handed it.
6527
+ */
6528
+ var StaleStageSecrets = class extends Error {
6529
+ stage;
6530
+ stale;
6531
+ constructor(stage, stale) {
6532
+ const one = stale.length === 1;
6533
+ super(`The stage '${stage}' holds ${one ? "a value" : "values"} an older gkm generated for ${one ? "an address a construct" : "addresses constructs"} now ${one ? "provides" : "provide"}:\n` + stale.map((s) => ` ${s.key}: ${s.construct}'s, stored pointing at ${s.host}`).join("\n") + `
6534
+ A stored value wins over the derived one, so the app would be handed an address where nothing answers inside its container. Remove ${one ? "it" : "each"}, and the construct's own value is used:\n` + stale.map((s) => ` gkm secrets:unset ${s.key} --stage ${stage}`).join("\n") + "\nA managed service set with its real host is not affected.");
6535
+ this.stage = stage;
6536
+ this.stale = stale;
6537
+ this.name = "StaleStageSecrets";
6538
+ }
6539
+ };
6540
+ /** The host a stored value names, if it is a URL. */
6541
+ function hostOf(value) {
6542
+ try {
6543
+ return new URL(value).hostname;
6544
+ } catch {
6545
+ return;
6546
+ }
6547
+ }
6548
+ /**
6549
+ * Each stored key that a construct provides an address for, holding an
6550
+ * address on this machine.
6551
+ */
6552
+ function staleStageSecrets(manifest, supplied) {
6553
+ const stale = [];
6554
+ for (const [id, declaration] of Object.entries(manifest)) {
6555
+ if (!ADDRESSED.has(declaration.kind)) continue;
6556
+ const key = providedKeyFor(id, declaration.kind, "url");
6557
+ const value = supplied[key];
6558
+ if (value === void 0) continue;
6559
+ const host = hostOf(value);
6560
+ if (host === void 0 || !LOOPBACK.has(host)) continue;
6561
+ stale.push({
6562
+ key,
6563
+ construct: id,
6564
+ host
6565
+ });
6566
+ }
6567
+ return stale.sort((a, b) => a.key.localeCompare(b.key));
6568
+ }
6569
+ /**
6570
+ * Refuse a stage whose stored secrets would shadow a construct's address with
6571
+ * `localhost`.
6572
+ *
6573
+ * @throws {StaleStageSecrets} naming each key and the command removing it
6574
+ */
6575
+ function assertNoStaleSecrets(options) {
6576
+ const stale = staleStageSecrets(options.manifest, options.supplied);
6577
+ if (stale.length > 0) throw new StaleStageSecrets(options.stage, stale);
6578
+ }
6579
+ //#endregion
6580
+ export { workspace_exports as $, readKey as $t, DevServicesNeedServerTarget as A, eventsBackendFor as At, requiredStageKeys as B, findAvailablePort as Bt, validateImageRef as C, TURBO_VERSION as Ct, isOtlpDestination as D, imageBuildCredentials as Dt, resolveHost as E, findBuildRoot as Et, devServicesUsed as F, fakeKey as Ft, workerEntryDir as G, isRemoteStore as Gt, workerUnits as H, loadEnvFiles as Ht, externalServices as I, portKeys as It, FAKE_ENV as J, store_exports as Jt, QueueGenerator as K, secretsStoreFor as Kt, manifestServiceDeclarations as L, primaryPortKey as Lt, STORAGE_KEY_PAIR as M, storageBackendFor as Mt, UnknownDevService as N, DEFAULT_IMAGES as Nt, otelEnv as O, isImageBuild as Ot, assertExternalServices as P, describeServices as Pt, reconcileWorkspace as Q, projectKey as Qt, parseDevServices as R, createCredentialsPreload as Rt, workerDockerfileOf as S, imageLayout as St, isMainFrontendApp as T, detectPackageManager as Tt, WorkerGenerator as U, loadSecretsForApp as Ut, suppliedOnly as V, isPortAvailable as Vt, workerBundleName as W, prepareEntryCredentials as Wt, constructGlobs as X, getKeyPath as Xt, backendsOf as Y, FileSecretsStore as Yt, derivedContainers as Z, keystoreProject as Zt, DockerPushFailed as _, localRolePassword as _t, isDnsVerified as a, markerOf as an, bucketPolicies as at, ensureDockerignore as b, hostFor as bt, setApplicationId as c, initStageSecrets as cn, quoteIdentifier as ct, setDnsVerification as d, toEmbeddableSecrets as dn, pgClient as dt, applicationName as en, LOCAL_CA_PATH as et, setGeneratedSecret as f, withCustomSecret as fn, appEnvKeys as ft, DockerBuildFailed as g, envFor as gt, withGeneratedSecrets as h, workerEnvKeys as ht, getGeneratedSecret as i, isOwnedBy as in, applyPostgres as it, ExternalServicesNotConfigured as j, providerOf as jt, DEV_SERVICES as k, cacheBackendFor as kt, setBackupState as l, maskPassword as ln, composeFor as lt, DeployJournal as m, networkEnv as mt, createEmptyState as n, imageName as nn, applyBuckets as nt, recordRelease as o, ownershipMarker as on, postgresDatabaseNames as ot, setPostgresBackupId as p, dockerfileOf as pt, CronGenerator as q, storeFromConfig as qt, getBackupState as r, imageRef as rn, applyPolicies as rt, recordRollback as s, projectName as sn, postgresStatements as st, assertNoStaleSecrets as t, deployIdentity as tn, forgetState as tt, setDnsRecord as u, storage_exports as un, bucketClient as ut, appDockerfile as v, planFor as vt, NoDomainForStage as w, WORKER_PORT as wt, workerDockerfile as x, composeBuildPaths as xt, dockerCommand as y, resourceName as yt, reportDevServices as z, createEntryWrapper as zt };
6356
6581
 
6357
- //# sourceMappingURL=state-BrWIOce_.mjs.map
6582
+ //# sourceMappingURL=stale-DGzpiN5S.mjs.map