@peerbit/server 5.3.2 → 5.4.0-a762412

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.
@@ -23,7 +23,7 @@
23
23
  Learn how to configure a non-root public URL by running `npm run build`.
24
24
  -->
25
25
  <title>Peerbit</title>
26
- <script type="module" crossorigin src="/assets/index-D7nQ7uHD.js"></script>
26
+ <script type="module" crossorigin src="/assets/index-D-KTj4Kv.js"></script>
27
27
  <link rel="stylesheet" crossorigin href="/assets/index-CIfVvUo9.css">
28
28
  </head>
29
29
 
package/package.json CHANGED
@@ -1,91 +1,91 @@
1
1
  {
2
- "name": "@peerbit/server",
3
- "version": "5.3.2",
4
- "author": "dao.xyz",
5
- "repository": {
6
- "type": "git",
7
- "url": "https://github.com/dao-xyz/peerbit"
8
- },
9
- "license": "Apache-2.0",
10
- "type": "module",
11
- "sideEffects": false,
12
- "bin": {
13
- "peerbit": "./dist/src/bin.js"
14
- },
15
- "module": "dist/src/index.js",
16
- "types": "dist/src/index.d.ts",
17
- "exports": {
18
- "import": "./dist/src/index.js"
19
- },
20
- "browser": {
21
- "./dist/src/server.js": "./dist/src/server.browser.js",
22
- "./server.js": "./dist/src/server.browser.js",
23
- "./dist/src/config.js": "./dist/src/config.browser.js",
24
- "./config.js": "./dist/src/config.browser.js",
25
- "./dist/src/remotes.js": "./dist/src/remotes.browser.js",
26
- "./remotes.js": "./dist/src/remotes.browser.js",
27
- "./dist/src/docker.js": "./dist/src/docker.browser.js",
28
- "./docker.js": "./dist/src/docker.browser.js",
29
- "./dist/src/aws.js": "./dist/src/aws.browser.js"
30
- },
31
- "files": [
32
- "dist",
33
- "src",
34
- "src/nginx-template.conf",
35
- "!src/test",
36
- "!src/**/__tests__",
37
- "!lib/**/__tests__",
38
- "patches",
39
- "LICENSE"
40
- ],
41
- "publishConfig": {
42
- "access": "public"
43
- },
44
- "engines": {
45
- "node": ">=18"
46
- },
47
- "eslintConfig": {
48
- "extends": "peerbit",
49
- "parserOptions": {
50
- "project": true,
51
- "sourceType": "module"
52
- },
53
- "ignorePatterns": [
54
- "!.aegir.js",
55
- "test/ts-use",
56
- "*.d.ts"
57
- ]
58
- },
59
- "scripts": {
60
- "clean": "shx rm -rf lib/*",
61
- "build": "yarn clean && yarn build-lib && yarn build-ui",
62
- "build-lib": "tsc -p tsconfig.json",
63
- "build-ui": "cd ../frontend && yarn build && cd ../node",
64
- "postbuild": "cp src/nginx-template.conf dist/src/ && cp -r ../frontend/dist/. dist/ui",
65
- "test": "aegir test --t node",
66
- "lint": "aegir lint"
67
- },
68
- "devDependencies": {
69
- "@peerbit/test-lib": "^0.0.1",
70
- "@peerbit/test-utils": "2.1.44",
71
- "@types/yargs": "17.0.24",
72
- "aws-sdk": "^2.1259.0",
73
- "dotenv": "^16.1.4",
74
- "@types/tmp": "^0.2.3",
75
- "@types/tar-stream": "^3.1.3",
76
- "shx": "^0.3.4"
77
- },
78
- "dependencies": {
79
- "axios": "^1.4.0",
80
- "chalk": "^5.3.0",
81
- "peerbit": "4.1.34",
82
- "yargs": "^17.7.2",
83
- "tar-stream": "^3.1.7",
84
- "tmp": "^0.2.1",
85
- "tty-table": "^4.2.1"
86
- },
87
- "optionalDependencies": {
88
- "@aws-sdk/client-ec2": "^3.390.0",
89
- "@aws-sdk/client-route-53": "^3.391.0"
90
- }
2
+ "name": "@peerbit/server",
3
+ "version": "5.4.0-a762412",
4
+ "author": "dao.xyz",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/dao-xyz/peerbit"
8
+ },
9
+ "license": "Apache-2.0",
10
+ "type": "module",
11
+ "sideEffects": false,
12
+ "bin": {
13
+ "peerbit": "./dist/src/bin.js"
14
+ },
15
+ "module": "dist/src/index.js",
16
+ "types": "dist/src/index.d.ts",
17
+ "exports": {
18
+ "import": "./dist/src/index.js"
19
+ },
20
+ "browser": {
21
+ "./dist/src/server.js": "./dist/src/server.browser.js",
22
+ "./server.js": "./dist/src/server.browser.js",
23
+ "./dist/src/config.js": "./dist/src/config.browser.js",
24
+ "./config.js": "./dist/src/config.browser.js",
25
+ "./dist/src/remotes.js": "./dist/src/remotes.browser.js",
26
+ "./remotes.js": "./dist/src/remotes.browser.js",
27
+ "./dist/src/docker.js": "./dist/src/docker.browser.js",
28
+ "./docker.js": "./dist/src/docker.browser.js",
29
+ "./dist/src/aws.js": "./dist/src/aws.browser.js"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "src",
34
+ "src/nginx-template.conf",
35
+ "!src/test",
36
+ "!src/**/__tests__",
37
+ "!lib/**/__tests__",
38
+ "patches",
39
+ "LICENSE"
40
+ ],
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "engines": {
45
+ "node": ">=18"
46
+ },
47
+ "eslintConfig": {
48
+ "extends": "peerbit",
49
+ "parserOptions": {
50
+ "project": true,
51
+ "sourceType": "module"
52
+ },
53
+ "ignorePatterns": [
54
+ "!.aegir.js",
55
+ "test/ts-use",
56
+ "*.d.ts"
57
+ ]
58
+ },
59
+ "scripts": {
60
+ "clean": "shx rm -rf lib/*",
61
+ "build": "yarn clean && yarn build-lib && yarn build-ui",
62
+ "build-lib": "tsc -p tsconfig.json",
63
+ "build-ui": "cd ../frontend && yarn build && cd ../node",
64
+ "postbuild": "cp src/nginx-template.conf dist/src/ && cp -r ../frontend/dist/. dist/ui",
65
+ "test": "aegir test --t node",
66
+ "lint": "aegir lint"
67
+ },
68
+ "devDependencies": {
69
+ "@peerbit/test-lib": "0.0.1-a762412",
70
+ "@peerbit/test-utils": "2.1.45-a762412",
71
+ "@types/yargs": "17.0.24",
72
+ "aws-sdk": "^2.1259.0",
73
+ "dotenv": "^16.1.4",
74
+ "@types/tmp": "^0.2.3",
75
+ "@types/tar-stream": "^3.1.3",
76
+ "shx": "^0.3.4"
77
+ },
78
+ "dependencies": {
79
+ "axios": "^1.4.0",
80
+ "chalk": "^5.3.0",
81
+ "peerbit": "4.1.35-a762412",
82
+ "yargs": "^17.7.2",
83
+ "tar-stream": "^3.1.7",
84
+ "tmp": "^0.2.1",
85
+ "tty-table": "^4.2.1"
86
+ },
87
+ "optionalDependencies": {
88
+ "@aws-sdk/client-ec2": "^3.390.0",
89
+ "@aws-sdk/client-route-53": "^3.391.0"
90
+ }
91
91
  }
