@mtndev/cli 2.0.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 (264) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/cjs/__chunks/VH7oDXx4.cjs +28 -0
  3. package/cjs/commands/aws/ec2/allow-ip/handler.cjs +261 -12
  4. package/cjs/commands/aws/ec2/allow-ip/index.cjs +25 -55
  5. package/cjs/commands/aws/ec2/allow-ip/schema.cjs +33 -13
  6. package/cjs/commands/aws/ec2/allow-ip/utils.cjs +379 -39
  7. package/cjs/commands/aws/iam/admin-group.cjs +111 -15
  8. package/cjs/commands/aws/iam/break-glass/handler.cjs +127 -12
  9. package/cjs/commands/aws/iam/break-glass/index.cjs +7 -19
  10. package/cjs/commands/aws/iam/break-glass/schema.cjs +21 -12
  11. package/cjs/commands/aws/iam/check-admin/handler.cjs +89 -10
  12. package/cjs/commands/aws/iam/check-admin/index.cjs +7 -17
  13. package/cjs/commands/aws/iam/check-admin/schema.cjs +19 -12
  14. package/cjs/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
  15. package/cjs/commands/aws/iam/policies/sts-federation.json +11 -0
  16. package/cjs/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
  17. package/cjs/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
  18. package/cjs/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
  19. package/cjs/commands/aws/iam/policies/user-admins-write-list.json +117 -0
  20. package/cjs/commands/aws/iam/remove-admin/handler.cjs +120 -11
  21. package/cjs/commands/aws/iam/remove-admin/index.cjs +7 -18
  22. package/cjs/commands/aws/iam/remove-admin/schema.cjs +22 -12
  23. package/cjs/commands/aws/iam/setup-acl/handler.cjs +227 -14
  24. package/cjs/commands/aws/iam/setup-acl/index.cjs +13 -33
  25. package/cjs/commands/aws/iam/setup-acl/schema.cjs +19 -7
  26. package/cjs/commands/aws/iam/setup-acl/utils.cjs +305 -20
  27. package/cjs/commands/aws/iam/users/handler.cjs +59 -12
  28. package/cjs/commands/aws/iam/users/index.cjs +18 -41
  29. package/cjs/commands/aws/iam/users/schema.cjs +17 -7
  30. package/cjs/commands/aws/iam/users/utils.cjs +454 -30
  31. package/cjs/commands/aws/index.cjs +223 -229
  32. package/cjs/commands/aws/route53/add-record/handler.cjs +264 -18
  33. package/cjs/commands/aws/route53/add-record/index.cjs +26 -57
  34. package/cjs/commands/aws/route53/add-record/schema.cjs +43 -11
  35. package/cjs/commands/aws/route53/add-record/utils.cjs +404 -37
  36. package/cjs/commands/aws/route53/remove-record/handler.cjs +114 -14
  37. package/cjs/commands/aws/route53/remove-record/index.cjs +5 -18
  38. package/cjs/commands/aws/route53/remove-record/schema.cjs +22 -8
  39. package/cjs/commands/aws/schema.cjs +19 -10
  40. package/cjs/commands/aws/ses/send-email/handler.cjs +73 -12
  41. package/cjs/commands/aws/ses/send-email/index.cjs +9 -23
  42. package/cjs/commands/aws/ses/send-email/schema.cjs +24 -7
  43. package/cjs/commands/aws/ses/send-email/utils.cjs +87 -11
  44. package/cjs/commands/aws/ses/smtp-password.cjs +72 -10
  45. package/cjs/commands/aws/utils/exec-aws.cjs +145 -16
  46. package/cjs/commands/aws/utils/resolve-policy-path.cjs +15 -6
  47. package/cjs/commands/aws/utils/resolve-profile.cjs +93 -11
  48. package/cjs/commands/aws/utils/tty.cjs +54 -10
  49. package/cjs/commands/db/create-readonly-user/handler.cjs +254 -11
  50. package/cjs/commands/db/create-readonly-user/index.cjs +18 -40
  51. package/cjs/commands/db/create-readonly-user/mysql.cjs +102 -9
  52. package/cjs/commands/db/create-readonly-user/postgres.cjs +209 -9
  53. package/cjs/commands/db/create-readonly-user/schema.cjs +39 -12
  54. package/cjs/commands/db/create-readonly-user/utils.cjs +160 -22
  55. package/cjs/commands/db/index.cjs +46 -44
  56. package/cjs/commands/doppler/handler.cjs +95 -11
  57. package/cjs/commands/doppler/index.cjs +33 -68
  58. package/cjs/commands/doppler/schema.cjs +130 -14
  59. package/cjs/commands/doppler/set-secret.cjs +378 -19
  60. package/cjs/commands/doppler/utils/exec.cjs +106 -12
  61. package/cjs/commands/doppler/utils.cjs +412 -34
  62. package/cjs/commands/icons/handler.cjs +82 -8
  63. package/cjs/commands/icons/index.cjs +15 -31
  64. package/cjs/commands/icons/schema.cjs +101 -13
  65. package/cjs/commands/icons/utils.cjs +131 -13
  66. package/cjs/commands/index.cjs +54 -161
  67. package/cjs/commands/schema.cjs +25 -8
  68. package/cjs/index.cjs +3 -4
  69. package/esm/commands/aws/ec2/allow-ip/handler.js +258 -12
  70. package/esm/commands/aws/ec2/allow-ip/index.js +4 -55
  71. package/esm/commands/aws/ec2/allow-ip/schema.js +29 -13
  72. package/esm/commands/aws/ec2/allow-ip/utils.js +363 -39
  73. package/esm/commands/aws/iam/admin-group.js +104 -15
  74. package/esm/commands/aws/iam/break-glass/handler.js +124 -12
  75. package/esm/commands/aws/iam/break-glass/index.js +4 -19
  76. package/esm/commands/aws/iam/break-glass/schema.js +19 -12
  77. package/esm/commands/aws/iam/check-admin/handler.js +86 -10
  78. package/esm/commands/aws/iam/check-admin/index.js +4 -17
  79. package/esm/commands/aws/iam/check-admin/schema.js +17 -12
  80. package/esm/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
  81. package/esm/commands/aws/iam/policies/sts-federation.json +11 -0
  82. package/esm/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
  83. package/esm/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
  84. package/esm/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
  85. package/esm/commands/aws/iam/policies/user-admins-write-list.json +117 -0
  86. package/esm/commands/aws/iam/remove-admin/handler.js +117 -11
  87. package/esm/commands/aws/iam/remove-admin/index.js +4 -18
  88. package/esm/commands/aws/iam/remove-admin/schema.js +20 -12
  89. package/esm/commands/aws/iam/setup-acl/handler.js +224 -14
  90. package/esm/commands/aws/iam/setup-acl/index.js +4 -33
  91. package/esm/commands/aws/iam/setup-acl/schema.js +18 -7
  92. package/esm/commands/aws/iam/setup-acl/utils.js +298 -20
  93. package/esm/commands/aws/iam/users/handler.js +56 -12
  94. package/esm/commands/aws/iam/users/index.js +4 -41
  95. package/esm/commands/aws/iam/users/schema.js +16 -7
  96. package/esm/commands/aws/iam/users/utils.js +440 -30
  97. package/esm/commands/aws/index.js +142 -229
  98. package/esm/commands/aws/route53/add-record/handler.js +258 -18
  99. package/esm/commands/aws/route53/add-record/index.js +4 -57
  100. package/esm/commands/aws/route53/add-record/schema.js +40 -11
  101. package/esm/commands/aws/route53/add-record/utils.js +389 -37
  102. package/esm/commands/aws/route53/remove-record/handler.js +111 -14
  103. package/esm/commands/aws/route53/remove-record/index.js +3 -18
  104. package/esm/commands/aws/route53/remove-record/schema.js +21 -8
  105. package/esm/commands/aws/schema.js +16 -10
  106. package/esm/commands/aws/ses/send-email/handler.js +70 -12
  107. package/esm/commands/aws/ses/send-email/index.js +4 -23
  108. package/esm/commands/aws/ses/send-email/schema.js +23 -7
  109. package/esm/commands/aws/ses/send-email/utils.js +84 -11
  110. package/esm/commands/aws/ses/smtp-password.js +69 -10
  111. package/esm/commands/aws/utils/exec-aws.js +136 -15
  112. package/esm/commands/aws/utils/resolve-policy-path.js +14 -6
  113. package/esm/commands/aws/utils/resolve-profile.js +88 -11
  114. package/esm/commands/aws/utils/tty.js +51 -10
  115. package/esm/commands/db/create-readonly-user/handler.js +251 -11
  116. package/esm/commands/db/create-readonly-user/index.js +4 -40
  117. package/esm/commands/db/create-readonly-user/mysql.js +98 -9
  118. package/esm/commands/db/create-readonly-user/postgres.js +205 -9
  119. package/esm/commands/db/create-readonly-user/schema.js +35 -12
  120. package/esm/commands/db/create-readonly-user/utils.js +151 -22
  121. package/esm/commands/db/index.js +31 -44
  122. package/esm/commands/doppler/handler.js +92 -11
  123. package/esm/commands/doppler/index.js +6 -68
  124. package/esm/commands/doppler/schema.js +125 -15
  125. package/esm/commands/doppler/set-secret.js +370 -19
  126. package/esm/commands/doppler/utils/exec.js +100 -12
  127. package/esm/commands/doppler/utils.js +396 -34
  128. package/esm/commands/icons/handler.js +79 -8
  129. package/esm/commands/icons/index.js +4 -31
  130. package/esm/commands/icons/schema.js +97 -15
  131. package/esm/commands/icons/utils.js +125 -13
  132. package/esm/commands/index.js +47 -155
  133. package/esm/commands/schema.js +22 -7
  134. package/esm/index.js +3 -4
  135. package/package.json +5 -2
  136. package/vitest.config.ts +11 -0
  137. package/cjs/__chunks/2FSYDFUV.cjs +0 -146
  138. package/cjs/__chunks/3A5ZYU5M.cjs +0 -105
  139. package/cjs/__chunks/3BY5Y4W7.cjs +0 -1
  140. package/cjs/__chunks/3NOHGUCF.cjs +0 -9
  141. package/cjs/__chunks/3T2LXW7J.cjs +0 -387
  142. package/cjs/__chunks/4SFWHCB3.cjs +0 -133
  143. package/cjs/__chunks/4XT5JEAS.cjs +0 -1
  144. package/cjs/__chunks/AZEB4H4I.cjs +0 -208
  145. package/cjs/__chunks/B2KFW7T7.cjs +0 -1
  146. package/cjs/__chunks/B5ENMOCD.cjs +0 -288
  147. package/cjs/__chunks/B6XM5KSF.cjs +0 -338
  148. package/cjs/__chunks/BDU2UCE5.cjs +0 -1
  149. package/cjs/__chunks/BLMSMR5E.cjs +0 -46
  150. package/cjs/__chunks/CMUD7LLN.cjs +0 -47
  151. package/cjs/__chunks/DTQ2LB3I.cjs +0 -49
  152. package/cjs/__chunks/FM5MVRQF.cjs +0 -23
  153. package/cjs/__chunks/FRHST54J.cjs +0 -135
  154. package/cjs/__chunks/FU4VP2LN.cjs +0 -1
  155. package/cjs/__chunks/G5K4PVIL.cjs +0 -26
  156. package/cjs/__chunks/GU3R54MK.cjs +0 -127
  157. package/cjs/__chunks/GUL36IFZ.cjs +0 -61
  158. package/cjs/__chunks/GZMTNK5N.cjs +0 -1
  159. package/cjs/__chunks/H74JSDBU.cjs +0 -30
  160. package/cjs/__chunks/INFOPAHN.cjs +0 -117
  161. package/cjs/__chunks/J36P6UNE.cjs +0 -75
  162. package/cjs/__chunks/JB7T7PKQ.cjs +0 -538
  163. package/cjs/__chunks/JSL2JDMW.cjs +0 -1
  164. package/cjs/__chunks/K4QNHRTP.cjs +0 -163
  165. package/cjs/__chunks/KU76LC42.cjs +0 -192
  166. package/cjs/__chunks/LFDSHANP.cjs +0 -34
  167. package/cjs/__chunks/LHE24ECK.cjs +0 -192
  168. package/cjs/__chunks/LIKQ3SI4.cjs +0 -1
  169. package/cjs/__chunks/LXDF5QVZ.cjs +0 -313
  170. package/cjs/__chunks/LXOOJR2R.cjs +0 -74
  171. package/cjs/__chunks/N5MXFOQZ.cjs +0 -167
  172. package/cjs/__chunks/N7D56LPP.cjs +0 -25
  173. package/cjs/__chunks/NFXQNOQH.cjs +0 -393
  174. package/cjs/__chunks/NIMXXHJQ.cjs +0 -92
  175. package/cjs/__chunks/NLKJIUEX.cjs +0 -126
  176. package/cjs/__chunks/NT2XXAI6.cjs +0 -89
  177. package/cjs/__chunks/NWZGFHKH.cjs +0 -121
  178. package/cjs/__chunks/R3GUC7O7.cjs +0 -110
  179. package/cjs/__chunks/RPVAXPJ4.cjs +0 -1
  180. package/cjs/__chunks/S3LVCWPN.cjs +0 -23
  181. package/cjs/__chunks/SBBNW2BF.cjs +0 -249
  182. package/cjs/__chunks/T2A7TN4F.cjs +0 -81
  183. package/cjs/__chunks/TKNNDDIB.cjs +0 -97
  184. package/cjs/__chunks/TNSRDJPR.cjs +0 -1
  185. package/cjs/__chunks/UWHPE2GI.cjs +0 -20
  186. package/cjs/__chunks/W6K7BV74.cjs +0 -1
  187. package/cjs/__chunks/WBOQ6AUN.cjs +0 -320
  188. package/cjs/__chunks/WHGN5PZI.cjs +0 -299
  189. package/cjs/__chunks/WOYF2L6T.cjs +0 -11
  190. package/cjs/__chunks/X26XY2N6.cjs +0 -18
  191. package/cjs/__chunks/XMKOKRXZ.cjs +0 -16
  192. package/cjs/__chunks/XTJPQ3EX.cjs +0 -1
  193. package/cjs/__chunks/YRHFKTW2.cjs +0 -63
  194. package/cjs/__chunks/ZMDIOZPT.cjs +0 -22
  195. package/cjs/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.cjs +0 -28
  196. package/cjs/commands/aws/iam/policies/sts-federation.cjs +0 -19
  197. package/cjs/commands/aws/iam/policies/user-admins-deny-list.cjs +0 -183
  198. package/cjs/commands/aws/iam/policies/user-admins-deny-regions-list.cjs +0 -49
  199. package/cjs/commands/aws/iam/policies/user-admins-self-service-iam.cjs +0 -64
  200. package/cjs/commands/aws/iam/policies/user-admins-write-list.cjs +0 -125
  201. package/esm/__chunks/2FTTEFEK.js +0 -97
  202. package/esm/__chunks/33UYMUQD.js +0 -338
  203. package/esm/__chunks/3BKWTHLJ.js +0 -25
  204. package/esm/__chunks/3HE4BEJX.js +0 -105
  205. package/esm/__chunks/3QLI5BDL.js +0 -387
  206. package/esm/__chunks/5GIUAFXL.js +0 -89
  207. package/esm/__chunks/5ZBVGSOK.js +0 -0
  208. package/esm/__chunks/6G4PXXKF.js +0 -75
  209. package/esm/__chunks/73BJG53F.js +0 -11
  210. package/esm/__chunks/7VF4Q43Q.js +0 -0
  211. package/esm/__chunks/AEDEAYF5.js +0 -0
  212. package/esm/__chunks/AZCP3SFJ.js +0 -0
  213. package/esm/__chunks/B2DVQ2UL.js +0 -61
  214. package/esm/__chunks/CVQVHLW5.js +0 -0
  215. package/esm/__chunks/D62SPZXC.js +0 -0
  216. package/esm/__chunks/DLEJ25GZ.js +0 -121
  217. package/esm/__chunks/DMYFNF54.js +0 -192
  218. package/esm/__chunks/DNFTUMGD.js +0 -23
  219. package/esm/__chunks/DVKD6YSR.js +0 -49
  220. package/esm/__chunks/EMSH4P76.js +0 -20
  221. package/esm/__chunks/FFKFVMIE.js +0 -167
  222. package/esm/__chunks/FL7AILGH.js +0 -133
  223. package/esm/__chunks/FNXUONAV.js +0 -110
  224. package/esm/__chunks/G4NJHFFU.js +0 -320
  225. package/esm/__chunks/HJSXC6HP.js +0 -117
  226. package/esm/__chunks/IEOGAQYI.js +0 -46
  227. package/esm/__chunks/IZFGBYGE.js +0 -34
  228. package/esm/__chunks/J34UVKLA.js +0 -26
  229. package/esm/__chunks/JZPBBBIG.js +0 -74
  230. package/esm/__chunks/KWUJP5MG.js +0 -135
  231. package/esm/__chunks/M35URMT4.js +0 -313
  232. package/esm/__chunks/NF3M2L6C.js +0 -81
  233. package/esm/__chunks/O3CCA76Q.js +0 -22
  234. package/esm/__chunks/PNPPDYKC.js +0 -299
  235. package/esm/__chunks/QFXN4EHM.js +0 -393
  236. package/esm/__chunks/QKDDLIWD.js +0 -146
  237. package/esm/__chunks/QSE66AKY.js +0 -208
  238. package/esm/__chunks/QUF7PS4R.js +0 -18
  239. package/esm/__chunks/S7IJPJ4R.js +0 -126
  240. package/esm/__chunks/SD3E3EPH.js +0 -163
  241. package/esm/__chunks/SJXQJ7RS.js +0 -92
  242. package/esm/__chunks/SNCKIAOR.js +0 -0
  243. package/esm/__chunks/T3TTUHTW.js +0 -30
  244. package/esm/__chunks/TIOVE6HR.js +0 -0
  245. package/esm/__chunks/TXKMEIDQ.js +0 -0
  246. package/esm/__chunks/U7HAE2RF.js +0 -288
  247. package/esm/__chunks/UXWY7BYE.js +0 -63
  248. package/esm/__chunks/VKAKISRG.js +0 -192
  249. package/esm/__chunks/WD2YR6I7.js +0 -0
  250. package/esm/__chunks/WOZFZKFY.js +0 -0
  251. package/esm/__chunks/XI7GZDE2.js +0 -0
  252. package/esm/__chunks/XOUWDB3T.js +0 -249
  253. package/esm/__chunks/XQN2TA4S.js +0 -23
  254. package/esm/__chunks/XXK32TIM.js +0 -16
  255. package/esm/__chunks/YGWTVPZE.js +0 -538
  256. package/esm/__chunks/YRG7PT33.js +0 -127
  257. package/esm/__chunks/ZHKVJO2U.js +0 -47
  258. package/esm/__chunks/ZO55YUSY.js +0 -9
  259. package/esm/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.js +0 -28
  260. package/esm/commands/aws/iam/policies/sts-federation.js +0 -19
  261. package/esm/commands/aws/iam/policies/user-admins-deny-list.js +0 -183
  262. package/esm/commands/aws/iam/policies/user-admins-deny-regions-list.js +0 -49
  263. package/esm/commands/aws/iam/policies/user-admins-self-service-iam.js +0 -64
  264. package/esm/commands/aws/iam/policies/user-admins-write-list.js +0 -125
