{"_id":"@alfredaoo/auth-policies","_rev":"10-620971bed977103ea3525cfa1f34f372","name":"@alfredaoo/auth-policies","dist-tags":{"latest":"1.0.0"},"versions":{"0.1.0":{"name":"@alfredaoo/auth-policies","version":"0.1.0","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","_id":"@alfredaoo/auth-policies@0.1.0","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"homepage":"https://github.com/Alfredao/auth-policies#readme","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"dist":{"shasum":"bedc429c9f0422c1070a926bfd1a35479fa36af6","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-0.1.0.tgz","fileCount":9,"integrity":"sha512-UQtYMOh6cg69lHCOJnxUXf4wLLuRcdnWmWa+xlKHMOhKk1CDKYtQfslfITWEWCzlPjL1CLmLRY9UKLCDsYZ17A==","signatures":[{"sig":"MEYCIQCXIfLAwDeUKFSMejAFpIOmuiHnUC/yBBGgaCXUSDVOTwIhANk4BXX8nPu5XDh1mtJ+65UXadO9oHYDXUbF4FNZqfLx","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":63802},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"8e0f529a6c5e42258e06facd777d317aea7eb518","scripts":{"dev":"tsup --watch","lint":"eslint src/","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"repository":{"url":"git+https://github.com/Alfredao/auth-policies.git","type":"git"},"_npmVersion":"10.9.4","description":"A flexible, framework-agnostic authorization library with policy-based access control","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","typescript":"^5.7.0","@types/node":"^22.0.0"},"peerDependencies":{"next":">=14.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auth-policies_0.1.0_1767544860434_0.8214624026951822","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@alfredaoo/auth-policies","version":"0.2.0","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","_id":"@alfredaoo/auth-policies@0.2.0","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"homepage":"https://github.com/Alfredao/auth-policies#readme","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"dist":{"shasum":"ba84cfe1fb43aeb28aba4838c816ccf49f45a7cd","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-0.2.0.tgz","fileCount":9,"integrity":"sha512-Cq49IGE4m9LR9SFuBxplCH/1hYDzXhj2siZkYCg+fSvxC7MLLdJ9zeod1zbj+jMIvLhmxwXfHgesHggfeBSBxQ==","signatures":[{"sig":"MEQCIDT3VIozltlFjTeaDsUxdRD+yzbkvi/Y2RekCUY0yHFkAiAHg+uHQaMkb/LgKsLmTz5t/WlGEDvAluEv4Dpz6HHXvw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":99199},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"9bcbc52ab79d6e843e2721bdaeabcbf776af04da","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"repository":{"url":"git+https://github.com/Alfredao/auth-policies.git","type":"git"},"_npmVersion":"10.9.4","description":"A flexible, framework-agnostic authorization library with policy-based access control","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^4.0.16","typescript":"^5.7.0","@types/node":"^22.0.0","@vitest/coverage-v8":"^4.0.16"},"peerDependencies":{"next":">=14.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auth-policies_0.2.0_1767547030687_0.024386758389307595","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@alfredaoo/auth-policies","version":"0.3.0","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","_id":"@alfredaoo/auth-policies@0.3.0","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"homepage":"https://github.com/Alfredao/auth-policies#readme","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"dist":{"shasum":"bbe8b1aa5810685fc47ac9d6608996068e1a0397","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-0.3.0.tgz","fileCount":15,"integrity":"sha512-3l/VklgNtsOGciJu4PQCkSYkXk1Zw2PUKRc5VVlOWT2WE/aqd2J/v5uicZwXWv6bJ/KRdUv3r6Y2xBFxX1rs8w==","signatures":[{"sig":"MEQCIHj1nGHt16uF/phlNuA+BslfUiF5kTDlYwcecqExinD7AiBThorOcyLxIjIHFobekwJasxpezxZSVjYHK2EVA/rloQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":161998},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}}},"gitHead":"70b36e89a1bb4bb87e70a00128fd652fec136042","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"repository":{"url":"git+https://github.com/Alfredao/auth-policies.git","type":"git"},"_npmVersion":"10.9.4","description":"A flexible, framework-agnostic authorization library with policy-based access control","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","jsdom":"^27.4.0","react":"^19.2.3","vitest":"^4.0.16","typescript":"^5.7.0","@types/node":"^22.0.0","@types/react":"^19.2.7","@vitest/coverage-v8":"^4.0.16","@testing-library/react":"^16.3.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auth-policies_0.3.0_1767548865922_0.7172382081390474","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@alfredaoo/auth-policies","version":"0.4.0","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","_id":"@alfredaoo/auth-policies@0.4.0","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"homepage":"https://github.com/Alfredao/auth-policies#readme","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"dist":{"shasum":"07af3b7cf1c9c27e49f15e9d60bb936c850c6c12","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-0.4.0.tgz","fileCount":21,"integrity":"sha512-PSKKmXFdt7TzDHAMAeenWtJfiw/AU95cFm6ScbJsOQ3yAD8HBOd6DpIr2qSlxtQnvFEMxj5fw5uoeoh8LyJZKw==","signatures":[{"sig":"MEUCIQCWPaoiHpLjkEnMGDj0GDGhYRwqdpnvrbnGt95PZdm7MAIgc9UKnlCBeDPZkzWsP+vosTNkZFwXGa+JZnXWKuim8t4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":289744},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./middleware":{"import":{"types":"./dist/middleware.d.ts","default":"./dist/middleware.js"},"require":{"types":"./dist/middleware.d.cts","default":"./dist/middleware.cjs"}}},"gitHead":"0113723fec03addf2918832af303acc5a607abbe","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"repository":{"url":"git+https://github.com/Alfredao/auth-policies.git","type":"git"},"_npmVersion":"10.9.4","description":"A flexible, framework-agnostic authorization library with policy-based access control","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","jsdom":"^27.4.0","react":"^19.2.3","vitest":"^4.0.16","typescript":"^5.7.0","@types/node":"^22.0.0","@types/react":"^19.2.7","@vitest/coverage-v8":"^4.0.16","@testing-library/react":"^16.3.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auth-policies_0.4.0_1767549890429_0.4160229814225871","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@alfredaoo/auth-policies","version":"0.5.0","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","_id":"@alfredaoo/auth-policies@0.5.0","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"homepage":"https://github.com/Alfredao/auth-policies#readme","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"dist":{"shasum":"8c05d6b4a7f8ea511f58858402b3cf7daf1cb772","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-0.5.0.tgz","fileCount":21,"integrity":"sha512-Ea5/MOMSdjfxLGhbJ7v4diCk73at9tnwA07otjUhCv0INn0kTf4IfoQg+Yq235uFLgBjXguWGdwIN8rZrHDH9g==","signatures":[{"sig":"MEYCIQCjoricwVJGSoyRpq2eNvdMyoL8TlROZPlG1oSBvWp/kAIhAIHQiR9wyS8NHsV7DrHWfXgfBEhFbkk6JpCBuxYJXE0m","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":342955},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./middleware":{"import":{"types":"./dist/middleware.d.ts","default":"./dist/middleware.js"},"require":{"types":"./dist/middleware.d.cts","default":"./dist/middleware.cjs"}}},"gitHead":"2dbf9416d3b171a46c6c2d7755fac6eea54f590e","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"repository":{"url":"git+https://github.com/Alfredao/auth-policies.git","type":"git"},"_npmVersion":"10.9.4","description":"A flexible, framework-agnostic authorization library with policy-based access control","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","jsdom":"^27.4.0","react":"^19.2.3","vitest":"^4.0.16","typescript":"^5.7.0","@types/node":"^22.0.0","@types/react":"^19.2.7","@vitest/coverage-v8":"^4.0.16","@testing-library/react":"^16.3.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auth-policies_0.5.0_1767552674512_0.06849912679369097","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@alfredaoo/auth-policies","version":"0.6.0","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","_id":"@alfredaoo/auth-policies@0.6.0","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"homepage":"https://github.com/Alfredao/auth-policies#readme","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"dist":{"shasum":"feb2f92ebd67e5be1a7ea8a3948f0ad2a41452d7","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-0.6.0.tgz","fileCount":21,"integrity":"sha512-plPt/US/ZxP6IgVaqP+BSfKMoEc3swN7ayAGIJOIDcnoP1pVkLp1HZiRpOb40mfCoSAvRCdFxucPNdrbHr3G+g==","signatures":[{"sig":"MEUCIQDO7RPbezgbJ2/Ynsaa2MJTgRx8IWRgqFOprugNxDxk/QIgfG/viupvud3DC+4YUV/c1r2A0ggD6ke865olmnvV+Ws=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":449065},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./middleware":{"import":{"types":"./dist/middleware.d.ts","default":"./dist/middleware.js"},"require":{"types":"./dist/middleware.d.cts","default":"./dist/middleware.cjs"}}},"gitHead":"ca9a96ac3d1f078274afa5fde3bb57dc1ec22832","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"repository":{"url":"git+https://github.com/Alfredao/auth-policies.git","type":"git"},"_npmVersion":"10.9.4","description":"A flexible, framework-agnostic authorization library with policy-based access control","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","jsdom":"^27.4.0","react":"^19.2.3","vitest":"^4.0.16","typescript":"^5.7.0","@types/node":"^22.0.0","@types/react":"^19.2.7","@vitest/coverage-v8":"^4.0.16","@testing-library/react":"^16.3.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auth-policies_0.6.0_1767553301439_0.10360285490128973","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@alfredaoo/auth-policies","version":"0.7.0","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","_id":"@alfredaoo/auth-policies@0.7.0","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"homepage":"https://github.com/Alfredao/auth-policies#readme","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"dist":{"shasum":"0a8e39119fab76a072e479b2dcc35a84dc4eb015","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-0.7.0.tgz","fileCount":21,"integrity":"sha512-1i/tSFzqkjJb0+DjHSLNQq3QdjnYojfGjJQ5oeRemTAvaf3O7elQ2acnn+foLfRhgfMb0QN87l9NWdhxZbP/8g==","signatures":[{"sig":"MEQCIAZV0kdSgJwzpj1zZB0NBa3e5KJugj/9OJt2NPL0M9YHAiBXHhrhbtU84VIhVv13vVsUTC8xQ2nsxv35UXQF+1YKKg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":494951},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./middleware":{"import":{"types":"./dist/middleware.d.ts","default":"./dist/middleware.js"},"require":{"types":"./dist/middleware.d.cts","default":"./dist/middleware.cjs"}}},"gitHead":"517dfbaff590d497f47b8b4a9973395ba560370e","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"repository":{"url":"git+https://github.com/Alfredao/auth-policies.git","type":"git"},"_npmVersion":"10.9.4","description":"A flexible, framework-agnostic authorization library with policy-based access control","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","jsdom":"^27.4.0","react":"^19.2.3","vitest":"^4.0.16","typescript":"^5.7.0","@types/node":"^22.0.0","@types/react":"^19.2.7","@vitest/coverage-v8":"^4.0.16","@testing-library/react":"^16.3.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auth-policies_0.7.0_1767555524408_0.20234765171435298","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@alfredaoo/auth-policies","version":"0.8.0","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","_id":"@alfredaoo/auth-policies@0.8.0","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"homepage":"https://github.com/Alfredao/auth-policies#readme","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"dist":{"shasum":"1f53acd8b6be8b0fe2add16e8720f3a976f33823","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-0.8.0.tgz","fileCount":21,"integrity":"sha512-527YErs6XfVCSezLXyiUiOjSnlgiwvGjItyXsWP3bXNCB+TIS/RlM6NO0BXU6RIwxSSX86SYopKxYRld6229nw==","signatures":[{"sig":"MEUCIBL1QPooIuyz0Kf6aa5R4KGTBeOOkKr+vnclvPjj8gw2AiEAkLodpkYoNYrpi84q0uZ6zHUmmpCSkngGBQqJ2xy1CLU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":518671},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./middleware":{"import":{"types":"./dist/middleware.d.ts","default":"./dist/middleware.js"},"require":{"types":"./dist/middleware.d.cts","default":"./dist/middleware.cjs"}}},"gitHead":"57e8283d4e1537c506b7cdeebd97ded4af27ed47","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"repository":{"url":"git+https://github.com/Alfredao/auth-policies.git","type":"git"},"_npmVersion":"10.9.4","description":"A flexible, framework-agnostic authorization library with policy-based access control","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","jsdom":"^27.4.0","react":"^19.2.3","vitest":"^4.0.16","typescript":"^5.7.0","@types/node":"^22.0.0","@types/react":"^19.2.7","@vitest/coverage-v8":"^4.0.16","@testing-library/react":"^16.3.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auth-policies_0.8.0_1767557141245_0.6314512808225909","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@alfredaoo/auth-policies","version":"0.9.0","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","_id":"@alfredaoo/auth-policies@0.9.0","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"homepage":"https://github.com/Alfredao/auth-policies#readme","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"dist":{"shasum":"48b331f5c9b8276e26d569f705048e8f012699eb","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-0.9.0.tgz","fileCount":21,"integrity":"sha512-0n/D5+47NAhdXsz3k4zUkTODbqvmVqKCkO/2Ha0XftEXTeijRgkrn4fP5JqgX413Dixh4O+TOq0J4K2EucxSqw==","signatures":[{"sig":"MEYCIQCX+8Lzrpa8OvZ6vP5sWoHiWIKhMQjuFgnqnkLVuHc+KgIhAKQk910jON7ikGePIVvXMTBLqKA+ZsDBVT2qgKtpSDYY","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":651204},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./middleware":{"import":{"types":"./dist/middleware.d.ts","default":"./dist/middleware.js"},"require":{"types":"./dist/middleware.d.cts","default":"./dist/middleware.cjs"}}},"gitHead":"bdb6e6512532837c3d1889c81992d94ac08b3fca","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"repository":{"url":"git+https://github.com/Alfredao/auth-policies.git","type":"git"},"_npmVersion":"10.9.4","description":"A flexible, framework-agnostic authorization library with policy-based access control","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","jsdom":"^27.4.0","react":"^19.2.3","vitest":"^4.0.16","typescript":"^5.7.0","@types/node":"^22.0.0","@types/react":"^19.2.7","@vitest/coverage-v8":"^4.0.16","@testing-library/react":"^16.3.1"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auth-policies_0.9.0_1767558511118_0.6087480014732998","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@alfredaoo/auth-policies","version":"1.0.0","description":"A flexible, framework-agnostic authorization library with policy-based access control","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./react":{"import":{"types":"./dist/react.d.ts","default":"./dist/react.js"},"require":{"types":"./dist/react.d.cts","default":"./dist/react.cjs"}},"./middleware":{"import":{"types":"./dist/middleware.d.ts","default":"./dist/middleware.js"},"require":{"types":"./dist/middleware.d.cts","default":"./dist/middleware.cjs"}}},"scripts":{"build":"tsup","dev":"tsup --watch","lint":"eslint src/","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/Alfredao/auth-policies.git"},"devDependencies":{"@testing-library/react":"^16.3.1","@types/node":"^22.0.0","@types/react":"^19.2.7","@vitest/coverage-v8":"^4.0.16","jsdom":"^27.4.0","react":"^19.2.3","tsup":"^8.0.0","typescript":"^5.7.0","vitest":"^4.0.16"},"peerDependencies":{"next":">=14.0.0","react":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true}},"engines":{"node":">=18.0.0"},"_id":"@alfredaoo/auth-policies@1.0.0","gitHead":"419369ee935673045ac10c6b8326d0d0b1aea153","bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"homepage":"https://github.com/Alfredao/auth-policies#readme","_nodeVersion":"22.21.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-V/ePmDLlCqfjVnS/DGLwejCaqRxXoRWhu0o6ReGx1GnABDcqflB1tMXmDnYSetv9SdRSRFVj7xTLOt0QBkVQLA==","shasum":"552100e2868ef2cc01c74374e830ae16bfb8bcf1","tarball":"https://registry.npmjs.org/@alfredaoo/auth-policies/-/auth-policies-1.0.0.tgz","fileCount":21,"unpackedSize":651204,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIC+QUT/U/P4xsplQ/ZFXOdUDt4LyJlvtNVDLKYmGCGWYAiBLDfgpag64LtDN3O8j2aPs3sjE9kQuZIL/4PCUyyfTow=="}]},"_npmUser":{"name":"alfredaoo","email":"alfredocosta@live.com"},"directories":{},"maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/auth-policies_1.0.0_1767558771554_0.9561481455217489"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-04T16:41:00.333Z","modified":"2026-01-04T20:32:51.909Z","0.1.0":"2026-01-04T16:41:00.585Z","0.2.0":"2026-01-04T17:17:10.824Z","0.3.0":"2026-01-04T17:47:46.062Z","0.4.0":"2026-01-04T18:04:50.590Z","0.5.0":"2026-01-04T18:51:14.669Z","0.6.0":"2026-01-04T19:01:41.598Z","0.7.0":"2026-01-04T19:38:44.577Z","0.8.0":"2026-01-04T20:05:41.402Z","0.9.0":"2026-01-04T20:28:31.296Z","1.0.0":"2026-01-04T20:32:51.710Z"},"bugs":{"url":"https://github.com/Alfredao/auth-policies/issues"},"author":{"name":"Alfredo","email":"alfredo@example.com"},"license":"MIT","homepage":"https://github.com/Alfredao/auth-policies#readme","keywords":["authorization","rbac","policies","permissions","access-control","typescript"],"repository":{"type":"git","url":"git+https://github.com/Alfredao/auth-policies.git"},"description":"A flexible, framework-agnostic authorization library with policy-based access control","maintainers":[{"name":"alfredaoo","email":"alfredocosta@live.com"}],"readme":"# @alfredaoo/auth-policies\n\nA flexible, framework-agnostic authorization library with policy-based access control (RBAC).\n\n## Features\n\n- **Policy-based authorization** - Define granular access rules per resource type\n- **Role-permission mapping** - Simple role to permissions configuration\n- **Permission inheritance** - Define role hierarchies with automatic permission inheritance\n- **Multiple roles** - Users can have multiple roles with merged permissions\n- **Multi-tenancy** - Different roles per organization/tenant with tenant-scoped permissions\n- **Context-aware checks** - Pass resources for dynamic authorization decisions\n- **Framework-agnostic** - Works with any Node.js application\n- **React hooks** - `useAuth`, `usePermission`, `<Can>` components for React apps\n- **Next.js integration** - Built-in helpers for Next.js applications\n- **Caching** - LRU cache with TTL for policy check results\n- **Audit logging** - Track all authorization decisions\n- **TypeScript-first** - Full type safety and IntelliSense support\n- **Lightweight** - Zero dependencies\n\n## Installation\n\n```bash\nnpm install @alfredaoo/auth-policies\n# or\npnpm add @alfredaoo/auth-policies\n# or\nyarn add @alfredaoo/auth-policies\n```\n\n## Quick Start\n\n### 1. Define your roles and permissions\n\n```typescript\n// lib/authorization/role-permissions.ts\nexport const rolePermissions = {\n  SUPER_ADMIN: [\n    'view.user', 'viewAll.user', 'create.user', 'update.user', 'delete.user',\n    'view.instance', 'viewAll.instance', 'create.instance', 'update.instance', 'delete.instance',\n  ],\n  ADMIN: [\n    'view.instance', 'viewAll.instance', 'create.instance', 'update.instance', 'delete.instance',\n  ],\n  OPERATOR: [\n    'view.instance', 'viewAll.instance',\n  ],\n} as const\n\nexport type Role = keyof typeof rolePermissions\nexport type Permission = (typeof rolePermissions)[Role][number]\n```\n\n### 2. Define your user type\n\n```typescript\n// lib/authorization/types.ts\nimport type { BaseUser } from '@alfredao/auth-policies'\nimport type { Role } from './role-permissions'\n\nexport interface AuthorizedUser extends BaseUser<Role> {\n  id: string\n  role: Role\n  email: string\n  name: string\n}\n```\n\n### 3. Create policies for your resources\n\n```typescript\n// lib/policies/user-policy.ts\nimport type { AuthorizedUser } from '../authorization/types'\nimport { hasPermission } from '../authorization'\n\nexport const UserPolicy = {\n  async view(user: AuthorizedUser, resource?: User) {\n    // Users can always view themselves\n    if (resource && user.id === resource.id) return true\n    return hasPermission(user, 'view.user')\n  },\n\n  async viewAll(user: AuthorizedUser) {\n    return hasPermission(user, 'viewAll.user')\n  },\n\n  async update(user: AuthorizedUser, resource?: User) {\n    // Users can update themselves\n    if (resource && user.id === resource.id) return true\n    // Admins cannot modify super admins\n    if (user.role === 'ADMIN' && resource?.role === 'SUPER_ADMIN') return false\n    return hasPermission(user, 'update.user')\n  },\n\n  async delete(user: AuthorizedUser, resource?: User) {\n    // Users cannot delete themselves\n    if (resource && user.id === resource.id) return false\n    return hasPermission(user, 'delete.user')\n  },\n}\n```\n\n### 4. Create the authorization instance\n\n```typescript\n// lib/authorization/index.ts\nimport { createAuth } from '@alfredao/auth-policies'\nimport { redirect } from 'next/navigation'\nimport { rolePermissions, type Role } from './role-permissions'\nimport type { AuthorizedUser } from './types'\nimport { UserPolicy } from '../policies/user-policy'\nimport { InstancePolicy } from '../policies/instance-policy'\n\n// Resource types in your application\ntype ResourceType = 'User' | 'Instance'\n\nexport const auth = createAuth<AuthorizedUser, Role, ResourceType>({\n  rolePermissions,\n  policies: {\n    User: UserPolicy,\n    Instance: InstancePolicy,\n  },\n  getUser: async () => {\n    // Your auth logic here (e.g., get session from cookies)\n    const session = await getSession()\n    return session?.user ?? null\n  },\n  handlers: {\n    onUnauthorizedRedirect: () => redirect('/unauthorized'),\n  },\n})\n\n// Re-export utilities for convenience\nexport const { can, canApi, hasPermission, requireUser } = auth\n```\n\n### 5. Use in your application\n\n```typescript\n// API Route\nimport { canApi } from '@/lib/authorization'\n\nexport async function PUT(request: Request, { params }: { params: { id: string } }) {\n  const user = await prisma.user.findUnique({ where: { id: params.id } })\n\n  await canApi('update', 'User', { resource: user })\n\n  // ... update logic\n}\n\n// Server Component\nimport { can } from '@/lib/authorization'\n\nexport default async function UsersPage() {\n  await can('viewAll', 'User')\n\n  const users = await prisma.user.findMany()\n  return <UserList users={users} />\n}\n```\n\n## API Reference\n\n### `createAuth(config)`\n\nCreates an authorization instance with the provided configuration.\n\n```typescript\nconst auth = createAuth({\n  rolePermissions: Record<Role, Permission[]>,\n  policies: PolicyMap,\n  getUser: () => Promise<User | null>,\n  handlers?: {\n    onUnauthorizedRedirect?: (message: string) => never,\n    onUnauthorizedThrow?: (message: string) => never,\n  },\n})\n```\n\nReturns:\n- `can(action, type, options?)` - For server components (redirects on failure)\n- `canApi(action, type, options?)` - For API routes (throws on failure)\n- `checkPermission(action, type, options?)` - Returns boolean, never throws\n- `hasPermission(user, permission)` - Check single permission\n- `hasAnyPermission(user, permissions)` - Check if user has any of the permissions\n- `hasAllPermissions(user, permissions)` - Check if user has all permissions\n- `requireUser()` - Get user or throw UnauthenticatedException\n- `getUser()` - Get user or null\n\n### `createNextAuth(config)`\n\nConvenience wrapper for Next.js applications.\n\n```typescript\nimport { createNextAuth } from '@alfredao/auth-policies'\nimport { redirect } from 'next/navigation'\n\nconst auth = createNextAuth({\n  rolePermissions,\n  policies,\n  getUser,\n  redirect,  // Pass Next.js redirect function\n  redirectTo: '/unauthorized',  // Optional, defaults to '/unauthorized'\n})\n```\n\n### Exceptions\n\n```typescript\nimport { UnauthorizedException, UnauthenticatedException } from '@alfredaoo/auth-policies'\n\n// In your API error handler\nfunction handleApiError(error: unknown) {\n  if (error instanceof UnauthorizedException) {\n    return new Response(error.message, { status: 403 })\n  }\n  if (error instanceof UnauthenticatedException) {\n    return new Response(error.message, { status: 401 })\n  }\n  // ... handle other errors\n}\n```\n\n## React Hooks\n\nThe library provides React hooks and components for client-side authorization.\n\n### Setup\n\nWrap your app with `AuthProvider`:\n\n```tsx\n// app/providers.tsx\n'use client'\n\nimport { AuthProvider } from '@alfredaoo/auth-policies/react'\nimport { auth } from '@/lib/authorization'\n\nexport function Providers({ children, user }: { children: React.ReactNode; user: User | null }) {\n  return (\n    <AuthProvider auth={auth} initialUser={user}>\n      {children}\n    </AuthProvider>\n  )\n}\n```\n\n### useAuth\n\nAccess the full auth context:\n\n```tsx\nimport { useAuth } from '@alfredaoo/auth-policies/react'\n\nfunction UserMenu() {\n  const { user, isLoading, isAuthenticated, refresh } = useAuth()\n\n  if (isLoading) return <Spinner />\n  if (!isAuthenticated) return <LoginButton />\n\n  return <div>Welcome, {user.name}</div>\n}\n```\n\n### useUser\n\nSimplified hook for user data:\n\n```tsx\nimport { useUser } from '@alfredaoo/auth-policies/react'\n\nfunction Profile() {\n  const { user, isAuthenticated } = useUser()\n\n  if (!isAuthenticated) return <LoginPrompt />\n  return <div>{user.email}</div>\n}\n```\n\n### usePermission\n\nCheck a single permission reactively:\n\n```tsx\nimport { usePermission } from '@alfredaoo/auth-policies/react'\n\nfunction DeleteButton({ postId }: { postId: string }) {\n  const { allowed, isLoading } = usePermission('delete', 'Post')\n\n  if (isLoading) return <button disabled>...</button>\n  if (!allowed) return null\n\n  return <button onClick={() => deletePost(postId)}>Delete</button>\n}\n```\n\n### usePermissions\n\nCheck multiple permissions at once:\n\n```tsx\nimport { usePermissions } from '@alfredaoo/auth-policies/react'\n\nfunction AdminPanel() {\n  const { permissions, isLoading } = usePermissions([\n    { action: 'create', resourceType: 'User' },\n    { action: 'delete', resourceType: 'User' },\n  ])\n\n  if (isLoading) return <Spinner />\n\n  return (\n    <div>\n      {permissions['create:User'] && <CreateUserButton />}\n      {permissions['delete:User'] && <DeleteUserButton />}\n    </div>\n  )\n}\n```\n\n### Can Component\n\nDeclarative conditional rendering:\n\n```tsx\nimport { Can } from '@alfredaoo/auth-policies/react'\n\nfunction PostActions({ post }: { post: Post }) {\n  return (\n    <div>\n      {/* Basic usage */}\n      <Can action=\"delete\" resourceType=\"Post\">\n        <DeleteButton postId={post.id} />\n      </Can>\n\n      {/* With fallback */}\n      <Can action=\"update\" resourceType=\"Post\" fallback={<span>Read only</span>}>\n        <EditButton postId={post.id} />\n      </Can>\n\n      {/* With loading state */}\n      <Can action=\"delete\" resourceType=\"Post\" loading={<Spinner />}>\n        <DeleteButton postId={post.id} />\n      </Can>\n\n      {/* Context-aware check */}\n      <Can action=\"update\" resourceType=\"Post\" resource={post}>\n        <EditButton postId={post.id} />\n      </Can>\n    </div>\n  )\n}\n```\n\n### Cannot Component\n\nRender content when permission is denied:\n\n```tsx\nimport { Cannot } from '@alfredaoo/auth-policies/react'\n\nfunction PostView({ post }: { post: Post }) {\n  return (\n    <div>\n      <h1>{post.title}</h1>\n      <Cannot action=\"update\" resourceType=\"Post\">\n        <p className=\"text-gray-500\">You don't have permission to edit this post.</p>\n      </Cannot>\n    </div>\n  )\n}\n```\n\n## Middleware\n\nThe library provides middleware helpers for API route protection.\n\n### Next.js App Router\n\nWrap API route handlers with authorization:\n\n```typescript\n// lib/authorization/middleware.ts\nimport { createAuthMiddleware } from '@alfredaoo/auth-policies/middleware'\n\nexport const withAuth = createAuthMiddleware({\n  rolePermissions,\n  policies,\n  getUser: async () => {\n    const session = await getSession()\n    return session?.user ?? null\n  },\n})\n```\n\n```typescript\n// app/api/posts/[id]/route.ts\nimport { withAuth } from '@/lib/authorization/middleware'\n\nexport const DELETE = withAuth(\n  async (request, { params }) => {\n    await deletePost(params.id)\n    return Response.json({ success: true })\n  },\n  { action: 'delete', type: 'Post' }\n)\n\n// With context-aware check\nexport const PUT = withAuth(\n  async (request, { params }) => {\n    const data = await request.json()\n    const post = await updatePost(params.id, data)\n    return Response.json(post)\n  },\n  {\n    action: 'update',\n    type: 'Post',\n    getResource: async (req) => {\n      const url = new URL(req.url)\n      const id = url.pathname.split('/').pop()\n      return await getPost(id)\n    },\n  }\n)\n```\n\n### Permission-Based Middleware\n\nSimpler middleware that checks permissions directly:\n\n```typescript\nimport { createPermissionMiddleware } from '@alfredaoo/auth-policies/middleware'\n\nconst requirePermission = createPermissionMiddleware({\n  rolePermissions,\n  getUser: async () => getSession()?.user ?? null,\n})\n\nexport const DELETE = requirePermission(\n  async (request) => {\n    return Response.json({ success: true })\n  },\n  { permission: 'delete.post' }\n)\n```\n\n### Express / Hono\n\nCompatible middleware for Express, Hono, and similar frameworks:\n\n```typescript\nimport express from 'express'\nimport { createExpressAuth } from '@alfredaoo/auth-policies/middleware'\n\nconst app = express()\n\nconst { protect, requireAuth, requirePermission } = createExpressAuth({\n  rolePermissions,\n  policies,\n  getUser: (req) => req.user, // From your auth middleware\n})\n\n// Require authentication only\napp.get('/profile', requireAuth, (req, res) => {\n  res.json(req.user)\n})\n\n// Policy-based protection\napp.delete('/posts/:id', protect({ action: 'delete', type: 'Post' }), (req, res) => {\n  res.json({ success: true })\n})\n\n// Permission-based protection\napp.post('/posts', requirePermission('create.post'), (req, res) => {\n  res.json({ success: true })\n})\n\n// With resource for context-aware check\napp.put('/posts/:id',\n  protect({\n    action: 'update',\n    type: 'Post',\n    getResource: async (req) => await getPost(req.params.id),\n  }),\n  (req, res) => {\n    res.json({ success: true })\n  }\n)\n```\n\n## Audit Logging\n\nTrack all authorization decisions for security monitoring and compliance:\n\n```typescript\nimport { createAuth, type AuditLogEntry } from '@alfredaoo/auth-policies'\n\nconst auth = createAuth({\n  rolePermissions,\n  policies,\n  getUser,\n  onAudit: async (entry: AuditLogEntry) => {\n    // Log to your preferred logging system\n    await logger.info('Authorization check', {\n      timestamp: entry.timestamp,\n      userId: entry.user?.id,\n      role: entry.user?.role,\n      action: entry.action,\n      resourceType: entry.resourceType,\n      allowed: entry.allowed,\n      reason: entry.reason,\n      duration: entry.duration,\n      metadata: entry.metadata,\n    })\n  },\n})\n```\n\n### Audit Entry Structure\n\n```typescript\ninterface AuditLogEntry {\n  timestamp: Date           // When the check occurred\n  user: User | null         // The user (null if unauthenticated)\n  action: string            // The action being performed\n  resourceType: string      // The resource type\n  allowed: boolean          // Whether access was granted\n  reason?: string           // Denial reason: 'unauthenticated' | 'policy_denied' | 'policy_not_found' | 'action_not_found'\n  resource?: unknown        // The resource being accessed\n  duration: number          // Policy check duration in ms\n  metadata?: Record<string, unknown>  // Custom metadata\n}\n```\n\n### Adding Metadata\n\nPass additional context for audit logs:\n\n```typescript\n// Include request metadata\nawait auth.canApi('delete', 'Post', {\n  resource: post,\n  metadata: {\n    ip: request.ip,\n    userAgent: request.headers['user-agent'],\n    requestId: request.id,\n  },\n})\n```\n\n### Integration Examples\n\n**Winston:**\n```typescript\nimport winston from 'winston'\n\nconst logger = winston.createLogger({ /* ... */ })\n\nconst auth = createAuth({\n  // ...\n  onAudit: (entry) => {\n    logger.info('auth', entry)\n  },\n})\n```\n\n**Pino:**\n```typescript\nimport pino from 'pino'\n\nconst logger = pino()\n\nconst auth = createAuth({\n  // ...\n  onAudit: (entry) => {\n    logger.info(entry, 'authorization check')\n  },\n})\n```\n\n**Database:**\n```typescript\nconst auth = createAuth({\n  // ...\n  onAudit: async (entry) => {\n    await prisma.auditLog.create({\n      data: {\n        timestamp: entry.timestamp,\n        userId: entry.user?.id,\n        action: entry.action,\n        resourceType: entry.resourceType,\n        allowed: entry.allowed,\n        reason: entry.reason,\n        duration: entry.duration,\n        metadata: entry.metadata,\n      },\n    })\n  },\n})\n```\n\n## Caching\n\nEnable caching to memoize policy check results and improve performance:\n\n```typescript\nconst auth = createAuth({\n  rolePermissions,\n  policies,\n  getUser,\n  cache: {\n    enabled: true,\n    ttl: 60000, // 1 minute (default)\n    maxSize: 1000, // Max entries (default)\n  },\n})\n```\n\n### Cache Configuration\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `enabled` | `boolean` | `false` | Enable or disable caching |\n| `ttl` | `number` | `60000` | Time-to-live in milliseconds. Set to 0 for no expiration |\n| `maxSize` | `number` | `1000` | Maximum cache entries. Uses LRU eviction when exceeded |\n| `getResourceKey` | `function` | Uses `resource.id` | Custom function to generate cache key for resources |\n\n### Cache Keys\n\nCache keys are generated from: `action:resourceType:userId:resourceId`\n\n```typescript\n// Without resource: \"view:Post:user-123:no-resource\"\nawait auth.can('view', 'Post')\n\n// With resource: \"update:Post:user-123:post-456\"\nawait auth.can('update', 'Post', { resource: { id: 'post-456' } })\n```\n\n### Custom Resource Key\n\nFor resources without an `id` property, provide a custom key generator:\n\n```typescript\nconst auth = createAuth({\n  // ...\n  cache: {\n    enabled: true,\n    getResourceKey: (resource) => {\n      if (resource && typeof resource === 'object' && 'uuid' in resource) {\n        return String(resource.uuid)\n      }\n      return undefined\n    },\n  },\n})\n```\n\n### Cache Invalidation\n\nInvalidate cached entries when permissions or resources change:\n\n```typescript\n// Invalidate all entries for a user (e.g., after role change)\nauth.cache?.invalidateUser('user-123')\n\n// Invalidate all entries for a resource type\nauth.cache?.invalidateResourceType('Post')\n\n// Invalidate entries for a specific resource\nauth.cache?.invalidateResource('Post', 'post-456')\n\n// Clear entire cache\nauth.cache?.clear()\n```\n\n### Cache Maintenance\n\nFor long-running processes, periodically clean up expired entries:\n\n```typescript\n// Clean up expired entries\nconst removed = auth.cache?.cleanup()\nconsole.log(`Removed ${removed} expired entries`)\n\n// Get cache statistics\nconst stats = auth.cache?.stats()\nconsole.log(`Cache size: ${stats?.size}/${stats?.maxSize}`)\n```\n\n### Audit Logging with Cache\n\nWhen caching is enabled, audit entries include a `cached` flag in metadata:\n\n```typescript\nconst auth = createAuth({\n  // ...\n  cache: { enabled: true },\n  onAudit: (entry) => {\n    if (entry.metadata?.cached) {\n      console.log('Result from cache')\n    }\n  },\n})\n```\n\n### Standalone Cache\n\nUse the cache independently for custom scenarios:\n\n```typescript\nimport { createPolicyCache } from '@alfredaoo/auth-policies'\n\nconst cache = createPolicyCache({\n  ttl: 30000,\n  maxSize: 500,\n})\n\nconst key = cache.generateKey('view', 'Post', 'user-123', { id: 'post-1' })\ncache.set(key, true)\nconst result = cache.get(key) // true\n```\n\n## Context-Aware Policies\n\nPolicies can receive the resource being accessed for dynamic authorization:\n\n```typescript\nconst InstancePolicy = {\n  async delete(user: AuthorizedUser, resource?: Instance) {\n    if (!hasPermission(user, 'delete.instance')) return false\n\n    // Can't delete instances that are being provisioned\n    if (resource?.status === 'PROVISIONING') return false\n\n    // Can't delete soft-deleted instances\n    if (resource?.deleted_at) return false\n\n    return true\n  },\n}\n\n// Usage\nawait canApi('delete', 'Instance', { resource: instance })\n```\n\n## Standalone Permission Checker\n\nIf you only need permission checking without the full policy system:\n\n```typescript\nimport { createPermissionChecker } from '@alfredaoo/auth-policies'\n\nconst { hasPermission, hasAnyPermission } = createPermissionChecker(rolePermissions)\n\nif (hasPermission(user, 'create.user')) {\n  // ...\n}\n```\n\n## Permission Inheritance\n\nDefine role hierarchies where higher roles automatically inherit permissions from lower roles:\n\n### Basic Inheritance\n\n```typescript\nconst rolePermissions = {\n  VIEWER: ['view.user', 'view.post'],\n  EDITOR: {\n    inherits: 'VIEWER',\n    permissions: ['create.post', 'update.post'],\n  },\n  ADMIN: {\n    inherits: 'EDITOR',\n    permissions: ['delete.post', 'delete.user'],\n  },\n}\n\n// Resolved permissions:\n// VIEWER: ['view.user', 'view.post']\n// EDITOR: ['view.user', 'view.post', 'create.post', 'update.post']\n// ADMIN:  ['view.user', 'view.post', 'create.post', 'update.post', 'delete.post', 'delete.user']\n```\n\n### Multiple Inheritance\n\nInherit from multiple roles at once:\n\n```typescript\nconst rolePermissions = {\n  VIEWER: ['view.dashboard'],\n  BILLING: {\n    inherits: 'VIEWER',\n    permissions: ['view.invoice', 'create.invoice'],\n  },\n  SUPPORT: {\n    inherits: 'VIEWER',\n    permissions: ['view.ticket', 'update.ticket'],\n  },\n  MANAGER: {\n    inherits: ['BILLING', 'SUPPORT'],  // Inherits from both\n    permissions: ['delete.user'],\n  },\n}\n\n// MANAGER gets: view.dashboard, view.invoice, create.invoice, view.ticket, update.ticket, delete.user\n```\n\n### Mixed Syntax\n\nYou can mix flat arrays and inheritance in the same configuration:\n\n```typescript\nconst rolePermissions = {\n  VIEWER: ['view.user'],  // Flat array\n  ADMIN: {                // With inheritance\n    inherits: 'VIEWER',\n    permissions: ['delete.user'],\n  },\n}\n```\n\n### Circular Inheritance Detection\n\nThe library automatically detects and throws an error for circular inheritance:\n\n```typescript\nimport { CircularInheritanceError } from '@alfredaoo/auth-policies'\n\nconst rolePermissions = {\n  A: { inherits: 'B', permissions: ['a'] },\n  B: { inherits: 'A', permissions: ['b'] },  // Circular!\n}\n\ntry {\n  createAuth({ rolePermissions, ... })\n} catch (error) {\n  if (error instanceof CircularInheritanceError) {\n    console.log(error.cycle)  // ['A', 'B', 'A']\n  }\n}\n```\n\n### Resolving Permissions Manually\n\nFor debugging or advanced use cases, resolve permissions manually:\n\n```typescript\nimport { resolvePermissions } from '@alfredaoo/auth-policies'\n\nconst resolved = resolvePermissions(rolePermissions)\nconsole.log(resolved.ADMIN)  // All permissions including inherited\n```\n\n## Multiple Roles\n\nUsers can have multiple roles, and permissions are merged from all roles:\n\n### Single Role (Simple)\n\n```typescript\ninterface User extends BaseUser<'ADMIN' | 'USER'> {\n  id: string\n  role: 'ADMIN' | 'USER'  // Single role\n}\n\nconst user: User = { id: '1', role: 'ADMIN' }\n```\n\n### Multiple Roles\n\n```typescript\ninterface User extends BaseUser<'VIEWER' | 'EDITOR' | 'BILLING'> {\n  id: string\n  roles: ('VIEWER' | 'EDITOR' | 'BILLING')[]  // Multiple roles\n}\n\nconst user: User = {\n  id: '1',\n  roles: ['VIEWER', 'BILLING'],  // Has permissions from both roles\n}\n\n// Permissions are merged from all roles\nauth.hasPermission(user, 'view.dashboard')  // true (from VIEWER)\nauth.hasPermission(user, 'view.invoice')    // true (from BILLING)\nauth.hasPermission(user, 'create.post')     // false (EDITOR only)\n```\n\n### Combined (role + roles)\n\nYou can use both `role` and `roles` together:\n\n```typescript\nconst user = {\n  id: '1',\n  role: 'VIEWER',           // Primary role\n  roles: ['BILLING'],       // Additional roles\n}\n\n// Gets permissions from VIEWER + BILLING\nauth.getPermissions(user)   // ['view.dashboard', 'view.invoice', ...]\nauth.getRoles(user)         // ['VIEWER', 'BILLING']\n```\n\n### Utility Functions\n\n```typescript\n// Get all roles for a user\nconst roles = auth.getRoles(user)  // ['VIEWER', 'BILLING']\n\n// Get all permissions (merged from all roles)\nconst permissions = auth.getPermissions(user)\n\n// Check permissions across all roles\nauth.hasPermission(user, 'view.invoice')\nauth.hasAnyPermission(user, ['view.invoice', 'create.post'])\nauth.hasAllPermissions(user, ['view.dashboard', 'view.invoice'])\n```\n\n## Multi-Tenancy\n\nSupport for SaaS applications where users have different roles in different organizations/tenants.\n\n### User Type with Tenant Roles\n\n```typescript\nimport type { TenantUser } from '@alfredaoo/auth-policies'\n\n// Define system-wide and tenant-specific roles\ntype SystemRole = 'SUPER_ADMIN' | 'USER'\ntype TenantRole = 'OWNER' | 'ADMIN' | 'MEMBER'\n\ninterface User extends TenantUser<SystemRole, TenantRole> {\n  id: string\n  email: string\n  role: SystemRole                                    // System-wide role\n  tenantRoles?: Record<string, TenantRole>            // Per-tenant roles\n}\n\n// Example user with different roles in different businesses\nconst user: User = {\n  id: '1',\n  email: 'user@example.com',\n  role: 'USER',\n  tenantRoles: {\n    'business-1': 'OWNER',    // Owner of business-1\n    'business-2': 'MEMBER',   // Member of business-2\n  },\n}\n```\n\n### Configure Multi-Tenancy\n\n```typescript\nconst auth = createAuth<User, SystemRole, 'Appointment'>({\n  // System-level role permissions (apply globally)\n  rolePermissions: {\n    SUPER_ADMIN: ['*'],\n    USER: ['view.profile'],\n  },\n  policies: {\n    Appointment: AppointmentPolicy,\n  },\n  getUser: async () => getCurrentUser(),\n\n  // Tenant configuration\n  tenant: {\n    // Tenant-level role permissions\n    rolePermissions: {\n      OWNER: ['manage.business', 'view.reports', 'manage.staff'],\n      ADMIN: ['view.reports', 'manage.staff'],\n      MEMBER: ['view.appointments'],\n    },\n    // How to get the current tenant context (e.g., from active business)\n    getTenantId: async () => {\n      const session = await getSession()\n      return session?.activeBusinessId ?? null\n    },\n  },\n})\n```\n\n### Tenant-Aware Policies\n\n```typescript\nimport { getTenantRoles } from '@alfredaoo/auth-policies'\n\nconst AppointmentPolicy = {\n  view: (user, resource, tenantId) => {\n    // SUPER_ADMIN can view all\n    if (user.role === 'SUPER_ADMIN') return true\n\n    // Check tenant role\n    if (!tenantId) return false\n    const tenantRoles = getTenantRoles(user, tenantId)\n    return tenantRoles.length > 0\n  },\n\n  manage: (user, resource, tenantId) => {\n    if (user.role === 'SUPER_ADMIN') return true\n    if (!tenantId) return false\n\n    const tenantRoles = getTenantRoles(user, tenantId)\n    return tenantRoles.includes('OWNER') || tenantRoles.includes('ADMIN')\n  },\n}\n```\n\n### Using Tenant Context\n\n```typescript\n// Uses tenant from config (getTenantId)\nawait auth.canApi('view', 'Appointment')\n\n// Override tenant for specific check\nawait auth.canApi('view', 'Appointment', { tenantId: 'business-2' })\n\n// In middleware, extract tenant from request\nexport const PUT = withAuth(handler, {\n  action: 'manage',\n  type: 'Appointment',\n  getTenantId: (req) => {\n    const url = new URL(req.url)\n    return url.searchParams.get('businessId')\n  },\n})\n```\n\n### Tenant Permission Checker\n\n```typescript\nimport { createTenantPermissionChecker } from '@alfredaoo/auth-policies'\n\nconst checker = createTenantPermissionChecker({\n  systemRolePermissions: {\n    SUPER_ADMIN: ['*'],\n    USER: ['view.profile'],\n  },\n  tenantRolePermissions: {\n    OWNER: ['manage.business', 'view.reports'],\n    MEMBER: ['view.appointments'],\n  },\n})\n\n// Check combined permissions (system + tenant)\nchecker.hasPermission(user, 'manage.business', 'business-1')  // true (OWNER)\nchecker.hasPermission(user, 'manage.business', 'business-2')  // false (MEMBER)\nchecker.hasPermission(user, 'view.profile', null)             // true (USER)\n\n// Get all permissions in a tenant context\nchecker.getPermissions(user, 'business-1')\n// ['view.profile', 'manage.business', 'view.reports']\n\n// Get roles breakdown\nchecker.getRoles(user, 'business-1')\n// { system: ['USER'], tenant: ['OWNER'] }\n```\n\n### Tenant Utilities on Auth Instance\n\n```typescript\n// Access tenant utilities\nauth.tenant?.getTenantRoles(user, 'business-1')    // ['OWNER']\nauth.tenant?.hasPermission(user, 'manage.business', 'business-1')\nauth.tenant?.getPermissions(user, 'business-1')\n\n// Check if multi-tenancy is enabled\nauth.config.tenantEnabled  // true\n```\n\n### Cache Invalidation by Tenant\n\n```typescript\n// Invalidate cache for a specific tenant (e.g., after role changes)\nauth.cache?.invalidateTenant('business-1')\n```\n\n### Audit Logging with Tenant\n\n```typescript\nconst auth = createAuth({\n  // ...\n  onAudit: (entry) => {\n    console.log('Tenant:', entry.tenantId)  // The tenant context used\n  },\n})\n```\n\n## TypeScript\n\nThe library is written in TypeScript and provides full type safety:\n\n```typescript\nimport type { BaseUser, Policy, PolicyMap, AuthConfig } from '@alfredaoo/auth-policies'\n\n// Your user type must extend BaseUser\ninterface MyUser extends BaseUser<'ADMIN' | 'USER'> {\n  id: string\n  role: 'ADMIN' | 'USER'\n  email: string\n}\n\n// Policies are type-safe\nconst MyPolicy: Policy<MyUser> = {\n  view: async (user, resource) => true,\n  update: async (user, resource) => user.role === 'ADMIN',\n}\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}