@elding/cli 0.9.3 → 0.9.4

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.
@@ -0,0 +1 @@
1
+ export declare function deploy(): Promise<void>;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deploy = deploy;
4
+ const config_js_1 = require("../lib/config.js");
5
+ const api_js_1 = require("../lib/api.js");
6
+ const terminal_js_1 = require("../lib/terminal.js");
7
+ // `elding deploy` : génère une clé de déploiement (visible dans l'onglet Clés API)
8
+ // et affiche les 2 variables d'environnement à coller en production.
9
+ async function deploy() {
10
+ const { default: chalk } = await import("chalk");
11
+ const { default: ora } = await import("ora");
12
+ const config = (0, config_js_1.readConfig)();
13
+ if (!config) {
14
+ console.error(chalk.red("Not signed in. Run `elding login` first."));
15
+ process.exit(1);
16
+ }
17
+ const project = (0, config_js_1.readProject)();
18
+ if (!project) {
19
+ console.error(chalk.red("Project not linked. Run `elding init` first."));
20
+ process.exit(1);
21
+ }
22
+ const spinner = ora("Creating deployment key...").start();
23
+ let result;
24
+ try {
25
+ const accessToken = await (0, api_js_1.exchangeToken)(config.refreshToken);
26
+ result = await (0, api_js_1.createDeployToken)(accessToken);
27
+ spinner.stop();
28
+ }
29
+ catch (err) {
30
+ spinner.fail(chalk.red((0, terminal_js_1.safeText)(err.message, 200) || "Creation failed."));
31
+ process.exit(1);
32
+ }
33
+ console.log(chalk.green(`✓ Key "${(0, terminal_js_1.safeText)(result.label, 80)}" created (visible in the API Keys tab).`));
34
+ console.log(chalk.dim("\nAdd these 2 environment variables to your host (Vercel, etc.):\n"));
35
+ console.log(` ELDING_REFRESH_TOKEN=${result.refreshToken}`);
36
+ console.log(` ELDING_SET_ID=${(0, terminal_js_1.safeText)(project.setId, 64)}`);
37
+ console.log(chalk.yellow("\n⚠ The key is shown only once. Copy it now."));
38
+ }
@@ -13,46 +13,46 @@ async function doctor() {
13
13
  // 1. Token local
14
14
  const config = (0, config_js_1.readConfig)();
15
15
  if (!config) {
16
- fail("Non connectélancez `elding login`");
16
+ fail("Not signed in run `elding login`");
17
17
  return;
18
18
  }
19
- ok("Token local présent (trousseau OS)");
19
+ ok("Local token present (OS keychain)");
20
20
  // 2. Token valide + utilisateur
21
21
  let accessToken;
22
22
  try {
23
23
  accessToken = await (0, api_js_1.exchangeToken)(config.refreshToken);
24
24
  const me = await (0, api_js_1.getMe)(accessToken);
25
- ok(`Authentifié : ${(0, terminal_js_1.safeText)(me.email)}`);
25
+ ok(`Authenticated: ${(0, terminal_js_1.safeText)(me.email)}`);
26
26
  }
27
27
  catch {
28
- fail("Token expiré ou révoquérelancez `elding login`");
28
+ fail("Token expired or revokedrun `elding login` again");
29
29
  return;
30
30
  }
31
31
  // 3. Set du projet
32
32
  const project = (0, config_js_1.readProject)();
33
33
  if (!project) {
34
- warn("Aucun set configurélancez `elding init` ou `elding use <set>`");
34
+ warn("No set configuredrun `elding init` or `elding use <set>`");
35
35
  return;
36
36
  }
37
- ok(`Set actif : ${(0, terminal_js_1.safeText)(project.setName)}`);
37
+ ok(`Active set: ${(0, terminal_js_1.safeText)(project.setName)}`);
38
38
  // 4. Clés + verrouillage host
39
39
  try {
40
40
  const keys = await (0, api_js_1.listKeys)(accessToken, project.setId);
41
41
  if (keys.length === 0)
42
- warn("Le set ne contient aucune clé");
42
+ warn("The set contains no keys");
43
43
  else {
44
44
  const locked = keys.filter((k) => k.allowedHost).length;
45
- ok(`${keys.length} clé(s) — ${locked} verrouillée(s) sur un domaine`);
45
+ ok(`${keys.length} key(s) — ${locked} locked to a domain`);
46
46
  if (locked < keys.length)
47
- warn(`${keys.length - locked} clé(s) sans domaine : exfiltrables via le proxy`);
47
+ warn(`${keys.length - locked} key(s) without a domain: exfiltratable via the proxy`);
48
48
  }
49
49
  }
50
50
  catch {
51
- fail("Impossible de lire les clés du set");
51
+ fail("Could not read the set's keys");
52
52
  }
53
53
  // 5. Proxy
54
54
  if (process.env.ELDING_PROXY_URL)
55
- ok(`Proxy actif : ${process.env.ELDING_PROXY_URL}`);
55
+ ok(`Proxy active: ${process.env.ELDING_PROXY_URL}`);
56
56
  else
57
- console.log(chalk.dim("○ Proxy inactif (normal hors `elding proxy`)"));
57
+ console.log(chalk.dim("○ Proxy inactive (normal outside `elding proxy`)"));
58
58
  }
