society-protocol 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/adapters.d.ts +101 -0
  4. package/dist/adapters.d.ts.map +1 -0
  5. package/dist/adapters.js +764 -0
  6. package/dist/adapters.js.map +1 -0
  7. package/dist/agents-md.d.ts +59 -0
  8. package/dist/agents-md.d.ts.map +1 -0
  9. package/dist/agents-md.js +204 -0
  10. package/dist/agents-md.js.map +1 -0
  11. package/dist/autoconfig.d.ts +137 -0
  12. package/dist/autoconfig.d.ts.map +1 -0
  13. package/dist/autoconfig.js +452 -0
  14. package/dist/autoconfig.js.map +1 -0
  15. package/dist/bootstrap.d.ts +68 -0
  16. package/dist/bootstrap.d.ts.map +1 -0
  17. package/dist/bootstrap.js +304 -0
  18. package/dist/bootstrap.js.map +1 -0
  19. package/dist/bridges/a2a-bridge.d.ts +156 -0
  20. package/dist/bridges/a2a-bridge.d.ts.map +1 -0
  21. package/dist/bridges/a2a-bridge.js +337 -0
  22. package/dist/bridges/a2a-bridge.js.map +1 -0
  23. package/dist/bridges/mcp-bridge.d.ts +87 -0
  24. package/dist/bridges/mcp-bridge.d.ts.map +1 -0
  25. package/dist/bridges/mcp-bridge.js +332 -0
  26. package/dist/bridges/mcp-bridge.js.map +1 -0
  27. package/dist/cache.d.ts +130 -0
  28. package/dist/cache.d.ts.map +1 -0
  29. package/dist/cache.js +257 -0
  30. package/dist/cache.js.map +1 -0
  31. package/dist/capsules.d.ts +23 -0
  32. package/dist/capsules.d.ts.map +1 -0
  33. package/dist/capsules.js +75 -0
  34. package/dist/capsules.js.map +1 -0
  35. package/dist/cli/commands.d.ts +8 -0
  36. package/dist/cli/commands.d.ts.map +1 -0
  37. package/dist/cli/commands.js +263 -0
  38. package/dist/cli/commands.js.map +1 -0
  39. package/dist/coc.d.ts +121 -0
  40. package/dist/coc.d.ts.map +1 -0
  41. package/dist/coc.js +629 -0
  42. package/dist/coc.js.map +1 -0
  43. package/dist/coc.test.d.ts +2 -0
  44. package/dist/coc.test.d.ts.map +1 -0
  45. package/dist/coc.test.js +80 -0
  46. package/dist/coc.test.js.map +1 -0
  47. package/dist/compression.d.ts +125 -0
  48. package/dist/compression.d.ts.map +1 -0
  49. package/dist/compression.js +573 -0
  50. package/dist/compression.js.map +1 -0
  51. package/dist/cot-stream.d.ts +220 -0
  52. package/dist/cot-stream.d.ts.map +1 -0
  53. package/dist/cot-stream.js +673 -0
  54. package/dist/cot-stream.js.map +1 -0
  55. package/dist/crypto-wasm.d.ts +100 -0
  56. package/dist/crypto-wasm.d.ts.map +1 -0
  57. package/dist/crypto-wasm.js +229 -0
  58. package/dist/crypto-wasm.js.map +1 -0
  59. package/dist/federation.d.ts +200 -0
  60. package/dist/federation.d.ts.map +1 -0
  61. package/dist/federation.js +691 -0
  62. package/dist/federation.js.map +1 -0
  63. package/dist/federation.test.d.ts +2 -0
  64. package/dist/federation.test.d.ts.map +1 -0
  65. package/dist/federation.test.js +71 -0
  66. package/dist/federation.test.js.map +1 -0
  67. package/dist/gateway/capability-router.d.ts +77 -0
  68. package/dist/gateway/capability-router.d.ts.map +1 -0
  69. package/dist/gateway/capability-router.js +222 -0
  70. package/dist/gateway/capability-router.js.map +1 -0
  71. package/dist/gateway/demand-spawner.d.ts +155 -0
  72. package/dist/gateway/demand-spawner.d.ts.map +1 -0
  73. package/dist/gateway/demand-spawner.js +426 -0
  74. package/dist/gateway/demand-spawner.js.map +1 -0
  75. package/dist/identity.d.ts +46 -0
  76. package/dist/identity.d.ts.map +1 -0
  77. package/dist/identity.js +102 -0
  78. package/dist/identity.js.map +1 -0
  79. package/dist/identity.test.d.ts +2 -0
  80. package/dist/identity.test.d.ts.map +1 -0
  81. package/dist/identity.test.js +45 -0
  82. package/dist/identity.test.js.map +1 -0
  83. package/dist/index.d.ts +36 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +1572 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/integration.d.ts +210 -0
  88. package/dist/integration.d.ts.map +1 -0
  89. package/dist/integration.js +1105 -0
  90. package/dist/integration.js.map +1 -0
  91. package/dist/integration.test.d.ts +2 -0
  92. package/dist/integration.test.d.ts.map +1 -0
  93. package/dist/integration.test.js +155 -0
  94. package/dist/integration.test.js.map +1 -0
  95. package/dist/knowledge.d.ts +219 -0
  96. package/dist/knowledge.d.ts.map +1 -0
  97. package/dist/knowledge.js +543 -0
  98. package/dist/knowledge.js.map +1 -0
  99. package/dist/knowledge.test.d.ts +2 -0
  100. package/dist/knowledge.test.d.ts.map +1 -0
  101. package/dist/knowledge.test.js +72 -0
  102. package/dist/knowledge.test.js.map +1 -0
  103. package/dist/latent-space.d.ts +178 -0
  104. package/dist/latent-space.d.ts.map +1 -0
  105. package/dist/latent-space.js +385 -0
  106. package/dist/latent-space.js.map +1 -0
  107. package/dist/lib.d.ts +30 -0
  108. package/dist/lib.d.ts.map +1 -0
  109. package/dist/lib.js +30 -0
  110. package/dist/lib.js.map +1 -0
  111. package/dist/mcp/server.d.ts +74 -0
  112. package/dist/mcp/server.d.ts.map +1 -0
  113. package/dist/mcp/server.js +1392 -0
  114. package/dist/mcp/server.js.map +1 -0
  115. package/dist/metrics.d.ts +98 -0
  116. package/dist/metrics.d.ts.map +1 -0
  117. package/dist/metrics.js +222 -0
  118. package/dist/metrics.js.map +1 -0
  119. package/dist/p2p.d.ts +87 -0
  120. package/dist/p2p.d.ts.map +1 -0
  121. package/dist/p2p.js +606 -0
  122. package/dist/p2p.js.map +1 -0
  123. package/dist/persona/capabilities.d.ts +17 -0
  124. package/dist/persona/capabilities.d.ts.map +1 -0
  125. package/dist/persona/capabilities.js +224 -0
  126. package/dist/persona/capabilities.js.map +1 -0
  127. package/dist/persona/domains.d.ts +22 -0
  128. package/dist/persona/domains.d.ts.map +1 -0
  129. package/dist/persona/domains.js +176 -0
  130. package/dist/persona/domains.js.map +1 -0
  131. package/dist/persona/embeddings.d.ts +40 -0
  132. package/dist/persona/embeddings.d.ts.map +1 -0
  133. package/dist/persona/embeddings.js +265 -0
  134. package/dist/persona/embeddings.js.map +1 -0
  135. package/dist/persona/engine.d.ts +79 -0
  136. package/dist/persona/engine.d.ts.map +1 -0
  137. package/dist/persona/engine.js +1087 -0
  138. package/dist/persona/engine.js.map +1 -0
  139. package/dist/persona/index.d.ts +11 -0
  140. package/dist/persona/index.d.ts.map +1 -0
  141. package/dist/persona/index.js +11 -0
  142. package/dist/persona/index.js.map +1 -0
  143. package/dist/persona/lifecycle.d.ts +17 -0
  144. package/dist/persona/lifecycle.d.ts.map +1 -0
  145. package/dist/persona/lifecycle.js +36 -0
  146. package/dist/persona/lifecycle.js.map +1 -0
  147. package/dist/persona/retrieval.d.ts +6 -0
  148. package/dist/persona/retrieval.d.ts.map +1 -0
  149. package/dist/persona/retrieval.js +122 -0
  150. package/dist/persona/retrieval.js.map +1 -0
  151. package/dist/persona/sync.d.ts +15 -0
  152. package/dist/persona/sync.d.ts.map +1 -0
  153. package/dist/persona/sync.js +92 -0
  154. package/dist/persona/sync.js.map +1 -0
  155. package/dist/persona/types.d.ts +283 -0
  156. package/dist/persona/types.d.ts.map +1 -0
  157. package/dist/persona/types.js +2 -0
  158. package/dist/persona/types.js.map +1 -0
  159. package/dist/persona/zkp/engine.d.ts +26 -0
  160. package/dist/persona/zkp/engine.d.ts.map +1 -0
  161. package/dist/persona/zkp/engine.js +370 -0
  162. package/dist/persona/zkp/engine.js.map +1 -0
  163. package/dist/persona/zkp/types.d.ts +39 -0
  164. package/dist/persona/zkp/types.d.ts.map +1 -0
  165. package/dist/persona/zkp/types.js +2 -0
  166. package/dist/persona/zkp/types.js.map +1 -0
  167. package/dist/planner.d.ts +114 -0
  168. package/dist/planner.d.ts.map +1 -0
  169. package/dist/planner.js +522 -0
  170. package/dist/planner.js.map +1 -0
  171. package/dist/proactive/checkpoints.d.ts +9 -0
  172. package/dist/proactive/checkpoints.d.ts.map +1 -0
  173. package/dist/proactive/checkpoints.js +20 -0
  174. package/dist/proactive/checkpoints.js.map +1 -0
  175. package/dist/proactive/engine.d.ts +59 -0
  176. package/dist/proactive/engine.d.ts.map +1 -0
  177. package/dist/proactive/engine.js +406 -0
  178. package/dist/proactive/engine.js.map +1 -0
  179. package/dist/proactive/scheduler.d.ts +11 -0
  180. package/dist/proactive/scheduler.d.ts.map +1 -0
  181. package/dist/proactive/scheduler.js +45 -0
  182. package/dist/proactive/scheduler.js.map +1 -0
  183. package/dist/proactive/swarm-controller.d.ts +189 -0
  184. package/dist/proactive/swarm-controller.d.ts.map +1 -0
  185. package/dist/proactive/swarm-controller.js +477 -0
  186. package/dist/proactive/swarm-controller.js.map +1 -0
  187. package/dist/proactive/swarm-registry.d.ts +13 -0
  188. package/dist/proactive/swarm-registry.d.ts.map +1 -0
  189. package/dist/proactive/swarm-registry.js +122 -0
  190. package/dist/proactive/swarm-registry.js.map +1 -0
  191. package/dist/proactive/types.d.ts +145 -0
  192. package/dist/proactive/types.d.ts.map +1 -0
  193. package/dist/proactive/types.js +25 -0
  194. package/dist/proactive/types.js.map +1 -0
  195. package/dist/registry.d.ts +35 -0
  196. package/dist/registry.d.ts.map +1 -0
  197. package/dist/registry.js +88 -0
  198. package/dist/registry.js.map +1 -0
  199. package/dist/reputation.d.ts +123 -0
  200. package/dist/reputation.d.ts.map +1 -0
  201. package/dist/reputation.js +366 -0
  202. package/dist/reputation.js.map +1 -0
  203. package/dist/reputation.test.d.ts +5 -0
  204. package/dist/reputation.test.d.ts.map +1 -0
  205. package/dist/reputation.test.js +265 -0
  206. package/dist/reputation.test.js.map +1 -0
  207. package/dist/rooms.d.ts +96 -0
  208. package/dist/rooms.d.ts.map +1 -0
  209. package/dist/rooms.js +410 -0
  210. package/dist/rooms.js.map +1 -0
  211. package/dist/sdk/client.d.ts +290 -0
  212. package/dist/sdk/client.d.ts.map +1 -0
  213. package/dist/sdk/client.js +1287 -0
  214. package/dist/sdk/client.js.map +1 -0
  215. package/dist/sdk/index.d.ts +32 -0
  216. package/dist/sdk/index.d.ts.map +1 -0
  217. package/dist/sdk/index.js +70 -0
  218. package/dist/sdk/index.js.map +1 -0
  219. package/dist/security.d.ts +230 -0
  220. package/dist/security.d.ts.map +1 -0
  221. package/dist/security.js +652 -0
  222. package/dist/security.js.map +1 -0
  223. package/dist/skills/engine.d.ts +262 -0
  224. package/dist/skills/engine.d.ts.map +1 -0
  225. package/dist/skills/engine.js +788 -0
  226. package/dist/skills/engine.js.map +1 -0
  227. package/dist/skills/engine.test.d.ts +2 -0
  228. package/dist/skills/engine.test.d.ts.map +1 -0
  229. package/dist/skills/engine.test.js +134 -0
  230. package/dist/skills/engine.test.js.map +1 -0
  231. package/dist/skills/parser.d.ts +129 -0
  232. package/dist/skills/parser.d.ts.map +1 -0
  233. package/dist/skills/parser.js +318 -0
  234. package/dist/skills/parser.js.map +1 -0
  235. package/dist/social.d.ts +149 -0
  236. package/dist/social.d.ts.map +1 -0
  237. package/dist/social.js +401 -0
  238. package/dist/social.js.map +1 -0
  239. package/dist/storage-optimized.d.ts +116 -0
  240. package/dist/storage-optimized.d.ts.map +1 -0
  241. package/dist/storage-optimized.js +264 -0
  242. package/dist/storage-optimized.js.map +1 -0
  243. package/dist/storage.d.ts +584 -0
  244. package/dist/storage.d.ts.map +1 -0
  245. package/dist/storage.js +2703 -0
  246. package/dist/storage.js.map +1 -0
  247. package/dist/storage.test.d.ts +2 -0
  248. package/dist/storage.test.d.ts.map +1 -0
  249. package/dist/storage.test.js +78 -0
  250. package/dist/storage.test.js.map +1 -0
  251. package/dist/swp.d.ts +443 -0
  252. package/dist/swp.d.ts.map +1 -0
  253. package/dist/swp.js +223 -0
  254. package/dist/swp.js.map +1 -0
  255. package/dist/swp.test.d.ts +5 -0
  256. package/dist/swp.test.d.ts.map +1 -0
  257. package/dist/swp.test.js +127 -0
  258. package/dist/swp.test.js.map +1 -0
  259. package/dist/templates.d.ts +25 -0
  260. package/dist/templates.d.ts.map +1 -0
  261. package/dist/templates.js +1048 -0
  262. package/dist/templates.js.map +1 -0
  263. package/dist/test-e2e.d.ts +14 -0
  264. package/dist/test-e2e.d.ts.map +1 -0
  265. package/dist/test-e2e.js +266 -0
  266. package/dist/test-e2e.js.map +1 -0
  267. package/dist/workers/research-worker.d.ts +19 -0
  268. package/dist/workers/research-worker.d.ts.map +1 -0
  269. package/dist/workers/research-worker.js +141 -0
  270. package/dist/workers/research-worker.js.map +1 -0
  271. package/package.json +110 -0
