@cerema/cadriciel 1.4.29 → 1.4.31
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/cli/global/init.js +2 -7
- package/cli/global/load.js +214 -0
- package/cli/global/upgrade.js +89 -0
- package/cli.js +45 -39
- package/package.json +2 -1
package/cli/global/init.js
CHANGED
|
@@ -11,12 +11,7 @@ module.exports = (args) => {
|
|
|
11
11
|
const cliProgress = require('cli-progress');
|
|
12
12
|
const userHome = require('os').homedir();
|
|
13
13
|
const error = require(path.join('..', '..', 'lib', 'message')).error;
|
|
14
|
-
const {
|
|
15
|
-
'..',
|
|
16
|
-
'..',
|
|
17
|
-
'lib',
|
|
18
|
-
'util'
|
|
19
|
-
));
|
|
14
|
+
const { getTemplates } = require(path.join('..', '..', 'lib', 'util'));
|
|
20
15
|
const link = (url, name) => {
|
|
21
16
|
if (!name) name = url;
|
|
22
17
|
if (url.includes('localhost')) url = 'http://' + url + '/';
|
|
@@ -133,7 +128,7 @@ Host cadriciel
|
|
|
133
128
|
|
|
134
129
|
try {
|
|
135
130
|
await execPromise(
|
|
136
|
-
`git config --local user.email "${response.prj.owner.email}" && git config --local user.name "${response.prj.owner.name}" && git add --all && git checkout -b ${response.prj.owner.trigram}`,
|
|
131
|
+
`git config --local user.email "${response.prj.owner.email}" && git config --local user.name "${response.prj.owner.name}" && git add --all && git checkout -b ${response.prj.owner.trigram} && git config pull.rebase true`,
|
|
137
132
|
{
|
|
138
133
|
cwd: process.cwd() + '/' + response.prj.title,
|
|
139
134
|
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
module.exports = (args) => {
|
|
2
|
+
const { promisify } = require('util');
|
|
3
|
+
const { exec } = require('child_process');
|
|
4
|
+
const execPromise = promisify(exec);
|
|
5
|
+
const chalk = require('chalk-v2');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const ora = require('ora');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const inquirer = require('inquirer');
|
|
10
|
+
const userHome = require('os').homedir();
|
|
11
|
+
const { error } = require(path.join('..', '..', 'lib', 'message'));
|
|
12
|
+
const { getTemplates } = require(path.join('..', '..', 'lib', 'util'));
|
|
13
|
+
const link = (url, name) => {
|
|
14
|
+
if (!name) name = url;
|
|
15
|
+
if (url.includes('localhost')) url = 'http://' + url + '/';
|
|
16
|
+
else url = 'https://' + url + '/';
|
|
17
|
+
return (
|
|
18
|
+
'\u001b[36m\u001b]8;;' +
|
|
19
|
+
url +
|
|
20
|
+
'\u0007' +
|
|
21
|
+
name +
|
|
22
|
+
'\u001b]8;;\u0007\u001b[0m\n'
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
const updatePK = async () => {
|
|
26
|
+
try {
|
|
27
|
+
var pk = await cadriciel.get(`privatekey`);
|
|
28
|
+
const pkey = Buffer.from(pk.private_key, 'base64').toString();
|
|
29
|
+
fs.writeFileSync(userHome + '/.cadriciel/id_rsa', pkey);
|
|
30
|
+
fs.chmodSync(userHome + '/.cadriciel/id_rsa', 0o600);
|
|
31
|
+
try {
|
|
32
|
+
fs.mkdirSync(userHome + '/.ssh');
|
|
33
|
+
} catch (e) {}
|
|
34
|
+
var ssh = fs.readFileSync(userHome + '/.ssh/config', 'utf-8');
|
|
35
|
+
if (!ssh.includes('87c7dfbf-172a-4084-a862-4a23f35a5b79 ')) {
|
|
36
|
+
ssh += '\n\n' + sshtemplate;
|
|
37
|
+
fs.writeFileSync(userHome + '/.ssh/config', ssh, { flag: 'a' });
|
|
38
|
+
fs.chmodSync(userHome + '/.ssh/config', 0o600);
|
|
39
|
+
}
|
|
40
|
+
} catch (e) {
|
|
41
|
+
console.log(e);
|
|
42
|
+
error(
|
|
43
|
+
"Une erreur s'est produite lors de la récupération de la clé privée"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const sshtemplate = `
|
|
48
|
+
# cadriciel -- 87c7dfbf-172a-4084-a862-4a23f35a5b79 --
|
|
49
|
+
Host cadriciel
|
|
50
|
+
HostName gitlab.cerema.fr
|
|
51
|
+
User git
|
|
52
|
+
IdentityFile ~/.cadriciel/id_rsa
|
|
53
|
+
IdentitiesOnly yes
|
|
54
|
+
# -----------------------------------------------------
|
|
55
|
+
`;
|
|
56
|
+
const CadricielAPI = require(path.join('..', '..', 'lib', 'cadriciel'));
|
|
57
|
+
const cadriciel = new CadricielAPI();
|
|
58
|
+
var templates = [];
|
|
59
|
+
|
|
60
|
+
/** loading the project */
|
|
61
|
+
const load = async (uri, title) => {
|
|
62
|
+
console.log(' ');
|
|
63
|
+
const step1 = ora('📥 Téléchargement du projet en cours...').start();
|
|
64
|
+
const git = await execPromise('git clone ' + uri, {
|
|
65
|
+
cwd: process.cwd(),
|
|
66
|
+
});
|
|
67
|
+
step1.succeed(chalk.bold('Téléchargement OK.'));
|
|
68
|
+
console.log(' ');
|
|
69
|
+
const step2 = ora('📦 Installation des dépendances...').start();
|
|
70
|
+
try {
|
|
71
|
+
try {
|
|
72
|
+
await execPromise('pnpm i', {
|
|
73
|
+
cwd: process.cwd() + '/' + title,
|
|
74
|
+
});
|
|
75
|
+
} catch (e) {
|
|
76
|
+
try {
|
|
77
|
+
await execPromise('yarn', {
|
|
78
|
+
cwd: process.cwd() + '/' + title,
|
|
79
|
+
});
|
|
80
|
+
} catch (e) {
|
|
81
|
+
await execPromise('npm i', {
|
|
82
|
+
cwd: process.cwd() + '/' + title,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const user = await cadriciel.get('account');
|
|
88
|
+
const url = uri
|
|
89
|
+
.replace('cadriciel:', 'gitlab.cerema.fr/')
|
|
90
|
+
.replace('git@', 'https://')
|
|
91
|
+
.replace('.git', '');
|
|
92
|
+
try {
|
|
93
|
+
await execPromise(
|
|
94
|
+
`git config --local user.email "${user.info.email}" && git config --local user.name "${user.info.name}" && git add --all && git checkout -b ${user.trigram} && git config pull.rebase true`,
|
|
95
|
+
{
|
|
96
|
+
cwd: process.cwd() + '/' + title,
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
step2.succeed(
|
|
100
|
+
'🎉 ' + chalk.bold('Votre projet a été correctement installé')
|
|
101
|
+
);
|
|
102
|
+
console.log(' ');
|
|
103
|
+
|
|
104
|
+
console.log(`
|
|
105
|
+
──────────────────────────────────────────────────────────────
|
|
106
|
+
URL du projet : ${link(url.split('https://')[1])}
|
|
107
|
+
|
|
108
|
+
Vous trouverez votre projet dans le dossier :
|
|
109
|
+
|
|
110
|
+
cd ${chalk.green(title)}
|
|
111
|
+
|
|
112
|
+
🚀 ${chalk.bold("Pour lancer l'environnement de développement :")}
|
|
113
|
+
|
|
114
|
+
${chalk.green('cad start')}
|
|
115
|
+
|
|
116
|
+
🚦 ${chalk.bold("Pour arrêter l'environnement de développement :")}
|
|
117
|
+
|
|
118
|
+
${chalk.green('cad stop')}
|
|
119
|
+
|
|
120
|
+
💻 ${chalk.bold('Pour manager votre projet :')}
|
|
121
|
+
|
|
122
|
+
👉 ${link('studio.k8-dev.cerema.fr', 'studio.k8-dev.cerema.fr')}
|
|
123
|
+
|
|
124
|
+
──────────────────────────────────────────────────────────────`);
|
|
125
|
+
console.log(' ');
|
|
126
|
+
} catch (e) {}
|
|
127
|
+
} catch (e) {
|
|
128
|
+
console.log(e);
|
|
129
|
+
step1.fail(chalk.red('Déploiement échoué'));
|
|
130
|
+
return process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
info: {
|
|
135
|
+
title: 'load',
|
|
136
|
+
description: `Charge un projet Cadriciel`,
|
|
137
|
+
},
|
|
138
|
+
start: async () => {
|
|
139
|
+
const spinner = ora('Veuillez patienter un instant...').start();
|
|
140
|
+
try {
|
|
141
|
+
templates = await getTemplates();
|
|
142
|
+
} catch (e) {
|
|
143
|
+
console.log(e);
|
|
144
|
+
spinner.stop();
|
|
145
|
+
error('Mise à jour impossible... Vérifier votre connexion internet');
|
|
146
|
+
return process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
await updatePK();
|
|
149
|
+
|
|
150
|
+
const response = await cadriciel.get('studio/projects');
|
|
151
|
+
spinner.stop();
|
|
152
|
+
let myProjects = [];
|
|
153
|
+
let DSIProjects = [];
|
|
154
|
+
for (let i = 0; i < response.myProjects.length; i++) {
|
|
155
|
+
let description = response.myProjects[i].description;
|
|
156
|
+
if (!description)
|
|
157
|
+
description = response.myProjects[i].name_with_namespace;
|
|
158
|
+
description = new inquirer.Separator(description);
|
|
159
|
+
const uri = response.myProjects[i].uri.replace(/@.*?:/, '@cadriciel:');
|
|
160
|
+
myProjects.push({
|
|
161
|
+
name: response.myProjects[i].name,
|
|
162
|
+
value: {
|
|
163
|
+
title: response.myProjects[i].name,
|
|
164
|
+
uri: uri,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
myProjects.push(new inquirer.Separator(description));
|
|
168
|
+
}
|
|
169
|
+
for (let i = 0; i < response.cerema.length; i++) {
|
|
170
|
+
let description = response.cerema[i].description;
|
|
171
|
+
if (!description) description = response.cerema[i].name_with_namespace;
|
|
172
|
+
description = new inquirer.Separator(description);
|
|
173
|
+
const uri = response.cerema[i].ssh_url_to_repo.replace(
|
|
174
|
+
/@.*?:/,
|
|
175
|
+
'@cadriciel:'
|
|
176
|
+
);
|
|
177
|
+
DSIProjects.push({
|
|
178
|
+
name: response.cerema[i].name,
|
|
179
|
+
value: { title: response.cerema[i].name, uri: uri },
|
|
180
|
+
});
|
|
181
|
+
DSIProjects.push(new inquirer.Separator(description));
|
|
182
|
+
}
|
|
183
|
+
if (args.length > 1) {
|
|
184
|
+
const prj = args[1];
|
|
185
|
+
if (prj.indexOf('dsi/') > -1) {
|
|
186
|
+
const t = DSIProjects.filter((p) => p.name == prj.split('dsi/')[1]);
|
|
187
|
+
if (t.length > 0) return load(t[0].value.uri, t[0].value.title);
|
|
188
|
+
return error('Projet introuvable');
|
|
189
|
+
} else {
|
|
190
|
+
const t = myProjects.filter((p) => p.name == prj);
|
|
191
|
+
if (t.length > 0) return load(t[0].value.uri, t[0].value.title);
|
|
192
|
+
return error('Projet introuvable');
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
const q = {
|
|
196
|
+
type: 'list',
|
|
197
|
+
name: 'choice',
|
|
198
|
+
message: 'Choisissez un projet existant:',
|
|
199
|
+
choices: [
|
|
200
|
+
new inquirer.Separator(' '),
|
|
201
|
+
new inquirer.Separator('=== Mes projets ==='),
|
|
202
|
+
...myProjects,
|
|
203
|
+
new inquirer.Separator(' '),
|
|
204
|
+
new inquirer.Separator('=== Projets DSI ==='),
|
|
205
|
+
...DSIProjects,
|
|
206
|
+
],
|
|
207
|
+
};
|
|
208
|
+
inquirer.prompt([q]).then((answers) => {
|
|
209
|
+
load(answers.choice.uri, answers.choice.title);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const ora = require('ora');
|
|
2
|
+
|
|
3
|
+
module.exports = (args) => {
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const userHomeDir = os.homedir();
|
|
8
|
+
const log = require('log-beautify');
|
|
9
|
+
const sep = path.sep;
|
|
10
|
+
const { nanoid } = require('nanoid');
|
|
11
|
+
const AdmZip = require('adm-zip');
|
|
12
|
+
const UID = nanoid();
|
|
13
|
+
const fse = require('fs-extra');
|
|
14
|
+
const chalk = require('chalk-v2');
|
|
15
|
+
|
|
16
|
+
var DEFAULT_TEMPLATE = '';
|
|
17
|
+
const unzipFile = (zipFilePath, outputPath, callback) => {
|
|
18
|
+
const zip = new AdmZip(zipFilePath);
|
|
19
|
+
try {
|
|
20
|
+
zip.extractAllTo(outputPath, true);
|
|
21
|
+
callback();
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error(
|
|
24
|
+
"Une erreur s'est produite lors de la décompression :",
|
|
25
|
+
err
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const download = async (name, cb) => {
|
|
30
|
+
const CadricielAPI = require(path.join('..', '..', 'lib', 'cadriciel'));
|
|
31
|
+
const cadriciel = new CadricielAPI();
|
|
32
|
+
await cadriciel.downloadFile(
|
|
33
|
+
'/template?key=' + name + '.zip',
|
|
34
|
+
`${os.tmpdir()}${sep}${name}.zip`
|
|
35
|
+
);
|
|
36
|
+
unzipFile(
|
|
37
|
+
`${os.tmpdir()}${sep}${name}.zip`,
|
|
38
|
+
`${os.tmpdir()}${sep}${UID}`,
|
|
39
|
+
() => {
|
|
40
|
+
DEFAULT_TEMPLATE = name;
|
|
41
|
+
fs.unlink(`${os.tmpdir()}${sep}${name}.zip`, cb);
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
async function updateCadriciel(srcDir, destDir) {
|
|
46
|
+
try {
|
|
47
|
+
const storeDir = path.join(destDir, '.store');
|
|
48
|
+
|
|
49
|
+
// Sauvegarde de .store
|
|
50
|
+
const backupDir = path.join(os.tmpdir(), 'backup_store');
|
|
51
|
+
await fse.copy(storeDir, backupDir);
|
|
52
|
+
|
|
53
|
+
// Suppression de xxx/.cadriciel
|
|
54
|
+
await fse.remove(path.join(destDir));
|
|
55
|
+
|
|
56
|
+
// Copie de yyy/.cadriciel vers xxx/.cadriciel
|
|
57
|
+
await fse.copy(srcDir, path.join(destDir));
|
|
58
|
+
|
|
59
|
+
// Restauration de .store
|
|
60
|
+
await fse.copy(backupDir, storeDir);
|
|
61
|
+
|
|
62
|
+
// Suppression du dossier de sauvegarde
|
|
63
|
+
await fse.remove(backupDir);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('Erreur lors de la mise à jour de .cadriciel:', error);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
info: {
|
|
71
|
+
title: '---',
|
|
72
|
+
description: 'upgrade cadriciel framework',
|
|
73
|
+
},
|
|
74
|
+
start: () => {
|
|
75
|
+
var spinner = ora('📥 Téléchargement du patch...').start();
|
|
76
|
+
const info = require(`${process.cwd()}/.cadriciel/version.json`);
|
|
77
|
+
const title = 'cadriciel-' + info.name;
|
|
78
|
+
download(title, async () => {
|
|
79
|
+
spinner.succeed(chalk.bold('Téléchargement OK.'));
|
|
80
|
+
spinner = ora('📥 Application du patch...').start();
|
|
81
|
+
const dir1 = `${os.tmpdir()}${sep}${UID}/§§project§§/.cadriciel`;
|
|
82
|
+
const dir2 = `${process.cwd()}/.cadriciel`;
|
|
83
|
+
await updateCadriciel(dir1, dir2);
|
|
84
|
+
spinner.succeed(chalk.bold('Application du patch OK.'));
|
|
85
|
+
console.log(' ');
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
};
|
package/cli.js
CHANGED
|
@@ -12,8 +12,8 @@ const boxen = require('boxen'); // For creating boxes in the console.
|
|
|
12
12
|
// Locating the '.cadriciel' directory starting from the current working directory.
|
|
13
13
|
const CADRICIEL_PATH = findCadricielDir(process.cwd());
|
|
14
14
|
const CADRICIEL_COMMAND = 'cad';
|
|
15
|
-
|
|
16
|
-
global.CADRICIEL_URI = 'http://localhost:3000/api';
|
|
15
|
+
global.CADRICIEL_URI = 'https://cadriciel.k8-dev.cerema.fr/api';
|
|
16
|
+
//global.CADRICIEL_URI = 'http://localhost:3000/api';
|
|
17
17
|
|
|
18
18
|
// Initialize command storage objects.
|
|
19
19
|
var CADRICIEL_GLOBAL_COMMANDS = {};
|
|
@@ -110,12 +110,14 @@ function findCadricielDir(startPath) {
|
|
|
110
110
|
|
|
111
111
|
// Function to load global commands.
|
|
112
112
|
const loadGlobalCommands = () => {
|
|
113
|
+
let args = process.argv;
|
|
114
|
+
//args.shift();
|
|
113
115
|
let dir = fs.readdirSync(__dirname + '/cli/global');
|
|
114
116
|
for (let i = 0; i < dir.length; i++) {
|
|
115
117
|
if (dir[i].indexOf('.js') > -1)
|
|
116
118
|
CADRICIEL_GLOBAL_COMMANDS[dir[i].split('.')[0]] = require(__dirname +
|
|
117
119
|
'/cli/global/' +
|
|
118
|
-
dir[i])();
|
|
120
|
+
dir[i])(args);
|
|
119
121
|
}
|
|
120
122
|
};
|
|
121
123
|
|
|
@@ -209,37 +211,38 @@ const display = (commands) => {
|
|
|
209
211
|
|
|
210
212
|
for (let el in commands) {
|
|
211
213
|
let title = el;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
if (commands[el].info.title != '---') {
|
|
215
|
+
if (commands[el].info) {
|
|
216
|
+
let description = commands[el].info.description;
|
|
217
|
+
if (commands[el].info.sub) {
|
|
218
|
+
title += ' <subcommand>';
|
|
219
|
+
const sc = [];
|
|
220
|
+
for (let i = 0; i < commands[el].info.sub.length; i++) {
|
|
221
|
+
sc.push(commands[el].info.sub[i].title);
|
|
222
|
+
}
|
|
223
|
+
description += chalk.white(' ');
|
|
224
|
+
description += chalk.grey(' (subcommands: ');
|
|
225
|
+
description += chalk.cyan(sc.join(', '));
|
|
226
|
+
description += chalk.grey(')');
|
|
220
227
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
228
|
+
const dots = '.'.repeat(maxWidth - title.length);
|
|
229
|
+
|
|
230
|
+
const formattedDesc = formatDescription(
|
|
231
|
+
description,
|
|
232
|
+
maxDescriptionLength
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
console.log(
|
|
236
|
+
' ' +
|
|
237
|
+
chalk.cyanBright(title) +
|
|
238
|
+
' ' +
|
|
239
|
+
chalk.grey(dots) +
|
|
240
|
+
' ' +
|
|
241
|
+
label(commands[el].info.label) +
|
|
242
|
+
' ' +
|
|
243
|
+
chalk.white(formattedDesc)
|
|
244
|
+
);
|
|
225
245
|
}
|
|
226
|
-
const dots = '.'.repeat(maxWidth - title.length);
|
|
227
|
-
|
|
228
|
-
const formattedDesc = formatDescription(
|
|
229
|
-
description,
|
|
230
|
-
maxDescriptionLength
|
|
231
|
-
);
|
|
232
|
-
|
|
233
|
-
console.log(
|
|
234
|
-
' ' +
|
|
235
|
-
chalk.cyanBright(title) +
|
|
236
|
-
' ' +
|
|
237
|
-
chalk.grey(dots) +
|
|
238
|
-
' ' +
|
|
239
|
-
label(commands[el].info.label) +
|
|
240
|
-
' ' +
|
|
241
|
-
chalk.white(formattedDesc)
|
|
242
|
-
);
|
|
243
246
|
}
|
|
244
247
|
}
|
|
245
248
|
};
|
|
@@ -297,17 +300,20 @@ const processCommands = (args) => {
|
|
|
297
300
|
const command = args[0];
|
|
298
301
|
const maxWidth = 30;
|
|
299
302
|
const maxDescriptionLength = 50;
|
|
303
|
+
|
|
300
304
|
loadCadricielCommands(CADRICIEL_PATH + '/../');
|
|
301
|
-
|
|
302
|
-
|
|
305
|
+
|
|
306
|
+
if (CADRICIEL_GLOBAL_COMMANDS[command]) {
|
|
307
|
+
CADRICIEL_GLOBAL_COMMANDS[command].start(args);
|
|
308
|
+
} else {
|
|
309
|
+
if (CADRICIEL_COMMANDS[command]) {
|
|
310
|
+
console.log(' ');
|
|
311
|
+
const dir = args.join('/');
|
|
312
|
+
return parseCommand(args);
|
|
313
|
+
} else {
|
|
303
314
|
log.error('Commande inconnue : ' + command);
|
|
304
315
|
return displayBanner();
|
|
305
316
|
}
|
|
306
|
-
CADRICIEL_GLOBAL_COMMANDS[command].start(args);
|
|
307
|
-
} else {
|
|
308
|
-
console.log(' ');
|
|
309
|
-
const dir = args.join('/');
|
|
310
|
-
return parseCommand(args);
|
|
311
317
|
}
|
|
312
318
|
};
|
|
313
319
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cerema/cadriciel",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.31",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"npm": ">=8.0.0",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"dotenv": "^16.3.1",
|
|
20
20
|
"express": "^4.18.2",
|
|
21
21
|
"figlet": "^1.5.2",
|
|
22
|
+
"fs-extra": "^11.2.0",
|
|
22
23
|
"inquirer": "8.2.5",
|
|
23
24
|
"isbinaryfile": "^5.0.0",
|
|
24
25
|
"jsonwebtoken": "^9.0.2",
|