package/src/cli.ts CHANGED
@@ -1129,6 +1129,25 @@ export const cli = async (args?: string[]) => {
1129
1129
  }
1130
1130
  },
1131
1131
  })
1132
+ .command({
1133
+ command: "versions",
1134
+ describe:
1135
+ "Print <pkg>@<version> for every dependency installed on the target node",
1136
+
1137
+ handler: async (args) => {
1138
+ for (const api of apis) {
1139
+ const packageWithVersion: Record<string, string> =
1140
+ await api.api.dependency.versions();
1141
+
1142
+ for (const [packageName, version] of Object.entries(
1143
+ packageWithVersion,
1144
+ )) {
1145
+ api.log(`${packageName}@${version}`);
1146
+ }
1147
+ }
1148
+ },
1149
+ })
1150
+
1132
1151
  .command({
1133
1152
  command: "restart",
1134
1153
  describe: "Restart the server",
package/src/client.ts CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  BOOTSTRAP_PATH,
16
16
  INSTALL_PATH,
17
17
  LOCAL_API_PORT,
18
- LOG_PATH, // <-- Added the log route constant
18
+ LOG_PATH,
19
19
  PEER_ID_PATH,
20
20
  PROGRAMS_PATH,
21
21
  PROGRAM_PATH,
@@ -24,6 +24,7 @@ import {
24
24
  RESTART_PATH,
25
25
  STOP_PATH,
26
26
  TRUST_PATH,
27
+ VERSIONS_PATH,
27
28
  } from "./routes.js";
28
29
  import { signRequest } from "./signed-request.js";
29
30
  import type { InstallDependency, StartProgram } from "./types.js";
@@ -257,6 +258,14 @@ export const createClient = async (
257
258
  }
258
259
  return resp.data;
259
260
  },
261
+ versions: async (): Promise<Record<string, string>> => {
262
+ const resp = throwIfNot200(
263
+ await axiosInstance.get(endpoint + VERSIONS_PATH, {
264
+ validateStatus,
265
+ }),
266
+ );
267
+ return resp.data as Record<string, string>;
268
+ },
260
269
  },
