society-protocol 1.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 (271) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/adapters.d.ts +101 -0
  4. package/dist/adapters.d.ts.map +1 -0
  5. package/dist/adapters.js +764 -0
  6. package/dist/adapters.js.map +1 -0
  7. package/dist/agents-md.d.ts +59 -0
  8. package/dist/agents-md.d.ts.map +1 -0
  9. package/dist/agents-md.js +204 -0
  10. package/dist/agents-md.js.map +1 -0
  11. package/dist/autoconfig.d.ts +137 -0
  12. package/dist/autoconfig.d.ts.map +1 -0
  13. package/dist/autoconfig.js +452 -0
  14. package/dist/autoconfig.js.map +1 -0
  15. package/dist/bootstrap.d.ts +68 -0
  16. package/dist/bootstrap.d.ts.map +1 -0
  17. package/dist/bootstrap.js +304 -0
  18. package/dist/bootstrap.js.map +1 -0
  19. package/dist/bridges/a2a-bridge.d.ts +156 -0
  20. package/dist/bridges/a2a-bridge.d.ts.map +1 -0
  21. package/dist/bridges/a2a-bridge.js +337 -0
  22. package/dist/bridges/a2a-bridge.js.map +1 -0
  23. package/dist/bridges/mcp-bridge.d.ts +87 -0
  24. package/dist/bridges/mcp-bridge.d.ts.map +1 -0
  25. package/dist/bridges/mcp-bridge.js +332 -0
  26. package/dist/bridges/mcp-bridge.js.map +1 -0
  27. package/dist/cache.d.ts +130 -0
  28. package/dist/cache.d.ts.map +1 -0
  29. package/dist/cache.js +257 -0
  30. package/dist/cache.js.map +1 -0
  31. package/dist/capsules.d.ts +23 -0
  32. package/dist/capsules.d.ts.map +1 -0
  33. package/dist/capsules.js +75 -0
  34. package/dist/capsules.js.map +1 -0
  35. package/dist/cli/commands.d.ts +8 -0
  36. package/dist/cli/commands.d.ts.map +1 -0
  37. package/dist/cli/commands.js +263 -0
  38. package/dist/cli/commands.js.map +1 -0
  39. package/dist/coc.d.ts +121 -0
  40. package/dist/coc.d.ts.map +1 -0
  41. package/dist/coc.js +629 -0
  42. package/dist/coc.js.map +1 -0
  43. package/dist/coc.test.d.ts +2 -0
  44. package/dist/coc.test.d.ts.map +1 -0
  45. package/dist/coc.test.js +80 -0
  46. package/dist/coc.test.js.map +1 -0
  47. package/dist/compression.d.ts +125 -0
  48. package/dist/compression.d.ts.map +1 -0
  49. package/dist/compression.js +573 -0
  50. package/dist/compression.js.map +1 -0
  51. package/dist/cot-stream.d.ts +220 -0
  52. package/dist/cot-stream.d.ts.map +1 -0
  53. package/dist/cot-stream.js +673 -0
  54. package/dist/cot-stream.js.map +1 -0
  55. package/dist/crypto-wasm.d.ts +100 -0
  56. package/dist/crypto-wasm.d.ts.map +1 -0
  57. package/dist/crypto-wasm.js +229 -0
  58. package/dist/crypto-wasm.js.map +1 -0
  59. package/dist/federation.d.ts +200 -0
  60. package/dist/federation.d.ts.map +1 -0
  61. package/dist/federation.js +691 -0
  62. package/dist/federation.js.map +1 -0
  63. package/dist/federation.test.d.ts +2 -0
  64. package/dist/federation.test.d.ts.map +1 -0
  65. package/dist/federation.test.js +71 -0
  66. package/dist/federation.test.js.map +1 -0
  67. package/dist/gateway/capability-router.d.ts +77 -0
  68. package/dist/gateway/capability-router.d.ts.map +1 -0
  69. package/dist/gateway/capability-router.js +222 -0
  70. package/dist/gateway/capability-router.js.map +1 -0
  71. package/dist/gateway/demand-spawner.d.ts +155 -0
  72. package/dist/gateway/demand-spawner.d.ts.map +1 -0
  73. package/dist/gateway/demand-spawner.js +426 -0
  74. package/dist/gateway/demand-spawner.js.map +1 -0
  75. package/dist/identity.d.ts +46 -0
  76. package/dist/identity.d.ts.map +1 -0
  77. package/dist/identity.js +102 -0
  78. package/dist/identity.js.map +1 -0
  79. package/dist/identity.test.d.ts +2 -0
  80. package/dist/identity.test.d.ts.map +1 -0
  81. package/dist/identity.test.js +45 -0
  82. package/dist/identity.test.js.map +1 -0
  83. package/dist/index.d.ts +36 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +1572 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/integration.d.ts +210 -0
  88. package/dist/integration.d.ts.map +1 -0
  89. package/dist/integration.js +1105 -0
  90. package/dist/integration.js.map +1 -0
  91. package/dist/integration.test.d.ts +2 -0
  92. package/dist/integration.test.d.ts.map +1 -0
  93. package/dist/integration.test.js +155 -0
  94. package/dist/integration.test.js.map +1 -0
  95. package/dist/knowledge.d.ts +219 -0
  96. package/dist/knowledge.d.ts.map +1 -0
  97. package/dist/knowledge.js +543 -0
  98. package/dist/knowledge.js.map +1 -0
  99. package/dist/knowledge.test.d.ts +2 -0
  100. package/dist/knowledge.test.d.ts.map +1 -0
  101. package/dist/knowledge.test.js +72 -0
  102. package/dist/knowledge.test.js.map +1 -0
  103. package/dist/latent-space.d.ts +178 -0
  104. package/dist/latent-space.d.ts.map +1 -0
  105. package/dist/latent-space.js +385 -0
  106. package/dist/latent-space.js.map +1 -0
  107. package/dist/lib.d.ts +30 -0
  108. package/dist/lib.d.ts.map +1 -0
  109. package/dist/lib.js +30 -0
  110. package/dist/lib.js.map +1 -0
  111. package/dist/mcp/server.d.ts +74 -0
  112. package/dist/mcp/server.d.ts.map +1 -0
  113. package/dist/mcp/server.js +1392 -0
  114. package/dist/mcp/server.js.map +1 -0
  115. package/dist/metrics.d.ts +98 -0
  116. package/dist/metrics.d.ts.map +1 -0
  117. package/dist/metrics.js +222 -0
  118. package/dist/metrics.js.map +1 -0
  119. package/dist/p2p.d.ts +87 -0
  120. package/dist/p2p.d.ts.map +1 -0
  121. package/dist/p2p.js +606 -0
  122. package/dist/p2p.js.map +1 -0
  123. package/dist/persona/capabilities.d.ts +17 -0
  124. package/dist/persona/capabilities.d.ts.map +1 -0
  125. package/dist/persona/capabilities.js +224 -0
  126. package/dist/persona/capabilities.js.map +1 -0
  127. package/dist/persona/domains.d.ts +22 -0
  128. package/dist/persona/domains.d.ts.map +1 -0
  129. package/dist/persona/domains.js +176 -0
  130. package/dist/persona/domains.js.map +1 -0
  131. package/dist/persona/embeddings.d.ts +40 -0
  132. package/dist/persona/embeddings.d.ts.map +1 -0
  133. package/dist/persona/embeddings.js +265 -0
  134. package/dist/persona/embeddings.js.map +1 -0
  135. package/dist/persona/engine.d.ts +79 -0
  136. package/dist/persona/engine.d.ts.map +1 -0
  137. package/dist/persona/engine.js +1087 -0
  138. package/dist/persona/engine.js.map +1 -0
  139. package/dist/persona/index.d.ts +11 -0
  140. package/dist/persona/index.d.ts.map +1 -0
  141. package/dist/persona/index.js +11 -0
  142. package/dist/persona/index.js.map +1 -0
  143. package/dist/persona/lifecycle.d.ts +17 -0
  144. package/dist/persona/lifecycle.d.ts.map +1 -0
  145. package/dist/persona/lifecycle.js +36 -0
  146. package/dist/persona/lifecycle.js.map +1 -0
  147. package/dist/persona/retrieval.d.ts +6 -0
  148. package/dist/persona/retrieval.d.ts.map +1 -0
  149. package/dist/persona/retrieval.js +122 -0
  150. package/dist/persona/retrieval.js.map +1 -0
  151. package/dist/persona/sync.d.ts +15 -0
  152. package/dist/persona/sync.d.ts.map +1 -0
  153. package/dist/persona/sync.js +92 -0
  154. package/dist/persona/sync.js.map +1 -0
  155. package/dist/persona/types.d.ts +283 -0
  156. package/dist/persona/types.d.ts.map +1 -0
  157. package/dist/persona/types.js +2 -0
  158. package/dist/persona/types.js.map +1 -0
  159. package/dist/persona/zkp/engine.d.ts +26 -0
  160. package/dist/persona/zkp/engine.d.ts.map +1 -0
  161. package/dist/persona/zkp/engine.js +370 -0
  162. package/dist/persona/zkp/engine.js.map +1 -0
  163. package/dist/persona/zkp/types.d.ts +39 -0
  164. package/dist/persona/zkp/types.d.ts.map +1 -0
  165. package/dist/persona/zkp/types.js +2 -0
  166. package/dist/persona/zkp/types.js.map +1 -0
  167. package/dist/planner.d.ts +114 -0
  168. package/dist/planner.d.ts.map +1 -0
  169. package/dist/planner.js +522 -0
  170. package/dist/planner.js.map +1 -0
  171. package/dist/proactive/checkpoints.d.ts +9 -0
  172. package/dist/proactive/checkpoints.d.ts.map +1 -0
  173. package/dist/proactive/checkpoints.js +20 -0
  174. package/dist/proactive/checkpoints.js.map +1 -0
  175. package/dist/proactive/engine.d.ts +59 -0
  176. package/dist/proactive/engine.d.ts.map +1 -0
  177. package/dist/proactive/engine.js +406 -0
  178. package/dist/proactive/engine.js.map +1 -0
  179. package/dist/proactive/scheduler.d.ts +11 -0
  180. package/dist/proactive/scheduler.d.ts.map +1 -0
  181. package/dist/proactive/scheduler.js +45 -0
  182. package/dist/proactive/scheduler.js.map +1 -0
  183. package/dist/proactive/swarm-controller.d.ts +189 -0
  184. package/dist/proactive/swarm-controller.d.ts.map +1 -0
  185. package/dist/proactive/swarm-controller.js +477 -0
  186. package/dist/proactive/swarm-controller.js.map +1 -0
  187. package/dist/proactive/swarm-registry.d.ts +13 -0
  188. package/dist/proactive/swarm-registry.d.ts.map +1 -0
  189. package/dist/proactive/swarm-registry.js +122 -0
  190. package/dist/proactive/swarm-registry.js.map +1 -0
  191. package/dist/proactive/types.d.ts +145 -0
  192. package/dist/proactive/types.d.ts.map +1 -0
  193. package/dist/proactive/types.js +25 -0
  194. package/dist/proactive/types.js.map +1 -0
  195. package/dist/registry.d.ts +35 -0
  196. package/dist/registry.d.ts.map +1 -0
  197. package/dist/registry.js +88 -0
  198. package/dist/registry.js.map +1 -0
  199. package/dist/reputation.d.ts +123 -0
  200. package/dist/reputation.d.ts.map +1 -0
  201. package/dist/reputation.js +366 -0
  202. package/dist/reputation.js.map +1 -0
  203. package/dist/reputation.test.d.ts +5 -0
  204. package/dist/reputation.test.d.ts.map +1 -0
  205. package/dist/reputation.test.js +265 -0
  206. package/dist/reputation.test.js.map +1 -0
  207. package/dist/rooms.d.ts +96 -0
  208. package/dist/rooms.d.ts.map +1 -0
  209. package/dist/rooms.js +410 -0
  210. package/dist/rooms.js.map +1 -0
  211. package/dist/sdk/client.d.ts +290 -0
  212. package/dist/sdk/client.d.ts.map +1 -0
  213. package/dist/sdk/client.js +1287 -0
  214. package/dist/sdk/client.js.map +1 -0
  215. package/dist/sdk/index.d.ts +32 -0
  216. package/dist/sdk/index.d.ts.map +1 -0
  217. package/dist/sdk/index.js +70 -0
  218. package/dist/sdk/index.js.map +1 -0
  219. package/dist/security.d.ts +230 -0
  220. package/dist/security.d.ts.map +1 -0
  221. package/dist/security.js +652 -0
  222. package/dist/security.js.map +1 -0
  223. package/dist/skills/engine.d.ts +262 -0
  224. package/dist/skills/engine.d.ts.map +1 -0
  225. package/dist/skills/engine.js +788 -0
  226. package/dist/skills/engine.js.map +1 -0
  227. package/dist/skills/engine.test.d.ts +2 -0
  228. package/dist/skills/engine.test.d.ts.map +1 -0
  229. package/dist/skills/engine.test.js +134 -0
  230. package/dist/skills/engine.test.js.map +1 -0
  231. package/dist/skills/parser.d.ts +129 -0
  232. package/dist/skills/parser.d.ts.map +1 -0
  233. package/dist/skills/parser.js +318 -0
  234. package/dist/skills/parser.js.map +1 -0
  235. package/dist/social.d.ts +149 -0
  236. package/dist/social.d.ts.map +1 -0
  237. package/dist/social.js +401 -0
  238. package/dist/social.js.map +1 -0
  239. package/dist/storage-optimized.d.ts +116 -0
  240. package/dist/storage-optimized.d.ts.map +1 -0
  241. package/dist/storage-optimized.js +264 -0
  242. package/dist/storage-optimized.js.map +1 -0
  243. package/dist/storage.d.ts +584 -0
  244. package/dist/storage.d.ts.map +1 -0
  245. package/dist/storage.js +2703 -0
  246. package/dist/storage.js.map +1 -0
  247. package/dist/storage.test.d.ts +2 -0
  248. package/dist/storage.test.d.ts.map +1 -0
  249. package/dist/storage.test.js +78 -0
  250. package/dist/storage.test.js.map +1 -0
  251. package/dist/swp.d.ts +443 -0
  252. package/dist/swp.d.ts.map +1 -0
  253. package/dist/swp.js +223 -0
  254. package/dist/swp.js.map +1 -0
  255. package/dist/swp.test.d.ts +5 -0
  256. package/dist/swp.test.d.ts.map +1 -0
  257. package/dist/swp.test.js +127 -0
  258. package/dist/swp.test.js.map +1 -0
  259. package/dist/templates.d.ts +25 -0
  260. package/dist/templates.d.ts.map +1 -0
  261. package/dist/templates.js +1048 -0
  262. package/dist/templates.js.map +1 -0
  263. package/dist/test-e2e.d.ts +14 -0
  264. package/dist/test-e2e.d.ts.map +1 -0
  265. package/dist/test-e2e.js +266 -0
  266. package/dist/test-e2e.js.map +1 -0
  267. package/dist/workers/research-worker.d.ts +19 -0
  268. package/dist/workers/research-worker.d.ts.map +1 -0
  269. package/dist/workers/research-worker.js +141 -0
  270. package/dist/workers/research-worker.js.map +1 -0
  271. package/package.json +110 -0
