enigma-memory 0.1.18 → 0.1.22

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 (276) hide show
  1. package/README.md +76 -24
  2. package/apps/cli/bin/enigma-desktop.mjs +140 -0
  3. package/apps/cli/bin/enigma-terminal.mjs +78 -0
  4. package/apps/cli/bin/enigma.mjs +1923 -285
  5. package/apps/desktop/electron-main.cjs +217 -0
  6. package/apps/desktop/package.json +12 -0
  7. package/apps/desktop/src/app.js +264 -7
  8. package/apps/desktop/src/index.html +3514 -1373
  9. package/apps/desktop/src/launch-electron.mjs +51 -0
  10. package/apps/desktop/src/server.mjs +2914 -0
  11. package/apps/desktop/src/styles.css +2972 -260
  12. package/apps/desktop/src/zk-browser-prove.mjs +53 -0
  13. package/apps/desktop/src/zk-state.mjs +1789 -0
  14. package/apps/gateway/bin/enigma-gateway.mjs +102 -5
  15. package/apps/gateway/src/server.mjs +271 -8
  16. package/apps/ios/EnigmaCore/Package.swift +12 -0
  17. package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
  18. package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
  19. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
  20. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
  21. package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
  22. package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
  23. package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
  24. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
  25. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
  26. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
  27. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
  28. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
  29. package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
  30. package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
  31. package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
  32. package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
  33. package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
  34. package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
  35. package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
  36. package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
  37. package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
  38. package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
  39. package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
  40. package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
  41. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
  42. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
  43. package/apps/native-host/README.md +19 -8
  44. package/apps/native-host/bin/enigma-native-host.mjs +229 -13
  45. package/apps/relay/bin/enigma-relay.mjs +103 -5
  46. package/apps/relay/src/federation-runtime.mjs +618 -0
  47. package/apps/relay/src/server.mjs +310 -9
  48. package/apps/verifier/bin/enigma-verify.mjs +327 -11
  49. package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
  50. package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
  51. package/cortex-v3/circuits/build/vk_bytes.json +32 -0
  52. package/cortex-v3/proving-assets.json +64 -0
  53. package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
  54. package/cortex-v3/zk/action-transition-vk.json +119 -0
  55. package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
  56. package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
  57. package/cortex-v3/zk/intent-witness.mjs +365 -0
  58. package/cortex-v3/zk/intent-witness.test.mjs +485 -0
  59. package/cortex-v3/zk/proving-assets.mjs +203 -0
  60. package/cortex-v3/zk/sale-witness.mjs +783 -0
  61. package/cortex-v3/zk/sale-witness.test.mjs +784 -0
  62. package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
  63. package/cortex-v3/zk/settlement-evidence.mjs +722 -0
  64. package/cortex-v3/zk/setup-intent.mjs +688 -0
  65. package/cortex-v3/zk/setup-sale.mjs +666 -0
  66. package/cortex-v3/zk/setup.mjs +594 -0
  67. package/cortex-v3/zk/witness.mjs +184 -0
  68. package/cortex-v3/zk/zk-codec.mjs +232 -0
  69. package/cortex-v3/zk/zk-codec.test.mjs +293 -0
  70. package/cortex-v3/zk/zk-settle.mjs +370 -0
  71. package/cortex-v3/zk/zk-tree.mjs +256 -0
  72. package/cortex-v3/zk/zk-tree.test.mjs +419 -0
  73. package/deploy/docker-compose.local-production-simulation.yml +36 -0
  74. package/docs/browser-extension-install.md +8 -6
  75. package/docs/client-connectors.md +15 -11
  76. package/docs/developer-ecosystem.md +15 -13
  77. package/docs/enigma-memory-ready-conformance.md +11 -9
  78. package/docs/install-anywhere.md +61 -28
  79. package/docs/installers-and-desktop.md +8 -7
  80. package/docs/novelty-invention-candidates.md +161 -161
  81. package/docs/proof-network-claim-boundaries.md +320 -318
  82. package/examples/01-quickstart-agent/index.mjs +49 -0
  83. package/examples/01_agent_memory_quickstart.mjs +57 -0
  84. package/examples/02-multi-agent-swarm/index.mjs +57 -0
  85. package/examples/02_cross_model_passport.mjs +64 -0
  86. package/examples/03-langchain-memory/index.mjs +41 -0
  87. package/examples/03_poseidon_commitment_verification.mjs +71 -0
  88. package/examples/04-python-trading-agent/trader.py +49 -0
  89. package/examples/README.md +27 -0
  90. package/examples/ci/github-actions.yml +7 -2
  91. package/package.json +142 -11
  92. package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
  93. package/packages/connectors/src/index.js +196 -4
  94. package/packages/connectors/swarm-router.mjs +168 -0
  95. package/packages/core/src/index.js +248 -1
  96. package/packages/core/src/version.mjs +7 -0
  97. package/packages/dev-tools/package.json +19 -0
  98. package/packages/dev-tools/src/index.js +4 -0
  99. package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
  100. package/packages/dev-tools/src/swarm-simulator.js +101 -0
  101. package/packages/dev-tools/src/vault-inspector.js +114 -0
  102. package/packages/dev-tools/src/vector-benchmark.js +100 -0
  103. package/packages/developer-platform/src/access-credentials.js +341 -0
  104. package/packages/developer-platform/src/http.js +132 -0
  105. package/packages/developer-platform/src/index.js +4 -0
  106. package/packages/developer-platform/src/usage-http.js +60 -0
  107. package/packages/developer-platform/src/usage.js +295 -0
  108. package/packages/enclave-runtime/attestation.mjs +159 -0
  109. package/packages/enclave-runtime/index.mjs +47 -0
  110. package/packages/enclave-runtime/session-manager.mjs +253 -0
  111. package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
  112. package/packages/enigma-reflex/package.json +14 -0
  113. package/packages/enigma-reflex/src/index.js +204 -0
  114. package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
  115. package/packages/enigma-reflex/training/requirements.txt +8 -0
  116. package/packages/enigma-reflex/training/train.py +314 -0
  117. package/packages/enigma-weave/LICENSE +22 -0
  118. package/packages/enigma-weave/UPSTREAM.json +21 -0
  119. package/packages/enigma-weave/package.json +14 -0
  120. package/packages/enigma-weave/src/index.js +286 -0
  121. package/packages/hosted-cloud/src/index.js +80 -5
  122. package/packages/importers/src/index.js +432 -0
  123. package/packages/inference-runtime/src/browser.js +401 -0
  124. package/packages/inference-runtime/src/chat.js +265 -0
  125. package/packages/inference-runtime/src/code.js +407 -0
  126. package/packages/inference-runtime/src/contracts.js +162 -0
  127. package/packages/inference-runtime/src/http.js +232 -0
  128. package/packages/inference-runtime/src/image.js +186 -0
  129. package/packages/inference-runtime/src/index.js +10 -0
  130. package/packages/inference-runtime/src/model-router.js +320 -0
  131. package/packages/inference-runtime/src/platform.js +125 -0
  132. package/packages/inference-runtime/src/privacy.js +400 -0
  133. package/packages/inference-runtime/src/video.js +253 -0
  134. package/packages/mcp-server/README.md +22 -6
  135. package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
  136. package/packages/mcp-server/src/index.js +1418 -105
  137. package/packages/mcp-server/src/oauth.js +561 -0
  138. package/packages/mcp-server/src/private-handoff.js +84 -0
  139. package/packages/mcp-server/src/remote-http.js +273 -0
  140. package/packages/mcp-server/src/remote-policy.js +72 -0
  141. package/packages/mcp-server/swarm-bridge.mjs +361 -0
  142. package/packages/mesh/index.d.ts +283 -0
  143. package/packages/mesh/package.json +23 -0
  144. package/packages/mesh/src/crypto.js +189 -0
  145. package/packages/mesh/src/federation-packets.js +353 -0
  146. package/packages/mesh/src/gossip.js +311 -0
  147. package/packages/mesh/src/index.js +6 -0
  148. package/packages/mesh/src/protocol.js +255 -0
  149. package/packages/mesh/src/router.js +279 -0
  150. package/packages/mesh/src/transport.js +306 -0
  151. package/packages/passport/src/index.js +426 -1
  152. package/packages/private-economy/src/credits-http.js +100 -0
  153. package/packages/private-economy/src/credits.js +447 -0
  154. package/packages/private-economy/src/index.js +5 -0
  155. package/packages/private-economy/src/payments-http.js +120 -0
  156. package/packages/private-economy/src/payments.js +509 -0
  157. package/packages/private-economy/src/x402.js +346 -0
  158. package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
  159. package/packages/rag/index.d.ts +182 -0
  160. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
  161. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
  162. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
  163. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
  164. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
  165. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
  166. package/packages/rag/package.json +27 -0
  167. package/packages/rag/src/blinded-search.js +109 -0
  168. package/packages/rag/src/bm25.js +169 -0
  169. package/packages/rag/src/embeddings.js +459 -0
  170. package/packages/rag/src/hybrid.js +76 -0
  171. package/packages/rag/src/index.js +38 -0
  172. package/packages/rag/src/reranker.js +61 -0
  173. package/packages/rag/src/research.js +107 -0
  174. package/packages/rag/src/vector-store.js +430 -0
  175. package/packages/rag/src/verify-model-artifacts.mjs +4 -0
  176. package/packages/sdk/index.d.ts +760 -0
  177. package/packages/sdk/package.json +33 -0
  178. package/packages/sdk/python/README.md +24 -0
  179. package/packages/sdk/python/enigma_sdk.py +250 -0
  180. package/packages/sdk/python/pyproject.toml +34 -0
  181. package/packages/sdk/python/requirements.txt +1 -0
  182. package/packages/sdk/python/setup.py +20 -0
  183. package/packages/sdk/src/federation/capability-grant.js +389 -0
  184. package/packages/sdk/src/federation/federation-router.js +360 -0
  185. package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
  186. package/packages/sdk/src/federation/index.js +3 -0
  187. package/packages/sdk/src/index.js +1796 -0
  188. package/packages/sdk/src/intelligence/contradiction.js +337 -0
  189. package/packages/sdk/src/intelligence/decision-engine.js +155 -0
  190. package/packages/sdk/src/intelligence/index.js +4 -0
  191. package/packages/sdk/src/intelligence/ontology.js +122 -0
  192. package/packages/sdk/src/intelligence/temporal.js +123 -0
  193. package/packages/sdk/src/market-client.js +142 -0
  194. package/packages/sdk/src/mesh-client.js +110 -0
  195. package/packages/sdk/src/middleware/index.js +3 -0
  196. package/packages/sdk/src/middleware/langchain.js +159 -0
  197. package/packages/sdk/src/middleware/llamaindex.js +101 -0
  198. package/packages/sdk/src/middleware/vercel-ai.js +112 -0
  199. package/packages/sdk/src/rag-client.js +85 -0
  200. package/packages/sdk/src/swarm-orchestrator.js +260 -0
  201. package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
  202. package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
  203. package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
  204. package/packages/snapcompact/index.d.ts +284 -0
  205. package/packages/snapcompact/package.json +25 -0
  206. package/packages/snapcompact/src/index.js +716 -0
  207. package/packages/storage/PACKAGE_CONTRACT.md +1 -1
  208. package/packages/terminal-console/animations.mjs +240 -0
  209. package/packages/terminal-console/auto-anchor.mjs +220 -0
  210. package/packages/terminal-console/banner.mjs +91 -0
  211. package/packages/terminal-console/commands.mjs +459 -0
  212. package/packages/terminal-console/delegation.mjs +152 -0
  213. package/packages/terminal-console/index.mjs +5 -0
  214. package/packages/terminal-console/outbox.mjs +143 -0
  215. package/packages/terminal-console/phantom-bridge.mjs +637 -0
  216. package/packages/terminal-console/repl.mjs +136 -0
  217. package/packages/terminal-console/signer-store.mjs +130 -0
  218. package/packages/terminal-console/solana-rpc.mjs +214 -0
  219. package/packages/terminal-console/solana-transport.mjs +189 -0
  220. package/packages/terminal-tui/dashboard.mjs +214 -0
  221. package/packages/terminal-tui/index.mjs +28 -0
  222. package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
  223. package/packages/terminal-tui/telemetry-hud.mjs +137 -0
  224. package/packages/vault/index.d.ts +449 -0
  225. package/packages/vault/package.json +27 -0
  226. package/packages/vault/src/e2ee.mjs +393 -0
  227. package/packages/vault/src/enclave.js +481 -0
  228. package/packages/vault/src/erasure.js +207 -0
  229. package/packages/vault/src/index.js +1018 -155
  230. package/packages/vault/src/persistence.js +307 -0
  231. package/packages/vault/src/poseidon.js +354 -0
  232. package/packages/vault/src/receipt.js +459 -0
  233. package/scripts/benchmark-optical-context.mjs +166 -0
  234. package/scripts/bootstrap-enigma.mjs +502 -0
  235. package/scripts/build-edge-backend-workers.mjs +20 -5
  236. package/scripts/build-goal-completion-audit.mjs +72 -25
  237. package/scripts/build-hosted-api-key-lifecycle.mjs +26 -8
  238. package/scripts/build-hosted-customer-lifecycle.mjs +20 -3
  239. package/scripts/build-hosted-probe-worker.mjs +19 -4
  240. package/scripts/build-installer-assets.mjs +41 -21
  241. package/scripts/build-operator-evidence-starter.mjs +59 -1
  242. package/scripts/build-production-backend-env-kit.mjs +2 -0
  243. package/scripts/build-production-unblocker.mjs +3 -0
  244. package/scripts/check.mjs +17 -3
  245. package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
  246. package/scripts/install-enigma-local.mjs +18 -5
  247. package/scripts/release-audit.mjs +65 -109
  248. package/scripts/release-provenance.mjs +6 -0
  249. package/scripts/run-backend-readiness-smoke.mjs +112 -10
  250. package/scripts/scan-secrets.mjs +1 -0
  251. package/scripts/simulate-production-env.mjs +7 -2
  252. package/scripts/validate-hosted-backend-live.mjs +112 -1
  253. package/specs/antibody-pack-v1.schema.json +95 -0
  254. package/specs/antigen-envelope-v1.schema.json +81 -0
  255. package/specs/boundary-manifest-v1.schema.json +35 -35
  256. package/specs/capsule-v1.schema.json +55 -55
  257. package/specs/claim-boundary-manifest-v1.schema.json +22 -22
  258. package/specs/claim-ledger-v1.schema.json +291 -0
  259. package/specs/context-passport-v1.schema.json +59 -0
  260. package/specs/deletion-tombstone-v1.schema.json +26 -26
  261. package/specs/evidence-packet-v1.schema.json +177 -0
  262. package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
  263. package/specs/immune-scan-report-v1.schema.json +112 -0
  264. package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
  265. package/specs/memory-atom-v1.schema.json +59 -0
  266. package/specs/memory-event-v1.schema.json +42 -42
  267. package/specs/passport-v1.schema.json +50 -50
  268. package/specs/proof-of-non-use-v1.schema.json +65 -0
  269. package/specs/quarantine-record-v1.schema.json +126 -0
  270. package/specs/receipt-v1.schema.json +61 -61
  271. package/specs/state-checkpoint-v1.schema.json +37 -37
  272. package/specs/trust-bundle-v1.schema.json +56 -56
  273. package/specs/trust-card-v1.schema.json +119 -0
  274. package/docs/proof-network-launch-plan.md +0 -421
  275. package/packages/metering/PACKAGE_CONTRACT.md +0 -20
  276. package/scripts/build-ai-orchestration-plan.mjs +0 -248
