@steve02081504/fount-p2p 0.0.3 → 0.0.4

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
@@ -34,7 +34,7 @@ Subpath exports mirror source directories, e.g. `@steve02081504/fount-p2p/dag`,
34
34
  | L1 | `crypto/`, `wire/`, `schemas/` | Cryptography, wire protocol, canonical validation |
35
35
  | L2 | `node/` | Node runtime: `identity`, `entity_store`, `denylist`, `reputation_store` |
36
36
  | L3 | `discovery/`, `link/`, `transport/`, `rooms/` | Discovery, RTC links, rooms |
37
- | L4 | `trust_graph/`, `mailbox/`, `dag/`, `federation/`, `files/`, `entity/` | Federation, store-and-forward, DAG, EVFS |
37
+ | L4 | `trust_graph/`, `mailbox/`, `dag/`, `federation/`, `files/` | Federation, store-and-forward, DAG, EVFS |
38
38
  | — | `registries/` | Pluggable registries (event type, part path, room provider, …) |
39
39
 
40
40
  Facade entry: `index.mjs` (`startNode`, `createGroupLinkSet`, `registerDiscoveryProvider`, …).
@@ -1,6 +1,7 @@
1
- import { encodeEntityHash, parseEntityHash } from '../core/entity_id.mjs'
2
1
  import { sha256TextHex } from '../crypto/crypto.mjs'
3
2
 
3
+ import { encodeEntityHash, parseEntityHash } from './entity_id.mjs'
4
+
4
5
  /** @type {string} 逻辑实体 sentinel nodeHash(非物理节点绑定) */
5
6
  export const LOGICAL_ENTITY_SENTINEL_NODE_HASH = '0'.repeat(64)
6
7
 
@@ -1,12 +1,12 @@
1
- import { isLogicalEntityHash } from '../logical_entity.mjs'
2
- import { isWritableLocalEntity } from '../replica.mjs'
1
+ import { isLogicalEntityHash } from '../core/logical_entity.mjs'
2
+ import { isWritableLocalEntity } from '../node/identity.mjs'
3
3
 
4
4
  import { checkManifestAcl, resolveManifestAclType } from './manifest_acl_registry.mjs'
5
5
 
6
6
  /**
7
7
  * @param {string} replicaUsername 请求 replica
8
8
  * @param {string} ownerEntityHash 文件 owner
9
- * @param {import('../../files/manifest.mjs').FileManifest} manifest 清单
9
+ * @param {import('./manifest.mjs').FileManifest} manifest 清单
10
10
  * @returns {Promise<boolean>} 是否允许读
11
11
  */
