@geekmidas/cli 10.0.0-alpha.10 → 10.0.0-alpha.101

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 (489) hide show
  1. package/README.md +315 -414
  2. package/bin/adjacent-tsconfig.mjs +46 -8
  3. package/bin/gkm.mjs +11 -3
  4. package/bin/owning-tsconfig-jsx-register.mjs +18 -0
  5. package/bin/owning-tsconfig-jsx.mjs +108 -0
  6. package/dist/EndpointGenerator-Br97xgs_.mjs +1031 -0
  7. package/dist/EndpointGenerator-Br97xgs_.mjs.map +1 -0
  8. package/dist/EndpointGenerator-By5_tYE9.cjs +1090 -0
  9. package/dist/EndpointGenerator-By5_tYE9.cjs.map +1 -0
  10. package/dist/GoDaddyProvider-BOuLf_Py.cjs +388 -0
  11. package/dist/GoDaddyProvider-BOuLf_Py.cjs.map +1 -0
  12. package/dist/GoDaddyProvider-u9MF-Dqk.mjs +388 -0
  13. package/dist/GoDaddyProvider-u9MF-Dqk.mjs.map +1 -0
  14. package/dist/{HostingerProvider-Cft7lEYr.mjs → HostingerProvider-BNpS9aRJ.mjs} +29 -25
  15. package/dist/HostingerProvider-BNpS9aRJ.mjs.map +1 -0
  16. package/dist/{HostingerProvider-h3EbEp-Z.cjs → HostingerProvider-DR1iws1P.cjs} +29 -25
  17. package/dist/HostingerProvider-DR1iws1P.cjs.map +1 -0
  18. package/dist/LegacyStateStore-DWmHGNgH.cjs +124 -0
  19. package/dist/LegacyStateStore-DWmHGNgH.cjs.map +1 -0
  20. package/dist/LegacyStateStore-vhkx7Bbq.mjs +124 -0
  21. package/dist/LegacyStateStore-vhkx7Bbq.mjs.map +1 -0
  22. package/dist/LocalStateStore-BVKDADoG.cjs +178 -0
  23. package/dist/LocalStateStore-BVKDADoG.cjs.map +1 -0
  24. package/dist/LocalStateStore-FVsg0UoM.mjs +167 -0
  25. package/dist/LocalStateStore-FVsg0UoM.mjs.map +1 -0
  26. package/dist/OpenApiTsGenerator-BgSX_Z-e.cjs +541 -0
  27. package/dist/OpenApiTsGenerator-BgSX_Z-e.cjs.map +1 -0
  28. package/dist/OpenApiTsGenerator-C8aTX--y.mjs +536 -0
  29. package/dist/OpenApiTsGenerator-C8aTX--y.mjs.map +1 -0
  30. package/dist/{Route53Provider-di2fMM5N.cjs → Route53Provider-Bllus2NR.cjs} +21 -22
  31. package/dist/Route53Provider-Bllus2NR.cjs.map +1 -0
  32. package/dist/{Route53Provider-RdpUDJQk.mjs → Route53Provider-QXxjkZO1.mjs} +13 -13
  33. package/dist/Route53Provider-QXxjkZO1.mjs.map +1 -0
  34. package/dist/S3StateStore-B8seZUsw.mjs +223 -0
  35. package/dist/S3StateStore-B8seZUsw.mjs.map +1 -0
  36. package/dist/S3StateStore-B_2gE9Un.cjs +222 -0
  37. package/dist/S3StateStore-B_2gE9Un.cjs.map +1 -0
  38. package/dist/SSMStateStore-CTDEI5Bi.cjs +204 -0
  39. package/dist/SSMStateStore-CTDEI5Bi.cjs.map +1 -0
  40. package/dist/SSMStateStore-DGTbBomw.mjs +205 -0
  41. package/dist/SSMStateStore-DGTbBomw.mjs.map +1 -0
  42. package/dist/SubscriberGenerator-1-IsjIwF.mjs +449 -0
  43. package/dist/SubscriberGenerator-1-IsjIwF.mjs.map +1 -0
  44. package/dist/SubscriberGenerator-BlIOdbi-.cjs +490 -0
  45. package/dist/SubscriberGenerator-BlIOdbi-.cjs.map +1 -0
  46. package/dist/add-BB2tLVc2.cjs +720 -0
  47. package/dist/add-BB2tLVc2.cjs.map +1 -0
  48. package/dist/add-CIbhGE5v.mjs +718 -0
  49. package/dist/add-CIbhGE5v.mjs.map +1 -0
  50. package/dist/appPorts-C9z9Pzn9.mjs +223 -0
  51. package/dist/appPorts-C9z9Pzn9.mjs.map +1 -0
  52. package/dist/appPorts-Cu79hJF6.cjs +264 -0
  53. package/dist/appPorts-Cu79hJF6.cjs.map +1 -0
  54. package/dist/aws-8QQ8n-t6.mjs +89 -0
  55. package/dist/aws-8QQ8n-t6.mjs.map +1 -0
  56. package/dist/aws-DY9NqQIT.cjs +100 -0
  57. package/dist/aws-DY9NqQIT.cjs.map +1 -0
  58. package/dist/awsStore-Bx5nCFnS.mjs +121 -0
  59. package/dist/awsStore-Bx5nCFnS.mjs.map +1 -0
  60. package/dist/awsStore-u3ehhMoY.cjs +138 -0
  61. package/dist/awsStore-u3ehhMoY.cjs.map +1 -0
  62. package/dist/{backup-provisioner-Bgj5Vi_L.mjs → backup-provisioner-C8DnCmxK.mjs} +11 -8
  63. package/dist/backup-provisioner-C8DnCmxK.mjs.map +1 -0
  64. package/dist/{backup-provisioner-BrsHwYG0.cjs → backup-provisioner-oDEsPj02.cjs} +22 -20
  65. package/dist/backup-provisioner-oDEsPj02.cjs.map +1 -0
  66. package/dist/backups/runner.cjs +519 -0
  67. package/dist/backups/runner.cjs.map +1 -0
  68. package/dist/backups/runner.d.cts +102 -0
  69. package/dist/backups/runner.d.cts.map +1 -0
  70. package/dist/backups/runner.d.mts +102 -0
  71. package/dist/backups/runner.d.mts.map +1 -0
  72. package/dist/backups/runner.mjs +506 -0
  73. package/dist/backups/runner.mjs.map +1 -0
  74. package/dist/{bundler-BY1OmV1e.cjs → bundler-Ba6BER3w.cjs} +38 -35
  75. package/dist/bundler-Ba6BER3w.cjs.map +1 -0
  76. package/dist/{bundler-Be8Zg4Wd.mjs → bundler-CHjRYVKh.mjs} +36 -32
  77. package/dist/bundler-CHjRYVKh.mjs.map +1 -0
  78. package/dist/cli-CtlqYRlN.cjs +71 -0
  79. package/dist/cli-CtlqYRlN.cjs.map +1 -0
  80. package/dist/cli-DOlkhrsh.mjs +71 -0
  81. package/dist/cli-DOlkhrsh.mjs.map +1 -0
  82. package/dist/compose-FDP_TaFt.mjs +3154 -0
  83. package/dist/compose-FDP_TaFt.mjs.map +1 -0
  84. package/dist/compose-uAWLy-nR.cjs +3267 -0
  85. package/dist/compose-uAWLy-nR.cjs.map +1 -0
  86. package/dist/config-D48erO2j.d.mts +269 -0
  87. package/dist/config-D48erO2j.d.mts.map +1 -0
  88. package/dist/config-DHDtsQrB.d.cts +269 -0
  89. package/dist/config-DHDtsQrB.d.cts.map +1 -0
  90. package/dist/config.cjs +421 -11
  91. package/dist/config.cjs.map +1 -0
  92. package/dist/config.d.cts +4 -120
  93. package/dist/config.d.mts +4 -120
  94. package/dist/config.mjs +405 -4
  95. package/dist/config.mjs.map +1 -0
  96. package/dist/credentialSchemas-DDda4Mmm.cjs +272 -0
  97. package/dist/credentialSchemas-DDda4Mmm.cjs.map +1 -0
  98. package/dist/credentialSchemas-DvitraL-.mjs +237 -0
  99. package/dist/credentialSchemas-DvitraL-.mjs.map +1 -0
  100. package/dist/credentials-B5N5yKk6.mjs +267 -0
  101. package/dist/credentials-B5N5yKk6.mjs.map +1 -0
  102. package/dist/credentials-Zqr3QQYB.cjs +350 -0
  103. package/dist/credentials-Zqr3QQYB.cjs.map +1 -0
  104. package/dist/databases-BeGP5eDh.mjs +495 -0
  105. package/dist/databases-BeGP5eDh.mjs.map +1 -0
  106. package/dist/databases-DGALFDG3.cjs +598 -0
  107. package/dist/databases-DGALFDG3.cjs.map +1 -0
  108. package/dist/define-6poNqm5O.mjs +106 -0
  109. package/dist/define-6poNqm5O.mjs.map +1 -0
  110. package/dist/define-crmMcXFS.cjs +153 -0
  111. package/dist/define-crmMcXFS.cjs.map +1 -0
  112. package/dist/deploy/public.cjs +212 -0
  113. package/dist/deploy/public.cjs.map +1 -0
  114. package/dist/deploy/public.d.cts +653 -0
  115. package/dist/deploy/public.d.cts.map +1 -0
  116. package/dist/deploy/public.d.mts +653 -0
  117. package/dist/deploy/public.d.mts.map +1 -0
  118. package/dist/deploy/public.mjs +145 -0
  119. package/dist/deploy/public.mjs.map +1 -0
  120. package/dist/deploy/sniffer-envkit-patch.cjs +18 -10
  121. package/dist/deploy/sniffer-envkit-patch.cjs.map +1 -1
  122. package/dist/deploy/sniffer-envkit-patch.d.cts +0 -2
  123. package/dist/deploy/sniffer-envkit-patch.d.cts.map +1 -1
  124. package/dist/deploy/sniffer-envkit-patch.d.mts +0 -2
  125. package/dist/deploy/sniffer-envkit-patch.d.mts.map +1 -1
  126. package/dist/deploy/sniffer-envkit-patch.mjs +10 -2
  127. package/dist/deploy/sniffer-envkit-patch.mjs.map +1 -1
  128. package/dist/deploy/sniffer-envparser-worker.cjs +54 -0
  129. package/dist/deploy/sniffer-envparser-worker.cjs.map +1 -0
  130. package/dist/deploy/sniffer-envparser-worker.d.cts +1 -0
  131. package/dist/deploy/sniffer-envparser-worker.d.mts +1 -0
  132. package/dist/deploy/sniffer-envparser-worker.mjs +55 -0
  133. package/dist/deploy/sniffer-envparser-worker.mjs.map +1 -0
  134. package/dist/deploy/sniffer-hooks.cjs +13 -7
  135. package/dist/deploy/sniffer-hooks.cjs.map +1 -1
  136. package/dist/deploy/sniffer-hooks.d.cts +1 -2
  137. package/dist/deploy/sniffer-hooks.d.cts.map +1 -1
  138. package/dist/deploy/sniffer-hooks.d.mts +1 -2
  139. package/dist/deploy/sniffer-hooks.d.mts.map +1 -1
  140. package/dist/deploy/sniffer-hooks.mjs +10 -3
  141. package/dist/deploy/sniffer-hooks.mjs.map +1 -1
  142. package/dist/deploy/sniffer-loader.cjs +16 -7
  143. package/dist/deploy/sniffer-loader.cjs.map +1 -1
  144. package/dist/deploy/sniffer-loader.d.cts +1 -1
  145. package/dist/deploy/sniffer-loader.d.mts +1 -1
  146. package/dist/deploy/sniffer-loader.mjs +14 -3
  147. package/dist/deploy/sniffer-loader.mjs.map +1 -1
  148. package/dist/deploy/sniffer-routes-worker.cjs +11 -11
  149. package/dist/deploy/sniffer-routes-worker.cjs.map +1 -1
  150. package/dist/deploy/sniffer-routes-worker.d.cts +1 -1
  151. package/dist/deploy/sniffer-routes-worker.d.mts +1 -1
  152. package/dist/deploy/sniffer-routes-worker.mjs +4 -4
  153. package/dist/deploy/sniffer-routes-worker.mjs.map +1 -1
  154. package/dist/deploy/sniffer-worker.cjs +15 -6
  155. package/dist/deploy/sniffer-worker.cjs.map +1 -1
  156. package/dist/deploy/sniffer-worker.d.cts +1 -3
  157. package/dist/deploy/sniffer-worker.d.cts.map +1 -1
  158. package/dist/deploy/sniffer-worker.d.mts +1 -3
  159. package/dist/deploy/sniffer-worker.d.mts.map +1 -1
  160. package/dist/deploy/sniffer-worker.mjs +15 -4
  161. package/dist/deploy/sniffer-worker.mjs.map +1 -1
  162. package/dist/deploy-DUUc3jV9.cjs +2390 -0
  163. package/dist/deploy-DUUc3jV9.cjs.map +1 -0
  164. package/dist/deploy-DgZxTnGS.mjs +2317 -0
  165. package/dist/deploy-DgZxTnGS.mjs.map +1 -0
  166. package/dist/derive-B4vDpzgP.mjs +150 -0
  167. package/dist/derive-B4vDpzgP.mjs.map +1 -0
  168. package/dist/derive-DAbo49sm.cjs +161 -0
  169. package/dist/derive-DAbo49sm.cjs.map +1 -0
  170. package/dist/discover-BfhVW_kT.cjs +600 -0
  171. package/dist/discover-BfhVW_kT.cjs.map +1 -0
  172. package/dist/discover-CvTtV5ZD.d.cts +108 -0
  173. package/dist/discover-CvTtV5ZD.d.cts.map +1 -0
  174. package/dist/discover-W2kab9Lc.d.mts +108 -0
  175. package/dist/discover-W2kab9Lc.d.mts.map +1 -0
  176. package/dist/discover-kziEht4W.mjs +527 -0
  177. package/dist/discover-kziEht4W.mjs.map +1 -0
  178. package/dist/dns-DDDCfj75.mjs +926 -0
  179. package/dist/dns-DDDCfj75.mjs.map +1 -0
  180. package/dist/dns-DnE_02tB.cjs +1057 -0
  181. package/dist/dns-DnE_02tB.cjs.map +1 -0
  182. package/dist/dokploy-BrfdeVEu.cjs +38 -0
  183. package/dist/dokploy-BrfdeVEu.cjs.map +1 -0
  184. package/dist/dokploy-DBlGSdnb.mjs +38 -0
  185. package/dist/dokploy-DBlGSdnb.mjs.map +1 -0
  186. package/dist/drivers-BLU1fNs_.cjs +200 -0
  187. package/dist/drivers-BLU1fNs_.cjs.map +1 -0
  188. package/dist/drivers-C08LL4E8.mjs +177 -0
  189. package/dist/drivers-C08LL4E8.mjs.map +1 -0
  190. package/dist/{emit-CiZS_5Ub.mjs → emit-C1e8qD08.mjs} +13 -26
  191. package/dist/emit-C1e8qD08.mjs.map +1 -0
  192. package/dist/{emit-CbcRolsa.cjs → emit-Dmc1nvdS.cjs} +31 -57
  193. package/dist/emit-Dmc1nvdS.cjs.map +1 -0
  194. package/dist/encryption-CeW3xpE1.cjs +90 -0
  195. package/dist/encryption-CeW3xpE1.cjs.map +1 -0
  196. package/dist/encryption-DC8zsh2s.mjs +89 -0
  197. package/dist/encryption-DC8zsh2s.mjs.map +1 -0
  198. package/dist/engine-BXxvcxVq.cjs +3195 -0
  199. package/dist/engine-BXxvcxVq.cjs.map +1 -0
  200. package/dist/engine-z0UClzE9.mjs +3082 -0
  201. package/dist/engine-z0UClzE9.mjs.map +1 -0
  202. package/dist/errors-D8Gwp5kU.mjs +23 -0
  203. package/dist/errors-D8Gwp5kU.mjs.map +1 -0
  204. package/dist/errors-DMC4Umsb.cjs +34 -0
  205. package/dist/errors-DMC4Umsb.cjs.map +1 -0
  206. package/dist/github-DJgO5z37.mjs +829 -0
  207. package/dist/github-DJgO5z37.mjs.map +1 -0
  208. package/dist/github-DWoFgxtl.cjs +829 -0
  209. package/dist/github-DWoFgxtl.cjs.map +1 -0
  210. package/dist/identity-CBXr4wNi.mjs +129 -0
  211. package/dist/identity-CBXr4wNi.mjs.map +1 -0
  212. package/dist/identity-CbLfgQNT.cjs +182 -0
  213. package/dist/identity-CbLfgQNT.cjs.map +1 -0
  214. package/dist/{index-C6e-ULLx.d.mts → index-8OfpOtSI.d.cts} +39 -24
  215. package/dist/index-8OfpOtSI.d.cts.map +1 -0
  216. package/dist/{index-CR5urhWX.d.cts → index-Dpji6Bxq.d.mts} +39 -24
  217. package/dist/index-Dpji6Bxq.d.mts.map +1 -0
  218. package/dist/index.cjs +10022 -12718
  219. package/dist/index.cjs.map +1 -1
  220. package/dist/index.d.cts +1 -1
  221. package/dist/index.d.mts +1 -1
  222. package/dist/index.mjs +10648 -13356
  223. package/dist/index.mjs.map +1 -1
  224. package/dist/local-BwC2v2Y8.mjs +224 -0
  225. package/dist/local-BwC2v2Y8.mjs.map +1 -0
  226. package/dist/local-DNhnkugT.cjs +241 -0
  227. package/dist/local-DNhnkugT.cjs.map +1 -0
  228. package/dist/migrate-B1OjPwUY.cjs +181 -0
  229. package/dist/migrate-B1OjPwUY.cjs.map +1 -0
  230. package/dist/migrate-CWSCkzu3.cjs +271 -0
  231. package/dist/migrate-CWSCkzu3.cjs.map +1 -0
  232. package/dist/migrate-DIVxoju6.mjs +266 -0
  233. package/dist/migrate-DIVxoju6.mjs.map +1 -0
  234. package/dist/migrate-DoI2hWNH.mjs +181 -0
  235. package/dist/migrate-DoI2hWNH.mjs.map +1 -0
  236. package/dist/openapi.cjs +214 -10
  237. package/dist/openapi.cjs.map +1 -0
  238. package/dist/openapi.d.cts +38 -17
  239. package/dist/openapi.d.cts.map +1 -1
  240. package/dist/openapi.d.mts +38 -17
  241. package/dist/openapi.d.mts.map +1 -1
  242. package/dist/openapi.mjs +208 -5
  243. package/dist/openapi.mjs.map +1 -0
  244. package/dist/projectBucket-BBbQ1lHF.cjs +263 -0
  245. package/dist/projectBucket-BBbQ1lHF.cjs.map +1 -0
  246. package/dist/projectBucket-C_DN4WzF.mjs +222 -0
  247. package/dist/projectBucket-C_DN4WzF.mjs.map +1 -0
  248. package/dist/provider-BqpjG9QM.cjs +57 -0
  249. package/dist/provider-BqpjG9QM.cjs.map +1 -0
  250. package/dist/provider-CEOKk8NS.mjs +46 -0
  251. package/dist/provider-CEOKk8NS.mjs.map +1 -0
  252. package/dist/ready-BtxiI7Qb.cjs +403 -0
  253. package/dist/ready-BtxiI7Qb.cjs.map +1 -0
  254. package/dist/ready-CzHNHhI6.mjs +374 -0
  255. package/dist/ready-CzHNHhI6.mjs.map +1 -0
  256. package/dist/reconcile/public.cjs +3 -5
  257. package/dist/reconcile/public.d.cts +11 -87
  258. package/dist/reconcile/public.d.cts.map +1 -1
  259. package/dist/reconcile/public.d.mts +11 -87
  260. package/dist/reconcile/public.d.mts.map +1 -1
  261. package/dist/reconcile/public.mjs +3 -4
  262. package/dist/{reconcile-CFs8C_1a.mjs → reconcile--I7V4Klj.mjs} +4 -7
  263. package/dist/reconcile--I7V4Klj.mjs.map +1 -0
  264. package/dist/{reconcile-D0pimNiy.cjs → reconcile-CuCQBa5-.cjs} +5 -8
  265. package/dist/reconcile-CuCQBa5-.cjs.map +1 -0
  266. package/dist/resolve-WAwYMN6q.cjs +316 -0
  267. package/dist/resolve-WAwYMN6q.cjs.map +1 -0
  268. package/dist/resolve-pmXIdi9j.mjs +263 -0
  269. package/dist/resolve-pmXIdi9j.mjs.map +1 -0
  270. package/dist/rollback-CLtwbByg.mjs +136 -0
  271. package/dist/rollback-CLtwbByg.mjs.map +1 -0
  272. package/dist/rollback-Cz8F9xSB.cjs +165 -0
  273. package/dist/rollback-Cz8F9xSB.cjs.map +1 -0
  274. package/dist/rolldown-runtime-BhDjJH2R.mjs +15 -0
  275. package/dist/{chunk-CUT6urMc.cjs → rolldown-runtime-C0BPl7ul.cjs} +23 -10
  276. package/dist/run-BJLIerMM.mjs +133 -0
  277. package/dist/run-BJLIerMM.mjs.map +1 -0
  278. package/dist/run-fVZ-rLnc.cjs +174 -0
  279. package/dist/run-fVZ-rLnc.cjs.map +1 -0
  280. package/dist/runtime-ACdfK59n.d.cts +82 -0
  281. package/dist/runtime-ACdfK59n.d.cts.map +1 -0
  282. package/dist/runtime-YyQuekxi.d.mts +82 -0
  283. package/dist/runtime-YyQuekxi.d.mts.map +1 -0
  284. package/dist/s3-CrPoA89T.cjs +215 -0
  285. package/dist/s3-CrPoA89T.cjs.map +1 -0
  286. package/dist/s3-DQXZdmCM.mjs +215 -0
  287. package/dist/s3-DQXZdmCM.mjs.map +1 -0
  288. package/dist/sandbox/config-worker.cjs +43 -0
  289. package/dist/sandbox/config-worker.cjs.map +1 -0
  290. package/dist/sandbox/config-worker.d.cts +1 -0
  291. package/dist/sandbox/config-worker.d.mts +1 -0
  292. package/dist/sandbox/config-worker.mjs +44 -0
  293. package/dist/sandbox/config-worker.mjs.map +1 -0
  294. package/dist/sandbox/credentials-worker.cjs +54 -0
  295. package/dist/sandbox/credentials-worker.cjs.map +1 -0
  296. package/dist/sandbox/credentials-worker.d.cts +1 -0
  297. package/dist/sandbox/credentials-worker.d.mts +1 -0
  298. package/dist/sandbox/credentials-worker.mjs +55 -0
  299. package/dist/sandbox/credentials-worker.mjs.map +1 -0
  300. package/dist/sandbox/discover-worker.cjs +47 -0
  301. package/dist/sandbox/discover-worker.cjs.map +1 -0
  302. package/dist/sandbox/discover-worker.d.cts +1 -0
  303. package/dist/sandbox/discover-worker.d.mts +1 -0
  304. package/dist/sandbox/discover-worker.mjs +48 -0
  305. package/dist/sandbox/discover-worker.mjs.map +1 -0
  306. package/dist/sandbox/migrate-worker.cjs +75 -0
  307. package/dist/sandbox/migrate-worker.cjs.map +1 -0
  308. package/dist/sandbox/migrate-worker.d.cts +1 -0
  309. package/dist/sandbox/migrate-worker.d.mts +1 -0
  310. package/dist/sandbox/migrate-worker.mjs +76 -0
  311. package/dist/sandbox/migrate-worker.mjs.map +1 -0
  312. package/dist/sandbox-C4g1eG31.d.mts +104 -0
  313. package/dist/sandbox-C4g1eG31.d.mts.map +1 -0
  314. package/dist/sandbox-CHv3OYXg.cjs +165 -0
  315. package/dist/sandbox-CHv3OYXg.cjs.map +1 -0
  316. package/dist/sandbox-CbVB7uOD.mjs +118 -0
  317. package/dist/sandbox-CbVB7uOD.mjs.map +1 -0
  318. package/dist/sandbox-CdKgQ3XU.d.cts +104 -0
  319. package/dist/sandbox-CdKgQ3XU.d.cts.map +1 -0
  320. package/dist/{workspace-C6VJQVtG.cjs → schemas-BCwKKA42.mjs} +958 -1842
  321. package/dist/schemas-BCwKKA42.mjs.map +1 -0
  322. package/dist/{workspace-zoqRbihZ.mjs → schemas-BQ_v0lEX.cjs} +1048 -1658
  323. package/dist/schemas-BQ_v0lEX.cjs.map +1 -0
  324. package/dist/secretsManager-CQORubp9.mjs +97 -0
  325. package/dist/secretsManager-CQORubp9.mjs.map +1 -0
  326. package/dist/secretsManager-RAGcEDX1.cjs +108 -0
  327. package/dist/secretsManager-RAGcEDX1.cjs.map +1 -0
  328. package/dist/seeds-BHKUAExH.mjs +8148 -0
  329. package/dist/seeds-BHKUAExH.mjs.map +1 -0
  330. package/dist/seeds-Dk4WHhjU.cjs +9115 -0
  331. package/dist/seeds-Dk4WHhjU.cjs.map +1 -0
  332. package/dist/sniffer-BjBZ01PE.cjs +1998 -0
  333. package/dist/sniffer-BjBZ01PE.cjs.map +1 -0
  334. package/dist/sniffer-CaXl51vO.mjs +1825 -0
  335. package/dist/sniffer-CaXl51vO.mjs.map +1 -0
  336. package/dist/sst-B-Uz4cvm.cjs +464 -0
  337. package/dist/sst-B-Uz4cvm.cjs.map +1 -0
  338. package/dist/sst-C1pxbFEd.mjs +441 -0
  339. package/dist/sst-C1pxbFEd.mjs.map +1 -0
  340. package/dist/stages-DJrOYLZ-.mjs +176 -0
  341. package/dist/stages-DJrOYLZ-.mjs.map +1 -0
  342. package/dist/stages-_3RVNG83.cjs +176 -0
  343. package/dist/stages-_3RVNG83.cjs.map +1 -0
  344. package/dist/target/public.cjs +15 -0
  345. package/dist/target/public.d.cts +28 -0
  346. package/dist/target/public.d.cts.map +1 -0
  347. package/dist/target/public.d.mts +28 -0
  348. package/dist/target/public.d.mts.map +1 -0
  349. package/dist/target/public.mjs +4 -0
  350. package/dist/terminal-Bs_lNQhL.mjs +85 -0
  351. package/dist/terminal-Bs_lNQhL.mjs.map +1 -0
  352. package/dist/terminal-CsQz4oT0.cjs +85 -0
  353. package/dist/terminal-CsQz4oT0.cjs.map +1 -0
  354. package/dist/types-B6UXlEkf.d.cts +7650 -0
  355. package/dist/types-B6UXlEkf.d.cts.map +1 -0
  356. package/dist/types-HqVPddRK.d.mts +7649 -0
  357. package/dist/types-HqVPddRK.d.mts.map +1 -0
  358. package/dist/utils-D2Nk1Nv2.cjs +205 -0
  359. package/dist/utils-D2Nk1Nv2.cjs.map +1 -0
  360. package/dist/utils-D_fxUqvU.mjs +156 -0
  361. package/dist/utils-D_fxUqvU.mjs.map +1 -0
  362. package/dist/vitest.cjs +65 -0
  363. package/dist/vitest.cjs.map +1 -0
  364. package/dist/vitest.d.cts +29 -0
  365. package/dist/vitest.d.cts.map +1 -0
  366. package/dist/vitest.d.mts +29 -0
  367. package/dist/vitest.d.mts.map +1 -0
  368. package/dist/vitest.mjs +65 -0
  369. package/dist/vitest.mjs.map +1 -0
  370. package/dist/workerRuntime-BXfhbe13.cjs +108 -0
  371. package/dist/workerRuntime-BXfhbe13.cjs.map +1 -0
  372. package/dist/workerRuntime-CsOyBRx2.mjs +79 -0
  373. package/dist/workerRuntime-CsOyBRx2.mjs.map +1 -0
  374. package/dist/workspace/index.cjs +8 -4
  375. package/dist/workspace/index.d.cts +3 -3
  376. package/dist/workspace/index.d.mts +3 -3
  377. package/dist/workspace/index.mjs +2 -3
  378. package/dist/workspace-BwqQnool.cjs +2806 -0
  379. package/dist/workspace-BwqQnool.cjs.map +1 -0
  380. package/dist/workspace-D1QbNd55.mjs +2394 -0
  381. package/dist/workspace-D1QbNd55.mjs.map +1 -0
  382. package/package.json +54 -22
  383. package/dist/CachedStateProvider-BLo7zv7S.cjs +0 -3
  384. package/dist/CachedStateProvider-BxoAm-B2.mjs +0 -3
  385. package/dist/CachedStateProvider-CqPdW7CB.cjs +0 -60
  386. package/dist/CachedStateProvider-CqPdW7CB.cjs.map +0 -1
  387. package/dist/CachedStateProvider-DTniehMP.mjs +0 -54
  388. package/dist/CachedStateProvider-DTniehMP.mjs.map +0 -1
  389. package/dist/HostingerProvider-Cft7lEYr.mjs.map +0 -1
  390. package/dist/HostingerProvider-h3EbEp-Z.cjs.map +0 -1
  391. package/dist/LocalStateProvider-Bn6tS-oL.mjs +0 -42
  392. package/dist/LocalStateProvider-Bn6tS-oL.mjs.map +0 -1
  393. package/dist/LocalStateProvider-Db9SEjyH.cjs +0 -43
  394. package/dist/LocalStateProvider-Db9SEjyH.cjs.map +0 -1
  395. package/dist/Route53Provider-RdpUDJQk.mjs.map +0 -1
  396. package/dist/Route53Provider-di2fMM5N.cjs.map +0 -1
  397. package/dist/SSMStateProvider-BRt2py-A.mjs +0 -66
  398. package/dist/SSMStateProvider-BRt2py-A.mjs.map +0 -1
  399. package/dist/SSMStateProvider-DyX8s9HI.cjs +0 -66
  400. package/dist/SSMStateProvider-DyX8s9HI.cjs.map +0 -1
  401. package/dist/backup-provisioner-Bgj5Vi_L.mjs.map +0 -1
  402. package/dist/backup-provisioner-BrsHwYG0.cjs.map +0 -1
  403. package/dist/bundler-BY1OmV1e.cjs.map +0 -1
  404. package/dist/bundler-Be8Zg4Wd.mjs.map +0 -1
  405. package/dist/chunk-Duj1WY3L.mjs +0 -7
  406. package/dist/config-BZ1F0WuA.cjs +0 -462
  407. package/dist/config-BZ1F0WuA.cjs.map +0 -1
  408. package/dist/config-DVVph9yz.mjs +0 -402
  409. package/dist/config-DVVph9yz.mjs.map +0 -1
  410. package/dist/config.d.cts.map +0 -1
  411. package/dist/config.d.mts.map +0 -1
  412. package/dist/credentials-B5zRHdAl.mjs +0 -141
  413. package/dist/credentials-B5zRHdAl.mjs.map +0 -1
  414. package/dist/credentials-BapzjyV5.cjs +0 -195
  415. package/dist/credentials-BapzjyV5.cjs.map +0 -1
  416. package/dist/credentials-Xamqe_NJ.cjs +0 -2681
  417. package/dist/credentials-Xamqe_NJ.cjs.map +0 -1
  418. package/dist/credentials-dP8vRVRv.mjs +0 -2549
  419. package/dist/credentials-dP8vRVRv.mjs.map +0 -1
  420. package/dist/discover-CAlFgYec.mjs +0 -229
  421. package/dist/discover-CAlFgYec.mjs.map +0 -1
  422. package/dist/discover-DTmFeloL.cjs +0 -271
  423. package/dist/discover-DTmFeloL.cjs.map +0 -1
  424. package/dist/dokploy-api-BS2xnJLZ.mjs +0 -3
  425. package/dist/dokploy-api-BsVH0y_s.cjs +0 -718
  426. package/dist/dokploy-api-BsVH0y_s.cjs.map +0 -1
  427. package/dist/dokploy-api-BuxDRo3l.cjs +0 -3
  428. package/dist/dokploy-api-aTFPz7_4.mjs +0 -706
  429. package/dist/dokploy-api-aTFPz7_4.mjs.map +0 -1
  430. package/dist/emit-CbcRolsa.cjs.map +0 -1
  431. package/dist/emit-CiZS_5Ub.mjs.map +0 -1
  432. package/dist/encryption-C6jaU0hE.cjs +0 -54
  433. package/dist/encryption-C6jaU0hE.cjs.map +0 -1
  434. package/dist/encryption-CHzzeR8a.cjs +0 -4
  435. package/dist/encryption-CQUncu7v.mjs +0 -3
  436. package/dist/encryption-D-abyhZx.mjs +0 -42
  437. package/dist/encryption-D-abyhZx.mjs.map +0 -1
  438. package/dist/fullstack-secrets-C-GGohke.cjs +0 -111
  439. package/dist/fullstack-secrets-C-GGohke.cjs.map +0 -1
  440. package/dist/fullstack-secrets-D1o9-G5l.mjs +0 -87
  441. package/dist/fullstack-secrets-D1o9-G5l.mjs.map +0 -1
  442. package/dist/generator-CNzBw7g5.cjs +0 -289
  443. package/dist/generator-CNzBw7g5.cjs.map +0 -1
  444. package/dist/generator-VE2JrFlY.mjs +0 -253
  445. package/dist/generator-VE2JrFlY.mjs.map +0 -1
  446. package/dist/index-C6e-ULLx.d.mts.map +0 -1
  447. package/dist/index-CR5urhWX.d.cts.map +0 -1
  448. package/dist/openapi-SjsgARie.cjs +0 -2075
  449. package/dist/openapi-SjsgARie.cjs.map +0 -1
  450. package/dist/openapi-Xx0A7Wg0.mjs +0 -2021
  451. package/dist/openapi-Xx0A7Wg0.mjs.map +0 -1
  452. package/dist/openapi-react-query-Byltvm_7.mjs +0 -167
  453. package/dist/openapi-react-query-Byltvm_7.mjs.map +0 -1
  454. package/dist/openapi-react-query-CmJ1xDbn.cjs +0 -173
  455. package/dist/openapi-react-query-CmJ1xDbn.cjs.map +0 -1
  456. package/dist/openapi-react-query.cjs +0 -4
  457. package/dist/openapi-react-query.d.cts +0 -11
  458. package/dist/openapi-react-query.d.cts.map +0 -1
  459. package/dist/openapi-react-query.d.mts +0 -11
  460. package/dist/openapi-react-query.d.mts.map +0 -1
  461. package/dist/openapi-react-query.mjs +0 -4
  462. package/dist/reconcile-CFs8C_1a.mjs.map +0 -1
  463. package/dist/reconcile-D0pimNiy.cjs.map +0 -1
  464. package/dist/setup-BA8ciTPU.mjs +0 -11
  465. package/dist/setup-BsZvZP6f.cjs +0 -11
  466. package/dist/setup-C8KOx8_8.mjs +0 -443
  467. package/dist/setup-C8KOx8_8.mjs.map +0 -1
  468. package/dist/setup-hC6hI86f.cjs +0 -473
  469. package/dist/setup-hC6hI86f.cjs.map +0 -1
  470. package/dist/storage-BJmzYxt8.cjs +0 -363
  471. package/dist/storage-BJmzYxt8.cjs.map +0 -1
  472. package/dist/storage-BM9hGpgv.cjs +0 -7
  473. package/dist/storage-Bi24WfoW.mjs +0 -297
  474. package/dist/storage-Bi24WfoW.mjs.map +0 -1
  475. package/dist/storage-CYlGwWTj.mjs +0 -3
  476. package/dist/sync-CmEuNZsB.mjs +0 -76
  477. package/dist/sync-CmEuNZsB.mjs.map +0 -1
  478. package/dist/sync-D306yOWu.cjs +0 -4
  479. package/dist/sync-SizaChmC.cjs +0 -93
  480. package/dist/sync-SizaChmC.cjs.map +0 -1
  481. package/dist/sync-hOqAWHR6.mjs +0 -3
  482. package/dist/types-6pkp2RRj.d.mts +0 -2220
  483. package/dist/types-6pkp2RRj.d.mts.map +0 -1
  484. package/dist/types-Y3fKQSAK.d.cts +0 -2220
  485. package/dist/types-Y3fKQSAK.d.cts.map +0 -1
  486. package/dist/workspace-BzrG_2SI.mjs +0 -8
  487. package/dist/workspace-C6VJQVtG.cjs.map +0 -1
  488. package/dist/workspace-XXtNhqJl.cjs +0 -9
  489. package/dist/workspace-zoqRbihZ.mjs.map +0 -1
