@steve02081504/fount-p2p 0.0.35 → 0.0.36

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 (51) hide show
  1. package/AGENTS.md +1 -1
  2. package/core/entity_id.mjs +6 -6
  3. package/core/entity_id_parse.mjs +7 -7
  4. package/core/hexIds.mjs +6 -18
  5. package/crypto/checkpoint_sign.mjs +4 -4
  6. package/dag/canonicalize_row.mjs +4 -7
  7. package/discovery/adverts.mjs +1 -2
  8. package/discovery/bt/index.mjs +11 -11
  9. package/discovery/bt/peer_hints.mjs +4 -7
  10. package/discovery/index.mjs +8 -12
  11. package/discovery/internal/signal_crypto.mjs +1 -2
  12. package/discovery/lan.mjs +7 -9
  13. package/discovery/lan_peer_hints.mjs +5 -8
  14. package/discovery/nostr.mjs +19 -20
  15. package/discovery/peer_clue.mjs +1 -4
  16. package/federation/entity_key_chain.mjs +10 -9
  17. package/federation/message_rate_limit.mjs +1 -3
  18. package/files/manifest/normalize.mjs +2 -2
  19. package/files/manifest/public.mjs +5 -5
  20. package/governance/branch.mjs +1 -2
  21. package/governance/join_pow.mjs +2 -4
  22. package/governance/owner_succession_ballot.mjs +5 -5
  23. package/infra/priority.mjs +1 -2
  24. package/link/handshake.mjs +21 -21
  25. package/link/pipe.mjs +1 -2
  26. package/link/providers/ble_gatt.mjs +2 -3
  27. package/link/providers/lan_tcp.mjs +2 -3
  28. package/link/providers/link_id_pipe.mjs +3 -3
  29. package/link/providers/nostr.mjs +6 -6
  30. package/mailbox/deliver_or_store.mjs +11 -11
  31. package/mailbox/prune.mjs +3 -4
  32. package/mailbox/rate.mjs +3 -2
  33. package/mailbox/store.mjs +6 -9
  34. package/node/denylist.mjs +25 -28
  35. package/node/identity.mjs +6 -6
  36. package/node/network.mjs +12 -12
  37. package/node/personal_block.mjs +4 -4
  38. package/node/reputation_store.mjs +13 -13
  39. package/node/reputation_sync.mjs +9 -10
  40. package/package.json +1 -1
  41. package/reputation/engine.mjs +14 -16
  42. package/schemas/discovery.mjs +5 -6
  43. package/schemas/federation_pull.mjs +7 -7
  44. package/schemas/mailbox.mjs +3 -3
  45. package/schemas/part_query.mjs +5 -5
  46. package/timeline/verify_remote.mjs +7 -7
  47. package/transport/link_registry.mjs +16 -19
  48. package/transport/mesh_keepalive.mjs +8 -11
  49. package/transport/offer_answer.mjs +3 -3
  50. package/transport/peer_health.mjs +12 -15
  51. package/trust_graph/send.mjs +3 -3
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { Buffer } from 'node:buffer'
5
5
 
6
- import { isHex64, isSignatureHex128, normalizeHex64 } from '../core/hexIds.mjs'
6
+ import { isHex64, isSignatureHex128 } from '../core/hexIds.mjs'
7
7
  import { pubKeyHash, verify } from '../crypto/crypto.mjs'
8
8
  import { eventBodyForSign, signPayloadBytes } from '../dag/index.mjs'
9
9
 
@@ -12,12 +12,12 @@ import { eventBodyForSign, signPayloadBytes } from '../dag/index.mjs'
12
12
  * @returns {Promise<boolean>} 验签是否通过
13
13
  */