@@ -1,12 +1,35 @@
1
- import {
2
- DEFAULT_MYSQL_HOST_PATTERN,
3
- DEFAULT_READONLY_USERNAME,
4
- ENGINES,
5
- createReadonlyUserOptionsSchema
6
- } from "../../../__chunks/T3TTUHTW.js";
7
- export {
8
- DEFAULT_MYSQL_HOST_PATTERN,
9
- DEFAULT_READONLY_USERNAME,
10
- ENGINES,
11
- createReadonlyUserOptionsSchema
12
- };
1
+ import { z } from "zod";
2
+ //#region src/commands/db/create-readonly-user/schema.js
3
+ /**
4
+ * Supported database engines.
5
+ * @type {readonly ["postgres", "mysql"]}
6
+ */
7
+ const ENGINES = ["postgres", "mysql"];
8
+ /**
9
+ * Zod schema for `db create-readonly-user` options.
10
+ */
11
+ const createReadonlyUserOptionsSchema = z.object({
12
+ engine: z.enum(["postgres", "mysql"]).optional().describe("Database engine (postgres or mysql); inferred from --url when omitted"),
13
+ url: z.string().optional().describe("Admin connection URL (postgres://… or mysql://…). Defaults to DATABASE_URL / MYSQL_URL / POSTGRES_URL."),
14
+ database: z.string().optional().describe("Target database name, or \"all\" for every non-system database"),
15
+ username: z.string().optional().describe("Read-only username to create (default: readonly)"),
16
+ password: z.string().optional().describe("Password for the new user (generated when omitted)"),
17
+ hostPattern: z.string().optional().describe("MySQL user host pattern (default: %)"),
18
+ ssl: z.boolean().optional().describe("Force SSL on/off. Default: off for localhost, on (loose) for remote hosts."),
19
+ yes: z.boolean().optional().default(false).describe("Skip the confirmation prompt"),
20
+ dryRun: z.boolean().optional().default(false).describe("Print the SQL plan without applying it"),
21
+ verbose: z.boolean().optional().default(false).describe("Enable verbose logging")
22
+ });
23
+ /**
24
+ * @typedef {z.infer<typeof createReadonlyUserOptionsSchema>} CreateReadonlyUserOptions
25
+ */
26
+ /**
27
+ * Default username when none is provided.
28
+ */
29
+ const DEFAULT_READONLY_USERNAME = "readonly";
30
+ /**
31
+ * Default MySQL host pattern (any client host).
32
+ */
33
+ const DEFAULT_MYSQL_HOST_PATTERN = "%";
34
+ //#endregion
35
+ export { DEFAULT_MYSQL_HOST_PATTERN, DEFAULT_READONLY_USERNAME, ENGINES, createReadonlyUserOptionsSchema };
@@ -1,22 +1,151 @@
1
- import {
2
- buildReadonlyUrl,
3
- detectEngineFromUrl,
4
- generatePassword,
5
- isSystemDatabase,
6
- parseConnectionUrl,
7
- quoteIdent,
8
- quoteLiteral,
9
- resolveAdminUrl,
10
- resolveSsl
11
- } from "../../../__chunks/DLEJ25GZ.js";
12
- export {
13
- buildReadonlyUrl,
14
- detectEngineFromUrl,
15
- generatePassword,
16
- isSystemDatabase,
17
- parseConnectionUrl,
18
- quoteIdent,
19
- quoteLiteral,
20
- resolveAdminUrl,
21
- resolveSsl
22
- };
1
+ import { randomBytes } from "crypto";
2
+ //#region src/commands/db/create-readonly-user/utils.js
3
+ /**
4
+ * @typedef {"postgres" | "mysql"} Engine
5
+ */
6
+ /**
7
+ * @typedef {Object} ConnectionConfig
8
+ * @property {Engine} engine
9
+ * @property {string} host
10
+ * @property {number} port
11
+ * @property {string} user
12
+ * @property {string} password
13
+ * @property {string} database
14
+ * @property {boolean | object} ssl
15
+ * @property {string} [url]
16
+ */
17
+ /**
18
+ * Generate a URL-safe random password.
19
+ * @param {{ length?: number }} [params]
20
+ * @returns {string}
21
+ */
22
+ function generatePassword(params = {}) {
23
+ const { length = 24 } = params;
24
+ const alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#$%^&*";
25
+ const bytes = randomBytes(length);
26
+ let result = "";
27
+ for (let i = 0; i < length; i += 1) {
28
+ const byte = bytes[i] ?? 0;
29
+ result += alphabet[byte % 65];
30
+ }
31
+ return result;
32
+ }
33
+ /**
34
+ * Detect engine from a connection URL scheme.
35
+ * @param {string} url
36
+ * @returns {Engine | null}
37
+ */
38
+ function detectEngineFromUrl(url) {
39
+ const trimmed = url.trim().toLowerCase();
40
+ if (trimmed.startsWith("postgres://") || trimmed.startsWith("postgresql://")) return "postgres";
41
+ if (trimmed.startsWith("mysql://") || trimmed.startsWith("mysql2://")) return "mysql";
42
+ return null;
43
+ }
44
+ /**
45
+ * Resolve an admin URL from flags / common env vars.
46
+ * @param {{ url?: string; engine?: Engine }} params
47
+ * @returns {string | null}
48
+ */
49
+ function resolveAdminUrl(params) {
50
+ const { url, engine } = params;
51
+ if (url) return url;
52
+ if (engine === "mysql") return process.env.MYSQL_URL ?? process.env.DATABASE_URL ?? process.env.MYSQL_DATABASE_URL ?? null;
53
+ if (engine === "postgres") return process.env.DATABASE_URL ?? process.env.POSTGRES_URL ?? process.env.POSTGRESQL_URL ?? null;
54
+ return process.env.DATABASE_URL ?? process.env.POSTGRES_URL ?? process.env.POSTGRESQL_URL ?? process.env.MYSQL_URL ?? process.env.MYSQL_DATABASE_URL ?? null;
55
+ }
56
+ /**
57
+ * Decide SSL settings: remote hosts get loose SSL by default (RDS-friendly).
58
+ * @param {{ host: string; sslOption?: boolean }} params
59
+ * @returns {boolean | object}
60
+ */
61
+ function resolveSsl(params) {
62
+ const { host, sslOption } = params;
63
+ if (sslOption === true) return { rejectUnauthorized: false };
64
+ if (sslOption === false) return false;
65
+ if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0") return false;
66
+ return { rejectUnauthorized: false };
67
+ }
68
+ /**
69
+ * Parse a postgres/mysql connection URL into a config object.
70
+ * @param {{ url: string; engine?: Engine; sslOption?: boolean }} params
71
+ * @returns {ConnectionConfig}
72
+ */
73
+ function parseConnectionUrl(params) {
74
+ const { url, engine: engineOption, sslOption } = params;
75
+ const engine = engineOption ?? detectEngineFromUrl(url);
76
+ if (!engine) throw new Error(`Could not detect engine from URL. Pass --engine postgres|mysql. URL starts with: ${url.slice(0, 24)}…`);
77
+ let parsed;
78
+ try {
79
+ parsed = new URL(url);
80
+ } catch {
81
+ throw new Error(`Invalid connection URL: ${url}`);
82
+ }
83
+ const defaultPort = engine === "postgres" ? 5432 : 3306;
84
+ const port = parsed.port ? Number.parseInt(parsed.port, 10) : defaultPort;
85
+ const database = decodeURIComponent(parsed.pathname.replace(/^\//, "")) || (engine === "postgres" ? "postgres" : "");
86
+ const host = parsed.hostname || "localhost";
87
+ const user = decodeURIComponent(parsed.username || "");
88
+ const password = decodeURIComponent(parsed.password || "");
89
+ if (!user) throw new Error("Connection URL is missing a username");
90
+ return {
91
+ engine,
92
+ host,
93
+ port: Number.isFinite(port) ? port : defaultPort,
94
+ user,
95
+ password,
96
+ database,
97
+ ssl: resolveSsl({
98
+ host,
99
+ sslOption
100
+ }),
101
+ url
102
+ };
103
+ }
104
+ /**
105
+ * Build a client connection URL for the new read-only user.
106
+ * @param {{
107
+ * engine: Engine;
108
+ * host: string;
109
+ * port: number;
110
+ * username: string;
111
+ * password: string;
112
+ * database: string;
113
+ * }} params
114
+ * @returns {string}
115
+ */
116
+ function buildReadonlyUrl(params) {
117
+ const { engine, host, port, username, password, database } = params;
118
+ return `${engine === "postgres" ? "postgresql" : "mysql"}://${`${encodeURIComponent(username)}:${encodeURIComponent(password)}`}@${host}:${port}${database ? `/${encodeURIComponent(database)}` : "/"}`;
119
+ }
120
+ /**
121
+ * Quote an identifier for the given engine (not for string literals).
122
+ * @param {{ engine: Engine; name: string }} params
123
+ * @returns {string}
124
+ */
125
+ function quoteIdent(params) {
126
+ const { engine, name } = params;
127
+ if (engine === "postgres") return `"${name.replace(/"/g, "\"\"")}"`;
128
+ return `\`${name.replace(/`/g, "``")}\``;
129
+ }
130
+ /**
131
+ * Escape a string literal for SQL (single-quote doubling).
132
+ * Prefer parameterized queries when the driver supports them for DDL.
133
+ * @param {string} value
134
+ * @returns {string}
135
+ */
136
+ function quoteLiteral(value) {
137
+ return `'${value.replace(/'/g, "''")}'`;
138
+ }
139
+ /**
140
+ * System / template databases to skip when granting "all".
141
+ * @param {{ engine: Engine; name: string }} params
142
+ * @returns {boolean}
143
+ */
144
+ function isSystemDatabase(params) {
145
+ const { engine, name } = params;
146
+ const lower = name.toLowerCase();
147
+ if (engine === "postgres") return lower === "template0" || lower === "template1" || lower === "rdsadmin" || lower === "cloudsqladmin";
148
+ return lower === "information_schema" || lower === "performance_schema" || lower === "mysql" || lower === "sys" || lower === "innodb" || lower === "#mysql50#lost+found";
149
+ }
150
+ //#endregion
151
+ export { buildReadonlyUrl, detectEngineFromUrl, generatePassword, isSystemDatabase, parseConnectionUrl, quoteIdent, quoteLiteral, resolveAdminUrl, resolveSsl };
@@ -1,44 +1,31 @@
1
- import {
2
- registerDbCommands
3
- } from "../../__chunks/DVKD6YSR.js";
4
- import "../../__chunks/WD2YR6I7.js";
5
- import {
6
- createReadonlyUserCommand
7
- } from "../../__chunks/M35URMT4.js";
8
- import "../../__chunks/3HE4BEJX.js";
9
- import "../../__chunks/SD3E3EPH.js";
10
- import {
11
- DEFAULT_MYSQL_HOST_PATTERN,
12
- DEFAULT_READONLY_USERNAME,
13
- ENGINES,
14
- createReadonlyUserOptionsSchema
15
- } from "../../__chunks/T3TTUHTW.js";
16
- import {
17
- buildReadonlyUrl,
18
- detectEngineFromUrl,
19
- generatePassword,
20
- isSystemDatabase,
21
- parseConnectionUrl,
22
- quoteIdent,
23
- quoteLiteral,
24
- resolveAdminUrl,
25
- resolveSsl
26
- } from "../../__chunks/DLEJ25GZ.js";
27
- import "../../__chunks/ZHKVJO2U.js";
28
- export {
29
- DEFAULT_MYSQL_HOST_PATTERN,
30
- DEFAULT_READONLY_USERNAME,
31
- ENGINES,
32
- buildReadonlyUrl,
33
- createReadonlyUserCommand,
34
- createReadonlyUserOptionsSchema,
35
- detectEngineFromUrl,
36
- generatePassword,
37
- isSystemDatabase,
38
- parseConnectionUrl,
39
- quoteIdent,
40
- quoteLiteral,
41
- registerDbCommands,
42
- resolveAdminUrl,
43
- resolveSsl
44
- };
1
+ import { buildReadonlyUrl, detectEngineFromUrl, generatePassword, isSystemDatabase, parseConnectionUrl, quoteIdent, quoteLiteral, resolveAdminUrl, resolveSsl } from "./create-readonly-user/utils.js";
2
+ import { DEFAULT_MYSQL_HOST_PATTERN, DEFAULT_READONLY_USERNAME, ENGINES, createReadonlyUserOptionsSchema } from "./create-readonly-user/schema.js";
3
+ import { createReadonlyUserCommand } from "./create-readonly-user/handler.js";
4
+ import "./create-readonly-user/index.js";
5
+ //#region src/commands/db/index.js
6
+ /**
7
+ * Register the `db` command group and its subcommands on the root program.
8
+ * @param {import('commander').Command} program
9
+ */
10
+ function registerDbCommands(program) {
11
+ program.command("db").summary("Database operational commands").description("Database operational helpers (MySQL and Postgres)").command("create-readonly-user").summary("Create a read-only database user").description("Create (or update) a read-only database user on MySQL or Postgres. Interactively pick a single database or all databases, then print a connection URL.").option("-e, --engine <engine>", "Database engine: postgres or mysql (inferred from --url when omitted)").option("-u, --url <url>", "Admin connection URL (defaults to DATABASE_URL / MYSQL_URL / POSTGRES_URL)").option("-d, --database <name>", "Target database name, or \"all\" for every non-system database").option("--username <name>", "Read-only username to create (default: readonly)").option("--password <password>", "Password for the new user (generated when omitted)").option("--host-pattern <pattern>", "MySQL user host pattern (default: %)").option("--ssl", "Force SSL on (loose verify — useful for RDS)").option("--no-ssl", "Force SSL off").option("-y, --yes", "Skip the confirmation prompt").option("--dry-run", "Print the SQL plan without applying it").option("-v, --verbose", "Enable verbose logging").action(async (options) => {
12
+ /** @type {boolean | undefined} */
13
+ let ssl;
14
+ if (options.ssl === true) ssl = true;
15
+ else if (options.noSsl === true) ssl = false;
16
+ await createReadonlyUserCommand({
17
+ engine: options.engine,
18
+ url: options.url,
19
+ database: options.database,
20
+ username: options.username,
21
+ password: options.password,
22
+ hostPattern: options.hostPattern,
23
+ ssl,
24
+ yes: options.yes ?? false,
25
+ dryRun: options.dryRun ?? false,
26
+ verbose: options.verbose ?? false
27
+ });
28
+ });
29
+ }
30
+ //#endregion
31
+ export { DEFAULT_MYSQL_HOST_PATTERN, DEFAULT_READONLY_USERNAME, ENGINES, buildReadonlyUrl, createReadonlyUserCommand, createReadonlyUserOptionsSchema, detectEngineFromUrl, generatePassword, isSystemDatabase, parseConnectionUrl, quoteIdent, quoteLiteral, registerDbCommands, resolveAdminUrl, resolveSsl };
@@ -1,11 +1,92 @@
1
- import {
2
- dopplerCommand
3
- } from "../../__chunks/YRG7PT33.js";
4
- import "../../__chunks/QFXN4EHM.js";
5
- import "../../__chunks/YGWTVPZE.js";
6
- import "../../__chunks/ZHKVJO2U.js";
7
- import "../../__chunks/SJXQJ7RS.js";
8
- import "../../__chunks/KWUJP5MG.js";
9
- export {
10
- dopplerCommand
11
- };
1
+ import { dopplerCommandMetadata, dopplerCommandOptionsSchema } from "./schema.js";
2
+ import { checkDependencies, checkDopplerAuth, cloneProject, downloadConfigs, uploadConfigs } from "./utils.js";
3
+ import { setSecretInteractive } from "./set-secret.js";
4
+ import chalk from "chalk";
5
+ import { ZodError } from "zod";
6
+ //#region src/commands/doppler/handler.js
7
+ /**
8
+ * Main doppler command handler
9
+ * @param {unknown} options - Command options (will be validated)
10
+ */
11
+ async function dopplerCommand(options) {
12
+ try {
13
+ const rawOptions = options ?? {};
14
+ if (rawOptions.help || !rawOptions.action) {
15
+ console.log(chalk.bold(`\nUsage: @mtndev/cli doppler [options] <action>`));
16
+ console.log(dopplerCommandMetadata.description);
17
+ console.log(chalk.bold("\nOptions:"));
18
+ Object.entries(dopplerCommandMetadata.options).forEach(([key, optionMeta]) => {
19
+ const meta = optionMeta;
20
+ const alias = meta?.alias ? chalk.cyan(`, -${meta.alias}`) : "";
21
+ const defaultValue = meta?.default ?? false;
22
+ console.log(chalk.cyan(` --${key}`) + alias + ` ${meta.description} (default: ${defaultValue})`);
23
+ });
24
+ console.log("");
25
+ return;
26
+ }
27
+ const validatedOptions = dopplerCommandOptionsSchema.parse(options);
28
+ const { action, verbose } = validatedOptions;
29
+ if (action === "set") checkDopplerAuth(verbose);
30
+ else checkDependencies(verbose);
31
+ if (action === "download") {
32
+ const { environments } = validatedOptions;
33
+ await downloadConfigs({
34
+ environments,
35
+ verbose
36
+ });
37
+ } else if (action === "upload") {
38
+ const { environments } = validatedOptions;
39
+ await uploadConfigs({
40
+ environments,
41
+ verbose
42
+ });
43
+ } else if (action === "clone") {
44
+ const { from, to, force, environments } = validatedOptions;
45
+ await cloneProject({
46
+ from,
47
+ to,
48
+ environments,
49
+ force,
50
+ verbose
51
+ });
52
+ } else if (action === "set") {
53
+ const { project, environment, config, name, value, yes } = validatedOptions;
54
+ await setSecretInteractive({
55
+ project,
56
+ environment,
57
+ config,
58
+ name,
59
+ value,
60
+ yes,
61
+ verbose
62
+ });
63
+ }
64
+ console.log(chalk.green(`\n✅ Doppler ${action} completed successfully!`));
65
+ } catch (error) {
66
+ if (error instanceof ZodError) {
67
+ console.error(chalk.red(`\n❌ Invalid command options:`));
68
+ error.errors.forEach((err) => {
69
+ console.error(chalk.red(` ${err.path.join(".")}: ${err.message}`));
70
+ });
71
+ process.exit(1);
72
+ }
73
+ const action = options?.action || "operation";
74
+ const verbose = options?.verbose || false;
75
+ console.error(chalk.red(`\n❌ Doppler ${action} failed:`));
76
+ if (error instanceof Error) {
77
+ console.error(chalk.red(` ${error.message}`));
78
+ if (verbose && error.stack) {
79
+ console.error(chalk.gray("\nStack trace:"));
80
+ console.error(chalk.gray(error.stack));
81
+ }
82
+ } else console.error(chalk.red(` ${String(error)}`));
83
+ console.error(chalk.yellow("\n💡 Troubleshooting tips:"));
84
+ console.error(chalk.yellow(" • Ensure Doppler CLI is installed (brew install dopplerhq/cli/doppler)"));
85
+ console.error(chalk.yellow(" • Make sure you're logged in (doppler login)"));
86
+ console.error(chalk.yellow(" • Verify project is configured (doppler setup)"));
87
+ console.error(chalk.yellow(" • Use --verbose for detailed error information\n"));
88
+ process.exit(1);
89
+ }
90
+ }
91
+ //#endregion
92
+ export { dopplerCommand };
@@ -1,68 +1,6 @@
1
- import "../../__chunks/AZCP3SFJ.js";
2
- import {
3
- dopplerCommand
4
- } from "../../__chunks/YRG7PT33.js";
5
- import {
6
- getSecret,
7
- listConfigs,
8
- listEnvironments,
9
- listProjects,
10
- setSecret,
11
- setSecretInteractive
12
- } from "../../__chunks/QFXN4EHM.js";
13
- import {
14
- checkDependencies,
15
- checkDopplerAuth,
16
- cloneProject,
17
- createDiff,
18
- downloadConfigs,
19
- execDoppler,
20
- getConfigs,
21
- normalizeEscapeSequences,
22
- promptConfirmation,
23
- uploadConfigs
24
- } from "../../__chunks/YGWTVPZE.js";
25
- import "../../__chunks/ZHKVJO2U.js";
26
- import {
27
- exec,
28
- execJson,
29
- execNumber,
30
- execString
31
- } from "../../__chunks/SJXQJ7RS.js";
32
- import {
33
- dopplerCloneSchema,
34
- dopplerCommandMetadata,
35
- dopplerCommandOptionsSchema,
36
- dopplerDownloadSchema,
37
- dopplerSetSchema,
38
- dopplerUploadSchema
39
- } from "../../__chunks/KWUJP5MG.js";
40
- export {
41
- checkDependencies,
42
- checkDopplerAuth,
43
- cloneProject,
44
- createDiff,
45
- dopplerCloneSchema,
46
- dopplerCommand,
47
- dopplerCommandMetadata,
48
- dopplerCommandOptionsSchema,
49
- dopplerDownloadSchema,
50
- dopplerSetSchema,
51
- dopplerUploadSchema,
52
- downloadConfigs,
53
- exec,
54
- execDoppler,
55
- execJson,
56
- execNumber,
57
- execString,
58
- getConfigs,
59
- getSecret,
60
- listConfigs,
61
- listEnvironments,
62
- listProjects,
63
- normalizeEscapeSequences,
64
- promptConfirmation,
65
- setSecret,
66
- setSecretInteractive,
67
- uploadConfigs
68
- };
1
+ import { exec, execJson, execNumber, execString } from "./utils/exec.js";
2
+ import { dopplerCloneSchema, dopplerCommandMetadata, dopplerCommandOptionsSchema, dopplerDownloadSchema, dopplerSetSchema, dopplerUploadSchema } from "./schema.js";
3
+ import { checkDependencies, checkDopplerAuth, cloneProject, createDiff, downloadConfigs, execDoppler, getConfigs, normalizeEscapeSequences, promptConfirmation, uploadConfigs } from "./utils.js";
4
+ import { getSecret, listConfigs, listEnvironments, listProjects, setSecret, setSecretInteractive } from "./set-secret.js";
5
+ import { dopplerCommand } from "./handler.js";
6
+ export { checkDependencies, checkDopplerAuth, cloneProject, createDiff, dopplerCloneSchema, dopplerCommand, dopplerCommandMetadata, dopplerCommandOptionsSchema, dopplerDownloadSchema, dopplerSetSchema, dopplerUploadSchema, downloadConfigs, exec, execDoppler, execJson, execNumber, execString, getConfigs, getSecret, listConfigs, listEnvironments, listProjects, normalizeEscapeSequences, promptConfirmation, setSecret, setSecretInteractive, uploadConfigs };
@@ -1,16 +1,126 @@
1
- import {
2
- dopplerCloneSchema,
3
- dopplerCommandMetadata,
4
- dopplerCommandOptionsSchema,
5
- dopplerDownloadSchema,
6
- dopplerSetSchema,
7
- dopplerUploadSchema
8
- } from "../../__chunks/KWUJP5MG.js";
9
- export {
10
- dopplerCloneSchema,
11
- dopplerCommandMetadata,
12
- dopplerCommandOptionsSchema,
13
- dopplerDownloadSchema,
14
- dopplerSetSchema,
15
- dopplerUploadSchema
1
+ import { z } from "zod";
2
+ //#region src/commands/doppler/schema.js
3
+ const environmentsBase = z.string().optional().describe("Environments to process, comma-separated (e.g., dev,stg,prd or \"all\")");
4
+ const commonFields = {
5
+ verbose: z.boolean().optional().default(false).describe("Enable verbose logging for detailed error information"),
6
+ help: z.boolean().optional().default(false).describe("Display help for command")
16
7
  };
8
+ const dopplerDownloadSchema = z.object({
9
+ action: z.literal("download"),
10
+ environments: environmentsBase.default("dev"),
11
+ ...commonFields
12
+ });
13
+ const dopplerUploadSchema = z.object({
14
+ action: z.literal("upload"),
15
+ environments: environmentsBase.default("all"),
16
+ ...commonFields
17
+ });
18
+ const dopplerCloneSchema = z.object({
19
+ action: z.literal("clone"),
20
+ from: z.string({ required_error: "--from <project> is required for clone" }).describe("Source Doppler project name"),
21
+ to: z.string({ required_error: "--to <project> is required for clone" }).describe("Target Doppler project name"),
22
+ force: z.boolean().optional().default(false).describe("Skip confirmation prompts when overwriting existing secrets"),
23
+ environments: environmentsBase.default("all"),
24
+ ...commonFields
25
+ });
26
+ const dopplerSetSchema = z.object({
27
+ action: z.literal("set"),
28
+ project: z.string().optional().describe("Doppler project name (prompts when omitted)"),
29
+ environment: z.string().optional().describe("Doppler environment id (e.g. dev, stg, prd) or \"all\" (prompts when omitted)"),
30
+ config: z.string().optional().describe("Config name, comma-separated list, or \"all\" within the chosen environment (prompts when omitted)"),
31
+ name: z.string().optional().describe("Secret name / env var key (e.g. DATABASE_URL)"),
32
+ value: z.string().optional().describe("Secret value (prompts when omitted)"),
33
+ yes: z.boolean().optional().default(false).describe("Skip the confirmation prompt"),
34
+ ...commonFields
35
+ });
36
+ const dopplerCommandOptionsSchema = z.discriminatedUnion("action", [
37
+ dopplerDownloadSchema,
38
+ dopplerUploadSchema,
39
+ dopplerCloneSchema,
40
+ dopplerSetSchema
41
+ ]);
42
+ /**
43
+ * Doppler command metadata
44
+ * Descriptions are extracted from subcommand schemas, aliases are CLI-specific
45
+ */
46
+ const dopplerCommandMetadata = {
47
+ name: "doppler",
48
+ description: `Manage Doppler configurations
49
+
50
+ Subcommands:
51
+ download Download configurations from Doppler to local .env files
52
+ upload Upload local .env files to Doppler (with confirmation prompt)
53
+ clone Clone all secrets from one Doppler project to another
54
+ set Add or update a secret (interactive project/env/config picker)
55
+
56
+ Examples:
57
+ $ @mtndev/cli doppler download # Download dev config
58
+ $ @mtndev/cli doppler download -e all # Download all configs
59
+ $ @mtndev/cli doppler download -e dev,stg # Download dev and stg
60
+ $ @mtndev/cli doppler upload # Upload .env.dev
61
+ $ @mtndev/cli doppler upload -e prd # Upload production config
62
+ $ @mtndev/cli doppler clone --from my-app --to my-app-copy # Clone all configs
63
+ $ @mtndev/cli doppler clone --from my-app --to my-app-copy -e dev,stg # Clone specific envs
64
+ $ @mtndev/cli doppler clone --from my-app --to my-app-copy --force # Clone without prompts
65
+ $ @mtndev/cli doppler set # Interactive set
66
+ $ @mtndev/cli doppler set -p core --environment dev -c dev --name API_KEY --value secret --yes`,
67
+ options: {
68
+ environments: {
69
+ description: dopplerDownloadSchema.shape.environments.description,
70
+ default: "dev",
71
+ alias: "e"
72
+ },
73
+ from: {
74
+ description: dopplerCloneSchema.shape.from.description,
75
+ default: void 0
76
+ },
77
+ to: {
78
+ description: dopplerCloneSchema.shape.to.description,
79
+ default: void 0
80
+ },
81
+ force: {
82
+ description: dopplerCloneSchema.shape.force.description,
83
+ default: false,
84
+ alias: "f"
85
+ },
86
+ project: {
87
+ description: dopplerSetSchema.shape.project.description,
88
+ default: void 0,
89
+ alias: "p"
90
+ },
91
+ environment: {
92
+ description: dopplerSetSchema.shape.environment.description,
93
+ default: void 0
94
+ },
95
+ config: {
96
+ description: dopplerSetSchema.shape.config.description,
97
+ default: void 0,
98
+ alias: "c"
99
+ },
100
+ name: {
101
+ description: dopplerSetSchema.shape.name.description,
102
+ default: void 0
103
+ },
104
+ value: {
105
+ description: dopplerSetSchema.shape.value.description,
106
+ default: void 0
107
+ },
108
+ yes: {
109
+ description: dopplerSetSchema.shape.yes.description,
110
+ default: false,
111
+ alias: "y"
112
+ },
113
+ verbose: {
114
+ description: dopplerDownloadSchema.shape.verbose.description,
115
+ default: false,
116
+ alias: "v"
117
+ },
118
+ help: {
119
+ description: dopplerDownloadSchema.shape.help.description,
120
+ default: false,
121
+ alias: "h"
122
+ }
123
+ }
124
+ };
125
+ //#endregion
126
+ export { dopplerCloneSchema, dopplerCommandMetadata, dopplerCommandOptionsSchema, dopplerDownloadSchema, dopplerSetSchema, dopplerUploadSchema };