12
12
  export async function canReadManifest(replicaUsername, ownerEntityHash, manifest) {
@@ -1,21 +1,21 @@
1
1
  import { Buffer } from 'node:buffer'
2
2
  import { Readable } from 'node:stream'
3
3
 
4
- import { FEDERATION_CHUNK_MAX_BYTES } from '../../core/constants.mjs'
5
- import { buildFileManifestFromEnc } from '../../files/assemble.mjs'
6
- import { encryptReadableToParts } from '../../files/assemble_stream.mjs'
7
- import { fetchChunk } from '../../files/chunk_fetch.mjs'
8
- import { getChunk, hasChunk, putChunk } from '../../files/chunk_store.mjs'
9
- import { normalizeFileManifest, publicTransferKeyDescriptor } from '../../files/manifest.mjs'
10
- import { assembleManifestPlaintext } from '../../files/transfer_key.mjs'
11
- import { readDagManifestPlaintext, resolveTransferKeyDeps } from '../../files/transfer_key_registry.mjs'
12
- import { getEntityStore } from '../../node/instance.mjs'
4
+ import { FEDERATION_CHUNK_MAX_BYTES } from '../core/constants.mjs'
5
+ import { getEntityStore } from '../node/instance.mjs'
13
6
 
7
+ import { buildFileManifestFromEnc, encryptPlaintextToParts, encryptPlaintextToMultiPartsAsync } from './assemble.mjs'
8
+ import { encryptReadableToParts } from './assemble_stream.mjs'
9
+ import { fetchChunk } from './chunk_fetch.mjs'
10
+ import { getChunk, hasChunk, putChunk } from './chunk_store.mjs'
11
+ import { normalizeFileManifest, publicTransferKeyDescriptor } from './manifest.mjs'
12
+ import { assembleManifestPlaintext } from './transfer_key.mjs'
13
+ import { readDagManifestPlaintext, resolveTransferKeyDeps } from './transfer_key_registry.mjs'
14
14
 
15
15
  /**
16
16
  * @param {string} ownerEntityHash 所有者
17
17
  * @param {string} logicalPath 路径
18
- * @returns {Promise<import('../../files/manifest.mjs').FileManifest | null>} 归一化 manifest
18
+ * @returns {Promise<import('./manifest.mjs').FileManifest | null>} 归一化 manifest
19
19
  */
20
20
  export async function loadFileManifest(ownerEntityHash, logicalPath) {
21
21
  const manifest = await getEntityStore().readManifest(ownerEntityHash, logicalPath)
@@ -23,7 +23,7 @@ export async function loadFileManifest(ownerEntityHash, logicalPath) {
23
23
  }
24
24
 
25
25
  /**
26
- * @param {import('../../files/manifest.mjs').FileManifest} manifest 清单
26
+ * @param {import('./manifest.mjs').FileManifest} manifest 清单
27
27
  * @returns {Promise<void>}
28
28
  */
29
29
  export async function saveFileManifest(manifest) {
@@ -31,7 +31,7 @@ export async function saveFileManifest(manifest) {
31
31
  }
32
32
 
33
33
  /**
34
- * @param {import('../../files/manifest.mjs').FileManifest} manifest 清单
34
+ * @param {import('./manifest.mjs').FileManifest} manifest 清单
35
35
  * @param {Array<Buffer | Uint8Array>} partBytes 密文块
36
36
  * @returns {Promise<void>}
37
37
  */
@@ -42,7 +42,7 @@ export async function storeManifestParts(manifest, partBytes) {
42
42
 
43
43
  /**
44
44
  * @param {string} replicaUsername 副本用户名
45
- * @param {import('../../files/manifest.mjs').FileManifest} manifest 清单
45
+ * @param {import('./manifest.mjs').FileManifest} manifest 清单
46
46
  * @param {{ username?: string, fetchChunk?: Function }} [opts] miss 拉取
47
47
  * @returns {Promise<Buffer | null>} 明文内容
48
48
  */
@@ -90,7 +90,7 @@ export async function readManifestPlaintext(replicaUsername, manifest, opts = {}
90
90
 
91
91
  /**
92
92
  * @param {string} replicaUsername 副本用户名
93
- * @param {import('../../files/manifest.mjs').FileManifest} manifest 清单
93
+ * @param {import('./manifest.mjs').FileManifest} manifest 清单
94
94
  * @param {{ username?: string, fetchChunk?: Function }} [opts] miss 拉取
95
95
  * @returns {Promise<import('node:stream').Readable | null>} 明文流
96
96
  */
@@ -107,13 +107,12 @@ export async function readManifestPlaintextStream(replicaUsername, manifest, opt
107
107
  * @param {Buffer | Uint8Array} params.plaintext 明文
108
108
  * @param {string} [params.name] 文件名
109
109
  * @param {string} [params.mimeType] MIME
110
- * @param {import('../../files/manifest.mjs').CeMode} [params.ceMode] 模式
111
- * @param {import('../../files/manifest.mjs').TransferKeyDescriptor} [params.transferKeyDescriptor] 传递密钥
110
+ * @param {import('./manifest.mjs').CeMode} [params.ceMode] 模式
111
+ * @param {import('./manifest.mjs').TransferKeyDescriptor} [params.transferKeyDescriptor] 传递密钥
112
112
  * @param {object} [params.meta] meta
113
- * @returns {Promise<import('../../files/manifest.mjs').FileManifest>} 写入后的 manifest
113
+ * @returns {Promise<import('./manifest.mjs').FileManifest>} 写入后的 manifest
114
114
  */
115
115
  export async function putFileManifest(params) {
116
- const { encryptPlaintextToParts, encryptPlaintextToMultiPartsAsync } = await import('../../files/assemble.mjs')
117
116
  const {
118
117
  ownerEntityHash,
119
118
  logicalPath,
@@ -152,10 +151,10 @@ export async function putFileManifest(params) {
152
151
  * @param {number} params.plainSize 明文字节数
153
152
  * @param {string} [params.name] 文件名
154
153
  * @param {string} [params.mimeType] MIME
155
- * @param {import('../../files/manifest.mjs').CeMode} [params.ceMode] 模式
156
- * @param {import('../../files/manifest.mjs').TransferKeyDescriptor} [params.transferKeyDescriptor] 传递密钥
154
+ * @param {import('./manifest.mjs').CeMode} [params.ceMode] 模式
155
+ * @param {import('./manifest.mjs').TransferKeyDescriptor} [params.transferKeyDescriptor] 传递密钥
157
156
  * @param {object} [params.meta] meta
158
- * @returns {Promise<import('../../files/manifest.mjs').FileManifest>} 写入后的 manifest
157
+ * @returns {Promise<import('./manifest.mjs').FileManifest>} 写入后的 manifest
159
158
  */
160
159
  export async function putFileManifestFromStream(params) {
161
160
  const {
@@ -197,7 +196,7 @@ export async function putFileManifestFromStream(params) {
197
196
  * @returns {Promise<Buffer | null>} 明文或 null
198
197
  */
199
198
  export async function readPublicFile(replicaUsername, entityHash, logicalPath, opts = {}) {
200
- const { fetchPublicManifest } = await import('../../files/manifest_fetch.mjs')
199
+ const { fetchPublicManifest } = await import('./manifest_fetch.mjs')
201
200
  const manifest = await fetchPublicManifest({
202
201
  username: opts.username || replicaUsername,
203
202
  ownerEntityHash: entityHash,
@@ -1,9 +1,7 @@
1
- import { isEntityHash128 } from '../../core/entity_id.mjs'
2
- import { assertSafeEvfsLogicalPath } from '../../core/evfs_logical_path.mjs'
1
+ import { isEntityHash128 } from '../core/entity_id.mjs'
2
+ import { assertSafeEvfsLogicalPath } from '../core/evfs_logical_path.mjs'
3
3
 
4
- /**
5
- *
6
- */
4
+ /** @type {string} evfs URI scheme */
7
5
  export const EVFS_SCHEME = 'evfs:'
8
6
 
9
7
  /**
@@ -5,14 +5,14 @@
5
5
  /** @type {Map<string, { ownerId: string, handler: (context: ManifestAclContext, logicalPath?: string) => Promise<boolean> }>} */
6
6
  const handlersByType = new Map()
7
7
 
8
- /** @type {Map<string, { ownerId: string, match: (manifest: import('../../files/manifest.mjs').FileManifest | null | undefined, ownerEntityHash: string) => string | null }>} */
8
+ /** @type {Map<string, { ownerId: string, match: (manifest: import('./manifest.mjs').FileManifest | null | undefined, ownerEntityHash: string) => string | null }>} */
9
9
  const matchersByOwner = new Map()
10
10
 
11
11
  /**
12
12
  * @typedef {{
13
13
  * replicaUsername: string,
14
14
  * ownerEntityHash: string,
15
- * manifest: import('../../files/manifest.mjs').FileManifest,
15
+ * manifest: import('./manifest.mjs').FileManifest,
16
16
  * }} ManifestAclContext
17
17
  */
18
18
 
@@ -46,7 +46,7 @@ export function unregisterManifestAcl(type, ownerId) {
46
46
 
47
47
  /**
48
48
  * @param {string} ownerId 注册方
49
- * @param {(manifest: import('../../files/manifest.mjs').FileManifest | null | undefined, ownerEntityHash: string) => string | null} match ACL 类型匹配
49
+ * @param {(manifest: import('./manifest.mjs').FileManifest | null | undefined, ownerEntityHash: string) => string | null} match ACL 类型匹配
50
50
  * @returns {void}
51
51
  */
52
52
  export function registerManifestAclMatcher(ownerId, match) {
@@ -68,7 +68,7 @@ export function clearManifestAclRegistry() {
68
68
  }
69
69
 
70
70
  /**
71
- * @param {import('../../files/manifest.mjs').FileManifest | null | undefined} manifest manifest
71
+ * @param {import('./manifest.mjs').FileManifest | null | undefined} manifest manifest
72
72
  * @param {string} ownerEntityHash 所有者
73
73
  * @returns {string | null} ACL 类型
74
74
  */
@@ -1,16 +1,16 @@
1
1
  import { randomUUID } from 'node:crypto'
2
2
 
3
- import { loadFileManifest, saveFileManifest } from '../entity/files/evfs.mjs'
4
- import { isWritableLocalEntity } from '../entity/replica.mjs'
5
3
  import {
6
4
  manifestFetchExpectedKey,
7
5
  MAX_PENDING_MANIFEST_FETCHES,
8
6
  pendingManifestFetches,
9
7
  registerManifestFetchWait,
10
8
  } from '../federation/manifest_fetch_pending.mjs'
9
+ import { isWritableLocalEntity } from '../node/identity.mjs'
11
10
  import { getEntityStore } from '../node/instance.mjs'
12
11
 
13
12
  import { resolveNodeHash } from './chunk_provider_registry.mjs'
13
+ import { loadFileManifest, saveFileManifest } from './evfs.mjs'
14
14
  import { fanoutFedFetch } from './fetch_fanout.mjs'
15
15
  import { normalizeFileManifest } from './manifest.mjs'
16
16
  import { shouldPreferIncomingPublicManifest } from './public_manifest.mjs'
@@ -6,6 +6,7 @@ import { assertSafeEvfsLogicalPath } from '../core/evfs_logical_path.mjs'
6
6
  import { isHex64, normalizeHex64 } from '../core/hexIds.mjs'
7
7
  import { sign, verify } from '../crypto/crypto.mjs'
8
8
 
9
+ import { putFileManifest, saveFileManifest } from './evfs.mjs'
9
10
  import { normalizeFileManifest, publicTransferKeyDescriptor } from './manifest.mjs'
10
11
 
11
12
  /** 实体公开 manifest 签名域 */
@@ -137,7 +138,6 @@ export async function publishPublicFile(params) {
137
138
  entityPubKeyHex,
138
139
  publishedAt = Date.now(),
139
140
  } = params
140
- const { putFileManifest, saveFileManifest } = await import('../entity/files/evfs.mjs')
141
141
  const base = await putFileManifest({
142
142
  ownerEntityHash,
143
143
  logicalPath,
package/node/identity.mjs CHANGED
@@ -1,8 +1,9 @@
1
+ import { Buffer } from 'node:buffer'
1
2
  import { randomBytes } from 'node:crypto'
2
3
 
3
- import { entityHashFromRecoveryPubKeyHex } from '../core/entity_id.mjs'
4
+ import { entityHashFromRecoveryPubKeyHex, parseEntityHash } from '../core/entity_id.mjs'
4
5
  import { isHex64 } from '../core/hexIds.mjs'
5
- import { nodeHashFromSeed } from '../entity/node_hash.mjs'
6
+ import { keyPairFromSeed, pubKeyHash } from '../crypto/crypto.mjs'
6
7
  import { normalizeMailboxSettings } from '../mailbox/settings.mjs'
7
8
 
8
9
  import { emitNodeChange } from './instance.mjs'
@@ -11,6 +12,18 @@ import { readNodeJsonSync, writeNodeJsonSync } from './storage.mjs'
11
12
  const NODE_SEED_HEX_RE = /^[\da-f]{64}$/iu
12
13
  const NODE_JSON = 'node'
13
14
 
15
+ /**
16
+ * 由持久化 nodeSeed 派生 nodeHash(64 hex)。
17
+ * @param {string} seedHex 32 字节 hex
18
+ * @returns {string} 节点哈希
19
+ */
20
+ export function nodeHashFromSeed(seedHex) {
21
+ const seed = Buffer.from(String(seedHex).trim(), 'hex')
22
+ if (seed.length !== 32) throw new Error('invalid node seed')
23
+ const { publicKey } = keyPairFromSeed(seed)
24
+ return pubKeyHash(publicKey)
25
+ }
26
+
14
27
  /**
15
28
  * @returns {object} 节点配置磁盘对象
16
29
  */
@@ -97,3 +110,21 @@ export function entityHashFromKeys(nodeHash, recoveryPubKeyHex) {
97
110
  if (!isHex64(nodeHash) || !isHex64(pub)) return null
98
111
  return entityHashFromRecoveryPubKeyHex(nodeHash, pub)
99
112
  }
113
+
114
+ /**
115
+ * @param {string} recoveryPubKeyHex 64 位十六进制 recovery 公钥
116
+ * @returns {string | null} 本节点 entityHash
117
+ */
118
+ export function resolveLocalEntityHashFromRecoveryPubKeyHex(recoveryPubKeyHex) {
119
+ return entityHashFromKeys(getNodeHash(), recoveryPubKeyHex)
120
+ }
121
+
122
+ /**
123
+ * @param {string} entityHash 目标 entityHash
124
+ * @returns {boolean} 是否为本节点可写实体
125
+ */
126
+ export function isWritableLocalEntity(entityHash) {
127
+ const parsed = parseEntityHash(entityHash)
128
+ if (!parsed) return false
129
+ return parsed.nodeHash === getNodeHash()
130
+ }
@@ -5,8 +5,8 @@
5
5
  */
6
6
  import { parseEntityHash } from '../core/entity_id.mjs'
7
7
  import { isHex64, normalizeHex64 } from '../core/hexIds.mjs'
8
- import { isWritableLocalEntity } from '../entity/replica.mjs'
9
8
 
9
+ import { isWritableLocalEntity } from './identity.mjs'
10
10
  import { isNodeInitialized, getEntityStore } from './instance.mjs'
11
11
 
12
12
  /** @typedef {'subject' | 'entity'} PersonalListScope */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steve02081504/fount-p2p",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "fount federation P2P layer — link, trust graph, mailbox, DAG, EVFS.",
5
5
  "keywords": [
6
6
  "network",
@@ -45,8 +45,6 @@
45
45
  "./rooms/*": "./rooms/*.mjs",
46
46
  "./overlay": "./overlay/index.mjs",
47
47
  "./overlay/*": "./overlay/*.mjs",
48
- "./entity/*": "./entity/*.mjs",
49
- "./entity/files/*": "./entity/files/*.mjs",
50
48
  "./trust_graph/*": "./trust_graph/*.mjs",
51
49
  "./mailbox/*": "./mailbox/*.mjs",
52
50
  "./dag": "./dag/index.mjs",
@@ -1,46 +0,0 @@
1
- import { getEntityStore } from '../../node/instance.mjs'
2
-
3
- /** @type {Map<string, { replica: string | null, at: number }>} */
4
- const replicaHostCache = new Map()
5
-
6
- const REPLICA_HOST_CACHE_MS = 60_000
7
-
8
- /**
9
- * @param {string | string[]} [entityHash] owner(单个或批量)
10
- * @returns {void}
11
- */
12
- export function invalidateReplicaHostCache(entityHash) {
13
- if (Array.isArray(entityHash)) {
14
- for (const eh of entityHash)
15
- replicaHostCache.delete(String(eh).trim().toLowerCase())
16
- return
17
- }
18
- if (entityHash) {
19
- replicaHostCache.delete(String(entityHash).trim().toLowerCase())
20
- return
21
- }
22
- replicaHostCache.clear()
23
- }
24
-
25
- /**
26
- * @param {string} ownerEntityHash 所有者
27
- * @returns {Promise<string | null>} 托管 manifest 的 replica
28
- */
29
- export async function findReplicaHostingEntityFiles(ownerEntityHash) {
30
- const eh = String(ownerEntityHash).trim().toLowerCase()
31
- const cached = replicaHostCache.get(eh)
32
- if (cached && Date.now() - cached.at < REPLICA_HOST_CACHE_MS)
33
- return cached.replica
34
-
35
- const store = getEntityStore()
36
- if (typeof store.findHostingUser === 'function') {
37
- const replica = await store.findHostingUser(eh)
38
- replicaHostCache.set(eh, { replica, at: Date.now() })
39
- return replica
40
- }
41
-
42
- const files = await store.listEntityFiles(eh)
43
- const replica = files.length ? '__node__' : null
44
- replicaHostCache.set(eh, { replica, at: Date.now() })
45
- return replica
46
- }
@@ -1,47 +0,0 @@
1
- /** @type {((username: string, entityHash: string) => string | null) | null} */
2
- let resolveAgentCharPartName = null
3
-
4
- /** @type {((username: string) => { entityHash: string, charPartName: string }[]) | null} */
5
- let listLocalAgents = null
6
-
7
- /**
8
- * Chat Load 时注册:解析本地 agent 的 chars 目录名。
9
- * @param {(username: string, entityHash: string) => string | null} resolver 解析函数
10
- * @returns {void}
11
- */
12
- export function registerAgentCharResolver(resolver) {
13
- resolveAgentCharPartName = resolver
14
- }
15
-
16
- /**
17
- * Chat Load 时注册:枚举 replica 下本地 agent 实体。
18
- * @param {(username: string) => { entityHash: string, charPartName: string }[]} provider 枚举函数
19
- * @returns {void}
20
- */
21
- export function registerListLocalAgentsProvider(provider) {
22
- listLocalAgents = provider
23
- }
24
-
25
- /** @returns {void} */
26
- export function unregisterAgentCharResolver() {
27
- resolveAgentCharPartName = null
28
- }
29
-
30
- /** @returns {void} */
31
- export function unregisterListLocalAgentsProvider() {
32
- listLocalAgents = null
33
- }
34
-
35
- /**
36
- * @returns {((username: string, entityHash: string) => string | null) | null} 已注册解析器
37
- */
38
- export function getAgentCharResolver() {
39
- return resolveAgentCharPartName
40
- }
41
-
42
- /**
43
- * @returns {((username: string) => { entityHash: string, charPartName: string }[]) | null} 已注册枚举器
44
- */
45
- export function getListLocalAgentsProvider() {
46
- return listLocalAgents
47
- }
@@ -1,40 +0,0 @@
1
- /** @type {Map<string, (username: string, entityHash: string) => Promise<string | null>>} */
2
- const resolversByOwner = new Map()
3
-
4
- /**
5
- * @param {string} ownerId 注册方
6
- * @param {(username: string, entityHash: string) => Promise<string | null>} resolver logical entity id 反查
7
- * @returns {void}
8
- */
9
- export function registerLogicalEntityIdResolver(ownerId, resolver) {
10
- resolversByOwner.set(String(ownerId), resolver)
11
- }
12
-
13
- /**
14
- * @param {string} ownerId 注册方
15
- * @returns {void}
16
- */
17
- export function unregisterLogicalEntityIdResolver(ownerId) {
18
- resolversByOwner.delete(String(ownerId))
19
- }
20
-
21
- /** @returns {void} */
22
- export function clearLogicalEntityIdRegistry() {
23
- resolversByOwner.clear()
24
- }
25
-
26
- /**
27
- * @param {string} username 副本用户名
28
- * @param {string} entityHash 128 位十六进制 logical entity
29
- * @returns {Promise<string | null>} 逻辑实体 id
30
- */
31
- export async function resolveLogicalEntityId(username, entityHash) {
32
- for (const resolver of resolversByOwner.values())
33
- try {
34
- const id = await resolver(username, entityHash)
35
- if (id) return id
36
- }
37
- catch { /* next */ }
38
-
39
- return null
40
- }
@@ -1,15 +0,0 @@
1
- import { Buffer } from 'node:buffer'
2
-
3
- import { keyPairFromSeed, pubKeyHash } from '../crypto/crypto.mjs'
4
-
5
- /**
6
- * 由持久化 nodeSeed 派生 nodeHash(64 hex)。
7
- * @param {string} seedHex 32 字节 hex
8
- * @returns {string} 节点哈希
9
- */
10
- export function nodeHashFromSeed(seedHex) {
11
- const seed = Buffer.from(String(seedHex).trim(), 'hex')
12
- if (seed.length !== 32) throw new Error('invalid node seed')
13
- const { publicKey } = keyPairFromSeed(seed)
14
- return pubKeyHash(publicKey)
15
- }
@@ -1,20 +0,0 @@
1
- import { parseEntityHash } from '../core/entity_id.mjs'
2
- import { entityHashFromKeys, getNodeHash } from '../node/identity.mjs'
3
-
4
- /**
5
- * @param {string} recoveryPubKeyHex 64 位十六进制 recovery 公钥
6
- * @returns {string | null} 本节点 entityHash
7
- */
8
- export function resolveLocalEntityHashFromRecoveryPubKeyHex(recoveryPubKeyHex) {
9
- return entityHashFromKeys(getNodeHash(), recoveryPubKeyHex)
10
- }
11
-
12
- /**
13
- * @param {string} entityHash 目标 entityHash
14
- * @returns {boolean} 是否为本节点可写实体
15
- */
16
- export function isWritableLocalEntity(entityHash) {
17
- const parsed = parseEntityHash(entityHash)
18
- if (!parsed) return false
19
- return parsed.nodeHash === getNodeHash()
20
- }
@@ -1,38 +0,0 @@
1
- /** @type {Map<string, (replicaUsername: string, groupId: string) => Promise<object | null>>} */
2
- const providersByOwner = new Map()
3
-
4
- /**
5
- * @param {string} ownerId 注册方
6
- * @param {(replicaUsername: string, groupId: string) => Promise<object | null>} provider 物化会话
7
- * @returns {void}
8
- */
9
- export function registerMaterializedSessionProvider(ownerId, provider) {
10
- providersByOwner.set(String(ownerId), provider)
11
- }
12
-
13
- /**
14
- * @param {string} ownerId 注册方
15
- * @returns {void}
16
- */
17
- export function unregisterMaterializedSessionProvider(ownerId) {
18
- providersByOwner.delete(String(ownerId))
19
- }
20
-
21
- /**
22
- * @param {string} replicaUsername 副本用户名
23
- * @param {string} groupId 群 ID
24
- * @param {string} [ownerId] 注册方 id;省略时遍历所有 provider
25
- * @returns {Promise<object | null>} 物化会话
26
- */
27
- export async function getMaterializedSession(replicaUsername, groupId, ownerId) {
28
- if (ownerId != null) {
29
- const provider = providersByOwner.get(String(ownerId))
30
- if (!provider) return null
31
- return provider(replicaUsername, groupId)
32
- }
33
- for (const provider of providersByOwner.values()) {
34
- const session = await provider(replicaUsername, groupId)
35
- if (session) return session
36
- }
37
- return null
38
- }
@@ -1,35 +0,0 @@
1
- /** @type {Map<string, (replicaUsername: string, groupId: string) => Promise<string>>} */
2
- const groupMemberEntityByOwner = new Map()
3
-
4
- /**
5
- * @param {string} ownerId 注册方
6
- * @param {(replicaUsername: string, groupId: string) => Promise<string>} resolver 群成员 entityHash
7
- * @returns {void}
8
- */
9
- export function registerGroupMemberEntityResolver(ownerId, resolver) {
10
- groupMemberEntityByOwner.set(String(ownerId), resolver)
11
- }
12
-
13
- /**
14
- * @param {string} ownerId 注册方
15
- * @returns {void}
16
- */
17
- export function unregisterGroupMemberEntityResolver(ownerId) {
18
- groupMemberEntityByOwner.delete(String(ownerId))
19
- }
20
-
21
- /**
22
- * @param {string} replicaUsername 副本用户名
23
- * @param {string} groupId 群 ID
24
- * @returns {Promise<string | null>} entityHash;无注册方时 null
25
- */
26
- export async function resolveGroupMemberEntityHash(replicaUsername, groupId) {
27
- for (const resolver of groupMemberEntityByOwner.values())
28
- try {
29
- const eh = await resolver(replicaUsername, groupId)
30
- if (eh) return eh
31
- }
32
- catch { /* next */ }
33
-
34
- return null
35
- }