@geekmidas/cli 10.0.0-alpha.65 → 10.0.0-alpha.66

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 (208) hide show
  1. package/README.md +14 -0
  2. package/dist/{HostingerProvider-Dlmbfass.cjs → HostingerProvider-BznqRC2S.cjs} +3 -3
  3. package/dist/HostingerProvider-BznqRC2S.cjs.map +1 -0
  4. package/dist/{HostingerProvider-x9gQTAGZ.mjs → HostingerProvider-CY_VpVud.mjs} +3 -3
  5. package/dist/HostingerProvider-CY_VpVud.mjs.map +1 -0
  6. package/dist/{LegacyStateStore-BGoo__sO.cjs → LegacyStateStore-BFcTT2QL.cjs} +2 -2
  7. package/dist/{LegacyStateStore-BGoo__sO.cjs.map → LegacyStateStore-BFcTT2QL.cjs.map} +1 -1
  8. package/dist/{LegacyStateStore-BUu1nQ5u.mjs → LegacyStateStore-CFheFo62.mjs} +2 -2
  9. package/dist/{LegacyStateStore-BUu1nQ5u.mjs.map → LegacyStateStore-CFheFo62.mjs.map} +1 -1
  10. package/dist/{LocalStateStore-93urXyQe.cjs → LocalStateStore-BVUexSvu.cjs} +2 -2
  11. package/dist/{LocalStateStore-93urXyQe.cjs.map → LocalStateStore-BVUexSvu.cjs.map} +1 -1
  12. package/dist/{LocalStateStore-BRhMQRuy.mjs → LocalStateStore-Bm3x9oOg.mjs} +2 -2
  13. package/dist/{LocalStateStore-BRhMQRuy.mjs.map → LocalStateStore-Bm3x9oOg.mjs.map} +1 -1
  14. package/dist/{OpenApiTsGenerator-BWuDRHe9.cjs → OpenApiTsGenerator-B2zrdyP4.cjs} +2 -2
  15. package/dist/{OpenApiTsGenerator-BWuDRHe9.cjs.map → OpenApiTsGenerator-B2zrdyP4.cjs.map} +1 -1
  16. package/dist/{OpenApiTsGenerator-C6v-IeHt.mjs → OpenApiTsGenerator-BmUAcR7d.mjs} +2 -2
  17. package/dist/{OpenApiTsGenerator-C6v-IeHt.mjs.map → OpenApiTsGenerator-BmUAcR7d.mjs.map} +1 -1
  18. package/dist/{Route53Provider-DVILBsvV.cjs → Route53Provider-Bllus2NR.cjs} +2 -2
  19. package/dist/Route53Provider-Bllus2NR.cjs.map +1 -0
  20. package/dist/{Route53Provider-Cvj40A8I.mjs → Route53Provider-QXxjkZO1.mjs} +2 -2
  21. package/dist/Route53Provider-QXxjkZO1.mjs.map +1 -0
  22. package/dist/{S3StateStore-pw1GhWwt.mjs → S3StateStore-BFHuctWM.mjs} +2 -2
  23. package/dist/{S3StateStore-pw1GhWwt.mjs.map → S3StateStore-BFHuctWM.mjs.map} +1 -1
  24. package/dist/{S3StateStore-F4dxw6kS.cjs → S3StateStore-CoXBhILd.cjs} +2 -2
  25. package/dist/{S3StateStore-F4dxw6kS.cjs.map → S3StateStore-CoXBhILd.cjs.map} +1 -1
  26. package/dist/{SSMStateStore-Bt9acuAF.cjs → SSMStateStore-BqCA9TP2.cjs} +2 -2
  27. package/dist/{SSMStateStore-Bt9acuAF.cjs.map → SSMStateStore-BqCA9TP2.cjs.map} +1 -1
  28. package/dist/{SSMStateStore-Dmj7zzFO.mjs → SSMStateStore-C1kvHScY.mjs} +2 -2
  29. package/dist/{SSMStateStore-Dmj7zzFO.mjs.map → SSMStateStore-C1kvHScY.mjs.map} +1 -1
  30. package/dist/{backup-provisioner-DIVCbfee.mjs → backup-provisioner-C8DnCmxK.mjs} +2 -2
  31. package/dist/backup-provisioner-C8DnCmxK.mjs.map +1 -0
  32. package/dist/{backup-provisioner-BmhIO_Yr.cjs → backup-provisioner-oDEsPj02.cjs} +2 -2
  33. package/dist/backup-provisioner-oDEsPj02.cjs.map +1 -0
  34. package/dist/{bundler-D_14JLZF.mjs → bundler-Dvaiud0h.mjs} +4 -4
  35. package/dist/{bundler-D_14JLZF.mjs.map → bundler-Dvaiud0h.mjs.map} +1 -1
  36. package/dist/{bundler-D6MlIfBT.cjs → bundler-orRqUJNZ.cjs} +4 -4
  37. package/dist/{bundler-D6MlIfBT.cjs.map → bundler-orRqUJNZ.cjs.map} +1 -1
  38. package/dist/{cli-P56vvrDQ.mjs → cli-CfHm0AO7.mjs} +5 -4
  39. package/dist/cli-CfHm0AO7.mjs.map +1 -0
  40. package/dist/{cli-BfH1deAT.cjs → cli-D1JkkOwg.cjs} +5 -4
  41. package/dist/cli-D1JkkOwg.cjs.map +1 -0
  42. package/dist/{compose-DprE3ASm.mjs → compose-CNQL8BnO.mjs} +18 -482
  43. package/dist/compose-CNQL8BnO.mjs.map +1 -0
  44. package/dist/{compose-391oEKj1.cjs → compose-jrLy7KGO.cjs} +16 -571
  45. package/dist/compose-jrLy7KGO.cjs.map +1 -0
  46. package/dist/{config-V_X_BMpm.d.cts → config-4XFxX1al.d.cts} +3 -3
  47. package/dist/{config-BonvTW8p.d.mts.map → config-4XFxX1al.d.cts.map} +1 -1
  48. package/dist/{config-BonvTW8p.d.mts → config-UtKzhpFb.d.mts} +3 -3
  49. package/dist/{config-V_X_BMpm.d.cts.map → config-UtKzhpFb.d.mts.map} +1 -1
  50. package/dist/config.cjs +3 -3
  51. package/dist/config.d.cts +3 -3
  52. package/dist/config.d.mts +3 -3
  53. package/dist/config.mjs +3 -3
  54. package/dist/databases-C2p5LGAp.cjs +419 -0
  55. package/dist/databases-C2p5LGAp.cjs.map +1 -0
  56. package/dist/databases-hUHTuwhx.mjs +346 -0
  57. package/dist/databases-hUHTuwhx.mjs.map +1 -0
  58. package/dist/deploy/public.cjs +26 -17
  59. package/dist/deploy/public.d.cts +136 -19
  60. package/dist/deploy/public.d.cts.map +1 -1
  61. package/dist/deploy/public.d.mts +136 -19
  62. package/dist/deploy/public.d.mts.map +1 -1
  63. package/dist/deploy/public.mjs +8 -8
  64. package/dist/deploy-B7aJi_Ah.cjs +511 -0
  65. package/dist/deploy-B7aJi_Ah.cjs.map +1 -0
  66. package/dist/deploy-DWn7YfIc.mjs +488 -0
  67. package/dist/deploy-DWn7YfIc.mjs.map +1 -0
  68. package/dist/{discover-LMrqsWSU.mjs → discover-BFoJWKGD.mjs} +4 -2
  69. package/dist/discover-BFoJWKGD.mjs.map +1 -0
  70. package/dist/{discover-DHdECueV.cjs → discover-OEfZ9OkA.cjs} +4 -2
  71. package/dist/discover-OEfZ9OkA.cjs.map +1 -0
  72. package/dist/dokploy-B4LcYG1E.cjs +38 -0
  73. package/dist/dokploy-B4LcYG1E.cjs.map +1 -0
  74. package/dist/dokploy-DalwLML5.mjs +38 -0
  75. package/dist/dokploy-DalwLML5.mjs.map +1 -0
  76. package/dist/{encryption-B1wJwgae.cjs → encryption-3KlGS1sl.cjs} +5 -7
  77. package/dist/{encryption-B1wJwgae.cjs.map → encryption-3KlGS1sl.cjs.map} +1 -1
  78. package/dist/{encryption-DF_hgIpl.mjs → encryption-CPfENwWO.mjs} +3 -5
  79. package/dist/{encryption-DF_hgIpl.mjs.map → encryption-CPfENwWO.mjs.map} +1 -1
  80. package/dist/{deploy-CZ5nlpsu.mjs → engine-CunvOG3s.mjs} +2100 -1733
  81. package/dist/engine-CunvOG3s.mjs.map +1 -0
  82. package/dist/{deploy-Cy8igpQF.cjs → engine-DR6KurWX.cjs} +2136 -1727
  83. package/dist/engine-DR6KurWX.cjs.map +1 -0
  84. package/dist/{github-CYcmTdFs.cjs → github-BJ5gh9bw.cjs} +7 -7
  85. package/dist/{github-CYcmTdFs.cjs.map → github-BJ5gh9bw.cjs.map} +1 -1
  86. package/dist/{github-B0YYE98x.mjs → github-MXA9v7Ge.mjs} +3 -3
  87. package/dist/{github-B0YYE98x.mjs.map → github-MXA9v7Ge.mjs.map} +1 -1
  88. package/dist/{index-DwKD_8lt.d.mts → index-CyApaHVe.d.cts} +2 -2
  89. package/dist/{index-DPUAGJaK.d.cts.map → index-CyApaHVe.d.cts.map} +1 -1
  90. package/dist/{index-DPUAGJaK.d.cts → index-DD1FfUHh.d.mts} +2 -2
  91. package/dist/{index-DwKD_8lt.d.mts.map → index-DD1FfUHh.d.mts.map} +1 -1
  92. package/dist/index.cjs +276 -68
  93. package/dist/index.cjs.map +1 -1
  94. package/dist/index.mjs +254 -50
  95. package/dist/index.mjs.map +1 -1
  96. package/dist/{migrate-B2qL5wj4.mjs → migrate-BJBcm4sG.mjs} +6 -6
  97. package/dist/{migrate-B2qL5wj4.mjs.map → migrate-BJBcm4sG.mjs.map} +1 -1
  98. package/dist/{migrate-q4pPAXtO.cjs → migrate-CF4J4GQS.cjs} +16 -16
  99. package/dist/{migrate-q4pPAXtO.cjs.map → migrate-CF4J4GQS.cjs.map} +1 -1
  100. package/dist/openapi.cjs +1 -1
  101. package/dist/openapi.d.cts +1 -1
  102. package/dist/openapi.d.mts +1 -1
  103. package/dist/openapi.mjs +1 -1
  104. package/dist/provider-B3Sv_a74.cjs +173 -0
  105. package/dist/provider-B3Sv_a74.cjs.map +1 -0
  106. package/dist/provider-D7rQzzzf.mjs +138 -0
  107. package/dist/provider-D7rQzzzf.mjs.map +1 -0
  108. package/dist/{ready-bQfu9GES.mjs → ready-2s3-CndS.mjs} +3 -3
  109. package/dist/{ready-bQfu9GES.mjs.map → ready-2s3-CndS.mjs.map} +1 -1
  110. package/dist/{ready-brEhh68f.cjs → ready-B6uHr4sm.cjs} +3 -3
  111. package/dist/{ready-brEhh68f.cjs.map → ready-B6uHr4sm.cjs.map} +1 -1
  112. package/dist/reconcile/public.cjs +1 -1
  113. package/dist/reconcile/public.d.cts +1 -1
  114. package/dist/reconcile/public.d.mts +1 -1
  115. package/dist/reconcile/public.mjs +1 -1
  116. package/dist/{resolve-N_i4XNd-.cjs → resolve-CVmch0wI.cjs} +3 -3
  117. package/dist/{resolve-N_i4XNd-.cjs.map → resolve-CVmch0wI.cjs.map} +1 -1
  118. package/dist/{resolve-DLkIXTct.mjs → resolve-Db0tNlrW.mjs} +3 -3
  119. package/dist/{resolve-DLkIXTct.mjs.map → resolve-Db0tNlrW.mjs.map} +1 -1
  120. package/dist/rollback-DvAo4OKS.mjs +133 -0
  121. package/dist/rollback-DvAo4OKS.mjs.map +1 -0
  122. package/dist/rollback-DxJK84hy.cjs +162 -0
  123. package/dist/rollback-DxJK84hy.cjs.map +1 -0
  124. package/dist/{runtime-BnD7Nn96.d.cts → runtime-BRqFOvPM.d.cts} +2 -2
  125. package/dist/{runtime-BnD7Nn96.d.cts.map → runtime-BRqFOvPM.d.cts.map} +1 -1
  126. package/dist/{runtime-j-tmFL65.d.mts → runtime-CEk5n4VH.d.mts} +2 -2
  127. package/dist/{runtime-j-tmFL65.d.mts.map → runtime-CEk5n4VH.d.mts.map} +1 -1
  128. package/dist/sandbox/discover-worker.cjs +1 -1
  129. package/dist/sandbox/discover-worker.mjs +1 -1
  130. package/dist/sandbox/migrate-worker.cjs +61 -0
  131. package/dist/sandbox/migrate-worker.cjs.map +1 -0
  132. package/dist/sandbox/migrate-worker.d.cts +1 -0
  133. package/dist/sandbox/migrate-worker.d.mts +1 -0
  134. package/dist/sandbox/migrate-worker.mjs +62 -0
  135. package/dist/sandbox/migrate-worker.mjs.map +1 -0
  136. package/dist/{schemas-D2LCF689.mjs → schemas-Cfhtpdo0.mjs} +10 -2
  137. package/dist/{schemas-Ckm_aBnF.cjs.map → schemas-Cfhtpdo0.mjs.map} +1 -1
  138. package/dist/{schemas-Ckm_aBnF.cjs → schemas-RUlKHu27.cjs} +15 -1
  139. package/dist/{schemas-D2LCF689.mjs.map → schemas-RUlKHu27.cjs.map} +1 -1
  140. package/dist/{sniffer-BSwaL-dX.cjs → sniffer-5xmrkh2a.cjs} +112 -606
  141. package/dist/sniffer-5xmrkh2a.cjs.map +1 -0
  142. package/dist/{sniffer-BZ-OJO4Y.mjs → sniffer-BAQhLEsI.mjs} +95 -546
  143. package/dist/sniffer-BAQhLEsI.mjs.map +1 -0
  144. package/dist/{state-DF26e_lo.cjs → state-Y6ATakMX.cjs} +744 -20
  145. package/dist/state-Y6ATakMX.cjs.map +1 -0
  146. package/dist/{state-B8YwmUZU.mjs → state-uuYqnRVO.mjs} +605 -19
  147. package/dist/state-uuYqnRVO.mjs.map +1 -0
  148. package/dist/target/public.cjs +1 -1
  149. package/dist/target/public.d.cts +2 -2
  150. package/dist/target/public.d.mts +2 -2
  151. package/dist/target/public.mjs +1 -1
  152. package/dist/{terminal-Bs5E1oxm.cjs → terminal-CHy_MdjG.cjs} +11 -15
  153. package/dist/{terminal-Bs5E1oxm.cjs.map → terminal-CHy_MdjG.cjs.map} +1 -1
  154. package/dist/{terminal-CfbiYUbZ.mjs → terminal-DUhcZ1ND.mjs} +4 -4
  155. package/dist/{terminal-CfbiYUbZ.mjs.map → terminal-DUhcZ1ND.mjs.map} +1 -1
  156. package/dist/{types-ByMWkXKP.d.cts → types-CSw2w69a.d.mts} +68 -10
  157. package/dist/types-CSw2w69a.d.mts.map +1 -0
  158. package/dist/{types-BCzMWBb6.d.mts → types-D5WIxRDP.d.cts} +69 -9
  159. package/dist/types-D5WIxRDP.d.cts.map +1 -0
  160. package/dist/vitest.cjs +1 -1
  161. package/dist/vitest.mjs +1 -1
  162. package/dist/workspace/index.cjs +1 -1
  163. package/dist/workspace/index.d.cts +2 -2
  164. package/dist/workspace/index.d.mts +2 -2
  165. package/dist/workspace/index.mjs +1 -1
  166. package/dist/{workspace-C06_pW4g.mjs → workspace-Be6uBhlF.mjs} +10 -3
  167. package/dist/workspace-Be6uBhlF.mjs.map +1 -0
  168. package/dist/{workspace-BewAHZIo.cjs → workspace-ON-bqiJz.cjs} +10 -3
  169. package/dist/workspace-ON-bqiJz.cjs.map +1 -0
  170. package/package.json +13 -13
  171. package/dist/HostingerProvider-Dlmbfass.cjs.map +0 -1
  172. package/dist/HostingerProvider-x9gQTAGZ.mjs.map +0 -1
  173. package/dist/Route53Provider-Cvj40A8I.mjs.map +0 -1
  174. package/dist/Route53Provider-DVILBsvV.cjs.map +0 -1
  175. package/dist/backup-provisioner-BmhIO_Yr.cjs.map +0 -1
  176. package/dist/backup-provisioner-DIVCbfee.mjs.map +0 -1
  177. package/dist/cli-BfH1deAT.cjs.map +0 -1
  178. package/dist/cli-P56vvrDQ.mjs.map +0 -1
  179. package/dist/compose-391oEKj1.cjs.map +0 -1
  180. package/dist/compose-DprE3ASm.mjs.map +0 -1
  181. package/dist/deploy-9MBG_QLd.mjs +0 -137
  182. package/dist/deploy-9MBG_QLd.mjs.map +0 -1
  183. package/dist/deploy-B80idPUZ.cjs +0 -142
  184. package/dist/deploy-B80idPUZ.cjs.map +0 -1
  185. package/dist/deploy-CZ5nlpsu.mjs.map +0 -1
  186. package/dist/deploy-Cy8igpQF.cjs.map +0 -1
  187. package/dist/discover-DHdECueV.cjs.map +0 -1
  188. package/dist/discover-LMrqsWSU.mjs.map +0 -1
  189. package/dist/dokploy-BdtBePjp.mjs +0 -32
  190. package/dist/dokploy-BdtBePjp.mjs.map +0 -1
  191. package/dist/dokploy-iFY8MY-L.cjs +0 -32
  192. package/dist/dokploy-iFY8MY-L.cjs.map +0 -1
  193. package/dist/sniffer-BSwaL-dX.cjs.map +0 -1
  194. package/dist/sniffer-BZ-OJO4Y.mjs.map +0 -1
  195. package/dist/state-B8YwmUZU.mjs.map +0 -1
  196. package/dist/state-DF26e_lo.cjs.map +0 -1
  197. package/dist/storage-BzaUxmqe.mjs +0 -124
  198. package/dist/storage-BzaUxmqe.mjs.map +0 -1
  199. package/dist/storage-CSGoC3bK.cjs +0 -152
  200. package/dist/storage-CSGoC3bK.cjs.map +0 -1
  201. package/dist/store-CJF1Tqkq.cjs +0 -510
  202. package/dist/store-CJF1Tqkq.cjs.map +0 -1
  203. package/dist/store-CLiHnqOY.mjs +0 -415
  204. package/dist/store-CLiHnqOY.mjs.map +0 -1
  205. package/dist/types-BCzMWBb6.d.mts.map +0 -1
  206. package/dist/types-ByMWkXKP.d.cts.map +0 -1
  207. package/dist/workspace-BewAHZIo.cjs.map +0 -1
  208. package/dist/workspace-C06_pW4g.mjs.map +0 -1
