{"_id":"@daanvandenbergh/policykit","_rev":"10-a589c0c481858a42253befd15ca44cd9","name":"@daanvandenbergh/policykit","dist-tags":{"latest":"1.4.0"},"versions":{"1.0.0":{"name":"@daanvandenbergh/policykit","version":"1.0.0","license":"UNLICENSED","_id":"@daanvandenbergh/policykit@1.0.0","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"dist":{"shasum":"85e0517e111b87723f2404b695117adfdcb85b9e","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.0.0.tgz","fileCount":18,"integrity":"sha512-PLyCbbHgBDvlEFpRwjz7qiLKooB4mg341YRsmB4qEQGnSSBcPSwHY5qFf0OQJuwAPvzobC/z/TvF6ntm1LaVIA==","signatures":[{"sig":"MEUCIHtwXDGm+DNg7EUKM66G5cnSPZu7EqAeMUia98xq0TBgAiEAkN3P74osVt11XnQ30dXVlH6cuBZcihPnJrdSsuAMOro=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":95693},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"gitHead":"bb7e90ac79a96b733c10964a96bc1046c133c7df","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"_npmVersion":"11.12.1","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","directories":{},"_nodeVersion":"26.0.0","dependencies":{"remark-gfm":"^4.0.1","gray-matter":"^4.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.10","react":"^19","vitest":"^3.0.0","react-dom":"^19","typescript":"^5.6.0","@types/node":"^22.20.1","server-only":"^0.0.1","@types/react":"^19","next-mdx-remote":"^6","@types/react-dom":"^19","@daanvandenbergh/claudekit":"^1.0.7"},"peerDependencies":{"next":">=14","react":">=18","react-dom":">=18","next-mdx-remote":"^5 || ^6"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"next-mdx-remote":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/policykit_1.0.0_1785326757458_0.14427361484324153","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@daanvandenbergh/policykit","version":"1.0.1","license":"UNLICENSED","_id":"@daanvandenbergh/policykit@1.0.1","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"dist":{"shasum":"eb7add29cb1181d94f7f641289f303962dd43389","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.0.1.tgz","fileCount":20,"integrity":"sha512-vMcYO7PisbZRKoKS39lYVh3rSQDvqjtl02sFQ+F4EbVP9fQkVDqqiPaO86g1d7woZ+/0rvz9IqnpnNR17NuzBw==","signatures":[{"sig":"MEQCIBf2cXFciZi87MrBQQ3dQakJi5625JHlMJItbOQ0UJouAiAa/L8ug3kH5AvYyFFijrSXFokdWdPIG0mlzgbzKIHc8Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":105925},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"gitHead":"e6293b1f4375e9c9ce87e5314af53b8b7ead1385","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"overrides":{"sharp":"^0.35.0","postcss":"^8.5.18"},"_npmVersion":"11.12.1","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","directories":{},"_nodeVersion":"26.0.0","dependencies":{"remark-gfm":"^4.0.1","gray-matter":"^4.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.10","react":"^19","vitest":"^3.0.0","react-dom":"^19","typescript":"^5.6.0","@types/node":"^22.20.1","server-only":"^0.0.1","@types/react":"^19","next-mdx-remote":"^6","@types/react-dom":"^19","@daanvandenbergh/claudekit":"^1.0.7","@daanvandenbergh/scribekit":"^1.2.1"},"peerDependencies":{"next":">=14","react":">=18","react-dom":">=18","next-mdx-remote":"^5 || ^6"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"next-mdx-remote":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/policykit_1.0.1_1785341799702_0.22831929821594188","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@daanvandenbergh/policykit","version":"1.0.2","license":"UNLICENSED","_id":"@daanvandenbergh/policykit@1.0.2","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"dist":{"shasum":"5387e696bdcf1deb72a4ee0d57f50c8f0714f2de","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.0.2.tgz","fileCount":20,"integrity":"sha512-369u4uaZwHZf4Yy1Fr2GTzaIjKzAShSI1Y/kyJmgS/ZY/C6keHTa779OitIqXWOtL3WZaSLO9iLleRVQmbAyUg==","signatures":[{"sig":"MEQCIC1ZfNVVM97gXjqHtT2ndLKuVm54q4/QAJjVOQmwUSyoAiBe9xeXcOa07ly0T5cYenklAgkz1eKccXBQROqGTFNnKg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":114048},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"gitHead":"d3650e82088eb909b72c52f099b2aa515d0e7ef4","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"overrides":{"sharp":"^0.35.0","postcss":"^8.5.18"},"_npmVersion":"11.12.1","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","directories":{},"_nodeVersion":"26.0.0","dependencies":{"remark-gfm":"^4.0.1","gray-matter":"^4.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.10","react":"^19","vitest":"^3.0.0","react-dom":"^19","typescript":"^5.6.0","@types/node":"^22.20.1","server-only":"^0.0.1","@types/react":"^19","next-mdx-remote":"^6","@types/react-dom":"^19","@daanvandenbergh/claudekit":"^1.0.7","@daanvandenbergh/scribekit":"^1.2.1"},"peerDependencies":{"next":">=14","react":">=18","react-dom":">=18","next-mdx-remote":"^5 || ^6"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"next-mdx-remote":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/policykit_1.0.2_1785347605841_0.8657517215539281","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@daanvandenbergh/policykit","version":"1.1.0","license":"UNLICENSED","_id":"@daanvandenbergh/policykit@1.1.0","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"dist":{"shasum":"9315d9182d079c9b1181f496a0372252eec158d7","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.1.0.tgz","fileCount":22,"integrity":"sha512-guN+xxq9fFUBGNDAxYUkB9Zx9GamtsZdhlwKecYsS+12HnVfsVGnAHEwMNJfIxKfYJfxOsJpMAllJMoUZqDzbQ==","signatures":[{"sig":"MEQCIGKDZOVLSZYe0q4n+IAlHYmpVGZMfwY9ob0Xz0NQHv2RAiAxdicn21nvsDUtEfpXJIDtnrINH3Ru3adxKimwlvE9tg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":124202},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"gitHead":"768942f44b553b892ece90b242579df2187b6373","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"overrides":{"sharp":"^0.35.0","postcss":"^8.5.18"},"_npmVersion":"11.12.1","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","directories":{},"_nodeVersion":"26.0.0","dependencies":{"remark-gfm":"^4.0.1","gray-matter":"^4.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.10","react":"^19","vitest":"^3.0.0","react-dom":"^19","typescript":"^5.6.0","@types/node":"^22.20.1","server-only":"^0.0.1","@types/react":"^19","next-mdx-remote":"^6","@types/react-dom":"^19","@daanvandenbergh/claudekit":"^1.0.7","@daanvandenbergh/scribekit":"^1.2.1"},"peerDependencies":{"next":">=14","react":">=18","react-dom":">=18","next-mdx-remote":"^5 || ^6"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"next-mdx-remote":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/policykit_1.1.0_1786293650869_0.486059209334313","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@daanvandenbergh/policykit","version":"1.1.1","license":"UNLICENSED","_id":"@daanvandenbergh/policykit@1.1.1","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"dist":{"shasum":"ba87065083b6fcefe6db51d1c652de9d1e44e54a","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.1.1.tgz","fileCount":22,"integrity":"sha512-kV16P8y/CUWQ0f3ailnjfGWwduECtNXJhB8nkRIXHXMzncr8QOoroM6biRhau+jUBmKPAgwesAI5UVmDHEOzvw==","signatures":[{"sig":"MEYCIQCyMk2Jy4pbSPpWR6Dt7xL+oGoE38Vk1rdFtKzxYNta8wIhANute4lzrG+srr9C6NIMFZs6E1EPJ4YvHoAWBLoP4rVu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":124749},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"gitHead":"50afda7d349fa86f1b469e45e3adac39de8f13ca","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"overrides":{"sharp":"^0.35.0","postcss":"^8.5.18"},"_npmVersion":"11.12.1","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","directories":{},"_nodeVersion":"26.0.0","dependencies":{"remark-gfm":"^4.0.1","gray-matter":"^4.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.10","react":"^19","vitest":"^3.0.0","react-dom":"^19","typescript":"^5.6.0","@types/node":"^22.20.1","server-only":"^0.0.1","@types/react":"^19","next-mdx-remote":"^6","@types/react-dom":"^19","@daanvandenbergh/claudekit":"^1.0.7","@daanvandenbergh/scribekit":"^1.2.1"},"peerDependencies":{"next":">=14","react":">=18","react-dom":">=18","next-mdx-remote":"^5 || ^6"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"next-mdx-remote":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/policykit_1.1.1_1786294845582_0.8242376690748472","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@daanvandenbergh/policykit","version":"1.1.2","license":"UNLICENSED","_id":"@daanvandenbergh/policykit@1.1.2","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"dist":{"shasum":"ed5ec7284c6499d3b83271135d5a1790398a6faf","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.1.2.tgz","fileCount":22,"integrity":"sha512-pVKFFbjCumbGpwmmuaYDZk0uMVel4Xn8rqpT8i5iWL6Tq94/LXGXiKqoBoYMWvYWPOM+hsHmHmp37Y/rT7hU4Q==","signatures":[{"sig":"MEYCIQDuohKaWLjZnTrftCnp1h3nqhbupbnO6XmFSz4qBy+PNQIhAKh842RqOjXRam3/IPwVEcm8CMWFIDZWqG4ed9DNXlCE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":124749},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"gitHead":"899ef76e142e9a3d48dfefa226c4ab8205f67a04","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"overrides":{"sharp":"^0.35.0","postcss":"^8.5.18"},"_npmVersion":"11.12.1","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","directories":{},"_nodeVersion":"26.0.0","dependencies":{"remark-gfm":"^4.0.1","gray-matter":"^4.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.10","react":"^19","vitest":"^3.0.0","react-dom":"^19","typescript":"^5.6.0","@types/node":"^22.20.1","server-only":"^0.0.1","@types/react":"^19","next-mdx-remote":"^6","@types/react-dom":"^19","@daanvandenbergh/claudekit":"^1.2.0","@daanvandenbergh/scribekit":"^1.7.2"},"peerDependencies":{"next":">=14","react":">=18","react-dom":">=18","next-mdx-remote":"^5 || ^6"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"next-mdx-remote":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/policykit_1.1.2_1786460897062_0.41203106981955995","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@daanvandenbergh/policykit","version":"1.2.0","license":"UNLICENSED","_id":"@daanvandenbergh/policykit@1.2.0","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"dist":{"shasum":"59ca9893d44543f8d6cd0dc4187e369ee598bba4","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.2.0.tgz","fileCount":22,"integrity":"sha512-rxUSP1Nh7iyLz22qGmEjyqYXl6m3Mx4tORx+ZFe9acwpPxY77dYVikC7Nt/HWdgPTFd/K42yP/1YFaa6mohMvg==","signatures":[{"sig":"MEYCIQDma8Hz1Q23t/8TSsPvdlJHZqLZA4BhJvAIKsEbQtmBdQIhAODWC2DMTUk25w9DYNoqvKgRmu5lDVepkDy2Hs4ey0Dn","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":124754},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"gitHead":"eec4ecf66ae90c33ca1971a669db146ee4dfa8c9","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"overrides":{"sharp":"^0.35.0","postcss":"^8.5.18"},"_npmVersion":"11.12.1","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","directories":{},"_nodeVersion":"26.0.0","dependencies":{"remark-gfm":"^4.0.1","gray-matter":"^4.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.10","react":"^19","vitest":"^3.0.0","react-dom":"^19","typescript":"^5.6.0","@types/node":"^22.20.1","server-only":"^0.0.1","@types/react":"^19","next-mdx-remote":"^6","@types/react-dom":"^19","@daanvandenbergh/claudekit":"^1.3.0","@daanvandenbergh/scribekit":"^1.7.2"},"peerDependencies":{"next":">=14","react":">=18","react-dom":">=18","next-mdx-remote":"^5 || ^6"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"next-mdx-remote":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/policykit_1.2.0_1786466617150_0.42909881994795085","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@daanvandenbergh/policykit","version":"1.2.1","license":"UNLICENSED","_id":"@daanvandenbergh/policykit@1.2.1","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"homepage":"https://daanvandenbergh.github.io/policykit","bugs":{"url":"https://github.com/daanvandenbergh/policykit/issues"},"dist":{"shasum":"c62f1bc2c15de65a3c7ba7dc4382f808dec79772","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.2.1.tgz","fileCount":22,"integrity":"sha512-79RCNdp/27LBUIjXeClm856pzdbE1QddD91D0vb7by96e3gPqB7O+rETWRa9/9ibIC8r9CUFnIBbHRvwp5pjtA==","signatures":[{"sig":"MEYCIQDDJYrCY6/B1/mGmlZhbuk10iBn/mDpSxE5fa3UQiyCdQIhAKnT+dfdWpi2hHtnkkmxeS16kZXq3Vb7uCezomFsoe0f","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":126101},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"gitHead":"0543b0d9644c5bce903666436604862824ea520f","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"overrides":{"sharp":"^0.35.0","postcss":"^8.5.18"},"repository":{"url":"git+https://github.com/daanvandenbergh/policykit.git","type":"git"},"_npmVersion":"11.12.1","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","directories":{},"_nodeVersion":"26.0.0","dependencies":{"remark-gfm":"^4.0.1","gray-matter":"^4.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.10","react":"^19","vitest":"^3.0.0","react-dom":"^19","typescript":"^5.6.0","@types/node":"^22.20.1","server-only":"^0.0.1","@types/react":"^19","next-mdx-remote":"^6","@types/react-dom":"^19","@daanvandenbergh/claudekit":"^1.3.0","@daanvandenbergh/scribekit":"^1.9.1"},"peerDependencies":{"next":">=14","react":">=18","react-dom":">=18","next-mdx-remote":"^5 || ^6"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"next-mdx-remote":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/policykit_1.2.1_1786479005043_0.2888571775314077","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@daanvandenbergh/policykit","version":"1.3.0","license":"UNLICENSED","_id":"@daanvandenbergh/policykit@1.3.0","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"homepage":"https://daanvandenbergh.github.io/policykit","bugs":{"url":"https://github.com/daanvandenbergh/policykit/issues"},"dist":{"shasum":"d014dc14119551883841a5215b7b72ef2e474a1a","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.3.0.tgz","fileCount":22,"integrity":"sha512-9WVBejaMFOHzOvLfz2G/AKKIIw87oIfexlyw32jTU9mHBo0LdL6uVNQKCnGfBTdqVemXsdQf5apFeXOnyJjT8Q==","signatures":[{"sig":"MEUCIHQGs1PYULxGPl7438DH0iYLuzhroGQJvctJCnFBO6vgAiEA0QgBxRi1IhHP72tSN9QpVGO35j10pa9PJEEzdC3cPHw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":129420},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"gitHead":"249ba0652a187eb5449d36e0de599e08d16d0ddc","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"overrides":{"sharp":"^0.35.0","postcss":"^8.5.18"},"repository":{"url":"git+https://github.com/daanvandenbergh/policykit.git","type":"git"},"_npmVersion":"11.12.1","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","directories":{},"_nodeVersion":"26.0.0","dependencies":{"remark-gfm":"^4.0.1","gray-matter":"^4.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.10","react":"^19","vitest":"^3.0.0","react-dom":"^19","typescript":"^5.6.0","@types/node":"^22.20.1","server-only":"^0.0.1","@types/react":"^19","next-mdx-remote":"^6","@types/react-dom":"^19","@daanvandenbergh/claudekit":"^1.3.0","@daanvandenbergh/scribekit":"^2.0.0"},"peerDependencies":{"next":">=14","react":">=18","react-dom":">=18","next-mdx-remote":"^5 || ^6"},"peerDependenciesMeta":{"next":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"next-mdx-remote":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/policykit_1.3.0_1786697869768_0.8934315477854116","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@daanvandenbergh/policykit","version":"1.4.0","description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","license":"UNLICENSED","homepage":"https://daanvandenbergh.github.io/policykit","repository":{"type":"git","url":"git+https://github.com/daanvandenbergh/policykit.git"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json"},"publishConfig":{"access":"public"},"scripts":{"build":"tsc -p tsconfig.build.json","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit","prepublishOnly":"npm run build","push-and-publish":"git add -A && git commit -m 'Updates' && npm version patch && npm publish && git push -u origin main"},"dependencies":{"gray-matter":"^4.0.3","remark-gfm":"^4.0.1"},"overrides":{"postcss":"^8.5.18","sharp":"^0.35.0"},"peerDependencies":{"next":">=14","next-mdx-remote":"^5 || ^6","react":">=18","react-dom":">=18"},"peerDependenciesMeta":{"next":{"optional":true},"next-mdx-remote":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"devDependencies":{"@daanvandenbergh/claudekit":"^1.4.0","@daanvandenbergh/scribekit":"^2.0.0","@types/node":"^22.20.1","@types/react":"^19","@types/react-dom":"^19","next":"^16.2.10","next-mdx-remote":"^6","react":"^19","react-dom":"^19","server-only":"^0.0.1","typescript":"^5.6.0","vitest":"^3.0.0"},"gitHead":"01a849d1d9e59f591f3fda76a01c658da12b40cf","_id":"@daanvandenbergh/policykit@1.4.0","bugs":{"url":"https://github.com/daanvandenbergh/policykit/issues"},"_nodeVersion":"26.0.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-MWMtAudNZT06qTfY3dWsPrvviGfi1ZnVyCLdRMNVNVPPgHqNzq76VjyB/kxHz1lmmLNlDahqoxrHcpaxj4T2lg==","shasum":"20ea9af9ae58bc64d8b38b5b2db91ba612bd4c45","tarball":"https://registry.npmjs.org/@daanvandenbergh/policykit/-/policykit-1.4.0.tgz","fileCount":22,"unpackedSize":135745,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCH8ZWuVG83R//T9fhpkjk2zQS/+a9AmDI1BNyIvx4r7gIgJfEpoi3Ypy/sOxbVXaHmllLhAyRJI2A0xi8yoW9e82g="}]},"_npmUser":{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"},"directories":{},"maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/policykit_1.4.0_1787312578525_0.8535958333852538"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-29T12:05:57.231Z","modified":"2026-08-21T11:42:58.863Z","1.0.0":"2026-07-29T12:05:57.609Z","1.0.1":"2026-07-29T16:16:39.851Z","1.0.2":"2026-07-29T17:53:25.990Z","1.1.0":"2026-08-09T16:40:51.017Z","1.1.1":"2026-08-09T17:00:45.718Z","1.1.2":"2026-08-11T15:08:17.212Z","1.2.0":"2026-08-11T16:43:37.289Z","1.2.1":"2026-08-11T20:10:05.231Z","1.3.0":"2026-08-14T08:57:49.908Z","1.4.0":"2026-08-21T11:42:58.683Z"},"bugs":{"url":"https://github.com/daanvandenbergh/policykit/issues"},"license":"UNLICENSED","homepage":"https://daanvandenbergh.github.io/policykit","repository":{"type":"git","url":"git+https://github.com/daanvandenbergh/policykit.git"},"description":"Versioned legal policies as MDX for Next.js App Router: a directory per revision, a file per locale, and a Policy class that answers which revision binds now, what notice is owed, and renders any revision in any locale - plus Claude Code rules and a skill","maintainers":[{"name":"daanvandenbergh","email":"d.vandenbergh2@gmail.com"}],"readme":"# @daanvandenbergh/policykit\n\n![Versioned legal policies as MDX](.agentstore/scribekit-hero/readme/hero.png)\n\nVersioned legal policies as MDX for **Next.js App Router**. A legal policy (terms of service,\nprivacy policy, DPA, ...) is a *versioned document*, not UI: it has revisions, each revision has\nan effective date and a notice obligation, the published text is legal evidence, and your app\nneeds to answer \"which revision binds right now?\", \"what notice is owed?\", and \"render revision X\nin locale Y\" - including OLD revisions, which ARE the version archive. policykit stores each\npolicy as a directory where **a version IS a directory** (`<date>/<locale>.mdx`), and the\n`Policy` class answers those three questions. Everything else - notice delivery, consent storage,\nyour notice-window arithmetic - deliberately stays yours.\n\n**📖 Full documentation: [daanvandenbergh.github.io/policykit](https://daanvandenbergh.github.io/policykit)**\n\n**Contents:** [Install](#install) · [The content directory](#the-content-directory) ·\n[Quickstart](#quickstart) · [The archive route](#the-archive-route) ·\n[The takes-effect banner](#the-takes-effect-banner) ·\n[The consent gate](#the-consent-gate) · [The notice job](#the-notice-job) ·\n[Lifecycle rules](#lifecycle-rules) · [Claude Code skill and rules](#claude-code-skill-and-rules) ·\n[API](#api) · [What this package does not do](#what-this-package-does-not-do)\n\n---\n\n## Install\n\n```bash\nnpm install @daanvandenbergh/policykit\n```\n\nPeer dependencies (you almost certainly already have the first three): `next`, `react`,\n`react-dom`, and `next-mdx-remote` (used by the `/react` entry to render MDX).\n\nThe root entry (`@daanvandenbergh/policykit`) is **react-free** - its module graph imports only\n`node:fs`, `node:path`, and `gray-matter` - so server-side packages that forbid react can import\nit safely. Only the `/react` subpath touches react.\n\n---\n\n## The content directory\n\nOne directory per policy; one directory per **revision** (its `YYYY-MM-DD` name IS the revision's\nidentity); one MDX file per locale:\n\n```\npolicies/terms-of-service/\n  2026-07-07/            # a revision - the date it was decided\n    en.mdx               # frontmatter lives here (the default locale)\n    nl.mdx\n  2026-07-28/            # a later revision\n    en.mdx\n    nl.mdx\n  drafts/                # IGNORED by the loader - the one parking spot for work in progress\n```\n\nThe grammar is STRICT and every breach is a loud error naming the offending entry (thrown at\nfirst use - which fails `next build` - never at import time):\n\n- a revision directory must be a real `YYYY-MM-DD` calendar day (a typo'd `2026-8-15/` or an\n  impossible `2026-02-30/` is an error, never an invisible revision);\n- inside a revision directory, every file is `<locale>.mdx` for a locale you configured;\n- every file must have a non-empty MDX body - frontmatter alone is not a legal document;\n- nothing else may sit at the policy root, except `drafts/`, which is skipped wholesale - a\n  committed dated directory is *published* (it ships on the next deploy and becomes `latest`).\n\nThe revision date is written once, the filesystem enforces revision uniqueness, and `ls` shows\nthe whole archive. There is deliberately no free-form revision naming and no date-in-frontmatter:\nlegal versions are cited by date (\"the terms of 28 July 2026\"), which is exactly the directory\nname, and your consent records store that same string.\n\n### Frontmatter\n\nThe **default locale's file** (`en` unless configured) carries the revision's metadata:\n\n```yaml\n---\neffectiveFrom: 2026-08-12    # REQUIRED. A real YYYY-MM-DD calendar day >= the revision date.\n                             # The gap IS the notice window: publish today, take effect after\n                             # the notice period. Impossible dates are errors - including\n                             # unquoted YAML dates that would otherwise roll over silently.\nnotice: notify               # REQUIRED. none | notify | reconsent - the recorded legal judgement.\nchangeSummary: \"Added the monthly fair-use limit and retiered change notice.\"\n                             # REQUIRED, non-empty, English. INTERNAL changelog/evidence -\n                             # never rendered to users.\ntitle: \"Terms of Service\"    # OPTIONAL display title.\n---\n```\n\nNon-default locale files may carry ONLY an optional `title:`. Any other key in any file is a\nvalidation error - metadata duplicated across locales is metadata that drifts.\n\nLocales follow a **contiguity** rule, not completeness: the default locale must exist for every\nrevision; any other locale, once introduced at revision R, must exist for every revision after R.\nIt may be absent before R - a locale added in 2027 never demands fake backdated translations of\nthe 2026 archive.\n\n---\n\n## Quickstart\n\n**1. Configure one instance per policy, in one module** (absolute `dir` - the same instance may\nrun from several working directories):\n\n```ts\n// e.g. src/content/policies.ts\nimport path from \"node:path\";\nimport { Policy } from \"@daanvandenbergh/policykit\";\n\nconst dir = (slug: string) => path.join(process.cwd(), \"policies\", slug);\n\nexport const termsPolicy = new Policy({\n    slug: \"terms-of-service\",\n    dir: dir(\"terms-of-service\"),\n    locales: [\"en\", \"nl\"],\n});\nexport const privacyPolicy = new Policy({\n    slug: \"privacy\",\n    dir: dir(\"privacy\"),\n    locales: [\"en\", \"nl\"],\n});\nexport const POLICIES = [termsPolicy, privacyPolicy];\n```\n\n**2. Render the live page.** `PolicyDocument` is an async server component that renders ONE\nrevision's MDX body (with GFM, so pipe tables work) - you own the page shell: title, \"last\nupdated\" label, prose styling, and the link component via the MDX component map (policykit never\nimports `next/link`):\n\n```tsx\n// app/[locale]/legal/terms/page.tsx\nimport { PolicyDocument } from \"@daanvandenbergh/policykit/react\";\nimport { termsPolicy } from \"@/content/policies\";\nimport { MyLink } from \"@/components/MyLink\"; // your locale-aware link component\n\nexport default async function TermsPage({ params }: { params: Promise<{ locale: string }> }) {\n    const { locale } = await params;\n    const now = new Date();\n    const shown = termsPolicy.effective(now) ?? termsPolicy.latest();\n    const pending = termsPolicy.pending(now);\n    // The locale file's own title; shown.title is the DEFAULT locale's and would be the wrong\n    // language here (content() deliberately does no fallback - the fallback is your call).\n    const title = termsPolicy.content(shown.revision, locale)?.title ?? shown.title;\n    return (\n        <article className=\"prose\">\n            <h1>{title}</h1>\n            {pending && <p>A new version takes effect on {pending.effectiveFrom}.</p>}\n            <PolicyDocument\n                policy={termsPolicy}\n                locale={locale}\n                revision={shown.revision}\n                components={{ a: MyLink }}\n            />\n        </article>\n    );\n}\n```\n\n`effective(now) ?? latest()` is the live-page revision: the text that binds, or the newest\npublished text before anything is effective. Passing `revision={shown.revision}` keeps your title\nand the body on the SAME revision; with `revision` omitted, `PolicyDocument` computes that same\ndefault itself - fine when you render no revision metadata around it.\n\n**3. Validate in CI.** One test proves a deploy cannot fail on policy content:\n\n```ts\nimport { it } from \"vitest\";\nimport { assertValidAll } from \"@daanvandenbergh/policykit\";\nimport { POLICIES } from \"@/content/policies\";\n\nit(\"policies are valid\", () => assertValidAll(POLICIES));\n```\n\n---\n\n## The archive route\n\nOld revisions ARE the version archive - serve them from a dynamic segment and 404 on anything\nunknown (`revision()` takes untrusted input and returns `undefined`, never throws):\n\n```tsx\n// app/[locale]/legal/terms/[revision]/page.tsx\nimport { notFound } from \"next/navigation\";\nimport { PolicyDocument } from \"@daanvandenbergh/policykit/react\";\nimport { termsPolicy } from \"@/content/policies\";\n\nexport default async function TermsRevisionPage({ params }: {\n    params: Promise<{ locale: string; revision: string }>;\n}) {\n    const { locale, revision } = await params;\n    if (!termsPolicy.revision(revision)) notFound();\n    if (!termsPolicy.content(revision, locale)) notFound(); // locale may legally be absent here\n    return <PolicyDocument policy={termsPolicy} locale={locale} revision={revision} />;\n}\n```\n\n---\n\n## The takes-effect banner\n\nSite-wide, \"a new version of our terms takes effect on {date}\". `PolicyBanner` is a **headless**\nserver component: it resolves which revision to announce and hands it to your `children` - the\ncopy, the date formatting, and the markup are yours (no CSS ships, and the sentence is localized\ntext only you can write). It renders `null` when there is nothing to announce:\n\n```tsx\n// app/[locale]/layout.tsx\nimport { PolicyBanner } from \"@daanvandenbergh/policykit/react\";\nimport { POLICIES } from \"@/content/policies\";\n\n<PolicyBanner policies={POLICIES}>\n    {({ policy, revision }) => (\n        <aside className=\"banner\">\n            {t(`legal.${policy.slug}.takesEffect`, { date: format(revision.effectiveFrom) })}{\" \"}\n            <MyLink href={`/legal/${policy.slug}`}>Read it</MyLink>\n        </aside>\n    )}\n</PolicyBanner>\n```\n\nIt announces the revision taking effect **soonest** across the policies you pass, and only one\nthat **owes notice** - a `notice: \"none\"` revision is never announced (the tier IS the recorded\ndecision that no notice is owed), and it never masks a later notice-owing revision behind it.\nSuperseded revisions are excluded, same as everywhere. Pass `now` to pin the clock in tests.\n\nNeed the same answer outside React (an in-app banner API, a mail digest header)? The core\nexports it directly - the component is a thin wrapper around this:\n\n```ts\nimport { pendingNotice } from \"@daanvandenbergh/policykit\";\n\nconst announcement = pendingNotice(POLICIES, new Date()); // { policy, revision } | undefined\n```\n\n**`pending()` vs `pendingNotice`.** On a policy's OWN page, `policy.pending(now)` is the right\ncall - it labels that document's next version whatever its tier (the quickstart does this).\n`pendingNotice` is the *notice* question, so it applies the tier filter; do not hand-roll it as\n`policies.map((p) => p.pending(now)).filter((r) => r?.notice !== \"none\")` - that drops a policy\nwhose soonest pending revision happens to be `none` and silently swallows the `reconsent` behind\nit.\n\n---\n\n## The consent gate\n\nStore the accepted revision as the **string** the package gives you (e.g. `\"2026-07-28\"`) and\ncompare with lexicographic `>=` - the strings are zero-padded ISO, so string order is date order:\n\n```ts\nimport { requiredConsentRevision } from \"@daanvandenbergh/policykit\";\n\nconst required = requiredConsentRevision(POLICIES, new Date());\n// \"\" means nothing is in force yet, so nobody owes consent; ?? \"\" keeps a never-accepted\n// user (undefined stamp) from failing the comparison for the wrong reason.\nconst consented = required === \"\" || (user.acceptedPolicyRevision ?? \"\") >= required;\n```\n\n`requiredConsentRevision` is the max *effective* revision that is either a policy's baseline\n(the first revision that ever binds) or carries `notice: \"reconsent\"`. A `\"notify\"` revision\ndeliberately never moves it - it must never re-prompt anyone. A revision superseded before its\neffective day never moves it either - its text never binds (see [the notice job](#the-notice-job)),\nso demanding consent to it would re-prompt everyone over nothing; if the superseding revision\nstill owes that reconsent, record `reconsent` on the superseding revision itself.\n\n**Stamp the joint threshold the user just satisfied - `requiredConsentRevision` itself, evaluated\nat acceptance time:**\n\n```ts\n// What an acceptance stamps. The value is monotone over time and NEVER runs ahead of a\n// requirement that has not bound yet - which is exactly what a hand-rolled stamp gets\n// wrong. Stamping one policy's revision lags the joint gate (re-prompting forever), and\n// stamping the max EFFECTIVE revision across policies can run AHEAD of a sibling policy's\n// pending reconsent (a newer-dated notify revision inflates the stamp past the reconsent's\n// revision string, silently masking it when it binds - consent recorded that was never\n// given). The threshold itself has neither failure mode.\nconst accepted = requiredConsentRevision(POLICIES, new Date());\n```\n\nThe user still SEES the effective texts (the quickstart page renders `effective(now)`); the stamp\nis the gate value those texts satisfy, not a display artifact. One cross-policy nuance to know:\nthe gate is a single joint threshold, so a reconsent revision whose date string is older than a\nsibling policy's newer baseline/reconsent revision is subsumed by it - users are re-prompted once\nagainst the joint threshold, not once per policy. If you need strictly per-policy reconsent\ntracking, run the gate per policy (`requiredConsentRevision([termsPolicy], now)` etc.) with one\nstored stamp per policy.\n\nAll binding comparisons reduce `now` to its **UTC calendar day** - a revision takes effect at UTC\nmidnight of its `effectiveFrom`, everywhere.\n\n---\n\n## The notice job\n\n`noticeQueue` lists every revision across your policies that owes user-facing notice\n(`notice !== \"none\"`) whose `effectiveFrom` is recent (within `horizonDays`, default 60) or still\nin the future. Your job delivers the notices and dedupes per `(user, policy, revision.revision)`:\n\n```ts\nimport { noticeQueue } from \"@daanvandenbergh/policykit\";\n\nfor (const { policy, revision } of noticeQueue(POLICIES, { now: new Date() })) {\n    await notifyUsersOnce(policy.slug, revision.revision, revision.effectiveFrom);\n}\n```\n\n**The horizon is load-bearing, not an optimization.** If your notice dedupe rows expire on a TTL,\nkeep the horizon comfortably INSIDE that TTL (the 60-day default suits a 90-day TTL): an\nunbounded queue would re-notify every user about every historical revision each time its dedupe\nrow expired.\n\nA revision superseded before it ever bound - a newer revision (say, an immediate law/security\nchange) took effect on or before its `effectiveFrom` - is never queued, and `pending()` never\nreturns it: its text will never bind, and announcing it would be misinformation.\n\nSupersession usually happens AFTER the announcement went out, though, so `supersededSince` gives\nyou the other half of the same window - the revisions `noticeQueue` just dropped. An email cannot\nbe unsent, but any announcement you still hold (a dashboard row, an in-app banner) is now promising\na change that will never land:\n\n```ts\nimport { supersededSince } from \"@daanvandenbergh/policykit\";\n\nfor (const { policy, revision } of supersededSince(POLICIES, { now: new Date() })) {\n    await withdrawNotice(policy.slug, revision.revision);\n}\n```\n\nIt is bounded by the same horizon as the queue, so it can only ever name a revision the queue\nwould have carried - clearing what it names can never reach back into history.\n\n---\n\n## Lifecycle rules\n\nThe package validates the layout and frontmatter; these judgement calls it deliberately leaves to\nyou (shipped as `rules/policies.md`, see below):\n\n- **Errata vs revision.** An immaterial fix (typo, link, formatting) edits the published file in\n  place - git is the errata trail. A change that moves the MEANING of a clause is a new revision;\n  a fake revision per typo would flip consent gates and re-prompt every user over a comma.\n- **One revision per day**, and never amend a shipped revision - notice dedupe is keyed on the\n  revision string and will not re-send.\n- **A committed dated directory IS published.** Drafts live in `drafts/` or on a branch.\n- **Notice windows are your contract, not the package's.** policykit validates only\n  `effectiveFrom >= revision`; the window your own terms promise (and its legal exceptions - a\n  change forced by law or security may be adverse AND immediate) is arithmetic you own. Pin your\n  promise with your own test.\n- **Promise the legal minimum, never more.** Every sentence is an obligation you must keep and can\n  only walk back with a new revision, a notice and possibly fresh consent - so write the statutory\n  bound, not a better one, and volunteer no guarantee, no unbounded absolute (\"never\",\n  \"immediately\") and no borrowed generous clause. Removing an over-promise you already published is\n  itself a material change.\n- **Fresh translations per revision** - a copied-forward old translation validates green and lies.\n- **Never rewrite git history over policy content** - the log is part of the acceptance-evidence\n  chain.\n\n---\n\n## Claude Code skill and rules\n\nThe package ships both halves of the agent contract:\n\n```bash\n# The authoring workflow skill (add/update a revision, end to end):\nmkdir -p .claude/skills\nln -s ../../node_modules/@daanvandenbergh/policykit/skills/policykit .claude/skills/policykit\n```\n\nAnd add this line to your `CLAUDE.md` so the editing rules load into every session:\n\n```\n@node_modules/@daanvandenbergh/policykit/rules/policies.md\n```\n\n---\n\n## API\n\nRoot entry - react-free:\n\n- `new Policy({ slug, dir, locales, defaultLocale? })` - construction stores config; all IO is\n  lazy, per-file memoized, and re-validated on every accessor (so `next dev` sees edits live and\n  a broken directory fails every call, loudly).\n- `policy.revisions()` - all revisions, ascending. Throws `PolicyValidationError` on any breach.\n- `policy.latest()` - the newest revision by date (the live page's fallback before anything is\n  effective; during a notice window it is published but not yet binding, so never what an\n  acceptance stamps).\n- `policy.effective(now)` - the revision that BINDS at `now`, or `undefined` before the first\n  `effectiveFrom`. What the live page renders, as `effective(now) ?? latest()`. NOT the consent\n  gate - that is `requiredConsentRevision`, and stamping this instead has a named failure mode\n  (see [the consent job](#the-consent-job)).\n- `policy.pending(now)` - published, not yet effective, and still going to bind (superseded\n  revisions are never announced). The right call to label ONE document's next version on its own\n  page; a site-wide \"takes effect on\" banner uses `pendingNotice`, which also filters by tier.\n- `policy.revision(date)` - lookup by exact revision string; `undefined` on a miss, never throws\n  on the lookup itself (an invalid corpus still throws `PolicyValidationError`).\n- `policy.content(revision, locale)` - `{ source, title? }` or `undefined` (absence is an\n  answer: a locale may legally be missing from an old revision). `title` is THAT locale's own;\n  `revision.title` is the default locale's - see the note in the quickstart.\n- `policy.has(revision, locale)` - the cheap existence check, no body read. What an archive route\n  asks before choosing between rendering and a 404, instead of calling `content()` twice.\n- `policy.owedNotices({ now, horizonDays? })` - the owed-notice revisions of THIS policy\n  (`readonly PolicyRevision[]`). Same semantics as `noticeQueue`, for per-document surfaces that\n  should not have to build a one-element array and unwrap `{ policy }` pairs.\n- `policy.assertValid()` / `assertValidAll(policies)` - walk everything, throw the first\n  violation naming the file and field; `assertValidAll` also rejects duplicate slugs.\n- `pendingNotice(policies, now)` - the one pending revision a banner should announce:\n  soonest-effective across the policies, still going to bind, and owing notice\n  (`notice !== \"none\"`); `{ policy, revision }` or `undefined`.\n- `noticeQueue(policies, { now, horizonDays? })` - the owed-notice queue (see above).\n- `supersededSince(policies, { now, horizonDays? })` - its complement in the same window: the\n  in-horizon revisions a newer one superseded, so an announcement already sent can be withdrawn.\n- `DEFAULT_NOTICE_HORIZON_DAYS` (`60`) - the default horizon, exported so a consumer can ASSERT it\n  against its own dedupe TTL. **A horizon longer than that TTL re-queues every historical revision\n  each time a dedupe row is swept**, re-notifying everyone on a schedule nobody watches. Compare\n  the two in a test.\n- `requiredConsentRevision(policies, now)` - the consent gate threshold (see above).\n- `PolicyValidationError` - carries `{ slug, file?, field? }` for precise rendering/logging.\n\nReact entry (`@daanvandenbergh/policykit/react`):\n\n- `<PolicyDocument policy locale revision? components? />` - async server component rendering\n  one revision's MDX body via `next-mdx-remote` with `remark-gfm`. The compile is memoized per (options, source), so a revision is compiled once per process and an edit is a different key - never a stale document. No CSS ships.\n- `<PolicyBanner policies now?>{({ policy, revision }) => ...}</PolicyBanner>` - headless server\n  component announcing the next revision to take effect (`pendingNotice`), or `null`. Reads the\n  filesystem, so it is server-only - never inside a `\"use client\"` tree.\n\n---\n\n## What this package does not do\n\npolicykit answers \"what binds, what is owed, render it\" - and stops. Notice DELIVERY (email,\nin-app), consent STORAGE, notice-window arithmetic, diff/redline rendering, content hashes (git\nis the integrity record), and draft/preview modes are deliberately out of scope.\n","readmeFilename":"README.md"}