@decentnetwork/lan 0.1.42 → 0.1.44

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.
@@ -0,0 +1,35 @@
1
+ # Default dora registries shipped with @decentnetwork/lan.
2
+ #
3
+ # `agentnet init` seeds these into a new client's ~/.agentnet/config.yaml
4
+ # (dora.userids) and sends each a one-time friend-request, so a fresh
5
+ # install auto-joins the shared network with zero extra commands.
6
+ #
7
+ # They are FEDERATED with NON-OVERLAPPING IP segments: the client merges
8
+ # every roster, and any single registry staying up is enough to get an IP
9
+ # allocation — redundancy against any one dora being down.
10
+ #
11
+ # To add/replace a registry, edit this file (data, not code) and republish,
12
+ # or override locally with `agentnet dora enable --userid <id> --address <addr>`.
13
+ #
14
+ # Each entry needs:
15
+ # userid — to talk to the registry over Carrier (goes into dora.userids)
16
+ # address — so `agentnet init` can send the one-time friend-request
17
+ # name — label only (logs / comments)
18
+ # segment — informational: the IP band this registry allocates from
19
+ doras:
20
+ - name: dora-mac
21
+ userid: 98rsHv17h8G6AP9RagyrBiT1kmw4cn8MFPEembS6ZVjv
22
+ address: Jt7w1pKkyLT5GVue9h6ZPkjg1EeuuTbD6JVSLycXLsdm6nvBGSUd
23
+ segment: 10.86.1.10-10.86.63.254
24
+ - name: dora-beagle
25
+ userid: AxKFEZFLDi23EmnJFNP6gjUM4CaNMPfWUvbFR9ixtMBN
26
+ address: NsuN81dZdEoyvwEFgWaHkT8SPJB6UWeRmdYcCGFV5CdbbPXoK2RM
27
+ segment: 10.86.64.10-10.86.127.254
28
+ - name: dora-sh
29
+ userid: GMEMLmCWLMBK6BJiMkbLPNkEjF4S2xRf1SqR9hM8fWV3
30
+ address: ajg1ZMBw86UyujmEJzqKSCbi3wwEtg6tdGFTdESakyqujyxmqJZK
31
+ segment: 10.86.128.10-10.86.191.254
32
+ - name: dora-tokyo
33
+ userid: AB6BZfbrTFWw9eUoVpHdJqhhRnY8bTttp4CHTZ2Xfzxi
34
+ address: MAW2eBqBuQ6SmaXTrnZRRayQjAj3aLatwPy4xmBp7spnJeV569op
35
+ segment: 10.86.192.10-10.86.254.254
@@ -4,7 +4,7 @@
4
4
  import { resolve, dirname } from "path";
5
5
  import { existsSync, mkdirSync, readFileSync } from "fs";
6
6
  import { createConnection } from "net";
7
- import { ConfigLoader, DEFAULT_DORA_USERID, DEFAULT_DORA_ADDRESS } from "../config/loader.js";
7
+ import { ConfigLoader, DEFAULT_DORAS } from "../config/loader.js";
8
8
  import { ipcSocketPath } from "../daemon/ipc.js";
9
9
  import { DaemonServer } from "../daemon/server.js";
10
10
  import { Ipam } from "../ipam/ipam.js";
