@decentnetwork/beagle 0.1.125 → 0.1.126

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.
@@ -1,4 +1,4 @@
1
- window.__DK_UI_VERSION="0.1.125";
1
+ window.__DK_UI_VERSION="0.1.126";
2
2
  "use strict";
3
3
  (() => {
4
4
  // packages/beagle-ui/dist/beagle-ui.js
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The npm global prefix a file inside a globally installed package lives
3
+ * under — the value `npm i -g --prefix` needs to replace THAT copy.
4
+ *
5
+ * /Users/x/.nvm/versions/node/v24.2.0/lib/node_modules/@decentnetwork/beagle → /Users/x/.nvm/versions/node/v24.2.0
6
+ * /usr/local/lib/node_modules/@decentnetwork/lan/dist/cli/index.js → /usr/local
7
+ * C:\Users\x\AppData\Roaming\npm\node_modules\@decentnetwork\beagle → C:\Users\x\AppData\Roaming\npm
8
+ *
9
+ * Empty when the path is not inside a global node_modules (dev checkout, npx).
10
+ * The FIRST match is the global root; a nested dependency's node_modules
11
+ * sits below it.
12
+ */
13
+ export declare function globalPrefixOf(path: string, s?: string): string;
@@ -0,0 +1,25 @@
1
+ import { sep } from "node:path";
2
+ /**
3
+ * The npm global prefix a file inside a globally installed package lives
4
+ * under — the value `npm i -g --prefix` needs to replace THAT copy.
5
+ *
6
+ * /Users/x/.nvm/versions/node/v24.2.0/lib/node_modules/@decentnetwork/beagle → /Users/x/.nvm/versions/node/v24.2.0
7
+ * /usr/local/lib/node_modules/@decentnetwork/lan/dist/cli/index.js → /usr/local
8
+ * C:\Users\x\AppData\Roaming\npm\node_modules\@decentnetwork\beagle → C:\Users\x\AppData\Roaming\npm
9
+ *
10
+ * Empty when the path is not inside a global node_modules (dev checkout, npx).
11
+ * The FIRST match is the global root; a nested dependency's node_modules
12
+ * sits below it.
13
+ */
14
+ export function globalPrefixOf(path, s = sep) {
15
+ const posix = `${s}lib${s}node_modules${s}`;
16
+ const i = path.indexOf(posix);
17
+ if (i > 0)
18
+ return path.slice(0, i);
19
+ if (s === "\\") {
20
+ const w = path.indexOf(`${s}node_modules${s}`);
21
+ if (w > 0)
22
+ return path.slice(0, w);
23
+ }
24
+ return "";
25
+ }
package/dist/server.js CHANGED
@@ -30,6 +30,7 @@ import { desktopRequestRow } from "./pending-requests.js";
30
30
  import { createDiscoverFetch } from "./discover-cache.js";
31
31
  import { applyWalletBind } from "@decentnetwork/beagle-ui/wallet-proof";
32
32
  import { settleUpload } from "./upload-settle.js";
33
+ import { globalPrefixOf } from "./global-prefix.js";
33
34
  // Directory holding the built desktop UI bundle (index.html, app.js, vendor/).
34
35
  // scripts/build-ui.mjs emits it next to this compiled module at dist/ui/desktop/.
35
36
  const DESKTOP_DIR = join(dirname(fileURLToPath(import.meta.url)), "desktop");
@@ -345,9 +346,15 @@ function verLt(a, b) {
345
346
  * different node than this app (nvm: launchd starts v24.2.0 while the shell's
346
347
  * npm is v24.3.0), and a global install lands in the prefix of whichever npm
347
348
  * ran it — the wrong one leaves the daemon on the old code with no error. */
348
- async function npmGlobalInstall(pkg, nodePath) {
349
+ /** `targetPrefix` is the global prefix the RUNNING copy lives in. Pinning node
350
+ * is not enough: an nvm npm-cli.js runs under whatever node its caller picks,
351
+ * and npm on PATH (pm2's PATH on mac-dev: v24.3.0) installs into its own
352
+ * prefix — beagle 0.1.124 ran from v24.2.0 while every click of Update put
353
+ * the new version into v24.3.0, reported success, and restarted onto the old
354
+ * code. An explicit --prefix puts the files where the restart will load them. */
355
+ async function npmGlobalInstall(pkg, nodePath, targetPrefix) {
349
356
  const { spawn } = await import("node:child_process");
350
- const args = ["i", "-g", `${pkg}@latest`];
357
+ const args = ["i", "-g", `${pkg}@latest`, ...(targetPrefix ? ["--prefix", targetPrefix] : [])];
351
358
  const cliFor = (node) => join(dirname(node), "..", "lib", "node_modules", "npm", "bin", "npm-cli.js");
352
359
  const npmCli = cliFor(process.execPath);
353
360
  const pinned = nodePath && existsSync(nodePath) && existsSync(cliFor(nodePath)) ? cliFor(nodePath) : "";
@@ -386,10 +393,10 @@ async function npmGlobalInstall(pkg, nodePath) {
386
393
  const npmCmd = a.cmd === "npm" ? resolveNpmOnPath(npmCli) : [a.cmd, a.args[0]];
387
394
  if (npmCmd.length) {
388
395
  const [exe, ...pre0] = npmCmd;
389
- const pre = await runOnce(exe, [...pre0, "prefix", "-g"], 15_000);
390
- const prefix = pre.code === 0 ? pre.out.trim().split("\n").pop()?.trim() : "";
396
+ const pre = targetPrefix ? undefined : await runOnce(exe, [...pre0, "prefix", "-g"], 15_000);
397
+ const prefix = targetPrefix || (pre?.code === 0 ? pre.out.trim().split("\n").pop()?.trim() : "");
391
398
  if (prefix) {
392
- const s = await runOnce("sudo", ["-n", "-H", ...npmCmd, ...args, "--prefix", prefix]);
399
+ const s = await runOnce("sudo", ["-n", "-H", ...npmCmd, ...args, ...(targetPrefix ? [] : ["--prefix", prefix])]);
393
400
  if (s.code === 0)
394
401
  return { ok: true, log: s.out.slice(-2000) };
395
402
  return { ok: false, error: `sudo -n npm exited ${s.code}`, log: s.out.slice(-2000) };
@@ -555,13 +562,31 @@ async function npmQuery(args) {
555
562
  /** The node binary the running daemon was started with, from its pid's
556
563
  * command line (`/…/bin/node /…/bin/agentnet up …`). Empty when unknown. */
557
564
  async function daemonNodePath(dataDir) {
565
+ const first = (await daemonCommand(dataDir))[0] ?? "";
566
+ return /(^|\/)node(\.exe)?$/.test(first) && existsSync(first) ? first : "";
567
+ }
568
+ /** The global prefix the running daemon's lan was loaded from: its script
569
+ * (`/…/bin/agentnet`, a symlink into `<prefix>/lib/node_modules/…`) resolved.
570
+ * Empty when unknown — the install then falls back to npm's own prefix. */
571
+ async function daemonLanPrefix(dataDir) {
572
+ const script = (await daemonCommand(dataDir))[1] ?? "";
573
+ if (!script || !existsSync(script))
574
+ return "";
575
+ try {
576
+ return globalPrefixOf(realpathSync(script));
577
+ }
578
+ catch {
579
+ return "";
580
+ }
581
+ }
582
+ /** The daemon's command line split on whitespace, from its pidfile's pid. */
583
+ async function daemonCommand(dataDir) {
558
584
  const pid = dataDir ? readDaemonPid(dataDir) : "";
559
585
  if (!/^\d+$/.test(pid) || process.platform === "win32")
560
- return "";
586
+ return [];
561
587
  const { execFile } = await import("node:child_process");
562
588
  const cmd = await new Promise((res) => execFile("ps", ["-o", "command=", "-p", pid], { timeout: 5000 }, (err, out) => res(err ? "" : String(out).trim())));
563
- const first = cmd.split(/\s+/)[0] ?? "";
564
- return /(^|\/)node(\.exe)?$/.test(first) && existsSync(first) ? first : "";
589
+ return cmd ? cmd.split(/\s+/) : [];
565
590
  }
566
591
  async function agentnetRestart(dataDir) {
567
592
  const pidBefore = dataDir ? readDaemonPid(dataDir) : "";
@@ -1895,7 +1920,7 @@ export function startBeagleServer(opts) {
1895
1920
  // lan (the agentnet daemon) updates independently of beagle's own
1896
1921
  // install mode: global reinstall, then ask the daemon to re-exec.
1897
1922
  if (body.pkg === "lan") {
1898
- const inst = await npmGlobalInstall("@decentnetwork/lan", await daemonNodePath(opts.lanHost?.dataDir));
1923
+ const inst = await npmGlobalInstall("@decentnetwork/lan", await daemonNodePath(opts.lanHost?.dataDir), await daemonLanPrefix(opts.lanHost?.dataDir));
1899
1924
  if (!inst.ok) {
1900
1925
  sendJson(res, 502, inst);
1901
1926
  return;
@@ -1919,7 +1944,8 @@ export function startBeagleServer(opts) {
1919
1944
  sendJson(res, 200, { ok: true, npx: true });
1920
1945
  return;
1921
1946
  }
1922
- const r = await npmGlobalInstall(BEAGLE_PKG);
1947
+ // Into the prefix THIS copy runs from, with this node's npm — see npmGlobalInstall.
1948
+ const r = await npmGlobalInstall(BEAGLE_PKG, process.execPath, globalPrefixOf(BEAGLE_ROOT) || undefined);
1923
1949
  updateCache = null; // next check reflects the new install
1924
1950
  sendJson(res, r.ok ? 200 : 502, r);
1925
1951
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/beagle",
3
- "version": "0.1.125",
3
+ "version": "0.1.126",
4
4
  "description": "Beagle — P2P chat, file transfer and calls for regular users, on the Decent Network. No admin privilege required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",