@steve02081504/fount-p2p 0.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 (154) hide show
  1. package/README.md +62 -0
  2. package/core/bytes_codec.mjs +51 -0
  3. package/core/canonical_json.mjs +21 -0
  4. package/core/composite_key.mjs +91 -0
  5. package/core/constants.mjs +53 -0
  6. package/core/entity_id.mjs +53 -0
  7. package/core/entity_id_parse.mjs +40 -0
  8. package/core/evfs_logical_path.mjs +15 -0
  9. package/core/hexIds.mjs +73 -0
  10. package/core/hlc.mjs +114 -0
  11. package/core/random_id.mjs +9 -0
  12. package/crypto/channel.mjs +101 -0
  13. package/crypto/checkpoint_sign.mjs +67 -0
  14. package/crypto/crypto.mjs +158 -0
  15. package/crypto/key.mjs +431 -0
  16. package/dag/canonicalize_row.mjs +65 -0
  17. package/dag/event_query.mjs +15 -0
  18. package/dag/index.mjs +335 -0
  19. package/dag/storage.mjs +333 -0
  20. package/dag/strip_extensions.mjs +18 -0
  21. package/dag/tunables.json +6 -0
  22. package/discovery/bt.mjs +260 -0
  23. package/discovery/index.mjs +134 -0
  24. package/discovery/mdns.mjs +138 -0
  25. package/discovery/nostr.mjs +273 -0
  26. package/entity/files/acl.mjs +38 -0
  27. package/entity/files/evfs.mjs +189 -0
  28. package/entity/files/evfs_ref.mjs +37 -0
  29. package/entity/files/manifest_acl_registry.mjs +93 -0
  30. package/entity/files/replica_host_cache.mjs +46 -0
  31. package/entity/files/url.mjs +19 -0
  32. package/entity/hosting_registry.mjs +47 -0
  33. package/entity/localized_core.mjs +141 -0
  34. package/entity/logical_entity.mjs +25 -0
  35. package/entity/logical_entity_id_registry.mjs +40 -0
  36. package/entity/node_hash.mjs +15 -0
  37. package/entity/presentation_registry.mjs +44 -0
  38. package/entity/profile.mjs +256 -0
  39. package/entity/replica.mjs +20 -0
  40. package/entity/session_snapshot_registry.mjs +38 -0
  41. package/federation/chunk_fetch_pending.mjs +128 -0
  42. package/federation/chunk_fetch_scheduler.mjs +97 -0
  43. package/federation/dag_order_cache.mjs +124 -0
  44. package/federation/dedupe_slot.mjs +33 -0
  45. package/federation/message_rate_limit.mjs +23 -0
  46. package/federation/operator_key_chain.mjs +200 -0
  47. package/federation/topo_order_memo.mjs +44 -0
  48. package/federation/volatile_streams.mjs +52 -0
  49. package/federation/want_ids.mjs +158 -0
  50. package/files/assemble.mjs +220 -0
  51. package/files/assemble_stream.mjs +129 -0
  52. package/files/chunk_fetch.mjs +113 -0
  53. package/files/chunk_fetch_verify.mjs +23 -0
  54. package/files/chunk_provider_registry.mjs +70 -0
  55. package/files/chunk_responder.mjs +79 -0
  56. package/files/chunk_store.mjs +87 -0
  57. package/files/manifest.mjs +99 -0
  58. package/files/transfer_key.mjs +87 -0
  59. package/files/transfer_key_registry.mjs +108 -0
  60. package/governance/branch.mjs +230 -0
  61. package/governance/join_pow.mjs +165 -0
  62. package/governance/owner_succession_ballot.mjs +57 -0
  63. package/governance/tunables.json +7 -0
  64. package/index.mjs +39 -0
  65. package/link/channel_mux.mjs +222 -0
  66. package/link/frame.mjs +246 -0
  67. package/link/handshake.mjs +175 -0
  68. package/link/link.mjs +617 -0
  69. package/link/rtc.mjs +109 -0
  70. package/link/sdp_fingerprint.mjs +25 -0
  71. package/mailbox/consumer_registry.mjs +71 -0
  72. package/mailbox/deliver_or_store.mjs +190 -0
  73. package/mailbox/importance.mjs +72 -0
  74. package/mailbox/parse.mjs +73 -0
  75. package/mailbox/prune.mjs +106 -0
  76. package/mailbox/rate.mjs +86 -0
  77. package/mailbox/settings.mjs +53 -0
  78. package/mailbox/store.mjs +256 -0
  79. package/mailbox/tunables.json +12 -0
  80. package/mailbox/wire.mjs +40 -0
  81. package/node/denylist.mjs +309 -0
  82. package/node/entity_store.mjs +214 -0
  83. package/node/identity.mjs +99 -0
  84. package/node/instance.mjs +115 -0
  85. package/node/network.mjs +306 -0
  86. package/node/personal_block.mjs +286 -0
  87. package/node/reputation_store.mjs +326 -0
  88. package/node/retention_policy.mjs +82 -0
  89. package/node/signaling_config.mjs +32 -0
  90. package/node/storage.mjs +30 -0
  91. package/node/storage_plugins.mjs +71 -0
  92. package/node/user_paths.mjs +10 -0
  93. package/overlay/index.mjs +191 -0
  94. package/package.json +73 -0
  95. package/permissions/bitmask.mjs +35 -0
  96. package/permissions/evaluator.mjs +90 -0
  97. package/permissions/index.mjs +12 -0
  98. package/permissions/layered.mjs +39 -0
  99. package/registries/action.mjs +94 -0
  100. package/registries/event_type.mjs +75 -0
  101. package/registries/inbound.mjs +90 -0
  102. package/registries/p2p_viewer.mjs +35 -0
  103. package/registries/part_path.mjs +35 -0
  104. package/registries/room_provider.mjs +47 -0
  105. package/reputation/engine.mjs +458 -0
  106. package/reputation/math.mjs +73 -0
  107. package/reputation/pick_score.mjs +11 -0
  108. package/reputation/relay_dedupe.mjs +22 -0
  109. package/reputation/tunables.json +36 -0
  110. package/rooms/scoped_link.mjs +185 -0
  111. package/schemas/discovery.mjs +110 -0
  112. package/schemas/federation_pull.mjs +102 -0
  113. package/schemas/mailbox.mjs +37 -0
  114. package/schemas/remote_event.mjs +17 -0
  115. package/timeline/append_core.mjs +54 -0
  116. package/timeline/materialize_runner.mjs +26 -0
  117. package/timeline/prune.mjs +39 -0
  118. package/timeline/retention.mjs +54 -0
  119. package/timeline/retention_runner.mjs +35 -0
  120. package/timeline/verify_remote.mjs +25 -0
  121. package/transport/group_link_set.mjs +324 -0
  122. package/transport/ice_servers.mjs +72 -0
  123. package/transport/link_registry.mjs +749 -0
  124. package/transport/peer_identity_maps.mjs +94 -0
  125. package/transport/peer_pool.mjs +355 -0
  126. package/transport/remote_user_room.mjs +109 -0
  127. package/transport/room_scopes.mjs +2 -0
  128. package/transport/room_wire_action.mjs +19 -0
  129. package/transport/rtc_connection_budget.mjs +180 -0
  130. package/transport/rtc_mdns_filter.mjs +118 -0
  131. package/transport/stale_peer_log.mjs +50 -0
  132. package/transport/user_room.mjs +263 -0
  133. package/trust_graph/build.mjs +99 -0
  134. package/trust_graph/cache.mjs +44 -0
  135. package/trust_graph/engine.mjs +184 -0
  136. package/trust_graph/registry.mjs +38 -0
  137. package/trust_graph/resolve.mjs +105 -0
  138. package/trust_graph/send.mjs +88 -0
  139. package/trust_graph/tunables.json +13 -0
  140. package/utils/async_mutex.mjs +69 -0
  141. package/utils/debug_log.mjs +16 -0
  142. package/utils/duration.mjs +28 -0
  143. package/utils/json_io.mjs +57 -0
  144. package/utils/lru.mjs +22 -0
  145. package/utils/map_pool.mjs +27 -0
  146. package/wire/group_part.mjs +43 -0
  147. package/wire/ingress.mjs +58 -0
  148. package/wire/part_common.mjs +55 -0
  149. package/wire/part_fanout.mjs +71 -0
  150. package/wire/part_ingress.mjs +172 -0
  151. package/wire/part_invoke.mjs +81 -0
  152. package/wire/rate_bucket.mjs +49 -0
  153. package/wire/volatile_signature.mjs +76 -0
  154. package/wire/wait.mjs +127 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * VOLATILE 流式分片签名域(§6.4):`pendingStreamId + chunkSeq + slices`。
