@decentnetwork/beagle 0.1.81 → 0.1.82

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/dist/cli.js CHANGED
@@ -12,6 +12,7 @@ import { startBeagleServer } from "./server.js";
12
12
  import { openPeerHost, defaultConfigDir, decentlanCarrierDir, makeDaemonHost } from "./peer-host.js";
13
13
  import { SwitchablePeerHost } from "./lan-handoff.js";
14
14
  import { loadNodeConfig, saveAutoAccept } from "./node-config.js";
15
+ import { setUiPortHint } from "./identity-lock.js";
15
16
  function parseArgs(argv) {
16
17
  const get = (flag) => {
17
18
  const i = argv.indexOf(flag);
@@ -134,6 +135,11 @@ async function main() {
134
135
  onAutoAcceptChange: (enabled) => saveAutoAccept(args.configDir, enabled),
135
136
  force: "embedded",
136
137
  })).host;
138
+ // Publish the port before anything takes the identity lock, so the lock file
139
+ // and the way to reach us are written together. `agentnet restart` reads it:
140
+ // on a machine where beagle holds the identity there is no daemon for it to
141
+ // talk to, and without this the documented upgrade one-liner just failed.
142
+ setUiPortHint(args.port, decentlanCarrierDir(args.configDir));
137
143
  const lanHost = new SwitchablePeerHost(peerHost, {
138
144
  dataDir: decentlanCarrierDir(args.configDir),
139
145
  makeEmbedded: openEmbedded,
@@ -1,4 +1,4 @@
1
- window.__DK_UI_VERSION="0.1.80";
1
+ window.__DK_UI_VERSION="0.1.81";
2
2
  "use strict";
3
3
  (() => {
4
4
  // packages/beagle-ui/dist/beagle-ui.js
@@ -15,4 +15,8 @@ export declare class IdentityLockedError extends Error {
15
15
  * A stale file (holder gone) is taken over silently: that is a crash we already
16
16
  * survived, not a conflict.
17
17
  */
18
+ /** Where a holder publishes the port its local HTTP API is on. */
19
+ export declare function uiPortHintPath(dataDir: string): string;
20
+ /** Called by the server once it knows which port it actually bound. */
21
+ export declare function setUiPortHint(port: number, dataDir?: string): void;
18
22
  export declare function acquireIdentityLock(dataDir: string): () => void;
@@ -13,7 +13,7 @@
13
13
  // exclusion protocol whose other participant we cannot modify (decentlan is
14
14
  // sealed) and must not fork.
15
15
  import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
16
- import { resolve } from "node:path";
16
+ import { resolve, join } from "node:path";
17
17
  /** Same path decentlan uses: `<carrier dataDir>/daemon.pid`. */
18
18
  export function identityLockPath(dataDir) {
19
19
  return resolve(dataDir, "daemon.pid");
@@ -55,6 +55,27 @@ export class IdentityLockedError extends Error {
55
55
  * A stale file (holder gone) is taken over silently: that is a crash we already
56
56
  * survived, not a conflict.
57
57
  */
58
+ /** Where a holder publishes the port its local HTTP API is on. */
59
+ export function uiPortHintPath(dataDir) {
60
+ return join(dataDir, "holder.http-port");
61
+ }
62
+ let uiPortForHint;
63
+ /** Called by the server once it knows which port it actually bound. */
64
+ export function setUiPortHint(port, dataDir) {
65
+ uiPortForHint = port;
66
+ if (dataDir)
67
+ writeUiPortHint(dataDir);
68
+ }
69
+ function writeUiPortHint(dataDir) {
70
+ if (!uiPortForHint)
71
+ return;
72
+ try {
73
+ writeFileSync(uiPortHintPath(dataDir), String(uiPortForHint), "utf-8");
74
+ }
75
+ catch {
76
+ /* best effort — the lock itself is what matters */
77
+ }
78
+ }
58
79
  export function acquireIdentityLock(dataDir) {
59
80
  const holder = identityLockHolder(dataDir);
60
81
  if (holder !== null && holder !== process.pid)
@@ -65,11 +86,22 @@ export function acquireIdentityLock(dataDir) {
65
86
  mkdirSync(dataDir, { recursive: true });
66
87
  const file = identityLockPath(dataDir);
67
88
  writeFileSync(file, String(process.pid), "utf-8");
89
+ // Also leave a way to REACH us. The documented upgrade is
90
+ // `npm i -g @decentnetwork/lan@latest && agentnet restart`, and on a machine
91
+ // where beagle holds the identity there is no daemon for that second half to
92
+ // talk to — it failed, and the person was left holding a new package and a
93
+ // process still running the old one. `agentnet restart` can drive our own
94
+ // /api/update-restart instead, but only if it can find the port.
95
+ writeUiPortHint(dataDir);
68
96
  let released = false;
69
97
  return () => {
70
98
  if (released)
71
99
  return;
72
100
  released = true;
101
+ try {
102
+ unlinkSync(uiPortHintPath(dataDir));
103
+ }
104
+ catch { /* may not exist */ }
73
105
  // Only remove it if it is still OURS. A daemon may have taken over after we
74
106
  // released the peer during the LAN handoff, and deleting its lock would
75
107
  // silently re-open the door this whole module exists to keep shut.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/beagle",
3
- "version": "0.1.81",
3
+ "version": "0.1.82",
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",