fscr 6.2.6 → 7.3.0

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 (72) hide show
  1. package/README.md +48 -30
  2. package/dist/index.js +502 -186
  3. package/dist/lib/auth/auth-conf.js +49 -45
  4. package/dist/lib/cache/README.md +341 -0
  5. package/dist/lib/cache/cli.js +152 -0
  6. package/dist/lib/cache/file-watcher.js +193 -0
  7. package/dist/lib/cache/index.js +422 -0
  8. package/dist/lib/cache/monitor.js +224 -0
  9. package/dist/lib/commands/doctor.js +225 -0
  10. package/dist/lib/completions/completion.js +342 -0
  11. package/dist/lib/completions/generator.js +152 -0
  12. package/dist/lib/completions/scripts/bash.sh +108 -0
  13. package/dist/lib/completions/scripts/fish.sh +105 -0
  14. package/dist/lib/completions/scripts/powershell.ps1 +168 -0
  15. package/dist/lib/completions/scripts/zsh.sh +124 -0
  16. package/dist/lib/diagnostics/cache.js +121 -0
  17. package/dist/lib/diagnostics/fileSystem.js +236 -0
  18. package/dist/lib/diagnostics/gitCheck.js +41 -0
  19. package/dist/lib/diagnostics/nodeVersion.js +68 -0
  20. package/dist/lib/diagnostics/packageManager.js +64 -0
  21. package/dist/lib/diagnostics/performance.js +141 -0
  22. package/dist/lib/encryption/decryptConfig.js +3 -2
  23. package/dist/lib/encryption/encryption.js +153 -113
  24. package/dist/lib/generators/generateFScripts.js +16 -13
  25. package/dist/lib/generators/generateToc.js +23 -14
  26. package/dist/lib/generators/index.js +1 -1
  27. package/dist/lib/git/pub.js +27 -17
  28. package/dist/lib/git/taskRunner.js +79 -69
  29. package/dist/lib/git/validateNotDev.js +65 -54
  30. package/dist/lib/optionList.js +69 -57
  31. package/dist/lib/parsers/parseScriptsMd.cached.js +208 -0
  32. package/dist/lib/parsers/parseScriptsMd.js +88 -79
  33. package/dist/lib/parsers/parseScriptsPackage.js +4 -3
  34. package/dist/lib/performance/cache.js +199 -0
  35. package/dist/lib/performance/lazy-loader.js +189 -0
  36. package/dist/lib/performance/monitor.js +303 -0
  37. package/dist/lib/plugins/deployment/index.js +113 -0
  38. package/dist/lib/plugins/hooks.js +17 -0
  39. package/dist/lib/plugins/loader.js +91 -0
  40. package/dist/lib/plugins/task-notifier/index.js +72 -0
  41. package/dist/lib/release/bump.js +50 -45
  42. package/dist/lib/release/commitWithMessage.js +80 -52
  43. package/dist/lib/release/publish.js +19 -14
  44. package/dist/lib/release/pushToGit.js +40 -31
  45. package/dist/lib/release/releasenotes.js +116 -97
  46. package/dist/lib/release/seeChangedFiles.js +68 -60
  47. package/dist/lib/release/sort.js +200 -116
  48. package/dist/lib/release/tree.js +161 -147
  49. package/dist/lib/release/validateNotDev.js +52 -44
  50. package/dist/lib/running/index.js +1 -1
  51. package/dist/lib/running/runCLICommand.js +41 -31
  52. package/dist/lib/running/runParallel.js +61 -59
  53. package/dist/lib/running/runSequence.js +55 -53
  54. package/dist/lib/startScripts.js +129 -114
  55. package/dist/lib/taskList.js +97 -90
  56. package/dist/lib/test-files/.fscripts.md +113 -0
  57. package/dist/lib/test-files/.fscripts.test.md +103 -0
  58. package/dist/lib/test-files/.fscriptsb.md +107 -0
  59. package/dist/lib/test-files/.mdtest.md +40 -0
  60. package/dist/lib/test-files/consoleSample.js +13 -9
  61. package/dist/lib/test-files/inputSample.js +17 -14
  62. package/dist/lib/test-files/testConsole.js +1 -1
  63. package/dist/lib/test-files/testInput.js +1 -1
  64. package/dist/lib/upgradePackages.js +56 -46
  65. package/dist/lib/utils/clear.js +16 -13
  66. package/dist/lib/utils/console.js +27 -21
  67. package/dist/lib/utils/encryption.js +55 -13
  68. package/dist/lib/utils/hash.js +128 -0
  69. package/dist/lib/utils/helpers.js +153 -142
  70. package/dist/lib/utils/index.js +1 -1
  71. package/dist/lib/utils/prompt.js +24 -29
  72. package/package.json +11 -29
