@geekmidas/cli 10.0.0-alpha.88 → 10.0.0-alpha.89

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 (176) hide show
  1. package/dist/GoDaddyProvider--36rw8cP.mjs +387 -0
  2. package/dist/GoDaddyProvider--36rw8cP.mjs.map +1 -0
  3. package/dist/GoDaddyProvider-DnRor066.cjs +387 -0
  4. package/dist/GoDaddyProvider-DnRor066.cjs.map +1 -0
  5. package/dist/{HostingerProvider-CVc3rLPB.mjs → HostingerProvider-BI6J7oJr.mjs} +2 -2
  6. package/dist/{HostingerProvider-CVc3rLPB.mjs.map → HostingerProvider-BI6J7oJr.mjs.map} +1 -1
  7. package/dist/{HostingerProvider-BCB1QJj1.cjs → HostingerProvider-CyTpG_jy.cjs} +2 -2
  8. package/dist/{HostingerProvider-BCB1QJj1.cjs.map → HostingerProvider-CyTpG_jy.cjs.map} +1 -1
  9. package/dist/{LegacyStateStore-CWG_HVC0.cjs → LegacyStateStore-BaBoYl59.cjs} +2 -2
  10. package/dist/{LegacyStateStore-CWG_HVC0.cjs.map → LegacyStateStore-BaBoYl59.cjs.map} +1 -1
  11. package/dist/{LegacyStateStore-B0R4LlX_.mjs → LegacyStateStore-CO7bzJCU.mjs} +2 -2
  12. package/dist/{LegacyStateStore-B0R4LlX_.mjs.map → LegacyStateStore-CO7bzJCU.mjs.map} +1 -1
  13. package/dist/{LocalStateStore-CLwa2DpK.cjs → LocalStateStore-CUWh2BWU.cjs} +2 -2
  14. package/dist/{LocalStateStore-CLwa2DpK.cjs.map → LocalStateStore-CUWh2BWU.cjs.map} +1 -1
  15. package/dist/{LocalStateStore-Q4vXg2ua.mjs → LocalStateStore-C_hYDv6I.mjs} +2 -2
  16. package/dist/{LocalStateStore-Q4vXg2ua.mjs.map → LocalStateStore-C_hYDv6I.mjs.map} +1 -1
  17. package/dist/{S3StateStore-Cea9_5gF.cjs → S3StateStore-O8EYfjfG.cjs} +2 -2
  18. package/dist/{S3StateStore-Cea9_5gF.cjs.map → S3StateStore-O8EYfjfG.cjs.map} +1 -1
  19. package/dist/{S3StateStore-CksKYKRa.mjs → S3StateStore-hIm8Rrmu.mjs} +2 -2
  20. package/dist/{S3StateStore-CksKYKRa.mjs.map → S3StateStore-hIm8Rrmu.mjs.map} +1 -1
  21. package/dist/{SSMStateStore-aBOTF018.cjs → SSMStateStore-DIzbiqCz.cjs} +2 -2
  22. package/dist/{SSMStateStore-aBOTF018.cjs.map → SSMStateStore-DIzbiqCz.cjs.map} +1 -1
  23. package/dist/{SSMStateStore-BszSCAS2.mjs → SSMStateStore-IvcjTk8h.mjs} +2 -2
  24. package/dist/{SSMStateStore-BszSCAS2.mjs.map → SSMStateStore-IvcjTk8h.mjs.map} +1 -1
  25. package/dist/SubscriberGenerator-BPqQf8fB.mjs.map +1 -1
  26. package/dist/SubscriberGenerator-BVn7cQ-2.cjs.map +1 -1
  27. package/dist/{add-5MZAXybv.cjs → add-C9qX4Juc.cjs} +30 -7
  28. package/dist/add-C9qX4Juc.cjs.map +1 -0
  29. package/dist/{add-D_jNqnfZ.mjs → add-v3tCbrpE.mjs} +30 -7
  30. package/dist/add-v3tCbrpE.mjs.map +1 -0
  31. package/dist/{bundler-1REMhKps.cjs → bundler-C4NmpRTD.cjs} +5 -5
  32. package/dist/{bundler-1REMhKps.cjs.map → bundler-C4NmpRTD.cjs.map} +1 -1
  33. package/dist/{bundler-BMo-JP5s.mjs → bundler-C_fCgcVO.mjs} +5 -5
  34. package/dist/{bundler-BMo-JP5s.mjs.map → bundler-C_fCgcVO.mjs.map} +1 -1
  35. package/dist/{cli-BL8ZHsLQ.cjs → cli-C85Dut8K.cjs} +6 -5
  36. package/dist/cli-C85Dut8K.cjs.map +1 -0
  37. package/dist/{cli-7edNFwGk.mjs → cli-REdO9X5b.mjs} +7 -6
  38. package/dist/cli-REdO9X5b.mjs.map +1 -0
  39. package/dist/{compose-xw86kVYi.cjs → compose-BvrhDwJ6.cjs} +556 -30
  40. package/dist/compose-BvrhDwJ6.cjs.map +1 -0
  41. package/dist/{compose-DbJhRQlh.mjs → compose-Dn0oAgQ0.mjs} +509 -31
  42. package/dist/compose-Dn0oAgQ0.mjs.map +1 -0
  43. package/dist/{config-DrCAyoH5.d.mts → config-CdEcTrjG.d.mts} +3 -3
  44. package/dist/{config-CpjsVxru.d.cts.map → config-CdEcTrjG.d.mts.map} +1 -1
  45. package/dist/{config-CpjsVxru.d.cts → config-pST7E0CS.d.cts} +3 -3
  46. package/dist/{config-DrCAyoH5.d.mts.map → config-pST7E0CS.d.cts.map} +1 -1
  47. package/dist/config.cjs +1 -1
  48. package/dist/config.d.cts +3 -3
  49. package/dist/config.d.mts +3 -3
  50. package/dist/config.mjs +1 -1
  51. package/dist/{credentials-tr26-KML.cjs → credentials-BKfIugu2.cjs} +47 -2
  52. package/dist/credentials-BKfIugu2.cjs.map +1 -0
  53. package/dist/{credentials-BgJ5mS_d.mjs → credentials-CnVqoXMb.mjs} +30 -3
  54. package/dist/credentials-CnVqoXMb.mjs.map +1 -0
  55. package/dist/deploy/public.cjs +10 -10
  56. package/dist/deploy/public.d.cts +9 -3
  57. package/dist/deploy/public.d.cts.map +1 -1
  58. package/dist/deploy/public.d.mts +9 -3
  59. package/dist/deploy/public.d.mts.map +1 -1
  60. package/dist/deploy/public.mjs +10 -10
  61. package/dist/{deploy-BTfmXd3g.mjs → deploy-BaERRh0Q.mjs} +10 -8
  62. package/dist/deploy-BaERRh0Q.mjs.map +1 -0
  63. package/dist/{deploy-CtbZj4zN.cjs → deploy-DbBGo3a6.cjs} +10 -8
  64. package/dist/deploy-DbBGo3a6.cjs.map +1 -0
  65. package/dist/{dokploy-r69yZaIt.mjs → dokploy-CMmD_ddX.mjs} +2 -2
  66. package/dist/{dokploy-r69yZaIt.mjs.map → dokploy-CMmD_ddX.mjs.map} +1 -1
  67. package/dist/{dokploy-TGk3oPwr.cjs → dokploy-DwAaKA9B.cjs} +2 -2
  68. package/dist/{dokploy-TGk3oPwr.cjs.map → dokploy-DwAaKA9B.cjs.map} +1 -1
  69. package/dist/{encryption-C-8Tt5Hh.mjs → encryption-BQmhq9_y.mjs} +3 -3
  70. package/dist/{encryption-C-8Tt5Hh.mjs.map → encryption-BQmhq9_y.mjs.map} +1 -1
  71. package/dist/{encryption-CDn7BH5O.cjs → encryption-BrN_9_CM.cjs} +3 -3
  72. package/dist/{encryption-CDn7BH5O.cjs.map → encryption-BrN_9_CM.cjs.map} +1 -1
  73. package/dist/{engine-jAINgiOB.mjs → engine-DILocOOH.mjs} +23 -404
  74. package/dist/engine-DILocOOH.mjs.map +1 -0
  75. package/dist/{engine-Bt5k_UMq.cjs → engine-DgHoFBMw.cjs} +25 -406
  76. package/dist/engine-DgHoFBMw.cjs.map +1 -0
  77. package/dist/{github-DFhuJQlp.cjs → github-Bf7pz6AV.cjs} +3 -3
  78. package/dist/{github-DFhuJQlp.cjs.map → github-Bf7pz6AV.cjs.map} +1 -1
  79. package/dist/{github-CZHAtwPT.mjs → github-xzg99wz8.mjs} +3 -3
  80. package/dist/{github-CZHAtwPT.mjs.map → github-xzg99wz8.mjs.map} +1 -1
  81. package/dist/{index-MnUJuUlj.d.mts → index-D-F_hTDz.d.cts} +21 -4
  82. package/dist/index-D-F_hTDz.d.cts.map +1 -0
  83. package/dist/{index-elsLJTUv.d.cts → index-YFNxR5Ns.d.mts} +21 -4
  84. package/dist/index-YFNxR5Ns.d.mts.map +1 -0
  85. package/dist/index.cjs +246 -63
  86. package/dist/index.cjs.map +1 -1
  87. package/dist/index.mjs +247 -65
  88. package/dist/index.mjs.map +1 -1
  89. package/dist/{local-Cq8qdgNX.cjs → local-BjxDfPvy.cjs} +2 -2
  90. package/dist/{local-Cq8qdgNX.cjs.map → local-BjxDfPvy.cjs.map} +1 -1
  91. package/dist/{local-Ciq-bTPr.mjs → local-IuoIF3CT.mjs} +2 -2
  92. package/dist/{local-Ciq-bTPr.mjs.map → local-IuoIF3CT.mjs.map} +1 -1
  93. package/dist/{migrate-B1rVlwj1.cjs → migrate-7xayVtzL.cjs} +3 -3
  94. package/dist/{migrate-B1rVlwj1.cjs.map → migrate-7xayVtzL.cjs.map} +1 -1
  95. package/dist/{migrate-ggkPVJRC.mjs → migrate-CKLJ73OO.mjs} +4 -4
  96. package/dist/{migrate-ggkPVJRC.mjs.map → migrate-CKLJ73OO.mjs.map} +1 -1
  97. package/dist/{migrate-Dn7nK6sh.mjs → migrate-CpmO5qnl.mjs} +3 -3
  98. package/dist/{migrate-Dn7nK6sh.mjs.map → migrate-CpmO5qnl.mjs.map} +1 -1
  99. package/dist/{migrate-B16qgYTn.cjs → migrate-DPF7ZF8M.cjs} +3 -3
  100. package/dist/{migrate-B16qgYTn.cjs.map → migrate-DPF7ZF8M.cjs.map} +1 -1
  101. package/dist/openapi.cjs +1 -1
  102. package/dist/openapi.d.cts +1 -1
  103. package/dist/openapi.d.mts +1 -1
  104. package/dist/openapi.mjs +1 -1
  105. package/dist/reconcile/public.d.cts +1 -1
  106. package/dist/reconcile/public.d.mts +1 -1
  107. package/dist/{reconcile--I7V4Klj.mjs → reconcile-Dh1Jk7WE.mjs} +2 -2
  108. package/dist/{reconcile--I7V4Klj.mjs.map → reconcile-Dh1Jk7WE.mjs.map} +1 -1
  109. package/dist/{resolve-BSke45k6.mjs → resolve-Dv_weZoh.mjs} +4 -4
  110. package/dist/{resolve-BSke45k6.mjs.map → resolve-Dv_weZoh.mjs.map} +1 -1
  111. package/dist/{resolve-BXeXzpmU.cjs → resolve-dlKPFNgv.cjs} +4 -4
  112. package/dist/{resolve-BXeXzpmU.cjs.map → resolve-dlKPFNgv.cjs.map} +1 -1
  113. package/dist/{rollback-DFMiBWf0.cjs → rollback-65VVIdBM.cjs} +6 -6
  114. package/dist/{rollback-DFMiBWf0.cjs.map → rollback-65VVIdBM.cjs.map} +1 -1
  115. package/dist/{rollback-CEE6dse4.mjs → rollback-DpSU2DsD.mjs} +6 -6
  116. package/dist/{rollback-CEE6dse4.mjs.map → rollback-DpSU2DsD.mjs.map} +1 -1
  117. package/dist/{runtime-HabiNBtJ.d.mts → runtime-CN_kmqxo.d.cts} +2 -2
  118. package/dist/{runtime-D48ZKk8_.d.cts.map → runtime-CN_kmqxo.d.cts.map} +1 -1
  119. package/dist/{runtime-D48ZKk8_.d.cts → runtime-Cjvon3oj.d.mts} +2 -2
  120. package/dist/{runtime-HabiNBtJ.d.mts.map → runtime-Cjvon3oj.d.mts.map} +1 -1
  121. package/dist/{seeds-CsI0A_Ef.cjs → seeds-CN6tB-va.cjs} +646 -187
  122. package/dist/{seeds-CsI0A_Ef.cjs.map → seeds-CN6tB-va.cjs.map} +1 -1
  123. package/dist/{seeds-BYdrtZsC.mjs → seeds-perzdN81.mjs} +599 -164
  124. package/dist/seeds-perzdN81.mjs.map +1 -0
  125. package/dist/{sniffer-B0EU73bj.mjs → sniffer-BTtX3NUM.mjs} +3 -3
  126. package/dist/{sniffer-B0EU73bj.mjs.map → sniffer-BTtX3NUM.mjs.map} +1 -1
  127. package/dist/{sniffer-DJYupBeK.cjs → sniffer-IAQEpsQb.cjs} +3 -3
  128. package/dist/{sniffer-DJYupBeK.cjs.map → sniffer-IAQEpsQb.cjs.map} +1 -1
  129. package/dist/{sst-DAqUoZKG.cjs → sst-BgcOsaBi.cjs} +3 -3
  130. package/dist/{sst-DAqUoZKG.cjs.map → sst-BgcOsaBi.cjs.map} +1 -1
  131. package/dist/{sst-D1Qj4sIs.mjs → sst-CJzvyrEz.mjs} +3 -3
  132. package/dist/{sst-D1Qj4sIs.mjs.map → sst-CJzvyrEz.mjs.map} +1 -1
  133. package/dist/{stages-Brn3vcdy.cjs → stages-CUn6gvXL.cjs} +2 -2
  134. package/dist/{stages-Brn3vcdy.cjs.map → stages-CUn6gvXL.cjs.map} +1 -1
  135. package/dist/{stages-DoHHz6pS.mjs → stages-CnZRYmkI.mjs} +2 -2
  136. package/dist/{stages-DoHHz6pS.mjs.map → stages-CnZRYmkI.mjs.map} +1 -1
  137. package/dist/target/public.cjs +1 -1
  138. package/dist/target/public.d.cts +2 -2
  139. package/dist/target/public.d.mts +2 -2
  140. package/dist/target/public.mjs +1 -1
  141. package/dist/{terminal-BTbZlrFV.mjs → terminal-D8TPK7o9.mjs} +3 -3
  142. package/dist/{terminal-BTbZlrFV.mjs.map → terminal-D8TPK7o9.mjs.map} +1 -1
  143. package/dist/{terminal-COv23heb.cjs → terminal-DuapRxh6.cjs} +2 -2
  144. package/dist/{terminal-COv23heb.cjs.map → terminal-DuapRxh6.cjs.map} +1 -1
  145. package/dist/{types-0oAyFOfR.d.cts → types-NqX1Hz4P.d.cts} +210 -205
  146. package/dist/types-NqX1Hz4P.d.cts.map +1 -0
  147. package/dist/{types-BZ01tZs-.d.mts → types-ZHuZ89hv.d.mts} +210 -205
  148. package/dist/types-ZHuZ89hv.d.mts.map +1 -0
  149. package/dist/workspace/index.cjs +3 -1
  150. package/dist/workspace/index.d.cts +3 -3
  151. package/dist/workspace/index.d.mts +3 -3
  152. package/dist/workspace/index.mjs +2 -2
  153. package/dist/{workspace-D2CYLMCW.mjs → workspace-CJ0lKFq-.mjs} +231 -10
  154. package/dist/workspace-CJ0lKFq-.mjs.map +1 -0
  155. package/dist/{workspace-CT0JM3Y8.cjs → workspace-CwW3Gkru.cjs} +266 -9
  156. package/dist/workspace-CwW3Gkru.cjs.map +1 -0
  157. package/package.json +15 -15
  158. package/dist/add-5MZAXybv.cjs.map +0 -1
  159. package/dist/add-D_jNqnfZ.mjs.map +0 -1
  160. package/dist/cli-7edNFwGk.mjs.map +0 -1
  161. package/dist/cli-BL8ZHsLQ.cjs.map +0 -1
  162. package/dist/compose-DbJhRQlh.mjs.map +0 -1
  163. package/dist/compose-xw86kVYi.cjs.map +0 -1
  164. package/dist/credentials-BgJ5mS_d.mjs.map +0 -1
  165. package/dist/credentials-tr26-KML.cjs.map +0 -1
  166. package/dist/deploy-BTfmXd3g.mjs.map +0 -1
  167. package/dist/deploy-CtbZj4zN.cjs.map +0 -1
  168. package/dist/engine-Bt5k_UMq.cjs.map +0 -1
  169. package/dist/engine-jAINgiOB.mjs.map +0 -1
  170. package/dist/index-MnUJuUlj.d.mts.map +0 -1
  171. package/dist/index-elsLJTUv.d.cts.map +0 -1
  172. package/dist/seeds-BYdrtZsC.mjs.map +0 -1
  173. package/dist/types-0oAyFOfR.d.cts.map +0 -1
  174. package/dist/types-BZ01tZs-.d.mts.map +0 -1
  175. package/dist/workspace-CT0JM3Y8.cjs.map +0 -1
  176. package/dist/workspace-D2CYLMCW.mjs.map +0 -1
