@envsafes-org/cli 0.0.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/README.md +343 -0
- package/STORAGE_AGENT_README.md +328 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.js +55 -0
- package/dist/commands/projects.d.ts +1 -0
- package/dist/commands/projects.js +40 -0
- package/dist/commands/pull.d.ts +4 -0
- package/dist/commands/pull.js +46 -0
- package/dist/commands/push.d.ts +4 -0
- package/dist/commands/push.js +56 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.js +49 -0
- package/dist/commands/whoami.d.ts +1 -0
- package/dist/commands/whoami.js +34 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +98 -0
- package/dist/utils/api.d.ts +7 -0
- package/dist/utils/api.js +25 -0
- package/package.json +42 -0
- package/src/commands/login.ts +58 -0
- package/src/commands/projects.ts +40 -0
- package/src/commands/pull.ts +53 -0
- package/src/commands/push.ts +64 -0
- package/src/commands/run.ts +55 -0
- package/src/commands/whoami.ts +33 -0
- package/src/index.ts +105 -0
- package/src/utils/api.ts +36 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.login = login;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
9
|
+
const index_js_1 = require("../index.js");
|
|
10
|
+
const api_js_1 = require("../utils/api.js");
|
|
11
|
+
const open_1 = __importDefault(require("open"));
|
|
12
|
+
async function login(options) {
|
|
13
|
+
let token = options.token;
|
|
14
|
+
if (!token) {
|
|
15
|
+
const dashboardUrl = index_js_1.config.get("dashboardUrl");
|
|
16
|
+
const loginUrl = `${dashboardUrl}/dashboard?redirect=tokens`;
|
|
17
|
+
console.log(chalk_1.default.cyan(`\nOuverture du navigateur pour générer un token...\n`));
|
|
18
|
+
console.log(chalk_1.default.dim(`Si le navigateur ne s'ouvre pas, visitez : ${loginUrl}`));
|
|
19
|
+
try {
|
|
20
|
+
await (0, open_1.default)(loginUrl);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
// Ignore error if browser fails to open
|
|
24
|
+
}
|
|
25
|
+
const answers = await inquirer_1.default.prompt([
|
|
26
|
+
{
|
|
27
|
+
type: "password",
|
|
28
|
+
name: "token",
|
|
29
|
+
message: "Collez votre token API EnvSafe ici:",
|
|
30
|
+
mask: "*",
|
|
31
|
+
validate: (input) => input.length > 0 || "Le token est requis",
|
|
32
|
+
},
|
|
33
|
+
]);
|
|
34
|
+
token = answers.token;
|
|
35
|
+
}
|
|
36
|
+
console.log(chalk_1.default.dim("Vérification du token..."));
|
|
37
|
+
try {
|
|
38
|
+
// Test the token
|
|
39
|
+
const response = await (0, api_js_1.apiRequest)("/api/v1/projects", {
|
|
40
|
+
method: "GET",
|
|
41
|
+
token,
|
|
42
|
+
});
|
|
43
|
+
if (response.error) {
|
|
44
|
+
console.log(chalk_1.default.red(`✗ Erreur: ${response.error}`));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Save token
|
|
48
|
+
index_js_1.config.set("token", token);
|
|
49
|
+
console.log(chalk_1.default.green("✓ Connexion réussie!"));
|
|
50
|
+
console.log(chalk_1.default.dim(` ${response.count} projet(s) accessible(s)`));
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.log(chalk_1.default.red(`✗ Erreur de connexion: ${error.message}`));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function projects(): Promise<void>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.projects = projects;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const index_js_1 = require("../index.js");
|
|
9
|
+
const api_js_1 = require("../utils/api.js");
|
|
10
|
+
async function projects() {
|
|
11
|
+
const token = index_js_1.config.get("token");
|
|
12
|
+
if (!token) {
|
|
13
|
+
console.log(chalk_1.default.red("✗ Non connecté. Utilisez 'envsafe login' d'abord."));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const response = await (0, api_js_1.apiRequest)("/api/v1/projects", {
|
|
18
|
+
method: "GET",
|
|
19
|
+
token,
|
|
20
|
+
});
|
|
21
|
+
if (response.error) {
|
|
22
|
+
console.log(chalk_1.default.red(`✗ ${response.error}`));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log(chalk_1.default.cyan("\n📁 Projets accessibles\n"));
|
|
26
|
+
if (response.projects.length === 0) {
|
|
27
|
+
console.log(chalk_1.default.dim(" Aucun projet trouvé."));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
for (const project of response.projects) {
|
|
31
|
+
console.log(chalk_1.default.bold(` ${project.name}`));
|
|
32
|
+
console.log(chalk_1.default.dim(` slug: ${project.slug}`));
|
|
33
|
+
console.log(chalk_1.default.dim(` envs: ${project.environments.join(", ")}`));
|
|
34
|
+
console.log("");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.log(chalk_1.default.red(`✗ Erreur: ${error.message}`));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.pull = pull;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const index_js_1 = require("../index.js");
|
|
11
|
+
const api_js_1 = require("../utils/api.js");
|
|
12
|
+
async function pull(project, options) {
|
|
13
|
+
const token = index_js_1.config.get("token");
|
|
14
|
+
if (!token) {
|
|
15
|
+
console.log(chalk_1.default.red("✗ Non connecté. Utilisez 'envsafe login' d'abord."));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const spinner = (0, ora_1.default)(`Téléchargement des variables pour ${project} (${options.env})...`).start();
|
|
19
|
+
try {
|
|
20
|
+
const response = await (0, api_js_1.apiRequest)(`/api/v1/projects/${project}/${options.env}`, {
|
|
21
|
+
method: "GET",
|
|
22
|
+
token,
|
|
23
|
+
});
|
|
24
|
+
if (response.error) {
|
|
25
|
+
spinner.fail(chalk_1.default.red(response.error));
|
|
26
|
+
// Suggestion intelligente si l'utilisateur a confondu projet et environnement
|
|
27
|
+
const commonEnvs = ["development", "dev", "staging", "stg", "production", "prod", "test"];
|
|
28
|
+
if (commonEnvs.includes(project.toLowerCase()) || response.error.includes("trouvé")) {
|
|
29
|
+
console.log(chalk_1.default.yellow("\n💡 Astuce : La syntaxe est 'envsafe pull <MON_PROJET>'"));
|
|
30
|
+
console.log(chalk_1.default.yellow(` Vous avez essayé de pull le projet "${project}".`));
|
|
31
|
+
console.log(chalk_1.default.yellow(` Utilisez 'envsafe projects' pour voir la liste de vos projets/slugs.`));
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Format as .env content
|
|
36
|
+
const envContent = Object.entries(response.variables)
|
|
37
|
+
.map(([key, value]) => `${key}="${value}"`)
|
|
38
|
+
.join("\n");
|
|
39
|
+
// Write to file
|
|
40
|
+
fs_1.default.writeFileSync(options.output, envContent + "\n");
|
|
41
|
+
spinner.succeed(chalk_1.default.green(`✓ ${response.count} variable(s) téléchargée(s) vers ${options.output}`));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
spinner.fail(chalk_1.default.red(`Erreur: ${error.message}`));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.push = push;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
11
|
+
const index_js_1 = require("../index.js");
|
|
12
|
+
const api_js_1 = require("../utils/api.js");
|
|
13
|
+
async function push(project, options) {
|
|
14
|
+
const token = index_js_1.config.get("token");
|
|
15
|
+
if (!token) {
|
|
16
|
+
console.log(chalk_1.default.red("✗ Non connecté. Utilisez 'envsafe login' d'abord."));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
// Check if file exists
|
|
20
|
+
if (!fs_1.default.existsSync(options.file)) {
|
|
21
|
+
console.log(chalk_1.default.red(`✗ Fichier non trouvé: ${options.file}`));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const spinner = (0, ora_1.default)(`Envoi des variables vers ${project} (${options.env})...`).start();
|
|
25
|
+
try {
|
|
26
|
+
// Parse .env file
|
|
27
|
+
const envContent = fs_1.default.readFileSync(options.file, "utf-8");
|
|
28
|
+
const parsed = dotenv_1.default.parse(envContent);
|
|
29
|
+
const response = await (0, api_js_1.apiRequest)(`/api/v1/projects/${project}/${options.env}`, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
token,
|
|
32
|
+
body: { variables: parsed },
|
|
33
|
+
});
|
|
34
|
+
if (response.error) {
|
|
35
|
+
spinner.fail(chalk_1.default.red(response.error));
|
|
36
|
+
// Suggestion intelligente
|
|
37
|
+
const commonEnvs = ["development", "dev", "staging", "stg", "production", "prod", "test"];
|
|
38
|
+
if (commonEnvs.includes(project.toLowerCase()) || response.error.includes("trouvé")) {
|
|
39
|
+
console.log(chalk_1.default.yellow("\n💡 Astuce : La syntaxe est 'envsafe push <MON_PROJET>'"));
|
|
40
|
+
console.log(chalk_1.default.yellow(` Vous avez essayé de push vers le projet "${project}".`));
|
|
41
|
+
console.log(chalk_1.default.yellow(` Utilisez 'envsafe projects' pour voir la liste de vos projets/slugs.`));
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
spinner.succeed(chalk_1.default.green(`✓ ${response.created} variable(s) créée(s)`));
|
|
46
|
+
if (response.errors?.length > 0) {
|
|
47
|
+
console.log(chalk_1.default.yellow("\nAvertissements:"));
|
|
48
|
+
response.errors.forEach((err) => {
|
|
49
|
+
console.log(chalk_1.default.dim(` - ${err}`));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
spinner.fail(chalk_1.default.red(`Erreur: ${error.message}`));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.run = run;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const index_js_1 = require("../index.js");
|
|
10
|
+
const api_js_1 = require("../utils/api.js");
|
|
11
|
+
async function run(project, command, options) {
|
|
12
|
+
const token = index_js_1.config.get("token");
|
|
13
|
+
if (!token) {
|
|
14
|
+
console.log(chalk_1.default.red("✗ Non connecté. Utilisez 'envsafe login' d'abord."));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
console.log(chalk_1.default.dim(`Récupération des variables pour ${project} (${options.env})...`));
|
|
18
|
+
try {
|
|
19
|
+
const response = await (0, api_js_1.apiRequest)(`/api/v1/projects/${project}/${options.env}`, {
|
|
20
|
+
method: "GET",
|
|
21
|
+
token,
|
|
22
|
+
});
|
|
23
|
+
if (response.error) {
|
|
24
|
+
console.log(chalk_1.default.red(`✗ ${response.error}`));
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const variables = response.variables;
|
|
28
|
+
console.log(chalk_1.default.green(`✓ ${Object.keys(variables).length} variable(s) chargée(s)`));
|
|
29
|
+
console.log(chalk_1.default.dim(`Exécution: ${command.join(" ")}\n`));
|
|
30
|
+
// Spawn the command with injected env vars
|
|
31
|
+
const [cmd, ...args] = command;
|
|
32
|
+
const child = (0, child_process_1.spawn)(cmd, args, {
|
|
33
|
+
env: { ...process.env, ...variables },
|
|
34
|
+
stdio: "inherit",
|
|
35
|
+
shell: true,
|
|
36
|
+
});
|
|
37
|
+
child.on("close", (code) => {
|
|
38
|
+
process.exit(code ?? 0);
|
|
39
|
+
});
|
|
40
|
+
child.on("error", (err) => {
|
|
41
|
+
console.error(chalk_1.default.red(`Erreur d'exécution: ${err.message}`));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.log(chalk_1.default.red(`✗ Erreur: ${error.message}`));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function whoami(): Promise<void>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.whoami = whoami;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const index_js_1 = require("../index.js");
|
|
9
|
+
const api_js_1 = require("../utils/api.js");
|
|
10
|
+
async function whoami() {
|
|
11
|
+
const token = index_js_1.config.get("token");
|
|
12
|
+
const apiUrl = index_js_1.config.get("apiUrl");
|
|
13
|
+
if (!token) {
|
|
14
|
+
console.log(chalk_1.default.red("✗ Non connecté. Utilisez 'envsafe login' d'abord."));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const user = await (0, api_js_1.apiRequest)("/api/v1/user/me", {
|
|
19
|
+
method: "GET",
|
|
20
|
+
token
|
|
21
|
+
});
|
|
22
|
+
console.log(chalk_1.default.cyan("\n🔐 EnvSafe CLI\n"));
|
|
23
|
+
console.log(` Utilisateur: ${chalk_1.default.white(user.name)} (${chalk_1.default.dim(user.email)})`);
|
|
24
|
+
if (user.lastLoginAt) {
|
|
25
|
+
const date = new Date(user.lastLoginAt).toLocaleString();
|
|
26
|
+
console.log(` Dernière connexion: ${chalk_1.default.dim(date)}`);
|
|
27
|
+
}
|
|
28
|
+
console.log(` API: ${chalk_1.default.dim(apiUrl)}`);
|
|
29
|
+
console.log(` Token: ${chalk_1.default.dim(token.substring(0, 12) + "...")}\n`);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.log(chalk_1.default.red(`✗ Impossible de récupérer les infos utilisateur: ${error.message}`));
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.config = void 0;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const conf_1 = __importDefault(require("conf"));
|
|
11
|
+
const login_js_1 = require("./commands/login.js");
|
|
12
|
+
const pull_js_1 = require("./commands/pull.js");
|
|
13
|
+
const push_js_1 = require("./commands/push.js");
|
|
14
|
+
const run_js_1 = require("./commands/run.js");
|
|
15
|
+
const projects_js_1 = require("./commands/projects.js");
|
|
16
|
+
const whoami_js_1 = require("./commands/whoami.js");
|
|
17
|
+
const package_json_1 = __importDefault(require("../package.json"));
|
|
18
|
+
// Config store for token
|
|
19
|
+
exports.config = new conf_1.default({
|
|
20
|
+
projectName: "envsafe-cli",
|
|
21
|
+
schema: {
|
|
22
|
+
token: { type: "string", default: "" },
|
|
23
|
+
apiUrl: { type: "string", default: "https://envsafe.vercel.app" },
|
|
24
|
+
dashboardUrl: { type: "string", default: "https://envsafe.vercel.app" },
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
const program = new commander_1.Command();
|
|
28
|
+
program
|
|
29
|
+
.name("envsafe")
|
|
30
|
+
.description(chalk_1.default.cyan("🔐 EnvSafe CLI - Gestionnaire sécurisé de variables d'environnement"))
|
|
31
|
+
.version(package_json_1.default.version);
|
|
32
|
+
// Login command
|
|
33
|
+
program
|
|
34
|
+
.command("login")
|
|
35
|
+
.description("Se connecter avec un token API")
|
|
36
|
+
.option("-t, --token <token>", "Token API")
|
|
37
|
+
.action(login_js_1.login);
|
|
38
|
+
// Whoami command
|
|
39
|
+
program
|
|
40
|
+
.command("whoami")
|
|
41
|
+
.description("Afficher l'utilisateur connecté")
|
|
42
|
+
.action(whoami_js_1.whoami);
|
|
43
|
+
// Projects command
|
|
44
|
+
program
|
|
45
|
+
.command("projects")
|
|
46
|
+
.alias("ls")
|
|
47
|
+
.description("Lister les projets accessibles")
|
|
48
|
+
.action(projects_js_1.projects);
|
|
49
|
+
// Pull command
|
|
50
|
+
program
|
|
51
|
+
.command("pull")
|
|
52
|
+
.description("Télécharger les variables d'environnement")
|
|
53
|
+
.argument("<project>", "Slug du projet")
|
|
54
|
+
.option("-e, --env <environment>", "Environnement (development, staging, production)", "development")
|
|
55
|
+
.option("-o, --output <file>", "Fichier de sortie", ".env")
|
|
56
|
+
.action(pull_js_1.pull);
|
|
57
|
+
// Push command
|
|
58
|
+
program
|
|
59
|
+
.command("push")
|
|
60
|
+
.description("Envoyer les variables d'environnement")
|
|
61
|
+
.argument("<project>", "Slug du projet")
|
|
62
|
+
.option("-e, --env <environment>", "Environnement", "development")
|
|
63
|
+
.option("-f, --file <file>", "Fichier source", ".env")
|
|
64
|
+
.action(push_js_1.push);
|
|
65
|
+
// Run command
|
|
66
|
+
program
|
|
67
|
+
.command("run")
|
|
68
|
+
.description("Exécuter une commande avec les variables d'environnement injectées")
|
|
69
|
+
.argument("<project>", "Slug du projet")
|
|
70
|
+
.option("-e, --env <environment>", "Environnement", "development")
|
|
71
|
+
.argument("<command...>", "Commande à exécuter")
|
|
72
|
+
.action(run_js_1.run);
|
|
73
|
+
// Config command
|
|
74
|
+
program
|
|
75
|
+
.command("config")
|
|
76
|
+
.description("Gérer la configuration")
|
|
77
|
+
.option("--api-url <url>", "Définir l'URL de l'API EnvSafe")
|
|
78
|
+
.option("--show", "Afficher la configuration actuelle")
|
|
79
|
+
.action((options) => {
|
|
80
|
+
if (options.apiUrl) {
|
|
81
|
+
exports.config.set("apiUrl", options.apiUrl);
|
|
82
|
+
console.log(chalk_1.default.green(`✓ URL de l'API définie: ${options.apiUrl}`));
|
|
83
|
+
}
|
|
84
|
+
if (options.show) {
|
|
85
|
+
console.log(chalk_1.default.cyan("Configuration actuelle:"));
|
|
86
|
+
console.log(` API URL: ${exports.config.get("apiUrl")}`);
|
|
87
|
+
console.log(` Token: ${exports.config.get("token") ? "••••••••" : "(non défini)"}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// Logout command
|
|
91
|
+
program
|
|
92
|
+
.command("logout")
|
|
93
|
+
.description("Se déconnecter")
|
|
94
|
+
.action(() => {
|
|
95
|
+
exports.config.set("token", "");
|
|
96
|
+
console.log(chalk_1.default.green("✓ Déconnexion réussie"));
|
|
97
|
+
});
|
|
98
|
+
program.parse();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.apiRequest = apiRequest;
|
|
4
|
+
const index_js_1 = require("../index.js");
|
|
5
|
+
async function apiRequest(endpoint, options) {
|
|
6
|
+
const apiUrl = index_js_1.config.get("apiUrl");
|
|
7
|
+
const token = options.token || index_js_1.config.get("token");
|
|
8
|
+
const url = `${apiUrl}${endpoint}`;
|
|
9
|
+
const headers = {
|
|
10
|
+
"Content-Type": "application/json",
|
|
11
|
+
};
|
|
12
|
+
if (token) {
|
|
13
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
14
|
+
}
|
|
15
|
+
const response = await fetch(url, {
|
|
16
|
+
method: options.method,
|
|
17
|
+
headers,
|
|
18
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
19
|
+
});
|
|
20
|
+
const data = await response.json();
|
|
21
|
+
if (!response.ok && !data.error) {
|
|
22
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
return data;
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@envsafes-org/cli",
|
|
3
|
+
"version": "0.0.6",
|
|
4
|
+
"description": "CLI pour EnvSafe - Gestionnaire sécurisé de variables d'environnement",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"envsafe": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/Ifiboys/envsafe-cli.git"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"dev": "tsx src/index.ts",
|
|
16
|
+
"start": "node dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"env",
|
|
20
|
+
"environment",
|
|
21
|
+
"variables",
|
|
22
|
+
"cli",
|
|
23
|
+
"secrets"
|
|
24
|
+
],
|
|
25
|
+
"author": "EnvSafe Team",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"chalk": "^5.3.0",
|
|
29
|
+
"commander": "^12.0.0",
|
|
30
|
+
"conf": "^12.0.0",
|
|
31
|
+
"dotenv": "^16.3.1",
|
|
32
|
+
"inquirer": "^9.2.12",
|
|
33
|
+
"open": "^11.0.0",
|
|
34
|
+
"ora": "^8.0.1"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/inquirer": "^9.0.7",
|
|
38
|
+
"@types/node": "^20.0.0",
|
|
39
|
+
"tsx": "^4.0.0",
|
|
40
|
+
"typescript": "^5.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
import { config } from "../index.js";
|
|
4
|
+
import { apiRequest } from "../utils/api.js";
|
|
5
|
+
|
|
6
|
+
import open from "open";
|
|
7
|
+
|
|
8
|
+
export async function login(options: { token?: string }) {
|
|
9
|
+
let token = options.token;
|
|
10
|
+
|
|
11
|
+
if (!token) {
|
|
12
|
+
const dashboardUrl = config.get("dashboardUrl") as string;
|
|
13
|
+
const loginUrl = `${dashboardUrl}/dashboard?redirect=tokens`;
|
|
14
|
+
|
|
15
|
+
console.log(chalk.cyan(`\nOuverture du navigateur pour générer un token...\n`));
|
|
16
|
+
console.log(chalk.dim(`Si le navigateur ne s'ouvre pas, visitez : ${loginUrl}`));
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
await open(loginUrl);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
// Ignore error if browser fails to open
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const answers = await inquirer.prompt([
|
|
25
|
+
{
|
|
26
|
+
type: "password",
|
|
27
|
+
name: "token",
|
|
28
|
+
message: "Collez votre token API EnvSafe ici:",
|
|
29
|
+
mask: "*",
|
|
30
|
+
validate: (input) => input.length > 0 || "Le token est requis",
|
|
31
|
+
},
|
|
32
|
+
]);
|
|
33
|
+
token = answers.token;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log(chalk.dim("Vérification du token..."));
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Test the token
|
|
40
|
+
const response = await apiRequest("/api/v1/projects", {
|
|
41
|
+
method: "GET",
|
|
42
|
+
token,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (response.error) {
|
|
46
|
+
console.log(chalk.red(`✗ Erreur: ${response.error}`));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Save token
|
|
51
|
+
config.set("token", token);
|
|
52
|
+
|
|
53
|
+
console.log(chalk.green("✓ Connexion réussie!"));
|
|
54
|
+
console.log(chalk.dim(` ${response.count} projet(s) accessible(s)`));
|
|
55
|
+
} catch (error: any) {
|
|
56
|
+
console.log(chalk.red(`✗ Erreur de connexion: ${error.message}`));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { config } from "../index.js";
|
|
3
|
+
import { apiRequest } from "../utils/api.js";
|
|
4
|
+
|
|
5
|
+
export async function projects() {
|
|
6
|
+
const token = config.get("token") as string;
|
|
7
|
+
|
|
8
|
+
if (!token) {
|
|
9
|
+
console.log(chalk.red("✗ Non connecté. Utilisez 'envsafe login' d'abord."));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const response = await apiRequest("/api/v1/projects", {
|
|
15
|
+
method: "GET",
|
|
16
|
+
token,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (response.error) {
|
|
20
|
+
console.log(chalk.red(`✗ ${response.error}`));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log(chalk.cyan("\n📁 Projets accessibles\n"));
|
|
25
|
+
|
|
26
|
+
if (response.projects.length === 0) {
|
|
27
|
+
console.log(chalk.dim(" Aucun projet trouvé."));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (const project of response.projects) {
|
|
32
|
+
console.log(chalk.bold(` ${project.name}`));
|
|
33
|
+
console.log(chalk.dim(` slug: ${project.slug}`));
|
|
34
|
+
console.log(chalk.dim(` envs: ${project.environments.join(", ")}`));
|
|
35
|
+
console.log("");
|
|
36
|
+
}
|
|
37
|
+
} catch (error: any) {
|
|
38
|
+
console.log(chalk.red(`✗ Erreur: ${error.message}`));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import { config } from "../index.js";
|
|
5
|
+
import { apiRequest } from "../utils/api.js";
|
|
6
|
+
|
|
7
|
+
export async function pull(
|
|
8
|
+
project: string,
|
|
9
|
+
options: { env: string; output: string }
|
|
10
|
+
) {
|
|
11
|
+
const token = config.get("token") as string;
|
|
12
|
+
|
|
13
|
+
if (!token) {
|
|
14
|
+
console.log(chalk.red("✗ Non connecté. Utilisez 'envsafe login' d'abord."));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const spinner = ora(`Téléchargement des variables pour ${project} (${options.env})...`).start();
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const response = await apiRequest(`/api/v1/projects/${project}/${options.env}`, {
|
|
22
|
+
method: "GET",
|
|
23
|
+
token,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (response.error) {
|
|
27
|
+
spinner.fail(chalk.red(response.error));
|
|
28
|
+
|
|
29
|
+
// Suggestion intelligente si l'utilisateur a confondu projet et environnement
|
|
30
|
+
const commonEnvs = ["development", "dev", "staging", "stg", "production", "prod", "test"];
|
|
31
|
+
if (commonEnvs.includes(project.toLowerCase()) || response.error.includes("trouvé")) {
|
|
32
|
+
console.log(chalk.yellow("\n💡 Astuce : La syntaxe est 'envsafe pull <MON_PROJET>'"));
|
|
33
|
+
console.log(chalk.yellow(` Vous avez essayé de pull le projet "${project}".`));
|
|
34
|
+
console.log(chalk.yellow(` Utilisez 'envsafe projects' pour voir la liste de vos projets/slugs.`));
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Format as .env content
|
|
40
|
+
const envContent = Object.entries(response.variables as Record<string, string>)
|
|
41
|
+
.map(([key, value]) => `${key}="${value}"`)
|
|
42
|
+
.join("\n");
|
|
43
|
+
|
|
44
|
+
// Write to file
|
|
45
|
+
fs.writeFileSync(options.output, envContent + "\n");
|
|
46
|
+
|
|
47
|
+
spinner.succeed(
|
|
48
|
+
chalk.green(`✓ ${response.count} variable(s) téléchargée(s) vers ${options.output}`)
|
|
49
|
+
);
|
|
50
|
+
} catch (error: any) {
|
|
51
|
+
spinner.fail(chalk.red(`Erreur: ${error.message}`));
|
|
52
|
+
}
|
|
53
|
+
}
|