@caoruhua/open-claude-remote 1.0.0 → 1.0.5

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.
Files changed (28) hide show
  1. package/README.md +8 -8
  2. package/dist/backend/src/api/file-routes.d.ts.map +1 -1
  3. package/dist/backend/src/api/file-routes.js +36 -6
  4. package/dist/backend/src/api/file-routes.js.map +1 -1
  5. package/dist/backend/src/index.d.ts.map +1 -1
  6. package/dist/backend/src/index.js +23 -5
  7. package/dist/backend/src/index.js.map +1 -1
  8. package/dist/backend/src/instance/instance-session.d.ts +7 -0
  9. package/dist/backend/src/instance/instance-session.d.ts.map +1 -1
  10. package/dist/backend/src/instance/instance-session.js +53 -13
  11. package/dist/backend/src/instance/instance-session.js.map +1 -1
  12. package/dist/backend/src/skills/skill-command-merger.d.ts +5 -6
  13. package/dist/backend/src/skills/skill-command-merger.d.ts.map +1 -1
  14. package/dist/backend/src/skills/skill-command-merger.js +41 -53
  15. package/dist/backend/src/skills/skill-command-merger.js.map +1 -1
  16. package/dist/backend/src/utils/ip-monitor.d.ts +53 -8
  17. package/dist/backend/src/utils/ip-monitor.d.ts.map +1 -1
  18. package/dist/backend/src/utils/ip-monitor.js +137 -25
  19. package/dist/backend/src/utils/ip-monitor.js.map +1 -1
  20. package/dist/backend/src/utils/network.d.ts +25 -0
  21. package/dist/backend/src/utils/network.d.ts.map +1 -1
  22. package/dist/backend/src/utils/network.js +59 -0
  23. package/dist/backend/src/utils/network.js.map +1 -1
  24. package/dist/shared/constants.d.ts +1 -1
  25. package/dist/shared/constants.js +1 -1
  26. package/frontend-dist/assets/{index-BsSXVL4r.js → index-CvWXztaS.js} +50 -50
  27. package/frontend-dist/index.html +1 -1
  28. package/package.json +1 -1
@@ -3,80 +3,68 @@ import { isSkillCommand } from './skill-commands.js';
3
3
  * 智能合并 Skill Commands
4
4
  *
5
5
  * 合并策略:
6
- * 1. 保留所有非 Skill commands(系统默认 + 用户自定义)
7
- * 2. 对于 Skill commands
8
- * - 新增 Skill → 添加到列表
9
- * - 删除 Skill → 从列表移除
10
- * - 保留的 Skill → 保留用户的 enabled、autoSend、desc 修改
6
+ * 1. 保留用户设置的命令顺序(这是最重要的)
7
+ * 2. 对于已存在的 Skill commands:保留 enabled、autoSend 设置,更新 desc
8
+ * 3. 对于新增的 Skill commands:添加到列表末尾
9
+ * 4. 对于已删除的 Skill commands:从列表中移除
11
10
  *
12
- * @param existingCommands 现有命令列表(可能包含用户的修改)
11
+ * @param existingCommands 现有命令列表(可能包含用户的修改和自定义顺序)
13
12
  * @param newSkillCommands 新扫描出的 Skill Commands
14
13
  * @returns 合并结果
15
14
  */