@@ -1,12 +1,12 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mjs";
2
- import { r as storedCredentials, s as run$1, v as gkmHome } from "./credentials-BgJ5mS_d.mjs";
2
+ import { r as storedCredentials, s as run$1, x as gkmHome } from "./credentials-CnVqoXMb.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 { B as provisioningOf, G as BucketKeySetElsewhere, H as S3_PROVISIONING, I as stageSampleRate, J as IamUserNotOwned, K as BucketNameUnavailable, L as telemetryEnv, Q as S3RegionRequired, R as LOGS_PORT, U as checkS3Config, V as stageProvider, W as AccessKeyLimit, X as RecordedBucketUnreachable, Y as ProvisionedBucketUnreachable, Z as RotationInProgress, g as getPublicEnvPrefix, h as PUBLIC_ENV_PREFIXES, k as TEST_STAGE, q as BucketOwnedByAnotherProject, r as allConstructGlobs, rt as UnknownSecretsStoreProvider } from "./workspace-D2CYLMCW.mjs";
5
+ import { $ as RotationInProgress, B as LOGS_PORT, G as checkS3Config, H as provisioningOf, J as BucketNameUnavailable, K as AccessKeyLimit, Q as RecordedBucketUnreachable, R as stageSampleRate, U as stageProvider, W as S3_PROVISIONING, X as IamUserNotOwned, Y as BucketOwnedByAnotherProject, Z as ProvisionedBucketUnreachable, _ as PUBLIC_ENV_PREFIXES, a as allConstructGlobs, at as SERVER_IPV6_KEY, et as S3RegionRequired, it as SERVER_IPV4_KEY, j as TEST_STAGE, lt as UnknownSecretsStoreProvider, q as BucketKeySetElsewhere, st as isReservedStageKey, v as getPublicEnvPrefix, z as telemetryEnv } from "./workspace-CJ0lKFq-.mjs";
6
6
  import { ConfigNotFound, NotInAnApp, loadWorkspaceAppInfo, loadWorkspaceConfig } from "./config.mjs";
