{"_id":"@broberg/consent-cookie","name":"@broberg/consent-cookie","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@broberg/consent-cookie","version":"0.1.0","description":"Headless GDPR consent / cookie-banner core: a framework-free consent state machine with category granularity (essential always-on + analytics/marketing), policy-version re-surfacing, an injectable ConsentStorage (localStorage + memory/SSR), a subscribe st","type":"module","license":"MIT","sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"build":"tsup","test":"vitest run","typecheck":"tsc --noEmit"},"devDependencies":{"tsup":"^8.3.0","typescript":"^5.6.0","vitest":"^2.1.0"},"keywords":["gdpr","consent","cookie-banner","cookie-consent","privacy","eprivacy","consent-manager","headless","broberg"],"repository":{"type":"git","url":"git+https://github.com/broberg-ai/components.git","directory":"packages/consent-cookie"},"publishConfig":{"access":"public"},"gitHead":"2ba6981e1363d0df7df847c51e78cb27eda32de8","_id":"@broberg/consent-cookie@0.1.0","bugs":{"url":"https://github.com/broberg-ai/components/issues"},"homepage":"https://github.com/broberg-ai/components#readme","_nodeVersion":"25.7.0","_npmVersion":"11.10.1","dist":{"integrity":"sha512-MFZjYLKzg72FGqMvHVTkPFhT/bP+eQGCOdYw8Od6jkk8bW0yPOYjDxVbT96fzab2BhCR+S8MEE5gRHrlx/+Hkg==","shasum":"ae809f828981b5be922054f2ff32aa8705cc4cdb","tarball":"https://registry.npmjs.org/@broberg/consent-cookie/-/consent-cookie-0.1.0.tgz","fileCount":8,"unpackedSize":39092,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDyKi0AuFDVUBww0voZNr3E46b9m1Jj5CufmRQ2mmohMAiAF3SZMM2+9lwphoGrsbZgpadIyvlK6Alj6gt5mkWmlAg=="}]},"_npmUser":{"name":"cbroberg","email":"cb@webhouse.dk"},"directories":{},"maintainers":[{"name":"cbroberg","email":"cb@webhouse.dk"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/consent-cookie_0.1.0_1783789214285_0.2122752273427737"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-11T17:00:14.143Z","0.1.0":"2026-07-11T17:00:14.804Z","modified":"2026-07-11T17:00:15.032Z"},"maintainers":[{"name":"cbroberg","email":"cb@webhouse.dk"}],"description":"Headless GDPR consent / cookie-banner core: a framework-free consent state machine with category granularity (essential always-on + analytics/marketing), policy-version re-surfacing, an injectable ConsentStorage (localStorage + memory/SSR), a subscribe st","homepage":"https://github.com/broberg-ai/components#readme","keywords":["gdpr","consent","cookie-banner","cookie-consent","privacy","eprivacy","consent-manager","headless","broberg"],"repository":{"type":"git","url":"git+https://github.com/broberg-ai/components.git","directory":"packages/consent-cookie"},"bugs":{"url":"https://github.com/broberg-ai/components/issues"},"license":"MIT","readme":"# @broberg/consent-cookie\n\nThe **headless core** for a GDPR consent / cookie banner. The banner *UI* is\ncopy-owned per brand (each product owns its policy text, categories and tokens),\nbut the consent *logic* — what counts as valid consent, when to re-surface after\na policy change, essential-always-on, the right to withdraw — is easy to get\nsubtly (and legally) wrong. This package owns that correct, tested state machine,\nframework-free and SSR-safe.\n\n```bash\nnpm i @broberg/consent-cookie\n```\n\n## Usage\n\n```ts\nimport { createConsentManager } from \"@broberg/consent-cookie\";\n\nconst consent = createConsentManager({\n  policyVersion: \"2026-05\",          // bump this when your policy changes → banner re-surfaces\n  storageKey: \"acme-consent\",        // localStorage key (or pass your own `storage`)\n});\n\nif (consent.needsBanner()) showBanner();   // first visit OR policy changed\n\n// user actions\nconsent.acceptAll();                        // grant every category\nconsent.rejectAll();                        // essential only\nconsent.setConsent({ analytics: true });    // granular; essential forced on, unlisted off\n\n// gate side-effects\nif (consent.has(\"analytics\")) loadAnalytics();\n\n// GDPR right to withdraw — clears consent, banner returns\nconsent.withdraw();\n\n// react to changes anywhere\nconst off = consent.subscribe((record) => sync(record));\n```\n\n## What it gets right\n\n- **Policy-version re-surface.** `needsBanner()` / `isOutdated()` return true when\n  there is no record, when the stored `policyVersion` differs from the current one,\n  or when a legacy record has no version — so a policy update re-asks users instead\n  of silently keeping stale consent.\n- **Essential is always on.** Essential categories can't be toggled off; `has(\"essential\")`\n  is `true` even before any decision.\n- **Right to withdraw.** `withdraw()` clears the record — a legal requirement most\n  hand-rolled banners forget.\n- **SSR-safe + injectable storage.** `createLocalStorageConsentStorage(key)` degrades\n  to memory when there's no DOM; implement `ConsentStorage` to persist server-side\n  (wire it to a profile row) without changing any call sites.\n\n## API\n\n```ts\ncreateConsentManager({ policyVersion, categories?, storage?, storageKey? }): ConsentManager\n// getRecord · needsBanner · isOutdated · has(category) · acceptAll · rejectAll\n// setConsent(selection) · withdraw · subscribe · categories\n\ninterface ConsentStorage { get(): ConsentRecord | null; set(r): void; clear(): void }\ncreateLocalStorageConsentStorage(key)   // SSR-safe, falls back to memory\ncreateMemoryConsentStorage()\nCONSENT_CATEGORIES                       // default: essential · analytics · marketing (overridable)\n```\n\nThe React / Preact banner + granular-toggle modal (built on shadcn Dialog/Switch,\non your tokens) are copy-owned adapters shipping on top of this core.\n\n## License\n\nMIT · part of the [`@broberg/*`](https://discovery.broberg.ai) shared inventory.\n","readmeFilename":"README.md","_rev":"1-ee8e08e5f7ce18f42111d0e174324e2f"}