@decentnetwork/lan 0.1.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.
- package/LICENSE +31 -0
- package/README.md +296 -0
- package/bin/tun-helper-darwin-amd64 +0 -0
- package/bin/tun-helper-darwin-arm64 +0 -0
- package/bin/tun-helper-linux-amd64 +0 -0
- package/bin/tun-helper-linux-arm64 +0 -0
- package/dist/acl/acl-engine.d.ts +43 -0
- package/dist/acl/acl-engine.js +189 -0
- package/dist/acl/audit.d.ts +70 -0
- package/dist/acl/audit.js +144 -0
- package/dist/acl/index.d.ts +4 -0
- package/dist/acl/index.js +3 -0
- package/dist/acl/policy.d.ts +31 -0
- package/dist/acl/policy.js +102 -0
- package/dist/acl/types.d.ts +18 -0
- package/dist/acl/types.js +4 -0
- package/dist/carrier/frame.d.ts +18 -0
- package/dist/carrier/frame.js +66 -0
- package/dist/carrier/index.d.ts +5 -0
- package/dist/carrier/index.js +4 -0
- package/dist/carrier/packet-session.d.ts +32 -0
- package/dist/carrier/packet-session.js +151 -0
- package/dist/carrier/peer-manager.d.ts +113 -0
- package/dist/carrier/peer-manager.js +392 -0
- package/dist/carrier/types.d.ts +10 -0
- package/dist/carrier/types.js +11 -0
- package/dist/cli/commands.d.ts +223 -0
- package/dist/cli/commands.js +932 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.js +196 -0
- package/dist/config/loader.d.ts +10 -0
- package/dist/config/loader.js +152 -0
- package/dist/daemon/index.d.ts +1 -0
- package/dist/daemon/index.js +1 -0
- package/dist/daemon/ipc.d.ts +60 -0
- package/dist/daemon/ipc.js +144 -0
- package/dist/daemon/server.d.ts +63 -0
- package/dist/daemon/server.js +510 -0
- package/dist/dns/index.d.ts +1 -0
- package/dist/dns/index.js +1 -0
- package/dist/dns/resolver.d.ts +44 -0
- package/dist/dns/resolver.js +82 -0
- package/dist/dns/server.d.ts +70 -0
- package/dist/dns/server.js +393 -0
- package/dist/dora/dora-integration.d.ts +90 -0
- package/dist/dora/dora-integration.js +325 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +15 -0
- package/dist/ipam/index.d.ts +1 -0
- package/dist/ipam/index.js +1 -0
- package/dist/ipam/ipam.d.ts +99 -0
- package/dist/ipam/ipam.js +254 -0
- package/dist/proxy/connect-proxy.d.ts +78 -0
- package/dist/proxy/connect-proxy.js +204 -0
- package/dist/router/index.d.ts +5 -0
- package/dist/router/index.js +4 -0
- package/dist/router/ip-parser.d.ts +36 -0
- package/dist/router/ip-parser.js +127 -0
- package/dist/router/packet-router.d.ts +49 -0
- package/dist/router/packet-router.js +251 -0
- package/dist/router/session-manager.d.ts +50 -0
- package/dist/router/session-manager.js +138 -0
- package/dist/router/types.d.ts +21 -0
- package/dist/router/types.js +6 -0
- package/dist/tun/index.d.ts +3 -0
- package/dist/tun/index.js +2 -0
- package/dist/tun/route-manager.d.ts +59 -0
- package/dist/tun/route-manager.js +353 -0
- package/dist/tun/tun-device.d.ts +45 -0
- package/dist/tun/tun-device.js +265 -0
- package/dist/tun/types.d.ts +28 -0
- package/dist/tun/types.js +4 -0
- package/dist/types.d.ts +176 -0
- package/dist/types.js +4 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.js +43 -0
- package/docs/CONFIGURATION.md +197 -0
- package/docs/INSTALL.md +145 -0
- package/package.json +93 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUN device abstraction for reading/writing IP packets
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* - mockMode (default): in-memory packet queue, used for tests
|
|
6
|
+
* - real mode: spawns a Go helper subprocess (bin/tun-helper-{platform})
|
|
7
|
+
* that owns the TUN device and pipes packets via stdin/stdout with
|
|
8
|
+
* 4-byte big-endian length-prefix framing.
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from "events";
|
|
11
|
+
import { spawn } from "child_process";
|
|
12
|
+
import { resolve, dirname } from "path";
|
|
13
|
+
import { existsSync } from "fs";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
import { Logger } from "../utils/logger.js";
|
|
16
|
+
export class TunDevice extends EventEmitter {
|
|
17
|
+
config;
|
|
18
|
+
logger;
|
|
19
|
+
mockMode;
|
|
20
|
+
helperPath;
|
|
21
|
+
isOpen = false;
|
|
22
|
+
packetQueue = [];
|
|
23
|
+
readLoopActive = false;
|
|
24
|
+
// Real-mode state
|
|
25
|
+
helper;
|
|
26
|
+
stdinBuffer = Buffer.alloc(0);
|
|
27
|
+
actualDeviceName;
|
|
28
|
+
constructor(opts) {
|
|
29
|
+
super();
|
|
30
|
+
this.config = opts.config;
|
|
31
|
+
this.mockMode = opts.mockMode ?? true;
|
|
32
|
+
this.helperPath = opts.helperPath;
|
|
33
|
+
this.logger = new Logger({ prefix: `TunDevice[${opts.config.name}]` });
|
|
34
|
+
}
|
|
35
|
+
async open() {
|
|
36
|
+
if (this.isOpen) {
|
|
37
|
+
throw new Error("TUN device already open");
|
|
38
|
+
}
|
|
39
|
+
this.logger.info("Opening TUN device");
|
|
40
|
+
if (this.mockMode) {
|
|
41
|
+
this.logger.info("Using mock TUN mode (no real /dev/net/tun)");
|
|
42
|
+
this.isOpen = true;
|
|
43
|
+
this.emit("ready");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
await this.openReal();
|
|
47
|
+
}
|
|
48
|
+
async close() {
|
|
49
|
+
if (!this.isOpen) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.logger.info("Closing TUN device");
|
|
53
|
+
this.readLoopActive = false;
|
|
54
|
+
this.isOpen = false;
|
|
55
|
+
this.packetQueue = [];
|
|
56
|
+
if (this.helper) {
|
|
57
|
+
this.helper.kill("SIGTERM");
|
|
58
|
+
this.helper = undefined;
|
|
59
|
+
}
|
|
60
|
+
this.emit("closed");
|
|
61
|
+
}
|
|
62
|
+
async write(packet) {
|
|
63
|
+
if (!this.isOpen) {
|
|
64
|
+
throw new Error("TUN device not open");
|
|
65
|
+
}
|
|
66
|
+
if (this.mockMode) {
|
|
67
|
+
// Mock mode: emit packet event after write (for test routing)
|
|
68
|
+
setImmediate(() => {
|
|
69
|
+
this.emit("packet", packet);
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Real mode: framed write to helper stdin
|
|
74
|
+
if (!this.helper || !this.helper.stdin) {
|
|
75
|
+
throw new Error("Helper process not available");
|
|
76
|
+
}
|
|
77
|
+
const lenBuf = Buffer.alloc(4);
|
|
78
|
+
lenBuf.writeUInt32BE(packet.length, 0);
|
|
79
|
+
const ok = this.helper.stdin.write(lenBuf) &&
|
|
80
|
+
this.helper.stdin.write(Buffer.from(packet));
|
|
81
|
+
if (!ok) {
|
|
82
|
+
// Wait for drain to avoid backpressure issues
|
|
83
|
+
await new Promise((resolveCb) => {
|
|
84
|
+
this.helper.stdin.once("drain", resolveCb);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async read(timeoutMs) {
|
|
89
|
+
if (!this.isOpen) {
|
|
90
|
+
throw new Error("TUN device not open");
|
|
91
|
+
}
|
|
92
|
+
return new Promise((resolveCb, rejectCb) => {
|
|
93
|
+
let timeoutHandle = null;
|
|
94
|
+
if (this.packetQueue.length > 0) {
|
|
95
|
+
const packet = this.packetQueue.shift();
|
|
96
|
+
resolveCb(packet);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const onPacket = (packet) => {
|
|
100
|
+
if (timeoutHandle)
|
|
101
|
+
clearTimeout(timeoutHandle);
|
|
102
|
+
this.removeListener("packet", onPacket);
|
|
103
|
+
resolveCb(packet);
|
|
104
|
+
};
|
|
105
|
+
this.once("packet", onPacket);
|
|
106
|
+
if (timeoutMs) {
|
|
107
|
+
timeoutHandle = setTimeout(() => {
|
|
108
|
+
this.removeListener("packet", onPacket);
|
|
109
|
+
rejectCb(new Error(`TUN read timeout after ${timeoutMs}ms`));
|
|
110
|
+
}, timeoutMs);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
queuePacket(packet) {
|
|
115
|
+
this.packetQueue.push(packet);
|
|
116
|
+
this.emit("packet", packet);
|
|
117
|
+
}
|
|
118
|
+
async startReadLoop() {
|
|
119
|
+
if (this.readLoopActive)
|
|
120
|
+
return;
|
|
121
|
+
this.readLoopActive = true;
|
|
122
|
+
this.logger.info("Starting packet read loop");
|
|
123
|
+
// Real-mode read loop is event-driven via helper stdout (handled in openReal)
|
|
124
|
+
// Mock-mode packets come from queuePacket() / write()
|
|
125
|
+
}
|
|
126
|
+
async stopReadLoop() {
|
|
127
|
+
this.readLoopActive = false;
|
|
128
|
+
this.logger.info("Stopped packet read loop");
|
|
129
|
+
}
|
|
130
|
+
getConfig() {
|
|
131
|
+
return this.config;
|
|
132
|
+
}
|
|
133
|
+
isActive() {
|
|
134
|
+
return this.isOpen;
|
|
135
|
+
}
|
|
136
|
+
getInterface() {
|
|
137
|
+
return this.actualDeviceName || this.config.name;
|
|
138
|
+
}
|
|
139
|
+
getVirtualIp() {
|
|
140
|
+
return this.config.ip;
|
|
141
|
+
}
|
|
142
|
+
getSubnet() {
|
|
143
|
+
return this.config.subnet;
|
|
144
|
+
}
|
|
145
|
+
// ============================================================
|
|
146
|
+
// Real-mode internals
|
|
147
|
+
// ============================================================
|
|
148
|
+
async openReal() {
|
|
149
|
+
const helperPath = this.helperPath || this.findHelperBinary();
|
|
150
|
+
if (!helperPath || !existsSync(helperPath)) {
|
|
151
|
+
throw new Error(`TUN helper binary not found: ${helperPath || "(none)"}\n` +
|
|
152
|
+
`Build it with: cd helper/tun-helper && go build -o bin/tun-helper-linux-amd64 .`);
|
|
153
|
+
}
|
|
154
|
+
this.logger.info(`Spawning TUN helper: ${helperPath}`);
|
|
155
|
+
this.helper = spawn(helperPath, ["--name", this.config.name], {
|
|
156
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
157
|
+
});
|
|
158
|
+
// Wait for "READY <devname>" line on stderr
|
|
159
|
+
const ready = await this.waitForReady();
|
|
160
|
+
this.actualDeviceName = ready;
|
|
161
|
+
this.logger.info(`TUN helper ready: ${ready}`);
|
|
162
|
+
// Set up packet read loop on stdout
|
|
163
|
+
this.helper.stdout.on("data", (chunk) => {
|
|
164
|
+
this.handleStdoutData(chunk);
|
|
165
|
+
});
|
|
166
|
+
this.helper.stderr.on("data", (chunk) => {
|
|
167
|
+
const text = chunk.toString().trim();
|
|
168
|
+
if (text && !text.startsWith("READY ")) {
|
|
169
|
+
this.logger.warn(`helper stderr: ${text}`);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
this.helper.on("exit", (code, signal) => {
|
|
173
|
+
this.logger.warn(`TUN helper exited code=${code} signal=${signal}`);
|
|
174
|
+
this.helper = undefined;
|
|
175
|
+
if (this.isOpen) {
|
|
176
|
+
this.isOpen = false;
|
|
177
|
+
this.emit("closed");
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
this.isOpen = true;
|
|
181
|
+
this.emit("ready");
|
|
182
|
+
}
|
|
183
|
+
async waitForReady() {
|
|
184
|
+
return new Promise((resolveCb, rejectCb) => {
|
|
185
|
+
let buf = "";
|
|
186
|
+
const timeout = setTimeout(() => {
|
|
187
|
+
rejectCb(new Error("TUN helper did not report READY within 5s"));
|
|
188
|
+
}, 5000);
|
|
189
|
+
const onStderr = (chunk) => {
|
|
190
|
+
buf += chunk.toString();
|
|
191
|
+
const lines = buf.split("\n");
|
|
192
|
+
for (const line of lines) {
|
|
193
|
+
const match = line.match(/^READY (\S+)/);
|
|
194
|
+
if (match) {
|
|
195
|
+
clearTimeout(timeout);
|
|
196
|
+
this.helper.stderr.removeListener("data", onStderr);
|
|
197
|
+
resolveCb(match[1]);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
this.helper.stderr.on("data", onStderr);
|
|
203
|
+
this.helper.on("exit", (code) => {
|
|
204
|
+
clearTimeout(timeout);
|
|
205
|
+
rejectCb(new Error(`TUN helper exited before ready (code=${code})`));
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
handleStdoutData(chunk) {
|
|
210
|
+
this.stdinBuffer = Buffer.concat([this.stdinBuffer, chunk]);
|
|
211
|
+
while (this.stdinBuffer.length >= 4) {
|
|
212
|
+
const length = this.stdinBuffer.readUInt32BE(0);
|
|
213
|
+
if (length === 0 || length > 65536) {
|
|
214
|
+
this.logger.error(`Invalid packet length from helper: ${length}`);
|
|
215
|
+
this.stdinBuffer = Buffer.alloc(0);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (this.stdinBuffer.length < 4 + length) {
|
|
219
|
+
// Wait for more data
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const packet = this.stdinBuffer.subarray(4, 4 + length);
|
|
223
|
+
this.stdinBuffer = this.stdinBuffer.subarray(4 + length);
|
|
224
|
+
// Emit as fresh Uint8Array (avoid tying to internal buffer)
|
|
225
|
+
this.emit("packet", new Uint8Array(packet));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
findHelperBinary() {
|
|
229
|
+
// Resolve relative to the running script
|
|
230
|
+
const scriptPath = fileURLToPath(import.meta.url);
|
|
231
|
+
const moduleDir = dirname(scriptPath);
|
|
232
|
+
// Walk up to find project root, then bin/
|
|
233
|
+
const candidates = [
|
|
234
|
+
resolve(moduleDir, "../../bin"),
|
|
235
|
+
resolve(moduleDir, "../../../bin"),
|
|
236
|
+
resolve(process.cwd(), "bin"),
|
|
237
|
+
];
|
|
238
|
+
const platform = process.platform;
|
|
239
|
+
const arch = process.arch;
|
|
240
|
+
let suffix;
|
|
241
|
+
if (platform === "linux" && arch === "x64") {
|
|
242
|
+
suffix = "linux-amd64";
|
|
243
|
+
}
|
|
244
|
+
else if (platform === "darwin" && arch === "arm64") {
|
|
245
|
+
suffix = "darwin-arm64";
|
|
246
|
+
}
|
|
247
|
+
else if (platform === "darwin" && arch === "x64") {
|
|
248
|
+
suffix = "darwin-amd64";
|
|
249
|
+
}
|
|
250
|
+
else if (platform === "linux" && arch === "arm64") {
|
|
251
|
+
suffix = "linux-arm64";
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
this.logger.warn(`Unsupported platform: ${platform}/${arch}`);
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
for (const dir of candidates) {
|
|
258
|
+
const path = resolve(dir, `tun-helper-${suffix}`);
|
|
259
|
+
if (existsSync(path)) {
|
|
260
|
+
return path;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUN interface types
|
|
3
|
+
*/
|
|
4
|
+
export interface TunDeviceConfig {
|
|
5
|
+
name: string;
|
|
6
|
+
ip: string;
|
|
7
|
+
subnet: string;
|
|
8
|
+
mtu?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface RouteConfig {
|
|
11
|
+
interface: string;
|
|
12
|
+
subnet: string;
|
|
13
|
+
ip: string;
|
|
14
|
+
}
|
|
15
|
+
export interface IpHeader {
|
|
16
|
+
version: number;
|
|
17
|
+
headerLength: number;
|
|
18
|
+
dscp: number;
|
|
19
|
+
totalLength: number;
|
|
20
|
+
identification: number;
|
|
21
|
+
flags: number;
|
|
22
|
+
fragmentOffset: number;
|
|
23
|
+
ttl: number;
|
|
24
|
+
protocol: number;
|
|
25
|
+
checksum: number;
|
|
26
|
+
srcIp: string;
|
|
27
|
+
dstIp: string;
|
|
28
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for Decent AgentNet
|
|
3
|
+
*/
|
|
4
|
+
export interface PeerIdentity {
|
|
5
|
+
pubkey: string;
|
|
6
|
+
address: string;
|
|
7
|
+
userid: string;
|
|
8
|
+
}
|
|
9
|
+
export interface RemotePeer {
|
|
10
|
+
pubkey: string;
|
|
11
|
+
status: "online" | "offline" | "connecting";
|
|
12
|
+
name?: string;
|
|
13
|
+
carrierId?: string;
|
|
14
|
+
virtualIp?: string;
|
|
15
|
+
lastSeen?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface FriendConnectionEvent {
|
|
18
|
+
pubkey: string;
|
|
19
|
+
status: "connected" | "disconnected";
|
|
20
|
+
timestamp?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface Service {
|
|
23
|
+
name: string;
|
|
24
|
+
proto: "tcp" | "udp";
|
|
25
|
+
port: number;
|
|
26
|
+
}
|
|
27
|
+
export interface IpamRecord {
|
|
28
|
+
name: string;
|
|
29
|
+
carrierId: string;
|
|
30
|
+
virtualIp: string;
|
|
31
|
+
services: Service[];
|
|
32
|
+
expiresAt?: number;
|
|
33
|
+
}
|
|
34
|
+
export interface IpamConfig {
|
|
35
|
+
namespace: string;
|
|
36
|
+
peers: IpamRecord[];
|
|
37
|
+
}
|
|
38
|
+
export interface TunConfig {
|
|
39
|
+
name: string;
|
|
40
|
+
ip: string;
|
|
41
|
+
subnet: string;
|
|
42
|
+
}
|
|
43
|
+
export interface RouteConfig {
|
|
44
|
+
interface: string;
|
|
45
|
+
subnet: string;
|
|
46
|
+
ip: string;
|
|
47
|
+
}
|
|
48
|
+
export type ProtocolType = "tcp" | "udp" | "any";
|
|
49
|
+
export interface AclRule {
|
|
50
|
+
peer: string;
|
|
51
|
+
direction?: "inbound" | "outbound" | "both";
|
|
52
|
+
allow?: AclPermission[];
|
|
53
|
+
deny?: AclPermission[];
|
|
54
|
+
expiresAt?: number;
|
|
55
|
+
audit?: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface AclPermission {
|
|
58
|
+
host?: string;
|
|
59
|
+
proto: ProtocolType;
|
|
60
|
+
port?: number;
|
|
61
|
+
purpose?: string;
|
|
62
|
+
}
|
|
63
|
+
export interface PolicyConfig {
|
|
64
|
+
defaultAction: "allow" | "deny";
|
|
65
|
+
rules: AclRule[];
|
|
66
|
+
}
|
|
67
|
+
export interface AuditEntry {
|
|
68
|
+
timestamp: number;
|
|
69
|
+
type: "access" | "grant" | "revoke" | "connect" | "disconnect" | "proxy_open" | "proxy_close";
|
|
70
|
+
srcPubkey?: string;
|
|
71
|
+
srcName?: string;
|
|
72
|
+
dstIp?: string;
|
|
73
|
+
dstPort?: number;
|
|
74
|
+
proto?: ProtocolType;
|
|
75
|
+
allowed?: boolean;
|
|
76
|
+
reason?: string;
|
|
77
|
+
proxyTarget?: string;
|
|
78
|
+
bytesTransferred?: number;
|
|
79
|
+
}
|
|
80
|
+
export interface PacketFrame {
|
|
81
|
+
sessionId: number;
|
|
82
|
+
opcode: number;
|
|
83
|
+
payload: Uint8Array;
|
|
84
|
+
}
|
|
85
|
+
export interface FrameEncodingOptions {
|
|
86
|
+
sessionId: number;
|
|
87
|
+
opcode?: number;
|
|
88
|
+
magic?: number;
|
|
89
|
+
}
|
|
90
|
+
export interface NodeConfig {
|
|
91
|
+
name: string;
|
|
92
|
+
namespace: string;
|
|
93
|
+
}
|
|
94
|
+
export interface BootstrapNode {
|
|
95
|
+
host: string;
|
|
96
|
+
port: number;
|
|
97
|
+
pk: string;
|
|
98
|
+
isTcp?: boolean;
|
|
99
|
+
}
|
|
100
|
+
export interface CarrierConfig {
|
|
101
|
+
dataDir: string;
|
|
102
|
+
bootstrapNodes: BootstrapNode[];
|
|
103
|
+
expressNodes?: BootstrapNode[];
|
|
104
|
+
}
|
|
105
|
+
export interface NetworkConfig {
|
|
106
|
+
interface: string;
|
|
107
|
+
ip: string;
|
|
108
|
+
subnet: string;
|
|
109
|
+
dnsDomain: string;
|
|
110
|
+
dnsPort: number;
|
|
111
|
+
}
|
|
112
|
+
export interface PathsConfig {
|
|
113
|
+
ipamFile: string;
|
|
114
|
+
policyFile: string;
|
|
115
|
+
auditLog: string;
|
|
116
|
+
}
|
|
117
|
+
export interface ProxyConfig {
|
|
118
|
+
enabled: boolean;
|
|
119
|
+
port: number;
|
|
120
|
+
allowHosts?: string[];
|
|
121
|
+
allowConnectPorts?: number[];
|
|
122
|
+
}
|
|
123
|
+
export interface FriendsConfig {
|
|
124
|
+
/** When true (default), the running daemon auto-accepts incoming
|
|
125
|
+
* friend requests so adding a new peer never requires stopping the
|
|
126
|
+
* daemon. Operators who want manual control set this to false; the
|
|
127
|
+
* daemon will log incoming requests and a future `agentnet friend
|
|
128
|
+
* accept` CLI will let them act on the running daemon. */
|
|
129
|
+
autoAccept?: boolean;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Optional integration with a dora (DHCP-style) registry node. When
|
|
133
|
+
* enabled, the daemon registers its own (userid, name, ip) on startup
|
|
134
|
+
* and queries the full roster — replacing the manual ipam.yaml dance.
|
|
135
|
+
* The dora node is just a Carrier peer; the operator friends it once
|
|
136
|
+
* out-of-band and puts its userid here.
|
|
137
|
+
*/
|
|
138
|
+
export interface DoraConfig {
|
|
139
|
+
enabled?: boolean;
|
|
140
|
+
/** Carrier userids of dora servers to try, in order. First responder
|
|
141
|
+
* wins. Empty / unset = manual ipam.yaml mode. */
|
|
142
|
+
userids?: string[];
|
|
143
|
+
/** How often to re-fetch the full roster from dora. Default 60_000ms. */
|
|
144
|
+
refreshIntervalMs?: number;
|
|
145
|
+
}
|
|
146
|
+
export interface DecentAgentNetConfig {
|
|
147
|
+
node: NodeConfig;
|
|
148
|
+
carrier: CarrierConfig;
|
|
149
|
+
network: NetworkConfig;
|
|
150
|
+
paths: PathsConfig;
|
|
151
|
+
proxy?: ProxyConfig;
|
|
152
|
+
friends?: FriendsConfig;
|
|
153
|
+
dora?: DoraConfig;
|
|
154
|
+
}
|
|
155
|
+
export interface PacketSessionInfo {
|
|
156
|
+
peerId: string;
|
|
157
|
+
sessionId: number;
|
|
158
|
+
createdAt: number;
|
|
159
|
+
lastActivity: number;
|
|
160
|
+
isActive: boolean;
|
|
161
|
+
}
|
|
162
|
+
export interface DaemonStatus {
|
|
163
|
+
isRunning: boolean;
|
|
164
|
+
uptime: number;
|
|
165
|
+
version: string;
|
|
166
|
+
identity?: PeerIdentity;
|
|
167
|
+
tunInterface?: TunConfig;
|
|
168
|
+
peers: RemotePeer[];
|
|
169
|
+
activeSessions: number;
|
|
170
|
+
}
|
|
171
|
+
export interface CliContext {
|
|
172
|
+
configFile: string;
|
|
173
|
+
config?: DecentAgentNetConfig;
|
|
174
|
+
verbose?: boolean;
|
|
175
|
+
debug?: boolean;
|
|
176
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple logging utility for Decent AgentNet
|
|
3
|
+
*/
|
|
4
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
5
|
+
export interface LoggerOptions {
|
|
6
|
+
level?: LogLevel;
|
|
7
|
+
prefix?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class Logger {
|
|
10
|
+
private levelStr;
|
|
11
|
+
private level;
|
|
12
|
+
private prefix;
|
|
13
|
+
constructor(options?: LoggerOptions);
|
|
14
|
+
debug(message: string, ...args: unknown[]): void;
|
|
15
|
+
info(message: string, ...args: unknown[]): void;
|
|
16
|
+
warn(message: string, ...args: unknown[]): void;
|
|
17
|
+
error(message: string, ...args: unknown[]): void;
|
|
18
|
+
child(prefix: string): Logger;
|
|
19
|
+
}
|
|
20
|
+
export declare const globalLogger: Logger;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple logging utility for Decent AgentNet
|
|
3
|
+
*/
|
|
4
|
+
const LOG_LEVELS = {
|
|
5
|
+
debug: 0,
|
|
6
|
+
info: 1,
|
|
7
|
+
warn: 2,
|
|
8
|
+
error: 3,
|
|
9
|
+
};
|
|
10
|
+
export class Logger {
|
|
11
|
+
levelStr;
|
|
12
|
+
level;
|
|
13
|
+
prefix;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.levelStr = (options?.level || process.env.AGENTNET_LOG_LEVEL || "info");
|
|
16
|
+
this.level = LOG_LEVELS[this.levelStr] ?? LOG_LEVELS.info;
|
|
17
|
+
this.prefix = options?.prefix ? `[${options.prefix}] ` : "";
|
|
18
|
+
}
|
|
19
|
+
debug(message, ...args) {
|
|
20
|
+
if (this.level <= LOG_LEVELS.debug) {
|
|
21
|
+
console.debug(`${this.prefix}DEBUG: ${message}`, ...args);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
info(message, ...args) {
|
|
25
|
+
if (this.level <= LOG_LEVELS.info) {
|
|
26
|
+
console.log(`${this.prefix}INFO: ${message}`, ...args);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
warn(message, ...args) {
|
|
30
|
+
if (this.level <= LOG_LEVELS.warn) {
|
|
31
|
+
console.warn(`${this.prefix}WARN: ${message}`, ...args);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
error(message, ...args) {
|
|
35
|
+
if (this.level <= LOG_LEVELS.error) {
|
|
36
|
+
console.error(`${this.prefix}ERROR: ${message}`, ...args);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
child(prefix) {
|
|
40
|
+
return new Logger({ level: this.levelStr, prefix });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export const globalLogger = new Logger();
|