@@ -1,12 +1,10 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
2
  const require_local = require("./local-BdH4XN0E.cjs");
3
- const require_discover = require("./discover-DHdECueV.cjs");
3
+ const require_discover = require("./discover-OEfZ9OkA.cjs");
4
4
  const require_derive = require("./derive-DAbo49sm.cjs");
5
- const require_workspace = require("./workspace-BewAHZIo.cjs");
5
+ const require_workspace = require("./workspace-ON-bqiJz.cjs");
6
6
  const require_config = require("./config.cjs");
7
- const require_storage = require("./storage-CSGoC3bK.cjs");
8
- const require_store = require("./store-CJF1Tqkq.cjs");
9
- const require_resolve = require("./resolve-N_i4XNd-.cjs");
7
+ const require_resolve = require("./resolve-CVmch0wI.cjs");
10
8
  const require_fakes = require("./fakes-zW-jNAbQ.cjs");
11
9
  let node_path = require("node:path");
12
10
  let node_fs = require("node:fs");
@@ -30,6 +28,530 @@ let _aws_sdk_client_sqs = require("@aws-sdk/client-sqs");
30
28
  let pg = require("pg");
31
29
  let yaml = require("yaml");
32
30
  let _geekmidas_cache_postgres = require("@geekmidas/cache/postgres");