@@ -0,0 +1,107 @@
1
+ <!-- toc -->
2
+
3
+ - [Build](#build)
4
+ * [v:publish](#vpublish)
5
+ * [script:js](#scriptjs)
6
+ - [Groups2](#groups2)
7
+ * [console:js](#consolejs)
8
+ * [input:js-](#inputjs-)
9
+ * [log:much:js](#logmuchjs)
10
+
11
+ <!-- tocstop -->
12
+
13
+ # Build
14
+
15
+ Build group description
16
+
17
+ ## v:publish
18
+
19
+ Update v and push
20
+
21
+ ```bash
22
+ sh publish.sh
23
+ ```
24
+
25
+ ## script:js
26
+
27
+ ```js
28
+ const chalk = require("chalk");
29
+ console.log(`${chalk.underline.bold("RUNS JS\n\nt")}`);
30
+ ```
31
+
32
+ # Groups2
33
+
34
+ That darn second group!!!!!
35
+
36
+ ## console:js
37
+
38
+ Only one script here with bash
39
+
40
+ ```bash
41
+ node src/sampleScripts/exampleLogTimeout.js
42
+ ```
43
+
44
+ ## input:js-
45
+
46
+ Get some input from user
47
+
48
+ ```bash
49
+ node src/sampleScripts/exampleInput.js
50
+ ```
51
+
52
+ ## log:much:js
53
+
54
+ Basically logs till yo momma says stop!
55
+
56
+ ```js
57
+ const chalk = require("chalk");
58
+ const sample = arr => arr[Math.floor(Math.random() * arr.length)];
59
+ const quotes = [
60
+ "The trickster's functiowhat they reslly s function is to break taboos, create mischief, stir things up. In the end, the trickster gives people what they res function is to break taboos, create mischief, stir things up. In the end, the trickster gives people what they rewant, some sort of freedom. - Tom Robbins",
61
+ '"Disbelief in magic can really s function is to break taboos, create mischief, stir things up. In the end, the trickster gives people what they res function is to break taboos, create mischief, stir things up. In the end, the trickster gives people what they rewant, some sort of freedom. - Tom Robbins",\n' +
62
+ ' "Disbelief in magic can force a poor soul into believing in government and business. - Tom Robbins',
63
+ 'The trouble with the fasforce a poor soul into believing in government and business. - Tom Robbins",\n' +
64
+ ' "The trouble with the fasforce a poor soul into believing in government and business. - Tom Robbins",\n' +
65
+ ' "The trouble with the fast lane is that all the movement is horizontal. And I like to go vertical sometimes. - Tom Robbins',
66
+ "Our world isn't made of earth, air and water or even molecules and atoms; our world is made of language. - Tom Robbimade of earth, air and water or even molecules and atoms; our world is made of language. - Tom Robbins",
67
+ "I'm not infatuated with frivoith frivoith frivoith frivoith frivoith frivoith frivoith frivolousness. We're just good friends. - Tom Robbins",
68
+ "In fiction, when you paint yourself into a corner, you can write a pair of suction cups onto the bottoms of your shoes and walk up the wall and out the skylight and see the sun breaking through the clouds. In nonfiction, you don't have that luxury. - Tom Robbins"
69
+ ];
70
+ let sxy;
71
+ const getOption = st => {
72
+ // if (Math.random() > 0.5) {
73
+ // st = st + sample(quotes) + sample(quotes) + sample(quotes);
74
+ // }
75
+ let options = [
76
+ chalk.blue(st),
77
+ chalk.underline.green(st),
78
+ chalk.green.bgRed.bold(st),
79
+ chalk.blue(st, st, st, st),
80
+ chalk.red(st, chalk.underline.bgBlue(st) + st)
81
+ ];
82
+ return sample(options);
83
+ };
84
+ let isMil = 0;
85
+ const theRun = async () => {
86
+ return new Promise(resolve => {
87
+ sxy = setInterval(() => {
88
+ const qt = sample(quotes);
89
+ console.log(new Date() + " ------- ----- ---- \n");
90
+ console.log(getOption(qt));
91
+ console.log(new Date() + " ------- ----- ---- \n");
92
+ console.log("----- ---- \n");
93
+ console.log("----- ---- \n");
94
+ console.log("----- ---- \n");
95
+ if (isMil === 30) {
96
+ clearInterval(sxy);
97
+ console.log("DONE DONE DONE");
98
+ resolve();
99
+ } else {
100
+ isMil += 10;
101
+ }
102
+ }, 1000);
103
+ });
104
+ };
105
+
106
+ theRun();
107
+ ```
@@ -0,0 +1,40 @@
1
+ # First category of scripts
2
+
3
+ Welcome to your new amazing .fscripts.md file. It replaces the headaches of npm scripts! But so much more.
4
+
5
+
6
+ ## fsr
7
+
8
+ TBD
9
+
10
+ ```bash
11
+ node bin/run
12
+ ```
13
+
14
+
15
+ ## fsr:d
16
+
17
+ TBD
18
+
19
+ ```bash
20
+ DEBUG=* node bin/run
21
+ ```
22
+
23
+
24
+ ## deploy
25
+
26
+ TBD
27
+
28
+ ```bash
29
+ node src/utils/release/publish.js
30
+ ```
31
+
32
+
33
+ ## pretty
34
+
35
+ TBD
36
+
37
+ ```bash
38
+ prettier src/*.js --write
39
+ ```
40
+
@@ -1,13 +1,17 @@
1
1
  import chalk from "chalk";
2
2
  import yargs from "yargs";
3
3
  const argv = yargs(process.argv.slice(2)).argv;
4
+
4
5
  (async function () {
5
- console.log(`${chalk.green("PRE --- TEST 52")} ${process.argv.slice(2)} ${JSON.stringify(argv)}`);
6
- await new Promise(resolve => {
7
- setTimeout(() => {
8
- console.log(`${chalk.green("ATTT --- TEST 52")}`);
9
- resolve();
10
- }, 3500);
11
- });
12
- console.log(`${chalk.green("POST --- TEST 52")}`);
13
- })();
6
+ console.log(
7
+ `${chalk.green("PRE --- TEST 52")} ${process.argv.slice(2)} ${JSON.stringify(argv)}`
8
+ );
9
+
10
+ await new Promise((resolve) => {
11
+ setTimeout(() => {
12
+ console.log(`${chalk.green("ATTT --- TEST 52")}`);
13
+ resolve();
14
+ }, 3500);
15
+ });
16
+ console.log(`${chalk.green("POST --- TEST 52")}`);
17
+ })();
@@ -1,17 +1,20 @@
1
1
  import chalk from "chalk";
2
2
  import inquirer from "inquirer";
3
+
3
4
  (async function () {
4
- console.log(`${chalk.green("PRE INPUT")}\n`);
5
- inquirer.prompt([{
6
- type: "list",
7
- name: "category",
8
- message: "What category do you want to run?",
9
- choices: [1, 2, 3, 4, 5]
10
- }]).then(({
11
- category
12
- }) => {
13
- console.log(`${chalk.green("CHOSEN ", category)}`);
14
- });
15
- console.log(`${chalk.green("POST INPUT")}`);
16
- console.log("NODEENV", process.env.INPUT);
17
- })();
5
+ console.log(`${chalk.green("PRE INPUT")}\n`);
6
+ inquirer
7
+ .prompt([
8
+ {
9
+ type: "list",
10
+ name: "category",
11
+ message: "What category do you want to run?",
12
+ choices: [1, 2, 3, 4, 5]
13
+ }
14
+ ])
15
+ .then(({ category }) => {
16
+ console.log(`${chalk.green("CHOSEN ", category)}`);
17
+ });
18
+ console.log(`${chalk.green("POST INPUT")}`);
19
+ console.log("NODEENV", process.env.INPUT);
20
+ })();
@@ -1 +1 @@
1
- console.log("TEST CONSOLE OUTPUT");
1
+ console.log("TEST CONSOLE OUTPUT");
@@ -1,2 +1,2 @@
1
1
  const input = process.env.INPUT || 'default';
2
- console.log(`INPUT: ${input}`);
2
+ console.log(`INPUT: ${input}`);
@@ -6,60 +6,70 @@ import { fileURLToPath } from "url";
6
6
  const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
  const logError = message => {
9
- console.log(chalk.red("[Error]: " + message));
9
+ console.log(chalk.red("[Error]: " + message));
10
10
  };
11
11
  const logInfo = message => {
12
- console.log(chalk.blue("[Start]: " + message));
12
+ console.log(chalk.blue("[Start]: " + message));
13
13
  };
14
14
  const logSuccess = message => {
15
- console.log(chalk.green("[Done]: " + message));
15
+ console.log(chalk.green("[Done]: " + message));
16
16
  };
17
+
17
18
  let global = "";
18
19
  let packagePath = path.resolve(process.cwd(), "package.json");
19
- if (!fs.existsSync(packagePath)) {
20
- logError("Cannot find package.json file in the current directory");
21
- process.exit(1);
22
- }
23
- const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
24
- let ignorePkgs = [];
20
+
25
21
  const upgradePackages = async () => {
26
- if (packageJson["fscripts"]) {
27
- if (packageJson["fscripts"]["ignore-upgrade"]) {
28
- ignorePkgs = packageJson["fscripts"]["ignore-upgrade"];
22
+ // Read package.json lazily so importing this module never crashes in a dir without one.
23
+ if (!fs.existsSync(packagePath)) {
24
+ logError("Cannot find package.json file in the current directory");
25
+ process.exit(1);
29
26
  }
30
- }
31
- let upgraded = {
32
- before: {},
33
- after: {}
34
- };
35
- for (let element of ["dependencies", "devDependencies", "peerDependencies"]) {
36
- if (packageJson[element]) {
37
- const packages = Object.keys(packageJson[element]);
38
- let packagesList = packages.filter(pkk => !ignorePkgs.includes(pkk)).map(pkk => {
39
- upgraded["before"][pkk] = packageJson[element][pkk];
40
- return pkk + "@latest";
41
- }).join(" ");
42
- let command = `yarn add ${packagesList}`;
43
- try {
44
- // logInfo(command);
45
- childProcess.execSync(command, {
46
- stdio: "inherit",
47
- env: Object.assign({}, process.env, {
48
- FORCE_COLOR: true,
49
- PATH: `${path.resolve("node_modules")}:${process.env.PATH}`
50
- })
51
- });
52
- const packageJsonAfter = JSON.parse(fs.readFileSync(packagePath));
53
- const packagesAfter = Object.keys(packageJsonAfter[element]);
54
- let packagesListAfter = packagesAfter.filter(pkk => !ignorePkgs.includes(pkk)).map(pkk => {
55
- upgraded["after"][pkk] = packageJsonAfter[element][pkk];
56
- return upgraded["before"][pkk] !== upgraded["after"][pkk] ? `Updated: ${pkk} from: ${upgraded["before"][pkk]} | to: ${upgraded["after"][pkk]}\n` : ``;
57
- }).join("");
58
- logSuccess(packagesListAfter);
59
- } catch (e) {
60
- logError(`${command} - ${e}`);
61
- }
27
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
28
+ let ignorePkgs = [];
29
+ if (packageJson["fscripts"]) {
30
+ if (packageJson["fscripts"]["ignore-upgrade"]) {
31
+ ignorePkgs = packageJson["fscripts"]["ignore-upgrade"];
32
+ }
33
+ }
34
+ let upgraded = { before: {}, after: {} };
35
+ for (let element of ["dependencies", "devDependencies", "peerDependencies"]) {
36
+ if (packageJson[element]) {
37
+ const packages = Object.keys(packageJson[element]);
38
+ let packagesList = packages
39
+ .filter(pkk => !ignorePkgs.includes(pkk))
40
+ .map(pkk => {
41
+ upgraded["before"][pkk] = packageJson[element][pkk];
42
+ return pkk + "@latest";
43
+ })
44
+ .join(" ");
45
+ let command = `yarn add ${packagesList}`;
46
+ try {
47
+ // logInfo(command);
48
+ childProcess.execSync(command, {
49
+ stdio: "inherit",
50
+ env: Object.assign({}, process.env, {
51
+ FORCE_COLOR: true,
52
+ PATH: `${path.resolve("node_modules")}:${process.env.PATH}`
53
+ })
54
+ });
55
+ const packageJsonAfter = JSON.parse(fs.readFileSync(packagePath));
56
+ const packagesAfter = Object.keys(packageJsonAfter[element]);
57
+ let packagesListAfter = packagesAfter
58
+ .filter(pkk => !ignorePkgs.includes(pkk))
59
+ .map(pkk => {
60
+ upgraded["after"][pkk] = packageJsonAfter[element][pkk];
61
+ return upgraded["before"][pkk] !== upgraded["after"][pkk]
62
+ ? `Updated: ${pkk} from: ${upgraded["before"][pkk]} | to: ${
63
+ upgraded["after"][pkk]
64
+ }\n`
65
+ : ``;
66
+ })
67
+ .join("");
68
+ logSuccess(packagesListAfter);
69
+ } catch (e) {
70
+ logError(`${command} - ${e}`);
71
+ }
72
+ }
62
73
  }
63
- }
64
74
  };
65
- export default upgradePackages;
75
+ export default upgradePackages;
@@ -3,16 +3,19 @@
3
3
  * @param opts pass true to fully clear
4
4
  */
5
5
  export default function clear(opts) {
6
- if (typeof opts === "boolean") {
7
- opts = {
8
- fullClear: opts
9
- };
10
- }
11
- opts = opts || {};
12
- opts.fullClear = opts.hasOwnProperty("fullClear") ? opts.fullClear : true;
13
- if (opts.fullClear === true) {
14
- process.stdout.write("\x1b[2J");
15
- }
16
- process.stdout.write("\x1b[0f");
17
- }
18
- ;
6
+ if (typeof opts === "boolean") {
7
+ opts = {
8
+ fullClear: opts
9
+ };
10
+ }
11
+
12
+ opts = opts || {};
13
+
14
+ opts.fullClear = opts.hasOwnProperty("fullClear") ? opts.fullClear : true;
15
+
16
+ if (opts.fullClear === true) {
17
+ process.stdout.write("\x1b[2J");
18
+ }
19
+
20
+ process.stdout.write("\x1b[0f");
21
+ };
@@ -1,33 +1,39 @@
1
1
  import { timestamp } from "./helpers.js";
2
2
  import chalk from "chalk";
3
+
3
4
  const d = timestamp();
5
+
4
6
  const colors = {
5
- Reset: "\x1b[0m",
6
- Red: "\x1b[31m",
7
- Green: "\x1b[32m",
8
- Yellow: "\x1b[33m"
7
+ Reset: "\x1b[0m",
8
+ Red: "\x1b[31m",
9
+ Green: "\x1b[32m",
10
+ Yellow: "\x1b[33m"
9
11
  };
12
+
10
13
  const infoLog = console.info;
11
14
  const logLog = console.log;
12
15
  const warnLog = console.warn;
13
16
  const errorLog = console.error;
14
- console.log = function (args) {
15
- const copyArgs = Array.prototype.slice.call(arguments);
16
- copyArgs.unshift(`${chalk.gray(d)} ${chalk.gray.bold("[LOG]")}️`);
17
- infoLog.apply(null, copyArgs);
17
+
18
+ console.log = function(args) {
19
+ const copyArgs = Array.prototype.slice.call(arguments);
20
+ copyArgs.unshift(`${chalk.gray(d)} ${chalk.gray.bold("[LOG]")}️`);
21
+ infoLog.apply(null, copyArgs);
18
22
  };
19
- console.info = function (args) {
20
- const copyArgs = Array.prototype.slice.call(arguments);
21
- copyArgs.unshift(`${chalk.gray(d)} ${chalk.blue.bold("i [INFO]")}️`);
22
- infoLog.apply(null, copyArgs);
23
+ console.info = function(args) {
24
+ const copyArgs = Array.prototype.slice.call(arguments);
25
+ copyArgs.unshift(`${chalk.gray(d)} ${chalk.blue.bold("i [INFO]")}️`);
26
+ infoLog.apply(null, copyArgs);
23
27
  };
24
- console.warn = function (args) {
25
- const copyArgs = Array.prototype.slice.call(arguments);
26
- copyArgs.unshift(`${chalk.gray(d)} ${chalk.yellow.bold("⚠ [WARN]")}️`);
27
- warnLog.apply(null, copyArgs);
28
+
29
+ console.warn = function(args) {
30
+ const copyArgs = Array.prototype.slice.call(arguments);
31
+ copyArgs.unshift(`${chalk.gray(d)} ${chalk.yellow.bold("⚠ [WARN]")}️`);
32
+ warnLog.apply(null, copyArgs);
33
+ };
34
+
35
+ console.error = function(args) {
36
+ const copyArgs = Array.prototype.slice.call(arguments);
37
+ copyArgs.unshift(`${chalk.gray(d)} ${chalk.red.bold("× [ERROR]")}️`);
38
+ warnLog.apply(null, copyArgs);
28
39
  };
29
- console.error = function (args) {
30
- const copyArgs = Array.prototype.slice.call(arguments);
31
- copyArgs.unshift(`${chalk.gray(d)} ${chalk.red.bold("× [ERROR]")}️`);
32
- warnLog.apply(null, copyArgs);
33
- };
@@ -1,18 +1,60 @@
1
1
  import crypto from "crypto";
2
- const algorithm = "aes-192-cbc";
3
- const iv = Buffer.alloc(16, 0); // Initialization vector.
2
+
3
+ // OpenSSL / CryptoJS-compatible AES-256-CBC.
4
+ // Output format matches `CryptoJS.AES.encrypt(text, password).toString()` and
5
+ // `openssl enc -aes-256-cbc -salt -base64`: base64("Salted__" + 8-byte salt + ciphertext).
6
+ const algorithm = "aes-256-cbc";
7
+ const MAGIC = Buffer.from("Salted__", "utf8");
8
+
9
+ // OpenSSL EVP_BytesToKey (MD5) key+IV derivation from password + salt.
10
+ const deriveKeyIv = (password, salt) => {
11
+ const pass = Buffer.from(password, "utf8");
12
+ let data = Buffer.alloc(0);
13
+ let block = Buffer.alloc(0);
14
+ while (data.length < 48) {
15
+ // 32-byte key + 16-byte IV
16
+ block = crypto.createHash("md5").update(Buffer.concat([block, pass, salt])).digest();
17
+ data = Buffer.concat([data, block]);
18
+ }
19
+ return { key: data.subarray(0, 32), iv: data.subarray(32, 48) };
20
+ };
21
+
4
22
  const encrypt = (toEncrypt, password) => {
5
- const key = crypto.scryptSync(password, "salt", 24);
6
- const cipher = crypto.createCipheriv(algorithm, key, iv);
7
- let encrypted = cipher.update(toEncrypt, "utf8", "hex");
8
- encrypted += cipher.final("hex");
9
- return encrypted;
23
+ const salt = crypto.randomBytes(8);
24
+ const { key, iv } = deriveKeyIv(password, salt);
25
+ const cipher = crypto.createCipheriv(algorithm, key, iv);
26
+ const ciphertext = Buffer.concat([
27
+ cipher.update(Buffer.from(toEncrypt, "utf8")),
28
+ cipher.final()
29
+ ]);
30
+ return Buffer.concat([MAGIC, salt, ciphertext]).toString("base64");
31
+ };
32
+
33
+ const decryptLegacy = (toDecrypt, password) => {
34
+ const key = crypto.scryptSync(password, "salt", 24);
35
+ const iv = Buffer.alloc(16, 0);
36
+ const decipher = crypto.createDecipheriv("aes-192-cbc", key, iv);
37
+ let decrypted = decipher.update(String(toDecrypt).trim(), "hex", "utf8");
38
+ decrypted += decipher.final("utf8");
39
+ return decrypted;
10
40
  };
41
+
11
42
  const decrypt = (toDecrypt, password) => {
12
- const key = crypto.scryptSync(password, "salt", 24);
13
- const decipher = crypto.createDecipheriv(algorithm, key, iv);
14
- let decrypted = decipher.update(toDecrypt, "hex", "utf8");
15
- decrypted += decipher.final("utf8");
16
- return decrypted;
43
+ const raw = String(toDecrypt).trim();
44
+ const data = Buffer.from(raw, "base64");
45
+ if (!data.subarray(0, 8).equals(MAGIC)) {
46
+ // legacy format: hex-encoded AES-192-CBC
47
+ return decryptLegacy(raw, password);
48
+ }
49
+ const salt = data.subarray(8, 16);
50
+ const ciphertext = data.subarray(16);
51
+ const { key, iv } = deriveKeyIv(password, salt);
52
+ const decipher = crypto.createDecipheriv(algorithm, key, iv);
53
+ try {
54
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
55
+ } catch (e) {
56
+ throw new Error("Decryption failed — wrong password or corrupted file");
57
+ }
17
58
  };
18
- export { decrypt, encrypt };
59
+
60
+ export { decrypt, encrypt };
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Hash utilities for cache key generation
3
+ * @module utils/hash
4
+ */
5
+
6
+ import { createHash } from 'crypto';
7
+ import { statSync } from 'fs';
8
+
9
+ /**
10
+ * Generate a SHA-256 hash from a string
11
+ * @param {string} input - Input string
12
+ * @param {number} [length=16] - Output length (characters)
13
+ * @returns {string} Hash string
14
+ */
15
+ export function hash(input, length = 16) {
16
+ return createHash('sha256')
17
+ .update(input)
18
+ .digest('hex')
19
+ .substring(0, length);
20
+ }
21
+
22
+ /**
23
+ * Generate a hash from multiple inputs
24
+ * @param {...string} inputs - Input strings
25
+ * @returns {string} Combined hash
26
+ */
27
+ export function hashMultiple(...inputs) {
28
+ const combined = inputs.join(':');
29
+ return hash(combined);
30
+ }
31
+
32
+ /**
33
+ * Generate a cache key from file path and metadata
34
+ * @param {string} filePath - File path
35
+ * @param {Object} [options] - Additional options
36
+ * @param {boolean} [options.includeMtime=true] - Include modification time
37
+ * @param {boolean} [options.includeSize=false] - Include file size
38
+ * @returns {string} Cache key
39
+ */
40
+ export function generateFileKey(filePath, options = {}) {
41
+ const includeMtime = options.includeMtime !== false;
42
+ const includeSize = options.includeSize || false;
43
+
44
+ try {
45
+ const stats = statSync(filePath);
46
+ const parts = [filePath];
47
+
48
+ if (includeMtime) {
49
+ parts.push(stats.mtimeMs.toString());
50
+ }
51
+
52
+ if (includeSize) {
53
+ parts.push(stats.size.toString());
54
+ }
55
+
56
+ return hash(parts.join(':'));
57
+ } catch (error) {
58
+ throw new Error(`Failed to generate file key for ${filePath}: ${error.message}`);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Generate a cache key from an object
64
+ * @param {Object} obj - Object to hash
65
+ * @returns {string} Cache key
66
+ */
67
+ export function hashObject(obj) {
68
+ const str = JSON.stringify(obj, Object.keys(obj).sort());
69
+ return hash(str);
70
+ }
71
+
72
+ /**
73
+ * Generate a cache key from file path and content hash
74
+ * @param {string} filePath - File path
75
+ * @param {string} content - File content
76
+ * @returns {string} Cache key
77
+ */
78
+ export function generateContentKey(filePath, content) {
79
+ const contentHash = hash(content);
80
+ return hash(`${filePath}:${contentHash}`);
81
+ }
82
+
83
+ /**
84
+ * Get file metadata for cache validation
85
+ * @param {string} filePath - File path
86
+ * @returns {Object} File metadata
87
+ */
88
+ export function getFileMetadata(filePath) {
89
+ try {
90
+ const stats = statSync(filePath);
91
+ return {
92
+ mtime: stats.mtimeMs,
93
+ size: stats.size,
94
+ exists: true
95
+ };
96
+ } catch (error) {
97
+ return {
98
+ mtime: null,
99
+ size: null,
100
+ exists: false
101
+ };
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Check if file has changed based on metadata
107
+ * @param {string} filePath - File path
108
+ * @param {number} cachedMtime - Cached modification time
109
+ * @returns {boolean} True if file has changed
110
+ */
111
+ export function hasFileChanged(filePath, cachedMtime) {
112
+ try {
113
+ const stats = statSync(filePath);
114
+ return stats.mtimeMs !== cachedMtime;
115
+ } catch {
116
+ return true; // Consider changed if file doesn't exist
117
+ }
118
+ }
119
+
120
+ export default {
121
+ hash,
122
+ hashMultiple,
123
+ hashObject,
124
+ generateFileKey,
125
+ generateContentKey,
126
+ getFileMetadata,
127
+ hasFileChanged
128
+ };