enigma-memory 0.1.17 → 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 (290) hide show
  1. package/README.md +85 -27
  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 +4979 -3263
  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/SIMULATION.md +14 -9
  74. package/deploy/docker-compose.local-production-simulation.yml +54 -12
  75. package/docs/benchmark-attestation-network.md +487 -487
  76. package/docs/benchmark-reproducibility.md +289 -289
  77. package/docs/blockchain-only-mechanisms.md +400 -400
  78. package/docs/browser-extension-install.md +8 -6
  79. package/docs/client-connectors.md +16 -12
  80. package/docs/demo-proof-network.md +275 -275
  81. package/docs/developer-ecosystem.md +15 -13
  82. package/docs/developer-proof-quickstart.md +325 -325
  83. package/docs/enigma-memory-ready-conformance.md +378 -376
  84. package/docs/install-anywhere.md +64 -30
  85. package/docs/installers-and-desktop.md +8 -7
  86. package/docs/memory-benchmarks.md +1 -1
  87. package/docs/memory-drive-health-model.md +690 -690
  88. package/docs/novelty-invention-candidates.md +161 -161
  89. package/docs/proof-network-build-notes.md +240 -240
  90. package/docs/proof-network-claim-boundaries.md +320 -318
  91. package/docs/proof-network.md +339 -339
  92. package/docs/sdk-api.md +324 -324
  93. package/docs/solana-proof-rail.md +453 -453
  94. package/examples/01-quickstart-agent/index.mjs +49 -0
  95. package/examples/01_agent_memory_quickstart.mjs +57 -0
  96. package/examples/02-multi-agent-swarm/index.mjs +57 -0
  97. package/examples/02_cross_model_passport.mjs +64 -0
  98. package/examples/03-langchain-memory/index.mjs +41 -0
  99. package/examples/03_poseidon_commitment_verification.mjs +71 -0
  100. package/examples/04-python-trading-agent/trader.py +49 -0
  101. package/examples/README.md +27 -0
  102. package/examples/ci/github-actions.yml +7 -2
  103. package/package.json +410 -278
  104. package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
  105. package/packages/connectors/src/index.js +196 -4
  106. package/packages/connectors/swarm-router.mjs +168 -0
  107. package/packages/core/src/index.js +249 -2
  108. package/packages/core/src/version.mjs +7 -0
  109. package/packages/dev-tools/package.json +19 -0
  110. package/packages/dev-tools/src/index.js +4 -0
  111. package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
  112. package/packages/dev-tools/src/swarm-simulator.js +101 -0
  113. package/packages/dev-tools/src/vault-inspector.js +114 -0
  114. package/packages/dev-tools/src/vector-benchmark.js +100 -0
  115. package/packages/developer-platform/src/access-credentials.js +341 -0
  116. package/packages/developer-platform/src/http.js +132 -0
  117. package/packages/developer-platform/src/index.js +4 -0
  118. package/packages/developer-platform/src/usage-http.js +60 -0
  119. package/packages/developer-platform/src/usage.js +295 -0
  120. package/packages/enclave-runtime/attestation.mjs +159 -0
  121. package/packages/enclave-runtime/index.mjs +47 -0
  122. package/packages/enclave-runtime/session-manager.mjs +253 -0
  123. package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
  124. package/packages/enigma-reflex/package.json +14 -0
  125. package/packages/enigma-reflex/src/index.js +204 -0
  126. package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
  127. package/packages/enigma-reflex/training/requirements.txt +8 -0
  128. package/packages/enigma-reflex/training/train.py +314 -0
  129. package/packages/enigma-weave/LICENSE +22 -0
  130. package/packages/enigma-weave/UPSTREAM.json +21 -0
  131. package/packages/enigma-weave/package.json +14 -0
  132. package/packages/enigma-weave/src/index.js +286 -0
  133. package/packages/hosted-cloud/src/index.js +80 -5
  134. package/packages/importers/src/index.js +432 -0
  135. package/packages/inference-runtime/src/browser.js +401 -0
  136. package/packages/inference-runtime/src/chat.js +265 -0
  137. package/packages/inference-runtime/src/code.js +407 -0
  138. package/packages/inference-runtime/src/contracts.js +162 -0
  139. package/packages/inference-runtime/src/http.js +232 -0
  140. package/packages/inference-runtime/src/image.js +186 -0
  141. package/packages/inference-runtime/src/index.js +10 -0
  142. package/packages/inference-runtime/src/model-router.js +320 -0
  143. package/packages/inference-runtime/src/platform.js +125 -0
  144. package/packages/inference-runtime/src/privacy.js +400 -0
  145. package/packages/inference-runtime/src/video.js +253 -0
  146. package/packages/mcp-server/README.md +22 -6
  147. package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
  148. package/packages/mcp-server/src/index.js +2498 -1185
  149. package/packages/mcp-server/src/oauth.js +561 -0
  150. package/packages/mcp-server/src/private-handoff.js +84 -0
  151. package/packages/mcp-server/src/remote-http.js +273 -0
  152. package/packages/mcp-server/src/remote-policy.js +72 -0
  153. package/packages/mcp-server/swarm-bridge.mjs +361 -0
  154. package/packages/mesh/index.d.ts +283 -0
  155. package/packages/mesh/package.json +23 -0
  156. package/packages/mesh/src/crypto.js +189 -0
  157. package/packages/mesh/src/federation-packets.js +353 -0
  158. package/packages/mesh/src/gossip.js +311 -0
  159. package/packages/mesh/src/index.js +6 -0
  160. package/packages/mesh/src/protocol.js +255 -0
  161. package/packages/mesh/src/router.js +279 -0
  162. package/packages/mesh/src/transport.js +306 -0
  163. package/packages/passport/src/index.js +436 -7
  164. package/packages/private-economy/src/credits-http.js +100 -0
  165. package/packages/private-economy/src/credits.js +447 -0
  166. package/packages/private-economy/src/index.js +5 -0
  167. package/packages/private-economy/src/payments-http.js +120 -0
  168. package/packages/private-economy/src/payments.js +509 -0
  169. package/packages/private-economy/src/x402.js +346 -0
  170. package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
  171. package/packages/rag/index.d.ts +182 -0
  172. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
  173. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
  174. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
  175. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
  176. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
  177. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
  178. package/packages/rag/package.json +27 -0
  179. package/packages/rag/src/blinded-search.js +109 -0
  180. package/packages/rag/src/bm25.js +169 -0
  181. package/packages/rag/src/embeddings.js +459 -0
  182. package/packages/rag/src/hybrid.js +76 -0
  183. package/packages/rag/src/index.js +38 -0
  184. package/packages/rag/src/reranker.js +61 -0
  185. package/packages/rag/src/research.js +107 -0
  186. package/packages/rag/src/vector-store.js +430 -0
  187. package/packages/rag/src/verify-model-artifacts.mjs +4 -0
  188. package/packages/sdk/index.d.ts +760 -0
  189. package/packages/sdk/package.json +33 -0
  190. package/packages/sdk/python/README.md +24 -0
  191. package/packages/sdk/python/enigma_sdk.py +250 -0
  192. package/packages/sdk/python/pyproject.toml +34 -0
  193. package/packages/sdk/python/requirements.txt +1 -0
  194. package/packages/sdk/python/setup.py +20 -0
  195. package/packages/sdk/src/federation/capability-grant.js +389 -0
  196. package/packages/sdk/src/federation/federation-router.js +360 -0
  197. package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
  198. package/packages/sdk/src/federation/index.js +3 -0
  199. package/packages/sdk/src/index.js +1796 -0
  200. package/packages/sdk/src/intelligence/contradiction.js +337 -0
  201. package/packages/sdk/src/intelligence/decision-engine.js +155 -0
  202. package/packages/sdk/src/intelligence/index.js +4 -0
  203. package/packages/sdk/src/intelligence/ontology.js +122 -0
  204. package/packages/sdk/src/intelligence/temporal.js +123 -0
  205. package/packages/sdk/src/market-client.js +142 -0
  206. package/packages/sdk/src/mesh-client.js +110 -0
  207. package/packages/sdk/src/middleware/index.js +3 -0
  208. package/packages/sdk/src/middleware/langchain.js +159 -0
  209. package/packages/sdk/src/middleware/llamaindex.js +101 -0
  210. package/packages/sdk/src/middleware/vercel-ai.js +112 -0
  211. package/packages/sdk/src/rag-client.js +85 -0
  212. package/packages/sdk/src/swarm-orchestrator.js +260 -0
  213. package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
  214. package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
  215. package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
  216. package/packages/snapcompact/index.d.ts +284 -0
  217. package/packages/snapcompact/package.json +25 -0
  218. package/packages/snapcompact/src/index.js +716 -0
  219. package/packages/storage/PACKAGE_CONTRACT.md +1 -1
  220. package/packages/terminal-console/animations.mjs +240 -0
  221. package/packages/terminal-console/auto-anchor.mjs +220 -0
  222. package/packages/terminal-console/banner.mjs +91 -0
  223. package/packages/terminal-console/commands.mjs +459 -0
  224. package/packages/terminal-console/delegation.mjs +152 -0
  225. package/packages/terminal-console/index.mjs +5 -0
  226. package/packages/terminal-console/outbox.mjs +143 -0
  227. package/packages/terminal-console/phantom-bridge.mjs +637 -0
  228. package/packages/terminal-console/repl.mjs +136 -0
  229. package/packages/terminal-console/signer-store.mjs +130 -0
  230. package/packages/terminal-console/solana-rpc.mjs +214 -0
  231. package/packages/terminal-console/solana-transport.mjs +189 -0
  232. package/packages/terminal-tui/dashboard.mjs +214 -0
  233. package/packages/terminal-tui/index.mjs +28 -0
  234. package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
  235. package/packages/terminal-tui/telemetry-hud.mjs +137 -0
  236. package/packages/vault/index.d.ts +449 -0
  237. package/packages/vault/package.json +27 -0
  238. package/packages/vault/src/e2ee.mjs +393 -0
  239. package/packages/vault/src/enclave.js +481 -0
  240. package/packages/vault/src/erasure.js +207 -0
  241. package/packages/vault/src/index.js +1150 -125
  242. package/packages/vault/src/persistence.js +307 -0
  243. package/packages/vault/src/poseidon.js +354 -0
  244. package/packages/vault/src/receipt.js +459 -0
  245. package/scripts/benchmark-optical-context.mjs +166 -0
  246. package/scripts/bootstrap-enigma.mjs +502 -0
  247. package/scripts/build-edge-backend-workers.mjs +20 -5
  248. package/scripts/build-goal-completion-audit.mjs +72 -25
  249. package/scripts/build-hosted-api-key-lifecycle.mjs +292 -274
  250. package/scripts/build-hosted-customer-lifecycle.mjs +493 -476
  251. package/scripts/build-hosted-probe-worker.mjs +19 -4
  252. package/scripts/build-installer-assets.mjs +409 -389
  253. package/scripts/build-operator-evidence-starter.mjs +59 -1
  254. package/scripts/build-production-backend-env-kit.mjs +2 -0
  255. package/scripts/build-production-unblocker.mjs +4 -1
  256. package/scripts/build-proof-network-packet.mjs +213 -213
  257. package/scripts/check.mjs +25 -4
  258. package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
  259. package/scripts/install-enigma-local.mjs +18 -5
  260. package/scripts/release-audit.mjs +74 -115
  261. package/scripts/release-provenance.mjs +12 -2
  262. package/scripts/run-backend-readiness-smoke.mjs +112 -10
  263. package/scripts/run-standard-memory-benchmarks.mjs +1354 -1352
  264. package/scripts/scan-secrets.mjs +178 -0
  265. package/scripts/simulate-production-env.mjs +71 -10
  266. package/scripts/validate-hosted-backend-live.mjs +112 -1
  267. package/specs/antibody-pack-v1.schema.json +95 -0
  268. package/specs/antigen-envelope-v1.schema.json +81 -0
  269. package/specs/boundary-manifest-v1.schema.json +35 -35
  270. package/specs/capsule-v1.schema.json +55 -55
  271. package/specs/claim-boundary-manifest-v1.schema.json +22 -22
  272. package/specs/claim-ledger-v1.schema.json +291 -0
  273. package/specs/context-passport-v1.schema.json +59 -0
  274. package/specs/deletion-tombstone-v1.schema.json +26 -26
  275. package/specs/evidence-packet-v1.schema.json +177 -0
  276. package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
  277. package/specs/immune-scan-report-v1.schema.json +112 -0
  278. package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
  279. package/specs/memory-atom-v1.schema.json +59 -0
  280. package/specs/memory-event-v1.schema.json +42 -42
  281. package/specs/passport-v1.schema.json +50 -50
  282. package/specs/proof-of-non-use-v1.schema.json +65 -0
  283. package/specs/quarantine-record-v1.schema.json +126 -0
  284. package/specs/receipt-v1.schema.json +61 -61
  285. package/specs/state-checkpoint-v1.schema.json +37 -37
  286. package/specs/trust-bundle-v1.schema.json +56 -56
  287. package/specs/trust-card-v1.schema.json +119 -0
  288. package/docs/proof-network-launch-plan.md +0 -421
  289. package/packages/metering/PACKAGE_CONTRACT.md +0 -20
  290. package/scripts/build-ai-orchestration-plan.mjs +0 -248
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { canonicalize, receiptHash, sha256Hex, verifyReceipt } from '../../core/src/index.js';
2
+ import { canonicalize, MerkleSet, receiptHash, sha256Hex, verifyReceipt } from '../../core/src/index.js';
3
3
  import {
4
4
  createMemoryAccessReceipt,
5
5
  createMemoryOptimizationPlan,
@@ -8,6 +8,50 @@ import {
8
8
 
9
9
  const PASSPORT_SCHEMA = 'enigma.passport.v1';
10
10
  const CONTEXT_PACK_SCHEMA = 'enigma.context_pack.v1';
11
+ const CONTEXT_PASSPORT_SCHEMA = 'enigma.context_passport.v1';
12
+ const PROOF_OF_NON_USE_SCHEMA = 'enigma.proof_of_non_use.v1';
13
+ const VERIFIED_STATUS = 'verified';
14
+ const FAILED_PROOF_STATUS = 'failed';
15
+ const FAIL_CLOSED_STATUS = 'fail_closed';
16
+ const PROOF_POLICY_DECISIONS = new Set(['allow', 'deny', 'redact', 'quarantine', 'tombstone_only']);
17
+ const PROOF_VERIFIER_STATUSES = new Set([VERIFIED_STATUS, FAILED_PROOF_STATUS, 'inconclusive']);
18
+ const CONTEXT_PASSPORT_FIELDS = Object.freeze([
19
+ 'schema',
20
+ 'passport_id',
21
+ 'issued_at',
22
+ 'subject_ref',
23
+ 'query_commitment',
24
+ 'selected_context_root',
25
+ 'omitted_context_root',
26
+ 'tombstone_context_root',
27
+ 'selected_count',
28
+ 'omitted_count',
29
+ 'tombstone_count',
30
+ 'capability_ids',
31
+ 'policy_ids',
32
+ 'proof_refs',
33
+ ]);
34
+ const PROOF_OF_NON_USE_FIELDS = Object.freeze([
35
+ 'schema',
36
+ 'proof_id',
37
+ 'issued_at',
38
+ 'subject_ref',
39
+ 'query_commitment',
40
+ 'candidate_set_root',
41
+ 'selected_set_root',
42
+ 'omitted_set_root',
43
+ 'tombstone_set_root',
44
+ 'candidate_count',
45
+ 'selected_count',
46
+ 'omitted_count',
47
+ 'tombstone_count',
48
+ 'policy_id',
49
+ 'policy_decision',
50
+ 'verifier_status',
51
+ 'verifier_ref',
52
+ 'receipt_log_root',
53
+ 'receipt_refs',
54
+ ]);
11
55
  const ZERO_ROOT = `sha256:${'0'.repeat(64)}`;
12
56
  const ROOT_RE = /^sha256:[a-f0-9]{64}$/;
13
57
  const PREVIOUS_RECEIPT_RE = /^(GENESIS|sha256:[a-f0-9]{64})$/;
@@ -134,12 +178,16 @@ function tokenOverlapScore(queryTokens, memoryTokens) {
134
178
  }
135
179
 
136
180
  function strictQueryRelevance(args) {
137
- return args.strict_relevance === true
138
- || args.strictRelevance === true
139
- || args.require_relevance === true
140
- || args.requireRelevance === true
141
- || args.query_relevance === 'strict'
142
- || args.queryRelevance === 'strict';
181
+ if (args.include_unrelated === true || args.includeUnrelated === true) return false;
182
+ if (args.no_strict_relevance === true || args.noStrictRelevance === true) return false;
183
+ if (args.strict_relevance === false || args.strictRelevance === false) return false;
184
+ if (args.require_relevance === false || args.requireRelevance === false) return false;
185
+ if (args.query_relevance === 'fallback' || args.queryRelevance === 'fallback') return false;
186
+ if (args.strict_relevance === true || args.strictRelevance === true) return true;
187
+ if (args.require_relevance === true || args.requireRelevance === true) return true;
188
+ if (args.query_relevance === 'strict' || args.queryRelevance === 'strict') return true;
189
+ const query = typeof args.query === 'string' ? args.query.trim() : String(args.query ?? '').trim();
190
+ return query.length > 0;
143
191
  }
144
192
 
145
193
  function relevanceCandidateSet(args, candidates) {
@@ -578,6 +626,222 @@ function receiptDigest(receipt) {
578
626
  }
579
627
  }
580
628
 
629
+ function merkleRootFrom(values) {
630
+ return new MerkleSet(sortedRefs(values)).root();
631
+ }
632
+
633
+ function sortedRefs(values) {
634
+ const refs = [];
635
+ for (const value of values ?? []) {
636
+ if (value === undefined || value === null) continue;
637
+ const ref = String(value);
638
+ if (ref.length > 0) refs.push(ref);
639
+ }
640
+ return [...new Set(refs)].sort();
641
+ }
642
+
643
+ function receiptRefsFromReceipts(receipts) {
644
+ const refs = [];
645
+ for (const receipt of receipts ?? []) {
646
+ const digest = typeof receipt === 'string' ? receipt : receiptDigest(publicReceipt(receipt)) ?? receiptDigest(receipt);
647
+ if (typeof digest === 'string' && digest.length > 0) refs.push(digest);
648
+ }
649
+ return sortedRefs(refs);
650
+ }
651
+
652
+ function receiptRefsFromContextPack(contextPack) {
653
+ return sortedRefs([
654
+ ...(contextPack?.receipt_hashes ?? []),
655
+ ...receiptRefsFromReceipts(contextPack?.receipts),
656
+ ...receiptRefsFromReceipts(contextPack?.retrieval_receipts),
657
+ ...receiptRefsFromReceipts(contextPack?.injection_receipts),
658
+ ]);
659
+ }
660
+
661
+ function receiptRefsFromArgs(args, contextPack) {
662
+ return sortedRefs([
663
+ ...(args.proof_refs ?? args.proofRefs ?? []),
664
+ ...(args.receipt_refs ?? args.receiptRefs ?? []),
665
+ ...receiptRefsFromContextPack(contextPack),
666
+ ]);
667
+ }
668
+
669
+ function hashedRef(prefix, value) {
670
+ return `${prefix}_${sha256Hex(canonical(value)).slice(0, 32)}`;
671
+ }
672
+
673
+ function queryCommitment(args, contextPack) {
674
+ const explicit = args.query_commitment ?? args.queryCommitment;
675
+ if (explicit !== undefined) return String(explicit);
676
+ return `sha256:${sha256Hex(String(args.query ?? contextPack?.query ?? ''))}`;
677
+ }
678
+
679
+ function policyIdsFrom(args, passport, contextPack) {
680
+ const ids = sortedRefs([
681
+ ...(args.policy_ids ?? args.policyIds ?? []),
682
+ ...(passport?.policies ?? []),
683
+ ...((contextPack?.receipts ?? []).map((receipt) => receipt?.policy_id).filter(Boolean)),
684
+ ]);
685
+ return ids.length > 0 ? ids : ['local-default'];
686
+ }
687
+
688
+ function capabilityIdsFrom(args) {
689
+ return sortedRefs(args.capability_ids ?? args.capabilityIds ?? ['capability:context-passport']);
690
+ }
691
+
692
+ function explicitRefs(args, snakeKey, camelKey) {
693
+ const refs = args[snakeKey] ?? args[camelKey];
694
+ return refs === undefined ? undefined : sortedRefs(refs);
695
+ }
696
+
697
+ function contextPackFromArgs(args) {
698
+ const contextPack = args.contextPack ?? args.context_pack ?? args.pack;
699
+ if (contextPack) return contextPack;
700
+ if (args.vault) return compileContextPack(args);
701
+ return undefined;
702
+ }
703
+
704
+ function contextSelectionSummary(args = {}) {
705
+ const contextPack = args.contextPack ?? args.context_pack ?? args.pack;
706
+ const passport = args.passport;
707
+ const selected = explicitRefs(args, 'selected_context_refs', 'selectedContextRefs')
708
+ ?? explicitRefs(args, 'selected_refs', 'selectedRefs')
709
+ ?? sortedRefs(memoryAddressesFromPack(contextPack));
710
+ const selectedSet = new Set(selected);
711
+
712
+ const activeRefs = sortedRefs([
713
+ ...activeAddressesFrom(args.active_state ?? args.activeState),
714
+ ...activeAddressesFrom(args.vault),
715
+ ...activeAddressesFrom(passport),
716
+ ]);
717
+ const omitted = explicitRefs(args, 'omitted_context_refs', 'omittedContextRefs')
718
+ ?? explicitRefs(args, 'omitted_refs', 'omittedRefs')
719
+ ?? activeRefs.filter((ref) => !selectedSet.has(ref));
720
+ const tombstone = explicitRefs(args, 'tombstone_context_refs', 'tombstoneContextRefs')
721
+ ?? explicitRefs(args, 'tombstone_refs', 'tombstoneRefs')
722
+ ?? sortedRefs([
723
+ ...tombstoneAddressesFrom(args.tombstones),
724
+ ...tombstoneAddressesFrom(args.vault),
725
+ ...tombstoneAddressesFrom(passport),
726
+ ...(passport?.tombstone_addresses ?? []),
727
+ ]);
728
+
729
+ return {
730
+ selected,
731
+ omitted,
732
+ tombstone,
733
+ selected_context_root: merkleRootFrom(selected),
734
+ omitted_context_root: merkleRootFrom(omitted),
735
+ tombstone_context_root: merkleRootFrom(tombstone),
736
+ selected_count: selected.length,
737
+ omitted_count: omitted.length,
738
+ tombstone_count: tombstone.length,
739
+ };
740
+ }
741
+
742
+ function proofSelectionSummary(args = {}) {
743
+ const base = contextSelectionSummary(args);
744
+ const candidate = explicitRefs(args, 'candidate_refs', 'candidateRefs')
745
+ ?? sortedRefs([...base.selected, ...base.omitted, ...base.tombstone]);
746
+ return {
747
+ ...base,
748
+ candidate,
749
+ candidate_set_root: merkleRootFrom(candidate),
750
+ selected_set_root: merkleRootFrom(base.selected),
751
+ omitted_set_root: merkleRootFrom(base.omitted),
752
+ tombstone_set_root: merkleRootFrom(base.tombstone),
753
+ candidate_count: candidate.length,
754
+ };
755
+ }
756
+
757
+ function missingBoundaryFields(artifact, requiredFields) {
758
+ const errors = [];
759
+ for (const field of requiredFields) {
760
+ if (artifact?.[field] === undefined || artifact?.[field] === null) errors.push(`missing ${field}`);
761
+ }
762
+ return errors;
763
+ }
764
+
765
+ function validateRootField(artifact, field, errors) {
766
+ if (!ROOT_RE.test(artifact?.[field] ?? '')) errors.push(`invalid ${field}`);
767
+ }
768
+
769
+ function validateCountField(artifact, field, errors) {
770
+ if (!Number.isInteger(artifact?.[field]) || artifact[field] < 0) errors.push(`invalid ${field}`);
771
+ }
772
+
773
+ function validateRefArray(artifact, field, errors) {
774
+ const refs = artifact?.[field];
775
+ if (!Array.isArray(refs) || refs.length === 0) {
776
+ errors.push(`missing ${field}`);
777
+ return;
778
+ }
779
+ for (const ref of refs) {
780
+ if (typeof ref !== 'string' || ref.length === 0) errors.push(`invalid ${field}`);
781
+ }
782
+ }
783
+
784
+ function publicBoundaryArtifact(artifact) {
785
+ if (!artifact || typeof artifact !== 'object') return null;
786
+ const fields = artifact.schema === CONTEXT_PASSPORT_SCHEMA
787
+ ? CONTEXT_PASSPORT_FIELDS
788
+ : artifact.schema === PROOF_OF_NON_USE_SCHEMA
789
+ ? PROOF_OF_NON_USE_FIELDS
790
+ : [];
791
+ if (fields.length === 0) return null;
792
+ const out = {};
793
+ for (const field of fields) {
794
+ if (artifact[field] !== undefined) out[field] = artifact[field];
795
+ }
796
+ return out;
797
+ }
798
+
799
+
800
+ function invalidBoundaryResult(artifact, errors, status = FAIL_CLOSED_STATUS) {
801
+ const publicArtifact = publicBoundaryArtifact(artifact);
802
+ return {
803
+ valid: false,
804
+ verifier_status: status,
805
+ error: errors[0],
806
+ reason: errors[0],
807
+ errors,
808
+ public_artifact: publicArtifact,
809
+ canonical: publicArtifact ? canonical(publicArtifact) : null,
810
+ };
811
+ }
812
+
813
+ function validBoundaryResult(artifact) {
814
+ return {
815
+ valid: true,
816
+ verifier_status: VERIFIED_STATUS,
817
+ public_artifact: artifact,
818
+ canonical: canonical(artifact),
819
+ };
820
+ }
821
+
822
+ function compareRootAndCount(artifact, expected, rootField, countField, expectedRootField, expectedCountField, errors) {
823
+ if (artifact[rootField] !== expected[expectedRootField]) errors.push(`${rootField} mismatch`);
824
+ if (artifact[countField] !== expected[expectedCountField]) errors.push(`${countField} mismatch`);
825
+ }
826
+
827
+ function verifyRequiredReceiptRefs(artifactRefs, expectedRefs, errors, field) {
828
+ if (expectedRefs.length === 0) return;
829
+ const refs = new Set(artifactRefs);
830
+ for (const ref of expectedRefs) {
831
+ if (!refs.has(ref)) errors.push(`missing ${field} receipt ref: ${ref}`);
832
+ }
833
+ }
834
+
835
+ function verifyContextPackWhenTrusted(args, contextPack, errors) {
836
+ if (!contextPack || !trustedKeyOptions(args)) return;
837
+ try {
838
+ const result = verifyContextPack({ ...args, contextPack });
839
+ if (result?.valid !== true) errors.push(`context pack verification failed: ${result?.reason ?? 'invalid'}`);
840
+ } catch (error) {
841
+ errors.push(`context pack verification failed: ${error.message}`);
842
+ }
843
+ }
844
+
581
845
  export function createPassport(args = {}) {
582
846
  const vault = args.vault;
583
847
  const createdAt = nowIso(args.now);
@@ -775,6 +1039,171 @@ export function verifyContextPack(args = {}) {
775
1039
  };
776
1040
  }
777
1041
 
1042
+ export function createContextPassport(args = {}) {
1043
+ const contextPack = contextPackFromArgs(args);
1044
+ const passport = args.passport ?? (args.vault ? createPassport({ vault: args.vault, now: args.now }) : undefined);
1045
+ const summary = contextSelectionSummary({ ...args, contextPack, passport });
1046
+ const proofRefs = receiptRefsFromArgs(args, contextPack);
1047
+ if (proofRefs.length === 0) throw new Error('createContextPassport requires proof_refs or context pack receipts');
1048
+ return {
1049
+ schema: CONTEXT_PASSPORT_SCHEMA,
1050
+ passport_id: args.passport_id ?? args.passportId ?? contextPack?.passport_id ?? passport?.passport_id ?? `context_passport_${randomUUID()}`,
1051
+ issued_at: nowIso(args.now),
1052
+ subject_ref: args.subject_ref ?? args.subjectRef ?? hashedRef('subject', passport?.owner?.subject_id ?? args.vault?.subject_id ?? contextPack?.passport_id ?? 'local-subject'),
1053
+ query_commitment: queryCommitment(args, contextPack),
1054
+ selected_context_root: summary.selected_context_root,
1055
+ omitted_context_root: summary.omitted_context_root,
1056
+ tombstone_context_root: summary.tombstone_context_root,
1057
+ selected_count: summary.selected_count,
1058
+ omitted_count: summary.omitted_count,
1059
+ tombstone_count: summary.tombstone_count,
1060
+ capability_ids: capabilityIdsFrom(args),
1061
+ policy_ids: policyIdsFrom(args, passport, contextPack),
1062
+ proof_refs: proofRefs,
1063
+ };
1064
+ }
1065
+
1066
+ export function verifyContextPassport(args = {}) {
1067
+ const contextPassport = args.schema === CONTEXT_PASSPORT_SCHEMA ? args : (args.contextPassport ?? args.context_passport ?? args.passportArtifact ?? args.artifact);
1068
+ if (!contextPassport || contextPassport.schema !== CONTEXT_PASSPORT_SCHEMA) {
1069
+ return invalidBoundaryResult(contextPassport, ['verifyContextPassport requires an enigma.context_passport.v1 artifact']);
1070
+ }
1071
+
1072
+ const errors = missingBoundaryFields(contextPassport, [
1073
+ 'schema',
1074
+ 'passport_id',
1075
+ 'issued_at',
1076
+ 'subject_ref',
1077
+ 'query_commitment',
1078
+ 'selected_context_root',
1079
+ 'omitted_context_root',
1080
+ 'tombstone_context_root',
1081
+ 'selected_count',
1082
+ 'omitted_count',
1083
+ 'tombstone_count',
1084
+ 'capability_ids',
1085
+ 'policy_ids',
1086
+ 'proof_refs',
1087
+ ]);
1088
+ validateRootField(contextPassport, 'query_commitment', errors);
1089
+ validateRootField(contextPassport, 'selected_context_root', errors);
1090
+ validateRootField(contextPassport, 'omitted_context_root', errors);
1091
+ validateRootField(contextPassport, 'tombstone_context_root', errors);
1092
+ validateCountField(contextPassport, 'selected_count', errors);
1093
+ validateCountField(contextPassport, 'omitted_count', errors);
1094
+ validateCountField(contextPassport, 'tombstone_count', errors);
1095
+ validateRefArray(contextPassport, 'capability_ids', errors);
1096
+ validateRefArray(contextPassport, 'policy_ids', errors);
1097
+ validateRefArray(contextPassport, 'proof_refs', errors);
1098
+
1099
+ const contextPack = args.contextPack ?? args.context_pack ?? args.pack;
1100
+ if (contextPack || args.vault || args.passport || args.active_state || args.activeState || args.tombstones) {
1101
+ const expected = contextSelectionSummary({ ...args, contextPack });
1102
+ compareRootAndCount(contextPassport, expected, 'selected_context_root', 'selected_count', 'selected_context_root', 'selected_count', errors);
1103
+ compareRootAndCount(contextPassport, expected, 'omitted_context_root', 'omitted_count', 'omitted_context_root', 'omitted_count', errors);
1104
+ compareRootAndCount(contextPassport, expected, 'tombstone_context_root', 'tombstone_count', 'tombstone_context_root', 'tombstone_count', errors);
1105
+ }
1106
+
1107
+ verifyContextPackWhenTrusted(args, contextPack, errors);
1108
+ verifyRequiredReceiptRefs(contextPassport.proof_refs ?? [], receiptRefsFromContextPack(contextPack), errors, 'proof_refs');
1109
+ if (errors.length > 0) return invalidBoundaryResult(contextPassport, errors);
1110
+ return validBoundaryResult(contextPassport);
1111
+ }
1112
+
1113
+ export function createProofOfNonUse(args = {}) {
1114
+ const contextPack = contextPackFromArgs(args);
1115
+ const passport = args.passport ?? (args.vault ? createPassport({ vault: args.vault, now: args.now }) : undefined);
1116
+ const roots = rootsFromVault(args.vault);
1117
+ const receiptLogRoot = args.receipt_log_root ?? args.receiptLogRoot ?? contextPack?.receipt_log_root ?? roots.receipt_log_root;
1118
+ const policyId = args.policy_id ?? args.policyId ?? contextPack?.receipts?.find((receipt) => receipt?.policy_id)?.policy_id ?? passport?.policies?.[0] ?? args.vault?.policy_id ?? 'local-default';
1119
+ const policyDecision = args.policy_decision ?? args.policyDecision ?? 'allow';
1120
+ const verifierRef = args.verifier_ref ?? args.verifierRef ?? hashedRef('verifier', { schema: PROOF_OF_NON_USE_SCHEMA, policy_id: policyId });
1121
+ if (!PROOF_POLICY_DECISIONS.has(policyDecision)) throw new Error('createProofOfNonUse policy_decision must be allow, deny, redact, quarantine, or tombstone_only');
1122
+ const summary = proofSelectionSummary({ ...args, contextPack, passport });
1123
+ const receiptRefs = receiptRefsFromArgs(args, contextPack);
1124
+ if (receiptRefs.length === 0) throw new Error('createProofOfNonUse requires receipt_refs or context pack receipts');
1125
+ return {
1126
+ schema: PROOF_OF_NON_USE_SCHEMA,
1127
+ proof_id: args.proof_id ?? args.proofId ?? `proof_non_use_${randomUUID()}`,
1128
+ issued_at: nowIso(args.now),
1129
+ subject_ref: args.subject_ref ?? args.subjectRef ?? hashedRef('subject', passport?.owner?.subject_id ?? args.vault?.subject_id ?? contextPack?.passport_id ?? 'local-subject'),
1130
+ query_commitment: queryCommitment(args, contextPack),
1131
+ candidate_set_root: summary.candidate_set_root,
1132
+ selected_set_root: summary.selected_set_root,
1133
+ omitted_set_root: summary.omitted_set_root,
1134
+ tombstone_set_root: summary.tombstone_set_root,
1135
+ candidate_count: summary.candidate_count,
1136
+ selected_count: summary.selected_count,
1137
+ omitted_count: summary.omitted_count,
1138
+ tombstone_count: summary.tombstone_count,
1139
+ policy_id: String(policyId),
1140
+ policy_decision: policyDecision,
1141
+ verifier_status: VERIFIED_STATUS,
1142
+ verifier_ref: verifierRef,
1143
+ receipt_log_root: receiptLogRoot,
1144
+ receipt_refs: receiptRefs,
1145
+ };
1146
+ }
1147
+
1148
+ export function verifyProofOfNonUse(args = {}) {
1149
+ const proof = args.schema === PROOF_OF_NON_USE_SCHEMA ? args : (args.proofOfNonUse ?? args.proof_of_non_use ?? args.proof ?? args.artifact);
1150
+ if (!proof || proof.schema !== PROOF_OF_NON_USE_SCHEMA) {
1151
+ return invalidBoundaryResult(proof, ['verifyProofOfNonUse requires an enigma.proof_of_non_use.v1 artifact']);
1152
+ }
1153
+
1154
+ const errors = missingBoundaryFields(proof, [
1155
+ 'schema',
1156
+ 'proof_id',
1157
+ 'issued_at',
1158
+ 'subject_ref',
1159
+ 'query_commitment',
1160
+ 'candidate_set_root',
1161
+ 'selected_set_root',
1162
+ 'omitted_set_root',
1163
+ 'tombstone_set_root',
1164
+ 'candidate_count',
1165
+ 'selected_count',
1166
+ 'omitted_count',
1167
+ 'tombstone_count',
1168
+ 'policy_id',
1169
+ 'policy_decision',
1170
+ 'verifier_status',
1171
+ 'verifier_ref',
1172
+ 'receipt_log_root',
1173
+ 'receipt_refs',
1174
+ ]);
1175
+ validateRootField(proof, 'query_commitment', errors);
1176
+ validateRootField(proof, 'candidate_set_root', errors);
1177
+ validateRootField(proof, 'selected_set_root', errors);
1178
+ validateRootField(proof, 'omitted_set_root', errors);
1179
+ validateRootField(proof, 'tombstone_set_root', errors);
1180
+ validateCountField(proof, 'candidate_count', errors);
1181
+ validateCountField(proof, 'selected_count', errors);
1182
+ validateCountField(proof, 'omitted_count', errors);
1183
+ validateCountField(proof, 'tombstone_count', errors);
1184
+ if (typeof proof.policy_id !== 'string' || proof.policy_id.length === 0) errors.push('invalid policy_id');
1185
+ if (!PROOF_POLICY_DECISIONS.has(proof.policy_decision)) errors.push('invalid policy_decision');
1186
+ if (!PROOF_VERIFIER_STATUSES.has(proof.verifier_status)) errors.push('invalid verifier_status');
1187
+ if (typeof proof.verifier_ref !== 'string' || proof.verifier_ref.length === 0) errors.push('invalid verifier_ref');
1188
+ validateRootField(proof, 'receipt_log_root', errors);
1189
+ validateRefArray(proof, 'receipt_refs', errors);
1190
+
1191
+ const contextPack = args.contextPack ?? args.context_pack ?? args.pack;
1192
+ if (contextPack || args.vault || args.passport || args.active_state || args.activeState || args.tombstones || args.candidate_refs || args.candidateRefs) {
1193
+ const expected = proofSelectionSummary({ ...args, contextPack });
1194
+ compareRootAndCount(proof, expected, 'candidate_set_root', 'candidate_count', 'candidate_set_root', 'candidate_count', errors);
1195
+ compareRootAndCount(proof, expected, 'selected_set_root', 'selected_count', 'selected_set_root', 'selected_count', errors);
1196
+ compareRootAndCount(proof, expected, 'omitted_set_root', 'omitted_count', 'omitted_set_root', 'omitted_count', errors);
1197
+ compareRootAndCount(proof, expected, 'tombstone_set_root', 'tombstone_count', 'tombstone_set_root', 'tombstone_count', errors);
1198
+ }
1199
+
1200
+ if (contextPack && proof.receipt_log_root !== contextPack.receipt_log_root) errors.push('receipt_log_root mismatch');
1201
+ verifyContextPackWhenTrusted(args, contextPack, errors);
1202
+ verifyRequiredReceiptRefs(proof.receipt_refs ?? [], receiptRefsFromContextPack(contextPack), errors, 'receipt_refs');
1203
+ if (errors.length > 0) return invalidBoundaryResult({ ...proof, verifier_status: FAILED_PROOF_STATUS }, errors);
1204
+ return validBoundaryResult({ ...proof, verifier_status: VERIFIED_STATUS });
1205
+ }
1206
+
778
1207
 
779
1208
  const MEMORY_DRIVE_HEALTH_SCHEMA = 'enigma.memory_drive_health_report.v1';
780
1209
  const DEFAULT_HEALTH_NOW = '2026-06-25T00:00:00.000Z';
@@ -0,0 +1,100 @@
1
+ const MAX_BODY_BYTES = 16 * 1024;
2
+
3
+ class CreditsHttpError extends Error {
4
+ constructor(status, code, message) {
5
+ super(message);
6
+ this.name = 'CreditsHttpError';
7
+ this.status = status;
8
+ this.code = code;
9
+ }
10
+ }
11
+
12
+ function json(response, status, payload) {
13
+ const body = JSON.stringify(payload);
14
+ response.statusCode = status;
15
+ response.setHeader('Cache-Control', 'no-store');
16
+ response.setHeader('Content-Type', 'application/json; charset=utf-8');
17
+ response.setHeader('Content-Length', Buffer.byteLength(body));
18
+ response.setHeader('Referrer-Policy', 'no-referrer');
19
+ response.setHeader('X-Content-Type-Options', 'nosniff');
20
+ response.end(body);
21
+ }
22
+
23
+ async function body(request) {
24
+ const type = String(request.headers['content-type'] || '').split(';', 1)[0].trim().toLowerCase();
25
+ if (type !== 'application/json') throw new CreditsHttpError(415, 'unsupported_media_type', 'Content-Type must be application/json');
26
+ const chunks = [];
27
+ let size = 0;
28
+ let tooLarge = false;
29
+ for await (const chunk of request) {
30
+ size += chunk.length;
31
+ if (size > MAX_BODY_BYTES) tooLarge = true;
32
+ else chunks.push(chunk);
33
+ }
34
+ if (tooLarge) throw new CreditsHttpError(413, 'payload_too_large', 'request body exceeds 16 KiB');
35
+ try {
36
+ const parsed = JSON.parse(Buffer.concat(chunks, size).toString('utf8') || '{}');
37
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error();
38
+ return parsed;
39
+ } catch {
40
+ throw new CreditsHttpError(400, 'invalid_json', 'request body must be a JSON object');
41
+ }
42
+ }
43
+
44
+ function bearer(request) {
45
+ const value = String(request.headers.authorization || '');
46
+ return value.startsWith('Bearer enigma_cv_') ? value.slice(7) : null;
47
+ }
48
+
49
+ export function createPrivateCreditsHttpHandler(options = {}) {
50
+ const credits = options.credits;
51
+ if (!credits || typeof credits.create !== 'function' || typeof credits.recover !== 'function') throw new TypeError('private credits service is required');
52
+ if (typeof options.authorizeCreation !== 'function') throw new TypeError('authorizeCreation is required to rate-limit anonymous vault creation');
53
+ if (typeof options.admitRecovery !== 'function') throw new TypeError('admitRecovery is required to rate-limit recovery attempts');
54
+ const basePath = String(options.basePath || '/v1/credits').replace(/\/+$/, '');
55
+
56
+ return async function privateCreditsHttpHandler(request, response) {
57
+ const url = new URL(request.url || '/', 'http://localhost');
58
+ if (url.pathname !== basePath && !url.pathname.startsWith(`${basePath}/`)) return false;
59
+ try {
60
+ if (request.method === 'POST' && url.pathname === `${basePath}/vaults`) {
61
+ const admitted = await options.authorizeCreation({ request, headers: request.headers });
62
+ if (!admitted) throw new CreditsHttpError(429, 'creation_not_admitted', 'private credits vault creation is not admitted');
63
+ json(response, 201, await credits.create());
64
+ return true;
65
+ }
66
+ if (request.method === 'POST' && url.pathname === `${basePath}/recover`) {
67
+ const admitted = await options.admitRecovery({ request, headers: request.headers });
68
+ if (!admitted) throw new CreditsHttpError(429, 'recovery_rate_limited', 'private credits recovery is rate limited');
69
+ const input = await body(request);
70
+ if (Object.keys(input).some((key) => key !== 'recoveryCode')) throw new CreditsHttpError(400, 'invalid_request', 'recoveryCode is the only accepted field');
71
+ const recovered = await credits.recover(input.recoveryCode);
72
+ if (!recovered) throw new CreditsHttpError(401, 'invalid_recovery_code', 'recovery code is invalid or has already been rotated');
73
+ json(response, 200, recovered);
74
+ return true;
75
+ }
76
+ if (request.method === 'GET' && url.pathname === basePath) {
77
+ const vault = await credits.status(bearer(request));
78
+ if (!vault) throw new CreditsHttpError(401, 'invalid_credits_session', 'private credits access token is invalid or expired');
79
+ json(response, 200, { vault });
80
+ return true;
81
+ }
82
+ if (request.method === 'DELETE' && url.pathname === `${basePath}/session`) {
83
+ const revoked = await credits.logout(bearer(request));
84
+ if (!revoked) throw new CreditsHttpError(401, 'invalid_credits_session', 'private credits access token is invalid or expired');
85
+ response.statusCode = 204;
86
+ response.setHeader('Cache-Control', 'no-store');
87
+ response.end();
88
+ return true;
89
+ }
90
+ throw new CreditsHttpError(404, 'not_found', 'private credits endpoint not found');
91
+ } catch (error) {
92
+ const normalized = error instanceof CreditsHttpError
93
+ ? error
94
+ : new CreditsHttpError(error instanceof TypeError ? 400 : 500, error instanceof TypeError ? 'invalid_request' : 'credits_error', error.message || 'private credits operation failed');
95
+ if (normalized.status === 401) response.setHeader('WWW-Authenticate', 'Bearer');
96
+ json(response, normalized.status, { error: { code: normalized.code, message: normalized.message } });
97
+ return true;
98
+ }
99
+ };
100
+ }