vana-cli 0.24.5 → 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.
Files changed (103) hide show
  1. package/README.md +1 -0
  2. package/dist/cli/auth.d.ts +2 -0
  3. package/dist/cli/auth.d.ts.map +1 -1
  4. package/dist/cli/auth.js +2 -1
  5. package/dist/cli/auth.js.map +1 -1
  6. package/dist/cli/index.d.ts +2 -0
  7. package/dist/cli/index.d.ts.map +1 -1
  8. package/dist/cli/index.js +128 -13
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/cli/server-start.d.ts +42 -0
  11. package/dist/cli/server-start.d.ts.map +1 -0
  12. package/dist/cli/server-start.js +189 -0
  13. package/dist/cli/server-start.js.map +1 -0
  14. package/dist/connectors/registry.d.ts +2 -0
  15. package/dist/connectors/registry.d.ts.map +1 -1
  16. package/dist/connectors/registry.js +18 -2
  17. package/dist/connectors/registry.js.map +1 -1
  18. package/dist/core/cli-types.d.ts +44 -0
  19. package/dist/core/cli-types.d.ts.map +1 -1
  20. package/dist/core/cli-types.js +14 -0
  21. package/dist/core/cli-types.js.map +1 -1
  22. package/dist/core/state-store.d.ts +6 -0
  23. package/dist/core/state-store.d.ts.map +1 -1
  24. package/dist/core/state-store.js.map +1 -1
  25. package/dist/pdpp/host.d.ts +66 -0
  26. package/dist/pdpp/host.d.ts.map +1 -0
  27. package/dist/pdpp/host.js +283 -0
  28. package/dist/pdpp/host.js.map +1 -0
  29. package/dist/pdpp/installer.d.ts +17 -0
  30. package/dist/pdpp/installer.d.ts.map +1 -0
  31. package/dist/pdpp/installer.js +117 -0
  32. package/dist/pdpp/installer.js.map +1 -0
  33. package/dist/pdpp/local.d.ts +14 -0
  34. package/dist/pdpp/local.d.ts.map +1 -0
  35. package/dist/pdpp/local.js +76 -0
  36. package/dist/pdpp/local.js.map +1 -0
  37. package/dist/pdpp/pins.d.ts +23 -0
  38. package/dist/pdpp/pins.d.ts.map +1 -0
  39. package/dist/pdpp/pins.js +18 -0
  40. package/dist/pdpp/pins.js.map +1 -0
  41. package/dist/pdpp/profile.d.ts +49 -0
  42. package/dist/pdpp/profile.d.ts.map +1 -0
  43. package/dist/pdpp/profile.js +17 -0
  44. package/dist/pdpp/profile.js.map +1 -0
  45. package/dist/pdpp/protocol.d.ts +79 -0
  46. package/dist/pdpp/protocol.d.ts.map +1 -0
  47. package/dist/pdpp/protocol.js +372 -0
  48. package/dist/pdpp/protocol.js.map +1 -0
  49. package/dist/pdpp/runtime.d.ts +43 -0
  50. package/dist/pdpp/runtime.d.ts.map +1 -0
  51. package/dist/pdpp/runtime.js +387 -0
  52. package/dist/pdpp/runtime.js.map +1 -0
  53. package/dist/pdpp/store.d.ts +43 -0
  54. package/dist/pdpp/store.d.ts.map +1 -0
  55. package/dist/pdpp/store.js +100 -0
  56. package/dist/pdpp/store.js.map +1 -0
  57. package/dist/personal-server/index.d.ts +1 -0
  58. package/dist/personal-server/index.d.ts.map +1 -1
  59. package/dist/personal-server/index.js +17 -2
  60. package/dist/personal-server/index.js.map +1 -1
  61. package/dist/personal-server/local/config.d.ts +23 -0
  62. package/dist/personal-server/local/config.d.ts.map +1 -0
  63. package/dist/personal-server/local/config.js +51 -0
  64. package/dist/personal-server/local/config.js.map +1 -0
  65. package/dist/personal-server/local/owner-binding.d.ts +33 -0
  66. package/dist/personal-server/local/owner-binding.d.ts.map +1 -0
  67. package/dist/personal-server/local/owner-binding.js +155 -0
  68. package/dist/personal-server/local/owner-binding.js.map +1 -0
  69. package/dist/personal-server/local/owner-secret.d.ts +17 -0
  70. package/dist/personal-server/local/owner-secret.d.ts.map +1 -0
  71. package/dist/personal-server/local/owner-secret.js +119 -0
  72. package/dist/personal-server/local/owner-secret.js.map +1 -0
  73. package/dist/personal-server/local/runtime-pkg/entry.mjs +153 -0
  74. package/dist/personal-server/local/runtime-pkg/package-lock.json +2342 -0
  75. package/dist/personal-server/local/runtime-pkg/package.json +13 -0
  76. package/dist/personal-server/local/runtime.d.ts +9 -0
  77. package/dist/personal-server/local/runtime.d.ts.map +1 -0
  78. package/dist/personal-server/local/runtime.js +66 -0
  79. package/dist/personal-server/local/runtime.js.map +1 -0
  80. package/dist/personal-server/local/server.d.ts +39 -0
  81. package/dist/personal-server/local/server.d.ts.map +1 -0
  82. package/dist/personal-server/local/server.js +203 -0
  83. package/dist/personal-server/local/server.js.map +1 -0
  84. package/dist/runtime/core/contracts.d.ts +2 -0
  85. package/dist/runtime/core/contracts.d.ts.map +1 -1
  86. package/dist/runtime/managed-playwright.d.ts +7 -0
  87. package/dist/runtime/managed-playwright.d.ts.map +1 -1
  88. package/dist/runtime/managed-playwright.js +7 -0
  89. package/dist/runtime/managed-playwright.js.map +1 -1
  90. package/dist/vendor/pdpp-connector-manager/LICENSE +202 -0
  91. package/dist/vendor/pdpp-connector-manager/NOTICE +2 -0
  92. package/dist/vendor/pdpp-connector-manager/VENDOR.md +27 -0
  93. package/dist/vendor/pdpp-connector-manager/catalog-schema-data.mjs +168 -0
  94. package/dist/vendor/pdpp-connector-manager/catalog-schema.mjs +62 -0
  95. package/dist/vendor/pdpp-connector-manager/index.d.mts +49 -0
  96. package/dist/vendor/pdpp-connector-manager/index.mjs +1646 -0
  97. package/dist/vendor/pdpp-connector-manager/oci-catalog.mjs +93 -0
  98. package/dist/vendor/pdpp-connector-manager/oci-registry.mjs +1002 -0
  99. package/dist/vendor/pdpp-connector-manager/oci-verify.mjs +515 -0
  100. package/dist/vendor/pdpp-connector-manager/package.json +51 -0
  101. package/dist/vendor/pdpp-connector-manager/retry.mjs +142 -0
  102. package/dist/vendor/pdpp-connector-manager/tar-stream.mjs +685 -0
  103. package/package.json +7 -2
