yakmesh 2.8.2 → 3.0.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.
Files changed (232) hide show
  1. package/CHANGELOG.md +637 -0
  2. package/CONTRIBUTING.md +42 -0
  3. package/Caddyfile +77 -0
  4. package/README.md +119 -29
  5. package/adapters/adapter-mlv-bible/README.md +124 -0
  6. package/adapters/adapter-mlv-bible/index.js +400 -0
  7. package/adapters/chat-mod-adapter.js +532 -0
  8. package/adapters/content-adapter.js +273 -0
  9. package/content/api.js +50 -41
  10. package/content/index.js +2 -2
  11. package/content/store.js +355 -173
  12. package/dashboard/index.html +19 -3
  13. package/database/replication.js +117 -37
  14. package/docs/CRYPTO-AGILITY.md +204 -0
  15. package/docs/MTLS-RESEARCH.md +367 -0
  16. package/docs/NAMCHE-SPEC.md +681 -0
  17. package/docs/PEERQUANTA-YAKMESH-INTEGRATION.md +407 -0
  18. package/docs/PRECISION-DISCLOSURE.md +96 -0
  19. package/docs/README.md +76 -0
  20. package/docs/ROADMAP-2.4.0.md +447 -0
  21. package/docs/ROADMAP-2.5.0.md +244 -0
  22. package/docs/SECURITY-AUDIT-REPORT.md +306 -0
  23. package/docs/SST-INTEGRATION.md +712 -0
  24. package/docs/STEADYWATCH-IMPLEMENTATION.md +303 -0
  25. package/docs/TERNARY-AUDIT-REPORT.md +247 -0
  26. package/docs/TME-FAQ.md +221 -0
  27. package/docs/WHITEPAPER.md +623 -0
  28. package/docs/adapters.html +1001 -0
  29. package/docs/advanced-systems.html +1045 -0
  30. package/docs/annex.html +1046 -0
  31. package/docs/api.html +970 -0
  32. package/docs/business/response-templates.md +160 -0
  33. package/docs/c2c.html +1225 -0
  34. package/docs/cli.html +1332 -0
  35. package/docs/configuration.html +1248 -0
  36. package/docs/darshan.html +1085 -0
  37. package/docs/dharma.html +966 -0
  38. package/docs/docs-bundle.html +1075 -0
  39. package/docs/docs.css +3120 -0
  40. package/docs/docs.js +556 -0
  41. package/docs/doko.html +969 -0
  42. package/docs/geo-proof.html +858 -0
  43. package/docs/getting-started.html +840 -0
  44. package/docs/gumba-tutorial.html +1144 -0
  45. package/docs/gumba.html +1098 -0
  46. package/docs/index.html +914 -0
  47. package/docs/jhilke.html +1312 -0
  48. package/docs/karma.html +1100 -0
  49. package/docs/katha.html +1037 -0
  50. package/docs/lama.html +978 -0
  51. package/docs/mandala.html +1067 -0
  52. package/docs/mani.html +964 -0
  53. package/docs/mantra.html +967 -0
  54. package/docs/mesh.html +1409 -0
  55. package/docs/nakpak.html +869 -0
  56. package/docs/namche.html +928 -0
  57. package/docs/nav-order.json +53 -0
  58. package/docs/prahari.html +1043 -0
  59. package/docs/prism-bash.min.js +1 -0
  60. package/docs/prism-javascript.min.js +1 -0
  61. package/docs/prism-json.min.js +1 -0
  62. package/docs/prism-tomorrow.min.css +1 -0
  63. package/docs/prism.min.js +1 -0
  64. package/docs/privacy.html +699 -0
  65. package/docs/quick-reference.html +1181 -0
  66. package/docs/sakshi.html +1402 -0
  67. package/docs/sandboxing.md +386 -0
  68. package/docs/seva.html +911 -0
  69. package/docs/sherpa.html +871 -0
  70. package/docs/studio.html +860 -0
  71. package/docs/stupa.html +995 -0
  72. package/docs/tailwind.min.css +2 -0
  73. package/docs/tattva.html +1332 -0
  74. package/docs/terms.html +686 -0
  75. package/docs/time-server-deployment.md +166 -0
  76. package/docs/time-sources.html +1392 -0
  77. package/docs/tivra.html +1127 -0
  78. package/docs/trademark-policy.html +686 -0
  79. package/docs/tribhuj.html +1183 -0
  80. package/docs/trust-security.html +1029 -0
  81. package/docs/tutorials/backup-recovery.html +654 -0
  82. package/docs/tutorials/dashboard.html +604 -0
  83. package/docs/tutorials/domain-setup.html +605 -0
  84. package/docs/tutorials/host-website.html +456 -0
  85. package/docs/tutorials/mesh-network.html +505 -0
  86. package/docs/tutorials/mobile-access.html +445 -0
  87. package/docs/tutorials/privacy.html +467 -0
  88. package/docs/tutorials/raspberry-pi.html +600 -0
  89. package/docs/tutorials/security-basics.html +539 -0
  90. package/docs/tutorials/share-files.html +431 -0
  91. package/docs/tutorials/troubleshooting.html +637 -0
  92. package/docs/tutorials/trust-karma.html +419 -0
  93. package/docs/tutorials/yak-protocol.html +456 -0
  94. package/docs/tutorials.html +1034 -0
  95. package/docs/vani.html +1270 -0
  96. package/docs/webserver.html +809 -0
  97. package/docs/yak-protocol.html +940 -0
  98. package/docs/yak-timeserver-design.md +475 -0
  99. package/docs/yakapp.html +1015 -0
  100. package/docs/ypc27.html +1069 -0
  101. package/docs/yurt.html +1344 -0
  102. package/embedded-docs/bundle.js +334 -74
  103. package/gossip/protocol.js +247 -27
  104. package/identity/key-resolver.js +262 -0
  105. package/identity/machine-seed.js +632 -0
  106. package/identity/node-key.js +669 -368
  107. package/identity/tribhuj-ratchet.js +506 -0
  108. package/knowledge-base.js +37 -8
  109. package/launcher/yakmesh.bat +62 -0
  110. package/launcher/yakmesh.sh +70 -0
  111. package/mesh/annex.js +462 -108
  112. package/mesh/beacon-broadcast.js +113 -1
  113. package/mesh/darshan.js +1718 -0
  114. package/mesh/gumba.js +1567 -0
  115. package/mesh/jhilke.js +651 -0
  116. package/mesh/katha.js +1012 -0
  117. package/mesh/nakpak-routing.js +8 -5
  118. package/mesh/network.js +724 -34
  119. package/mesh/pulse-sync.js +4 -1
  120. package/mesh/rate-limiter.js +127 -15
  121. package/mesh/seva.js +526 -0
  122. package/mesh/sherpa-discovery.js +89 -8
  123. package/mesh/sybil-defense.js +19 -5
  124. package/mesh/temporal-encoder.js +4 -3
  125. package/mesh/vani.js +1364 -0
  126. package/mesh/yurt.js +1340 -0
  127. package/models/entropy-sentinel.onnx +0 -0
  128. package/models/karma-trust.onnx +0 -0
  129. package/models/manifest.json +43 -0
  130. package/models/sakshi-anomaly.onnx +0 -0
  131. package/oracle/code-proof-protocol.js +7 -6
  132. package/oracle/codebase-lock.js +257 -28
  133. package/oracle/index.js +74 -15
  134. package/oracle/ma902-snmp.js +678 -0
  135. package/oracle/module-sealer.js +5 -3
  136. package/oracle/network-identity.js +16 -0
  137. package/oracle/packet-checksum.js +201 -0
  138. package/oracle/sst.js +579 -0
  139. package/oracle/ternary-144t.js +714 -0
  140. package/oracle/ternary-ml.js +481 -0
  141. package/oracle/time-api.js +239 -0
  142. package/oracle/time-source.js +137 -47
  143. package/oracle/validation-oracle-hardened.js +1111 -1071
  144. package/oracle/validation-oracle.js +4 -2
  145. package/oracle/ypc27.js +211 -0
  146. package/package.json +20 -3
  147. package/protocol/yak-handler.js +35 -9
  148. package/protocol/yak-protocol.js +28 -13
  149. package/reference/cpp/yakmesh_mceliece_shard.cpp +168 -0
  150. package/reference/cpp/yakmesh_ypc27.cpp +179 -0
  151. package/sbom.json +87 -0
  152. package/scripts/security-audit.mjs +264 -0
  153. package/scripts/update-docs-nav.js +194 -0
  154. package/scripts/update-docs-sidebar.cjs +164 -0
  155. package/security/crypto-config.js +4 -3
  156. package/security/dharma-moderation.js +517 -0
  157. package/security/doko-identity.js +193 -143
  158. package/security/domain-consensus.js +86 -85
  159. package/security/fs-hardening.js +620 -0
  160. package/security/hardware-attestation.js +5 -3
  161. package/security/hybrid-trust.js +227 -87
  162. package/security/karma-rate-limiter.js +692 -0
  163. package/security/khata-protocol.js +22 -21
  164. package/security/khata-trust-integration.js +277 -150
  165. package/security/memory-safety.js +635 -0
  166. package/security/mesh-auth.js +11 -10
  167. package/security/mesh-revocation.js +373 -5
  168. package/security/namche-gateway.js +298 -69
  169. package/security/sakshi.js +460 -3
  170. package/security/sangha.js +770 -0
  171. package/security/secure-config.js +473 -0
  172. package/security/silicon-parity.js +13 -10
  173. package/security/steadywatch.js +1142 -0
  174. package/security/strike-system.js +32 -3
  175. package/security/temporal-signing.js +488 -0
  176. package/security/trit-commitment.js +464 -0
  177. package/server/crypto/annex.js +247 -0
  178. package/server/darshan-api.js +343 -0
  179. package/server/index.js +3259 -362
  180. package/server/komm-api.js +668 -0
  181. package/utils/accel.js +2273 -0
  182. package/utils/ternary-id.js +79 -0
  183. package/utils/verify-worker.js +57 -0
  184. package/webserver/index.js +95 -5
  185. package/assets/yakmesh-logo.png +0 -0
  186. package/assets/yakmesh-logo.svg +0 -80
  187. package/assets/yakmesh-logo2.png +0 -0
  188. package/assets/yakmesh-logo2sm.png +0 -0
  189. package/assets/ymsm.png +0 -0
  190. package/website/assets/silhouettes/adapters.svg +0 -107
  191. package/website/assets/silhouettes/api-endpoints.svg +0 -115
  192. package/website/assets/silhouettes/atomic-clock.svg +0 -83
  193. package/website/assets/silhouettes/base-camp.svg +0 -81
  194. package/website/assets/silhouettes/bridge.svg +0 -69
  195. package/website/assets/silhouettes/docs-bundle.svg +0 -113
  196. package/website/assets/silhouettes/doko-basket.svg +0 -70
  197. package/website/assets/silhouettes/fortress.svg +0 -93
  198. package/website/assets/silhouettes/gateway.svg +0 -54
  199. package/website/assets/silhouettes/gears.svg +0 -93
  200. package/website/assets/silhouettes/globe-satellite.svg +0 -67
  201. package/website/assets/silhouettes/karma-wheel.svg +0 -137
  202. package/website/assets/silhouettes/lama-council.svg +0 -141
  203. package/website/assets/silhouettes/mandala-network.svg +0 -169
  204. package/website/assets/silhouettes/mani-stones.svg +0 -149
  205. package/website/assets/silhouettes/mantra-wheel.svg +0 -116
  206. package/website/assets/silhouettes/mesh-nodes.svg +0 -113
  207. package/website/assets/silhouettes/nakpak.svg +0 -56
  208. package/website/assets/silhouettes/peak-lightning.svg +0 -73
  209. package/website/assets/silhouettes/sherpa.svg +0 -69
  210. package/website/assets/silhouettes/stupa-tower.svg +0 -119
  211. package/website/assets/silhouettes/tattva-eye.svg +0 -78
  212. package/website/assets/silhouettes/terminal.svg +0 -74
  213. package/website/assets/silhouettes/webserver.svg +0 -145
  214. package/website/assets/silhouettes/yak.svg +0 -78
  215. package/website/assets/yakmesh-logo.png +0 -0
  216. package/website/assets/yakmesh-logo.webp +0 -0
  217. package/website/assets/yakmesh-logo128x140.webp +0 -0
  218. package/website/assets/yakmesh-logo2.png +0 -0
  219. package/website/assets/yakmesh-logo2.svg +0 -51
  220. package/website/assets/yakmesh-logo40x44.webp +0 -0
  221. package/website/assets/yakmesh.gif +0 -0
  222. package/website/assets/yakmesh.ico +0 -0
  223. package/website/assets/yakmesh.jpg +0 -0
  224. package/website/assets/yakmesh.pdf +0 -0
  225. package/website/assets/yakmesh.png +0 -0
  226. package/website/assets/yakmesh.svg +0 -70
  227. package/website/assets/yakmesh128.webp +0 -0
  228. package/website/assets/yakmesh32.png +0 -0
  229. package/website/assets/yakmesh32.svg +0 -65
  230. package/website/assets/yakmesh32o.ico +0 -2
  231. package/website/assets/yakmesh32o.svg +0 -65
  232. package/website/assets/yakmesh32o.svgz +0 -0