31
+ //#region src/secrets/storage.ts
32
+ var storage_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
33
+ initStageSecrets: () => initStageSecrets,
34
+ maskPassword: () => maskPassword,
35
+ toEmbeddableSecrets: () => toEmbeddableSecrets,
36
+ validateEnvironmentVariables: () => validateEnvironmentVariables,
37
+ withCustomSecret: () => withCustomSecret
38
+ });
39
+ /**
40
+ * Initialize an empty StageSecrets object for a stage.
41
+ */
42
+ function initStageSecrets(stage) {
43
+ const now = (/* @__PURE__ */ new Date()).toISOString();
44
+ return {
45
+ stage,
46
+ createdAt: now,
47
+ updatedAt: now,
48
+ services: {},
49
+ urls: {},
50
+ custom: {}
51
+ };
52
+ }
53
+ /**
54
+ * Convert StageSecrets to embeddable format (flat key-value pairs).
55
+ * This is what gets encrypted and embedded in the bundle.
56
+ */
57
+ function toEmbeddableSecrets(secrets) {
58
+ return {
59
+ ...secrets.urls,
60
+ ...secrets.custom,
61
+ ...secrets.services.postgres && {
62
+ POSTGRES_USER: secrets.services.postgres.username,
63
+ POSTGRES_PASSWORD: secrets.services.postgres.password,
64
+ POSTGRES_DB: secrets.services.postgres.database ?? "app",
65
+ POSTGRES_HOST: secrets.services.postgres.host,
66
+ POSTGRES_PORT: String(secrets.services.postgres.port)
67
+ },
68
+ ...secrets.services.redis && {
69
+ REDIS_PASSWORD: secrets.services.redis.password,
70
+ REDIS_HOST: secrets.services.redis.host,
71
+ REDIS_PORT: String(secrets.services.redis.port)
72
+ },
73
+ ...secrets.services.minio && {
74
+ STORAGE_ACCESS_KEY_ID: secrets.services.minio.username,
75
+ STORAGE_SECRET_ACCESS_KEY: secrets.services.minio.password,
76
+ STORAGE_BUCKET: secrets.services.minio.bucket ?? "app",
77
+ STORAGE_REGION: "eu-west-1",
78
+ STORAGE_FORCE_PATH_STYLE: "true"
79
+ },
80
+ ...secrets.services.mailpit && {
81
+ SMTP_HOST: secrets.services.mailpit.host,
82
+ SMTP_PORT: String(secrets.services.mailpit.port),
83
+ SMTP_USER: secrets.services.mailpit.username,
84
+ SMTP_PASS: secrets.services.mailpit.password,
85
+ SMTP_SECURE: "false",
86
+ MAIL_FROM: "noreply@localhost"
87
+ },
88
+ ...secrets.services.localstack && {
89
+ AWS_ACCESS_KEY_ID: secrets.services.localstack.accessKeyId ?? secrets.services.localstack.username,
90
+ AWS_SECRET_ACCESS_KEY: secrets.services.localstack.password,
91
+ AWS_REGION: secrets.services.localstack.region ?? "us-east-1",
92
+ AWS_ENDPOINT_URL: `http://${secrets.services.localstack.host}:${secrets.services.localstack.port}`
93
+ },
94
+ ...secrets.services.pgboss && {
95
+ PGBOSS_DB_USER: secrets.services.pgboss.username,
96
+ PGBOSS_DB_PASSWORD: secrets.services.pgboss.password
97
+ }
98
+ };
99
+ }
100
+ /** The same secrets with one custom value set, and `updatedAt` moved on. */
101
+ function withCustomSecret(secrets, key, value) {
102
+ return {
103
+ ...secrets,
104
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
105
+ custom: {
106
+ ...secrets.custom,
107
+ [key]: value
108
+ }
109
+ };
110
+ }
111
+ /**
112
+ * Mask a password for display (show first 4 and last 2 chars).
113
+ */
114
+ function maskPassword(password) {
115
+ if (password.length <= 8) return "********";
116
+ return `${password.slice(0, 4)}${"*".repeat(password.length - 6)}${password.slice(-2)}`;
117
+ }
118
+ /**
119
+ * Validate that all required environment variables are present in secrets.
120
+ *
121
+ * @param requiredVars - Array of environment variable names required by the application
122
+ * @param secrets - Stage secrets to validate against
123
+ * @returns Validation result with missing and provided variables
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];
128
+ * const secrets = await secretsStoreFor(workspace, 'production').then((s) => s.read('production'));
129
+ * const result = validateEnvironmentVariables(required, secrets);
130
+ *
131
+ * if (!result.valid) {
132
+ * console.error(`Missing environment variables: ${result.missing.join(', ')}`);
133
+ * }
134
+ * ```
135
+ */
136
+ function validateEnvironmentVariables(requiredVars, secrets) {
137
+ const embeddable = toEmbeddableSecrets(secrets);
138
+ const availableVars = new Set(Object.keys(embeddable));
139
+ const missing = [];
140
+ const provided = [];
141
+ for (const varName of requiredVars) if (availableVars.has(varName)) provided.push(varName);
142
+ else missing.push(varName);
143
+ return {
144
+ valid: missing.length === 0,
145
+ missing: missing.sort(),
146
+ provided: provided.sort(),
147
+ required: [...requiredVars].sort()
148
+ };
149
+ }
150
+ //#endregion
151
+ //#region src/deploy/identity.ts
152
+ /**
153
+ * Who a deploy is, on a target it shares with other workspaces.
154
+ *
155
+ * A Dokploy server is one flat namespace of projects, images and Docker
156
+ * service names. Deploys used to identify everything they made by the
157
+ * workspace name alone, so two workspaces called `shop` — or `Shop` and
158
+ * `shop` — deploying to one server landed in the same project, pushed over
159
+ * each other's images and redeployed each other's applications. A
160
+ * `DeployIdentity` is what a deploy names and claims its resources by instead.
161
+ */
162
+ /** A namespace that cannot be part of a Dokploy name or an image path. */
163
+ var DeployNamespaceInvalid = class extends Error {
164
+ namespace;
165
+ constructor(namespace) {
166
+ super(`deploy.namespace '${namespace}' is not usable as a name: use lowercase letters, digits and single '-' between them (e.g. 'acme' or 'acme-platform') in gkm.config.ts.`);
167
+ this.namespace = namespace;
168
+ this.name = "DeployNamespaceInvalid";
169
+ }
170
+ };
171
+ /** A workspace name with nothing a target can name a resource by. */
172
+ var DeployProjectNameInvalid = class extends Error {
173
+ workspaceName;
174
+ constructor(workspaceName) {
175
+ super(`The workspace name '${workspaceName}' has no letters or digits to name deployed resources by. Set "name" in gkm.config.ts.`);
176
+ this.workspaceName = workspaceName;
177
+ this.name = "DeployProjectNameInvalid";
178
+ }
179
+ };
180
+ const NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
181
+ /**
182
+ * Lowercase `[a-z0-9-]`, runs of anything else collapsed to one `-`: valid as
183
+ * a Docker image path component, a Docker service name and a Dokploy name.
184
+ */
185
+ function slug(value) {
186
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
187
+ }
188
+ /** The namespace a workspace is in when it does not name one. */
189
+ function defaultNamespace(workspaceName) {
190
+ return slug((0, _geekmidas_manifest.kebabCase)(workspaceName));
191
+ }
192
+ function deployIdentity(workspace, stage) {
193
+ const project = slug(workspace.name);
194
+ if (!project) throw new DeployProjectNameInvalid(workspace.name);
195
+ const fallback = defaultNamespace(workspace.name);
196
+ const namespace = workspace.deploy?.namespace ?? fallback;
197
+ if (!NAME.test(namespace)) throw new DeployNamespaceInvalid(namespace);
198
+ return {
199
+ namespace,
200
+ project,
201
+ stage,
202
+ key: `${namespace}/${project}`,
203
+ scope: namespace === fallback ? project : `${namespace}-${project}`
204
+ };
205
+ }
206
+ /**
207
+ * The token a Dokploy project's description carries to say which identity
208
+ * created it. A project with the right name and no marker belongs to someone
209
+ * else, and a deploy never adopts it.
210
+ */
211
+ function ownershipMarker(identity) {
212
+ return `gkm:${identity.key}`;
213
+ }
214
+ /** Whether a project description carries `identity`'s marker. */
215
+ function isOwnedBy(description, identity) {
216
+ const marker = ownershipMarker(identity);
217
+ return (description ?? "").split(/\s+/).includes(marker);
218
+ }
219
+ /** Any `gkm:` marker a description carries — whoever's it is. */
220
+ function markerOf(description) {
221
+ return (description ?? "").split(/\s+/).find((t) => t.startsWith("gkm:"));
222
+ }
223
+ /** What the Dokploy project is called. */
224
+ function projectName(identity) {
225
+ return identity.scope;
226
+ }
227
+ /**
228
+ * The repository an app's image is pushed to, below the registry:
229
+ * `<namespace>/<project>-<app>`.
230
+ *
231
+ * The namespace is a path segment of its own so that a registry that maps
232
+ * paths to owners (an organisation's packages, a Harbor project) can grant it
233
+ * as one; the app is joined to the project so the two read as one name.
234
+ */
235
+ function imageName(identity, app) {
236
+ return `${identity.namespace}/${identity.project}-${slug((0, _geekmidas_manifest.kebabCase)(app))}`;
237
+ }
238
+ /** The full image ref an app is built, pushed and deployed as. */
239
+ function imageRef(identity, app, registry, tag) {
240
+ const name = imageName(identity, app);
241
+ return registry ? `${registry.replace(/\/+$/, "")}/${name}:${tag}` : `${name}:${tag}`;
242
+ }
243
+ /**
244
+ * What one application is called on the target.
245
+ *
246
+ * The same rule the constructs use, through the same `scopedName`, scoped by
247
+ * the stage and the identity: the application beside
248
+ * `production-kitchen-sink-database` is `production-kitchen-sink-api`. A
249
+ * Dokploy application's name is also its Docker service name, which is unique
250
+ * on the whole server, so the namespace has to be in it too — `acme`'s and
251
+ * `globex`'s `shop` would otherwise both run `production-shop-api`.
252
+ *
253
+ * The app id is dropped when it repeats the project, so a project named for its
254
+ * one application is `production-kitchen-sink` rather than
255
+ * `production-kitchen-sink-kitchen-sink`.
256
+ */
257
+ function applicationName(identity, app) {
258
+ return slug(app) === identity.project ? `${identity.stage}-${identity.scope}` : (0, _geekmidas_manifest.scopedName)([identity.stage, identity.scope], app);
259
+ }
260
+ //#endregion
261
+ //#region src/secrets/keystore.ts
262
+ /**
263
+ * The keys that open each stage's encrypted secrets file, kept outside the
264
+ * project in the CLI's home.
265
+ *
266
+ * Keys were kept at `~/.gkm/<folder>/<stage>.key`, named after the project
267
+ * directory — so two checkouts in folders with the same name (`~/work/api`
268
+ * and `~/oss/api`) shared one key, and the second `gkm secrets:init`
269
+ * overwrote the first project's. They are now kept under the project's
270
+ * identity, `<home>/keys/<namespace>/<project>/<stage>.key`, the same
271
+ * `<namespace>/<project>` a deploy claims its Dokploy project by. A key still
272
+ * at the old place is copied to the new one the first time it is read; the
273
+ * old file stays, so an older CLI on the same machine keeps working.
274
+ */
275
+ /** Key length for AES-256 encryption */
276
+ const KEY_LENGTH = 32;
277
+ /** A keystore project key that is not `<namespace>/<project>`. */
278
+ var KeystoreProjectInvalid = class extends Error {
279
+ key;
280
+ constructor(key) {
281
+ super(`'${key}' is not a keystore project: expected '<namespace>/<project>' in lowercase letters, digits and '-', as deployIdentity() produces. Pass the workspace's identity key.`);
282
+ this.key = key;
283
+ this.name = "KeystoreProjectInvalid";
284
+ }
285
+ };
286
+ /** A stage has no key, here or at the place keys used to be kept. */
287
+ var KeyNotFound = class extends Error {
288
+ stage;
289
+ project;
290
+ path;
291
+ constructor(stage, project, path) {
292
+ super(`Encryption key not found for stage "${stage}" in project "${project}". Expected key at: ${path}. Run \`gkm secrets:init --stage ${stage}\` to create one, or copy the stage's key there.`);
293
+ this.stage = stage;
294
+ this.project = project;
295
+ this.path = path;
296
+ this.name = "KeyNotFound";
297
+ }
298
+ };
299
+ const PROJECT_KEY = /^[a-z0-9]+(?:-[a-z0-9]+)*\/[a-z0-9]+(?:-[a-z0-9]+)*$/;
300
+ /**
301
+ * The keystore key of a workspace: its deploy identity without the stage, so
302
+ * a project's keys and its Dokploy project are named by the same thing.
303
+ */
304
+ function projectKey(workspace) {
305
+ return deployIdentity(workspace, "").key;
306
+ }
307
+ /** The keystore project of a loaded workspace. */
308
+ function keystoreProject(workspace, home) {
309
+ const key = projectKey(workspace);
310
+ const unscoped = projectKey({ name: workspace.name });
311
+ return {
312
+ key,
313
+ legacy: [.../* @__PURE__ */ new Set([folderName(workspace.root), workspace.name])].filter((name) => !!name),
314
+ ...unscoped !== key ? { aliases: [unscoped] } : {},
315
+ ...home ? { home } : {}
316
+ };
317
+ }
318
+ /**
319
+ * Whether `name` stays inside the home it is joined to. A workspace name was
320
+ * joined as is — `@acme/shop` is `~/.gkm/@acme/shop` — but never upwards.
321
+ */
322
+ function isLegacyName(name) {
323
+ return name.split(/[\\/]/).every((part) => part !== ".." && part !== "");
324
+ }
325
+ /** The last segment of a path, as the old keystore named projects. */
326
+ function folderName(path) {
327
+ const name = path.split(/[\\/]/).filter(Boolean).at(-1);
328
+ return name && name !== "." && name !== ".." ? name : void 0;
329
+ }
330
+ /**
331
+ * Get the keystore directory for a project:
332
+ * `<home>/keys/<namespace>/<project>`.
333
+ */
334
+ function getKeystoreDir(project) {
335
+ if (!PROJECT_KEY.test(project.key)) throw new KeystoreProjectInvalid(project.key);
336
+ const [namespace, name] = project.key.split("/");
337
+ return (0, node_path.join)(project.home ?? require_local.gkmHome(), "keys", namespace, name);
338
+ }
339
+ /** Get the path to a stage's encryption key. */
340
+ function getKeyPath(stage, project) {
341
+ return (0, node_path.join)(getKeystoreDir(project), `${stage}.key`);
342
+ }
343
+ /**
344
+ * Where else a stage's key may be, most likely first: under an alias of the
345
+ * project, then where keys were kept before they were keyed by identity —
346
+ * under the configured home, then under `~/.gkm`, which is where every CLI
347
+ * before `GKM_HOME` wrote.
348
+ */
349
+ function legacyKeyPaths(stage, project) {
350
+ const aliases = (project.aliases ?? []).map((key) => getKeyPath(stage, {
351
+ key,
352
+ home: project.home
353
+ }));
354
+ const homes = [.../* @__PURE__ */ new Set([project.home ?? require_local.gkmHome(), (0, node_path.join)((0, node_os.homedir)(), ".gkm")])];
355
+ const names = (project.legacy ?? []).filter(isLegacyName);
356
+ return [...aliases, ...names.flatMap((name) => homes.map((home) => (0, node_path.join)(home, name, `${stage}.key`)))];
357
+ }
358
+ /**
359
+ * Generate a new encryption key for a stage, stored owner-only at
360
+ * `<home>/keys/<namespace>/<project>/<stage>.key`.
361
+ */
362
+ async function generateKey(stage, project, flag = "w") {
363
+ const keyDir = getKeystoreDir(project);
364
+ const keyPath = getKeyPath(stage, project);
365
+ await (0, node_fs_promises.mkdir)(keyDir, {
366
+ recursive: true,
367
+ mode: 448
368
+ });
369
+ const key = (0, node_crypto.randomBytes)(KEY_LENGTH).toString("hex");
370
+ await (0, node_fs_promises.writeFile)(keyPath, key, {
371
+ mode: 384,
372
+ encoding: "utf-8",
373
+ flag
374
+ });
375
+ await (0, node_fs_promises.chmod)(keyPath, 384);
376
+ return key;
377
+ }
378
+ /**
379
+ * Copy a key from where it used to be kept to where it is kept now.
380
+ *
381
+ * Copied, not moved: an older CLI on the same machine still reads the old
382
+ * place. Exclusive, so two processes migrating at once cannot overwrite a key
383
+ * one of them already put there.
384
+ */
385
+ async function migrateLegacyKey(stage, project) {
386
+ const legacy = legacyKeyPaths(stage, project).find((path) => (0, node_fs.existsSync)(path));
387
+ if (!legacy) return false;
388
+ const keyPath = getKeyPath(stage, project);
389
+ await (0, node_fs_promises.mkdir)(getKeystoreDir(project), {
390
+ recursive: true,
391
+ mode: 448
392
+ });
393
+ try {
394
+ await (0, node_fs_promises.copyFile)(legacy, keyPath, node_fs.constants.COPYFILE_EXCL);
395
+ } catch (error) {
396
+ if (error.code !== "EEXIST") throw error;
397
+ }
398
+ await (0, node_fs_promises.chmod)(keyPath, 384);
399
+ return true;
400
+ }
401
+ /**
402
+ * Read an encryption key for a stage, or `null` when there is none — after
403
+ * copying it over from where keys used to be kept, if it is still there.
404
+ */
405
+ async function readKey(stage, project) {
406
+ const keyPath = getKeyPath(stage, project);
407
+ if (!(0, node_fs.existsSync)(keyPath) && !await migrateLegacyKey(stage, project)) return null;
408
+ return (await (0, node_fs_promises.readFile)(keyPath, "utf-8")).trim();
409
+ }
410
+ /**
411
+ * Read an encryption key for a stage, throwing {@link KeyNotFound} if there
412
+ * is none.
413
+ */
414
+ async function requireKey(stage, project) {
415
+ const key = await readKey(stage, project);
416
+ if (!key) throw new KeyNotFound(stage, project.key, getKeyPath(stage, project));
417
+ return key;
418
+ }
419
+ /**
420
+ * Get or create a key for a stage.
421
+ * If the key already exists, it is returned. Otherwise, a new key is generated.
422
+ */
423
+ async function getOrCreateKey(stage, project) {
424
+ const existingKey = await readKey(stage, project);
425
+ if (existingKey) return existingKey;
426
+ try {
427
+ return await generateKey(stage, project, "wx");
428
+ } catch (error) {
429
+ if (error.code !== "EEXIST") throw error;
430
+ return requireKey(stage, project);
431
+ }
432
+ }
433
+ //#endregion
434
+ //#region src/secrets/file.ts
435
+ /** Where the files live, relative to the project root. */
436
+ const SECRETS_DIR = ".gkm/secrets";
437
+ /** AES-256-GCM configuration */
438
+ const ALGORITHM = "aes-256-gcm";
439
+ const IV_LENGTH = 12;
440
+ /**
441
+ * A stage's secrets as an encrypted file on this machine:
442
+ * `.gkm/secrets/<stage>.json`, with its key in the CLI's home at
443
+ * `keys/<namespace>/<project>/<stage>.key`.
444
+ *
445
+ * The local stage's store, always — its secrets belong to the machine running
446
+ * `gkm dev` — and a deployed stage's when `secrets.store` is `'file'`.
447
+ */
448
+ var FileSecretsStore = class {
449
+ root;
450
+ name = "file";
451
+ project;
452
+ /**
453
+ * @param project - Whose keys: a workspace's `keystoreProject()`. Outside a
454
+ * workspace there is no config to name the project, so it is named the
455
+ * way a workspace without `name` is — its package name, else its folder.
456
+ */
457
+ constructor(root, project) {
458
+ this.root = root;
459
+ this.project = project ?? {
460
+ key: projectKey({ name: packageName(root) ?? (0, node_path.basename)(root) }),
461
+ legacy: [(0, node_path.basename)(root)]
462
+ };
463
+ }
464
+ /** The file a stage's secrets are kept in. */
465
+ path(stage) {
466
+ return (0, node_path.join)(this.root, SECRETS_DIR, `${stage}.json`);
467
+ }
468
+ async read(stage) {
469
+ const path = this.path(stage);
470
+ if (!(0, node_fs.existsSync)(path)) return null;
471
+ const data = JSON.parse(await (0, node_fs_promises.readFile)(path, "utf-8"));
472
+ if (!(data.version === 1 && data.encrypted && data.iv)) return data;
473
+ const key = await readKey(stage, this.project);
474
+ if (!key) throw new MissingSecretsKey(stage, this.project.key, getKeyPath(stage, this.project));
475
+ return decrypt(data, key);
476
+ }
477
+ async write(stage, secrets) {
478
+ await (0, node_fs_promises.mkdir)((0, node_path.join)(this.root, SECRETS_DIR), { recursive: true });
479
+ const key = await getOrCreateKey(stage, this.project);
480
+ await (0, node_fs_promises.writeFile)(this.path(stage), JSON.stringify(encrypt(secrets, key), null, 2), "utf-8");
481
+ }
482
+ };
483
+ /** A stage's secrets file exists, and the key that opens it does not. */
484
+ var MissingSecretsKey = class extends Error {
485
+ stage;
486
+ project;
487
+ path;
488
+ constructor(stage, project, path) {
489
+ super(`Decryption key not found for stage "${stage}". Expected key at: ${path}. Copy the stage's key there from whoever created it, or set secrets.store to a store this machine can reach.`);
490
+ this.stage = stage;
491
+ this.project = project;
492
+ this.path = path;
493
+ this.name = "MissingSecretsKey";
494
+ }
495
+ };
496
+ /** A project's package name without its scope, as a workspace name reads it. */
497
+ function packageName(root) {
498
+ try {
499
+ const pkg = JSON.parse((0, node_fs.readFileSync)((0, node_path.join)(root, "package.json"), "utf-8"));
500
+ return typeof pkg.name === "string" ? pkg.name.replace(/^@[^/]+\//, "") : void 0;
501
+ } catch {
502
+ return;
503
+ }
504
+ }
505
+ function encrypt(secrets, keyHex) {
506
+ const key = Buffer.from(keyHex, "hex");
507
+ const iv = (0, node_crypto.randomBytes)(IV_LENGTH);
508
+ const cipher = (0, node_crypto.createCipheriv)(ALGORITHM, key, iv);
509
+ const ciphertext = Buffer.concat([cipher.update(JSON.stringify(secrets), "utf-8"), cipher.final()]);
510
+ return {
511
+ version: 1,
512
+ encrypted: Buffer.concat([ciphertext, cipher.getAuthTag()]).toString("base64"),
513
+ iv: iv.toString("hex")
514
+ };
515
+ }
516
+ function decrypt(data, keyHex) {
517
+ const key = Buffer.from(keyHex, "hex");
518
+ const combined = Buffer.from(data.encrypted, "base64");
519
+ const decipher = (0, node_crypto.createDecipheriv)(ALGORITHM, key, Buffer.from(data.iv, "hex"));
520
+ decipher.setAuthTag(combined.subarray(-16));
521
+ const plaintext = Buffer.concat([decipher.update(combined.subarray(0, -16)), decipher.final()]);
522
+ return JSON.parse(plaintext.toString("utf-8"));
523
+ }
524
+ //#endregion
525
+ //#region src/secrets/store.ts
526
+ var store_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
527
+ FileSecretsStore: () => FileSecretsStore,
528
+ isRemoteStore: () => isRemoteStore,
529
+ secretsStoreFor: () => secretsStoreFor
530
+ });
531
+ /**
532
+ * The store a stage's secrets are kept in — what every command reads and
533
+ * writes, for the stage it acts on.
534
+ *
535
+ * The local stage is always the file: its secrets belong to the machine
536
+ * running `gkm dev`. A deployed stage uses `secrets.store`.
537
+ */
538
+ async function secretsStoreFor(workspace, stage, options = {}) {
539
+ const configured = workspace.secrets.store ?? "file";
540
+ if (stage === workspace.stages.local || configured === "file") return new FileSecretsStore(workspace.root, keystoreProject(workspace, options.home));
541
+ if (configured.provider !== "ssm") return configured.provider;
542
+ const { AwsSecretsStore } = await Promise.resolve().then(() => require("./aws-DkHdTV-p.cjs"));
543
+ return new AwsSecretsStore({
544
+ project: workspace.name,
545
+ region: configured.region,
546
+ ...options.profile ? { profile: options.profile } : {}
547
+ });
548
+ }
549
+ /** Whether a stage's secrets live somewhere other than this machine. */
550
+ function isRemoteStore(workspace, stage) {
551
+ const configured = workspace.secrets.store ?? "file";
552
+ return stage !== workspace.stages.local && configured !== "file";
553
+ }
554
+ //#endregion
33
555
  //#region src/credentials/index.ts
