poad 2.5.4 → 2.5.6

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/0.txt ADDED
@@ -0,0 +1,16 @@
1
+ docker run
2
+ --platform=linux/amd64
3
+ --rm
4
+ -v ~/prj/omneedia/infra/aio/data:/data
5
+ -e OMNEEDIA_GATEWAY_URL=http://localhost:8000
6
+ -e DATA_VOLUME_MOUNTPOINT=/data
7
+ -e POSTGRES_PASSWORD=dreams
8
+ -p 5432:5432
9
+ -p 8000:8000
10
+ -e ADMIN_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic3VwYWJhc2VfYWRtaW4iLCJpc3MiOiJzdXBhYmFzZS1kZW1vIiwiaWF0IjoxNjQxNzY5MjAwLCJleHAiOjE3OTk1MzU2MDB9.Y9mSNVuTw2TdfryoaqM5wySvwQemGGWfSe9ixcklVfM
11
+ -e JWT_SECRET=277e90e7515dbf46bf76ddabfbfa6fa04a11966f4e7550ef3330a31258c49be95944a87c97b725defb264dbb772567592b8a91849115dce1ece7b949a668900ac0738a8d0a89db4a48d77706474e4ea34d20134ac889b73f7ecd732b046bdce7b7367fb9f56638eed1db1bba916a5e674a472ed443d316127b6176a2a6066ca08bffd97ed47ef9f1cfe22c668afca3f7d0011352d113e4315803c35787a3c2bc16424ab02a88452ab7c04ad48143c11f2616c148f85461842afcf28295a0281281c69f2df6344476286425290f7721470c9f92576ece15f275feac53a3dd6763eb0d88bbcdc9391c64f62c4bf556c131f49a5de9de9e914f544c42a5ef33ca10
12
+ -e ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTcyNjg2MTQ4OH0.fsIJu0uDoMBBxXnHuoXtMlwF4sGHxkFGkLpFDfKuV9g
13
+ -e SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
14
+ poadio/engine
15
+ &>data/service.log
16
+ &
package/global/cli.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ *
3
+ * @label [BETA]
4
+ * @label [EXPERIMENTAL]
5
+ * @label [DOCKER]
6
+ * @label [AI]
7
+ *
8
+ */
9
+ module.exports = {
10
+ install: `Install poad environment`,
11
+ init: `Init poad project`,
12
+ start: 'Start containers for poad local development',
13
+ };
package/global/init.js ADDED
@@ -0,0 +1,42 @@
1
+ module.exports = async (args) => {
2
+ const path = require('path');
3
+ const jwt = require('jsonwebtoken');
4
+ const { findFreePorts } = require('../utils/ports');
5
+ const { generateSecret } = require('../utils/jwtkey');
6
+ const json2toml = require('json2toml');
7
+ const fs = require('fs').promises;
8
+ const generateUniqueId = require('generate-unique-id');
9
+ const anon = {
10
+ role: 'anon',
11
+ iss: 'poad',
12
+ };
13
+ const service = {
14
+ role: 'service',
15
+ iss: 'poad',
16
+ };
17
+ const admin = {
18
+ role: 'admin',
19
+ iss: 'poad',
20
+ };
21
+ let config = {};
22
+ config.project_id = path.basename(process.cwd());
23
+ config.project_uuid = generateUniqueId();
24
+ await fs.mkdir(path.join(process.cwd(), 'poad', 'data'), { recursive: true });
25
+ const ports = await findFreePorts(3);
26
+ config.db = {
27
+ port: ports[0],
28
+ };
29
+ config.web = {
30
+ port: ports[1],
31
+ };
32
+ const key = generateSecret();
33
+ config.auth = {
34
+ jwt_expiry: 3600,
35
+ secret: key,
36
+ anon: jwt.sign(anon, key),
37
+ service: jwt.sign(service, key),
38
+ admin: jwt.sign(admin, key),
39
+ };
40
+ const toml = json2toml(config);
41
+ await fs.writeFile(path.join(process.cwd(), 'poad', 'config.toml'), toml);
42
+ };
@@ -0,0 +1,49 @@
1
+ module.exports = async (args) => {
2
+ const chalk = require('chalk');
3
+ const Docker = require('dockerode');
4
+ const cliProgress = require('cli-progress');
5
+
6
+ const docker = new Docker();
7
+ const imageName = 'poadio/engine:latest';
8
+ const platform = 'linux/amd64';
9
+
10
+ // Create a new progress bar
11
+ const progressBar = new cliProgress.SingleBar(
12
+ {},
13
+ cliProgress.Presets.shades_classic
14
+ );
15
+
16
+ console.log(chalk.bold('\nInstalling poad environment...'));
17
+
18
+ docker.pull(imageName, { platform }, (err, stream) => {
19
+ if (err) {
20
+ console.error('Error pulling image:', err);
21
+ return;
22
+ }
23
+
24
+ let downloadedSize = 0;
25
+ let totalSize = 0;
26
+
27
+ docker.modem.followProgress(stream, onFinished, onProgress);
28
+
29
+ function onProgress(event) {
30
+ if (event.progressDetail && event.progressDetail.total) {
31
+ if (totalSize === 0) {
32
+ totalSize = event.progressDetail.total;
33
+ progressBar.start(totalSize, 0);
34
+ }
35
+ downloadedSize = event.progressDetail.current;
36
+ progressBar.update(downloadedSize);
37
+ }
38
+ }
39
+
40
+ function onFinished(err, output) {
41
+ progressBar.stop();
42
+ if (err) {
43
+ console.error('Error:', err);
44
+ } else {
45
+ console.log(chalk.bold('poad environment installed successfully.'));
46
+ }
47
+ }
48
+ });
49
+ };
@@ -0,0 +1,46 @@
1
+ module.exports = async (args) => {
2
+ const Docker = require('dockerode');
3
+ const docker = new Docker();
4
+ const toml = require('toml');
5
+ const path = require('path');
6
+ const fs = require('fs').promises;
7
+ const { findPoadDir } = require('../utils/findpoad');
8
+ const root = findPoadDir(process.cwd());
9
+ const config = toml.parse(await fs.readFile(root, 'utf-8'));
10
+
11
+ const webPort = config.web.port;
12
+ const dbPort = config.db.port;
13
+
14
+ docker
15
+ .createContainer({
16
+ Image: 'poadio/engine',
17
+ Tty: false,
18
+ Env: [
19
+ 'OMNEEDIA_GATEWAY_URL=http://localhost:' + config.web.port,
20
+ 'DATA_VOLUME_MOUNTPOINT=/data',
21
+ 'POSTGRES_PASSWORD=dreams',
22
+ 'ADMIN_API_KEY=' + config.auth.admin,
23
+ 'JWT_SECRET=' + config.auth.secret,
24
+ 'ANON_KEY=' + config.auth.anon,
25
+ 'SERVICE_ROLE_KEY=' + config.auth.service,
26
+ ],
27
+ HostConfig: {
28
+ PortBindings: {
29
+ '5432/tcp': [{ HostPort: config.db.port.toString() }],
30
+ '8000/tcp': [{ HostPort: config.web.port.toString() }],
31
+ },
32
+ Binds: [path.dirname(root) + '/data:/data'],
33
+ AutoRemove: true,
34
+ },
35
+ Platform: 'linux/amd64',
36
+ })
37
+ .then((container) => {
38
+ return container.start();
39
+ })
40
+ .then((container) => {
41
+ console.log('Container started successfully');
42
+ })
43
+ .catch((err) => {
44
+ console.error('Error:', err);
45
+ });
46
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poad",
3
- "version": "2.5.4",
3
+ "version": "2.5.6",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -11,10 +11,14 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "axios": "^1.7.7",
14
- "box": "^0.0.4",
15
14
  "boxen": "^5.1.2",
16
15
  "chalk-v2": "^1.0.2",
16
+ "cli-progress": "^3.12.0",
17
+ "dockerode": "^4.0.2",
17
18
  "figlet": "^1.7.0",
19
+ "generate-unique-id": "^2.0.3",
20
+ "json2toml": "^6.1.1",
21
+ "jsonwebtoken": "^9.0.2",
18
22
  "log-beautify": "^1.2.0",
19
23
  "toml": "^3.0.0"
20
24
  }