@@ -0,0 +1,1087 @@
1
+ import { EventEmitter } from 'events';
2
+ import crypto from 'crypto';
3
+ import * as Automerge from '@automerge/automerge';
4
+ import { ulid } from 'ulid';
5
+ import { publicKeyFromDid, verify as verifySignature } from '../identity.js';
6
+ import { DOMAIN_POLICIES, getDomainPolicy, redactByDomainOperation } from './domains.js';
7
+ import { PersonaLifecycle } from './lifecycle.js';
8
+ import { PersonaCapabilityManager } from './capabilities.js';
9
+ import { PersonaEmbeddingService } from './embeddings.js';
10
+ import { computePersonalizedPageRank, rankMemories } from './retrieval.js';
11
+ import { createPersonaDelta, mergeDomainDoc, mergeEdgeWeighted, mergeNodeLww } from './sync.js';
12
+ import { PersonaZkpEngine } from './zkp/engine.js';
13
+ function isEncryptedPayload(value) {
14
+ const v = value;
15
+ return !!v && v.enc === true && typeof v.iv === 'string' && typeof v.tag === 'string' && typeof v.data === 'string';
16
+ }
17
+ export class PersonaVaultEngine extends EventEmitter {
18
+ storage;
19
+ identityDid;
20
+ capabilityManager;
21
+ lifecycle;
22
+ embeddings;
23
+ zkp;
24
+ encryptionKey;
25
+ claimSigningSecret;
26
+ graphRankCache = new Map();
27
+ constructor(storage, identityDid, config = {}) {
28
+ super();
29
+ this.storage = storage;
30
+ this.identityDid = identityDid;
31
+ this.capabilityManager = new PersonaCapabilityManager(storage);
32
+ this.lifecycle = new PersonaLifecycle(config.shortTermWindow ?? 50, config.emaAlpha ?? 0.15);
33
+ this.embeddings = new PersonaEmbeddingService({ onnxModelPath: config.onnxModelPath });
34
+ this.zkp = new PersonaZkpEngine(storage, identityDid);
35
+ const rawKey = config.encryptionKey ||
36
+ process.env.SOCIETY_PERSONA_FIELD_KEY ||
37
+ crypto.createHash('sha256').update(`persona:${identityDid}`).digest('hex');
38
+ this.encryptionKey = crypto.createHash('sha256').update(rawKey).digest();
39
+ this.claimSigningSecret = crypto.createHash('sha256').update(`persona-claim:${rawKey}`).digest();
40
+ if (config.defaultVaultName !== undefined) {
41
+ this.ensureDefaultVault(config.defaultVaultName).catch(() => { });
42
+ }
43
+ }
44
+ async createVault(input) {
45
+ const now = Date.now();
46
+ const vault = {
47
+ id: `vault_${ulid()}`,
48
+ ownerDid: input.ownerDid || this.identityDid,
49
+ name: input.name,
50
+ createdAt: now,
51
+ updatedAt: now,
52
+ settings: {
53
+ shortTermWindow: 50,
54
+ emaAlpha: 0.15,
55
+ maxShareResults: 200,
56
+ },
57
+ };
58
+ this.storage.savePersonaVault?.(vault);
59
+ this.emit('persona:vault:created', vault);
60
+ return vault;
61
+ }
62
+ async addMemory(input) {
63
+ const vaultId = await this.resolveVaultId(input.vaultId);
64
+ const now = Date.now();
65
+ const policy = getDomainPolicy(input.domain);
66
+ const rawContent = input.content;
67
+ const content = policy.sensitive ? '[ENCRYPTED]' : rawContent;
68
+ const metadata = { ...(input.metadata || {}) };
69
+ if (policy.sensitive) {
70
+ metadata.encryptedContent = this.encrypt(rawContent);
71
+ }
72
+ const node = {
73
+ id: `pmem_${ulid()}`,
74
+ vaultId,
75
+ domain: input.domain,
76
+ type: input.type,
77
+ title: input.title,
78
+ content,
79
+ tags: input.tags || [],
80
+ confidence: input.confidence ?? 0.8,
81
+ source: input.source || { type: 'sdk', actorDid: this.identityDid },
82
+ metadata,
83
+ validFrom: input.validFrom,
84
+ validTo: input.validTo,
85
+ createdAt: now,
86
+ updatedAt: now,
87
+ };
88
+ this.storage.upsertPersonaNode?.(node);
89
+ await this.indexEmbedding(node);
90
+ this.upsertLocalDomainDoc(vaultId, node.domain, {
91
+ [node.id]: { title: node.title, updatedAt: node.updatedAt, deletedAt: node.deletedAt ?? null },
92
+ });
93
+ this.bumpLifecycle(vaultId, node);
94
+ this.emit('persona:memory:added', node);
95
+ return this.inflateNode(node);
96
+ }
97
+ async updateMemory(nodeId, patch) {
98
+ const current = this.storage.getPersonaNode?.(nodeId);
99
+ if (!current || current.deletedAt) {
100
+ throw new Error(`Persona node not found: ${nodeId}`);
101
+ }
102
+ const policy = getDomainPolicy(current.domain);
103
+ const merged = {
104
+ ...current,
105
+ title: patch.title ?? current.title,
106
+ content: patch.content !== undefined ? (policy.sensitive ? '[ENCRYPTED]' : patch.content) : current.content,
107
+ tags: patch.tags ?? current.tags,
108
+ confidence: patch.confidence ?? current.confidence,
109
+ metadata: {
110
+ ...current.metadata,
111
+ ...(patch.metadata || {}),
112
+ },
113
+ validFrom: patch.validFrom ?? current.validFrom,
114
+ validTo: patch.validTo ?? current.validTo,
115
+ updatedAt: Date.now(),
116
+ };
117
+ if (policy.sensitive && patch.content !== undefined) {
118
+ merged.metadata = {
119
+ ...merged.metadata,
120
+ encryptedContent: this.encrypt(patch.content),
121
+ };
122
+ }
123
+ this.storage.upsertPersonaNode?.(merged);
124
+ await this.indexEmbedding(merged);
125
+ this.upsertLocalDomainDoc(merged.vaultId, merged.domain, {
126
+ [merged.id]: { title: merged.title, updatedAt: merged.updatedAt, deletedAt: merged.deletedAt ?? null },
127
+ });
128
+ this.bumpLifecycle(merged.vaultId, merged);
129
+ this.emit('persona:memory:updated', merged);
130
+ return this.inflateNode(merged);
131
+ }
132
+ async deleteMemory(nodeId, _reason) {
133
+ const current = this.storage.getPersonaNode?.(nodeId);
134
+ if (!current || current.deletedAt)
135
+ return;
136
+ this.storage.softDeletePersonaNode?.(nodeId, Date.now());
137
+ this.storage.deletePersonaEmbedding?.(nodeId);
138
+ this.upsertLocalDomainDoc(current.vaultId, current.domain, {
139
+ [nodeId]: { deletedAt: Date.now() },
140
+ });
141
+ this.emit('persona:memory:deleted', { nodeId, vaultId: current.vaultId });
142
+ }
143
+ async linkMemories(input) {
144
+ const source = this.storage.getPersonaNode?.(input.sourceNodeId);
145
+ const target = this.storage.getPersonaNode?.(input.targetNodeId);
146
+ if (!source || !target) {
147
+ throw new Error('Cannot create edge: source or target node not found');
148
+ }
149
+ const edge = {
150
+ id: `pedge_${ulid()}`,
151
+ vaultId: input.vaultId || source.vaultId,
152
+ sourceNodeId: input.sourceNodeId,
153
+ targetNodeId: input.targetNodeId,
154
+ type: input.type,
155
+ weight: input.weight ?? 0.8,
156
+ confidence: input.confidence ?? 0.8,
157
+ metadata: input.metadata || {},
158
+ validFrom: input.validFrom,
159
+ validTo: input.validTo,
160
+ updatedAt: Date.now(),
161
+ };
162
+ this.storage.upsertPersonaEdge?.(edge);
163
+ this.emit('persona:edge:upserted', edge);
164
+ return edge;
165
+ }
166
+ async queryMemories(input) {
167
+ const startedAt = Date.now();
168
+ const vaultId = await this.resolveVaultId(input.vaultId);
169
+ const nodes = (this.storage.listPersonaNodes?.(vaultId, {
170
+ includeDeleted: input.includeDeleted,
171
+ domain: input.domain,
172
+ domains: input.domains,
173
+ types: input.types,
174
+ tags: input.tags,
175
+ }) || []);
176
+ const edges = (this.storage.listPersonaEdges?.(vaultId) || []);
177
+ const hydratedNodes = nodes.map((n) => this.inflateNode(n));
178
+ const graphRank = this.getOrBuildGraphRank(vaultId, hydratedNodes, edges, input);
179
+ let result = rankMemories(hydratedNodes, edges, input, { graphRank });
180
+ // Blend with FTS when query is present.
181
+ if (input.query && input.query.trim()) {
182
+ const fts = (this.storage.searchPersonaNodes?.(vaultId, input.query, input.limit || 20) || []);
183
+ const ftsMap = new Map(fts.map((r) => [r.id, r.score]));
184
+ const embedding = await this.embeddings.embedText(input.query);
185
+ const vectorRows = (this.storage.searchPersonaVector?.(vaultId, embedding.vector, input.limit || 20) || []);
186
+ const vectorMap = new Map(vectorRows.map((r) => [r.nodeId, r.score]));
187
+ result = {
188
+ ...result,
189
+ nodes: result.nodes
190
+ .map((node) => {
191
+ const lexical = Math.max(node.scoreBreakdown.lexical || 0, ftsMap.get(node.id) || 0);
192
+ const vector = vectorMap.get(node.id) || 0;
193
+ const graph = node.scoreBreakdown.graph || 0;
194
+ const final = 0.4 * lexical + 0.35 * vector + 0.25 * graph;
195
+ return {
196
+ ...node,
197
+ score: final,
198
+ scoreBreakdown: {
199
+ lexical,
200
+ vector,
201
+ graph,
202
+ final,
203
+ },
204
+ };
205
+ })
206
+ .sort((a, b) => b.score - a.score),
207
+ };
208
+ }
209
+ const elapsed = Date.now() - startedAt;
210
+ this.recordMetric('persona.query.latency_ms', elapsed, {
211
+ vaultId,
212
+ domain: input.domain || (input.domains?.join(',') || '*'),
213
+ query: input.query ? 'yes' : 'no',
214
+ resultCount: result.nodes.length,
215
+ });
216
+ return {
217
+ ...result,
218
+ elapsedMs: elapsed,
219
+ };
220
+ }
221
+ async queryGraph(input) {
222
+ const vaultId = await this.resolveVaultId(input.vaultId);
223
+ const maxDepth = Math.max(1, input.maxDepth || 2);
224
+ const limit = Math.max(1, input.limit || 200);
225
+ const allNodes = (this.storage.listPersonaNodes?.(vaultId, {
226
+ includeDeleted: false,
227
+ domain: input.domain,
228
+ }) || []);
229
+ const allEdges = (this.storage.listPersonaEdges?.(vaultId) || []);
230
+ const allHyperEdges = (this.storage.listPersonaHyperEdges?.(vaultId) || []);
231
+ if (!input.rootNodeId) {
232
+ return {
233
+ nodes: allNodes.slice(0, limit).map((n) => this.inflateNode(n)),
234
+ edges: allEdges.slice(0, limit),
235
+ hyperEdges: allHyperEdges.slice(0, limit),
236
+ };
237
+ }
238
+ const visited = new Set([input.rootNodeId]);
239
+ let frontier = new Set([input.rootNodeId]);
240
+ for (let depth = 0; depth < maxDepth; depth++) {
241
+ const next = new Set();
242
+ for (const edge of allEdges) {
243
+ if (edge.deletedAt)
244
+ continue;
245
+ if (frontier.has(edge.sourceNodeId) && !visited.has(edge.targetNodeId)) {
246
+ visited.add(edge.targetNodeId);
247
+ next.add(edge.targetNodeId);
248
+ }
249
+ if (frontier.has(edge.targetNodeId) && !visited.has(edge.sourceNodeId)) {
250
+ visited.add(edge.sourceNodeId);
251
+ next.add(edge.sourceNodeId);
252
+ }
253
+ }
254
+ frontier = next;
255
+ if (frontier.size === 0)
256
+ break;
257
+ }
258
+ const nodes = allNodes.filter((n) => visited.has(n.id)).slice(0, limit).map((n) => this.inflateNode(n));
259
+ const edges = allEdges.filter((e) => visited.has(e.sourceNodeId) && visited.has(e.targetNodeId)).slice(0, limit);
260
+ const hyperEdges = allHyperEdges.filter((h) => h.nodeIds.some((id) => visited.has(id))).slice(0, limit);
261
+ return { nodes, edges, hyperEdges };
262
+ }
263
+ async updatePreference(input) {
264
+ const node = await this.addMemory({
265
+ vaultId: input.vaultId,
266
+ domain: input.domain || 'preferences',
267
+ type: 'preference',
268
+ title: input.key,
269
+ content: JSON.stringify(input.value),
270
+ confidence: input.confidence ?? 0.9,
271
+ tags: ['preference', ...(input.tags || [])],
272
+ metadata: { key: input.key, value: input.value },
273
+ source: { type: 'sdk', actorDid: this.identityDid },
274
+ });
275
+ this.emit('persona:preference:updated', node);
276
+ return node;
277
+ }
278
+ async verifyPersonaAccessLog(input) {
279
+ const log = this.storage.getPersonaAccessLog?.(input.logId);
280
+ if (!log) {
281
+ return { logId: input.logId, valid: false, reason: 'Log not found' };
282
+ }
283
+ if (!log.signature) {
284
+ return { logId: input.logId, valid: false, reason: 'Missing signature' };
285
+ }
286
+ if (!log.signerDid) {
287
+ return { logId: input.logId, valid: false, reason: 'Missing signer DID' };
288
+ }
289
+ if (log.sigAlg && log.sigAlg !== 'ed25519') {
290
+ return { logId: input.logId, valid: false, reason: `Unsupported signature algorithm: ${log.sigAlg}` };
291
+ }
292
+ const payload = JSON.stringify({
293
+ vaultId: log.vaultId,
294
+ tokenId: log.tokenId || null,
295
+ serviceDid: log.serviceDid,
296
+ operation: log.operation,
297
+ resource: log.resource,
298
+ result: log.result,
299
+ details: log.details || null,
300
+ ts: log.ts,
301
+ });
302
+ const payloadBase64 = Buffer.from(new TextEncoder().encode(payload)).toString('base64');
303
+ const valid = verifySignature(publicKeyFromDid(log.signerDid), payloadBase64, log.signature);
304
+ if (!valid) {
305
+ return { logId: input.logId, valid: false, reason: 'Invalid signature' };
306
+ }
307
+ return { logId: input.logId, valid: true };
308
+ }
309
+ async runRetentionSweep(input = {}) {
310
+ const now = Date.now();
311
+ const domains = input.domain
312
+ ? [input.domain]
313
+ : Object.keys(DOMAIN_POLICIES);
314
+ const vaultIds = input.vaultId
315
+ ? [input.vaultId]
316
+ : (this.storage.getPersonaVaults?.(this.identityDid)?.map((vault) => vault.id) || []);
317
+ let scanned = 0;
318
+ let deleted = 0;
319
+ for (const vaultId of vaultIds) {
320
+ for (const domain of domains) {
321
+ const policy = getDomainPolicy(domain);
322
+ const cutoff = now - policy.retentionDays * 24 * 60 * 60 * 1000;
323
+ const nodes = (this.storage.listPersonaNodes?.(vaultId, {
324
+ includeDeleted: false,
325
+ domain,
326
+ }) || []);
327
+ scanned += nodes.length;
328
+ const stale = nodes.filter((node) => {
329
+ const ageMarker = node.validTo ?? node.updatedAt ?? node.createdAt;
330
+ return ageMarker <= cutoff;
331
+ });
332
+ if (!input.dryRun) {
333
+ for (const node of stale) {
334
+ this.storage.softDeletePersonaNode?.(node.id, now);
335
+ this.storage.deletePersonaEmbedding?.(node.id);
336
+ deleted += 1;
337
+ }
338
+ }
339
+ this.storage.upsertPersonaRetentionState?.({
340
+ vaultId,
341
+ domain,
342
+ lastCleanupAt: now,
343
+ });
344
+ }
345
+ }
346
+ this.recordMetric('persona.retention.sweep.scanned', scanned, {
347
+ vaultCount: vaultIds.length,
348
+ domainCount: domains.length,
349
+ dryRun: !!input.dryRun,
350
+ });
351
+ this.recordMetric('persona.retention.sweep.deleted', deleted, {
352
+ vaultCount: vaultIds.length,
353
+ domainCount: domains.length,
354
+ dryRun: !!input.dryRun,
355
+ });
356
+ return { scanned, deleted };
357
+ }
358
+ async issueCapability(input) {
359
+ const vaultId = await this.resolveVaultId(input.vaultId);
360
+ const cap = this.capabilityManager.issue({ ...input, vaultId });
361
+ this.emit('persona:capability:issued', cap);
362
+ return cap;
363
+ }
364
+ async attenuateCapability(input) {
365
+ const cap = this.capabilityManager.attenuate(input.tokenId, input.caveatsPatch);
366
+ this.emit('persona:capability:attenuated', cap);
367
+ return cap;
368
+ }
369
+ async revokeCapability(tokenId, reason) {
370
+ this.capabilityManager.revoke(tokenId, reason);
371
+ this.emit('persona:capability:revoked', { tokenId, reason });
372
+ }
373
+ validateCapability(input) {
374
+ return this.capabilityManager.validate(input);
375
+ }
376
+ async issueClaim(input) {
377
+ const vaultId = await this.resolveVaultId(input.vaultId);
378
+ const now = Date.now();
379
+ const subjectDid = input.subjectDid || this.identityDid;
380
+ const payloadEnc = this.encrypt(JSON.stringify(input.payload));
381
+ const payloadForSig = JSON.stringify({
382
+ vaultId,
383
+ subjectDid,
384
+ issuerDid: input.issuerDid || this.identityDid,
385
+ schema: input.schema,
386
+ payload: input.payload,
387
+ issuedAt: now,
388
+ expiresAt: input.expiresAt,
389
+ });
390
+ if (input.issuerDid && input.issuerSignature) {
391
+ const ok = verifySignature(publicKeyFromDid(input.issuerDid), payloadForSig, input.issuerSignature);
392
+ if (!ok) {
393
+ throw new Error('Invalid issuer signature for claim');
394
+ }
395
+ }
396
+ const signature = crypto
397
+ .createHmac('sha256', this.claimSigningSecret)
398
+ .update(payloadForSig)
399
+ .digest('base64url');
400
+ const claim = {
401
+ id: `claim_${ulid()}`,
402
+ vaultId,
403
+ subjectDid,
404
+ issuerDid: input.issuerDid || this.identityDid,
405
+ schema: input.schema,
406
+ payload: input.payload,
407
+ status: 'active',
408
+ issuedAt: now,
409
+ expiresAt: input.expiresAt,
410
+ signature,
411
+ };
412
+ this.storage.savePersonaClaim?.({
413
+ id: claim.id,
414
+ vaultId: claim.vaultId,
415
+ subjectDid: claim.subjectDid,
416
+ issuerDid: claim.issuerDid,
417
+ schema: claim.schema,
418
+ payloadEnc: JSON.stringify(payloadEnc),
419
+ status: claim.status,
420
+ issuedAt: claim.issuedAt,
421
+ expiresAt: claim.expiresAt,
422
+ signature: claim.signature,
423
+ });
424
+ this.emit('persona:claim:issued', claim);
425
+ return claim;
426
+ }
427
+ async revokeClaim(claimId, _reason) {
428
+ this.storage.updatePersonaClaimStatus?.(claimId, 'revoked');
429
+ this.emit('persona:claim:revoked', { claimId });
430
+ }
431
+ async generateZkProof(input) {
432
+ const vaultId = await this.resolveVaultId(input.vaultId);
433
+ const bundle = this.zkp.generateProof(vaultId, input);
434
+ this.emit('persona:zkp:generated', bundle);
435
+ return bundle;
436
+ }
437
+ async verifyZkProof(input) {
438
+ const startedAt = Date.now();
439
+ const result = this.zkp.verifyProof(input);
440
+ this.recordMetric('persona.zkp.verify.latency_ms', Date.now() - startedAt, {
441
+ circuitId: result.circuitId,
442
+ valid: result.valid,
443
+ });
444
+ this.emit('persona:zkp:verified', result);
445
+ return result;
446
+ }
447
+ async applySyncDelta(delta) {
448
+ const startedAt = Date.now();
449
+ const vaultId = await this.resolveVaultId(delta.vaultId);
450
+ if (vaultId !== delta.vaultId) {
451
+ const result = { applied: 0, ignored: delta.operations.length, cursor: delta.id };
452
+ this.recordMetric('persona.sync.apply.latency_ms', Date.now() - startedAt, {
453
+ vaultId: delta.vaultId,
454
+ applied: result.applied,
455
+ ignored: result.ignored,
456
+ reason: 'vault-mismatch',
457
+ });
458
+ return result;
459
+ }
460
+ if (this.storage.hasPersonaSyncApplied?.(delta.fromDid, delta.id)) {
461
+ const result = { applied: 0, ignored: delta.operations.length, cursor: delta.id };
462
+ this.recordMetric('persona.sync.apply.latency_ms', Date.now() - startedAt, {
463
+ vaultId: delta.vaultId,
464
+ applied: result.applied,
465
+ ignored: result.ignored,
466
+ reason: 'delta-already-applied',
467
+ });
468
+ return result;
469
+ }
470
+ const requiredProofs = new Set();
471
+ for (const op of delta.operations) {
472
+ if (op.type === 'node_upsert' ||
473
+ op.type === 'node_delete' ||
474
+ op.type === 'edge_upsert' ||
475
+ op.type === 'edge_delete' ||
476
+ op.type === 'claim_upsert') {
477
+ const payload = op.payload;
478
+ const nestedNode = payload.node && typeof payload.node === 'object'
479
+ ? payload.node
480
+ : undefined;
481
+ const domainRaw = (typeof payload.domain === 'string' ? payload.domain : undefined) ||
482
+ (nestedNode && typeof nestedNode.domain === 'string' ? nestedNode.domain : '') ||
483
+ '';
484
+ const domain = String(domainRaw).toLowerCase();
485
+ if (domain === 'health' || domain === 'finance' || domain === 'identity') {
486
+ requiredProofs.add('domain_membership');
487
+ }
488
+ }
489
+ if (op.type === 'capability_revoke' || op.type === 'capability_attenuate') {
490
+ requiredProofs.add('capability_possession');
491
+ }
492
+ }
493
+ if (requiredProofs.size > 0) {
494
+ const proofs = delta.proofs || [];
495
+ for (const required of requiredProofs) {
496
+ const found = proofs.find((p) => p.circuitId === required);
497
+ if (!found) {
498
+ const result = {
499
+ applied: 0,
500
+ ignored: delta.operations.length,
501
+ cursor: delta.id,
502
+ };
503
+ this.recordMetric('persona.sync.apply.latency_ms', Date.now() - startedAt, {
504
+ vaultId: delta.vaultId,
505
+ applied: result.applied,
506
+ ignored: result.ignored,
507
+ reason: 'missing-proof',
508
+ });
509
+ return result;
510
+ }
511
+ const verified = await this.verifyZkProof({
512
+ vaultId: delta.vaultId,
513
+ proofBundle: found,
514
+ });
515
+ if (!verified.valid) {
516
+ const result = {
517
+ applied: 0,
518
+ ignored: delta.operations.length,
519
+ cursor: delta.id,
520
+ };
521
+ this.recordMetric('persona.sync.apply.latency_ms', Date.now() - startedAt, {
522
+ vaultId: delta.vaultId,
523
+ applied: result.applied,
524
+ ignored: result.ignored,
525
+ reason: 'invalid-proof',
526
+ });
527
+ return result;
528
+ }
529
+ }
530
+ }
531
+ let applied = 0;
532
+ let ignored = 0;
533
+ for (const op of delta.operations) {
534
+ switch (op.type) {
535
+ case 'node_upsert': {
536
+ const incoming = op.payload;
537
+ const local = this.storage.getPersonaNode?.(incoming.id);
538
+ const merged = mergeNodeLww(local, incoming);
539
+ this.storage.upsertPersonaNode?.(merged);
540
+ await this.indexEmbedding(merged);
541
+ this.mergeCrdtDomainDoc({
542
+ vaultId: merged.vaultId,
543
+ domain: merged.domain,
544
+ patch: {
545
+ nodes: {
546
+ [merged.id]: {
547
+ id: merged.id,
548
+ title: merged.title,
549
+ updatedAt: merged.updatedAt,
550
+ deletedAt: merged.deletedAt ?? null,
551
+ },
552
+ },
553
+ },
554
+ clock: delta.vectorClock,
555
+ });
556
+ applied += 1;
557
+ break;
558
+ }
559
+ case 'node_delete': {
560
+ const nodeId = String(op.payload.nodeId || '');
561
+ if (!nodeId) {
562
+ ignored += 1;
563
+ break;
564
+ }
565
+ const existing = this.storage.getPersonaNode?.(nodeId);
566
+ this.storage.softDeletePersonaNode?.(nodeId, Date.now());
567
+ this.storage.deletePersonaEmbedding?.(nodeId);
568
+ if (existing) {
569
+ this.mergeCrdtDomainDoc({
570
+ vaultId: existing.vaultId,
571
+ domain: existing.domain,
572
+ patch: {
573
+ nodes: {
574
+ [nodeId]: {
575
+ id: nodeId,
576
+ deletedAt: Date.now(),
577
+ },
578
+ },
579
+ },
580
+ clock: delta.vectorClock,
581
+ });
582
+ }
583
+ applied += 1;
584
+ break;
585
+ }
586
+ case 'edge_upsert': {
587
+ const incoming = op.payload;
588
+ const local = this.storage.getPersonaEdge?.(incoming.id);
589
+ const merged = mergeEdgeWeighted(local, incoming);
590
+ this.storage.upsertPersonaEdge?.(merged);
591
+ const sourceNode = this.storage.getPersonaNode?.(merged.sourceNodeId);
592
+ this.mergeCrdtDomainDoc({
593
+ vaultId: merged.vaultId,
594
+ domain: sourceNode?.domain || 'general',
595
+ patch: {
596
+ edges: {
597
+ [merged.id]: {
598
+ id: merged.id,
599
+ sourceNodeId: merged.sourceNodeId,
600
+ targetNodeId: merged.targetNodeId,
601
+ confidence: merged.confidence,
602
+ weight: merged.weight,
603
+ updatedAt: merged.updatedAt,
604
+ },
605
+ },
606
+ },
607
+ clock: delta.vectorClock,
608
+ });
609
+ applied += 1;
610
+ break;
611
+ }
612
+ case 'edge_delete': {
613
+ const edgeId = String(op.payload.edgeId || '');
614
+ if (!edgeId) {
615
+ ignored += 1;
616
+ break;
617
+ }
618
+ const existing = this.storage.getPersonaEdge?.(edgeId);
619
+ this.storage.softDeletePersonaEdge?.(edgeId, Date.now());
620
+ if (existing) {
621
+ const sourceNode = this.storage.getPersonaNode?.(existing.sourceNodeId);
622
+ this.mergeCrdtDomainDoc({
623
+ vaultId: existing.vaultId,
624
+ domain: sourceNode?.domain || 'general',
625
+ patch: {
626
+ edges: {
627
+ [edgeId]: {
628
+ id: edgeId,
629
+ deletedAt: Date.now(),
630
+ },
631
+ },
632
+ },
633
+ clock: delta.vectorClock,
634
+ });
635
+ }
636
+ applied += 1;
637
+ break;
638
+ }
639
+ case 'capability_revoke': {
640
+ const tokenId = String(op.payload.tokenId || '');
641
+ const reason = String(op.payload.reason || 'sync-revocation');
642
+ if (!tokenId) {
643
+ ignored += 1;
644
+ break;
645
+ }
646
+ this.storage.updatePersonaCapabilityStatus?.(tokenId, 'revoked', reason, Date.now());
647
+ applied += 1;
648
+ break;
649
+ }
650
+ case 'capability_attenuate': {
651
+ const tokenId = String(op.payload.tokenId || '');
652
+ const caveatsPatch = (op.payload.caveatsPatch || {});
653
+ if (!tokenId) {
654
+ ignored += 1;
655
+ break;
656
+ }
657
+ this.capabilityManager.attenuate(tokenId, caveatsPatch);
658
+ applied += 1;
659
+ break;
660
+ }
661
+ case 'claim_upsert': {
662
+ const claim = op.payload;
663
+ if (!claim?.id) {
664
+ ignored += 1;
665
+ break;
666
+ }
667
+ this.storage.savePersonaClaim?.({
668
+ id: claim.id,
669
+ vaultId: claim.vaultId,
670
+ subjectDid: claim.subjectDid,
671
+ issuerDid: claim.issuerDid,
672
+ schema: claim.schema,
673
+ payloadEnc: JSON.stringify(this.encrypt(JSON.stringify(claim.payload || {}))),
674
+ status: claim.status,
675
+ issuedAt: claim.issuedAt,
676
+ expiresAt: claim.expiresAt,
677
+ revokedAt: claim.revokedAt,
678
+ signature: claim.signature,
679
+ });
680
+ this.mergeCrdtDomainDoc({
681
+ vaultId: claim.vaultId,
682
+ domain: 'identity',
683
+ patch: {
684
+ claims: {
685
+ [claim.id]: {
686
+ id: claim.id,
687
+ schema: claim.schema,
688
+ status: claim.status,
689
+ updatedAt: claim.issuedAt,
690
+ },
691
+ },
692
+ },
693
+ clock: delta.vectorClock,
694
+ });
695
+ applied += 1;
696
+ break;
697
+ }
698
+ case 'claim_revoke': {
699
+ const claimId = String(op.payload.claimId || '');
700
+ if (!claimId) {
701
+ ignored += 1;
702
+ break;
703
+ }
704
+ this.storage.updatePersonaClaimStatus?.(claimId, 'revoked');
705
+ this.mergeCrdtDomainDoc({
706
+ vaultId: delta.vaultId,
707
+ domain: 'identity',
708
+ patch: {
709
+ claims: {
710
+ [claimId]: {
711
+ id: claimId,
712
+ status: 'revoked',
713
+ updatedAt: Date.now(),
714
+ },
715
+ },
716
+ },
717
+ clock: delta.vectorClock,
718
+ });
719
+ applied += 1;
720
+ break;
721
+ }
722
+ case 'zkp_proof_upsert': {
723
+ const proof = op.payload;
724
+ if (!proof?.id) {
725
+ ignored += 1;
726
+ break;
727
+ }
728
+ this.storage.savePersonaZkpProof?.({
729
+ id: proof.id,
730
+ vaultId: proof.vaultId,
731
+ circuitId: proof.circuitId,
732
+ proofBlob: proof.proof,
733
+ publicInputs: proof.publicInputs || {},
734
+ claimIds: proof.claimIds || [],
735
+ createdAt: proof.createdAt,
736
+ expiresAt: proof.expiresAt,
737
+ });
738
+ applied += 1;
739
+ break;
740
+ }
741
+ default:
742
+ ignored += 1;
743
+ break;
744
+ }
745
+ }
746
+ this.storage.savePersonaSyncState?.({
747
+ peerDid: delta.fromDid,
748
+ vaultId: delta.vaultId,
749
+ cursorId: delta.id,
750
+ clock: delta.vectorClock,
751
+ updatedAt: Date.now(),
752
+ });
753
+ this.storage.markPersonaSyncApplied?.(delta.fromDid, delta.id, delta.vaultId);
754
+ const result = { applied, ignored, cursor: delta.id };
755
+ this.recordMetric('persona.sync.apply.latency_ms', Date.now() - startedAt, {
756
+ vaultId: delta.vaultId,
757
+ applied,
758
+ ignored,
759
+ operationCount: delta.operations.length,
760
+ });
761
+ return result;
762
+ }
763
+ async exportSubgraph(input) {
764
+ const redactionOperation = input.redactionOperation || 'export';
765
+ const graph = await this.queryGraph({
766
+ vaultId: input.vaultId,
767
+ domain: input.domain,
768
+ rootNodeId: input.nodeIds?.[0],
769
+ maxDepth: input.includeNeighbors ? 2 : 1,
770
+ limit: 1000,
771
+ });
772
+ if (!input.nodeIds?.length) {
773
+ return {
774
+ vaultId: graph.nodes[0]?.vaultId || (await this.resolveVaultId(input.vaultId)),
775
+ exportedAt: Date.now(),
776
+ nodes: graph.nodes.map((node) => redactByDomainOperation(node.domain, node, redactionOperation)),
777
+ edges: graph.edges,
778
+ hyperEdges: graph.hyperEdges,
779
+ };
780
+ }
781
+ const selected = new Set(input.nodeIds);
782
+ const nodes = graph.nodes
783
+ .filter((n) => selected.has(n.id))
784
+ .map((node) => redactByDomainOperation(node.domain, node, redactionOperation));
785
+ const edges = graph.edges.filter((e) => selected.has(e.sourceNodeId) || selected.has(e.targetNodeId));
786
+ const hyperEdges = graph.hyperEdges.filter((h) => h.nodeIds.some((id) => selected.has(id)));
787
+ return {
788
+ vaultId: await this.resolveVaultId(input.vaultId),
789
+ exportedAt: Date.now(),
790
+ nodes,
791
+ edges,
792
+ hyperEdges,
793
+ };
794
+ }
795
+ async getProfile(vaultId) {
796
+ const resolvedVaultId = await this.resolveVaultId(vaultId);
797
+ const prefs = await this.queryMemories({
798
+ vaultId: resolvedVaultId,
799
+ domain: 'preferences',
800
+ limit: 50,
801
+ });
802
+ const identity = await this.queryMemories({
803
+ vaultId: resolvedVaultId,
804
+ domain: 'identity',
805
+ limit: 50,
806
+ });
807
+ return {
808
+ vaultId: resolvedVaultId,
809
+ did: this.identityDid,
810
+ preferences: prefs.nodes.map((n) => ({ key: n.title, value: n.content })),
811
+ identity: identity.nodes.map((n) => redactByDomainOperation(n.domain, n, 'read')),
812
+ generatedAt: Date.now(),
813
+ };
814
+ }
815
+ async listClaims(vaultId, includeRevoked = false) {
816
+ const resolvedVaultId = await this.resolveVaultId(vaultId);
817
+ const claims = this.storage.listPersonaClaims?.(resolvedVaultId, { includeRevoked }) || [];
818
+ return claims.map((record) => this.inflateClaim(record));
819
+ }
820
+ async getClaim(claimId) {
821
+ const record = this.storage.getPersonaClaim?.(claimId);
822
+ if (!record)
823
+ return undefined;
824
+ return this.inflateClaim(record);
825
+ }
826
+ listZkProofs(vaultId) {
827
+ const resolvedVaultId = vaultId || this.storage.getPersonaVaults?.(this.identityDid)?.[0]?.id;
828
+ if (!resolvedVaultId)
829
+ return [];
830
+ const rows = this.storage.listPersonaZkpProofs?.(resolvedVaultId) || [];
831
+ return rows.map((row) => ({
832
+ id: row.id,
833
+ vaultId: row.vaultId,
834
+ circuitId: row.circuitId,
835
+ proof: row.proofBlob,
836
+ publicInputs: row.publicInputs || {},
837
+ claimIds: row.claimIds || [],
838
+ createdAt: row.createdAt,
839
+ expiresAt: row.expiresAt,
840
+ proofSystem: this.detectProofSystem(row.proofBlob),
841
+ }));
842
+ }
843
+ getZkProof(proofId) {
844
+ const row = this.storage.getPersonaZkpProof?.(proofId);
845
+ if (!row)
846
+ return undefined;
847
+ return {
848
+ id: row.id,
849
+ vaultId: row.vaultId,
850
+ circuitId: row.circuitId,
851
+ proof: row.proofBlob,
852
+ publicInputs: row.publicInputs || {},
853
+ claimIds: row.claimIds || [],
854
+ createdAt: row.createdAt,
855
+ expiresAt: row.expiresAt,
856
+ proofSystem: this.detectProofSystem(row.proofBlob),
857
+ };
858
+ }
859
+ listZkCircuits() {
860
+ return this.zkp.listCircuits();
861
+ }
862
+ buildSyncDelta(input) {
863
+ const state = this.storage.getPersonaSyncState?.(this.identityDid, input.vaultId);
864
+ const clock = { ...(state?.clock || {}), [this.identityDid]: ((state?.clock?.[this.identityDid] || 0) + 1) };
865
+ return createPersonaDelta({
866
+ vaultId: input.vaultId,
867
+ fromDid: this.identityDid,
868
+ operations: input.operations,
869
+ vectorClock: clock,
870
+ cursor: input.cursor,
871
+ proofs: input.proofs,
872
+ });
873
+ }
874
+ async resolveVaultId(vaultId) {
875
+ if (vaultId)
876
+ return vaultId;
877
+ const existing = this.storage.getPersonaVaults?.(this.identityDid) || [];
878
+ if (existing.length > 0) {
879
+ return existing[0].id;
880
+ }
881
+ const created = await this.createVault({ name: 'Persona Vault', ownerDid: this.identityDid });
882
+ return created.id;
883
+ }
884
+ async ensureDefaultVault(name) {
885
+ const existing = this.storage.getPersonaVaults?.(this.identityDid) || [];
886
+ if (existing.length > 0)
887
+ return;
888
+ await this.createVault({ name, ownerDid: this.identityDid });
889
+ }
890
+ bumpLifecycle(vaultId, node) {
891
+ const vault = this.storage.getPersonaVault?.(vaultId);
892
+ const state = vault?.lifecycle || undefined;
893
+ const domainPolicy = getDomainPolicy(node.domain);
894
+ const next = this.lifecycle.update(state, node, {
895
+ shortTermWindow: domainPolicy.pamu.shortTermWindow,
896
+ emaAlpha: domainPolicy.pamu.emaAlpha,
897
+ promoteThreshold: domainPolicy.pamu.promoteThreshold,
898
+ });
899
+ if (vault) {
900
+ this.storage.savePersonaVault?.({
901
+ ...vault,
902
+ lifecycle: next,
903
+ updatedAt: Date.now(),
904
+ });
905
+ }
906
+ }
907
+ async indexEmbedding(node) {
908
+ const embedding = await this.embeddings.embedText(`${node.title}\n${node.content}\n${(node.tags || []).join(' ')}`);
909
+ const existing = this.storage.getPersonaEmbedding?.(node.id);
910
+ const rowId = existing?.vecRowId || this.nextVectorRowId(node.id);
911
+ this.storage.upsertPersonaVector?.(rowId, embedding.vector);
912
+ this.storage.upsertPersonaEmbedding?.({
913
+ nodeId: node.id,
914
+ vaultId: node.vaultId,
915
+ model: embedding.model,
916
+ dim: embedding.dim,
917
+ vecRowId: rowId,
918
+ vector: embedding.vector,
919
+ updatedAt: Date.now(),
920
+ });
921
+ }
922
+ nextVectorRowId(seed) {
923
+ const digest = crypto.createHash('sha256').update(seed).digest();
924
+ const value = digest.readUInt32BE(0);
925
+ return Math.max(1, value);
926
+ }
927
+ upsertLocalDomainDoc(vaultId, domain, entries) {
928
+ const docId = `crdt_${vaultId}_${domain}`;
929
+ const current = this.storage.getPersonaCrdtDoc?.(docId);
930
+ const data = { ...(current?.data || {}), ...entries };
931
+ const clock = { ...(current?.clock || {}) };
932
+ clock[this.identityDid] = (clock[this.identityDid] || 0) + 1;
933
+ this.storage.upsertPersonaCrdtDoc?.({
934
+ docId,
935
+ vaultId,
936
+ domain,
937
+ data,
938
+ clock,
939
+ updatedAt: Date.now(),
940
+ });
941
+ }
942
+ mergeCrdtDomainDoc(input) {
943
+ const docId = `crdt_${input.vaultId}_${input.domain}`;
944
+ const current = this.storage.getPersonaCrdtDoc?.(docId);
945
+ const currentDoc = current?.data
946
+ ? Automerge.from(current.data)
947
+ : undefined;
948
+ const merged = mergeDomainDoc(currentDoc, input.patch);
949
+ const mergedClock = { ...(current?.clock || {}) };
950
+ for (const [did, counter] of Object.entries(input.clock || {})) {
951
+ mergedClock[did] = Math.max(mergedClock[did] || 0, counter);
952
+ }
953
+ this.storage.upsertPersonaCrdtDoc?.({
954
+ docId,
955
+ vaultId: input.vaultId,
956
+ domain: input.domain,
957
+ data: JSON.parse(JSON.stringify(merged)),
958
+ clock: mergedClock,
959
+ updatedAt: Date.now(),
960
+ });
961
+ }
962
+ recordMetric(metric, value, labels) {
963
+ if (!Number.isFinite(value))
964
+ return;
965
+ try {
966
+ this.storage.appendPersonaMetric?.({
967
+ ts: Date.now(),
968
+ metric,
969
+ value,
970
+ labels,
971
+ });
972
+ }
973
+ catch {
974
+ // Metrics should never break core flows.
975
+ }
976
+ }
977
+ getOrBuildGraphRank(vaultId, nodes, edges, query) {
978
+ const domainScope = query.domain
979
+ ? query.domain
980
+ : query.domains?.length
981
+ ? [...query.domains].sort().join(',')
982
+ : '*';
983
+ const maxNodeUpdatedAt = nodes.reduce((acc, node) => Math.max(acc, node.updatedAt || 0), 0);
984
+ const maxEdgeUpdatedAt = edges.reduce((acc, edge) => Math.max(acc, edge.updatedAt || 0), 0);
985
+ const version = `${nodes.length}:${edges.length}:${maxNodeUpdatedAt}:${maxEdgeUpdatedAt}`;
986
+ const key = `${vaultId}:${domainScope}:${version}`;
987
+ const cached = this.graphRankCache.get(key);
988
+ if (cached) {
989
+ return cached;
990
+ }
991
+ const persisted = this.storage.getPersonaGraphCache?.(vaultId, domainScope, version);
992
+ if (persisted?.ppr) {
993
+ const fromStorage = new Map();
994
+ for (const [nodeId, score] of Object.entries(persisted.ppr)) {
995
+ fromStorage.set(nodeId, Number(score) || 0);
996
+ }
997
+ this.graphRankCache.set(key, fromStorage);
998
+ return fromStorage;
999
+ }
1000
+ const built = computePersonalizedPageRank(nodes, edges);
1001
+ this.graphRankCache.set(key, built);
1002
+ this.storage.upsertPersonaGraphCache?.({
1003
+ vaultId,
1004
+ domain: domainScope,
1005
+ graphVersion: version,
1006
+ ppr: Object.fromEntries(Array.from(built.entries()).map(([k, v]) => [k, Number(v || 0)])),
1007
+ updatedAt: Date.now(),
1008
+ });
1009
+ this.storage.prunePersonaGraphCache?.(vaultId, domainScope, 8);
1010
+ if (this.graphRankCache.size > 128) {
1011
+ const first = this.graphRankCache.keys().next().value;
1012
+ if (first)
1013
+ this.graphRankCache.delete(first);
1014
+ }
1015
+ return built;
1016
+ }
1017
+ inflateNode(node) {
1018
+ const policy = getDomainPolicy(node.domain);
1019
+ if (!policy.sensitive)
1020
+ return node;
1021
+ const encrypted = node.metadata?.encryptedContent;
1022
+ if (!isEncryptedPayload(encrypted)) {
1023
+ return node;
1024
+ }
1025
+ try {
1026
+ const decrypted = this.decrypt(encrypted);
1027
+ return {
1028
+ ...node,
1029
+ content: decrypted,
1030
+ };
1031
+ }
1032
+ catch {
1033
+ return node;
1034
+ }
1035
+ }
1036
+ encrypt(plaintext) {
1037
+ const iv = crypto.randomBytes(12);
1038
+ const cipher = crypto.createCipheriv('aes-256-gcm', this.encryptionKey, iv);
1039
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
1040
+ const tag = cipher.getAuthTag();
1041
+ return {
1042
+ enc: true,
1043
+ iv: iv.toString('base64'),
1044
+ tag: tag.toString('base64'),
1045
+ data: encrypted.toString('base64'),
1046
+ };
1047
+ }
1048
+ decrypt(payload) {
1049
+ const decipher = crypto.createDecipheriv('aes-256-gcm', this.encryptionKey, Buffer.from(payload.iv, 'base64'));
1050
+ decipher.setAuthTag(Buffer.from(payload.tag, 'base64'));
1051
+ const decrypted = Buffer.concat([
1052
+ decipher.update(Buffer.from(payload.data, 'base64')),
1053
+ decipher.final(),
1054
+ ]);
1055
+ return decrypted.toString('utf8');
1056
+ }
1057
+ inflateClaim(record) {
1058
+ let payload = {};
1059
+ try {
1060
+ const encrypted = JSON.parse(record.payloadEnc);
1061
+ if (isEncryptedPayload(encrypted)) {
1062
+ payload = JSON.parse(this.decrypt(encrypted));
1063
+ }
1064
+ }
1065
+ catch {
1066
+ payload = {};
1067
+ }
1068
+ return {
1069
+ id: record.id,
1070
+ vaultId: record.vaultId,
1071
+ subjectDid: record.subjectDid,
1072
+ issuerDid: record.issuerDid,
1073
+ schema: record.schema,
1074
+ payload,
1075
+ status: record.status,
1076
+ issuedAt: record.issuedAt,
1077
+ expiresAt: record.expiresAt,
1078
+ revokedAt: record.revokedAt,
1079
+ signature: record.signature,
1080
+ };
1081
+ }
1082
+ detectProofSystem(proof) {
1083
+ return String(proof || '').startsWith('bb1.') ? 'noir-bb' : 'mock-noir-bb';
1084
+ }
1085
+ }
1086
+ export default PersonaVaultEngine;
1087
+ //# sourceMappingURL=engine.js.map