7
7
  import { a as telemetryArgs, c as startTelemetryCode, n as runtimeFor, u as writeTelemetryModule } from "./EndpointGenerator-CVc6Oi1Y.mjs";
8
8
  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-BPqQf8fB.mjs";
9
- import { c as runtimeOf } from "./resolve-BSke45k6.mjs";
9
+ import { c as runtimeOf } from "./resolve-Dv_weZoh.mjs";
10
10
  import { basename, dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
11
11
  import { constants, existsSync, readFileSync } from "node:fs";
12
12
  import { appendFile, chmod, copyFile, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
@@ -29,6 +29,7 @@ import { CreateTopicCommand, GetTopicAttributesCommand, SNSClient } from "@aws-s
29
29
  import { CreateQueueCommand, GetQueueUrlCommand, SQSClient } from "@aws-sdk/client-sqs";
30
30
  import { Client } from "pg";
31
31
  import { cacheTableStatements } from "@geekmidas/cache/postgres";
32
+ import { lookup } from "node:dns/promises";
32
33
  import * as s3Url from "@geekmidas/storage/s3-url";
33
34
  //#region src/workspace/rootSite.ts
34
35
  /**
@@ -74,11 +75,11 @@ var AmbiguousRootSite = class extends Error {
74
75
  };
75
76
  //#endregion
76
77
  //#region src/target/dokploy/domain.ts
77
- /** A stage was deployed that `deploy.domains` gives no domain. */
78
+ /** A stage was deployed that `domains` gives no domain. */
78
79
  var NoDomainForStage = class extends Error {
79
80
  stage;
80
81
  constructor(stage) {
81
- super(`No domain for stage "${stage}". Add it to gkm.config.ts: deploy: { domains: { ${stage}: 'example.com' } }.`);
82
+ super(`No domain for stage "${stage}". Add it to gkm.config.ts: domains: { ${stage}: 'example.com' }.`);
82
83
  this.stage = stage;
83
84
  this.name = "NoDomainForStage";
84
85
  }
@@ -87,11 +88,11 @@ var NoDomainForStage = class extends Error {
87
88
  * The hostname an app answers on for a stage.
88
89
  *
89
90
  * 1. An explicit `app.domain` — a string, or one per stage — wins.
90
- * 2. Otherwise from the stage's base domain in `deploy.domains`: the root site
91
+ * 2. Otherwise from the stage's base domain in `domains`: the root site
91
92
  * answers on the domain itself, and every other app on
92
93
  * `{subdomain}.{domain}` — its declaration's `subdomain`, or its own name.
93
94
  *
94
- * @throws {NoDomainForStage} when `deploy.domains` names no domain for it
95
+ * @throws {NoDomainForStage} when `domains` names no domain for it
95
96
  */
96
97
  function resolveHost(appName, app, stage, domains, isMainFrontend) {
97
98
  if (app.domain) {
@@ -300,6 +301,11 @@ function logsAccess(logs, ctx) {
300
301
  }
301
302
  //#endregion
302
303
  //#region src/secrets/storage.ts
304
+ /**
305
+ * What a stage's secrets are, independent of where they are kept: building
306
+ * them, changing them, and handing them to a process. Where they are kept is a
307
+ * {@link SecretsStore}'s business — see `secretsStoreFor`.
308
+ */
303
309
  var storage_exports = /* @__PURE__ */ __exportAll({
304
310
  initStageSecrets: () => initStageSecrets,
305
311
  maskPassword: () => maskPassword,
@@ -328,7 +334,7 @@ function initStageSecrets(stage) {
328
334
  function toEmbeddableSecrets(secrets) {
329
335
  return {
330
336
  ...secrets.urls,
331
- ...secrets.custom,
337
+ ...Object.fromEntries(Object.entries(secrets.custom).filter(([key]) => !isReservedStageKey(key))),
332
338
  ...secrets.services.postgres && {
333
339
  POSTGRES_USER: secrets.services.postgres.username,
334
340
  POSTGRES_PASSWORD: secrets.services.postgres.password,
@@ -854,7 +860,7 @@ function isRemoteStore(workspace, stage) {
854
860
  }
855
861
  //#endregion
856
862
  //#region src/credentials/index.ts
857
- const logger$1 = console;
863
+ const logger$2 = console;
858
864
  /**
859
865
  * Load environment files
860
866
  * @internal Exported for testing
@@ -905,7 +911,7 @@ async function findAvailablePort(preferredPort, maxAttempts = 10) {
905
911
  for (let i = 0; i < maxAttempts; i++) {
906
912
  const port = preferredPort + i;
907
913
  if (await isPortAvailable(port)) return port;
908
- logger$1.log(`⚠️ Port ${port} is in use, trying ${port + 1}...`);
914
+ logger$2.log(`⚠️ Port ${port} is in use, trying ${port + 1}...`);
909
915
  }
910
916
  throw new Error(`Could not find an available port after trying ${maxAttempts} ports starting from ${preferredPort}`);
911
917
  }
@@ -942,7 +948,7 @@ async function savePortState(workspaceRoot, ports) {
942
948
  async function loadSecretsForApp(store, stage) {
943
949
  const stageSecrets = await store.read(stage);
944
950
  if (!stageSecrets) return {};
945
- logger$1.log(`🔐 Loading secrets from stage: ${stage}`);
951
+ logger$2.log(`🔐 Loading secrets from stage: ${stage}`);
946
952
  return toEmbeddableSecrets(stageSecrets);
947
953
  }
948
954
  /**
@@ -1040,7 +1046,7 @@ async function prepareEntryCredentials(options) {
1040
1046
  free: isPortAvailable,
1041
1047
  holder: holderOf
1042
1048
  });
1043
- for (const { app, from, to, holder } of assigned.moved) logger$1.log(`↪️ ${app}: ${from} is held by ${describeHolder(holder)}, which is not this workspace's — using ${to}`);
1049
+ for (const { app, from, to, holder } of assigned.moved) logger$2.log(`↪️ ${app}: ${from} is held by ${describeHolder(holder)}, which is not this workspace's — using ${to}`);
1044
1050
  workspace = withAppPorts(workspace, assigned.ports);
1045
1051
  workspaceAppPort = assigned.ports[appName] ?? workspaceAppPort;
1046
1052
  }
@@ -1064,7 +1070,7 @@ async function prepareEntryCredentials(options) {
1064
1070
  });
1065
1071
  Object.assign(credentials, reconciled.env);
1066
1072
  declaredKeys.push(...Object.keys(reconciled.env));
1067
- if (Object.keys(reconciled.env).length > 0) logger$1.log(`🔌 Resolved ${Object.keys(reconciled.env).length} declared URL(s)`);
1073
+ if (Object.keys(reconciled.env).length > 0) logger$2.log(`🔌 Resolved ${Object.keys(reconciled.env).length} declared URL(s)`);
1068
1074
  }
1069
1075
  const secretsDir = join(secretsRoot, ".gkm");
1070
1076
  await mkdir(secretsDir, { recursive: true });
@@ -6771,6 +6777,14 @@ function requiredStageKeys(input) {
6771
6777
  ...apps(d)
6772
6778
  });
6773
6779
  }
6780
+ if (!input.local && input.server) add({
6781
+ key: SERVER_IPV4_KEY,
6782
+ id: "server",
6783
+ kind: "server",
6784
+ what: "the public IPv4 address of the server the stage's stack runs on — its hosts' DNS records point at it, and every deploy checks they do",
6785
+ note: `${SERVER_IPV6_KEY} adds its IPv6 address (AAAA records); neither is ever handed to an app`,
6786
+ example: "203.0.113.10"
6787
+ });
6774
6788
  for (const d of byId(input.credentials)) add({
6775
6789
  key: provideKey(d.id, "credentials"),
6776
6790
  id: d.id,
@@ -7201,17 +7215,17 @@ function isStateStore(value) {
7201
7215
  async function createStateStore(options) {
7202
7216
  const { config, workspaceRoot, workspaceName } = options;
7203
7217
  if (!config || config.provider === "local") {
7204
- const { LocalStateStore } = await import("./LocalStateStore-Q4vXg2ua.mjs").then((n) => n.n);
7218
+ const { LocalStateStore } = await import("./LocalStateStore-C_hYDv6I.mjs").then((n) => n.n);
7205
7219
  return new LocalStateStore(workspaceRoot);
7206
7220
  }
7207
7221
  if (isStateStore(config.provider)) return config.provider;
7208
7222
  if (isStateProvider(config.provider)) {
7209
- const { LegacyStateStore } = await import("./LegacyStateStore-B0R4LlX_.mjs");
7223
+ const { LegacyStateStore } = await import("./LegacyStateStore-CO7bzJCU.mjs");
7210
7224
  return new LegacyStateStore(config.provider, { warn: options.warn });
7211
7225
  }
7212
7226
  if (config.provider === "ssm") {
7213
7227
  if (!workspaceName) throw new StateStoreNeedsWorkspaceName("ssm");
7214
- const { SSMStateStore } = await import("./SSMStateStore-BszSCAS2.mjs");
7228
+ const { SSMStateStore } = await import("./SSMStateStore-IvcjTk8h.mjs");
7215
7229
  const ssm = config;
7216
7230
  return SSMStateStore.create({
7217
7231
  workspaceName,
@@ -7221,7 +7235,7 @@ async function createStateStore(options) {
7221
7235
  }
7222
7236
  if (config.provider === "s3") {
7223
7237
  if (!workspaceName) throw new StateStoreNeedsWorkspaceName("s3");
7224
- const { S3StateStore } = await import("./S3StateStore-CksKYKRa.mjs");
7238
+ const { S3StateStore } = await import("./S3StateStore-hIm8Rrmu.mjs");
7225
7239
  const s3 = config;
7226
7240
  return S3StateStore.create({
7227
7241
  workspaceName,
@@ -7234,6 +7248,570 @@ async function createStateStore(options) {
7234
7248
  throw new UnknownStateProvider(config);
7235
7249
  }
7236
7250
  //#endregion
7251
+ //#region src/target/dokploy/dns/DnsProvider.ts
7252
+ /**
7253
+ * Check if value is a DnsProvider implementation.
7254
+ */
7255
+ function isDnsProvider(value) {
7256
+ return typeof value === "object" && value !== null && typeof value.name === "string" && typeof value.getRecords === "function" && typeof value.upsertRecords === "function" && typeof value.deleteRecords === "function";
7257
+ }
7258
+ /**
7259
+ * Create a DNS provider based on configuration.
7260
+ *
7261
+ * - 'hostinger': HostingerProvider
7262
+ * - 'route53': Route53Provider
7263
+ * - 'godaddy': GoDaddyProvider
7264
+ * - 'manual': Returns null (user handles DNS)
7265
+ * - Custom: Use provided DnsProvider implementation
7266
+ */
7267
+ async function createDnsProvider(options) {
7268
+ const { config } = options;
7269
+ if (config.provider === "manual") return null;
7270
+ if (isDnsProvider(config.provider)) return config.provider;
7271
+ const provider = config.provider;
7272
+ if (provider === "hostinger") {
7273
+ const { HostingerProvider } = await import("./HostingerProvider-BI6J7oJr.mjs");
7274
+ return new HostingerProvider();
7275
+ }
7276
+ if (provider === "route53") {
7277
+ const { Route53Provider } = await import("./Route53Provider-QXxjkZO1.mjs");
7278
+ const route53Config = config;
7279
+ return new Route53Provider({
7280
+ region: route53Config.region,
7281
+ profile: route53Config.profile,
7282
+ hostedZoneId: route53Config.hostedZoneId
7283
+ });
7284
+ }
7285
+ if (provider === "godaddy") {
7286
+ const { GoDaddyProvider } = await import("./GoDaddyProvider--36rw8cP.mjs");
7287
+ return new GoDaddyProvider(options.godaddy ?? {});
7288
+ }
7289
+ if (provider === "cloudflare") throw new DnsProviderNotImplemented("cloudflare");
7290
+ throw new DnsProviderUnknown(config);
7291
+ }
7292
+ /**
7293
+ * The provider's credentials can write records and not read them — a key
7294
+ * scoped to updates only. What reads them falls back to writing every record,
7295
+ * which is idempotent, without a diff.
7296
+ */
7297
+ var DnsRecordsUnreadable = class extends Error {
7298
+ provider;
7299
+ domain;
7300
+ reason;
7301
+ constructor(provider, domain, reason) {
7302
+ super(`The ${provider} key cannot read ${domain}'s DNS records (${reason}), so changes cannot be compared with what is there: every record is written, which leaves one that already has its value as it was.`);
7303
+ this.provider = provider;
7304
+ this.domain = domain;
7305
+ this.reason = reason;
7306
+ this.name = "DnsRecordsUnreadable";
7307
+ }
7308
+ };
7309
+ /** A DNS provider gkm names and does not have yet. */
7310
+ var DnsProviderNotImplemented = class extends Error {
7311
+ provider;
7312
+ constructor(provider) {
7313
+ super(`The ${provider} DNS provider is not implemented yet. Use 'route53', 'godaddy', 'hostinger' or 'manual' for this domain in dns, or pass your own DnsProvider object.`);
7314
+ this.provider = provider;
7315
+ this.name = "DnsProviderNotImplemented";
7316
+ }
7317
+ };
7318
+ /** A `provider:` that is none of the built-ins, nor a DnsProvider object. */
7319
+ var DnsProviderUnknown = class extends Error {
7320
+ config;
7321
+ constructor(config) {
7322
+ super(`Unknown DNS provider: ${JSON.stringify(config)}. dns takes 'route53', 'godaddy', 'hostinger', 'manual', or an object implementing DnsProvider.`);
7323
+ this.config = config;
7324
+ this.name = "DnsProviderUnknown";
7325
+ }
7326
+ };
7327
+ //#endregion
7328
+ //#region src/deploy/state.ts
7329
+ /**
7330
+ * Create a new empty state for a stage
7331
+ */
7332
+ function createEmptyState(stage, projectId, environmentId) {
7333
+ return {
7334
+ provider: "dokploy",
7335
+ stage,
7336
+ projectId,
7337
+ environmentId,
7338
+ applications: {},
7339
+ services: {},
7340
+ lastDeployedAt: (/* @__PURE__ */ new Date()).toISOString()
7341
+ };
7342
+ }
7343
+ /**
7344
+ * Set application ID in state (mutates state)
7345
+ */
7346
+ function setApplicationId(state, appName, applicationId) {
7347
+ state.applications[appName] = applicationId;
7348
+ }
7349
+ /** Two records naming the same image: by digest when both have one. */
7350
+ function sameImage(a, b) {
7351
+ return a.digest && b.digest ? a.digest === b.digest : a.ref === b.ref;
7352
+ }
7353
+ /** The newest release in `history` after `index` that a rollback may restore. */
7354
+ function restorable(history, index, current) {
7355
+ return history.slice(index + 1).find((entry) => !entry.rolledBack && !sameImage(entry, current));
7356
+ }
7357
+ /**
7358
+ * Record that `image` went live for `appName` (mutates state): it becomes
7359
+ * `current`, and what was current becomes `previous`. Releasing what already
7360
+ * runs — a redeploy of the same digest — changes nothing.
7361
+ */
7362
+ function recordRelease(state, appName, image, releasedAt = /* @__PURE__ */ new Date()) {
7363
+ const releases = state.releases?.[appName];
7364
+ if (releases && sameImage(releases.current, image)) return;
7365
+ const entry = {
7366
+ ...image,
7367
+ releasedAt: releasedAt.toISOString()
7368
+ };
7369
+ const history = [entry, ...releases?.history ?? []].slice(0, 10);
7370
+ const previous = releases?.current;
7371
+ state.releases = {
7372
+ ...state.releases,
7373
+ [appName]: {
7374
+ current: entry,
7375
+ ...previous ? { previous } : {},
7376
+ history
7377
+ }
7378
+ };
7379
+ }
7380
+ /**
7381
+ * Record that `appName` was rolled back to `to` (mutates state): every
7382
+ * release newer than it is marked rolled back, so neither this rollback nor
7383
+ * a later one restores it, and `previous` moves to the release before `to`.
7384
+ */
7385
+ function recordRollback(state, appName, to) {
7386
+ const releases = state.releases?.[appName];
7387
+ if (!releases) return;
7388
+ const index = releases.history.findIndex((entry) => !entry.rolledBack && sameImage(entry, to));
7389
+ if (index === -1) return;
7390
+ const history = releases.history.map((entry, i) => i < index ? {
7391
+ ...entry,
7392
+ rolledBack: true
7393
+ } : entry);
7394
+ const current = history[index];
7395
+ const previous = restorable(history, index, current);
7396
+ state.releases = {
7397
+ ...state.releases,
7398
+ [appName]: {
7399
+ current,
7400
+ ...previous ? { previous } : {},
7401
+ history
7402
+ }
7403
+ };
7404
+ }
7405
+ /**
7406
+ * Get a generated secret for an app
7407
+ */
7408
+ function getGeneratedSecret(state, appName, secretName) {
7409
+ return state?.generatedSecrets?.[appName]?.[secretName];
7410
+ }
7411
+ /**
7412
+ * Set a generated secret for an app (mutates state)
7413
+ */
7414
+ function setGeneratedSecret(state, appName, secretName, value) {
7415
+ if (!state.generatedSecrets) state.generatedSecrets = {};
7416
+ if (!state.generatedSecrets[appName]) state.generatedSecrets[appName] = {};
7417
+ state.generatedSecrets[appName][secretName] = value;
7418
+ }
7419
+ /**
7420
+ * Set DNS verification record for a hostname (mutates state)
7421
+ */
7422
+ function setDnsVerification(state, hostname, serverIp) {
7423
+ if (!state.dnsVerified) state.dnsVerified = {};
7424
+ state.dnsVerified[hostname] = {
7425
+ serverIp,
7426
+ verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
7427
+ };
7428
+ }
7429
+ /**
7430
+ * Check if a hostname is already verified with the given IP
7431
+ */
7432
+ function isDnsVerified(state, hostname, serverIp) {
7433
+ return (state?.dnsVerified?.[hostname])?.serverIp === serverIp;
7434
+ }
7435
+ /**
7436
+ * Get the key for a DNS record in state
7437
+ */
7438
+ function getDnsRecordKey(name, type) {
7439
+ return `${name}:${type}`;
7440
+ }
7441
+ /**
7442
+ * Set a created DNS record in state (mutates state)
7443
+ */
7444
+ function setDnsRecord(state, record) {
7445
+ if (!state.dnsRecords) state.dnsRecords = {};
7446
+ const key = getDnsRecordKey(record.name, record.type);
7447
+ state.dnsRecords[key] = {
7448
+ ...record,
7449
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
7450
+ };
7451
+ }
7452
+ /**
7453
+ * Get backup state from state
7454
+ */
7455
+ function getBackupState(state) {
7456
+ return state?.backups;
7457
+ }
7458
+ /**
7459
+ * Set backup state (mutates state)
7460
+ */
7461
+ function setBackupState(state, backupState) {
7462
+ state.backups = backupState;
7463
+ }
7464
+ /**
7465
+ * Set postgres backup ID in state (mutates state)
7466
+ */
7467
+ function setPostgresBackupId(state, backupId) {
7468
+ if (state.backups) state.backups.postgresBackupId = backupId;
7469
+ }
7470
+ //#endregion
7471
+ //#region src/target/dokploy/dns/index.ts
7472
+ /**
7473
+ * DNS orchestration for deployments
7474
+ *
7475
+ * Handles automatic DNS record creation for deployed applications.
7476
+ */
7477
+ const logger$1 = output;
7478
+ /**
7479
+ * Check if DNS config is legacy format (single domain with `domain` property)
7480
+ */
7481
+ function isLegacyDnsConfig(config) {
7482
+ return typeof config === "object" && config !== null && "provider" in config && "domain" in config;
7483
+ }
7484
+ /**
7485
+ * Normalize DNS config to new multi-domain format
7486
+ */
7487
+ function normalizeDnsConfig(config) {
7488
+ if (isLegacyDnsConfig(config)) {
7489
+ const { domain, ...providerConfig } = config;
7490
+ return { [domain]: providerConfig };
7491
+ }
7492
+ return config;
7493
+ }
7494
+ /**
7495
+ * Find the root domain for a hostname from available DNS configs
7496
+ *
7497
+ * @example
7498
+ * findRootDomain('api.geekmidas.com', { 'geekmidas.com': {...}, 'geekmidas.dev': {...} })
7499
+ * // Returns 'geekmidas.com'
7500
+ */
7501
+ function findRootDomain(hostname, dnsConfig) {
7502
+ const domains = Object.keys(dnsConfig).sort((a, b) => b.length - a.length);
7503
+ for (const domain of domains) if (hostname === domain || hostname.endsWith(`.${domain}`)) return domain;
7504
+ return null;
7505
+ }
7506
+ /**
7507
+ * Group hostnames by their root domain
7508
+ */
7509
+ function groupHostnamesByDomain(appHostnames, dnsConfig) {
7510
+ const grouped = /* @__PURE__ */ new Map();
7511
+ for (const [appName, hostname] of appHostnames) {
7512
+ const rootDomain = findRootDomain(hostname, dnsConfig);
7513
+ if (!rootDomain) {
7514
+ logger$1.log(` ⚠ No DNS config found for hostname: ${hostname}`);
7515
+ continue;
7516
+ }
7517
+ if (!grouped.has(rootDomain)) grouped.set(rootDomain, /* @__PURE__ */ new Map());
7518
+ grouped.get(rootDomain).set(appName, hostname);
7519
+ }
7520
+ return grouped;
7521
+ }
7522
+ /**
7523
+ * Resolve IP address from a hostname
7524
+ */
7525
+ async function resolveHostnameToIp(hostname) {
7526
+ try {
7527
+ return (await lookup(hostname, { family: 4 })).address;
7528
+ } catch (error) {
7529
+ throw new Error(`Failed to resolve IP for ${hostname}: ${error instanceof Error ? error.message : "Unknown error"}`);
7530
+ }
7531
+ }
7532
+ /**
7533
+ * Extract subdomain from full hostname relative to root domain
7534
+ *
7535
+ * @example
7536
+ * extractSubdomain('api.joemoer.traflabs.io', 'traflabs.io') => 'api.joemoer'
7537
+ * extractSubdomain('joemoer.traflabs.io', 'traflabs.io') => 'joemoer'
7538
+ */
7539
+ function extractSubdomain(hostname, rootDomain) {
7540
+ if (!hostname.endsWith(rootDomain)) throw new Error(`Hostname ${hostname} is not under root domain ${rootDomain}`);
7541
+ return hostname.slice(0, -(rootDomain.length + 1)) || "@";
7542
+ }
7543
+ /**
7544
+ * Generate required DNS records for a deployment
7545
+ */
7546
+ function generateRequiredRecords(appHostnames, rootDomain, serverIp) {
7547
+ const records = [];
7548
+ for (const [appName, hostname] of appHostnames) {
7549
+ const subdomain = extractSubdomain(hostname, rootDomain);
7550
+ records.push({
7551
+ hostname,
7552
+ subdomain,
7553
+ type: "A",
7554
+ value: serverIp,
7555
+ appName
7556
+ });
7557
+ }
7558
+ return records;
7559
+ }
7560
+ /**
7561
+ * Print DNS records table
7562
+ */
7563
+ function printDnsRecordsTable(records, rootDomain) {
7564
+ logger$1.log(`\n 📋 DNS Records for ${rootDomain}:`);
7565
+ logger$1.log(" ┌─────────────────────────────────────┬──────┬─────────────────┬────────┐");
7566
+ logger$1.log(" │ Subdomain │ Type │ Value │ Status │");
7567
+ logger$1.log(" ├─────────────────────────────────────┼──────┼─────────────────┼────────┤");
7568
+ for (const record of records) {
7569
+ const subdomain = record.subdomain.padEnd(35);
7570
+ const type = record.type.padEnd(4);
7571
+ const value = record.value.padEnd(15);
7572
+ let status;
7573
+ if (record.error) status = "✗";
7574
+ else if (record.created) status = "✓ new";
7575
+ else if (record.existed) status = "✓";
7576
+ else status = "?";
7577
+ logger$1.log(` │ ${subdomain} │ ${type} │ ${value} │ ${status.padEnd(6)} │`);
7578
+ }
7579
+ logger$1.log(" └─────────────────────────────────────┴──────┴─────────────────┴────────┘");
7580
+ }
7581
+ /**
7582
+ * Print DNS records in a simple format for manual setup
7583
+ */
7584
+ function printDnsRecordsSimple(records, rootDomain) {
7585
+ logger$1.log("\n 📋 Required DNS Records:");
7586
+ logger$1.log(` Add these A records to your DNS provider (${rootDomain}):\n`);
7587
+ for (const record of records) logger$1.log(` ${record.subdomain} → ${record.value} (A record)`);
7588
+ logger$1.log("");
7589
+ }
7590
+ /**
7591
+ * Create DNS records for a single domain using its configured provider
7592
+ */
7593
+ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
7594
+ const ttl = "ttl" in providerConfig && providerConfig.ttl ? providerConfig.ttl : 300;
7595
+ let provider;
7596
+ try {
7597
+ provider = await createDnsProvider({ config: providerConfig });
7598
+ } catch (error) {
7599
+ const message = error instanceof Error ? error.message : "Unknown error";
7600
+ logger$1.log(` ⚠ Failed to create DNS provider for ${rootDomain}: ${message}`);
7601
+ return records.map((r) => ({
7602
+ ...r,
7603
+ error: message
7604
+ }));
7605
+ }
7606
+ if (!provider) return records.map((r) => ({
7607
+ ...r,
7608
+ created: false,
7609
+ existed: false
7610
+ }));
7611
+ const results = [];
7612
+ const upsertRecords = records.map((r) => ({
7613
+ name: r.subdomain,
7614
+ type: r.type,
7615
+ ttl,
7616
+ value: r.value
7617
+ }));
7618
+ try {
7619
+ const upsertResults = await provider.upsertRecords(rootDomain, upsertRecords);
7620
+ for (const [i, record] of records.entries()) {
7621
+ const result = upsertResults[i];
7622
+ if (!result) {
7623
+ results.push({
7624
+ hostname: record.hostname,
7625
+ subdomain: record.subdomain,
7626
+ type: record.type,
7627
+ value: record.value,
7628
+ appName: record.appName,
7629
+ error: "No result returned from provider"
7630
+ });
7631
+ continue;
7632
+ }
7633
+ if (result.unchanged) results.push({
7634
+ hostname: record.hostname,
7635
+ subdomain: record.subdomain,
7636
+ type: record.type,
7637
+ value: record.value,
7638
+ appName: record.appName,
7639
+ existed: true,
7640
+ created: false
7641
+ });
7642
+ else results.push({
7643
+ hostname: record.hostname,
7644
+ subdomain: record.subdomain,
7645
+ type: record.type,
7646
+ value: record.value,
7647
+ appName: record.appName,
7648
+ created: result.created,
7649
+ existed: !result.created
7650
+ });
7651
+ }
7652
+ } catch (error) {
7653
+ const message = error instanceof Error ? error.message : "Unknown error";
7654
+ logger$1.log(` ⚠ Failed to create DNS records for ${rootDomain}: ${message}`);
7655
+ return records.map((r) => ({
7656
+ hostname: r.hostname,
7657
+ subdomain: r.subdomain,
7658
+ type: r.type,
7659
+ value: r.value,
7660
+ appName: r.appName,
7661
+ error: message
7662
+ }));
7663
+ }
7664
+ return results;
7665
+ }
7666
+ /**
7667
+ * Main DNS orchestration function for deployments
7668
+ *
7669
+ * Supports both legacy single-domain format and new multi-domain format:
7670
+ * - Legacy: { provider: 'hostinger', domain: 'example.com' }
7671
+ * - Multi: { 'example.com': { provider: 'hostinger' }, 'example.dev': { provider: 'route53' } }
7672
+ *
7673
+ * @param appHostnames - Map of app names to hostnames
7674
+ * @param dnsConfig - DNS configuration (legacy or multi-domain)
7675
+ * @param dokployEndpoint - Dokploy server endpoint to resolve IP from
7676
+ * @param state - Optional state to save created records for later deletion
7677
+ */
7678
+ async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
7679
+ if (!dnsConfig) return null;
7680
+ const normalizedConfig = normalizeDnsConfig(dnsConfig);
7681
+ logger$1.log("\n🌐 Setting up DNS records...");
7682
+ let serverIp;
7683
+ try {
7684
+ const endpointUrl = new URL(dokployEndpoint);
7685
+ serverIp = await resolveHostnameToIp(endpointUrl.hostname);
7686
+ logger$1.log(` Server IP: ${serverIp} (from ${endpointUrl.hostname})`);
7687
+ } catch (error) {
7688
+ const message = error instanceof Error ? error.message : "Unknown error";
7689
+ logger$1.log(` ⚠ Failed to resolve server IP: ${message}`);
7690
+ return null;
7691
+ }
7692
+ const groupedHostnames = groupHostnamesByDomain(appHostnames, normalizedConfig);
7693
+ if (groupedHostnames.size === 0) {
7694
+ logger$1.log(" No DNS records needed (no hostnames match configured domains)");
7695
+ return {
7696
+ records: [],
7697
+ success: true,
7698
+ serverIp
7699
+ };
7700
+ }
7701
+ const allRecords = [];
7702
+ let hasFailures = false;
7703
+ for (const [rootDomain, domainHostnames] of groupedHostnames) {
7704
+ const providerConfig = normalizedConfig[rootDomain];
7705
+ if (!providerConfig) {
7706
+ logger$1.log(` ⚠ No provider config for ${rootDomain}`);
7707
+ continue;
7708
+ }
7709
+ const providerName = typeof providerConfig.provider === "string" ? providerConfig.provider : "custom";
7710
+ const requiredRecords = generateRequiredRecords(domainHostnames, rootDomain, serverIp);
7711
+ if (requiredRecords.length === 0) continue;
7712
+ logger$1.log(` Creating DNS records for ${rootDomain} (${providerName})...`);
7713
+ const domainRecords = await createDnsRecordsForDomain(requiredRecords, rootDomain, providerConfig);
7714
+ allRecords.push(...domainRecords);
7715
+ const created = domainRecords.filter((r) => r.created).length;
7716
+ const existed = domainRecords.filter((r) => r.existed).length;
7717
+ const failed = domainRecords.filter((r) => r.error).length;
7718
+ if (created > 0) logger$1.log(` ✓ Created ${created} DNS record(s) for ${rootDomain}`);
7719
+ if (existed > 0) logger$1.log(` ✓ ${existed} record(s) already exist for ${rootDomain}`);
7720
+ if (failed > 0) {
7721
+ logger$1.log(` ⚠ ${failed} record(s) failed for ${rootDomain}`);
7722
+ hasFailures = true;
7723
+ }
7724
+ if (state) {
7725
+ for (const record of domainRecords) if (record.created || record.existed) setDnsRecord(state, {
7726
+ domain: rootDomain,
7727
+ name: record.subdomain,
7728
+ type: record.type,
7729
+ value: record.value,
7730
+ ttl: "ttl" in providerConfig && providerConfig.ttl ? providerConfig.ttl : 300
7731
+ });
7732
+ }
7733
+ printDnsRecordsTable(domainRecords, rootDomain);
7734
+ if (providerConfig.provider === "manual" || failed > 0) printDnsRecordsSimple(domainRecords.filter((r) => !r.created && !r.existed), rootDomain);
7735
+ }
7736
+ return {
7737
+ records: allRecords,
7738
+ success: !hasFailures,
7739
+ serverIp
7740
+ };
7741
+ }
7742
+ /**
7743
+ * Verify DNS records resolve correctly after deployment.
7744
+ *
7745
+ * This function:
7746
+ * 1. Checks state for previously verified hostnames (skips if already verified with same IP)
7747
+ * 2. Attempts to resolve each hostname to an IP
7748
+ * 3. Compares resolved IP with expected server IP
7749
+ * 4. Updates state with verification results
7750
+ *
7751
+ * @param appHostnames - Map of app names to hostnames
7752
+ * @param serverIp - Expected IP address the hostnames should resolve to
7753
+ * @param state - Deploy state for caching verification results
7754
+ * @returns Array of verification results
7755
+ */
7756
+ async function verifyDnsRecords(appHostnames, serverIp, state) {
7757
+ const results = [];
7758
+ logger$1.log("\n🔍 Verifying DNS records...");
7759
+ for (const [appName, hostname] of appHostnames) {
7760
+ if (isDnsVerified(state, hostname, serverIp)) {
7761
+ logger$1.log(` ✓ ${hostname} (previously verified)`);
7762
+ results.push({
7763
+ hostname,
7764
+ appName,
7765
+ verified: true,
7766
+ expectedIp: serverIp,
7767
+ skipped: true
7768
+ });
7769
+ continue;
7770
+ }
7771
+ try {
7772
+ const resolvedIp = await resolveHostnameToIp(hostname);
7773
+ if (resolvedIp === serverIp) {
7774
+ setDnsVerification(state, hostname, serverIp);
7775
+ logger$1.log(` ✓ ${hostname} → ${resolvedIp}`);
7776
+ results.push({
7777
+ hostname,
7778
+ appName,
7779
+ verified: true,
7780
+ resolvedIp,
7781
+ expectedIp: serverIp
7782
+ });
7783
+ } else {
7784
+ logger$1.log(` ⚠ ${hostname} resolves to ${resolvedIp}, expected ${serverIp}`);
7785
+ results.push({
7786
+ hostname,
7787
+ appName,
7788
+ verified: false,
7789
+ resolvedIp,
7790
+ expectedIp: serverIp
7791
+ });
7792
+ }
7793
+ } catch (error) {
7794
+ const message = error instanceof Error ? error.message : "Unknown error";
7795
+ logger$1.log(` ⚠ ${hostname} DNS not propagated (${message})`);
7796
+ results.push({
7797
+ hostname,
7798
+ appName,
7799
+ verified: false,
7800
+ expectedIp: serverIp,
7801
+ error: message
7802
+ });
7803
+ }
7804
+ }
7805
+ const verified = results.filter((r) => r.verified).length;
7806
+ const skipped = results.filter((r) => r.skipped).length;
7807
+ const pending = results.filter((r) => !r.verified).length;
7808
+ if (pending > 0) {
7809
+ logger$1.log(`\n ${verified} verified, ${pending} pending propagation`);
7810
+ logger$1.log(" DNS changes may take 5-30 minutes to propagate");
7811
+ } else if (skipped > 0) logger$1.log(` ${verified} verified (${skipped} from cache)`);
7812
+ return results;
7813
+ }
7814
+ //#endregion
7237
7815
  //#region src/docker/imageRef.ts
7238
7816
  /**
7239
7817
  * An image reference, checked before it reaches `docker`.
@@ -7717,149 +8295,6 @@ var DeployJournal = class DeployJournal {
7717
8295
  }
7718
8296
  };
7719
8297
  //#endregion
7720
- //#region src/deploy/state.ts
7721
- /**
7722
- * Create a new empty state for a stage
7723
- */
7724
- function createEmptyState(stage, projectId, environmentId) {
7725
- return {
7726
- provider: "dokploy",
7727
- stage,
7728
- projectId,
7729
- environmentId,
7730
- applications: {},
7731
- services: {},
7732
- lastDeployedAt: (/* @__PURE__ */ new Date()).toISOString()
7733
- };
7734
- }
7735
- /**
7736
- * Set application ID in state (mutates state)
7737
- */
7738
- function setApplicationId(state, appName, applicationId) {
7739
- state.applications[appName] = applicationId;
7740
- }
7741
- /** Two records naming the same image: by digest when both have one. */
7742
- function sameImage(a, b) {
7743
- return a.digest && b.digest ? a.digest === b.digest : a.ref === b.ref;
7744
- }
7745
- /** The newest release in `history` after `index` that a rollback may restore. */
7746
- function restorable(history, index, current) {
7747
- return history.slice(index + 1).find((entry) => !entry.rolledBack && !sameImage(entry, current));
7748
- }
7749
- /**
7750
- * Record that `image` went live for `appName` (mutates state): it becomes
7751
- * `current`, and what was current becomes `previous`. Releasing what already
7752
- * runs — a redeploy of the same digest — changes nothing.
7753
- */
7754
- function recordRelease(state, appName, image, releasedAt = /* @__PURE__ */ new Date()) {
7755
- const releases = state.releases?.[appName];
7756
- if (releases && sameImage(releases.current, image)) return;
7757
- const entry = {
7758
- ...image,
7759
- releasedAt: releasedAt.toISOString()
7760
- };
7761
- const history = [entry, ...releases?.history ?? []].slice(0, 10);
7762
- const previous = releases?.current;
7763
- state.releases = {
7764
- ...state.releases,
7765
- [appName]: {
7766
- current: entry,
7767
- ...previous ? { previous } : {},
7768
- history
7769
- }
7770
- };
7771
- }
7772
- /**
7773
- * Record that `appName` was rolled back to `to` (mutates state): every
7774
- * release newer than it is marked rolled back, so neither this rollback nor
7775
- * a later one restores it, and `previous` moves to the release before `to`.
7776
- */
7777
- function recordRollback(state, appName, to) {
7778
- const releases = state.releases?.[appName];
7779
- if (!releases) return;
7780
- const index = releases.history.findIndex((entry) => !entry.rolledBack && sameImage(entry, to));
7781
- if (index === -1) return;
7782
- const history = releases.history.map((entry, i) => i < index ? {
7783
- ...entry,
7784
- rolledBack: true
7785
- } : entry);
7786
- const current = history[index];
7787
- const previous = restorable(history, index, current);
7788
- state.releases = {
7789
- ...state.releases,
7790
- [appName]: {
7791
- current,
7792
- ...previous ? { previous } : {},
7793
- history
7794
- }
7795
- };
7796
- }
7797
- /**
7798
- * Get a generated secret for an app
7799
- */
7800
- function getGeneratedSecret(state, appName, secretName) {
7801
- return state?.generatedSecrets?.[appName]?.[secretName];
7802
- }
7803
- /**
7804
- * Set a generated secret for an app (mutates state)
7805
- */
7806
- function setGeneratedSecret(state, appName, secretName, value) {
7807
- if (!state.generatedSecrets) state.generatedSecrets = {};
7808
- if (!state.generatedSecrets[appName]) state.generatedSecrets[appName] = {};
7809
- state.generatedSecrets[appName][secretName] = value;
7810
- }
7811
- /**
7812
- * Set DNS verification record for a hostname (mutates state)
7813
- */
7814
- function setDnsVerification(state, hostname, serverIp) {
7815
- if (!state.dnsVerified) state.dnsVerified = {};
7816
- state.dnsVerified[hostname] = {
7817
- serverIp,
7818
- verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
7819
- };
7820
- }
7821
- /**
7822
- * Check if a hostname is already verified with the given IP
7823
- */
7824
- function isDnsVerified(state, hostname, serverIp) {
7825
- return (state?.dnsVerified?.[hostname])?.serverIp === serverIp;
7826
- }
7827
- /**
7828
- * Get the key for a DNS record in state
7829
- */
7830
- function getDnsRecordKey(name, type) {
7831
- return `${name}:${type}`;
7832
- }
7833
- /**
7834
- * Set a created DNS record in state (mutates state)
7835
- */
7836
- function setDnsRecord(state, record) {
7837
- if (!state.dnsRecords) state.dnsRecords = {};
7838
- const key = getDnsRecordKey(record.name, record.type);
7839
- state.dnsRecords[key] = {
7840
- ...record,
7841
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
7842
- };
7843
- }
7844
- /**
7845
- * Get backup state from state
7846
- */
7847
- function getBackupState(state) {
7848
- return state?.backups;
7849
- }
7850
- /**
7851
- * Set backup state (mutates state)
7852
- */
7853
- function setBackupState(state, backupState) {
7854
- state.backups = backupState;
7855
- }
7856
- /**
7857
- * Set postgres backup ID in state (mutates state)
7858
- */
7859
- function setPostgresBackupId(state, backupId) {
7860
- if (state.backups) state.backups.postgresBackupId = backupId;
7861
- }
7862
- //#endregion
7863
8298
  //#region src/providers/aws.ts
7864
8299
  /**
7865
8300
  * The AWS account a provider provisions in — the stage's, found the way the
@@ -8055,7 +8490,7 @@ function bucketOrigins(input) {
8055
8490
  continue;
8056
8491
  }
8057
8492
  try {
8058
- const host = resolveHost(name, app, stage, workspace.deploy?.domains, isMainFrontendApp(name, app, workspace.apps));
8493
+ const host = resolveHost(name, app, stage, workspace.domains, isMainFrontendApp(name, app, workspace.apps));
8059
8494
  origins.add(`https://${host}`);
8060
8495
  } catch (error) {
8061
8496
  if (!(error instanceof NoDomainForStage)) throw error;
@@ -8497,7 +8932,7 @@ async function ensureBucketSettings(ctx, clients, input) {
8497
8932
  stage: ctx.stage,
8498
8933
  bucket: id
8499
8934
  });
8500
- if (unresolved.length > 0) ctx.log(` ${unresolved.join(", ")} ${unresolved.length === 1 ? "has" : "have"} no address on '${ctx.stage}' (deploy.domains.${ctx.stage}), so ${unresolved.length === 1 ? "is" : "are"} not in '${bucket}''s CORS`);
8935
+ if (unresolved.length > 0) ctx.log(` ${unresolved.join(", ")} ${unresolved.length === 1 ? "has" : "have"} no address on '${ctx.stage}' (domains.${ctx.stage}), so ${unresolved.length === 1 ? "is" : "are"} not in '${bucket}''s CORS`);
8501
8936
  if (origins.length === 0) return;
8502
8937
  const rule = corsRule(origins);
8503
8938
  const cors = await read(() => s3.send(new S3.GetBucketCorsCommand({ Bucket })), ["NoSuchCORSConfiguration"]);
@@ -9046,6 +9481,6 @@ function reportPlannedSeeds(planned, log) {
9046
9481
  for (const { folder, seeds } of planned) log(`🌱 ${folder}: would run ${seeds.length} (${seeds.join(", ")})`);
9047
9482
  }
9048
9483
  //#endregion
9049
- export { suppliedOnly as $, stackLogs as $n, storageBackendFor as $t, workerDockerfileOf as A, store_exports as An, postgresStatements as At, newLockHolder as B, isOwnedBy as Bn, envFor as Bt, stageProviderNotes as C, loadEnvFiles as Cn, LOCAL_CA_PATH as Ct, dockerCommand as D, isRemoteStore as Dn, applyPostgres as Dt, appDockerfile as E, prepareEntryCredentials as En, applyPolicies as Et, StateStoreBusy as F, readKey as Fn, pgClient as Ft, STORAGE_KEY_PAIR as G, maskPassword as Gn, WORKER_PORT as Gt, DEV_SERVICES as H, ownershipMarker as Hn, composeBuildPaths as Ht, StateStoreWithoutLocking as I, applicationName as In, appEnvKeys as It, devServicesUsed as J, withCustomSecret as Jn, imageBuildCredentials as Jt, assertDevServicesFlag as K, storage_exports as Kn, detectPackageManager as Kt, StateVersionConflict as L, deployIdentity as Ln, dockerfileOf as Lt, DocumentStateStore as M, getKeyPath as Mn, LEGACY_LOCAL_LOGIN as Mt, StageStateMissing as N, keystoreProject as Nn, ensurePostgresLogin as Nt, ensureDockerignore as O, secretsStoreFor as On, bucketPolicies as Ot, StateLocked as P, projectKey as Pn, bucketClient as Pt, requiredStageKeys as Q, logsService as Qn, providerOf as Qt, contentVersion as R, imageName as Rn, networkEnv as Rt, provisionCommand as S, isPortAvailable as Sn, withRedisPassword as St, DockerPushFailed as T, loadSecretsForApp as Tn, applyBuckets as Tt, DevServicesNeedServerTarget as U, projectName as Un, imageLayout as Ut, AllowDevServicesTakesNoValue as V, markerOf as Vn, localRolePassword as Vt, ExternalServicesNotConfigured as W, initStageSecrets as Wn, TURBO_VERSION as Wt, manifestServiceDeclarations as X, LOGS_SERVICE as Xn, cacheBackendFor as Xt, externalServices as Y, LOCAL_LOGS_EMAIL as Yn, isImageBuild as Yt, reportDevServices as Z, logsAccess as Zn, eventsBackendFor as Zt, setGeneratedSecret as _, portsOf as _n, REDIS_SERVICE as _t, provisionStage as a, resourceName as an, CronGenerator as at, StageProviderDisabled as b, createEntryWrapper as bn, runsRedis as bt, getBackupState as c, isTelemetryKey as cn, constructGlobs as ct, recordRelease as d, telemetryOf as dn, workspace_exports as dt, CLUSTER_DATABASE as en, withLogsPassword as er, workerUnits as et, recordRollback as f, usesTelemetry as fn, LOCAL_RABBITMQ_USER as ft, setDnsVerification as g, portKeys as gn, withGeneratedSecrets as gt, setDnsRecord as h, fakeKey as hn, readLocalCredentials as ht, assertNoStaleSecrets as i, planFor as in, QueueGenerator as it, validateImageRef as j, FileSecretsStore as jn, quoteIdentifier as jt, workerDockerfile as k, storeFromConfig as kn, postgresDatabaseNames as kt, getGeneratedSecret as l, scopeTelemetryEnv as ln, derivedContainers as lt, setBackupState as m, describeServices as mn, postgresSuperuser as mt, reportDatabaseRuns as n, EMULATOR_ACCESS_KEY_ID as nn, isMainFrontendApp as nr, workerBundleName as nt, verifyStageProviders as o, hostFor as on, FAKE_ENV as ot, setApplicationId as p, DEFAULT_IMAGES as pn, loadLocalCredentials as pt, assertExternalServices as q, toEmbeddableSecrets as qn, findBuildRoot as qt, reportPlannedSeeds as r, TELEMETRY_CONTAINER as rn, resolveHost as rr, workerEntryDir as rt, createEmptyState as s, appTelemetry as sn, backendsOf as st, DeploySeedsFailed as t, composeFor as tn, NoDomainForStage as tr, WorkerGenerator as tt, isDnsVerified as u, surfaceClientTraced as un, reconcileWorkspace as ut, setPostgresBackupId as v, primaryPortKey as vn, STACK_CACHE as vt, DockerBuildFailed as w, loadPortState as wn, forgetState as wt, assertStageProvidersEnabled as x, findAvailablePort as xn, stackRedis as xt, DeployJournal as y, createCredentialsPreload as yn, redisService as yt, createStateStore as z, imageRef as zn, workerEnvKeys as zt };
9484
+ export { externalServices as $, LOCAL_LOGS_EMAIL as $n, isImageBuild as $t, setApplicationId as A, prepareEntryCredentials as An, applyPolicies as At, StateStoreWithoutLocking as B, applicationName as Bn, appEnvKeys as Bt, orchestrateDns as C, createCredentialsPreload as Cn, redisService as Ct, getGeneratedSecret as D, loadEnvFiles as Dn, LOCAL_CA_PATH as Dt, getBackupState as E, isPortAvailable as En, withRedisPassword as Et, createDnsProvider as F, FileSecretsStore as Fn, quoteIdentifier as Ft, AllowDevServicesTakesNoValue as G, markerOf as Gn, localRolePassword as Gt, contentVersion as H, imageName as Hn, networkEnv as Ht, DocumentStateStore as I, getKeyPath as In, LEGACY_LOCAL_LOGIN as It, ExternalServicesNotConfigured as J, initStageSecrets as Jn, TURBO_VERSION as Jt, DEV_SERVICES as K, ownershipMarker as Kn, composeBuildPaths as Kt, StageStateMissing as L, keystoreProject as Ln, ensurePostgresLogin as Lt, setGeneratedSecret as M, secretsStoreFor as Mn, bucketPolicies as Mt, setPostgresBackupId as N, storeFromConfig as Nn, postgresDatabaseNames as Nt, recordRelease as O, loadPortState as On, forgetState as Ot, DnsRecordsUnreadable as P, store_exports as Pn, postgresStatements as Pt, devServicesUsed as Q, withCustomSecret as Qn, imageBuildCredentials as Qt, StateLocked as R, projectKey as Rn, bucketClient as Rt, normalizeDnsConfig as S, primaryPortKey as Sn, STACK_CACHE as St, createEmptyState as T, findAvailablePort as Tn, stackRedis as Tt, createStateStore as U, imageRef as Un, workerEnvKeys as Ut, StateVersionConflict as V, deployIdentity as Vn, dockerfileOf as Vt, newLockHolder as W, isOwnedBy as Wn, envFor as Wt, assertDevServicesFlag as X, storage_exports as Xn, detectPackageManager as Xt, STORAGE_KEY_PAIR as Y, maskPassword as Yn, WORKER_PORT as Yt, assertExternalServices as Z, toEmbeddableSecrets as Zn, findBuildRoot as Zt, workerDockerfile as _, DEFAULT_IMAGES as _n, loadLocalCredentials as _t, provisionStage as a, composeFor as an, NoDomainForStage as ar, WorkerGenerator as at, extractSubdomain as b, portKeys as bn, withGeneratedSecrets as bt, StageProviderDisabled as c, planFor as cn, QueueGenerator as ct, stageProviderNotes as d, appTelemetry as dn, backendsOf as dt, cacheBackendFor as en, LOGS_SERVICE as er, manifestServiceDeclarations as et, DockerBuildFailed as f, isTelemetryKey as fn, constructGlobs as ft, ensureDockerignore as g, usesTelemetry as gn, LOCAL_RABBITMQ_USER as gt, dockerCommand as h, telemetryOf as hn, workspace_exports as ht, assertNoStaleSecrets as i, CLUSTER_DATABASE as in, withLogsPassword as ir, workerUnits as it, setBackupState as j, isRemoteStore as jn, applyPostgres as jt, recordRollback as k, loadSecretsForApp as kn, applyBuckets as kt, assertStageProvidersEnabled as l, resourceName as ln, CronGenerator as lt, appDockerfile as m, surfaceClientTraced as mn, reconcileWorkspace as mt, reportDatabaseRuns as n, providerOf as nn, logsService as nr, requiredStageKeys as nt, verifyStageProviders as o, EMULATOR_ACCESS_KEY_ID as on, isMainFrontendApp as or, workerBundleName as ot, DockerPushFailed as p, scopeTelemetryEnv as pn, derivedContainers as pt, DevServicesNeedServerTarget as q, projectName as qn, imageLayout as qt, reportPlannedSeeds as r, storageBackendFor as rn, stackLogs as rr, suppliedOnly as rt, DeployJournal as s, TELEMETRY_CONTAINER as sn, resolveHost as sr, workerEntryDir as st, DeploySeedsFailed as t, eventsBackendFor as tn, logsAccess as tr, reportDevServices as tt, provisionCommand as u, hostFor as un, FAKE_ENV as ut, workerDockerfileOf as v, describeServices as vn, postgresSuperuser as vt, verifyDnsRecords as w, createEntryWrapper as wn, runsRedis as wt, findRootDomain as x, portsOf as xn, REDIS_SERVICE as xt, validateImageRef as y, fakeKey as yn, readLocalCredentials as yt, StateStoreBusy as z, readKey as zn, pgClient as zt };
9050
9485
 
9051
- //# sourceMappingURL=seeds-BYdrtZsC.mjs.map
9486
+ //# sourceMappingURL=seeds-perzdN81.mjs.map