@@ -0,0 +1,691 @@
1
+ /**
2
+ * Society Protocol - Federation System v1.0
3
+ *
4
+ * Sistema de federações inspirado no Matrix Protocol
5
+ * - Federações permissionadas com governança
6
+ * - Políticas customizáveis por federação
7
+ * - Homeservers e rooms hierárquicos
8
+ * - ACLs e permissões granulares
9
+ * - social.md para definição de federações
10
+ */
11
+ import { EventEmitter } from 'events';
12
+ import { ulid } from 'ulid';
13
+ import YAML from 'yaml';
14
+ // ─── Federation Engine ───────────────────────────────────────────
15
+ export class FederationEngine extends EventEmitter {
16
+ storage;
17
+ identity;
18
+ federations = new Map();
19
+ memberFederations = new Map(); // did -> federations
20
+ proposals = new Map();
21
+ peerings = new Map();
22
+ constructor(storage, identity) {
23
+ super();
24
+ this.storage = storage;
25
+ this.identity = identity;
26
+ this.loadFederations();
27
+ this.loadGovernance();
28
+ this.loadPeerings();
29
+ }
30
+ // ─── Federation CRUD ─────────────────────────────────────────
31
+ async createFederation(name, description, visibility = 'private', manifest) {
32
+ const id = `fed_${ulid()}`;
33
+ const now = Date.now();
34
+ const federation = {
35
+ id,
36
+ name,
37
+ description,
38
+ visibility,
39
+ did: `did:society:${id}`,
40
+ creator: this.identity.did,
41
+ createdAt: now,
42
+ governance: manifest?.federation.governance ? {
43
+ model: manifest.federation.governance,
44
+ admins: [this.identity.did],
45
+ moderators: [],
46
+ policyChangeThreshold: 51,
47
+ electionEnabled: manifest.federation.governance === 'democracy',
48
+ votingPower: 'reputation'
49
+ } : {
50
+ model: 'dictatorship',
51
+ admins: [this.identity.did],
52
+ moderators: [],
53
+ policyChangeThreshold: 100,
54
+ electionEnabled: false,
55
+ votingPower: 'equal'
56
+ },
57
+ policies: manifest?.policies.map((p) => ({
58
+ id: `pol_${ulid()}`,
59
+ name: p.name,
60
+ description: '',
61
+ type: p.type,
62
+ resource: p.resource,
63
+ conditions: p.conditions,
64
+ createdAt: now,
65
+ createdBy: this.identity.did
66
+ })) || [this.getDefaultPolicy()],
67
+ roles: manifest?.roles.map((r, i) => ({
68
+ id: `role_${i}`,
69
+ name: r.name,
70
+ description: '',
71
+ permissions: r.permissions,
72
+ hierarchy: r.hierarchy
73
+ })) || this.getDefaultRoles(),
74
+ members: new Map(),
75
+ memberCount: 1,
76
+ onlineCount: 1,
77
+ rooms: [],
78
+ settings: manifest?.settings ? {
79
+ allowGuestAccess: manifest.settings.allowGuestAccess,
80
+ requireInvitation: manifest.settings.requireInvitation,
81
+ autoVerifyMembers: false,
82
+ messageRetentionDays: manifest.settings.messageRetentionDays,
83
+ maxRoomSize: manifest.settings.maxRoomSize,
84
+ federationOutbound: true,
85
+ federationInbound: visibility === 'public'
86
+ } : {
87
+ allowGuestAccess: false,
88
+ requireInvitation: visibility !== 'public',
89
+ autoVerifyMembers: false,
90
+ messageRetentionDays: 30,
91
+ maxRoomSize: 1000,
92
+ federationOutbound: true,
93
+ federationInbound: visibility === 'public'
94
+ },
95
+ encryption: {
96
+ enabled: visibility !== 'public',
97
+ algorithm: 'x25519-xsalsa20-poly1305',
98
+ keyRotationDays: 30
99
+ },
100
+ tags: [],
101
+ language: 'pt-BR',
102
+ timezone: 'America/Sao_Paulo'
103
+ };
104
+ // Criador é admin automaticamente
105
+ federation.members.set(this.identity.did, {
106
+ did: this.identity.did,
107
+ displayName: this.identity.displayName,
108
+ status: 'admin',
109
+ role: 'admin',
110
+ joinedAt: now,
111
+ reputationAtJoin: 100,
112
+ lastActivity: now
113
+ });
114
+ this.federations.set(id, federation);
115
+ this.addMemberToIndex(this.identity.did, id);
116
+ await this.saveFederation(federation);
117
+ this.emit('federation:created', federation);
118
+ return federation;
119
+ }
120
+ async joinFederation(federationId, did, displayName, inviterDid) {
121
+ const federation = this.federations.get(federationId);
122
+ if (!federation)
123
+ throw new Error('Federation not found');
124
+ // Verificar se já é membro
125
+ if (federation.members.has(did)) {
126
+ throw new Error('Already a member');
127
+ }
128
+ // Verificar políticas de entrada
129
+ if (federation.settings.requireInvitation && !inviterDid) {
130
+ throw new Error('Invitation required');
131
+ }
132
+ if (federation.visibility === 'invite-only' && !inviterDid) {
133
+ throw new Error('Invitation required for invite-only federation');
134
+ }
135
+ // Verificar ban
136
+ const existingMember = federation.members.get(did);
137
+ if (existingMember?.status === 'banned') {
138
+ throw new Error('Banned from federation');
139
+ }
140
+ // Fetch actual reputation from storage
141
+ let reputationAtJoin = 0;
142
+ try {
143
+ const repRecord = this.storage.getReputationRecord?.(did);
144
+ if (repRecord?.overall_score) {
145
+ reputationAtJoin = repRecord.overall_score;
146
+ }
147
+ }
148
+ catch {
149
+ // Storage may not have reputation data yet; default to 0
150
+ }
151
+ const member = {
152
+ did,
153
+ displayName,
154
+ status: federation.settings.autoVerifyMembers ? 'member' : 'pending',
155
+ role: 'member',
156
+ joinedAt: Date.now(),
157
+ invitedBy: inviterDid,
158
+ reputationAtJoin,
159
+ lastActivity: Date.now()
160
+ };
161
+ federation.members.set(did, member);
162
+ federation.memberCount++;
163
+ this.addMemberToIndex(did, federationId);
164
+ await this.saveFederation(federation);
165
+ this.emit('federation:member:joined', federationId, member);
166
+ return true;
167
+ }
168
+ async leaveFederation(federationId, did) {
169
+ const federation = this.federations.get(federationId);
170
+ if (!federation)
171
+ throw new Error('Federation not found');
172
+ if (!federation.members.has(did)) {
173
+ throw new Error('Not a member');
174
+ }
175
+ // Não permitir se for o último admin
176
+ const member = federation.members.get(did);
177
+ if (member.status === 'admin') {
178
+ const adminCount = Array.from(federation.members.values())
179
+ .filter(m => m.status === 'admin').length;
180
+ if (adminCount <= 1) {
181
+ throw new Error('Cannot leave: last admin must transfer ownership');
182
+ }
183
+ }
184
+ federation.members.delete(did);
185
+ federation.memberCount--;
186
+ this.removeMemberFromIndex(did, federationId);
187
+ await this.saveFederation(federation);
188
+ this.emit('federation:member:left', federationId, did);
189
+ }
190
+ // ─── Governance ─────────────────────────────────────────────
191
+ async proposePolicyChange(federationId, policy, proposerDid) {
192
+ const federation = this.federations.get(federationId);
193
+ if (!federation)
194
+ throw new Error('Federation not found');
195
+ // Verificar permissão
196
+ if (!this.hasPermission(federation, proposerDid, 'federation:policy:propose')) {
197
+ throw new Error('No permission to propose policy changes');
198
+ }
199
+ const proposalId = `prop_${ulid()}`;
200
+ const now = Date.now();
201
+ const proposal = {
202
+ id: proposalId,
203
+ federationId,
204
+ proposerDid,
205
+ status: 'open',
206
+ createdAt: now,
207
+ policy: {
208
+ id: policy.id || `pol_${ulid()}`,
209
+ name: policy.name || 'Policy Update',
210
+ description: policy.description || '',
211
+ type: policy.type || 'require',
212
+ resource: policy.resource || '*',
213
+ conditions: policy.conditions,
214
+ createdAt: now,
215
+ createdBy: proposerDid
216
+ },
217
+ votes: new Map()
218
+ };
219
+ this.proposals.set(proposalId, proposal);
220
+ this.storage.saveFederationProposal(proposalId, federationId, proposerDid, proposal.policy, 'open');
221
+ this.emit('federation:policy:proposed', federationId, proposalId, policy);
222
+ return proposalId;
223
+ }
224
+ async voteOnProposal(federationId, proposalId, voterDid, vote) {
225
+ const federation = this.federations.get(federationId);
226
+ if (!federation)
227
+ throw new Error('Federation not found');
228
+ // Calcular poder de voto
229
+ const votingPower = this.calculateVotingPower(federation, voterDid);
230
+ const proposal = this.getProposal(proposalId);
231
+ if (!proposal || proposal.federationId !== federationId) {
232
+ throw new Error('Proposal not found');
233
+ }
234
+ if (proposal.status !== 'open') {
235
+ throw new Error('Proposal is closed');
236
+ }
237
+ if (!federation.members.has(voterDid)) {
238
+ throw new Error('Only federation members can vote');
239
+ }
240
+ const voteRecord = {
241
+ voterDid,
242
+ vote,
243
+ votingPower,
244
+ votedAt: Date.now()
245
+ };
246
+ proposal.votes.set(voterDid, voteRecord);
247
+ this.storage.saveFederationVote(proposalId, voterDid, vote, votingPower);
248
+ this.evaluateProposal(federation, proposal);
249
+ this.emit('federation:vote', federationId, proposalId, voterDid, vote, votingPower);
250
+ }
251
+ // ─── Federation Mesh: Peering ───────────────────────────────
252
+ async requestPeering(sourceFederationId, targetFederationDid, policy = {}) {
253
+ const federation = this.federations.get(sourceFederationId);
254
+ if (!federation) {
255
+ throw new Error(`Federation not found: ${sourceFederationId}`);
256
+ }
257
+ if (!federation.settings.federationOutbound) {
258
+ throw new Error('Federation outbound peering is disabled');
259
+ }
260
+ if (!this.hasPermission(federation, this.identity.did, 'federation:peer:request')) {
261
+ throw new Error('No permission to request peering');
262
+ }
263
+ if (targetFederationDid === federation.did) {
264
+ throw new Error('Cannot peer federation with itself');
265
+ }
266
+ const now = Date.now();
267
+ const peering = {
268
+ id: `peer_${ulid()}`,
269
+ sourceFederationId,
270
+ sourceFederationDid: federation.did,
271
+ targetFederationDid,
272
+ requestedBy: this.identity.did,
273
+ status: 'pending',
274
+ policy: this.normalizePeeringPolicy(policy),
275
+ createdAt: now,
276
+ updatedAt: now
277
+ };
278
+ this.peerings.set(peering.id, peering);
279
+ this.persistPeering(peering);
280
+ this.emit('federation:peering:requested', peering);
281
+ return peering;
282
+ }
283
+ async respondPeering(peeringId, accepted, reason) {
284
+ const peering = this.peerings.get(peeringId);
285
+ if (!peering) {
286
+ throw new Error(`Peering not found: ${peeringId}`);
287
+ }
288
+ if (peering.status !== 'pending') {
289
+ throw new Error(`Peering ${peeringId} is not pending`);
290
+ }
291
+ const now = Date.now();
292
+ peering.status = accepted ? 'active' : 'rejected';
293
+ peering.reason = reason;
294
+ peering.respondedAt = now;
295
+ peering.updatedAt = now;
296
+ this.peerings.set(peering.id, peering);
297
+ this.persistPeering(peering);
298
+ this.emit(accepted ? 'federation:peering:accepted' : 'federation:peering:rejected', peering);
299
+ return peering;
300
+ }
301
+ async revokePeering(peeringId, reason) {
302
+ const peering = this.peerings.get(peeringId);
303
+ if (!peering) {
304
+ throw new Error(`Peering not found: ${peeringId}`);
305
+ }
306
+ const now = Date.now();
307
+ peering.status = 'revoked';
308
+ peering.reason = reason;
309
+ peering.respondedAt = peering.respondedAt ?? now;
310
+ peering.updatedAt = now;
311
+ this.peerings.set(peering.id, peering);
312
+ this.persistPeering(peering);
313
+ this.emit('federation:peering:revoked', peering);
314
+ return peering;
315
+ }
316
+ listPeerings(federationId, status) {
317
+ const federationDid = this.federations.get(federationId)?.did;
318
+ if (!federationDid) {
319
+ return [];
320
+ }
321
+ return Array.from(this.peerings.values())
322
+ .filter((peering) => {
323
+ if (status && peering.status !== status)
324
+ return false;
325
+ return (peering.sourceFederationId === federationId ||
326
+ peering.targetFederationDid === federationDid);
327
+ })
328
+ .sort((a, b) => b.updatedAt - a.updatedAt);
329
+ }
330
+ getPeering(peeringId) {
331
+ return this.peerings.get(peeringId);
332
+ }
333
+ // ─── Permissions & ACL ─────────────────────────────────────
334
+ hasPermission(federation, did, permission) {
335
+ const member = federation.members.get(did);
336
+ if (!member)
337
+ return false;
338
+ // Admin tem todas as permissões
339
+ if (member.status === 'admin')
340
+ return true;
341
+ // Verificar role
342
+ const role = federation.roles.find(r => r.id === member.role);
343
+ if (!role)
344
+ return false;
345
+ return role.permissions.includes(permission) ||
346
+ role.permissions.includes('*');
347
+ }
348
+ checkPolicy(federation, action, actorDid, context) {
349
+ // Buscar políticas aplicáveis
350
+ const policies = federation.policies.filter(p => p.resource === action ||
351
+ p.resource === '*' ||
352
+ action.startsWith(p.resource.replace('*', '')));
353
+ // Ordenar: deny primeiro, depois require, depois allow
354
+ policies.sort((a, b) => {
355
+ const order = { deny: 0, require: 1, allow: 2 };
356
+ return order[a.type] - order[b.type];
357
+ });
358
+ for (const policy of policies) {
359
+ // Verificar condições
360
+ if (policy.conditions) {
361
+ const member = federation.members.get(actorDid);
362
+ if (!member)
363
+ continue;
364
+ if (policy.conditions.minReputation) {
365
+ // TODO: Verificar reputação real
366
+ }
367
+ if (policy.conditions.allowedRoles) {
368
+ if (!policy.conditions.allowedRoles.includes(member.role)) {
369
+ continue;
370
+ }
371
+ }
372
+ }
373
+ switch (policy.type) {
374
+ case 'deny':
375
+ return { allowed: false, reason: `Policy denies: ${policy.name}` };
376
+ case 'require':
377
+ // Verificar se requisito está satisfeito
378
+ break;
379
+ case 'allow':
380
+ return { allowed: true };
381
+ }
382
+ }
383
+ // Default: deny
384
+ return { allowed: false, reason: 'No policy allows this action' };
385
+ }
386
+ // ─── social.md Parser ───────────────────────────────────────
387
+ static parseSocialManifest(yamlContent) {
388
+ const parsed = YAML.parse(yamlContent);
389
+ if (!parsed?.social?.name || !parsed?.social?.description) {
390
+ throw new Error('Invalid social manifest: social.name and social.description are required');
391
+ }
392
+ return {
393
+ social: {
394
+ name: parsed.social.name,
395
+ version: parsed.social.version || '1.0.0',
396
+ description: parsed.social.description,
397
+ author: parsed.social.author || 'unknown',
398
+ created: parsed.social.created || new Date().toISOString()
399
+ },
400
+ federation: {
401
+ visibility: parsed.federation?.visibility || 'private',
402
+ governance: parsed.federation?.governance || 'dictatorship',
403
+ homeserver: parsed.federation?.homeserver
404
+ },
405
+ policies: parsed.policies || [],
406
+ roles: parsed.roles || [],
407
+ settings: {
408
+ allowGuestAccess: parsed.settings?.allowGuestAccess ?? false,
409
+ requireInvitation: parsed.settings?.requireInvitation ?? true,
410
+ messageRetentionDays: parsed.settings?.messageRetentionDays ?? 30,
411
+ maxRoomSize: parsed.settings?.maxRoomSize ?? 1000
412
+ }
413
+ };
414
+ }
415
+ async createFederationFromSocial(socialPath) {
416
+ // Ler arquivo
417
+ const fs = await import('fs');
418
+ const content = fs.readFileSync(socialPath, 'utf-8');
419
+ const manifest = FederationEngine.parseSocialManifest(content);
420
+ return this.createFederation(manifest.social.name, manifest.social.description, manifest.federation.visibility, manifest);
421
+ }
422
+ // ─── Queries ────────────────────────────────────────────────
423
+ getFederation(id) {
424
+ return this.federations.get(id);
425
+ }
426
+ getMemberFederations(did) {
427
+ const ids = this.memberFederations.get(did);
428
+ if (!ids)
429
+ return [];
430
+ return Array.from(ids).map(id => this.federations.get(id)).filter(Boolean);
431
+ }
432
+ getPublicFederations() {
433
+ return Array.from(this.federations.values())
434
+ .filter(f => f.visibility === 'public');
435
+ }
436
+ searchFederations(query) {
437
+ const lowerQuery = query.toLowerCase();
438
+ return Array.from(this.federations.values())
439
+ .filter(f => f.name.toLowerCase().includes(lowerQuery) ||
440
+ f.description.toLowerCase().includes(lowerQuery) ||
441
+ f.tags.some(t => t.toLowerCase().includes(lowerQuery)));
442
+ }
443
+ // ─── Private Helpers ────────────────────────────────────────
444
+ getDefaultPolicy() {
445
+ return {
446
+ id: `pol_${ulid()}`,
447
+ name: 'Default Allow',
448
+ description: 'Allow all actions by default',
449
+ type: 'allow',
450
+ resource: '*',
451
+ createdAt: Date.now(),
452
+ createdBy: this.identity.did
453
+ };
454
+ }
455
+ getDefaultRoles() {
456
+ return [
457
+ {
458
+ id: 'admin',
459
+ name: 'Administrator',
460
+ description: 'Full control of federation',
461
+ permissions: ['*'],
462
+ hierarchy: 100,
463
+ color: '#ff0000'
464
+ },
465
+ {
466
+ id: 'moderator',
467
+ name: 'Moderator',
468
+ description: 'Can moderate content and members',
469
+ permissions: [
470
+ 'room:moderate',
471
+ 'member:ban',
472
+ 'message:delete',
473
+ 'federation:policy:propose'
474
+ ],
475
+ hierarchy: 50,
476
+ color: '#00ff00'
477
+ },
478
+ {
479
+ id: 'member',
480
+ name: 'Member',
481
+ description: 'Regular member',
482
+ permissions: [
483
+ 'room:join',
484
+ 'room:create',
485
+ 'message:send',
486
+ 'member:invite'
487
+ ],
488
+ hierarchy: 10,
489
+ color: '#0000ff'
490
+ },
491
+ {
492
+ id: 'guest',
493
+ name: 'Guest',
494
+ description: 'Limited access',
495
+ permissions: [
496
+ 'room:join',
497
+ 'message:send:readonly'
498
+ ],
499
+ hierarchy: 0,
500
+ color: '#808080'
501
+ }
502
+ ];
503
+ }
504
+ normalizePeeringPolicy(policy) {
505
+ const allowedTypes = policy.allowedTypes?.length
506
+ ? policy.allowedTypes
507
+ : ['chat.msg', 'coc.open', 'coc.plan', 'coc.submit', 'federation.bridge.sync'];
508
+ const maxRatePerMinute = Number(policy.maxRatePerMinute);
509
+ return {
510
+ allowedTypes,
511
+ maxRatePerMinute: Number.isFinite(maxRatePerMinute) && maxRatePerMinute > 0
512
+ ? Math.floor(maxRatePerMinute)
513
+ : 200,
514
+ privacyMode: policy.privacyMode || 'summary',
515
+ allowedRooms: policy.allowedRooms,
516
+ blockedRooms: policy.blockedRooms
517
+ };
518
+ }
519
+ calculateVotingPower(federation, did) {
520
+ const member = federation.members.get(did);
521
+ if (!member)
522
+ return 0;
523
+ switch (federation.governance.votingPower) {
524
+ case 'equal':
525
+ return 1;
526
+ case 'reputation':
527
+ const reputation = this.storage.getReputationRecord?.(did);
528
+ if (reputation?.overall_score) {
529
+ return Math.max(0.1, reputation.overall_score);
530
+ }
531
+ return Math.max(0.1, member.reputationAtJoin || 1);
532
+ case 'stake':
533
+ // Stake ainda não está disponível - fallback para peso igual
534
+ return 1;
535
+ default:
536
+ return 1;
537
+ }
538
+ }
539
+ addMemberToIndex(did, federationId) {
540
+ if (!this.memberFederations.has(did)) {
541
+ this.memberFederations.set(did, new Set());
542
+ }
543
+ this.memberFederations.get(did).add(federationId);
544
+ }
545
+ removeMemberFromIndex(did, federationId) {
546
+ this.memberFederations.get(did)?.delete(federationId);
547
+ }
548
+ async saveFederation(federation) {
549
+ this.storage.saveFederation?.(federation);
550
+ }
551
+ loadFederations() {
552
+ const federations = this.storage.getFederations?.() || [];
553
+ for (const fed of federations) {
554
+ const hydrated = this.hydrateFederation(fed);
555
+ this.federations.set(hydrated.id, hydrated);
556
+ for (const [did] of hydrated.members) {
557
+ this.addMemberToIndex(did, fed.id);
558
+ }
559
+ }
560
+ }
561
+ loadGovernance() {
562
+ const proposals = this.storage.getFederationProposals?.() || [];
563
+ for (const proposalRow of proposals) {
564
+ const proposal = {
565
+ id: proposalRow.proposal_id,
566
+ federationId: proposalRow.federation_id,
567
+ proposerDid: proposalRow.proposer_did,
568
+ policy: proposalRow.policy,
569
+ status: proposalRow.status,
570
+ createdAt: proposalRow.created_at,
571
+ closedAt: proposalRow.closed_at || undefined,
572
+ votes: new Map()
573
+ };
574
+ const votes = this.storage.getFederationVotes?.(proposal.id) || [];
575
+ for (const vote of votes) {
576
+ proposal.votes.set(vote.voter_did, {
577
+ voterDid: vote.voter_did,
578
+ vote: vote.vote,
579
+ votingPower: vote.voting_power,
580
+ votedAt: vote.voted_at
581
+ });
582
+ }
583
+ this.proposals.set(proposal.id, proposal);
584
+ }
585
+ }
586
+ loadPeerings() {
587
+ const rows = this.storage.listFederationPeerings?.() || [];
588
+ for (const row of rows) {
589
+ const storedPolicy = (row.policy || {});
590
+ const peering = {
591
+ id: row.peeringId,
592
+ sourceFederationId: row.sourceFederationId,
593
+ sourceFederationDid: row.sourceFederationDid,
594
+ targetFederationDid: row.targetFederationDid,
595
+ requestedBy: typeof storedPolicy.requestedBy === 'string'
596
+ ? storedPolicy.requestedBy
597
+ : row.sourceFederationDid,
598
+ status: row.status,
599
+ policy: this.normalizePeeringPolicy(storedPolicy),
600
+ reason: row.reason,
601
+ createdAt: row.createdAt,
602
+ updatedAt: row.updatedAt,
603
+ respondedAt: row.respondedAt
604
+ };
605
+ this.peerings.set(peering.id, peering);
606
+ }
607
+ }
608
+ persistPeering(peering) {
609
+ this.storage.saveFederationPeering?.({
610
+ peeringId: peering.id,
611
+ sourceFederationId: peering.sourceFederationId,
612
+ sourceFederationDid: peering.sourceFederationDid,
613
+ targetFederationDid: peering.targetFederationDid,
614
+ policy: {
615
+ ...peering.policy,
616
+ requestedBy: peering.requestedBy
617
+ },
618
+ status: peering.status,
619
+ reason: peering.reason,
620
+ createdAt: peering.createdAt,
621
+ updatedAt: peering.updatedAt,
622
+ respondedAt: peering.respondedAt
623
+ });
624
+ }
625
+ getProposal(proposalId) {
626
+ return this.proposals.get(proposalId);
627
+ }
628
+ evaluateProposal(federation, proposal) {
629
+ if (proposal.status !== 'open')
630
+ return;
631
+ const eligibleMembers = Array.from(federation.members.values())
632
+ .filter((member) => member.status !== 'pending' && member.status !== 'banned');
633
+ const totalEligiblePower = eligibleMembers.reduce((acc, member) => acc + this.calculateVotingPower(federation, member.did), 0);
634
+ if (totalEligiblePower <= 0) {
635
+ return;
636
+ }
637
+ let yesPower = 0;
638
+ let noPower = 0;
639
+ for (const vote of proposal.votes.values()) {
640
+ if (vote.vote === 'yes')
641
+ yesPower += vote.votingPower;
642
+ if (vote.vote === 'no')
643
+ noPower += vote.votingPower;
644
+ }
645
+ const threshold = federation.governance.policyChangeThreshold / 100;
646
+ if (yesPower / totalEligiblePower >= threshold) {
647
+ const policyIndex = federation.policies.findIndex(p => p.id === proposal.policy.id);
648
+ if (policyIndex >= 0) {
649
+ federation.policies[policyIndex] = proposal.policy;
650
+ }
651
+ else {
652
+ federation.policies.push(proposal.policy);
653
+ }
654
+ proposal.status = 'approved';
655
+ proposal.closedAt = Date.now();
656
+ this.storage.setFederationProposalStatus?.(proposal.id, 'approved');
657
+ this.saveFederation(federation);
658
+ this.emit('federation:policy:approved', federation.id, proposal.id, proposal.policy);
659
+ return;
660
+ }
661
+ if (noPower / totalEligiblePower > (1 - threshold)) {
662
+ proposal.status = 'rejected';
663
+ proposal.closedAt = Date.now();
664
+ this.storage.setFederationProposalStatus?.(proposal.id, 'rejected');
665
+ this.emit('federation:policy:rejected', federation.id, proposal.id);
666
+ }
667
+ }
668
+ hydrateFederation(raw) {
669
+ const members = this.normalizeMembers(raw.members);
670
+ return {
671
+ ...raw,
672
+ members,
673
+ memberCount: raw.memberCount ?? members.size,
674
+ onlineCount: raw.onlineCount ?? 0
675
+ };
676
+ }
677
+ normalizeMembers(rawMembers) {
678
+ if (rawMembers instanceof Map) {
679
+ return rawMembers;
680
+ }
681
+ if (Array.isArray(rawMembers)) {
682
+ return new Map(rawMembers);
683
+ }
684
+ if (rawMembers && typeof rawMembers === 'object') {
685
+ return new Map(Object.entries(rawMembers));
686
+ }
687
+ return new Map();
688
+ }
689
+ }
690
+ // Classes already exported via 'export class'
691
+ //# sourceMappingURL=federation.js.map