@suronai/sdk 0.1.8 → 0.1.9

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/index.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ export interface VaultOptions {
2
+ /** Directory containing .suron.json. Default: process.cwd() */
3
+ configPath?: string;
4
+ /** Milliseconds to wait for Telegram approval. Default: 300000 (5 min) */
5
+ timeout?: number;
6
+ /** Milliseconds between status polls. Default: 3000 */
7
+ pollInterval?: number;
8
+ }
9
+
10
+ /**
11
+ * Waits for Telegram approval, then decrypts .env into process.env.
12
+ * Must be awaited before any code that reads process.env.
13
+ */
14
+ export function vault(options?: VaultOptions): Promise<void>;
15
+
16
+ export class SuronError extends Error {}
17
+ export class SuronConfigError extends SuronError {}
18
+ export class SuronAppNotFoundError extends SuronError {}
19
+ export class SuronRateLimitError extends SuronError {}
20
+ export class SuronDeniedError extends SuronError {}
21
+ export class SuronTimeoutError extends SuronError {}
package/package.json CHANGED
@@ -1,25 +1,27 @@
1
1
  {
2
2
  "name": "@suronai/sdk",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "App SDK for Suron — await vault() to load secrets",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "types": "./index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./index.d.ts",
11
+ "default": "./src/index.js"
12
+ }
13
+ },
7
14
  "files": [
8
- "dist"
15
+ "src",
16
+ "index.d.ts"
9
17
  ],
10
18
  "scripts": {
11
- "build": "node ../../node_modules/typescript/bin/tsc",
12
- "dev": "node ../../node_modules/typescript/bin/tsc --watch",
13
- "clean": "rimraf dist"
19
+ "build": "node --check src/index.js src/vault.js src/errors.js src/poll.js src/decrypt.js",
20
+ "lint": "node --check src/index.js src/vault.js src/errors.js src/poll.js src/decrypt.js"
14
21
  },
15
22
  "dependencies": {
16
23
  "@dotenvx/dotenvx": "^1.0.0"
17
24
  },
18
- "devDependencies": {
19
- "@types/node": "^20.0.0",
20
- "rimraf": "^5.0.0",
21
- "typescript": "^5.9.3"
22
- },
23
25
  "engines": {
24
26
  "node": ">=18.0.0"
25
27
  }