261
270
  network: {
262
271
  bootstrap: async (): Promise<void> => {
package/src/routes.ts CHANGED
@@ -23,3 +23,4 @@ export const RESTART_PATH = "/restart";
23
23
  export const TERMINATE_PATH = "/terminate";
24
24
  export const STOP_PATH = "/path";
25
25
  export const LOG_PATH = "/log";
26
+ export const VERSIONS_PATH = "/versions";
package/src/server.ts CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  getProgramFromVariants,
10
10
  } from "@peerbit/program";
11
11
  import { waitFor } from "@peerbit/time";
12
- import { execSync, spawn } from "child_process";
12
+ import { execSync, spawn, spawnSync } from "child_process";
13
13
  import { setMaxListeners } from "events";
14
14
  import fs from "fs";
15
15
  import http from "http";
@@ -37,6 +37,7 @@ import {
37
37
  RESTART_PATH,
38
38
  STOP_PATH,
39
39
  TRUST_PATH,
40
+ VERSIONS_PATH,
40
41
  } from "./routes.js";
41
42
  import { Session } from "./session.js";
42
43
  import { getBody, verifyRequest } from "./signed-request.js";
@@ -48,9 +49,52 @@ import type {
48
49
  StartProgram,
49
50
  } from "./types.js";
50
51
 
52
+ const MAX_LISTENER_LIMIT = 1e5;
53
+
54
+ const getInstallDir = (): string | null => {
55
+ return (
56
+ process.env.PEERBIT_MODULES_PATH ||
57
+ findPeerbitProgramFolder(__dirname) || // same util used by /install
58
+ null
59
+ );
60
+ };
61
+
51
62
  // eslint-disable-next-line @typescript-eslint/naming-convention
52
63
  const __dirname = dirname(fileURLToPath(import.meta.url));
53
64
 
65
+ const extraNodePath = () => {
66
+ const installDir = getInstallDir();
67
+ return installDir ? path.join(installDir, "node_modules") : undefined;
68
+ };
69
+ const extra = extraNodePath();
70
+ if (extra) {
71
+ process.env.NODE_PATH = process.env.NODE_PATH
72
+ ? process.env.NODE_PATH + path.delimiter + extra
73
+ : extra;
74
+
75
+ // always re-parse NODE_PATH for *this* process
76
+ ((await import("module")).default as any)["_initPaths"]();
77
+ }
78
+
79
+ // add next to execSync
80
+
81
+ const listVersions = (dir: string): Record<string, string> => {
82
+ const proc = spawnSync("npm", ["ls", "--depth", "0", "--json", "--silent"], {
83
+ cwd: dir,
84
+ encoding: "utf8",
85
+ });
86
+
87
+ // npm may exit 1, but proc.stdout usually contains valid JSON
88
+ if (!proc.stdout) throw new Error(proc.stderr || "npm ls failed");
89
+
90
+ const tree = JSON.parse(proc.stdout);
91
+ const versions: Record<string, string> = {};
92
+ for (const [name, info] of Object.entries(tree.dependencies || {})) {
93
+ versions[name] = (info as any)?.version || "UNKNOWN";
94
+ }
95
+ return versions;
96
+ };
97
+
54
98
  export const stopAndWait = (server: http.Server) => {
55
99
  let closed = false;
56
100
  server.on("close", () => {
@@ -230,24 +274,36 @@ export const startApiServer = async (
230
274
  const port = properties?.port ?? LOCAL_API_PORT;
231
275
 
232
276
  const restart = async () => {
233
- await client.stop();
234
- await stopAndWait(server);
235
-
236
- // We filter out the reset command, since restarting means that we want to resume something
237
- spawn(
238
- process.argv.shift()!,
239
- [
240
- ...process.execArgv,
241
- ...process.argv.filter((x) => x !== "--reset" && x !== "-r"),
242
- ],
243
- {
244
- cwd: process.cwd(),
245
- detached: true,
246
- stdio: "inherit",
247
- gid: process.getgid!(),
248
- },
277
+ console.log(
278
+ "Process will be lost during restart. Please find it using a process monitor. Or find it from the port e.g. 'lsof -i tcp:8001'",
249
279
  );
250
- process.exit(0);
280
+ process.nextTick(async () => {
281
+ await client.stop();
282
+ await stopAndWait(server);
283
+
284
+ // We filter out the reset command, since restarting means that we want to resume something
285
+ spawn(
286
+ process.argv.shift()!,
287
+ [
288
+ ...process.execArgv,
289
+ ...process.argv.filter((x) => x !== "--reset" && x !== "-r"),
290
+ ],
291
+ {
292
+ cwd: process.cwd(),
293
+ detached: true,
294
+ stdio: "inherit",
295
+ gid: process.getgid!(),
296
+ env: {
297
+ ...process.env,
298
+ NODE_PATH:
299
+ (process.env.NODE_PATH
300
+ ? process.env.NODE_PATH + path.delimiter
301
+ : "") + (extraNodePath() ?? ""),
302
+ },
303
+ },
304
+ );
305
+ process.exit(0);
306
+ });
251
307
  };
252
308
  if (!client.peerId.equals(await client.identity.publicKey.toPeerId())) {
253
309
  throw new Error("Expecting node identity to equal peerId");
@@ -494,9 +550,8 @@ export const startApiServer = async (
494
550
  } else {
495
551
  try {
496
552
  // TODO do this without sudo. i.e. for servers provide arguments so that this app folder is writeable by default by the user
497
- const installDir =
498
- process.env.PEERBIT_MODULES_PATH ||
499
- findPeerbitProgramFolder(__dirname);
553
+ const installDir = getInstallDir();
554
+
500
555
  let permission = "";
501
556
  if (!installDir) {
502
557
  res.writeHead(400);
@@ -563,6 +618,31 @@ export const startApiServer = async (
563
618
  break;
564
619
  }
565
620
  }
621
+ } else if (req.url.startsWith(VERSIONS_PATH)) {
622
+ if (req.method === "GET") {
623
+ try {
624
+ const installDir = getInstallDir();
625
+ if (!installDir) {
626
+ res.writeHead(400);
627
+ res.end("Cannot determine install directory");
628
+ return;
629
+ }
630
+
631
+ const versions = listVersions(installDir);
632
+
633
+ res.setHeader("Content-Type", "application/json");
634
+ res.writeHead(200);
635
+ res.end(JSON.stringify(versions, null, 2));
636
+ } catch (err) {
637
+ console.error("Failed to list versions:", err);
638
+ res.writeHead(500);
639
+ res.end("Error fetching versions");
640
+ }
641
+ } else {
642
+ r404();
643
+ }
644
+
645
+ /* keep the remaining else-if blocks (PEER_ID_PATH, etc.) unchanged */
566
646
  } else if (req.url.startsWith(BOOTSTRAP_PATH)) {
567
647
  switch (req.method) {
568
648
  case "POST":
@@ -692,8 +772,8 @@ export const startApiServer = async (
692
772
  };
693
773
  };
694
774
 
695
- setMaxListeners(Infinity); // TODO make this better (lower and large enough)
696
- process.setMaxListeners(Infinity); // TODO make this better (lower and large enough)
775
+ setMaxListeners(MAX_LISTENER_LIMIT); // TODO make this better (lower and large enough)
776
+ process.setMaxListeners(MAX_LISTENER_LIMIT); // TODO make this better (lower and large enough)
697
777
 
698
778
  const server = http.createServer(endpoints(client));
699
779
  server.listen(port);