14
14
  export async function verifyTimelineRemoteSignature(event) {
15
- const sender = normalizeHex64(event?.sender)
16
- if (!isHex64(sender)) return false
17
- const signatureHex = String(event?.signature || '')
18
- if (!isSignatureHex128(signatureHex)) return false
19
- const pubKeyHex = normalizeHex64(event?.senderPubKey)
20
- if (!isHex64(pubKeyHex)) return false
15
+ const sender = isHex64(event?.sender)
16
+ if (!sender) return false
17
+ const signatureHex = isSignatureHex128(event?.signature)
18
+ if (!signatureHex) return false
19
+ const pubKeyHex = isHex64(event?.senderPubKey)
20
+ if (!pubKeyHex) return false
21
21
  const publicKeyBytes = new Uint8Array(Buffer.from(pubKeyHex, 'hex'))
22
22
  if (pubKeyHash(publicKeyBytes) !== sender) return false
23
23
  const signatureBytes = new Uint8Array(Buffer.from(signatureHex, 'hex'))
@@ -1,6 +1,6 @@
1
1
  import { Buffer } from 'node:buffer'
2
2
 
3
- import { compareHex64Asc, normalizeHex64 } from '../core/hexIds.mjs'
3
+ import { compareHex64Asc, isHex64 } from '../core/hexIds.mjs'
4
4
  import { keyPairFromSeed } from '../crypto/crypto.mjs'
5
5
  import { noteAdvertPeerHints } from '../discovery/advert_peer_hints.mjs'
6
6
  import { watchVerifiedNodeAdvert, setDiscoveryLinkDialer, prepareConnectToNode } from '../discovery/index.mjs'
@@ -34,8 +34,8 @@ const DIAL_COOLDOWN_MAX_MS = ms('10m')
34
34
  function resolveLocalIdentity(localIdentity) {
35
35
  if (localIdentity?.nodeHash && localIdentity?.nodePubKey && localIdentity?.secretKey)
36
36
  return {
37
- nodeHash: normalizeHex64(localIdentity.nodeHash),
38
- nodePubKey: normalizeHex64(localIdentity.nodePubKey),
37
+ nodeHash: localIdentity.nodeHash,
38
+ nodePubKey: localIdentity.nodePubKey,
39
39
  secretKey: localIdentity.secretKey,
40
40
  }
41
41
  const secretKey = Buffer.from(ensureNodeSeed(), 'hex')
@@ -154,7 +154,7 @@ export function createLinkRegistry(options = {}) {
154
154
  * @returns {Promise<void>}
155
155
  */
156
156
  async function registerResolvedLink(remoteNodeHash, candidate) {
157
- const normalized = normalizeHex64(remoteNodeHash)
157
+ const normalized = remoteNodeHash
158
158
  const existing = links.get(normalized)
159
159
  if (existing && existing !== candidate && !linkIsPreferred(candidate, normalized, existing)) {
160
160
  await candidate.close(candidate.level !== existing.level ? 'provider-loser' : 'glare-loser')
@@ -176,7 +176,7 @@ export function createLinkRegistry(options = {}) {
176
176
  void (async () => {
177
177
  try {
178
178
  await link.ready
179
- const remote = normalizeHex64(link.nodeHash)
179
+ const remote = isHex64(link.nodeHash)
180
180
  if (!remote) {
181
181
  await link.close('inbound-no-nodehash')
182
182
  return
@@ -241,7 +241,7 @@ export function createLinkRegistry(options = {}) {
241
241
  * @param {string} remoteNodeHash 远端 nodeHash
242
242
  * @returns {object | null} 已有规范链路
243
243
  */
244
- getCanonicalLink: remoteNodeHash => links.get(normalizeHex64(remoteNodeHash)),
244
+ getCanonicalLink: remoteNodeHash => links.get(remoteNodeHash),
245
245
  }))
246
246
 
247
247
  /**
@@ -271,7 +271,7 @@ export function createLinkRegistry(options = {}) {
271
271
  async function ensureDirectLinkToNode(remoteNodeHash) {
272
272
  await bootstrap.ensureRuntime()
273
273
  await bootstrap.whenSignalListening()
274
- const normalized = normalizeHex64(remoteNodeHash)
274
+ const normalized = remoteNodeHash
275
275
  if (!normalized || normalized === localIdentity.nodeHash) return null
276
276
  if (links.has(normalized)) return links.get(normalized)
277
277
  if (inflights.has(normalized)) return await inflights.get(normalized)
@@ -356,7 +356,7 @@ export function createLinkRegistry(options = {}) {
356
356
  * @param {string} nodeHash 目标 nodeHash
357
357
  * @returns {object | null} 已有链路或 null
358
358
  */
359
- getLink: nodeHash => links.get(normalizeHex64(nodeHash)) || null,
359
+ getLink: nodeHash => links.get(nodeHash) || null,
360
360
  ensureLinkToNode: ensureDirectLinkToNode,
361
361
  /**
362
362
  * @param {(nodeHash: string) => void} listener link up 回调
@@ -380,10 +380,9 @@ export function createLinkRegistry(options = {}) {
380
380
  exploreLinkHashes = meshKeepalive.exploreLinkHashes
381
381
  setDiscoveryLinkDialer(ensureDirectLinkToNode)
382
382
  setDiscoveryPeerClueListener(nodeHash => {
383
- const hash = normalizeHex64(nodeHash)
384
- if (!hash) return
385
- dialCooldown.delete(hash)
386
- recentAdverts.touch(hash, Date.now())
383
+ if (!nodeHash) return
384
+ dialCooldown.delete(nodeHash)
385
+ recentAdverts.touch(nodeHash, Date.now())
387
386
  })
388
387
 
389
388
  /**
@@ -401,7 +400,7 @@ export function createLinkRegistry(options = {}) {
401
400
  * @returns {Promise<boolean>} 是否发送成功
402
401
  */
403
402
  async function sendDirectToNodeLink(remoteNodeHash, envelope) {
404
- const normalized = normalizeHex64(remoteNodeHash)
403
+ const normalized = remoteNodeHash
405
404
  if (!normalized) return false
406
405
  const link = links.get(normalized)
407
406
  if (!link) return false
@@ -591,7 +590,7 @@ export function createLinkRegistry(options = {}) {
591
590
  * @returns {object | null} 链路实例;不存在时 null
592
591
  */
593
592
  getLink(nodeHash) {
594
- return links.get(normalizeHex64(nodeHash)) || null
593
+ return links.get(nodeHash) || null
595
594
  },
596
595
  /**
597
596
  * 列出所有活跃链路。
@@ -607,8 +606,7 @@ export function createLinkRegistry(options = {}) {
607
606
  * @returns {Promise<void>}
608
607
  */
609
608
  async closeLink(nodeHash, reason = 'manual-close') {
610
- const normalized = normalizeHex64(nodeHash)
611
- const link = links.get(normalized)
609
+ const link = links.get(nodeHash)
612
610
  if (!link) return
613
611
  await link.close(reason)
614
612
  },
@@ -638,7 +636,7 @@ export function createLinkRegistry(options = {}) {
638
636
  * @returns {void}
639
637
  */
640
638
  registerScopeInterest(scope, nodeHashes) {
641
- scopeInterests.set(scope, new Set((nodeHashes || []).map(normalizeHex64).filter(Boolean)))
639
+ scopeInterests.set(scope, new Set((nodeHashes || []).filter(isHex64)))
642
640
  },
643
641
  /**
644
642
  * 释放 scope 兴趣。
@@ -673,8 +671,7 @@ export function createLinkRegistry(options = {}) {
673
671
  * @returns {Promise<() => void>} 取消函数
674
672
  */
675
673
  async watchNodeAdvert(nodeHash, onAdvert) {
676
- const hash = normalizeHex64(nodeHash)
677
- return await watchVerifiedNodeAdvert(hash, async (verifiedNodeHash, body, meta) => {
674
+ return await watchVerifiedNodeAdvert(nodeHash, async (verifiedNodeHash, body, meta) => {
678
675
  noteAdvertPeerHints(verifiedNodeHash, body, meta)
679
676
  recentAdverts.touch(verifiedNodeHash, Date.now())
680
677
  dialCooldown.delete(verifiedNodeHash)
@@ -1,4 +1,3 @@
1
- import { normalizeHex64 } from '../core/hexIds.mjs'
2
1
  import { listVisibleNodeHashes as discoveryListVisible } from '../discovery/index.mjs'
3
2
  import { nodeDebug, shortHash } from '../node/log.mjs'
4
3
  import { applyNetworkHint, loadPeerPoolView, promoteExplorePeer } from '../node/network.mjs'
@@ -54,15 +53,14 @@ export function createMeshKeepalive(deps) {
54
53
  * @returns {void}
55
54
  */
56
55
  function syncExploreMark(nodeHash, trustedPeers) {
57
- const hash = normalizeHex64(nodeHash)
58
- if (!hash) return
56
+ if (!nodeHash) return
59
57
  const trusted = trustedPeers ?? loadPeerPoolView().trustedPeers
60
- if (trusted.includes(hash)) {
61
- exploreLinks.delete(hash)
62
- exploreStableSince.delete(hash)
58
+ if (trusted.includes(nodeHash)) {
59
+ exploreLinks.delete(nodeHash)
60
+ exploreStableSince.delete(nodeHash)
63
61
  return
64
62
  }
65
- exploreLinks.add(hash)
63
+ exploreLinks.add(nodeHash)
66
64
  }
67
65
 
68
66
  /**
@@ -187,10 +185,9 @@ export function createMeshKeepalive(deps) {
187
185
  syncExploreMark(nodeHash)
188
186
  }) ?? null
189
187
  stopLinkDown = registry.onLinkDown((nodeHash, reason) => {
190
- const hash = normalizeHex64(nodeHash)
191
- exploreLinks.delete(hash)
192
- exploreStableSince.delete(hash)
193
- nodeDebug('p2p:mesh link down', { peer: shortHash(hash), reason })
188
+ exploreLinks.delete(nodeHash)
189
+ exploreStableSince.delete(nodeHash)
190
+ nodeDebug('p2p:mesh link down', { peer: shortHash(nodeHash), reason })
194
191
  // 主动关链不立刻补洞(避免 budget-evict 刚踢又连);意外断链用 tick 按 N/K 重选,而非粘住原对端。
195
192
  if (isMeshIntentionalClose(reason)) return
196
193
  void runTick()
@@ -1,6 +1,6 @@
1
1
  import { randomBytes } from 'node:crypto'
2
2
 
3
- import { normalizeHex64 } from '../core/hexIds.mjs'
3
+ import { isHex64 } from '../core/hexIds.mjs'
4
4
  import { decryptNodeSignalPacket, sendNodeSignalPacket } from '../discovery/index.mjs'
5
5
  import { listLinkProviders } from '../link/providers/index.mjs'
6
6
  import { nodeDebug, shortHash } from '../node/log.mjs'
@@ -92,7 +92,7 @@ export function createOfferAnswerDial(deps) {
92
92
  * @returns {ReturnType<typeof createBufferedSignalSession>} 该连接的缓冲信令会话
93
93
  */
94
94
  function createConnSession(remoteNodeHash, connId) {
95
- const normalized = normalizeHex64(remoteNodeHash)
95
+ const normalized = remoteNodeHash
96
96
  return createBufferedSignalSession(async message => {
97
97
  await sendNodeSignalPacket(normalized, {
98
98
  type: 'signal',
@@ -153,7 +153,7 @@ export function createOfferAnswerDial(deps) {
153
153
  */
154
154
  async function handleSignalPacket(packet) {
155
155
  if (packet?.type !== 'signal') return
156
- const remoteNodeHash = normalizeHex64(packet.from)
156
+ const remoteNodeHash = isHex64(packet.from)
157
157
  const connId = String(packet.connId || '')
158
158
  if (!remoteNodeHash || remoteNodeHash === localIdentity.nodeHash || !connId) return
159
159
  let session = signalSessions.get(connId)
@@ -1,4 +1,3 @@
1
- import { normalizeHex64 } from '../core/hexIds.mjs'
2
1
  import { emitSafe } from '../utils/emit_safe.mjs'
3
2
 
4
3
  /**
@@ -56,37 +55,35 @@ export function createPeerHealthTracker(registry) {
56
55
  }
57
56
 
58
57
  const stopUp = registry.onLinkUp?.((nodeHash, link) => {
59
- const hash = normalizeHex64(nodeHash)
60
- if (!hash) return
58
+ if (!nodeHash) return
61
59
  const stopRtt = link?.onRtt?.(() => {
62
60
  const stats = link.stats?.() ?? {}
63
- update(hash, {
61
+ update(nodeHash, {
64
62
  rttMs: stats.rttMs ?? null,
65
63
  avgRttMs: stats.avgRttMs ?? null,
66
64
  lastSeenAt: Date.now(),
67
65
  })
68
66
  }) ?? null
69
67
  const stopDown = link?.onDown?.(() => {
70
- cleanups.get(hash)?.()
71
- cleanups.delete(hash)
72
- update(hash, { connected: false, lastSeenAt: Date.now() })
68
+ cleanups.get(nodeHash)?.()
69
+ cleanups.delete(nodeHash)
70
+ update(nodeHash, { connected: false, lastSeenAt: Date.now() })
73
71
  }) ?? null
74
- update(hash, {
72
+ update(nodeHash, {
75
73
  connected: true,
76
74
  source: link?.providerId ?? null,
77
75
  lastSeenAt: Date.now(),
78
76
  })
79
- cleanups.set(hash, () => {
77
+ cleanups.set(nodeHash, () => {
80
78
  stopRtt?.()
81
79
  stopDown?.()
82
80
  })
83
81
  }) ?? null
84
82
  const stopDown = registry.onLinkDown?.(nodeHash => {
85
- const hash = normalizeHex64(nodeHash)
86
- if (!hash) return
87
- cleanups.get(hash)?.()
88
- cleanups.delete(hash)
89
- update(hash, { connected: false, lastSeenAt: Date.now() })
83
+ if (!nodeHash) return
84
+ cleanups.get(nodeHash)?.()
85
+ cleanups.delete(nodeHash)
86
+ update(nodeHash, { connected: false, lastSeenAt: Date.now() })
90
87
  }) ?? null
91
88
 
92
89
  return {
@@ -95,7 +92,7 @@ export function createPeerHealthTracker(registry) {
95
92
  * @returns {PeerHealthEntry | null} 健康记录;无记录时 null
96
93
  */
97
94
  getPeerHealth(nodeHash) {
98
- return entries.get(normalizeHex64(nodeHash)) ?? null
95
+ return entries.get(nodeHash) ?? null
99
96
  },
100
97
  /**
101
98
  * @returns {PeerHealthEntry[]} 所有邻居健康记录
@@ -1,4 +1,4 @@
1
- import { isHex64, normalizeHex64 } from '../core/hexIds.mjs'
1
+ import { isHex64 } from '../core/hexIds.mjs'
2
2
  import { getNodeHash } from '../node/identity.mjs'
3
3
  import { loadReputation } from '../node/reputation_store.mjs'
4
4
  import { listFederationRoomSlots } from '../registries/room_provider.mjs'
@@ -20,8 +20,8 @@ import trustGraphTunables from './tunables.json' with { type: 'json' }
20
20
  * @returns {Promise<boolean>} 是否已发送
21
21
  */
22
22
  export async function sendToNode(username, targetNodeHash, actionName, payload, graph) {
23
- const target = normalizeHex64(targetNodeHash)
24
- if (!isHex64(target)) return false
23
+ const target = isHex64(targetNodeHash)
24
+ if (!target) return false
25
25
 
26
26
  // 已直连 peer 不经 trust-graph scope 也应能收发 node scope action(非成员 CAS chunk / follow hint 等)
27
27
  if (await sendToNodeLink(target, { scope: 'node', action: actionName, payload }))