@@ -10,16 +10,16 @@ async function init() {
10
10
  const { default: inquirer } = await import("inquirer");
11
11
  const config = (0, config_js_1.readConfig)();
12
12
  if (!config) {
13
- console.error(chalk.red("Non connecté. Lancez `elding login` d'abord."));
13
+ console.error(chalk.red("Not signed in. Run `elding login` first."));
14
14
  process.exit(1);
15
15
  }
16
- const spinner = ora("Récupération des sets...").start();
16
+ const spinner = ora("Fetching sets...").start();
17
17
  let accessToken;
18
18
  try {
19
19
  accessToken = await (0, api_js_1.exchangeToken)(config.refreshToken);
20
20
  }
21
21
  catch (err) {
22
- spinner.fail(chalk.red("Impossible d'obtenir un access token. Relancez `elding login`."));
22
+ spinner.fail(chalk.red("Could not get an access token. Run `elding login` again."));
23
23
  process.exit(1);
24
24
  }
25
25
  let sets;
@@ -28,11 +28,11 @@ async function init() {
28
28
  spinner.stop();
29
29
  }
30
30
  catch (err) {
31
- spinner.fail(chalk.red("Impossible de récupérer les sets."));
31
+ spinner.fail(chalk.red("Could not fetch sets."));
32
32
  process.exit(1);
33
33
  }
34
34
  if (sets.length === 0) {
35
- console.log(chalk.yellow("Aucun set trouvé. Créez-en un sur le vault."));
35
+ console.log(chalk.yellow("No sets found. Create one in the vault."));
36
36
  process.exit(0);
37
37
  }
38
38
  // Étape 1 : choisir l'organisation (toujours, pour une approche projet cohérente)
@@ -41,7 +41,7 @@ async function init() {
41
41
  {
42
42
  type: "select",
43
43
  name: "workspaceId",
44
- message: "Quelle organisation ?",
44
+ message: "Which organization?",
45
45
  choices: orgs.map(([id, name]) => ({ name: (0, terminal_js_1.safeText)(name), value: id })),
46
46
  },
47
47
  ]);