package/poad.js CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
+
3
+ // import required modules
2
4
  const figlet = require('figlet');
3
5
  const chalk = require('chalk-v2');
4
6
  const fs = require('fs');
@@ -9,8 +11,13 @@ const os = require('os');
9
11
  const userHomeDir = os.homedir();
10
12
  const boxen = require('boxen');
11
13
  const axios = require('axios');
14
+ const { parseArgs } = require('./utils/parseArgs');
15
+ const { findPoadDir } = require('./utils/findpoad');
16
+
17
+ const packageJsonPath = path.join(__dirname, 'package.json');
12
18
 
13
- const { version } = require('./package.json');
19
+ const package = require(packageJsonPath);
20
+ let args = process.argv.slice(2);
14
21
 
15
22
  // Function to check internet connection
16
23
  const checkInternetConnection = async () => {
@@ -22,31 +29,479 @@ const checkInternetConnection = async () => {
22
29
  }
23
30
  };
24
31
 
32
+ // Locating the '.cadriciel' directory starting from the current working directory.
33
+ const POAD_PATH = findPoadDir(process.cwd());
34
+ const POAD_COMMAND = 'poad';
35
+ const POAD_PERMALINK =
36
+ 'https://raw.githubusercontent.com/poadio/permalink/refs/heads/main/poad.json';
37
+ global.POAD_URI = '';
38
+
39
+ // Path for version checking file.
40
+ const VERSION_CHECK_FILE = path.join(userHomeDir, '.poad_last_check.json');
41
+ const CACHE_FILE_PATH = path.join(userHomeDir, '.poad_cache.json');
42
+ global.CACHE_URI = {};
43
+
44
+ // Initialize command storage objects.
45
+ var POAD_GLOBAL_COMMANDS = {};
46
+ var POAD_COMMANDS = {};
47
+
48
+ // Function to decide whether a version check is needed.
49
+ const shouldCheckVersion = async () => {
50
+ try {
51
+ const data = fs.readFileSync(VERSION_CHECK_FILE, 'utf8');
52
+ const lastCheck = JSON.parse(data);
53
+ const lastCheckDate = new Date(lastCheck.date);
54
+ const diff = Date.now() - lastCheckDate.getTime();
55
+ const twelveHours = 12 * 60 * 60 * 1000;
56
+
57
+ return diff > twelveHours;
58
+ } catch (e) {
59
+ return true;
60
+ }
61
+ };
62
+
63
+ // Function to update the date of the last version check.
64
+ const updateLastCheckDate = (version) => {
65
+ const data = JSON.stringify({ date: new Date(), version });
66
+ fs.writeFileSync(VERSION_CHECK_FILE, data, 'utf8');
67
+ };
68
+
69
+ // Function to check the current version of the package.
70
+ const checkVersion = async () => {
71
+ if (!(await shouldCheckVersion())) {
72
+ let version = 0;
73
+ try {
74
+ version = JSON.parse(fs.readFileSync(VERSION_CHECK_FILE, 'utf8')).version;
75
+ } catch (e) {
76
+ version = 0;
77
+ }
78
+ return Promise.resolve(version);
79
+ }
80
+ return new Promise((resolve, reject) => {
81
+ const packageName = 'poad';
82
+ const child = spawn('npm', ['view', packageName, 'version'], {
83
+ shell: true,
84
+ });
85
+
86
+ let version = '';
87
+
88
+ child.stdout.on('data', (data) => {
89
+ version += data.toString();
90
+ });
91
+
92
+ child.stderr.on('data', (data) => {
93
+ console.error(`err: ${data}`);
94
+ });
95
+
96
+ child.on('error', (error) => {
97
+ console.error(`Erreur lors de l'exécution de npm view: ${error.message}`);
98
+ reject(error);
99
+ });
100
+
101
+ child.on('close', (code) => {
102
+ if (code !== 0) {
103
+ console.error(
104
+ `Le processus npm view s'est terminé avec le code ${code}`
105
+ );
106
+ return reject(
107
+ new Error('Erreur lors de la récupération de la version')
108
+ );
109
+ }
110
+
111
+ version = version.trim();
112
+ updateLastCheckDate(version);
113
+ resolve(version);
114
+ });
115
+ });
116
+ };
117
+
118
+ // Function to display the banner and the list of commands.
119
+ const displayBanner = () => {
120
+ figlet('poad', function (err, data) {
121
+ console.log(chalk.cyan(data));
122
+ console.log(chalk.white.bold(` version ${package.version}`));
123
+ console.log(' ');
124
+ console.log(
125
+ `${chalk.bold(' Usage :')} ${chalk.cyanBright(
126
+ POAD_COMMAND + ' <command>'
127
+ )} ${chalk.cyan('[<args>]')}`
128
+ );
129
+ console.log(' ');
130
+ console.log(chalk.bold(' Global commands :'));
131
+ console.log(' ');
132
+ display(POAD_GLOBAL_COMMANDS);
133
+ console.log(' ');
134
+ console.log(chalk.bold(' Project commands :'));
135
+ if (!POAD_PATH) {
136
+ console.log(`\n You are not in a project directory. `);
137
+ console.log(' ');
138
+ } else {
139
+ POAD_COMMANDS = loadPoadCommands(__dirname + '/project/cli.js');
140
+ console.log(' ');
141
+ display(POAD_COMMANDS);
142
+ console.log(' ');
143
+ }
144
+ console.log(' ');
145
+ });
146
+ };
147
+
148
+ // Function to load project specific commands.
149
+ const loadPoadCommands = (path) => {
150
+ let POAD_COMMANDS = {};
151
+ try {
152
+ const cli = require(path);
153
+ for (let el in cli) {
154
+ if (cli[el].description) {
155
+ let subs = [];
156
+ for (let s in cli[el]) {
157
+ if (s !== 'description') subs.push({ title: s });
158
+ }
159
+ let description = '';
160
+ if (cli[el].description.indexOf(']') > -1) {
161
+ description = cli[el].description.split('] ')[1];
162
+ let lbl = cli[el].description
163
+ .split('] ')[0]
164
+ .replace('[', '')
165
+ .replace(']', '');
166
+ POAD_COMMANDS[el] = {
167
+ info: {
168
+ title: el,
169
+ description: description,
170
+ label: lbl.toLowerCase(),
171
+ sub: subs,
172
+ },
173
+ };
174
+ } else {
175
+ description = cli[el].description;
176
+ POAD_COMMANDS[el] = {
177
+ info: {
178
+ title: el,
179
+ description: cli[el].description,
180
+ sub: subs,
181
+ },
182
+ };
183
+ }
184
+ } else {
185
+ let description = '';
186
+ if (cli[el].indexOf(']') > -1) {
187
+ description = cli[el].split('] ')[1];
188
+ let lbl = cli[el].split('] ')[0].replace('[', '').replace(']', '');
189
+ POAD_COMMANDS[el] = {
190
+ info: {
191
+ title: el,
192
+ description: description,
193
+ label: lbl.toLowerCase(),
194
+ },
195
+ };
196
+ } else {
197
+ description = cli[el];
198
+ POAD_COMMANDS[el] = {
199
+ info: {
200
+ title: el,
201
+ description: description,
202
+ },
203
+ };
204
+ }
205
+ }
206
+ }
207
+ return POAD_COMMANDS;
208
+ } catch (e) {
209
+ console.log(e);
210
+ }
211
+ };
212
+
25
213
  /**
26
- * Recursively searches for the '.cadriciel' directory.
27
- * @param {string} startPath - Starting path for the search.
28
- * @returns {string|null} Path of the found directory or null.
214
+ * Displays the subcommands and their descriptions for a given command.
215
+ *
216
+ * @param {string} path - The path of the command.
217
+ * @param {string} title - The title of the command.
218
+ * @param {string} description - The description of the command.
219
+ * @param {object} cli - The command line interface object.
29
220
  */
