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 +16 -0
- package/global/cli.js +13 -0
- package/global/init.js +42 -0
- package/global/install.js +49 -0
- package/global/start.js +46 -0
- package/package.json +6 -2
- package/poad.js +477 -22
- package/project/cli.js +53 -0
- package/project/init.js +9 -0
- package/project/rm/api.js +3 -0
- package/utils/findpoad.js +23 -0
- package/utils/jwtkey.js +13 -0
- package/utils/parseArgs.js +35 -0
- package/utils/ports.js +59 -0
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
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
|
+
};
|
package/global/start.js
ADDED
|
@@ -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.
|
|
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
|
|
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
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* @
|
|
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
|
-
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
+
};
|
package/project/init.js
ADDED
|
@@ -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 };
|
package/utils/jwtkey.js
ADDED
|
@@ -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 };
|