@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.
- package/CHANGELOG.md +13 -0
- package/cjs/__chunks/VH7oDXx4.cjs +28 -0
- package/cjs/commands/aws/ec2/allow-ip/handler.cjs +261 -12
- package/cjs/commands/aws/ec2/allow-ip/index.cjs +25 -55
- package/cjs/commands/aws/ec2/allow-ip/schema.cjs +33 -13
- package/cjs/commands/aws/ec2/allow-ip/utils.cjs +379 -39
- package/cjs/commands/aws/iam/admin-group.cjs +111 -15
- package/cjs/commands/aws/iam/break-glass/handler.cjs +127 -12
- package/cjs/commands/aws/iam/break-glass/index.cjs +7 -19
- package/cjs/commands/aws/iam/break-glass/schema.cjs +21 -12
- package/cjs/commands/aws/iam/check-admin/handler.cjs +89 -10
- package/cjs/commands/aws/iam/check-admin/index.cjs +7 -17
- package/cjs/commands/aws/iam/check-admin/schema.cjs +19 -12
- package/cjs/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
- package/cjs/commands/aws/iam/policies/sts-federation.json +11 -0
- package/cjs/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
- package/cjs/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
- package/cjs/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
- package/cjs/commands/aws/iam/policies/user-admins-write-list.json +117 -0
- package/cjs/commands/aws/iam/remove-admin/handler.cjs +120 -11
- package/cjs/commands/aws/iam/remove-admin/index.cjs +7 -18
- package/cjs/commands/aws/iam/remove-admin/schema.cjs +22 -12
- package/cjs/commands/aws/iam/setup-acl/handler.cjs +227 -14
- package/cjs/commands/aws/iam/setup-acl/index.cjs +13 -33
- package/cjs/commands/aws/iam/setup-acl/schema.cjs +19 -7
- package/cjs/commands/aws/iam/setup-acl/utils.cjs +305 -20
- package/cjs/commands/aws/iam/users/handler.cjs +59 -12
- package/cjs/commands/aws/iam/users/index.cjs +18 -41
- package/cjs/commands/aws/iam/users/schema.cjs +17 -7
- package/cjs/commands/aws/iam/users/utils.cjs +454 -30
- package/cjs/commands/aws/index.cjs +223 -229
- package/cjs/commands/aws/route53/add-record/handler.cjs +264 -18
- package/cjs/commands/aws/route53/add-record/index.cjs +26 -57
- package/cjs/commands/aws/route53/add-record/schema.cjs +43 -11
- package/cjs/commands/aws/route53/add-record/utils.cjs +404 -37
- package/cjs/commands/aws/route53/remove-record/handler.cjs +114 -14
- package/cjs/commands/aws/route53/remove-record/index.cjs +5 -18
- package/cjs/commands/aws/route53/remove-record/schema.cjs +22 -8
- package/cjs/commands/aws/schema.cjs +19 -10
- package/cjs/commands/aws/ses/send-email/handler.cjs +73 -12
- package/cjs/commands/aws/ses/send-email/index.cjs +9 -23
- package/cjs/commands/aws/ses/send-email/schema.cjs +24 -7
- package/cjs/commands/aws/ses/send-email/utils.cjs +87 -11
- package/cjs/commands/aws/ses/smtp-password.cjs +72 -10
- package/cjs/commands/aws/utils/exec-aws.cjs +145 -16
- package/cjs/commands/aws/utils/resolve-policy-path.cjs +15 -6
- package/cjs/commands/aws/utils/resolve-profile.cjs +93 -11
- package/cjs/commands/aws/utils/tty.cjs +54 -10
- package/cjs/commands/db/create-readonly-user/handler.cjs +254 -11
- package/cjs/commands/db/create-readonly-user/index.cjs +18 -40
- package/cjs/commands/db/create-readonly-user/mysql.cjs +102 -9
- package/cjs/commands/db/create-readonly-user/postgres.cjs +209 -9
- package/cjs/commands/db/create-readonly-user/schema.cjs +39 -12
- package/cjs/commands/db/create-readonly-user/utils.cjs +160 -22
- package/cjs/commands/db/index.cjs +46 -44
- package/cjs/commands/doppler/handler.cjs +95 -11
- package/cjs/commands/doppler/index.cjs +33 -68
- package/cjs/commands/doppler/schema.cjs +130 -14
- package/cjs/commands/doppler/set-secret.cjs +378 -19
- package/cjs/commands/doppler/utils/exec.cjs +106 -12
- package/cjs/commands/doppler/utils.cjs +412 -34
- package/cjs/commands/icons/handler.cjs +82 -8
- package/cjs/commands/icons/index.cjs +15 -31
- package/cjs/commands/icons/schema.cjs +101 -13
- package/cjs/commands/icons/utils.cjs +131 -13
- package/cjs/commands/index.cjs +54 -161
- package/cjs/commands/schema.cjs +25 -8
- package/cjs/index.cjs +3 -4
- package/esm/commands/aws/ec2/allow-ip/handler.js +258 -12
- package/esm/commands/aws/ec2/allow-ip/index.js +4 -55
- package/esm/commands/aws/ec2/allow-ip/schema.js +29 -13
- package/esm/commands/aws/ec2/allow-ip/utils.js +363 -39
- package/esm/commands/aws/iam/admin-group.js +104 -15
- package/esm/commands/aws/iam/break-glass/handler.js +124 -12
- package/esm/commands/aws/iam/break-glass/index.js +4 -19
- package/esm/commands/aws/iam/break-glass/schema.js +19 -12
- package/esm/commands/aws/iam/check-admin/handler.js +86 -10
- package/esm/commands/aws/iam/check-admin/index.js +4 -17
- package/esm/commands/aws/iam/check-admin/schema.js +17 -12
- package/esm/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
- package/esm/commands/aws/iam/policies/sts-federation.json +11 -0
- package/esm/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
- package/esm/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
- package/esm/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
- package/esm/commands/aws/iam/policies/user-admins-write-list.json +117 -0
- package/esm/commands/aws/iam/remove-admin/handler.js +117 -11
- package/esm/commands/aws/iam/remove-admin/index.js +4 -18
- package/esm/commands/aws/iam/remove-admin/schema.js +20 -12
- package/esm/commands/aws/iam/setup-acl/handler.js +224 -14
- package/esm/commands/aws/iam/setup-acl/index.js +4 -33
- package/esm/commands/aws/iam/setup-acl/schema.js +18 -7
- package/esm/commands/aws/iam/setup-acl/utils.js +298 -20
- package/esm/commands/aws/iam/users/handler.js +56 -12
- package/esm/commands/aws/iam/users/index.js +4 -41
- package/esm/commands/aws/iam/users/schema.js +16 -7
- package/esm/commands/aws/iam/users/utils.js +440 -30
- package/esm/commands/aws/index.js +142 -229
- package/esm/commands/aws/route53/add-record/handler.js +258 -18
- package/esm/commands/aws/route53/add-record/index.js +4 -57
- package/esm/commands/aws/route53/add-record/schema.js +40 -11
- package/esm/commands/aws/route53/add-record/utils.js +389 -37
- package/esm/commands/aws/route53/remove-record/handler.js +111 -14
- package/esm/commands/aws/route53/remove-record/index.js +3 -18
- package/esm/commands/aws/route53/remove-record/schema.js +21 -8
- package/esm/commands/aws/schema.js +16 -10
- package/esm/commands/aws/ses/send-email/handler.js +70 -12
- package/esm/commands/aws/ses/send-email/index.js +4 -23
- package/esm/commands/aws/ses/send-email/schema.js +23 -7
- package/esm/commands/aws/ses/send-email/utils.js +84 -11
- package/esm/commands/aws/ses/smtp-password.js +69 -10
- package/esm/commands/aws/utils/exec-aws.js +136 -15
- package/esm/commands/aws/utils/resolve-policy-path.js +14 -6
- package/esm/commands/aws/utils/resolve-profile.js +88 -11
- package/esm/commands/aws/utils/tty.js +51 -10
- package/esm/commands/db/create-readonly-user/handler.js +251 -11
- package/esm/commands/db/create-readonly-user/index.js +4 -40
- package/esm/commands/db/create-readonly-user/mysql.js +98 -9
- package/esm/commands/db/create-readonly-user/postgres.js +205 -9
- package/esm/commands/db/create-readonly-user/schema.js +35 -12
- package/esm/commands/db/create-readonly-user/utils.js +151 -22
- package/esm/commands/db/index.js +31 -44
- package/esm/commands/doppler/handler.js +92 -11
- package/esm/commands/doppler/index.js +6 -68
- package/esm/commands/doppler/schema.js +125 -15
- package/esm/commands/doppler/set-secret.js +370 -19
- package/esm/commands/doppler/utils/exec.js +100 -12
- package/esm/commands/doppler/utils.js +396 -34
- package/esm/commands/icons/handler.js +79 -8
- package/esm/commands/icons/index.js +4 -31
- package/esm/commands/icons/schema.js +97 -15
- package/esm/commands/icons/utils.js +125 -13
- package/esm/commands/index.js +47 -155
- package/esm/commands/schema.js +22 -7
- package/esm/index.js +3 -4
- package/package.json +5 -2
- package/vitest.config.ts +11 -0
- package/cjs/__chunks/2FSYDFUV.cjs +0 -146
- package/cjs/__chunks/3A5ZYU5M.cjs +0 -105
- package/cjs/__chunks/3BY5Y4W7.cjs +0 -1
- package/cjs/__chunks/3NOHGUCF.cjs +0 -9
- package/cjs/__chunks/3T2LXW7J.cjs +0 -387
- package/cjs/__chunks/4SFWHCB3.cjs +0 -133
- package/cjs/__chunks/4XT5JEAS.cjs +0 -1
- package/cjs/__chunks/AZEB4H4I.cjs +0 -208
- package/cjs/__chunks/B2KFW7T7.cjs +0 -1
- package/cjs/__chunks/B5ENMOCD.cjs +0 -288
- package/cjs/__chunks/B6XM5KSF.cjs +0 -338
- package/cjs/__chunks/BDU2UCE5.cjs +0 -1
- package/cjs/__chunks/BLMSMR5E.cjs +0 -46
- package/cjs/__chunks/CMUD7LLN.cjs +0 -47
- package/cjs/__chunks/DTQ2LB3I.cjs +0 -49
- package/cjs/__chunks/FM5MVRQF.cjs +0 -23
- package/cjs/__chunks/FRHST54J.cjs +0 -135
- package/cjs/__chunks/FU4VP2LN.cjs +0 -1
- package/cjs/__chunks/G5K4PVIL.cjs +0 -26
- package/cjs/__chunks/GU3R54MK.cjs +0 -127
- package/cjs/__chunks/GUL36IFZ.cjs +0 -61
- package/cjs/__chunks/GZMTNK5N.cjs +0 -1
- package/cjs/__chunks/H74JSDBU.cjs +0 -30
- package/cjs/__chunks/INFOPAHN.cjs +0 -117
- package/cjs/__chunks/J36P6UNE.cjs +0 -75
- package/cjs/__chunks/JB7T7PKQ.cjs +0 -538
- package/cjs/__chunks/JSL2JDMW.cjs +0 -1
- package/cjs/__chunks/K4QNHRTP.cjs +0 -163
- package/cjs/__chunks/KU76LC42.cjs +0 -192
- package/cjs/__chunks/LFDSHANP.cjs +0 -34
- package/cjs/__chunks/LHE24ECK.cjs +0 -192
- package/cjs/__chunks/LIKQ3SI4.cjs +0 -1
- package/cjs/__chunks/LXDF5QVZ.cjs +0 -313
- package/cjs/__chunks/LXOOJR2R.cjs +0 -74
- package/cjs/__chunks/N5MXFOQZ.cjs +0 -167
- package/cjs/__chunks/N7D56LPP.cjs +0 -25
- package/cjs/__chunks/NFXQNOQH.cjs +0 -393
- package/cjs/__chunks/NIMXXHJQ.cjs +0 -92
- package/cjs/__chunks/NLKJIUEX.cjs +0 -126
- package/cjs/__chunks/NT2XXAI6.cjs +0 -89
- package/cjs/__chunks/NWZGFHKH.cjs +0 -121
- package/cjs/__chunks/R3GUC7O7.cjs +0 -110
- package/cjs/__chunks/RPVAXPJ4.cjs +0 -1
- package/cjs/__chunks/S3LVCWPN.cjs +0 -23
- package/cjs/__chunks/SBBNW2BF.cjs +0 -249
- package/cjs/__chunks/T2A7TN4F.cjs +0 -81
- package/cjs/__chunks/TKNNDDIB.cjs +0 -97
- package/cjs/__chunks/TNSRDJPR.cjs +0 -1
- package/cjs/__chunks/UWHPE2GI.cjs +0 -20
- package/cjs/__chunks/W6K7BV74.cjs +0 -1
- package/cjs/__chunks/WBOQ6AUN.cjs +0 -320
- package/cjs/__chunks/WHGN5PZI.cjs +0 -299
- package/cjs/__chunks/WOYF2L6T.cjs +0 -11
- package/cjs/__chunks/X26XY2N6.cjs +0 -18
- package/cjs/__chunks/XMKOKRXZ.cjs +0 -16
- package/cjs/__chunks/XTJPQ3EX.cjs +0 -1
- package/cjs/__chunks/YRHFKTW2.cjs +0 -63
- package/cjs/__chunks/ZMDIOZPT.cjs +0 -22
- package/cjs/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.cjs +0 -28
- package/cjs/commands/aws/iam/policies/sts-federation.cjs +0 -19
- package/cjs/commands/aws/iam/policies/user-admins-deny-list.cjs +0 -183
- package/cjs/commands/aws/iam/policies/user-admins-deny-regions-list.cjs +0 -49
- package/cjs/commands/aws/iam/policies/user-admins-self-service-iam.cjs +0 -64
- package/cjs/commands/aws/iam/policies/user-admins-write-list.cjs +0 -125
- package/esm/__chunks/2FTTEFEK.js +0 -97
- package/esm/__chunks/33UYMUQD.js +0 -338
- package/esm/__chunks/3BKWTHLJ.js +0 -25
- package/esm/__chunks/3HE4BEJX.js +0 -105
- package/esm/__chunks/3QLI5BDL.js +0 -387
- package/esm/__chunks/5GIUAFXL.js +0 -89
- package/esm/__chunks/5ZBVGSOK.js +0 -0
- package/esm/__chunks/6G4PXXKF.js +0 -75
- package/esm/__chunks/73BJG53F.js +0 -11
- package/esm/__chunks/7VF4Q43Q.js +0 -0
- package/esm/__chunks/AEDEAYF5.js +0 -0
- package/esm/__chunks/AZCP3SFJ.js +0 -0
- package/esm/__chunks/B2DVQ2UL.js +0 -61
- package/esm/__chunks/CVQVHLW5.js +0 -0
- package/esm/__chunks/D62SPZXC.js +0 -0
- package/esm/__chunks/DLEJ25GZ.js +0 -121
- package/esm/__chunks/DMYFNF54.js +0 -192
- package/esm/__chunks/DNFTUMGD.js +0 -23
- package/esm/__chunks/DVKD6YSR.js +0 -49
- package/esm/__chunks/EMSH4P76.js +0 -20
- package/esm/__chunks/FFKFVMIE.js +0 -167
- package/esm/__chunks/FL7AILGH.js +0 -133
- package/esm/__chunks/FNXUONAV.js +0 -110
- package/esm/__chunks/G4NJHFFU.js +0 -320
- package/esm/__chunks/HJSXC6HP.js +0 -117
- package/esm/__chunks/IEOGAQYI.js +0 -46
- package/esm/__chunks/IZFGBYGE.js +0 -34
- package/esm/__chunks/J34UVKLA.js +0 -26
- package/esm/__chunks/JZPBBBIG.js +0 -74
- package/esm/__chunks/KWUJP5MG.js +0 -135
- package/esm/__chunks/M35URMT4.js +0 -313
- package/esm/__chunks/NF3M2L6C.js +0 -81
- package/esm/__chunks/O3CCA76Q.js +0 -22
- package/esm/__chunks/PNPPDYKC.js +0 -299
- package/esm/__chunks/QFXN4EHM.js +0 -393
- package/esm/__chunks/QKDDLIWD.js +0 -146
- package/esm/__chunks/QSE66AKY.js +0 -208
- package/esm/__chunks/QUF7PS4R.js +0 -18
- package/esm/__chunks/S7IJPJ4R.js +0 -126
- package/esm/__chunks/SD3E3EPH.js +0 -163
- package/esm/__chunks/SJXQJ7RS.js +0 -92
- package/esm/__chunks/SNCKIAOR.js +0 -0
- package/esm/__chunks/T3TTUHTW.js +0 -30
- package/esm/__chunks/TIOVE6HR.js +0 -0
- package/esm/__chunks/TXKMEIDQ.js +0 -0
- package/esm/__chunks/U7HAE2RF.js +0 -288
- package/esm/__chunks/UXWY7BYE.js +0 -63
- package/esm/__chunks/VKAKISRG.js +0 -192
- package/esm/__chunks/WD2YR6I7.js +0 -0
- package/esm/__chunks/WOZFZKFY.js +0 -0
- package/esm/__chunks/XI7GZDE2.js +0 -0
- package/esm/__chunks/XOUWDB3T.js +0 -249
- package/esm/__chunks/XQN2TA4S.js +0 -23
- package/esm/__chunks/XXK32TIM.js +0 -16
- package/esm/__chunks/YGWTVPZE.js +0 -538
- package/esm/__chunks/YRG7PT33.js +0 -127
- package/esm/__chunks/ZHKVJO2U.js +0 -47
- package/esm/__chunks/ZO55YUSY.js +0 -9
- package/esm/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.js +0 -28
- package/esm/commands/aws/iam/policies/sts-federation.js +0 -19
- package/esm/commands/aws/iam/policies/user-admins-deny-list.js +0 -183
- package/esm/commands/aws/iam/policies/user-admins-deny-regions-list.js +0 -49
- package/esm/commands/aws/iam/policies/user-admins-self-service-iam.js +0 -64
- package/esm/commands/aws/iam/policies/user-admins-write-list.js +0 -125
|
@@ -1,34 +1,396 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
import { exec, execJson, execNumber, execString } from "./utils/exec.js";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import { copyFileSync, existsSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { createInterface } from "readline";
|
|
7
|
+
import { tmpdir } from "os";
|
|
8
|
+
//#region src/commands/doppler/utils.js
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {import('./utils/exec.js').VerbosityLevel} VerbosityLevel
|
|
11
|
+
* @typedef {import('./utils/exec.js').ExecOptions} ExecOptions
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_DOPPLER_ENVIRONMENT = "dev";
|
|
14
|
+
const DOPPLER_INTERNAL_KEYS = /* @__PURE__ */ new Set([
|
|
15
|
+
"DOPPLER_CONFIG",
|
|
16
|
+
"DOPPLER_ENVIRONMENT",
|
|
17
|
+
"DOPPLER_PROJECT"
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* Execute a doppler command and return the result
|
|
21
|
+
* @param {string[]} args - Command arguments
|
|
22
|
+
* @param {'string' | 'json'} parser - How to parse the output
|
|
23
|
+
* @param {boolean} silent - Suppress output
|
|
24
|
+
* @param {boolean} verbose - Show verbose output
|
|
25
|
+
* @returns {string | any}
|
|
26
|
+
*/
|
|
27
|
+
function execDoppler(args, parser = "string", silent = false, verbose = false) {
|
|
28
|
+
const command = `doppler ${args.join(" ")}`;
|
|
29
|
+
/** @type {import('./utils/exec.js').VerbosityLevel} */
|
|
30
|
+
let verbosity = "default";
|
|
31
|
+
if (verbose) verbosity = "verbose";
|
|
32
|
+
else if (silent) verbosity = "silent";
|
|
33
|
+
return exec(command, {
|
|
34
|
+
verbosity,
|
|
35
|
+
stdoutParser: parser,
|
|
36
|
+
throwOnError: true
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Check if the Doppler CLI is installed and the user is logged in.
|
|
41
|
+
* Does not require a local project setup (doppler setup).
|
|
42
|
+
* @param {boolean} verbose - Show verbose output
|
|
43
|
+
*/
|
|
44
|
+
function checkDopplerAuth(verbose = false) {
|
|
45
|
+
if (verbose) console.log(chalk.blue("\n🔍 Checking Doppler authentication..."));
|
|
46
|
+
try {
|
|
47
|
+
execSync("which doppler", { stdio: "pipe" });
|
|
48
|
+
if (verbose) console.log(chalk.green(" ✓ Doppler CLI is installed"));
|
|
49
|
+
} catch {
|
|
50
|
+
throw new Error("Doppler is not installed. Please install Doppler (brew install dopplerhq/cli/doppler), login, and try again.");
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
execDoppler(["me"], "string", true, verbose);
|
|
54
|
+
if (verbose) console.log(chalk.green(" ✓ Doppler is authenticated"));
|
|
55
|
+
} catch {
|
|
56
|
+
throw new Error("Doppler is not logged in. Please run 'doppler login' and try again.");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Check if doppler CLI is installed, logged in, and a project is configured.
|
|
61
|
+
* @param {boolean} verbose - Show verbose output
|
|
62
|
+
*/
|
|
63
|
+
function checkDependencies(verbose = false) {
|
|
64
|
+
checkDopplerAuth(verbose);
|
|
65
|
+
if (verbose) console.log(chalk.blue("\n🔍 Checking Doppler project setup..."));
|
|
66
|
+
try {
|
|
67
|
+
execDoppler(["configs", "--json"], "json", true, verbose);
|
|
68
|
+
if (verbose) console.log(chalk.green(" ✓ Doppler project is configured"));
|
|
69
|
+
} catch {
|
|
70
|
+
throw new Error("Doppler is not configured. Please run 'doppler setup' and try again.");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get list of configurations based on environments parameter
|
|
75
|
+
* @param {string} environments - Comma-separated env names ('all', 'dev', 'dev,stg', etc.)
|
|
76
|
+
* @param {boolean} verbose - Show verbose output
|
|
77
|
+
* @param {string | null} project - Optional Doppler project name
|
|
78
|
+
* @returns {string[]}
|
|
79
|
+
*/
|
|
80
|
+
function getConfigs(environments, verbose = false, project = null) {
|
|
81
|
+
if (verbose) console.log(chalk.blue(`\n📋 Resolving configurations for environments: ${chalk.cyan(environments)}`));
|
|
82
|
+
const configArgs = ["configs", "--json"];
|
|
83
|
+
if (project) configArgs.push("--project", project);
|
|
84
|
+
const availableConfigs = execDoppler(configArgs, "json", true, verbose);
|
|
85
|
+
const configNames = Array.isArray(availableConfigs) ? availableConfigs.map((config) => config.name) : [];
|
|
86
|
+
if (verbose && configNames.length > 0) console.log(chalk.gray(` Available configurations: ${configNames.join(", ")}`));
|
|
87
|
+
if (environments === "all") {
|
|
88
|
+
if (configNames.length === 0) throw new Error("No configurations found in Doppler");
|
|
89
|
+
if (verbose) console.log(chalk.green(` ✓ Using all ${configNames.length} configurations`));
|
|
90
|
+
return configNames;
|
|
91
|
+
}
|
|
92
|
+
const requested = environments.split(",").map((e) => e.trim());
|
|
93
|
+
if (configNames.length > 0) {
|
|
94
|
+
const missing = requested.filter((e) => !configNames.includes(e));
|
|
95
|
+
if (missing.length > 0) throw new Error(`Configurations not found: ${missing.join(", ")}. Available: ${configNames.join(", ")}`);
|
|
96
|
+
}
|
|
97
|
+
if (verbose) console.log(chalk.green(` ✓ Using configurations: ${requested.join(", ")}`));
|
|
98
|
+
return requested;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Normalize escape sequences in file content
|
|
102
|
+
* @param {string} content - File content
|
|
103
|
+
* @returns {string}
|
|
104
|
+
*/
|
|
105
|
+
function normalizeEscapeSequences(content) {
|
|
106
|
+
return content.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\r/g, "\r");
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create a unified diff between two strings
|
|
110
|
+
* @param {string} oldContent - Original content
|
|
111
|
+
* @param {string} newContent - New content
|
|
112
|
+
* @returns {string[]}
|
|
113
|
+
*/
|
|
114
|
+
function createDiff(oldContent, newContent) {
|
|
115
|
+
const oldLines = oldContent.split("\n");
|
|
116
|
+
const newLines = newContent.split("\n");
|
|
117
|
+
const diff = [];
|
|
118
|
+
const maxLines = Math.max(oldLines.length, newLines.length);
|
|
119
|
+
for (let i = 0; i < maxLines; i++) {
|
|
120
|
+
const oldLine = oldLines[i] || "";
|
|
121
|
+
const newLine = newLines[i] || "";
|
|
122
|
+
if (oldLine !== newLine) {
|
|
123
|
+
if (oldLine && !newLine) diff.push(`-${oldLine}`);
|
|
124
|
+
else if (!oldLine && newLine) diff.push(`+${newLine}`);
|
|
125
|
+
else {
|
|
126
|
+
diff.push(`-${oldLine}`);
|
|
127
|
+
diff.push(`+${newLine}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return diff;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Prompt user for confirmation
|
|
135
|
+
* @param {string} message - Prompt message
|
|
136
|
+
* @returns {Promise<boolean>}
|
|
137
|
+
*/
|
|
138
|
+
function promptConfirmation(message) {
|
|
139
|
+
return new Promise((resolve) => {
|
|
140
|
+
const rl = createInterface({
|
|
141
|
+
input: process.stdin,
|
|
142
|
+
output: process.stdout
|
|
143
|
+
});
|
|
144
|
+
rl.question(message, (answer) => {
|
|
145
|
+
rl.close();
|
|
146
|
+
resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Download configurations from Doppler
|
|
152
|
+
* @param {{
|
|
153
|
+
* verbose: boolean;
|
|
154
|
+
* environments: string;
|
|
155
|
+
* }} options - Options for downloading configurations
|
|
156
|
+
*/
|
|
157
|
+
async function downloadConfigs(options) {
|
|
158
|
+
const { environments, verbose } = options;
|
|
159
|
+
const actualEnvironments = environments ?? DEFAULT_DOPPLER_ENVIRONMENT;
|
|
160
|
+
const configs = getConfigs(actualEnvironments, verbose);
|
|
161
|
+
if (verbose) console.log(chalk.blue(`\n⬇️ Starting download process for ${configs.length} configuration(s)...`));
|
|
162
|
+
if (configs.length === 1 && actualEnvironments !== "all") console.log("You can use -e all to download all configurations, or -e dev,stg for specific environments.");
|
|
163
|
+
for (const config of configs) {
|
|
164
|
+
const envFile = `.env.${config}`;
|
|
165
|
+
const backupFile = `${envFile}.backup`;
|
|
166
|
+
let backupMsg = "";
|
|
167
|
+
if (verbose) console.log(chalk.blue(`\n📦 Processing config: ${chalk.cyan(config)}`));
|
|
168
|
+
try {
|
|
169
|
+
if (existsSync(envFile)) {
|
|
170
|
+
if (verbose) console.log(chalk.gray(` Creating backup: ${backupFile}`));
|
|
171
|
+
renameSync(envFile, backupFile);
|
|
172
|
+
backupMsg = "Backed up existing file, ";
|
|
173
|
+
}
|
|
174
|
+
if (verbose) console.log(chalk.gray(` Downloading secrets from Doppler...`));
|
|
175
|
+
const content = execDoppler([
|
|
176
|
+
"secrets",
|
|
177
|
+
"download",
|
|
178
|
+
"--no-file",
|
|
179
|
+
"--format",
|
|
180
|
+
"env",
|
|
181
|
+
"--config",
|
|
182
|
+
config
|
|
183
|
+
], "string", !verbose, verbose);
|
|
184
|
+
if (typeof content === "string") {
|
|
185
|
+
writeFileSync(envFile, content, "utf-8");
|
|
186
|
+
if (verbose) console.log(chalk.gray(` Written to: ${envFile}`));
|
|
187
|
+
} else throw new Error("Invalid content received from Doppler");
|
|
188
|
+
console.log(`Config ${chalk.blue(config)}: ${backupMsg}downloaded successfully to ${chalk.green(envFile)}`);
|
|
189
|
+
if (config === "dev" && !existsSync(".env")) {
|
|
190
|
+
copyFileSync(envFile, ".env");
|
|
191
|
+
console.log(`Copied ${chalk.green(".env.dev")} to ${chalk.green(".env")}`);
|
|
192
|
+
}
|
|
193
|
+
if (existsSync(backupFile)) {
|
|
194
|
+
if (verbose) console.log(chalk.gray(` Removing backup file`));
|
|
195
|
+
unlinkSync(backupFile);
|
|
196
|
+
}
|
|
197
|
+
} catch (error) {
|
|
198
|
+
console.error(`Failed to download ${config}: ${error?.message || error}`);
|
|
199
|
+
if (existsSync(backupFile)) {
|
|
200
|
+
renameSync(backupFile, envFile);
|
|
201
|
+
console.log(`Restored backup for ${envFile}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Upload configurations to Doppler
|
|
208
|
+
* @param {{
|
|
209
|
+
* environments: string;
|
|
210
|
+
* verbose: boolean;
|
|
211
|
+
* }} options - Options for uploading configurations
|
|
212
|
+
*/
|
|
213
|
+
async function uploadConfigs(options) {
|
|
214
|
+
const { environments, verbose } = options;
|
|
215
|
+
const configs = getConfigs(environments, verbose);
|
|
216
|
+
if (verbose) console.log(chalk.blue(`\n⬆️ Starting upload process for ${configs.length} configuration(s)...`));
|
|
217
|
+
for (const config of configs) {
|
|
218
|
+
const envFile = `.env.${config}`;
|
|
219
|
+
const backupFile = `${envFile}.doppler`;
|
|
220
|
+
const normalizedFile = `${envFile}.normalized`;
|
|
221
|
+
if (verbose) console.log(chalk.blue(`\n📦 Processing config: ${chalk.cyan(config)}`));
|
|
222
|
+
try {
|
|
223
|
+
if (!existsSync(envFile)) {
|
|
224
|
+
console.log(`Config ${config}: ${chalk.green(envFile)} does not exist. Skipping upload.`);
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (verbose) console.log(chalk.gray(` Creating backup of current Doppler config...`));
|
|
228
|
+
try {
|
|
229
|
+
const backupContent = execDoppler([
|
|
230
|
+
"secrets",
|
|
231
|
+
"download",
|
|
232
|
+
"--no-file",
|
|
233
|
+
"--format",
|
|
234
|
+
"env",
|
|
235
|
+
"--config",
|
|
236
|
+
config
|
|
237
|
+
], "string", !verbose, verbose);
|
|
238
|
+
if (typeof backupContent === "string") {
|
|
239
|
+
writeFileSync(backupFile, backupContent, "utf-8");
|
|
240
|
+
if (verbose) console.log(chalk.gray(` Backup created: ${backupFile}`));
|
|
241
|
+
} else throw new Error("Invalid backup content received from Doppler");
|
|
242
|
+
} catch {
|
|
243
|
+
console.log(`Config ${config}: Failed to create backup. Skipping upload.`);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (verbose) console.log(chalk.gray(` Reading local file: ${envFile}`));
|
|
247
|
+
const normalizedContent = normalizeEscapeSequences(readFileSync(envFile, "utf-8"));
|
|
248
|
+
writeFileSync(normalizedFile, normalizedContent, "utf-8");
|
|
249
|
+
if (verbose) console.log(chalk.gray(` Comparing local changes with Doppler...`));
|
|
250
|
+
const diff = createDiff(readFileSync(backupFile, "utf-8"), normalizedContent);
|
|
251
|
+
if (diff.length === 0) {
|
|
252
|
+
console.log(`Config ${config}: No differences found. Skipping upload.`);
|
|
253
|
+
unlinkSync(backupFile);
|
|
254
|
+
unlinkSync(normalizedFile);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (verbose) console.log(chalk.yellow(` Found ${diff.length} line changes`));
|
|
258
|
+
console.log("\nChanges to be uploaded:");
|
|
259
|
+
for (const line of diff) if (line.startsWith("-")) console.log(chalk.red(line));
|
|
260
|
+
else if (line.startsWith("+")) console.log(chalk.green(line));
|
|
261
|
+
if (!await promptConfirmation("\nDo you want to proceed with the upload? (y/n) ")) {
|
|
262
|
+
console.log(`Upload cancelled for ${chalk.green(envFile)}`);
|
|
263
|
+
unlinkSync(backupFile);
|
|
264
|
+
unlinkSync(normalizedFile);
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (verbose) console.log(chalk.gray(` Uploading to Doppler...`));
|
|
268
|
+
try {
|
|
269
|
+
execDoppler([
|
|
270
|
+
"secrets",
|
|
271
|
+
"upload",
|
|
272
|
+
normalizedFile,
|
|
273
|
+
"--config",
|
|
274
|
+
config,
|
|
275
|
+
"--silent"
|
|
276
|
+
], "string", !verbose, verbose);
|
|
277
|
+
if (config === "dev") console.log(`Config ${chalk.blue(config)}: Successfully uploaded ${chalk.green(envFile)}`);
|
|
278
|
+
else console.log(`Config ${config}: Successfully uploaded ${chalk.green(envFile)}`);
|
|
279
|
+
} catch {
|
|
280
|
+
console.error(`Config ${config}: Failed to upload ${chalk.green(envFile)}. Restoring previous configuration.`);
|
|
281
|
+
try {
|
|
282
|
+
if (verbose) console.log(chalk.gray(` Restoring previous configuration...`));
|
|
283
|
+
execDoppler([
|
|
284
|
+
"secrets",
|
|
285
|
+
"upload",
|
|
286
|
+
backupFile,
|
|
287
|
+
"--config",
|
|
288
|
+
config,
|
|
289
|
+
"--silent"
|
|
290
|
+
], "string", !verbose, verbose);
|
|
291
|
+
console.log(`Config ${config}: Successfully restored previous configuration`);
|
|
292
|
+
} catch {
|
|
293
|
+
console.error(`Config ${config}: Failed to restore previous configuration`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (existsSync(backupFile)) unlinkSync(backupFile);
|
|
297
|
+
if (existsSync(normalizedFile)) unlinkSync(normalizedFile);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
console.error(`Error processing config ${config}: ${error?.message || error}`);
|
|
300
|
+
if (existsSync(backupFile)) unlinkSync(backupFile);
|
|
301
|
+
if (existsSync(normalizedFile)) unlinkSync(normalizedFile);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Clone secrets from one Doppler project to another
|
|
307
|
+
* @param {{
|
|
308
|
+
* from: string;
|
|
309
|
+
* to: string;
|
|
310
|
+
* environments: string;
|
|
311
|
+
* force: boolean;
|
|
312
|
+
* verbose: boolean;
|
|
313
|
+
* }} options
|
|
314
|
+
*/
|
|
315
|
+
async function cloneProject({ from, to, environments, force, verbose }) {
|
|
316
|
+
if (verbose) console.log(chalk.blue(`\n🔁 Cloning from ${chalk.cyan(from)} to ${chalk.cyan(to)}...`));
|
|
317
|
+
const configsToClone = getConfigs(environments, verbose, from);
|
|
318
|
+
if (configsToClone.length === 0) throw new Error(`No configurations found in source project "${from}"`);
|
|
319
|
+
const targetConfigsRaw = execDoppler([
|
|
320
|
+
"configs",
|
|
321
|
+
"--json",
|
|
322
|
+
"--project",
|
|
323
|
+
to
|
|
324
|
+
], "json", true, verbose);
|
|
325
|
+
const targetConfigNames = Array.isArray(targetConfigsRaw) ? targetConfigsRaw.map((c) => c.name) : [];
|
|
326
|
+
const missingInTarget = configsToClone.filter((c) => !targetConfigNames.includes(c));
|
|
327
|
+
if (missingInTarget.length > 0) throw new Error(`Configs missing in target project "${to}": ${missingInTarget.join(", ")}. Create them in Doppler first.`);
|
|
328
|
+
for (const config of configsToClone) {
|
|
329
|
+
if (verbose) console.log(chalk.blue(`\n📦 Processing config: ${chalk.cyan(config)}`));
|
|
330
|
+
const sourceSecrets = execDoppler([
|
|
331
|
+
"secrets",
|
|
332
|
+
"--json",
|
|
333
|
+
"--project",
|
|
334
|
+
from,
|
|
335
|
+
"--config",
|
|
336
|
+
config
|
|
337
|
+
], "json", true, verbose);
|
|
338
|
+
const sourceKeys = sourceSecrets ? Object.keys(sourceSecrets).filter((k) => !DOPPLER_INTERNAL_KEYS.has(k)) : [];
|
|
339
|
+
const targetSecrets = execDoppler([
|
|
340
|
+
"secrets",
|
|
341
|
+
"--json",
|
|
342
|
+
"--project",
|
|
343
|
+
to,
|
|
344
|
+
"--config",
|
|
345
|
+
config
|
|
346
|
+
], "json", true, verbose);
|
|
347
|
+
const targetKeys = targetSecrets ? Object.keys(targetSecrets) : [];
|
|
348
|
+
const conflicts = sourceKeys.filter((k) => targetKeys.includes(k));
|
|
349
|
+
if (conflicts.length > 0) {
|
|
350
|
+
if (process.env["CI"]) throw new Error(`Config "${config}" has ${conflicts.length} conflicting key(s) in target: ${conflicts.join(", ")}`);
|
|
351
|
+
if (!force) {
|
|
352
|
+
console.log(`\nConfig ${chalk.cyan(config)}: ${conflicts.length} key(s) already exist in ${chalk.cyan(to)}:`);
|
|
353
|
+
conflicts.forEach((k) => console.log(chalk.yellow(` • ${k}`)));
|
|
354
|
+
if (!await promptConfirmation(`\nOverwrite these keys in "${to}/${config}"? (y/n) `)) {
|
|
355
|
+
console.log(`Skipped ${chalk.blue(config)}`);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const tmpFile = join(tmpdir(), `doppler-clone-${config}-${Date.now()}.env`);
|
|
361
|
+
try {
|
|
362
|
+
const content = execDoppler([
|
|
363
|
+
"secrets",
|
|
364
|
+
"download",
|
|
365
|
+
"--no-file",
|
|
366
|
+
"--format",
|
|
367
|
+
"env",
|
|
368
|
+
"--project",
|
|
369
|
+
from,
|
|
370
|
+
"--config",
|
|
371
|
+
config
|
|
372
|
+
], "string", true, verbose);
|
|
373
|
+
if (typeof content !== "string" || !content) throw new Error(`No secrets returned for config "${config}"`);
|
|
374
|
+
const filtered = content.split("\n").filter((line) => {
|
|
375
|
+
const key = line.split("=")[0] ?? "";
|
|
376
|
+
return !DOPPLER_INTERNAL_KEYS.has(key);
|
|
377
|
+
}).join("\n");
|
|
378
|
+
writeFileSync(tmpFile, filtered, "utf-8");
|
|
379
|
+
execDoppler([
|
|
380
|
+
"secrets",
|
|
381
|
+
"upload",
|
|
382
|
+
tmpFile,
|
|
383
|
+
"--project",
|
|
384
|
+
to,
|
|
385
|
+
"--config",
|
|
386
|
+
config,
|
|
387
|
+
"--silent"
|
|
388
|
+
], "string", true, verbose);
|
|
389
|
+
console.log(`Config ${chalk.blue(config)}: cloned to ${chalk.green(to)}`);
|
|
390
|
+
} finally {
|
|
391
|
+
if (existsSync(tmpFile)) unlinkSync(tmpFile);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
//#endregion
|
|
396
|
+
export { checkDependencies, checkDopplerAuth, cloneProject, createDiff, downloadConfigs, exec, execDoppler, execJson, execNumber, execString, getConfigs, normalizeEscapeSequences, promptConfirmation, uploadConfigs };
|
|
@@ -1,8 +1,79 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import "
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
1
|
+
import { iconsCommandMetadata, iconsCommandOptionsSchema } from "./schema.js";
|
|
2
|
+
import { checkDependencies, generateAllIcons, validateBaseIcons } from "./utils.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { ZodError } from "zod";
|
|
5
|
+
//#region src/commands/icons/handler.js
|
|
6
|
+
/**
|
|
7
|
+
* Main icons command handler
|
|
8
|
+
* @param {unknown} options - Command options (will be validated)
|
|
9
|
+
*/
|
|
10
|
+
async function iconsCommand(options) {
|
|
11
|
+
try {
|
|
12
|
+
const validatedOptions = iconsCommandOptionsSchema.parse(options);
|
|
13
|
+
if (validatedOptions.help) {
|
|
14
|
+
console.log(chalk.bold(`\nUsage: mtn icons <input> [options]`));
|
|
15
|
+
console.log(chalk.gray(iconsCommandMetadata.description));
|
|
16
|
+
console.log(chalk.bold("\nOptions:"));
|
|
17
|
+
Object.entries(iconsCommandOptionsSchema.shape).forEach(([key, fieldSchema]) => {
|
|
18
|
+
if (key === "input") return;
|
|
19
|
+
const description = fieldSchema.description || "No description available";
|
|
20
|
+
const optionMeta = iconsCommandMetadata.options[key];
|
|
21
|
+
const defaultValue = optionMeta?.default ?? false;
|
|
22
|
+
const alias = optionMeta?.alias ? chalk.cyan(`, -${optionMeta.alias}`) : "";
|
|
23
|
+
console.log(chalk.cyan(` --${key}`) + alias + ` ${description} (default: ${defaultValue})`);
|
|
24
|
+
});
|
|
25
|
+
console.log("");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const { input, channels, iconTypes, verbose } = validatedOptions;
|
|
29
|
+
if (verbose) {
|
|
30
|
+
console.log(chalk.blue("\n📱 Icon Generation"));
|
|
31
|
+
console.log(chalk.gray(` Input directory: ${input}`));
|
|
32
|
+
console.log(chalk.gray(` Channels: ${channels.join(", ")}`));
|
|
33
|
+
console.log(chalk.gray(` Icon types: ${iconTypes.join(", ")}`));
|
|
34
|
+
}
|
|
35
|
+
checkDependencies(verbose);
|
|
36
|
+
validateBaseIcons(input, iconTypes, verbose);
|
|
37
|
+
const result = generateAllIcons({
|
|
38
|
+
baseDir: input,
|
|
39
|
+
channels,
|
|
40
|
+
iconTypes,
|
|
41
|
+
verbose
|
|
42
|
+
});
|
|
43
|
+
console.log(chalk.bold("\n📊 Summary:"));
|
|
44
|
+
console.log(chalk.green(` ✓ Successfully generated: ${result.success.length} icon(s)`));
|
|
45
|
+
if (result.failed.length > 0) {
|
|
46
|
+
console.log(chalk.red(` ✗ Failed: ${result.failed.length} icon(s)`));
|
|
47
|
+
result.failed.forEach(({ icon, error }) => {
|
|
48
|
+
console.log(chalk.red(` - ${icon}: ${error}`));
|
|
49
|
+
});
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
console.log(chalk.green(`\n✅ All icons generated successfully!`));
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error instanceof ZodError) {
|
|
55
|
+
console.error(chalk.red(`\n❌ Invalid command options:`));
|
|
56
|
+
error.errors.forEach((err) => {
|
|
57
|
+
console.error(chalk.red(` ${err.path.join(".")}: ${err.message}`));
|
|
58
|
+
});
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
const verbose = options?.verbose || false;
|
|
62
|
+
console.error(chalk.red(`\n❌ Icon generation failed:`));
|
|
63
|
+
if (error instanceof Error) {
|
|
64
|
+
console.error(chalk.red(` ${error.message}`));
|
|
65
|
+
if (verbose && error.stack) {
|
|
66
|
+
console.error(chalk.gray("\nStack trace:"));
|
|
67
|
+
console.error(chalk.gray(error.stack));
|
|
68
|
+
}
|
|
69
|
+
} else console.error(chalk.red(` ${String(error)}`));
|
|
70
|
+
console.error(chalk.yellow("\n💡 Troubleshooting tips:"));
|
|
71
|
+
console.error(chalk.yellow(" • Ensure ImageMagick is installed (brew install imagemagick)"));
|
|
72
|
+
console.error(chalk.yellow(" • Make sure icon.png and adaptive-icon.png exist in the input directory"));
|
|
73
|
+
console.error(chalk.yellow(" • Verify the input directory path is correct"));
|
|
74
|
+
console.error(chalk.yellow(" • Use --verbose for detailed error information\n"));
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { iconsCommand };
|
|
@@ -1,31 +1,4 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
checkDependencies,
|
|
7
|
-
generateAllIcons,
|
|
8
|
-
generateIcon,
|
|
9
|
-
validateBaseIcons
|
|
10
|
-
} from "../../__chunks/FL7AILGH.js";
|
|
11
|
-
import {
|
|
12
|
-
CHANNELS,
|
|
13
|
-
CHANNEL_TEXT_MAP,
|
|
14
|
-
ICON_SIZE_MAP,
|
|
15
|
-
ICON_TYPES,
|
|
16
|
-
iconsCommandMetadata,
|
|
17
|
-
iconsCommandOptionsSchema
|
|
18
|
-
} from "../../__chunks/6G4PXXKF.js";
|
|
19
|
-
export {
|
|
20
|
-
CHANNELS,
|
|
21
|
-
CHANNEL_TEXT_MAP,
|
|
22
|
-
ICON_SIZE_MAP,
|
|
23
|
-
ICON_TYPES,
|
|
24
|
-
checkDependencies,
|
|
25
|
-
generateAllIcons,
|
|
26
|
-
generateIcon,
|
|
27
|
-
iconsCommand,
|
|
28
|
-
iconsCommandMetadata,
|
|
29
|
-
iconsCommandOptionsSchema,
|
|
30
|
-
validateBaseIcons
|
|
31
|
-
};
|
|
1
|
+
import { CHANNELS, CHANNEL_TEXT_MAP, ICON_SIZE_MAP, ICON_TYPES, iconsCommandMetadata, iconsCommandOptionsSchema } from "./schema.js";
|
|
2
|
+
import { checkDependencies, generateAllIcons, generateIcon, validateBaseIcons } from "./utils.js";
|
|
3
|
+
import { iconsCommand } from "./handler.js";
|
|
4
|
+
export { CHANNELS, CHANNEL_TEXT_MAP, ICON_SIZE_MAP, ICON_TYPES, checkDependencies, generateAllIcons, generateIcon, iconsCommand, iconsCommandMetadata, iconsCommandOptionsSchema, validateBaseIcons };
|
|
@@ -1,16 +1,98 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/commands/icons/schema.js
|
|
3
|
+
/**
|
|
4
|
+
* Available channels for icon generation
|
|
5
|
+
*/
|
|
6
|
+
const CHANNELS = [
|
|
7
|
+
"dev",
|
|
8
|
+
"staging",
|
|
9
|
+
"test"
|
|
10
|
+
];
|
|
11
|
+
/**
|
|
12
|
+
* Available icon types
|
|
13
|
+
*/
|
|
14
|
+
const ICON_TYPES = ["icon", "adaptive-icon"];
|
|
15
|
+
/**
|
|
16
|
+
* Channel text mapping for icon overlay
|
|
17
|
+
*/
|
|
18
|
+
const CHANNEL_TEXT_MAP = {
|
|
19
|
+
dev: "DEV",
|
|
20
|
+
local: "LOC",
|
|
21
|
+
staging: "STG",
|
|
22
|
+
test: "TST"
|
|
16
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Icon type to point size mapping
|
|
26
|
+
*/
|
|
27
|
+
const ICON_SIZE_MAP = {
|
|
28
|
+
"adaptive-icon": 250,
|
|
29
|
+
icon: 378
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Zod schema for icons command options
|
|
33
|
+
*/
|
|
34
|
+
const iconsCommandOptionsSchema = z.object({
|
|
35
|
+
input: z.string().describe("Path to the input image directory containing icon.png and adaptive-icon.png"),
|
|
36
|
+
channels: z.array(z.enum([
|
|
37
|
+
"dev",
|
|
38
|
+
"local",
|
|
39
|
+
"staging",
|
|
40
|
+
"test"
|
|
41
|
+
])).optional().default([
|
|
42
|
+
"dev",
|
|
43
|
+
"local",
|
|
44
|
+
"staging",
|
|
45
|
+
"test"
|
|
46
|
+
]).describe("Channels to generate icons for"),
|
|
47
|
+
iconTypes: z.array(z.enum(["icon", "adaptive-icon"])).optional().default(["icon", "adaptive-icon"]).describe("Icon types to generate"),
|
|
48
|
+
verbose: z.boolean().optional().default(false).describe("Enable verbose logging for detailed error information"),
|
|
49
|
+
help: z.boolean().optional().default(false).describe("Display help for command")
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* Icons command metadata
|
|
53
|
+
*/
|
|
54
|
+
const iconsCommandMetadata = {
|
|
55
|
+
name: "icons",
|
|
56
|
+
description: `Generate app channel version icons with overlay text
|
|
57
|
+
|
|
58
|
+
This command generates icon variants for different app channels (dev, local, staging, test)
|
|
59
|
+
by overlaying text on base icon images using ImageMagick.
|
|
60
|
+
|
|
61
|
+
Requirements:
|
|
62
|
+
• ImageMagick must be installed (brew install imagemagick)
|
|
63
|
+
• Base icons (icon.png, adaptive-icon.png) must exist in the input directory
|
|
64
|
+
|
|
65
|
+
Examples:
|
|
66
|
+
$ mtn icons ./apps/my-app/assets # Generate all channel icons
|
|
67
|
+
$ mtn icons ./assets -c dev,staging # Generate only dev and staging icons
|
|
68
|
+
$ mtn icons ./assets -t icon # Generate only standard icons
|
|
69
|
+
$ mtn icons ./assets -v # Verbose output`,
|
|
70
|
+
options: {
|
|
71
|
+
input: {
|
|
72
|
+
description: iconsCommandOptionsSchema.shape.input.description,
|
|
73
|
+
required: true
|
|
74
|
+
},
|
|
75
|
+
channels: {
|
|
76
|
+
description: iconsCommandOptionsSchema.shape.channels.description,
|
|
77
|
+
default: "dev,local,staging,test",
|
|
78
|
+
alias: "c"
|
|
79
|
+
},
|
|
80
|
+
iconTypes: {
|
|
81
|
+
description: iconsCommandOptionsSchema.shape.iconTypes.description,
|
|
82
|
+
default: "icon,adaptive-icon",
|
|
83
|
+
alias: "t"
|
|
84
|
+
},
|
|
85
|
+
verbose: {
|
|
86
|
+
description: iconsCommandOptionsSchema.shape.verbose.description,
|
|
87
|
+
default: false,
|
|
88
|
+
alias: "v"
|
|
89
|
+
},
|
|
90
|
+
help: {
|
|
91
|
+
description: iconsCommandOptionsSchema.shape.help.description,
|
|
92
|
+
default: false,
|
|
93
|
+
alias: "h"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
//#endregion
|
|
98
|
+
export { CHANNELS, CHANNEL_TEXT_MAP, ICON_SIZE_MAP, ICON_TYPES, iconsCommandMetadata, iconsCommandOptionsSchema };
|