34
556
  const logger$1 = console;
35
557
  /**
@@ -118,7 +640,7 @@ async function loadSecretsForApp(store, stage, appName) {
118
640
  const stageSecrets = await store.read(stage);
119
641
  if (stageSecrets) {
120
642
  logger$1.log(`🔐 Loading secrets from stage: ${stage}`);
121
- secrets = require_storage.toEmbeddableSecrets(stageSecrets);
643
+ secrets = toEmbeddableSecrets(stageSecrets);
122
644
  }
123
645
  if (Object.keys(secrets).length === 0) return {};
124
646
  if (!appName) return secrets;
@@ -233,7 +755,7 @@ async function prepareEntryCredentials(options) {
233
755
  }
234
756
  const resolvedPort = options.explicitPort ?? workspaceAppPort ?? 3e3;
235
757
  const stage = options.stage ?? workspace?.stages.local;
236
- const store = stage ? workspace ? await require_store.secretsStoreFor(workspace, stage) : new require_store.FileSecretsStore(secretsRoot) : void 0;
758
+ const store = stage ? workspace ? await secretsStoreFor(workspace, stage) : new FileSecretsStore(secretsRoot) : void 0;
237
759
  const credentials = store && stage ? await loadSecretsForApp(store, stage, appName) : {};
238
760
  credentials.PORT = String(resolvedPort);
239
761
  if (appInfo?.app.type === "mobile") credentials.RCT_METRO_PORT = String(resolvedPort);
@@ -3160,7 +3682,7 @@ function localAddress(port) {
3160
3682
  return `http://localhost:${port}`;
3161
3683
  }
3162
3684
  //#endregion
3163
- //#region src/deploy/domain.ts
3685
+ //#region src/target/dokploy/domain.ts
3164
3686
  /** A stage was deployed that `deploy.domains` gives no domain. */
