{"_id":"@bolyra/mpp","_rev":"9-77e5d1ddb940f8858a99c5321a892db6","name":"@bolyra/mpp","dist-tags":{"latest":"0.7.0"},"versions":{"0.1.0":{"name":"@bolyra/mpp","version":"0.1.0","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"author":{"name":"ZKProva Inc."},"license":"Apache-2.0","_id":"@bolyra/mpp@0.1.0","maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"homepage":"https://bolyra.ai","bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"dist":{"shasum":"a434491e374501bb53f69b4de2fbea48f0461666","tarball":"https://registry.npmjs.org/@bolyra/mpp/-/mpp-0.1.0.tgz","fileCount":34,"integrity":"sha512-1KFFMYVvrrlbIdYKADGSJY5KPx7CbFrEzj8jyMI4eLTvetfOu5VPHJoDgx4VS/EFo8a+NU0MGqx/26gaqpaUxw==","signatures":[{"sig":"MEUCIQD4ZEjx7SfTUUdH9NpACk3DPEJ014h5Th4oqOaKYxKGfQIgXKk249Qz/+KKGVOj5FnGeYqssnjMvljJAs0PpJBc1tI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":181722},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"37a8d9190507217638ba9f29f3735ef936576fbf","scripts":{"test":"jest","build":"tsc","prepare":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"saneguy","email":"kondojuviswanadha@gmail.com"},"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"_npmVersion":"11.6.2","description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","directories":{},"_nodeVersion":"24.13.0","dependencies":{"@bolyra/sdk":"^0.6.1","@bolyra/receipts":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","mppx":">=0.8.0","ts-jest":"^29.2.0","typescript":"^5.5.0","@types/jest":"^30.0.0","@types/node":"^26.0.0"},"peerDependencies":{"mppx":">=0.8.0"},"peerDependenciesMeta":{"mppx":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mpp_0.1.0_1783832044615_0.10601057195595676","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bolyra/mpp","version":"0.2.0","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"author":{"name":"ZKProva Inc."},"license":"Apache-2.0","_id":"@bolyra/mpp@0.2.0","maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"homepage":"https://bolyra.ai","bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"dist":{"shasum":"68e9735b6a1e14b79c0c0031983c008dae483c67","tarball":"https://registry.npmjs.org/@bolyra/mpp/-/mpp-0.2.0.tgz","fileCount":37,"integrity":"sha512-ZoOaAzi14toY/EzSQXZP08Mbn87Vgb3xwgi8QQR0TRh52WPnmnSw+wIW8f/1aEqTJxK5o8FP2hDdmW8C/LapkA==","signatures":[{"sig":"MEUCIQDzsArtQLvvZAFum7wF6SZQtABAYt/fVrKRYwgVAJ1QiAIgRZ5EG+/hejeoiBvYrsds0b6xA/5CugPTS7ehyIjn9xo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":223842},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"27bc219a1c759d9cc14459bf5e6c9fe6bcbbdcde","scripts":{"test":"jest","build":"tsc","prepare":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"saneguy","email":"kondojuviswanadha@gmail.com"},"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"_npmVersion":"11.6.2","description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","directories":{},"_nodeVersion":"24.13.0","dependencies":{"@bolyra/sdk":"^0.6.1","@bolyra/receipts":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","mppx":">=0.8.0","ts-jest":"^29.2.0","typescript":"^5.5.0","@types/jest":"^30.0.0","@types/node":"^26.0.0"},"peerDependencies":{"mppx":">=0.8.0"},"peerDependenciesMeta":{"mppx":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mpp_0.2.0_1784295368096_0.9015681689490687","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@bolyra/mpp","version":"0.2.1","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"author":{"name":"ZKProva Inc."},"license":"Apache-2.0","_id":"@bolyra/mpp@0.2.1","maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"homepage":"https://bolyra.ai","bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"dist":{"shasum":"112096c59928d7f9c846ec2f519eea027092a52d","tarball":"https://registry.npmjs.org/@bolyra/mpp/-/mpp-0.2.1.tgz","fileCount":37,"integrity":"sha512-KIeA/uxAuFN1G4OkV4lbEtjfdBtxnsV/STj09MzJz6opY89wa5q1JthPuhbHpQEQ8dhpitY6ITzhGzQBzWBupg==","signatures":[{"sig":"MEYCIQDkPLRXT7WReZ2OkfMXewHYDZNenoBnSGqQZ9GOkO9J1gIhALdy5nTgxrPzk2Sm1H984tJ2Rh3f7GngQv8wwNBtbLuG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bolyra%2fmpp@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":223900},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"d0b4abe3951404e3422e71554b36b88bdded398a","scripts":{"test":"jest","build":"tsc","prepare":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0b84bc9-4b8f-4128-b51b-d8ffb191afb5"}},"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"_npmVersion":"11.18.0","description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"@bolyra/sdk":"^0.6.1","@bolyra/receipts":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","mppx":"^0.8.12","ts-jest":"^29.2.0","typescript":"^5.5.0","@types/jest":"^30.0.0","@types/node":"^26.0.0"},"peerDependencies":{"mppx":">=0.8.0"},"peerDependenciesMeta":{"mppx":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mpp_0.2.1_1784327080883_0.841904123978078","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@bolyra/mpp","version":"0.3.0","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"author":{"name":"ZKProva Inc."},"license":"Apache-2.0","_id":"@bolyra/mpp@0.3.0","maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"homepage":"https://bolyra.ai","bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"bin":{"bolyra-mpp":"dist/demo/cli.js"},"dist":{"shasum":"4ed4d8b95aac438b992edd8c56197cab17d14517","tarball":"https://registry.npmjs.org/@bolyra/mpp/-/mpp-0.3.0.tgz","fileCount":40,"integrity":"sha512-YDzArpk5ArX9tkSLe82ZpKc8Oz45tVD3B2RToFiW4X319rhkWW3+OM30NclTlO2uBwoQnKO1KUDTvnmNBDe02A==","signatures":[{"sig":"MEQCIDhmek/B8Mt+Wfg+JiAbe+2piVFNZX0aAJSwhW8OuYCHAiBPCqJcku9mwfpuW+ETtwxdybmhk97I4olzg38t+rqn9g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bolyra%2fmpp@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":250318},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"dec28db5397dda91926ca3321751168a9e51b7e1","scripts":{"test":"jest","build":"tsc","prepare":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0b84bc9-4b8f-4128-b51b-d8ffb191afb5"}},"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"_npmVersion":"11.18.0","description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"@bolyra/sdk":"^0.6.1","@bolyra/receipts":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","mppx":"^0.8.12","ts-jest":"^29.2.0","typescript":"^5.5.0","@types/jest":"^30.0.0","@types/node":"^26.0.0"},"peerDependencies":{"mppx":">=0.8.0"},"peerDependenciesMeta":{"mppx":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mpp_0.3.0_1784333171879_0.0038630719184589157","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@bolyra/mpp","version":"0.3.1","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"author":{"name":"ZKProva Inc."},"license":"Apache-2.0","_id":"@bolyra/mpp@0.3.1","maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"homepage":"https://bolyra.ai","bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"bin":{"bolyra-mpp":"dist/demo/cli.js"},"dist":{"shasum":"29f90d1ae4f9b13091f84dd68a5ca6be97e43beb","tarball":"https://registry.npmjs.org/@bolyra/mpp/-/mpp-0.3.1.tgz","fileCount":40,"integrity":"sha512-uxy8pjqtTjKuNbmbxYIfD/Hwd1XvpD/qDuDMAhCZ0z8oR7ozoREElL9QBgxQKQPVmBQxNunHxx7fUFWYSBQueA==","signatures":[{"sig":"MEQCIDdOIXkLxhvPPGUQQv6Epc9hr7aAfB2vwFVYLg+QtwRxAiBNghB0DhwjDQIApWyKfL0D4uP19qaE8mvzVTF45OLSnA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bolyra%2fmpp@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":250738},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"7ea74971e77870b1e44e17373474495910b058fe","scripts":{"test":"jest","build":"tsc","prepare":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0b84bc9-4b8f-4128-b51b-d8ffb191afb5"}},"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"_npmVersion":"11.18.0","description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"@bolyra/sdk":"^0.6.1","@bolyra/receipts":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","mppx":"^0.8.12","ts-jest":"^29.2.0","typescript":"^5.5.0","@types/jest":"^30.0.0","@types/node":"^26.0.0"},"peerDependencies":{"mppx":">=0.8.0"},"peerDependenciesMeta":{"mppx":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mpp_0.3.1_1784351789514_0.9384825039839804","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@bolyra/mpp","version":"0.4.0","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"author":{"name":"ZKProva Inc."},"license":"Apache-2.0","_id":"@bolyra/mpp@0.4.0","maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"homepage":"https://bolyra.ai","bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"bin":{"bolyra-mpp":"dist/demo/cli.js"},"dist":{"shasum":"79569458e20f1abc0fe3042332c32d83891c9bae","tarball":"https://registry.npmjs.org/@bolyra/mpp/-/mpp-0.4.0.tgz","fileCount":40,"integrity":"sha512-UJOc3v1HLUjvwBMAbcvN8veuwcP36X5UHu8lhijMqZJQ3HNp0tA2ZE0AUmwRJZ2z3KYjLWgoplS1X/z1nijXCw==","signatures":[{"sig":"MEUCICIqTdsu7BrYvxZWH/Nwckl4KxQkhVJK8Xv8i1R5UDz3AiEAnvvX67pT99FF7b99DpgkROR9OldHlCQ2VFdqzpD/sgQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bolyra%2fmpp@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":273323},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"a23e73a4d5a049ddb9e732f1d51dd405590de18a","scripts":{"test":"jest","build":"tsc","prepare":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0b84bc9-4b8f-4128-b51b-d8ffb191afb5"}},"overrides":{"ws":"8.21.0","underscore":"1.13.8","brace-expansion":"5.0.9"},"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"_npmVersion":"11.19.0","description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","directories":{},"_nodeVersion":"22.23.2","dependencies":{"@bolyra/sdk":"^0.6.1","@bolyra/receipts":"^0.10.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2","mppx":"^0.8.12","ts-jest":"^29.2.0","typescript":"^5.5.0","@types/jest":"^30.0.0","@types/node":"^26.0.0"},"peerDependencies":{"mppx":">=0.8.0"},"peerDependenciesMeta":{"mppx":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mpp_0.4.0_1787652701273_0.2128283512644904","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@bolyra/mpp","version":"0.5.0","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"author":{"name":"ZKProva Inc."},"license":"Apache-2.0","_id":"@bolyra/mpp@0.5.0","maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"homepage":"https://bolyra.ai","bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"bin":{"bolyra-mpp":"dist/demo/cli.js"},"dist":{"shasum":"549d271a21e07fc96908ffe7f5c73a059a2c6c3a","tarball":"https://registry.npmjs.org/@bolyra/mpp/-/mpp-0.5.0.tgz","fileCount":46,"integrity":"sha512-TY1qxnZAWphTdrdoISlHKIH5JaRsbYSasstX0FPWQtAe5B5ckSW8GJoxbU5Xl3cIvdCj8SZefJ9gOYzgCh+fKg==","signatures":[{"sig":"MEQCIFl3sJ6g8Oxngv2OVvHSg1idS3kozBGJ8fuF5F07BC4HAiBhc5Auy5DBOiWQ68U1gVKXr+54b+36p1S41k4llQwIbA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCDJSfwfoJYhLwIcANwWTTF0FwceplOkEMVq5jfLASw8wIhAPFxglhV8mjv6yCte9yQUbXT6dYJJJd/IC4WWCTtp2bo","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bolyra%2fmpp@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":314592},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"73d87bf5797ac08cf70a9e559280495b14bdcc89","scripts":{"test":"jest","build":"tsc","prepare":"tsc","typecheck":"tsc --noEmit","test:integration":"node --import tsx --test test-integration/*.test.mts","typecheck:integration":"tsc -p tsconfig.integration.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0b84bc9-4b8f-4128-b51b-d8ffb191afb5"}},"overrides":{"ws":"8.21.0","underscore":"1.13.8","brace-expansion":"5.0.9"},"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"_npmVersion":"11.19.1","description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","directories":{},"_nodeVersion":"22.23.2","dependencies":{"@bolyra/sdk":"^0.6.1","@bolyra/receipts":"^0.10.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.0","jest":"^30.4.2","mppx":"0.8.13","ts-jest":"^29.2.0","typescript":"^5.5.0","@types/jest":"^30.0.0","@types/node":"^26.0.0"},"peerDependencies":{"mppx":"0.8.13"},"peerDependenciesMeta":{"mppx":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mpp_0.5.0_1789866030156_0.28707155665249373","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@bolyra/mpp","version":"0.6.0","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"author":{"name":"ZKProva Inc."},"license":"Apache-2.0","_id":"@bolyra/mpp@0.6.0","maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"homepage":"https://bolyra.ai","bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"bin":{"bolyra-mpp":"dist/demo/cli.js"},"dist":{"shasum":"beb2b8dc46eb003c24055e133ba75e6be104c54a","tarball":"https://registry.npmjs.org/@bolyra/mpp/-/mpp-0.6.0.tgz","fileCount":46,"integrity":"sha512-vJ0kI/1mNhliGGKOvpQ9/52whqFfiPKFRhMOM4vBnT4kRJ07W4mlIBJx5/VtTenddF1IMGR1bwHPNhiV8LKVjg==","signatures":[{"sig":"MEUCIB9v2cI5kfhdr/OJ1zwjWuBEyGASC+7KmiFca3HjhTZRAiEAhoecX+HHb1jHs37h4D+fmb22XqLwuaR5pS1QKxh+iRA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCICb6k/v5Q6HCTyQAv/F6p2RScAYu9Zm0c/u3iTC472ixAiAmaoKQJLzYDU9waLUu1bVU6hOYhsUnIZWXCwqK1ays6g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bolyra%2fmpp@0.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":355116},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18"},"gitHead":"be3193de406111ae264689c275dd89abb5cc6a22","scripts":{"test":"jest","build":"tsc","prepare":"tsc","typecheck":"tsc --noEmit","test:integration":"node --import tsx --test test-integration/*.test.mts","typecheck:integration":"tsc -p tsconfig.integration.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0b84bc9-4b8f-4128-b51b-d8ffb191afb5"}},"overrides":{"ws":"8.21.0","underscore":"1.13.8","brace-expansion":"5.0.9"},"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"_npmVersion":"11.19.1","description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","directories":{},"_nodeVersion":"22.23.2","dependencies":{"@bolyra/sdk":"^0.6.1","@bolyra/receipts":"^0.10.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.0","jest":"^30.4.2","mppx":"0.8.13","ts-jest":"^29.2.0","typescript":"^5.5.0","@types/jest":"^30.0.0","@types/node":"^26.0.0"},"peerDependencies":{"mppx":"0.8.13"},"peerDependenciesMeta":{"mppx":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mpp_0.6.0_1790093796725_0.9410836193730621","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"_id":"@bolyra/mpp@0.7.0","bin":{"bolyra-mpp":"dist/demo/cli.js"},"bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"dist":{"shasum":"b4fcbbf2eb4f74543f85cb265547ed6d69bc1af0","tarball":"https://registry.npmjs.org/@bolyra/mpp/-/mpp-0.7.0.tgz","fileCount":46,"integrity":"sha512-t8XxqlEEDYdtJdwnzJZRNOqg8yMa71cXfMtu+NaIbwuH8IamInQHtYIq5xj6xYfVyxDGJh2aYNBuXwum8vPMiA==","signatures":[{"sig":"MEUCICGZ2FcDvrNmSJ9ofr/gc2/kGLrRRuJFF+CRM9GtpmJeAiEAuMZp9TLUjQd4sCLWKWQEilNod7jTm+BKpgjaBQrtcM4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCwSyssBFe0YxMDwNmKEzFjizWw/f4DdCgfAwNuYHhfYwIgPic5/qO6xtKGzYkXlwu1eKHgUAHk+qeaV8QPtxEJjOM="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bolyra%2fmpp@0.7.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":399795},"main":"dist/index.js","name":"@bolyra/mpp","types":"dist/index.d.ts","author":{"name":"ZKProva Inc."},"engines":{"node":">=20"},"gitHead":"6aa8be6b2522d615b75daad30a398d69d0e8ade3","license":"Apache-2.0","scripts":{"test":"jest","build":"tsc","prepare":"tsc","typecheck":"tsc --noEmit","test:integration":"node --import tsx --test test-integration/*.test.mts","typecheck:integration":"tsc -p tsconfig.integration.json"},"version":"0.7.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0b84bc9-4b8f-4128-b51b-d8ffb191afb5"}},"homepage":"https://bolyra.ai","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"overrides":{"ws":"8.21.0","underscore":"1.13.8","brace-expansion":"5.0.9"},"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"_npmVersion":"11.20.0","description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","directories":{},"maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"_nodeVersion":"22.23.2","dependencies":{"@bolyra/sdk":"^0.6.1","@bolyra/receipts":"^0.10.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.0","jest":"^30.4.2","mppx":"0.8.13","ts-jest":"^29.2.0","typescript":"^5.5.0","@types/jest":"^30.0.0","@types/node":"^26.0.0"},"peerDependencies":{"mppx":"0.8.13"},"peerDependenciesMeta":{"mppx":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mpp_0.7.0_1790297365947_0.6517811923563199"}}},"time":{"created":"2026-07-12T04:54:04.453Z","modified":"2026-09-25T00:49:26.382Z","0.1.0":"2026-07-12T04:54:04.754Z","0.2.0":"2026-07-17T13:36:08.237Z","0.2.1":"2026-07-17T22:24:41.054Z","0.3.0":"2026-07-18T00:06:12.024Z","0.3.1":"2026-07-18T05:16:29.647Z","0.4.0":"2026-08-25T10:11:41.397Z","0.5.0":"2026-09-20T01:00:30.267Z","0.6.0":"2026-09-22T16:16:36.818Z","0.7.0":"2026-09-25T00:49:26.062Z"},"bugs":{"url":"https://github.com/bolyra/bolyra/issues"},"author":{"name":"ZKProva Inc."},"license":"Apache-2.0","homepage":"https://bolyra.ai","keywords":["mpp","mppx","machine-payments-protocol","402","payment-required","bolyra","authorization","delegation","spend-mandate","ai-agents"],"repository":{"url":"git+https://github.com/bolyra/bolyra.git","type":"git","directory":"integrations/mpp-payments"},"description":"Verify an agent's delegated spend mandate before accepting an MPP payment credential.","maintainers":[{"name":"saneguy","email":"kondojuviswanadha@gmail.com"}],"readme":"# @bolyra/mpp\n\n**Verify an agent's delegated spend mandate before accepting an MPP payment credential.**\n\n[MPP](https://mpp.dev) (Machine Payments Protocol) gives machines a payment\ninterface: Request → 402 Challenge → payment Credential → Verification +\nPayment-Receipt. It answers *\"did this client pay?\"* — deliberately not\n*\"was this agent authorized to spend?\"*. When the paying client is an\nautonomous agent rather than its operator, that second question is the missing\nprecondition. This package adds it as a small authorization middleware for\n[mppx](https://github.com/wevm/mppx) servers: the agent presents an\noperator-signed Bolyra spend mandate in a request header, and the gate\nverifies it — fail-closed — **before the MPP payment flow proceeds**.\n\nHow the two protocols compose (without modifying either) is mapped in\n[Bolyra as an Authorization Companion to MPP](https://github.com/bolyra/bolyra/blob/main/docs/mpp-authorization-companion.md).\nOne line: **MPP moves the money; Bolyra proves the mandate.**\n\n> This is a community-built integration. It is not affiliated with, endorsed\n> by, or sponsored by the MPP authors, wevm, Tempo, or Stripe.\n\n## Install\n\nInto an existing mppx server:\n\n```bash\nnpm install @bolyra/mpp\n```\n\nStarting fresh? Install both, pinned to the supported pair:\n\n```bash\nnpm install @bolyra/mpp mppx@0.8.13\n```\n\n`mppx` is an optional peer dependency — this package never imports it at\nruntime; it wraps the method objects you already build with mppx. The peer\nrange is **exactly `0.8.13`**, so an unpinned `npm install ... mppx` can fail\nwith `ERESOLVE`; the command above avoids it.\n\n### Supported versions\n\n| | Version |\n|---|---|\n| `@bolyra/mpp` | 0.7.0 |\n| `mppx` (peer) | exactly 0.8.13 |\n| `@bolyra/cli` | requires `@bolyra/mpp` ^0.6.0, which excludes 0.7.0 on 0.x semver; the CLI's range gets its own bump after 0.7.0 is published (follow-up) |\n| Node | `>=20` (`engines`; 18 dropped in 0.7.0); CI runs Node 20, release validation Node 22; Node 24 is exercised only locally |\n\n### Spend mandates authorize a TIER, not an amount\n\n`issueMandate` takes either `tier` or `coversAmountUsd`. The second one selects\nthe smallest tier that covers the amount, and the credential then authorizes\nthat whole tier — so `coversAmountUsd: 25` authorizes any amount under $100.\nRead `authorizedMaxUsd` / `authorizedRange` on the result for the ceiling you\nactually got, and prefer `tier` when you want the authorization to equal the\ninput. (`maxUsd` was removed in 0.6.0; it named a ceiling it never enforced.)\n\nNothing accumulates across requests: a mandate bounds each request, not a\nrunning total. A succession of separately-permitted $99 charges is not capped\nat $99.\n\n### Replay retention is bounded\n\nA host-mode verifier tells the gate how long to retain each consumed nonce, and\nthe gate honours that exactly — EVC §3.2 makes it an obligation, so the store\nnever silently retains for less. Bolyra's own verifiers now bound what they ask\nfor to 30 days, which is what keeps a long-lived credential from turning the\nreplay store into an unbounded structure.\n\nThe tradeoff, stated: once a reservation ages out, the same unmodified\npresentation is accepted again and reserves afresh, repeatedly until the\ncredential expires. If you need protection for the credential's whole life,\nissue credentials that expire inside the retention window.\n\nSet `maxRetentionSeconds` to refuse a verifier's requirement you do not want to\nhonour; it fails closed rather than pretending. At `maxEntries` the store\nrefuses new reservations and the gate denies `internal_error` rather than\nevicting a live reservation.\n\n## Quickstart\n\nSee it run first — one command, nothing else to install:\n\n```bash\nnpx @bolyra/mpp demo\n```\n\nUnder two minutes, fully in-process: an operator issues a small-tier spend\nmandate (`issueMandate`), an agent presents it to a route gated by\n`bolyraGate`, a $25 spend **allows**, a $500 spend **denies** with the RFC\n9457 problem body before any payment logic runs, a mandate-less request\n**denies**, and the ES256K-signed authorization receipt is verified. The\nverification path is the real shipped code; only the route is a clearly\nlabeled stub standing in for an mppx method (for the same flow against real\nmppx, see [`examples/mandate-demo`](./examples/mandate-demo)).\n\nThis snippet shows the integration shape (placeholders like `secretKey` and the\noperator pubkeys are yours to fill in); for a copy-paste-runnable version with\na mock agent and real values, see [`examples/mandate-demo`](./examples/mandate-demo).\nThe adapter wraps `Method.Server` *before* it is passed to `Mppx.create()`, so\nno middleware changes are needed and every mppx framework adapter (Express,\nHono, Elysia, Next.js) is covered automatically:\n\n```ts\nimport { Mppx, tempo } from 'mppx/server'\nimport { bolyraGate, handleDenials } from '@bolyra/mpp'\n\nconst tempoCharge = tempo({\n  currency: '0x20c0000000000000000000000000000000000000',\n  recipient: '0x742d35Cc6634c0532925a3b844bC9e7595F8fE00',\n})\n\nconst gatedCharge = bolyraGate(tempoCharge, {\n  // The payee identity the operator's mandate must be signed for.\n  audience: 'api.merchant.example',\n  // In-process classical verification (default, no ZK dependency).\n  // Fail-closed: an empty trusted set never means \"all operators trusted\".\n  verifier: {\n    kind: 'classical',\n    trustedOperators: [{ x: '<operator pubkey x>', y: '<operator pubkey y>' }],\n  },\n})\n\nconst mppx = Mppx.create({ methods: [gatedCharge], secretKey })\n\n// A denial THROWS `BolyraDeniedError` before your handler body runs, so the\n// protected action below can only execute on an allow. `handleDenials` turns\n// the throw into the RFC 9457 response; without it, the error propagates and\n// your framework's error path answers (still no side effect).\nexport const handler = handleDenials(async (request: Request) => {\n  const result = await mppx.charge({ amount: '25' })(request)\n  if (result.status === 402) return result.challenge\n  // ...the protected action...\n  return result.withReceipt(Response.json({ data: '...' }))\n})\n```\n\n`handleDenials` is for frameworks that consume a *returned* `Response` (Next\nApp Router, Cloudflare Workers, Hono, Bun). An Express/Node handler must write\nto `res`, and a returned `Response` does not complete the request — use mppx's\nown Express middleware and `sendDenial(err, res)` in an error middleware:\n\n```ts\nimport { payment } from 'mppx/express'\nimport { sendDenial } from '@bolyra/mpp'\n\napp.post('/paid', payment(mppx.charge, { amount: '25' }), (req, res) => {\n  // ...the protected action (only reached on an allow + verified payment)...\n  res.json({ ok: true })\n})\n\napp.use(async (err, req, res, next) => {\n  if (await sendDenial(err, res)) return // status + application/problem+json written\n  next(err)\n})\n```\n\nUnder `mppx/express` a preflight denial rejects the middleware's promise, and\nExpress >= 5 forwards async rejections to error middleware (Express 4 needs an\nasync wrapper).\n\n> **Why it throws.** mppx maps any non-402 `Response` returned from a method\n> `preflight` to an outer `{ status: 200, withReceipt }`, so a *returned* denial\n> reaches your handler as success and the action runs before the client sees\n> the 401/403. 0.5.0 changed the gate to throw. (Breaking for handlers that\n> relied on a returned denial; see CHANGELOG.)\n\nThe agent carries its mandate presentation (a `bvp/1` bundle, base64url JSON)\nin the `X-Bolyra-Authorization` header on every request. A denial is thrown as\n`BolyraDeniedError` **before** any challenge is issued or payment logic runs;\n`handleDenials` renders it as RFC 9457 Problem Details\n(`application/problem+json`) with a stable machine-readable `code`:\n\n```json\n{\n  \"type\": \"https://bolyra.ai/problems/mpp/scope-exceeded\",\n  \"title\": \"Spend Exceeds Delegated Tier\",\n  \"status\": 403,\n  \"detail\": \"required scope exceeds the credential scope\",\n  \"code\": \"scope_exceeded\"\n}\n```\n\nWhen the verifier's deny carries `detail.reason` / `detail.credential_id` (the\nhosted verifier's registry deny does), they are copied into the body as\n`reason` and `credential_id` — e.g. `\"reason\": \"credential_not_active\"`.\n`reason` is an identifier (`/^[a-z][a-z0-9_]{0,63}$/`, e.g. `tier_2_exceeded`);\nfree-text validator messages are not surfaced (they stay on\n`BolyraDeniedError.verdict.detail` in-process). `credential_id` is copied when\nit is a string of at most 256 characters (longer values are dropped, so a\nmisbehaving verifier cannot reflect a huge value). No other `detail` member reaches\nthe HTTP body.\n\nOn allow, the mppx receipt (and therefore the `Payment-Receipt` header) gains\na `bolyraAuthorization` extension field — tier, amount, verifier kind, and the\nES256K-signed, hash-chained authorization receipt reference — giving the\n**approved → paid** audit pair described in the companion note.\n\n### Hooks and discovery (read before combining with method hooks)\n\n- The gate uses `enforce: 'always'` unless you say otherwise: Bolyra runs before your method's `preflight`/`authorize`, including on requests with no Payment credential.\n- `enforce: 'payment'` keeps credential-less 402 discovery **only** when the method has **no `authorize` hook** (refused at construction with `BolyraGateConfigError`) and its `preflight` returns nothing or a 402. Any other credential-less outcome fails closed.\n- Every hook that runs during ungated discovery must perform **no protected effects**. The gate cannot verify that by inspecting hooks; it is your integration's obligation.\n- At request time, nothing inside the gate escapes as an exception **except `BolyraDeniedError`** (internal faults, including a throwing `onReceipt` sink, become a 500 `internal_error` denial thrown the same way — a sink failure denies even an otherwise-valid request). Construction-time validation throws `TypeError`/`BolyraGateConfigError` synchronously; your method's own hooks keep their own error behavior.\n- **`onReceipt` is synchronous.** A sink that returns a Promise is treated as a failure and the request is denied (an async sink's rejection could otherwise never fail the decision); do your I/O in a queue the sink hands off to synchronously.\n- **`onDecision` is an observer, not a gate.** See \"Observing decisions\" below; its failures never change authorization.\n- **Where a denial surfaces depends on the stage.** A `preflight` denial propagates out of `mppx.charge(...)(request)` (this is what `handleDenials` catches). A denial thrown from `verify` — a missing or already-consumed decision — is caught by mppx itself, logged as `mppx: internal verification error`, and re-issued as a 402 challenge; the Bolyra Problem Details are not recoverable there. Both are fail-closed.\n- A failed `originalVerify` is not retryable against the same captured request: the decision is consumed one-use; the client re-runs the request **with a fresh presentation** (a fresh authorization decision; in host-nonce mode the original presentation's nonce was already reserved on the allow, so re-sending it would deny `nonce_replayed`).\n- **One bundle = one presentation.** Issue a fresh presentation per gated HTTP attempt — including the payment retry after a 402 challenge under `enforce: 'always'`, because the discovery attempt already ran the gate and reserved its nullifier; only `enforce: 'payment'` skips the gate on discovery (`issueMandate` / `bolyra mandate issue`; the signer is local and cheap) — rather than re-sending one. Each issuance mints a fresh random nullifier (`publicSignals[1]`); a hosted verifier hands that nullifier back for the gate to reserve before acting, so the same bundle presented twice denies `nonce_replayed` while a re-issued one does not. Classical-mode replay protection is **cooperative**: the nullifier is host-reserved, not proof-bound — an in-process `{ kind: 'classical' }` verifier reserves nothing (see \"What is and isn't checked\").\n- Tested scope: single-method HTTP `Request` charge handlers at mppx 0.8.13. `compose` intents, non-`Request` transports, and per-item streaming authorization are not established.\n\n### Issuing the mandate (operator side)\n\nThe presentation the agent carries is minted by the operator with the Bolyra\nCLI — [`bolyra mandate issue`](../cli#issue-a-spend-mandate-bolyra-mandate-issue)\n— not hand-assembled. The operator signs a request binding for one agent, one\naudience, and one financial tier, and the CLI prints the exact `bvp/1`\npresentation this gate verifies:\n\n```bash\nbolyra key generate --out operator.key         # one-time: the operator key\nbolyra mandate issue \\\n  --operator-key operator.key \\\n  --agent shopper-bot \\\n  --audience api.merchant.example \\\n  --model opus-4.1 \\\n  --tier small \\\n  --expiry 30d\n# stdout: the base64url bvp/1 presentation → the X-Bolyra-Authorization header.\n# stderr: a summary + the operator public key to list in `trustedOperators` above.\n```\n\nA relative `--expiry 30d` is recomputed from the clock on every issue, and\n`expiry` is signed, so each run mints a distinct binding. Against a hosted\nverifier's credential registry that is a new `credential_id` to register; pass\nan absolute Unix timestamp to re-issue the same binding — see\n[Renewal](../../pilot/INTEGRATION.md#renewal).\n\nThe operator public key printed on stderr is exactly what you configure as a\n`trustedOperators` entry in the gate. **This is issuance, not key management or\na wallet:** the operator key is one you already hold; `bolyra mandate issue`\nnever generates, stores, or rotates keys, holds funds, or settles payments — it\nsigns one standing spend mandate. `@bolyra/mpp`'s test fixtures mint through the\nsame issuance path (`issueMandate`), so there is one code path, not two.\n\nThe mandate is standing; the **presentation is one-shot**. Every issuance carries\na fresh random nullifier, and a hosted verifier has the gate reserve it on allow,\nso mint a new presentation for each action instead of re-sending one (the signer\nis local; issuing is cheap). See \"Hooks and discovery\" above.\n\nIn classical mode the operator signature binds the request binding\n(`{agent, audience, program, model, capabilities, expiry}` — binding v2), so both\nthe **spend ceiling** (signed capability tier) and the **time bound** (`expiry`,\npinned equal to the credential expiry) are tamper-evident: a presenter can no\nlonger re-anchor a later expiry on an issued mandate. The `permission_bitmask`\nremains a self-asserted consistency field; sound bitmask enforcement still needs\nthe zk-class verifier. See \"What is and isn't checked\" below.\n\n## Amount → tier mapping\n\nThe route's `amount` is resolved to USD and mapped to the cumulative\nfinancial-tier bits of `@bolyra/sdk`'s Permission model. Comparison is\nexact-decimal (never float); boundaries are strict:\n\n| Route amount (USD) | Required capability | Permission bits |\n|---|---|---|\n| `< 100` | `mpp:financial:small` | `FINANCIAL_SMALL` |\n| `100 … < 10,000` | `mpp:financial:medium` | `FINANCIAL_SMALL + FINANCIAL_MEDIUM` |\n| `>= 10,000` | `mpp:financial:unlimited` | all three financial bits |\n\nAn operator delegating up to the medium tier signs the binding with\n`capabilities: [\"mpp:financial:small\", \"mpp:financial:medium\"]` — higher tiers\nlist the lower ones, mirroring the cumulative bit encoding. By default\n`amount` is read as a decimal USD string (the `mppx.charge({ amount: '1' })`\nconvention); pass `amountToUsd` when your route prices in token base units or\nanother currency. Unresolvable amounts fail closed.\n\n## Configuration\n\n| Option | Type | Default | Notes |\n|---|---|---|---|\n| `audience` | `string` | required | Byte-literal match against the mandate's signed `project_key` (payee binding). Must be a stable machine identifier — printable ASCII excluding space, 1..256 chars (receipt instance binding §3.1.1); display names are rejected at construction |\n| `verifier` | `VerifierConfig` | required | `classical` (in-process), `command` (EVC v1 spawn), or `url` (hosted verifier) |\n| `verifier.trustedOperators` | `{x, y}[]` | required for `classical` | Decimal-string operator pubkeys; empty set fails closed |\n| `program` | `string` | `\"mpp\"` | Binding `program` discriminator |\n| `model` | `string` | echo bundle | Optional model pin; when set, the signed binding must name it |\n| `amountToUsd` | `(ctx) => string \\| number` | `options.amount` as USD | Resolve route amounts for tier mapping; errors fail closed |\n| `enforce` | `\"always\" \\| \"payment\"` | `\"always\"` | `\"payment\"` skips gating on credential-less challenge probes |\n| `header` | `string` | `x-bolyra-authorization` | Request header carrying the presentation; `Authorization` is rejected (MPP's payment credential rides it) |\n| `nonceStore` | `NonceStoreLike` | in-memory | Reserve-before-act store for host-nonce-mode verifiers; **inject a shared, durable store for multi-instance deployments** |\n| `receipts` | `{issuer?, keyId?, privateKey?}` | ephemeral key | ES256K decision receipts; pin a key in production |\n| `onDecision` | `(decision: Decision) => void \\| Promise<void>` | — | Observer for the gate's final decision, once per gate invocation (see \"Observing decisions\"). Failures are logged and contained; never affects authorization |\n| `onReceipt` | `(receipt) => void` | — | Sink for every signed decision receipt (allow and deny). Receipts carry a signed `instance` block (receipt instance binding v1) whenever the spend facts are resolved; verify with `verifyInstanceBinding` from `@bolyra/receipts` in addition to `verifyReceipt` |\n| `now` | `() => number` | `Date.now`-derived | Clock override (unix **seconds**). Tests only. Mutually exclusive with `nowMs`; receipts built from it carry `.000Z` decision timestamps |\n| `nowMs` | `() => number` | `Date.now` | Clock override (epoch **milliseconds**). Tests only. Mutually exclusive with `now`; drives both the verifier clock and the ms-precision `decisionAt` in the receipt instance block |\n\nRelated exports: `buildDecisionInstance(facts)` builds the signed instance block from `DecisionInstanceFacts` — the pure spec-§3 preimage facts (`audience`/`program`/`capabilities`/`amountUsd`/`decisionAt`/`requestNonce?`); derive them from resolved receipt facts with `instanceFactsFrom(receiptFacts)`. Hosts emitting their own receipts — e.g. x402 EVC profile hosts — set `requestNonce` to their pre-decision challenge nonce. `AUDIENCE_IDENTIFIER_PATTERN` is the §3.1.1 audience syntax.\n\nVerifier backends:\n\n```ts\n// External Verifier Contract v1 command (zk-class checks, delegation chains).\n// `bolyra verify` needs the MPP capability vocabulary mapped to Permission\n// bits — write MPP_CAPABILITY_MAP (exported by this package) to a JSON file:\n//   { \"mpp:financial:small\": [\"FINANCIAL_SMALL\"],\n//     \"mpp:financial:medium\": [\"FINANCIAL_SMALL\", \"FINANCIAL_MEDIUM\"],\n//     \"mpp:financial:unlimited\": [\"FINANCIAL_SMALL\", \"FINANCIAL_MEDIUM\", \"FINANCIAL_UNLIMITED\"] }\nverifier: {\n  kind: 'command',\n  command: 'bolyra',\n  args: ['verify', '--roots', 'roots.json', '--capability-map', 'mpp-capabilities.json'],\n}\n\n// Hosted verifier endpoint (e.g. the Bolyra hosted-verify preview):\nverifier: { kind: 'url', url: 'https://…/v1/verify', token: process.env.BOLYRA_VERIFY_TOKEN }\n```\n\n`verifier.url` is the verifier's origin, or a full URL to your verifier's\nverify route; only a bare origin is rewritten. `https://verify.example` and\n`https://verify.example/` are POSTed to `https://verify.example/v1/verify`\n(a query string and fragment are kept). The root check reads the path as you\nwrote it, so dot segments (`/..`, `/%2e`, `/custom/..`) are not roots. Any\nother path — including `/custom/` with its trailing slash — and any query\nstring are used byte-for-byte. A `url` that is not an absolute\n`scheme://authority` URL, or has leading or trailing whitespace (never\ntrimmed), is a `TypeError` at `bolyraGate()` construction.\n`normalizeVerifierUrl(url)` is exported as a helper for pre-validating a\nconfigured URL: it returns the exact endpoint the gate will POST to, or\nthrows `TypeError`.\n\nTo call a hosted verifier directly, `callUrlVerifierWithEvidence(config,\nrequest)` returns `{ verdict, status?, credentialId?, receipt? }`: the same\nfail-closed verdict as `callUrlVerifier` (which still returns only the\nverdict), the verifier's HTTP `status` (absent when no response arrived), and\nthe raw `x-bolyra-credential-id` / `x-bolyra-receipt` response headers\n(absent when not sent; not decoded, not verified, and unbounded: the 256-character\ncap applies only to `Decision.credentialId` and the HTTP error body). The same URL\nrule applies.\n\nBoth external modes speak the\n[External Verifier Contract v1](https://github.com/bolyra/bolyra/blob/main/spec/external-verifier-contract-v1.md)\n(one JSON request in, one fail-closed verdict out) and implement the host\nobligations: 10s default timeout, stdout/response-body caps (1 MiB), strict\nsingle-object closed-schema verdict parsing (unknown members and unrecognized\n`kind` values reject), and reserve-before-act nonce handling. **Every**\nverifier failure class — timeout, crash, garbage output, unreachable\nendpoint, oversized response — denies with `internal_error`; a broken\nverifier is never an allow.\n\n### Observing decisions (`onDecision`)\n\n```ts\nbolyraGate(method, {\n  audience, verifier,\n  onDecision: (d) => {\n    if (d.outcome === 'deny') metrics.deny(d.code, d.status, d.reason)\n    else metrics.allow(d.credentialId)\n  },\n})\n```\n\n`Decision` is a discriminated union — narrow on `outcome`:\n`AllowDecision { outcome: 'allow', credentialId?, receipt?, request }` |\n`DenyDecision { outcome: 'deny', code, status, reason?, credentialId?, request }`.\n\n- **deny** — `code` (required) is the final denial code and `status`\n  (required) the HTTP status it maps to (`DENY_STATUS[code]`); `reason` comes\n  from the verifier's `detail.reason` — `reason` is an identifier; free-text\n  validator messages are not surfaced — and `credentialId` from\n  `detail.credential_id` when it is a string of at most 256 characters.\n- **allow** — no `code` or `status`; with a `url` verifier, `credentialId` and\n  `receipt` are the raw `x-bolyra-credential-id` / `x-bolyra-receipt` response\n  headers (absent in `classical`/`command` mode; a `credentialId` over 256\n  characters is dropped). This `receipt` is the hosted\n  verifier's, distinct from the gate's own signed decision receipt\n  (`onReceipt`, `bolyraAuthorization.receipt`).\n- `request` is the request context the gate built (`agent_name`,\n  `project_key`, `program`, `model`, `granted_capabilities`); a copy.\n\nThe contract:\n\n- **Exactly once per gate invocation** (one `preflight` run), **after the final\n  decision** — after nonce reservation and after the `onReceipt` sink's\n  outcome. A sink failure that turns an allow into a 500 is reported as\n  `deny` / `internal_error` / 500; a replay as `nonce_replayed` / 403. A\n  fault inside the gate's own denial path (e.g. the receipt signer throwing)\n  is still exactly one `deny` / `internal_error` / 500 Decision, thrown as\n  `BolyraDeniedError`.\n- **On allow, the order is: stash the decision → report → your method's own\n  `preflight`.** If the method's own preflight throws after an allow\n  Decision, the Decision stands (it reports the Bolyra decision, not the\n  method's).\n- **Observer failures never affect authorization.** A throwing `onDecision`\n  getter, a throw, a rejected Promise, or a broken thenable is logged with\n  `console.error` (itself guarded) and contained; the verdict and response\n  are unchanged and no unhandled rejection is raised. The callback is not\n  awaited. Boundary: tampered native Promise internals are outside the\n  guarantee — an already-rejected native Promise whose `constructor` getter\n  throws leaves its own rejection unhandled (authorization is still\n  unaffected).\n- **Credential-less discovery under `enforce: 'payment'` produces no\n  Decision**, because no Bolyra decision was made. The two credential-less\n  refusals in that mode (an `authorize` hook attached after construction, a\n  non-402 preflight result) are reported as `deny` / `internal_error`.\n- **Under `enforce: 'always'` the 402 discovery request is its own gate\n  invocation**, so a 402→pay pair reports two Decisions (the discovery\n  `allow`, then the paid request's outcome). An app counting allow events\n  counts discovery too; correlate by request if you need per-action counts.\n- **The `verify` hook never reports.** Trade-off: a Decision may say `allow`\n  and payment can still be refused at the verify hook if the stashed decision\n  is missing (see \"Where a denial surfaces\").\n\n## What is and isn't checked (read this)\n\nThe default verifier is **classical** — the same classical pipeline as the\nBolyra hosted-verify preview, run in-process. It does **not** verify\nzero-knowledge proofs, so every public signal and credential field in the\nbundle is self-asserted. The one cryptographically load-bearing fact is the\noperator's EdDSA-Poseidon signature over the request binding. A classical\n`allow` means, and only means:\n\n> A configured trusted operator signed a binding authorizing this exact\n> `{agent_name, project_key, program, model, capabilities, expiry}`, the request\n> matches that signed binding, and the granted capability (the amount's\n> financial tier) is a subset of it.\n\nChecked (classical):\n\n- trusted-operator gate (`trustedOperators`; empty set fails closed)\n- EdDSA-Poseidon binding signature against that operator key (binding v2 — the\n  signed binding includes `expiry`)\n- signed `binding.expiry == credential.expiry` (binding v2); an obsolete\n  five-field v1 binding is rejected `unsupported_version`\n- byte-literal request↔binding match — `project_key` is your `audience`\n- granted tier capability ⊆ operator-signed capabilities\n- consistency checks on the revealed credential: Poseidon scope anchoring,\n  model-hash binding, cumulative permission-bit subset, strict expiry\n  (`now == expiry` is expired) over the signature-bound expiry\n\n**Not** checked (classical):\n\n- Groth16 proof verification, Merkle-root inclusion, human-uniqueness, and\n  delegation-chain proofs — bundles carrying zk-only slots are **denied**,\n  not half-verified; use a zk-class external verifier (`bolyra verify`) via\n  `verifier: { kind: 'command', … }` for those\n- sound **permission-bitmask** enforcement against a malicious trusted operator:\n  the revealed `permission_bitmask` is a self-asserted consistency field (the\n  scope commitment is recomputable from public inputs). `expiry`, by contrast,\n  IS tamper-evident as of binding v2 — signed and pinned to the credential\n  expiry — so a re-anchored expiry no longer verifies. For sound bitmask/scope\n  enforcement use the zk-class verifier (`bolyra verify`).\n- replay: a spend mandate is a *standing* authorization, reusable within tier\n  and expiry by design; per-payment idempotency is MPP's challenge binding.\n  Replay protection in classical mode is **cooperative**: the binding\n  signature does not cover the nullifier (`publicSignals[1]`), so a presenter\n  can rewrite it and re-present. External verifiers in host nonce mode make\n  UNMODIFIED re-sends one-shot — the gate reserves their `consume_nonces`\n  before acting — but nothing binds the nullifier to the proof. The default\n  reservation store is in-memory and per-process: it does not survive\n  restarts or span instances — inject `nonceStore` for that.\n- dynamic pricing: the tier check reads the **route's configured amount** at\n  preflight time, before any method `request` hook runs. For standard methods\n  mppx pins the economic request fields across calls (stable binding), so the\n  configured amount is authoritative; if you build a custom method whose\n  request hook changes the amount, make `amountToUsd` resolve the\n  authoritative price — the gate cannot see post-hook values.\n- `agent_name` and `model` (unless pinned via `model`) are echoed from the\n  presented bundle — they identify, they don't restrict. The load-bearing\n  host-asserted fields are `audience` and the amount tier.\n- payment validity itself — that is mppx's job, which runs after the gate\n\nScope: HTTP request flows. If mppx's payment verification is somehow reached\nwithout a gate decision for that request (standalone `verifyCredential()`\ncalls, non-HTTP transports), the wrapped `verify` **fails closed**.\n\n## Example\n\nA self-contained runnable demo — mppx server + this gate, a mock agent with a\ndelegated small-tier mandate issued by the real `bolyra mandate issue` CLI, an\nallowed $25 spend and a denied $500 spend — lives in\n[`examples/mandate-demo`](./examples/mandate-demo). It shells out to the CLI, so\nbuild the CLI first:\n\n```bash\ncd \"$(git rev-parse --show-toplevel)/integrations/mpp-payments\"   # in a checkout of this repo\n(cd ../cli && npm install && npm run build)   # once: build the CLI the demo calls\ncd examples/mandate-demo && npm install && npm run demo\n```\n\n## License\n\nApache-2.0 — see [LICENSE](./LICENSE) and [NOTICE](./NOTICE).\n","readmeFilename":"README.md"}