@tonyruan/dsh-bridge-host 0.1.1-beta.4 → 0.1.1-beta.6

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/README.md CHANGED
@@ -7,3 +7,6 @@ Package: @tonyruan/dsh-bridge-host. Use the official DSH plugin manager for inst
7
7
  This generic build contains no personal relay preset or update root/feed. Import the original trusted deployment configuration or use the private migration bridge locally before replacing an old configured build. Existing paired profiles without deployment configuration fail recoverably and retain identity, pairing and login data. Strict LAN-only use does not enable update or diagnostic networking.
8
8
 
9
9
  Own project code is licensed under the standard PolyForm Noncommercial License1.0.0 in LICENSE. This is not OSI open-source; permitted purposes and exceptions are governed by that exact text, not a blanket promise about every business/payment scenario. Third-party components retain their own permission, copyright and NOTICE terms in THIRD-PARTY-NOTICES.txt and oss-licenses/. These own-code terms do not restrict upstream rights. The complete own development project/Git repository is not included; npm runtime JavaScript is publicly readable. Native platform download assets are not included in this npm release.
10
+
11
+
12
+ Beta6/build26 retains the original validated persisted connection realm across upgrades and LAN-only restarts, including previously paired WSS realms without an unused relay leaf. Existing trusted deployment is reused without import or rewrite. AUTO still requires trusted TLS material. Legacy private code-only presets require the separately delivered Linux pre-upgrade migration helper before replacement; it statically validates the original local package and pin, never executes old code or fetches a new network leaf. No identity/pairing/schema reinitialization or client update-source JSON is required. Physical LAN management and the original phone-connection product label/icon remain as in the tested beta5.
package/lib/agent.mjs CHANGED
@@ -332,7 +332,13 @@ var require_is_electron = __commonJS({
332
332
  }
333
333
  });
334
334
 
335
- // npm-release-beta-r1/host/phone-access-plugin/src/agent.mjs
335
+ // host-config-migration-r1/host/phone-access-plugin/src/lan-provenance.mjs
336
+ var accepted = /* @__PURE__ */ new WeakMap();
337
+ function acceptedLanEndpoint(socket) {
338
+ return socket.destroyed ? null : accepted.get(socket) ?? null;
339
+ }
340
+
341
+ // host-config-migration-r1/host/phone-access-plugin/src/agent.mjs
336
342
  import net from "node:net";
337
343
  import { once } from "node:events";
338
344
 
@@ -15327,7 +15333,7 @@ function noise(init = {}) {
15327
15333
  return (components) => new Noise(components, init);
15328
15334
  }
15329
15335
 
15330
- // npm-release-beta-r1/host/phone-access-plugin/src/lan-trace.mjs
15336
+ // host-config-migration-r1/host/phone-access-plugin/src/lan-trace.mjs
15331
15337
  var LAN_DETAIL_CODES = Object.freeze(["LAN_TCP_ACCEPTED", "LAN_TCP_CLOSED_REJECTED", "LAN_TCP_DISABLED_REJECTED", "LAN_TCP_POLICY_REJECTED", "LAN_TCP_SUBNET_REJECTED", "LAN_TCP_LIMIT_REJECTED", "LAN_TCP_GLOBAL_RATE_REJECTED", "LAN_TCP_SOURCE_RATE_REJECTED", "LAN_TCP_RATE_KEYS_REJECTED", "LAN_AGENT_CLOSED_REJECTED", "LAN_AGENT_LIMIT_REJECTED", "LAN_AGENT_HANDSHAKE_LIMIT_REJECTED", "LAN_AGENT_PEER_LIMIT_REJECTED", "LAN_AGENT_ADMISSION_REJECTED", "LAN_AGENT_READMISSION_REJECTED", "LAN_AGENT_FIRST_FRAME_EOF", "LAN_AGENT_NOISE_FAILED", "LAN_AGENT_FIRST_FRAME_TIMEOUT", "LAN_AGENT_FIRST_FRAME_FAILED", "LAN_AGENT_BACKEND_CONNECT_FAILED", "LAN_AGENT_REGISTER_FAILED", "LAN_AGENT_FORWARD_FAILED", "LAN_AGENT_CHANNEL_READY", "LAN_AGENT_CHANNEL_CLOSED"]);
15332
15338
  var codes = new Set(LAN_DETAIL_CODES);
