@steve02081504/fount-p2p 0.0.5 → 0.0.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.
@@ -91,12 +91,12 @@ function activeLinkRoster() {
91
91
 
92
92
  /**
93
93
  * 初始化 node scope 订阅与 wire 派发(幂等)。
94
- * @param {{ replicaUsername?: string }} ctx 入站上下文
94
+ * @param {{ replicaUsername?: string }} wireContext 入站上下文
95
95
  * @returns {Promise<void>}
96
96
  */
97
- async function ensureNodeScopeRuntime(ctx) {
97
+ async function ensureNodeScopeRuntime(wireContext) {
98
98
  if (nodeScopeCleanup) return
99
- nodeScopeReplicaUsername = String(ctx.replicaUsername || nodeScopeReplicaUsername || '')
99
+ nodeScopeReplicaUsername = String(wireContext.replicaUsername || nodeScopeReplicaUsername || '')
100
100
  nodeScopeCleanup = subscribeScope('node', (senderNodeHash, envelope) => {
101
101
  const handlers = nodeActionHandlers.get(String(envelope?.action || ''))
102
102
  if (!handlers?.size) return
@@ -105,12 +105,12 @@ async function ensureNodeScopeRuntime(ctx) {
105
105
  })
106
106
  const wire = createNodeScopeWire()
107
107
  nodeScopeWire = wire
108
- attachPartWire({ replicaUsername: ctx.replicaUsername }, wire)
109
- attachPartQueryWire({ replicaUsername: ctx.replicaUsername }, wire)
110
- attachMailboxWire({ replicaUsername: ctx.replicaUsername }, wire)
111
- attachUserRoomChunkHandlers(ctx.replicaUsername || '', wire)
108
+ attachPartWire({ replicaUsername: wireContext.replicaUsername }, wire)
109
+ attachPartQueryWire({ replicaUsername: wireContext.replicaUsername }, wire)
110
+ attachMailboxWire({ replicaUsername: wireContext.replicaUsername }, wire)
111
+ attachUserRoomChunkHandlers(wireContext.replicaUsername || '', wire)
112
112
  for (const hook of nodeScopeWireHooks)
113
- try { hook(ctx.replicaUsername || '', wire) } catch { /* ignore */ }
113
+ try { hook(wireContext.replicaUsername || '', wire) } catch { /* ignore */ }
114
114
  }
115
115
 
116
116
  /**
@@ -162,10 +162,10 @@ export function resolveUserRoomCredentials() {
162
162
  }
163
163
 
164
164
  /**
165
- * @param {{ replicaUsername?: string }} [ctx] 入站上下文(part/mailbox 派发用)
165
+ * @param {{ replicaUsername?: string }} [wireContext] 入站上下文(part/mailbox 派发用)
166
166
  * @returns {Promise<UserRoomSlot | null>} 用户级联邦房间槽
167
167
  */
168
- export async function ensureUserRoom(ctx = {}) {
168
+ export async function ensureUserRoom(wireContext = {}) {
169
169
  if (userRoomSlot) return userRoomSlot
170
170
  if (userRoomInflight) return await userRoomInflight
171
171
 
@@ -173,7 +173,7 @@ export async function ensureUserRoom(ctx = {}) {
173
173
  ensureNodeDefaults()
174
174
  try {
175
175
  await getLinkRegistry().ensureRuntime()
176
- await ensureNodeScopeRuntime(ctx)
176
+ await ensureNodeScopeRuntime(wireContext)
177
177
  const creds = resolveUserRoomCredentials()
178
178
  /** @type {UserRoomSlot} */
179
179
  userRoomSlot = {
@@ -238,9 +238,7 @@ export async function deliverToUserRoomPeers(username, actionName, payload, exce
238
238
  .filter(({ peerId }) => peerId && peerId !== exceptPeerId)]
239
239
  for (let swapIndex = peers.length - 1; swapIndex > 0; swapIndex--) {
240
240
  const pickIndex = Math.floor(Math.random() * (swapIndex + 1))
241
- const tmp = peers[swapIndex]
242
- peers[swapIndex] = peers[pickIndex]
243
- peers[pickIndex] = tmp
241
+ ;[peers[swapIndex], peers[pickIndex]] = [peers[pickIndex], peers[swapIndex]]
244
242
  }
245
243
  for (const { peerId } of peers)
246
244
  try {
@@ -29,14 +29,14 @@ function wrapWireOn(wire, groupId) {
29
29
 
30
30
  /**
31
31
  * 群联邦房间挂载 part_wire(要求线载荷带 `groupId`)。
32
- * @param {{ replicaUsername?: string }} ctx 入站上下文
32
+ * @param {{ replicaUsername?: string }} wireContext 入站上下文
33
33
  * @param {string} groupId 群 ID
34
34
  * @param {import('./part_ingress.mjs').PartWireAdapter} wire Trystero 适配器
35
35
  * @param {{ allowPartInvoke?: (payload: object) => boolean }} [options] 入站过滤
36
36
  * @returns {void}
37
37
  */
38
- export function attachGroupPartWire(ctx, groupId, wire, options = {}) {
39
- attachPartWire(ctx, {
38
+ export function attachGroupPartWire(wireContext, groupId, wire, options = {}) {
39
+ attachPartWire(wireContext, {
40
40
  send: wire.send.bind(wire),
41
41
  on: wrapWireOn(wire, groupId),
42
42
  }, options)
@@ -45,16 +45,16 @@ function parsePartTimelinePut(data, partpath) {
45
45
  }
46
46
 
47
47
  /**
48
- * @param {PartWireContext} ctx 入站上下文
48
+ * @param {PartWireContext} wireContext 入站上下文
49
49
  * @param {object} payload part_invoke 请求
50
50
  * @returns {Promise<PartInvokeResponse | null>} RPC 处理器返回值
51
51
  */
52
- async function dispatchPartInvoke(ctx, payload) {
52
+ async function dispatchPartInvoke(wireContext, payload) {
53
53
  const partpath = normalizePartpath(payload?.partpath)
54
54
  const invoke = payload?.invoke
55
55
  if (!partpath || !isPlainObject(invoke)) return null
56
56
  return dispatchRpcInbound({
57
- replicaUsername: ctx.replicaUsername,
57
+ replicaUsername: wireContext.replicaUsername,
58
58
  requesterNodeHash: payload.nodeHash ? String(payload.nodeHash).trim() : null,
59
59
  groupId: payload.groupId ? String(payload.groupId).trim() : undefined,
60
60
  peerId: payload.peerId,
@@ -70,12 +70,12 @@ async function dispatchPartInvoke(ctx, payload) {
70
70
 
71
71
  /**
72
72
  * 挂载 part_timeline_put / part_invoke / part_invoke_response。
73
- * @param {PartWireContext} ctx 入站上下文
73
+ * @param {PartWireContext} wireContext 入站上下文
74
74
  * @param {PartWireAdapter} wire Trystero 适配器
75
75
  * @param {{ allowPartInvoke?: (payload: object) => boolean }} [options] 入站过滤
76
76
  * @returns {void}
77
77
  */
78
- export function attachPartWire(ctx, wire, options = {}) {
78
+ export function attachPartWire(wireContext, wire, options = {}) {
79
79
  wire.on('part_timeline_put', data => {
80
80
  if (!isPlainObject(data)) return
81
81
  const partpath = normalizePartpath(data.partpath)
@@ -83,7 +83,7 @@ export function attachPartWire(ctx, wire, options = {}) {
83
83
  const message = parsePartTimelinePut(data, partpath)
84
84
  if (!message) return
85
85
  void dispatchDeliveryInbound({
86
- replicaUsername: ctx.replicaUsername,
86
+ replicaUsername: wireContext.replicaUsername,
87
87
  requesterNodeHash: data.nodeHash ? String(data.nodeHash).trim() : null,
88
88
  }, message)
89
89
  })
@@ -93,9 +93,9 @@ export function attachPartWire(ctx, wire, options = {}) {
93
93
  if (options.allowPartInvoke?.(data) === false) return
94
94
  const payload = { ...data, peerId }
95
95
  if (payload.requestId)
96
- void handleIncomingPartInvokeRequest(ctx, payload, wire, peerId)
96
+ void handleIncomingPartInvokeRequest(wireContext, payload, wire, peerId)
97
97
  else
98
- void handleIncomingPartInvokeFireAndForget(ctx, payload, wire, peerId)
98
+ void handleIncomingPartInvokeFireAndForget(wireContext, payload, wire, peerId)
99
99
  })
100
100
 
101
101
  wire.on('part_invoke_response', (data, peerId) => {
@@ -105,17 +105,17 @@ export function attachPartWire(ctx, wire, options = {}) {
105
105
  }
106
106
 
107
107
  /**
108
- * @param {PartWireContext} ctx 入站上下文
108
+ * @param {PartWireContext} wireContext 入站上下文
109
109
  * @param {object} payload part_invoke 请求(含 requestId)
110
110
  * @param {PartWireAdapter} wire 发送适配器
111
111
  * @param {string} peerId 对端
112
112
  * @returns {Promise<void>}
113
113
  */
114
- export async function handleIncomingPartInvokeRequest(ctx, payload, wire, peerId) {
114
+ export async function handleIncomingPartInvokeRequest(wireContext, payload, wire, peerId) {
115
115
  const partpath = normalizePartpath(payload?.partpath)
116
116
  if (!partpath || !payload.requestId) return
117
117
 
118
- const response = await dispatchPartInvoke(ctx, { ...payload, peerId })
118
+ const response = await dispatchPartInvoke(wireContext, { ...payload, peerId })
119
119
  if (response == null || !isPartInvokeResponse(response)) return
120
120
 
121
121
  try {
@@ -129,17 +129,17 @@ export async function handleIncomingPartInvokeRequest(ctx, payload, wire, peerId
129
129
  }
130
130
 
131
131
  /**
132
- * @param {PartWireContext} ctx 入站上下文
132
+ * @param {PartWireContext} wireContext 入站上下文
133
133
  * @param {object} payload part_invoke 请求(无 requestId)
134
134
  * @param {PartWireAdapter} wire 发送适配器
135
135
  * @param {string} peerId 对端
136
136
  * @returns {Promise<void>}
137
137
  */
138
- export async function handleIncomingPartInvokeFireAndForget(ctx, payload, wire, peerId) {
138
+ export async function handleIncomingPartInvokeFireAndForget(wireContext, payload, wire, peerId) {
139
139
  const partpath = normalizePartpath(payload?.partpath)
140
140
  if (!partpath) return
141
141
 
142
- const response = await dispatchPartInvoke(ctx, { ...payload, peerId })
142
+ const response = await dispatchPartInvoke(wireContext, { ...payload, peerId })
143
143
  const followUp = unwrapPartInvokeResult(response)
144
144
  if (!isPartInvoke(followUp)) return
145
145
  try {
@@ -16,8 +16,8 @@ import { resolveFederationFanoutTopK } from '../trust_graph/resolve.mjs'
16
16
  import trustGraphTunables from '../trust_graph/tunables.json' with { type: 'json' }
17
17
 
18
18
  import { isPlainObject } from './ingress.mjs'
19
- import { createPartQueryCache, partQueryCache } from './part_query_cache.mjs'
20
19
  import partQueryTunables from './part_query.tunables.json' with { type: 'json' }
20
+ import { createPartQueryCache, partQueryCache } from './part_query_cache.mjs'
21
21
  import { consumeWireRateBucket } from './rate_bucket.mjs'
22
22
  import { finishMultiWireWaiters, registerMultiWireWait } from './wait.mjs'
23
23
 
@@ -34,7 +34,7 @@ import { finishMultiWireWaiters, registerMultiWireWait } from './wait.mjs'
34
34
  */
35
35
 
36
36
  /**
37
- * @typedef {(ctx: QueryInboundContext, query: unknown) => Promise<unknown[] | null | undefined> | unknown[] | null | undefined} QueryInboundHandler
37
+ * @typedef {(queryContext: QueryInboundContext, query: unknown) => Promise<unknown[] | null | undefined> | unknown[] | null | undefined} QueryInboundHandler
38
38
  */
39
39
 
40
40
  /**
@@ -55,14 +55,14 @@ import { finishMultiWireWaiters, registerMultiWireWait } from './wait.mjs'
55
55
  * getNodeHash?: () => string
56
56
  * now?: () => number
57
57
  * state?: PartQueryNodeState
58
- * }} PartQueryDeps
58
+ * }} PartQueryDependencies
59
59
  */
60
60
 
61
61
  /**
62
62
  * @typedef {{
63
63
  * upstreamPeerId: string
64
64
  * wire: PartWireAdapter
65
- * req: PartQueryReq
65
+ * request: PartQueryReq
66
66
  * localRows: unknown[]
67
67
  * remoteRows: unknown[]
68
68
  * expected: number
@@ -70,7 +70,7 @@ import { finishMultiWireWaiters, registerMultiWireWait } from './wait.mjs'
70
70
  * respondedPeers: Set<string>
71
71
  * flushed: boolean
72
72
  * timer: ReturnType<typeof setTimeout> | null
73
- * deps: PartQueryDeps
73
+ * dependencies: PartQueryDependencies
74
74
  * state: PartQueryNodeState
75
75
  * }} RelayPending
76
76
  */
@@ -97,11 +97,11 @@ export function createPartQueryNodeState(options = {}) {
97
97
  const defaultState = createPartQueryNodeState({ cache: partQueryCache })
98
98
 
99
99
  /**
100
- * @param {PartQueryDeps} [deps] 依赖
100
+ * @param {PartQueryDependencies} [dependencies] 依赖
101
101
  * @returns {PartQueryNodeState} 节点状态
102
102
  */
103
- function resolveState(deps = {}) {
104
- return deps.state || defaultState
103
+ function resolveState(dependencies = {}) {
104
+ return dependencies.state || defaultState
105
105
  }
106
106
 
107
107
  /**
@@ -167,27 +167,27 @@ export function mergeQueryRows(lists, maxHits, rowKey) {
167
167
 
168
168
  /**
169
169
  * @param {PartQueryNodeState} state 节点状态
170
- * @param {QueryInboundContext} ctx 入站上下文
170
+ * @param {QueryInboundContext} queryContext 入站上下文
171
171
  * @param {string} partpath part 路径
172
172
  * @param {string} kind 查询标签
173
173
  * @param {unknown} query 查询体
174
174
  * @returns {Promise<unknown[]>} 本地 rows
175
175
  */
176
- async function runLocalHandler(state, ctx, partpath, kind, query) {
176
+ async function runLocalHandler(state, queryContext, partpath, kind, query) {
177
177
  const handler = state.handlers.get(handlerKey(partpath, kind))
178
178
  if (!handler) return []
179
- const rows = await handler(ctx, query)
179
+ const rows = await handler(queryContext, query)
180
180
  return Array.isArray(rows) ? rows : []
181
181
  }
182
182
 
183
183
  /**
184
184
  * @param {string} username trust graph 上下文
185
185
  * @param {Set<string>} exclude 排除节点
186
- * @param {PartQueryDeps} deps 可注入依赖
186
+ * @param {PartQueryDependencies} dependencies 可注入依赖
187
187
  * @returns {Promise<string[]>} 邻居 nodeHash
188
188
  */
189
- async function selectQueryNeighbors(username, exclude, deps) {
190
- if (deps.selectNeighbors) return deps.selectNeighbors(exclude)
189
+ async function selectQueryNeighbors(username, exclude, dependencies) {
190
+ if (dependencies.selectNeighbors) return dependencies.selectNeighbors(exclude)
191
191
  const graph = await buildMergedGraph(username)
192
192
  const fanoutCap = Math.max(1, Math.floor(Number(partQueryTunables.fanoutCap) || 4))
193
193
  const k = Math.min(fanoutCap, resolveFederationFanoutTopK(graph.size, trustGraphTunables))
@@ -207,24 +207,24 @@ async function selectQueryNeighbors(username, exclude, deps) {
207
207
  * @param {string} nodeHash 目标
208
208
  * @param {string} action action 名
209
209
  * @param {unknown} payload 载荷
210
- * @param {PartQueryDeps} deps 依赖
210
+ * @param {PartQueryDependencies} dependencies 依赖
211
211
  * @returns {Promise<boolean>} 是否发出
212
212
  */
213
- async function deliverQuery(username, nodeHash, action, payload, deps) {
214
- if (deps.deliver) return Boolean(await deps.deliver(nodeHash, action, payload))
213
+ async function deliverQuery(username, nodeHash, action, payload, dependencies) {
214
+ if (dependencies.deliver) return Boolean(await dependencies.deliver(nodeHash, action, payload))
215
215
  return requireTrustGraphProvider(DEFAULT_TRUST_GRAPH_OWNER).sendToNode(username, nodeHash, action, payload)
216
216
  }
217
217
 
218
218
  /**
219
- * @param {PartQueryReq} req 请求
219
+ * @param {PartQueryReq} request 请求
220
220
  * @param {unknown[]} rows 行
221
221
  * @param {() => string} nodeHashOf 本机 hash
222
222
  * @returns {PartQueryRes} 响应载荷
223
223
  */
224
- function buildRes(req, rows, nodeHashOf) {
225
- const capped = clampPartQueryRows(rows, req.budget.maxHits) || []
224
+ function buildResponse(request, rows, nodeHashOf) {
225
+ const capped = clampPartQueryRows(rows, request.budget.maxHits) || []
226
226
  return {
227
- requestId: req.requestId,
227
+ requestId: request.requestId,
228
228
  fromNodeHash: nodeHashOf(),
229
229
  rows: capped,
230
230
  }
@@ -241,62 +241,62 @@ function flushRelayPending(pending) {
241
241
  clearTimeout(pending.timer)
242
242
  pending.timer = null
243
243
  }
244
- pending.state.relayPending.delete(pending.req.requestId)
245
- const merged = mergeQueryRows([pending.localRows, pending.remoteRows], pending.req.budget.maxHits)
246
- const now = pending.deps.now || Date.now
247
- pending.state.cache.set(pending.req.partpath, pending.req.kind, pending.req.query, merged, now())
248
- const nodeHashOf = pending.deps.getNodeHash || getNodeHash
244
+ pending.state.relayPending.delete(pending.request.requestId)
245
+ const merged = mergeQueryRows([pending.localRows, pending.remoteRows], pending.request.budget.maxHits)
246
+ const now = pending.dependencies.now || Date.now
247
+ pending.state.cache.set(pending.request.partpath, pending.request.kind, pending.request.query, merged, now())
248
+ const nodeHashOf = pending.dependencies.getNodeHash || getNodeHash
249
249
  try {
250
- pending.wire.send('part_query_res', buildRes(pending.req, merged, nodeHashOf), pending.upstreamPeerId)
250
+ pending.wire.send('part_query_res', buildResponse(pending.request, merged, nodeHashOf), pending.upstreamPeerId)
251
251
  }
252
252
  catch { /* disconnected */ }
253
253
  }
254
254
 
255
255
  /**
256
- * @param {object} ctx attach 上下文
256
+ * @param {{ replicaUsername?: string }} wireContext attach 上下文
257
257
  * @param {PartWireAdapter} wire wire
258
- * @param {PartQueryReq} req 已校验请求
258
+ * @param {PartQueryReq} request 已校验请求
259
259
  * @param {string} peerId 来路
260
- * @param {PartQueryDeps} deps 依赖
260
+ * @param {PartQueryDependencies} dependencies 依赖
261
261
  * @returns {Promise<void>}
262
262
  */
263
- async function processIncomingReq(ctx, wire, req, peerId, deps) {
264
- const state = resolveState(deps)
265
- const nodeHashOf = deps.getNodeHash || getNodeHash
266
- const now = deps.now || Date.now
267
- const username = String(ctx.replicaUsername || '')
263
+ async function processIncomingRequest(wireContext, wire, request, peerId, dependencies) {
264
+ const state = resolveState(dependencies)
265
+ const nodeHashOf = dependencies.getNodeHash || getNodeHash
266
+ const now = dependencies.now || Date.now
267
+ const username = String(wireContext.replicaUsername || '')
268
268
 
269
- const cached = state.cache.get(req.partpath, req.kind, req.query, now())
269
+ const cached = state.cache.get(request.partpath, request.kind, request.query, now())
270
270
  if (cached) {
271
- try { wire.send('part_query_res', buildRes(req, cached, nodeHashOf), peerId) }
271
+ try { wire.send('part_query_res', buildResponse(request, cached, nodeHashOf), peerId) }
272
272
  catch { /* disconnected */ }
273
273
  return
274
274
  }
275
275
 
276
276
  const localRows = await runLocalHandler(state, {
277
- replicaUsername: ctx.replicaUsername,
278
- requesterNodeHash: req.originNodeHash,
277
+ replicaUsername: wireContext.replicaUsername,
278
+ requesterNodeHash: request.originNodeHash,
279
279
  peerId,
280
- }, req.partpath, req.kind, req.query)
280
+ }, request.partpath, request.kind, request.query)
281
281
 
282
- const nextTtl = req.ttl - 1
282
+ const nextTtl = request.ttl - 1
283
283
  if (nextTtl <= 0) {
284
- state.cache.set(req.partpath, req.kind, req.query, localRows, now())
285
- try { wire.send('part_query_res', buildRes(req, localRows, nodeHashOf), peerId) }
284
+ state.cache.set(request.partpath, request.kind, request.query, localRows, now())
285
+ try { wire.send('part_query_res', buildResponse(request, localRows, nodeHashOf), peerId) }
286
286
  catch { /* disconnected */ }
287
287
  return
288
288
  }
289
289
 
290
290
  const selfHash = nodeHashOf()
291
- const exclude = new Set([selfHash, req.originNodeHash, String(peerId || '').trim().toLowerCase()].filter(Boolean))
292
- const neighbors = username ? await selectQueryNeighbors(username, exclude, deps) : []
293
- const forwardPayload = { ...req, ttl: nextTtl }
291
+ const exclude = new Set([selfHash, request.originNodeHash, String(peerId || '').trim().toLowerCase()].filter(Boolean))
292
+ const neighbors = username ? await selectQueryNeighbors(username, exclude, dependencies) : []
293
+ const forwardPayload = { ...request, ttl: nextTtl }
294
294
 
295
295
  /** @type {RelayPending} */
296
296
  const pending = {
297
297
  upstreamPeerId: peerId,
298
298
  wire,
299
- req,
299
+ request,
300
300
  localRows,
301
301
  remoteRows: [],
302
302
  expected: 0,
@@ -304,14 +304,14 @@ async function processIncomingReq(ctx, wire, req, peerId, deps) {
304
304
  respondedPeers: new Set(),
305
305
  flushed: false,
306
306
  timer: null,
307
- deps,
307
+ dependencies,
308
308
  state,
309
309
  }
310
- state.relayPending.set(req.requestId, pending)
310
+ state.relayPending.set(request.requestId, pending)
311
311
 
312
312
  let sent = 0
313
313
  for (const target of neighbors)
314
- if (await deliverQuery(username, target, 'part_query_req', forwardPayload, deps)) sent++
314
+ if (await deliverQuery(username, target, 'part_query_req', forwardPayload, dependencies)) sent++
315
315
  pending.expected = sent
316
316
 
317
317
  if (sent === 0 || pending.received >= pending.expected) {
@@ -319,69 +319,69 @@ async function processIncomingReq(ctx, wire, req, peerId, deps) {
319
319
  return
320
320
  }
321
321
 
322
- pending.timer = setTimeout(() => flushRelayPending(pending), resolvePartQueryHopTimeoutMs(req.ttl))
322
+ pending.timer = setTimeout(() => flushRelayPending(pending), resolvePartQueryHopTimeoutMs(request.ttl))
323
323
  }
324
324
 
325
325
  /**
326
326
  * 挂载 part_query_req / part_query_res。
327
- * @param {{ replicaUsername?: string }} ctx 入站上下文
327
+ * @param {{ replicaUsername?: string }} wireContext 入站上下文
328
328
  * @param {PartWireAdapter} wire wire
329
- * @param {PartQueryDeps} [deps] 可注入依赖(含 per-node state)
329
+ * @param {PartQueryDependencies} [dependencies] 可注入依赖(含 per-node state)
330
330
  * @returns {void}
331
331
  */
332
- export function attachPartQueryWire(ctx, wire, deps = {}) {
333
- const state = resolveState(deps)
332
+ export function attachPartQueryWire(wireContext, wire, dependencies = {}) {
333
+ const state = resolveState(dependencies)
334
334
  wire.on('part_query_req', (data, peerId) => {
335
335
  if (!isPlainObject(data)) return
336
- const req = parsePartQueryReq(data)
337
- if (!req) return
338
- if (!state.takeDedupe(req.requestId)) return
339
- const source = String(peerId || req.originNodeHash || '').trim().toLowerCase()
336
+ const request = parsePartQueryReq(data)
337
+ if (!request) return
338
+ if (!state.takeDedupe(request.requestId)) return
339
+ const source = String(peerId || request.originNodeHash || '').trim().toLowerCase()
340
340
  if (source && !consumeWireRateBucket(`part_query:${source}`, {
341
341
  maxCount: partQueryTunables.ratePerSourcePerMin,
342
342
  })) return
343
- void processIncomingReq(ctx, wire, req, String(peerId || ''), deps)
343
+ void processIncomingRequest(wireContext, wire, request, String(peerId || ''), dependencies)
344
344
  })
345
345
 
346
346
  wire.on('part_query_res', (data, peerId) => {
347
- const res = parsePartQueryRes(data)
348
- if (!res) return
349
- handleIncomingPartQueryRes(res, String(peerId || ''), deps)
347
+ const response = parsePartQueryRes(data)
348
+ if (!response) return
349
+ handleIncomingPartQueryResponse(response, String(peerId || ''), dependencies)
350
350
  })
351
351
  }
352
352
 
353
353
  /**
354
- * @param {PartQueryRes} res 响应
354
+ * @param {PartQueryRes} response 响应
355
355
  * @param {string} peerId 来路
356
- * @param {PartQueryDeps} [deps] 依赖
356
+ * @param {PartQueryDependencies} [dependencies] 依赖
357
357
  * @returns {void}
358
358
  */
359
- export function handleIncomingPartQueryRes(res, peerId = '', deps = {}) {
360
- const state = resolveState(deps)
359
+ export function handleIncomingPartQueryResponse(response, peerId = '', dependencies = {}) {
360
+ const state = resolveState(dependencies)
361
361
  // 同一 peer 只计一次,防重复回包灌水/提早凑齐 expected
362
- const responderKey = String(peerId || res.fromNodeHash || '').trim().toLowerCase()
363
- const relay = state.relayPending.get(res.requestId)
362
+ const responderKey = String(peerId || response.fromNodeHash || '').trim().toLowerCase()
363
+ const relay = state.relayPending.get(response.requestId)
364
364
  if (relay) {
365
365
  if (responderKey) {
366
366
  if (relay.respondedPeers.has(responderKey)) return
367
367
  relay.respondedPeers.add(responderKey)
368
368
  }
369
- relay.remoteRows.push(...res.rows)
369
+ relay.remoteRows.push(...response.rows)
370
370
  relay.received += 1
371
371
  if (relay.expected > 0 && relay.received >= relay.expected) flushRelayPending(relay)
372
372
  return
373
373
  }
374
374
 
375
- const bag = state.originBags.get(res.requestId)
375
+ const bag = state.originBags.get(response.requestId)
376
376
  if (!bag) return
377
377
  if (responderKey) {
378
378
  if (bag.respondedPeers.has(responderKey)) return
379
379
  bag.respondedPeers.add(responderKey)
380
380
  }
381
- bag.rows = mergeQueryRows([bag.rows, res.rows], bag.maxHits, bag.rowKey)
381
+ bag.rows = mergeQueryRows([bag.rows, response.rows], bag.maxHits, bag.rowKey)
382
382
  bag.received += 1
383
383
  if (bag.expected > 0 && bag.received >= bag.expected)
384
- finishMultiWireWaiters(state.originWaits, res.requestId, '')
384
+ finishMultiWireWaiters(state.originWaits, response.requestId, '')
385
385
  }
386
386
 
387
387
  /**
@@ -396,14 +396,13 @@ export function handleIncomingPartQueryRes(res, peerId = '', deps = {}) {
396
396
  * maxHits?: number
397
397
  * rowKey?: (row: unknown) => string
398
398
  * budget?: { maxHits?: number }
399
- * } & PartQueryDeps} [options] 选项
399
+ * } & PartQueryDependencies} [options] 选项
400
400
  * @returns {Promise<unknown[]>} 合并后的 rows
401
401
  */
402
402
  export async function queryNetwork(username, partpath, kind, query, options = {}) {
403
- const deps = options
404
- const state = resolveState(deps)
405
- const now = deps.now || Date.now
406
- const nodeHashOf = deps.getNodeHash || getNodeHash
403
+ const state = resolveState(options)
404
+ const now = options.now || Date.now
405
+ const nodeHashOf = options.getNodeHash || getNodeHash
407
406
 
408
407
  const cached = state.cache.get(partpath, kind, query, now())
409
408
  if (cached) return cached
@@ -428,7 +427,7 @@ export async function queryNetwork(username, partpath, kind, query, options = {}
428
427
  }, partpath, kind, query)
429
428
 
430
429
  /** @type {PartQueryReq} */
431
- const req = {
430
+ const request = {
432
431
  requestId: randomUUID(),
433
432
  originNodeHash: nodeHashOf(),
434
433
  partpath: String(partpath || '').trim(),
@@ -437,7 +436,7 @@ export async function queryNetwork(username, partpath, kind, query, options = {}
437
436
  ttl,
438
437
  budget: { maxHits },
439
438
  }
440
- const parsed = parsePartQueryReq(req)
439
+ const parsed = parsePartQueryReq(request)
441
440
  if (!parsed) return mergeQueryRows([localRows], maxHits, options.rowKey)
442
441
 
443
442
  // 预占 dedupe:若查询绕环回流到本机,入站侧直接丢弃
@@ -456,10 +455,10 @@ export async function queryNetwork(username, partpath, kind, query, options = {}
456
455
 
457
456
  const selfHash = nodeHashOf()
458
457
  const exclude = new Set([selfHash, parsed.originNodeHash])
459
- const neighbors = await selectQueryNeighbors(username, exclude, deps)
458
+ const neighbors = await selectQueryNeighbors(username, exclude, options)
460
459
  let sent = 0
461
460
  for (const target of neighbors)
462
- if (await deliverQuery(username, target, 'part_query_req', parsed, deps)) sent++
461
+ if (await deliverQuery(username, target, 'part_query_req', parsed, options)) sent++
463
462
  bag.expected = sent
464
463
 
465
464
  // deliver 可能同步回流;在赋值 expected 后再检查是否已齐
@@ -22,6 +22,13 @@ export function partQueryCacheKey(partpath, kind, query) {
22
22
 
23
23
  /**
24
24
  * LRU + TTL 中继缓存(未验证线索;发起端仍需验签复核)。
25
+ * @param {{ maxKeys?: number, ttlMs?: number, maxHits?: number }} [options] 容量 / TTL / 单键 rows 上限
26
+ * @returns {{
27
+ * get: (partpath: string, kind: string, query: unknown, now?: number) => unknown[] | null
28
+ * set: (partpath: string, kind: string, query: unknown, rows: unknown[], now?: number) => void
29
+ * clear: () => void
30
+ * readonly size: number
31
+ * }} 缓存 API
25
32
  */
26
33
  export function createPartQueryCache(options = {}) {
27
34
  const maxKeys = Math.max(1, Math.floor(Number(options.maxKeys) || partQueryTunables.cacheMaxKeys))