3
+ */
4
+ import { Buffer } from 'node:buffer'
5
+ import { createHash } from 'node:crypto'
6
+
7
+ import { isHex64, isSignatureHex128 } from '../core/hexIds.mjs'
8
+ import { keyPairFromSeed, sign, verify } from '../crypto/crypto.mjs'
9
+
10
+ const CHUNK_DOMAIN = 'fount-volatile-chunk'
11
+
12
+ /** 入站 stream_chunk 切片数量上限。 */
13
+ export const MAX_STREAM_VOLATILE_SLICES = 256
14
+
15
+ /**
16
+ * @param {unknown} slices 入站切片
17
+ * @returns {object[] | null} 合法切片或 null
18
+ */
19
+ export function boundStreamSlices(slices) {
20
+ if (!Array.isArray(slices) || slices.length > MAX_STREAM_VOLATILE_SLICES) return null
21
+ return slices
22
+ }
23
+
24
+ /**
25
+ * @param {string} pendingStreamId 逻辑流 id
26
+ * @param {number} chunkSeq 分片序号(从 1 递增)
27
+ * @param {object[]} slices 差异切片数组
28
+ * @returns {Uint8Array} 验签消息字节
29
+ */
30
+ export function streamChunkSignBytes(pendingStreamId, chunkSeq, slices) {
31
+ const streamId = String(pendingStreamId ?? '')
32
+ const sequence = Number.isFinite(Number(chunkSeq)) ? String(chunkSeq) : '0'
33
+ const body = JSON.stringify(slices ?? [])
34
+ return new TextEncoder().encode(`${CHUNK_DOMAIN}\0${streamId}\0${sequence}\0${body}`)
35
+ }
36
+
37
+ /**
38
+ * @param {Uint8Array} bytes 签名域
39
+ * @param {Uint8Array} secretKey 私钥种子(32 字节)
40
+ * @returns {Promise<string>} 128 位 hex 签名
41
+ */
42
+ export async function signStreamSignatureHex(bytes, secretKey) {
43
+ const signatureBytes = await sign(bytes, secretKey)
44
+ return Buffer.from(signatureBytes).toString('hex')
45
+ }
46
+
47
+ /**
48
+ * @param {Uint8Array} bytes 签名域
49
+ * @param {string} signatureHex 128 位十六进制 签名
50
+ * @param {string} publicKeyHex 64 位十六进制 公钥
51
+ * @returns {Promise<boolean>} 验签是否通过
52
+ */
53
+ export async function verifyStreamSignatureHex(bytes, signatureHex, publicKeyHex) {
54
+ const signature = String(signatureHex || '').trim().toLowerCase()
55
+ const publicKey = String(publicKeyHex || '').trim().toLowerCase()
56
+ if (!isSignatureHex128(signature) || !isHex64(publicKey)) return false
57
+ try {
58
+ return await verify(Buffer.from(signature, 'hex'), bytes, Buffer.from(publicKey, 'hex'))
59
+ }
60
+ catch {
61
+ return false
62
+ }
63
+ }
64
+
65
+ /**
66
+ * 本节点出站 VOLATILE 签名密钥(由用户名 + 联邦口令材料确定性派生)。
67
+ * @param {string} username 用户
68
+ * @param {string} seedMaterial 口令或回退材料
69
+ * @returns {{ publicKey: Uint8Array, secretKey: Uint8Array }} 密钥对
70
+ */
71
+ export function streamKeyPairFromUserSeed(username, seedMaterial) {
72
+ const user = String(username ?? '')
73
+ const material = String(seedMaterial ?? '')
74
+ const seed = createHash('sha256').update(`fount-stream-sign\0${user}\0${material}`).digest()
75
+ return keyPairFromSeed(seed)
76
+ }
package/wire/wait.mjs ADDED
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Trystero 请求-响应等待表(gossip、channel history 等共用)。
3
+ */
4
+
5
+ /**
6
+ * @typedef {{ resolve: (value?: unknown) => void, timer: ReturnType<typeof setTimeout> }} WireWaiter
7
+ */
8
+
9
+ /**
10
+ * @param {Map<string, unknown>} pending 等待表
11
+ * @param {string} key 等待键
12
+ * @param {number} timeoutMs 超时毫秒
13
+ * @param {() => unknown} onTimeout 超时回调值
14
+ * @returns {{ resolve: (value: unknown) => void, promise: Promise<unknown> }} 等待句柄
15
+ */
16
+ export function registerWireWait(pending, key, timeoutMs, onTimeout) {
17
+ const waitPromise = new Promise(resolve => {
18
+ const timer = setTimeout(() => {
19
+ pending.delete(key)
20
+ resolve(onTimeout())
21
+ }, timeoutMs)
22
+ pending.set(key, {
23
+ /** @param {unknown} value 应答值 */
24
+ resolve: value => {
25
+ clearTimeout(timer)
26
+ pending.delete(key)
27
+ resolve(value)
28
+ },
29
+ timer,
30
+ })
31
+ })
32
+ const entry = pending.get(key)
33
+ return {
34
+ resolve: entry.resolve,
35
+ promise: waitPromise,
36
+ }
37
+ }
38
+
39
+ /**
40
+ * @param {Map<string, Map<string, WireWaiter[]>>} pending 按前缀分桶的多 waiter 表
41
+ * @param {string} keyPrefix 键前缀(如 `user\0group\0`)
42
+ * @param {string} suffixKey 后缀键
43
+ * @returns {Map<string, WireWaiter[]>} 后缀桶
44
+ */
45
+ function ensurePrefixBucket(pending, keyPrefix, suffixKey) {
46
+ let bucket = pending.get(keyPrefix)
47
+ if (!bucket) {
48
+ bucket = new Map()
49
+ pending.set(keyPrefix, bucket)
50
+ }
51
+ return bucket
52
+ }
53
+
54
+ /**
55
+ * 多 waiter 注册(gossip 等同键并发等待)。
56
+ * @param {Map<string, Map<string, WireWaiter[]>>} pending 多 waiter 表
57
+ * @param {string} keyPrefix 键前缀
58
+ * @param {string} suffixKey 后缀键
59
+ * @param {number} timeoutMs 超时毫秒
60
+ * @param {() => unknown} [onTimeout] 超时返回值
61
+ * @returns {Promise<unknown>} 完成 promise
62
+ */
63
+ export function registerMultiWireWait(pending, keyPrefix, suffixKey, timeoutMs, onTimeout = () => undefined) {
64
+ return new Promise(resolve => {
65
+ const timer = setTimeout(() => {
66
+ finishMultiWireWaiters(pending, keyPrefix, suffixKey)
67
+ resolve(onTimeout())
68
+ }, timeoutMs)
69
+ const bucket = ensurePrefixBucket(pending, keyPrefix, suffixKey)
70
+ let waiters = bucket.get(suffixKey)
71
+ if (!waiters) {
72
+ waiters = []
73
+ bucket.set(suffixKey, waiters)
74
+ }
75
+ waiters.push({ resolve, timer })
76
+ })
77
+ }
78
+
79
+ /**
80
+ * @param {Map<string, Map<string, WireWaiter[]>>} pending 多 waiter 表
81
+ * @param {string} keyPrefix 键前缀
82
+ * @param {string} suffixKey 后缀键
83
+ * @returns {void}
84
+ */
85
+ export function finishMultiWireWaiters(pending, keyPrefix, suffixKey) {
86
+ const bucket = pending.get(keyPrefix)
87
+ const waiters = bucket?.get(suffixKey)
88
+ if (!waiters?.length) return
89
+ bucket.delete(suffixKey)
90
+ if (!bucket.size) pending.delete(keyPrefix)
91
+ for (const waiter of waiters) {
92
+ clearTimeout(waiter.timer)
93
+ waiter.resolve()
94
+ }
95
+ }
96
+
97
+ /**
98
+ * 前缀桶内按 want id 命中唤醒 waiter。
99
+ * @param {Map<string, Map<string, WireWaiter[]>>} pending 多 waiter 表
100
+ * @param {string} keyPrefix 键前缀
101
+ * @param {ReadonlySet<string>} hitIds 命中 id 集合
102
+ * @param {(suffixKey: string) => string[] | null} parseWantIds 从后缀键解析 want id 列表
103
+ * @returns {void}
104
+ */
105
+ export function notifyMultiWireWaitersByPrefix(pending, keyPrefix, hitIds, parseWantIds) {
106
+ if (!hitIds.size) return
107
+ const bucket = pending.get(keyPrefix)
108
+ if (!bucket) return
109
+ for (const [suffixKey, waiters] of bucket) {
110
+ const wanted = parseWantIds(suffixKey)
111
+ if (!wanted?.length) continue
112
+ let hit = false
113
+ for (const id of hitIds)
114
+ if (wanted.includes(id)) {
115
+ hit = true
116
+ break
117
+ }
118
+
119
+ if (!hit) continue
120
+ bucket.delete(suffixKey)
121
+ for (const waiter of waiters) {
122
+ clearTimeout(waiter.timer)
123
+ waiter.resolve()
124
+ }
125
+ }
126
+ if (!bucket.size) pending.delete(keyPrefix)
127
+ }