package/src/decrypt.js ADDED
@@ -0,0 +1,21 @@
1
+ import { config as dotenvxConfig } from "@dotenvx/dotenvx";
2
+
3
+ /**
4
+ * Decrypts the encrypted .env into process.env using dotenvx.
5
+ * dotenvx reads DOTENV_PRIVATE_KEY from process.env, so we set it
6
+ * temporarily, call config(), then restore the previous value.
7
+ * @param {string} privateKey
8
+ */
9
+ export function decryptEnv(privateKey) {
10
+ const prev = process.env.DOTENV_PRIVATE_KEY;
11
+ process.env.DOTENV_PRIVATE_KEY = privateKey;
12
+ try {
13
+ dotenvxConfig();
14
+ } finally {
15
+ if (prev === undefined) {
16
+ delete process.env.DOTENV_PRIVATE_KEY;
17
+ } else {
18
+ process.env.DOTENV_PRIVATE_KEY = prev;
19
+ }
20
+ }
21
+ }
package/src/errors.js ADDED
@@ -0,0 +1,14 @@
1
+ export class SuronError extends Error {
2
+ /** @param {string} message */
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = this.constructor.name;
6
+ Object.setPrototypeOf(this, new.target.prototype);
7
+ }
8
+ }
9
+
10
+ export class SuronConfigError extends SuronError {}
11
+ export class SuronAppNotFoundError extends SuronError {}
12
+ export class SuronRateLimitError extends SuronError {}
13
+ export class SuronDeniedError extends SuronError {}
14
+ export class SuronTimeoutError extends SuronError {}
package/src/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export { vault } from "./vault.js";
2
+ export {
3
+ SuronError,
4
+ SuronConfigError,
5
+ SuronAppNotFoundError,
6
+ SuronRateLimitError,
7
+ SuronDeniedError,
8
+ SuronTimeoutError,
9
+ } from "./errors.js";
package/src/poll.js ADDED
@@ -0,0 +1,52 @@
1
+ import { SuronDeniedError, SuronTimeoutError } from "./errors.js";
2
+
3
+ const DEFAULT_TIMEOUT_MS = 300_000; // 5 minutes
4
+ const DEFAULT_POLL_INTERVAL_MS = 3_000; // 3 seconds
5
+
6
+ /**
7
+ * Polls /status until the request is approved, denied, or times out.
8
+ * @param {string} apiUrl
9
+ * @param {string} requestId
10
+ * @param {number} [timeout]
11
+ * @param {number} [pollInterval]
12
+ * @returns {Promise<void>}
13
+ */
14
+ export async function pollUntilApproved(
15
+ apiUrl,
16
+ requestId,
17
+ timeout = DEFAULT_TIMEOUT_MS,
18
+ pollInterval = DEFAULT_POLL_INTERVAL_MS
19
+ ) {
20
+ const deadline = Date.now() + timeout;
21
+
22
+ while (Date.now() < deadline) {
23
+ await sleep(pollInterval);
24
+
25
+ let res;
26
+ try {
27
+ res = await fetch(`${apiUrl}/status?request_id=${encodeURIComponent(requestId)}`);
28
+ } catch {
29
+ // Network hiccup — keep polling
30
+ continue;
31
+ }
32
+
33
+ if (!res.ok) continue; // Transient error — keep polling
34
+
35
+ const { status } = await res.json();
36
+
37
+ if (status === "approved") return;
38
+ if (status === "denied") {
39
+ throw new SuronDeniedError("Boot denied — you tapped Deny in Telegram.");
40
+ }
41
+ // "pending" → keep polling
42
+ }
43
+
44
+ throw new SuronTimeoutError(
45
+ `No Telegram approval received within ${timeout / 1000}s.`
46
+ );
47
+ }
48
+
49
+ /** @param {number} ms @returns {Promise<void>} */
50
+ function sleep(ms) {
51
+ return new Promise((resolve) => setTimeout(resolve, ms));
52
+ }
package/src/vault.js ADDED
@@ -0,0 +1,122 @@
1
+ import { existsSync, readFileSync } from "fs";
2
+ import { join } from "path";
3
+ import { SuronConfigError, SuronAppNotFoundError, SuronRateLimitError } from "./errors.js";
4
+ import { pollUntilApproved } from "./poll.js";
5
+ import { decryptEnv } from "./decrypt.js";
6
+
7
+ /**
8
+ * @typedef {Object} VaultOptions
9
+ * @property {string} [configPath] - Dir containing .suron.json. Default: process.cwd()
10
+ * @property {number} [timeout] - Ms to wait for Telegram approval. Default: 300000
11
+ * @property {number} [pollInterval] - Ms between status polls. Default: 3000
12
+ */
13
+
14
+ /**
15
+ * Reads and validates .suron.json from the given directory.
16
+ * @param {string} dir
17
+ * @returns {{ app: string, id: string, api_url?: string }}
18
+ */
19
+ function readSuronJson(dir) {
20
+ const path = join(dir, ".suron.json");
21
+ if (!existsSync(path)) {
22
+ throw new SuronConfigError(`.suron.json not found in ${dir}. Run: suron init`);
23
+ }
24
+ let raw;
25
+ try {
26
+ raw = readFileSync(path, "utf-8");
27
+ } catch (err) {
28
+ throw new SuronConfigError(`.suron.json could not be read: ${err}`);
29
+ }
30
+ let parsed;
31
+ try {
32
+ parsed = JSON.parse(raw);
33
+ } catch {
34
+ throw new SuronConfigError(".suron.json is malformed JSON");
35
+ }
36
+ if (!parsed.app || !parsed.id) {
37
+ throw new SuronConfigError(".suron.json is missing 'app' or 'id' field");
38
+ }
39
+ return parsed;
40
+ }
41
+
42
+ /**
43
+ * Sends a boot request and returns the request_id.
44
+ * @param {string} apiUrl
45
+ * @param {string} appId
46
+ * @returns {Promise<string>}
47
+ */
48
+ async function requestAccess(apiUrl, appId) {
49
+ let res;
50
+ try {
51
+ res = await fetch(`${apiUrl}/request-access`, {
52
+ method: "POST",
53
+ headers: { "Content-Type": "application/json" },
54
+ body: JSON.stringify({ app_id: appId }),
55
+ });
56
+ } catch (err) {
57
+ throw new Error(`Could not reach Suron API (${apiUrl}): ${err.message}`);
58
+ }
59
+
60
+ if (res.status === 404) throw new SuronAppNotFoundError("App not found in Suron. Run: suron init");
61
+ if (res.status === 429) throw new SuronRateLimitError("Rate limit exceeded — max 20 boot requests per app per hour.");
62
+ if (!res.ok) {
63
+ const text = await res.text().catch(() => "");
64
+ throw new Error(`Suron /request-access failed (${res.status}): ${text}`);
65
+ }
66
+
67
+ const { request_id } = await res.json();
68
+ return request_id;
69
+ }
70
+
71
+ /**
72
+ * Fetches the private key after approval. Single-use.
73
+ * @param {string} apiUrl
74
+ * @param {string} requestId
75
+ * @returns {Promise<string>}
76
+ */
77
+ async function fetchKey(apiUrl, requestId) {
78
+ const res = await fetch(`${apiUrl}/fetch-key`, {
79
+ method: "POST",
80
+ headers: { "Content-Type": "application/json" },
81
+ body: JSON.stringify({ request_id: requestId }),
82
+ });
83
+ if (!res.ok) {
84
+ const data = await res.json().catch(() => ({}));
85
+ throw new Error(`Suron /fetch-key failed (${res.status}): ${data.error ?? "unknown"}`);
86
+ }
87
+ const { private_key } = await res.json();
88
+ return private_key;
89
+ }
90
+
91
+ /**
92
+ * Waits for Telegram approval, then decrypts .env into process.env.
93
+ * Must be awaited before any code that reads process.env.
94
+ * @param {VaultOptions} [options]
95
+ * @returns {Promise<void>}
96
+ */
97
+ export async function vault(options = {}) {
98
+ const {
99
+ configPath = process.cwd(),
100
+ timeout = 300_000,
101
+ pollInterval = 3_000,
102
+ } = options;
103
+
104
+ const config = readSuronJson(configPath);
105
+
106
+ const rawUrl = process.env.SURON_API_URL ?? config.api_url;
107
+ if (!rawUrl) throw new SuronConfigError("SURON_API_URL not set. Run: suron login");
108
+ const apiUrl = rawUrl.replace(/\/$/, "");
109
+
110
+ const requestId = await requestAccess(apiUrl, config.id);
111
+
112
+ process.stdout.write(`[suron] Waiting for Telegram approval for "${config.app}" ...\n`);
113
+
114
+ await pollUntilApproved(apiUrl, requestId, timeout, pollInterval);
115
+
116
+ const privateKey = await fetchKey(apiUrl, requestId);
117
+ decryptEnv(privateKey);
118
+ // Note: JS strings are immutable — there is no way to scrub the value from
119
+ // heap memory. The reference is dropped here and will be GC'd normally.
120
+
121
+ process.stdout.write(`[suron] Secrets loaded for "${config.app}"\n`);
122
+ }
package/dist/decrypt.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare function decryptEnv(privateKey: string): void;
2
- //# sourceMappingURL=decrypt.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"decrypt.d.ts","sourceRoot":"","sources":["../src/decrypt.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAOnD"}
package/dist/decrypt.js DELETED
@@ -1,10 +0,0 @@
1
- "use strict";
2
- // Wraps dotenvx programmatic API to decrypt .env using the private key
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.decryptEnv = decryptEnv;
5
- function decryptEnv(privateKey) {
6
- // eslint-disable-next-line @typescript-eslint/no-var-requires
7
- const dotenvx = require("@dotenvx/dotenvx");
8
- dotenvx.config({ DOTENV_PRIVATE_KEY: privateKey });
9
- }
10
- //# sourceMappingURL=decrypt.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"decrypt.js","sourceRoot":"","sources":["../src/decrypt.ts"],"names":[],"mappings":";AAAA,uEAAuE;;AAEvE,gCAOC;AAPD,SAAgB,UAAU,CAAC,UAAkB;IAC3C,8DAA8D;IAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAEzC,CAAC;IAEF,OAAO,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,UAAU,EAAE,CAAC,CAAC;AACrD,CAAC"}
package/dist/errors.d.ts DELETED
@@ -1,14 +0,0 @@
1
- export declare class SuronError extends Error {
2
- constructor(message: string);
3
- }
4
- export declare class SuronConfigError extends SuronError {
5
- }
6
- export declare class SuronAppNotFoundError extends SuronError {
7
- }
8
- export declare class SuronRateLimitError extends SuronError {
9
- }
10
- export declare class SuronDeniedError extends SuronError {
11
- }
12
- export declare class SuronTimeoutError extends SuronError {
13
- }
14
- //# sourceMappingURL=errors.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAK5B;AAED,qBAAa,gBAAiB,SAAQ,UAAU;CAAG;AACnD,qBAAa,qBAAsB,SAAQ,UAAU;CAAG;AACxD,qBAAa,mBAAoB,SAAQ,UAAU;CAAG;AACtD,qBAAa,gBAAiB,SAAQ,UAAU;CAAG;AACnD,qBAAa,iBAAkB,SAAQ,UAAU;CAAG"}
package/dist/errors.js DELETED
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SuronTimeoutError = exports.SuronDeniedError = exports.SuronRateLimitError = exports.SuronAppNotFoundError = exports.SuronConfigError = exports.SuronError = void 0;
4
- class SuronError extends Error {
5
- constructor(message) {
6
- super(message);
7
- this.name = this.constructor.name;
8
- Object.setPrototypeOf(this, new.target.prototype);
9
- }
10
- }
11
- exports.SuronError = SuronError;
12
- class SuronConfigError extends SuronError {
13
- }
14
- exports.SuronConfigError = SuronConfigError;
15
- class SuronAppNotFoundError extends SuronError {
16
- }
17
- exports.SuronAppNotFoundError = SuronAppNotFoundError;
18
- class SuronRateLimitError extends SuronError {
19
- }
20
- exports.SuronRateLimitError = SuronRateLimitError;
21
- class SuronDeniedError extends SuronError {
22
- }
23
- exports.SuronDeniedError = SuronDeniedError;
24
- class SuronTimeoutError extends SuronError {
25
- }
26
- exports.SuronTimeoutError = SuronTimeoutError;
27
- //# sourceMappingURL=errors.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAND,gCAMC;AAED,MAAa,gBAAiB,SAAQ,UAAU;CAAG;AAAnD,4CAAmD;AACnD,MAAa,qBAAsB,SAAQ,UAAU;CAAG;AAAxD,sDAAwD;AACxD,MAAa,mBAAoB,SAAQ,UAAU;CAAG;AAAtD,kDAAsD;AACtD,MAAa,gBAAiB,SAAQ,UAAU;CAAG;AAAnD,4CAAmD;AACnD,MAAa,iBAAkB,SAAQ,UAAU;CAAG;AAApD,8CAAoD"}
package/dist/index.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export { vault } from "./vault";
2
- export type { VaultOptions } from "./vault";
3
- export { SuronError, SuronConfigError, SuronAppNotFoundError, SuronRateLimitError, SuronDeniedError, SuronTimeoutError, } from "./errors";
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,UAAU,CAAC"}
package/dist/index.js DELETED
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SuronTimeoutError = exports.SuronDeniedError = exports.SuronRateLimitError = exports.SuronAppNotFoundError = exports.SuronConfigError = exports.SuronError = exports.vault = void 0;
4
- var vault_1 = require("./vault");
5
- Object.defineProperty(exports, "vault", { enumerable: true, get: function () { return vault_1.vault; } });
6
- var errors_1 = require("./errors");
7
- Object.defineProperty(exports, "SuronError", { enumerable: true, get: function () { return errors_1.SuronError; } });
8
- Object.defineProperty(exports, "SuronConfigError", { enumerable: true, get: function () { return errors_1.SuronConfigError; } });
9
- Object.defineProperty(exports, "SuronAppNotFoundError", { enumerable: true, get: function () { return errors_1.SuronAppNotFoundError; } });
10
- Object.defineProperty(exports, "SuronRateLimitError", { enumerable: true, get: function () { return errors_1.SuronRateLimitError; } });
11
- Object.defineProperty(exports, "SuronDeniedError", { enumerable: true, get: function () { return errors_1.SuronDeniedError; } });
12
- Object.defineProperty(exports, "SuronTimeoutError", { enumerable: true, get: function () { return errors_1.SuronTimeoutError; } });
13
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,iCAAgC;AAAvB,8FAAA,KAAK,OAAA;AAEd,mCAOkB;AANhB,oGAAA,UAAU,OAAA;AACV,0GAAA,gBAAgB,OAAA;AAChB,+GAAA,qBAAqB,OAAA;AACrB,6GAAA,mBAAmB,OAAA;AACnB,0GAAA,gBAAgB,OAAA;AAChB,2GAAA,iBAAiB,OAAA"}
package/dist/poll.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare function pollUntilApproved(apiUrl: string, request_id: string, timeout?: number, pollInterval?: number): Promise<void>;
2
- //# sourceMappingURL=poll.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"poll.d.ts","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":"AAKA,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,SAAqB,EAC5B,YAAY,SAA2B,GACtC,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
package/dist/poll.js DELETED
@@ -1,29 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.pollUntilApproved = pollUntilApproved;
4
- const errors_1 = require("./errors");
5
- const DEFAULT_TIMEOUT_MS = 300000; // 5 minutes
6
- const DEFAULT_POLL_INTERVAL_MS = 3000; // 3 seconds
7
- async function pollUntilApproved(apiUrl, request_id, timeout = DEFAULT_TIMEOUT_MS, pollInterval = DEFAULT_POLL_INTERVAL_MS) {
8
- const deadline = Date.now() + timeout;
9
- while (Date.now() < deadline) {
10
- await sleep(pollInterval);
11
- const res = await fetch(`${apiUrl}/status?request_id=${encodeURIComponent(request_id)}`);
12
- if (!res.ok) {
13
- // Transient error — keep polling
14
- continue;
15
- }
16
- const data = (await res.json());
17
- if (data.status === "approved")
18
- return;
19
- if (data.status === "denied") {
20
- throw new errors_1.SuronDeniedError("Boot denied. You tapped Deny in Telegram.");
21
- }
22
- // status === "pending" — keep polling
23
- }
24
- throw new errors_1.SuronTimeoutError(`No Telegram approval received within ${timeout / 1000}s timeout.`);
25
- }
26
- function sleep(ms) {
27
- return new Promise((resolve) => setTimeout(resolve, ms));
28
- }
29
- //# sourceMappingURL=poll.js.map
package/dist/poll.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"poll.js","sourceRoot":"","sources":["../src/poll.ts"],"names":[],"mappings":";;AAKA,8CAgCC;AArCD,qCAA+D;AAE/D,MAAM,kBAAkB,GAAG,MAAO,CAAC,CAAC,YAAY;AAChD,MAAM,wBAAwB,GAAG,IAAK,CAAC,CAAC,YAAY;AAE7C,KAAK,UAAU,iBAAiB,CACrC,MAAc,EACd,UAAkB,EAClB,OAAO,GAAG,kBAAkB,EAC5B,YAAY,GAAG,wBAAwB;IAEvC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;IAEtC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;QAE1B,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,MAAM,sBAAsB,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAChE,CAAC;QAEF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,iCAAiC;YACjC,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAuB,CAAC;QAEtD,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU;YAAE,OAAO;QACvC,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC7B,MAAM,IAAI,yBAAgB,CAAC,2CAA2C,CAAC,CAAC;QAC1E,CAAC;QACD,sCAAsC;IACxC,CAAC;IAED,MAAM,IAAI,0BAAiB,CACzB,wCAAwC,OAAO,GAAG,IAAI,YAAY,CACnE,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
package/dist/vault.d.ts DELETED
@@ -1,7 +0,0 @@
1
- export interface VaultOptions {
2
- configPath?: string;
3
- timeout?: number;
4
- pollInterval?: number;
5
- }
6
- export declare function vault(options?: VaultOptions): Promise<void>;
7
- //# sourceMappingURL=vault.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA0ED,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCrE"}
package/dist/vault.js DELETED
@@ -1,82 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.vault = vault;
4
- const fs_1 = require("fs");
5
- const path_1 = require("path");
6
- const errors_1 = require("./errors");
7
- const poll_1 = require("./poll");
8
- const decrypt_1 = require("./decrypt");
9
- function readSuronJson(dir) {
10
- const path = (0, path_1.join)(dir, ".suron.json");
11
- if (!(0, fs_1.existsSync)(path)) {
12
- throw new errors_1.SuronConfigError(`.suron.json not found in ${dir}. Run: suron init`);
13
- }
14
- let raw;
15
- try {
16
- raw = (0, fs_1.readFileSync)(path, "utf-8");
17
- }
18
- catch (err) {
19
- throw new errors_1.SuronConfigError(`.suron.json could not be read: ${err}`);
20
- }
21
- try {
22
- const parsed = JSON.parse(raw);
23
- if (!parsed.app || !parsed.id) {
24
- throw new errors_1.SuronConfigError(".suron.json is missing 'app' or 'id' field");
25
- }
26
- return parsed;
27
- }
28
- catch (err) {
29
- if (err instanceof errors_1.SuronConfigError)
30
- throw err;
31
- throw new errors_1.SuronConfigError(".suron.json is malformed JSON");
32
- }
33
- }
34
- async function requestAccess(apiUrl, app_id) {
35
- const res = await fetch(`${apiUrl}/request-access`, {
36
- method: "POST",
37
- headers: { "Content-Type": "application/json" },
38
- body: JSON.stringify({ app_id }),
39
- });
40
- if (res.status === 404) {
41
- throw new errors_1.SuronAppNotFoundError("App not found in Suron. Run: suron init");
42
- }
43
- if (res.status === 429) {
44
- throw new errors_1.SuronRateLimitError("Rate limit exceeded. Max 20 boot requests per app per hour.");
45
- }
46
- if (!res.ok) {
47
- const text = await res.text().catch(() => "");
48
- throw new Error(`Suron /request-access failed (${res.status}): ${text}`);
49
- }
50
- const data = (await res.json());
51
- return data.request_id;
52
- }
53
- async function fetchKey(apiUrl, request_id) {
54
- const res = await fetch(`${apiUrl}/fetch-key`, {
55
- method: "POST",
56
- headers: { "Content-Type": "application/json" },
57
- body: JSON.stringify({ request_id }),
58
- });
59
- if (!res.ok) {
60
- const data = (await res.json().catch(() => ({})));
61
- throw new Error(`Suron /fetch-key failed (${res.status}): ${data.error ?? "unknown"}`);
62
- }
63
- const data = (await res.json());
64
- return data.private_key;
65
- }
66
- async function vault(options = {}) {
67
- const { configPath = process.cwd(), timeout = 300000, pollInterval = 3000, } = options;
68
- const config = readSuronJson(configPath);
69
- const apiUrl = (process.env.SURON_API_URL ?? config.api_url)?.replace(/\/$/, "") ??
70
- (() => {
71
- throw new errors_1.SuronConfigError("SURON_API_URL not set and not found in .suron.json. Run: suron init");
72
- })();
73
- const request_id = await requestAccess(apiUrl, config.id);
74
- process.stdout.write(`[suron] Waiting for Telegram approval for "${config.app}" ...\n`);
75
- await (0, poll_1.pollUntilApproved)(apiUrl, request_id, timeout, pollInterval);
76
- const private_key = await fetchKey(apiUrl, request_id);
77
- (0, decrypt_1.decryptEnv)(private_key);
78
- // Overwrite reference so GC can reclaim it
79
- private_key = "";
80
- process.stdout.write(`[suron] Secrets loaded for "${config.app}"\n`);
81
- }
82
- //# sourceMappingURL=vault.js.map
package/dist/vault.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"vault.js","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"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"}