@@ -0,0 +1,23 @@
1
+ import type { VanaNetworkName } from "../../core/network.js";
2
+ /** What a Personal Server needs to know about the network it serves. */
3
+ export interface LocalServerNetwork {
4
+ name: VanaNetworkName;
5
+ chainId: number;
6
+ gatewayUrl: string;
7
+ storageApiUrl: string;
8
+ contracts: Record<string, string>;
9
+ }
10
+ export declare function localServerNetwork(name: VanaNetworkName): LocalServerNetwork;
11
+ /** The pinned server release, matching runtime-pkg/package.json. */
12
+ export declare const PERSONAL_SERVER_VERSION = "1.24.6";
13
+ export declare function localServerHome(): string;
14
+ /**
15
+ * The CLI's own data dir per network. Never Desktop's
16
+ * (`~/.vana/desktop/personal-server/...`): two processes on one index and one
17
+ * server key would corrupt both.
18
+ */
19
+ export declare function localServerDataDir(network: VanaNetworkName): string;
20
+ export declare function localServerRuntimeDir(): string;
21
+ /** Ports Desktop and the CLI both try first; the loopback approval page is port + 1. */
22
+ export declare const LOCAL_SERVER_PORTS: readonly [8080, 8082, 8084];
23
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/personal-server/local/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,wEAAwE;AACxE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AA+BD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,kBAAkB,CAE5E;AAED,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAEnE;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wFAAwF;AACxF,eAAO,MAAM,kBAAkB,6BAA8B,CAAC"}
@@ -0,0 +1,51 @@
1
+ import path from "node:path";
2
+ import { getVanaHome } from "../../core/paths.js";
3
+ // Same deployment on both chains. Mirrors the `contracts` block of Vana
4
+ // Desktop's packages/app-runtime/src/personal-server/environments.json.
5
+ const CONTRACTS = {
6
+ dataPortabilityEscrow: "0x07d7769081adc3a3DBe91f5E4B98E9A5a6B292e3",
7
+ dataPortabilityGrantees: "0x8325C0A0948483EdA023A1A2Fd895e62C5131234",
8
+ dataPortabilityPermissions: "0x4d3FA76064D88e0454cFc4CaD7e5FeC3e3124011",
9
+ dataPortabilityServer: "0xCae2CE0e9caa6643ed28186cF57bd40Bd9E17Eab",
10
+ dataRefinerRegistry: "0x93c3EF89369fDcf08Be159D9DeF0F18AB6Be008c",
11
+ dataRegistry: "0x8f1eFCdff3d0d5BB535e32620721c7EBed151867",
12
+ feeRegistry: "0xb4FA18443E0FA6cdC0280D20b8cCDB2377D13Bf2",
13
+ };
14
+ const NETWORKS = {
15
+ moksha: {
16
+ name: "moksha",
17
+ chainId: 14800,
18
+ gatewayUrl: "https://dp-rpc.moksha.vana.org",
19
+ storageApiUrl: "https://storage-dev.vana.org",
20
+ contracts: CONTRACTS,
21
+ },
22
+ mainnet: {
23
+ name: "mainnet",
24
+ chainId: 1480,
25
+ gatewayUrl: "https://dp-rpc.vana.org",
26
+ storageApiUrl: "https://storage.vana.org",
27
+ contracts: CONTRACTS,
28
+ },
29
+ };
30
+ export function localServerNetwork(name) {
31
+ return NETWORKS[name];
32
+ }
33
+ /** The pinned server release, matching runtime-pkg/package.json. */
34
+ export const PERSONAL_SERVER_VERSION = "1.24.6";
35
+ export function localServerHome() {
36
+ return path.join(getVanaHome(), "cli", "personal-server");
37
+ }
38
+ /**
39
+ * The CLI's own data dir per network. Never Desktop's
40
+ * (`~/.vana/desktop/personal-server/...`): two processes on one index and one
41
+ * server key would corrupt both.
42
+ */
43
+ export function localServerDataDir(network) {
44
+ return path.join(localServerHome(), network);
45
+ }
46
+ export function localServerRuntimeDir() {
47
+ return path.join(localServerHome(), "runtime", PERSONAL_SERVER_VERSION);
48
+ }
49
+ /** Ports Desktop and the CLI both try first; the loopback approval page is port + 1. */
50
+ export const LOCAL_SERVER_PORTS = [8080, 8082, 8084];
51
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/personal-server/local/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAYlD,wEAAwE;AACxE,wEAAwE;AACxE,MAAM,SAAS,GAA2B;IACxC,qBAAqB,EAAE,4CAA4C;IACnE,uBAAuB,EAAE,4CAA4C;IACrE,0BAA0B,EAAE,4CAA4C;IACxE,qBAAqB,EAAE,4CAA4C;IACnE,mBAAmB,EAAE,4CAA4C;IACjE,YAAY,EAAE,4CAA4C;IAC1D,WAAW,EAAE,4CAA4C;CAC1D,CAAC;AAEF,MAAM,QAAQ,GAAgD;IAC5D,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,KAAK;QACd,UAAU,EAAE,gCAAgC;QAC5C,aAAa,EAAE,8BAA8B;QAC7C,SAAS,EAAE,SAAS;KACrB;IACD,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,yBAAyB;QACrC,aAAa,EAAE,0BAA0B;QACzC,SAAS,EAAE,SAAS;KACrB;CACF,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,IAAqB;IACtD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAEhD,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAwB;IACzD,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,uBAAuB,CAAC,CAAC;AAC1E,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The signature a Personal Server's owner makes over this exact message. The
3
+ * server recovers its owner from it and derives the data encryption key from
4
+ * it, so it is as sensitive as a key.
5
+ */
6
+ export declare const OWNER_BINDING_MESSAGE = "vana-master-key-v1";
7
+ export declare const OWNER_BINDING_INTENT = "personal_server.owner_binding.v1";
8
+ export interface OwnerBinding {
9
+ signature: string;
10
+ signerAddress: string;
11
+ /**
12
+ * Account's proof that this owner approved this client, needed later to
13
+ * register the server. Present for public native clients such as the CLI.
14
+ */
15
+ trustToken: string | null;
16
+ }
17
+ export interface OwnerBindingDeps {
18
+ fetchImpl?: typeof fetch;
19
+ openBrowser: (url: string) => void;
20
+ /** Called with the confirmation URL, so a person can open it by hand. */
21
+ onConfirmationUrl?: (url: string) => void;
22
+ timeoutMs?: number;
23
+ }
24
+ /**
25
+ * Get the owner-binding signature through Account's signing exchange: Account
26
+ * never signs silently for the CLI, so the person confirms in the browser,
27
+ * and the result comes back to a one-time loopback listener.
28
+ */
29
+ export declare function runOwnerBindingExchange(input: {
30
+ accountUrl: string;
31
+ accessToken: string;
32
+ }, deps: OwnerBindingDeps): Promise<OwnerBinding>;
33
+ //# sourceMappingURL=owner-binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner-binding.d.ts","sourceRoot":"","sources":["../../../src/personal-server/local/owner-binding.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAC1D,eAAO,MAAM,oBAAoB,qCAAqC,CAAC;AAEvE,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAClD,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,YAAY,CAAC,CA6FvB"}
@@ -0,0 +1,155 @@
1
+ import crypto from "node:crypto";
2
+ import http from "node:http";
3
+ /**
4
+ * The signature a Personal Server's owner makes over this exact message. The
5
+ * server recovers its owner from it and derives the data encryption key from
6
+ * it, so it is as sensitive as a key.
7
+ */
8
+ export const OWNER_BINDING_MESSAGE = "vana-master-key-v1";
9
+ export const OWNER_BINDING_INTENT = "personal_server.owner_binding.v1";
10
+ const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;
11
+ function base64url(bytes) {
12
+ return bytes.toString("base64url");
13
+ }
14
+ const DONE_PAGE = `<!doctype html><meta charset="utf-8"><title>Vana CLI</title>
15
+ <body style="font-family:system-ui;margin:4rem"><h1>Done</h1><p>You can close this tab and return to the terminal.</p></body>`;
16
+ const FAILED_PAGE = `<!doctype html><meta charset="utf-8"><title>Vana CLI</title>
17
+ <body style="font-family:system-ui;margin:4rem"><h1>That did not work</h1><p>Return to the terminal for details.</p></body>`;
18
+ /**
19
+ * Wait for Account to send the browser back to this machine with the
20
+ * exchange's one-time code. Listens on 127.0.0.1 only, accepts exactly one
21
+ * request whose state matches, and closes.
22
+ */
23
+ async function startLoopbackCallback(expectedState) {
24
+ let settle = null;
25
+ const code = new Promise((resolve, reject) => {
26
+ settle = { resolve, reject };
27
+ });
28
+ const server = http.createServer((request, response) => {
29
+ const url = new URL(request.url ?? "/", "http://127.0.0.1");
30
+ if (url.pathname !== "/signing/callback") {
31
+ response.writeHead(404).end();
32
+ return;
33
+ }
34
+ const state = url.searchParams.get("state");
35
+ const received = url.searchParams.get("code");
36
+ const error = url.searchParams.get("error");
37
+ if (state !== expectedState) {
38
+ // Not ours; keep waiting for the real callback.
39
+ response.writeHead(400, { "content-type": "text/html" }).end(FAILED_PAGE);
40
+ return;
41
+ }
42
+ if (error || !received) {
43
+ response.writeHead(200, { "content-type": "text/html" }).end(FAILED_PAGE);
44
+ settle?.reject(new Error(error === "access_denied"
45
+ ? "The request was declined in the browser."
46
+ : `Account returned ${error ?? "no code"}.`));
47
+ return;
48
+ }
49
+ response.writeHead(200, { "content-type": "text/html" }).end(DONE_PAGE);
50
+ settle?.resolve(received);
51
+ });
52
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
53
+ const { port } = server.address();
54
+ return {
55
+ redirectUri: `http://127.0.0.1:${port}/signing/callback`,
56
+ code,
57
+ close: () => server.close(),
58
+ };
59
+ }
60
+ /**
61
+ * Get the owner-binding signature through Account's signing exchange: Account
62
+ * never signs silently for the CLI, so the person confirms in the browser,
63
+ * and the result comes back to a one-time loopback listener.
64
+ */
65
+ export async function runOwnerBindingExchange(input, deps) {
66
+ const fetchImpl = deps.fetchImpl ?? fetch;
67
+ const account = input.accountUrl.replace(/\/+$/, "");
68
+ const state = base64url(crypto.randomBytes(32));
69
+ const codeVerifier = base64url(crypto.randomBytes(32));
70
+ const codeChallenge = base64url(crypto.createHash("sha256").update(codeVerifier).digest());
71
+ const callback = await startLoopbackCallback(state);
72
+ try {
73
+ const created = await fetchImpl(`${account}/api/v1/signing-exchanges`, {
74
+ method: "POST",
75
+ headers: {
76
+ "content-type": "application/json",
77
+ authorization: `Bearer ${input.accessToken}`,
78
+ },
79
+ body: JSON.stringify({
80
+ intent: OWNER_BINDING_INTENT,
81
+ redirectUri: callback.redirectUri,
82
+ state,
83
+ codeChallenge,
84
+ codeChallengeMethod: "S256",
85
+ }),
86
+ });
87
+ if (!created.ok) {
88
+ throw new Error(await describeFailure("start the owner confirmation", created));
89
+ }
90
+ const { confirmationUrl } = (await created.json());
91
+ if (!confirmationUrl) {
92
+ throw new Error("Account did not return a confirmation page.");
93
+ }
94
+ deps.onConfirmationUrl?.(confirmationUrl);
95
+ deps.openBrowser(confirmationUrl);
96
+ const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS;
97
+ let timer = null;
98
+ const code = await Promise.race([
99
+ callback.code,
100
+ new Promise((_, reject) => {
101
+ timer = setTimeout(() => reject(new Error("Nobody confirmed in the browser in time.")), timeoutMs);
102
+ }),
103
+ ]).finally(() => {
104
+ if (timer)
105
+ clearTimeout(timer);
106
+ });
107
+ const redeemed = await fetchImpl(`${account}/api/v1/signing-exchanges/redeem`, {
108
+ method: "POST",
109
+ headers: {
110
+ "content-type": "application/json",
111
+ authorization: `Bearer ${input.accessToken}`,
112
+ },
113
+ body: JSON.stringify({
114
+ code,
115
+ state,
116
+ codeVerifier,
117
+ redirectUri: callback.redirectUri,
118
+ }),
119
+ });
120
+ if (!redeemed.ok) {
121
+ throw new Error(await describeFailure("finish the owner confirmation", redeemed));
122
+ }
123
+ const body = (await redeemed.json());
124
+ if (body.status !== "signed" || !body.signature || !body.signerAddress) {
125
+ throw new Error("Account answered the owner confirmation without a signature.");
126
+ }
127
+ return {
128
+ signature: body.signature,
129
+ signerAddress: body.signerAddress,
130
+ trustToken: body.desktopSigningTrustToken ?? null,
131
+ };
132
+ }
133
+ finally {
134
+ callback.close();
135
+ }
136
+ }
137
+ async function describeFailure(step, response) {
138
+ let code = "";
139
+ try {
140
+ const body = (await response.json());
141
+ code = body.error?.code ?? "";
142
+ }
143
+ catch {
144
+ // Not JSON.
145
+ }
146
+ if (response.status === 401) {
147
+ return `Could not ${step}: your vana login is not accepted. Run \`vana login\` again.`;
148
+ }
149
+ if (code === "client_not_allowed" ||
150
+ code === "intent_not_allowed_for_client") {
151
+ return `Could not ${step}: this Vana Account does not let the CLI run a Personal Server yet (${code}).`;
152
+ }
153
+ return `Could not ${step} (HTTP ${response.status}${code ? `, ${code}` : ""}).`;
154
+ }
155
+ //# sourceMappingURL=owner-binding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner-binding.js","sourceRoot":"","sources":["../../../src/personal-server/local/owner-binding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { OwnerBinding } from "./owner-binding.js";
2
+ /**
3
+ * Where the owner-binding signature is kept between starts, so starting a
4
+ * server does not ask for a browser confirmation every time. It derives the
5
+ * server's encryption key, so on macOS it lives in the keychain; elsewhere in
6
+ * a 0600 file, as the app key does.
7
+ */
8
+ export interface OwnerSecretStore {
9
+ get(key: string): OwnerBinding | null;
10
+ set(key: string, binding: OwnerBinding): void;
11
+ delete(key: string): void;
12
+ }
13
+ export declare function ownerSecretKey(accountUrl: string, address: string): string;
14
+ declare function fileStore(file?: string): OwnerSecretStore;
15
+ export declare function defaultOwnerSecretStore(): OwnerSecretStore;
16
+ export { fileStore as fileOwnerSecretStore };
17
+ //# sourceMappingURL=owner-secret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner-secret.d.ts","sourceRoot":"","sources":["../../../src/personal-server/local/owner-secret.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;IACtC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAID,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1E;AAoED,iBAAS,SAAS,CAChB,IAAI,SAAsD,GACzD,gBAAgB,CA4BlB;AAiBD,wBAAgB,uBAAuB,IAAI,gBAAgB,CAI1D;AAED,OAAO,EAAE,SAAS,IAAI,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { localServerHome } from "./config.js";
5
+ const KEYCHAIN_SERVICE = "org.vana.cli.personal-server-owner";
6
+ export function ownerSecretKey(accountUrl, address) {
7
+ return `${new URL(accountUrl).host}:${address.toLowerCase()}`;
8
+ }
9
+ function parse(raw) {
10
+ if (!raw)
11
+ return null;
12
+ try {
13
+ const value = JSON.parse(raw);
14
+ if (typeof value.signature === "string" &&
15
+ typeof value.signerAddress === "string") {
16
+ return {
17
+ signature: value.signature,
18
+ signerAddress: value.signerAddress,
19
+ trustToken: typeof value.trustToken === "string" ? value.trustToken : null,
20
+ };
21
+ }
22
+ }
23
+ catch {
24
+ // Unreadable entry: treat as absent.
25
+ }
26
+ return null;
27
+ }
28
+ function keychainStore() {
29
+ const run = (args) => execFileSync("security", args, {
30
+ encoding: "utf8",
31
+ stdio: ["ignore", "pipe", "ignore"],
32
+ });
33
+ return {
34
+ get(key) {
35
+ try {
36
+ return parse(run([
37
+ "find-generic-password",
38
+ "-s",
39
+ KEYCHAIN_SERVICE,
40
+ "-a",
41
+ key,
42
+ "-w",
43
+ ]).trim());
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ },
49
+ set(key, binding) {
50
+ run([
51
+ "add-generic-password",
52
+ "-U",
53
+ "-s",
54
+ KEYCHAIN_SERVICE,
55
+ "-a",
56
+ key,
57
+ "-w",
58
+ JSON.stringify(binding),
59
+ ]);
60
+ },
61
+ delete(key) {
62
+ try {
63
+ run(["delete-generic-password", "-s", KEYCHAIN_SERVICE, "-a", key]);
64
+ }
65
+ catch {
66
+ // Already gone.
67
+ }
68
+ },
69
+ };
70
+ }
71
+ function fileStore(file = path.join(localServerHome(), "owner-bindings.json")) {
72
+ const read = () => {
73
+ try {
74
+ return JSON.parse(fs.readFileSync(file, "utf8"));
75
+ }
76
+ catch {
77
+ return {};
78
+ }
79
+ };
80
+ const write = (entries) => {
81
+ fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
82
+ fs.writeFileSync(file, `${JSON.stringify(entries, null, 2)}\n`, {
83
+ mode: 0o600,
84
+ });
85
+ };
86
+ return {
87
+ get: (key) => parse(read()[key]),
88
+ set(key, binding) {
89
+ write({ ...read(), [key]: JSON.stringify(binding) });
90
+ },
91
+ delete(key) {
92
+ const entries = read();
93
+ delete entries[key];
94
+ write(entries);
95
+ },
96
+ };
97
+ }
98
+ // Without a default keychain (a HOME with no login keychain, a fresh
99
+ // account), `security add-generic-password` does not fail: it puts up a GUI
100
+ // dialog and waits. Asking for the default keychain never prompts.
101
+ function hasDefaultKeychain() {
102
+ try {
103
+ execFileSync("security", ["default-keychain"], {
104
+ stdio: ["ignore", "ignore", "ignore"],
105
+ timeout: 5_000,
106
+ });
107
+ return true;
108
+ }
109
+ catch {
110
+ return false;
111
+ }
112
+ }
113
+ export function defaultOwnerSecretStore() {
114
+ return process.platform === "darwin" && hasDefaultKeychain()
115
+ ? keychainStore()
116
+ : fileStore();
117
+ }
118
+ export { fileStore as fileOwnerSecretStore };
119
+ //# sourceMappingURL=owner-secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner-secret.js","sourceRoot":"","sources":["../../../src/personal-server/local/owner-secret.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,153 @@
1
+ // The Personal Server process `vana server start` runs, modeled on Vana
2
+ // Desktop's sidecar (apps/desktop/personal-server/index.js in unity-surfaces).
3
+ //
4
+ // It reads one JSON line on stdin, so the owner signature never appears in the
5
+ // process list or environment:
6
+ // { rootPath, port, ownerSignature, ownerAddress, network: { gatewayUrl, chainId,
7
+ // contracts, storageApiUrl } }
8
+ // and writes one JSON object per line on stdout: ready, error, stopped.
9
+ // Logs go to stderr.
10
+
11
+ import { readFile, rename, writeFile } from "node:fs/promises";
12
+ import { join } from "node:path";
13
+ import readline from "node:readline";
14
+
15
+ import {
16
+ loadConfig,
17
+ startPersonalServer,
18
+ } from "@opendatalabs/personal-server-ts/node";
19
+
20
+ const send = (message) => process.stdout.write(`${JSON.stringify(message)}\n`);
21
+
22
+ function isPlainObject(value) {
23
+ return (
24
+ typeof value === "object" &&
25
+ value !== null &&
26
+ !Array.isArray(value) &&
27
+ Object.getPrototypeOf(value) !== null
28
+ );
29
+ }
30
+
31
+ // Derived leaves win and every other persisted key survives, as in Desktop's
32
+ // applyDerivedServerConfig.
33
+ function applyDerived(persisted, derived) {
34
+ if (!isPlainObject(persisted)) return structuredClone(derived);
35
+ const merged = { ...persisted };
36
+ for (const [key, value] of Object.entries(derived)) {
37
+ merged[key] =
38
+ isPlainObject(value) && isPlainObject(merged[key])
39
+ ? applyDerived(merged[key], value)
40
+ : structuredClone(value);
41
+ }
42
+ return merged;
43
+ }
44
+
45
+ // Everything that follows from the network. Local only for now: no tunnel,
46
+ // so nothing is reachable from outside and nothing may be registered, and no
47
+ // sync to Vana storage until registration exists.
48
+ function derivedConfig(network) {
49
+ return {
50
+ devUi: { enabled: true },
51
+ gateway: {
52
+ url: network.gatewayUrl,
53
+ chainId: network.chainId,
54
+ contracts: network.contracts,
55
+ },
56
+ inference: {
57
+ baseUrl: `${network.gatewayUrl.replace(/\/+$/, "")}/v1/inference`,
58
+ },
59
+ logging: { level: "info", pretty: false },
60
+ storage: {
61
+ backend: "vana",
62
+ config: { vana: { apiUrl: network.storageApiUrl } },
63
+ },
64
+ sync: { enabled: false },
65
+ tunnel: { enabled: false },
66
+ };
67
+ }
68
+
69
+ async function readInput() {
70
+ const rl = readline.createInterface({ input: process.stdin });
71
+ for await (const line of rl) {
72
+ if (line.trim()) {
73
+ rl.close();
74
+ return JSON.parse(line);
75
+ }
76
+ }
77
+ throw new Error("No configuration on stdin.");
78
+ }
79
+
80
+ let ps = null;
81
+
82
+ async function main() {
83
+ const input = await readInput();
84
+ const { rootPath, port, ownerSignature, ownerAddress, network } = input;
85
+ const configPath = join(rootPath, "server.json");
86
+ const derived = derivedConfig(network);
87
+
88
+ // Persist the derived block the way Desktop does, so a network change can
89
+ // never leave an old gateway or storage host behind in server.json.
90
+ let persisted = null;
91
+ try {
92
+ persisted = JSON.parse(await readFile(configPath, "utf8"));
93
+ } catch {
94
+ persisted = null;
95
+ }
96
+ const next = applyDerived(persisted, derived);
97
+ const temporary = `${configPath}.${process.pid}.tmp`;
98
+ await writeFile(temporary, `${JSON.stringify(next, null, 2)}\n`, {
99
+ mode: 0o600,
100
+ });
101
+ await rename(temporary, configPath);
102
+
103
+ // configDefaults merges shallowly for some sections, so hand back whole
104
+ // sections from the schema-complete loaded config.
105
+ const loaded = await loadConfig({ configPath, rootPath });
106
+ const configDefaults = {
107
+ server: {
108
+ ...loaded.server,
109
+ port,
110
+ ...(ownerAddress ? { address: ownerAddress } : {}),
111
+ },
112
+ };
113
+ for (const key of Object.keys(derived)) {
114
+ configDefaults[key] = applyDerived(loaded[key], derived[key]);
115
+ }
116
+
117
+ ps = await startPersonalServer({
118
+ configPath,
119
+ rootPath,
120
+ port,
121
+ ownerSignature,
122
+ mcpOAuthApprovalUrl: "vana://mcp-authorization",
123
+ configDefaults,
124
+ onStatus: (status) => process.stderr.write(`[status] ${status}\n`),
125
+ });
126
+ const info = await ps.ready();
127
+ send({
128
+ type: "ready",
129
+ port,
130
+ url: info.urls?.local ?? `http://localhost:${port}`,
131
+ });
132
+ }
133
+
134
+ async function shutdown(signal) {
135
+ process.stderr.write(`[entry] ${signal}, stopping\n`);
136
+ try {
137
+ await ps?.stop();
138
+ } finally {
139
+ send({ type: "stopped" });
140
+ process.exit(0);
141
+ }
142
+ }
143
+
144
+ process.on("SIGINT", () => void shutdown("SIGINT"));
145
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
146
+
147
+ main().catch((error) => {
148
+ send({
149
+ type: "error",
150
+ message: error instanceof Error ? error.message : String(error),
151
+ });
152
+ process.exit(1);
153
+ });