@mtndev/cli 1.1.0 → 2.0.1

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 (260) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/cjs/__chunks/VH7oDXx4.cjs +28 -0
  3. package/cjs/commands/aws/ec2/allow-ip/handler.cjs +261 -0
  4. package/cjs/commands/aws/ec2/allow-ip/handler.d.ts +6 -0
  5. package/cjs/commands/aws/ec2/allow-ip/index.cjs +25 -0
  6. package/cjs/commands/aws/ec2/allow-ip/index.d.ts +3 -0
  7. package/cjs/commands/aws/ec2/allow-ip/schema.cjs +33 -0
  8. package/cjs/commands/aws/ec2/allow-ip/schema.d.ts +33 -0
  9. package/cjs/commands/aws/ec2/allow-ip/utils.cjs +379 -0
  10. package/cjs/commands/aws/ec2/allow-ip/utils.d.ts +189 -0
  11. package/cjs/commands/aws/iam/admin-group.cjs +111 -0
  12. package/cjs/commands/aws/iam/admin-group.d.ts +55 -0
  13. package/cjs/commands/aws/iam/break-glass/handler.cjs +127 -0
  14. package/cjs/commands/aws/iam/break-glass/handler.d.ts +7 -0
  15. package/cjs/commands/aws/iam/break-glass/index.cjs +7 -0
  16. package/cjs/commands/aws/iam/break-glass/index.d.ts +2 -0
  17. package/cjs/commands/aws/iam/break-glass/schema.cjs +21 -0
  18. package/cjs/commands/aws/iam/break-glass/schema.d.ts +25 -0
  19. package/cjs/commands/aws/iam/check-admin/handler.cjs +89 -0
  20. package/cjs/commands/aws/iam/check-admin/handler.d.ts +5 -0
  21. package/cjs/commands/aws/iam/check-admin/index.cjs +7 -0
  22. package/cjs/commands/aws/iam/check-admin/index.d.ts +2 -0
  23. package/cjs/commands/aws/iam/check-admin/schema.cjs +19 -0
  24. package/cjs/commands/aws/iam/check-admin/schema.d.ts +19 -0
  25. package/cjs/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
  26. package/cjs/commands/aws/iam/policies/sts-federation.json +11 -0
  27. package/cjs/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
  28. package/cjs/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
  29. package/cjs/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
  30. package/cjs/commands/aws/iam/policies/user-admins-write-list.json +117 -0
  31. package/cjs/commands/aws/iam/remove-admin/handler.cjs +120 -0
  32. package/cjs/commands/aws/iam/remove-admin/handler.d.ts +6 -0
  33. package/cjs/commands/aws/iam/remove-admin/index.cjs +7 -0
  34. package/cjs/commands/aws/iam/remove-admin/index.d.ts +2 -0
  35. package/cjs/commands/aws/iam/remove-admin/schema.cjs +22 -0
  36. package/cjs/commands/aws/iam/remove-admin/schema.d.ts +28 -0
  37. package/cjs/commands/aws/iam/setup-acl/handler.cjs +227 -0
  38. package/cjs/commands/aws/iam/setup-acl/handler.d.ts +6 -0
  39. package/cjs/commands/aws/iam/setup-acl/index.cjs +13 -0
  40. package/cjs/commands/aws/iam/setup-acl/index.d.ts +3 -0
  41. package/cjs/commands/aws/iam/setup-acl/schema.cjs +19 -0
  42. package/cjs/commands/aws/iam/setup-acl/schema.d.ts +24 -0
  43. package/cjs/commands/aws/iam/setup-acl/utils.cjs +305 -0
  44. package/cjs/commands/aws/iam/setup-acl/utils.d.ts +61 -0
  45. package/cjs/commands/aws/iam/users/handler.cjs +59 -0
  46. package/cjs/commands/aws/iam/users/handler.d.ts +5 -0
  47. package/cjs/commands/aws/iam/users/index.cjs +18 -0
  48. package/cjs/commands/aws/iam/users/index.d.ts +3 -0
  49. package/cjs/commands/aws/iam/users/schema.cjs +17 -0
  50. package/cjs/commands/aws/iam/users/schema.d.ts +18 -0
  51. package/cjs/commands/aws/iam/users/utils.cjs +454 -0
  52. package/cjs/commands/aws/iam/users/utils.d.ts +119 -0
  53. package/cjs/commands/aws/index.cjs +223 -0
  54. package/cjs/commands/aws/index.d.ts +14 -0
  55. package/cjs/commands/aws/route53/add-record/handler.cjs +264 -0
  56. package/cjs/commands/aws/route53/add-record/handler.d.ts +36 -0
  57. package/cjs/commands/aws/route53/add-record/index.cjs +26 -0
  58. package/cjs/commands/aws/route53/add-record/index.d.ts +3 -0
  59. package/cjs/commands/aws/route53/add-record/schema.cjs +43 -0
  60. package/cjs/commands/aws/route53/add-record/schema.d.ts +45 -0
  61. package/cjs/commands/aws/route53/add-record/utils.cjs +404 -0
  62. package/cjs/commands/aws/route53/add-record/utils.d.ts +216 -0
  63. package/cjs/commands/aws/route53/remove-record/handler.cjs +114 -0
  64. package/cjs/commands/aws/route53/remove-record/handler.d.ts +6 -0
  65. package/cjs/commands/aws/route53/remove-record/index.cjs +5 -0
  66. package/cjs/commands/aws/route53/remove-record/index.d.ts +2 -0
  67. package/cjs/commands/aws/route53/remove-record/schema.cjs +22 -0
  68. package/cjs/commands/aws/route53/remove-record/schema.d.ts +30 -0
  69. package/cjs/commands/aws/schema.cjs +19 -0
  70. package/cjs/commands/aws/schema.d.ts +13 -0
  71. package/cjs/commands/aws/ses/send-email/handler.cjs +73 -0
  72. package/cjs/commands/aws/ses/send-email/handler.d.ts +5 -0
  73. package/cjs/commands/aws/ses/send-email/index.cjs +9 -0
  74. package/cjs/commands/aws/ses/send-email/index.d.ts +3 -0
  75. package/cjs/commands/aws/ses/send-email/schema.cjs +24 -0
  76. package/cjs/commands/aws/ses/send-email/schema.d.ts +39 -0
  77. package/cjs/commands/aws/ses/send-email/utils.cjs +87 -0
  78. package/cjs/commands/aws/ses/send-email/utils.d.ts +47 -0
  79. package/cjs/commands/aws/ses/smtp-password.cjs +72 -0
  80. package/cjs/commands/aws/ses/smtp-password.d.ts +21 -0
  81. package/cjs/commands/aws/utils/exec-aws.cjs +145 -0
  82. package/cjs/commands/aws/utils/exec-aws.d.ts +79 -0
  83. package/cjs/commands/aws/utils/resolve-policy-path.cjs +15 -0
  84. package/cjs/commands/aws/utils/resolve-policy-path.d.ts +8 -0
  85. package/cjs/commands/aws/utils/resolve-profile.cjs +93 -0
  86. package/cjs/commands/aws/utils/resolve-profile.d.ts +28 -0
  87. package/cjs/commands/aws/utils/tty.cjs +54 -0
  88. package/cjs/commands/aws/utils/tty.d.ts +24 -0
  89. package/cjs/commands/db/create-readonly-user/handler.cjs +254 -0
  90. package/cjs/commands/db/create-readonly-user/handler.d.ts +5 -0
  91. package/cjs/commands/db/create-readonly-user/index.cjs +18 -0
  92. package/cjs/commands/db/create-readonly-user/index.d.ts +3 -0
  93. package/cjs/commands/db/create-readonly-user/mysql.cjs +102 -0
  94. package/cjs/commands/db/create-readonly-user/mysql.d.ts +33 -0
  95. package/cjs/commands/db/create-readonly-user/postgres.cjs +209 -0
  96. package/cjs/commands/db/create-readonly-user/postgres.d.ts +31 -0
  97. package/cjs/commands/db/create-readonly-user/schema.cjs +39 -0
  98. package/cjs/commands/db/create-readonly-user/schema.d.ts +55 -0
  99. package/cjs/commands/db/create-readonly-user/utils.cjs +160 -0
  100. package/cjs/commands/db/create-readonly-user/utils.d.ts +112 -0
  101. package/cjs/commands/db/index.cjs +46 -0
  102. package/cjs/commands/db/index.d.ts +6 -0
  103. package/cjs/commands/doppler/handler.cjs +95 -9
  104. package/cjs/commands/doppler/index.cjs +33 -41
  105. package/cjs/commands/doppler/index.d.ts +1 -0
  106. package/cjs/commands/doppler/schema.cjs +130 -6
  107. package/cjs/commands/doppler/schema.d.ts +233 -17
  108. package/cjs/commands/doppler/set-secret.cjs +378 -0
  109. package/cjs/commands/doppler/set-secret.d.ts +113 -0
  110. package/cjs/commands/doppler/utils/exec.cjs +106 -12
  111. package/cjs/commands/doppler/utils.cjs +412 -30
  112. package/cjs/commands/doppler/utils.d.ts +32 -8
  113. package/cjs/commands/icons/handler.cjs +82 -8
  114. package/cjs/commands/icons/index.cjs +15 -31
  115. package/cjs/commands/icons/schema.cjs +101 -13
  116. package/cjs/commands/icons/schema.d.ts +1 -1
  117. package/cjs/commands/icons/utils.cjs +131 -13
  118. package/cjs/commands/index.cjs +54 -82
  119. package/cjs/commands/schema.cjs +25 -8
  120. package/cjs/index.cjs +3 -4
  121. package/esm/commands/aws/ec2/allow-ip/handler.d.ts +6 -0
  122. package/esm/commands/aws/ec2/allow-ip/handler.js +258 -0
  123. package/esm/commands/aws/ec2/allow-ip/index.d.ts +3 -0
  124. package/esm/commands/aws/ec2/allow-ip/index.js +4 -0
  125. package/esm/commands/aws/ec2/allow-ip/schema.d.ts +33 -0
  126. package/esm/commands/aws/ec2/allow-ip/schema.js +29 -0
  127. package/esm/commands/aws/ec2/allow-ip/utils.d.ts +189 -0
  128. package/esm/commands/aws/ec2/allow-ip/utils.js +363 -0
  129. package/esm/commands/aws/iam/admin-group.d.ts +55 -0
  130. package/esm/commands/aws/iam/admin-group.js +104 -0
  131. package/esm/commands/aws/iam/break-glass/handler.d.ts +7 -0
  132. package/esm/commands/aws/iam/break-glass/handler.js +124 -0
  133. package/esm/commands/aws/iam/break-glass/index.d.ts +2 -0
  134. package/esm/commands/aws/iam/break-glass/index.js +4 -0
  135. package/esm/commands/aws/iam/break-glass/schema.d.ts +25 -0
  136. package/esm/commands/aws/iam/break-glass/schema.js +19 -0
  137. package/esm/commands/aws/iam/check-admin/handler.d.ts +5 -0
  138. package/esm/commands/aws/iam/check-admin/handler.js +86 -0
  139. package/esm/commands/aws/iam/check-admin/index.d.ts +2 -0
  140. package/esm/commands/aws/iam/check-admin/index.js +4 -0
  141. package/esm/commands/aws/iam/check-admin/schema.d.ts +19 -0
  142. package/esm/commands/aws/iam/check-admin/schema.js +17 -0
  143. package/esm/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
  144. package/esm/commands/aws/iam/policies/sts-federation.json +11 -0
  145. package/esm/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
  146. package/esm/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
  147. package/esm/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
  148. package/esm/commands/aws/iam/policies/user-admins-write-list.json +117 -0
  149. package/esm/commands/aws/iam/remove-admin/handler.d.ts +6 -0
  150. package/esm/commands/aws/iam/remove-admin/handler.js +117 -0
  151. package/esm/commands/aws/iam/remove-admin/index.d.ts +2 -0
  152. package/esm/commands/aws/iam/remove-admin/index.js +4 -0
  153. package/esm/commands/aws/iam/remove-admin/schema.d.ts +28 -0
  154. package/esm/commands/aws/iam/remove-admin/schema.js +20 -0
  155. package/esm/commands/aws/iam/setup-acl/handler.d.ts +6 -0
  156. package/esm/commands/aws/iam/setup-acl/handler.js +224 -0
  157. package/esm/commands/aws/iam/setup-acl/index.d.ts +3 -0
  158. package/esm/commands/aws/iam/setup-acl/index.js +4 -0
  159. package/esm/commands/aws/iam/setup-acl/schema.d.ts +24 -0
  160. package/esm/commands/aws/iam/setup-acl/schema.js +18 -0
  161. package/esm/commands/aws/iam/setup-acl/utils.d.ts +61 -0
  162. package/esm/commands/aws/iam/setup-acl/utils.js +298 -0
  163. package/esm/commands/aws/iam/users/handler.d.ts +5 -0
  164. package/esm/commands/aws/iam/users/handler.js +56 -0
  165. package/esm/commands/aws/iam/users/index.d.ts +3 -0
  166. package/esm/commands/aws/iam/users/index.js +4 -0
  167. package/esm/commands/aws/iam/users/schema.d.ts +18 -0
  168. package/esm/commands/aws/iam/users/schema.js +16 -0
  169. package/esm/commands/aws/iam/users/utils.d.ts +119 -0
  170. package/esm/commands/aws/iam/users/utils.js +440 -0
  171. package/esm/commands/aws/index.d.ts +14 -0
  172. package/esm/commands/aws/index.js +142 -0
  173. package/esm/commands/aws/route53/add-record/handler.d.ts +36 -0
  174. package/esm/commands/aws/route53/add-record/handler.js +258 -0
  175. package/esm/commands/aws/route53/add-record/index.d.ts +3 -0
  176. package/esm/commands/aws/route53/add-record/index.js +4 -0
  177. package/esm/commands/aws/route53/add-record/schema.d.ts +45 -0
  178. package/esm/commands/aws/route53/add-record/schema.js +40 -0
  179. package/esm/commands/aws/route53/add-record/utils.d.ts +216 -0
  180. package/esm/commands/aws/route53/add-record/utils.js +389 -0
  181. package/esm/commands/aws/route53/remove-record/handler.d.ts +6 -0
  182. package/esm/commands/aws/route53/remove-record/handler.js +111 -0
  183. package/esm/commands/aws/route53/remove-record/index.d.ts +2 -0
  184. package/esm/commands/aws/route53/remove-record/index.js +3 -0
  185. package/esm/commands/aws/route53/remove-record/schema.d.ts +30 -0
  186. package/esm/commands/aws/route53/remove-record/schema.js +21 -0
  187. package/esm/commands/aws/schema.d.ts +13 -0
  188. package/esm/commands/aws/schema.js +16 -0
  189. package/esm/commands/aws/ses/send-email/handler.d.ts +5 -0
  190. package/esm/commands/aws/ses/send-email/handler.js +70 -0
  191. package/esm/commands/aws/ses/send-email/index.d.ts +3 -0
  192. package/esm/commands/aws/ses/send-email/index.js +4 -0
  193. package/esm/commands/aws/ses/send-email/schema.d.ts +39 -0
  194. package/esm/commands/aws/ses/send-email/schema.js +23 -0
  195. package/esm/commands/aws/ses/send-email/utils.d.ts +47 -0
  196. package/esm/commands/aws/ses/send-email/utils.js +84 -0
  197. package/esm/commands/aws/ses/smtp-password.d.ts +21 -0
  198. package/esm/commands/aws/ses/smtp-password.js +69 -0
  199. package/esm/commands/aws/utils/exec-aws.d.ts +79 -0
  200. package/esm/commands/aws/utils/exec-aws.js +137 -0
  201. package/esm/commands/aws/utils/resolve-policy-path.d.ts +8 -0
  202. package/esm/commands/aws/utils/resolve-policy-path.js +14 -0
  203. package/esm/commands/aws/utils/resolve-profile.d.ts +28 -0
  204. package/esm/commands/aws/utils/resolve-profile.js +88 -0
  205. package/esm/commands/aws/utils/tty.d.ts +24 -0
  206. package/esm/commands/aws/utils/tty.js +51 -0
  207. package/esm/commands/db/create-readonly-user/handler.d.ts +5 -0
  208. package/esm/commands/db/create-readonly-user/handler.js +251 -0
  209. package/esm/commands/db/create-readonly-user/index.d.ts +3 -0
  210. package/esm/commands/db/create-readonly-user/index.js +4 -0
  211. package/esm/commands/db/create-readonly-user/mysql.d.ts +33 -0
  212. package/esm/commands/db/create-readonly-user/mysql.js +98 -0
  213. package/esm/commands/db/create-readonly-user/postgres.d.ts +31 -0
  214. package/esm/commands/db/create-readonly-user/postgres.js +205 -0
  215. package/esm/commands/db/create-readonly-user/schema.d.ts +55 -0
  216. package/esm/commands/db/create-readonly-user/schema.js +35 -0
  217. package/esm/commands/db/create-readonly-user/utils.d.ts +112 -0
  218. package/esm/commands/db/create-readonly-user/utils.js +151 -0
  219. package/esm/commands/db/index.d.ts +6 -0
  220. package/esm/commands/db/index.js +31 -0
  221. package/esm/commands/doppler/handler.js +92 -9
  222. package/esm/commands/doppler/index.d.ts +1 -0
  223. package/esm/commands/doppler/index.js +6 -41
  224. package/esm/commands/doppler/schema.d.ts +233 -17
  225. package/esm/commands/doppler/schema.js +125 -7
  226. package/esm/commands/doppler/set-secret.d.ts +113 -0
  227. package/esm/commands/doppler/set-secret.js +370 -0
  228. package/esm/commands/doppler/utils/exec.js +100 -12
  229. package/esm/commands/doppler/utils.d.ts +32 -8
  230. package/esm/commands/doppler/utils.js +396 -30
  231. package/esm/commands/icons/handler.js +79 -8
  232. package/esm/commands/icons/index.js +4 -31
  233. package/esm/commands/icons/schema.d.ts +1 -1
  234. package/esm/commands/icons/schema.js +97 -15
  235. package/esm/commands/icons/utils.js +125 -13
  236. package/esm/commands/index.js +49 -78
  237. package/esm/commands/schema.js +22 -7
  238. package/esm/index.js +3 -4
  239. package/package.json +12 -2
  240. package/vitest.config.ts +11 -0
  241. package/cjs/__chunks/4GFJUCSP.cjs +0 -52
  242. package/cjs/__chunks/4SFWHCB3.cjs +0 -133
  243. package/cjs/__chunks/B2KFW7T7.cjs +0 -1
  244. package/cjs/__chunks/EMMC33QA.cjs +0 -401
  245. package/cjs/__chunks/INFOPAHN.cjs +0 -117
  246. package/cjs/__chunks/J36P6UNE.cjs +0 -75
  247. package/cjs/__chunks/NIMXXHJQ.cjs +0 -92
  248. package/cjs/__chunks/NSRFG4DF.cjs +0 -100
  249. package/cjs/__chunks/WNJ3ZYLI.cjs +0 -1
  250. package/cjs/__chunks/ZMDIOZPT.cjs +0 -22
  251. package/esm/__chunks/46HGXFME.js +0 -0
  252. package/esm/__chunks/6G4PXXKF.js +0 -75
  253. package/esm/__chunks/6L5RNR7G.js +0 -100
  254. package/esm/__chunks/FL7AILGH.js +0 -133
  255. package/esm/__chunks/HJSXC6HP.js +0 -117
  256. package/esm/__chunks/O262GK4B.js +0 -401
  257. package/esm/__chunks/O3CCA76Q.js +0 -22
  258. package/esm/__chunks/SJXQJ7RS.js +0 -92
  259. package/esm/__chunks/SNCKIAOR.js +0 -0
  260. package/esm/__chunks/X3R5PSWH.js +0 -52
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Common Route53 record types offered in the interactive picker.
3
+ * Alias records are not supported by this command.
4
+ */
5
+ export const RECORD_TYPES: string[];
6
+ /**
7
+ * Default TTL (seconds) when creating or replacing a record set.
8
+ */
9
+ export const DEFAULT_TTL: 300;
10
+ /**
11
+ * Zod schema for `aws route53 add-record` options.
12
+ */
13
+ export const addRecordOptionsSchema: z.ZodObject<{
14
+ profile: z.ZodOptional<z.ZodString>;
15
+ zone: z.ZodOptional<z.ZodString>;
16
+ type: z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodString>, string | undefined, string | undefined>, string | undefined, string | undefined>;
17
+ name: z.ZodOptional<z.ZodString>;
18
+ value: z.ZodOptional<z.ZodString>;
19
+ ttl: z.ZodOptional<z.ZodNumber>;
20
+ yes: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
21
+ dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
22
+ verbose: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
23
+ }, "strip", z.ZodTypeAny, {
24
+ verbose: boolean;
25
+ yes: boolean;
26
+ dryRun: boolean;
27
+ profile?: string | undefined;
28
+ value?: string | undefined;
29
+ type?: string | undefined;
30
+ name?: string | undefined;
31
+ zone?: string | undefined;
32
+ ttl?: number | undefined;
33
+ }, {
34
+ profile?: string | undefined;
35
+ verbose?: boolean | undefined;
36
+ yes?: boolean | undefined;
37
+ value?: string | undefined;
38
+ type?: string | undefined;
39
+ dryRun?: boolean | undefined;
40
+ name?: string | undefined;
41
+ zone?: string | undefined;
42
+ ttl?: number | undefined;
43
+ }>;
44
+ export type AddRecordOptions = z.infer<typeof addRecordOptionsSchema>;
45
+ import { z } from "zod";
@@ -0,0 +1,404 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_commands_aws_utils_exec_aws = require("../../utils/exec-aws.cjs");
3
+ require("./schema.cjs");
4
+ //#region src/commands/aws/route53/add-record/utils.js
5
+ /**
6
+ * @typedef {Object} HostedZone
7
+ * @property {string} id - Bare hosted zone ID (without /hostedzone/ prefix)
8
+ * @property {string} name - Zone name with trailing dot (e.g. mountaindev.com.)
9
+ * @property {boolean} privateZone
10
+ * @property {number} recordCount
11
+ */
12
+ /**
13
+ * @typedef {Object} ResourceRecordSet
14
+ * @property {string} name
15
+ * @property {string} type
16
+ * @property {number | undefined} ttl
17
+ * @property {string[]} values
18
+ * @property {boolean} isAlias
19
+ * @property {any} [aliasTarget] - Raw AliasTarget block (present when isAlias)
20
+ */
21
+ /**
22
+ * Strip the `/hostedzone/` prefix from a Route53 hosted zone Id.
23
+ * @param {string} rawId
24
+ * @returns {string}
25
+ */
26
+ function bareHostedZoneId(rawId) {
27
+ return rawId.replace(/^\/hostedzone\//, "");
28
+ }
29
+ /**
30
+ * Ensure a DNS name ends with a trailing dot (Route53 FQDN form).
31
+ * @param {string} name
32
+ * @returns {string}
33
+ */
34
+ function withTrailingDot(name) {
35
+ const trimmed = name.trim();
36
+ if (trimmed === "") return trimmed;
37
+ return trimmed.endsWith(".") ? trimmed : `${trimmed}.`;
38
+ }
39
+ /**
40
+ * Strip a trailing dot for display.
41
+ * @param {string} name
42
+ * @returns {string}
43
+ */
44
+ function withoutTrailingDot(name) {
45
+ return name.endsWith(".") ? name.slice(0, -1) : name;
46
+ }
47
+ /**
48
+ * List hosted zones for the profile.
49
+ * @param {{ profile?: string; verbose?: boolean }} params
50
+ * @returns {HostedZone[]}
51
+ */
52
+ function listHostedZones(params) {
53
+ const { profile, verbose } = params;
54
+ const data = require_commands_aws_utils_exec_aws.runAws({
55
+ profile,
56
+ args: ["route53", "list-hosted-zones"],
57
+ verbose
58
+ });
59
+ /** @type {HostedZone[]} */
60
+ const zones = [];
61
+ for (const zone of data.HostedZones ?? []) {
62
+ const id = bareHostedZoneId(String(zone.Id ?? ""));
63
+ const name = withTrailingDot(String(zone.Name ?? ""));
64
+ if (!id || !name) continue;
65
+ zones.push({
66
+ id,
67
+ name,
68
+ privateZone: Boolean(zone.Config?.PrivateZone),
69
+ recordCount: Number(zone.ResourceRecordSetCount ?? 0)
70
+ });
71
+ }
72
+ return zones.sort((a, b) => a.name.localeCompare(b.name));
73
+ }
74
+ /**
75
+ * Resolve a hosted zone from a name (mountaindev.com) or bare/prefixed ID.
76
+ * @param {{ zones: HostedZone[]; zoneInput: string }} params
77
+ * @returns {HostedZone | null}
78
+ */
79
+ function findHostedZone(params) {
80
+ const { zones, zoneInput } = params;
81
+ const input = zoneInput.trim();
82
+ if (!input) return null;
83
+ const bareId = bareHostedZoneId(input);
84
+ const byId = zones.find((zone) => zone.id === bareId);
85
+ if (byId) return byId;
86
+ const normalized = withTrailingDot(input).toLowerCase();
87
+ const matches = zones.filter((zone) => zone.name.toLowerCase() === normalized);
88
+ if (matches.length === 1) return matches[0] ?? null;
89
+ if (matches.length > 1) return matches.find((zone) => !zone.privateZone) ?? matches[0] ?? null;
90
+ return null;
91
+ }
92
+ /**
93
+ * Build a display label for a hosted zone in the picker.
94
+ * @param {HostedZone} zone
95
+ * @returns {string}
96
+ */
97
+ function hostedZoneLabel(zone) {
98
+ const visibility = zone.privateZone ? "private" : "public";
99
+ return `${withoutTrailingDot(zone.name)} (${zone.id}, ${visibility}, ${zone.recordCount} records)`;
100
+ }
101
+ /**
102
+ * Turn a relative or absolute name into a Route53 FQDN under the zone.
103
+ * Apex / "@" / empty → the zone apex.
104
+ * @param {{ nameInput: string; zoneName: string }} params
105
+ * @returns {string} FQDN with trailing dot
106
+ */
107
+ function resolveRecordName(params) {
108
+ const { nameInput, zoneName } = params;
109
+ const zoneFqdn = withTrailingDot(zoneName);
110
+ const raw = nameInput.trim();
111
+ if (raw === "" || raw === "@") return zoneFqdn;
112
+ const asFqdn = withTrailingDot(raw);
113
+ const zoneLower = zoneFqdn.toLowerCase();
114
+ if (asFqdn.toLowerCase() === zoneLower) return zoneFqdn;
115
+ if (asFqdn.toLowerCase().endsWith(`.${zoneLower}`)) return asFqdn;
116
+ return withTrailingDot(`${raw.replace(/\.$/, "")}.${withoutTrailingDot(zoneFqdn)}`);
117
+ }
118
+ /**
119
+ * Fetch every resource record set at an exact name, across all types.
120
+ * Paginates when needed; Route53 list is ordered by name then type.
121
+ * @param {{
122
+ * profile?: string;
123
+ * hostedZoneId: string;
124
+ * name: string;
125
+ * verbose?: boolean;
126
+ * }} params
127
+ * @returns {ResourceRecordSet[]}
128
+ */
129
+ function getRecordSetsAtName(params) {
130
+ const { profile, hostedZoneId, name, verbose } = params;
131
+ const targetName = withTrailingDot(name).toLowerCase();
132
+ let startRecordName = withTrailingDot(name);
133
+ /** @type {string | undefined} */
134
+ let startRecordType;
135
+ /** @type {string | undefined} */
136
+ let nextRecordIdentifier;
137
+ /** @type {ResourceRecordSet[]} */
138
+ const collected = [];
139
+ for (let page = 0; page < 20; page += 1) {
140
+ /** @type {string[]} */
141
+ const args = [
142
+ "route53",
143
+ "list-resource-record-sets",
144
+ "--hosted-zone-id",
145
+ hostedZoneId,
146
+ "--max-items",
147
+ "100"
148
+ ];
149
+ if (startRecordName) args.push("--start-record-name", startRecordName);
150
+ if (startRecordType) args.push("--start-record-type", startRecordType);
151
+ if (nextRecordIdentifier) args.push("--start-record-identifier", nextRecordIdentifier);
152
+ const data = require_commands_aws_utils_exec_aws.runAws({
153
+ profile,
154
+ args,
155
+ verbose
156
+ });
157
+ const sets = data.ResourceRecordSets ?? [];
158
+ for (const set of sets) {
159
+ const setName = withTrailingDot(String(set.Name ?? "")).toLowerCase();
160
+ if (setName === targetName) {
161
+ collected.push(normalizeRecordSet(set));
162
+ continue;
163
+ }
164
+ if (setName > targetName) return collected;
165
+ }
166
+ if (!(data.IsTruncated === true)) return collected;
167
+ startRecordName = data.NextRecordName ? String(data.NextRecordName) : startRecordName;
168
+ startRecordType = data.NextRecordType ? String(data.NextRecordType) : void 0;
169
+ nextRecordIdentifier = data.NextRecordIdentifier ? String(data.NextRecordIdentifier) : void 0;
170
+ }
171
+ return collected;
172
+ }
173
+ /**
174
+ * Fetch a single resource record set by exact name + type, if it exists.
175
+ * @param {{
176
+ * profile?: string;
177
+ * hostedZoneId: string;
178
+ * name: string;
179
+ * type: string;
180
+ * verbose?: boolean;
181
+ * }} params
182
+ * @returns {ResourceRecordSet | null}
183
+ */
184
+ function getResourceRecordSet(params) {
185
+ const { type, ...rest } = params;
186
+ const targetType = type.toUpperCase();
187
+ return getRecordSetsAtName(rest).find((set) => set.type === targetType) ?? null;
188
+ }
189
+ /**
190
+ * Route53 forbids a CNAME from coexisting with any other record type at the
191
+ * same name. Given the type about to be written and the record sets already at
192
+ * that name, return the sets that would conflict (empty when there is none).
193
+ * A same-type set is an overwrite, not a conflict.
194
+ * @param {{ existingSets: ResourceRecordSet[]; type: string }} params
195
+ * @returns {ResourceRecordSet[]}
196
+ */
197
+ function findCnameConflicts(params) {
198
+ const { existingSets, type } = params;
199
+ const upperType = type.toUpperCase();
200
+ return existingSets.filter((set) => {
201
+ if (set.type === upperType) return false;
202
+ return upperType === "CNAME" || set.type === "CNAME";
203
+ });
204
+ }
205
+ /**
206
+ * @param {any} set
207
+ * @returns {ResourceRecordSet}
208
+ */
209
+ function normalizeRecordSet(set) {
210
+ const values = (set.ResourceRecords ?? []).map((record) => String(record.Value ?? ""));
211
+ return {
212
+ name: withTrailingDot(String(set.Name ?? "")),
213
+ type: String(set.Type ?? "").toUpperCase(),
214
+ ttl: typeof set.TTL === "number" ? set.TTL : void 0,
215
+ values,
216
+ isAlias: Boolean(set.AliasTarget),
217
+ aliasTarget: set.AliasTarget ?? void 0
218
+ };
219
+ }
220
+ /**
221
+ * Format existing values for console display.
222
+ * @param {string[]} values
223
+ * @returns {string}
224
+ */
225
+ function formatValues(values) {
226
+ if (values.length === 0) return "(none)";
227
+ if (values.length === 1) return values[0] ?? "(none)";
228
+ return values.map((value) => `\n - ${value}`).join("");
229
+ }
230
+ /**
231
+ * Normalize a single record value for a given type (trailing dots, TXT quotes).
232
+ * @param {{ type: string; value: string }} params
233
+ * @returns {string}
234
+ */
235
+ function normalizeRecordValue(params) {
236
+ const { type, value } = params;
237
+ const trimmed = value.trim();
238
+ if (type === "CNAME" || type === "NS" || type === "MX" || type === "SRV") {
239
+ if (type === "MX") {
240
+ const parts = trimmed.split(/\s+/);
241
+ if (parts.length >= 2) return `${parts[0]} ${withTrailingDot(parts.slice(1).join(" "))}`;
242
+ }
243
+ if (type === "SRV") {
244
+ const parts = trimmed.split(/\s+/);
245
+ if (parts.length >= 4) return `${parts.slice(0, 3).join(" ")} ${withTrailingDot(parts.slice(3).join(" "))}`;
246
+ }
247
+ return withTrailingDot(trimmed);
248
+ }
249
+ if (type === "TXT") {
250
+ if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed;
251
+ return `"${trimmed}"`;
252
+ }
253
+ return trimmed;
254
+ }
255
+ /**
256
+ * Decide how the new value relates to an existing RRSet.
257
+ * @param {{
258
+ * existing: ResourceRecordSet | null;
259
+ * newValue: string;
260
+ * mode?: "replace" | "append";
261
+ * }} params
262
+ * @returns {{
263
+ * action: "create" | "overwrite" | "append" | "noop";
264
+ * finalValues: string[];
265
+ * summary: string;
266
+ * }}
267
+ */
268
+ function planRecordChange(params) {
269
+ const { existing, newValue, mode = "replace" } = params;
270
+ if (!existing) return {
271
+ action: "create",
272
+ finalValues: [newValue],
273
+ summary: "Adding a new record (nothing exists at this name + type)."
274
+ };
275
+ if (existing.isAlias) return {
276
+ action: "overwrite",
277
+ finalValues: [newValue],
278
+ summary: "Overwriting an existing ALIAS record with a standard record set."
279
+ };
280
+ const alreadyPresent = existing.values.some((value) => value === newValue || value === `"${newValue}"`);
281
+ if (alreadyPresent && mode !== "replace") return {
282
+ action: "noop",
283
+ finalValues: existing.values,
284
+ summary: "Record already has this value. Nothing to do."
285
+ };
286
+ if (alreadyPresent && mode === "replace" && existing.values.length === 1 && existing.values[0] === newValue) return {
287
+ action: "noop",
288
+ finalValues: existing.values,
289
+ summary: "Record already has exactly this value. Nothing to do."
290
+ };
291
+ if (mode === "append") return {
292
+ action: "append",
293
+ finalValues: [...existing.values, newValue],
294
+ summary: `Adding to the existing ${existing.type} record (${existing.values.length} value(s) → ${existing.values.length + 1}).`
295
+ };
296
+ return {
297
+ action: "overwrite",
298
+ finalValues: [newValue],
299
+ summary: existing.values.length === 1 ? `Overwriting existing value:\n ${existing.values[0]}\n → ${newValue}` : `Replacing ${existing.values.length} existing values with a single new value.`
300
+ };
301
+ }
302
+ /**
303
+ * Submit a Route53 UPSERT for a simple (non-alias) resource record set.
304
+ * @param {{
305
+ * profile?: string;
306
+ * hostedZoneId: string;
307
+ * name: string;
308
+ * type: string;
309
+ * ttl: number;
310
+ * values: string[];
311
+ * verbose?: boolean;
312
+ * }} params
313
+ * @returns {any} ChangeInfo from Route53
314
+ */
315
+ function upsertResourceRecordSet(params) {
316
+ const { profile, hostedZoneId, name, type, ttl, values, verbose } = params;
317
+ const changeBatch = {
318
+ Comment: `mtn aws route53 add-record: ${type} ${name}`,
319
+ Changes: [{
320
+ Action: "UPSERT",
321
+ ResourceRecordSet: {
322
+ Name: withTrailingDot(name),
323
+ Type: type,
324
+ TTL: ttl ?? 300,
325
+ ResourceRecords: values.map((value) => ({ Value: value }))
326
+ }
327
+ }]
328
+ };
329
+ const data = require_commands_aws_utils_exec_aws.runAws({
330
+ profile,
331
+ args: [
332
+ "route53",
333
+ "change-resource-record-sets",
334
+ "--hosted-zone-id",
335
+ hostedZoneId,
336
+ "--change-batch",
337
+ JSON.stringify(changeBatch)
338
+ ],
339
+ verbose
340
+ });
341
+ return data.ChangeInfo ?? data;
342
+ }
343
+ /**
344
+ * Submit a Route53 DELETE for an existing resource record set. Route53 requires
345
+ * the record's exact current definition, so this is driven by the record set
346
+ * returned from {@link getResourceRecordSet} — alias records reuse their
347
+ * AliasTarget; standard records reuse their TTL + values.
348
+ * @param {{
349
+ * profile?: string;
350
+ * hostedZoneId: string;
351
+ * record: ResourceRecordSet;
352
+ * verbose?: boolean;
353
+ * }} params
354
+ * @returns {any} ChangeInfo from Route53
355
+ */
356
+ function deleteResourceRecordSet(params) {
357
+ const { profile, hostedZoneId, record, verbose } = params;
358
+ /** @type {Record<string, any>} */
359
+ const resourceRecordSet = {
360
+ Name: withTrailingDot(record.name),
361
+ Type: record.type
362
+ };
363
+ if (record.isAlias && record.aliasTarget) resourceRecordSet.AliasTarget = record.aliasTarget;
364
+ else {
365
+ resourceRecordSet.TTL = record.ttl ?? 300;
366
+ resourceRecordSet.ResourceRecords = record.values.map((value) => ({ Value: value }));
367
+ }
368
+ const changeBatch = {
369
+ Comment: `mtn aws route53 remove-record: ${record.type} ${record.name}`,
370
+ Changes: [{
371
+ Action: "DELETE",
372
+ ResourceRecordSet: resourceRecordSet
373
+ }]
374
+ };
375
+ const data = require_commands_aws_utils_exec_aws.runAws({
376
+ profile,
377
+ args: [
378
+ "route53",
379
+ "change-resource-record-sets",
380
+ "--hosted-zone-id",
381
+ hostedZoneId,
382
+ "--change-batch",
383
+ JSON.stringify(changeBatch)
384
+ ],
385
+ verbose
386
+ });
387
+ return data.ChangeInfo ?? data;
388
+ }
389
+ //#endregion
390
+ exports.bareHostedZoneId = bareHostedZoneId;
391
+ exports.deleteResourceRecordSet = deleteResourceRecordSet;
392
+ exports.findCnameConflicts = findCnameConflicts;
393
+ exports.findHostedZone = findHostedZone;
394
+ exports.formatValues = formatValues;
395
+ exports.getRecordSetsAtName = getRecordSetsAtName;
396
+ exports.getResourceRecordSet = getResourceRecordSet;
397
+ exports.hostedZoneLabel = hostedZoneLabel;
398
+ exports.listHostedZones = listHostedZones;
399
+ exports.normalizeRecordValue = normalizeRecordValue;
400
+ exports.planRecordChange = planRecordChange;
401
+ exports.resolveRecordName = resolveRecordName;
402
+ exports.upsertResourceRecordSet = upsertResourceRecordSet;
403
+ exports.withTrailingDot = withTrailingDot;
404
+ exports.withoutTrailingDot = withoutTrailingDot;
@@ -0,0 +1,216 @@
1
+ /**
2
+ * @typedef {Object} HostedZone
3
+ * @property {string} id - Bare hosted zone ID (without /hostedzone/ prefix)
4
+ * @property {string} name - Zone name with trailing dot (e.g. mountaindev.com.)
5
+ * @property {boolean} privateZone
6
+ * @property {number} recordCount
7
+ */
8
+ /**
9
+ * @typedef {Object} ResourceRecordSet
10
+ * @property {string} name
11
+ * @property {string} type
12
+ * @property {number | undefined} ttl
13
+ * @property {string[]} values
14
+ * @property {boolean} isAlias
15
+ * @property {any} [aliasTarget] - Raw AliasTarget block (present when isAlias)
16
+ */
17
+ /**
18
+ * Strip the `/hostedzone/` prefix from a Route53 hosted zone Id.
19
+ * @param {string} rawId
20
+ * @returns {string}
21
+ */
22
+ export function bareHostedZoneId(rawId: string): string;
23
+ /**
24
+ * Ensure a DNS name ends with a trailing dot (Route53 FQDN form).
25
+ * @param {string} name
26
+ * @returns {string}
27
+ */
28
+ export function withTrailingDot(name: string): string;
29
+ /**
30
+ * Strip a trailing dot for display.
31
+ * @param {string} name
32
+ * @returns {string}
33
+ */
34
+ export function withoutTrailingDot(name: string): string;
35
+ /**
36
+ * List hosted zones for the profile.
37
+ * @param {{ profile?: string; verbose?: boolean }} params
38
+ * @returns {HostedZone[]}
39
+ */
40
+ export function listHostedZones(params: {
41
+ profile?: string;
42
+ verbose?: boolean;
43
+ }): HostedZone[];
44
+ /**
45
+ * Resolve a hosted zone from a name (mountaindev.com) or bare/prefixed ID.
46
+ * @param {{ zones: HostedZone[]; zoneInput: string }} params
47
+ * @returns {HostedZone | null}
48
+ */
49
+ export function findHostedZone(params: {
50
+ zones: HostedZone[];
51
+ zoneInput: string;
52
+ }): HostedZone | null;
53
+ /**
54
+ * Build a display label for a hosted zone in the picker.
55
+ * @param {HostedZone} zone
56
+ * @returns {string}
57
+ */
58
+ export function hostedZoneLabel(zone: HostedZone): string;
59
+ /**
60
+ * Turn a relative or absolute name into a Route53 FQDN under the zone.
61
+ * Apex / "@" / empty → the zone apex.
62
+ * @param {{ nameInput: string; zoneName: string }} params
63
+ * @returns {string} FQDN with trailing dot
64
+ */
65
+ export function resolveRecordName(params: {
66
+ nameInput: string;
67
+ zoneName: string;
68
+ }): string;
69
+ /**
70
+ * Fetch every resource record set at an exact name, across all types.
71
+ * Paginates when needed; Route53 list is ordered by name then type.
72
+ * @param {{
73
+ * profile?: string;
74
+ * hostedZoneId: string;
75
+ * name: string;
76
+ * verbose?: boolean;
77
+ * }} params
78
+ * @returns {ResourceRecordSet[]}
79
+ */
80
+ export function getRecordSetsAtName(params: {
81
+ profile?: string;
82
+ hostedZoneId: string;
83
+ name: string;
84
+ verbose?: boolean;
85
+ }): ResourceRecordSet[];
86
+ /**
87
+ * Fetch a single resource record set by exact name + type, if it exists.
88
+ * @param {{
89
+ * profile?: string;
90
+ * hostedZoneId: string;
91
+ * name: string;
92
+ * type: string;
93
+ * verbose?: boolean;
94
+ * }} params
95
+ * @returns {ResourceRecordSet | null}
96
+ */
97
+ export function getResourceRecordSet(params: {
98
+ profile?: string;
99
+ hostedZoneId: string;
100
+ name: string;
101
+ type: string;
102
+ verbose?: boolean;
103
+ }): ResourceRecordSet | null;
104
+ /**
105
+ * Route53 forbids a CNAME from coexisting with any other record type at the
106
+ * same name. Given the type about to be written and the record sets already at
107
+ * that name, return the sets that would conflict (empty when there is none).
108
+ * A same-type set is an overwrite, not a conflict.
109
+ * @param {{ existingSets: ResourceRecordSet[]; type: string }} params
110
+ * @returns {ResourceRecordSet[]}
111
+ */
112
+ export function findCnameConflicts(params: {
113
+ existingSets: ResourceRecordSet[];
114
+ type: string;
115
+ }): ResourceRecordSet[];
116
+ /**
117
+ * Format existing values for console display.
118
+ * @param {string[]} values
119
+ * @returns {string}
120
+ */
121
+ export function formatValues(values: string[]): string;
122
+ /**
123
+ * Normalize a single record value for a given type (trailing dots, TXT quotes).
124
+ * @param {{ type: string; value: string }} params
125
+ * @returns {string}
126
+ */
127
+ export function normalizeRecordValue(params: {
128
+ type: string;
129
+ value: string;
130
+ }): string;
131
+ /**
132
+ * Decide how the new value relates to an existing RRSet.
133
+ * @param {{
134
+ * existing: ResourceRecordSet | null;
135
+ * newValue: string;
136
+ * mode?: "replace" | "append";
137
+ * }} params
138
+ * @returns {{
139
+ * action: "create" | "overwrite" | "append" | "noop";
140
+ * finalValues: string[];
141
+ * summary: string;
142
+ * }}
143
+ */
144
+ export function planRecordChange(params: {
145
+ existing: ResourceRecordSet | null;
146
+ newValue: string;
147
+ mode?: "replace" | "append";
148
+ }): {
149
+ action: "create" | "overwrite" | "append" | "noop";
150
+ finalValues: string[];
151
+ summary: string;
152
+ };
153
+ /**
154
+ * Submit a Route53 UPSERT for a simple (non-alias) resource record set.
155
+ * @param {{
156
+ * profile?: string;
157
+ * hostedZoneId: string;
158
+ * name: string;
159
+ * type: string;
160
+ * ttl: number;
161
+ * values: string[];
162
+ * verbose?: boolean;
163
+ * }} params
164
+ * @returns {any} ChangeInfo from Route53
165
+ */
166
+ export function upsertResourceRecordSet(params: {
167
+ profile?: string;
168
+ hostedZoneId: string;
169
+ name: string;
170
+ type: string;
171
+ ttl: number;
172
+ values: string[];
173
+ verbose?: boolean;
174
+ }): any;
175
+ /**
176
+ * Submit a Route53 DELETE for an existing resource record set. Route53 requires
177
+ * the record's exact current definition, so this is driven by the record set
178
+ * returned from {@link getResourceRecordSet} — alias records reuse their
179
+ * AliasTarget; standard records reuse their TTL + values.
180
+ * @param {{
181
+ * profile?: string;
182
+ * hostedZoneId: string;
183
+ * record: ResourceRecordSet;
184
+ * verbose?: boolean;
185
+ * }} params
186
+ * @returns {any} ChangeInfo from Route53
187
+ */
188
+ export function deleteResourceRecordSet(params: {
189
+ profile?: string;
190
+ hostedZoneId: string;
191
+ record: ResourceRecordSet;
192
+ verbose?: boolean;
193
+ }): any;
194
+ export type HostedZone = {
195
+ /**
196
+ * - Bare hosted zone ID (without /hostedzone/ prefix)
197
+ */
198
+ id: string;
199
+ /**
200
+ * - Zone name with trailing dot (e.g. mountaindev.com.)
201
+ */
202
+ name: string;
203
+ privateZone: boolean;
204
+ recordCount: number;
205
+ };
206
+ export type ResourceRecordSet = {
207
+ name: string;
208
+ type: string;
209
+ ttl: number | undefined;
210
+ values: string[];
211
+ isAlias: boolean;
212
+ /**
213
+ * - Raw AliasTarget block (present when isAlias)
214
+ */
215
+ aliasTarget?: any;
216
+ };