@@ -1,8 +1,12 @@
1
- const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- const __aws_sdk_client_s3 = require_chunk.__toESM(require("@aws-sdk/client-s3"));
3
- const __aws_sdk_client_iam = require_chunk.__toESM(require("@aws-sdk/client-iam"));
4
-
5
- //#region src/deploy/backup-provisioner.ts
1
+ let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
2
+ let _aws_sdk_client_iam = require("@aws-sdk/client-iam");
3
+ //#region src/target/dokploy/backup-provisioner.ts
4
+ /**
5
+ * Backup Destination Provisioner
6
+ *
7
+ * Creates AWS resources (S3 bucket, IAM user, access keys) and configures
8
+ * Dokploy backup destinations for database backups.
9
+ */
6
10
  /**
7
11
  * Generate a random suffix for unique resource names
8
12
  */
@@ -33,8 +37,8 @@ async function createAwsClients(region, profile, endpoint) {
33
37
  };
34
38
  }
35
39
  return {
36
- s3: new __aws_sdk_client_s3.S3Client(config),
37
- iam: new __aws_sdk_client_iam.IAMClient(config)
40
+ s3: new _aws_sdk_client_s3.S3Client(config),
41
+ iam: new _aws_sdk_client_iam.IAMClient(config)
38
42
  };
