@geekmidas/cli 10.0.0-alpha.91 → 10.0.0-alpha.93

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 (318) hide show
  1. package/dist/{EndpointGenerator-CVc6Oi1Y.mjs → EndpointGenerator-Bor2tZCm.mjs} +14 -4
  2. package/dist/EndpointGenerator-Bor2tZCm.mjs.map +1 -0
  3. package/dist/{EndpointGenerator-CwLjBCFE.cjs → EndpointGenerator-De03t1hd.cjs} +14 -4
  4. package/dist/EndpointGenerator-De03t1hd.cjs.map +1 -0
  5. package/dist/{GoDaddyProvider-DqZ1qD_F.cjs → GoDaddyProvider-BZb-V14e.cjs} +11 -10
  6. package/dist/GoDaddyProvider-BZb-V14e.cjs.map +1 -0
  7. package/dist/{GoDaddyProvider-DSStJVAv.mjs → GoDaddyProvider-Mi3vptSR.mjs} +11 -10
  8. package/dist/GoDaddyProvider-Mi3vptSR.mjs.map +1 -0
  9. package/dist/{HostingerProvider-BI6J7oJr.mjs → HostingerProvider-1mqD6aG8.mjs} +2 -2
  10. package/dist/{HostingerProvider-BI6J7oJr.mjs.map → HostingerProvider-1mqD6aG8.mjs.map} +1 -1
  11. package/dist/{HostingerProvider-CyTpG_jy.cjs → HostingerProvider-C6t-PSNe.cjs} +2 -2
  12. package/dist/{HostingerProvider-CyTpG_jy.cjs.map → HostingerProvider-C6t-PSNe.cjs.map} +1 -1
  13. package/dist/{LegacyStateStore-DXmNA7hy.cjs → LegacyStateStore-BlYXQQSE.cjs} +44 -10
  14. package/dist/LegacyStateStore-BlYXQQSE.cjs.map +1 -0
  15. package/dist/LegacyStateStore-CtwO7fwy.mjs +123 -0
  16. package/dist/LegacyStateStore-CtwO7fwy.mjs.map +1 -0
  17. package/dist/{LocalStateStore-CU-O0SBp.mjs → LocalStateStore-D40_SDmJ.mjs} +2 -2
  18. package/dist/{LocalStateStore-CU-O0SBp.mjs.map → LocalStateStore-D40_SDmJ.mjs.map} +1 -1
  19. package/dist/{LocalStateStore-BBeTlRTH.cjs → LocalStateStore-oX_zxj9V.cjs} +2 -2
  20. package/dist/{LocalStateStore-BBeTlRTH.cjs.map → LocalStateStore-oX_zxj9V.cjs.map} +1 -1
  21. package/dist/{OpenApiTsGenerator-B--HV-sW.cjs → OpenApiTsGenerator-CS_RtWOz.cjs} +2 -2
  22. package/dist/{OpenApiTsGenerator-B--HV-sW.cjs.map → OpenApiTsGenerator-CS_RtWOz.cjs.map} +1 -1
  23. package/dist/{OpenApiTsGenerator-CkvsPdgg.mjs → OpenApiTsGenerator-DWAF-7Fu.mjs} +2 -2
  24. package/dist/{OpenApiTsGenerator-CkvsPdgg.mjs.map → OpenApiTsGenerator-DWAF-7Fu.mjs.map} +1 -1
  25. package/dist/{S3StateStore-bwxcI_wQ.mjs → S3StateStore-BzS0IeSt.mjs} +2 -2
  26. package/dist/{S3StateStore-bwxcI_wQ.mjs.map → S3StateStore-BzS0IeSt.mjs.map} +1 -1
  27. package/dist/{S3StateStore-Br8VMY22.cjs → S3StateStore-DeI7jtvi.cjs} +2 -2
  28. package/dist/{S3StateStore-Br8VMY22.cjs.map → S3StateStore-DeI7jtvi.cjs.map} +1 -1
  29. package/dist/{SSMStateStore-DoZE1Wi1.cjs → SSMStateStore-CaCtrzFL.cjs} +2 -2
  30. package/dist/{SSMStateStore-DoZE1Wi1.cjs.map → SSMStateStore-CaCtrzFL.cjs.map} +1 -1
  31. package/dist/{SSMStateStore-CsOS0W1y.mjs → SSMStateStore-k_Ew7TWx.mjs} +2 -2
  32. package/dist/{SSMStateStore-CsOS0W1y.mjs.map → SSMStateStore-k_Ew7TWx.mjs.map} +1 -1
  33. package/dist/{SubscriberGenerator-BPqQf8fB.mjs → SubscriberGenerator-CyN2VF5X.mjs} +6 -5
  34. package/dist/SubscriberGenerator-CyN2VF5X.mjs.map +1 -0
  35. package/dist/{SubscriberGenerator-BVn7cQ-2.cjs → SubscriberGenerator-Dvz7EzqK.cjs} +6 -5
  36. package/dist/SubscriberGenerator-Dvz7EzqK.cjs.map +1 -0
  37. package/dist/{add-BSHk5Ngn.mjs → add-CP1podDH.mjs} +7 -7
  38. package/dist/add-CP1podDH.mjs.map +1 -0
  39. package/dist/{add-DmmBDV2e.cjs → add-VcyJnsPX.cjs} +8 -8
  40. package/dist/add-VcyJnsPX.cjs.map +1 -0
  41. package/dist/{aws-BTawF0F-.cjs → aws-BTReGjpY.cjs} +24 -6
  42. package/dist/aws-BTReGjpY.cjs.map +1 -0
  43. package/dist/{aws-B-6uEhgP.mjs → aws-Dz2bYxK1.mjs} +24 -6
  44. package/dist/aws-Dz2bYxK1.mjs.map +1 -0
  45. package/dist/awsStore-B5We7bMg.cjs +136 -0
  46. package/dist/awsStore-B5We7bMg.cjs.map +1 -0
  47. package/dist/awsStore-BWa1KNY-.mjs +119 -0
  48. package/dist/awsStore-BWa1KNY-.mjs.map +1 -0
  49. package/dist/{bundler-D6eBfVkl.mjs → bundler-BWrh-AJH.mjs} +5 -5
  50. package/dist/{bundler-D6eBfVkl.mjs.map → bundler-BWrh-AJH.mjs.map} +1 -1
  51. package/dist/{bundler-BQJiB7Ub.cjs → bundler-Dfsr6KXU.cjs} +5 -5
  52. package/dist/{bundler-BQJiB7Ub.cjs.map → bundler-Dfsr6KXU.cjs.map} +1 -1
  53. package/dist/{cli-DD-Yk-I5.mjs → cli-B8otnZfX.mjs} +6 -6
  54. package/dist/{cli-DD-Yk-I5.mjs.map → cli-B8otnZfX.mjs.map} +1 -1
  55. package/dist/{cli-BE9mqeX8.cjs → cli-DL19w4OE.cjs} +5 -5
  56. package/dist/{cli-BE9mqeX8.cjs.map → cli-DL19w4OE.cjs.map} +1 -1
  57. package/dist/compose-BHVKLluX.cjs +1523 -0
  58. package/dist/compose-BHVKLluX.cjs.map +1 -0
  59. package/dist/compose-DrEB_4F-.mjs +1476 -0
  60. package/dist/compose-DrEB_4F-.mjs.map +1 -0
  61. package/dist/{config-pST7E0CS.d.cts → config-CHX5GOo3.d.mts} +8 -8
  62. package/dist/{config-CdEcTrjG.d.mts.map → config-CHX5GOo3.d.mts.map} +1 -1
  63. package/dist/{config-CdEcTrjG.d.mts → config-DCCcrOSo.d.cts} +8 -8
  64. package/dist/{config-pST7E0CS.d.cts.map → config-DCCcrOSo.d.cts.map} +1 -1
  65. package/dist/config.cjs +8 -7
  66. package/dist/config.cjs.map +1 -1
  67. package/dist/config.d.cts +3 -3
  68. package/dist/config.d.mts +3 -3
  69. package/dist/config.mjs +8 -7
  70. package/dist/config.mjs.map +1 -1
  71. package/dist/{credentialSchemas-BJqRJNK4.mjs → credentialSchemas-BJFvfkaz.mjs} +5 -4
  72. package/dist/credentialSchemas-BJFvfkaz.mjs.map +1 -0
  73. package/dist/{credentialSchemas-DCR4Wd1W.cjs → credentialSchemas-CAPKFkrG.cjs} +5 -4
  74. package/dist/credentialSchemas-CAPKFkrG.cjs.map +1 -0
  75. package/dist/{credentials-CnVqoXMb.mjs → credentials-C4KII3PD.mjs} +3 -2
  76. package/dist/{credentials-CnVqoXMb.mjs.map → credentials-C4KII3PD.mjs.map} +1 -1
  77. package/dist/{credentials-BKfIugu2.cjs → credentials-QBu7VgaQ.cjs} +3 -2
  78. package/dist/credentials-QBu7VgaQ.cjs.map +1 -0
  79. package/dist/{databases-CzszQV0N.mjs → databases-BeGP5eDh.mjs} +11 -10
  80. package/dist/databases-BeGP5eDh.mjs.map +1 -0
  81. package/dist/{databases-BY-pEImp.cjs → databases-DGALFDG3.cjs} +11 -10
  82. package/dist/databases-DGALFDG3.cjs.map +1 -0
  83. package/dist/{define-DR8xGYfL.mjs → define-6poNqm5O.mjs} +12 -3
  84. package/dist/define-6poNqm5O.mjs.map +1 -0
  85. package/dist/{define-DzRz8FgH.cjs → define-crmMcXFS.cjs} +12 -3
  86. package/dist/define-crmMcXFS.cjs.map +1 -0
  87. package/dist/deploy/public.cjs +18 -16
  88. package/dist/deploy/public.cjs.map +1 -1
  89. package/dist/deploy/public.d.cts +31 -31
  90. package/dist/deploy/public.d.cts.map +1 -1
  91. package/dist/deploy/public.d.mts +31 -31
  92. package/dist/deploy/public.d.mts.map +1 -1
  93. package/dist/deploy/public.mjs +18 -17
  94. package/dist/deploy/public.mjs.map +1 -1
  95. package/dist/{deploy-CuHasEA4.cjs → deploy-C3Mhnmus.cjs} +15 -13
  96. package/dist/deploy-C3Mhnmus.cjs.map +1 -0
  97. package/dist/{deploy-QNtx_eWR.mjs → deploy-DYIyIUYd.mjs} +15 -13
  98. package/dist/deploy-DYIyIUYd.mjs.map +1 -0
  99. package/dist/{discover-D1It5r_h.cjs → discover-DPgu-ScS.cjs} +4 -3
  100. package/dist/discover-DPgu-ScS.cjs.map +1 -0
  101. package/dist/{discover-CU0paUyH.d.cts → discover-DqwlBVyY.d.mts} +2 -2
  102. package/dist/{discover-CU0paUyH.d.cts.map → discover-DqwlBVyY.d.mts.map} +1 -1
  103. package/dist/{discover-BPelzeGW.mjs → discover-qjFapetL.mjs} +4 -3
  104. package/dist/discover-qjFapetL.mjs.map +1 -0
  105. package/dist/{discover-DFiJxwfv.d.mts → discover-vk2r5giK.d.cts} +2 -2
  106. package/dist/{discover-DFiJxwfv.d.mts.map → discover-vk2r5giK.d.cts.map} +1 -1
  107. package/dist/{dokploy-CYcMLh9-.mjs → dokploy-o4I6vb9W.mjs} +3 -3
  108. package/dist/{dokploy-CYcMLh9-.mjs.map → dokploy-o4I6vb9W.mjs.map} +1 -1
  109. package/dist/{dokploy-DIowwyIB.cjs → dokploy-rivb1RFt.cjs} +3 -3
  110. package/dist/{dokploy-DIowwyIB.cjs.map → dokploy-rivb1RFt.cjs.map} +1 -1
  111. package/dist/{drivers-DTZzxeIl.mjs → drivers-CTaWrA_L.mjs} +2 -2
  112. package/dist/{drivers-DTZzxeIl.mjs.map → drivers-CTaWrA_L.mjs.map} +1 -1
  113. package/dist/{drivers-LYSdQDmd.cjs → drivers-DDojgzz0.cjs} +2 -2
  114. package/dist/{drivers-LYSdQDmd.cjs.map → drivers-DDojgzz0.cjs.map} +1 -1
  115. package/dist/{encryption-BrEef7Jk.mjs → encryption-B6ilrT7p.mjs} +7 -6
  116. package/dist/encryption-B6ilrT7p.mjs.map +1 -0
  117. package/dist/{encryption-CjYdUb2s.cjs → encryption-D7zmwzWz.cjs} +7 -6
  118. package/dist/encryption-D7zmwzWz.cjs.map +1 -0
  119. package/dist/{engine-BhJ7ZP9K.cjs → engine-Cfx8fEZU.cjs} +40 -28
  120. package/dist/engine-Cfx8fEZU.cjs.map +1 -0
  121. package/dist/{engine-2h4k5ICq.mjs → engine-DjEcovm-.mjs} +40 -28
  122. package/dist/engine-DjEcovm-.mjs.map +1 -0
  123. package/dist/errors-D8Gwp5kU.mjs +23 -0
  124. package/dist/errors-D8Gwp5kU.mjs.map +1 -0
  125. package/dist/errors-DMC4Umsb.cjs +34 -0
  126. package/dist/errors-DMC4Umsb.cjs.map +1 -0
  127. package/dist/{github-BCDF6xVH.mjs → github-CzBbs43W.mjs} +31 -9
  128. package/dist/github-CzBbs43W.mjs.map +1 -0
  129. package/dist/{github-B5Bw4HIu.cjs → github-zneTMvnO.cjs} +31 -9
  130. package/dist/github-zneTMvnO.cjs.map +1 -0
  131. package/dist/{index-YFNxR5Ns.d.mts → index-BiYU7cUl.d.mts} +6 -6
  132. package/dist/{index-D-F_hTDz.d.cts.map → index-BiYU7cUl.d.mts.map} +1 -1
  133. package/dist/{index-D-F_hTDz.d.cts → index-Dm6V9bwh.d.cts} +6 -6
  134. package/dist/{index-YFNxR5Ns.d.mts.map → index-Dm6V9bwh.d.cts.map} +1 -1
  135. package/dist/index.cjs +256 -346
  136. package/dist/index.cjs.map +1 -1
  137. package/dist/index.mjs +252 -341
  138. package/dist/index.mjs.map +1 -1
  139. package/dist/{local-BjxDfPvy.cjs → local-B61kUh0w.cjs} +3 -3
  140. package/dist/{local-BjxDfPvy.cjs.map → local-B61kUh0w.cjs.map} +1 -1
  141. package/dist/{local-IuoIF3CT.mjs → local-Otp74ak0.mjs} +3 -3
  142. package/dist/{local-IuoIF3CT.mjs.map → local-Otp74ak0.mjs.map} +1 -1
  143. package/dist/{migrate-DWZz9kah.mjs → migrate-BaC4w0sb.mjs} +8 -7
  144. package/dist/migrate-BaC4w0sb.mjs.map +1 -0
  145. package/dist/{migrate-q2YYLJLE.cjs → migrate-C8wTpakT.cjs} +8 -7
  146. package/dist/migrate-C8wTpakT.cjs.map +1 -0
  147. package/dist/{migrate-DbtcuOr_.mjs → migrate-CsBZKALY.mjs} +9 -8
  148. package/dist/migrate-CsBZKALY.mjs.map +1 -0
  149. package/dist/{migrate-CGaancHY.cjs → migrate-DFjbGnSr.cjs} +8 -7
  150. package/dist/migrate-DFjbGnSr.cjs.map +1 -0
  151. package/dist/openapi.cjs +3 -3
  152. package/dist/openapi.d.cts +1 -10
  153. package/dist/openapi.d.cts.map +1 -1
  154. package/dist/openapi.d.mts +1 -10
  155. package/dist/openapi.d.mts.map +1 -1
  156. package/dist/openapi.mjs +3 -3
  157. package/dist/{provider-C9_-45d5.cjs → provider-BqpjG9QM.cjs} +4 -3
  158. package/dist/provider-BqpjG9QM.cjs.map +1 -0
  159. package/dist/{provider-q4lsYzYG.mjs → provider-CEOKk8NS.mjs} +4 -3
  160. package/dist/provider-CEOKk8NS.mjs.map +1 -0
  161. package/dist/{ready-BpNbORRB.cjs → ready-D3PIjx3S.cjs} +9 -8
  162. package/dist/ready-D3PIjx3S.cjs.map +1 -0
  163. package/dist/{ready-b6vm0-W-.mjs → ready-naOSJpeJ.mjs} +9 -8
  164. package/dist/ready-naOSJpeJ.mjs.map +1 -0
  165. package/dist/reconcile/public.cjs +1 -1
  166. package/dist/reconcile/public.d.cts +2 -2
  167. package/dist/reconcile/public.d.mts +2 -2
  168. package/dist/reconcile/public.mjs +1 -1
  169. package/dist/{reconcile-Dh1Jk7WE.mjs → reconcile--I7V4Klj.mjs} +2 -2
  170. package/dist/{reconcile-Dh1Jk7WE.mjs.map → reconcile--I7V4Klj.mjs.map} +1 -1
  171. package/dist/{resolve-DNg0icnh.mjs → resolve-Ccjlpnd9.mjs} +12 -11
  172. package/dist/resolve-Ccjlpnd9.mjs.map +1 -0
  173. package/dist/{resolve-Cns0v6dN.cjs → resolve-g8htuR80.cjs} +12 -11
  174. package/dist/resolve-g8htuR80.cjs.map +1 -0
  175. package/dist/{rollback-UIjS25F1.cjs → rollback--ympG9ss.cjs} +13 -11
  176. package/dist/rollback--ympG9ss.cjs.map +1 -0
  177. package/dist/{rollback-CFrNLmxs.mjs → rollback-Drbg0OeR.mjs} +13 -11
  178. package/dist/rollback-Drbg0OeR.mjs.map +1 -0
  179. package/dist/{runtime-CN_kmqxo.d.cts → runtime-D_J3ExJn.d.cts} +11 -19
  180. package/dist/runtime-D_J3ExJn.d.cts.map +1 -0
  181. package/dist/{runtime-Cjvon3oj.d.mts → runtime-_wEVtshH.d.mts} +11 -19
  182. package/dist/runtime-_wEVtshH.d.mts.map +1 -0
  183. package/dist/sandbox/credentials-worker.cjs +3 -3
  184. package/dist/sandbox/credentials-worker.mjs +3 -3
  185. package/dist/sandbox/discover-worker.cjs +1 -1
  186. package/dist/sandbox/discover-worker.mjs +1 -1
  187. package/dist/sandbox/migrate-worker.cjs +3 -3
  188. package/dist/sandbox/migrate-worker.mjs +3 -3
  189. package/dist/{sandbox-CL--ZDui.cjs → sandbox-CHv3OYXg.cjs} +4 -3
  190. package/dist/sandbox-CHv3OYXg.cjs.map +1 -0
  191. package/dist/{sandbox-M8UnLhXE.d.cts → sandbox-CPJq1Kia.d.mts} +4 -26
  192. package/dist/sandbox-CPJq1Kia.d.mts.map +1 -0
  193. package/dist/{sandbox-Dm247NGx.mjs → sandbox-CbVB7uOD.mjs} +4 -3
  194. package/dist/sandbox-CbVB7uOD.mjs.map +1 -0
  195. package/dist/{sandbox-M8UnLhXE.d.mts → sandbox-JwuPAl7I.d.cts} +4 -26
  196. package/dist/sandbox-JwuPAl7I.d.cts.map +1 -0
  197. package/dist/secrets-DJteijZo.cjs +47 -0
  198. package/dist/secrets-DJteijZo.cjs.map +1 -0
  199. package/dist/secrets-DbPmAS4k.mjs +36 -0
  200. package/dist/secrets-DbPmAS4k.mjs.map +1 -0
  201. package/dist/{secretsManager-Chs9VV2r.mjs → secretsManager-C6wm-9uZ.mjs} +24 -3
  202. package/dist/secretsManager-C6wm-9uZ.mjs.map +1 -0
  203. package/dist/{secretsManager-DcMlHnRC.cjs → secretsManager-Cwwgs81g.cjs} +24 -3
  204. package/dist/secretsManager-Cwwgs81g.cjs.map +1 -0
  205. package/dist/{seeds-odfgSCmu.mjs → seeds-BSL55F6q.mjs} +946 -107
  206. package/dist/seeds-BSL55F6q.mjs.map +1 -0
  207. package/dist/{seeds-CkIPFGNO.cjs → seeds-c-ByX9je.cjs} +1065 -130
  208. package/dist/seeds-c-ByX9je.cjs.map +1 -0
  209. package/dist/{sniffer-BTtX3NUM.mjs → sniffer-BTtGAtm3.mjs} +14 -8
  210. package/dist/sniffer-BTtGAtm3.mjs.map +1 -0
  211. package/dist/{sniffer-IAQEpsQb.cjs → sniffer-Dq5BS98f.cjs} +14 -8
  212. package/dist/{sniffer-IAQEpsQb.cjs.map → sniffer-Dq5BS98f.cjs.map} +1 -1
  213. package/dist/{sst-CJzvyrEz.mjs → sst-BaRXp2Dd.mjs} +18 -8
  214. package/dist/sst-BaRXp2Dd.mjs.map +1 -0
  215. package/dist/{sst-BgcOsaBi.cjs → sst-CnKY-CSh.cjs} +18 -8
  216. package/dist/sst-CnKY-CSh.cjs.map +1 -0
  217. package/dist/stack-1PeLJS2j.cjs +1346 -0
  218. package/dist/stack-1PeLJS2j.cjs.map +1 -0
  219. package/dist/stack-Co4uZkAo.mjs +1239 -0
  220. package/dist/stack-Co4uZkAo.mjs.map +1 -0
  221. package/dist/{stages-CUn6gvXL.cjs → stages-BI8JvPzI.cjs} +6 -5
  222. package/dist/stages-BI8JvPzI.cjs.map +1 -0
  223. package/dist/{stages-CnZRYmkI.mjs → stages-DY-fQKmo.mjs} +6 -5
  224. package/dist/stages-DY-fQKmo.mjs.map +1 -0
  225. package/dist/target/public.cjs +3 -3
  226. package/dist/target/public.d.cts +2 -2
  227. package/dist/target/public.d.mts +2 -2
  228. package/dist/target/public.mjs +3 -3
  229. package/dist/{terminal-DuapRxh6.cjs → terminal-8XngdSTo.cjs} +6 -5
  230. package/dist/terminal-8XngdSTo.cjs.map +1 -0
  231. package/dist/{terminal-D8TPK7o9.mjs → terminal-C4XRdwnU.mjs} +7 -6
  232. package/dist/terminal-C4XRdwnU.mjs.map +1 -0
  233. package/dist/{types-NqX1Hz4P.d.cts → types-B6lmD3en.d.mts} +94 -47
  234. package/dist/types-B6lmD3en.d.mts.map +1 -0
  235. package/dist/{types-ZHuZ89hv.d.mts → types-BibpiHKB.d.cts} +95 -46
  236. package/dist/types-BibpiHKB.d.cts.map +1 -0
  237. package/dist/vitest.cjs +1 -1
  238. package/dist/vitest.mjs +1 -1
  239. package/dist/workspace/index.cjs +1 -1
  240. package/dist/workspace/index.d.cts +2 -2
  241. package/dist/workspace/index.d.mts +2 -2
  242. package/dist/workspace/index.mjs +1 -1
  243. package/dist/{workspace-CJ0lKFq-.mjs → workspace-Bzw7Zs82.mjs} +34 -33
  244. package/dist/workspace-Bzw7Zs82.mjs.map +1 -0
  245. package/dist/{workspace-CwW3Gkru.cjs → workspace-CHOB2Xg3.cjs} +34 -33
  246. package/dist/workspace-CHOB2Xg3.cjs.map +1 -0
  247. package/package.json +15 -15
  248. package/dist/EndpointGenerator-CVc6Oi1Y.mjs.map +0 -1
  249. package/dist/EndpointGenerator-CwLjBCFE.cjs.map +0 -1
  250. package/dist/GoDaddyProvider-DSStJVAv.mjs.map +0 -1
  251. package/dist/GoDaddyProvider-DqZ1qD_F.cjs.map +0 -1
  252. package/dist/LegacyStateStore-DXmNA7hy.cjs.map +0 -1
  253. package/dist/LegacyStateStore-ZkdmiUFZ.mjs +0 -89
  254. package/dist/LegacyStateStore-ZkdmiUFZ.mjs.map +0 -1
  255. package/dist/SubscriberGenerator-BPqQf8fB.mjs.map +0 -1
  256. package/dist/SubscriberGenerator-BVn7cQ-2.cjs.map +0 -1
  257. package/dist/add-BSHk5Ngn.mjs.map +0 -1
  258. package/dist/add-DmmBDV2e.cjs.map +0 -1
  259. package/dist/aws-B-6uEhgP.mjs.map +0 -1
  260. package/dist/aws-BTawF0F-.cjs.map +0 -1
  261. package/dist/awsStore-7VmS_cZR.cjs +0 -54
  262. package/dist/awsStore-7VmS_cZR.cjs.map +0 -1
  263. package/dist/awsStore-B529csle.mjs +0 -43
  264. package/dist/awsStore-B529csle.mjs.map +0 -1
  265. package/dist/compose-Bhmf0n4o.mjs +0 -3140
  266. package/dist/compose-Bhmf0n4o.mjs.map +0 -1
  267. package/dist/compose-CvpU6ooi.cjs +0 -3265
  268. package/dist/compose-CvpU6ooi.cjs.map +0 -1
  269. package/dist/credentialSchemas-BJqRJNK4.mjs.map +0 -1
  270. package/dist/credentialSchemas-DCR4Wd1W.cjs.map +0 -1
  271. package/dist/credentials-BKfIugu2.cjs.map +0 -1
  272. package/dist/databases-BY-pEImp.cjs.map +0 -1
  273. package/dist/databases-CzszQV0N.mjs.map +0 -1
  274. package/dist/define-DR8xGYfL.mjs.map +0 -1
  275. package/dist/define-DzRz8FgH.cjs.map +0 -1
  276. package/dist/deploy-CuHasEA4.cjs.map +0 -1
  277. package/dist/deploy-QNtx_eWR.mjs.map +0 -1
  278. package/dist/discover-BPelzeGW.mjs.map +0 -1
  279. package/dist/discover-D1It5r_h.cjs.map +0 -1
  280. package/dist/encryption-BrEef7Jk.mjs.map +0 -1
  281. package/dist/encryption-CjYdUb2s.cjs.map +0 -1
  282. package/dist/engine-2h4k5ICq.mjs.map +0 -1
  283. package/dist/engine-BhJ7ZP9K.cjs.map +0 -1
  284. package/dist/github-B5Bw4HIu.cjs.map +0 -1
  285. package/dist/github-BCDF6xVH.mjs.map +0 -1
  286. package/dist/migrate-CGaancHY.cjs.map +0 -1
  287. package/dist/migrate-DWZz9kah.mjs.map +0 -1
  288. package/dist/migrate-DbtcuOr_.mjs.map +0 -1
  289. package/dist/migrate-q2YYLJLE.cjs.map +0 -1
  290. package/dist/provider-C9_-45d5.cjs.map +0 -1
  291. package/dist/provider-q4lsYzYG.mjs.map +0 -1
  292. package/dist/ready-BpNbORRB.cjs.map +0 -1
  293. package/dist/ready-b6vm0-W-.mjs.map +0 -1
  294. package/dist/resolve-Cns0v6dN.cjs.map +0 -1
  295. package/dist/resolve-DNg0icnh.mjs.map +0 -1
  296. package/dist/rollback-CFrNLmxs.mjs.map +0 -1
  297. package/dist/rollback-UIjS25F1.cjs.map +0 -1
  298. package/dist/runtime-CN_kmqxo.d.cts.map +0 -1
  299. package/dist/runtime-Cjvon3oj.d.mts.map +0 -1
  300. package/dist/sandbox-CL--ZDui.cjs.map +0 -1
  301. package/dist/sandbox-Dm247NGx.mjs.map +0 -1
  302. package/dist/sandbox-M8UnLhXE.d.cts.map +0 -1
  303. package/dist/sandbox-M8UnLhXE.d.mts.map +0 -1
  304. package/dist/secretsManager-Chs9VV2r.mjs.map +0 -1
  305. package/dist/secretsManager-DcMlHnRC.cjs.map +0 -1
  306. package/dist/seeds-CkIPFGNO.cjs.map +0 -1
  307. package/dist/seeds-odfgSCmu.mjs.map +0 -1
  308. package/dist/sniffer-BTtX3NUM.mjs.map +0 -1
  309. package/dist/sst-BgcOsaBi.cjs.map +0 -1
  310. package/dist/sst-CJzvyrEz.mjs.map +0 -1
  311. package/dist/stages-CUn6gvXL.cjs.map +0 -1
  312. package/dist/stages-CnZRYmkI.mjs.map +0 -1
  313. package/dist/terminal-D8TPK7o9.mjs.map +0 -1
  314. package/dist/terminal-DuapRxh6.cjs.map +0 -1
  315. package/dist/types-NqX1Hz4P.d.cts.map +0 -1
  316. package/dist/types-ZHuZ89hv.d.mts.map +0 -1
  317. package/dist/workspace-CJ0lKFq-.mjs.map +0 -1
  318. package/dist/workspace-CwW3Gkru.cjs.map +0 -1