@@ -52,7 +52,7 @@ async function init() {
52
52
  {
53
53
  type: "select",
54
54
  name: "setId",
55
- message: "Quel set utiliser pour ce projet ?",
55
+ message: "Which set should this project use?",
56
56
  choices: orgSets.map((s) => {
57
57
  const env = s.environment ? ENV_LABELS[s.environment] : undefined;
58
58
  return { name: env ? `${(0, terminal_js_1.safeText)(s.name)} (${env})` : (0, terminal_js_1.safeText)(s.name), value: s.id };
@@ -68,5 +68,5 @@ async function init() {
68
68
  };
69
69
  (0, config_js_1.writeProject)(project);
70
70
  (0, config_js_1.trustProject)(project);
71
- console.log(chalk.green(`✓ Set "${(0, terminal_js_1.safeText)(selected.name)}" (${(0, terminal_js_1.safeText)(selected.workspaceName)}) configuré dans .elding.json`));
71
+ console.log(chalk.green(`✓ Set "${(0, terminal_js_1.safeText)(selected.name)}" (${(0, terminal_js_1.safeText)(selected.workspaceName)}) saved in .elding.json`));
72
72
  }
@@ -10,22 +10,22 @@ async function keys() {
10
10
  const { default: ora } = await import("ora");
11
11
  const project = (0, config_js_1.readProject)();
12
12
  if (!project) {
13
- console.error(chalk.red("Projet non initialisé. Lancez `elding init` ou `elding use <set>`."));
13
+ console.error(chalk.red("Project not initialized. Run `elding init` or `elding use <set>`."));
14
14
  process.exit(1);
15
15
  }
16
- const spinner = ora("Récupération des clés...").start();
16
+ const spinner = ora("Fetching keys...").start();
17
17
  const accessToken = await (0, session_js_1.requireAccessToken)();
18
18
  const list = await (0, api_js_1.listKeys)(accessToken, project.setId);
19
19
  spinner.stop();
20
20
  console.log(chalk.dim(`Set : ${(0, terminal_js_1.safeText)(project.setName)}`));
21
21
  if (list.length === 0) {
22
- console.log(chalk.yellow("Aucune clé dans ce set."));
22
+ console.log(chalk.yellow("No keys in this set."));
23
23
  return;
24
24
  }
25
25
  for (const k of list) {
26
26
  const host = k.allowedHost
27
27
  ? chalk.dim(` → ${(0, terminal_js_1.safeText)(k.allowedHost)}`)
28
- : chalk.yellow(" → aucun domaine (non verrouillé)");
28
+ : chalk.yellow(" → no domain (not locked)");
29
29
  console.log(` ${(0, terminal_js_1.safeText)(k.name)}${host}`);
30
30
  }
31
31
  }
@@ -15,11 +15,11 @@ async function login() {
15
15
  const { default: open } = await import("open");
16
16
  const { default: ora } = await import("ora");
17
17
  const state = crypto_1.default.randomBytes(16).toString("hex");
18
- const spinner = ora("En attente d'autorisation dans le navigateur...").start();
18
+ const spinner = ora("Waiting for authorization in the browser...").start();
19
19
  const token = await new Promise((resolve, reject) => {
20
20
  const timeout = setTimeout(() => {
21
21
  server.close();
22
- reject(new Error("Timeout — aucune réponse après 5 minutes"));
22
+ reject(new Error("Timeout — no response after 5 minutes"));
23
23
  }, TIMEOUT_MS);
24
24
  const server = http_1.default.createServer(async (req, res) => {
25
25
  const addr = server.address();
@@ -32,7 +32,7 @@ async function login() {
32
32
  /^[A-Za-z0-9._~-]{16,512}$/.test(receivedCode);
33
33
  if (receivedState !== state || !codeValid) {
34
34
  res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
35
- res.end("<p>Paramètres invalides. Fermez cet onglet.</p>");
35
+ res.end("<p>Invalid parameters. Close this tab.</p>");
36
36
  return;
37
37
  }
38
38
  try {
@@ -42,7 +42,7 @@ async function login() {
42
42
  "Referrer-Policy": "no-referrer",
43
43
  "Cache-Control": "no-store",
44
44
  });
45
- res.end(`<!DOCTYPE html><html lang="fr"><head><meta charset="utf-8"><title>Elding</title><script>history.replaceState(null,"","/")</script><style>
45
+ res.end(`<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Elding</title><script>history.replaceState(null,"","/")</script><style>
46
46
  *{margin:0;padding:0;box-sizing:border-box}
47
47
  html,body{height:100%}
48
48
  body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:#fff;color:#000;display:flex;align-items:center;justify-content:center;text-align:center}
@@ -51,9 +51,9 @@ async function login() {
51
51
  p{font-size:1rem;color:#6b7280}
52
52
  </style></head><body>
53
53
  <div class="wrap">
54
- <h1>Tout est prêt, codez l'esprit tranquille</h1>
55
- <p>Vous êtes connecté à Elding.</p>
56
- <p>Vous pouvez maintenant fermer cette fenêtre.</p>
54
+ <h1>All set, code with peace of mind</h1>
55
+ <p>You are signed in to Elding.</p>
56
+ <p>You can now close this window.</p>
57
57
  </div>
58
58
  </body></html>`);
59
59
  clearTimeout(timeout);
@@ -62,7 +62,7 @@ async function login() {
62
62
  }
63
63
  catch (err) {
64
64
  res.writeHead(502, { "Content-Type": "text/html; charset=utf-8" });
65
- res.end("<p>Impossible de finaliser l'authentification. Fermez cet onglet et relancez le login.</p>");
65
+ res.end("<p>Could not finalize authentication. Close this tab and run login again.</p>");
66
66
  clearTimeout(timeout);
67
67
  server.close();
68
68
  reject(new Error((0, terminal_js_1.safeError)(err)));
@@ -80,12 +80,12 @@ async function login() {
80
80
  `?state=${encodeURIComponent(state)}` +
81
81
  `&callback=${encodeURIComponent(callbackUrl)}`;
82
82
  open(authUrl).catch((err) => {
83
- spinner.warn(`Impossible d'ouvrir le navigateur automatiquement.`);
84
- console.log(chalk.cyan(`Ouvrez manuellement : ${authUrl}`));
83
+ spinner.warn("Could not open the browser automatically.");
84
+ console.log(chalk.cyan(`Open manually: ${authUrl}`));
85
85
  });
86
86
  });
87
87
  });
88
88
  (0, config_js_1.writeConfig)({ refreshToken: token });
89
- spinner.succeed(chalk.green("Connecté avec succès."));
90
- console.log(chalk.dim("Token sauvegardé dans le trousseau de votre OS."));
89
+ spinner.succeed(chalk.green("Signed in successfully."));
90
+ console.log(chalk.dim("Token saved in your OS keychain."));
91
91
  }
@@ -8,12 +8,12 @@ async function logout() {
8
8
  const { default: ora } = await import("ora");
9
9
  const config = (0, config_js_1.readConfig)();
10
10
  if (!config) {
11
- console.log(chalk.dim("Déjà déconnecté."));
11
+ console.log(chalk.dim("Already signed out."));
12
12
  return;
13
13
  }
14
- const spinner = ora("Déconnexion...").start();
14
+ const spinner = ora("Signing out...").start();
15
15
  // Révoque côté serveur (best-effort) puis efface le token local
16
16
  await (0, api_js_1.revokeToken)(config.refreshToken);
17
17
  (0, config_js_1.clearConfig)();
18
- spinner.succeed(chalk.green("Déconnecté. Token révoqué et supprimé localement."));
18
+ spinner.succeed(chalk.green("Signed out. Token revoked and removed locally."));
19
19
  }
@@ -7,7 +7,7 @@ async function open() {
7
7
  const { default: openUrl } = await import("open");
8
8
  const url = `${api_js_1.BASE_URL}/vault`;
9
9
  await openUrl(url).catch(() => {
10
- console.log(chalk.cyan(`Ouvrez manuellement : ${url}`));
10
+ console.log(chalk.cyan(`Open manually: ${url}`));
11
11
  });
12
- console.log(chalk.dim(`Vault ouvert : ${url}`));
12
+ console.log(chalk.dim(`Vault opened: ${url}`));
13
13
  }
@@ -17,19 +17,19 @@ async function proxy(cmd, args, options = {}) {
17
17
  const { default: ora } = await import("ora");
18
18
  const config = (0, config_js_1.readConfig)();
19
19
  if (!config) {
20
- console.error(chalk.red("Non connecté. Lancez `elding login` d'abord."));
20
+ console.error(chalk.red("Not signed in. Run `elding login` first."));
21
21
  process.exit(1);
22
22
  }
23
23
  const project = (0, config_js_1.readProject)();
24
24
  if (!project) {
25
- console.error(chalk.red("Projet non initialisé. Lancez `elding init` d'abord."));
25
+ console.error(chalk.red("Project not initialized. Run `elding init` first."));
26
26
  process.exit(1);
27
27
  }
28
28
  await (0, trust_js_1.ensureProjectTrusted)(project);
29
29
  if (!options.shell && /\s/.test(cmd)) {
30
- throw new Error("Commande invalide sans --shell. Passez le binaire et ses arguments separement, ou ajoutez --shell explicitement.");
30
+ throw new Error("Invalid command without --shell. Pass the binary and its arguments separately, or add --shell explicitly.");
31
31
  }
32
- const spinner = ora("Démarrage du proxy...").start();
32
+ const spinner = ora("Starting proxy...").start();
33
33
  let secrets;
34
34
  let hosts;
35
35
  try {
@@ -44,12 +44,12 @@ async function proxy(cmd, args, options = {}) {
44
44
  ? (0, logBatcher_js_1.createLogBatcher)(config.refreshToken, project.setId, project.setName)
45
45
  : null;
46
46
  const server = await (0, proxyServer_js_1.startProxy)(secrets, hosts, !!options.verbose, batcher ? (e) => batcher.add(e) : undefined);
47
- spinner.succeed(chalk.green(`Proxy actif sur ${server.url} — ${Object.keys(secrets).length} secret(s) pour ${(0, terminal_js_1.safeText)(project.setName)}`));
48
- console.log(chalk.dim("Les clés restent dans le proxy, jamais dans la mémoire de l'app."));
47
+ spinner.succeed(chalk.green(`Proxy active on ${server.url} — ${Object.keys(secrets).length} secret(s) for ${(0, terminal_js_1.safeText)(project.setName)}`));
48
+ console.log(chalk.dim("Keys stay in the proxy, never in the app's memory."));
49
49
  if (!options.reportLogs)
50
- console.log(chalk.dim("Logs cloud proxy désactivés (--no-report-logs)."));
50
+ console.log(chalk.dim("Cloud proxy logs disabled (--no-report-logs)."));
51
51
  else
52
- console.log(chalk.dim("Métadonnées de requêtes envoyées au vault (jamais les valeurs). Couper avec --no-report-logs."));
52
+ console.log(chalk.dim("Request metadata sent to the vault (never the values). Disable with --no-report-logs."));
53
53
  // Résout les binaires locaux (next, vite...) comme le ferait npm, en
54
54
  // cross-platform : path.delimiter = ";" sur Windows, ":" sur POSIX.
55
55
  const localBin = path_1.default.join(process.cwd(), "node_modules", ".bin");
@@ -16,34 +16,34 @@ async function run(cmd, args, options = {}) {
16
16
  const { default: ora } = await import("ora");
17
17
  const config = (0, config_js_1.readConfig)();
18
18
  if (!config) {
19
- console.error(chalk.red("Non connecté. Lancez `elding login` d'abord."));
19
+ console.error(chalk.red("Not signed in. Run `elding login` first."));
20
20
  process.exit(1);
21
21
  }
22
22
  const project = (0, config_js_1.readProject)();
23
23
  if (!project) {
24
- console.error(chalk.red("Projet non initialisé. Lancez `elding init` d'abord."));
24
+ console.error(chalk.red("Project not initialized. Run `elding init` first."));
25
25
  process.exit(1);
26
26
  }
27
27
  await (0, trust_js_1.ensureProjectTrusted)(project);
28
28
  if (!options.shell && /\s/.test(cmd)) {
29
- throw new Error("Commande invalide sans --shell. Passez le binaire et ses arguments separement, ou ajoutez --shell explicitement.");
29
+ throw new Error("Invalid command without --shell. Pass the binary and its arguments separately, or add --shell explicitly.");
30
30
  }
31
- const spinner = ora("Récupération des secrets...").start();
31
+ const spinner = ora("Fetching secrets...").start();
32
32
  let secrets;
33
33
  try {
34
34
  const accessToken = await (0, api_js_1.exchangeToken)(config.refreshToken);
35
35
  ({ secrets } = await (0, api_js_1.fetchSecrets)(accessToken, project.setId, "run"));
36
- spinner.succeed(chalk.green(`${Object.keys(secrets).length} secret(s) chargé(s) pour ${(0, terminal_js_1.safeText)(project.setName)}.`));
36
+ spinner.succeed(chalk.green(`${Object.keys(secrets).length} secret(s) loaded for ${(0, terminal_js_1.safeText)(project.setName)}.`));
37
37
  }
38
38
  catch (err) {
39
39
  spinner.fail(chalk.red((0, terminal_js_1.safeError)(err)));
40
40
  process.exit(1);
41
41
  }
42
- console.error(chalk.yellow("⚠ Mode run : les clés sont injectées en clair dans process.env (lisibles par votre IA et vos dépendances)."));
43
- console.error(chalk.dim(" Pour que les clés n'entrent jamais dans votre app, préférez `elding proxy`."));
42
+ console.error(chalk.yellow("⚠ Run mode: keys are injected in clear text into process.env (readable by your AI and your dependencies)."));
43
+ console.error(chalk.dim(" To keep keys out of your app entirely, prefer `elding proxy`."));
44
44
  const { env: safeSecrets, rejected } = (0, env_js_1.filterSecretsForEnv)(secrets);
45
45
  if (rejected.length > 0) {
46
- throw new Error(`Secrets refuses car leurs noms sont dangereux pour l'environnement: ${rejected.map((name) => (0, terminal_js_1.safeText)(name, 80)).join(", ")}`);
46
+ throw new Error(`Secrets rejected because their names are unsafe for the environment: ${rejected.map((name) => (0, terminal_js_1.safeText)(name, 80)).join(", ")}`);
47
47
  }
48
48
  // Résout les binaires locaux (next, vite...) en cross-platform.
49
49
  const localBin = path_1.default.join(process.cwd(), "node_modules", ".bin");
@@ -60,7 +60,7 @@ async function run(cmd, args, options = {}) {
60
60
  shell: useShell,
61
61
  });
62
62
  if (result.error) {
63
- console.error(chalk.red(`Impossible de lancer la commande : ${result.error.message}`));
63
+ console.error(chalk.red(`Could not run the command: ${result.error.message}`));
64
64
  process.exit(1);
65
65
  }
66
66
  process.exit(result.status ?? 0);
@@ -8,12 +8,12 @@ const terminal_js_1 = require("../lib/terminal.js");
8
8
  async function sets() {
9
9
  const { default: chalk } = await import("chalk");
10
10
  const { default: ora } = await import("ora");
11
- const spinner = ora("Récupération des sets...").start();
11
+ const spinner = ora("Fetching sets...").start();
12
12
  const accessToken = await (0, session_js_1.requireAccessToken)();
13
13
  const list = await (0, api_js_1.listSets)(accessToken);
14
14
  spinner.stop();
15
15
  if (list.length === 0) {
16
- console.log(chalk.yellow("Aucun set. Créez-en un sur le vault."));
16
+ console.log(chalk.yellow("No sets. Create one in the vault."));
17
17
  return;
18
18
  }
19
19
  const activeId = (0, config_js_1.readProject)()?.setId;
@@ -8,7 +8,7 @@ async function status() {
8
8
  const { default: chalk } = await import("chalk");
9
9
  const config = (0, config_js_1.readConfig)();
10
10
  if (!config) {
11
- console.log(chalk.yellow("Non connecté.") + chalk.dim(" Lancez `elding login`."));
11
+ console.log(chalk.yellow("Not signed in.") + chalk.dim(" Run `elding login`."));
12
12
  return;
13
13
  }
14
14
  // Vérifie la validité du token + récupère l'utilisateur
@@ -18,13 +18,13 @@ async function status() {
18
18
  user = await (0, api_js_1.getMe)(accessToken);
19
19
  }
20
20
  catch {
21
- console.log(chalk.red("Token expiré ou révoqué.") + chalk.dim(" Relancez `elding login`."));
21
+ console.log(chalk.red("Token expired or revoked.") + chalk.dim(" Run `elding login` again."));
22
22
  return;
23
23
  }
24
24
  const project = (0, config_js_1.readProject)();
25
25
  const proxyActive = !!process.env.ELDING_PROXY_URL;
26
- console.log(chalk.green("● Connecté"));
27
- console.log(` ${chalk.dim("Utilisateur")} ${(0, terminal_js_1.safeText)(user.email)}${user.name ? chalk.dim(` (${(0, terminal_js_1.safeText)(user.name)})`) : ""}`);
28
- console.log(` ${chalk.dim("Set actif")} ${project ? `${(0, terminal_js_1.safeText)(project.setName)} ${chalk.dim(`(${(0, terminal_js_1.safeText)(project.setId)})`)}` : chalk.yellow("aucun — `elding init`")}`);
29
- console.log(` ${chalk.dim("Proxy")} ${proxyActive ? chalk.green("actif") : chalk.dim("inactif")}`);
26
+ console.log(chalk.green("● Signed in"));
27
+ console.log(` ${chalk.dim("User")} ${(0, terminal_js_1.safeText)(user.email)}${user.name ? chalk.dim(` (${(0, terminal_js_1.safeText)(user.name)})`) : ""}`);
28
+ console.log(` ${chalk.dim("Active set")} ${project ? `${(0, terminal_js_1.safeText)(project.setName)} ${chalk.dim(`(${(0, terminal_js_1.safeText)(project.setId)})`)}` : chalk.yellow("none — `elding init`")}`);
29
+ console.log(` ${chalk.dim("Proxy")} ${proxyActive ? chalk.green("active") : chalk.dim("inactive")}`);
30
30
  }
@@ -8,7 +8,7 @@ const terminal_js_1 = require("../lib/terminal.js");
8
8
  async function use(nameArg) {
9
9
  const { default: chalk } = await import("chalk");
10
10
  const { default: ora } = await import("ora");
11
- const spinner = ora("Récupération des sets...").start();
11
+ const spinner = ora("Fetching sets...").start();
12
12
  const accessToken = await (0, session_js_1.requireAccessToken)();
13
13
  const list = await (0, api_js_1.listSets)(accessToken);
14
14
  spinner.stop();
@@ -16,11 +16,11 @@ async function use(nameArg) {
16
16
  const matches = list.filter((s) => s.name.toLowerCase() === query);
17
17
  const candidates = matches.length ? matches : list.filter((s) => s.name.toLowerCase().includes(query));
18
18
  if (candidates.length === 0) {
19
- console.error(chalk.red(`Aucun set nommé "${(0, terminal_js_1.safeText)(nameArg)}".`) + chalk.dim(" Voir `elding sets`."));
19
+ console.error(chalk.red(`No set named "${(0, terminal_js_1.safeText)(nameArg)}".`) + chalk.dim(" See `elding sets`."));
20
20
  process.exit(1);
21
21
  }
22
22
  if (candidates.length > 1) {
23
- console.error(chalk.red(`Plusieurs sets correspondent à "${(0, terminal_js_1.safeText)(nameArg)}" :`));
23
+ console.error(chalk.red(`Several sets match "${(0, terminal_js_1.safeText)(nameArg)}":`));
24
24
  candidates.forEach((s) => console.error(chalk.dim(` - ${(0, terminal_js_1.safeText)(s.name)}`)));
25
25
  process.exit(1);
26
26
  }
@@ -33,5 +33,5 @@ async function use(nameArg) {
33
33
  };
34
34
  (0, config_js_1.writeProject)(project);
35
35
  (0, config_js_1.trustProject)(project);
36
- console.log(chalk.green(`✓ Set actif : "${(0, terminal_js_1.safeText)(set.name)}"`));
36
+ console.log(chalk.green(`✓ Active set: "${(0, terminal_js_1.safeText)(set.name)}"`));
37
37
  }
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const commander_1 = require("commander");
5
5
  const login_js_1 = require("./commands/login.js");
6
6
  const init_js_1 = require("./commands/init.js");
7
+ const deploy_js_1 = require("./commands/deploy.js");
7
8
  const run_js_1 = require("./commands/run.js");
8
9
  const proxy_js_1 = require("./commands/proxy.js");
9
10
  const logout_js_1 = require("./commands/logout.js");
@@ -17,13 +18,13 @@ const whoami_js_1 = require("./commands/whoami.js");
17
18
  const program = new commander_1.Command();
18
19
  program
19
20
  .name("elding")
20
- .description("Elding CLI — secrets depuis le vault, zéro .env")
21
- .version("0.8.2")
21
+ .description("Elding CLI — secrets from the vault, zero .env")
22
+ .version("0.9.3")
22
23
  // Permet aux sous-commandes de passer les flags de la commande wrappée (next dev --turbopack...).
23
24
  .enablePositionalOptions();
24
25
  program
25
26
  .command("login")
26
- .description("Authentifier le CLI via le navigateur")
27
+ .description("Authenticate the CLI through the browser")
27
28
  .action(async () => {
28
29
  await (0, login_js_1.login)().catch((err) => {
29
30
  console.error(err.message);
@@ -32,17 +33,26 @@ program
32
33
  });
33
34
  program
34
35
  .command("init")
35
- .description("Associer ce projet à un set de secrets")
36
+ .description("Link this project to a secret set")
36
37
  .action(async () => {
37
38
  await (0, init_js_1.init)().catch((err) => {
38
39
  console.error(err.message);
39
40
  process.exit(1);
40
41
  });
41
42
  });
43
+ program
44
+ .command("deploy")
45
+ .description("Generate a deployment key and the env variables for production")
46
+ .action(async () => {
47
+ await (0, deploy_js_1.deploy)().catch((err) => {
48
+ console.error(err.message);
49
+ process.exit(1);
50
+ });
51
+ });
42
52
  program
43
53
  .command("run <cmd> [args...]")
44
- .description("Lancer une commande avec les secrets injectés en variables d'environnement")
45
- .option("--shell", "Executer via le shell systeme (a utiliser seulement si necessaire)")
54
+ .description("Run a command with secrets injected as environment variables")
55
+ .option("--shell", "Run through the system shell (use only if necessary)")
46
56
  .passThroughOptions()
47
57
  .allowUnknownOption()
48
58
  .action(async (cmd, args = [], options) => {
@@ -53,10 +63,10 @@ program
53
63
  });
54
64
  program
55
65
  .command("proxy <cmd> [args...]")
56
- .description("Lancer une commande derrière un proxy local qui injecte les clésjamais en mémoire de l'app")
57
- .option("-v, --verbose", "Logger chaque requête (méthode/host/status/latence)")
58
- .option("--no-report-logs", "Ne pas envoyer les metadonnees de requetes proxy au vault")
59
- .option("--shell", "Executer via le shell systeme (a utiliser seulement si necessaire)")
66
+ .description("Run a command behind a local proxy that injects keysnever in the app's memory")
67
+ .option("-v, --verbose", "Log every request (method/host/status/latency)")
68
+ .option("--no-report-logs", "Do not send proxy request metadata to the vault")
69
+ .option("--shell", "Run through the system shell (use only if necessary)")
60
70
  .passThroughOptions()
61
71
  .allowUnknownOption()
62
72
  .action(async (cmd, args = [], options) => {
@@ -71,7 +81,7 @@ program
71
81
  });
72
82
  program
73
83
  .command("logout")
74
- .description("Révoquer le token et le supprimer localement")
84
+ .description("Revoke the token and remove it locally")
75
85
  .action(async () => {
76
86
  await (0, logout_js_1.logout)().catch((err) => {
77
87
  console.error(err.message);
@@ -80,7 +90,7 @@ program
80
90
  });
81
91
  program
82
92
  .command("status")
83
- .description("Afficher l'état de connexion, le set actif et le proxy")
93
+ .description("Show sign-in status, active set and proxy")
84
94
  .action(async () => {
85
95
  await (0, status_js_1.status)().catch((err) => {
86
96
  console.error(err.message);
@@ -89,7 +99,7 @@ program
89
99
  });
90
100
  program
91
101
  .command("sets")
92
- .description("Lister les sets accessibles")
102
+ .description("List accessible sets")
93
103
  .action(async () => {
94
104
  await (0, sets_js_1.sets)().catch((err) => {
95
105
  console.error(err.message);
@@ -98,7 +108,7 @@ program
98
108
  });
99
109
  program
100
110
  .command("use <name>")
101
- .description("Changer le set actif du projet")
111
+ .description("Switch the project's active set")
102
112
  .action(async (name) => {
103
113
  await (0, use_js_1.use)(name).catch((err) => {
104
114
  console.error(err.message);
@@ -107,7 +117,7 @@ program
107
117
  });
108
118
  program
109
119
  .command("keys")
110
- .description("Lister les noms de clés du set actif (jamais les valeurs)")
120
+ .description("List the key names of the active set (never the values)")
111
121
  .action(async () => {
112
122
  await (0, keys_js_1.keys)().catch((err) => {
113
123
  console.error(err.message);
@@ -116,7 +126,7 @@ program
116
126
  });
117
127
  program
118
128
  .command("doctor")
119
- .description("Diagnostiquer la configuration (connexion, set, clés, proxy)")
129
+ .description("Diagnose the configuration (sign-in, set, keys, proxy)")
120
130
  .action(async () => {
121
131
  await (0, doctor_js_1.doctor)().catch((err) => {
122
132
  console.error(err.message);
@@ -125,7 +135,7 @@ program
125
135
  });
126
136
  program
127
137
  .command("open")
128
- .description("Ouvrir le vault dans le navigateur")
138
+ .description("Open the vault in the browser")
129
139
  .action(async () => {
130
140
  await (0, open_js_1.open)().catch((err) => {
131
141
  console.error(err.message);
@@ -134,7 +144,7 @@ program
134
144
  });
135
145
  program
136
146
  .command("whoami")
137
- .description("Afficher l'utilisateur connecté")
147
+ .description("Show the signed-in user")
138
148
  .action(async () => {
139
149
  await (0, whoami_js_1.whoami)().catch((err) => {
140
150
  console.error(err.message);
package/dist/lib/api.d.ts CHANGED
@@ -12,6 +12,10 @@ export type KeyItem = {
12
12
  };
13
13
  export declare function listKeys(accessToken: string, setId: string): Promise<KeyItem[]>;
14
14
  export declare function exchangeToken(refreshToken: string): Promise<string>;
15
+ export declare function createDeployToken(accessToken: string, label?: string): Promise<{
16
+ refreshToken: string;
17
+ label: string;
18
+ }>;
15
19
  export declare function exchangeLoginCode(code: string, state: string, callbackUrl: string): Promise<string>;
16
20
  export declare function reportProxyLogs(accessToken: string, setId: string, setName: string, entries: unknown[]): Promise<void>;
17
21
  export declare function revokeToken(refreshToken: string): Promise<void>;
package/dist/lib/api.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BASE_URL = void 0;
4
4
  exports.listKeys = listKeys;
5
5
  exports.exchangeToken = exchangeToken;
6
+ exports.createDeployToken = createDeployToken;
6
7
  exports.exchangeLoginCode = exchangeLoginCode;
7
8
  exports.reportProxyLogs = reportProxyLogs;
8
9
  exports.revokeToken = revokeToken;
@@ -24,26 +25,37 @@ async function listKeys(accessToken, setId) {
24
25
  }
25
26
  async function exchangeToken(refreshToken) {
26
27
  if (!REFRESH_TOKEN.test(refreshToken))
27
- throw new Error("Token local invalide. Relancez `elding login`.");
28
+ throw new Error("Invalid local token. Run `elding login` again.");
28
29
  const body = await requestJson("/api/cli/auth/token", {
29
30
  method: "POST",
30
31
  headers: { "Content-Type": "application/json" },
31
32
  body: JSON.stringify({ refreshToken }),
32
33
  });
33
34
  if (!body.success || !body.accessToken)
34
- throw new Error((0, terminal_js_1.safeText)(body.error, 200) || "Impossible d'obtenir un access token");
35
+ throw new Error((0, terminal_js_1.safeText)(body.error, 200) || "Could not get an access token");
35
36
  return body.accessToken;
36
37
  }
38
+ // Crée une clé API de service (déploiement). Apparaît dans l'onglet Clés API.
39
+ async function createDeployToken(accessToken, label) {
40
+ const body = await requestJson("/api/cli/deploy-token", {
41
+ method: "POST",
42
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${accessToken}` },
43
+ body: JSON.stringify({ label }),
44
+ });
45
+ if (!body.success || !body.refreshToken)
46
+ throw new Error((0, terminal_js_1.safeText)(body.error, 200) || "Could not create the deployment key");
47
+ return { refreshToken: body.refreshToken, label: body.label ?? "Deployment" };
48
+ }
37
49
  async function exchangeLoginCode(code, state, callbackUrl) {
38
50
  if (!LOGIN_CODE.test(code))
39
- throw new Error("Code d'autorisation invalide.");
51
+ throw new Error("Invalid authorization code.");
40
52
  const body = await requestJson("/api/cli/auth/exchange", {
41
53
  method: "POST",
42
54
  headers: { "Content-Type": "application/json" },
43
55
  body: JSON.stringify({ code, state, callbackUrl }),
44
56
  });
45
57
  if (!body.success || !body.refreshToken || !REFRESH_TOKEN.test(body.refreshToken)) {
46
- throw new Error((0, terminal_js_1.safeText)(body.error, 200) || "Impossible de finaliser l'authentification.");
58
+ throw new Error((0, terminal_js_1.safeText)(body.error, 200) || "Could not finalize authentication.");
47
59
  }
48
60
  return body.refreshToken;
49
61
  }
@@ -70,7 +82,7 @@ async function getMe(accessToken) {
70
82
  headers: { Authorization: `Bearer ${accessToken}` },
71
83
  });
72
84
  if (!body.success || !body.user)
73
- throw new Error("Réponse invalide");
85
+ throw new Error("Invalid response");
74
86
  return body.user;
75
87
  }
76
88
  async function listSets(accessToken) {
@@ -84,7 +96,7 @@ async function fetchSecrets(accessToken, setId, mode = "proxy") {
84
96
  headers: { Authorization: `Bearer ${accessToken}` },
85
97
  });
86
98
  if (!body.success || !body.secrets || typeof body.secrets !== "object")
87
- throw new Error("Réponse invalide");
99
+ throw new Error("Invalid response");
88
100
  return {
89
101
  secrets: sanitizeSecrets(body.secrets),
90
102
  hosts: body.hosts && typeof body.hosts === "object" ? sanitizeSecrets(body.hosts) : {},
@@ -112,9 +124,9 @@ async function requestJson(path, init) {
112
124
  });
113
125
  const body = (await res.json().catch(() => null));
114
126
  if (!res.ok) {
115
- throw new Error((0, terminal_js_1.safeText)(body?.error, 200) || `Erreur ${res.status}`);
127
+ throw new Error((0, terminal_js_1.safeText)(body?.error, 200) || `Error ${res.status}`);
116
128
  }
117
129
  if (!body || typeof body !== "object")
118
- throw new Error("Réponse invalide");
130
+ throw new Error("Invalid response");
119
131
  return body;
120
132
  }
@@ -28,17 +28,17 @@ function resolveBaseUrl(raw = process.env.ELDING_API_URL) {
28
28
  url = new URL(input);
29
29
  }
30
30
  catch {
31
- throw new Error("ELDING_API_URL invalide.");
31
+ throw new Error("Invalid ELDING_API_URL.");
32
32
  }
33
33
  if (url.username || url.password) {
34
- throw new Error("ELDING_API_URL ne doit pas contenir d'identifiants.");
34
+ throw new Error("ELDING_API_URL must not contain credentials.");
35
35
  }
36
36
  if (url.pathname !== "/" || url.search || url.hash) {
37
- throw new Error("ELDING_API_URL doit etre une origine seule, par exemple https://elding.app.");
37
+ throw new Error("ELDING_API_URL must be an origin only, for example https://elding.app.");
38
38
  }
39
39
  if (url.protocol === "https:")
40
40
  return url.origin;
41
41
  if (url.protocol === "http:" && isLoopbackHost(url.hostname))
42
42
  return url.origin;
43
- throw new Error("ELDING_API_URL doit utiliser HTTPS, sauf pour localhost en developpement.");
43
+ throw new Error("ELDING_API_URL must use HTTPS, except for localhost during development.");
44
44
  }
@@ -62,7 +62,7 @@ function ensureConfigDir() {
62
62
  try {
63
63
  const stat = fs_1.default.lstatSync(CONFIG_DIR);
64
64
  if (stat.isSymbolicLink() || !stat.isDirectory()) {
65
- throw new Error(`${CONFIG_DIR} doit etre un dossier non symbolique.`);
65
+ throw new Error(`${CONFIG_DIR} must be a non-symbolic directory.`);
66
66
  }
67
67
  }
68
68
  catch (err) {
@@ -123,7 +123,7 @@ function isProjectTrusted(project, cwd = process.cwd()) {
123
123
  function trustProject(project, cwd = process.cwd()) {
124
124
  const config = readConfig();
125
125
  if (!config)
126
- throw new Error("Non connecté. Lancez `elding login` d'abord.");
126
+ throw new Error("Not signed in. Run `elding login` first.");
127
127
  writeConfig({
128
128
  ...config,
129
129
  trustedProjects: {
@@ -144,13 +144,13 @@ function startProxy(secrets, hosts = {}, verbose = false, onLog) {
144
144
  for (const m of val.matchAll(PLACEHOLDER)) {
145
145
  const name = m[1];
146
146
  if (!Object.prototype.hasOwnProperty.call(secrets, name))
147
- return `${name} inconnu`;
147
+ return `${name} is unknown`;
148
148
  const allowed = hosts[name];
149
149
  if (!allowed)
150
- return `${name} sans domaine autorise`;
150
+ return `${name} has no allowed domain`;
151
151
  const allowedHost = normalizeAllowedHost(allowed);
152
152
  if (!allowedHost || allowedHost !== targetHost)
153
- return `${name} non autorise`;
153
+ return `${name} is not allowed`;
154
154
  }
155
155
  return null;
156
156
  };
@@ -193,7 +193,7 @@ function startProxy(secrets, hosts = {}, verbose = false, onLog) {
193
193
  const targetHost = normalizeHostname(targetUrl.hostname);
194
194
  const resolved = await resolvePublicAddresses(targetHost);
195
195
  if (resolved.length === 0) {
196
- log(req.method ?? "?", targetHost, req.url ?? "/", "BLOCKED", Date.now() - started, "host bloqué");
196
+ log(req.method ?? "?", targetHost, req.url ?? "/", "BLOCKED", Date.now() - started, "blocked host");
197
197
  res.writeHead(403);
198
198
  res.end("blocked host");
199
199
  return;
@@ -211,7 +211,7 @@ function startProxy(secrets, hosts = {}, verbose = false, onLog) {
211
211
  continue;
212
212
  log(req.method ?? "?", targetHost, upstream.pathname, "BLOCKED", Date.now() - started, bad);
213
213
  res.writeHead(403);
214
- res.end(`secret bloque: ${bad}`);
214
+ res.end(`blocked secret: ${bad}`);
215
215
  return;
216
216
  }
217
217
  }
@@ -7,11 +7,11 @@ const api_js_1 = require("./api.js");
7
7
  async function requireAccessToken() {
8
8
  const config = (0, config_js_1.readConfig)();
9
9
  if (!config)
10
- throw new Error("Non connecté. Lancez `elding login` d'abord.");
10
+ throw new Error("Not signed in. Run `elding login` first.");
11
11
  try {
12
12
  return await (0, api_js_1.exchangeToken)(config.refreshToken);
13
13
  }
14
14
  catch {
15
- throw new Error("Token expiré ou révoqué. Relancez `elding login`.");
15
+ throw new Error("Token expired or revoked. Run `elding login` again.");
16
16
  }
17
17
  }
@@ -11,5 +11,5 @@ function safeText(value, maxLength = 500) {
11
11
  .slice(0, maxLength);
12
12
  }
13
13
  function safeError(value) {
14
- return safeText(value instanceof Error ? value.message : value, 300) || "Erreur inconnue";
14
+ return safeText(value instanceof Error ? value.message : value, 300) || "Unknown error";
15
15
  }
package/dist/lib/trust.js CHANGED
@@ -15,15 +15,15 @@ async function ensureProjectTrusted(project) {
15
15
  const target = `${(0, terminal_js_1.safeText)(project.setName)} (${(0, terminal_js_1.safeText)(project.setId)})`;
16
16
  const workspace = project.workspaceName ? ` / ${(0, terminal_js_1.safeText)(project.workspaceName)}` : "";
17
17
  if (!process_1.stdin.isTTY || !process_1.stdout.isTTY) {
18
- throw new Error(`Projet non approuve pour le set ${target}${workspace}. Lancez \`elding init\` ou \`elding use <set>\` interactivement.`);
18
+ throw new Error(`Project not approved for set ${target}${workspace}. Run \`elding init\` or \`elding use <set>\` interactively.`);
19
19
  }
20
20
  const rl = promises_1.default.createInterface({ input: process_1.stdin, output: process_1.stdout });
21
21
  try {
22
- console.log(`Projet : ${(0, terminal_js_1.safeText)(location)}`);
23
- console.log(`Set Elding : ${target}${workspace}`);
24
- const answer = await rl.question("Approuver ce projet pour ce set ? [y/N] ");
22
+ console.log(`Project: ${(0, terminal_js_1.safeText)(location)}`);
23
+ console.log(`Elding set: ${target}${workspace}`);
24
+ const answer = await rl.question("Approve this project for this set? [y/N] ");
25
25
  if (!/^y(es)?$/i.test(answer.trim())) {
26
- throw new Error("Projet non approuve.");
26
+ throw new Error("Project not approved.");
27
27
  }
28
28
  (0, config_js_1.trustProject)(project);
29
29
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elding/cli",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "Elding CLI — zero .env, secrets from vault",
5
5
  "bin": {
6
6
  "elding": "dist/index.js"