{"_id":"@3flabs/guardian-defaults","_rev":"13-ac13017ed6890284d17aea918774807c","name":"@3flabs/guardian-defaults","dist-tags":{"latest":"0.3.2"},"versions":{"0.1.1":{"name":"@3flabs/guardian-defaults","version":"0.1.1","license":"MIT","_id":"@3flabs/guardian-defaults@0.1.1","maintainers":[{"name":"maxencerb","email":"maxenceraballand00@gmail.com"}],"dist":{"shasum":"cf25c8ff206f5cd4fecffea0e3dd6b5963a1d940","tarball":"https://registry.npmjs.org/@3flabs/guardian-defaults/-/guardian-defaults-0.1.1.tgz","fileCount":67,"integrity":"sha512-Eoa2w0f8yQ9VpJVo7qklJyoeUDPk+ClLwgFQCO2QuCYYJ8956gehPItDwY7yjoeMqonE4aQW7E39uI4+OPE7cw==","signatures":[{"sig":"MEUCIFLBpJfTVoc8cWUE+3GjQ9ewnOOIFltgqo6Cvc14SBl9AiEAzPYr0QhnudGIR0DMxg8zRef9qdElXwTBfWZUIvc0Cro=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":180969},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","shasum":"cf25c8ff206f5cd4fecffea0e3dd6b5963a1d940","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./checks":{"types":"./dist/checks/index.d.ts","import":"./dist/checks/index.js"},"./logger":{"types":"./dist/logger/index.d.ts","import":"./dist/logger/index.js"},"./rate-limit":{"types":"./dist/rate-limit/index.d.ts","import":"./dist/rate-limit/index.js"}},"scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","build:clean":"rm -rf dist && bun run build"},"_npmUser":{"name":"maxencerb","email":"maxenceraballand00@gmail.com"},"_integrity":"sha512-Eoa2w0f8yQ9VpJVo7qklJyoeUDPk+ClLwgFQCO2QuCYYJ8956gehPItDwY7yjoeMqonE4aQW7E39uI4+OPE7cw==","repository":{"url":"git+https://github.com/3FLabs/3f-guardian.git","type":"git","directory":"packages/guardian-defaults"},"_npmVersion":"10.8.3","description":"Default Logger, in-memory rate limiter, and Appendix-A check builders for @3flabs/guardian.","directories":{},"sideEffects":false,"_nodeVersion":"24.3.0","dependencies":{"pino":"^9.5.0","viem":"^2.48.4","pino-pretty":"^13.0.0","better-result":"^2.9.0","@3flabs/guardian":"0.1.0"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.5","typescript":"^5.6.0"},"_npmOperationalInternal":{"tmp":"tmp/guardian-defaults_0.1.1_1778069908853_0.5946726442090904","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@3flabs/guardian-defaults","version":"0.2.0","license":"MIT","_id":"@3flabs/guardian-defaults@0.2.0","maintainers":[{"name":"maxencerb","email":"maxenceraballand00@gmail.com"}],"homepage":"https://github.com/3FLabs/3f-guardian#readme","bugs":{"url":"https://github.com/3FLabs/3f-guardian/issues"},"dist":{"shasum":"ddc6433f3fd17bc4214a0d4963498eae3aac0f96","tarball":"https://registry.npmjs.org/@3flabs/guardian-defaults/-/guardian-defaults-0.2.0.tgz","fileCount":127,"integrity":"sha512-sIRA2qW5rS7v8A4blDzKMovH81Dk2hfamOB3RDL581fq6AEk6P2kfyoGh22woQp8ZKHJcOFUAzKy+m8V/8qBRw==","signatures":[{"sig":"MEUCIQCBYKytivb1Inr0eBI4wgBbI1h61BaIjJxIU7w61DJGJQIgVpvDqNkiq1Izoy5qQ3qK6x59ymiaRsWZ2/kocbtR4b0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@3flabs%2fguardian-defaults@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":362469},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./cache":{"types":"./dist/cache/index.d.ts","import":"./dist/cache/index.js"},"./checks":{"types":"./dist/checks/index.d.ts","import":"./dist/checks/index.js"},"./logger":{"types":"./dist/logger/index.d.ts","import":"./dist/logger/index.js"},"./rate-limit":{"types":"./dist/rate-limit/index.d.ts","import":"./dist/rate-limit/index.js"}},"gitHead":"ae8288300ba22c2d8ca9591482f977f891ab0b49","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","build:clean":"rm -rf dist && bun run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:10b7dcb7-3016-450d-ad55-a7eaee25366a"}},"repository":{"url":"git+https://github.com/3FLabs/3f-guardian.git","type":"git","directory":"packages/guardian-defaults"},"_npmVersion":"11.11.0","description":"Default Logger, in-memory rate limiter, and Appendix-A check builders for @3flabs/guardian.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","dependencies":{"pino":"^9.5.0","viem":"^2.48.4","pino-pretty":"^13.0.0","better-result":"^2.9.0","@3flabs/guardian":"workspace:*"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.5","typescript":"^5.6.0"},"_npmOperationalInternal":{"tmp":"tmp/guardian-defaults_0.2.0_1778158305587_0.9682436909739252","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@3flabs/guardian-defaults","version":"0.2.1","license":"MIT","_id":"@3flabs/guardian-defaults@0.2.1","maintainers":[{"name":"maxencerb","email":"maxenceraballand00@gmail.com"}],"homepage":"https://github.com/3FLabs/3f-guardian#readme","bugs":{"url":"https://github.com/3FLabs/3f-guardian/issues"},"dist":{"shasum":"4fb076551ca6420dd894e3f7350580ef1741aa35","tarball":"https://registry.npmjs.org/@3flabs/guardian-defaults/-/guardian-defaults-0.2.1.tgz","fileCount":127,"integrity":"sha512-OOgHug6TrmUMxvEUPuDtrnrOv2/7dKsY0RCBGP68GrkB4d6N4lwgQPxvTsCcm311/Y8FbEtF9JuRngSd60V4aQ==","signatures":[{"sig":"MEYCIQCQ1HQAiSyrvprhrSEC9k8/4/ORWvWyyCqTPg/O1OqWkQIhALvJ9robGNwK60u23GLHokjp/wicqhGQMrvnhbzgR5kK","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@3flabs%2fguardian-defaults@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":368809},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./cache":{"types":"./dist/cache/index.d.ts","import":"./dist/cache/index.js"},"./checks":{"types":"./dist/checks/index.d.ts","import":"./dist/checks/index.js"},"./logger":{"types":"./dist/logger/index.d.ts","import":"./dist/logger/index.js"},"./rate-limit":{"types":"./dist/rate-limit/index.d.ts","import":"./dist/rate-limit/index.js"}},"gitHead":"78bbdaa2eb85994bf9dbf8de6cd13aee2150bead","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","build:clean":"rm -rf dist && bun run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:10b7dcb7-3016-450d-ad55-a7eaee25366a"}},"repository":{"url":"git+https://github.com/3FLabs/3f-guardian.git","type":"git","directory":"packages/guardian-defaults"},"_npmVersion":"11.11.0","description":"Default Logger, in-memory rate limiter, and Appendix-A check builders for @3flabs/guardian.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","dependencies":{"pino":"^9.5.0","viem":"^2.48.4","pino-pretty":"^13.0.0","better-result":"^2.9.0","@3flabs/guardian":"0.2.1"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.5","typescript":"^5.6.0"},"_npmOperationalInternal":{"tmp":"tmp/guardian-defaults_0.2.1_1778161886775_0.7218877110184663","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@3flabs/guardian-defaults","version":"0.2.2","license":"MIT","_id":"@3flabs/guardian-defaults@0.2.2","maintainers":[{"name":"maxencerb","email":"maxenceraballand00@gmail.com"}],"homepage":"https://github.com/3FLabs/3f-guardian#readme","bugs":{"url":"https://github.com/3FLabs/3f-guardian/issues"},"dist":{"shasum":"f2381a51cbc78c11edf8455186b8e6c43b79f7e6","tarball":"https://registry.npmjs.org/@3flabs/guardian-defaults/-/guardian-defaults-0.2.2.tgz","fileCount":127,"integrity":"sha512-+L5Xmp7fhFbt4vSTZcQ6fr9RcTnZhSNB+hUqJmMpN7VgQDMD+cg3E76ClpZgSUDoXoi/0SDjv0/VjpbEhEV6mw==","signatures":[{"sig":"MEUCIDTjLG4op7wExyp2sDNMwF3Wh9Bi+0Fh7VBZZqDVtduSAiEA1vLreKE002XfHDIA/wBstr37pXskd3JhJbRGNlY4xWw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@3flabs%2fguardian-defaults@0.2.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":386679},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./cache":{"types":"./dist/cache/index.d.ts","import":"./dist/cache/index.js"},"./checks":{"types":"./dist/checks/index.d.ts","import":"./dist/checks/index.js"},"./logger":{"types":"./dist/logger/index.d.ts","import":"./dist/logger/index.js"},"./rate-limit":{"types":"./dist/rate-limit/index.d.ts","import":"./dist/rate-limit/index.js"}},"gitHead":"baf9dfde730768318f3f4442bed24debf2221cce","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","build:clean":"rm -rf dist && bun run build","test:integration":"vitest run --config vitest.integration.config.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:10b7dcb7-3016-450d-ad55-a7eaee25366a"}},"repository":{"url":"git+https://github.com/3FLabs/3f-guardian.git","type":"git","directory":"packages/guardian-defaults"},"_npmVersion":"11.11.0","description":"Default Logger, in-memory rate limiter, and Appendix-A check builders for @3flabs/guardian.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","dependencies":{"pino":"^9.5.0","viem":"^2.48.4","pino-pretty":"^13.0.0","better-result":"^2.9.0","@3flabs/guardian":"0.3.0"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.5","typescript":"^5.6.0","@3flabs/guardian-test-fixtures":"0.0.0"},"_npmOperationalInternal":{"tmp":"tmp/guardian-defaults_0.2.2_1778176449548_0.9916988598303556","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@3flabs/guardian-defaults","version":"0.2.3","license":"MIT","_id":"@3flabs/guardian-defaults@0.2.3","maintainers":[{"name":"maxencerb","email":"maxenceraballand00@gmail.com"}],"homepage":"https://github.com/3FLabs/3f-guardian#readme","bugs":{"url":"https://github.com/3FLabs/3f-guardian/issues"},"dist":{"shasum":"d2ccaf8ca4d4e67549df5fe91ed28e70cee95b7b","tarball":"https://registry.npmjs.org/@3flabs/guardian-defaults/-/guardian-defaults-0.2.3.tgz","fileCount":127,"integrity":"sha512-oV7Qo3jnaXzXQqttjfzoDKI2xxLnxu6Wdb92aoWZfIohXqjbYIz5/uvcvAKnHFMo1rit4MshTBFwQv6J5vzNjg==","signatures":[{"sig":"MEUCIQC/kdjEJu+x79CxMA/WAEbZcG2/wozdvawHAwGiVzcSSwIgVldlbAnkxF3y6wuXoEQt1x0jSGNZuRoebsFR2Xl+B9w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@3flabs%2fguardian-defaults@0.2.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":386679},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./cache":{"types":"./dist/cache/index.d.ts","import":"./dist/cache/index.js"},"./checks":{"types":"./dist/checks/index.d.ts","import":"./dist/checks/index.js"},"./logger":{"types":"./dist/logger/index.d.ts","import":"./dist/logger/index.js"},"./rate-limit":{"types":"./dist/rate-limit/index.d.ts","import":"./dist/rate-limit/index.js"}},"gitHead":"95904f2cc82e6b8946d9706108eafc66192c172e","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","build:clean":"rm -rf dist && bun run build","test:integration":"vitest run --config vitest.integration.config.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:10b7dcb7-3016-450d-ad55-a7eaee25366a"}},"repository":{"url":"git+https://github.com/3FLabs/3f-guardian.git","type":"git","directory":"packages/guardian-defaults"},"_npmVersion":"11.11.0","description":"Default Logger, in-memory rate limiter, and Appendix-A check builders for @3flabs/guardian.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","dependencies":{"pino":"^9.5.0","viem":"^2.48.4","pino-pretty":"^13.0.0","better-result":"^2.9.0","@3flabs/guardian":"0.3.1"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.5","typescript":"^5.6.0","@3flabs/guardian-test-fixtures":"0.0.0"},"_npmOperationalInternal":{"tmp":"tmp/guardian-defaults_0.2.3_1778178507146_0.21141786749451397","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@3flabs/guardian-defaults","version":"0.3.0","license":"MIT","_id":"@3flabs/guardian-defaults@0.3.0","maintainers":[{"name":"maxencerb","email":"maxenceraballand00@gmail.com"}],"homepage":"https://github.com/3FLabs/3f-guardian#readme","bugs":{"url":"https://github.com/3FLabs/3f-guardian/issues"},"dist":{"shasum":"fa354defa1ff35cae0a824e6c1092e631a05dcf5","tarball":"https://registry.npmjs.org/@3flabs/guardian-defaults/-/guardian-defaults-0.3.0.tgz","fileCount":132,"integrity":"sha512-rcIh7pZ+RgwB+zG4tGL2OXoYruCnkFdmBU6L8Qgwhn3ygDma92+onHQsf4izIXxah6h5ihQXHtQoohq7fit4Vg==","signatures":[{"sig":"MEUCIQCpIfC7kxN32J5QTpCG7oDcOwTttWWscOl3fG/X7zXYPQIgcvq2RiuZC/12BSJgQv2/RGdE1sD+VvhaxMFO5AImn44=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@3flabs%2fguardian-defaults@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":597219},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./cache":{"types":"./dist/cache/index.d.ts","import":"./dist/cache/index.js"},"./checks":{"types":"./dist/checks/index.d.ts","import":"./dist/checks/index.js"},"./logger":{"types":"./dist/logger/index.d.ts","import":"./dist/logger/index.js"},"./rate-limit":{"types":"./dist/rate-limit/index.d.ts","import":"./dist/rate-limit/index.js"}},"gitHead":"0d1a85e9e7b7550c7bcd38b51d9e0ca21ec1b547","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","build:clean":"rm -rf dist && bun run build","test:integration":"vitest run --config vitest.integration.config.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:10b7dcb7-3016-450d-ad55-a7eaee25366a"}},"repository":{"url":"git+https://github.com/3FLabs/3f-guardian.git","type":"git","directory":"packages/guardian-defaults"},"_npmVersion":"11.13.0","description":"Default Logger, in-memory rate limiter, and Appendix-A check builders for @3flabs/guardian.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","dependencies":{"zod":"^4.0.0","pino":"^10.3.1","viem":"^2.52.2","pino-pretty":"^13.1.3","better-result":"^2.9.2","@3flabs/guardian":"0.4.0"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.8","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/guardian-defaults_0.3.0_1781179296907_0.10163316190366878","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@3flabs/guardian-defaults","version":"0.3.1","license":"MIT","_id":"@3flabs/guardian-defaults@0.3.1","maintainers":[{"name":"maxencerb","email":"maxenceraballand00@gmail.com"}],"homepage":"https://github.com/3FLabs/3f-guardian#readme","bugs":{"url":"https://github.com/3FLabs/3f-guardian/issues"},"dist":{"shasum":"51f556b9757a338b32e2cd53733f5b05c588c86c","tarball":"https://registry.npmjs.org/@3flabs/guardian-defaults/-/guardian-defaults-0.3.1.tgz","fileCount":132,"integrity":"sha512-jXolWUbfDewemEgy9nHQItDyw+Rpjo8m5PsXTzqtHNiiUZa8V1Ocm9bd97HDisHF9pwI39uvDT38CKciCH8Arw==","signatures":[{"sig":"MEYCIQDhmNimaUqVWzDg+TmRcdYrN8RY9saEY3kDOVX9EZz5+gIhAOR5Pg4UgBFr8911Nys/qk20pUaZn6emRZWGrJ8XV1nM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@3flabs%2fguardian-defaults@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":597219},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./cache":{"types":"./dist/cache/index.d.ts","import":"./dist/cache/index.js"},"./checks":{"types":"./dist/checks/index.d.ts","import":"./dist/checks/index.js"},"./logger":{"types":"./dist/logger/index.d.ts","import":"./dist/logger/index.js"},"./rate-limit":{"types":"./dist/rate-limit/index.d.ts","import":"./dist/rate-limit/index.js"}},"gitHead":"ed1bdf49697ffe9cd9113eb98e6066c224797adf","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","build:clean":"rm -rf dist && bun run build","test:integration":"vitest run --config vitest.integration.config.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:10b7dcb7-3016-450d-ad55-a7eaee25366a"}},"repository":{"url":"git+https://github.com/3FLabs/3f-guardian.git","type":"git","directory":"packages/guardian-defaults"},"_npmVersion":"11.13.0","description":"Default Logger, in-memory rate limiter, and Appendix-A check builders for @3flabs/guardian.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","dependencies":{"zod":"^4.0.0","pino":"^10.3.1","viem":"^2.52.2","pino-pretty":"^13.1.3","better-result":"^2.9.2","@3flabs/guardian":"0.5.0"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.8","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/guardian-defaults_0.3.1_1782133816858_0.11125556800065883","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@3flabs/guardian-defaults","version":"0.3.2","description":"Default Logger, in-memory rate limiter, and Appendix-A check builders for @3flabs/guardian.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./logger":{"types":"./dist/logger/index.d.ts","import":"./dist/logger/index.js"},"./rate-limit":{"types":"./dist/rate-limit/index.d.ts","import":"./dist/rate-limit/index.js"},"./cache":{"types":"./dist/cache/index.d.ts","import":"./dist/cache/index.js"},"./checks":{"types":"./dist/checks/index.d.ts","import":"./dist/checks/index.js"}},"publishConfig":{"access":"public","provenance":true},"scripts":{"build":"tsc -p tsconfig.build.json","build:clean":"rm -rf dist && bun run build","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","test:integration":"vitest run --config vitest.integration.config.ts"},"dependencies":{"@3flabs/guardian":"0.5.0","better-result":"^2.9.2","pino":"^10.3.1","pino-pretty":"^13.1.3","viem":"^2.52.2","zod":"^4.0.0"},"devDependencies":{"typescript":"^5.9.3","vitest":"^4.1.8"},"repository":{"type":"git","url":"git+https://github.com/3FLabs/3f-guardian.git","directory":"packages/guardian-defaults"},"license":"MIT","sideEffects":false,"gitHead":"f54c2abe347a8d8d1744b54c032618346a792cf5","_id":"@3flabs/guardian-defaults@0.3.2","bugs":{"url":"https://github.com/3FLabs/3f-guardian/issues"},"homepage":"https://github.com/3FLabs/3f-guardian#readme","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-Ipk8j+7U+VYv/cYUoZuCX/LCmTQaYWFm6t0u6EmgTEePLfx5j1Z1Cc3kIhnAZw9Cf98jhGs2rKDQ/u756XriTw==","shasum":"762a3672c2f89e95ecd2ac562825ec8f39dbd404","tarball":"https://registry.npmjs.org/@3flabs/guardian-defaults/-/guardian-defaults-0.3.2.tgz","fileCount":132,"unpackedSize":623721,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@3flabs%2fguardian-defaults@0.3.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBag0YpY3BuVQVuq+lTY5KIASPmjznahQgl/hgD8ZfDDAiEA0bmSXppNTcvSTyaUuugHGPGtVMJyTksfG88KfKKDKCU="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:10b7dcb7-3016-450d-ad55-a7eaee25366a"}},"directories":{},"maintainers":[{"name":"maxencerb","email":"me@maxencerb.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/guardian-defaults_0.3.2_1785404600520_0.14851832399600906"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-06T12:18:28.752Z","modified":"2026-07-30T09:43:21.010Z","0.1.0":"2026-05-06T12:00:50.993Z","0.1.1":"2026-05-06T12:18:28.993Z","0.2.0":"2026-05-07T12:51:45.779Z","0.2.1":"2026-05-07T13:51:26.939Z","0.2.2":"2026-05-07T17:54:09.690Z","0.2.3":"2026-05-07T18:28:27.290Z","0.3.0":"2026-06-11T12:01:37.170Z","0.3.1":"2026-06-22T13:10:17.002Z","0.3.2":"2026-07-30T09:43:20.661Z"},"bugs":{"url":"https://github.com/3FLabs/3f-guardian/issues"},"license":"MIT","homepage":"https://github.com/3FLabs/3f-guardian#readme","repository":{"type":"git","url":"git+https://github.com/3FLabs/3f-guardian.git","directory":"packages/guardian-defaults"},"description":"Default Logger, in-memory rate limiter, and Appendix-A check builders for @3flabs/guardian.","maintainers":[{"name":"maxencerb","email":"me@maxencerb.com"}],"readme":"# @3flabs/guardian-defaults\n\nDefault building blocks for [`@3flabs/guardian`](https://npmjs.com/package/@3flabs/guardian) hosts.\n\nFour subsystems, each independently usable via a dedicated subpath export so tree-shaking\nstays effective:\n\n- **Logger** (`/logger`) — pino + pino-pretty backed structured logger.\n- **Rate limiter** (`/rate-limit`) — single-process fixed-window in-memory counter with a pluggable store.\n- **Cache** (`/cache`) — generic `AsyncCache<V>` interface plus an in-memory implementation, used by §A.1 / §A.4 to amortise on-chain reads, and by the `makeSign*` orchestrators to amortise ERC-5267 `eip712Domain()` reads.\n- **Checks** (`/checks`) — Appendix-A check-runner builders for the four signing endpoints. (The on-chain ABIs they read are exported from the package root — see the [ABIs](#abis) section.)\n\nThe package depends on `@3flabs/guardian` for its types (`Logger`, `TokenInfo`, `RateLimitWindow`,\n`SigningContext`, error classes, body schemas) and on `viem` for the on-chain reads.\n\n## Contents\n\n- [Install](#install)\n- [Full quickstart — a working Guardian on a private key](#full-quickstart--a-working-guardian-on-a-private-key)\n- [Logger](#logger)\n- [Rate limiter](#rate-limiter)\n- [Cache](#cache)\n- [Checks](#checks)\n  - [The four builders](#the-four-builders)\n  - [Scan & failure semantics](#scan--failure-semantics)\n  - [Policy shapes](#policy-shapes)\n  - [Helpers](#helpers)\n- [ABIs](#abis)\n- [Running integration tests](#running-integration-tests)\n- [License](#license)\n\n## Install\n\n```bash\nbun add @3flabs/guardian @3flabs/guardian-defaults viem better-result\n# or\nnpm install @3flabs/guardian @3flabs/guardian-defaults viem better-result\n```\n\n## Full quickstart — a working Guardian on a private key\n\nCopy-pastable. Provide `GUARDIAN_SIGNER_KEY`, the RPC URLs, and at least one bearer token\nin env, then `bun run src/server.ts` (or `node --import tsx src/server.ts`). The result is a\nfully functional HTTP shell that:\n\n- authenticates `Authorization: Bearer …` against an in-memory token map,\n- rate-limits per token (60 req / 60 s),\n- runs the §A check runners (real on-chain reads via viem),\n- signs the EIP-712 typed-data with the configured private key,\n- caches `eip712Domain()` reads + §A.1/§A.4 on-chain reads in-process.\n\nReplace the `*ADDRESSES` and the bearer token with your real values; everything else is\nready as-is. The address sets are deliberately empty `Set<string>` placeholders — the\nrunner will *fail every check* until you populate them, which makes it obvious where the\nhost policy needs to live.\n\n```ts\n// src/server.ts\nimport { Result } from \"better-result\";\nimport { http, createPublicClient, type Hex, type PublicClient } from \"viem\";\nimport { mainnet, base } from \"viem/chains\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { z } from \"zod\";\n\nimport {\n  buildGuardianServer,\n  ENDPOINT_SCOPES,\n  makeSignIntentFundBinding,\n  makeSignIntentRequestBinding,\n  makeSignIntentSwap,\n  makeSignRequestWhitelisting,\n  privateKeyToSignTypedData,\n  UnauthenticatedError,\n  UnsupportedChainError,\n  type GuardianAbstractions,\n  type TokenInfo,\n} from \"@3flabs/guardian\";\nimport { pinoLogger } from \"@3flabs/guardian-defaults/logger\";\nimport { inMemoryRateLimiter } from \"@3flabs/guardian-defaults/rate-limit\";\nimport { inMemoryCache } from \"@3flabs/guardian-defaults/cache\";\nimport {\n  buildIntentFundBindingChecks,\n  buildIntentRequestBindingChecks,\n  buildIntentSwapChecks,\n  buildRequestWhitelistingChecks,\n  zA1OnChainData,\n  type IntentFundBindingPolicy,\n  type IntentRequestBindingPolicy,\n  type IntentSwapPolicy,\n  type RequestWhitelistingPolicy,\n} from \"@3flabs/guardian-defaults/checks\";\n\n// ── 1. Signing key ────────────────────────────────────────────────────\n//\n// Dev only. Production deployments substitute a KMS / HSM-backed\n// `SignTypedData` for `privateKeyToSignTypedData`; the host owns the\n// key, this package never sees it.\nconst PRIVATE_KEY = process.env.GUARDIAN_SIGNER_KEY as Hex | undefined;\nif (!PRIVATE_KEY) throw new Error(\"Missing GUARDIAN_SIGNER_KEY\");\nconst guardianSigner = privateKeyToAccount(PRIVATE_KEY).address;\nconst signTypedData = privateKeyToSignTypedData(PRIVATE_KEY);\n\n// ── 2. Chain clients ──────────────────────────────────────────────────\n//\n// Typed as `Record<number, PublicClient>` and individually cast so the\n// chain-narrowed generics viem produces (e.g. base's deposit-tx\n// formatter) are widened to the generic `PublicClient` shape\n// `GuardianAbstractions.getChainClient` expects. The Guardian only\n// reads on-chain views, so a chain-less generic `PublicClient` is\n// sufficient.\nconst clients: Record<number, PublicClient> = {\n  1: createPublicClient({\n    chain: mainnet,\n    transport: http(process.env.RPC_MAINNET),\n  }) as PublicClient,\n  8453: createPublicClient({\n    chain: base,\n    transport: http(process.env.RPC_BASE),\n  }) as PublicClient,\n};\nconst supportedChains = Object.keys(clients).map(Number);\n\n// ── 3. Bearer-token directory ─────────────────────────────────────────\n//\n// Tiny in-memory map for the quickstart. Real deployments pull this\n// from the host's secret store. `requiresHmac: true` would additionally\n// gate the route on §5.4 timestamp + body-HMAC verification using\n// `hmacSecret`.\nconst TOKENS = new Map<string, TokenInfo>([\n  [\n    process.env.DEV_BEARER_TOKEN ?? \"dev-token\",\n    {\n      tokenId: \"dev\",\n      scopes: new Set(ENDPOINT_SCOPES),\n      requiresHmac: false,\n    },\n  ],\n]);\n\n// ── 4. Caches ─────────────────────────────────────────────────────────\n//\n// Two independent caches — see the \"Cache\" section below for the\n// rationale on splitting them. Sized for a small operator; bump\n// `maxEntries` for high-traffic deployments. The first argument is a\n// schema (any Standard Schema — zod, valibot, arktype) that every hit\n// is re-validated against on read; a value that fails to parse counts\n// as a miss, so a poisoned or stale-shaped entry can never reach the\n// checks.\nconst eip712DomainCache = inMemoryCache(z.object({ name: z.string(), version: z.string() }), {\n  defaultTtlMs: 24 * 60 * 60_000, // 24h — domains are immutable absent a contract upgrade\n  maxEntries: 256,\n});\nconst a1OnChainCache = inMemoryCache(zA1OnChainData, {\n  defaultTtlMs: 5 * 60_000, // 5min — Request roles change rarely but not never\n  maxEntries: 1024,\n});\n\n// ── 5. Policies ───────────────────────────────────────────────────────\n//\n// Per-chain accepted-set membership. The runner FAILS each check when\n// its accepted set is empty, so populate these with the real factory /\n// owner / puller / consumer / fund / position-manager addresses your\n// deployment trusts. Address comparisons are case-insensitive.\nconst requestBindingPolicy: IntentRequestBindingPolicy = {\n  maxDeadlineSecondsAhead: 600,\n  acceptedRequestFactories: new Map([\n    [1, new Set<string>(/* \"0xRequestFactoryOnMainnet\" */)],\n    [8453, new Set<string>(/* \"0xRequestFactoryOnBase\" */)],\n  ]),\n  acceptedOwners: new Map([\n    [1, new Set<string>(/* \"0xOwner1\", \"0xOwner2\", … */)],\n    [8453, new Set<string>()],\n  ]),\n  acceptedPullers: new Map([\n    [1, new Set<string>(/* \"0xPullerSafe\" */)],\n    [8453, new Set<string>()],\n  ]),\n  acceptedConsumers: new Map([\n    [1, new Set<string>(/* \"0xConsumer\" */)],\n    [8453, new Set<string>()],\n  ]),\n  eventScanBlockRange: 10_000n,\n  eventScanMaxLookbackBlocks: 1_000_000n,\n};\n\nconst fundBindingPolicy: IntentFundBindingPolicy = {\n  maxDeadlineSecondsAhead: 600,\n  acceptedFunds: new Map([\n    [1, new Set<string>(/* \"0xFundContract\" */)],\n    [8453, new Set<string>()],\n  ]),\n  acceptedOwners: new Map([\n    [1, new Set<string>(/* \"0xOwner1\" */)],\n    [8453, new Set<string>()],\n  ]),\n};\n\nconst swapPolicy: IntentSwapPolicy = {\n  maxDeadlineSecondsAhead: 600,\n  acceptedPmFactories: new Map([\n    [1, new Set<string>(/* \"0xPositionManagerFactory\" */)],\n    [8453, new Set<string>()],\n  ]),\n  acceptedPmOwners: new Map([\n    [1, new Set<string>(/* \"0xOwner1\" */)],\n    [8453, new Set<string>()],\n  ]),\n  swapPriceToleranceBps: 1, // ~1 wei mulDiv rounding tolerance\n};\n\nconst whitelistingPolicy: RequestWhitelistingPolicy = {\n  ...requestBindingPolicy, // same accepted sets — whitelist op runs §A.1 per-contract\n  maxNonceAboveFloor: 100n,\n};\n\n// ── 6. Abstractions object ────────────────────────────────────────────\nconst abs: GuardianAbstractions = {\n  metadata: {\n    build: process.env.BUILD_ID ?? \"0.1.0\",\n    guardianSigner,\n    supportedChains,\n  },\n  logger: pinoLogger({\n    level: \"info\",\n    pretty: process.env.NODE_ENV !== \"production\",\n    bindings: { service: \"guardian\" },\n  }),\n  liveness: async () => Result.ok(),\n  getChainClient: (chainId) => {\n    const client = clients[chainId];\n    return client\n      ? Result.ok(client)\n      : Result.err(\n          new UnsupportedChainError({ message: `Unsupported chain ${chainId}`, chainId }),\n        );\n  },\n  authenticate: async (token) => {\n    const info = TOKENS.get(token);\n    return info\n      ? Result.ok(info)\n      : Result.err(new UnauthenticatedError({ message: \"Unknown token\" }));\n  },\n  signTypedData,\n  accountRateLimit: inMemoryRateLimiter({ limit: 60, windowSeconds: 60 }),\n\n  // The four §7 sign-runners. Each composes:\n  //   real check runner (this package) → typed-data builder + ERC-5267\n  //   `eip712Domain()` resolution + `signTypedData` (@3flabs/guardian).\n  signIntentRequestBinding: makeSignIntentRequestBinding({\n    checks: buildIntentRequestBindingChecks({\n      policy: requestBindingPolicy,\n      cache: a1OnChainCache,\n    }),\n    guardianSigner,\n    cache: eip712DomainCache,\n  }),\n  signIntentFundBinding: makeSignIntentFundBinding({\n    checks: buildIntentFundBindingChecks({ policy: fundBindingPolicy }),\n    guardianSigner,\n    cache: eip712DomainCache,\n  }),\n  signIntentSwap: makeSignIntentSwap({\n    checks: buildIntentSwapChecks({ policy: swapPolicy }),\n    guardianSigner,\n    cache: eip712DomainCache,\n  }),\n  signRequestWhitelisting: makeSignRequestWhitelisting({\n    checks: buildRequestWhitelistingChecks({\n      policy: whitelistingPolicy,\n      guardianSigner,\n      cache: a1OnChainCache,\n    }),\n    guardianSigner,\n    cache: eip712DomainCache,\n  }),\n};\n\n// ── 7. Listen ─────────────────────────────────────────────────────────\nbuildGuardianServer(abs).listen(3000);\nconsole.log(\"Guardian listening on :3000\");\nconsole.log(`  GET  http://localhost:3000/health`);\nconsole.log(`  GET  http://localhost:3000/version`);\nconsole.log(`  GET  http://localhost:3000/openapi`);\n```\n\nSmoke test:\n\n```bash\ncurl -s localhost:3000/health\n# {\"status\":\"ok\"}\n\ncurl -s localhost:3000/version\n# {\"apiVersion\":\"v1\",\"build\":\"0.1.0\",\"guardianSigner\":\"0x…\",\"supportedChains\":[1,8453]}\n\ncurl -s localhost:3000/v1/facility/intent-request-bindings \\\n  -H \"Authorization: Bearer dev-token\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"X-Client-Name: smoke-test\" \\\n  -H \"X-Client-Version: 1.0.0\" \\\n  -d '{ \"chainId\": 1, \"facility\": \"0x…\", \"intent\": { \"id\": \"1\" }, \"requestContract\": \"0x…\", \"deadline\": 9999999999 }'\n# either { ...SigningSuccess } or { error: \"validation_failed\", checks: [...] }\n```\n\nThe §6.2 `X-Client-Name` / `X-Client-Version` headers are required on every protected\n`/v1/*` route — a missing or malformed value yields `400 bad_request`.\n\n`buildGuardianServer` returns a vanilla [Elysia](https://elysiajs.com/) instance — `.listen`,\n`.handle` (for tests), `.use` (for further composition) all work as you'd expect.\n\n## Logger\n\n```ts\nimport { pinoLogger } from \"@3flabs/guardian-defaults/logger\";\n\nconst logger = pinoLogger({\n  level: \"info\",\n  pretty: process.env.NODE_ENV !== \"production\",\n  bindings: { service: \"guardian\" },\n});\n```\n\n`PinoLoggerOptions`:\n\n| Field | Type | Default | Notes |\n|---|---|---|---|\n| `level` | `\"trace\" \\| \"debug\" \\| \"info\" \\| \"warn\" \\| \"error\" \\| \"fatal\" \\| \"silent\"` | `LOG_LEVEL` env, else `\"info\"` | `LOG_LEVEL` is case-insensitive and accepts the syslog-style alias `warning` (→ `warn`); unrecognised values fall back to `\"info\"` with a one-time stderr warning instead of crashing pino at construction. |\n| `pretty` | `boolean` | auto: `process.stdout.isTTY` | When `false`, emits NDJSON for log shippers. |\n| `bindings` | `Record<string, unknown>` | — | Top-level fields stamped onto every record. |\n| `redact` | `readonly string[]` | `DEFAULT_REDACT_PATHS` | Pino redact paths. The defaults mask `Authorization`, `X-Guardian-Signature`, `X-Guardian-Timestamp`, and `hmacSecret` / `secret` / `privateKey` fields up to two levels deep (e.g. `auth.tokenInfo.hmacSecret`). |\n\nSupplying `redact` REPLACES the defaults. `DEFAULT_REDACT_PATHS` is exported from\n`@3flabs/guardian-defaults/logger` so hosts can merge it with their own paths:\n\n```ts\nimport { DEFAULT_REDACT_PATHS, pinoLogger } from \"@3flabs/guardian-defaults/logger\";\n\nconst logger = pinoLogger({\n  redact: [...DEFAULT_REDACT_PATHS, \"config.db.password\"],\n});\n```\n\nNote pino wildcards match exactly one path segment — there is no recursive wildcard — so\nsecrets nested three or more levels deep still need host-supplied paths.\n\nThe returned value is a `pino.Logger` cast to the Guardian `Logger` contract.\n\n## Rate limiter\n\n```ts\nimport { inMemoryRateLimiter } from \"@3flabs/guardian-defaults/rate-limit\";\n\nconst accountRateLimit = inMemoryRateLimiter({\n  limit: 60,\n  windowSeconds: 60,\n});\n```\n\n`RateLimiterOptions`:\n\n| Field | Type | Default | Notes |\n|---|---|---|---|\n| `limit` | `number` | required | Requests permitted per window. Must be a positive integer. |\n| `windowSeconds` | `number` | required | Width of the fixed window. Must be > 0. |\n| `now` | `() => number` | `Date.now` | Clock injection for tests. |\n| `keyOf` | `(token: TokenInfo) => string` | `(t) => t.tokenId` | Extract the rate-limit key. |\n| `store` | `RateLimitStore` | `inMemoryRateLimitStore()` | Pluggable storage. |\n\n`RateLimitStore` exposes `read` / `write` plus an optional atomic\n`consume(key, limit, windowSeconds, nowSec)` returning a `RateLimitDecision`\n(`{ allowed, count, resetUnixSeconds }`; both types are exported from\n`@3flabs/guardian-defaults/rate-limit`). The limiter delegates the check-and-increment to\n`store.consume` when available; for custom stores exposing only `read` / `write` it\nserialises the read-modify-write per key in-process, so a concurrent burst cannot bypass\nthe per-token limit — but that fallback is single-process safe only. The bundled\n`inMemoryRateLimitStore` implements `consume`.\n\nFor multi-replica deployments, supply your own `RateLimitStore` and implement `consume` on\na transactional primitive (Redis `INCR` + `EXPIRE`, a Cloudflare Durable Object). The\nsingle-process Map-based default is not atomic across processes.\n\n`resetUnixSeconds` and `retryAfterSeconds` are rounded up to whole seconds, so `Retry-After`\nand `X-RateLimit-Reset` are always RFC-9110-valid integers even with a fractional\n`windowSeconds`.\n\n## Cache\n\nTwo distinct cache surfaces — keep them separate so TTLs and eviction policies can diverge.\n\n| Cache | Value type | What it caches | Sensible TTL |\n|---|---|---|---|\n| EIP-712 domain | `{ name: string; version: string }` | `eip712Domain()` reads per `(chainId, verifyingContract)` — used by the `makeSign*` orchestrators in `@3flabs/guardian`. | 24h (immutable absent contract upgrade) |\n| §A.1 / §A.4 on-chain | `A1OnChainData` | Request-contract roles + factory linkage scanned by the §A.1 runner (also used by §A.4 per-contract). | 1–5 min |\n\nEvery cache is constructed with a schema — any [Standard Schema](https://standardschema.dev)\n(zod ≥ 3.24 / v4, valibot ≥ 1.0, arktype ≥ 2.0, …) — and the value type is inferred from\nthe schema's output. `get` re-validates each raw hit through the schema (`safeParse`-style,\nnon-throwing); a stored value that fails to parse is reported as a **miss**, never returned,\nso a poisoned, truncated, or old-package-version entry in a shared store falls back to a\nfresh authoritative fetch. `zA1OnChainData` is exported from `./checks` so you don't have to\nhand-roll the §A.1 discriminated-union schema.\n\nThe schema MUST be idempotent over its own output: `set` stores the schema's **output**\ntype and `get` re-validates exactly that shape, so transforming schemas whose output no\nlonger parses (e.g. `z.string().transform(s => s.length)`) silently turn every hit into a\nmiss, and re-applicable transforms would re-run on every read. Pure validation schemas are\nalways safe.\n\n```ts\nimport { z } from \"zod\";\nimport { inMemoryCache, type AsyncCache } from \"@3flabs/guardian-defaults/cache\";\nimport { zA1OnChainData, type A1OnChainData } from \"@3flabs/guardian-defaults/checks\";\n\nconst eip712DomainCache = inMemoryCache(z.object({ name: z.string(), version: z.string() }), {\n  defaultTtlMs: 24 * 60 * 60_000,\n  maxEntries: 256,\n});\n\nconst a1OnChainCache: AsyncCache<A1OnChainData> = inMemoryCache(zA1OnChainData, {\n  defaultTtlMs: 5 * 60_000,\n  maxEntries: 1024,\n});\n```\n\n`InMemoryCacheOptions`:\n\n| Field | Type | Default | Notes |\n|---|---|---|---|\n| `defaultTtlMs` | `number` | unset | Applied when `set` is called without `ttlMs`. If omitted, entries live forever (until evicted by `maxEntries`). |\n| `maxEntries` | `number` | `4096` (`DEFAULT_MAX_ENTRIES`) | Soft LRU bound. On overflow: sweep expired, then trim oldest insertion-ordered entries. Pass an explicit `0` to opt back into unbounded growth. |\n| `now` | `() => number` | `Date.now` | Clock injection for tests. |\n\n`set` throws on a non-finite or non-positive per-call `ttlMs` (e.g. `NaN` from an unset env\nvar) instead of silently creating an immortal or instantly-expiring entry; callers already\ntreat a throwing `set` as best-effort per the `AsyncCache` contract.\n\n`AsyncCache<V>` is an abstract class. The base class owns the validated read path (`get`);\nimplementations subclass it and provide the raw storage primitives — a protected\n`rawGet(key): Promise<unknown>` (return `undefined` for miss/expired, no validation) plus\n`set` and `delete`. Back it with Redis / Memcached / KV freely; transport-backed adapters\nMUST handle their own serialisation and revive the domain shape (`Map` ↔ entries,\n`bigint` ↔ `string`) before `rawGet` returns, so the schema sees the same shape `set`\nreceived (the in-memory cache stores by reference and side-steps serialisation entirely):\n\n```ts\nimport { AsyncCache } from \"@3flabs/guardian-defaults/cache\";\nimport { zA1OnChainData, type A1OnChainData } from \"@3flabs/guardian-defaults/checks\";\n\nclass RedisA1Cache extends AsyncCache<A1OnChainData> {\n  constructor(private readonly redis: RedisClient) {\n    super(zA1OnChainData);\n  }\n  protected async rawGet(key: string): Promise<unknown> {\n    const raw = await this.redis.get(key);\n    return raw === null ? undefined : reviveA1(JSON.parse(raw)); // Map/bigint revival\n  }\n  async set(key: string, value: A1OnChainData, options?: { ttlMs?: number }): Promise<void> {\n    await this.redis.set(key, serialiseA1(value), options?.ttlMs);\n  }\n  async delete(key: string): Promise<void> {\n    await this.redis.del(key);\n  }\n}\n```\n\n## Checks\n\nEach builder evaluates the corresponding Appendix-A checks and returns a\n`CheckRunner<Body, NeedsConflict>` — an async function taking `(SigningContext, Body)` and\nyielding `Result<readonly CheckEntry[], CheckRunnerError<NeedsConflict>>`. On a green run\nthe entries are returned `Ok`; otherwise the error union is `ValidationFailedError | UpstreamUnavailableError`\n(plus `StateConflictError` for §A.2).\n\nHosts compose the builder's runner with the typed-data orchestrators in `@3flabs/guardian`\nto produce a drop-in `SignIntent…` / `SignRequestWhitelisting` abstraction — see the\nquickstart above for the full wiring of all four endpoints.\n\n```ts\nimport {\n  buildIntentSwapChecks,\n  type IntentSwapPolicy,\n} from \"@3flabs/guardian-defaults/checks\";\nimport { makeSignIntentSwap } from \"@3flabs/guardian\";\n\nconst policy: IntentSwapPolicy = {\n  maxDeadlineSecondsAhead: 600,\n  swapPriceToleranceBps: 1,\n  acceptedPmFactories: new Map([\n    [1, new Set([\"0xPositionManagerFactoryAddress\"])],\n  ]),\n  acceptedPmOwners: new Map([\n    [1, new Set([\"0xAcceptedOwnerAddress\"])],\n  ]),\n};\n\nconst signIntentSwap = makeSignIntentSwap({\n  checks: buildIntentSwapChecks({ policy }),\n  guardianSigner: \"0x…\", // metadata.guardianSigner\n});\n```\n\n`makeSign*` reads each verifying contract's EIP-712 domain (`name`/`version`)\nvia ERC-5267 `eip712Domain()` and hands the matching typed-data to\n`ctx.signTypedData`. Pass an optional `cache` (`AsyncCache<{ name; version }>`\n— `inMemoryCache` constructed with a `{ name, version }` schema qualifies) to\namortise the domain read across signing calls.\n\nFor callers that need the raw building blocks, the four `build*TypedData`\nhelpers (`buildIntentRequestBindingTypedData`, `buildIntentFundBindingTypedData`,\n`buildIntentSwapTypedData`, `buildWhitelistRequestTypedData` /\n`buildUnwhitelistRequestTypedData`) are exported alongside the orchestrators.\n\nNote: the runner reads the on-chain state itself via `ctx.client` and the bundled ABIs\n(see [ABIs](#abis) below). There is **no** oracle adapter port — the package is\nviem-driven, not ABI-agnostic.\n\n### The four builders\n\n| Endpoint | Builder | `deps` |\n|---|---|---|\n| `intent-request-bindings` (§A.1) | `buildIntentRequestBindingChecks` | `{ policy: IntentRequestBindingPolicy, cache?, cacheTtlMs? }` |\n| `intent-fund-bindings` (§A.2)    | `buildIntentFundBindingChecks`    | `{ policy: IntentFundBindingPolicy }` |\n| `intent-swaps` (§A.3)            | `buildIntentSwapChecks`           | `{ policy: IntentSwapPolicy }` |\n| `request-whitelistings` (§A.4)   | `buildRequestWhitelistingChecks`  | `{ policy: RequestWhitelistingPolicy, guardianSigner: Address, cache?, cacheTtlMs? }` |\n\n`buildIntentFundBindingChecks` is the only runner whose error union includes\n`StateConflictError` — the §A.2 fund-state check is the only 409-class check in v1. Per\n§6.6.1 it returns `ValidationFailedError` over `StateConflictError` when both classes fail.\n\n### Scan & failure semantics\n\nThe §A.1 role-events scan (also run per request contract by §A.4 whitelist ops) walks\n`getLogs` backwards in `eventScanBlockRange`-sized chunks — every chunk, including the\ndeepest one, spans at most `eventScanBlockRange` blocks, so providers with a hard range\nlimit equal to the configured range never reject a chunk.\n\n- **Lookback exhausted** — when the scan exhausts `eventScanMaxLookbackBlocks` without\n  observing the contract's deployment, role grants observed inside the scanned window are\n  still evaluated one-sidedly: any non-accepted puller / consumer holder observed in-window\n  fails the §A.1 / §A.4 checks (422). Partial data can only reject, never approve. The\n  residual disposition is governed by `onLookbackExhausted`: `\"skip\"` (default) emits the\n  role checks as skipped, `\"fail\"` fails closed (422).\n- **Trusted request contracts** — `trustedRequestContracts` (optional) short-circuits\n  §A.1 for a listed `requestContract` before the cache lookup and every RPC: the factory,\n  owner, and puller / consumer / executor role checks are emitted as skipped, nothing is\n  read on chain, and only the deadline check still applies. §A.4 whitelist ops inherit it\n  per request contract, so a batch of listed contracts costs no scan at all. This\n  delegates provenance, ownership, and role configuration to whoever controls the listed\n  contract — including grants made after it was listed — so treat the set as an extension\n  of the Guardian's own trust boundary; every bypass is logged at warn level.\n- **Scan budget** — `eventScanDeadlineMs` (optional) bounds a single scan's wall clock;\n  when exceeded the request fails `503 upstream_unavailable` instead of holding the\n  handler indefinitely.\n- **422 vs 503** — a deterministic `owner()` failure (revert / no return data, e.g. an EOA\n  or unrelated contract supplied as `requestContract`) is classified as a cached `noFactory`\n  result that fails the \"deployed by an accepted factory\" check (422). A deterministic\n  `isRequest()` failure on an operator-configured accepted factory is a configuration\n  error, not a client error: it is logged at error level and treated as a non-match, and if\n  no healthy factory recognises the contract the request fails `503 upstream_unavailable`\n  and is never cached. Likewise a `whitelistBook` whose nonce reads deterministically revert\n  or return no data (e.g. an EOA) fails a 422 \"whitelist book exposes per-validator nonce\n  state\" check. `503 upstream_unavailable` covers genuine transport-level RPC failures and\n  the failed-factory-slot case above.\n- **§A.4 request guards** — before any RPC: a `requestContracts` batch larger than\n  `maxRequestContracts` (default `DEFAULT_MAX_REQUEST_CONTRACTS = 50`, exported from\n  `@3flabs/guardian-defaults/checks`) fails a 422 check for both whitelist and unwhitelist\n  operations — the builder throws at construction for a non-positive or fractional cap —\n  and, when `acceptedWhitelistBooks` is configured, an off-policy `whitelistBook` (the\n  EIP-712 `verifyingContract`) fails a 422 \"whitelist book is on the accepted-books list\"\n  check.\n- **Swap tolerance** — `buildIntentSwapChecks` throws a `TypeError` at construction when\n  `swapPriceToleranceBps` is not a non-negative integer. Whenever the bps is > 0 the\n  tolerance is floored at 1 wei, so small legs (`expectedDebt × bps < 10,000`) retain the\n  documented ~1 wei mulDiv rounding slack; `0` still means strict equality.\n\n### Policy shapes\n\nEvery policy keys per-chain accepted sets by EIP-155 chain id; address comparisons are\ncase-insensitive.\n\n```ts\ntype IntentRequestBindingPolicy = {\n  maxDeadlineSecondsAhead: number;\n  trustedRequestContracts?: ReadonlyMap<number, ReadonlySet<string>>; // listed ⇒ skip every on-chain check\n  acceptedRequestFactories: ReadonlyMap<number, ReadonlySet<string>>;\n  acceptedOwners:           ReadonlyMap<number, ReadonlySet<string>>;\n  acceptedPullers:          ReadonlyMap<number, ReadonlySet<string>>;\n  acceptedConsumers:        ReadonlyMap<number, ReadonlySet<string>>;\n  eventScanBlockRange:        bigint;  // chunk size for getLogs (every chunk ≤ this)\n  eventScanMaxLookbackBlocks: bigint;  // give-up horizon\n  eventScanDeadlineMs?:       number;  // wall-clock budget per scan; exceeded ⇒ 503\n  onLookbackExhausted?: \"skip\" | \"fail\"; // role checks when the horizon is exhausted (default \"skip\")\n};\n\ntype IntentFundBindingPolicy = {\n  maxDeadlineSecondsAhead: number;\n  acceptedFunds:  ReadonlyMap<number, ReadonlySet<string>>;\n  acceptedOwners: ReadonlyMap<number, ReadonlySet<string>>;\n};\n\ntype IntentSwapPolicy = {\n  maxDeadlineSecondsAhead: number;\n  acceptedPmFactories: ReadonlyMap<number, ReadonlySet<string>>;\n  acceptedPmOwners:    ReadonlyMap<number, ReadonlySet<string>>;\n  swapPriceToleranceBps: number;       // non-negative integer; 1 absorbs the ~1 wei mulDiv rounding\n};\n\ntype RequestWhitelistingPolicy = IntentRequestBindingPolicy & {\n  maxNonceAboveFloor: bigint;          // per-validator nonce window in the whitelist book\n  acceptedWhitelistBooks?: ReadonlyMap<number, ReadonlySet<string>>; // gate on the EIP-712 verifyingContract\n  maxRequestContracts?: number;        // batch cap; default DEFAULT_MAX_REQUEST_CONTRACTS (50)\n};\n```\n\n### Helpers\n\n- `failed(description, reason)` / `passed(description)` / `skipped(description)` — `CheckEntry`\n  builders. Re-exported from `@3flabs/guardian` so hosts writing their own runners get\n  the same shape.\n- `checkDeadline`, `checkMembership`, `checkNonceWindow`, `checkSwapPriceTolerance`,\n  `rollUp` — primitives the bundled runners are built from. Useful when assembling\n  custom check arrays. `checkSwapPriceTolerance` never throws: an invalid `toleranceBps`\n  yields a failed check entry (fail closed) instead of an exception.\n\n## ABIs\n\nThe on-chain reads happen against bundled ABIs and constants, exported from the package\nroot for hosts that want to issue their own contract calls (e.g., to enrich responses or\nto implement adjacent flows the Guardian doesn't sign for):\n\n| Export | What it is |\n|---|---|\n| `facilityAbi` | Facility contract — `getIntent(id)` for §A.2. |\n| `fundAbi` | Fund contract — `Ownable.owner()` plus role / order-state views. |\n| `requestAbi` | Request contract — `Ownable.owner()` plus the `RolesUpdated` event scanned in §A.1. |\n| `requestFactoryAbi` | Request factory — `isRequest(addr)` for §A.1, `RequestCreated` event for the deployment-block lookup. |\n| `positionManagerAbi` | Position manager — `owner / assets / pendingFees / virtualShareOffset` for §A.3. |\n| `positionManagerFactoryAbi` | Position-manager factory — `isPositionManager(addr)` for §A.3. |\n| `whitelistBookAbi` | Whitelist book — `validatorNonceFloor` and `isNonceConsumed` for §A.4. |\n| `ORDER_STATE` / `ORDER_STATE_NAME` / `OrderState` | Numeric enum + reverse map for `IFund.state(Order)`. |\n| `DEPOSITOR_ROLE` | `keccak256(\"DEPOSITOR_ROLE\")` constant referenced by §A.2. |\n| `ROLE_PULLER` / `ROLE_CONSUMER` | Role bitfield constants used by the §A.1 role-events scan. |\n| `VIRTUAL_ASSETS` | The `1n` constant grunt's `LibView.convertToShares` adds to `totalAssets` (used in the §A.3 share-price math). |\n\n## Running integration tests\n\nThe four §A.1–§A.4 check runners and the four `makeSign*` orchestrators are\nintegration-tested against a real on-chain deployment. Each vitest worker spins up its\nown anvil (via [prool](https://github.com/wevm/prool)), deploys the Guardian-relevant\nslice of the 3F protocol (Facility, RequestFactory + a real Request, PositionManagerFactory\n+ a real PositionManager, RequestWhitelist proxy, `OwnableMockFund`, two MockERC20s,\nmulticall3 at the canonical address), and runs the runners + orchestrators against the\nlive state.\n\n- `tests/integration/intent-request-binding.integration.test.ts` — §A.1 happy path,\n  rogue contract (Facility passed where a Request is expected), bad puller list.\n- `tests/integration/intent-fund-binding.integration.test.ts` — §A.2 happy path plus\n  rotated-owner case (`OwnableMockFund.setOwner(…)` mutates the on-chain owner mid-test).\n- `tests/integration/intent-swap.integration.test.ts` — §A.3 with one PM leg + one debt\n  leg priced at the empty-PM share price, neither-leg-PM, bad PM owner.\n- `tests/integration/request-whitelisting.integration.test.ts` — §A.4 whitelist op at\n  `nonce == floor == 0`, unwhitelist op (skips per-contract §A.1), nonce-window violation.\n- `tests/integration/e2e-sign-runners.integration.test.ts` — full end-to-end flow per §7\n  endpoint: real check runner → real `makeSign*` orchestrator → broadcast on-chain via\n  `Facility.setRequest` / `setFund` / `swap` / `RequestWhitelist.{whitelist,unwhitelist}BySig`.\n  Failure paths cover `NotGuardian`, `DeadlineExpired` / `SwapExpired`, `QuorumNotMet`,\n  `DuplicateSignature`, and `NonceConsumed`.\n\nPrerequisite: `anvil` on `PATH`. From the repo root:\n\n```bash\nbun run test:integration\n```\n\nThe shared anvil pool, deployment script, and foundry artifacts live in the private\n`@3flabs/guardian-test-fixtures` workspace package and are never published.\n\n## License\n\nMIT.\n","readmeFilename":"README.md"}