@suronai/cli 0.1.2
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 +47 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +77 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +61 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/rotate.d.ts +2 -0
- package/dist/commands/rotate.js +83 -0
- package/dist/commands/rotate.js.map +1 -0
- package/dist/commands/whoami.d.ts +2 -0
- package/dist/commands/whoami.js +38 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/config.d.ts +4 -0
- package/dist/utils/config.js +42 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/dotenvx.d.ts +14 -0
- package/dist/utils/dotenvx.js +47 -0
- package/dist/utils/dotenvx.js.map +1 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# @suronai/cli
|
|
2
|
+
|
|
3
|
+
CLI for Suron — link your Telegram account and manage secrets.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @suronai/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
Set your Convex deployment URL:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
export SURON_API_URL=https://your-deployment.convex.site
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
|
|
21
|
+
### `suron login`
|
|
22
|
+
Links your Telegram account. Opens a Telegram bot URL, tap Start. Saves `VAULT_API_KEY` to `~/.suron`.
|
|
23
|
+
|
|
24
|
+
### `suron init`
|
|
25
|
+
Run inside your project directory. Encrypts `.env` with dotenvx, registers your app in Convex, stores the private key encrypted under your `MASTER_KEY`, deletes `.env.keys`, writes `.suron.json`.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd my-project
|
|
29
|
+
suron init
|
|
30
|
+
# or with explicit name:
|
|
31
|
+
suron init --name my-project
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `suron whoami`
|
|
35
|
+
Prints your linked Telegram username.
|
|
36
|
+
|
|
37
|
+
### `suron rotate`
|
|
38
|
+
Re-encrypts `.env` with a new private key, updates Convex, deletes `.env.keys`.
|
|
39
|
+
|
|
40
|
+
## Files
|
|
41
|
+
|
|
42
|
+
| File | Commit? | Notes |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `.suron.json` | yes | app name + id |
|
|
45
|
+
| `.env` | yes | encrypted by dotenvx |
|
|
46
|
+
| `~/.suron` | no | your API key |
|
|
47
|
+
| `.env.keys` | no | deleted by suron init |
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initCommand = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const config_1 = require("../utils/config");
|
|
8
|
+
const dotenvx_1 = require("../utils/dotenvx");
|
|
9
|
+
exports.initCommand = new commander_1.Command("init")
|
|
10
|
+
.description("Encrypt .env and register this app with Suron")
|
|
11
|
+
.option("--name <name>", "App name (defaults to current directory name)")
|
|
12
|
+
.action(async (opts) => {
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
const apiKey = (0, config_1.requireApiKey)();
|
|
15
|
+
const apiUrl = (0, config_1.getApiUrl)();
|
|
16
|
+
// 1. Check .env exists
|
|
17
|
+
if (!(0, fs_1.existsSync)((0, path_1.join)(cwd, ".env"))) {
|
|
18
|
+
console.error("error: .env not found in current directory");
|
|
19
|
+
console.error(" Create a .env file first, then run: suron init");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const appName = opts.name ?? require("path").basename(cwd) ?? "my-project";
|
|
23
|
+
console.log(`[suron] Encrypting .env with dotenvx...`);
|
|
24
|
+
// 2. Encrypt .env → produces encrypted .env + .env.keys
|
|
25
|
+
try {
|
|
26
|
+
(0, dotenvx_1.encryptDotenv)(cwd);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
console.error(`error: dotenvx encryption failed: ${err}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
// 3. Read private key from .env.keys
|
|
33
|
+
let privateKey;
|
|
34
|
+
try {
|
|
35
|
+
privateKey = (0, dotenvx_1.readPrivateKey)(cwd);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.error(`error: ${err}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
console.log("[suron] Registering app...");
|
|
42
|
+
// 4. Register app in Convex — backend encrypts privateKey with MASTER_KEY
|
|
43
|
+
let res;
|
|
44
|
+
try {
|
|
45
|
+
res = await fetch(`${apiUrl}/cli/register-app`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
|
+
Authorization: `Bearer ${apiKey}`,
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify({ name: appName, private_key: privateKey }),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.error(`error: could not reach Suron API: ${err}`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
if (!res.ok) {
|
|
59
|
+
const text = await res.text().catch(() => "");
|
|
60
|
+
console.error(`error: register-app failed (${res.status}): ${text}`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
const data = (await res.json());
|
|
64
|
+
// 5. Delete .env.keys — private key now lives encrypted in Convex
|
|
65
|
+
(0, dotenvx_1.deleteKeysFile)(cwd);
|
|
66
|
+
// 6. Write .suron.json
|
|
67
|
+
const suronJson = { app: appName, id: data.app_id };
|
|
68
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(cwd, ".suron.json"), JSON.stringify(suronJson, null, 2) + "\n", "utf-8");
|
|
69
|
+
console.log(`[suron] Done.`);
|
|
70
|
+
console.log(` .env is encrypted — safe to commit`);
|
|
71
|
+
console.log(` .env.keys deleted`);
|
|
72
|
+
console.log(` .suron.json written — safe to commit`);
|
|
73
|
+
console.log(`\n Next: add to your app entry point:`);
|
|
74
|
+
console.log(` import { vault } from '@suronai/sdk'`);
|
|
75
|
+
console.log(` await vault()\n`);
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loginCommand = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const config_1 = require("../utils/config");
|
|
7
|
+
exports.loginCommand = new commander_1.Command("login")
|
|
8
|
+
.description("Link your Telegram account to Suron")
|
|
9
|
+
.action(async () => {
|
|
10
|
+
const apiUrl = (0, config_1.getApiUrl)();
|
|
11
|
+
console.log("[suron] Starting login flow...");
|
|
12
|
+
// Step 1: Request a one-time login token from the backend
|
|
13
|
+
let res;
|
|
14
|
+
try {
|
|
15
|
+
res = await fetch(`${apiUrl}/cli/start-login`, { method: "POST" });
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
console.error(`error: could not reach Suron API at ${apiUrl}`);
|
|
19
|
+
console.error(` Check that SURON_API_URL is correct.`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
const text = await res.text().catch(() => "");
|
|
24
|
+
console.error(`error: /cli/start-login failed (${res.status}): ${text}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const data = (await res.json());
|
|
28
|
+
const telegramUrl = `https://t.me/${data.bot_username}?start=${data.token}`;
|
|
29
|
+
console.log(`\n Open Telegram and tap Start:\n ${telegramUrl}\n`);
|
|
30
|
+
// Try to open browser automatically (best effort, ignore errors)
|
|
31
|
+
const opener = process.platform === "win32" ? "start" :
|
|
32
|
+
process.platform === "darwin" ? "open" : "xdg-open";
|
|
33
|
+
(0, child_process_1.exec)(`${opener} "${telegramUrl}"`);
|
|
34
|
+
// Step 2: Poll until Telegram confirms the link
|
|
35
|
+
console.log("[suron] Waiting for Telegram confirmation...");
|
|
36
|
+
const deadline = Date.now() + 120000; // 2 minute timeout
|
|
37
|
+
while (Date.now() < deadline) {
|
|
38
|
+
await sleep(2000);
|
|
39
|
+
let statusRes;
|
|
40
|
+
try {
|
|
41
|
+
statusRes = await fetch(`${apiUrl}/cli/login-status?token=${encodeURIComponent(data.token)}`);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (!statusRes.ok)
|
|
47
|
+
continue;
|
|
48
|
+
const status = (await statusRes.json());
|
|
49
|
+
if (status.confirmed && status.api_key) {
|
|
50
|
+
(0, config_1.saveApiKey)(status.api_key);
|
|
51
|
+
console.log("[suron] Logged in. Credentials saved to ~/.suron");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
console.error("error: login timed out. Run: suron login");
|
|
56
|
+
process.exit(1);
|
|
57
|
+
});
|
|
58
|
+
function sleep(ms) {
|
|
59
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rotateCommand = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const config_1 = require("../utils/config");
|
|
8
|
+
const dotenvx_1 = require("../utils/dotenvx");
|
|
9
|
+
exports.rotateCommand = new commander_1.Command("rotate")
|
|
10
|
+
.description("Re-encrypt .env with a new private key and update Suron")
|
|
11
|
+
.action(async () => {
|
|
12
|
+
const cwd = process.cwd();
|
|
13
|
+
const apiKey = (0, config_1.requireApiKey)();
|
|
14
|
+
const apiUrl = (0, config_1.getApiUrl)();
|
|
15
|
+
// 1. Read existing .suron.json
|
|
16
|
+
const suronJsonPath = (0, path_1.join)(cwd, ".suron.json");
|
|
17
|
+
if (!(0, fs_1.existsSync)(suronJsonPath)) {
|
|
18
|
+
console.error("error: .suron.json not found. Run: suron init first");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
let suronConfig;
|
|
22
|
+
try {
|
|
23
|
+
suronConfig = JSON.parse((0, fs_1.readFileSync)(suronJsonPath, "utf-8"));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
console.error("error: .suron.json is malformed");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
// 2. Check .env exists
|
|
30
|
+
if (!(0, fs_1.existsSync)((0, path_1.join)(cwd, ".env"))) {
|
|
31
|
+
console.error("error: .env not found");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
console.log("[suron] Re-encrypting .env with a new private key...");
|
|
35
|
+
// 3. Re-encrypt — dotenvx generates a new private key
|
|
36
|
+
try {
|
|
37
|
+
(0, dotenvx_1.encryptDotenv)(cwd);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
console.error(`error: dotenvx encryption failed: ${err}`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
// 4. Read new private key
|
|
44
|
+
let newPrivateKey;
|
|
45
|
+
try {
|
|
46
|
+
newPrivateKey = (0, dotenvx_1.readPrivateKey)(cwd);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error(`error: ${err}`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
console.log("[suron] Updating private key in Suron...");
|
|
53
|
+
// 5. Send new private key to Convex (backend encrypts it with MASTER_KEY)
|
|
54
|
+
let res;
|
|
55
|
+
try {
|
|
56
|
+
res = await fetch(`${apiUrl}/cli/rotate-key`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: {
|
|
59
|
+
"Content-Type": "application/json",
|
|
60
|
+
Authorization: `Bearer ${apiKey}`,
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
app_id: suronConfig.id,
|
|
64
|
+
private_key: newPrivateKey,
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
console.error(`error: could not reach Suron API: ${err}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
if (!res.ok) {
|
|
73
|
+
const text = await res.text().catch(() => "");
|
|
74
|
+
console.error(`error: rotate-key failed (${res.status}): ${text}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
// 6. Delete .env.keys
|
|
78
|
+
(0, dotenvx_1.deleteKeysFile)(cwd);
|
|
79
|
+
console.log("[suron] Key rotated.");
|
|
80
|
+
console.log(" .env re-encrypted — safe to commit");
|
|
81
|
+
console.log(" .env.keys deleted");
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=rotate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotate.js","sourceRoot":"","sources":["../../src/commands/rotate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.whoamiCommand = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const config_1 = require("../utils/config");
|
|
6
|
+
exports.whoamiCommand = new commander_1.Command("whoami")
|
|
7
|
+
.description("Show your linked Telegram account and app info")
|
|
8
|
+
.action(async () => {
|
|
9
|
+
const apiKey = (0, config_1.requireApiKey)();
|
|
10
|
+
const apiUrl = (0, config_1.getApiUrl)();
|
|
11
|
+
let res;
|
|
12
|
+
try {
|
|
13
|
+
res = await fetch(`${apiUrl}/cli/whoami`, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: {
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
Authorization: `Bearer ${apiKey}`,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
console.error(`error: could not reach Suron API: ${err}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
if (res.status === 401) {
|
|
26
|
+
console.error("error: invalid API key. Run: suron login");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
const text = await res.text().catch(() => "");
|
|
31
|
+
console.error(`error: whoami failed (${res.status}): ${text}`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const data = (await res.json());
|
|
35
|
+
console.log(`telegram: @${data.telegram_username}`);
|
|
36
|
+
console.log(`id: ${data.telegram_id}`);
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=whoami.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":";;;AAAA,yCAAoC;AACpC,4CAA2D;AAE9C,QAAA,aAAa,GAAG,IAAI,mBAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,gDAAgD,CAAC;KAC7D,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,MAAM,GAAG,IAAA,sBAAa,GAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAA,kBAAS,GAAE,CAAC;IAE3B,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,aAAa,EAAE;YACxC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,MAAM,EAAE;aAClC;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,qCAAqC,GAAG,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,yBAAyB,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAG7B,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const login_1 = require("./commands/login");
|
|
6
|
+
const init_1 = require("./commands/init");
|
|
7
|
+
const whoami_1 = require("./commands/whoami");
|
|
8
|
+
const rotate_1 = require("./commands/rotate");
|
|
9
|
+
const program = new commander_1.Command();
|
|
10
|
+
program
|
|
11
|
+
.name("suron")
|
|
12
|
+
.description("Secrets delivery with Telegram approval")
|
|
13
|
+
.version("0.1.0");
|
|
14
|
+
program.addCommand(login_1.loginCommand);
|
|
15
|
+
program.addCommand(init_1.initCommand);
|
|
16
|
+
program.addCommand(whoami_1.whoamiCommand);
|
|
17
|
+
program.addCommand(rotate_1.rotateCommand);
|
|
18
|
+
program.parse(process.argv);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,yCAAoC;AACpC,4CAAgD;AAChD,0CAA8C;AAC9C,8CAAkD;AAClD,8CAAkD;AAElD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,yCAAyC,CAAC;KACtD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,oBAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,kBAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAElC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getApiKey = getApiKey;
|
|
4
|
+
exports.saveApiKey = saveApiKey;
|
|
5
|
+
exports.requireApiKey = requireApiKey;
|
|
6
|
+
exports.getApiUrl = getApiUrl;
|
|
7
|
+
const os_1 = require("os");
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const CONFIG_PATH = (0, path_1.join)((0, os_1.homedir)(), ".suron");
|
|
11
|
+
function getApiKey() {
|
|
12
|
+
if (!(0, fs_1.existsSync)(CONFIG_PATH))
|
|
13
|
+
return null;
|
|
14
|
+
try {
|
|
15
|
+
const content = (0, fs_1.readFileSync)(CONFIG_PATH, "utf-8");
|
|
16
|
+
const match = content.match(/VAULT_API_KEY=(.+)/);
|
|
17
|
+
return match?.[1]?.trim() ?? null;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function saveApiKey(key) {
|
|
24
|
+
(0, fs_1.writeFileSync)(CONFIG_PATH, `VAULT_API_KEY=${key}\n`, { mode: 0o600 });
|
|
25
|
+
}
|
|
26
|
+
function requireApiKey() {
|
|
27
|
+
const key = getApiKey();
|
|
28
|
+
if (!key) {
|
|
29
|
+
console.error("error: not logged in. Run: suron login");
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
return key;
|
|
33
|
+
}
|
|
34
|
+
function getApiUrl() {
|
|
35
|
+
const url = process.env.SURON_API_URL?.replace(/\/$/, "");
|
|
36
|
+
if (!url) {
|
|
37
|
+
console.error("error: SURON_API_URL is not set. Export your Convex deployment URL.");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
return url;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":";;AAMA,8BASC;AAED,gCAEC;AAED,sCAOC;AAED,8BASC;AAvCD,2BAA6B;AAC7B,+BAA4B;AAC5B,2BAA6D;AAE7D,MAAM,WAAW,GAAG,IAAA,WAAI,EAAC,IAAA,YAAO,GAAE,EAAE,QAAQ,CAAC,CAAC;AAE9C,SAAgB,SAAS;IACvB,IAAI,CAAC,IAAA,eAAU,EAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAClD,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAgB,UAAU,CAAC,GAAW;IACpC,IAAA,kBAAa,EAAC,WAAW,EAAE,iBAAiB,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,SAAgB,aAAa;IAC3B,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAgB,SAAS;IACvB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,CAAC,KAAK,CACX,qEAAqE,CACtE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs: dotenvx encrypt
|
|
3
|
+
* Requires @dotenvx/dotenvx to be installed globally or in path.
|
|
4
|
+
* After encryption: .env is encrypted, .env.keys holds the private key.
|
|
5
|
+
*/
|
|
6
|
+
export declare function encryptDotenv(cwd: string): void;
|
|
7
|
+
/**
|
|
8
|
+
* Reads DOTENV_PRIVATE_KEY from .env.keys file.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readPrivateKey(cwd: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Deletes .env.keys — called after private key is stored in Convex.
|
|
13
|
+
*/
|
|
14
|
+
export declare function deleteKeysFile(cwd: string): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encryptDotenv = encryptDotenv;
|
|
4
|
+
exports.readPrivateKey = readPrivateKey;
|
|
5
|
+
exports.deleteKeysFile = deleteKeysFile;
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
/**
|
|
10
|
+
* Runs: dotenvx encrypt
|
|
11
|
+
* Requires @dotenvx/dotenvx to be installed globally or in path.
|
|
12
|
+
* After encryption: .env is encrypted, .env.keys holds the private key.
|
|
13
|
+
*/
|
|
14
|
+
function encryptDotenv(cwd) {
|
|
15
|
+
const dotenvPath = (0, path_1.join)(cwd, ".env");
|
|
16
|
+
if (!(0, fs_1.existsSync)(dotenvPath)) {
|
|
17
|
+
throw new Error(`.env not found in ${cwd}`);
|
|
18
|
+
}
|
|
19
|
+
(0, child_process_1.execSync)("npx @dotenvx/dotenvx encrypt", { cwd, stdio: "inherit" });
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Reads DOTENV_PRIVATE_KEY from .env.keys file.
|
|
23
|
+
*/
|
|
24
|
+
function readPrivateKey(cwd) {
|
|
25
|
+
const keysPath = (0, path_1.join)(cwd, ".env.keys");
|
|
26
|
+
if (!(0, fs_1.existsSync)(keysPath)) {
|
|
27
|
+
throw new Error(".env.keys not found after encryption");
|
|
28
|
+
}
|
|
29
|
+
const { readFileSync } = require("fs");
|
|
30
|
+
const content = readFileSync(keysPath, "utf-8");
|
|
31
|
+
const match = content.match(/DOTENV_PRIVATE_KEY(?:_\w+)?="?([^"\n]+)"?/);
|
|
32
|
+
if (!match?.[1]) {
|
|
33
|
+
throw new Error("Could not parse DOTENV_PRIVATE_KEY from .env.keys");
|
|
34
|
+
}
|
|
35
|
+
return match[1].trim();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Deletes .env.keys — called after private key is stored in Convex.
|
|
39
|
+
*/
|
|
40
|
+
function deleteKeysFile(cwd) {
|
|
41
|
+
const keysPath = (0, path_1.join)(cwd, ".env.keys");
|
|
42
|
+
if ((0, fs_1.existsSync)(keysPath)) {
|
|
43
|
+
const { unlinkSync } = require("fs");
|
|
44
|
+
unlinkSync(keysPath);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=dotenvx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dotenvx.js","sourceRoot":"","sources":["../../src/utils/dotenvx.ts"],"names":[],"mappings":";;AASA,sCAMC;AAKD,wCAaC;AAKD,wCAMC;AA5CD,iDAAyC;AACzC,2BAAgC;AAChC,+BAA4B;AAE5B;;;;GAIG;AACH,SAAgB,aAAa,CAAC,GAAW;IACvC,MAAM,UAAU,GAAG,IAAA,WAAI,EAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACrC,IAAI,CAAC,IAAA,eAAU,EAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,IAAA,wBAAQ,EAAC,8BAA8B,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;AACtE,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,GAAW;IACxC,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACxC,IAAI,CAAC,IAAA,eAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAwB,CAAC;IAC9D,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IACzE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,GAAW;IACxC,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACxC,IAAI,IAAA,eAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAwB,CAAC;QAC5D,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@suronai/cli",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "CLI for Suron — suron login, init, whoami, rotate",
|
|
5
|
+
"bin": {
|
|
6
|
+
"suron": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc && node -e \"const fs=require('fs'),f='dist/index.js',c=fs.readFileSync(f,'utf8');if(!c.startsWith('#!/usr/bin/env node'))fs.writeFileSync(f,'#!/usr/bin/env node\\n'+c)\"",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"clean": "rimraf dist"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"commander": "^12.0.0",
|
|
18
|
+
"chalk": "^5.3.0",
|
|
19
|
+
"@dotenvx/dotenvx": "^1.0.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"typescript": "^5.4.0",
|
|
23
|
+
"@types/node": "^20.0.0",
|
|
24
|
+
"rimraf": "^5.0.0"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|