30
- function findCadricielDir(startPath) {
31
- let currentPath = startPath;
221
+ const displaySub = (path, title, description, cli) => {
222
+ POAD_COMMANDS = {};
223
+ delete cli.description;
224
+ for (let el in cli) {
225
+ if (cli[el].description) {
226
+ let subs = [];
227
+ for (let s in cli[el]) {
228
+ if (s !== 'description') subs.push({ title: s });
229
+ }
230
+ let description = '';
231
+ if (cli[el].description.indexOf(']') > -1) {
232
+ description = cli[el].description.split('] ')[1];
233
+ let lbl = cli[el].description
234
+ .split('] ')[0]
235
+ .replace('[', '')
236
+ .replace(']', '');
237
+ POAD_COMMANDS[el] = {
238
+ info: {
239
+ title: el,
240
+ description: description,
241
+ label: lbl.toLowerCase(),
242
+ sub: subs,
243
+ },
244
+ };
245
+ } else {
246
+ description = cli[el].description;
247
+ POAD_COMMANDS[el] = {
248
+ info: {
249
+ title: el,
250
+ description: cli[el].description,
251
+ sub: subs,
252
+ },
253
+ };
254
+ }
255
+ } else {
256
+ let description = '';
257
+ if (cli[el].indexOf(']') > -1) {
258
+ description = cli[el].split('] ')[1];
259
+ let lbl = cli[el].split('] ')[0].replace('[', '').replace(']', '');
260
+ POAD_COMMANDS[el] = {
261
+ info: {
262
+ title: el,
263
+ description: description,
264
+ label: lbl.toLowerCase(),
265
+ },
266
+ };
267
+ } else {
268
+ POAD_COMMANDS[el] = {
269
+ info: {
270
+ title: el,
271
+ description: cli[el],
272
+ },
273
+ };
274
+ }
275
+ }
276
+ }
277
+
278
+ console.log(
279
+ `${chalk.bold(' Usage :')} ${chalk.cyanBright(
280
+ POAD_COMMAND + ' ' + args.join(' ')
281
+ )} ${chalk.cyan('[<args>]')}`
282
+ );
283
+ console.log(' ');
284
+ display(POAD_COMMANDS);
285
+ console.log(' ');
286
+ };
32
287
 
33
- while (currentPath !== path.parse(currentPath).root) {
34
- const potentialPath = path.join(currentPath, '.cadriciel/cli');
35
- if (
36
- fs.existsSync(potentialPath) &&
37
- fs.statSync(potentialPath).isDirectory()
38
- ) {
39
- return potentialPath;
288
+ // Function to parse commands.
289
+ const parseCommand = (args) => {
290
+ const cli = require(__dirname + '/project/cli');
291
+ let cmd = cli;
292
+ let arguments = [];
293
+ let title = '';
294
+ let path = '';
295
+ for (let i = 0; i < args.length; i++) {
296
+ if (!cmd[args[i]]) arguments.push(args[i]);
297
+ else {
298
+ cmd = cmd[args[i]];
299
+ title = args[i];
300
+ path += ' ' + title;
40
301
  }
41
- currentPath = path.dirname(currentPath); // Monter vers le répertoire parent.
42
302
  }
303
+ if (cmd.description) displaySub(path, title, cmd.description, cmd);
304
+ else {
305
+ ExecCommand(path.replace(/ /g, '/'), arguments);
306
+ }
307
+ };
43
308
 
44
- return null;
45
- }
309
+ /**
310
+ * Fonction qui vérifie si un chemin existe dans un objet donné
311
+ * @param {object} obj - L'objet dans lequel chercher
312
+ * @param {Array} pathArray - Le tableau représentant le chemin
313
+ * @returns {*} - L'objet ou la valeur si le chemin existe, sinon null
314
+ */
315
+ const getPathInObject = (obj, pathArray) => {
316
+ return pathArray.reduce((acc, key) => {
317
+ if (acc && acc[key]) {
318
+ return acc[key];
319
+ } else {
320
+ return null;
321
+ }
322
+ }, obj);
323
+ };
46
324
 
47
- // Locating the '.cadriciel' directory starting from the current working directory.
48
- const CADRICIEL_PATH = findCadricielDir(process.cwd());
49
- const CADRICIEL_COMMAND = 'oa';
50
- const CADRICIEL_PERMALINK =
51
- 'https://gist.githubusercontent.com/zucatti/08b37516b23c08028a2b07694f0329b6/raw/cadriciel-url.json';
52
- global.CADRICIEL_URI = '';
325
+ /**
326
+ * Fonction pour construire un chemin valide dans l'objet de commandes
327
+ * et séparer les arguments complémentaires
328
+ * @param {object} commands - L'objet contenant les commandes
329
+ * @param {Array} args - Le tableau d'arguments de la commande
330
+ * @returns {object} - Un objet avec dir (le chemin) et args (les arguments complémentaires)
331
+ */
332
+ const parseCommandArgs = (commands, args) => {
333
+ let dir = []; // Stocke les parties valides du chemin
334
+ let complementaryArgs = []; // Stocke les arguments complémentaires
335
+ let currentCommands = commands; // Commence à la racine des commandes
336
+
337
+ for (let i = 0; i < args.length; i++) {
338
+ const currentPath = args[i];
339
+ if (currentCommands[currentPath]) {
340
+ // Si le chemin est valide, ajoute à dir et descend dans la structure
341
+ dir.push(currentPath);
342
+ currentCommands = currentCommands[currentPath];
343
+ } else {
344
+ // Dès que le chemin n'existe plus, on considère le reste comme des arguments complémentaires
345
+ complementaryArgs = args.slice(i);
346
+ break;
347
+ }
348
+ }
349
+
350
+ return {
351
+ dir: dir.join('/'), // Concatène le chemin avec des "/"
352
+ args: complementaryArgs, // Arguments supplémentaires
353
+ };
354
+ };
355
+
356
+ // Function to process entered commands.
357
+ const processCommands = (args) => {
358
+ const command = args[0];
359
+ const maxWidth = 30;
360
+ const maxDescriptionLength = 50;
361
+
362
+ POAD_COMMANDS = loadPoadCommands(__dirname + '/project/cli.js');
363
+
364
+ if (POAD_GLOBAL_COMMANDS[command]) {
365
+ const px = parseCommandArgs(require(__dirname + '/global/cli'), args);
366
+ const unit = require(path.join(__dirname, 'global', px.dir));
367
+ unit(parseArgs(px.args));
368
+ } else {
369
+ if (POAD_COMMANDS[command]) {
370
+ console.log(' ');
371
+
372
+ const dir = args.join('/');
373
+ const px = parseCommandArgs(require(__dirname + '/project/cli'), args);
374
+
375
+ const unit = require(path.join(__dirname, 'project', px.dir));
376
+ return unit(parseArgs(px.args));
377
+ } else {
378
+ log.error('Unknown command : ' + command);
379
+ return displayBanner();
380
+ }
381
+ }
382
+ };
383
+
384
+ // Function to format command labels with chalk for color coding.
385
+ const label = (o) => {
386
+ const caption = o.label;
387
+
388
+ if (caption === 'experimental') return chalk.red(' (' + caption + ')');
389
+ if (caption === 'alpha') return chalk.cyan(' (' + caption + ')');
390
+ if (caption === 'beta') return chalk.magenta(' (' + caption + ')');
391
+ if (caption === 'docker') return chalk.green(' (' + caption + ')');
392
+ if (caption === 'ai') return chalk.yellow(' (' + caption.toUpperCase() + ')');
393
+ return '';
394
+ };
395
+
396
+ // Function to execute commands.
397
+ const ExecCommand = (p, args) => {
398
+ console.log(p, args);
399
+ const unit = require(__dirname + p);
400
+ const params = {
401
+ dir: {
402
+ home: `${userHomeDir}/.cadriciel`,
403
+ cadriciel: path.normalize(CADRICIEL_PATH + '/..'),
404
+ root: path.normalize(CADRICIEL_PATH + '/../..'),
405
+ },
406
+ };
407
+ unit(args, params);
408
+ };
409
+
410
+ // Function to format command descriptions.
411
+ const formatDescription = (description, maxLength) => {
412
+ if (description.length <= maxLength) return description;
413
+
414
+ const breakPoint = description.lastIndexOf(' ', maxLength);
415
+ const firstPart = description.substring(0, breakPoint);
416
+ const secondPart = description.substring(breakPoint + 1).trim();
417
+
418
+ return firstPart + '\n ' + secondPart;
419
+ };
420
+
421
+ // Function to display commands.
422
+ const display = (commands) => {
423
+ const maxWidth = 30;
424
+ const maxDescriptionLength = 50;
425
+
426
+ for (let el in commands) {
427
+ let title = el;
428
+ if (commands[el].info.title != '---') {
429
+ if (commands[el].info) {
430
+ let description = commands[el].info.description;
431
+ if (commands[el].info.sub) {
432
+ title += ' <subcommand>';
433
+ const sc = [];
434
+ for (let i = 0; i < commands[el].info.sub.length; i++) {
435
+ sc.push(commands[el].info.sub[i].title);
436
+ }
437
+ description += chalk.white(' ');
438
+ description += chalk.grey(' (subcommands: ');
439
+ description += chalk.cyan(sc.join(', '));
440
+ description += chalk.grey(')');
441
+ }
442
+ const dots = '.'.repeat(maxWidth - title.length);
443
+
444
+ const formattedDesc = formatDescription(
445
+ description,
446
+ maxDescriptionLength
447
+ );
448
+
449
+ console.log(
450
+ ' ' +
451
+ chalk.cyanBright(title) +
452
+ ' ' +
453
+ chalk.grey(dots) +
454
+ ' ' +
455
+ label(commands[el].info) +
456
+ ' ' +
457
+ chalk.white(formattedDesc)
458
+ );
459
+ }
460
+ }
461
+ }
462
+ };
463
+
464
+ // Main function.
465
+ const main = async () => {
466
+ let version = await checkVersion();
467
+ const current_version = require(__dirname + '/package.json').version;
468
+
469
+ if (version === null) {
470
+ version = current_version;
471
+ }
472
+ if (current_version != version) {
473
+ const message =
474
+ `A new version (${version}) is available. You can upgrade by running:\n` +
475
+ chalk.white.bold(`npm i -g poad@${version}`);
476
+
477
+ // Options pour le cadre
478
+ const boxenOptions = {
479
+ padding: 1,
480
+ margin: 1,
481
+ borderColor: 'yellow',
482
+ borderStyle: 'double',
483
+ };
484
+
485
+ // Mise en forme du message avec Chalk
486
+ const styledMessage = chalk.yellow(message);
487
+
488
+ // Création de l'encadré avec Boxen
489
+ const framedMessage = boxen(styledMessage, boxenOptions);
490
+
491
+ console.log(framedMessage);
492
+
493
+ POAD_GLOBAL_COMMANDS = loadPoadCommands(__dirname + '/global/cli.js');
494
+ process.argv.shift();
495
+ process.argv.shift();
496
+ if (process.argv.length <= 0) return displayBanner();
497
+ processCommands(process.argv);
498
+ } else {
499
+ POAD_GLOBAL_COMMANDS = loadPoadCommands(__dirname + '/global/cli.js');
500
+ process.argv.shift();
501
+ process.argv.shift();
502
+ if (process.argv.length <= 0) return displayBanner();
503
+ processCommands(process.argv);
504
+ }
505
+ };
506
+
507
+ main();
package/project/cli.js ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ *
3
+ * @label [BETA]
4
+ * @label [EXPERIMENTAL]
5
+ * @label [DOCKER]
6
+ * @label [AI]
7
+ *
8
+ */
9
+ module.exports = {
10
+ info: `Information about your project`,
11
+ /* status: `[AI] Vérification du statut de l'environnement`,
12
+ gen: {
13
+ description: 'Génération automatique des éléments clés pour votre projet',
14
+ db: {
15
+ description: `Utilitaires base de données`,
16
+ create: `[AI] Aide à la création de tables`,
17
+ ext: 'Gestion des extensions Postgres',
18
+ import: 'Importation de données',
19
+ models: 'Génération des modèles Client/Serveur',
20
+ query: '[AI] Aide à la génération de requêtes',
21
+ snapshot: '[BETA] Crée un snapshot de la base de données',
22
+ sql: '[EXPERIMENTAL] Création de repository à partir de SQL',
23
+ },
24
+ api: `Génération des API`,
25
+ component: `Génération de composant angular`,
26
+ page: `Génération de pages angular`,
27
+ project: `Gestion de projet`,
28
+ service: `Génération de services angular`,
29
+ },
30
+ logs: 'Affichage des logs des services',
31
+ project: {
32
+ description: 'Gestion de votre projet (mise à jour,logo) ',
33
+ api: `Génération des API`,
34
+ },
35
+ reset: "Arrête l'environnement et supprime les données",
36
+ restart: "Redémarrage d'un service particulier",
37
+ rm: {
38
+ description: `Suppression automatique des éléments clés pour votre projet`,
39
+ api: `Suppression d'une API`,
40
+ component: `Suppression de composant angular`,
41
+ db: {
42
+ description: `Suppression de base de données`,
43
+ ext: 'Suppression des extensions Postgres',
44
+ models: 'Suppression des modèles Client/Serveur',
45
+ },
46
+ page: `Suppression de pages angular`,
47
+ project: `Suppression de projet`,
48
+ service: `Suppression de services angular`,
49
+ },
50
+ start: "Démarrage de l'environnement",
51
+ stop: "Arrête l'environnement",
52
+ upgrade: `Mise à jour du runtime du cadriciel`,*/
53
+ };
@@ -0,0 +1,9 @@
1
+ module.exports = (args) => {
2
+ return {
3
+ info: {
4
+ title: 'init',
5
+ description: `Démarrage d'un projet poad.`,
6
+ },
7
+ start: async () => {},
8
+ };
9
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = async (args) => {
2
+ console.log(args);
3
+ };
@@ -0,0 +1,23 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+
4
+ /**
5
+ * Recursively searches for the '.cadriciel' directory.
6
+ * @param {string} startPath - Starting path for the search.
7
+ * @returns {string|null} Path of the found directory or null.
8
+ */
9
+ function findPoadDir(startPath) {
10
+ let currentPath = startPath;
11
+
12
+ while (currentPath !== path.parse(currentPath).root) {
13
+ const potentialPath = path.join(currentPath, 'poad', 'config.toml');
14
+ if (fs.existsSync(potentialPath)) {
15
+ return potentialPath;
16
+ }
17
+ currentPath = path.dirname(currentPath); // Monter vers le répertoire parent.
18
+ }
19
+
20
+ return null;
21
+ }
22
+
23
+ module.exports = { findPoadDir };
@@ -0,0 +1,13 @@
1
+ const crypto = require('crypto');
2
+
3
+ /**
4
+ * Generate a secret key in hexadecimal format for signing a JWT
5
+ * @param {number} length - Length of the secret in bytes (default is 32 bytes)
6
+ * @returns {string} - Hexadecimal representation of the secret key
7
+ */
8
+ const generateSecret = (length = 32) => {
9
+ // Generate random bytes and convert them to hexadecimal format
10
+ return crypto.randomBytes(length).toString('hex');
11
+ };
12
+
13
+ module.exports = { generateSecret };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Fonction pour parser une liste d'arguments en un objet clé-valeur
3
+ * @param {Array} args - Le tableau des arguments à parser
4
+ * @returns {object} - Un objet contenant les arguments parsés
5
+ */
6
+ const parseArgs = (args) => {
7
+ const result = {};
8
+
9
+ args.forEach((arg) => {
10
+ // Vérifie si l'argument est sous forme clé=valeur
11
+ if (arg.includes('=')) {
12
+ const [key, value] = arg.split('=');
13
+
14
+ // Tente de convertir la valeur en nombre ou booléen si applicable, sinon garde-la en tant que chaîne
15
+ let parsedValue = value;
16
+ if (!isNaN(value)) {
17
+ parsedValue = Number(value); // Convertit en nombre si possible
18
+ } else if (
19
+ value.toLowerCase() === 'true' ||
20
+ value.toLowerCase() === 'false'
21
+ ) {
22
+ parsedValue = value.toLowerCase() === 'true'; // Convertit en booléen
23
+ }
24
+
25
+ result[key] = parsedValue;
26
+ } else {
27
+ // Si l'argument est un drapeau simple (par exemple 'x'), on le met à true
28
+ result[arg] = true;
29
+ }
30
+ });
31
+
32
+ return result;
33
+ };
34
+
35
+ module.exports = { parseArgs };
package/utils/ports.js ADDED
@@ -0,0 +1,59 @@
1
+ const net = require('net');
2
+
3
+ /**
4
+ * Check if a specific port is free
5
+ * @param {number} port
6
+ * @returns {Promise<boolean>}
7
+ */
8
+ const isPortFree = (port) => {
9
+ return new Promise((resolve, reject) => {
10
+ const server = net.createServer();
11
+
12
+ server.once('error', (err) => {
13
+ if (err.code === 'EADDRINUSE') {
14
+ resolve(false); // Port is in use
15
+ } else {
16
+ reject(err); // Unexpected error
17
+ }
18
+ });
19
+
20
+ server.once('listening', () => {
21
+ server.close(() => resolve(true)); // Port is free
22
+ });
23
+
24
+ server.listen(port);
25
+ });
26
+ };
27
+
28
+ /**
29
+ * Generate a random port within a specified range
30
+ * @param {number} min - Minimum port number
31
+ * @param {number} max - Maximum port number
32
+ * @returns {number}
33
+ */
34
+ const getRandomPort = (min = 1024, max = 65535) => {
35
+ return Math.floor(Math.random() * (max - min + 1)) + min;
36
+ };
37
+
38
+ /**
39
+ * Find a list of free ports, using randomized port numbers
40
+ * @param {number} count - Number of free ports to find
41
+ * @param {number} minPort - Minimum port number for randomization
42
+ * @param {number} maxPort - Maximum port number for randomization
43
+ * @returns {Promise<number[]>}
44
+ */
45
+ const findFreePorts = async (count, minPort = 1024, maxPort = 65535) => {
46
+ const freePorts = new Set(); // Use a Set to avoid duplicate ports
47
+
48
+ while (freePorts.size < count) {
49
+ const port = getRandomPort(minPort, maxPort);
50
+
51
+ if (await isPortFree(port)) {
52
+ freePorts.add(port); // Add only if the port is free
53
+ }
54
+ }
55
+
56
+ return Array.from(freePorts);
57
+ };
58
+
59
+ module.exports = { findFreePorts };