vana-cli 0.25.0 → 0.26.0
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 +1 -0
- package/dist/cli/auth.d.ts +2 -0
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +2 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +37 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/server-start.d.ts +42 -0
- package/dist/cli/server-start.d.ts.map +1 -0
- package/dist/cli/server-start.js +189 -0
- package/dist/cli/server-start.js.map +1 -0
- package/dist/personal-server/index.d.ts +1 -0
- package/dist/personal-server/index.d.ts.map +1 -1
- package/dist/personal-server/index.js +17 -2
- package/dist/personal-server/index.js.map +1 -1
- package/dist/personal-server/local/config.d.ts +23 -0
- package/dist/personal-server/local/config.d.ts.map +1 -0
- package/dist/personal-server/local/config.js +51 -0
- package/dist/personal-server/local/config.js.map +1 -0
- package/dist/personal-server/local/owner-binding.d.ts +33 -0
- package/dist/personal-server/local/owner-binding.d.ts.map +1 -0
- package/dist/personal-server/local/owner-binding.js +155 -0
- package/dist/personal-server/local/owner-binding.js.map +1 -0
- package/dist/personal-server/local/owner-secret.d.ts +17 -0
- package/dist/personal-server/local/owner-secret.d.ts.map +1 -0
- package/dist/personal-server/local/owner-secret.js +119 -0
- package/dist/personal-server/local/owner-secret.js.map +1 -0
- package/dist/personal-server/local/runtime-pkg/entry.mjs +153 -0
- package/dist/personal-server/local/runtime-pkg/package-lock.json +2342 -0
- package/dist/personal-server/local/runtime-pkg/package.json +13 -0
- package/dist/personal-server/local/runtime.d.ts +9 -0
- package/dist/personal-server/local/runtime.d.ts.map +1 -0
- package/dist/personal-server/local/runtime.js +66 -0
- package/dist/personal-server/local/runtime.js.map +1 -0
- package/dist/personal-server/local/server.d.ts +39 -0
- package/dist/personal-server/local/server.d.ts.map +1 -0
- package/dist/personal-server/local/server.js +203 -0
- package/dist/personal-server/local/server.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vana-cli-personal-server-runtime",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "The Personal Server vana-cli runs on its own. Installed with npm ci from this lockfile so every install is the same.",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@opendatalabs/personal-server-ts": "1.24.6"
|
|
8
|
+
},
|
|
9
|
+
"allowScripts": {
|
|
10
|
+
"better-sqlite3@12.11.1": true,
|
|
11
|
+
"secp256k1@5.0.2": true
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ResolvedNode } from "../../pdpp/host.js";
|
|
2
|
+
export declare function isRuntimeInstalled(dir?: string): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Install the pinned Personal Server into its versioned dir with `npm ci`, so
|
|
5
|
+
* every install resolves to the same dependency tree, then prove the native
|
|
6
|
+
* module loads under the Node that will run it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function ensureRuntime(node: ResolvedNode, logPath: string, dir?: string): Promise<string>;
|
|
9
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/personal-server/local/runtime.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA4BvD,wBAAgB,kBAAkB,CAAC,GAAG,SAA0B,GAAG,OAAO,CAYzE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,MAAM,EACf,GAAG,SAA0B,GAC5B,OAAO,CAAC,MAAM,CAAC,CAyCjB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import fsp from "node:fs/promises";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
import { localServerRuntimeDir } from "./config.js";
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
10
|
+
/** Files shipped with the CLI that define the runtime: the pin, its lock, the entry. */
|
|
11
|
+
const ASSET_FILES = ["package.json", "package-lock.json", "entry.mjs"];
|
|
12
|
+
function assetDir() {
|
|
13
|
+
return fileURLToPath(new URL("./runtime-pkg/", import.meta.url));
|
|
14
|
+
}
|
|
15
|
+
function lockHash(dir) {
|
|
16
|
+
return crypto
|
|
17
|
+
.createHash("sha256")
|
|
18
|
+
.update(fs.readFileSync(path.join(dir, "package-lock.json")))
|
|
19
|
+
.digest("hex");
|
|
20
|
+
}
|
|
21
|
+
function npmFor(node) {
|
|
22
|
+
// A Node release keeps npm beside the binary; using that npm means the
|
|
23
|
+
// native modules are built for the Node that will load them.
|
|
24
|
+
return path.join(path.dirname(node.path), process.platform === "win32" ? "npm.cmd" : "npm");
|
|
25
|
+
}
|
|
26
|
+
export function isRuntimeInstalled(dir = localServerRuntimeDir()) {
|
|
27
|
+
try {
|
|
28
|
+
return (fs.readFileSync(path.join(dir, ".installed"), "utf8").trim() ===
|
|
29
|
+
lockHash(assetDir()) &&
|
|
30
|
+
fs.existsSync(path.join(dir, "node_modules", "@opendatalabs", "personal-server-ts")));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Install the pinned Personal Server into its versioned dir with `npm ci`, so
|
|
38
|
+
* every install resolves to the same dependency tree, then prove the native
|
|
39
|
+
* module loads under the Node that will run it.
|
|
40
|
+
*/
|
|
41
|
+
export async function ensureRuntime(node, logPath, dir = localServerRuntimeDir()) {
|
|
42
|
+
await fsp.mkdir(dir, { recursive: true });
|
|
43
|
+
// The entry script changes with the CLI, not with the pin: refresh it always.
|
|
44
|
+
await fsp.copyFile(path.join(assetDir(), "entry.mjs"), path.join(dir, "entry.mjs"));
|
|
45
|
+
if (isRuntimeInstalled(dir)) {
|
|
46
|
+
return dir;
|
|
47
|
+
}
|
|
48
|
+
for (const file of ASSET_FILES) {
|
|
49
|
+
await fsp.copyFile(path.join(assetDir(), file), path.join(dir, file));
|
|
50
|
+
}
|
|
51
|
+
await fsp.rm(path.join(dir, "node_modules"), {
|
|
52
|
+
recursive: true,
|
|
53
|
+
force: true,
|
|
54
|
+
});
|
|
55
|
+
await fsp.appendFile(logPath, `npm ci in ${dir}\n`, "utf8");
|
|
56
|
+
const env = {
|
|
57
|
+
...process.env,
|
|
58
|
+
PATH: `${path.dirname(node.path)}${path.delimiter}${process.env.PATH ?? ""}`,
|
|
59
|
+
};
|
|
60
|
+
const { stdout, stderr } = await execFileAsync(npmFor(node), ["ci", "--omit=dev", "--no-audit", "--no-fund"], { cwd: dir, env, maxBuffer: 32 * 1024 * 1024, windowsHide: true });
|
|
61
|
+
await fsp.appendFile(logPath, `${stdout}${stderr}`, "utf8");
|
|
62
|
+
await execFileAsync(node.path, ["-e", "new (require('better-sqlite3'))(':memory:').close()"], { cwd: dir, env, windowsHide: true });
|
|
63
|
+
await fsp.writeFile(path.join(dir, ".installed"), `${lockHash(assetDir())}\n`, "utf8");
|
|
64
|
+
return dir;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/personal-server/local/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,GAAG,MAAM,kBAAkB,CAAC;AACnC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,wFAAwF;AACxF,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,mBAAmB,EAAE,WAAW,CAAU,CAAC;AAEhF,SAAS,QAAQ;IACf,OAAO,aAAa,CAAC,IAAI,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO,MAAM;SACV,UAAU,CAAC,QAAQ,CAAC;SACpB,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC,CAAC;SAC5D,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC;AAED,SAAS,MAAM,CAAC,IAAkB;IAChC,uEAAuE;IACvE,6DAA6D;IAC7D,OAAO,IAAI,CAAC,IAAI,CACd,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EACvB,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CACjD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAG,GAAG,qBAAqB,EAAE;IAC9D,IAAI,CAAC;QACH,OAAO,CACL,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE;YAC1D,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACtB,EAAE,CAAC,UAAU,CACX,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,eAAe,EAAE,oBAAoB,CAAC,CACtE,CACF,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAkB,EAClB,OAAe,EACf,GAAG,GAAG,qBAAqB,EAAE;IAE7B,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,8EAA8E;IAC9E,MAAM,GAAG,CAAC,QAAQ,CAChB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,WAAW,CAAC,EAClC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAC5B,CAAC;IACF,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE;QAC3C,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IACH,MAAM,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5D,MAAM,GAAG,GAAG;QACV,GAAG,OAAO,CAAC,GAAG;QACd,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE;KAC7E,CAAC;IACF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAC5C,MAAM,CAAC,IAAI,CAAC,EACZ,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,CAAC,EAC/C,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAClE,CAAC;IACF,MAAM,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;IAE5D,MAAM,aAAa,CACjB,IAAI,CAAC,IAAI,EACT,CAAC,IAAI,EAAE,qDAAqD,CAAC,EAC7D,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,CACrC,CAAC;IACF,MAAM,GAAG,CAAC,SAAS,CACjB,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAC5B,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAC3B,MAAM,CACP,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { VanaNetworkName } from "../../core/network.js";
|
|
2
|
+
import type { ResolvedNode } from "../../pdpp/host.js";
|
|
3
|
+
import type { OwnerBinding } from "./owner-binding.js";
|
|
4
|
+
/** A server already answering on a local port, and who owns it. */
|
|
5
|
+
export interface RunningServer {
|
|
6
|
+
url: string;
|
|
7
|
+
owner: string | null;
|
|
8
|
+
}
|
|
9
|
+
/** Every server answering on the ports Desktop and the CLI use. */
|
|
10
|
+
export declare function findRunningServers(fetchImpl?: typeof fetch): Promise<RunningServer[]>;
|
|
11
|
+
/** A port whose neighbour is free too: the server's approval page takes port + 1. */
|
|
12
|
+
export declare function choosePort(requested?: number): Promise<number | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Claim a data dir for this process. A lock whose pid is gone is stale and is
|
|
15
|
+
* taken over; a live one means a server is already running from that dir.
|
|
16
|
+
*/
|
|
17
|
+
export declare function acquireDataDirLock(dir: string): Promise<() => Promise<void>>;
|
|
18
|
+
export interface LocalServerHandle {
|
|
19
|
+
url: string;
|
|
20
|
+
port: number;
|
|
21
|
+
accessToken: string;
|
|
22
|
+
/** Resolves when the server process exits, for whatever reason. */
|
|
23
|
+
exited: Promise<number | null>;
|
|
24
|
+
stop(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Start the pinned Personal Server as a foreground child process on the
|
|
28
|
+
* managed Node, local only, and wait until it answers.
|
|
29
|
+
*/
|
|
30
|
+
export declare function startLocalServer(input: {
|
|
31
|
+
network: VanaNetworkName;
|
|
32
|
+
node: ResolvedNode;
|
|
33
|
+
runtimeDir: string;
|
|
34
|
+
binding: OwnerBinding;
|
|
35
|
+
port: number;
|
|
36
|
+
logPath: string;
|
|
37
|
+
readyTimeoutMs?: number;
|
|
38
|
+
}): Promise<LocalServerHandle>;
|
|
39
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/personal-server/local/server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,mEAAmE;AACnE,wBAAsB,kBAAkB,CACtC,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,aAAa,EAAE,CAAC,CA+B1B;AAWD,qFAAqF;AACrF,wBAAsB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQ3E;AAWD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CA8B9B;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC5C,OAAO,EAAE,eAAe,CAAC;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAwH7B"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import fsp from "node:fs/promises";
|
|
5
|
+
import net from "node:net";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { LOCAL_SERVER_PORTS, localServerDataDir, localServerNetwork, } from "./config.js";
|
|
8
|
+
/** Every server answering on the ports Desktop and the CLI use. */
|
|
9
|
+
export async function findRunningServers(fetchImpl = fetch) {
|
|
10
|
+
const found = [];
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
for (let port = 8080; port <= 8085; port += 1) {
|
|
13
|
+
const url = `http://localhost:${port}`;
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetchImpl(`${url}/health`, {
|
|
16
|
+
signal: AbortSignal.timeout(1_500),
|
|
17
|
+
});
|
|
18
|
+
if (!response.ok)
|
|
19
|
+
continue;
|
|
20
|
+
const body = (await response.json());
|
|
21
|
+
// A server also answers on its approval port (port + 1); its own key
|
|
22
|
+
// says it is the same server.
|
|
23
|
+
const identity = typeof body.identity?.address === "string"
|
|
24
|
+
? body.identity.address
|
|
25
|
+
: null;
|
|
26
|
+
if (identity && seen.has(identity.toLowerCase()))
|
|
27
|
+
continue;
|
|
28
|
+
if (identity)
|
|
29
|
+
seen.add(identity.toLowerCase());
|
|
30
|
+
found.push({
|
|
31
|
+
url,
|
|
32
|
+
owner: typeof body.owner === "string" ? body.owner : null,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Nothing there.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return found;
|
|
40
|
+
}
|
|
41
|
+
function portIsFree(port) {
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const probe = net.createServer();
|
|
44
|
+
probe.once("error", () => resolve(false));
|
|
45
|
+
probe.once("listening", () => probe.close(() => resolve(true)));
|
|
46
|
+
probe.listen(port, "127.0.0.1");
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/** A port whose neighbour is free too: the server's approval page takes port + 1. */
|
|
50
|
+
export async function choosePort(requested) {
|
|
51
|
+
const candidates = requested ? [requested] : [...LOCAL_SERVER_PORTS];
|
|
52
|
+
for (const port of candidates) {
|
|
53
|
+
if ((await portIsFree(port)) && (await portIsFree(port + 1))) {
|
|
54
|
+
return port;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function processIsRunning(pid) {
|
|
60
|
+
try {
|
|
61
|
+
process.kill(pid, 0);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return error.code === "EPERM";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Claim a data dir for this process. A lock whose pid is gone is stale and is
|
|
70
|
+
* taken over; a live one means a server is already running from that dir.
|
|
71
|
+
*/
|
|
72
|
+
export async function acquireDataDirLock(dir) {
|
|
73
|
+
await fsp.mkdir(dir, { recursive: true, mode: 0o700 });
|
|
74
|
+
const lockPath = path.join(dir, ".vana-cli.lock");
|
|
75
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
76
|
+
try {
|
|
77
|
+
const handle = await fsp.open(lockPath, "wx", 0o600);
|
|
78
|
+
await handle.writeFile(`${JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() })}\n`);
|
|
79
|
+
await handle.close();
|
|
80
|
+
return async () => {
|
|
81
|
+
await fsp.rm(lockPath, { force: true });
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (error.code !== "EEXIST")
|
|
86
|
+
throw error;
|
|
87
|
+
let pid = 0;
|
|
88
|
+
try {
|
|
89
|
+
pid = Number(JSON.parse(fs.readFileSync(lockPath, "utf8")).pid);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
pid = 0;
|
|
93
|
+
}
|
|
94
|
+
if (pid > 0 && processIsRunning(pid)) {
|
|
95
|
+
throw new Error(`A Personal Server started by vana is already running from ${dir} (pid ${pid}).`);
|
|
96
|
+
}
|
|
97
|
+
await fsp.rm(lockPath, { force: true });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Could not lock ${dir}.`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Start the pinned Personal Server as a foreground child process on the
|
|
104
|
+
* managed Node, local only, and wait until it answers.
|
|
105
|
+
*/
|
|
106
|
+
export async function startLocalServer(input) {
|
|
107
|
+
const dataDir = localServerDataDir(input.network);
|
|
108
|
+
const release = await acquireDataDirLock(dataDir);
|
|
109
|
+
const accessToken = crypto.randomBytes(32).toString("hex");
|
|
110
|
+
const log = fs.createWriteStream(input.logPath, { flags: "a" });
|
|
111
|
+
// Only what the server needs: no PDPP_*, no tokens from the caller's shell.
|
|
112
|
+
const env = {
|
|
113
|
+
HOME: process.env.HOME,
|
|
114
|
+
PATH: `${path.dirname(input.node.path)}${path.delimiter}${process.env.PATH ?? ""}`,
|
|
115
|
+
NODE_ENV: "production",
|
|
116
|
+
PS_ACCESS_TOKEN: accessToken,
|
|
117
|
+
TUNNEL_ENABLED: "false",
|
|
118
|
+
...(process.env.TMPDIR ? { TMPDIR: process.env.TMPDIR } : {}),
|
|
119
|
+
};
|
|
120
|
+
const child = spawn(input.node.path, ["entry.mjs"], {
|
|
121
|
+
cwd: input.runtimeDir,
|
|
122
|
+
env,
|
|
123
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
124
|
+
windowsHide: true,
|
|
125
|
+
});
|
|
126
|
+
child.stderr?.on("data", (chunk) => log.write(chunk));
|
|
127
|
+
const exited = new Promise((resolve) => {
|
|
128
|
+
child.once("exit", (code) => {
|
|
129
|
+
void release();
|
|
130
|
+
log.end();
|
|
131
|
+
resolve(code);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
const ready = new Promise((resolve, reject) => {
|
|
135
|
+
let buffer = "";
|
|
136
|
+
child.stdout?.setEncoding("utf8");
|
|
137
|
+
child.stdout?.on("data", (chunk) => {
|
|
138
|
+
buffer += chunk;
|
|
139
|
+
let newline = buffer.indexOf("\n");
|
|
140
|
+
while (newline >= 0) {
|
|
141
|
+
const line = buffer.slice(0, newline).trim();
|
|
142
|
+
buffer = buffer.slice(newline + 1);
|
|
143
|
+
newline = buffer.indexOf("\n");
|
|
144
|
+
if (!line)
|
|
145
|
+
continue;
|
|
146
|
+
try {
|
|
147
|
+
const message = JSON.parse(line);
|
|
148
|
+
log.write(`[entry] ${line}\n`);
|
|
149
|
+
if (message.type === "ready")
|
|
150
|
+
resolve(message.url ?? `http://localhost:${input.port}`);
|
|
151
|
+
if (message.type === "error")
|
|
152
|
+
reject(new Error(message.message ?? "The Personal Server failed to start."));
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
log.write(`[entry] ${line}\n`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
child.once("error", (error) => reject(error));
|
|
160
|
+
void exited.then((code) => reject(new Error(`The Personal Server exited (code ${code}) before it was ready. See ${input.logPath}.`)));
|
|
161
|
+
});
|
|
162
|
+
const network = localServerNetwork(input.network);
|
|
163
|
+
child.stdin?.write(`${JSON.stringify({
|
|
164
|
+
rootPath: dataDir,
|
|
165
|
+
port: input.port,
|
|
166
|
+
ownerSignature: input.binding.signature,
|
|
167
|
+
ownerAddress: input.binding.signerAddress,
|
|
168
|
+
network: {
|
|
169
|
+
gatewayUrl: network.gatewayUrl,
|
|
170
|
+
chainId: network.chainId,
|
|
171
|
+
contracts: network.contracts,
|
|
172
|
+
storageApiUrl: network.storageApiUrl,
|
|
173
|
+
},
|
|
174
|
+
})}\n`);
|
|
175
|
+
child.stdin?.end();
|
|
176
|
+
const stop = async () => {
|
|
177
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
178
|
+
return;
|
|
179
|
+
child.kill("SIGINT");
|
|
180
|
+
const killer = setTimeout(() => child.kill("SIGKILL"), 10_000);
|
|
181
|
+
await exited;
|
|
182
|
+
clearTimeout(killer);
|
|
183
|
+
};
|
|
184
|
+
let timer = null;
|
|
185
|
+
try {
|
|
186
|
+
const url = await Promise.race([
|
|
187
|
+
ready,
|
|
188
|
+
new Promise((_, reject) => {
|
|
189
|
+
timer = setTimeout(() => reject(new Error(`The Personal Server did not become ready in time. See ${input.logPath}.`)), input.readyTimeoutMs ?? 120_000);
|
|
190
|
+
}),
|
|
191
|
+
]);
|
|
192
|
+
return { url, port: input.port, accessToken, exited, stop };
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
await stop();
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
if (timer)
|
|
200
|
+
clearTimeout(timer);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/personal-server/local/server.ts"],"names":[],"mappings":"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"}
|