@@ -1,12 +1,12 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
+ const require_errors = require("./errors-DMC4Umsb.cjs");
2
3
  const require_schemas = require("./schemas-BObwxB_t.cjs");
3
- const require_discover = require("./discover-D1It5r_h.cjs");
4
+ const require_discover = require("./discover-DPgu-ScS.cjs");
4
5
  const require_derive = require("./derive-DAbo49sm.cjs");
5
- const require_workspace = require("./workspace-CwW3Gkru.cjs");
6
+ const require_workspace = require("./workspace-CHOB2Xg3.cjs");
6
7
  const require_config = require("./config.cjs");
7
- const require_seeds = require("./seeds-CkIPFGNO.cjs");
8
- const require_credentialSchemas = require("./credentialSchemas-DCR4Wd1W.cjs");
9
- const require_index = require("./index.cjs");
8
+ const require_seeds = require("./seeds-c-ByX9je.cjs");
9
+ const require_credentialSchemas = require("./credentialSchemas-CAPKFkrG.cjs");
10
10
  let _geekmidas_manifest = require("@geekmidas/manifest");
11
11
  let node_net = require("node:net");
12
12
  let prompts = require("prompts");
@@ -124,7 +124,7 @@ function workspaceStageKeys(input) {
124
124
  * with `gkm secrets:set`.
125
125
  */
126
126
  /** `gkm secrets:add` with nobody at a terminal to answer it. */
127
- var SecretsAddNeedsTerminal = class extends Error {
127
+ var SecretsAddNeedsTerminal = class extends require_errors.GkmError {
128
128
  stage;
129
129
  constructor(stage) {
130
130
  super(`gkm secrets:add asks for each key, and there is no terminal to ask at. List what the stage needs with gkm secrets:add --stage ${stage} --missing --json, and set each with gkm secrets:set <KEY> <value> --stage ${stage}.`);
@@ -174,7 +174,7 @@ async function secretsAddCommand(options, io = defaultIo()) {
174
174
  supplied: stored?.custom ?? {},
175
175
  ...domain ? { domain } : {},
176
176
  providers: require_seeds.stageProviderNotes(workspace, stage),
177
- ...!local && domain && require_index.deploysWithCompose(workspace) ? { server: true } : {}
177
+ ...!local && domain && require_seeds.deploysWithCompose(workspace) ? { server: true } : {}
178
178
  });
179
179
  const scope = [...all.filter((k) => !k.set), ...all.filter((k) => k.set)];
180
180
  const keys = options.missing ? scope.filter((k) => !k.set) : scope;
@@ -746,4 +746,4 @@ async function askFields(ask, io, shape) {
746
746
  //#endregion
747
747
  exports.secretsAddCommand = secretsAddCommand;
748
748
 
749
- //# sourceMappingURL=add-DmmBDV2e.cjs.map
749
+ //# sourceMappingURL=add-VcyJnsPX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-VcyJnsPX.cjs","names":["provideKey","appKey","appEnvKeys","requiredStageKeys","GkmError","loadWorkspaceSettings","constructGlobs","discover","secretsStoreFor","stageProviderNotes","deploysWithCompose","stageProvider","provisionCommand","initStageSecrets","loadCredentialSchemas","isIPv4","SERVER_IPV4_KEY","isIPv6","SERVER_IPV6_KEY","s3Parse","s3Build","issueLine"],"sources":["../src/secrets/stageKeys.ts","../src/secrets/add.ts"],"sourcesContent":["/**\n * The keys a workspace's stage must be given — across every app, each once,\n * with who reads it and whether the stage holds it.\n *\n * The keys themselves are `requiredStageKeys`'s, the list a deploy refuses a\n * stage by. What this adds is the workspace: which constructs its apps read\n * (`appEnvKeys`, the keys each app's environment is built from) and which of\n * the keys the stage has set.\n */\n\nimport { type ConstructManifest, provideKey } from '@geekmidas/manifest';\nimport {\n\ttype CredentialDeclaration,\n\trequiredStageKeys,\n\ttype ServiceDeclaration,\n\ttype StageKey,\n\ttype StageProviderNotes,\n} from '../deploy/devServices';\nimport { appEnvKeys } from '../reconcile/apps';\nimport { appKey } from '../workspace/derive';\n\n/** A stage key, and whether the stage's secrets hold it. */\nexport interface WorkspaceStageKey extends StageKey {\n\tset: boolean;\n}\n\nexport interface WorkspaceStageKeysInput {\n\tmanifest: ConstructManifest;\n\t/** Each owner's runnables' edges, from discovery. */\n\trunnables?: Readonly<Record<string, readonly string[]>>;\n\t/** Whether the stage is the workspace's local one. */\n\tlocal: boolean;\n\t/** What the stage's secrets hold, by key. */\n\tsupplied: Readonly<Record<string, string>>;\n\t/** The stage's base domain, for the examples. */\n\tdomain?: string;\n\t/** What the stage's providers say — a missing key's hint. */\n\tproviders?: StageProviderNotes;\n\t/** The stage serves a domain from its own server: `GKM_SERVER_IPV4`. */\n\tserver?: boolean;\n}\n\n/** The keys of each kind of construct an app reads, that the stage supplies. */\nfunction keysOf(id: string, kind: string): string[] {\n\tswitch (kind) {\n\t\tcase 'email':\n\t\t\treturn [provideKey(id, 'url'), provideKey(id, 'from')];\n\t\tcase 'objects':\n\t\tcase 'file-server':\n\t\t\treturn [provideKey(id, 'url')];\n\t\tcase 'external-api':\n\t\tcase 'credential':\n\t\t\treturn [provideKey(id, 'credentials')];\n\t\tdefault:\n\t\t\treturn [];\n\t}\n}\n\n/**\n * Every key the stage must be given for the constructs its apps read — a\n * file server's whenever its bucket is read, since its client reads both —\n * and every file server's bucket, which serves it whether or not an app\n * reads it directly.\n */\nexport function workspaceStageKeys(\n\tinput: WorkspaceStageKeysInput,\n): WorkspaceStageKey[] {\n\tconst { manifest } = input;\n\n\t// What each app's environment holds.\n\tconst reads = new Map<string, Set<string>>();\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tconst { kind } = declaration;\n\t\tif (kind !== 'rest-api' && kind !== 'site' && kind !== 'mobile-app') {\n\t\t\tcontinue;\n\t\t}\n\t\tconst name = appKey(id);\n\t\tconst keys = appEnvKeys(manifest, name, input.runnables);\n\t\tif (keys) reads.set(name, keys);\n\t}\n\n\tconst readers = (id: string, kind: string) => {\n\t\tconst keys = keysOf(id, kind);\n\t\treturn [...reads]\n\t\t\t.filter(([, env]) => keys.some((key) => env.has(key)))\n\t\t\t.map(([app]) => app)\n\t\t\t.sort();\n\t};\n\n\tconst services: ServiceDeclaration[] = [];\n\tconst credentials: CredentialDeclaration[] = [];\n\tconst buckets = new Set<string>();\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tconst { kind } = declaration;\n\t\t// A file server's client reads its bucket's URL and its own, and an\n\t\t// app's edge is to the bucket: whoever reads the bucket reads both.\n\t\tconst apps =\n\t\t\tdeclaration.kind === 'file-server' && declaration.of\n\t\t\t\t? [\n\t\t\t\t\t\t...new Set([\n\t\t\t\t\t\t\t...readers(id, kind),\n\t\t\t\t\t\t\t...readers(declaration.of, 'objects'),\n\t\t\t\t\t\t]),\n\t\t\t\t\t].sort()\n\t\t\t\t: readers(id, kind);\n\t\tif (kind === 'external-api' || kind === 'credential') {\n\t\t\tif (apps.length > 0) credentials.push({ id, kind, apps });\n\t\t\tcontinue;\n\t\t}\n\t\tif (kind !== 'email' && kind !== 'objects' && kind !== 'file-server') {\n\t\t\tcontinue;\n\t\t}\n\t\tif (apps.length === 0) continue;\n\t\tconst of = declaration.kind === 'file-server' ? declaration.of : undefined;\n\t\tservices.push({ id, kind, ...(of ? { of } : {}), apps });\n\t\tif (of) buckets.add(of);\n\t}\n\tfor (const of of buckets) {\n\t\tif (services.some((s) => s.id === of)) continue;\n\t\tif (manifest[of]?.kind !== 'objects') continue;\n\t\tservices.push({ id: of, kind: 'objects', apps: readers(of, 'objects') });\n\t}\n\n\treturn requiredStageKeys({\n\t\tlocal: input.local,\n\t\tservices,\n\t\tcredentials,\n\t\t...(input.domain ? { domain: input.domain } : {}),\n\t\t...(input.providers ? { providers: input.providers } : {}),\n\t\t...(input.server ? { server: true } : {}),\n\t}).map((key) => ({ ...key, set: input.supplied[key.key] !== undefined }));\n}\n","/**\n * `gkm secrets:add --stage <stage>` — the secrets a stage must be given,\n * built key by key.\n *\n * It offers exactly the keys a deploy would refuse the stage without\n * (`requiredStageKeys`), across every app in the workspace, each once: the\n * stage's buckets, mail and file servers where it is deployed, and every\n * third party's credentials. A key is built by what it is — a bucket from its\n * provider, mail from its SMTP server, credentials field by field from their\n * construct's schema — checked, and saved through the stage's own store, the\n * one `gkm secrets:set` writes. No value is ever printed.\n *\n * The keys are walked one at a time — unset ones first — and each is a\n * checkpoint: set it now, skip it, or stop here. A key is saved the moment it\n * is built, so stopping, Ctrl-C or a failure keeps every key before it, and\n * running the command again picks up what is still missing. A key a provider\n * on the stage creates (a bucket under `deploy.objects.<stage>`, written by\n * `gkm setup`) is not a checkpoint: it is listed, with what creates it.\n *\n * `--json` asks nothing: it prints the keys, for a script or an agent to set\n * with `gkm secrets:set`.\n */\n\nimport { isIPv4, isIPv6 } from 'node:net';\nimport {\n\ttype S3Address,\n\tbuild as s3Build,\n\tparse as s3Parse,\n} from '@geekmidas/storage/s3-url';\nimport prompts, { type PromptObject } from 'prompts';\nimport { z } from 'zod';\nimport { SERVER_IPV4_KEY, SERVER_IPV6_KEY } from '../compose/dnsConfig.js';\nimport { loadWorkspaceSettings } from '../config';\nimport { GkmError } from '../errors';\nimport { stageProvider } from '../providers/config.js';\nimport { deploysWithCompose } from '../providers/dns.js';\nimport { provisionCommand, stageProviderNotes } from '../providers/notes.js';\nimport { discover } from '../reconcile/discover';\nimport { constructGlobs } from '../reconcile/workspace';\nimport { assertDeployedStage } from '../workspace/stages';\nimport {\n\ttype CredentialSchemaInfo,\n\ttype CredentialSchemas,\n\tissueLine,\n\tloadCredentialSchemas,\n} from './credentialSchemas';\nimport { type WorkspaceStageKey, workspaceStageKeys } from './stageKeys';\nimport { initStageSecrets } from './storage';\nimport { secretsStoreFor } from './store';\n\nexport interface SecretsAddOptions {\n\tstage: string;\n\t/** Only the keys the stage has not set. */\n\tmissing?: boolean;\n\t/** Print the keys as JSON and ask nothing. */\n\tjson?: boolean;\n\t/** The workspace — the current directory when absent. */\n\tcwd?: string;\n\t/** The CLI's home, for a file store's keys. Defaults to `GKM_HOME`. */\n\thome?: string;\n}\n\n/** Where the command writes, and whether there is anyone to ask. */\nexport interface SecretsAddIo {\n\t/** A line for the person at the terminal. */\n\tlog(line: string): void;\n\t/** `--json`'s output. */\n\twrite(chunk: string): void;\n\t/** Whether prompts can be answered. */\n\tinteractive: boolean;\n}\n\n/** What a run of the command came to. */\nexport interface SecretsAddResult {\n\t/** The keys offered, in the order they were walked. */\n\tkeys: WorkspaceStageKey[];\n\t/** The keys saved, in the order they were built. */\n\tsaved: string[];\n\t/** The keys skipped at their checkpoint. */\n\tskipped: string[];\n\t/** The keys the stage must still be given, once the run is over. */\n\tmissing: string[];\n}\n\n/** One key as `--json` prints it. */\nexport interface StageKeyJson {\n\tkey: string;\n\tkind: WorkspaceStageKey['kind'];\n\tconstruct: string;\n\tapps: string[];\n\tset: boolean;\n\t/** A provider on the stage creates it: `gkm setup --stage <stage>`. */\n\tprovisioned?: true;\n}\n\n/** `gkm secrets:add` with nobody at a terminal to answer it. */\nexport class SecretsAddNeedsTerminal extends GkmError {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`gkm secrets:add asks for each key, and there is no terminal to ask ` +\n\t\t\t\t`at. List what the stage needs with ` +\n\t\t\t\t`gkm secrets:add --stage ${stage} --missing --json, and set each ` +\n\t\t\t\t`with gkm secrets:set <KEY> <value> --stage ${stage}.`,\n\t\t);\n\t\tthis.name = 'SecretsAddNeedsTerminal';\n\t}\n}\n\n/**\n * The person stopped the builder at a prompt (Ctrl-C). Every key saved\n * before it is kept; the run ends with what was saved and what is missing.\n */\nexport class SecretsAddCancelled extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`Stopped. Every key saved to the stage '${stage}' before it is kept.`,\n\t\t);\n\t\tthis.name = 'SecretsAddCancelled';\n\t}\n}\n\nconst defaultIo = (): SecretsAddIo => ({\n\tlog: (line) => console.log(line),\n\twrite: (chunk) => {\n\t\tprocess.stdout.write(chunk);\n\t},\n\tinteractive: process.stdin.isTTY === true && process.stdout.isTTY === true,\n});\n\n/** `gkm secrets:add`. */\nexport async function secretsAddCommand(\n\toptions: SecretsAddOptions,\n\tio: SecretsAddIo = defaultIo(),\n): Promise<SecretsAddResult> {\n\tconst { stage } = options;\n\tconst workspace = await loadWorkspaceSettings(options.cwd ?? process.cwd());\n\tconst local = stage === workspace.stages.local;\n\tif (!local) assertDeployedStage(workspace.stages, stage);\n\n\tconst patterns = constructGlobs(workspace);\n\tconst runnables: Record<string, string[]> = {};\n\tconst manifest = await discover({\n\t\tpatterns,\n\t\tcwd: workspace.root,\n\t\trunnables,\n\t});\n\n\tconst store = await secretsStoreFor(workspace, stage, {\n\t\t...(options.home ? { home: options.home } : {}),\n\t});\n\tconst stored = await store.read(stage);\n\tconst domain = workspace.domains?.[stage];\n\n\tconst all = workspaceStageKeys({\n\t\tmanifest,\n\t\trunnables,\n\t\tlocal,\n\t\tsupplied: stored?.custom ?? {},\n\t\t...(domain ? { domain } : {}),\n\t\tproviders: stageProviderNotes(workspace, stage),\n\t\t// A compose stage that serves a domain names its server.\n\t\t...(!local && domain && deploysWithCompose(workspace)\n\t\t\t? { server: true }\n\t\t\t: {}),\n\t});\n\t// Unset keys first: a run is for what the stage still lacks.\n\tconst scope = [...all.filter((k) => !k.set), ...all.filter((k) => k.set)];\n\tconst keys = options.missing ? scope.filter((k) => !k.set) : scope;\n\n\t// A key a provider on the stage writes — `gkm setup` creates its bucket.\n\tconst objects = stageProvider(workspace as never, 'objects', stage);\n\tconst provisioned = (k: WorkspaceStageKey) =>\n\t\tobjects.mode === 'provider' &&\n\t\tk.hint !== undefined &&\n\t\t(k.kind === 'bucket' || k.kind === 'file-server');\n\n\tif (options.json) {\n\t\tconst listed: StageKeyJson[] = keys.map((k) => ({\n\t\t\tkey: k.key,\n\t\t\tkind: k.kind,\n\t\t\tconstruct: k.id,\n\t\t\tapps: [...(k.apps ?? [])],\n\t\t\tset: k.set,\n\t\t\t...(provisioned(k) ? { provisioned: true as const } : {}),\n\t\t}));\n\t\tio.write(`${JSON.stringify(listed, null, 2)}\\n`);\n\t\treturn { keys, saved: [], skipped: [], missing: [] };\n\t}\n\n\tif (!io.interactive) throw new SecretsAddNeedsTerminal(stage);\n\n\t// A provisioned key is no checkpoint: it is listed, with what creates it.\n\tconst offered = keys.filter((k) => !provisioned(k));\n\tconst created = keys.filter(provisioned);\n\tif (created.length > 0 && objects.mode === 'provider') {\n\t\tio.log('Not offered — a provider on the stage creates them:');\n\t\tfor (const k of created) {\n\t\t\tio.log(\n\t\t\t\t` ${k.key} — created by ${provisionCommand(stage)} ` +\n\t\t\t\t\t`(deploy.objects.${stage} is ${objects.name})`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (offered.length === 0) {\n\t\tio.log(\n\t\t\tall.every(provisioned)\n\t\t\t\t? `Nothing to add: no construct on '${stage}' needs a key only the stage can supply.`\n\t\t\t\t: `Nothing to add: the stage '${stage}' has every key it needs.`,\n\t\t);\n\t\treturn { keys: offered, saved: [], skipped: [], missing: [] };\n\t}\n\n\tconst ask = asker(stage);\n\tlet current = stored ?? initStageSecrets(stage);\n\tconst saved: string[] = [];\n\tconst skipped: string[] = [];\n\tconst has = (key: string) => current.custom?.[key] !== undefined;\n\tlet schemas: CredentialSchemas | undefined;\n\n\t// Each key is saved as soon as it is built: what is set survives a stop.\n\tconst save = async (values: Record<string, string>) => {\n\t\tcurrent = {\n\t\t\t...current,\n\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\tcustom: { ...current.custom, ...values },\n\t\t};\n\t\tawait store.write(stage, current);\n\t\tsaved.push(...Object.keys(values));\n\t\tio.log(` ✓ Saved ${Object.keys(values).join(', ')}.`);\n\t};\n\n\tconst walk = async () => {\n\t\tfor (const [index, entry] of offered.entries()) {\n\t\t\tio.log(`\\n[${index + 1}/${offered.length}] ${entry.key} — ${entry.what}`);\n\t\t\tif (entry.hint) io.log(` ${entry.hint}`);\n\n\t\t\tconst step = await ask<'set' | 'skip' | 'stop'>({\n\t\t\t\ttype: 'select',\n\t\t\t\tmessage: `${entry.key} ${KIND_LABEL[entry.kind]} '${entry.id}'${entry.apps?.length ? ` · ${entry.apps.join(', ')}` : ''}${entry.set ? ' · set' : ''}`,\n\t\t\t\tchoices: [\n\t\t\t\t\t{ title: 'Set it now', value: 'set' },\n\t\t\t\t\t{ title: 'Skip', value: 'skip' },\n\t\t\t\t\t{ title: 'Stop here', value: 'stop' },\n\t\t\t\t],\n\t\t\t\tinitial: 0,\n\t\t\t});\n\t\t\tif (step === 'stop') return;\n\t\t\tif (step !== 'set') {\n\t\t\t\tskipped.push(entry.key);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (entry.set) {\n\t\t\t\tconst overwrite: boolean = await ask({\n\t\t\t\t\ttype: 'confirm',\n\t\t\t\t\tmessage: `${entry.key} is set. Replace it?`,\n\t\t\t\t\tinitial: false,\n\t\t\t\t});\n\t\t\t\tif (!overwrite) {\n\t\t\t\t\tskipped.push(entry.key);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tswitch (entry.kind) {\n\t\t\t\tcase 'bucket':\n\t\t\t\t\tawait save(await buildBucket(ask, io, entry, has));\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'email':\n\t\t\t\t\tawait save({\n\t\t\t\t\t\t[entry.key]: entry.key.endsWith('_FROM')\n\t\t\t\t\t\t\t? await askFrom(ask, io)\n\t\t\t\t\t\t\t: await buildSmtpUrl(ask, io),\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'file-server':\n\t\t\t\t\tawait save({\n\t\t\t\t\t\t[entry.key]: await askHttpUrl(ask, io, 'Its public URL'),\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'server':\n\t\t\t\t\tawait save(await buildServer(ask, io, has));\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'external-api':\n\t\t\t\tcase 'credential':\n\t\t\t\t\tschemas ??= await loadCredentialSchemas({\n\t\t\t\t\t\troot: workspace.root,\n\t\t\t\t\t\tpatterns,\n\t\t\t\t\t});\n\t\t\t\t\tawait save({\n\t\t\t\t\t\t[entry.key]: await buildCredentials(ask, io, entry, schemas),\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t};\n\n\ttry {\n\t\tawait walk();\n\t} catch (error) {\n\t\tif (!(error instanceof SecretsAddCancelled)) throw error;\n\t\tio.log(`\\n${error.message}`);\n\t}\n\n\tconst missing = all\n\t\t.filter((k) => !provisioned(k) && !has(k.key))\n\t\t.map((k) => k.key);\n\tio.log('');\n\tio.log(\n\t\tsaved.length > 0\n\t\t\t? `✓ Saved to the stage '${stage}' (${store.name} store): ${saved.join(', ')}`\n\t\t\t: 'Nothing was saved.',\n\t);\n\tif (skipped.length > 0) io.log(` Skipped: ${skipped.join(', ')}`);\n\tif (missing.length > 0) {\n\t\tio.log(` Still missing: ${missing.join(', ')}`);\n\t\tio.log(\n\t\t\t` Run gkm secrets:add --stage ${stage} --missing again to pick up where this left off.`,\n\t\t);\n\t}\n\treturn { keys: offered, saved, skipped, missing };\n}\n\nconst KIND_LABEL: Record<WorkspaceStageKey['kind'], string> = {\n\tbucket: 'bucket',\n\temail: 'email',\n\t'file-server': 'file server',\n\t'external-api': 'external API',\n\tcredential: 'credential',\n\tserver: 'server address',\n};\n\n/** The server's IPv4 address, and — if it has one — its IPv6 address. */\nasync function buildServer(\n\task: Ask,\n\tio: SecretsAddIo,\n\thas: (key: string) => boolean,\n): Promise<Record<string, string>> {\n\tconst ipv4 = text(\n\t\tawait askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{ type: 'text', message: \"The server's public IPv4 address\" },\n\t\t\t(value) =>\n\t\t\t\tisIPv4(text(value))\n\t\t\t\t\t? undefined\n\t\t\t\t\t: 'An IPv4 address is required, e.g. 203.0.113.10.',\n\t\t),\n\t);\n\tconst values: Record<string, string> = { [SERVER_IPV4_KEY]: ipv4 };\n\tif (has(SERVER_IPV6_KEY)) return values;\n\tconst ipv6 = text(\n\t\tawait askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{\n\t\t\t\ttype: 'text',\n\t\t\t\tmessage: 'Its public IPv6 address (empty for none — no AAAA records)',\n\t\t\t},\n\t\t\t(value) =>\n\t\t\t\t!text(value) || isIPv6(text(value))\n\t\t\t\t\t? undefined\n\t\t\t\t\t: 'An IPv6 address, e.g. 2001:db8::10, or nothing.',\n\t\t),\n\t);\n\tif (ipv6) values[SERVER_IPV6_KEY] = ipv6;\n\treturn values;\n}\n\n/** One question, answered — or the run stopped. */\ntype Ask = <T = string>(question: Omit<PromptObject, 'name'>) => Promise<T>;\n\nfunction asker(stage: string): Ask {\n\treturn async <T>(question: Omit<PromptObject, 'name'>) => {\n\t\tconst answers = await prompts(\n\t\t\t{ ...question, name: 'value' } as PromptObject,\n\t\t\t{\n\t\t\t\tonCancel: () => {\n\t\t\t\t\tthrow new SecretsAddCancelled(stage);\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\treturn answers.value as T;\n\t};\n}\n\n/** Ask until `accept` takes the answer; `accept` returns why it did not. */\nasync function askUntil<T>(\n\task: Ask,\n\tio: SecretsAddIo,\n\tquestion: Omit<PromptObject, 'name'>,\n\taccept: (value: T) => string | undefined,\n): Promise<T> {\n\tfor (;;) {\n\t\tconst value = await ask<T>(question);\n\t\tconst problem = accept(value);\n\t\tif (!problem) return value;\n\t\tio.log(` ✗ ${problem}`);\n\t}\n}\n\nconst required =\n\t(what: string) =>\n\t(value: string | undefined): string | undefined =>\n\t\tvalue?.trim() ? undefined : `${what} is required.`;\n\nconst text = (value: unknown) => String(value ?? '').trim();\n\n/** An `http(s)://` URL. */\nconst HttpUrl = z.url({ protocol: /^https?$/ });\n\nasync function askHttpUrl(\n\task: Ask,\n\tio: SecretsAddIo,\n\tmessage: string,\n): Promise<string> {\n\treturn text(\n\t\tawait askUntil<string>(ask, io, { type: 'text', message }, (value) =>\n\t\t\tHttpUrl.safeParse(text(value)).success\n\t\t\t\t? undefined\n\t\t\t\t: 'An http:// or https:// URL is required.',\n\t\t),\n\t);\n}\n\nasync function askFrom(ask: Ask, io: SecretsAddIo): Promise<string> {\n\treturn text(\n\t\tawait askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{ type: 'text', message: 'The address it sends from' },\n\t\t\t(value) =>\n\t\t\t\tz.email().safeParse(text(value)).success\n\t\t\t\t\t? undefined\n\t\t\t\t\t: 'An email address is required, e.g. noreply@example.com.',\n\t\t),\n\t);\n}\n\n/** A mail service whose SMTP settings are known: only its secrets are asked. */\ntype MailService = 'resend' | 'ses' | 'postmark' | 'mailgun' | 'other';\n\n/**\n * An SMTP server as the URL `@geekmidas/emailkit` reads: `smtp://` for\n * STARTTLS, `smtps://` for TLS from the first byte, with the user and\n * password percent-encoded.\n *\n * A known service fills in its own host, port and user; each from its docs:\n * - Resend: smtp.resend.com, 465 implicit TLS, user `resend`, password the\n * API key — https://resend.com/docs/send-with-smtp\n * - Amazon SES: email-smtp.<region>.amazonaws.com, 587 STARTTLS, SMTP\n * credentials — https://docs.aws.amazon.com/ses/latest/dg/smtp-connect.html,\n * https://docs.aws.amazon.com/general/latest/gr/ses.html\n * - Postmark: smtp.postmarkapp.com, 587 STARTTLS, the server API token as\n * user and password —\n * https://postmarkapp.com/developer/user-guide/send-email-with-smtp\n * - Mailgun: smtp.mailgun.org (EU: smtp.eu.mailgun.org), 587 STARTTLS, the\n * domain's SMTP credentials —\n * https://documentation.mailgun.com/docs/mailgun/user-manual/sending-messages/send-smtp,\n * https://documentation.mailgun.com/docs/mailgun/api-reference/api-overview\n */\nasync function buildSmtpUrl(ask: Ask, io: SecretsAddIo): Promise<string> {\n\tconst service = await ask<MailService>({\n\t\ttype: 'select',\n\t\tmessage: 'Which mail service?',\n\t\tchoices: [\n\t\t\t{ title: 'Resend', value: 'resend' },\n\t\t\t{ title: 'Amazon SES', value: 'ses' },\n\t\t\t{ title: 'Postmark', value: 'postmark' },\n\t\t\t{ title: 'Mailgun', value: 'mailgun' },\n\t\t\t{ title: 'Other SMTP server', value: 'other' },\n\t\t],\n\t\tinitial: 0,\n\t});\n\tconst secret = async (message: string, what: string) =>\n\t\ttext(\n\t\t\tawait askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message },\n\t\t\t\trequired(what),\n\t\t\t),\n\t\t);\n\tconst login = async (message: string, what: string) =>\n\t\ttext(\n\t\t\tawait askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'text', message },\n\t\t\t\trequired(what),\n\t\t\t),\n\t\t);\n\n\tswitch (service) {\n\t\tcase 'resend':\n\t\t\treturn smtpUrl({\n\t\t\t\ttls: 'tls',\n\t\t\t\thost: 'smtp.resend.com',\n\t\t\t\tport: 465,\n\t\t\t\tuser: 'resend',\n\t\t\t\tpassword: await secret('API key (re_…)', 'The API key'),\n\t\t\t});\n\t\tcase 'ses': {\n\t\t\tconst region = await login('Region', 'The region');\n\t\t\treturn smtpUrl({\n\t\t\t\ttls: 'starttls',\n\t\t\t\thost: `email-smtp.${region}.amazonaws.com`,\n\t\t\t\tport: 587,\n\t\t\t\tuser: await login('SMTP user name', 'The SMTP user name'),\n\t\t\t\tpassword: await secret('SMTP password', 'The SMTP password'),\n\t\t\t});\n\t\t}\n\t\tcase 'postmark': {\n\t\t\tconst token = await secret('Server API token', 'The server API token');\n\t\t\treturn smtpUrl({\n\t\t\t\ttls: 'starttls',\n\t\t\t\thost: 'smtp.postmarkapp.com',\n\t\t\t\tport: 587,\n\t\t\t\tuser: token,\n\t\t\t\tpassword: token,\n\t\t\t});\n\t\t}\n\t\tcase 'mailgun': {\n\t\t\tconst region = await ask<'us' | 'eu'>({\n\t\t\t\ttype: 'select',\n\t\t\t\tmessage: 'Region',\n\t\t\t\tchoices: [\n\t\t\t\t\t{ title: 'US (smtp.mailgun.org)', value: 'us' },\n\t\t\t\t\t{ title: 'EU (smtp.eu.mailgun.org)', value: 'eu' },\n\t\t\t\t],\n\t\t\t\tinitial: 0,\n\t\t\t});\n\t\t\treturn smtpUrl({\n\t\t\t\ttls: 'starttls',\n\t\t\t\thost: region === 'eu' ? 'smtp.eu.mailgun.org' : 'smtp.mailgun.org',\n\t\t\t\tport: 587,\n\t\t\t\tuser: await login(\n\t\t\t\t\t'SMTP login (e.g. postmaster@mg.example.com)',\n\t\t\t\t\t'The SMTP login',\n\t\t\t\t),\n\t\t\t\tpassword: await secret('SMTP password', 'The SMTP password'),\n\t\t\t});\n\t\t}\n\t\tcase 'other':\n\t\t\tbreak;\n\t}\n\n\tconst host = text(\n\t\tawait askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{ type: 'text', message: 'SMTP host' },\n\t\t\trequired('The host'),\n\t\t),\n\t);\n\tconst port = await askUntil<string | number>(\n\t\task,\n\t\tio,\n\t\t{ type: 'text', message: 'Port', initial: '587' },\n\t\t(value) => {\n\t\t\tconst n = Number(value);\n\t\t\treturn Number.isInteger(n) && n > 0 && n < 65536\n\t\t\t\t? undefined\n\t\t\t\t: 'A port number is required.';\n\t\t},\n\t);\n\tconst user = text(\n\t\tawait ask<string>({ type: 'text', message: 'User (empty for none)' }),\n\t);\n\tconst password = user\n\t\t? await ask<string>({ type: 'password', message: 'Password' })\n\t\t: '';\n\tconst tls = await ask<'starttls' | 'tls'>({\n\t\ttype: 'select',\n\t\tmessage: 'TLS',\n\t\tchoices: [\n\t\t\t{ title: 'STARTTLS (smtp://, usually port 587)', value: 'starttls' },\n\t\t\t{ title: 'TLS on connect (smtps://, usually port 465)', value: 'tls' },\n\t\t],\n\t\tinitial: 0,\n\t});\n\treturn smtpUrl({ tls, host, port: Number(port), user, password });\n}\n\nfunction smtpUrl(server: {\n\ttls: 'starttls' | 'tls';\n\thost: string;\n\tport: number;\n\tuser?: string;\n\tpassword?: string;\n}): string {\n\tconst url = new URL(\n\t\t`${server.tls === 'tls' ? 'smtps' : 'smtp'}://${server.host}`,\n\t);\n\turl.port = String(server.port);\n\tif (server.user) {\n\t\turl.username = encodeURIComponent(server.user);\n\t\turl.password = encodeURIComponent(server.password ?? '');\n\t}\n\treturn url.toString().replace(/\\/$/, '');\n}\n\n/**\n * A bucket's URL, from its provider — and, optionally, a key for it alone in\n * the URL, or the stage's shared pair. Credentials are never required: without\n * them the SDK's own chain signs, a role included.\n */\nasync function buildBucket(\n\task: Ask,\n\tio: SecretsAddIo,\n\tentry: WorkspaceStageKey,\n\thas: (key: string) => boolean,\n): Promise<Record<string, string>> {\n\tconst provider = await ask<'s3' | 'r2' | 'compatible' | 'url'>({\n\t\ttype: 'select',\n\t\tmessage: 'Where is the bucket?',\n\t\tchoices: [\n\t\t\t{ title: 'AWS S3', value: 's3' },\n\t\t\t{ title: 'Cloudflare R2', value: 'r2' },\n\t\t\t{ title: 'MinIO, or another S3-compatible store', value: 'compatible' },\n\t\t\t{ title: 'Paste an s3:// URL', value: 'url' },\n\t\t],\n\t\tinitial: 0,\n\t});\n\n\tconst bucketName = async () =>\n\t\ttext(\n\t\t\tawait askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'text', message: 'Bucket name' },\n\t\t\t\trequired('The bucket name'),\n\t\t\t),\n\t\t);\n\n\tlet address: S3Address;\n\tswitch (provider) {\n\t\tcase 's3': {\n\t\t\tconst bucket = await bucketName();\n\t\t\tconst region = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{ type: 'text', message: 'Region', initial: 'eu-west-1' },\n\t\t\t\t\trequired('The region'),\n\t\t\t\t),\n\t\t\t);\n\t\t\taddress = { bucket, region };\n\t\t\tbreak;\n\t\t}\n\t\tcase 'r2': {\n\t\t\tconst account = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\tmessage: 'Cloudflare account id, or the R2 endpoint URL',\n\t\t\t\t\t},\n\t\t\t\t\trequired('The account id or endpoint'),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst bucket = await bucketName();\n\t\t\taddress = {\n\t\t\t\tbucket,\n\t\t\t\tregion: 'auto',\n\t\t\t\tendpoint: /^https?:\\/\\//.test(account)\n\t\t\t\t\t? account\n\t\t\t\t\t: `https://${account}.r2.cloudflarestorage.com`,\n\t\t\t};\n\t\t\tbreak;\n\t\t}\n\t\tcase 'compatible': {\n\t\t\tconst endpoint = await askHttpUrl(ask, io, 'Endpoint URL');\n\t\t\tconst bucket = await bucketName();\n\t\t\tconst region = text(\n\t\t\t\tawait ask<string>({\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\tmessage: 'Region',\n\t\t\t\t\tinitial: 'us-east-1',\n\t\t\t\t}),\n\t\t\t);\n\t\t\tconst forcePathStyle = await ask<boolean>({\n\t\t\t\ttype: 'confirm',\n\t\t\t\tmessage: 'Path-style addressing? (MinIO needs it)',\n\t\t\t\tinitial: true,\n\t\t\t});\n\t\t\taddress = {\n\t\t\t\tbucket,\n\t\t\t\t...(region ? { region } : {}),\n\t\t\t\tendpoint,\n\t\t\t\t...(forcePathStyle ? { forcePathStyle } : {}),\n\t\t\t};\n\t\t\tbreak;\n\t\t}\n\t\tcase 'url': {\n\t\t\tconst pasted = await askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message: 'The s3:// URL' },\n\t\t\t\t(value) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\ts3Parse(text(value));\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\treturn `Not an s3:// URL the storage client can read (${(error as Error).name}).`;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t\taddress = s3Parse(text(pasted));\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!address.accessKeyId) {\n\t\tconst own = await ask<boolean>({\n\t\t\ttype: 'confirm',\n\t\t\tmessage: `A key for '${entry.id}' alone, in its URL? (optional)`,\n\t\t\tinitial: false,\n\t\t});\n\t\tif (own) {\n\t\t\tconst accessKeyId = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{ type: 'text', message: 'Access key id' },\n\t\t\t\t\trequired('The access key id'),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst secretAccessKey = await askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message: 'Secret access key' },\n\t\t\t\trequired('The secret access key'),\n\t\t\t);\n\t\t\taddress = { ...address, accessKeyId, secretAccessKey };\n\t\t}\n\t}\n\n\tconst values: Record<string, string> = { [entry.key]: s3Build(address) };\n\n\tif (!address.accessKeyId && !has('AWS_ACCESS_KEY_ID')) {\n\t\tconst shared = await ask<boolean>({\n\t\t\ttype: 'confirm',\n\t\t\tmessage:\n\t\t\t\t\"Set the stage's shared AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY? \" +\n\t\t\t\t'(optional: without them a role signs)',\n\t\t\tinitial: false,\n\t\t});\n\t\tif (shared) {\n\t\t\tvalues.AWS_ACCESS_KEY_ID = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{ type: 'text', message: 'AWS_ACCESS_KEY_ID' },\n\t\t\t\t\trequired('The access key id'),\n\t\t\t\t),\n\t\t\t);\n\t\t\tvalues.AWS_SECRET_ACCESS_KEY = await askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message: 'AWS_SECRET_ACCESS_KEY' },\n\t\t\t\trequired('The secret access key'),\n\t\t\t);\n\t\t}\n\t}\n\n\treturn values;\n}\n\n/** A field whose name says it is a secret, asked for without echo. */\nconst SECRET_FIELD = /secret|key|token|password/i;\n\ninterface JsonSchemaProperty {\n\ttype?: string | string[];\n\tenum?: unknown[];\n\tdescription?: string;\n}\n\n/** The properties of an object schema, or nothing for any other shape. */\nfunction objectProperties(\n\tinfo: CredentialSchemaInfo | undefined,\n):\n\t| { properties: Record<string, JsonSchemaProperty>; required: string[] }\n\t| undefined {\n\tconst schema = info?.jsonSchema;\n\tif (!schema || schema.type !== 'object') return undefined;\n\tconst properties = schema.properties;\n\tif (!properties || typeof properties !== 'object') return undefined;\n\treturn {\n\t\tproperties: properties as Record<string, JsonSchemaProperty>,\n\t\trequired: Array.isArray(schema.required)\n\t\t\t? (schema.required as string[])\n\t\t\t: [],\n\t};\n}\n\nfunction typesOf(property: JsonSchemaProperty): string[] {\n\tif (Array.isArray(property.type)) return property.type;\n\treturn property.type ? [property.type] : [];\n}\n\n/**\n * Credentials, field by field where the construct's schema is an object it\n * can describe, and as JSON otherwise — checked against the schema itself\n * before anything is kept, and asked again, with each issue's path, until\n * the schema takes it.\n */\nasync function buildCredentials(\n\task: Ask,\n\tio: SecretsAddIo,\n\tentry: WorkspaceStageKey,\n\tschemas: CredentialSchemas,\n): Promise<string> {\n\tconst info = schemas.schemas.find((s) => s.key === entry.key);\n\tconst shape = objectProperties(info);\n\tif (!info) {\n\t\tio.log(\n\t\t\t` '${entry.id}' exposes no schema to check against; the value is stored as given.`,\n\t\t);\n\t}\n\n\tfor (;;) {\n\t\tconst raw = shape\n\t\t\t? JSON.stringify(await askFields(ask, io, shape))\n\t\t\t: text(\n\t\t\t\t\tawait ask<string>({\n\t\t\t\t\t\ttype: 'password',\n\t\t\t\t\t\tmessage: 'The value, as JSON (or one opaque string)',\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\tconst check = await schemas.check(entry.key, raw);\n\t\tif (check.ok) return raw;\n\t\tio.log(` ✗ The schema of '${entry.id}' refuses it:`);\n\t\tfor (const issue of check.issues) {\n\t\t\tio.log(` ${issueLine(entry.key, issue)}`);\n\t\t}\n\t\tio.log(' Again:');\n\t}\n}\n\nasync function askFields(\n\task: Ask,\n\tio: SecretsAddIo,\n\tshape: {\n\t\tproperties: Record<string, JsonSchemaProperty>;\n\t\trequired: string[];\n\t},\n): Promise<Record<string, unknown>> {\n\tconst value: Record<string, unknown> = {};\n\tfor (const [name, property] of Object.entries(shape.properties)) {\n\t\tconst optional = !shape.required.includes(name);\n\t\tconst label = `${name}${optional ? ' (optional)' : ''}${property.description ? ` — ${property.description}` : ''}`;\n\t\tconst types = typesOf(property);\n\n\t\tif (property.enum?.length) {\n\t\t\tconst choices = property.enum.map((option) => ({\n\t\t\t\ttitle: String(option),\n\t\t\t\tvalue: option,\n\t\t\t}));\n\t\t\tconst picked = await ask<unknown>({\n\t\t\t\ttype: 'select',\n\t\t\t\tmessage: label,\n\t\t\t\tchoices: optional\n\t\t\t\t\t? [{ title: '(none)', value: undefined }, ...choices]\n\t\t\t\t\t: choices,\n\t\t\t} as Omit<PromptObject, 'name'>);\n\t\t\tif (picked !== undefined) value[name] = picked;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (types.includes('boolean')) {\n\t\t\tvalue[name] = await ask<boolean>({\n\t\t\t\ttype: 'confirm',\n\t\t\t\tmessage: label,\n\t\t\t\tinitial: false,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst numeric = types.includes('number') || types.includes('integer');\n\t\tconst plain = types.length === 0 || types.includes('string');\n\t\tconst answer = await askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{\n\t\t\t\ttype: SECRET_FIELD.test(name) ? 'password' : 'text',\n\t\t\t\tmessage: label,\n\t\t\t},\n\t\t\t(given) => {\n\t\t\t\tconst typed = text(given);\n\t\t\t\tif (!typed) return optional ? undefined : `${name} is required.`;\n\t\t\t\tif (numeric && !plain && Number.isNaN(Number(typed))) {\n\t\t\t\t\treturn `${name} is a number.`;\n\t\t\t\t}\n\t\t\t\tif (!numeric && !plain) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tJSON.parse(typed);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn `${name} is JSON (${types.join(' or ')}).`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t);\n\t\tconst typed = text(answer);\n\t\tif (!typed) continue;\n\t\tvalue[name] = plain ? typed : numeric ? Number(typed) : JSON.parse(typed);\n\t}\n\treturn value;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
- const require_awsStore = require("./awsStore-7VmS_cZR.cjs");
2
+ const require_awsStore = require("./awsStore-B5We7bMg.cjs");
3
3
  let _aws_sdk_client_ssm = require("@aws-sdk/client-ssm");
4
4
  //#region src/secrets/aws.ts
5
5
  /**
@@ -40,29 +40,47 @@ var AwsSecretsStore = class {
40
40
  this.client = new _aws_sdk_client_ssm.SSMClient(await require_awsStore.awsClientConfig(this.options));
41
41
  return this.client;
42
42
  }
43
+ /** Where a call for `stage` is, for an error saying it has no credentials. */
44
+ context(stage, access) {
45
+ return {
46
+ stage,
47
+ store: this.name,
48
+ profile: this.options.profile,
49
+ access
50
+ };
51
+ }
52
+ /**
53
+ * @throws {StageSecretsUnreadable} when there are no AWS credentials to
54
+ * read it with, or they have expired
55
+ */
43
56
  async read(stage) {
44
57
  const ssm = await this.ssm();
45
58
  try {
46
- const { Parameter } = await ssm.send(new _aws_sdk_client_ssm.GetParameterCommand({
59
+ const { Parameter } = await require_awsStore.withStageCredentials(this.context(stage, "read"), () => ssm.send(new _aws_sdk_client_ssm.GetParameterCommand({
47
60
  Name: secretsParameterName(this.options.project, stage),
48
61
  WithDecryption: true
49
- }));
62
+ })));
50
63
  return Parameter?.Value ? JSON.parse(Parameter.Value) : null;
51
64
  } catch (error) {
52
65
  if (error instanceof _aws_sdk_client_ssm.ParameterNotFound) return null;
53
66
  throw error;
54
67
  }
55
68
  }
69
+ /**
70
+ * @throws {StageSecretsUnreadable} when there are no AWS credentials to
71
+ * write it with, or they have expired
72
+ */
56
73
  async write(stage, secrets) {
57
74
  const value = require_awsStore.serializeWithin(stage, this.name, secrets, SSM_PARAMETER_LIMIT);
58
- await (await this.ssm()).send(new _aws_sdk_client_ssm.PutParameterCommand({
75
+ const ssm = await this.ssm();
76
+ await require_awsStore.withStageCredentials(this.context(stage, "write"), () => ssm.send(new _aws_sdk_client_ssm.PutParameterCommand({
59
77
  Name: secretsParameterName(this.options.project, stage),
60
78
  Value: value,
61
79
  Type: "SecureString",
62
80
  Tier: "Intelligent-Tiering",
63
81
  Overwrite: true,
64
82
  Description: `gkm secrets for ${this.options.project}/${stage}`
65
- }));
83
+ })));
66
84
  }
67
85
  };
68
86
  //#endregion
@@ -79,4 +97,4 @@ Object.defineProperty(exports, "secretsParameterName", {
79
97
  }
80
98
  });
81
99
 
82
- //# sourceMappingURL=aws-BTawF0F-.cjs.map
100
+ //# sourceMappingURL=aws-BTReGjpY.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aws-BTReGjpY.cjs","names":["SSMClient","awsClientConfig","withStageCredentials","GetParameterCommand","ParameterNotFound","serializeWithin","PutParameterCommand"],"sources":["../src/secrets/aws.ts"],"sourcesContent":["/**\n * A stage's secrets in SSM Parameter Store, in the stage's own AWS account.\n *\n * One parameter per stage, `/gkm/<project>/<stage>/secrets`, a SecureString —\n * encrypted at rest by KMS, so nothing about it needs a key file anywhere.\n * Which account it is in is whichever credentials are active: the stage's\n * OIDC role in a deploy job, or `--profile` on a developer's machine. With\n * staging and production in different accounts, each stage's secrets sit\n * beside its infrastructure, and a staging role cannot read production's.\n *\n * Written in the Intelligent-Tiering tier: a stage under 4 KB stays a free\n * standard parameter, a larger one becomes advanced (up to 8 KB). Past 8 KB\n * the write is refused with {@link StageSecretsTooLarge} before AWS is\n * called; Secrets Manager (`secretsManager.ts`) holds up to 64 KB.\n */\n\nimport {\n\tGetParameterCommand,\n\tParameterNotFound,\n\tPutParameterCommand,\n\tSSMClient,\n} from '@aws-sdk/client-ssm';\nimport {\n\ttype AwsStoreOptions,\n\tawsClientConfig,\n\tserializeWithin,\n\twithStageCredentials,\n} from './awsStore.js';\nimport type { SecretsStore } from './store.js';\nimport type { StageSecrets } from './types.js';\n\nexport type AwsSecretsStoreOptions = AwsStoreOptions;\n\n/** The most an SSM parameter holds: 8 KB, in the advanced tier. */\nexport const SSM_PARAMETER_LIMIT = 8 * 1024;\n\n/** The parameter a stage's secrets are kept in. */\nexport function secretsParameterName(project: string, stage: string): string {\n\treturn `/gkm/${project}/${stage}/secrets`;\n}\n\nexport class AwsSecretsStore implements SecretsStore {\n\treadonly name = 'ssm';\n\n\tprivate client?: SSMClient;\n\n\tconstructor(private readonly options: AwsSecretsStoreOptions) {}\n\n\tprivate async ssm(): Promise<SSMClient> {\n\t\tif (this.client) return this.client;\n\n\t\tthis.client = new SSMClient(await awsClientConfig(this.options));\n\t\treturn this.client;\n\t}\n\n\t/** Where a call for `stage` is, for an error saying it has no credentials. */\n\tprivate context(stage: string, access: 'read' | 'write') {\n\t\treturn { stage, store: this.name, profile: this.options.profile, access };\n\t}\n\n\t/**\n\t * @throws {StageSecretsUnreadable} when there are no AWS credentials to\n\t * read it with, or they have expired\n\t */\n\tasync read(stage: string): Promise<StageSecrets | null> {\n\t\tconst ssm = await this.ssm();\n\n\t\ttry {\n\t\t\tconst { Parameter } = await withStageCredentials(\n\t\t\t\tthis.context(stage, 'read'),\n\t\t\t\t() =>\n\t\t\t\t\tssm.send(\n\t\t\t\t\t\tnew GetParameterCommand({\n\t\t\t\t\t\t\tName: secretsParameterName(this.options.project, stage),\n\t\t\t\t\t\t\tWithDecryption: true,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t);\n\t\t\treturn Parameter?.Value\n\t\t\t\t? (JSON.parse(Parameter.Value) as StageSecrets)\n\t\t\t\t: null;\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterNotFound) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * @throws {StageSecretsUnreadable} when there are no AWS credentials to\n\t * write it with, or they have expired\n\t */\n\tasync write(stage: string, secrets: StageSecrets): Promise<void> {\n\t\tconst value = serializeWithin(\n\t\t\tstage,\n\t\t\tthis.name,\n\t\t\tsecrets,\n\t\t\tSSM_PARAMETER_LIMIT,\n\t\t);\n\t\tconst ssm = await this.ssm();\n\n\t\tawait withStageCredentials(this.context(stage, 'write'), () =>\n\t\t\tssm.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName: secretsParameterName(this.options.project, stage),\n\t\t\t\t\tValue: value,\n\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\t// Standard (free) under 4 KB, advanced past it; never the other way.\n\t\t\t\t\tTier: 'Intelligent-Tiering',\n\t\t\t\t\tOverwrite: true,\n\t\t\t\t\tDescription: `gkm secrets for ${this.options.project}/${stage}`,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,sBAAsB;;AAGnC,SAAgB,qBAAqB,SAAiB,OAAuB;CAC5E,OAAO,QAAQ,QAAQ,GAAG,MAAM;AACjC;AAEA,IAAa,kBAAb,MAAqD;CAKvB;CAJ7B,OAAgB;CAEhB;CAEA,YAAY,SAAkD;EAAjC,KAAA,UAAA;CAAkC;CAE/D,MAAc,MAA0B;EACvC,IAAI,KAAK,QAAQ,OAAO,KAAK;EAE7B,KAAK,SAAS,IAAIA,oBAAAA,UAAU,MAAMC,iBAAAA,gBAAgB,KAAK,OAAO,CAAC;EAC/D,OAAO,KAAK;CACb;;CAGA,QAAgB,OAAe,QAA0B;EACxD,OAAO;GAAE;GAAO,OAAO,KAAK;GAAM,SAAS,KAAK,QAAQ;GAAS;EAAO;CACzE;;;;;CAMA,MAAM,KAAK,OAA6C;EACvD,MAAM,MAAM,MAAM,KAAK,IAAI;EAE3B,IAAI;GACH,MAAM,EAAE,cAAc,MAAMC,iBAAAA,qBAC3B,KAAK,QAAQ,OAAO,MAAM,SAEzB,IAAI,KACH,IAAIC,oBAAAA,oBAAoB;IACvB,MAAM,qBAAqB,KAAK,QAAQ,SAAS,KAAK;IACtD,gBAAgB;GACjB,CAAC,CACF,CACF;GACA,OAAO,WAAW,QACd,KAAK,MAAM,UAAU,KAAK,IAC3B;EACJ,SAAS,OAAO;GACf,IAAI,iBAAiBC,oBAAAA,mBAAmB,OAAO;GAC/C,MAAM;EACP;CACD;;;;;CAMA,MAAM,MAAM,OAAe,SAAsC;EAChE,MAAM,QAAQC,iBAAAA,gBACb,OACA,KAAK,MACL,SACA,mBACD;EACA,MAAM,MAAM,MAAM,KAAK,IAAI;EAE3B,MAAMH,iBAAAA,qBAAqB,KAAK,QAAQ,OAAO,OAAO,SACrD,IAAI,KACH,IAAII,oBAAAA,oBAAoB;GACvB,MAAM,qBAAqB,KAAK,QAAQ,SAAS,KAAK;GACtD,OAAO;GACP,MAAM;GAEN,MAAM;GACN,WAAW;GACX,aAAa,mBAAmB,KAAK,QAAQ,QAAQ,GAAG;EACzD,CAAC,CACF,CACD;CACD;AACD"}
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mjs";
2
- import { n as serializeWithin, t as awsClientConfig } from "./awsStore-B529csle.mjs";
2
+ import { n as serializeWithin, r as withStageCredentials, t as awsClientConfig } from "./awsStore-BWa1KNY-.mjs";
3
3
  import { GetParameterCommand, ParameterNotFound, PutParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
4
4
  //#region src/secrets/aws.ts
5
5
  /**
@@ -40,32 +40,50 @@ var AwsSecretsStore = class {
40
40
  this.client = new SSMClient(await awsClientConfig(this.options));
41
41
  return this.client;
42
42
  }
43
+ /** Where a call for `stage` is, for an error saying it has no credentials. */
44
+ context(stage, access) {
45
+ return {
46
+ stage,
47
+ store: this.name,
48
+ profile: this.options.profile,
49
+ access
50
+ };
51
+ }
52
+ /**
53
+ * @throws {StageSecretsUnreadable} when there are no AWS credentials to
54
+ * read it with, or they have expired
55
+ */
43
56
  async read(stage) {
44
57
  const ssm = await this.ssm();
45
58
  try {
46
- const { Parameter } = await ssm.send(new GetParameterCommand({
59
+ const { Parameter } = await withStageCredentials(this.context(stage, "read"), () => ssm.send(new GetParameterCommand({
47
60
  Name: secretsParameterName(this.options.project, stage),
48
61
  WithDecryption: true
49
- }));
62
+ })));
50
63
  return Parameter?.Value ? JSON.parse(Parameter.Value) : null;
51
64
  } catch (error) {
52
65
  if (error instanceof ParameterNotFound) return null;
53
66
  throw error;
54
67
  }
55
68
  }
69
+ /**
70
+ * @throws {StageSecretsUnreadable} when there are no AWS credentials to
71
+ * write it with, or they have expired
72
+ */
56
73
  async write(stage, secrets) {
57
74
  const value = serializeWithin(stage, this.name, secrets, SSM_PARAMETER_LIMIT);
58
- await (await this.ssm()).send(new PutParameterCommand({
75
+ const ssm = await this.ssm();
76
+ await withStageCredentials(this.context(stage, "write"), () => ssm.send(new PutParameterCommand({
59
77
  Name: secretsParameterName(this.options.project, stage),
60
78
  Value: value,
61
79
  Type: "SecureString",
62
80
  Tier: "Intelligent-Tiering",
63
81
  Overwrite: true,
64
82
  Description: `gkm secrets for ${this.options.project}/${stage}`
65
- }));
83
+ })));
66
84
  }
67
85
  };
68
86
  //#endregion
69
87
  export { secretsParameterName as n, aws_exports as t };
70
88
 
71
- //# sourceMappingURL=aws-B-6uEhgP.mjs.map
89
+ //# sourceMappingURL=aws-Dz2bYxK1.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aws-Dz2bYxK1.mjs","names":[],"sources":["../src/secrets/aws.ts"],"sourcesContent":["/**\n * A stage's secrets in SSM Parameter Store, in the stage's own AWS account.\n *\n * One parameter per stage, `/gkm/<project>/<stage>/secrets`, a SecureString —\n * encrypted at rest by KMS, so nothing about it needs a key file anywhere.\n * Which account it is in is whichever credentials are active: the stage's\n * OIDC role in a deploy job, or `--profile` on a developer's machine. With\n * staging and production in different accounts, each stage's secrets sit\n * beside its infrastructure, and a staging role cannot read production's.\n *\n * Written in the Intelligent-Tiering tier: a stage under 4 KB stays a free\n * standard parameter, a larger one becomes advanced (up to 8 KB). Past 8 KB\n * the write is refused with {@link StageSecretsTooLarge} before AWS is\n * called; Secrets Manager (`secretsManager.ts`) holds up to 64 KB.\n */\n\nimport {\n\tGetParameterCommand,\n\tParameterNotFound,\n\tPutParameterCommand,\n\tSSMClient,\n} from '@aws-sdk/client-ssm';\nimport {\n\ttype AwsStoreOptions,\n\tawsClientConfig,\n\tserializeWithin,\n\twithStageCredentials,\n} from './awsStore.js';\nimport type { SecretsStore } from './store.js';\nimport type { StageSecrets } from './types.js';\n\nexport type AwsSecretsStoreOptions = AwsStoreOptions;\n\n/** The most an SSM parameter holds: 8 KB, in the advanced tier. */\nexport const SSM_PARAMETER_LIMIT = 8 * 1024;\n\n/** The parameter a stage's secrets are kept in. */\nexport function secretsParameterName(project: string, stage: string): string {\n\treturn `/gkm/${project}/${stage}/secrets`;\n}\n\nexport class AwsSecretsStore implements SecretsStore {\n\treadonly name = 'ssm';\n\n\tprivate client?: SSMClient;\n\n\tconstructor(private readonly options: AwsSecretsStoreOptions) {}\n\n\tprivate async ssm(): Promise<SSMClient> {\n\t\tif (this.client) return this.client;\n\n\t\tthis.client = new SSMClient(await awsClientConfig(this.options));\n\t\treturn this.client;\n\t}\n\n\t/** Where a call for `stage` is, for an error saying it has no credentials. */\n\tprivate context(stage: string, access: 'read' | 'write') {\n\t\treturn { stage, store: this.name, profile: this.options.profile, access };\n\t}\n\n\t/**\n\t * @throws {StageSecretsUnreadable} when there are no AWS credentials to\n\t * read it with, or they have expired\n\t */\n\tasync read(stage: string): Promise<StageSecrets | null> {\n\t\tconst ssm = await this.ssm();\n\n\t\ttry {\n\t\t\tconst { Parameter } = await withStageCredentials(\n\t\t\t\tthis.context(stage, 'read'),\n\t\t\t\t() =>\n\t\t\t\t\tssm.send(\n\t\t\t\t\t\tnew GetParameterCommand({\n\t\t\t\t\t\t\tName: secretsParameterName(this.options.project, stage),\n\t\t\t\t\t\t\tWithDecryption: true,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t);\n\t\t\treturn Parameter?.Value\n\t\t\t\t? (JSON.parse(Parameter.Value) as StageSecrets)\n\t\t\t\t: null;\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterNotFound) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * @throws {StageSecretsUnreadable} when there are no AWS credentials to\n\t * write it with, or they have expired\n\t */\n\tasync write(stage: string, secrets: StageSecrets): Promise<void> {\n\t\tconst value = serializeWithin(\n\t\t\tstage,\n\t\t\tthis.name,\n\t\t\tsecrets,\n\t\t\tSSM_PARAMETER_LIMIT,\n\t\t);\n\t\tconst ssm = await this.ssm();\n\n\t\tawait withStageCredentials(this.context(stage, 'write'), () =>\n\t\t\tssm.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName: secretsParameterName(this.options.project, stage),\n\t\t\t\t\tValue: value,\n\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\t// Standard (free) under 4 KB, advanced past it; never the other way.\n\t\t\t\t\tTier: 'Intelligent-Tiering',\n\t\t\t\t\tOverwrite: true,\n\t\t\t\t\tDescription: `gkm secrets for ${this.options.project}/${stage}`,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,sBAAsB;;AAGnC,SAAgB,qBAAqB,SAAiB,OAAuB;CAC5E,OAAO,QAAQ,QAAQ,GAAG,MAAM;AACjC;AAEA,IAAa,kBAAb,MAAqD;CAKvB;CAJ7B,OAAgB;CAEhB;CAEA,YAAY,SAAkD;EAAjC,KAAA,UAAA;CAAkC;CAE/D,MAAc,MAA0B;EACvC,IAAI,KAAK,QAAQ,OAAO,KAAK;EAE7B,KAAK,SAAS,IAAI,UAAU,MAAM,gBAAgB,KAAK,OAAO,CAAC;EAC/D,OAAO,KAAK;CACb;;CAGA,QAAgB,OAAe,QAA0B;EACxD,OAAO;GAAE;GAAO,OAAO,KAAK;GAAM,SAAS,KAAK,QAAQ;GAAS;EAAO;CACzE;;;;;CAMA,MAAM,KAAK,OAA6C;EACvD,MAAM,MAAM,MAAM,KAAK,IAAI;EAE3B,IAAI;GACH,MAAM,EAAE,cAAc,MAAM,qBAC3B,KAAK,QAAQ,OAAO,MAAM,SAEzB,IAAI,KACH,IAAI,oBAAoB;IACvB,MAAM,qBAAqB,KAAK,QAAQ,SAAS,KAAK;IACtD,gBAAgB;GACjB,CAAC,CACF,CACF;GACA,OAAO,WAAW,QACd,KAAK,MAAM,UAAU,KAAK,IAC3B;EACJ,SAAS,OAAO;GACf,IAAI,iBAAiB,mBAAmB,OAAO;GAC/C,MAAM;EACP;CACD;;;;;CAMA,MAAM,MAAM,OAAe,SAAsC;EAChE,MAAM,QAAQ,gBACb,OACA,KAAK,MACL,SACA,mBACD;EACA,MAAM,MAAM,MAAM,KAAK,IAAI;EAE3B,MAAM,qBAAqB,KAAK,QAAQ,OAAO,OAAO,SACrD,IAAI,KACH,IAAI,oBAAoB;GACvB,MAAM,qBAAqB,KAAK,QAAQ,SAAS,KAAK;GACtD,OAAO;GACP,MAAM;GAEN,MAAM;GACN,WAAW;GACX,aAAa,mBAAmB,KAAK,QAAQ,QAAQ,GAAG;EACzD,CAAC,CACF,CACD;CACD;AACD"}
@@ -0,0 +1,136 @@
1
+ const require_errors = require("./errors-DMC4Umsb.cjs");
2
+ //#region src/secrets/awsStore.ts
3
+ /**
4
+ * What the two AWS secrets stores share: how a client finds its credentials,
5
+ * what it says when it has none, and how big a stage may be before AWS would
6
+ * refuse it.
7
+ */
8
+ /** The client config both stores build their SDK client from. */
9
+ async function awsClientConfig(options) {
10
+ const config = { region: options.region };
11
+ if (options.profile) {
12
+ const { fromIni } = await import("@aws-sdk/credential-providers");
13
+ config.credentials = fromIni({ profile: options.profile });
14
+ }
15
+ if (options.endpoint) config.endpoint = options.endpoint;
16
+ return config;
17
+ }
18
+ /**
19
+ * A stage's secrets, serialized, are larger than the store can hold: 8 KB for
20
+ * an SSM parameter (advanced tier), 64 KB for a Secrets Manager secret.
21
+ *
22
+ * Refused before AWS is called, so nothing half-written is left behind and
23
+ * the answer is not a bare `ValidationException`.
24
+ */
25
+ var StageSecretsTooLarge = class extends require_errors.GkmError {
26
+ stage;
27
+ store;
28
+ bytes;
29
+ limit;
30
+ constructor(stage, store, bytes, limit) {
31
+ super(`The secrets for stage "${stage}" are ${bytes} bytes, more than the ${limit} bytes ${store} holds in one ${store === "ssm" ? "parameter" : "secret"}. ` + (store === "ssm" ? `Keep them in Secrets Manager instead, which holds up to 64 KB: set secrets.store to { provider: 'secrets-manager', region } in gkm.config.ts, then move the stage with gkm secrets:migrate --stage ${stage} --from ssm.` : "Remove credentials the stage no longer uses, or keep the largest ones somewhere they are fetched from at runtime."));
32
+ this.stage = stage;
33
+ this.store = store;
34
+ this.bytes = bytes;
35
+ this.limit = limit;
36
+ this.name = "StageSecretsTooLarge";
37
+ }
38
+ };
39
+ /** The stage serialized, refused if it is larger than `limit` bytes. */
40
+ function serializeWithin(stage, store, value, limit) {
41
+ const serialized = JSON.stringify(value);
42
+ const bytes = Buffer.byteLength(serialized, "utf8");
43
+ if (bytes > limit) throw new StageSecretsTooLarge(stage, store, bytes, limit);
44
+ return serialized;
45
+ }
46
+ /** Where each AWS store keeps a stage's secrets, as a person reads it. */
47
+ const AWS_STORES = {
48
+ ssm: "SSM Parameter Store",
49
+ "secrets-manager": "Secrets Manager"
50
+ };
51
+ /**
52
+ * A deployed stage's secrets are kept in its AWS account, and no AWS
53
+ * credentials were found to reach them with — or the ones found have expired.
54
+ *
55
+ * Raised by the AWS stores themselves, on a read or a write, so every command
56
+ * that touches a stage's secrets says it the same way.
57
+ */
58
+ var StageSecretsUnreadable = class extends require_errors.GkmError {
59
+ stage;
60
+ store;
61
+ profile;
62
+ access;
63
+ reason;
64
+ constructor(input, cause) {
65
+ const { stage, store, profile } = input;
66
+ const access = input.access ?? "read";
67
+ const reason = input.reason ?? "no-credentials";
68
+ const where = AWS_STORES[store] ?? `the '${store}' store`;
69
+ const named = "--profile <profile> where the command takes it, or AWS_PROFILE=<profile>";
70
+ const lacking = reason === "expired" ? profile ? `the AWS profile '${profile}' signed in, but its session has expired. ` : "the AWS credentials found have expired. " : profile ? `the AWS profile '${profile}' has no credentials to ${access} them with. ` : `no AWS credentials were found to ${access} them with. `;
71
+ const fix = profile ? `Sign in to it (aws sso login --profile ${profile}) or name another: ${named}.` : reason === "expired" ? `Export fresh ones, or name the account's profile: ${named}.` : `Name the account's profile: ${named}.`;
72
+ super(`The '${stage}' stage's secrets are kept in ${where}, in the stage's AWS account, and ` + lacking + fix, cause === void 0 ? void 0 : { cause });
73
+ this.name = "StageSecretsUnreadable";
74
+ this.stage = stage;
75
+ this.store = store;
76
+ this.profile = profile;
77
+ this.access = access;
78
+ this.reason = reason;
79
+ }
80
+ };
81
+ /**
82
+ * Why an AWS call failed for want of credentials, by the SDK's error name —
83
+ * its message being free to change — or undefined when it failed for any
84
+ * other reason.
85
+ *
86
+ * - `CredentialsProviderError`: the credential chain found nothing, or a
87
+ * profile's SSO session is missing or expired (the SSO provider wraps its
88
+ * token errors in this one).
89
+ * - `TokenProviderError`: an SSO token, should one reach here unwrapped.
90
+ * - `ExpiredTokenException`/`ExpiredToken`: credentials were found, and AWS
91
+ * refused them as expired.
92
+ */
93
+ function credentialsFailure(error) {
94
+ const name = error?.name;
95
+ if (name === "CredentialsProviderError" || name === "TokenProviderError") return "no-credentials";
96
+ if (name === "ExpiredTokenException" || name === "ExpiredToken") return "expired";
97
+ }
98
+ /**
99
+ * Run one AWS call of a store, refusing a failure for want of credentials
100
+ * with {@link StageSecretsUnreadable}. Any other failure is the store's own,
101
+ * and passes through.
102
+ */
103
+ async function withStageCredentials(context, call) {
104
+ try {
105
+ return await call();
106
+ } catch (error) {
107
+ const reason = credentialsFailure(error);
108
+ if (reason === void 0) throw error;
109
+ throw new StageSecretsUnreadable({
110
+ ...context,
111
+ profile: context.profile ?? (process.env.AWS_PROFILE || void 0),
112
+ reason
113
+ }, error);
114
+ }
115
+ }
116
+ //#endregion
117
+ Object.defineProperty(exports, "awsClientConfig", {
118
+ enumerable: true,
119
+ get: function() {
120
+ return awsClientConfig;
121
+ }
122
+ });
123
+ Object.defineProperty(exports, "serializeWithin", {
124
+ enumerable: true,
125
+ get: function() {
126
+ return serializeWithin;
127
+ }
128
+ });
129
+ Object.defineProperty(exports, "withStageCredentials", {
130
+ enumerable: true,
131
+ get: function() {
132
+ return withStageCredentials;
133
+ }
134
+ });
135
+
136
+ //# sourceMappingURL=awsStore-B5We7bMg.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"awsStore-B5We7bMg.cjs","names":["GkmError"],"sources":["../src/secrets/awsStore.ts"],"sourcesContent":["/**\n * What the two AWS secrets stores share: how a client finds its credentials,\n * what it says when it has none, and how big a stage may be before AWS would\n * refuse it.\n */\n\nimport { GkmError } from '../errors';\n\nexport interface AwsStoreOptions {\n\t/** The workspace name, which scopes where the stage is kept. */\n\tproject: string;\n\tregion: string;\n\t/**\n\t * A named AWS profile, resolved with `fromIni` only. The default chain\n\t * reads AWS_* from the environment first, so exported staging keys would\n\t * win over `--profile prod` and put production's secrets in staging.\n\t */\n\tprofile?: string;\n\t/** For tests: an endpoint such as the AWS emulator. */\n\tendpoint?: string;\n}\n\n/** The client config both stores build their SDK client from. */\nexport async function awsClientConfig(options: AwsStoreOptions): Promise<{\n\tregion: string;\n\tendpoint?: string;\n\tcredentials?: ReturnType<\n\t\ttypeof import('@aws-sdk/credential-providers').fromIni\n\t>;\n}> {\n\tconst config: Awaited<ReturnType<typeof awsClientConfig>> = {\n\t\tregion: options.region,\n\t};\n\tif (options.profile) {\n\t\tconst { fromIni } = await import('@aws-sdk/credential-providers');\n\t\tconfig.credentials = fromIni({ profile: options.profile });\n\t}\n\tif (options.endpoint) {\n\t\tconfig.endpoint = options.endpoint;\n\t}\n\treturn config;\n}\n\n/**\n * A stage's secrets, serialized, are larger than the store can hold: 8 KB for\n * an SSM parameter (advanced tier), 64 KB for a Secrets Manager secret.\n *\n * Refused before AWS is called, so nothing half-written is left behind and\n * the answer is not a bare `ValidationException`.\n */\nexport class StageSecretsTooLarge extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly store: string,\n\t\treadonly bytes: number,\n\t\treadonly limit: number,\n\t) {\n\t\tsuper(\n\t\t\t`The secrets for stage \"${stage}\" are ${bytes} bytes, more than the ${limit} bytes ${store} holds in one ${store === 'ssm' ? 'parameter' : 'secret'}. ` +\n\t\t\t\t(store === 'ssm'\n\t\t\t\t\t? `Keep them in Secrets Manager instead, which holds up to 64 KB: set secrets.store to { provider: 'secrets-manager', region } in gkm.config.ts, then move the stage with gkm secrets:migrate --stage ${stage} --from ssm.`\n\t\t\t\t\t: 'Remove credentials the stage no longer uses, or keep the largest ones somewhere they are fetched from at runtime.'),\n\t\t);\n\t\tthis.name = 'StageSecretsTooLarge';\n\t}\n}\n\n/** The stage serialized, refused if it is larger than `limit` bytes. */\nexport function serializeWithin(\n\tstage: string,\n\tstore: string,\n\tvalue: unknown,\n\tlimit: number,\n): string {\n\tconst serialized = JSON.stringify(value);\n\tconst bytes = Buffer.byteLength(serialized, 'utf8');\n\tif (bytes > limit) {\n\t\tthrow new StageSecretsTooLarge(stage, store, bytes, limit);\n\t}\n\treturn serialized;\n}\n\n/** Where each AWS store keeps a stage's secrets, as a person reads it. */\nconst AWS_STORES: Record<string, string> = {\n\tssm: 'SSM Parameter Store',\n\t'secrets-manager': 'Secrets Manager',\n};\n\n/** Why the stage's account could not be reached. */\nexport type StageSecretsUnreadableReason = 'no-credentials' | 'expired';\n\nexport interface StageSecretsUnreadableInput {\n\tstage: string;\n\t/** The store's name: `ssm`, `secrets-manager`. */\n\tstore: string;\n\t/** The AWS profile the credentials were looked up with, where one was. */\n\tprofile?: string;\n\t/** Whether the stage was being read or written. */\n\taccess?: 'read' | 'write';\n\treason?: StageSecretsUnreadableReason;\n}\n\n/**\n * A deployed stage's secrets are kept in its AWS account, and no AWS\n * credentials were found to reach them with — or the ones found have expired.\n *\n * Raised by the AWS stores themselves, on a read or a write, so every command\n * that touches a stage's secrets says it the same way.\n */\nexport class StageSecretsUnreadable extends GkmError {\n\treadonly stage: string;\n\treadonly store: string;\n\treadonly profile: string | undefined;\n\treadonly access: 'read' | 'write';\n\treadonly reason: StageSecretsUnreadableReason;\n\n\tconstructor(input: StageSecretsUnreadableInput, cause?: unknown) {\n\t\tconst { stage, store, profile } = input;\n\t\tconst access = input.access ?? 'read';\n\t\tconst reason = input.reason ?? 'no-credentials';\n\t\tconst where = AWS_STORES[store] ?? `the '${store}' store`;\n\t\t// How to name the account: the command's --profile, where it takes\n\t\t// one, or the SDK's own variable.\n\t\tconst named =\n\t\t\t'--profile <profile> where the command takes it, or AWS_PROFILE=<profile>';\n\t\tconst lacking =\n\t\t\treason === 'expired'\n\t\t\t\t? profile\n\t\t\t\t\t? `the AWS profile '${profile}' signed in, but its session has expired. `\n\t\t\t\t\t: 'the AWS credentials found have expired. '\n\t\t\t\t: profile\n\t\t\t\t\t? `the AWS profile '${profile}' has no credentials to ${access} them with. `\n\t\t\t\t\t: `no AWS credentials were found to ${access} them with. `;\n\t\tconst fix = profile\n\t\t\t? `Sign in to it (aws sso login --profile ${profile}) or name another: ${named}.`\n\t\t\t: reason === 'expired'\n\t\t\t\t? `Export fresh ones, or name the account's profile: ${named}.`\n\t\t\t\t: `Name the account's profile: ${named}.`;\n\t\tsuper(\n\t\t\t`The '${stage}' stage's secrets are kept in ${where}, in the stage's AWS account, and ` +\n\t\t\t\tlacking +\n\t\t\t\tfix,\n\t\t\tcause === undefined ? undefined : { cause },\n\t\t);\n\t\tthis.name = 'StageSecretsUnreadable';\n\t\tthis.stage = stage;\n\t\tthis.store = store;\n\t\tthis.profile = profile;\n\t\tthis.access = access;\n\t\tthis.reason = reason;\n\t}\n}\n\n/**\n * Why an AWS call failed for want of credentials, by the SDK's error name —\n * its message being free to change — or undefined when it failed for any\n * other reason.\n *\n * - `CredentialsProviderError`: the credential chain found nothing, or a\n * profile's SSO session is missing or expired (the SSO provider wraps its\n * token errors in this one).\n * - `TokenProviderError`: an SSO token, should one reach here unwrapped.\n * - `ExpiredTokenException`/`ExpiredToken`: credentials were found, and AWS\n * refused them as expired.\n */\nexport function credentialsFailure(\n\terror: unknown,\n): StageSecretsUnreadableReason | undefined {\n\tconst name = (error as Error | undefined)?.name;\n\tif (name === 'CredentialsProviderError' || name === 'TokenProviderError') {\n\t\treturn 'no-credentials';\n\t}\n\tif (name === 'ExpiredTokenException' || name === 'ExpiredToken') {\n\t\treturn 'expired';\n\t}\n\treturn undefined;\n}\n\n/**\n * Run one AWS call of a store, refusing a failure for want of credentials\n * with {@link StageSecretsUnreadable}. Any other failure is the store's own,\n * and passes through.\n */\nexport async function withStageCredentials<T>(\n\tcontext: {\n\t\tstage: string;\n\t\tstore: string;\n\t\tprofile: string | undefined;\n\t\taccess: 'read' | 'write';\n\t},\n\tcall: () => Promise<T>,\n): Promise<T> {\n\ttry {\n\t\treturn await call();\n\t} catch (error) {\n\t\tconst reason = credentialsFailure(error);\n\t\tif (reason === undefined) throw error;\n\t\tthrow new StageSecretsUnreadable(\n\t\t\t{\n\t\t\t\t...context,\n\t\t\t\t// The profile the SDK's default chain read, when none was named.\n\t\t\t\tprofile: context.profile ?? (process.env.AWS_PROFILE || undefined),\n\t\t\t\treason,\n\t\t\t},\n\t\t\terror,\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;;AAuBA,eAAsB,gBAAgB,SAMnC;CACF,MAAM,SAAsD,EAC3D,QAAQ,QAAQ,OACjB;CACA,IAAI,QAAQ,SAAS;EACpB,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,OAAO,cAAc,QAAQ,EAAE,SAAS,QAAQ,QAAQ,CAAC;CAC1D;CACA,IAAI,QAAQ,UACX,OAAO,WAAW,QAAQ;CAE3B,OAAO;AACR;;;;;;;;AASA,IAAa,uBAAb,cAA0CA,eAAAA,SAAS;CAExC;CACA;CACA;CACA;CAJV,YACC,OACA,OACA,OACA,OACC;EACD,MACC,0BAA0B,MAAM,QAAQ,MAAM,wBAAwB,MAAM,SAAS,MAAM,gBAAgB,UAAU,QAAQ,cAAc,SAAS,OAClJ,UAAU,QACR,sMAAsM,MAAM,gBAC5M,oHACL;EAVS,KAAA,QAAA;EACA,KAAA,QAAA;EACA,KAAA,QAAA;EACA,KAAA,QAAA;EAQT,KAAK,OAAO;CACb;AACD;;AAGA,SAAgB,gBACf,OACA,OACA,OACA,OACS;CACT,MAAM,aAAa,KAAK,UAAU,KAAK;CACvC,MAAM,QAAQ,OAAO,WAAW,YAAY,MAAM;CAClD,IAAI,QAAQ,OACX,MAAM,IAAI,qBAAqB,OAAO,OAAO,OAAO,KAAK;CAE1D,OAAO;AACR;;AAGA,MAAM,aAAqC;CAC1C,KAAK;CACL,mBAAmB;AACpB;;;;;;;;AAuBA,IAAa,yBAAb,cAA4CA,eAAAA,SAAS;CACpD;CACA;CACA;CACA;CACA;CAEA,YAAY,OAAoC,OAAiB;EAChE,MAAM,EAAE,OAAO,OAAO,YAAY;EAClC,MAAM,SAAS,MAAM,UAAU;EAC/B,MAAM,SAAS,MAAM,UAAU;EAC/B,MAAM,QAAQ,WAAW,UAAU,QAAQ,MAAM;EAGjD,MAAM,QACL;EACD,MAAM,UACL,WAAW,YACR,UACC,oBAAoB,QAAQ,8CAC5B,6CACD,UACC,oBAAoB,QAAQ,0BAA0B,OAAO,gBAC7D,oCAAoC,OAAO;EAChD,MAAM,MAAM,UACT,0CAA0C,QAAQ,qBAAqB,MAAM,KAC7E,WAAW,YACV,qDAAqD,MAAM,KAC3D,+BAA+B,MAAM;EACzC,MACC,QAAQ,MAAM,gCAAgC,MAAM,sCACnD,UACA,KACD,UAAU,KAAA,IAAY,KAAA,IAAY,EAAE,MAAM,CAC3C;EACA,KAAK,OAAO;EACZ,KAAK,QAAQ;EACb,KAAK,QAAQ;EACb,KAAK,UAAU;EACf,KAAK,SAAS;EACd,KAAK,SAAS;CACf;AACD;;;;;;;;;;;;;AAcA,SAAgB,mBACf,OAC2C;CAC3C,MAAM,OAAQ,OAA6B;CAC3C,IAAI,SAAS,8BAA8B,SAAS,sBACnD,OAAO;CAER,IAAI,SAAS,2BAA2B,SAAS,gBAChD,OAAO;AAGT;;;;;;AAOA,eAAsB,qBACrB,SAMA,MACa;CACb,IAAI;EACH,OAAO,MAAM,KAAK;CACnB,SAAS,OAAO;EACf,MAAM,SAAS,mBAAmB,KAAK;EACvC,IAAI,WAAW,KAAA,GAAW,MAAM;EAChC,MAAM,IAAI,uBACT;GACC,GAAG;GAEH,SAAS,QAAQ,YAAY,QAAQ,IAAI,eAAe,KAAA;GACxD;EACD,GACA,KACD;CACD;AACD"}
@@ -0,0 +1,119 @@
1
+ import { t as GkmError } from "./errors-D8Gwp5kU.mjs";
2
+ //#region src/secrets/awsStore.ts
3
+ /**
4
+ * What the two AWS secrets stores share: how a client finds its credentials,
5
+ * what it says when it has none, and how big a stage may be before AWS would
6
+ * refuse it.
7
+ */
8
+ /** The client config both stores build their SDK client from. */
9
+ async function awsClientConfig(options) {
10
+ const config = { region: options.region };
11
+ if (options.profile) {
12
+ const { fromIni } = await import("@aws-sdk/credential-providers");
13
+ config.credentials = fromIni({ profile: options.profile });
14
+ }
15
+ if (options.endpoint) config.endpoint = options.endpoint;
16
+ return config;
17
+ }
18
+ /**
19
+ * A stage's secrets, serialized, are larger than the store can hold: 8 KB for
20
+ * an SSM parameter (advanced tier), 64 KB for a Secrets Manager secret.
21
+ *
22
+ * Refused before AWS is called, so nothing half-written is left behind and
23
+ * the answer is not a bare `ValidationException`.
24
+ */
25
+ var StageSecretsTooLarge = class extends GkmError {
26
+ stage;
27
+ store;
28
+ bytes;
29
+ limit;
30
+ constructor(stage, store, bytes, limit) {
31
+ super(`The secrets for stage "${stage}" are ${bytes} bytes, more than the ${limit} bytes ${store} holds in one ${store === "ssm" ? "parameter" : "secret"}. ` + (store === "ssm" ? `Keep them in Secrets Manager instead, which holds up to 64 KB: set secrets.store to { provider: 'secrets-manager', region } in gkm.config.ts, then move the stage with gkm secrets:migrate --stage ${stage} --from ssm.` : "Remove credentials the stage no longer uses, or keep the largest ones somewhere they are fetched from at runtime."));
32
+ this.stage = stage;
33
+ this.store = store;
34
+ this.bytes = bytes;
35
+ this.limit = limit;
36
+ this.name = "StageSecretsTooLarge";
37
+ }
38
+ };
39
+ /** The stage serialized, refused if it is larger than `limit` bytes. */
40
+ function serializeWithin(stage, store, value, limit) {
41
+ const serialized = JSON.stringify(value);
42
+ const bytes = Buffer.byteLength(serialized, "utf8");
43
+ if (bytes > limit) throw new StageSecretsTooLarge(stage, store, bytes, limit);
44
+ return serialized;
45
+ }
46
+ /** Where each AWS store keeps a stage's secrets, as a person reads it. */
47
+ const AWS_STORES = {
48
+ ssm: "SSM Parameter Store",
49
+ "secrets-manager": "Secrets Manager"
50
+ };
51
+ /**
52
+ * A deployed stage's secrets are kept in its AWS account, and no AWS
53
+ * credentials were found to reach them with — or the ones found have expired.
54
+ *
55
+ * Raised by the AWS stores themselves, on a read or a write, so every command
56
+ * that touches a stage's secrets says it the same way.
57
+ */
58
+ var StageSecretsUnreadable = class extends GkmError {
59
+ stage;
60
+ store;
61
+ profile;
62
+ access;
63
+ reason;
64
+ constructor(input, cause) {
65
+ const { stage, store, profile } = input;
66
+ const access = input.access ?? "read";
67
+ const reason = input.reason ?? "no-credentials";
68
+ const where = AWS_STORES[store] ?? `the '${store}' store`;
69
+ const named = "--profile <profile> where the command takes it, or AWS_PROFILE=<profile>";
70
+ const lacking = reason === "expired" ? profile ? `the AWS profile '${profile}' signed in, but its session has expired. ` : "the AWS credentials found have expired. " : profile ? `the AWS profile '${profile}' has no credentials to ${access} them with. ` : `no AWS credentials were found to ${access} them with. `;
71
+ const fix = profile ? `Sign in to it (aws sso login --profile ${profile}) or name another: ${named}.` : reason === "expired" ? `Export fresh ones, or name the account's profile: ${named}.` : `Name the account's profile: ${named}.`;
72
+ super(`The '${stage}' stage's secrets are kept in ${where}, in the stage's AWS account, and ` + lacking + fix, cause === void 0 ? void 0 : { cause });
73
+ this.name = "StageSecretsUnreadable";
74
+ this.stage = stage;
75
+ this.store = store;
76
+ this.profile = profile;
77
+ this.access = access;
78
+ this.reason = reason;
79
+ }
80
+ };
81
+ /**
82
+ * Why an AWS call failed for want of credentials, by the SDK's error name —
83
+ * its message being free to change — or undefined when it failed for any
84
+ * other reason.
85
+ *
86
+ * - `CredentialsProviderError`: the credential chain found nothing, or a
87
+ * profile's SSO session is missing or expired (the SSO provider wraps its
88
+ * token errors in this one).
89
+ * - `TokenProviderError`: an SSO token, should one reach here unwrapped.
90
+ * - `ExpiredTokenException`/`ExpiredToken`: credentials were found, and AWS
91
+ * refused them as expired.
92
+ */
93
+ function credentialsFailure(error) {
94
+ const name = error?.name;
95
+ if (name === "CredentialsProviderError" || name === "TokenProviderError") return "no-credentials";
96
+ if (name === "ExpiredTokenException" || name === "ExpiredToken") return "expired";
97
+ }
98
+ /**
99
+ * Run one AWS call of a store, refusing a failure for want of credentials
100
+ * with {@link StageSecretsUnreadable}. Any other failure is the store's own,
101
+ * and passes through.
102
+ */
103
+ async function withStageCredentials(context, call) {
104
+ try {
105
+ return await call();
106
+ } catch (error) {
107
+ const reason = credentialsFailure(error);
108
+ if (reason === void 0) throw error;
109
+ throw new StageSecretsUnreadable({
110
+ ...context,
111
+ profile: context.profile ?? (process.env.AWS_PROFILE || void 0),
112
+ reason
113
+ }, error);
114
+ }
115
+ }
116
+ //#endregion
117
+ export { serializeWithin as n, withStageCredentials as r, awsClientConfig as t };
118
+
119
+ //# sourceMappingURL=awsStore-BWa1KNY-.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"awsStore-BWa1KNY-.mjs","names":[],"sources":["../src/secrets/awsStore.ts"],"sourcesContent":["/**\n * What the two AWS secrets stores share: how a client finds its credentials,\n * what it says when it has none, and how big a stage may be before AWS would\n * refuse it.\n */\n\nimport { GkmError } from '../errors';\n\nexport interface AwsStoreOptions {\n\t/** The workspace name, which scopes where the stage is kept. */\n\tproject: string;\n\tregion: string;\n\t/**\n\t * A named AWS profile, resolved with `fromIni` only. The default chain\n\t * reads AWS_* from the environment first, so exported staging keys would\n\t * win over `--profile prod` and put production's secrets in staging.\n\t */\n\tprofile?: string;\n\t/** For tests: an endpoint such as the AWS emulator. */\n\tendpoint?: string;\n}\n\n/** The client config both stores build their SDK client from. */\nexport async function awsClientConfig(options: AwsStoreOptions): Promise<{\n\tregion: string;\n\tendpoint?: string;\n\tcredentials?: ReturnType<\n\t\ttypeof import('@aws-sdk/credential-providers').fromIni\n\t>;\n}> {\n\tconst config: Awaited<ReturnType<typeof awsClientConfig>> = {\n\t\tregion: options.region,\n\t};\n\tif (options.profile) {\n\t\tconst { fromIni } = await import('@aws-sdk/credential-providers');\n\t\tconfig.credentials = fromIni({ profile: options.profile });\n\t}\n\tif (options.endpoint) {\n\t\tconfig.endpoint = options.endpoint;\n\t}\n\treturn config;\n}\n\n/**\n * A stage's secrets, serialized, are larger than the store can hold: 8 KB for\n * an SSM parameter (advanced tier), 64 KB for a Secrets Manager secret.\n *\n * Refused before AWS is called, so nothing half-written is left behind and\n * the answer is not a bare `ValidationException`.\n */\nexport class StageSecretsTooLarge extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly store: string,\n\t\treadonly bytes: number,\n\t\treadonly limit: number,\n\t) {\n\t\tsuper(\n\t\t\t`The secrets for stage \"${stage}\" are ${bytes} bytes, more than the ${limit} bytes ${store} holds in one ${store === 'ssm' ? 'parameter' : 'secret'}. ` +\n\t\t\t\t(store === 'ssm'\n\t\t\t\t\t? `Keep them in Secrets Manager instead, which holds up to 64 KB: set secrets.store to { provider: 'secrets-manager', region } in gkm.config.ts, then move the stage with gkm secrets:migrate --stage ${stage} --from ssm.`\n\t\t\t\t\t: 'Remove credentials the stage no longer uses, or keep the largest ones somewhere they are fetched from at runtime.'),\n\t\t);\n\t\tthis.name = 'StageSecretsTooLarge';\n\t}\n}\n\n/** The stage serialized, refused if it is larger than `limit` bytes. */\nexport function serializeWithin(\n\tstage: string,\n\tstore: string,\n\tvalue: unknown,\n\tlimit: number,\n): string {\n\tconst serialized = JSON.stringify(value);\n\tconst bytes = Buffer.byteLength(serialized, 'utf8');\n\tif (bytes > limit) {\n\t\tthrow new StageSecretsTooLarge(stage, store, bytes, limit);\n\t}\n\treturn serialized;\n}\n\n/** Where each AWS store keeps a stage's secrets, as a person reads it. */\nconst AWS_STORES: Record<string, string> = {\n\tssm: 'SSM Parameter Store',\n\t'secrets-manager': 'Secrets Manager',\n};\n\n/** Why the stage's account could not be reached. */\nexport type StageSecretsUnreadableReason = 'no-credentials' | 'expired';\n\nexport interface StageSecretsUnreadableInput {\n\tstage: string;\n\t/** The store's name: `ssm`, `secrets-manager`. */\n\tstore: string;\n\t/** The AWS profile the credentials were looked up with, where one was. */\n\tprofile?: string;\n\t/** Whether the stage was being read or written. */\n\taccess?: 'read' | 'write';\n\treason?: StageSecretsUnreadableReason;\n}\n\n/**\n * A deployed stage's secrets are kept in its AWS account, and no AWS\n * credentials were found to reach them with — or the ones found have expired.\n *\n * Raised by the AWS stores themselves, on a read or a write, so every command\n * that touches a stage's secrets says it the same way.\n */\nexport class StageSecretsUnreadable extends GkmError {\n\treadonly stage: string;\n\treadonly store: string;\n\treadonly profile: string | undefined;\n\treadonly access: 'read' | 'write';\n\treadonly reason: StageSecretsUnreadableReason;\n\n\tconstructor(input: StageSecretsUnreadableInput, cause?: unknown) {\n\t\tconst { stage, store, profile } = input;\n\t\tconst access = input.access ?? 'read';\n\t\tconst reason = input.reason ?? 'no-credentials';\n\t\tconst where = AWS_STORES[store] ?? `the '${store}' store`;\n\t\t// How to name the account: the command's --profile, where it takes\n\t\t// one, or the SDK's own variable.\n\t\tconst named =\n\t\t\t'--profile <profile> where the command takes it, or AWS_PROFILE=<profile>';\n\t\tconst lacking =\n\t\t\treason === 'expired'\n\t\t\t\t? profile\n\t\t\t\t\t? `the AWS profile '${profile}' signed in, but its session has expired. `\n\t\t\t\t\t: 'the AWS credentials found have expired. '\n\t\t\t\t: profile\n\t\t\t\t\t? `the AWS profile '${profile}' has no credentials to ${access} them with. `\n\t\t\t\t\t: `no AWS credentials were found to ${access} them with. `;\n\t\tconst fix = profile\n\t\t\t? `Sign in to it (aws sso login --profile ${profile}) or name another: ${named}.`\n\t\t\t: reason === 'expired'\n\t\t\t\t? `Export fresh ones, or name the account's profile: ${named}.`\n\t\t\t\t: `Name the account's profile: ${named}.`;\n\t\tsuper(\n\t\t\t`The '${stage}' stage's secrets are kept in ${where}, in the stage's AWS account, and ` +\n\t\t\t\tlacking +\n\t\t\t\tfix,\n\t\t\tcause === undefined ? undefined : { cause },\n\t\t);\n\t\tthis.name = 'StageSecretsUnreadable';\n\t\tthis.stage = stage;\n\t\tthis.store = store;\n\t\tthis.profile = profile;\n\t\tthis.access = access;\n\t\tthis.reason = reason;\n\t}\n}\n\n/**\n * Why an AWS call failed for want of credentials, by the SDK's error name —\n * its message being free to change — or undefined when it failed for any\n * other reason.\n *\n * - `CredentialsProviderError`: the credential chain found nothing, or a\n * profile's SSO session is missing or expired (the SSO provider wraps its\n * token errors in this one).\n * - `TokenProviderError`: an SSO token, should one reach here unwrapped.\n * - `ExpiredTokenException`/`ExpiredToken`: credentials were found, and AWS\n * refused them as expired.\n */\nexport function credentialsFailure(\n\terror: unknown,\n): StageSecretsUnreadableReason | undefined {\n\tconst name = (error as Error | undefined)?.name;\n\tif (name === 'CredentialsProviderError' || name === 'TokenProviderError') {\n\t\treturn 'no-credentials';\n\t}\n\tif (name === 'ExpiredTokenException' || name === 'ExpiredToken') {\n\t\treturn 'expired';\n\t}\n\treturn undefined;\n}\n\n/**\n * Run one AWS call of a store, refusing a failure for want of credentials\n * with {@link StageSecretsUnreadable}. Any other failure is the store's own,\n * and passes through.\n */\nexport async function withStageCredentials<T>(\n\tcontext: {\n\t\tstage: string;\n\t\tstore: string;\n\t\tprofile: string | undefined;\n\t\taccess: 'read' | 'write';\n\t},\n\tcall: () => Promise<T>,\n): Promise<T> {\n\ttry {\n\t\treturn await call();\n\t} catch (error) {\n\t\tconst reason = credentialsFailure(error);\n\t\tif (reason === undefined) throw error;\n\t\tthrow new StageSecretsUnreadable(\n\t\t\t{\n\t\t\t\t...context,\n\t\t\t\t// The profile the SDK's default chain read, when none was named.\n\t\t\t\tprofile: context.profile ?? (process.env.AWS_PROFILE || undefined),\n\t\t\t\treason,\n\t\t\t},\n\t\t\terror,\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;;AAuBA,eAAsB,gBAAgB,SAMnC;CACF,MAAM,SAAsD,EAC3D,QAAQ,QAAQ,OACjB;CACA,IAAI,QAAQ,SAAS;EACpB,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,OAAO,cAAc,QAAQ,EAAE,SAAS,QAAQ,QAAQ,CAAC;CAC1D;CACA,IAAI,QAAQ,UACX,OAAO,WAAW,QAAQ;CAE3B,OAAO;AACR;;;;;;;;AASA,IAAa,uBAAb,cAA0C,SAAS;CAExC;CACA;CACA;CACA;CAJV,YACC,OACA,OACA,OACA,OACC;EACD,MACC,0BAA0B,MAAM,QAAQ,MAAM,wBAAwB,MAAM,SAAS,MAAM,gBAAgB,UAAU,QAAQ,cAAc,SAAS,OAClJ,UAAU,QACR,sMAAsM,MAAM,gBAC5M,oHACL;EAVS,KAAA,QAAA;EACA,KAAA,QAAA;EACA,KAAA,QAAA;EACA,KAAA,QAAA;EAQT,KAAK,OAAO;CACb;AACD;;AAGA,SAAgB,gBACf,OACA,OACA,OACA,OACS;CACT,MAAM,aAAa,KAAK,UAAU,KAAK;CACvC,MAAM,QAAQ,OAAO,WAAW,YAAY,MAAM;CAClD,IAAI,QAAQ,OACX,MAAM,IAAI,qBAAqB,OAAO,OAAO,OAAO,KAAK;CAE1D,OAAO;AACR;;AAGA,MAAM,aAAqC;CAC1C,KAAK;CACL,mBAAmB;AACpB;;;;;;;;AAuBA,IAAa,yBAAb,cAA4C,SAAS;CACpD;CACA;CACA;CACA;CACA;CAEA,YAAY,OAAoC,OAAiB;EAChE,MAAM,EAAE,OAAO,OAAO,YAAY;EAClC,MAAM,SAAS,MAAM,UAAU;EAC/B,MAAM,SAAS,MAAM,UAAU;EAC/B,MAAM,QAAQ,WAAW,UAAU,QAAQ,MAAM;EAGjD,MAAM,QACL;EACD,MAAM,UACL,WAAW,YACR,UACC,oBAAoB,QAAQ,8CAC5B,6CACD,UACC,oBAAoB,QAAQ,0BAA0B,OAAO,gBAC7D,oCAAoC,OAAO;EAChD,MAAM,MAAM,UACT,0CAA0C,QAAQ,qBAAqB,MAAM,KAC7E,WAAW,YACV,qDAAqD,MAAM,KAC3D,+BAA+B,MAAM;EACzC,MACC,QAAQ,MAAM,gCAAgC,MAAM,sCACnD,UACA,KACD,UAAU,KAAA,IAAY,KAAA,IAAY,EAAE,MAAM,CAC3C;EACA,KAAK,OAAO;EACZ,KAAK,QAAQ;EACb,KAAK,QAAQ;EACb,KAAK,UAAU;EACf,KAAK,SAAS;EACd,KAAK,SAAS;CACf;AACD;;;;;;;;;;;;;AAcA,SAAgB,mBACf,OAC2C;CAC3C,MAAM,OAAQ,OAA6B;CAC3C,IAAI,SAAS,8BAA8B,SAAS,sBACnD,OAAO;CAER,IAAI,SAAS,2BAA2B,SAAS,gBAChD,OAAO;AAGT;;;;;;AAOA,eAAsB,qBACrB,SAMA,MACa;CACb,IAAI;EACH,OAAO,MAAM,KAAK;CACnB,SAAS,OAAO;EACf,MAAM,SAAS,mBAAmB,KAAK;EACvC,IAAI,WAAW,KAAA,GAAW,MAAM;EAChC,MAAM,IAAI,uBACT;GACC,GAAG;GAEH,SAAS,QAAQ,YAAY,QAAQ,IAAI,eAAe,KAAA;GACxD;EACD,GACA,KACD;CACD;AACD"}