@@ -129,18 +129,21 @@ export async function cmdInit(args) {
129
129
  console.log(` Config dir: ${dir}`);
130
130
  console.log(` Subnet: ${config.network.subnet}`);
131
131
  console.log(` Interface: ${config.network.interface}`);
132
- // Send the one-time friend-request to the default dora so the daemon
132
+ // Send the one-time friend-request to each default dora so the daemon
133
133
  // can register on first start. Best-effort: a friend-request requires
134
134
  // joinNetwork + an announce round, ~10-30s; we cap the wait and
135
- // surface a hint if it doesn't go through. Skipped when the user
136
- // overrode dora.userids away from the default (i.e. they're pointing
137
- // at a private dora — they'll run `agentnet dora enable` themselves).
138
- const defaultDoraConfigured = (config.dora?.userids ?? []).includes(DEFAULT_DORA_USERID);
139
- if (defaultDoraConfigured) {
140
- console.log(`\nFriending the public dora (${DEFAULT_DORA_USERID.slice(0, 16)}...) so the daemon can join the shared network on first start.`);
135
+ // surface a hint if it doesn't go through. Skipped for any dora the
136
+ // user removed from dora.userids (i.e. they're pointing at a private
137
+ // set — they'll run `agentnet dora enable` themselves). The defaults
138
+ // are federated with non-overlapping IP segments, so friending all of
139
+ // them gives redundancy: any one staying up is enough to get an IP.
140
+ const configuredUserids = new Set(config.dora?.userids ?? []);
141
+ const dorasToFriend = DEFAULT_DORAS.filter((d) => configuredUserids.has(d.userid));
142
+ for (const dora of dorasToFriend) {
143
+ console.log(`\nFriending ${dora.name} (${dora.userid.slice(0, 16)}...) so the daemon can join the shared network on first start.`);
141
144
  try {
142
145
  await cmdFriendRequest({
143
- address: DEFAULT_DORA_ADDRESS,
146
+ address: dora.address,
144
147
  hello: `decentlan init (${nodeName})`,
145
148
  waitMs: 8000,
146
149
  configDir: dir,
@@ -149,8 +152,8 @@ export async function cmdInit(args) {
149
152
  }
150
153
  catch (err) {
151
154
  const msg = err instanceof Error ? err.message : String(err);
152
- console.warn(` Friend-request to the default dora failed: ${msg}`);
153
- console.warn(` Re-run later: agentnet dora enable --address ${DEFAULT_DORA_ADDRESS}`);
155
+ console.warn(` Friend-request to ${dora.name} failed: ${msg}`);
156
+ console.warn(` Re-run later: agentnet dora enable --address ${dora.address}`);
154
157
  }
155
158
  }
156
159
  console.log(`\nNext: sudo agentnet service install # or 'agentnet up --real-tun' to run in foreground`);
@@ -1,17 +1,31 @@
1
1
  import type { DecentAgentNetConfig } from "../types.js";
2
2
  /**
3
- * Public dora server baked into `agentnet init` so an operator can join
3
+ * Public dora servers baked into `agentnet init` so an operator can join
4
4
  * the canonical Decent AgentNet without first hunting down a registry
5
5
  * address. Override by editing `dora.userids` (and re-running
6
6
  * `agentnet dora enable --address <yours>`) — or by running a private
7
7
  * dora and pointing your own peers at it.
8
8
  *
9
- * Both fields are required: the daemon needs `userid` to talk to the
10
- * server over Carrier, and `address` so `agentnet init` can send the
11
- * one-time friend-request that establishes the Carrier session.
9
+ * These are FEDERATED with NON-OVERLAPPING IP segments, so the client
10
+ * merges all their rosters and any one staying up is enough to get an
11
+ * IP allocation redundancy against any single registry being down.
12
+ *
13
+ * The list is loaded from the data file `config/default-doras.yaml` that
14
+ * ships in the npm package (servers are config, not code — edit that file
15
+ * and republish to change the default network). The hardcoded array below
16
+ * is only a last-resort fallback if the data file is missing/unreadable.
17
+ *
18
+ * Each entry needs `userid` (to talk to the server over Carrier) and
19
+ * `address` (so `agentnet init` can send the one-time friend-request).
12
20
  */
13
- export declare const DEFAULT_DORA_USERID = "98rsHv17h8G6AP9RagyrBiT1kmw4cn8MFPEembS6ZVjv";
14
- export declare const DEFAULT_DORA_ADDRESS = "Jt7w1pKkyLT5GVue9h6ZPkjg1EeuuTbD6JVSLycXLsdm6nvBGSUd";
21
+ export interface DefaultDora {
22
+ name: string;
23
+ userid: string;
24
+ address: string;
25
+ }
26
+ export declare const DEFAULT_DORAS: DefaultDora[];
27
+ export declare const DEFAULT_DORA_USERID: string;
28
+ export declare const DEFAULT_DORA_ADDRESS: string;
15
29
  export declare class ConfigLoader {
16
30
  static defaultConfigPath(): string;
17
31
  static defaultConfigDir(): string;
@@ -39,19 +39,32 @@ const DEFAULT_BOOTSTRAP_NODES = [
39
39
  const DEFAULT_EXPRESS_NODES = [
40
40
  { host: "lens.beagle.chat", port: 443, pk: "ECbs4GxwGzxGerNkmqDJFibEmevu8jAXqAZtikccvD95" },
41
41
  ];
42
- /**
43
- * Public dora server baked into `agentnet init` so an operator can join
44
- * the canonical Decent AgentNet without first hunting down a registry
45
- * address. Override by editing `dora.userids` (and re-running
46
- * `agentnet dora enable --address <yours>`) or by running a private
47
- * dora and pointing your own peers at it.
48
- *
49
- * Both fields are required: the daemon needs `userid` to talk to the
50
- * server over Carrier, and `address` so `agentnet init` can send the
51
- * one-time friend-request that establishes the Carrier session.
52
- */
53
- export const DEFAULT_DORA_USERID = "98rsHv17h8G6AP9RagyrBiT1kmw4cn8MFPEembS6ZVjv";
54
- export const DEFAULT_DORA_ADDRESS = "Jt7w1pKkyLT5GVue9h6ZPkjg1EeuuTbD6JVSLycXLsdm6nvBGSUd";
42
+ const DEFAULT_DORAS_FALLBACK = [
43
+ { name: "dora-mac", userid: "98rsHv17h8G6AP9RagyrBiT1kmw4cn8MFPEembS6ZVjv", address: "Jt7w1pKkyLT5GVue9h6ZPkjg1EeuuTbD6JVSLycXLsdm6nvBGSUd" }, // 10.86.1.10–63.254
44
+ { name: "dora-beagle", userid: "AxKFEZFLDi23EmnJFNP6gjUM4CaNMPfWUvbFR9ixtMBN", address: "NsuN81dZdEoyvwEFgWaHkT8SPJB6UWeRmdYcCGFV5CdbbPXoK2RM" }, // 10.86.64.10–127.254
45
+ { name: "dora-sh", userid: "GMEMLmCWLMBK6BJiMkbLPNkEjF4S2xRf1SqR9hM8fWV3", address: "ajg1ZMBw86UyujmEJzqKSCbi3wwEtg6tdGFTdESakyqujyxmqJZK" }, // 10.86.128.10–191.254
46
+ { name: "dora-tokyo", userid: "AB6BZfbrTFWw9eUoVpHdJqhhRnY8bTttp4CHTZ2Xfzxi", address: "MAW2eBqBuQ6SmaXTrnZRRayQjAj3aLatwPy4xmBp7spnJeV569op" }, // 10.86.192.10–254.254
47
+ ];
48
+ function loadDefaultDoras() {
49
+ // dist/config/loader.js package root is two levels up; data file ships
50
+ // at <pkg>/config/default-doras.yaml. Same path holds when running from
51
+ // src/ in dev. Fall back to the embedded list if it can't be read.
52
+ try {
53
+ const file = resolve(dirname(new URL(import.meta.url).pathname), "../../config/default-doras.yaml");
54
+ const parsed = yaml.load(readFileSync(file, "utf-8"));
55
+ const doras = (parsed?.doras ?? []).filter((d) => d && d.userid && d.address);
56
+ if (doras.length > 0)
57
+ return doras;
58
+ }
59
+ catch {
60
+ // missing/unreadable/malformed — use the fallback below
61
+ }
62
+ return DEFAULT_DORAS_FALLBACK;
63
+ }
64
+ export const DEFAULT_DORAS = loadDefaultDoras();
65
+ // Back-compat single-value exports (first/primary dora).
66
+ export const DEFAULT_DORA_USERID = DEFAULT_DORAS[0].userid;
67
+ export const DEFAULT_DORA_ADDRESS = DEFAULT_DORAS[0].address;
55
68
  export class ConfigLoader {
56
69
  static defaultConfigPath() {
57
70
  return DEFAULT_CONFIG_FILE;
@@ -139,7 +152,7 @@ export class ConfigLoader {
139
152
  // replaces the default).
140
153
  dora: {
141
154
  enabled: true,
142
- userids: [DEFAULT_DORA_USERID],
155
+ userids: DEFAULT_DORAS.map((d) => d.userid),
143
156
  refreshIntervalMs: 60_000,
144
157
  // Default: auto-friend every peer in the dora roster. Dora
145
158
  // membership IS the trust statement — joining a dora means
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/lan",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "description": "Private virtual LAN for self-hosted services and AI agents, built on Elastos Carrier. NAT-traversal, name service, ACL, all over a peer-to-peer mesh — no public IP required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,6 +18,7 @@
18
18
  "files": [
19
19
  "dist",
20
20
  "bin",
21
+ "config/default-doras.yaml",
21
22
  "README.md",
22
23
  "LICENSE",
23
24
  "docs/INSTALL.md",