39
43
  }
40
44
  /**
@@ -42,7 +46,7 @@ async function createAwsClients(region, profile, endpoint) {
42
46
  */
43
47
  async function bucketExists(s3, bucketName) {
44
48
  try {
45
- await s3.send(new __aws_sdk_client_s3.HeadBucketCommand({ Bucket: bucketName }));
49
+ await s3.send(new _aws_sdk_client_s3.HeadBucketCommand({ Bucket: bucketName }));
46
50
  return true;
47
51
  } catch (error) {
48
52
  if (error.name === "NotFound") return false;
@@ -55,7 +59,7 @@ async function bucketExists(s3, bucketName) {
55
59
  */
56
60
  async function userExists(iam, userName) {
57
61
  try {
58
- await iam.send(new __aws_sdk_client_iam.GetUserCommand({ UserName: userName }));
62
+ await iam.send(new _aws_sdk_client_iam.GetUserCommand({ UserName: userName }));
59
63
  return true;
60
64
  } catch (error) {
61
65
  const errorName = error.name;
@@ -81,22 +85,20 @@ async function provisionBackupDestination(options) {
81
85
  const aws = await createAwsClients(config.region, config.profile, awsEndpoint);
82
86
  const sanitizedProject = sanitizeName(projectName);
83
87
  const bucketName = existingState?.bucketName ?? `${sanitizedProject}-${stage}-backups-${randomSuffix()}`;
84
- const bucketAlreadyExists = await bucketExists(aws.s3, bucketName);
85
- if (!bucketAlreadyExists) {
88
+ if (!await bucketExists(aws.s3, bucketName)) {
86
89
  logger.log(` Creating S3 bucket: ${bucketName}`);
87
90
  const createBucketParams = { Bucket: bucketName };
88
91
  if (config.region !== "us-east-1") createBucketParams.CreateBucketConfiguration = { LocationConstraint: config.region };
89
- await aws.s3.send(new __aws_sdk_client_s3.CreateBucketCommand(createBucketParams));
90
- await aws.s3.send(new __aws_sdk_client_s3.PutBucketVersioningCommand({
92
+ await aws.s3.send(new _aws_sdk_client_s3.CreateBucketCommand(createBucketParams));
93
+ await aws.s3.send(new _aws_sdk_client_s3.PutBucketVersioningCommand({
91
94
  Bucket: bucketName,
92
95
  VersioningConfiguration: { Status: "Enabled" }
93
96
  }));
94
97
  } else logger.log(` Using existing S3 bucket: ${bucketName}`);
95
98
  const iamUserName = existingState?.iamUserName ?? `dokploy-backup-${sanitizedProject}-${stage}`;
96
- const iamUserAlreadyExists = await userExists(aws.iam, iamUserName);
97
- if (!iamUserAlreadyExists) {
99
+ if (!await userExists(aws.iam, iamUserName)) {
98
100
  logger.log(` Creating IAM user: ${iamUserName}`);
99
- await aws.iam.send(new __aws_sdk_client_iam.CreateUserCommand({ UserName: iamUserName }));
101
+ await aws.iam.send(new _aws_sdk_client_iam.CreateUserCommand({ UserName: iamUserName }));
100
102
  } else logger.log(` Using existing IAM user: ${iamUserName}`);
101
103
  const policyDocument = {
102
104
  Version: "2012-10-17",
@@ -113,7 +115,7 @@ async function provisionBackupDestination(options) {
113
115
  }]
114
116
  };
115
117
  logger.log(" Updating IAM policy");
116
- await aws.iam.send(new __aws_sdk_client_iam.PutUserPolicyCommand({
118
+ await aws.iam.send(new _aws_sdk_client_iam.PutUserPolicyCommand({
117
119
  UserName: iamUserName,
118
120
  PolicyName: "DokployBackupAccess",
119
121
  PolicyDocument: JSON.stringify(policyDocument)
@@ -126,7 +128,7 @@ async function provisionBackupDestination(options) {
126
128
  secretAccessKey = existingState.iamSecretAccessKey;
127
129
  } else {
128
130
  logger.log(" Creating IAM access key");
129
- const accessKeyResult = await aws.iam.send(new __aws_sdk_client_iam.CreateAccessKeyCommand({ UserName: iamUserName }));
131
+ const accessKeyResult = await aws.iam.send(new _aws_sdk_client_iam.CreateAccessKeyCommand({ UserName: iamUserName }));
130
132
  if (!accessKeyResult.AccessKey) throw new Error("Failed to create IAM access key");
131
133
  accessKeyId = accessKeyResult.AccessKey.AccessKeyId;
132
134
  secretAccessKey = accessKeyResult.AccessKey.SecretAccessKey;
@@ -158,7 +160,7 @@ async function provisionBackupDestination(options) {
158
160
  createdAt: existingState?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
159
161
  };
160
162
  }
161
-
162
163
  //#endregion
163
164
  exports.provisionBackupDestination = provisionBackupDestination;
164
- //# sourceMappingURL=backup-provisioner-BrsHwYG0.cjs.map
165
+
166
+ //# sourceMappingURL=backup-provisioner-oDEsPj02.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup-provisioner-oDEsPj02.cjs","names":["S3Client","IAMClient","HeadBucketCommand","GetUserCommand","CreateBucketCommand","PutBucketVersioningCommand","CreateUserCommand","PutUserPolicyCommand","CreateAccessKeyCommand"],"sources":["../src/target/dokploy/backup-provisioner.ts"],"sourcesContent":["/**\n * Backup Destination Provisioner\n *\n * Creates AWS resources (S3 bucket, IAM user, access keys) and configures\n * Dokploy backup destinations for database backups.\n */\n\nimport {\n\tCreateAccessKeyCommand,\n\tCreateUserCommand,\n\tGetUserCommand,\n\tIAMClient,\n\ttype IAMClientConfig,\n\tPutUserPolicyCommand,\n} from '@aws-sdk/client-iam';\nimport {\n\ttype BucketLocationConstraint,\n\tCreateBucketCommand,\n\tHeadBucketCommand,\n\tPutBucketVersioningCommand,\n\tS3Client,\n\ttype S3ClientConfig,\n} from '@aws-sdk/client-s3';\nimport type { BackupState } from '../../deploy/state.js';\nimport type { DokployBackupsConfig } from '../../workspace/types.js';\nimport type { DokployApi } from './dokploy-api.js';\n\nexport interface ProvisionBackupOptions {\n\t/** Dokploy API client */\n\tapi: DokployApi;\n\t/** Dokploy project ID */\n\tprojectId: string;\n\t/** Workspace name (used for resource naming) */\n\tprojectName: string;\n\t/** Deploy stage (e.g., 'production', 'staging') */\n\tstage: string;\n\t/** Backup configuration */\n\tconfig: DokployBackupsConfig;\n\t/** Existing backup state (if any) */\n\texistingState?: BackupState;\n\t/** Logger for progress output */\n\tlogger: { log: (msg: string) => void };\n\t/** AWS endpoint override (for testing with LocalStack) */\n\tawsEndpoint?: string;\n}\n\n/**\n * Generate a random suffix for unique resource names\n */\nfunction randomSuffix(): string {\n\treturn Math.random().toString(36).substring(2, 8);\n}\n\n/**\n * Sanitize a name for AWS resources (lowercase alphanumeric and hyphens)\n */\nfunction sanitizeName(name: string): string {\n\treturn name.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n}\n\n/**\n * Create AWS clients with optional profile credentials\n */\nasync function createAwsClients(\n\tregion: string,\n\tprofile?: string,\n\tendpoint?: string,\n): Promise<{ s3: S3Client; iam: IAMClient }> {\n\tconst config: S3ClientConfig & IAMClientConfig = { region };\n\n\tif (profile) {\n\t\tconst { fromIni } = await import('@aws-sdk/credential-providers');\n\t\tconfig.credentials = fromIni({ profile });\n\t}\n\n\t// Support custom endpoint for testing (e.g., LocalStack)\n\tif (endpoint) {\n\t\tconfig.endpoint = endpoint;\n\t\t(config as S3ClientConfig).forcePathStyle = true;\n\t\t// Use test credentials when endpoint is specified\n\t\tconfig.credentials = {\n\t\t\taccessKeyId: 'test',\n\t\t\tsecretAccessKey: 'test',\n\t\t};\n\t}\n\n\treturn {\n\t\ts3: new S3Client(config),\n\t\tiam: new IAMClient(config),\n\t};\n}\n\n/**\n * Check if an S3 bucket exists\n */\nasync function bucketExists(\n\ts3: S3Client,\n\tbucketName: string,\n): Promise<boolean> {\n\ttry {\n\t\tawait s3.send(new HeadBucketCommand({ Bucket: bucketName }));\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as { name?: string }).name === 'NotFound') {\n\t\t\treturn false;\n\t\t}\n\t\t// 403 means bucket exists but we don't have access\n\t\tif (\n\t\t\t(error as { $metadata?: { httpStatusCode?: number } }).$metadata\n\t\t\t\t?.httpStatusCode === 403\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Check if an IAM user exists\n */\nasync function userExists(iam: IAMClient, userName: string): Promise<boolean> {\n\ttry {\n\t\tawait iam.send(new GetUserCommand({ UserName: userName }));\n\t\treturn true;\n\t} catch (error) {\n\t\tconst errorName = (error as { name?: string }).name;\n\t\t// AWS returns 'NoSuchEntity', LocalStack returns 'NoSuchEntityException'\n\t\tif (errorName === 'NoSuchEntity' || errorName === 'NoSuchEntityException') {\n\t\t\treturn false;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Provision backup destination for a deployment.\n *\n * Creates AWS resources (S3 bucket, IAM user) and Dokploy destination if needed.\n * Reuses existing resources from state when possible.\n */\nexport async function provisionBackupDestination(\n\toptions: ProvisionBackupOptions,\n): Promise<BackupState> {\n\tconst {\n\t\tapi,\n\t\tprojectName,\n\t\tstage,\n\t\tconfig,\n\t\texistingState,\n\t\tlogger,\n\t\tawsEndpoint,\n\t} = options;\n\n\t// If we have existing state, verify the Dokploy destination still exists\n\tif (existingState?.destinationId) {\n\t\ttry {\n\t\t\tawait api.getDestination(existingState.destinationId);\n\t\t\tlogger.log(' Using existing backup destination');\n\t\t\treturn existingState;\n\t\t} catch {\n\t\t\tlogger.log(' Existing destination not found, recreating...');\n\t\t}\n\t}\n\n\t// Create AWS clients\n\tconst aws = await createAwsClients(\n\t\tconfig.region,\n\t\tconfig.profile,\n\t\tawsEndpoint,\n\t);\n\tconst sanitizedProject = sanitizeName(projectName);\n\n\t// 1. Create or verify S3 bucket\n\tconst bucketName =\n\t\texistingState?.bucketName ??\n\t\t`${sanitizedProject}-${stage}-backups-${randomSuffix()}`;\n\n\tconst bucketAlreadyExists = await bucketExists(aws.s3, bucketName);\n\tif (!bucketAlreadyExists) {\n\t\tlogger.log(` Creating S3 bucket: ${bucketName}`);\n\n\t\t// CreateBucket needs LocationConstraint for non-us-east-1 regions\n\t\tconst createBucketParams: {\n\t\t\tBucket: string;\n\t\t\tCreateBucketConfiguration?: {\n\t\t\t\tLocationConstraint: BucketLocationConstraint;\n\t\t\t};\n\t\t} = {\n\t\t\tBucket: bucketName,\n\t\t};\n\t\tif (config.region !== 'us-east-1') {\n\t\t\tcreateBucketParams.CreateBucketConfiguration = {\n\t\t\t\tLocationConstraint: config.region as BucketLocationConstraint,\n\t\t\t};\n\t\t}\n\n\t\tawait aws.s3.send(new CreateBucketCommand(createBucketParams));\n\n\t\t// Enable versioning for backup integrity\n\t\tawait aws.s3.send(\n\t\t\tnew PutBucketVersioningCommand({\n\t\t\t\tBucket: bucketName,\n\t\t\t\tVersioningConfiguration: { Status: 'Enabled' },\n\t\t\t}),\n\t\t);\n\t} else {\n\t\tlogger.log(` Using existing S3 bucket: ${bucketName}`);\n\t}\n\n\t// 2. Create or verify IAM user\n\tconst iamUserName =\n\t\texistingState?.iamUserName ?? `dokploy-backup-${sanitizedProject}-${stage}`;\n\n\tconst iamUserAlreadyExists = await userExists(aws.iam, iamUserName);\n\tif (!iamUserAlreadyExists) {\n\t\tlogger.log(` Creating IAM user: ${iamUserName}`);\n\t\tawait aws.iam.send(new CreateUserCommand({ UserName: iamUserName }));\n\t} else {\n\t\tlogger.log(` Using existing IAM user: ${iamUserName}`);\n\t}\n\n\t// 3. Attach bucket policy to IAM user\n\tconst policyDocument = {\n\t\tVersion: '2012-10-17',\n\t\tStatement: [\n\t\t\t{\n\t\t\t\tEffect: 'Allow',\n\t\t\t\tAction: [\n\t\t\t\t\t's3:GetObject',\n\t\t\t\t\t's3:PutObject',\n\t\t\t\t\t's3:DeleteObject',\n\t\t\t\t\t's3:ListBucket',\n\t\t\t\t\t's3:GetBucketLocation',\n\t\t\t\t],\n\t\t\t\tResource: [\n\t\t\t\t\t`arn:aws:s3:::${bucketName}`,\n\t\t\t\t\t`arn:aws:s3:::${bucketName}/*`,\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tlogger.log(' Updating IAM policy');\n\tawait aws.iam.send(\n\t\tnew PutUserPolicyCommand({\n\t\t\tUserName: iamUserName,\n\t\t\tPolicyName: 'DokployBackupAccess',\n\t\t\tPolicyDocument: JSON.stringify(policyDocument),\n\t\t}),\n\t);\n\n\t// 4. Create access key (or reuse existing if state has it and destination needs recreation)\n\tlet accessKeyId: string;\n\tlet secretAccessKey: string;\n\n\tif (existingState?.iamAccessKeyId && existingState?.iamSecretAccessKey) {\n\t\t// Reuse existing credentials\n\t\tlogger.log(' Using existing IAM access key');\n\t\taccessKeyId = existingState.iamAccessKeyId;\n\t\tsecretAccessKey = existingState.iamSecretAccessKey;\n\t} else {\n\t\t// Create new access key\n\t\tlogger.log(' Creating IAM access key');\n\t\tconst accessKeyResult = await aws.iam.send(\n\t\t\tnew CreateAccessKeyCommand({ UserName: iamUserName }),\n\t\t);\n\n\t\tif (!accessKeyResult.AccessKey) {\n\t\t\tthrow new Error('Failed to create IAM access key');\n\t\t}\n\n\t\taccessKeyId = accessKeyResult.AccessKey.AccessKeyId!;\n\t\tsecretAccessKey = accessKeyResult.AccessKey.SecretAccessKey!;\n\t}\n\n\t// 5. Create Dokploy destination\n\tconst destinationName = `${sanitizedProject}-${stage}-s3`;\n\tlogger.log(` Creating Dokploy destination: ${destinationName}`);\n\n\tconst { destination, created } = await api.findOrCreateDestination(\n\t\tdestinationName,\n\t\t{\n\t\t\taccessKey: accessKeyId,\n\t\t\tsecretAccessKey: secretAccessKey,\n\t\t\tbucket: bucketName,\n\t\t\tregion: config.region,\n\t\t},\n\t);\n\n\tif (created) {\n\t\tlogger.log(' ✓ Dokploy destination created');\n\t} else {\n\t\tlogger.log(' ✓ Using existing Dokploy destination');\n\t}\n\n\t// 6. Test connection\n\ttry {\n\t\tawait api.testDestinationConnection(destination.destinationId);\n\t\tlogger.log(' ✓ Destination connection verified');\n\t} catch (error) {\n\t\tlogger.log(\n\t\t\t` ⚠ Warning: Could not verify destination connection: ${error}`,\n\t\t);\n\t}\n\n\treturn {\n\t\tbucketName,\n\t\tbucketArn: `arn:aws:s3:::${bucketName}`,\n\t\tiamUserName,\n\t\tiamAccessKeyId: accessKeyId,\n\t\tiamSecretAccessKey: secretAccessKey,\n\t\tdestinationId: destination.destinationId,\n\t\tregion: config.region,\n\t\tcreatedAt: existingState?.createdAt ?? new Date().toISOString(),\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,519 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_rolldown_runtime = require("../rolldown-runtime-C0BPl7ul.cjs");
3
+ let node_fs = require("node:fs");
4
+ let node_child_process = require("node:child_process");
5
+ let node_crypto = require("node:crypto");
6
+ let node_http = require("node:http");
7
+ node_http = require_rolldown_runtime.__toESM(node_http, 1);
8
+ let node_zlib = require("node:zlib");
9
+ let node_https = require("node:https");
10
+ node_https = require_rolldown_runtime.__toESM(node_https, 1);
11
+ //#region src/backups/runner.ts
12
+ /**
13
+ * The backups container's program: `pg_dump` each of the stack's databases
14
+ * on schedule and stream it, gzipped, to the stage's backups prefix.
15
+ *
16
+ * It ships alone — copied into an image built `FROM postgres:<major>-alpine`
17
+ * with Node added — so it imports nothing but Node's own modules: S3 is
18
+ * spoken to with a SigV4 signature made here, not the AWS SDK.
19
+ *
20
+ * node backup.mjs serve run on schedule, forever (the container's command)
21
+ * node backup.mjs run one backup now (`gkm backup:now`)
22
+ * node backup.mjs health exit 1 when the last good run is too old
23
+ *
24
+ * Its key may only put objects under the prefix: it never reads, lists or
25
+ * deletes, so nothing here does either. A dump is uploaded in parts as it is
26
+ * made, so no database is ever held on disk or in memory whole.
27
+ *
28
+ * Environment:
29
+ *
30
+ * - `BACKUPS_URL` — `s3://KEY:SECRET@bucket?region=…`, the stage's backups key
31
+ * - `BACKUPS_PREFIX` — `gkm/<project>/<stage>/backups`
32
+ * - `BACKUPS_DATABASES` — `[{"file":"auth-database","name":"auth_database_production"}]`
33
+ * - `BACKUPS_SCHEDULE` — `{"kind":"every","seconds":86400,"offset":7200}`, or
34
+ * a cron expanded: `{"kind":"cron","minutes":[0],"hours":[0,6,12,18],…}`
35
+ * - `BACKUPS_MAX_GAP_SECONDS` — the longest the schedule goes between runs
36
+ * - `PGHOST`, `PGPORT`, `PGUSER`, `PGPASSWORD` — read by `pg_dump` itself
37
+ * - `OTEL_EXPORTER_OTLP_ENDPOINT`/`_HEADERS` — where each run's result is
38
+ * also sent as an OTLP log, when the stage's telemetry is on
39
+ */
40
+ /** Where the runner keeps what its health check reads. */
41
+ const STATE_DIR = process.env.BACKUPS_STATE_DIR ?? "/tmp/gkm-backups";
42
+ /** How long a container may go without a good run before it has had one. */
43
+ const STARTUP_GRACE_SECONDS = 900;
44
+ /** S3's smallest part, but the last; and the size each part is cut at. */
45
+ const PART_BYTES = Number(process.env.BACKUPS_PART_BYTES) || 16777216;
46
+ /** Four years: how far ahead a cron schedule is looked for its next run. */
47
+ const CRON_HORIZON_DAYS = 1464;
48
+ function cronDay(schedule, date) {
49
+ if (schedule.months && !schedule.months.includes(date.getUTCMonth() + 1)) return false;
50
+ const dom = schedule.days?.includes(date.getUTCDate());
51
+ const dow = schedule.weekdays?.includes(date.getUTCDay());
52
+ if (schedule.days && schedule.weekdays) return Boolean(dom || dow);
53
+ if (schedule.days) return Boolean(dom);
54
+ if (schedule.weekdays) return Boolean(dow);
55
+ return true;
56
+ }
57
+ /**
58
+ * The first time after `after`, to the minute, the schedule runs — the copy
59
+ * of `schedule.ts`'s `nextRun` this file carries, since it ships alone.
60
+ */
61
+ function nextRun(schedule, after) {
62
+ const from = Math.floor(after.getTime() / 6e4) * 6e4 + 6e4;
63
+ if (schedule.kind === "every") {
64
+ const interval = schedule.seconds * 1e3;
65
+ const offset = schedule.offset * 1e3;
66
+ return new Date(offset + Math.ceil((from - offset) / interval) * interval);
67
+ }
68
+ const start = new Date(from);
69
+ const day = Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate());
70
+ for (let i = 0; i < CRON_HORIZON_DAYS; i++) {
71
+ const date = new Date(day + i * 864e5);
72
+ if (!cronDay(schedule, date)) continue;
73
+ for (const hour of schedule.hours) for (const minute of schedule.minutes) {
74
+ const at = date.getTime() + hour * 36e5 + minute * 6e4;
75
+ if (at >= from) return new Date(at);
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+ /** One run's folder: `2026-10-10/02-00-00Z`. */
81
+ function runFolder(at) {
82
+ const iso = at.toISOString();
83
+ return `${iso.slice(0, 10)}/${iso.slice(11, 19).replace(/:/g, "-")}Z`;
84
+ }
85
+ /** `BACKUPS_URL`, read the way `@geekmidas/storage/s3-url` writes it. */
86
+ function destination(url) {
87
+ const parsed = new URL(url);
88
+ if (parsed.protocol !== "s3:" || !parsed.hostname) throw new BackupsEnvInvalid("BACKUPS_URL", "is not an s3:// URL with a bucket");
89
+ const endpoint = parsed.searchParams.get("endpoint") ?? void 0;
90
+ return {
91
+ bucket: parsed.hostname,
92
+ region: parsed.searchParams.get("region") ?? "us-east-1",
93
+ ...endpoint ? { endpoint } : {},
94
+ forcePathStyle: parsed.searchParams.get("forcePathStyle") === "true",
95
+ accessKeyId: decodeURIComponent(parsed.username),
96
+ secretAccessKey: decodeURIComponent(parsed.password)
97
+ };
98
+ }
99
+ const sha256 = (data) => (0, node_crypto.createHash)("sha256").update(data).digest("hex");
100
+ const hmac = (key, data) => (0, node_crypto.createHmac)("sha256", key).update(data).digest();
101
+ /** RFC 3986, as SigV4 wants it: everything but unreserved characters. */
102
+ function encode(value) {
103
+ return encodeURIComponent(value).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
104
+ }
105
+ /** One request to S3, signed with SigV4; the response's status and body. */
106
+ async function s3Send(to, request, now = /* @__PURE__ */ new Date()) {
107
+ const body = request.body ?? Buffer.alloc(0);
108
+ const path = request.key.split("/").map(encode).join("/");
109
+ let url;
110
+ if (to.endpoint) {
111
+ const base = to.endpoint.replace(/\/+$/, "");
112
+ url = to.forcePathStyle ? new URL(`${base}/${to.bucket}/${path}`) : new URL(`${base.replace("://", `://${to.bucket}.`)}/${path}`);
113
+ } else url = new URL(`https://${to.bucket}.s3.${to.region}.amazonaws.com/${path}`);
114
+ const query = Object.entries(request.query ?? {}).map(([k, v]) => [encode(k), encode(v)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => `${k}=${v}`).join("&");
115
+ const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, "");
116
+ const day = amzDate.slice(0, 8);
117
+ const payload = sha256(body);
118
+ const headers = {
119
+ host: url.host,
120
+ "x-amz-content-sha256": payload,
121
+ "x-amz-date": amzDate,
122
+ ...Object.fromEntries(Object.entries(request.headers ?? {}).map(([k, v]) => [k.toLowerCase(), v]))
123
+ };
124
+ const names = Object.keys(headers).sort();
125
+ const canonical = [
126
+ request.method,
127
+ url.pathname,
128
+ query,
129
+ names.map((n) => `${n}:${headers[n].trim()}\n`).join(""),
130
+ names.join(";"),
131
+ payload
132
+ ].join("\n");
133
+ const scope = `${day}/${to.region}/s3/aws4_request`;
134
+ const toSign = [
135
+ "AWS4-HMAC-SHA256",
136
+ amzDate,
137
+ scope,
138
+ sha256(canonical)
139
+ ].join("\n");
140
+ const key = hmac(hmac(hmac(hmac(`AWS4${to.secretAccessKey}`, day), to.region), "s3"), "aws4_request");
141
+ const signature = (0, node_crypto.createHmac)("sha256", key).update(toSign).digest("hex");
142
+ headers.authorization = `AWS4-HMAC-SHA256 Credential=${to.accessKeyId}/${scope}, SignedHeaders=${names.join(";")}, Signature=${signature}`;
143
+ headers["content-length"] = String(body.length);
144
+ const send = url.protocol === "https:" ? node_https.default.request : node_http.default.request;
145
+ return new Promise((resolve, reject) => {
146
+ const req = send(url, {
147
+ method: request.method,
148
+ headers,
149
+ path: `${url.pathname}${query ? `?${query}` : ""}`
150
+ }, (res) => {
151
+ const chunks = [];
152
+ res.on("data", (chunk) => chunks.push(chunk));
153
+ res.on("end", () => resolve({
154
+ status: res.statusCode ?? 0,
155
+ body: Buffer.concat(chunks).toString("utf-8"),
156
+ headers: Object.fromEntries(Object.entries(res.headers).map(([k, v]) => [k, String(v ?? "")]))
157
+ }));
158
+ res.on("error", reject);
159
+ });
160
+ req.on("error", reject);
161
+ req.setTimeout(3e5, () => req.destroy(new RequestTimedOut(request.key)));
162
+ req.end(body);
163
+ });
164
+ }
165
+ /** S3 did not answer a request within five minutes. */
166
+ var RequestTimedOut = class extends Error {
167
+ key;
168
+ constructor(key) {
169
+ super(`S3 did not answer within five minutes putting ${key}.`);
170
+ this.key = key;
171
+ this.name = "RequestTimedOut";
172
+ }
173
+ };
174
+ /** A variable the container is started with that is missing or wrong. */
175
+ var BackupsEnvInvalid = class extends Error {
176
+ variable;
177
+ reason;
178
+ constructor(variable, reason) {
179
+ super(`${variable} ${reason}. It is written by gkm into the stack's backups.env; deploy the stage again.`);
180
+ this.variable = variable;
181
+ this.reason = reason;
182
+ this.name = "BackupsEnvInvalid";
183
+ }
184
+ };
185
+ /** `pg_dump` exited with an error: the dump is not uploaded. */
186
+ var DumpFailed = class extends Error {
187
+ database;
188
+ code;
189
+ stderr;
190
+ constructor(database, code, stderr) {
191
+ super(`pg_dump ${database} exited ${code}: ${stderr.trim().slice(-500)}`);
192
+ this.database = database;
193
+ this.code = code;
194
+ this.stderr = stderr;
195
+ this.name = "DumpFailed";
196
+ }
197
+ };
198
+ /** A request S3 refused, or that never got an answer. */
199
+ var UploadFailed = class extends Error {
200
+ key;
201
+ status;
202
+ said;
203
+ constructor(key, status, said) {
204
+ super(`S3 answered HTTP ${status} putting ${key}: ${said.replace(/\s+/g, " ").slice(0, 500)}`);
205
+ this.key = key;
206
+ this.status = status;
207
+ this.said = said;
208
+ this.name = "UploadFailed";
209
+ }
210
+ };
211
+ /** `s3Send`, again after 1, 4 and 9 seconds when the network or S3 fails. */
212
+ async function sendWithRetry(to, request) {
213
+ let last;
214
+ for (let attempt = 0; attempt < 4; attempt++) {
215
+ if (attempt > 0) await new Promise((r) => setTimeout(r, attempt * attempt * 1e3));
216
+ try {
217
+ const res = await s3Send(to, request);
218
+ if (res.status >= 200 && res.status < 300) return res;
219
+ last = new UploadFailed(request.key, res.status, res.body);
220
+ if (res.status < 500) break;
221
+ } catch (error) {
222
+ last = error;
223
+ }
224
+ }
225
+ throw last;
226
+ }
227
+ /**
228
+ * Upload a stream to `key`: one PUT when it fits in a part, else a multipart
229
+ * upload — every action of which is `s3:PutObject`, all the key may do. A
230
+ * failed upload is left for the bucket's lifecycle to abort.
231
+ */
232
+ async function upload(to, key, stream, finished = Promise.resolve()) {
233
+ let buffered = [];
234
+ let size = 0;
235
+ let total = 0;
236
+ let uploadId;
237
+ const parts = [];
238
+ const flush = async (body) => {
239
+ if (!uploadId) {
240
+ const created = await sendWithRetry(to, {
241
+ method: "POST",
242
+ key,
243
+ query: { uploads: "" },
244
+ headers: { "content-type": "application/gzip" }
245
+ });
246
+ uploadId = /<UploadId>([^<]+)<\/UploadId>/.exec(created.body)?.[1];
247
+ if (!uploadId) throw new UploadFailed(key, created.status, created.body);
248
+ }
249
+ const part = await sendWithRetry(to, {
250
+ method: "PUT",
251
+ key,
252
+ query: {
253
+ partNumber: String(parts.length + 1),
254
+ uploadId
255
+ },
256
+ body
257
+ });
258
+ parts.push(part.headers.etag ?? "");
259
+ };
260
+ for await (const chunk of stream) {
261
+ buffered.push(chunk);
262
+ size += chunk.length;
263
+ total += chunk.length;
264
+ if (size >= PART_BYTES) {
265
+ const body = Buffer.concat(buffered);
266
+ buffered = [];
267
+ size = 0;
268
+ await flush(body);
269
+ }
270
+ }
271
+ await finished;
272
+ const rest = Buffer.concat(buffered);
273
+ if (!uploadId) {
274
+ await sendWithRetry(to, {
275
+ method: "PUT",
276
+ key,
277
+ body: rest,
278
+ headers: { "content-type": "application/gzip" }
279
+ });
280
+ return total;
281
+ }
282
+ if (rest.length > 0) await flush(rest);
283
+ const complete = parts.map((etag, i) => `<Part><PartNumber>${i + 1}</PartNumber><ETag>${etag}</ETag></Part>`).join("");
284
+ const done = await sendWithRetry(to, {
285
+ method: "POST",
286
+ key,
287
+ query: { uploadId },
288
+ body: Buffer.from(`<CompleteMultipartUpload>${complete}</CompleteMultipartUpload>`),
289
+ headers: { "content-type": "application/xml" }
290
+ });
291
+ if (/<Error>/.test(done.body)) throw new UploadFailed(key, 200, done.body);
292
+ return total;
293
+ }
294
+ /** Who else is told each line — a test, reading what a run said. */
295
+ const listeners = /* @__PURE__ */ new Set();
296
+ /** Be handed each line the runner logs. Returns what stops it. */
297
+ function onReport(listener) {
298
+ listeners.add(listener);
299
+ return () => listeners.delete(listener);
300
+ }
301
+ /** One line of the run's result: JSON on stdout, and OTLP when telemetry is on. */
302
+ async function report(level, message, fields) {
303
+ const at = /* @__PURE__ */ new Date();
304
+ const line = {
305
+ time: at.toISOString(),
306
+ level,
307
+ msg: message,
308
+ ...fields
309
+ };
310
+ (level === "error" ? process.stderr : process.stdout).write(`${JSON.stringify(line)}\n`);
311
+ for (const listener of listeners) listener(line);
312
+ if (process.pid !== 1 && process.platform === "linux") try {
313
+ (0, node_fs.appendFileSync)(`/proc/1/fd/${level === "error" ? 2 : 1}`, `${JSON.stringify(line)}\n`);
314
+ } catch {}
315
+ const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
316
+ if (!endpoint) return;
317
+ const headers = { "content-type": "application/json" };
318
+ for (const pair of (process.env.OTEL_EXPORTER_OTLP_HEADERS ?? "").split(",")) {
319
+ const at = pair.indexOf("=");
320
+ if (at > 0) headers[decodeURIComponent(pair.slice(0, at).trim())] = decodeURIComponent(pair.slice(at + 1).trim());
321
+ }
322
+ const value = (v) => typeof v === "number" ? { doubleValue: v } : typeof v === "boolean" ? { boolValue: v } : { stringValue: typeof v === "string" ? v : JSON.stringify(v) };
323
+ const body = JSON.stringify({ resourceLogs: [{
324
+ resource: { attributes: [{
325
+ key: "service.name",
326
+ value: { stringValue: process.env.OTEL_SERVICE_NAME ?? "backups" }
327
+ }] },
328
+ scopeLogs: [{
329
+ scope: { name: "gkm-backups" },
330
+ logRecords: [{
331
+ timeUnixNano: `${at.getTime()}000000`,
332
+ severityText: level.toUpperCase(),
333
+ severityNumber: level === "error" ? 17 : 9,
334
+ body: { stringValue: message },
335
+ attributes: Object.entries(fields).map(([key, v]) => ({
336
+ key,
337
+ value: value(v)
338
+ }))
339
+ }]
340
+ }]
341
+ }] });
342
+ try {
343
+ await fetch(`${endpoint.replace(/\/+$/, "")}/v1/logs`, {
344
+ method: "POST",
345
+ headers,
346
+ body,
347
+ signal: AbortSignal.timeout(1e4)
348
+ });
349
+ } catch {}
350
+ }
351
+ /** `pg_dump` of one database, gzipped, as a stream — and how it ended. */
352
+ function dump(database) {
353
+ const child = (0, node_child_process.spawn)("pg_dump", [
354
+ "--format=plain",
355
+ "--create",
356
+ "--clean",
357
+ "--if-exists",
358
+ "--dbname",
359
+ database
360
+ ], { stdio: [
361
+ "ignore",
362
+ "pipe",
363
+ "pipe"
364
+ ] });
365
+ let stderr = "";
366
+ child.stderr.on("data", (chunk) => {
367
+ stderr += chunk.toString();
368
+ });
369
+ const gzip = (0, node_zlib.createGzip)();
370
+ child.stdout.pipe(gzip);
371
+ return {
372
+ stream: gzip,
373
+ done: new Promise((resolve, reject) => {
374
+ child.on("error", reject);
375
+ child.on("close", (code) => code === 0 ? resolve() : reject(new DumpFailed(database, code, stderr)));
376
+ })
377
+ };
378
+ }
379
+ function readEnv(name) {
380
+ const value = process.env[name];
381
+ if (!value) throw new BackupsEnvInvalid(name, "is not set");
382
+ return value;
383
+ }
384
+ /** A lock, so `backup:now` and the schedule never dump at once. */
385
+ async function withLock(run) {
386
+ (0, node_fs.mkdirSync)(STATE_DIR, { recursive: true });
387
+ const lock = `${STATE_DIR}/lock`;
388
+ for (;;) try {
389
+ (0, node_fs.mkdirSync)(lock);
390
+ break;
391
+ } catch {
392
+ await new Promise((r) => setTimeout(r, 2e3));
393
+ }
394
+ try {
395
+ return await run();
396
+ } finally {
397
+ (0, node_fs.rmdirSync)(lock);
398
+ }
399
+ }
400
+ /** One backup of every database, into one run folder. Resolves whether it all went. */
401
+ async function backupOnce(at = /* @__PURE__ */ new Date()) {
402
+ return withLock(async () => {
403
+ const to = destination(readEnv("BACKUPS_URL"));
404
+ const prefix = readEnv("BACKUPS_PREFIX").replace(/\/+$/, "");
405
+ const databases = JSON.parse(readEnv("BACKUPS_DATABASES"));
406
+ let startedAt = at;
407
+ const last = (() => {
408
+ try {
409
+ return (0, node_fs.readFileSync)(`${STATE_DIR}/last-folder`, "utf-8");
410
+ } catch {
411
+ return;
412
+ }
413
+ })();
414
+ while (runFolder(startedAt) === last) {
415
+ await new Promise((r) => setTimeout(r, 1e3 - Date.now() % 1e3 + 5));
416
+ startedAt = /* @__PURE__ */ new Date();
417
+ }
418
+ (0, node_fs.writeFileSync)(`${STATE_DIR}/last-folder`, runFolder(startedAt));
419
+ const folder = `${prefix}/${runFolder(startedAt)}`;
420
+ const started = Date.now();
421
+ const sizes = {};
422
+ const failed = {};
423
+ for (const database of databases) {
424
+ const key = `${folder}/${database.file}.sql.gz`;
425
+ try {
426
+ const { stream, done } = dump(database.name);
427
+ done.catch(() => {});
428
+ sizes[database.file] = await upload(to, key, stream, done);
429
+ } catch (error) {
430
+ failed[database.file] = error instanceof Error ? error.message : String(error);
431
+ }
432
+ }
433
+ const ok = Object.keys(failed).length === 0;
434
+ const fields = {
435
+ folder,
436
+ databases: databases.map((d) => d.file),
437
+ bytes: sizes,
438
+ durationMs: Date.now() - started,
439
+ ...ok ? {} : { failed }
440
+ };
441
+ if (ok) {
442
+ (0, node_fs.writeFileSync)(`${STATE_DIR}/last-success`, String(Date.now()));
443
+ await report("info", "backup finished", {
444
+ ok,
445
+ ...fields
446
+ });
447
+ } else await report("error", "backup failed", {
448
+ ok,
449
+ ...fields
450
+ });
451
+ return ok;
452
+ });
453
+ }
454
+ /** Whether the last good run — or, before one, the start — is recent enough. */
455
+ function healthy(now = Date.now()) {
456
+ const gap = Number(readEnv("BACKUPS_MAX_GAP_SECONDS"));
457
+ const read = (file) => {
458
+ try {
459
+ return Number((0, node_fs.readFileSync)(`${STATE_DIR}/${file}`, "utf-8"));
460
+ } catch {
461
+ return;
462
+ }
463
+ };
464
+ const since = read("last-success") ?? read("started");
465
+ if (since === void 0) return false;
466
+ return now - since <= (2 * gap + STARTUP_GRACE_SECONDS) * 1e3;
467
+ }
468
+ /** Run on schedule, forever. */
469
+ async function serve() {
470
+ (0, node_fs.mkdirSync)(STATE_DIR, { recursive: true });
471
+ (0, node_fs.writeFileSync)(`${STATE_DIR}/started`, String(Date.now()));
472
+ const schedule = JSON.parse(readEnv("BACKUPS_SCHEDULE"));
473
+ let stopping = false;
474
+ for (const signal of ["SIGTERM", "SIGINT"]) process.once(signal, () => {
475
+ stopping = true;
476
+ process.exit(0);
477
+ });
478
+ await report("info", "backups scheduled", { next: nextRun(schedule, /* @__PURE__ */ new Date())?.toISOString() ?? null });
479
+ while (!stopping) {
480
+ const next = nextRun(schedule, /* @__PURE__ */ new Date());
481
+ if (!next) return;
482
+ while (Date.now() < next.getTime()) await new Promise((r) => setTimeout(r, Math.min(next.getTime() - Date.now(), 36e5)));
483
+ await backupOnce(next).catch((error) => report("error", "backup failed", {
484
+ ok: false,
485
+ error: error instanceof Error ? error.message : String(error)
486
+ }));
487
+ }
488
+ }
489
+ /** What `node backup.mjs <command>` runs; resolves with its exit code. */
490
+ async function main(command) {
491
+ if (command === "serve") {
492
+ await serve();
493
+ return 0;
494
+ }
495
+ if (command === "run") return await backupOnce() ? 0 : 1;
496
+ if (command === "health") return healthy() ? 0 : 1;
497
+ await report("error", "usage: backup.mjs serve | run | health", { command: command ?? null });
498
+ return 2;
499
+ }
500
+ if (process.argv[1] && /backup\.mjs$|runner\.(?:ts|mjs)$/.test(process.argv[1])) main(process.argv[2]).then((code) => process.exit(code), async (error) => {
501
+ await report("error", "backup failed", {
502
+ ok: false,
503
+ error: error instanceof Error ? error.message : String(error)
504
+ });
505
+ process.exit(1);
506
+ });
507
+ //#endregion
508
+ exports.backupOnce = backupOnce;
509
+ exports.destination = destination;
510
+ exports.healthy = healthy;
511
+ exports.main = main;
512
+ exports.nextRun = nextRun;
513
+ exports.onReport = onReport;
514
+ exports.runFolder = runFolder;
515
+ exports.s3Send = s3Send;
516
+ exports.serve = serve;
517
+ exports.upload = upload;
518
+
519
+ //# sourceMappingURL=runner.cjs.map