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.
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/dist/adapters.d.ts +101 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +764 -0
- package/dist/adapters.js.map +1 -0
- package/dist/agents-md.d.ts +59 -0
- package/dist/agents-md.d.ts.map +1 -0
- package/dist/agents-md.js +204 -0
- package/dist/agents-md.js.map +1 -0
- package/dist/autoconfig.d.ts +137 -0
- package/dist/autoconfig.d.ts.map +1 -0
- package/dist/autoconfig.js +452 -0
- package/dist/autoconfig.js.map +1 -0
- package/dist/bootstrap.d.ts +68 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +304 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/bridges/a2a-bridge.d.ts +156 -0
- package/dist/bridges/a2a-bridge.d.ts.map +1 -0
- package/dist/bridges/a2a-bridge.js +337 -0
- package/dist/bridges/a2a-bridge.js.map +1 -0
- package/dist/bridges/mcp-bridge.d.ts +87 -0
- package/dist/bridges/mcp-bridge.d.ts.map +1 -0
- package/dist/bridges/mcp-bridge.js +332 -0
- package/dist/bridges/mcp-bridge.js.map +1 -0
- package/dist/cache.d.ts +130 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +257 -0
- package/dist/cache.js.map +1 -0
- package/dist/capsules.d.ts +23 -0
- package/dist/capsules.d.ts.map +1 -0
- package/dist/capsules.js +75 -0
- package/dist/capsules.js.map +1 -0
- package/dist/cli/commands.d.ts +8 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +263 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/coc.d.ts +121 -0
- package/dist/coc.d.ts.map +1 -0
- package/dist/coc.js +629 -0
- package/dist/coc.js.map +1 -0
- package/dist/coc.test.d.ts +2 -0
- package/dist/coc.test.d.ts.map +1 -0
- package/dist/coc.test.js +80 -0
- package/dist/coc.test.js.map +1 -0
- package/dist/compression.d.ts +125 -0
- package/dist/compression.d.ts.map +1 -0
- package/dist/compression.js +573 -0
- package/dist/compression.js.map +1 -0
- package/dist/cot-stream.d.ts +220 -0
- package/dist/cot-stream.d.ts.map +1 -0
- package/dist/cot-stream.js +673 -0
- package/dist/cot-stream.js.map +1 -0
- package/dist/crypto-wasm.d.ts +100 -0
- package/dist/crypto-wasm.d.ts.map +1 -0
- package/dist/crypto-wasm.js +229 -0
- package/dist/crypto-wasm.js.map +1 -0
- package/dist/federation.d.ts +200 -0
- package/dist/federation.d.ts.map +1 -0
- package/dist/federation.js +691 -0
- package/dist/federation.js.map +1 -0
- package/dist/federation.test.d.ts +2 -0
- package/dist/federation.test.d.ts.map +1 -0
- package/dist/federation.test.js +71 -0
- package/dist/federation.test.js.map +1 -0
- package/dist/gateway/capability-router.d.ts +77 -0
- package/dist/gateway/capability-router.d.ts.map +1 -0
- package/dist/gateway/capability-router.js +222 -0
- package/dist/gateway/capability-router.js.map +1 -0
- package/dist/gateway/demand-spawner.d.ts +155 -0
- package/dist/gateway/demand-spawner.d.ts.map +1 -0
- package/dist/gateway/demand-spawner.js +426 -0
- package/dist/gateway/demand-spawner.js.map +1 -0
- package/dist/identity.d.ts +46 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +102 -0
- package/dist/identity.js.map +1 -0
- package/dist/identity.test.d.ts +2 -0
- package/dist/identity.test.d.ts.map +1 -0
- package/dist/identity.test.js +45 -0
- package/dist/identity.test.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1572 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.d.ts +210 -0
- package/dist/integration.d.ts.map +1 -0
- package/dist/integration.js +1105 -0
- package/dist/integration.js.map +1 -0
- package/dist/integration.test.d.ts +2 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +155 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/knowledge.d.ts +219 -0
- package/dist/knowledge.d.ts.map +1 -0
- package/dist/knowledge.js +543 -0
- package/dist/knowledge.js.map +1 -0
- package/dist/knowledge.test.d.ts +2 -0
- package/dist/knowledge.test.d.ts.map +1 -0
- package/dist/knowledge.test.js +72 -0
- package/dist/knowledge.test.js.map +1 -0
- package/dist/latent-space.d.ts +178 -0
- package/dist/latent-space.d.ts.map +1 -0
- package/dist/latent-space.js +385 -0
- package/dist/latent-space.js.map +1 -0
- package/dist/lib.d.ts +30 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +30 -0
- package/dist/lib.js.map +1 -0
- package/dist/mcp/server.d.ts +74 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +1392 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/metrics.d.ts +98 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +222 -0
- package/dist/metrics.js.map +1 -0
- package/dist/p2p.d.ts +87 -0
- package/dist/p2p.d.ts.map +1 -0
- package/dist/p2p.js +606 -0
- package/dist/p2p.js.map +1 -0
- package/dist/persona/capabilities.d.ts +17 -0
- package/dist/persona/capabilities.d.ts.map +1 -0
- package/dist/persona/capabilities.js +224 -0
- package/dist/persona/capabilities.js.map +1 -0
- package/dist/persona/domains.d.ts +22 -0
- package/dist/persona/domains.d.ts.map +1 -0
- package/dist/persona/domains.js +176 -0
- package/dist/persona/domains.js.map +1 -0
- package/dist/persona/embeddings.d.ts +40 -0
- package/dist/persona/embeddings.d.ts.map +1 -0
- package/dist/persona/embeddings.js +265 -0
- package/dist/persona/embeddings.js.map +1 -0
- package/dist/persona/engine.d.ts +79 -0
- package/dist/persona/engine.d.ts.map +1 -0
- package/dist/persona/engine.js +1087 -0
- package/dist/persona/engine.js.map +1 -0
- package/dist/persona/index.d.ts +11 -0
- package/dist/persona/index.d.ts.map +1 -0
- package/dist/persona/index.js +11 -0
- package/dist/persona/index.js.map +1 -0
- package/dist/persona/lifecycle.d.ts +17 -0
- package/dist/persona/lifecycle.d.ts.map +1 -0
- package/dist/persona/lifecycle.js +36 -0
- package/dist/persona/lifecycle.js.map +1 -0
- package/dist/persona/retrieval.d.ts +6 -0
- package/dist/persona/retrieval.d.ts.map +1 -0
- package/dist/persona/retrieval.js +122 -0
- package/dist/persona/retrieval.js.map +1 -0
- package/dist/persona/sync.d.ts +15 -0
- package/dist/persona/sync.d.ts.map +1 -0
- package/dist/persona/sync.js +92 -0
- package/dist/persona/sync.js.map +1 -0
- package/dist/persona/types.d.ts +283 -0
- package/dist/persona/types.d.ts.map +1 -0
- package/dist/persona/types.js +2 -0
- package/dist/persona/types.js.map +1 -0
- package/dist/persona/zkp/engine.d.ts +26 -0
- package/dist/persona/zkp/engine.d.ts.map +1 -0
- package/dist/persona/zkp/engine.js +370 -0
- package/dist/persona/zkp/engine.js.map +1 -0
- package/dist/persona/zkp/types.d.ts +39 -0
- package/dist/persona/zkp/types.d.ts.map +1 -0
- package/dist/persona/zkp/types.js +2 -0
- package/dist/persona/zkp/types.js.map +1 -0
- package/dist/planner.d.ts +114 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +522 -0
- package/dist/planner.js.map +1 -0
- package/dist/proactive/checkpoints.d.ts +9 -0
- package/dist/proactive/checkpoints.d.ts.map +1 -0
- package/dist/proactive/checkpoints.js +20 -0
- package/dist/proactive/checkpoints.js.map +1 -0
- package/dist/proactive/engine.d.ts +59 -0
- package/dist/proactive/engine.d.ts.map +1 -0
- package/dist/proactive/engine.js +406 -0
- package/dist/proactive/engine.js.map +1 -0
- package/dist/proactive/scheduler.d.ts +11 -0
- package/dist/proactive/scheduler.d.ts.map +1 -0
- package/dist/proactive/scheduler.js +45 -0
- package/dist/proactive/scheduler.js.map +1 -0
- package/dist/proactive/swarm-controller.d.ts +189 -0
- package/dist/proactive/swarm-controller.d.ts.map +1 -0
- package/dist/proactive/swarm-controller.js +477 -0
- package/dist/proactive/swarm-controller.js.map +1 -0
- package/dist/proactive/swarm-registry.d.ts +13 -0
- package/dist/proactive/swarm-registry.d.ts.map +1 -0
- package/dist/proactive/swarm-registry.js +122 -0
- package/dist/proactive/swarm-registry.js.map +1 -0
- package/dist/proactive/types.d.ts +145 -0
- package/dist/proactive/types.d.ts.map +1 -0
- package/dist/proactive/types.js +25 -0
- package/dist/proactive/types.js.map +1 -0
- package/dist/registry.d.ts +35 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +88 -0
- package/dist/registry.js.map +1 -0
- package/dist/reputation.d.ts +123 -0
- package/dist/reputation.d.ts.map +1 -0
- package/dist/reputation.js +366 -0
- package/dist/reputation.js.map +1 -0
- package/dist/reputation.test.d.ts +5 -0
- package/dist/reputation.test.d.ts.map +1 -0
- package/dist/reputation.test.js +265 -0
- package/dist/reputation.test.js.map +1 -0
- package/dist/rooms.d.ts +96 -0
- package/dist/rooms.d.ts.map +1 -0
- package/dist/rooms.js +410 -0
- package/dist/rooms.js.map +1 -0
- package/dist/sdk/client.d.ts +290 -0
- package/dist/sdk/client.d.ts.map +1 -0
- package/dist/sdk/client.js +1287 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/index.d.ts +32 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +70 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/security.d.ts +230 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +652 -0
- package/dist/security.js.map +1 -0
- package/dist/skills/engine.d.ts +262 -0
- package/dist/skills/engine.d.ts.map +1 -0
- package/dist/skills/engine.js +788 -0
- package/dist/skills/engine.js.map +1 -0
- package/dist/skills/engine.test.d.ts +2 -0
- package/dist/skills/engine.test.d.ts.map +1 -0
- package/dist/skills/engine.test.js +134 -0
- package/dist/skills/engine.test.js.map +1 -0
- package/dist/skills/parser.d.ts +129 -0
- package/dist/skills/parser.d.ts.map +1 -0
- package/dist/skills/parser.js +318 -0
- package/dist/skills/parser.js.map +1 -0
- package/dist/social.d.ts +149 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +401 -0
- package/dist/social.js.map +1 -0
- package/dist/storage-optimized.d.ts +116 -0
- package/dist/storage-optimized.d.ts.map +1 -0
- package/dist/storage-optimized.js +264 -0
- package/dist/storage-optimized.js.map +1 -0
- package/dist/storage.d.ts +584 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +2703 -0
- package/dist/storage.js.map +1 -0
- package/dist/storage.test.d.ts +2 -0
- package/dist/storage.test.d.ts.map +1 -0
- package/dist/storage.test.js +78 -0
- package/dist/storage.test.js.map +1 -0
- package/dist/swp.d.ts +443 -0
- package/dist/swp.d.ts.map +1 -0
- package/dist/swp.js +223 -0
- package/dist/swp.js.map +1 -0
- package/dist/swp.test.d.ts +5 -0
- package/dist/swp.test.d.ts.map +1 -0
- package/dist/swp.test.js +127 -0
- package/dist/swp.test.js.map +1 -0
- package/dist/templates.d.ts +25 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +1048 -0
- package/dist/templates.js.map +1 -0
- package/dist/test-e2e.d.ts +14 -0
- package/dist/test-e2e.d.ts.map +1 -0
- package/dist/test-e2e.js +266 -0
- package/dist/test-e2e.js.map +1 -0
- package/dist/workers/research-worker.d.ts +19 -0
- package/dist/workers/research-worker.d.ts.map +1 -0
- package/dist/workers/research-worker.js +141 -0
- package/dist/workers/research-worker.js.map +1 -0
- package/package.json +110 -0
|
@@ -0,0 +1,1287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Society Protocol — JavaScript/TypeScript SDK
|
|
3
|
+
*
|
|
4
|
+
* SDK oficial para integração com Society Protocol.
|
|
5
|
+
* Facilita a criação de agents e integração em aplicações existentes.
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from 'events';
|
|
8
|
+
import { generateIdentity, restoreIdentity } from '../identity.js';
|
|
9
|
+
import { Storage } from '../storage.js';
|
|
10
|
+
import { P2PNode } from '../p2p.js';
|
|
11
|
+
import { RoomManager } from '../rooms.js';
|
|
12
|
+
import { CocEngine } from '../coc.js';
|
|
13
|
+
import { ReputationEngine } from '../reputation.js';
|
|
14
|
+
import { Planner } from '../planner.js';
|
|
15
|
+
import { CapsuleExporter } from '../capsules.js';
|
|
16
|
+
import { FederationEngine } from '../federation.js';
|
|
17
|
+
import { KnowledgePool } from '../knowledge.js';
|
|
18
|
+
import { SkillsEngine } from '../skills/engine.js';
|
|
19
|
+
import { SecurityManager } from '../security.js';
|
|
20
|
+
import { IntegrationEngine } from '../integration.js';
|
|
21
|
+
import { listTemplates } from '../templates.js';
|
|
22
|
+
import { ProactiveMissionEngine } from '../proactive/engine.js';
|
|
23
|
+
import { PersonaVaultEngine, } from '../persona/index.js';
|
|
24
|
+
// ─── SocietyClient ──────────────────────────────────────────────
|
|
25
|
+
export class SocietyClient extends EventEmitter {
|
|
26
|
+
identity;
|
|
27
|
+
storage;
|
|
28
|
+
p2p;
|
|
29
|
+
rooms;
|
|
30
|
+
coc;
|
|
31
|
+
reputation;
|
|
32
|
+
planner;
|
|
33
|
+
exporter;
|
|
34
|
+
federation;
|
|
35
|
+
knowledge;
|
|
36
|
+
skills;
|
|
37
|
+
security;
|
|
38
|
+
integration;
|
|
39
|
+
persona;
|
|
40
|
+
proactive;
|
|
41
|
+
researchWorker;
|
|
42
|
+
config;
|
|
43
|
+
connected = false;
|
|
44
|
+
constructor(config = {}) {
|
|
45
|
+
super();
|
|
46
|
+
this.config = config;
|
|
47
|
+
}
|
|
48
|
+
// ─── Lifecycle ────────────────────────────────────────────────
|
|
49
|
+
async connect() {
|
|
50
|
+
if (this.connected)
|
|
51
|
+
return;
|
|
52
|
+
// Initialize storage
|
|
53
|
+
this.storage = new Storage(this.config.storage?.path
|
|
54
|
+
? { dbPath: this.config.storage.path }
|
|
55
|
+
: undefined);
|
|
56
|
+
// Initialize or restore identity
|
|
57
|
+
if (this.config.identity?.did && this.config.identity?.privateKeyHex) {
|
|
58
|
+
this.identity = restoreIdentity(this.config.identity.privateKeyHex, this.config.identity.name);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const existing = this.storage.getIdentity();
|
|
62
|
+
if (existing) {
|
|
63
|
+
this.identity = restoreIdentity(existing.private_key_hex, this.config.identity?.name || existing.display_name);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
this.identity = generateIdentity(this.config.identity?.name || 'Anonymous');
|
|
67
|
+
const privHex = Buffer.from(this.identity.privateKey).toString('hex');
|
|
68
|
+
const pubHex = Buffer.from(this.identity.publicKey).toString('hex');
|
|
69
|
+
this.storage.saveIdentity(this.identity.did, privHex, pubHex, this.identity.displayName);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Initialize reputation
|
|
73
|
+
this.reputation = new ReputationEngine(this.storage);
|
|
74
|
+
// Initialize P2P
|
|
75
|
+
this.p2p = new P2PNode();
|
|
76
|
+
await this.p2p.start({
|
|
77
|
+
port: this.config.network?.port,
|
|
78
|
+
bootstrapAddrs: this.config.network?.bootstrap,
|
|
79
|
+
enableGossipsub: this.config.network?.enableGossipsub ?? true,
|
|
80
|
+
enableDht: this.config.network?.enableDht ?? true,
|
|
81
|
+
});
|
|
82
|
+
// Initialize rooms
|
|
83
|
+
this.rooms = new RoomManager(this.identity, this.p2p, this.storage);
|
|
84
|
+
// Initialize CoC
|
|
85
|
+
this.coc = new CocEngine(this.identity, this.rooms, this.storage, this.reputation);
|
|
86
|
+
// Initialize federation + integration stack
|
|
87
|
+
this.federation = new FederationEngine(this.storage, this.identity);
|
|
88
|
+
this.knowledge = new KnowledgePool(this.storage, this.identity);
|
|
89
|
+
this.skills = new SkillsEngine(this.storage, this.identity);
|
|
90
|
+
this.security = new SecurityManager(this.identity);
|
|
91
|
+
this.integration = new IntegrationEngine(this.storage, this.identity, this.federation, this.rooms, this.knowledge, this.coc, this.skills, this.security);
|
|
92
|
+
this.persona = new PersonaVaultEngine(this.storage, this.identity.did, {
|
|
93
|
+
defaultVaultName: `${this.identity.displayName} Persona Vault`,
|
|
94
|
+
});
|
|
95
|
+
this.integration.attachPersonaVault(this.persona);
|
|
96
|
+
// Initialize planner
|
|
97
|
+
this.planner = new Planner({
|
|
98
|
+
provider: this.config.planner?.provider,
|
|
99
|
+
apiKey: this.config.planner?.apiKey,
|
|
100
|
+
enableCache: this.config.planner?.enableCache ?? true,
|
|
101
|
+
});
|
|
102
|
+
// Initialize exporter
|
|
103
|
+
this.exporter = new CapsuleExporter(this.coc, this.storage);
|
|
104
|
+
this.proactive = new ProactiveMissionEngine(this.identity, this.storage, this.rooms, this.coc, this.planner, this.knowledge, undefined, undefined, {
|
|
105
|
+
enableLeadership: this.config.proactive?.enableLeadership ?? false,
|
|
106
|
+
autoRestoreMissions: this.config.proactive?.autoRestoreMissions ?? false,
|
|
107
|
+
leaseTtlMs: this.config.proactive?.leaseTtlMs,
|
|
108
|
+
leaseRenewIntervalMs: this.config.proactive?.leaseRenewIntervalMs,
|
|
109
|
+
});
|
|
110
|
+
// Setup event forwarding
|
|
111
|
+
this.setupEventForwarding();
|
|
112
|
+
this.connected = true;
|
|
113
|
+
this.emit('connected');
|
|
114
|
+
}
|
|
115
|
+
async disconnect() {
|
|
116
|
+
if (!this.connected)
|
|
117
|
+
return;
|
|
118
|
+
this.skills?.stop?.();
|
|
119
|
+
await this.researchWorker?.stop?.();
|
|
120
|
+
this.proactive?.destroy?.();
|
|
121
|
+
this.coc.destroy();
|
|
122
|
+
this.rooms.destroy();
|
|
123
|
+
await this.p2p.stop();
|
|
124
|
+
this.storage.close();
|
|
125
|
+
this.connected = false;
|
|
126
|
+
this.emit('disconnected');
|
|
127
|
+
}
|
|
128
|
+
setupEventForwarding() {
|
|
129
|
+
// Forward CoC events
|
|
130
|
+
this.coc.on('chain:opened', (id, goal) => this.emit('chain:opened', { id, goal }));
|
|
131
|
+
this.coc.on('chain:completed', (id) => this.emit('chain:completed', { id }));
|
|
132
|
+
this.coc.on('step:unlocked', (chainId, stepId, step) => this.emit('step:unlocked', { chainId, stepId, step }));
|
|
133
|
+
this.coc.on('step:assigned', (chainId, stepId, assignee) => this.emit('step:assigned', { chainId, stepId, assignee }));
|
|
134
|
+
// Forward room events
|
|
135
|
+
this.rooms.on('chat:message', (roomId, envelope) => this.emit('message', { roomId, from: envelope.from, body: envelope.body }));
|
|
136
|
+
this.rooms.on('mission:event', (roomId, envelope) => this.emit('mission:event', { roomId, envelope }));
|
|
137
|
+
this.persona.on('persona:memory:added', (node) => this.emit('persona:memory:added', node));
|
|
138
|
+
this.persona.on('persona:memory:updated', (node) => this.emit('persona:memory:updated', node));
|
|
139
|
+
this.persona.on('persona:memory:deleted', (evt) => this.emit('persona:memory:deleted', evt));
|
|
140
|
+
}
|
|
141
|
+
// ─── Room Operations ──────────────────────────────────────────
|
|
142
|
+
async joinRoom(roomId, displayName) {
|
|
143
|
+
this.ensureConnected();
|
|
144
|
+
await this.rooms.joinRoom(roomId, displayName);
|
|
145
|
+
this.emit('room:joined', { roomId });
|
|
146
|
+
}
|
|
147
|
+
async leaveRoom(roomId) {
|
|
148
|
+
this.ensureConnected();
|
|
149
|
+
await this.rooms.leaveRoom(roomId);
|
|
150
|
+
this.emit('room:left', { roomId });
|
|
151
|
+
}
|
|
152
|
+
getJoinedRooms() {
|
|
153
|
+
this.ensureConnected();
|
|
154
|
+
return this.rooms.getJoinedRooms();
|
|
155
|
+
}
|
|
156
|
+
// ─── Messaging ────────────────────────────────────────────────
|
|
157
|
+
async sendMessage(roomId, message, replyTo) {
|
|
158
|
+
this.ensureConnected();
|
|
159
|
+
await this.rooms.sendChatMessage(roomId, message, {
|
|
160
|
+
replyTo,
|
|
161
|
+
formatting: 'plain',
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// ─── Collaboration (CoC) ──────────────────────────────────────
|
|
165
|
+
async summon(options) {
|
|
166
|
+
this.ensureConnected();
|
|
167
|
+
let dag;
|
|
168
|
+
if (options.template) {
|
|
169
|
+
const { getTemplate } = await import('../templates.js');
|
|
170
|
+
const template = getTemplate(options.template);
|
|
171
|
+
dag = template.generate(options.goal);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
const plan = await this.planner.generatePlan(options.goal);
|
|
175
|
+
dag = plan.dag;
|
|
176
|
+
}
|
|
177
|
+
const chainId = await this.coc.openChain(options.roomId, options.goal, {
|
|
178
|
+
priority: options.priority || 'normal',
|
|
179
|
+
templateId: options.template,
|
|
180
|
+
});
|
|
181
|
+
await this.coc.publishPlan(options.roomId, chainId, dag);
|
|
182
|
+
// Setup listeners if callbacks provided
|
|
183
|
+
if (options.onStep || options.onComplete) {
|
|
184
|
+
this.setupChainListeners(chainId, options);
|
|
185
|
+
}
|
|
186
|
+
return this.getChain(chainId);
|
|
187
|
+
}
|
|
188
|
+
setupChainListeners(chainId, options) {
|
|
189
|
+
if (options.onStep) {
|
|
190
|
+
this.coc.on('step:unlocked', (cid, stepId, step) => {
|
|
191
|
+
if (cid === chainId) {
|
|
192
|
+
options.onStep({
|
|
193
|
+
id: stepId,
|
|
194
|
+
chainId: cid,
|
|
195
|
+
kind: step.kind,
|
|
196
|
+
title: step.title,
|
|
197
|
+
status: 'unlocked',
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (options.onComplete) {
|
|
203
|
+
this.coc.on('chain:completed', (cid) => {
|
|
204
|
+
if (cid === chainId) {
|
|
205
|
+
this.getChain(chainId).then((chain) => {
|
|
206
|
+
options.onComplete({
|
|
207
|
+
id: chain.id,
|
|
208
|
+
goal: chain.goal,
|
|
209
|
+
status: chain.status,
|
|
210
|
+
steps: chain.steps,
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async listChains(roomId) {
|
|
218
|
+
this.ensureConnected();
|
|
219
|
+
const chains = this.coc.getActiveChains().filter((c) => c.room_id === roomId);
|
|
220
|
+
return chains.map((c) => ({
|
|
221
|
+
id: c.chain_id,
|
|
222
|
+
goal: c.goal,
|
|
223
|
+
status: c.status,
|
|
224
|
+
steps: c.steps.map((s) => ({
|
|
225
|
+
id: s.step_id,
|
|
226
|
+
chainId: c.chain_id,
|
|
227
|
+
kind: s.kind,
|
|
228
|
+
title: s.title,
|
|
229
|
+
status: s.status,
|
|
230
|
+
assignee: s.assignee_did || undefined,
|
|
231
|
+
})),
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
234
|
+
async getChain(chainId) {
|
|
235
|
+
this.ensureConnected();
|
|
236
|
+
const chain = this.coc.getChain(chainId);
|
|
237
|
+
if (!chain)
|
|
238
|
+
throw new Error(`Chain not found: ${chainId}`);
|
|
239
|
+
return {
|
|
240
|
+
id: chain.chain_id,
|
|
241
|
+
goal: chain.goal,
|
|
242
|
+
status: chain.status,
|
|
243
|
+
steps: chain.steps.map((s) => ({
|
|
244
|
+
id: s.step_id,
|
|
245
|
+
chainId: chain.chain_id,
|
|
246
|
+
kind: s.kind,
|
|
247
|
+
title: s.title,
|
|
248
|
+
status: s.status,
|
|
249
|
+
assignee: s.assignee_did || undefined,
|
|
250
|
+
})),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
async submitStep(stepId, result) {
|
|
254
|
+
this.ensureConnected();
|
|
255
|
+
const step = this.storage.getStepRecord(stepId);
|
|
256
|
+
if (!step) {
|
|
257
|
+
throw new Error(`Step ${stepId} not found`);
|
|
258
|
+
}
|
|
259
|
+
const chain = this.storage.getChain(step.chain_id);
|
|
260
|
+
if (!chain) {
|
|
261
|
+
throw new Error(`Chain not found for step ${stepId}`);
|
|
262
|
+
}
|
|
263
|
+
await this.coc.submitStep(chain.room_id, step.chain_id, stepId, result.status, result.output, result.artifacts || []);
|
|
264
|
+
}
|
|
265
|
+
async reviewStep(stepId, decision, notes) {
|
|
266
|
+
this.ensureConnected();
|
|
267
|
+
const chains = this.coc.getActiveChains();
|
|
268
|
+
const chain = chains.find((c) => c.steps.find((s) => s.step_id === stepId));
|
|
269
|
+
if (!chain) {
|
|
270
|
+
throw new Error(`Step ${stepId} not found`);
|
|
271
|
+
}
|
|
272
|
+
await this.coc.reviewStep(chain.room_id, chain.chain_id, stepId, decision, notes);
|
|
273
|
+
}
|
|
274
|
+
async cancelChain(chainId, reason) {
|
|
275
|
+
this.ensureConnected();
|
|
276
|
+
const chain = this.coc.getChain(chainId);
|
|
277
|
+
if (!chain)
|
|
278
|
+
throw new Error(`Chain not found: ${chainId}`);
|
|
279
|
+
await this.coc.closeChain(chain.room_id, chainId, 'cancelled', reason || 'Cancelled via SDK');
|
|
280
|
+
}
|
|
281
|
+
async getPendingSteps() {
|
|
282
|
+
this.ensureConnected();
|
|
283
|
+
const rows = this.storage.getAssignedStepsForDid(this.identity.did);
|
|
284
|
+
return rows.map((step) => ({
|
|
285
|
+
id: step.step_id,
|
|
286
|
+
chainId: step.chain_id,
|
|
287
|
+
kind: step.kind,
|
|
288
|
+
title: step.title,
|
|
289
|
+
status: step.status,
|
|
290
|
+
}));
|
|
291
|
+
}
|
|
292
|
+
// ─── Proactive Missions ──────────────────────────────────────
|
|
293
|
+
async startMission(spec) {
|
|
294
|
+
this.ensureConnected();
|
|
295
|
+
if (!this.config.proactive?.enableLeadership) {
|
|
296
|
+
throw new Error('Mission leadership is disabled for this client. Set proactive.enableLeadership=true.');
|
|
297
|
+
}
|
|
298
|
+
return this.proactive.startMission(spec);
|
|
299
|
+
}
|
|
300
|
+
async pauseMission(missionId) {
|
|
301
|
+
this.ensureConnected();
|
|
302
|
+
await this.proactive.pauseMission(missionId);
|
|
303
|
+
}
|
|
304
|
+
async resumeMission(missionId) {
|
|
305
|
+
this.ensureConnected();
|
|
306
|
+
await this.proactive.resumeMission(missionId);
|
|
307
|
+
}
|
|
308
|
+
async stopMission(missionId, reason) {
|
|
309
|
+
this.ensureConnected();
|
|
310
|
+
await this.proactive.stopMission(missionId, reason);
|
|
311
|
+
}
|
|
312
|
+
async listMissions(roomId) {
|
|
313
|
+
this.ensureConnected();
|
|
314
|
+
return this.proactive.listMissions(roomId);
|
|
315
|
+
}
|
|
316
|
+
async getMission(missionId) {
|
|
317
|
+
this.ensureConnected();
|
|
318
|
+
return this.proactive.getMission(missionId);
|
|
319
|
+
}
|
|
320
|
+
async getSwarmStatus(roomId) {
|
|
321
|
+
this.ensureConnected();
|
|
322
|
+
return this.proactive.getSwarmStatus(roomId);
|
|
323
|
+
}
|
|
324
|
+
async startResearchWorker(config) {
|
|
325
|
+
this.ensureConnected();
|
|
326
|
+
const { ResearchWorkerNode } = await import('../workers/research-worker.js');
|
|
327
|
+
await this.researchWorker?.stop?.();
|
|
328
|
+
this.researchWorker = new ResearchWorkerNode(this, config);
|
|
329
|
+
await this.researchWorker.start();
|
|
330
|
+
}
|
|
331
|
+
// ─── Reputation ───────────────────────────────────────────────
|
|
332
|
+
async getReputation(did) {
|
|
333
|
+
this.ensureConnected();
|
|
334
|
+
const targetDid = did || this.identity.did;
|
|
335
|
+
return this.reputation.getReputation(targetDid);
|
|
336
|
+
}
|
|
337
|
+
// ─── Templates ────────────────────────────────────────────────
|
|
338
|
+
listTemplates(category) {
|
|
339
|
+
return listTemplates(category);
|
|
340
|
+
}
|
|
341
|
+
// ─── Capsules ─────────────────────────────────────────────────
|
|
342
|
+
async exportCapsule(chainId, outputPath) {
|
|
343
|
+
this.ensureConnected();
|
|
344
|
+
return this.exporter.export(chainId, outputPath || './');
|
|
345
|
+
}
|
|
346
|
+
// ─── Peers ────────────────────────────────────────────────────
|
|
347
|
+
async getPeers(roomId) {
|
|
348
|
+
this.ensureConnected();
|
|
349
|
+
const peers = this.rooms.getOnlinePeers();
|
|
350
|
+
const result = [];
|
|
351
|
+
for (const peer of peers) {
|
|
352
|
+
const rep = await this.reputation.getReputation(peer.peer_did);
|
|
353
|
+
result.push({
|
|
354
|
+
did: peer.peer_did,
|
|
355
|
+
name: peer.peer_name || 'Unknown',
|
|
356
|
+
status: peer.status,
|
|
357
|
+
reputation: rep.overall,
|
|
358
|
+
specialties: rep.specialties.map((s) => s.specialty),
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
return result;
|
|
362
|
+
}
|
|
363
|
+
async announceWorker(roomId, profile) {
|
|
364
|
+
this.ensureConnected();
|
|
365
|
+
await this.rooms.publishAdapterRegistration(roomId, profile);
|
|
366
|
+
this.storage.registerAdapter(profile.adapter_id, profile.runtime, profile.display_name, profile.specialties || [], profile.kinds || [], profile.max_concurrency || 1, profile.endpoint || '', profile.auth_type || 'none', {
|
|
367
|
+
ownerDid: profile.owner_did,
|
|
368
|
+
roomId: profile.room_id || roomId,
|
|
369
|
+
missionTags: profile.mission_tags,
|
|
370
|
+
hostId: profile.host_id,
|
|
371
|
+
peerId: profile.peer_id,
|
|
372
|
+
health: 'healthy',
|
|
373
|
+
});
|
|
374
|
+
this.storage.upsertSwarmWorker({
|
|
375
|
+
did: profile.owner_did || this.identity.did,
|
|
376
|
+
peerId: profile.peer_id,
|
|
377
|
+
roomId: profile.room_id || roomId,
|
|
378
|
+
hostId: profile.host_id || profile.peer_id || this.identity.did,
|
|
379
|
+
runtime: profile.runtime === 'nanobot' || profile.runtime === 'docker' || profile.runtime === 'ollama'
|
|
380
|
+
? profile.runtime
|
|
381
|
+
: 'custom',
|
|
382
|
+
specialties: profile.specialties || [],
|
|
383
|
+
capabilities: profile.capabilities || [],
|
|
384
|
+
kinds: profile.kinds || ['task'],
|
|
385
|
+
maxConcurrency: profile.max_concurrency || 1,
|
|
386
|
+
load: 0,
|
|
387
|
+
health: 'healthy',
|
|
388
|
+
missionTags: profile.mission_tags || [],
|
|
389
|
+
adapterId: profile.adapter_id,
|
|
390
|
+
displayName: profile.display_name,
|
|
391
|
+
endpoint: profile.endpoint,
|
|
392
|
+
lastSeen: Date.now(),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
async heartbeatWorker(roomId, heartbeat) {
|
|
396
|
+
this.ensureConnected();
|
|
397
|
+
await this.rooms.publishAdapterHeartbeat(roomId, heartbeat);
|
|
398
|
+
this.storage.updateAdapterHeartbeat(heartbeat.adapter_id, heartbeat.health, heartbeat.queue_depth, heartbeat.metrics?.success_rate);
|
|
399
|
+
}
|
|
400
|
+
async updateWorkerCapabilities(roomId, capabilities) {
|
|
401
|
+
this.ensureConnected();
|
|
402
|
+
await this.rooms.publishAdapterCapabilities(roomId, capabilities);
|
|
403
|
+
}
|
|
404
|
+
async sendWorkerPresence(roomId, options) {
|
|
405
|
+
this.ensureConnected();
|
|
406
|
+
await this.rooms.sendPresence(roomId, options.status, options);
|
|
407
|
+
}
|
|
408
|
+
async getVisibleWorkers(roomId) {
|
|
409
|
+
this.ensureConnected();
|
|
410
|
+
return this.rooms.getVisibleWorkers(roomId);
|
|
411
|
+
}
|
|
412
|
+
// ─── Federation ─────────────────────────────────────────────
|
|
413
|
+
async createFederation(name, description, visibility = 'private') {
|
|
414
|
+
this.ensureConnected();
|
|
415
|
+
return this.federation.createFederation(name, description, visibility);
|
|
416
|
+
}
|
|
417
|
+
listFederations() {
|
|
418
|
+
this.ensureConnected();
|
|
419
|
+
return this.federation.getMemberFederations(this.identity.did);
|
|
420
|
+
}
|
|
421
|
+
getFederation(federationId) {
|
|
422
|
+
this.ensureConnected();
|
|
423
|
+
return this.federation.getFederation(federationId);
|
|
424
|
+
}
|
|
425
|
+
async joinFederation(federationId) {
|
|
426
|
+
this.ensureConnected();
|
|
427
|
+
return this.federation.joinFederation(federationId, this.identity.did, this.identity.displayName);
|
|
428
|
+
}
|
|
429
|
+
// ─── Knowledge ──────────────────────────────────────────────
|
|
430
|
+
async createKnowledgeSpace(name, description, type = 'team') {
|
|
431
|
+
this.ensureConnected();
|
|
432
|
+
return this.knowledge.createSpace(name, description, type);
|
|
433
|
+
}
|
|
434
|
+
async createKnowledgeCard(spaceId, type, title, content, options) {
|
|
435
|
+
this.ensureConnected();
|
|
436
|
+
return this.knowledge.createCard(spaceId, type, title, content, options);
|
|
437
|
+
}
|
|
438
|
+
queryKnowledgeCards(options) {
|
|
439
|
+
this.ensureConnected();
|
|
440
|
+
return this.knowledge.queryCards(options);
|
|
441
|
+
}
|
|
442
|
+
getKnowledgeGraph(spaceId) {
|
|
443
|
+
this.ensureConnected();
|
|
444
|
+
return this.knowledge.getKnowledgeGraph(spaceId);
|
|
445
|
+
}
|
|
446
|
+
async linkKnowledgeCards(sourceId, targetId, type, strength) {
|
|
447
|
+
this.ensureConnected();
|
|
448
|
+
return this.knowledge.linkCards(sourceId, targetId, type, strength);
|
|
449
|
+
}
|
|
450
|
+
// ─── Federation Mesh ─────────────────────────────────────────
|
|
451
|
+
async createPeering(sourceFederationId, targetFederationDid, policy) {
|
|
452
|
+
this.ensureConnected();
|
|
453
|
+
return this.federation.requestPeering(sourceFederationId, targetFederationDid, policy || {});
|
|
454
|
+
}
|
|
455
|
+
async acceptPeering(peeringId, reason) {
|
|
456
|
+
this.ensureConnected();
|
|
457
|
+
return this.federation.respondPeering(peeringId, true, reason);
|
|
458
|
+
}
|
|
459
|
+
async rejectPeering(peeringId, reason) {
|
|
460
|
+
this.ensureConnected();
|
|
461
|
+
return this.federation.respondPeering(peeringId, false, reason);
|
|
462
|
+
}
|
|
463
|
+
async revokePeering(peeringId, reason) {
|
|
464
|
+
this.ensureConnected();
|
|
465
|
+
return this.federation.revokePeering(peeringId, reason);
|
|
466
|
+
}
|
|
467
|
+
listPeerings(federationId, status) {
|
|
468
|
+
this.ensureConnected();
|
|
469
|
+
return this.federation.listPeerings(federationId, status);
|
|
470
|
+
}
|
|
471
|
+
async openBridge(peeringId, localRoomId, remoteRoomId, rules) {
|
|
472
|
+
this.ensureConnected();
|
|
473
|
+
return this.integration.openMeshBridge(peeringId, localRoomId, remoteRoomId, rules);
|
|
474
|
+
}
|
|
475
|
+
async closeBridge(bridgeId) {
|
|
476
|
+
this.ensureConnected();
|
|
477
|
+
await this.integration.closeMeshBridge(bridgeId);
|
|
478
|
+
}
|
|
479
|
+
listBridges(federationId) {
|
|
480
|
+
this.ensureConnected();
|
|
481
|
+
return this.integration.listMeshBridges(federationId);
|
|
482
|
+
}
|
|
483
|
+
getMeshStats(federationId) {
|
|
484
|
+
this.ensureConnected();
|
|
485
|
+
return this.integration.getMeshStats(federationId);
|
|
486
|
+
}
|
|
487
|
+
// ─── Persona Vault ───────────────────────────────────────────
|
|
488
|
+
async createPersonaVault(input) {
|
|
489
|
+
this.ensureConnected();
|
|
490
|
+
return this.persona.createVault(input);
|
|
491
|
+
}
|
|
492
|
+
async addMemory(input) {
|
|
493
|
+
this.ensureConnected();
|
|
494
|
+
const { capabilityToken, zkpProofs, ...payload } = input;
|
|
495
|
+
const auth = await this.authorizePersonaAccess({
|
|
496
|
+
capabilityToken,
|
|
497
|
+
operation: 'write',
|
|
498
|
+
domain: payload.domain,
|
|
499
|
+
resource: 'persona://memory/*',
|
|
500
|
+
zkpProofs,
|
|
501
|
+
});
|
|
502
|
+
try {
|
|
503
|
+
const node = await this.persona.addMemory(payload);
|
|
504
|
+
await this.auditPersonaAccess({
|
|
505
|
+
vaultId: node.vaultId,
|
|
506
|
+
tokenId: auth.tokenId,
|
|
507
|
+
serviceDid: auth.serviceDid,
|
|
508
|
+
operation: 'write',
|
|
509
|
+
resource: `persona://memory/${node.id}`,
|
|
510
|
+
result: 'allowed',
|
|
511
|
+
details: { domain: node.domain, type: node.type },
|
|
512
|
+
});
|
|
513
|
+
return node;
|
|
514
|
+
}
|
|
515
|
+
catch (error) {
|
|
516
|
+
await this.auditPersonaAccess({
|
|
517
|
+
vaultId: payload.vaultId,
|
|
518
|
+
tokenId: auth.tokenId,
|
|
519
|
+
serviceDid: auth.serviceDid,
|
|
520
|
+
operation: 'write',
|
|
521
|
+
resource: 'persona://memory/*',
|
|
522
|
+
result: 'denied',
|
|
523
|
+
details: { reason: error.message },
|
|
524
|
+
});
|
|
525
|
+
throw error;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
async updateMemory(nodeId, patch, options) {
|
|
529
|
+
this.ensureConnected();
|
|
530
|
+
const current = this.storage.getPersonaNode?.(nodeId);
|
|
531
|
+
const domain = options?.domain || current?.domain;
|
|
532
|
+
const auth = await this.authorizePersonaAccess({
|
|
533
|
+
capabilityToken: options?.capabilityToken,
|
|
534
|
+
operation: 'write',
|
|
535
|
+
domain,
|
|
536
|
+
resource: `persona://memory/${nodeId}`,
|
|
537
|
+
appendMutation: true,
|
|
538
|
+
zkpProofs: options?.zkpProofs,
|
|
539
|
+
});
|
|
540
|
+
try {
|
|
541
|
+
const updated = await this.persona.updateMemory(nodeId, patch);
|
|
542
|
+
await this.auditPersonaAccess({
|
|
543
|
+
vaultId: updated.vaultId,
|
|
544
|
+
tokenId: auth.tokenId,
|
|
545
|
+
serviceDid: auth.serviceDid,
|
|
546
|
+
operation: 'write',
|
|
547
|
+
resource: `persona://memory/${nodeId}`,
|
|
548
|
+
result: 'allowed',
|
|
549
|
+
details: { domain: updated.domain, patchKeys: Object.keys(patch || {}) },
|
|
550
|
+
});
|
|
551
|
+
return updated;
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
await this.auditPersonaAccess({
|
|
555
|
+
vaultId: current?.vaultId,
|
|
556
|
+
tokenId: auth.tokenId,
|
|
557
|
+
serviceDid: auth.serviceDid,
|
|
558
|
+
operation: 'write',
|
|
559
|
+
resource: `persona://memory/${nodeId}`,
|
|
560
|
+
result: 'denied',
|
|
561
|
+
details: { reason: error.message },
|
|
562
|
+
});
|
|
563
|
+
throw error;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
async deleteMemory(nodeId, reason, options) {
|
|
567
|
+
this.ensureConnected();
|
|
568
|
+
const current = this.storage.getPersonaNode?.(nodeId);
|
|
569
|
+
const domain = options?.domain || current?.domain;
|
|
570
|
+
const auth = await this.authorizePersonaAccess({
|
|
571
|
+
capabilityToken: options?.capabilityToken,
|
|
572
|
+
operation: 'delete',
|
|
573
|
+
domain,
|
|
574
|
+
resource: `persona://memory/${nodeId}`,
|
|
575
|
+
appendMutation: true,
|
|
576
|
+
zkpProofs: options?.zkpProofs,
|
|
577
|
+
});
|
|
578
|
+
try {
|
|
579
|
+
await this.persona.deleteMemory(nodeId, reason);
|
|
580
|
+
await this.auditPersonaAccess({
|
|
581
|
+
vaultId: current?.vaultId,
|
|
582
|
+
tokenId: auth.tokenId,
|
|
583
|
+
serviceDid: auth.serviceDid,
|
|
584
|
+
operation: 'delete',
|
|
585
|
+
resource: `persona://memory/${nodeId}`,
|
|
586
|
+
result: 'allowed',
|
|
587
|
+
details: reason ? { reason } : undefined,
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
catch (error) {
|
|
591
|
+
await this.auditPersonaAccess({
|
|
592
|
+
vaultId: current?.vaultId,
|
|
593
|
+
tokenId: auth.tokenId,
|
|
594
|
+
serviceDid: auth.serviceDid,
|
|
595
|
+
operation: 'delete',
|
|
596
|
+
resource: `persona://memory/${nodeId}`,
|
|
597
|
+
result: 'denied',
|
|
598
|
+
details: { reason: error.message },
|
|
599
|
+
});
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
async queryMemories(input) {
|
|
604
|
+
this.ensureConnected();
|
|
605
|
+
const { capabilityToken, zkpProofs, ...payload } = input;
|
|
606
|
+
const auth = await this.authorizePersonaAccess({
|
|
607
|
+
capabilityToken,
|
|
608
|
+
operation: 'read',
|
|
609
|
+
domain: payload.domain,
|
|
610
|
+
resource: 'persona://memory/*',
|
|
611
|
+
requestedLimit: payload.limit,
|
|
612
|
+
zkpProofs,
|
|
613
|
+
});
|
|
614
|
+
const scoped = { ...payload };
|
|
615
|
+
if (auth.limit !== undefined) {
|
|
616
|
+
scoped.limit = Math.min(scoped.limit ?? auth.limit, auth.limit);
|
|
617
|
+
}
|
|
618
|
+
if (auth.domains?.length) {
|
|
619
|
+
if (scoped.domain && !auth.domains.includes(scoped.domain)) {
|
|
620
|
+
throw new Error(`Capability denied: domain ${scoped.domain} not allowed`);
|
|
621
|
+
}
|
|
622
|
+
if (!scoped.domain) {
|
|
623
|
+
const existing = new Set(scoped.domains || []);
|
|
624
|
+
for (const d of auth.domains)
|
|
625
|
+
existing.add(d);
|
|
626
|
+
scoped.domains = Array.from(existing);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
try {
|
|
630
|
+
const result = await this.persona.queryMemories(scoped);
|
|
631
|
+
const vaultId = result.nodes[0]?.vaultId || scoped.vaultId;
|
|
632
|
+
await this.auditPersonaAccess({
|
|
633
|
+
vaultId,
|
|
634
|
+
tokenId: auth.tokenId,
|
|
635
|
+
serviceDid: auth.serviceDid,
|
|
636
|
+
operation: 'read',
|
|
637
|
+
resource: 'persona://memory/*',
|
|
638
|
+
result: 'allowed',
|
|
639
|
+
details: {
|
|
640
|
+
query: scoped.query,
|
|
641
|
+
domain: scoped.domain,
|
|
642
|
+
domains: scoped.domains,
|
|
643
|
+
returned: result.nodes.length,
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
return result;
|
|
647
|
+
}
|
|
648
|
+
catch (error) {
|
|
649
|
+
await this.auditPersonaAccess({
|
|
650
|
+
vaultId: scoped.vaultId,
|
|
651
|
+
tokenId: auth.tokenId,
|
|
652
|
+
serviceDid: auth.serviceDid,
|
|
653
|
+
operation: 'read',
|
|
654
|
+
resource: 'persona://memory/*',
|
|
655
|
+
result: 'denied',
|
|
656
|
+
details: { reason: error.message },
|
|
657
|
+
});
|
|
658
|
+
throw error;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
async queryGraph(input) {
|
|
662
|
+
this.ensureConnected();
|
|
663
|
+
const { capabilityToken, zkpProofs, ...payload } = input;
|
|
664
|
+
const auth = await this.authorizePersonaAccess({
|
|
665
|
+
capabilityToken,
|
|
666
|
+
operation: 'read',
|
|
667
|
+
domain: payload.domain,
|
|
668
|
+
resource: payload.domain ? `persona://graph/${payload.domain}` : 'persona://graph/*',
|
|
669
|
+
requestedLimit: payload.limit,
|
|
670
|
+
zkpProofs,
|
|
671
|
+
});
|
|
672
|
+
const scoped = { ...payload };
|
|
673
|
+
if (auth.limit !== undefined) {
|
|
674
|
+
scoped.limit = Math.min(scoped.limit ?? auth.limit, auth.limit);
|
|
675
|
+
}
|
|
676
|
+
if (auth.domains?.length && scoped.domain && !auth.domains.includes(scoped.domain)) {
|
|
677
|
+
throw new Error(`Capability denied: domain ${scoped.domain} not allowed`);
|
|
678
|
+
}
|
|
679
|
+
try {
|
|
680
|
+
const graph = await this.persona.queryGraph(scoped);
|
|
681
|
+
let result = graph;
|
|
682
|
+
if (auth.domains?.length) {
|
|
683
|
+
const allowedNodes = graph.nodes.filter((node) => auth.domains.includes(node.domain));
|
|
684
|
+
const allowedIds = new Set(allowedNodes.map((node) => node.id));
|
|
685
|
+
result = {
|
|
686
|
+
...graph,
|
|
687
|
+
nodes: allowedNodes,
|
|
688
|
+
edges: graph.edges.filter((edge) => allowedIds.has(edge.sourceNodeId) && allowedIds.has(edge.targetNodeId)),
|
|
689
|
+
hyperEdges: graph.hyperEdges.filter((edge) => edge.nodeIds.some((id) => allowedIds.has(id))),
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
await this.auditPersonaAccess({
|
|
693
|
+
vaultId: result.nodes[0]?.vaultId || scoped.vaultId,
|
|
694
|
+
tokenId: auth.tokenId,
|
|
695
|
+
serviceDid: auth.serviceDid,
|
|
696
|
+
operation: 'read',
|
|
697
|
+
resource: scoped.domain ? `persona://graph/${scoped.domain}` : 'persona://graph/*',
|
|
698
|
+
result: 'allowed',
|
|
699
|
+
details: { returnedNodes: result.nodes.length },
|
|
700
|
+
});
|
|
701
|
+
return result;
|
|
702
|
+
}
|
|
703
|
+
catch (error) {
|
|
704
|
+
await this.auditPersonaAccess({
|
|
705
|
+
vaultId: scoped.vaultId,
|
|
706
|
+
tokenId: auth.tokenId,
|
|
707
|
+
serviceDid: auth.serviceDid,
|
|
708
|
+
operation: 'read',
|
|
709
|
+
resource: scoped.domain ? `persona://graph/${scoped.domain}` : 'persona://graph/*',
|
|
710
|
+
result: 'denied',
|
|
711
|
+
details: { reason: error.message },
|
|
712
|
+
});
|
|
713
|
+
throw error;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
async updatePreference(input) {
|
|
717
|
+
this.ensureConnected();
|
|
718
|
+
const { capabilityToken, zkpProofs, ...payload } = input;
|
|
719
|
+
const domain = payload.domain || 'preferences';
|
|
720
|
+
const auth = await this.authorizePersonaAccess({
|
|
721
|
+
capabilityToken,
|
|
722
|
+
operation: 'write',
|
|
723
|
+
domain,
|
|
724
|
+
resource: `persona://preferences/${domain}`,
|
|
725
|
+
zkpProofs,
|
|
726
|
+
});
|
|
727
|
+
try {
|
|
728
|
+
const node = await this.persona.updatePreference(payload);
|
|
729
|
+
await this.auditPersonaAccess({
|
|
730
|
+
vaultId: node.vaultId,
|
|
731
|
+
tokenId: auth.tokenId,
|
|
732
|
+
serviceDid: auth.serviceDid,
|
|
733
|
+
operation: 'write',
|
|
734
|
+
resource: `persona://preferences/${domain}`,
|
|
735
|
+
result: 'allowed',
|
|
736
|
+
details: { key: payload.key },
|
|
737
|
+
});
|
|
738
|
+
return node;
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
await this.auditPersonaAccess({
|
|
742
|
+
vaultId: payload.vaultId,
|
|
743
|
+
tokenId: auth.tokenId,
|
|
744
|
+
serviceDid: auth.serviceDid,
|
|
745
|
+
operation: 'write',
|
|
746
|
+
resource: `persona://preferences/${domain}`,
|
|
747
|
+
result: 'denied',
|
|
748
|
+
details: { reason: error.message },
|
|
749
|
+
});
|
|
750
|
+
throw error;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
async issueCapability(input) {
|
|
754
|
+
this.ensureConnected();
|
|
755
|
+
const { capabilityToken, zkpProofs, ...payload } = input;
|
|
756
|
+
const auth = await this.authorizePersonaAccess({
|
|
757
|
+
capabilityToken,
|
|
758
|
+
operation: 'write',
|
|
759
|
+
domain: payload.caveats.domains?.[0],
|
|
760
|
+
resource: 'persona://capabilities/*',
|
|
761
|
+
appendMutation: true,
|
|
762
|
+
zkpProofs,
|
|
763
|
+
});
|
|
764
|
+
try {
|
|
765
|
+
const token = await this.persona.issueCapability(payload);
|
|
766
|
+
await this.auditPersonaAccess({
|
|
767
|
+
vaultId: token.vaultId,
|
|
768
|
+
tokenId: auth.tokenId || token.id,
|
|
769
|
+
serviceDid: auth.serviceDid,
|
|
770
|
+
operation: 'share',
|
|
771
|
+
resource: `persona://capabilities/${token.id}`,
|
|
772
|
+
result: 'allowed',
|
|
773
|
+
details: { scope: token.scope, serviceDid: token.serviceDid },
|
|
774
|
+
});
|
|
775
|
+
return token;
|
|
776
|
+
}
|
|
777
|
+
catch (error) {
|
|
778
|
+
await this.auditPersonaAccess({
|
|
779
|
+
vaultId: payload.vaultId,
|
|
780
|
+
tokenId: auth.tokenId,
|
|
781
|
+
serviceDid: auth.serviceDid,
|
|
782
|
+
operation: 'share',
|
|
783
|
+
resource: 'persona://capabilities/*',
|
|
784
|
+
result: 'denied',
|
|
785
|
+
details: { reason: error.message },
|
|
786
|
+
});
|
|
787
|
+
throw error;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
async attenuateCapability(tokenId, caveatsPatch, options) {
|
|
791
|
+
this.ensureConnected();
|
|
792
|
+
const auth = await this.authorizePersonaAccess({
|
|
793
|
+
capabilityToken: options?.capabilityToken,
|
|
794
|
+
operation: 'write',
|
|
795
|
+
resource: `persona://capabilities/${tokenId}`,
|
|
796
|
+
appendMutation: true,
|
|
797
|
+
zkpProofs: options?.zkpProofs,
|
|
798
|
+
});
|
|
799
|
+
try {
|
|
800
|
+
const token = await this.persona.attenuateCapability({ tokenId, caveatsPatch });
|
|
801
|
+
await this.auditPersonaAccess({
|
|
802
|
+
vaultId: token.vaultId,
|
|
803
|
+
tokenId: auth.tokenId || token.id,
|
|
804
|
+
serviceDid: auth.serviceDid,
|
|
805
|
+
operation: 'share',
|
|
806
|
+
resource: `persona://capabilities/${token.id}`,
|
|
807
|
+
result: 'allowed',
|
|
808
|
+
details: { parentTokenId: token.parentTokenId },
|
|
809
|
+
});
|
|
810
|
+
return token;
|
|
811
|
+
}
|
|
812
|
+
catch (error) {
|
|
813
|
+
await this.auditPersonaAccess({
|
|
814
|
+
tokenId: auth.tokenId || tokenId,
|
|
815
|
+
serviceDid: auth.serviceDid,
|
|
816
|
+
operation: 'share',
|
|
817
|
+
resource: `persona://capabilities/${tokenId}`,
|
|
818
|
+
result: 'denied',
|
|
819
|
+
details: { reason: error.message },
|
|
820
|
+
});
|
|
821
|
+
throw error;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
async revokeCapability(tokenId, reason, options) {
|
|
825
|
+
this.ensureConnected();
|
|
826
|
+
const auth = await this.authorizePersonaAccess({
|
|
827
|
+
capabilityToken: options?.capabilityToken,
|
|
828
|
+
operation: 'write',
|
|
829
|
+
resource: `persona://capabilities/${tokenId}`,
|
|
830
|
+
appendMutation: true,
|
|
831
|
+
zkpProofs: options?.zkpProofs,
|
|
832
|
+
});
|
|
833
|
+
try {
|
|
834
|
+
await this.persona.revokeCapability(tokenId, reason);
|
|
835
|
+
await this.auditPersonaAccess({
|
|
836
|
+
tokenId: auth.tokenId || tokenId,
|
|
837
|
+
serviceDid: auth.serviceDid,
|
|
838
|
+
operation: 'revoke',
|
|
839
|
+
resource: `persona://capabilities/${tokenId}`,
|
|
840
|
+
result: 'allowed',
|
|
841
|
+
details: { reason },
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
catch (error) {
|
|
845
|
+
await this.auditPersonaAccess({
|
|
846
|
+
tokenId: auth.tokenId || tokenId,
|
|
847
|
+
serviceDid: auth.serviceDid,
|
|
848
|
+
operation: 'revoke',
|
|
849
|
+
resource: `persona://capabilities/${tokenId}`,
|
|
850
|
+
result: 'denied',
|
|
851
|
+
details: { reason: error.message },
|
|
852
|
+
});
|
|
853
|
+
throw error;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
async shareSubgraph(input) {
|
|
857
|
+
this.ensureConnected();
|
|
858
|
+
const { capabilityToken, zkpProofs, ...payload } = input;
|
|
859
|
+
const domain = payload.domain;
|
|
860
|
+
const auth = await this.authorizePersonaAccess({
|
|
861
|
+
capabilityToken,
|
|
862
|
+
operation: 'share',
|
|
863
|
+
domain,
|
|
864
|
+
resource: domain ? `persona://graph/${domain}` : 'persona://graph/*',
|
|
865
|
+
requestedLimit: 1000,
|
|
866
|
+
zkpProofs,
|
|
867
|
+
});
|
|
868
|
+
try {
|
|
869
|
+
const redacted = await this.persona.exportSubgraph({
|
|
870
|
+
...payload,
|
|
871
|
+
redactionOperation: 'share',
|
|
872
|
+
});
|
|
873
|
+
if (auth.limit !== undefined && redacted.nodes.length > auth.limit) {
|
|
874
|
+
const kept = redacted.nodes.slice(0, auth.limit);
|
|
875
|
+
const keptIds = new Set(kept.map((node) => node.id));
|
|
876
|
+
redacted.nodes = kept;
|
|
877
|
+
redacted.edges = redacted.edges.filter((edge) => keptIds.has(edge.sourceNodeId) && keptIds.has(edge.targetNodeId));
|
|
878
|
+
redacted.hyperEdges = redacted.hyperEdges.filter((edge) => edge.nodeIds.some((id) => keptIds.has(id)));
|
|
879
|
+
}
|
|
880
|
+
await this.auditPersonaAccess({
|
|
881
|
+
vaultId: redacted.vaultId,
|
|
882
|
+
tokenId: auth.tokenId,
|
|
883
|
+
serviceDid: auth.serviceDid,
|
|
884
|
+
operation: 'share',
|
|
885
|
+
resource: domain ? `persona://graph/${domain}` : 'persona://graph/*',
|
|
886
|
+
result: 'allowed',
|
|
887
|
+
details: { nodes: redacted.nodes.length, domain },
|
|
888
|
+
});
|
|
889
|
+
return redacted;
|
|
890
|
+
}
|
|
891
|
+
catch (error) {
|
|
892
|
+
await this.auditPersonaAccess({
|
|
893
|
+
vaultId: payload.vaultId,
|
|
894
|
+
tokenId: auth.tokenId,
|
|
895
|
+
serviceDid: auth.serviceDid,
|
|
896
|
+
operation: 'share',
|
|
897
|
+
resource: domain ? `persona://graph/${domain}` : 'persona://graph/*',
|
|
898
|
+
result: 'denied',
|
|
899
|
+
details: { reason: error.message },
|
|
900
|
+
});
|
|
901
|
+
throw error;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
async getPersonaProfile(vaultId, options) {
|
|
905
|
+
this.ensureConnected();
|
|
906
|
+
const auth = await this.authorizePersonaAccess({
|
|
907
|
+
capabilityToken: options?.capabilityToken,
|
|
908
|
+
operation: 'read',
|
|
909
|
+
resource: 'persona://profile',
|
|
910
|
+
zkpProofs: options?.zkpProofs,
|
|
911
|
+
});
|
|
912
|
+
try {
|
|
913
|
+
const profile = { ...(await this.persona.getProfile(vaultId)) };
|
|
914
|
+
if (auth.domains?.length) {
|
|
915
|
+
const preferences = Array.isArray(profile.preferences) ? profile.preferences : [];
|
|
916
|
+
const identity = Array.isArray(profile.identity) ? profile.identity : [];
|
|
917
|
+
profile.preferences = auth.domains.includes('preferences') ? preferences : [];
|
|
918
|
+
profile.identity = identity.filter((entry) => auth.domains.includes(entry?.domain));
|
|
919
|
+
}
|
|
920
|
+
await this.auditPersonaAccess({
|
|
921
|
+
vaultId: typeof profile.vaultId === 'string' ? profile.vaultId : vaultId,
|
|
922
|
+
tokenId: auth.tokenId,
|
|
923
|
+
serviceDid: auth.serviceDid,
|
|
924
|
+
operation: 'read',
|
|
925
|
+
resource: 'persona://profile',
|
|
926
|
+
result: 'allowed',
|
|
927
|
+
});
|
|
928
|
+
return profile;
|
|
929
|
+
}
|
|
930
|
+
catch (error) {
|
|
931
|
+
await this.auditPersonaAccess({
|
|
932
|
+
vaultId,
|
|
933
|
+
tokenId: auth.tokenId,
|
|
934
|
+
serviceDid: auth.serviceDid,
|
|
935
|
+
operation: 'read',
|
|
936
|
+
resource: 'persona://profile',
|
|
937
|
+
result: 'denied',
|
|
938
|
+
details: { reason: error.message },
|
|
939
|
+
});
|
|
940
|
+
throw error;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
async listPersonaCapabilities(vaultId) {
|
|
944
|
+
this.ensureConnected();
|
|
945
|
+
const resolvedVaultId = vaultId || this.storage.getPersonaVaults?.(this.identity.did)?.[0]?.id;
|
|
946
|
+
if (!resolvedVaultId)
|
|
947
|
+
return [];
|
|
948
|
+
return this.storage.listPersonaCapabilities?.(resolvedVaultId) || [];
|
|
949
|
+
}
|
|
950
|
+
async getPersonaCapability(tokenId, vaultId) {
|
|
951
|
+
const all = await this.listPersonaCapabilities(vaultId);
|
|
952
|
+
return all.find((item) => item.id === tokenId);
|
|
953
|
+
}
|
|
954
|
+
async issuePersonaClaim(input) {
|
|
955
|
+
this.ensureConnected();
|
|
956
|
+
const { capabilityToken, zkpProofs, ...payload } = input;
|
|
957
|
+
const auth = await this.authorizePersonaAccess({
|
|
958
|
+
capabilityToken,
|
|
959
|
+
operation: 'write',
|
|
960
|
+
resource: 'persona://claims/*',
|
|
961
|
+
zkpProofs,
|
|
962
|
+
});
|
|
963
|
+
const claim = await this.persona.issueClaim(payload);
|
|
964
|
+
await this.auditPersonaAccess({
|
|
965
|
+
vaultId: claim.vaultId,
|
|
966
|
+
tokenId: auth.tokenId,
|
|
967
|
+
serviceDid: auth.serviceDid,
|
|
968
|
+
operation: 'write',
|
|
969
|
+
resource: `persona://claims/${claim.id}`,
|
|
970
|
+
result: 'allowed',
|
|
971
|
+
details: { schema: claim.schema },
|
|
972
|
+
});
|
|
973
|
+
return claim;
|
|
974
|
+
}
|
|
975
|
+
async revokePersonaClaim(claimId, reason, options) {
|
|
976
|
+
this.ensureConnected();
|
|
977
|
+
const auth = await this.authorizePersonaAccess({
|
|
978
|
+
capabilityToken: options?.capabilityToken,
|
|
979
|
+
operation: 'delete',
|
|
980
|
+
resource: `persona://claims/${claimId}`,
|
|
981
|
+
zkpProofs: options?.zkpProofs,
|
|
982
|
+
});
|
|
983
|
+
await this.persona.revokeClaim(claimId, reason);
|
|
984
|
+
await this.auditPersonaAccess({
|
|
985
|
+
tokenId: auth.tokenId,
|
|
986
|
+
serviceDid: auth.serviceDid,
|
|
987
|
+
operation: 'delete',
|
|
988
|
+
resource: `persona://claims/${claimId}`,
|
|
989
|
+
result: 'allowed',
|
|
990
|
+
details: { reason },
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
async generatePersonaZkProof(input) {
|
|
994
|
+
this.ensureConnected();
|
|
995
|
+
const { capabilityToken, ...payload } = input;
|
|
996
|
+
const auth = await this.authorizePersonaAccess({
|
|
997
|
+
capabilityToken,
|
|
998
|
+
operation: 'read',
|
|
999
|
+
resource: 'persona://zkp/proofs/*',
|
|
1000
|
+
});
|
|
1001
|
+
const bundle = await this.persona.generateZkProof(payload);
|
|
1002
|
+
await this.auditPersonaAccess({
|
|
1003
|
+
vaultId: bundle.vaultId,
|
|
1004
|
+
tokenId: auth.tokenId,
|
|
1005
|
+
serviceDid: auth.serviceDid,
|
|
1006
|
+
operation: 'read',
|
|
1007
|
+
resource: `persona://zkp/proofs/${bundle.id}`,
|
|
1008
|
+
result: 'allowed',
|
|
1009
|
+
details: { circuit: bundle.circuitId },
|
|
1010
|
+
});
|
|
1011
|
+
return bundle;
|
|
1012
|
+
}
|
|
1013
|
+
async verifyPersonaZkProof(input) {
|
|
1014
|
+
this.ensureConnected();
|
|
1015
|
+
const { capabilityToken, ...payload } = input;
|
|
1016
|
+
const auth = await this.authorizePersonaAccess({
|
|
1017
|
+
capabilityToken,
|
|
1018
|
+
operation: 'read',
|
|
1019
|
+
resource: 'persona://zkp/proofs/*',
|
|
1020
|
+
});
|
|
1021
|
+
const result = await this.persona.verifyZkProof(payload);
|
|
1022
|
+
await this.auditPersonaAccess({
|
|
1023
|
+
vaultId: payload.vaultId || payload.proofBundle.vaultId,
|
|
1024
|
+
tokenId: auth.tokenId,
|
|
1025
|
+
serviceDid: auth.serviceDid,
|
|
1026
|
+
operation: 'read',
|
|
1027
|
+
resource: `persona://zkp/proofs/${payload.proofBundle.id}`,
|
|
1028
|
+
result: result.valid ? 'allowed' : 'denied',
|
|
1029
|
+
details: { circuit: result.circuitId, reason: result.reason },
|
|
1030
|
+
});
|
|
1031
|
+
return result;
|
|
1032
|
+
}
|
|
1033
|
+
async listPersonaClaims(vaultId, includeRevoked = false) {
|
|
1034
|
+
this.ensureConnected();
|
|
1035
|
+
return this.persona.listClaims(vaultId, includeRevoked);
|
|
1036
|
+
}
|
|
1037
|
+
async getPersonaClaim(claimId) {
|
|
1038
|
+
this.ensureConnected();
|
|
1039
|
+
return this.persona.getClaim(claimId);
|
|
1040
|
+
}
|
|
1041
|
+
listPersonaZkCircuits() {
|
|
1042
|
+
this.ensureConnected();
|
|
1043
|
+
return this.persona.listZkCircuits();
|
|
1044
|
+
}
|
|
1045
|
+
listPersonaZkProofs(vaultId) {
|
|
1046
|
+
this.ensureConnected();
|
|
1047
|
+
return this.persona.listZkProofs(vaultId);
|
|
1048
|
+
}
|
|
1049
|
+
getPersonaZkProof(proofId) {
|
|
1050
|
+
this.ensureConnected();
|
|
1051
|
+
return this.persona.getZkProof(proofId);
|
|
1052
|
+
}
|
|
1053
|
+
async verifyPersonaAccessLog(input) {
|
|
1054
|
+
this.ensureConnected();
|
|
1055
|
+
const auth = await this.authorizePersonaAccess({
|
|
1056
|
+
capabilityToken: input.capabilityToken,
|
|
1057
|
+
operation: 'read',
|
|
1058
|
+
resource: `persona://audit/log/${input.logId}`,
|
|
1059
|
+
zkpProofs: input.zkpProofs,
|
|
1060
|
+
});
|
|
1061
|
+
const result = await this.persona.verifyPersonaAccessLog({ logId: input.logId });
|
|
1062
|
+
await this.auditPersonaAccess({
|
|
1063
|
+
tokenId: auth.tokenId,
|
|
1064
|
+
serviceDid: auth.serviceDid,
|
|
1065
|
+
operation: 'read',
|
|
1066
|
+
resource: `persona://audit/log/${input.logId}`,
|
|
1067
|
+
result: result.valid ? 'allowed' : 'denied',
|
|
1068
|
+
details: result.reason ? { reason: result.reason } : undefined,
|
|
1069
|
+
});
|
|
1070
|
+
return result;
|
|
1071
|
+
}
|
|
1072
|
+
async runPersonaRetentionSweep(input = {}) {
|
|
1073
|
+
this.ensureConnected();
|
|
1074
|
+
const auth = await this.authorizePersonaAccess({
|
|
1075
|
+
capabilityToken: input.capabilityToken,
|
|
1076
|
+
operation: 'delete',
|
|
1077
|
+
domain: input.domain,
|
|
1078
|
+
resource: 'persona://retention/sweep',
|
|
1079
|
+
zkpProofs: input.zkpProofs,
|
|
1080
|
+
});
|
|
1081
|
+
const result = await this.persona.runRetentionSweep({
|
|
1082
|
+
vaultId: input.vaultId,
|
|
1083
|
+
domain: input.domain,
|
|
1084
|
+
dryRun: input.dryRun,
|
|
1085
|
+
});
|
|
1086
|
+
await this.auditPersonaAccess({
|
|
1087
|
+
vaultId: input.vaultId,
|
|
1088
|
+
tokenId: auth.tokenId,
|
|
1089
|
+
serviceDid: auth.serviceDid,
|
|
1090
|
+
operation: 'delete',
|
|
1091
|
+
resource: 'persona://retention/sweep',
|
|
1092
|
+
result: 'allowed',
|
|
1093
|
+
details: { dryRun: !!input.dryRun, scanned: result.scanned, deleted: result.deleted },
|
|
1094
|
+
});
|
|
1095
|
+
return result;
|
|
1096
|
+
}
|
|
1097
|
+
async applyPersonaSyncDelta(delta, options) {
|
|
1098
|
+
this.ensureConnected();
|
|
1099
|
+
const auth = await this.authorizePersonaAccess({
|
|
1100
|
+
capabilityToken: options?.capabilityToken,
|
|
1101
|
+
operation: 'write',
|
|
1102
|
+
resource: 'persona://sync/delta',
|
|
1103
|
+
zkpProofs: options?.zkpProofs || delta.proofs,
|
|
1104
|
+
});
|
|
1105
|
+
try {
|
|
1106
|
+
const result = await this.persona.applySyncDelta(delta);
|
|
1107
|
+
await this.auditPersonaAccess({
|
|
1108
|
+
vaultId: delta.vaultId,
|
|
1109
|
+
tokenId: auth.tokenId,
|
|
1110
|
+
serviceDid: auth.serviceDid,
|
|
1111
|
+
operation: 'write',
|
|
1112
|
+
resource: 'persona://sync/delta',
|
|
1113
|
+
result: 'allowed',
|
|
1114
|
+
details: { applied: result.applied, ignored: result.ignored },
|
|
1115
|
+
});
|
|
1116
|
+
return result;
|
|
1117
|
+
}
|
|
1118
|
+
catch (error) {
|
|
1119
|
+
await this.auditPersonaAccess({
|
|
1120
|
+
vaultId: delta.vaultId,
|
|
1121
|
+
tokenId: auth.tokenId,
|
|
1122
|
+
serviceDid: auth.serviceDid,
|
|
1123
|
+
operation: 'write',
|
|
1124
|
+
resource: 'persona://sync/delta',
|
|
1125
|
+
result: 'denied',
|
|
1126
|
+
details: { reason: error.message },
|
|
1127
|
+
});
|
|
1128
|
+
throw error;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
// ─── Identity ─────────────────────────────────────────────────
|
|
1132
|
+
getIdentity() {
|
|
1133
|
+
return {
|
|
1134
|
+
did: this.identity.did,
|
|
1135
|
+
name: this.identity.displayName,
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
getPeerId() {
|
|
1139
|
+
this.ensureConnected();
|
|
1140
|
+
return this.p2p.getPeerId();
|
|
1141
|
+
}
|
|
1142
|
+
getMultiaddrs() {
|
|
1143
|
+
this.ensureConnected();
|
|
1144
|
+
return this.p2p.getMultiaddrs();
|
|
1145
|
+
}
|
|
1146
|
+
getCapabilities() {
|
|
1147
|
+
return ['chat', 'coc', 'plan', 'reputation', 'persona-vault', 'missions', 'swarm'];
|
|
1148
|
+
}
|
|
1149
|
+
// ─── Helpers ──────────────────────────────────────────────────
|
|
1150
|
+
ensureConnected() {
|
|
1151
|
+
if (!this.connected) {
|
|
1152
|
+
throw new Error('Client not connected. Call connect() first.');
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
async authorizePersonaAccess(input) {
|
|
1156
|
+
if (!input.capabilityToken) {
|
|
1157
|
+
return {
|
|
1158
|
+
serviceDid: this.identity.did,
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
const validation = this.persona.validateCapability({
|
|
1162
|
+
token: input.capabilityToken,
|
|
1163
|
+
operation: input.operation,
|
|
1164
|
+
domain: input.domain,
|
|
1165
|
+
resource: input.resource,
|
|
1166
|
+
});
|
|
1167
|
+
if (!validation.allowed || !validation.capability) {
|
|
1168
|
+
throw new Error(`Capability denied: ${validation.reason || 'unknown reason'}`);
|
|
1169
|
+
}
|
|
1170
|
+
if (input.appendMutation && validation.capability.caveats.appendOnly) {
|
|
1171
|
+
throw new Error('Capability denied: append-only token cannot mutate existing data');
|
|
1172
|
+
}
|
|
1173
|
+
const requiredProofs = validation.capability.caveats.requireProofs || [];
|
|
1174
|
+
if (requiredProofs.length > 0) {
|
|
1175
|
+
const provided = input.zkpProofs || [];
|
|
1176
|
+
for (const circuitId of requiredProofs) {
|
|
1177
|
+
const proof = provided.find((item) => item.circuitId === circuitId);
|
|
1178
|
+
if (!proof) {
|
|
1179
|
+
throw new Error(`Capability denied: missing required ZKP proof (${circuitId})`);
|
|
1180
|
+
}
|
|
1181
|
+
const verified = await this.persona.verifyZkProof({
|
|
1182
|
+
vaultId: validation.capability.vaultId,
|
|
1183
|
+
proofBundle: proof,
|
|
1184
|
+
});
|
|
1185
|
+
if (!verified.valid) {
|
|
1186
|
+
throw new Error(`Capability denied: invalid ZKP proof (${circuitId})${verified.reason ? `: ${verified.reason}` : ''}`);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return {
|
|
1191
|
+
tokenId: validation.capability.id,
|
|
1192
|
+
serviceDid: validation.capability.serviceDid,
|
|
1193
|
+
domains: validation.capability.caveats.domains,
|
|
1194
|
+
limit: validation.capability.caveats.limit,
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
async auditPersonaAccess(entry) {
|
|
1198
|
+
const resolvedVaultId = entry.vaultId ||
|
|
1199
|
+
this.storage.getPersonaVaults?.(this.identity.did)?.[0]?.id;
|
|
1200
|
+
if (!resolvedVaultId)
|
|
1201
|
+
return;
|
|
1202
|
+
const ts = Date.now();
|
|
1203
|
+
const body = JSON.stringify({
|
|
1204
|
+
vaultId: resolvedVaultId,
|
|
1205
|
+
tokenId: entry.tokenId || null,
|
|
1206
|
+
serviceDid: entry.serviceDid,
|
|
1207
|
+
operation: entry.operation,
|
|
1208
|
+
resource: entry.resource,
|
|
1209
|
+
result: entry.result,
|
|
1210
|
+
details: entry.details || null,
|
|
1211
|
+
ts,
|
|
1212
|
+
});
|
|
1213
|
+
const signatureBytes = await this.security.sign(new TextEncoder().encode(body));
|
|
1214
|
+
const signature = Buffer.from(signatureBytes).toString('base64');
|
|
1215
|
+
this.storage.appendPersonaAccessLog?.({
|
|
1216
|
+
vaultId: resolvedVaultId,
|
|
1217
|
+
tokenId: entry.tokenId,
|
|
1218
|
+
serviceDid: entry.serviceDid,
|
|
1219
|
+
operation: entry.operation,
|
|
1220
|
+
resource: entry.resource,
|
|
1221
|
+
result: entry.result,
|
|
1222
|
+
details: entry.details,
|
|
1223
|
+
ts,
|
|
1224
|
+
signature,
|
|
1225
|
+
signerDid: this.identity.did,
|
|
1226
|
+
sigAlg: 'ed25519',
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
// ─── Factory Function ───────────────────────────────────────────
|
|
1231
|
+
export async function createClient(config) {
|
|
1232
|
+
const client = new SocietyClient(config);
|
|
1233
|
+
await client.connect();
|
|
1234
|
+
return client;
|
|
1235
|
+
}
|
|
1236
|
+
export async function society(config) {
|
|
1237
|
+
// Allow: society('Alice') as shorthand
|
|
1238
|
+
const opts = typeof config === 'string'
|
|
1239
|
+
? { name: config }
|
|
1240
|
+
: config || {};
|
|
1241
|
+
const name = opts.name || `Agent-${Math.random().toString(36).slice(2, 6)}`;
|
|
1242
|
+
const room = opts.room || 'lobby';
|
|
1243
|
+
const sdkConfig = {
|
|
1244
|
+
identity: { name },
|
|
1245
|
+
network: {
|
|
1246
|
+
enableGossipsub: true,
|
|
1247
|
+
enableDht: true,
|
|
1248
|
+
},
|
|
1249
|
+
};
|
|
1250
|
+
// If connecting to a remote network
|
|
1251
|
+
if (opts.connect) {
|
|
1252
|
+
sdkConfig.network.bootstrap = [opts.connect];
|
|
1253
|
+
}
|
|
1254
|
+
const client = await createClient(sdkConfig);
|
|
1255
|
+
await client.joinRoom(room);
|
|
1256
|
+
// If capabilities are provided, announce as worker
|
|
1257
|
+
if (opts.capabilities?.length) {
|
|
1258
|
+
const peerId = client.getPeerId();
|
|
1259
|
+
await client.announceWorker(room, {
|
|
1260
|
+
owner_did: client.getIdentity().did,
|
|
1261
|
+
room_id: room,
|
|
1262
|
+
adapter_id: `adapter_${peerId?.slice(-8) || 'local'}`,
|
|
1263
|
+
runtime: 'custom',
|
|
1264
|
+
display_name: name,
|
|
1265
|
+
specialties: opts.capabilities,
|
|
1266
|
+
kinds: ['execute'],
|
|
1267
|
+
max_concurrency: 1,
|
|
1268
|
+
version: '1.0.0',
|
|
1269
|
+
endpoint: '',
|
|
1270
|
+
auth_type: 'none',
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
return client;
|
|
1274
|
+
}
|
|
1275
|
+
// ─── React Hook (para integração frontend) ──────────────────────
|
|
1276
|
+
export function useSociety(config) {
|
|
1277
|
+
// Esta seria uma implementação React hook
|
|
1278
|
+
// Deixada como referência para implementação futura
|
|
1279
|
+
return {
|
|
1280
|
+
client: null,
|
|
1281
|
+
connected: false,
|
|
1282
|
+
chains: [],
|
|
1283
|
+
connect: async () => { },
|
|
1284
|
+
disconnect: async () => { },
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
//# sourceMappingURL=client.js.map
|