@@ -0,0 +1,497 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import {
3
+ FEDERATION_PACKET_KINDS,
4
+ createFederationPacket,
5
+ deriveDestination,
6
+ hashFederationValue,
7
+ openFederationPacket,
8
+ } from '../../../mesh/src/index.js';
9
+ import {
10
+ createFederatedQueryRequest,
11
+ verifyBlindedMemoryGrant,
12
+ } from './capability-grant.js';
13
+
14
+ function publicKeyHex(value) {
15
+ if (Buffer.isBuffer(value) || value instanceof Uint8Array) return Buffer.from(value).toString('hex');
16
+ return String(value || '').toLowerCase();
17
+ }
18
+
19
+ function keyBuffer(value, name) {
20
+ if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
21
+ const buffer = Buffer.from(value);
22
+ if (buffer.length === 32) return buffer;
23
+ } else if (typeof value === 'string' && /^[0-9a-fA-F]{64}$/.test(value)) {
24
+ return Buffer.from(value, 'hex');
25
+ }
26
+ throw new Error(`${name} must be exactly 32 bytes`);
27
+ }
28
+
29
+ function samePublicKey(left, right) {
30
+ return publicKeyHex(left) === publicKeyHex(right);
31
+ }
32
+
33
+ function peerDescriptor(peerId, peer) {
34
+ if (!peer || typeof peer !== 'object') throw new Error('peer descriptor is required');
35
+ if (typeof peerId !== 'string' || peerId.length === 0) throw new Error('peerId is required');
36
+ const publicKey = keyBuffer(peer.publicKey ?? peer.public_key, 'peer.publicKey');
37
+ const encryptionPublicKey = keyBuffer(
38
+ peer.encryptionPublicKey ?? peer.encryption_public_key,
39
+ 'peer.encryptionPublicKey'
40
+ );
41
+ if (typeof peer.scope !== 'string' || peer.scope.length === 0) throw new Error('peer.scope is required');
42
+ const destination = deriveDestination(publicKey, encryptionPublicKey, peer.scope);
43
+ const declaredDestination = peer.destination ?? peer.destinationHex ?? peer.destination_hex;
44
+ if (declaredDestination !== undefined &&
45
+ !destination.equals(keyBuffer(declaredDestination, 'peer.destination'))) {
46
+ throw new Error('peer.destination does not match its signing key, encryption key, and scope');
47
+ }
48
+ return {
49
+ peerId,
50
+ publicKey,
51
+ encryptionPublicKey,
52
+ destination,
53
+ scope: peer.scope,
54
+ allowGrants: peer.allowGrants !== false,
55
+ };
56
+ }
57
+ const MAX_FEDERATION_BRIDGE_PEERS = 1_024;
58
+ const MAX_FEDERATION_BRIDGE_PENDING_QUERIES = 256;
59
+ const MAX_FEDERATION_BRIDGE_REPLAYS = 10_000;
60
+ const FEDERATION_BRIDGE_REPLAY_TTL_MS = 120_000;
61
+
62
+ /**
63
+ * Transport-neutral bridge between SDK federation authorization and encrypted,
64
+ * signed GhostMesh frames. Any EventEmitter-compatible GhostMesh transport with
65
+ * start(), stop(), and send(buffer, peerId) works, including in-memory and WS.
66
+ */
67
+ export class GhostMeshFederationBridge extends EventEmitter {
68
+ constructor(options = {}) {
69
+ super();
70
+ if (!options.enigma) throw new Error('enigma SDK instance is required');
71
+ if (!options.transport || typeof options.transport.send !== 'function' ||
72
+ typeof options.transport.on !== 'function') {
73
+ throw new Error('GhostMesh transport with send() and on() is required');
74
+ }
75
+
76
+ this.enigma = options.enigma;
77
+ this.router = options.router || options.enigma.federation;
78
+ this.identity = options.identity || options.enigma.mesh?.identity;
79
+ if (!this.identity) throw new Error('mesh identity is required');
80
+ this.scope = options.scope || this.identity.scope || options.enigma.scope;
81
+ if (!this.scope) throw new Error('mesh identity scope is required');
82
+ this.transport = options.transport;
83
+ this.manageTransport = options.manageTransport !== false;
84
+ this.requestTimeoutMs = options.requestTimeoutMs === undefined ? 5000 : options.requestTimeoutMs;
85
+ if (!Number.isSafeInteger(this.requestTimeoutMs) || this.requestTimeoutMs < 1) {
86
+ throw new Error('requestTimeoutMs must be a positive safe integer');
87
+ }
88
+
89
+ this.peers = new Map();
90
+ this.pendingQueries = new Map();
91
+ this.knownGrants = new Map();
92
+ this.seenPackets = new Map();
93
+ this.started = false;
94
+ this._packetHandler = ({ packetBuffer, fromPeerId, transportId }) => {
95
+ this.handlePacket(packetBuffer, fromPeerId, transportId).catch((error) => {
96
+ this.emit('rejected', { error, fromPeerId, transportId });
97
+ });
98
+ };
99
+
100
+ if (options.state !== undefined) this.importState(options.state);
101
+ for (const [grantId, record] of this.router.activeGrants) {
102
+ this.knownGrants.set(grantId, record.grant);
103
+ }
104
+ }
105
+
106
+ get localEndpoint() {
107
+ return { ...this.identity, scope: this.scope };
108
+ }
109
+
110
+ // Registration is the bridge's explicit peer-admission step. Callers may set
111
+ // allowGrants:false to admit query traffic without consenting to grants.
112
+ registerPeer(peerId, peer) {
113
+ if (!this.peers.has(peerId) && this.peers.size >= MAX_FEDERATION_BRIDGE_PEERS) {
114
+ throw new Error(`Federation peer capacity ${MAX_FEDERATION_BRIDGE_PEERS} reached`);
115
+ }
116
+ const descriptor = peerDescriptor(peerId, peer);
117
+ this.peers.set(peerId, descriptor);
118
+ return descriptor;
119
+ }
120
+
121
+ unregisterPeer(peerId) {
122
+ return this.peers.delete(peerId);
123
+ }
124
+
125
+ resolvePeer(target) {
126
+ if (typeof target === 'string') {
127
+ const peer = this.peers.get(target);
128
+ if (!peer) throw new Error(`Unknown federation peer: ${target}`);
129
+ return peer;
130
+ }
131
+ if (!target || typeof target !== 'object') throw new Error('Federation peer target is required');
132
+ const peerId = target.peerId ?? target.peer_id;
133
+ return peerDescriptor(peerId, target);
134
+ }
135
+
136
+ async start() {
137
+ if (this.started) return this;
138
+ this.transport.on('packet', this._packetHandler);
139
+ if (this.manageTransport && !this.transport.running) await this.transport.start();
140
+ this.started = true;
141
+ return this;
142
+ }
143
+
144
+ async stop() {
145
+ if (!this.started) return;
146
+ this.transport.off('packet', this._packetHandler);
147
+ for (const [packetId, pending] of this.pendingQueries) {
148
+ clearTimeout(pending.timer);
149
+ pending.reject(new Error(`Federation bridge stopped before response to ${packetId}`));
150
+ }
151
+ this.pendingQueries.clear();
152
+ this.started = false;
153
+ if (this.manageTransport && this.transport.running) await this.transport.stop();
154
+ }
155
+
156
+ exportState() {
157
+ return this.router.exportState();
158
+ }
159
+
160
+ importState(state) {
161
+ this.router.importState(state);
162
+ this.knownGrants.clear();
163
+ for (const [grantId, record] of this.router.activeGrants) {
164
+ this.knownGrants.set(grantId, record.grant);
165
+ }
166
+ return this;
167
+ }
168
+
169
+ getGrant(grantId) {
170
+ return this.knownGrants.get(grantId) || this.router.activeGrants.get(grantId)?.grant || null;
171
+ }
172
+
173
+ async sendFrame(frame, peerId) {
174
+ if (!this.started) throw new Error('Federation bridge must be started before sending');
175
+ const sent = await this.transport.send(frame.packetBuffer, peerId);
176
+ if (!sent) throw new Error(`GhostMesh transport could not send federation packet to ${peerId}`);
177
+ return frame;
178
+ }
179
+
180
+ async persistRouterMutation(snapshot) {
181
+ try {
182
+ await this.router.persistStateMutation();
183
+ } catch (error) {
184
+ this.router.importState(snapshot);
185
+ this.knownGrants.clear();
186
+ for (const [grantId, record] of this.router.activeGrants) {
187
+ this.knownGrants.set(grantId, record.grant);
188
+ }
189
+ throw error;
190
+ }
191
+ }
192
+
193
+ async distributeGrant(grant, target) {
194
+ const peer = this.resolvePeer(target);
195
+ const verdict = verifyBlindedMemoryGrant(grant, { expectedGranteePubkey: publicKeyHex(peer.publicKey) });
196
+ if (!verdict.ok) throw new Error(`Cannot distribute invalid capability grant: ${verdict.errors.join('; ')}`);
197
+ if (!samePublicKey(grant.granter_pubkey, this.identity.publicKey)) {
198
+ throw new Error('Only the grant granter may distribute a capability grant');
199
+ }
200
+
201
+ const priorState = this.router.exportState();
202
+ this.router.registerGrant(grant);
203
+ this.knownGrants.set(grant.grant_id, grant);
204
+ await this.persistRouterMutation(priorState);
205
+ const frame = createFederationPacket({
206
+ kind: FEDERATION_PACKET_KINDS.CAPABILITY_GRANT,
207
+ senderIdentity: this.localEndpoint,
208
+ senderScope: this.scope,
209
+ recipient: peer,
210
+ body: { grant },
211
+ });
212
+ await this.sendFrame(frame, peer.peerId);
213
+ return { ok: true, grant_id: grant.grant_id, packet_id: frame.packetId };
214
+ }
215
+
216
+ async query(grantOrId, query, target, options = {}) {
217
+ const grant = typeof grantOrId === 'string' ? this.getGrant(grantOrId) : grantOrId;
218
+ if (!grant) throw new Error(`Unknown capability grant: ${grantOrId}`);
219
+ if (this.router.revokedGrantIds.has(grant.grant_id)) {
220
+ throw new Error(`Capability grant ${grant.grant_id} has been revoked by granter`);
221
+ }
222
+ const verdict = verifyBlindedMemoryGrant(grant, {
223
+ expectedGranteePubkey: publicKeyHex(this.identity.publicKey),
224
+ });
225
+ if (!verdict.ok) throw new Error(`Cannot query with invalid capability grant: ${verdict.errors.join('; ')}`);
226
+
227
+ const peer = this.resolvePeer(target);
228
+ if (!samePublicKey(grant.granter_pubkey, peer.publicKey)) {
229
+ throw new Error('Federated query destination does not match the grant granter');
230
+ }
231
+ const topK = options.topK === undefined ? 5 : options.topK;
232
+ if (!Number.isSafeInteger(topK) || topK < 1 || topK > 100) {
233
+ throw new Error('topK must be an integer between 1 and 100');
234
+ }
235
+
236
+ const request = createFederatedQueryRequest({
237
+ grant,
238
+ query,
239
+ requesterSecretKey: this.identity.secretKey,
240
+ requesterPublicKey: this.identity.publicKey,
241
+ nonce: options.nonce,
242
+ timestamp: options.timestamp,
243
+ });
244
+ const body = { request, top_k: topK };
245
+ const requestHash = hashFederationValue(body);
246
+ const frame = createFederationPacket({
247
+ kind: FEDERATION_PACKET_KINDS.QUERY_REQUEST,
248
+ senderIdentity: this.localEndpoint,
249
+ senderScope: this.scope,
250
+ recipient: peer,
251
+ body,
252
+ hopTtl: options.hopTtl,
253
+ });
254
+
255
+ if (this.pendingQueries.size >= MAX_FEDERATION_BRIDGE_PENDING_QUERIES) {
256
+ throw new Error(`Federation pending query capacity ${MAX_FEDERATION_BRIDGE_PENDING_QUERIES} reached`);
257
+ }
258
+ const responsePromise = new Promise((resolve, reject) => {
259
+ const timer = setTimeout(() => {
260
+ this.pendingQueries.delete(frame.packetId);
261
+ reject(new Error(`Timed out waiting for federated query response ${frame.packetId}`));
262
+ }, options.timeoutMs ?? this.requestTimeoutMs);
263
+ timer.unref?.();
264
+ this.pendingQueries.set(frame.packetId, {
265
+ grant,
266
+ requestHash,
267
+ expectedSenderPublicKey: peer.publicKey,
268
+ resolve,
269
+ reject,
270
+ timer,
271
+ });
272
+ });
273
+
274
+ try {
275
+ await this.sendFrame(frame, peer.peerId);
276
+ } catch (error) {
277
+ const pending = this.pendingQueries.get(frame.packetId);
278
+ if (pending) {
279
+ clearTimeout(pending.timer);
280
+ this.pendingQueries.delete(frame.packetId);
281
+ pending.reject(error);
282
+ }
283
+ }
284
+ return await responsePromise;
285
+ }
286
+
287
+ async revoke(grantOrId, target, options = {}) {
288
+ const grant = typeof grantOrId === 'string' ? this.getGrant(grantOrId) : grantOrId;
289
+ if (!grant) throw new Error(`Unknown capability grant: ${grantOrId}`);
290
+ if (!samePublicKey(grant.granter_pubkey, this.identity.publicKey)) {
291
+ throw new Error('Only the grant granter may revoke a capability grant');
292
+ }
293
+ const peer = this.resolvePeer(target);
294
+ if (!samePublicKey(grant.grantee_pubkey, peer.publicKey)) {
295
+ throw new Error('Capability revocation destination does not match the grant grantee');
296
+ }
297
+ const revokedAt = options.revokedAt || new Date().toISOString();
298
+ const frame = createFederationPacket({
299
+ kind: FEDERATION_PACKET_KINDS.CAPABILITY_REVOCATION,
300
+ senderIdentity: this.localEndpoint,
301
+ senderScope: this.scope,
302
+ recipient: peer,
303
+ body: { grant_id: grant.grant_id, revoked_at: revokedAt },
304
+ });
305
+
306
+ const priorState = this.router.exportState();
307
+ this.router.revokeGrant(grant.grant_id);
308
+ this.knownGrants.delete(grant.grant_id);
309
+ await this.persistRouterMutation(priorState);
310
+ await this.sendFrame(frame, peer.peerId);
311
+ return { ok: true, grant_id: grant.grant_id, packet_id: frame.packetId, revoked_at: revokedAt };
312
+ }
313
+
314
+ async handlePacket(packetBuffer, fromPeerId, transportId = this.transport.id) {
315
+ const opened = openFederationPacket(packetBuffer, {
316
+ recipientIdentity: this.localEndpoint,
317
+ recipientScope: this.scope,
318
+ });
319
+ let resolvedPeerId = fromPeerId;
320
+ let peer = this.peers.get(resolvedPeerId);
321
+ if (!peer) {
322
+ const matches = Array.from(this.peers.entries())
323
+ .filter(([, candidate]) => samePublicKey(opened.sender.publicKey, candidate.publicKey));
324
+ if (matches.length !== 1) {
325
+ throw new Error(`Federation packet arrived from unregistered peer: ${fromPeerId}`);
326
+ }
327
+ [[resolvedPeerId, peer]] = matches;
328
+ }
329
+ if (!samePublicKey(opened.sender.publicKey, peer.publicKey)) {
330
+ throw new Error('Federation packet sender does not match the registered transport peer');
331
+ }
332
+ fromPeerId = resolvedPeerId;
333
+ const now = Date.now();
334
+ for (const [identity, seenAt] of this.seenPackets) {
335
+ if (now - seenAt > FEDERATION_BRIDGE_REPLAY_TTL_MS) this.seenPackets.delete(identity);
336
+ }
337
+ if (this.seenPackets.has(opened.replayIdentity)) {
338
+ throw new Error(`GhostMesh federation replay rejected: ${opened.replayIdentity}`);
339
+ }
340
+ if (this.seenPackets.size >= MAX_FEDERATION_BRIDGE_REPLAYS) {
341
+ throw new Error(`Federation packet replay cache capacity ${MAX_FEDERATION_BRIDGE_REPLAYS} reached`);
342
+ }
343
+ this.seenPackets.set(opened.replayIdentity, now);
344
+
345
+ try {
346
+ switch (opened.kind) {
347
+ case FEDERATION_PACKET_KINDS.CAPABILITY_GRANT:
348
+ return await this.handleGrant(opened, fromPeerId, transportId, peer);
349
+ case FEDERATION_PACKET_KINDS.QUERY_REQUEST:
350
+ return await this.handleQuery(opened, fromPeerId, transportId);
351
+ case FEDERATION_PACKET_KINDS.QUERY_RESPONSE:
352
+ return this.handleResponse(opened, fromPeerId, transportId);
353
+ case FEDERATION_PACKET_KINDS.CAPABILITY_REVOCATION:
354
+ return await this.handleRevocation(opened, fromPeerId, transportId);
355
+ default:
356
+ throw new Error(`Unsupported federation packet kind: ${opened.kind}`);
357
+ }
358
+ } catch (error) {
359
+ this.seenPackets.delete(opened.replayIdentity);
360
+ throw error;
361
+ }
362
+ }
363
+
364
+ async handleGrant(opened, fromPeerId, transportId, peer) {
365
+ if (!peer.allowGrants) {
366
+ throw new Error(`Federation peer ${fromPeerId} is not admitted to send capability grants`);
367
+ }
368
+ const grant = opened.body.grant;
369
+ if (!samePublicKey(opened.sender.publicKey, grant.granter_pubkey)) {
370
+ throw new Error('Capability grant packet sender does not match grant granter');
371
+ }
372
+ const verdict = verifyBlindedMemoryGrant(grant, {
373
+ expectedGranteePubkey: publicKeyHex(this.identity.publicKey),
374
+ });
375
+ if (!verdict.ok) throw new Error(`Received invalid capability grant: ${verdict.errors.join('; ')}`);
376
+ const priorState = this.router.exportState();
377
+ this.router.registerGrant(grant);
378
+ this.knownGrants.set(grant.grant_id, grant);
379
+ await this.persistRouterMutation(priorState);
380
+ const event = { grant, packet_id: opened.packetId, fromPeerId, transportId };
381
+ this.emit('grant', event);
382
+ return { action: 'GRANT_REGISTERED', ...event };
383
+ }
384
+
385
+ async handleQuery(opened, fromPeerId, transportId) {
386
+ const request = opened.body.request;
387
+ const grant = request.grant;
388
+ if (!samePublicKey(opened.sender.publicKey, request.requester_pubkey)) {
389
+ throw new Error('Federated query packet sender does not match request proof-of-possession key');
390
+ }
391
+ if (!samePublicKey(grant.granter_pubkey, this.identity.publicKey)) {
392
+ throw new Error('Federated query grant is not addressed to this granter');
393
+ }
394
+
395
+ const requestHash = hashFederationValue(opened.body);
396
+ let responseBody;
397
+ try {
398
+ const result = await this.router.queryFederatedCluster(request, undefined, { topK: opened.body.top_k });
399
+ const unlimitedAccess = !Number.isFinite(result.remainingAccess);
400
+ responseBody = {
401
+ ok: true,
402
+ result: {
403
+ ...result,
404
+ remainingAccess: unlimitedAccess ? null : result.remainingAccess,
405
+ unlimitedAccess,
406
+ },
407
+ error: null,
408
+ request_hash: requestHash,
409
+ };
410
+ } catch (error) {
411
+ responseBody = {
412
+ ok: false,
413
+ result: null,
414
+ error: error.message,
415
+ request_hash: requestHash,
416
+ };
417
+ }
418
+
419
+ const responseFrame = createFederationPacket({
420
+ kind: FEDERATION_PACKET_KINDS.QUERY_RESPONSE,
421
+ senderIdentity: this.localEndpoint,
422
+ senderScope: this.scope,
423
+ recipient: opened.sender,
424
+ correlationId: opened.packetId,
425
+ body: responseBody,
426
+ });
427
+ await this.sendFrame(responseFrame, fromPeerId);
428
+ const event = {
429
+ request,
430
+ response: responseBody,
431
+ packet_id: opened.packetId,
432
+ response_packet_id: responseFrame.packetId,
433
+ fromPeerId,
434
+ transportId,
435
+ };
436
+ this.emit('query', event);
437
+ return { action: 'QUERY_RESPONDED', ...event, responsePacket: responseFrame.packetBuffer };
438
+ }
439
+
440
+ handleResponse(opened, fromPeerId, transportId) {
441
+ const pending = this.pendingQueries.get(opened.correlationId);
442
+ if (!pending) {
443
+ throw new Error(`Federated response correlation is unknown or already settled: ${opened.correlationId}`);
444
+ }
445
+ if (!samePublicKey(opened.sender.publicKey, pending.expectedSenderPublicKey)) {
446
+ throw new Error('Federated response sender does not match query destination');
447
+ }
448
+ if (opened.body.request_hash !== pending.requestHash) {
449
+ throw new Error('Federated response request hash does not match the correlated query');
450
+ }
451
+ if (opened.body.ok && (opened.body.result.grant_id !== pending.grant.grant_id ||
452
+ opened.body.result.scope !== pending.grant.scope)) {
453
+ throw new Error('Federated response result does not match the capability grant');
454
+ }
455
+
456
+ clearTimeout(pending.timer);
457
+ this.pendingQueries.delete(opened.correlationId);
458
+ if (opened.body.ok) {
459
+ pending.resolve({
460
+ ...opened.body.result,
461
+ request_packet_id: opened.correlationId,
462
+ response_packet_id: opened.packetId,
463
+ });
464
+ } else {
465
+ pending.reject(new Error(`Federated query rejected: ${opened.body.error}`));
466
+ }
467
+ const event = { response: opened.body, packet_id: opened.packetId, fromPeerId, transportId };
468
+ this.emit('response', event);
469
+ return { action: 'RESPONSE_CORRELATED', ...event };
470
+ }
471
+
472
+ async handleRevocation(opened, fromPeerId, transportId) {
473
+ const grantId = opened.body.grant_id;
474
+ const grant = this.getGrant(grantId);
475
+ if (!grant) throw new Error(`Received revocation for unknown capability grant: ${grantId}`);
476
+ if (!samePublicKey(opened.sender.publicKey, grant.granter_pubkey)) {
477
+ throw new Error('Capability revocation packet sender does not match grant granter');
478
+ }
479
+ const priorState = this.router.exportState();
480
+ this.router.revokeGrant(grantId);
481
+ this.knownGrants.delete(grantId);
482
+ await this.persistRouterMutation(priorState);
483
+ const event = {
484
+ grant_id: grantId,
485
+ revoked_at: opened.body.revoked_at,
486
+ packet_id: opened.packetId,
487
+ fromPeerId,
488
+ transportId,
489
+ };
490
+ this.emit('revocation', event);
491
+ return { action: 'GRANT_REVOKED', ...event };
492
+ }
493
+ }
494
+
495
+ export function createGhostMeshFederationBridge(options) {
496
+ return new GhostMeshFederationBridge(options);
497
+ }
@@ -0,0 +1,3 @@
1
+ export * from './capability-grant.js';
2
+ export * from './federation-router.js';
3
+ export * from './ghostmesh-bridge.js';