15333
15339
  var bounded = (v, max) => Number.isSafeInteger(v) && v >= 0 ? Math.min(max, v) : 0;
@@ -15395,7 +15401,7 @@ function createLanTrace(diagnostic = () => {
15395
15401
  return { sample, lifetime, now };
15396
15402
  }
15397
15403
 
15398
- // npm-release-beta-r1/host/noise-lab/core.mjs
15404
+ // host-config-migration-r1/host/noise-lab/core.mjs
15399
15405
  var silent = Object.assign(() => {
15400
15406
  }, { enabled: false, error: () => {
15401
15407
  }, trace: () => {
@@ -15435,7 +15441,7 @@ async function temporaryIdentity() {
15435
15441
  return { privateKey, peerId: peerIdFromPrivateKey(privateKey) };
15436
15442
  }
15437
15443
 
15438
- // npm-release-beta-r1/host/phone-access-plugin/src/agent.mjs
15444
+ // host-config-migration-r1/host/phone-access-plugin/src/agent.mjs
15439
15445
  async function createPcAgent({ backendPort, listenPort = 0, listen = true, identity: providedIdentity, pairing = () => ({ confirmed: false, pin: null }), acquireLease, registerBackend, diagnostic = () => {
15440
15446
  }, factories = {} }) {
15441
15447
  if (!Number.isInteger(backendPort) || backendPort < 1 || backendPort > 65535) throw Error("INVALID_FIXED_BACKEND");
@@ -15452,7 +15458,7 @@ async function createPcAgent({ backendPort, listenPort = 0, listen = true, ident
15452
15458
  let handshaking = 0, closed = false, attempts = 0;
15453
15459
  const stats = { handshakes: 0, rejected: 0, handshakeFailed: 0, dshConnections: 0, upBytes: 0, downBytes: 0 };
15454
15460
  const acceptWire = (wire, { route = "RELAY", pairId } = {}) => {
15455
- const attempt = ++attempts, began = trace.now();
15461
+ const attempt = ++attempts, began = trace.now(), lanEndpoint = route === "LAN" ? acceptedLanEndpoint(wire) : null;
15456
15462
  const event = (code3) => {
15457
15463
  try {
15458
15464
  diagnostic({ stage: route === "LAN" ? "LAN" : "AUTH", code: code3, attempt });
@@ -15629,7 +15635,7 @@ async function createPcAgent({ backendPort, listenPort = 0, listen = true, ident
15629
15635
  check();
15630
15636
  if (registerBackend) {
15631
15637
  phase = "REGISTER";
15632
- const registration = Promise.resolve(registerBackend({ localAddress: backend.localAddress, localPort: backend.localPort, remoteAddress: backend.remoteAddress, remotePort: backend.remotePort })).then((fn) => {
15638
+ const registration = Promise.resolve(registerBackend({ localAddress: backend.localAddress, localPort: backend.localPort, remoteAddress: backend.remoteAddress, remotePort: backend.remotePort }, lease && lease.valid() ? { schema: 1, route: route === "LAN" && lanEndpoint ? "LAN" : route === "RELAY" ? "RELAY" : "UNKNOWN", peerId: lease.peerId, pairId: lease.pairId, generation: lease.generation, lanEndpoint: route === "LAN" ? lanEndpoint : null } : null)).then((fn) => {
15633
15639
  let released = false;
15634
15640
  const once2 = () => {
15635
15641
  if (released) return;
package/lib/child.mjs CHANGED
@@ -1,38 +1,38 @@
1
- import {createPcAgent} from './agent.mjs';
2
- import {createPhoneSession} from './session.mjs';
3
- import {randomUUID} from 'node:crypto';
4
- let agent,closing=false,heartbeat;
5
- const registrations=new Map();
6
- function registerBackend(tuple){return new Promise((resolve,reject)=>{
7
- const registrationId=randomUUID(),timer=setTimeout(()=>{registrations.delete(registrationId);process.send?.({op:'backend.close',registrationId},()=>{});reject(Error('BACKEND_REGISTRATION_TIMEOUT'));},3000);
8
- registrations.set(registrationId,{resolve,reject,timer});
9
- process.send?.({op:'backend.open',registrationId,tuple},error=>{if(error){clearTimeout(timer);registrations.delete(registrationId);reject(Error('BACKEND_REGISTRATION_FAILED'));}});
10
- });}
11
- const finish=async()=>{if(closing)return;closing=true;clearInterval(heartbeat);await agent?.close();process.exit(0);};
12
- process.on('disconnect',finish);process.on('SIGTERM',finish);process.on('SIGINT',finish);
13
- // Parent IPC is the only controller. No unauthenticated control HTTP listener exists.
14
- process.on('message',async message=>{
15
- if(closing)return;
16
- try{
17
- if(message?.op==='backend.ack'){
18
- const r=registrations.get(message.registrationId);if(!r)return;registrations.delete(message.registrationId);clearTimeout(r.timer);
19
- if(!message.ok)r.reject(Error('BACKEND_REGISTRATION_REJECTED'));else {let released=false;r.resolve(()=>{if(released)return;released=true;process.send?.({op:'backend.close',registrationId:message.registrationId},()=>{});});}return;
20
- }
21
- if(message?.op==='init'){
22
- if(agent)throw Error('ALREADY_INITIALIZED');
23
- if(message.profileDirectory&&!message.relay)throw Error('PERSISTENT_PROFILE_REQUIRES_FIXED_RELAY');
24
- agent=message.relay?await createPhoneSession({backendPort:message.backendPort,connectionMode:message.connectionMode??'auto',lanAddress:message.lanAddress,relay:message.relay,relayCa:message.relayCa,relayLeaf:message.relayLeaf,profileDirectory:message.profileDirectory,lanEnabled:message.lanEnabled===true,registerBackend,diagnostics:{record:event=>{if(process.connected)process.send?.({op:'diagnostic',event:{...event,generation:Number.isInteger(message.diagnosticGeneration)?message.diagnosticGeneration:0}},()=>{});}}}):await createPcAgent({backendPort:message.backendPort,registerBackend});
25
- heartbeat=setInterval(()=>{if(process.connected)process.send?.({op:'diagnostic',event:{stage:'LOCAL',code:'COMPANION_HEARTBEAT',count:1,generation:Number.isInteger(message.diagnosticGeneration)?message.diagnosticGeneration:0}},()=>{});},30000);heartbeat.unref?.();
26
- process.send?.({id:message.id,ok:true,status:{pid:process.pid,...agent.status()}});
27
- }else if(message?.op==='status'&&agent)process.send?.({id:message.id,ok:true,status:{pid:process.pid,...agent.status()}});
28
- else if(message?.op==='confirmReverseScan'&&agent?.confirmReverseScan){await agent.confirmReverseScan(message.qr);process.send?.({id:message.id,ok:true,status:agent.status()});}
29
- else if(message?.op==='pair/start'&&agent?.beginPairing){await agent.beginPairing();process.send?.({id:message.id,ok:true,status:agent.status()});}
30
- else if(message?.op==='pair/cancel'&&agent?.cancelPairing){await agent.cancelPairing(message.sessionId);process.send?.({id:message.id,ok:true,status:agent.status()});}
31
- else if(message?.op==='revoke'&&agent?.revoke){await agent.revoke(message.target);process.send?.({id:message.id,ok:true,status:agent.status()});}
32
- else if(message?.op==='lan/settings'&&agent?.setLanEnabled){await agent.setLanEnabled(message.enabled);process.send?.({id:message.id,ok:true,status:agent.status()});}
33
- else if(message?.op==='reconnect'&&agent?.reconnect){await agent.reconnect();process.send?.({id:message.id,ok:true,status:agent.status()});}
34
- else if(message?.op==='stop')await finish();
35
- }catch(error){const code=error?.code??error?.message;process.send?.({id:message?.id,ok:false,error:/^[A-Z_]{3,70}$/.test(code??'')?code:'AGENT_OPERATION_FAILED'});if(!agent)await finish();}
36
- });
37
- // Failed owners must not leave a child waiting forever before init.
38
- setTimeout(()=>{if(!agent)finish();},10000).unref();
1
+ import {createPcAgent} from './agent.mjs';
2
+ import {createPhoneSession} from './session.mjs';
3
+ import {randomUUID} from 'node:crypto';
4
+ let agent,closing=false,heartbeat;
5
+ const registrations=new Map();
6
+ function registerBackend(tuple,provenance){return new Promise((resolve,reject)=>{
7
+ const registrationId=randomUUID(),timer=setTimeout(()=>{registrations.delete(registrationId);process.send?.({op:'backend.close',registrationId},()=>{});reject(Error('BACKEND_REGISTRATION_TIMEOUT'));},3000);
8
+ registrations.set(registrationId,{resolve,reject,timer});
9
+ process.send?.({op:'backend.open',registrationId,tuple,provenance},error=>{if(error){clearTimeout(timer);registrations.delete(registrationId);reject(Error('BACKEND_REGISTRATION_FAILED'));}});
10
+ });}
11
+ const finish=async()=>{if(closing)return;closing=true;clearInterval(heartbeat);await agent?.close();process.exit(0);};
12
+ process.on('disconnect',finish);process.on('SIGTERM',finish);process.on('SIGINT',finish);
13
+ // Parent IPC is the only controller. No unauthenticated control HTTP listener exists.
14
+ process.on('message',async message=>{
15
+ if(closing)return;
16
+ try{
17
+ if(message?.op==='backend.ack'){
18
+ const r=registrations.get(message.registrationId);if(!r)return;registrations.delete(message.registrationId);clearTimeout(r.timer);
19
+ if(!message.ok)r.reject(Error('BACKEND_REGISTRATION_REJECTED'));else {let released=false;r.resolve(()=>{if(released)return;released=true;process.send?.({op:'backend.close',registrationId:message.registrationId},()=>{});});}return;
20
+ }
21
+ if(message?.op==='init'){
22
+ if(agent)throw Error('ALREADY_INITIALIZED');
23
+ if(message.profileDirectory&&!message.relay)throw Error('PERSISTENT_PROFILE_REQUIRES_FIXED_RELAY');
24
+ agent=message.relay?await createPhoneSession({backendPort:message.backendPort,connectionMode:message.connectionMode??'auto',lanAddress:message.lanAddress,relay:message.relay,relayCa:message.relayCa,relayLeaf:message.relayLeaf,profileDirectory:message.profileDirectory,lanEnabled:message.lanEnabled===true,registerBackend,diagnostics:{record:event=>{if(process.connected)process.send?.({op:'diagnostic',event:{...event,generation:Number.isInteger(message.diagnosticGeneration)?message.diagnosticGeneration:0}},()=>{});}}}):await createPcAgent({backendPort:message.backendPort,registerBackend});
25
+ heartbeat=setInterval(()=>{if(process.connected)process.send?.({op:'diagnostic',event:{stage:'LOCAL',code:'COMPANION_HEARTBEAT',count:1,generation:Number.isInteger(message.diagnosticGeneration)?message.diagnosticGeneration:0}},()=>{});},30000);heartbeat.unref?.();
26
+ process.send?.({id:message.id,ok:true,status:{pid:process.pid,...agent.status()}});
27
+ }else if(message?.op==='status'&&agent)process.send?.({id:message.id,ok:true,status:{pid:process.pid,...agent.status()}});
28
+ else if(message?.op==='confirmReverseScan'&&agent?.confirmReverseScan){await agent.confirmReverseScan(message.qr);process.send?.({id:message.id,ok:true,status:agent.status()});}
29
+ else if(message?.op==='pair/start'&&agent?.beginPairing){await agent.beginPairing();process.send?.({id:message.id,ok:true,status:agent.status()});}
30
+ else if(message?.op==='pair/cancel'&&agent?.cancelPairing){await agent.cancelPairing(message.sessionId);process.send?.({id:message.id,ok:true,status:agent.status()});}
31
+ else if(message?.op==='revoke'&&agent?.revoke){await agent.revoke(message.target);process.send?.({id:message.id,ok:true,status:agent.status()});}
32
+ else if(message?.op==='lan/settings'&&agent?.setLanEnabled){await agent.setLanEnabled(message.enabled);process.send?.({id:message.id,ok:true,status:agent.status()});}
33
+ else if(message?.op==='reconnect'&&agent?.reconnect){await agent.reconnect();process.send?.({id:message.id,ok:true,status:agent.status()});}
34
+ else if(message?.op==='stop')await finish();
35
+ }catch(error){const code=error?.code??error?.message;process.send?.({id:message?.id,ok:false,error:/^[A-Z_]{3,70}$/.test(code??'')?code:'AGENT_OPERATION_FAILED'});if(!agent)await finish();}
36
+ });
37
+ // Failed owners must not leave a child waiting forever before init.
38
+ setTimeout(()=>{if(!agent)finish();},10000).unref();