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,1105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Society Protocol - Module Integration Layer v1.0
|
|
3
|
+
*
|
|
4
|
+
* Integrações entre módulos:
|
|
5
|
+
* - Federation ↔ Rooms (salas pertencem a federações)
|
|
6
|
+
* - Knowledge ↔ CoC (CoCs geram knowledge automaticamente)
|
|
7
|
+
* - Skills ↔ Runtime (execução multi-runtime)
|
|
8
|
+
* - Security ↔ All (segurança em todos os pontos)
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import { ulid } from 'ulid';
|
|
12
|
+
// ─── Integration Engine ──────────────────────────────────────────
|
|
13
|
+
class IntegrationEngine extends EventEmitter {
|
|
14
|
+
storage;
|
|
15
|
+
identity;
|
|
16
|
+
federationEngine;
|
|
17
|
+
roomManager;
|
|
18
|
+
knowledgePool;
|
|
19
|
+
cocEngine;
|
|
20
|
+
skillsEngine;
|
|
21
|
+
securityManager;
|
|
22
|
+
config;
|
|
23
|
+
federationRooms = new Map(); // federationId -> rooms
|
|
24
|
+
cocKnowledgeBindings = new Map();
|
|
25
|
+
meshBridges = new Map();
|
|
26
|
+
bridgeRateLimits = new Map();
|
|
27
|
+
personaVault;
|
|
28
|
+
personaHooksBound = false;
|
|
29
|
+
cotStream;
|
|
30
|
+
cotHooksBound = false;
|
|
31
|
+
constructor(storage, identity, federationEngine, roomManager, knowledgePool, cocEngine, skillsEngine, securityManager, config) {
|
|
32
|
+
super();
|
|
33
|
+
this.storage = storage;
|
|
34
|
+
this.identity = identity;
|
|
35
|
+
this.federationEngine = federationEngine;
|
|
36
|
+
this.roomManager = roomManager;
|
|
37
|
+
this.knowledgePool = knowledgePool;
|
|
38
|
+
this.cocEngine = cocEngine;
|
|
39
|
+
this.skillsEngine = skillsEngine;
|
|
40
|
+
this.securityManager = securityManager;
|
|
41
|
+
this.config = {
|
|
42
|
+
autoIndexCoC: true,
|
|
43
|
+
autoCreateKnowledgeSpace: true,
|
|
44
|
+
enforceFederationACLs: true,
|
|
45
|
+
autoCompressMessages: true,
|
|
46
|
+
maxKnowledgeCardSize: 10000,
|
|
47
|
+
...config
|
|
48
|
+
};
|
|
49
|
+
this.loadFromStorage();
|
|
50
|
+
this.setupHooks();
|
|
51
|
+
}
|
|
52
|
+
attachPersonaVault(engine) {
|
|
53
|
+
this.personaVault = engine;
|
|
54
|
+
if (this.personaHooksBound)
|
|
55
|
+
return;
|
|
56
|
+
this.personaHooksBound = true;
|
|
57
|
+
const publishDelta = async (operations, vaultId) => {
|
|
58
|
+
const resolvedVaultId = vaultId || this.storage.getPersonaVaults?.(this.identity.did)?.[0]?.id;
|
|
59
|
+
if (!resolvedVaultId)
|
|
60
|
+
return;
|
|
61
|
+
const delta = this.personaVault.buildSyncDelta({
|
|
62
|
+
vaultId: resolvedVaultId,
|
|
63
|
+
operations,
|
|
64
|
+
});
|
|
65
|
+
const rooms = this.roomManager.getJoinedRooms?.() || [];
|
|
66
|
+
await Promise.all(rooms.map((roomId) => this.roomManager.sendMessage(roomId, delta, 'persona.sync.delta')));
|
|
67
|
+
};
|
|
68
|
+
engine.on('persona:memory:added', (node) => {
|
|
69
|
+
publishDelta([{ type: 'node_upsert', payload: node }], node.vaultId).catch(() => { });
|
|
70
|
+
});
|
|
71
|
+
engine.on('persona:memory:updated', (node) => {
|
|
72
|
+
publishDelta([{ type: 'node_upsert', payload: node }], node.vaultId).catch(() => { });
|
|
73
|
+
});
|
|
74
|
+
engine.on('persona:memory:deleted', (evt) => {
|
|
75
|
+
publishDelta([{ type: 'node_delete', payload: { nodeId: evt.nodeId } }], evt.vaultId).catch(() => { });
|
|
76
|
+
});
|
|
77
|
+
engine.on('persona:edge:upserted', (edge) => {
|
|
78
|
+
publishDelta([{ type: 'edge_upsert', payload: edge }], edge.vaultId).catch(() => { });
|
|
79
|
+
});
|
|
80
|
+
engine.on('persona:capability:revoked', (evt) => {
|
|
81
|
+
publishDelta([{ type: 'capability_revoke', payload: { tokenId: evt.tokenId, reason: evt.reason } }]).catch(() => { });
|
|
82
|
+
});
|
|
83
|
+
engine.on('persona:capability:attenuated', (cap) => {
|
|
84
|
+
publishDelta([{ type: 'capability_attenuate', payload: { tokenId: cap.parentTokenId, caveatsPatch: cap.caveats } }], cap.vaultId).catch(() => { });
|
|
85
|
+
});
|
|
86
|
+
engine.on('persona:claim:issued', (claim) => {
|
|
87
|
+
publishDelta([{ type: 'claim_upsert', payload: claim }], claim.vaultId).catch(() => { });
|
|
88
|
+
});
|
|
89
|
+
engine.on('persona:claim:revoked', (evt) => {
|
|
90
|
+
publishDelta([{ type: 'claim_revoke', payload: { claimId: evt.claimId } }]).catch(() => { });
|
|
91
|
+
});
|
|
92
|
+
engine.on('persona:zkp:generated', (proof) => {
|
|
93
|
+
publishDelta([{ type: 'zkp_proof_upsert', payload: proof }], proof.vaultId).catch(() => { });
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Attach CoT Stream Engine for insight→knowledge auto-indexing
|
|
98
|
+
* and CoC step→stream correlation.
|
|
99
|
+
*/
|
|
100
|
+
attachCotStream(engine) {
|
|
101
|
+
this.cotStream = engine;
|
|
102
|
+
if (this.cotHooksBound)
|
|
103
|
+
return;
|
|
104
|
+
this.cotHooksBound = true;
|
|
105
|
+
// Hook: CoT insight with high confidence → auto-create knowledge card
|
|
106
|
+
engine.on('insight:received', async (_streamId, insight) => {
|
|
107
|
+
if (this.config.autoIndexCoC && insight.confidence >= 0.7) {
|
|
108
|
+
this.emit('cot:insight:indexed', insight);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
// Hook: CoT stream ended → index summary as knowledge
|
|
112
|
+
engine.on('stream:ended', async (streamId, status, summary) => {
|
|
113
|
+
if (status === 'completed' && this.config.autoIndexCoC) {
|
|
114
|
+
const stream = engine.getStream(streamId);
|
|
115
|
+
if (stream?.chain_id) {
|
|
116
|
+
this.emit('cot:stream:completed', streamId, summary);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
// Hook: CoC step unlocked → notify CoT engine for potential auto-stream
|
|
121
|
+
this.cocEngine.on('step:unlocked', (chainId, stepId, step) => {
|
|
122
|
+
this.emit('cot:step:available', chainId, stepId, step);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// ═══════════════════════════════════════════════════════════════
|
|
126
|
+
// FEDERATION ↔ ROOMS INTEGRATION
|
|
127
|
+
// ═══════════════════════════════════════════════════════════════
|
|
128
|
+
/**
|
|
129
|
+
* Criar room vinculada a uma federação
|
|
130
|
+
*/
|
|
131
|
+
async createFederatedRoom(roomId, name, federationId, options) {
|
|
132
|
+
// Verificar se federação existe
|
|
133
|
+
const federation = this.federationEngine.getFederation(federationId);
|
|
134
|
+
if (!federation) {
|
|
135
|
+
throw new Error(`Federation ${federationId} not found`);
|
|
136
|
+
}
|
|
137
|
+
// Verificar permissão de criar room na federação
|
|
138
|
+
const canCreate = this.federationEngine.checkPolicy(federation, 'room:create', this.identity.did);
|
|
139
|
+
if (!canCreate.allowed) {
|
|
140
|
+
throw new Error(`Cannot create room: ${canCreate.reason}`);
|
|
141
|
+
}
|
|
142
|
+
// Criar room no RoomManager (se não existir)
|
|
143
|
+
// Note: RoomManager.createRoom só aceita name, então criamos via storage
|
|
144
|
+
this.storage.createRoom(roomId, name, this.identity.did);
|
|
145
|
+
this.storage.addRoomMember(roomId, this.identity.did, this.identity.displayName);
|
|
146
|
+
// Criar vínculo federation-room
|
|
147
|
+
const federationRoom = {
|
|
148
|
+
roomId,
|
|
149
|
+
federationId,
|
|
150
|
+
policies: federation.policies.map(p => p.id),
|
|
151
|
+
requiresInvitation: options?.requireInvitation ?? federation.settings.requireInvitation,
|
|
152
|
+
memberCount: 0
|
|
153
|
+
};
|
|
154
|
+
if (!this.federationRooms.has(federationId)) {
|
|
155
|
+
this.federationRooms.set(federationId, []);
|
|
156
|
+
}
|
|
157
|
+
this.federationRooms.get(federationId).push(federationRoom);
|
|
158
|
+
this.storage.saveFederationRoom?.(federationId, roomId, federationRoom);
|
|
159
|
+
// Criar knowledge space para a room se configurado
|
|
160
|
+
let knowledgeSpace;
|
|
161
|
+
if (this.config.autoCreateKnowledgeSpace) {
|
|
162
|
+
knowledgeSpace = await this.knowledgePool.createSpace(`${name} Knowledge`, `Shared knowledge for ${name}`, 'team', federation.visibility === 'public' ? 'public' : 'federation');
|
|
163
|
+
}
|
|
164
|
+
// Emitir evento
|
|
165
|
+
this.emit('federation:room:created', { roomId, federationId, knowledgeSpace });
|
|
166
|
+
return {
|
|
167
|
+
room: { room_id: roomId, name },
|
|
168
|
+
federationRoom
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Verificar se usuário pode entrar na room (ACL da federação)
|
|
173
|
+
*/
|
|
174
|
+
async canJoinRoom(roomId, did) {
|
|
175
|
+
// Encontrar federação da room
|
|
176
|
+
const federationRoom = this.findFederationForRoom(roomId);
|
|
177
|
+
if (!federationRoom) {
|
|
178
|
+
// Room não está em nenhuma federação - livre
|
|
179
|
+
return { allowed: true };
|
|
180
|
+
}
|
|
181
|
+
const federation = this.federationEngine.getFederation(federationRoom.federationId);
|
|
182
|
+
if (!federation) {
|
|
183
|
+
return { allowed: false, reason: 'Federation not found' };
|
|
184
|
+
}
|
|
185
|
+
// Verificar se já é membro da federação
|
|
186
|
+
const isMember = federation.members.has(did);
|
|
187
|
+
if (!isMember) {
|
|
188
|
+
// Verificar se pode entrar na federação
|
|
189
|
+
if (federationRoom.requiresInvitation) {
|
|
190
|
+
return {
|
|
191
|
+
allowed: false,
|
|
192
|
+
reason: 'Invitation required to join federation',
|
|
193
|
+
requiresInvite: true
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Tentar juntar à federação primeiro
|
|
197
|
+
try {
|
|
198
|
+
await this.federationEngine.joinFederation(federationRoom.federationId, did, 'Unknown' // Nome será atualizado depois
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
return { allowed: false, reason: err.message };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Verificar políticas específicas da room
|
|
206
|
+
const checkResult = this.federationEngine.checkPolicy(federation, 'room:join', did);
|
|
207
|
+
return {
|
|
208
|
+
allowed: checkResult.allowed,
|
|
209
|
+
reason: checkResult.reason
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Listar rooms de uma federação
|
|
214
|
+
*/
|
|
215
|
+
getFederationRooms(federationId) {
|
|
216
|
+
return this.federationRooms.get(federationId) || [];
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Obter federação de uma room
|
|
220
|
+
*/
|
|
221
|
+
findFederationForRoom(roomId) {
|
|
222
|
+
for (const rooms of this.federationRooms.values()) {
|
|
223
|
+
const room = rooms.find(r => r.roomId === roomId);
|
|
224
|
+
if (room)
|
|
225
|
+
return room;
|
|
226
|
+
}
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
// ═══════════════════════════════════════════════════════════════
|
|
230
|
+
// FEDERATION MESH (Peering + Bridge + Sync)
|
|
231
|
+
// ═══════════════════════════════════════════════════════════════
|
|
232
|
+
async openMeshBridge(peeringId, localRoomId, remoteRoomId, rules) {
|
|
233
|
+
const peering = this.federationEngine.getPeering(peeringId);
|
|
234
|
+
if (!peering) {
|
|
235
|
+
throw new Error(`Peering ${peeringId} not found`);
|
|
236
|
+
}
|
|
237
|
+
if (peering.status !== 'active') {
|
|
238
|
+
throw new Error(`Peering ${peeringId} is not active`);
|
|
239
|
+
}
|
|
240
|
+
const now = Date.now();
|
|
241
|
+
const bridge = {
|
|
242
|
+
id: `bridge_${ulid()}`,
|
|
243
|
+
peeringId,
|
|
244
|
+
localFederationId: peering.sourceFederationId,
|
|
245
|
+
localRoomId,
|
|
246
|
+
remoteRoomId,
|
|
247
|
+
rules: this.mergeBridgeRules(peering.policy, rules),
|
|
248
|
+
status: 'active',
|
|
249
|
+
eventsIn: 0,
|
|
250
|
+
eventsOut: 0,
|
|
251
|
+
createdAt: now,
|
|
252
|
+
updatedAt: now
|
|
253
|
+
};
|
|
254
|
+
this.meshBridges.set(bridge.id, bridge);
|
|
255
|
+
this.persistMeshBridge(bridge);
|
|
256
|
+
this.emit('mesh:bridge:opened', bridge);
|
|
257
|
+
return bridge;
|
|
258
|
+
}
|
|
259
|
+
async closeMeshBridge(bridgeId) {
|
|
260
|
+
const bridge = this.meshBridges.get(bridgeId);
|
|
261
|
+
if (!bridge) {
|
|
262
|
+
throw new Error(`Bridge ${bridgeId} not found`);
|
|
263
|
+
}
|
|
264
|
+
bridge.status = 'closed';
|
|
265
|
+
bridge.updatedAt = Date.now();
|
|
266
|
+
this.meshBridges.set(bridge.id, bridge);
|
|
267
|
+
this.persistMeshBridge(bridge);
|
|
268
|
+
this.storage.updateFederationBridgeStatus?.(bridge.id, 'closed', bridge.lastSyncAt);
|
|
269
|
+
this.emit('mesh:bridge:closed', bridge);
|
|
270
|
+
}
|
|
271
|
+
listMeshBridges(federationId, status) {
|
|
272
|
+
return Array.from(this.meshBridges.values())
|
|
273
|
+
.filter((bridge) => {
|
|
274
|
+
if (federationId && bridge.localFederationId !== federationId)
|
|
275
|
+
return false;
|
|
276
|
+
if (status && bridge.status !== status)
|
|
277
|
+
return false;
|
|
278
|
+
return true;
|
|
279
|
+
})
|
|
280
|
+
.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
281
|
+
}
|
|
282
|
+
async publishMeshEvent(bridgeId, envelope) {
|
|
283
|
+
const bridge = this.meshBridges.get(bridgeId);
|
|
284
|
+
if (!bridge) {
|
|
285
|
+
return { delivered: false, reason: `Bridge ${bridgeId} not found` };
|
|
286
|
+
}
|
|
287
|
+
if (bridge.status !== 'active') {
|
|
288
|
+
return { delivered: false, reason: `Bridge ${bridgeId} is not active` };
|
|
289
|
+
}
|
|
290
|
+
const peering = this.federationEngine.getPeering(bridge.peeringId);
|
|
291
|
+
if (!peering || peering.status !== 'active') {
|
|
292
|
+
await this.closeMeshBridge(bridgeId);
|
|
293
|
+
return { delivered: false, reason: `Peering ${bridge.peeringId} is not active` };
|
|
294
|
+
}
|
|
295
|
+
if (envelope.room !== bridge.localRoomId) {
|
|
296
|
+
return { delivered: false, reason: 'Envelope room does not match bridge local room' };
|
|
297
|
+
}
|
|
298
|
+
if (!this.isMessageTypeAllowed(bridge.rules.allowedTypes, envelope.t)) {
|
|
299
|
+
this.storage.appendFederationSyncLog?.({
|
|
300
|
+
bridgeId: bridge.id,
|
|
301
|
+
envelopeId: envelope.id,
|
|
302
|
+
direction: 'out',
|
|
303
|
+
messageType: envelope.t,
|
|
304
|
+
fromFederationId: bridge.localFederationId,
|
|
305
|
+
toFederationId: peering.targetFederationDid,
|
|
306
|
+
status: 'rejected',
|
|
307
|
+
error: `type ${envelope.t} blocked by mesh policy`,
|
|
308
|
+
ts: Date.now()
|
|
309
|
+
});
|
|
310
|
+
return { delivered: false, reason: `Message type ${envelope.t} blocked by mesh policy` };
|
|
311
|
+
}
|
|
312
|
+
if (!this.consumeBridgeRateLimit(bridge)) {
|
|
313
|
+
return { delivered: false, reason: `Rate limit exceeded for bridge ${bridge.id}` };
|
|
314
|
+
}
|
|
315
|
+
if (this.storage.hasFederationSyncLog?.(bridge.id, envelope.id, 'out')) {
|
|
316
|
+
return { delivered: false, reason: 'Duplicate envelope blocked by sync log' };
|
|
317
|
+
}
|
|
318
|
+
const outboundEnvelope = this.applyPrivacyMode(envelope, bridge.rules.privacyMode);
|
|
319
|
+
const payload = {
|
|
320
|
+
bridge_id: bridge.id,
|
|
321
|
+
peering_id: bridge.peeringId,
|
|
322
|
+
source_federation_id: bridge.localFederationId,
|
|
323
|
+
target_federation_did: peering.targetFederationDid,
|
|
324
|
+
direction: 'out',
|
|
325
|
+
cursor: envelope.id,
|
|
326
|
+
envelope: outboundEnvelope
|
|
327
|
+
};
|
|
328
|
+
try {
|
|
329
|
+
await this.roomManager.sendMessage(bridge.remoteRoomId, payload, 'federation.bridge.sync');
|
|
330
|
+
const now = Date.now();
|
|
331
|
+
bridge.eventsOut += 1;
|
|
332
|
+
bridge.lastSyncAt = now;
|
|
333
|
+
bridge.updatedAt = now;
|
|
334
|
+
this.meshBridges.set(bridge.id, bridge);
|
|
335
|
+
this.persistMeshBridge(bridge);
|
|
336
|
+
this.storage.incrementFederationBridgeCounters?.(bridge.id, 'out', 1, now);
|
|
337
|
+
this.storage.saveFederationSyncCursor?.({
|
|
338
|
+
bridgeId: bridge.id,
|
|
339
|
+
direction: 'out',
|
|
340
|
+
cursorId: envelope.id,
|
|
341
|
+
updatedAt: now
|
|
342
|
+
});
|
|
343
|
+
this.storage.appendFederationSyncLog?.({
|
|
344
|
+
bridgeId: bridge.id,
|
|
345
|
+
envelopeId: envelope.id,
|
|
346
|
+
direction: 'out',
|
|
347
|
+
messageType: envelope.t,
|
|
348
|
+
fromFederationId: bridge.localFederationId,
|
|
349
|
+
toFederationId: peering.targetFederationDid,
|
|
350
|
+
status: 'processed',
|
|
351
|
+
ts: now
|
|
352
|
+
});
|
|
353
|
+
this.emit('mesh:event:published', {
|
|
354
|
+
bridgeId: bridge.id,
|
|
355
|
+
envelopeId: envelope.id,
|
|
356
|
+
messageType: envelope.t
|
|
357
|
+
});
|
|
358
|
+
return { delivered: true };
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
362
|
+
this.storage.appendFederationSyncLog?.({
|
|
363
|
+
bridgeId: bridge.id,
|
|
364
|
+
envelopeId: envelope.id,
|
|
365
|
+
direction: 'out',
|
|
366
|
+
messageType: envelope.t,
|
|
367
|
+
fromFederationId: bridge.localFederationId,
|
|
368
|
+
toFederationId: peering.targetFederationDid,
|
|
369
|
+
status: 'failed',
|
|
370
|
+
error: message,
|
|
371
|
+
ts: Date.now()
|
|
372
|
+
});
|
|
373
|
+
return { delivered: false, reason: message };
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
getMeshStats(federationId) {
|
|
377
|
+
if (this.storage.getFederationMeshStats) {
|
|
378
|
+
return this.storage.getFederationMeshStats(federationId);
|
|
379
|
+
}
|
|
380
|
+
const bridges = this.listMeshBridges(federationId);
|
|
381
|
+
let eventsIn = 0;
|
|
382
|
+
let eventsOut = 0;
|
|
383
|
+
let lastSyncAt;
|
|
384
|
+
for (const bridge of bridges) {
|
|
385
|
+
eventsIn += bridge.eventsIn;
|
|
386
|
+
eventsOut += bridge.eventsOut;
|
|
387
|
+
if (bridge.lastSyncAt && (!lastSyncAt || bridge.lastSyncAt > lastSyncAt)) {
|
|
388
|
+
lastSyncAt = bridge.lastSyncAt;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
bridgeCount: bridges.length,
|
|
393
|
+
activeBridges: bridges.filter((bridge) => bridge.status === 'active').length,
|
|
394
|
+
eventsIn,
|
|
395
|
+
eventsOut,
|
|
396
|
+
lastSyncAt
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
// ═══════════════════════════════════════════════════════════════
|
|
400
|
+
// KNOWLEDGE ↔ CoC INTEGRATION
|
|
401
|
+
// ═══════════════════════════════════════════════════════════════
|
|
402
|
+
/**
|
|
403
|
+
* Criar CoC vinculado a knowledge space
|
|
404
|
+
*/
|
|
405
|
+
async createCoCWithKnowledge(roomId, goal, options) {
|
|
406
|
+
// Criar CoC
|
|
407
|
+
const chainId = await this.cocEngine.openChain(roomId, goal, { templateId: options?.template });
|
|
408
|
+
// Criar ou usar knowledge space
|
|
409
|
+
let knowledgeSpaceId = options?.knowledgeSpaceId;
|
|
410
|
+
if (!knowledgeSpaceId && this.config.autoCreateKnowledgeSpace) {
|
|
411
|
+
const space = await this.knowledgePool.createSpace(`CoC: ${goal.slice(0, 50)}`, `Knowledge generated from CoC ${chainId}`, 'team', 'room');
|
|
412
|
+
knowledgeSpaceId = space.id;
|
|
413
|
+
}
|
|
414
|
+
// Criar binding
|
|
415
|
+
if (knowledgeSpaceId && (options?.autoIndex ?? this.config.autoIndexCoC)) {
|
|
416
|
+
const binding = {
|
|
417
|
+
cocId: chainId,
|
|
418
|
+
knowledgeSpaceId,
|
|
419
|
+
autoIndexSteps: true,
|
|
420
|
+
indexArtifacts: true,
|
|
421
|
+
indexDecisions: true
|
|
422
|
+
};
|
|
423
|
+
this.cocKnowledgeBindings.set(chainId, binding);
|
|
424
|
+
// Salvar no storage
|
|
425
|
+
this.storage.saveCoCKnowledgeBinding?.(binding);
|
|
426
|
+
}
|
|
427
|
+
this.emit('coc:knowledge:linked', { chainId, knowledgeSpaceId });
|
|
428
|
+
return { chainId, binding: this.cocKnowledgeBindings.get(chainId) };
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Indexar step do CoC como knowledge card
|
|
432
|
+
*/
|
|
433
|
+
async indexStepAsKnowledge(chainId, stepId) {
|
|
434
|
+
const binding = this.cocKnowledgeBindings.get(chainId);
|
|
435
|
+
if (!binding || !binding.autoIndexSteps) {
|
|
436
|
+
return undefined;
|
|
437
|
+
}
|
|
438
|
+
// Obter step do CoC
|
|
439
|
+
const step = this.cocEngine.getStep(stepId);
|
|
440
|
+
if (!step)
|
|
441
|
+
return undefined;
|
|
442
|
+
// Determinar tipo de knowledge
|
|
443
|
+
let knowledgeType = 'insight';
|
|
444
|
+
if (step.kind === 'decision')
|
|
445
|
+
knowledgeType = 'decision';
|
|
446
|
+
else if (step.kind === 'synthesis')
|
|
447
|
+
knowledgeType = 'document';
|
|
448
|
+
else if (step.kind === 'task')
|
|
449
|
+
knowledgeType = 'code';
|
|
450
|
+
// Criar knowledge card
|
|
451
|
+
const card = await this.knowledgePool.createCard(binding.knowledgeSpaceId, knowledgeType, step.title, step.result_memo || 'No content', {
|
|
452
|
+
tags: ['coc-generated', step.kind, `chain-${chainId}`],
|
|
453
|
+
source: {
|
|
454
|
+
type: 'coc',
|
|
455
|
+
id: chainId,
|
|
456
|
+
context: `Step ${stepId} in CoC ${chainId}`
|
|
457
|
+
},
|
|
458
|
+
privacy: 'federation'
|
|
459
|
+
});
|
|
460
|
+
// Indexar artifacts se configurado
|
|
461
|
+
if (binding.indexArtifacts && step.artifacts) {
|
|
462
|
+
for (const artifactId of step.artifacts) {
|
|
463
|
+
await this.linkArtifactToKnowledge(artifactId, card.id);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
this.emit('coc:step:indexed', { chainId, stepId, cardId: card.id });
|
|
467
|
+
return card;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Indexar decisão do CoC
|
|
471
|
+
*/
|
|
472
|
+
async indexDecision(chainId, decision, rationale) {
|
|
473
|
+
const binding = this.cocKnowledgeBindings.get(chainId);
|
|
474
|
+
if (!binding || !binding.indexDecisions) {
|
|
475
|
+
return undefined;
|
|
476
|
+
}
|
|
477
|
+
const card = await this.knowledgePool.createCard(binding.knowledgeSpaceId, 'decision', `Decision: ${decision.slice(0, 100)}`, rationale, {
|
|
478
|
+
tags: ['coc-decision', `chain-${chainId}`],
|
|
479
|
+
source: { type: 'coc', id: chainId },
|
|
480
|
+
privacy: 'federation'
|
|
481
|
+
});
|
|
482
|
+
return card;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Linkar artifact a knowledge card
|
|
486
|
+
*/
|
|
487
|
+
async linkArtifactToKnowledge(artifactId, knowledgeCardId) {
|
|
488
|
+
// Criar link no knowledge graph
|
|
489
|
+
await this.knowledgePool.linkCards(knowledgeCardId, artifactId, // Artifact como pseudo-card
|
|
490
|
+
'depends-on', 0.9);
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Query knowledge relacionado a CoC
|
|
494
|
+
*/
|
|
495
|
+
async queryKnowledgeForCoC(chainId, query) {
|
|
496
|
+
const binding = this.cocKnowledgeBindings.get(chainId);
|
|
497
|
+
if (!binding) {
|
|
498
|
+
// Buscar em todos os spaces
|
|
499
|
+
return this.knowledgePool.queryCards({ query });
|
|
500
|
+
}
|
|
501
|
+
return this.knowledgePool.queryCards({
|
|
502
|
+
spaceId: binding.knowledgeSpaceId,
|
|
503
|
+
query
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Obter contexto de conhecimento para CoC
|
|
508
|
+
*/
|
|
509
|
+
async getKnowledgeContextForCoC(chainId) {
|
|
510
|
+
const binding = this.cocKnowledgeBindings.get(chainId);
|
|
511
|
+
if (!binding)
|
|
512
|
+
return '';
|
|
513
|
+
// Obter collective unconscious do space
|
|
514
|
+
const cu = this.knowledgePool.getCollectiveUnconscious(binding.knowledgeSpaceId);
|
|
515
|
+
if (!cu)
|
|
516
|
+
return '';
|
|
517
|
+
return this.knowledgePool.getSharedContext(binding.knowledgeSpaceId);
|
|
518
|
+
}
|
|
519
|
+
// ═══════════════════════════════════════════════════════════════
|
|
520
|
+
// SKILLS ↔ RUNTIME INTEGRATION
|
|
521
|
+
// ═══════════════════════════════════════════════════════════════
|
|
522
|
+
/**
|
|
523
|
+
* Executar skill com acesso a todos os módulos
|
|
524
|
+
*/
|
|
525
|
+
async executeIntegratedSkill(skillId, inputs, context) {
|
|
526
|
+
// Criar contexto de segurança
|
|
527
|
+
const securityContext = {
|
|
528
|
+
identity: this.identity,
|
|
529
|
+
permissions: [], // Será preenchido baseado na skill
|
|
530
|
+
sessionId: `session_${Date.now()}`,
|
|
531
|
+
mfaVerified: false,
|
|
532
|
+
reputation: 0,
|
|
533
|
+
trustTier: 'bronze'
|
|
534
|
+
};
|
|
535
|
+
// Verificar permissões
|
|
536
|
+
const resource = `skill:${skillId}`;
|
|
537
|
+
const allowed = await this.securityManager.checkAccess(securityContext, resource, 'execute');
|
|
538
|
+
if (!allowed) {
|
|
539
|
+
throw new Error('Permission denied to execute skill');
|
|
540
|
+
}
|
|
541
|
+
// Enriquecer inputs com contexto
|
|
542
|
+
const enrichedInputs = await this.enrichSkillInputs(inputs, context);
|
|
543
|
+
// Executar skill
|
|
544
|
+
const result = await this.skillsEngine.executeSkill(skillId, enrichedInputs, context ? {
|
|
545
|
+
room: context.roomId,
|
|
546
|
+
federation: context.federationId
|
|
547
|
+
} : undefined);
|
|
548
|
+
// Auditar
|
|
549
|
+
await this.securityManager.audit.log({
|
|
550
|
+
type: 'action',
|
|
551
|
+
severity: 'info',
|
|
552
|
+
actor: this.identity.did,
|
|
553
|
+
resource,
|
|
554
|
+
action: 'execute',
|
|
555
|
+
result: result.status === 'completed' ? 'success' : 'failure',
|
|
556
|
+
details: { skillId, inputs: Object.keys(inputs) }
|
|
557
|
+
});
|
|
558
|
+
return result;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Enriquecer inputs de skill com contexto do sistema
|
|
562
|
+
*/
|
|
563
|
+
async enrichSkillInputs(inputs, context) {
|
|
564
|
+
const enriched = { ...inputs };
|
|
565
|
+
// Adicionar contexto compartilhado se room especificada
|
|
566
|
+
if (context?.roomId && inputs.use_shared_context !== false) {
|
|
567
|
+
const federationRoom = this.findFederationForRoom(context.roomId);
|
|
568
|
+
if (federationRoom) {
|
|
569
|
+
const knowledgeContext = await this.knowledgePool.getSharedContext(federationRoom.roomId);
|
|
570
|
+
enriched._sharedContext = knowledgeContext;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
// Adicionar info da federação
|
|
574
|
+
if (context?.federationId) {
|
|
575
|
+
const federation = this.federationEngine.getFederation(context.federationId);
|
|
576
|
+
if (federation) {
|
|
577
|
+
enriched._federation = {
|
|
578
|
+
name: federation.name,
|
|
579
|
+
policies: federation.policies.map(p => p.name)
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return enriched;
|
|
584
|
+
}
|
|
585
|
+
// ═══════════════════════════════════════════════════════════════
|
|
586
|
+
// SECURITY INTEGRATION (todos os módulos)
|
|
587
|
+
// ═══════════════════════════════════════════════════════════════
|
|
588
|
+
/**
|
|
589
|
+
* Processar envelope com segurança completa
|
|
590
|
+
*/
|
|
591
|
+
async processSecureEnvelope(envelope) {
|
|
592
|
+
// 1. Verificar ameaças
|
|
593
|
+
const threatCheck = this.securityManager.threats.analyzeEnvelope(envelope);
|
|
594
|
+
if (threatCheck.threat && threatCheck.severity === 'critical') {
|
|
595
|
+
return { allowed: false, reason: 'Threat detected' };
|
|
596
|
+
}
|
|
597
|
+
// 2. Verificar ACL da federação/room
|
|
598
|
+
if (this.config.enforceFederationACLs) {
|
|
599
|
+
const federationRoom = this.findFederationForRoom(envelope.room);
|
|
600
|
+
if (federationRoom) {
|
|
601
|
+
const federation = this.federationEngine.getFederation(federationRoom.federationId);
|
|
602
|
+
if (federation) {
|
|
603
|
+
const check = this.federationEngine.checkPolicy(federation, 'message:send', envelope.from.did);
|
|
604
|
+
if (!check.allowed) {
|
|
605
|
+
return { allowed: false, reason: check.reason };
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
// 3. Processar com security manager
|
|
611
|
+
return this.securityManager.processIncoming(envelope);
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Comprimir mensagem se configurado
|
|
615
|
+
*/
|
|
616
|
+
async compressMessageIfNeeded(data) {
|
|
617
|
+
if (!this.config.autoCompressMessages || data.length < 1024) {
|
|
618
|
+
return { data, compressed: false };
|
|
619
|
+
}
|
|
620
|
+
// Usar compressor do módulo de compression
|
|
621
|
+
const { MessageCompressor } = await import('./compression.js');
|
|
622
|
+
const compressor = new MessageCompressor({ algorithm: 'zstd' });
|
|
623
|
+
const compressed = await compressor.compress(data);
|
|
624
|
+
const stats = compressor.getCompressionStats(data.length, compressed.length);
|
|
625
|
+
if (stats.savingsPercent > 20) {
|
|
626
|
+
return { data: compressed, compressed: true, algorithm: 'zstd' };
|
|
627
|
+
}
|
|
628
|
+
return { data, compressed: false };
|
|
629
|
+
}
|
|
630
|
+
// ═══════════════════════════════════════════════════════════════
|
|
631
|
+
// HOOKS SETUP
|
|
632
|
+
// ═══════════════════════════════════════════════════════════════
|
|
633
|
+
setupHooks() {
|
|
634
|
+
// Hook: CoC step completed → Indexar como knowledge
|
|
635
|
+
this.cocEngine.on('step:submitted', async (chainId, stepId) => {
|
|
636
|
+
if (this.config.autoIndexCoC) {
|
|
637
|
+
try {
|
|
638
|
+
await this.indexStepAsKnowledge(chainId, stepId);
|
|
639
|
+
}
|
|
640
|
+
catch (err) {
|
|
641
|
+
console.error('Failed to index step:', err);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
// Hook: CoC completed → Indexar decisões
|
|
646
|
+
this.cocEngine.on('chain:completed', async (chainId) => {
|
|
647
|
+
const binding = this.cocKnowledgeBindings.get(chainId);
|
|
648
|
+
if (binding?.indexDecisions) {
|
|
649
|
+
const chain = this.cocEngine.getChain(chainId);
|
|
650
|
+
if (chain?.final_report) {
|
|
651
|
+
await this.indexDecision(chainId, 'CoC Completed', chain.final_report);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
// Hook: Knowledge criado → Notificar room
|
|
656
|
+
this.knowledgePool.on('card:created', async (card) => {
|
|
657
|
+
// Notificar room se o card for público/federation
|
|
658
|
+
if (card.privacy !== 'private') {
|
|
659
|
+
this.emit('knowledge:shared', card);
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
// Hook: Federation member joined → Adicionar às rooms
|
|
663
|
+
this.federationEngine.on('federation:member:joined', async (federationId, member) => {
|
|
664
|
+
const rooms = this.getFederationRooms(federationId);
|
|
665
|
+
for (const room of rooms) {
|
|
666
|
+
if (!room.requiresInvitation) {
|
|
667
|
+
this.storage.addRoomMember(room.roomId, member.did, member.displayName);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
// Hook: Mesh federation events routed by RoomManager
|
|
672
|
+
this.roomManager.on('federation:event', async (_roomId, envelope) => {
|
|
673
|
+
try {
|
|
674
|
+
await this.handleMeshEnvelope(envelope);
|
|
675
|
+
}
|
|
676
|
+
catch (err) {
|
|
677
|
+
console.warn('[integration] Failed to handle mesh envelope:', err.message);
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
this.roomManager.on('persona:event', async (roomId, envelope) => {
|
|
681
|
+
try {
|
|
682
|
+
await this.handlePersonaEnvelope(roomId, envelope);
|
|
683
|
+
}
|
|
684
|
+
catch (err) {
|
|
685
|
+
console.warn('[integration] Failed to handle persona envelope:', err.message);
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
// ═══════════════════════════════════════════════════════════════
|
|
690
|
+
// UTILS
|
|
691
|
+
// ═══════════════════════════════════════════════════════════════
|
|
692
|
+
loadFromStorage() {
|
|
693
|
+
// Federation rooms
|
|
694
|
+
const federations = this.storage.getFederations?.() || [];
|
|
695
|
+
for (const federation of federations) {
|
|
696
|
+
const rooms = this.storage.getFederationRooms?.(federation.id) || [];
|
|
697
|
+
if (rooms.length > 0) {
|
|
698
|
+
this.federationRooms.set(federation.id, rooms);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
// CoC knowledge bindings
|
|
702
|
+
try {
|
|
703
|
+
const bindings = this.storage.query('SELECT coc_id, knowledge_space_id, auto_index_steps, index_artifacts, index_decisions FROM coc_knowledge_bindings');
|
|
704
|
+
for (const row of bindings) {
|
|
705
|
+
this.cocKnowledgeBindings.set(row.coc_id, {
|
|
706
|
+
cocId: row.coc_id,
|
|
707
|
+
knowledgeSpaceId: row.knowledge_space_id,
|
|
708
|
+
autoIndexSteps: !!row.auto_index_steps,
|
|
709
|
+
indexArtifacts: !!row.index_artifacts,
|
|
710
|
+
indexDecisions: !!row.index_decisions
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
catch {
|
|
715
|
+
// Optional table may not exist in early schemas
|
|
716
|
+
}
|
|
717
|
+
// Mesh bridges
|
|
718
|
+
const bridges = this.storage.listFederationBridges?.() || [];
|
|
719
|
+
for (const row of bridges) {
|
|
720
|
+
const bridge = {
|
|
721
|
+
id: row.bridgeId,
|
|
722
|
+
peeringId: row.peeringId,
|
|
723
|
+
localFederationId: row.localFederationId,
|
|
724
|
+
localRoomId: row.localRoomId,
|
|
725
|
+
remoteRoomId: row.remoteRoomId,
|
|
726
|
+
rules: this.mergeBridgeRules(undefined, row.rules),
|
|
727
|
+
status: row.status,
|
|
728
|
+
eventsIn: row.eventsIn,
|
|
729
|
+
eventsOut: row.eventsOut,
|
|
730
|
+
createdAt: row.createdAt,
|
|
731
|
+
updatedAt: row.updatedAt,
|
|
732
|
+
lastSyncAt: row.lastSyncAt
|
|
733
|
+
};
|
|
734
|
+
this.meshBridges.set(bridge.id, bridge);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
persistMeshBridge(bridge) {
|
|
738
|
+
this.storage.saveFederationBridge?.({
|
|
739
|
+
bridgeId: bridge.id,
|
|
740
|
+
peeringId: bridge.peeringId,
|
|
741
|
+
localFederationId: bridge.localFederationId,
|
|
742
|
+
localRoomId: bridge.localRoomId,
|
|
743
|
+
remoteRoomId: bridge.remoteRoomId,
|
|
744
|
+
rules: bridge.rules,
|
|
745
|
+
status: bridge.status,
|
|
746
|
+
eventsIn: bridge.eventsIn,
|
|
747
|
+
eventsOut: bridge.eventsOut,
|
|
748
|
+
lastSyncAt: bridge.lastSyncAt,
|
|
749
|
+
createdAt: bridge.createdAt,
|
|
750
|
+
updatedAt: bridge.updatedAt
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
mergeBridgeRules(policy, rules) {
|
|
754
|
+
const allowedTypes = rules?.allowedTypes?.length
|
|
755
|
+
? rules.allowedTypes
|
|
756
|
+
: policy?.allowedTypes?.length
|
|
757
|
+
? policy.allowedTypes
|
|
758
|
+
: ['chat.msg', 'coc.open', 'coc.plan', 'coc.submit', 'federation.bridge.sync', 'persona.sync.delta', 'persona.capability.revoke'];
|
|
759
|
+
const maxRatePerMinute = Number(rules?.maxRatePerMinute ?? policy?.maxRatePerMinute ?? 200);
|
|
760
|
+
return {
|
|
761
|
+
allowedTypes,
|
|
762
|
+
maxRatePerMinute: Number.isFinite(maxRatePerMinute) && maxRatePerMinute > 0
|
|
763
|
+
? Math.floor(maxRatePerMinute)
|
|
764
|
+
: 200,
|
|
765
|
+
privacyMode: rules?.privacyMode || policy?.privacyMode || 'summary'
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
isMessageTypeAllowed(allowed, messageType) {
|
|
769
|
+
return allowed.some((pattern) => this.matchesMessageTypePattern(pattern, messageType));
|
|
770
|
+
}
|
|
771
|
+
matchesMessageTypePattern(pattern, messageType) {
|
|
772
|
+
if (pattern === '*')
|
|
773
|
+
return true;
|
|
774
|
+
if (pattern.endsWith('*')) {
|
|
775
|
+
return messageType.startsWith(pattern.slice(0, -1));
|
|
776
|
+
}
|
|
777
|
+
return pattern === messageType;
|
|
778
|
+
}
|
|
779
|
+
consumeBridgeRateLimit(bridge) {
|
|
780
|
+
const now = Date.now();
|
|
781
|
+
const current = this.bridgeRateLimits.get(bridge.id);
|
|
782
|
+
if (!current || now - current.windowStartedAt >= 60_000) {
|
|
783
|
+
this.bridgeRateLimits.set(bridge.id, { windowStartedAt: now, count: 1 });
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
786
|
+
if (current.count >= bridge.rules.maxRatePerMinute) {
|
|
787
|
+
return false;
|
|
788
|
+
}
|
|
789
|
+
current.count += 1;
|
|
790
|
+
this.bridgeRateLimits.set(bridge.id, current);
|
|
791
|
+
return true;
|
|
792
|
+
}
|
|
793
|
+
applyPrivacyMode(envelope, mode) {
|
|
794
|
+
if (mode === 'full') {
|
|
795
|
+
return envelope;
|
|
796
|
+
}
|
|
797
|
+
if (mode === 'metadata-only') {
|
|
798
|
+
return {
|
|
799
|
+
...envelope,
|
|
800
|
+
body: {
|
|
801
|
+
redacted: true,
|
|
802
|
+
original_type: envelope.t,
|
|
803
|
+
original_id: envelope.id,
|
|
804
|
+
original_ts: envelope.ts
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
const body = envelope.body;
|
|
809
|
+
if (envelope.t === 'chat.msg') {
|
|
810
|
+
const text = typeof body.text === 'string' ? body.text : '';
|
|
811
|
+
return {
|
|
812
|
+
...envelope,
|
|
813
|
+
body: {
|
|
814
|
+
summary: text.length > 180 ? `${text.slice(0, 180)}...` : text,
|
|
815
|
+
has_attachments: Array.isArray(body.attachments) && body.attachments.length > 0
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
if (envelope.t.startsWith('coc.')) {
|
|
820
|
+
return {
|
|
821
|
+
...envelope,
|
|
822
|
+
body: {
|
|
823
|
+
chain_id: body.chain_id,
|
|
824
|
+
step_id: body.step_id,
|
|
825
|
+
status: body.status,
|
|
826
|
+
kind: body.kind
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
return envelope;
|
|
831
|
+
}
|
|
832
|
+
async handleMeshEnvelope(envelope) {
|
|
833
|
+
if (envelope.t === 'federation.peer.revoke') {
|
|
834
|
+
const body = envelope.body;
|
|
835
|
+
if (body.peering_id) {
|
|
836
|
+
for (const bridge of this.meshBridges.values()) {
|
|
837
|
+
if (bridge.peeringId === body.peering_id && bridge.status === 'active') {
|
|
838
|
+
await this.closeMeshBridge(bridge.id);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
if (envelope.t !== 'federation.bridge.sync') {
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
const body = envelope.body;
|
|
848
|
+
if (!body.bridge_id) {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
const bridge = this.meshBridges.get(body.bridge_id);
|
|
852
|
+
if (!bridge || bridge.status !== 'active') {
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
const innerEnvelope = body.envelope || envelope;
|
|
856
|
+
const envelopeId = innerEnvelope.id || body.cursor || envelope.id;
|
|
857
|
+
const messageType = innerEnvelope.t || 'federation.bridge.sync';
|
|
858
|
+
if (this.storage.hasFederationSyncLog?.(bridge.id, envelopeId, 'in')) {
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
if (!this.isMessageTypeAllowed(bridge.rules.allowedTypes, messageType)) {
|
|
862
|
+
this.storage.appendFederationSyncLog?.({
|
|
863
|
+
bridgeId: bridge.id,
|
|
864
|
+
envelopeId,
|
|
865
|
+
direction: 'in',
|
|
866
|
+
messageType,
|
|
867
|
+
fromFederationId: body.source_federation_id,
|
|
868
|
+
toFederationId: bridge.localFederationId,
|
|
869
|
+
status: 'rejected',
|
|
870
|
+
error: `type ${messageType} blocked by mesh policy`,
|
|
871
|
+
ts: Date.now()
|
|
872
|
+
});
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
const now = Date.now();
|
|
876
|
+
bridge.eventsIn += 1;
|
|
877
|
+
bridge.lastSyncAt = now;
|
|
878
|
+
bridge.updatedAt = now;
|
|
879
|
+
this.meshBridges.set(bridge.id, bridge);
|
|
880
|
+
this.persistMeshBridge(bridge);
|
|
881
|
+
this.storage.incrementFederationBridgeCounters?.(bridge.id, 'in', 1, now);
|
|
882
|
+
this.storage.saveFederationSyncCursor?.({
|
|
883
|
+
bridgeId: bridge.id,
|
|
884
|
+
direction: 'in',
|
|
885
|
+
cursorId: envelopeId,
|
|
886
|
+
updatedAt: now
|
|
887
|
+
});
|
|
888
|
+
this.storage.appendFederationSyncLog?.({
|
|
889
|
+
bridgeId: bridge.id,
|
|
890
|
+
envelopeId,
|
|
891
|
+
direction: 'in',
|
|
892
|
+
messageType,
|
|
893
|
+
fromFederationId: body.source_federation_id,
|
|
894
|
+
toFederationId: bridge.localFederationId,
|
|
895
|
+
status: 'processed',
|
|
896
|
+
ts: now
|
|
897
|
+
});
|
|
898
|
+
this.emit('mesh:event:received', {
|
|
899
|
+
bridgeId: bridge.id,
|
|
900
|
+
envelope: innerEnvelope,
|
|
901
|
+
messageType
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
async handlePersonaEnvelope(roomId, envelope) {
|
|
905
|
+
if (!this.personaVault)
|
|
906
|
+
return;
|
|
907
|
+
if (envelope.t === 'persona.sync.delta') {
|
|
908
|
+
const body = envelope.body;
|
|
909
|
+
const result = await this.personaVault.applySyncDelta(body);
|
|
910
|
+
this.emit('persona:sync:applied', {
|
|
911
|
+
roomId,
|
|
912
|
+
deltaId: body.id,
|
|
913
|
+
applied: result.applied,
|
|
914
|
+
ignored: result.ignored
|
|
915
|
+
});
|
|
916
|
+
await this.roomManager.sendMessage(roomId, {
|
|
917
|
+
delta_id: body.id,
|
|
918
|
+
vault_id: body.vaultId,
|
|
919
|
+
applied: result.applied,
|
|
920
|
+
ignored: result.ignored,
|
|
921
|
+
cursor: result.cursor,
|
|
922
|
+
need_snapshot: result.applied === 0 && result.ignored > 0
|
|
923
|
+
}, 'persona.sync.ack');
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
if (envelope.t === 'persona.preference.update') {
|
|
927
|
+
const body = envelope.body;
|
|
928
|
+
const fallbackVaultId = this.storage.getPersonaVaults?.(this.identity.did)?.[0]?.id;
|
|
929
|
+
const vaultId = body.vault_id || body.vaultId || fallbackVaultId;
|
|
930
|
+
if (!vaultId)
|
|
931
|
+
return;
|
|
932
|
+
const node = body.node ||
|
|
933
|
+
(body.key
|
|
934
|
+
? {
|
|
935
|
+
id: body.node_id || `pref_${envelope.id}`,
|
|
936
|
+
vaultId,
|
|
937
|
+
domain: body.domain || 'preferences',
|
|
938
|
+
type: 'preference',
|
|
939
|
+
title: body.key,
|
|
940
|
+
content: JSON.stringify(body.value),
|
|
941
|
+
tags: body.tags || ['preference'],
|
|
942
|
+
confidence: body.confidence ?? 0.9,
|
|
943
|
+
source: { type: 'sync', actorDid: envelope.from.did },
|
|
944
|
+
metadata: { key: body.key, value: body.value },
|
|
945
|
+
createdAt: envelope.ts,
|
|
946
|
+
updatedAt: envelope.ts,
|
|
947
|
+
}
|
|
948
|
+
: undefined);
|
|
949
|
+
if (!node)
|
|
950
|
+
return;
|
|
951
|
+
await this.personaVault.applySyncDelta({
|
|
952
|
+
id: `delta_${envelope.id}`,
|
|
953
|
+
vaultId,
|
|
954
|
+
fromDid: envelope.from.did,
|
|
955
|
+
operations: [{ type: 'node_upsert', payload: node }],
|
|
956
|
+
vectorClock: { [envelope.from.did]: 1 },
|
|
957
|
+
createdAt: envelope.ts,
|
|
958
|
+
});
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
if (envelope.t === 'persona.sync.ack') {
|
|
962
|
+
const body = envelope.body;
|
|
963
|
+
if (body.need_snapshot && body.vault_id) {
|
|
964
|
+
const snapshot = await this.personaVault.exportSubgraph({
|
|
965
|
+
vaultId: body.vault_id,
|
|
966
|
+
includeNeighbors: true,
|
|
967
|
+
});
|
|
968
|
+
const delta = this.personaVault.buildSyncDelta({
|
|
969
|
+
vaultId: snapshot.vaultId,
|
|
970
|
+
operations: snapshot.nodes.map((node) => ({
|
|
971
|
+
type: 'node_upsert',
|
|
972
|
+
payload: node,
|
|
973
|
+
})),
|
|
974
|
+
cursor: body.cursor,
|
|
975
|
+
});
|
|
976
|
+
await this.roomManager.sendMessage(roomId, delta, 'persona.sync.delta');
|
|
977
|
+
}
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
if (envelope.t === 'persona.capability.revoke') {
|
|
981
|
+
const body = envelope.body;
|
|
982
|
+
if (body.token_id) {
|
|
983
|
+
await this.personaVault.revokeCapability(body.token_id, body.reason || 'remote-revoke');
|
|
984
|
+
}
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (envelope.t === 'persona.capability.attenuate') {
|
|
988
|
+
const body = envelope.body;
|
|
989
|
+
if (body.token_id) {
|
|
990
|
+
await this.personaVault.attenuateCapability({
|
|
991
|
+
tokenId: body.token_id,
|
|
992
|
+
caveatsPatch: (body.caveats_patch || {}),
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (envelope.t === 'persona.memory.upsert') {
|
|
998
|
+
const body = envelope.body;
|
|
999
|
+
await this.personaVault.applySyncDelta({
|
|
1000
|
+
id: `delta_${envelope.id}`,
|
|
1001
|
+
vaultId: body.vaultId,
|
|
1002
|
+
fromDid: envelope.from.did,
|
|
1003
|
+
operations: [{ type: 'node_upsert', payload: body.node }],
|
|
1004
|
+
vectorClock: body.vectorClock || { [envelope.from.did]: 1 },
|
|
1005
|
+
createdAt: envelope.ts,
|
|
1006
|
+
});
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
if (envelope.t === 'persona.claim.upsert') {
|
|
1010
|
+
const body = envelope.body;
|
|
1011
|
+
await this.personaVault.applySyncDelta({
|
|
1012
|
+
id: `delta_${envelope.id}`,
|
|
1013
|
+
vaultId: body.vaultId,
|
|
1014
|
+
fromDid: envelope.from.did,
|
|
1015
|
+
operations: [{ type: 'claim_upsert', payload: body.claim }],
|
|
1016
|
+
vectorClock: body.vectorClock || { [envelope.from.did]: 1 },
|
|
1017
|
+
createdAt: envelope.ts,
|
|
1018
|
+
});
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
if (envelope.t === 'persona.claim.revoke') {
|
|
1022
|
+
const body = envelope.body;
|
|
1023
|
+
await this.personaVault.applySyncDelta({
|
|
1024
|
+
id: `delta_${envelope.id}`,
|
|
1025
|
+
vaultId: body.vaultId,
|
|
1026
|
+
fromDid: envelope.from.did,
|
|
1027
|
+
operations: [{ type: 'claim_revoke', payload: { claimId: body.claimId } }],
|
|
1028
|
+
vectorClock: body.vectorClock || { [envelope.from.did]: 1 },
|
|
1029
|
+
createdAt: envelope.ts,
|
|
1030
|
+
});
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
if (envelope.t === 'persona.zkp.proof') {
|
|
1034
|
+
const body = envelope.body;
|
|
1035
|
+
await this.personaVault.applySyncDelta({
|
|
1036
|
+
id: `delta_${envelope.id}`,
|
|
1037
|
+
vaultId: body.vaultId,
|
|
1038
|
+
fromDid: envelope.from.did,
|
|
1039
|
+
operations: [{ type: 'zkp_proof_upsert', payload: body.proof }],
|
|
1040
|
+
vectorClock: body.vectorClock || { [envelope.from.did]: 1 },
|
|
1041
|
+
createdAt: envelope.ts,
|
|
1042
|
+
});
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
if (envelope.t === 'persona.edge.upsert') {
|
|
1046
|
+
const body = envelope.body;
|
|
1047
|
+
await this.personaVault.applySyncDelta({
|
|
1048
|
+
id: `delta_${envelope.id}`,
|
|
1049
|
+
vaultId: body.vaultId,
|
|
1050
|
+
fromDid: envelope.from.did,
|
|
1051
|
+
operations: [{ type: 'edge_upsert', payload: body.edge }],
|
|
1052
|
+
vectorClock: body.vectorClock || { [envelope.from.did]: 1 },
|
|
1053
|
+
createdAt: envelope.ts,
|
|
1054
|
+
});
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
if (envelope.t === 'persona.memory.delete') {
|
|
1058
|
+
const body = envelope.body;
|
|
1059
|
+
await this.personaVault.applySyncDelta({
|
|
1060
|
+
id: `delta_${envelope.id}`,
|
|
1061
|
+
vaultId: body.vaultId,
|
|
1062
|
+
fromDid: envelope.from.did,
|
|
1063
|
+
operations: [{ type: 'node_delete', payload: { nodeId: body.nodeId } }],
|
|
1064
|
+
vectorClock: body.vectorClock || { [envelope.from.did]: 1 },
|
|
1065
|
+
createdAt: envelope.ts,
|
|
1066
|
+
});
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Obter estatísticas de integração
|
|
1072
|
+
*/
|
|
1073
|
+
getStats() {
|
|
1074
|
+
let totalRooms = 0;
|
|
1075
|
+
for (const rooms of this.federationRooms.values()) {
|
|
1076
|
+
totalRooms += rooms.length;
|
|
1077
|
+
}
|
|
1078
|
+
return {
|
|
1079
|
+
federationRooms: totalRooms,
|
|
1080
|
+
cocKnowledgeBindings: this.cocKnowledgeBindings.size,
|
|
1081
|
+
indexedSteps: 0 // TODO: contar do storage
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1086
|
+
// DECORATORS (para facilitar uso)
|
|
1087
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1088
|
+
/**
|
|
1089
|
+
* Decorator: Aplicar ACL da federação em método
|
|
1090
|
+
*/
|
|
1091
|
+
export function requireFederationPermission(resource, action) {
|
|
1092
|
+
return function (target, propertyKey, descriptor) {
|
|
1093
|
+
const originalMethod = descriptor.value;
|
|
1094
|
+
descriptor.value = async function (...args) {
|
|
1095
|
+
// Verificação de permissão seria feita aqui
|
|
1096
|
+
// usando o integrationEngine da instância
|
|
1097
|
+
return originalMethod.apply(this, args);
|
|
1098
|
+
};
|
|
1099
|
+
return descriptor;
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
// Types already exported via 'export interface'
|
|
1103
|
+
export { IntegrationEngine };
|
|
1104
|
+
export default IntegrationEngine;
|
|
1105
|
+
//# sourceMappingURL=integration.js.map
|