16
15
  export function mergeSkillCommands(existingCommands, newSkillCommands) {
17
- // 1. 分离现有命令:非 Skill commands 和 Skill commands
18
- const nonSkillCommands = [];
19
- const existingSkillCommands = new Map();
20
- // 构建新 skill label 集合,用于 orphan 检测
21
- const newSkillLabels = new Set(newSkillCommands.map((c) => c.label));
22
- for (const cmd of existingCommands) {
23
- if (isSkillCommand(cmd)) {
24
- existingSkillCommands.set(cmd.label, cmd);
25
- }
26
- else if (newSkillLabels.has(cmd.label)) {
27
- // Orphan: 丢失 fromSkill 标记但与新 skill 同名 → 回收为 skill command
28
- existingSkillCommands.set(cmd.label, cmd);
29
- }
30
- else {
31
- nonSkillCommands.push(cmd);
32
- }
33
- }
34
- // 2. 构建新 Skill 命令映射
16
+ // 1. 构建新 Skill 映射和标签集合
35
17
  const newSkillMap = new Map();
18
+ const newSkillLabels = new Set();
36
19
  for (const cmd of newSkillCommands) {
37
20
  newSkillMap.set(cmd.label, cmd);
21
+ newSkillLabels.add(cmd.label);
38
22
  }
39
- // 3. 合并 Skill commands
40
- const mergedSkillCommands = [];
41
- let added = 0;
42
- let removed = 0;
23
+ // 2. 遍历现有命令,保留用户设置的顺序
24
+ const finalCommands = [];
25
+ const processedLabels = new Set();
43
26
  let preserved = 0;
44
- // 处理新 Skill
45
- for (const [label, newCmd] of newSkillMap) {
46
- const existingCmd = existingSkillCommands.get(label);
47
- if (existingCmd) {
48
- // Skill 存在,保留用户的交互设置,desc 始终从 Skill 源更新
49
- mergedSkillCommands.push({
50
- ...newCmd,
51
- // 保留用户的 enabled 设置
52
- enabled: existingCmd.enabled,
53
- // 保留用户的 autoSend 设置
54
- autoSend: existingCmd.autoSend ?? newCmd.autoSend,
55
- });
56
- preserved++;
27
+ let removed = 0;
28
+ for (const cmd of existingCommands) {
29
+ const isExistingSkill = isSkillCommand(cmd);
30
+ const isOrphanSkill = !isExistingSkill && newSkillLabels.has(cmd.label);
31
+ if (isExistingSkill || isOrphanSkill) {
32
+ // 这是一个 Skill command(或 orphan)
33
+ const newSkill = newSkillMap.get(cmd.label);
34
+ if (newSkill) {
35
+ // Skill 仍然存在,保留用户设置,更新 desc
36
+ finalCommands.push({
37
+ ...newSkill,
38
+ enabled: cmd.enabled,
39
+ autoSend: cmd.autoSend ?? newSkill.autoSend,
40
+ });
41
+ processedLabels.add(cmd.label);
42
+ preserved++;
43
+ }
44
+ else {
45
+ // Skill 已被删除,跳过(移除)
46
+ removed++;
47
+ }
57
48
  }
58
49
  else {
59
- // Skill,直接添加
60
- mergedSkillCommands.push(newCmd);
61
- added++;
50
+ // 这是一个 non-Skill command(系统默认或用户自定义),直接保留
51
+ finalCommands.push(cmd);
62
52
  }
63
53
  }
64
- // 统计移除的 Skill
65
- for (const [label] of existingSkillCommands) {
66
- if (!newSkillMap.has(label)) {
67
- removed++;
54
+ // 3. 添加新增的 Skill commands 到末尾
55
+ let added = 0;
56
+ for (const [label, newCmd] of newSkillMap) {
57
+ if (!processedLabels.has(label)) {
58
+ finalCommands.push(newCmd);
59
+ added++;
68
60
  }
69
61
  }
70
- // 4. 组合最终结果:非 Skill commands + 合并后的 Skill commands
71
- // 按 label 排序 Skill commands
72
- mergedSkillCommands.sort((a, b) => a.label.localeCompare(b.label));
73
- const finalCommands = [...nonSkillCommands, ...mergedSkillCommands];
74
62
  return {
75
63
  commands: finalCommands,
76
64
  added,
77
65
  removed,
78
66
  preserved,
79
- total: mergedSkillCommands.length,
67
+ total: newSkillCommands.length,
80
68
  };
81
69
  }
82
70
  //# sourceMappingURL=skill-command-merger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill-command-merger.js","sourceRoot":"","sources":["../../../../backend/src/skills/skill-command-merger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAkBrD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB,CAChC,gBAAuC,EACvC,gBAAuC;IAEvC,8CAA8C;IAC9C,MAAM,gBAAgB,GAA0B,EAAE,CAAC;IACnD,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAA+B,CAAC;IAErE,kCAAkC;IAClC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAErE,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACnC,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC5C,CAAC;aAAM,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACzC,0DAA0D;YAC1D,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,MAAM,WAAW,GAAG,IAAI,GAAG,EAA+B,CAAC;IAC3D,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACnC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,uBAAuB;IACvB,MAAM,mBAAmB,GAA0B,EAAE,CAAC;IACtD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,YAAY;IACZ,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAErD,IAAI,WAAW,EAAE,CAAC;YAChB,wCAAwC;YACxC,mBAAmB,CAAC,IAAI,CAAC;gBACvB,GAAG,MAAM;gBACT,mBAAmB;gBACnB,OAAO,EAAE,WAAW,CAAC,OAAO;gBAC5B,oBAAoB;gBACpB,QAAQ,EAAE,WAAW,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ;aAClD,CAAC,CAAC;YACH,SAAS,EAAE,CAAC;QACd,CAAC;aAAM,CAAC;YACN,eAAe;YACf,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjC,KAAK,EAAE,CAAC;QACV,CAAC;IACH,CAAC;IAED,cAAc;IACd,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI,qBAAqB,EAAE,CAAC;QAC5C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,mDAAmD;IACnD,4BAA4B;IAC5B,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAEnE,MAAM,aAAa,GAAG,CAAC,GAAG,gBAAgB,EAAE,GAAG,mBAAmB,CAAC,CAAC;IAEpE,OAAO;QACL,QAAQ,EAAE,aAAa;QACvB,KAAK;QACL,OAAO;QACP,SAAS;QACT,KAAK,EAAE,mBAAmB,CAAC,MAAM;KAClC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"skill-command-merger.js","sourceRoot":"","sources":["../../../../backend/src/skills/skill-command-merger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAkBrD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,gBAAuC,EACvC,gBAAuC;IAEvC,uBAAuB;IACvB,MAAM,WAAW,GAAG,IAAI,GAAG,EAA+B,CAAC;IAC3D,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACnC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAChC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,sBAAsB;IACtB,MAAM,aAAa,GAA0B,EAAE,CAAC;IAChD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAC1C,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACnC,MAAM,eAAe,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,aAAa,GAAG,CAAC,eAAe,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAExE,IAAI,eAAe,IAAI,aAAa,EAAE,CAAC;YACrC,+BAA+B;YAC/B,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC5C,IAAI,QAAQ,EAAE,CAAC;gBACb,4BAA4B;gBAC5B,aAAa,CAAC,IAAI,CAAC;oBACjB,GAAG,QAAQ;oBACX,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;iBAC5C,CAAC,CAAC;gBACH,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC/B,SAAS,EAAE,CAAC;YACd,CAAC;iBAAM,CAAC;gBACN,oBAAoB;gBACpB,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;aAAM,CAAC;YACN,0CAA0C;YAC1C,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAChC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC3B,KAAK,EAAE,CAAC;QACV,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,aAAa;QACvB,KAAK;QACL,OAAO;QACP,SAAS;QACT,KAAK,EAAE,gBAAgB,CAAC,MAAM;KAC/B,CAAC;AACJ,CAAC"}
@@ -1,7 +1,21 @@
1
- import { type NetworkInterface } from './network.js';
2
- export type IpChangeCallback = (newIp: string, oldIp: string) => void;
1
+ import { type NetworkInterface, type PreferredInterface } from './network.js';
2
+ /**
3
+ * IP 变化回调,包含网卡信息。
4
+ */
5
+ export interface IpChangeEvent {
6
+ newIp: string;
7
+ oldIp: string;
8
+ interfaceName: string;
9
+ }
10
+ /**
11
+ * 网卡切换事件。
12
+ */
13
+ export interface InterfaceSwitchEvent {
14
+ newInterface: PreferredInterface;
15
+ previousInterface: PreferredInterface;
16
+ }
17
+ export type IpChangeCallback = (event: IpChangeEvent) => void;
3
18
  export type NetworkChangeCallback = (interfaces: NetworkInterface[], preferredIp: string) => void;
4
- export type GetIpFunction = () => string | null;
5
19
  /**
6
20
  * IP 变化监控器。
7
21
  *
@@ -10,43 +24,74 @@ export type GetIpFunction = () => string | null;
10
24
  * - 连续 stabilityThreshold 次检测到相同新 IP 才触发回调
11
25
  * - 避免短暂网络波动导致误报
12
26
  *
13
- * 增强功能:同时监控所有网络接口的变化
27
+ * 绑定特定网卡监控:
28
+ * - 启动时记录当前首选网卡
29
+ * - 只监控该网卡的 IP 变化
30
+ * - 当前网卡断开时自动切换到备用网卡
31
+ * - 高优先级网卡恢复时(如 VPN)自动切回
14
32
  */
15
33
  export declare class IpMonitor {
16
34
  private readonly onChange;
17
35
  private readonly intervalMs;
18
36
  private readonly stabilityThreshold;
19
- private readonly getIp;
20
37
  private readonly onNetworkChange?;
38
+ private readonly onInterfaceSwitch?;
21
39
  private intervalId;
22
40
  private pendingIp;
23
41
  private stabilityCount;
24
42
  private _currentIp;
43
+ private _currentInterfaceName;
44
+ private _currentInterfaceIsVpn;
45
+ private _currentInterfaceIsPrivate;
25
46
  private _currentInterfaces;
26
47
  private pendingInterfaces;
27
48
  private interfaceStabilityCount;
28
- constructor(onChange: IpChangeCallback, intervalMs?: number, stabilityThreshold?: number, getIp?: GetIpFunction, onNetworkChange?: NetworkChangeCallback | undefined);
49
+ private disconnectedCount;
50
+ private readonly disconnectThreshold;
51
+ private _disconnectHandled;
52
+ constructor(onChange: IpChangeCallback, intervalMs?: number, stabilityThreshold?: number, onNetworkChange?: NetworkChangeCallback | undefined, onInterfaceSwitch?: ((event: InterfaceSwitchEvent) => void) | undefined);
29
53
  /**
30
54
  * 启动 IP 监控。
31
- * @param initialIp 初始 IP 地址
55
+ * @param initialInterface 初始网卡信息(名称和 IP
32
56
  */
33
- start(initialIp: string): void;
57
+ start(initialInterface: PreferredInterface): void;
34
58
  /**
35
59
  * 停止 IP 监控。
36
60
  */
37
61
  stop(): void;
38
62
  /**
39
63
  * 检测 IP 变化。
64
+ * 只监控当前绑定的网卡,当前网卡断开时尝试切换。
40
65
  */
41
66
  private check;
67
+ /**
68
+ * 处理当前网卡断开的情况:切换到其他可用网卡。
69
+ * 不直接触发 onChange,让 check() 通过稳定性阈值处理 IP 变化通知。
70
+ */
71
+ private handleInterfaceDisconnect;
72
+ /**
73
+ * 切换监控目标到新网卡。
74
+ * 不直接触发 onChange — 让 check() 通过稳定性阈值处理 IP 变化。
75
+ */
76
+ private switchInterface;
42
77
  /**
43
78
  * 检测网络接口列表变化。
79
+ * 同时检查是否有更高优先级的网卡恢复(如 VPN 重连)。
44
80
  */
45
81
  private checkInterfaces;
82
+ /**
83
+ * 检查是否有更高优先级的网卡可用(VPN 恢复场景)。
84
+ * 仅在优先级更高时切换,避免在同级别间反复切换。
85
+ */
86
+ private checkPreferredInterface;
46
87
  /**
47
88
  * 获取当前 IP。
48
89
  */
49
90
  get currentIp(): string;
91
+ /**
92
+ * 获取当前监控的网卡名称。
93
+ */
94
+ get currentInterfaceName(): string;
50
95
  /**
51
96
  * 获取当前所有网络接口。
52
97
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ip-monitor.d.ts","sourceRoot":"","sources":["../../../../backend/src/utils/ip-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6D,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;AACtE,MAAM,MAAM,qBAAqB,GAAG,CAAC,UAAU,EAAE,gBAAgB,EAAE,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;AAClG,MAAM,MAAM,aAAa,GAAG,MAAM,MAAM,GAAG,IAAI,CAAC;AAmBhD;;;;;;;;;GASG;AACH,qBAAa,SAAS;IAUlB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IAbnC,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,kBAAkB,CAA0B;IACpD,OAAO,CAAC,iBAAiB,CAAmC;IAC5D,OAAO,CAAC,uBAAuB,CAAK;gBAGjB,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,SAAQ,EAClB,kBAAkB,SAAI,EACtB,KAAK,GAAE,aAA4B,EACnC,eAAe,CAAC,EAAE,qBAAqB,YAAA;IAG1D;;;OAGG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAsB9B;;OAEG;IACH,IAAI,IAAI,IAAI;IAWZ;;OAEG;IACH,OAAO,CAAC,KAAK;IAgDb;;OAEG;IACH,OAAO,CAAC,eAAe;IAiDvB;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;OAEG;IACH,IAAI,iBAAiB,IAAI,gBAAgB,EAAE,CAE1C;CACF"}
1
+ {"version":3,"file":"ip-monitor.d.ts","sourceRoot":"","sources":["../../../../backend/src/utils/ip-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAC;AAGtB;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,kBAAkB,CAAC;IACjC,iBAAiB,EAAE,kBAAkB,CAAC;CACvC;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAC9D,MAAM,MAAM,qBAAqB,GAAG,CAAC,UAAU,EAAE,gBAAgB,EAAE,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;AAYlG;;;;;;;;;;;;;GAaG;AACH,qBAAa,SAAS;IAgBlB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAnBrC,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,qBAAqB,CAAc;IAC3C,OAAO,CAAC,sBAAsB,CAAkB;IAChD,OAAO,CAAC,0BAA0B,CAAkB;IACpD,OAAO,CAAC,kBAAkB,CAA0B;IACpD,OAAO,CAAC,iBAAiB,CAAmC;IAC5D,OAAO,CAAC,uBAAuB,CAAK;IACpC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAK;IACzC,OAAO,CAAC,kBAAkB,CAAS;gBAGhB,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,SAAQ,EAClB,kBAAkB,SAAI,EACtB,eAAe,CAAC,EAAE,qBAAqB,YAAA,EACvC,iBAAiB,CAAC,GAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,aAAA;IAG5E;;;OAGG;IACH,KAAK,CAAC,gBAAgB,EAAE,kBAAkB,GAAG,IAAI;IAoCjD;;OAEG;IACH,IAAI,IAAI,IAAI;IAaZ;;;OAGG;IACH,OAAO,CAAC,KAAK;IAmFb;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAmBjC;;;OAGG;IACH,OAAO,CAAC,eAAe;IA0BvB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAyDvB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAmB/B;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;OAEG;IACH,IAAI,oBAAoB,IAAI,MAAM,CAEjC;IAED;;OAEG;IACH,IAAI,iBAAiB,IAAI,gBAAgB,EAAE,CAE1C;CACF"}
@@ -1,11 +1,5 @@
1
- import { detectLanIp, detectNonLoopbackIp, getAllNetworkInterfaces } from './network.js';
1
+ import { getAllNetworkInterfaces, getInterfaceIp, detectSecondaryInterface, detectPreferredInterface, } from './network.js';
2
2
  import { logger } from '../logger/logger.js';
3
- /**
4
- * 默认的 IP 检测函数:优先使用 LAN IP,其次使用非回环 IP
5
- */
6
- function defaultGetIp() {
7
- return detectLanIp() ?? detectNonLoopbackIp();
8
- }
9
3
  /**
10
4
  * 序列化接口列表,用于比对变化
11
5
  */
@@ -23,37 +17,52 @@ function serializeInterfaces(interfaces) {
23
17
  * - 连续 stabilityThreshold 次检测到相同新 IP 才触发回调
24
18
  * - 避免短暂网络波动导致误报
25
19
  *
26
- * 增强功能:同时监控所有网络接口的变化
20
+ * 绑定特定网卡监控:
21
+ * - 启动时记录当前首选网卡
22
+ * - 只监控该网卡的 IP 变化
23
+ * - 当前网卡断开时自动切换到备用网卡
24
+ * - 高优先级网卡恢复时(如 VPN)自动切回
27
25
  */
28
26
  export class IpMonitor {
29
27
  onChange;
30
28
  intervalMs;
31
29
  stabilityThreshold;
32
- getIp;
33
30
  onNetworkChange;
31
+ onInterfaceSwitch;
34
32
  intervalId = null;
35
33
  pendingIp = null;
36
34
  stabilityCount = 0;
37
35
  _currentIp = '';
36
+ _currentInterfaceName = '';
37
+ _currentInterfaceIsVpn = false;
38
+ _currentInterfaceIsPrivate = false;
38
39
  _currentInterfaces = [];
39
40
  pendingInterfaces = null;
40
41
  interfaceStabilityCount = 0;
41
- constructor(onChange, intervalMs = 30000, stabilityThreshold = 2, getIp = defaultGetIp, onNetworkChange) {
42
+ disconnectedCount = 0;
43
+ disconnectThreshold = 3; // 连续 3 次检测不到认为断开
44
+ _disconnectHandled = false;
45
+ constructor(onChange, intervalMs = 30000, stabilityThreshold = 2, onNetworkChange, onInterfaceSwitch) {
42
46
  this.onChange = onChange;
43
47
  this.intervalMs = intervalMs;
44
48
  this.stabilityThreshold = stabilityThreshold;
45
- this.getIp = getIp;
46
49
  this.onNetworkChange = onNetworkChange;
50
+ this.onInterfaceSwitch = onInterfaceSwitch;
47
51
  }
48
52
  /**
49
53
  * 启动 IP 监控。
50
- * @param initialIp 初始 IP 地址
54
+ * @param initialInterface 初始网卡信息(名称和 IP
51
55
  */
52
- start(initialIp) {
56
+ start(initialInterface) {
53
57
  this.stop();
54
- this._currentIp = initialIp;
58
+ this._currentIp = initialInterface.address;
59
+ this._currentInterfaceName = initialInterface.name;
60
+ this._currentInterfaceIsVpn = initialInterface.isVpn;
61
+ this._currentInterfaceIsPrivate = initialInterface.isPrivate;
55
62
  this.pendingIp = null;
56
63
  this.stabilityCount = 0;
64
+ this.disconnectedCount = 0;
65
+ this._disconnectHandled = false;
57
66
  this._currentInterfaces = getAllNetworkInterfaces();
58
67
  this.pendingInterfaces = null;
59
68
  this.interfaceStabilityCount = 0;
@@ -65,7 +74,13 @@ export class IpMonitor {
65
74
  if (this.intervalId.unref) {
66
75
  this.intervalId.unref();
67
76
  }
68
- logger.info({ initialIp, interfaces: this._currentInterfaces.length, intervalMs: this.intervalMs }, 'IP monitor started');
77
+ logger.info({
78
+ ip: initialInterface.address,
79
+ interface: initialInterface.name,
80
+ isVpn: initialInterface.isVpn,
81
+ isPrivate: initialInterface.isPrivate,
82
+ intervalMs: this.intervalMs,
83
+ }, 'IP monitor started');
69
84
  }
70
85
  /**
71
86
  * 停止 IP 监控。
@@ -77,22 +92,46 @@ export class IpMonitor {
77
92
  }
78
93
  this.pendingIp = null;
79
94
  this.stabilityCount = 0;
95
+ this.disconnectedCount = 0;
96
+ this._disconnectHandled = false;
80
97
  this.pendingInterfaces = null;
81
98
  this.interfaceStabilityCount = 0;
82
99
  }
83
100
  /**
84
101
  * 检测 IP 变化。
102
+ * 只监控当前绑定的网卡,当前网卡断开时尝试切换。
85
103
  */
86
104
  check() {
87
- const newIp = this.getIp();
88
- // 网络断开时不处理
105
+ // 只检查当前绑定的网卡
106
+ const newIp = getInterfaceIp(this._currentInterfaceName);
89
107
  if (!newIp) {
108
+ // 当前网卡可能已断开,增加断开计数
109
+ this.disconnectedCount++;
110
+ logger.debug({
111
+ interface: this._currentInterfaceName,
112
+ disconnectCount: this.disconnectedCount,
113
+ threshold: this.disconnectThreshold,
114
+ }, 'Current interface IP not detected, counting disconnect');
115
+ // 达到断开阈值且未处理过,尝试切换到其他网卡
116
+ if (this.disconnectedCount >= this.disconnectThreshold && !this._disconnectHandled) {
117
+ this._disconnectHandled = true;
118
+ this.handleInterfaceDisconnect();
119
+ }
90
120
  return;
91
121
  }
122
+ // 网卡恢复,重置断开计数
123
+ if (this.disconnectedCount > 0) {
124
+ logger.debug({ interface: this._currentInterfaceName, ip: newIp }, 'Interface recovered');
125
+ this.disconnectedCount = 0;
126
+ this._disconnectHandled = false;
127
+ }
92
128
  // IP 未变化,重置待确认状态
93
129
  if (newIp === this._currentIp) {
94
130
  if (this.pendingIp !== null) {
95
- logger.debug('IP stabilized to original, resetting monitor state');
131
+ logger.debug({
132
+ ip: newIp,
133
+ interface: this._currentInterfaceName,
134
+ }, 'IP stabilized to original, resetting monitor state');
96
135
  }
97
136
  this.pendingIp = null;
98
137
  this.stabilityCount = 0;
@@ -104,6 +143,7 @@ export class IpMonitor {
104
143
  this.stabilityCount++;
105
144
  logger.debug({
106
145
  pendingIp: this.pendingIp,
146
+ interface: this._currentInterfaceName,
107
147
  stabilityCount: this.stabilityCount,
108
148
  threshold: this.stabilityThreshold,
109
149
  }, 'IP change detected, counting stability');
@@ -114,6 +154,7 @@ export class IpMonitor {
114
154
  this.stabilityCount = 1;
115
155
  logger.debug({
116
156
  newIp,
157
+ interface: this._currentInterfaceName,
117
158
  }, 'New IP detected, waiting for stability');
118
159
  }
119
160
  // 达到稳定性阈值,触发回调
@@ -122,17 +163,57 @@ export class IpMonitor {
122
163
  this._currentIp = newIp;
123
164
  this.pendingIp = null;
124
165
  this.stabilityCount = 0;
125
- logger.info({ oldIp, newIp }, 'IP change confirmed, triggering callback');
126
- this.onChange(newIp, oldIp);
166
+ logger.info({ oldIp, newIp, interface: this._currentInterfaceName }, 'IP change confirmed, triggering callback');
167
+ this.onChange({
168
+ newIp,
169
+ oldIp,
170
+ interfaceName: this._currentInterfaceName,
171
+ });
172
+ }
173
+ }
174
+ /**
175
+ * 处理当前网卡断开的情况:切换到其他可用网卡。
176
+ * 不直接触发 onChange,让 check() 通过稳定性阈值处理 IP 变化通知。
177
+ */
178
+ handleInterfaceDisconnect() {
179
+ logger.warn({ interface: this._currentInterfaceName, previousIp: this._currentIp }, 'Current interface disconnected, searching for alternative');
180
+ const alternative = detectSecondaryInterface(this._currentInterfaceName);
181
+ if (alternative) {
182
+ this.switchInterface(alternative);
183
+ }
184
+ else {
185
+ logger.warn({ interface: this._currentInterfaceName }, 'No alternative network interfaces available, waiting for recovery');
186
+ // _disconnectHandled = true 阻止重复触发,等 checkInterfaces 检测到新接口后重置
187
+ }
188
+ }
189
+ /**
190
+ * 切换监控目标到新网卡。
191
+ * 不直接触发 onChange — 让 check() 通过稳定性阈值处理 IP 变化。
192
+ */
193
+ switchInterface(newInterface) {
194
+ const previousInterface = {
195
+ name: this._currentInterfaceName,
196
+ address: this._currentIp,
197
+ isVpn: this._currentInterfaceIsVpn,
198
+ isPrivate: this._currentInterfaceIsPrivate,
199
+ };
200
+ this._currentInterfaceName = newInterface.name;
201
+ this._currentInterfaceIsVpn = newInterface.isVpn;
202
+ this._currentInterfaceIsPrivate = newInterface.isPrivate;
203
+ this.disconnectedCount = 0;
204
+ this._disconnectHandled = false;
205
+ this.pendingIp = null;
206
+ this.stabilityCount = 0;
207
+ logger.info({ oldInterface: previousInterface.name, newInterface: newInterface.name, newIp: newInterface.address }, 'Switched monitoring to new interface');
208
+ if (this.onInterfaceSwitch) {
209
+ this.onInterfaceSwitch({ newInterface, previousInterface });
127
210
  }
128
211
  }
129
212
  /**
130
213
  * 检测网络接口列表变化。
214
+ * 同时检查是否有更高优先级的网卡恢复(如 VPN 重连)。
131
215
  */
132
216
  checkInterfaces() {
133
- // 如果没有网络变化回调,跳过此检查
134
- if (!this.onNetworkChange)
135
- return;
136
217
  const newInterfaces = getAllNetworkInterfaces();
137
218
  const currentSerialized = serializeInterfaces(this._currentInterfaces);
138
219
  const newSerialized = serializeInterfaces(newInterfaces);
@@ -169,16 +250,47 @@ export class IpMonitor {
169
250
  this.interfaceStabilityCount = 0;
170
251
  logger.info({
171
252
  interfaces: newInterfaces.map(i => `${i.name}:${i.address}`),
172
- }, 'Network interface change confirmed, triggering callback');
173
- this.onNetworkChange(newInterfaces, this._currentIp);
253
+ }, 'Network interface change confirmed');
254
+ // 检查是否有更高优先级的网卡恢复(如 VPN 重连)
255
+ this.checkPreferredInterface();
256
+ // 重置断开处理标记,新接口可能提供替代方案
257
+ if (this._disconnectHandled) {
258
+ this._disconnectHandled = false;
259
+ }
260
+ // 通知外部
261
+ if (this.onNetworkChange) {
262
+ this.onNetworkChange(newInterfaces, this._currentIp);
263
+ }
174
264
  }
175
265
  }
266
+ /**
267
+ * 检查是否有更高优先级的网卡可用(VPN 恢复场景)。
268
+ * 仅在优先级更高时切换,避免在同级别间反复切换。
269
+ */
270
+ checkPreferredInterface() {
271
+ const preferred = detectPreferredInterface();
272
+ if (!preferred || preferred.name === this._currentInterfaceName)
273
+ return;
274
+ // 仅当新首选网卡优先级更高时才切换
275
+ const shouldSwitch = (preferred.isVpn && !this._currentInterfaceIsVpn) ||
276
+ (preferred.isPrivate && !this._currentInterfaceIsPrivate && !this._currentInterfaceIsVpn);
277
+ if (!shouldSwitch)
278
+ return;
279
+ logger.info({ currentInterface: this._currentInterfaceName, preferredInterface: preferred.name }, 'Higher-priority interface detected, switching');
280
+ this.switchInterface(preferred);
281
+ }
176
282
  /**
177
283
  * 获取当前 IP。
178
284
  */
179
285
  get currentIp() {
180
286
  return this._currentIp;
181
287
  }
288
+ /**
289
+ * 获取当前监控的网卡名称。
290
+ */
291
+ get currentInterfaceName() {
292
+ return this._currentInterfaceName;
293
+ }
182
294
  /**
183
295
  * 获取当前所有网络接口。
184
296
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ip-monitor.js","sourceRoot":"","sources":["../../../../backend/src/utils/ip-monitor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ip-monitor.js","sourceRoot":"","sources":["../../../../backend/src/utils/ip-monitor.ts"],"names":[],"mappings":"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"}
@@ -58,4 +58,29 @@ export declare function detectAllLocalIps(): string[];
58
58
  * Useful for environments with non-RFC1918 internal networks (e.g., corporate networks).
59
59
  */
60
60
  export declare function detectNonLoopbackIp(): string | null;
61
+ /**
62
+ * Result of detecting the preferred network interface.
63
+ */
64
+ export interface PreferredInterface {
65
+ name: string;
66
+ address: string;
67
+ isVpn: boolean;
68
+ isPrivate: boolean;
69
+ }
70
+ /**
71
+ * Detect the preferred network interface for monitoring.
72
+ * Priority: VPN > Private LAN > Public
73
+ * Returns null if no suitable interface found.
74
+ */
75
+ export declare function detectPreferredInterface(): PreferredInterface | null;
76
+ /**
77
+ * Detect a secondary interface when the primary one is disconnected.
78
+ * Excludes the given interface name from consideration.
79
+ */
80
+ export declare function detectSecondaryInterface(excludeInterfaceName: string): PreferredInterface | null;
81
+ /**
82
+ * Get the IP address of a specific network interface.
83
+ * Returns null if interface not found or has no IPv4 address.
84
+ */
85
+ export declare function getInterfaceIp(interfaceName: string): string | null;
61
86
  //# sourceMappingURL=network.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../../backend/src/utils/network.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAiBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAsBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAS/D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CASpD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,GAAE,MAAM,EAAO,GAAG,OAAO,CAc3F;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,gBAAgB,EAAE,CAmC5D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAWlD;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAY3C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,EAAE,CAW5C;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAYnD"}
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../../backend/src/utils/network.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAiBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAsBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAS/D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CASpD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,GAAE,MAAM,EAAO,GAAG,OAAO,CAc3F;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,gBAAgB,EAAE,CAmC5D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAWlD;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAY3C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,EAAE,CAW5C;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAYnD;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,kBAAkB,GAAG,IAAI,CAsBpE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,oBAAoB,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAwBhG;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAenE"}
@@ -193,4 +193,63 @@ export function detectNonLoopbackIp() {
193
193
  logger.warn('No non-loopback IP detected');
194
194
  return null;
195
195
  }
196
+ /**
197
+ * Detect the preferred network interface for monitoring.
198
+ * Priority: VPN > Private LAN > Public
199
+ * Returns null if no suitable interface found.
200
+ */
201
+ export function detectPreferredInterface() {
202
+ const interfaces = getAllNetworkInterfaces();
203
+ if (interfaces.length === 0) {
204
+ logger.warn('No network interfaces detected');
205
+ return null;
206
+ }
207
+ // getAllNetworkInterfaces already returns interfaces sorted by preference
208
+ const preferred = interfaces[0];
209
+ logger.info({ name: preferred.name, ip: preferred.address, isVpn: preferred.isVpn, isPrivate: preferred.isPrivate }, 'Detected preferred network interface');
210
+ return {
211
+ name: preferred.name,
212
+ address: preferred.address,
213
+ isVpn: preferred.isVpn,
214
+ isPrivate: preferred.isPrivate,
215
+ };
216
+ }
217
+ /**
218
+ * Detect a secondary interface when the primary one is disconnected.
219
+ * Excludes the given interface name from consideration.
220
+ */
221
+ export function detectSecondaryInterface(excludeInterfaceName) {
222
+ const interfaces = getAllNetworkInterfaces();
223
+ // Filter out the excluded interface
224
+ const available = interfaces.filter(i => i.name !== excludeInterfaceName);
225
+ if (available.length === 0) {
226
+ logger.warn({ excludedInterface: excludeInterfaceName }, 'No secondary network interfaces available');
227
+ return null;
228
+ }
229
+ const selected = available[0];
230
+ logger.info({ name: selected.name, ip: selected.address, excludedInterface: excludeInterfaceName }, 'Switched to secondary network interface');
231
+ return {
232
+ name: selected.name,
233
+ address: selected.address,
234
+ isVpn: selected.isVpn,
235
+ isPrivate: selected.isPrivate,
236
+ };
237
+ }
238
+ /**
239
+ * Get the IP address of a specific network interface.
240
+ * Returns null if interface not found or has no IPv4 address.
241
+ */
242
+ export function getInterfaceIp(interfaceName) {
243
+ const nets = networkInterfaces();
244
+ const interfaceList = nets[interfaceName];
245
+ if (!interfaceList) {
246
+ return null;
247
+ }
248
+ for (const net of interfaceList) {
249
+ if (net.family === 'IPv4' && !net.internal) {
250
+ return net.address;
251
+ }
252
+ }
253
+ return null;
254
+ }
196
255
  //# sourceMappingURL=network.js.map