@peerbit/server 5.3.2 → 5.4.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.
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "@peerbit/server",
3
- "version": "5.3.2",
3
+ "version": "5.4.0",
4
4
  "author": "dao.xyz",
5
5
  "repository": {
6
6
  "type": "git",
@@ -67,7 +67,7 @@
67
67
  },
68
68
  "devDependencies": {
69
69
  "@peerbit/test-lib": "^0.0.1",
70
- "@peerbit/test-utils": "2.1.44",
70
+ "@peerbit/test-utils": "2.1.45",
71
71
  "@types/yargs": "17.0.24",
72
72
  "aws-sdk": "^2.1259.0",
73
73
  "dotenv": "^16.1.4",
@@ -78,7 +78,7 @@
78
78
  "dependencies": {
79
79
  "axios": "^1.4.0",
80
80
  "chalk": "^5.3.0",
81
- "peerbit": "4.1.34",
81
+ "peerbit": "4.1.35",
82
82
  "yargs": "^17.7.2",
83
83
  "tar-stream": "^3.1.7",
84
84
  "tmp": "^0.2.1",
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
@@ -10,6 +10,7 @@ import {
10
10
  } from "@peerbit/program";
11
11
  import { waitFor } from "@peerbit/time";
12
12
  import { execSync, spawn } from "child_process";
13
+ import { spawnSync } from "child_process";
13
14
  import { setMaxListeners } from "events";
14
15
  import fs from "fs";
15
16
  import http from "http";
@@ -37,6 +38,7 @@ import {
37
38
  RESTART_PATH,
38
39
  STOP_PATH,
39
40
  TRUST_PATH,
41
+ VERSIONS_PATH,
40
42
  } from "./routes.js";
41
43
  import { Session } from "./session.js";
42
44
  import { getBody, verifyRequest } from "./signed-request.js";
@@ -48,9 +50,37 @@ import type {
48
50
  StartProgram,
49
51
  } from "./types.js";
50
52
 
53
+ const MAX_LISTENER_LIMIT = 1e5;
54
+
51
55
  // eslint-disable-next-line @typescript-eslint/naming-convention
52
56
  const __dirname = dirname(fileURLToPath(import.meta.url));
53
57
 
58
+ const getInstallDir = (): string | null => {
59
+ return (
60
+ process.env.PEERBIT_MODULES_PATH ||
61
+ findPeerbitProgramFolder(__dirname) || // same util used by /install
62
+ null
63
+ );
64
+ };
65
+ // add next to execSync
66
+
67
+ const listVersions = (dir: string): Record<string, string> => {
68
+ const proc = spawnSync("npm", ["ls", "--depth", "0", "--json", "--silent"], {
69
+ cwd: dir,
70
+ encoding: "utf8",
71
+ });
72
+
73
+ // npm may exit 1, but proc.stdout usually contains valid JSON
74
+ if (!proc.stdout) throw new Error(proc.stderr || "npm ls failed");
75
+
76
+ const tree = JSON.parse(proc.stdout);
77
+ const versions: Record<string, string> = {};
78
+ for (const [name, info] of Object.entries(tree.dependencies || {})) {
79
+ versions[name] = (info as any)?.version || "UNKNOWN";
80
+ }
81
+ return versions;
82
+ };
83
+
54
84
  export const stopAndWait = (server: http.Server) => {
55
85
  let closed = false;
56
86
  server.on("close", () => {
@@ -494,9 +524,8 @@ export const startApiServer = async (
494
524
  } else {
495
525
  try {
496
526
  // 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);
527
+ const installDir = getInstallDir();
528
+
500
529
  let permission = "";
501
530
  if (!installDir) {
502
531
  res.writeHead(400);
@@ -563,6 +592,31 @@ export const startApiServer = async (
563
592
  break;
564
593
  }
565
594
  }
595
+ } else if (req.url.startsWith(VERSIONS_PATH)) {
596
+ if (req.method === "GET") {
597
+ try {
598
+ const installDir = getInstallDir();
599
+ if (!installDir) {
600
+ res.writeHead(400);
601
+ res.end("Cannot determine install directory");
602
+ return;
603
+ }
604
+
605
+ const versions = listVersions(installDir);
606
+
607
+ res.setHeader("Content-Type", "application/json");
608
+ res.writeHead(200);
609
+ res.end(JSON.stringify(versions, null, 2));
610
+ } catch (err) {
611
+ console.error("Failed to list versions:", err);
612
+ res.writeHead(500);
613
+ res.end("Error fetching versions");
614
+ }
615
+ } else {
616
+ r404();
617
+ }
618
+
619
+ /* keep the remaining else-if blocks (PEER_ID_PATH, etc.) unchanged */
566
620
  } else if (req.url.startsWith(BOOTSTRAP_PATH)) {
567
621
  switch (req.method) {
568
622
  case "POST":
@@ -692,8 +746,8 @@ export const startApiServer = async (
692
746
  };
693
747
  };
694
748
 
695
- setMaxListeners(Infinity); // TODO make this better (lower and large enough)
696
- process.setMaxListeners(Infinity); // TODO make this better (lower and large enough)
749
+ setMaxListeners(MAX_LISTENER_LIMIT); // TODO make this better (lower and large enough)
750
+ process.setMaxListeners(MAX_LISTENER_LIMIT); // TODO make this better (lower and large enough)
697
751
 
698
752
  const server = http.createServer(endpoints(client));
699
753
  server.listen(port);