@@ -22,6 +22,7 @@
22
22
  import { sha3_256 } from '@noble/hashes/sha3.js';
23
23
  import { bytesToHex, randomBytes, utf8ToBytes } from '@noble/hashes/utils.js';
24
24
  import { EventEmitter } from 'events';
25
+ const peerTag = (id) => id?.split('-pq-').pop() || id?.slice?.(-8) || String(id);
25
26
 
26
27
  // v2.7.0 Ternary Math Integration (TRIBHUJ)
27
28
  import { Trit, TritState, calculatePathBalance, POSITIVE, NEUTRAL, NEGATIVE } from '../oracle/tribhuj.js';
@@ -257,6 +258,11 @@ class BeaconMessage {
257
258
  this.timestamp = options.timestamp || Date.now();
258
259
  this.ttl = options.ttl || 3600; // 1 hour default TTL
259
260
 
261
+ // Explicit reachable endpoints (override auto-constructed from ports)
262
+ // These let nodes behind firewalls/NAT advertise their actual connectable URLs
263
+ this.wsEndpoint = options.wsEndpoint || null; // e.g., "wss://mesh.yakmesh.dev"
264
+ this.relayEndpoint = options.relayEndpoint || null; // e.g., "https://yakmesh.dev/mesh/relay"
265
+
260
266
  // Node capabilities
261
267
  this.capabilities = {
262
268
  wsPort: options.wsPort || null,
@@ -336,6 +342,7 @@ class BeaconMessage {
336
342
  nodeId: peerInfo.nodeId,
337
343
  endpoint: peerInfo.endpoint, // e.g., "https://example.com"
338
344
  wsEndpoint: peerInfo.wsEndpoint, // e.g., "wss://example.com:9001"
345
+ relayEndpoint: peerInfo.relayEndpoint || null, // e.g., "https://example.com/mesh/relay"
339
346
  lastSeen: peerInfo.lastSeen || Date.now(),
340
347
  score: peerInfo.score || 1.0,
341
348
  networkName: peerInfo.networkName,
@@ -363,7 +370,7 @@ class BeaconMessage {
363
370
  * Serialize beacon for HTTP response
364
371
  */
365
372
  serialize() {
366
- return {
373
+ const data = {
367
374
  version: this.version,
368
375
  nodeId: this.nodeId,
369
376
  networkName: this.networkName,
@@ -376,6 +383,12 @@ class BeaconMessage {
376
383
  publicKey: this.publicKey,
377
384
  signature: this.signature,
378
385
  };
386
+
387
+ // Include explicit endpoints if configured (firewall/NAT traversal)
388
+ if (this.wsEndpoint) data.wsEndpoint = this.wsEndpoint;
389
+ if (this.relayEndpoint) data.relayEndpoint = this.relayEndpoint;
390
+
391
+ return data;
379
392
  }
380
393
 
381
394
  /**
@@ -390,6 +403,9 @@ class BeaconMessage {
390
403
  capabilities: this.capabilities,
391
404
  geo: this.geo, // v2.5.0 include geo in signature
392
405
  namche: this.namche, // Include NAMCHE in signature
406
+ // Include endpoints in signature to prevent tampering
407
+ wsEndpoint: this.wsEndpoint || undefined,
408
+ relayEndpoint: this.relayEndpoint || undefined,
393
409
  });
394
410
  }
395
411
 
@@ -402,6 +418,9 @@ class BeaconMessage {
402
418
  networkName: data.networkName,
403
419
  timestamp: data.timestamp,
404
420
  ttl: data.ttl,
421
+ // Explicit reachable endpoints (must match what was signed)
422
+ wsEndpoint: data.wsEndpoint || null,
423
+ relayEndpoint: data.relayEndpoint || null,
405
424
  wsPort: data.capabilities?.wsPort,
406
425
  httpPort: data.capabilities?.httpPort,
407
426
  supportsAnnex: data.capabilities?.supportsAnnex,
@@ -466,6 +485,8 @@ class PeerRegistry {
466
485
  // Update existing peer
467
486
  existing.endpoint = peerInfo.endpoint || existing.endpoint;
468
487
  existing.wsEndpoint = peerInfo.wsEndpoint || existing.wsEndpoint;
488
+ existing.relayEndpoint = peerInfo.relayEndpoint || existing.relayEndpoint;
489
+ existing.publicKey = peerInfo.publicKey || existing.publicKey;
469
490
  existing.lastSeen = Math.max(existing.lastSeen, peerInfo.lastSeen || Date.now());
470
491
  existing.score = Math.min(1.0, existing.score + SHERPA_CONFIG.successBonus);
471
492
  existing.capabilities = peerInfo.capabilities || existing.capabilities;
@@ -479,6 +500,8 @@ class PeerRegistry {
479
500
  nodeId: peerInfo.nodeId,
480
501
  endpoint: peerInfo.endpoint,
481
502
  wsEndpoint: peerInfo.wsEndpoint,
503
+ relayEndpoint: peerInfo.relayEndpoint || null,
504
+ publicKey: peerInfo.publicKey || null,
482
505
  lastSeen: peerInfo.lastSeen || Date.now(),
483
506
  score: peerInfo.score || 1.0,
484
507
  networkName: peerInfo.networkName,
@@ -595,6 +618,7 @@ class SherpaDiscovery extends EventEmitter {
595
618
  // Our own endpoint info
596
619
  this.selfEndpoint = options.selfEndpoint || null; // e.g., "https://mynode.com"
597
620
  this.wsEndpoint = options.wsEndpoint || null;
621
+ this.relayEndpoint = options.relayEndpoint || null; // e.g., "https://mynode.com/mesh/relay"
598
622
  this.capabilities = options.capabilities || {};
599
623
 
600
624
  // v2.5.0 Geographic proof configuration
@@ -688,6 +712,9 @@ class SherpaDiscovery extends EventEmitter {
688
712
  supportsNakpak: this.capabilities.supportsNakpak ?? true,
689
713
  supportsGossip: this.capabilities.supportsGossip ?? true,
690
714
  publicKey: this.publicKey,
715
+ // Explicit reachable endpoints (firewall/NAT traversal)
716
+ wsEndpoint: this.wsEndpoint,
717
+ relayEndpoint: this.relayEndpoint,
691
718
  // v2.5.0 Geographic coordinates (if configured)
692
719
  supportsGeoProof: this.geoConfig.enabled,
693
720
  geoLat: this.geoConfig.lat,
@@ -745,12 +772,16 @@ class SherpaDiscovery extends EventEmitter {
745
772
 
746
773
  // Add the beacon source as a peer
747
774
  if (beacon.nodeId && beacon.nodeId !== this.nodeId) {
775
+ // Prefer explicit wsEndpoint from beacon (firewall/NAT aware)
776
+ // Fall back to auto-constructed from hostname:wsPort
777
+ const autoWsEndpoint = beacon.capabilities?.wsPort
778
+ ? `wss://${new URL(endpoint).hostname}:${beacon.capabilities.wsPort}`
779
+ : null;
748
780
  this.registry.upsert({
749
781
  nodeId: beacon.nodeId,
750
782
  endpoint: endpoint,
751
- wsEndpoint: beacon.capabilities?.wsPort
752
- ? `wss://${new URL(endpoint).hostname}:${beacon.capabilities.wsPort}`
753
- : null,
783
+ wsEndpoint: beacon.wsEndpoint || autoWsEndpoint,
784
+ relayEndpoint: beacon.relayEndpoint || null,
754
785
  networkName: beacon.networkName,
755
786
  capabilities: beacon.capabilities,
756
787
  });
@@ -769,6 +800,7 @@ class SherpaDiscovery extends EventEmitter {
769
800
  nodeId: peer.nodeId,
770
801
  endpoint: peer.endpoint,
771
802
  wsEndpoint: peer.wsEndpoint,
803
+ relayEndpoint: peer.relayEndpoint,
772
804
  networkName: peer.networkName,
773
805
  lastSeen: peer.lastSeen,
774
806
  });
@@ -807,7 +839,54 @@ class SherpaDiscovery extends EventEmitter {
807
839
  * v2.5.0: Also measures RTT for geographic proof
808
840
  */
809
841
  async _fetchBeacon(endpoint) {
810
- const url = new URL(SHERPA_CONFIG.beaconPath, endpoint).toString();
842
+ // ── SSRF Protection: Validate endpoint URL before fetching ──
843
+ // Peer-supplied endpoints could target internal services, cloud metadata,
844
+ // or private networks. Block anything that isn't public HTTP(S).
845
+ let parsedUrl;
846
+ try {
847
+ parsedUrl = new URL(SHERPA_CONFIG.beaconPath, endpoint);
848
+ } catch {
849
+ throw new Error(`Invalid beacon endpoint URL: ${endpoint}`);
850
+ }
851
+
852
+ // Only allow HTTP and HTTPS schemes
853
+ if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
854
+ throw new Error(`Blocked beacon fetch: disallowed scheme ${parsedUrl.protocol}`);
855
+ }
856
+
857
+ // Block private/reserved IP ranges and cloud metadata endpoints
858
+ const hostname = parsedUrl.hostname.toLowerCase();
859
+ const BLOCKED_HOSTS = [
860
+ 'localhost', '127.0.0.1', '::1', '[::1]', '0.0.0.0',
861
+ '169.254.169.254', // AWS/GCP/Azure metadata
862
+ 'metadata.google.internal',
863
+ 'metadata.google',
864
+ ];
865
+ if (BLOCKED_HOSTS.includes(hostname)) {
866
+ throw new Error(`Blocked beacon fetch: reserved host ${hostname}`);
867
+ }
868
+
869
+ // Block private IP ranges: 10.x, 172.16-31.x, 192.168.x, fc00::/7, fe80::/10
870
+ const ipv4Match = hostname.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
871
+ if (ipv4Match) {
872
+ const [, a, b] = ipv4Match.map(Number);
873
+ if (a === 10 || // 10.0.0.0/8
874
+ (a === 172 && b >= 16 && b <= 31) || // 172.16.0.0/12
875
+ (a === 192 && b === 168) || // 192.168.0.0/16
876
+ a === 127 || // 127.0.0.0/8
877
+ a === 0 || // 0.0.0.0/8
878
+ (a === 169 && b === 254)) { // 169.254.0.0/16 (link-local)
879
+ throw new Error(`Blocked beacon fetch: private IP ${hostname}`);
880
+ }
881
+ }
882
+
883
+ // Block IPv6 private: starts with fc, fd, or fe80
884
+ const bareV6 = hostname.replace(/^\[|\]$/g, '');
885
+ if (bareV6.startsWith('fc') || bareV6.startsWith('fd') || bareV6.startsWith('fe80')) {
886
+ throw new Error(`Blocked beacon fetch: private IPv6 ${hostname}`);
887
+ }
888
+
889
+ const url = parsedUrl.toString();
811
890
 
812
891
  const controller = new AbortController();
813
892
  const timeout = setTimeout(() => controller.abort(), SHERPA_CONFIG.crawlTimeout);
@@ -877,14 +956,16 @@ class SherpaDiscovery extends EventEmitter {
877
956
  }
878
957
 
879
958
  /**
880
- * Get connection candidates for mesh networking
959
+ * Get connection candidates for mesh networking.
960
+ * Returns peers that have either a wsEndpoint or relayEndpoint.
881
961
  */
882
962
  getConnectionCandidates(count = 5) {
883
963
  return this.registry.getBestPeers(count)
884
- .filter(p => p.wsEndpoint)
964
+ .filter(p => p.wsEndpoint || p.relayEndpoint)
885
965
  .map(p => ({
886
966
  nodeId: p.nodeId,
887
967
  wsEndpoint: p.wsEndpoint,
968
+ relayEndpoint: p.relayEndpoint || null,
888
969
  score: p.score,
889
970
  }));
890
971
  }
@@ -979,7 +1060,7 @@ class SherpaDiscovery extends EventEmitter {
979
1060
  beacon.geo.lat,
980
1061
  beacon.geo.lon,
981
1062
  {
982
- name: beacon.geo.name || `SHERPA Beacon ${beacon.nodeId.slice(0, 8)}`,
1063
+ name: beacon.geo.name || `SHERPA Beacon ${peerTag(beacon.nodeId)}`,
983
1064
  endpoint: beacon._endpoint,
984
1065
  timeTier: beacon.geo.timeTier,
985
1066
  accuracyKm: beacon.geo.accuracyKm,
@@ -1,11 +1,20 @@
1
1
  /**
2
2
  * Sybil Attack Protection Module
3
+ *
4
+ * Uses TRIBHUJ balanced ternary for connection evaluation:
5
+ * POSITIVE (+1): Accept — node is trusted or verified
6
+ * NEUTRAL ( 0): Challenge — node must prove itself (NAVR required)
7
+ * NEGATIVE (-1): Reject — node is banned or subnet saturated
8
+ *
3
9
  * @module mesh/sybil-defense.js
4
10
  */
5
11
 
6
12
  import { sha3_256 } from '@noble/hashes/sha3.js';
7
13
  import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils.js';
8
14
 
15
+ // ═══ TRIBHUJ — Balanced ternary for connection decisions ═══
16
+ import { POSITIVE, NEUTRAL, NEGATIVE } from '../oracle/tribhuj.js';
17
+
9
18
  export class NAVR {
10
19
  constructor(options = {}) {
11
20
  this.difficulty = options.difficulty || 16;
@@ -125,16 +134,21 @@ export class SybilDefense {
125
134
  this.diversity = new SubnetDiversity(options.diversity || {});
126
135
  }
127
136
 
137
+ /**
138
+ * Evaluate a connection request.
139
+ * Returns `allowed` boolean (backward compat) plus `verdict` trit:
140
+ * POSITIVE: accept, NEUTRAL: challenge required, NEGATIVE: reject
141
+ */
128
142
  evaluateConnection(ip, nodeId, NAVRSolution = null) {
129
143
  const divCheck = this.diversity.allowConnection(ip);
130
- if (!divCheck.allowed) return { allowed: false, reason: divCheck.reason };
144
+ if (!divCheck.allowed) return { allowed: false, verdict: NEGATIVE, reason: divCheck.reason };
131
145
  let record = this.reputation.nodes.get(nodeId);
132
146
  if (!record) record = this.reputation.registerNode(nodeId, NAVRSolution);
133
147
  const trustLevel = this.reputation.getTrustLevel(nodeId);
134
- if (trustLevel === 'banned') return { allowed: false, reason: 'Node is banned' };
135
- if (trustLevel === 'unknown' && !NAVRSolution) return { allowed: false, reason: 'NAVR required', challenge: this.NAVR.createChallenge(nodeId) };
148
+ if (trustLevel === 'banned') return { allowed: false, verdict: NEGATIVE, reason: 'Node is banned' };
149
+ if (trustLevel === 'unknown' && !NAVRSolution) return { allowed: false, verdict: NEUTRAL, reason: 'NAVR required', challenge: this.NAVR.createChallenge(nodeId) };
136
150
  this.diversity.addConnection(ip, nodeId);
137
- return { allowed: true, trustLevel, reputation: record.reputation };
151
+ return { allowed: true, verdict: POSITIVE, trustLevel, reputation: record.reputation };
138
152
  }
139
153
 
140
154
  reportMessage(nodeId, valid) {
@@ -148,4 +162,4 @@ export class SybilDefense {
148
162
  }
149
163
 
150
164
  export default SybilDefense;
151
-
165
+
@@ -20,7 +20,8 @@
20
20
  * @copyright 2026 YAKMESH™ Contributors
21
21
  */
22
22
 
23
- import { randomBytes, createHash } from 'crypto';
23
+ import { createHash } from 'crypto';
24
+ import { ternaryId } from '../utils/ternary-id.js';
24
25
 
25
26
  const TME_CONFIG = {
26
27
  defaultSliceIntervalNs: 50_000_000,
@@ -112,7 +113,7 @@ class TemporalStream {
112
113
  }
113
114
 
114
115
  _generateStreamId() {
115
- return randomBytes(16).toString('hex');
116
+ return ternaryId(16);
116
117
  }
117
118
 
118
119
  encode(message, meshPosition = [0, 0, 0]) {
@@ -287,7 +288,7 @@ class TemporalReconstructor {
287
288
 
288
289
  class TemporalMeshEncoder {
289
290
  constructor(options = {}) {
290
- this.nodeId = options.nodeId || randomBytes(16).toString('hex');
291
+ this.nodeId = options.nodeId || ternaryId(16);
291
292
  this.meshPosition = options.meshPosition || [0, 0, 0];
292
293
  this.reconstructor = new TemporalReconstructor();
293
294
  this.outboundStreams = new Map();