3165
3687
  var NoDomainForStage = class extends Error {
3166
3688
  stage;
@@ -3774,6 +4296,12 @@ USER nextjs
3774
4296
 
3775
4297
  EXPOSE ${port}
3776
4298
 
4299
+ # A site answers at its root; Docker, and Dokploy, read the container's
4300
+ # health from it rather than from the process merely running. 127.0.0.1, not
4301
+ # localhost: the server listens on IPv4, and localhost can resolve to ::1.
4302
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\
4303
+ CMD wget -qO- http://127.0.0.1:${port}/ > /dev/null 2>&1 || exit 1
4304
+
3777
4305
  ENTRYPOINT ["/sbin/tini", "--"]
3778
4306
  CMD ["node", "${appPath}/server.js"]
3779
4307
  `;
@@ -4041,6 +4569,12 @@ ENV HOSTNAME="0.0.0.0"
4041
4569
  USER app
4042
4570
  EXPOSE ${port}
4043
4571
 
4572
+ # A site answers at its root; Docker, and Dokploy, read the container's
4573
+ # health from it rather than from the process merely running. 127.0.0.1, not
4574
+ # localhost: the server listens on IPv4, and localhost can resolve to ::1.
4575
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\
4576
+ CMD wget -qO- http://127.0.0.1:${port}/ > /dev/null 2>&1 || exit 1
4577
+
4044
4578
  ENTRYPOINT ["/sbin/tini", "--"]
4045
4579
  CMD ["sh", "-c", "cd ${appPath} && ${startCmd}"]
4046
4580
  `;
@@ -4088,6 +4622,11 @@ COPY --from=builder /app/${appPath}/dist /usr/share/nginx/html
4088
4622
  RUN printf 'server {\\n listen ${port};\\n root /usr/share/nginx/html;\\n index index.html;\\n location / { try_files $uri $uri/ /index.html; }\\n}\\n' \\
4089
4623
  > /etc/nginx/conf.d/default.conf
4090
4624
  EXPOSE ${port}
4625
+ # A site answers at its root; Docker, and Dokploy, read the container's
4626
+ # health from it rather than from the process merely running. 127.0.0.1, not
4627
+ # localhost: the server listens on IPv4, and localhost can resolve to ::1.
4628
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\
4629
+ CMD wget -qO- http://127.0.0.1:${port}/ > /dev/null 2>&1 || exit 1
4091
4630
  CMD ["nginx", "-g", "daemon off;"]
4092
4631
  `;
4093
4632
  }
@@ -4592,13 +5131,60 @@ function createEmptyState(stage, projectId, environmentId) {
4592
5131
  function setApplicationId(state, appName, applicationId) {
4593
5132
  state.applications[appName] = applicationId;
4594
5133
  }
5134
+ /** Two records naming the same image: by digest when both have one. */
5135
+ function sameImage(a, b) {
5136
+ return a.digest && b.digest ? a.digest === b.digest : a.ref === b.ref;
5137
+ }
5138
+ /** The newest release in `history` after `index` that a rollback may restore. */
5139
+ function restorable(history, index, current) {
5140
+ return history.slice(index + 1).find((entry) => !entry.rolledBack && !sameImage(entry, current));
5141
+ }
4595
5142
  /**
4596
- * Record the image an app was deployed with (mutates state)
5143
+ * Record that `image` went live for `appName` (mutates state): it becomes
5144
+ * `current`, and what was current becomes `previous`. Releasing what already
5145
+ * runs — a redeploy of the same digest — changes nothing.
4597
5146
  */
4598
- function setDeployedImage(state, appName, image) {
4599
- state.images = {
4600
- ...state.images,
4601
- [appName]: image
5147
+ function recordRelease(state, appName, image, releasedAt = /* @__PURE__ */ new Date()) {
5148
+ const releases = state.releases?.[appName];
5149
+ if (releases && sameImage(releases.current, image)) return;
5150
+ const entry = {
5151
+ ...image,
5152
+ releasedAt: releasedAt.toISOString()
5153
+ };
5154
+ const history = [entry, ...releases?.history ?? []].slice(0, 10);
5155
+ const previous = releases?.current;
5156
+ state.releases = {
5157
+ ...state.releases,
5158
+ [appName]: {
5159
+ current: entry,
5160
+ ...previous ? { previous } : {},
5161
+ history
5162
+ }
5163
+ };
5164
+ }
5165
+ /**
5166
+ * Record that `appName` was rolled back to `to` (mutates state): every
5167
+ * release newer than it is marked rolled back, so neither this rollback nor
5168
+ * a later one restores it, and `previous` moves to the release before `to`.
5169
+ */
5170
+ function recordRollback(state, appName, to) {
5171
+ const releases = state.releases?.[appName];
5172
+ if (!releases) return;
5173
+ const index = releases.history.findIndex((entry) => !entry.rolledBack && sameImage(entry, to));
5174
+ if (index === -1) return;
5175
+ const history = releases.history.map((entry, i) => i < index ? {
5176
+ ...entry,
5177
+ rolledBack: true
5178
+ } : entry);
5179
+ const current = history[index];
5180
+ const previous = restorable(history, index, current);
5181
+ state.releases = {
5182
+ ...state.releases,
5183
+ [appName]: {
5184
+ current,
5185
+ ...previous ? { previous } : {},
5186
+ history
5187
+ }
4602
5188
  };
4603
5189
  }
4604
5190
  /**
@@ -4697,6 +5283,12 @@ Object.defineProperty(exports, "FAKE_ENV", {
4697
5283
  return FAKE_ENV;
4698
5284
  }
4699
5285
  });
5286
+ Object.defineProperty(exports, "FileSecretsStore", {
5287
+ enumerable: true,
5288
+ get: function() {
5289
+ return FileSecretsStore;
5290
+ }
5291
+ });
4700
5292
  Object.defineProperty(exports, "LOCAL_CA_PATH", {
4701
5293
  enumerable: true,
4702
5294
  get: function() {
@@ -4715,6 +5307,12 @@ Object.defineProperty(exports, "appPackageName", {
4715
5307
  return appPackageName;
4716
5308
  }
4717
5309
  });
5310
+ Object.defineProperty(exports, "applicationName", {
5311
+ enumerable: true,
5312
+ get: function() {
5313
+ return applicationName;
5314
+ }
5315
+ });
4718
5316
  Object.defineProperty(exports, "applyPostgres", {
4719
5317
  enumerable: true,
4720
5318
  get: function() {
@@ -4763,6 +5361,12 @@ Object.defineProperty(exports, "createEntryWrapper", {
4763
5361
  return createEntryWrapper;
4764
5362
  }
4765
5363
  });
5364
+ Object.defineProperty(exports, "deployIdentity", {
5365
+ enumerable: true,
5366
+ get: function() {
5367
+ return deployIdentity;
5368
+ }
5369
+ });
4766
5370
  Object.defineProperty(exports, "derivedContainers", {
4767
5371
  enumerable: true,
4768
5372
  get: function() {
@@ -4787,6 +5391,12 @@ Object.defineProperty(exports, "dockerCommand", {
4787
5391
  return dockerCommand;
4788
5392
  }
4789
5393
  });
5394
+ Object.defineProperty(exports, "dockerfileOf", {
5395
+ enumerable: true,
5396
+ get: function() {
5397
+ return dockerfileOf;
5398
+ }
5399
+ });
4790
5400
  Object.defineProperty(exports, "envFor", {
4791
5401
  enumerable: true,
4792
5402
  get: function() {
@@ -4841,12 +5451,36 @@ Object.defineProperty(exports, "getGeneratedSecret", {
4841
5451
  return getGeneratedSecret;
4842
5452
  }
4843
5453
  });
5454
+ Object.defineProperty(exports, "getKeyPath", {
5455
+ enumerable: true,
5456
+ get: function() {
5457
+ return getKeyPath;
5458
+ }
5459
+ });
4844
5460
  Object.defineProperty(exports, "hostFor", {
4845
5461
  enumerable: true,
4846
5462
  get: function() {
4847
5463
  return hostFor;
4848
5464
  }
4849
5465
  });
5466
+ Object.defineProperty(exports, "imageName", {
5467
+ enumerable: true,
5468
+ get: function() {
5469
+ return imageName;
5470
+ }
5471
+ });
5472
+ Object.defineProperty(exports, "imageRef", {
5473
+ enumerable: true,
5474
+ get: function() {
5475
+ return imageRef;
5476
+ }
5477
+ });
5478
+ Object.defineProperty(exports, "initStageSecrets", {
5479
+ enumerable: true,
5480
+ get: function() {
5481
+ return initStageSecrets;
5482
+ }
5483
+ });
4850
5484
  Object.defineProperty(exports, "isDnsVerified", {
4851
5485
  enumerable: true,
4852
5486
  get: function() {
@@ -4859,12 +5493,30 @@ Object.defineProperty(exports, "isMainFrontendApp", {
4859
5493
  return isMainFrontendApp;
4860
5494
  }
4861
5495
  });
5496
+ Object.defineProperty(exports, "isOwnedBy", {
5497
+ enumerable: true,
5498
+ get: function() {
5499
+ return isOwnedBy;
5500
+ }
5501
+ });
4862
5502
  Object.defineProperty(exports, "isPortAvailable", {
4863
5503
  enumerable: true,
4864
5504
  get: function() {
4865
5505
  return isPortAvailable;
4866
5506
  }
4867
5507
  });
5508
+ Object.defineProperty(exports, "isRemoteStore", {
5509
+ enumerable: true,
5510
+ get: function() {
5511
+ return isRemoteStore;
5512
+ }
5513
+ });
5514
+ Object.defineProperty(exports, "keystoreProject", {
5515
+ enumerable: true,
5516
+ get: function() {
5517
+ return keystoreProject;
5518
+ }
5519
+ });
4868
5520
  Object.defineProperty(exports, "loadEnvFiles", {
4869
5521
  enumerable: true,
4870
5522
  get: function() {
@@ -4883,12 +5535,30 @@ Object.defineProperty(exports, "localRolePassword", {
4883
5535
  return localRolePassword;
4884
5536
  }
4885
5537
  });
5538
+ Object.defineProperty(exports, "markerOf", {
5539
+ enumerable: true,
5540
+ get: function() {
5541
+ return markerOf;
5542
+ }
5543
+ });
5544
+ Object.defineProperty(exports, "maskPassword", {
5545
+ enumerable: true,
5546
+ get: function() {
5547
+ return maskPassword;
5548
+ }
5549
+ });
4886
5550
  Object.defineProperty(exports, "networkEnv", {
4887
5551
  enumerable: true,
4888
5552
  get: function() {
4889
5553
  return networkEnv;
4890
5554
  }
4891
5555
  });
5556
+ Object.defineProperty(exports, "ownershipMarker", {
5557
+ enumerable: true,
5558
+ get: function() {
5559
+ return ownershipMarker;
5560
+ }
5561
+ });
4892
5562
  Object.defineProperty(exports, "pgClient", {
4893
5563
  enumerable: true,
4894
5564
  get: function() {
@@ -4931,6 +5601,18 @@ Object.defineProperty(exports, "primaryPortKey", {
4931
5601
  return primaryPortKey;
4932
5602
  }
4933
5603
  });
5604
+ Object.defineProperty(exports, "projectKey", {
5605
+ enumerable: true,
5606
+ get: function() {
5607
+ return projectKey;
5608
+ }
5609
+ });
5610
+ Object.defineProperty(exports, "projectName", {
5611
+ enumerable: true,
5612
+ get: function() {
5613
+ return projectName;
5614
+ }
5615
+ });
4934
5616
  Object.defineProperty(exports, "providerOf", {
4935
5617
  enumerable: true,
4936
5618
  get: function() {
@@ -4943,12 +5625,30 @@ Object.defineProperty(exports, "quoteIdentifier", {
4943
5625
  return quoteIdentifier;
4944
5626
  }
4945
5627
  });
5628
+ Object.defineProperty(exports, "readKey", {
5629
+ enumerable: true,
5630
+ get: function() {
5631
+ return readKey;
5632
+ }
5633
+ });
4946
5634
  Object.defineProperty(exports, "reconcileWorkspace", {
4947
5635
  enumerable: true,
4948
5636
  get: function() {
4949
5637
  return reconcileWorkspace;
4950
5638
  }
4951
5639
  });
5640
+ Object.defineProperty(exports, "recordRelease", {
5641
+ enumerable: true,
5642
+ get: function() {
5643
+ return recordRelease;
5644
+ }
5645
+ });
5646
+ Object.defineProperty(exports, "recordRollback", {
5647
+ enumerable: true,
5648
+ get: function() {
5649
+ return recordRollback;
5650
+ }
5651
+ });
4952
5652
  Object.defineProperty(exports, "resolveHost", {
4953
5653
  enumerable: true,
4954
5654
  get: function() {
@@ -4961,22 +5661,22 @@ Object.defineProperty(exports, "resourceName", {
4961
5661
  return resourceName;
4962
5662
  }
4963
5663
  });
4964
- Object.defineProperty(exports, "setApplicationId", {
5664
+ Object.defineProperty(exports, "secretsStoreFor", {
4965
5665
  enumerable: true,
4966
5666
  get: function() {
4967
- return setApplicationId;
5667
+ return secretsStoreFor;
4968
5668
  }
4969
5669
  });
4970
- Object.defineProperty(exports, "setBackupState", {
5670
+ Object.defineProperty(exports, "setApplicationId", {
4971
5671
  enumerable: true,
4972
5672
  get: function() {
4973
- return setBackupState;
5673
+ return setApplicationId;
4974
5674
  }
4975
5675
  });
4976
- Object.defineProperty(exports, "setDeployedImage", {
5676
+ Object.defineProperty(exports, "setBackupState", {
4977
5677
  enumerable: true,
4978
5678
  get: function() {
4979
- return setDeployedImage;
5679
+ return setBackupState;
4980
5680
  }
4981
5681
  });
4982
5682
  Object.defineProperty(exports, "setDnsRecord", {
@@ -5015,12 +5715,36 @@ Object.defineProperty(exports, "storageBackendFor", {
5015
5715
  return storageBackendFor;
5016
5716
  }
5017
5717
  });
5718
+ Object.defineProperty(exports, "storage_exports", {
5719
+ enumerable: true,
5720
+ get: function() {
5721
+ return storage_exports;
5722
+ }
5723
+ });
5724
+ Object.defineProperty(exports, "store_exports", {
5725
+ enumerable: true,
5726
+ get: function() {
5727
+ return store_exports;
5728
+ }
5729
+ });
5730
+ Object.defineProperty(exports, "toEmbeddableSecrets", {
5731
+ enumerable: true,
5732
+ get: function() {
5733
+ return toEmbeddableSecrets;
5734
+ }
5735
+ });
5018
5736
  Object.defineProperty(exports, "validateImageRef", {
5019
5737
  enumerable: true,
5020
5738
  get: function() {
5021
5739
  return validateImageRef;
5022
5740
  }
5023
5741
  });
5742
+ Object.defineProperty(exports, "withCustomSecret", {
5743
+ enumerable: true,
5744
+ get: function() {
5745
+ return withCustomSecret;
5746
+ }
5747
+ });
5024
5748
  Object.defineProperty(exports, "withGeneratedSecrets", {
5025
5749
  enumerable: true,
5026
5750
  get: function() {
@@ -5034,4 +5758,4 @@ Object.defineProperty(exports, "workspace_exports", {
5034
5758
  }
5035
5759
  });
5036
5760
 
5037
- //# sourceMappingURL=state-DF26e_lo.cjs.map
5761
+ //# sourceMappingURL=state-Y6ATakMX.cjs.map