@consenti/ui 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vue.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/vue.ts"],"sourcesContent":["/**\n * Vue 3 composable integration for `@consenti/ui`.\n *\n * Import from the `@consenti/ui/vue` subpath to keep this module\n * tree-shaken out of vanilla JS or React bundles.\n *\n * Intended for **Nuxt 3** and any Vue 3 project where you manage the `ConsentiSetup`\n * instance yourself (typically in a `.client.ts` plugin) and want `useConsent()`\n * to be reactive in components.\n *\n * @example\n * ```ts\n * // plugins/consenti.client.ts (Nuxt 3)\n * import { ConsentiSetup } from '@consenti/ui'\n * import { setConsentiWidget } from '@consenti/ui/vue'\n *\n * export default defineNuxtPlugin(() => {\n * const widget = new ConsentiSetup({ core: { profileId: 0 } })\n * setConsentiWidget(widget)\n * })\n *\n * // Any component\n * import { useConsent } from '@consenti/ui/vue'\n *\n * const { hasConsent, submitConsent } = useConsent()\n * ```\n */\n\nimport { ref, onMounted, onUnmounted } from 'vue'\nimport type { ConsentValue } from './types'\nimport type { ConsentiSetup } from './core/consenti-setup'\n\n/**\n * Module-level singleton — the active `ConsentiSetup` instance.\n * Using a module-level variable (rather than `provide`/`inject`) keeps the integration\n * zero-configuration: no wrapper component is required.\n */\nlet _widget: ConsentiSetup | null = null\n\n/**\n * Registers the active `ConsentiSetup` instance so `useConsent()` can read from it.\n * Call this once after creating your widget, typically in a `.client.ts` Nuxt plugin.\n *\n * @param widget - The `ConsentiSetup` instance to register.\n */\nexport function setConsentiWidget(widget: ConsentiSetup): void {\n _widget = widget\n}\n\n/**\n * Vue 3 composable that exposes consent state and triggers reactivity on consent changes.\n *\n * Listens to `consenti:consentSubmitted` on `window` via `onMounted` / `onUnmounted`\n * and increments a `ref(tick)` counter. Reactive getters read `tick.value` to register\n * a Vue dependency so components re-render when consent changes.\n *\n * Returns SSR-safe fallback values during Nuxt server render.\n *\n * @returns An object with `hasConsent`, `getConsent`, `submitConsent`, and `getConsentDate`.\n */\nexport function useConsent() {\n const isServer = typeof window === 'undefined'\n\n const tick = ref(0)\n const handler = () => { tick.value++ }\n\n onMounted(() => {\n window.addEventListener('consenti:consentSubmitted', handler)\n })\n\n onUnmounted(() => {\n window.removeEventListener('consenti:consentSubmitted', handler)\n })\n\n if (isServer) {\n return {\n hasConsent: () => false as boolean,\n getConsent: () => null as ConsentValue | null,\n submitConsent: async (_consent: Partial<ConsentValue>) => {},\n getConsentDate: () => false as Date | false,\n }\n }\n\n return {\n /** Returns `true` if the visitor has saved consent. Reactive — re-evaluated on consent change. */\n hasConsent: () => {\n void tick.value // registers Vue dependency\n return _widget?.hasConsent() ?? false\n },\n /** Returns the stored consent map, or `null`. Reactive. */\n getConsent: () => {\n void tick.value\n return _widget?.getConsent() ?? null\n },\n /** Saves the given partial consent map. Missing keys default to `'denied'`. */\n submitConsent: (consent: Partial<ConsentValue>) =>\n _widget?.submitConsent(consent) ?? Promise.resolve(),\n /** Returns the `Date` of last consent submission, or `false`. Reactive. */\n getConsentDate: () => {\n void tick.value\n return _widget?.getConsentDate() ?? false\n },\n }\n}\n"],"mappings":";AA4BA,SAAS,KAAK,WAAW,mBAAmB;AAS5C,IAAI,UAAgC;AAQ7B,SAAS,kBAAkB,QAA6B;AAC7D,YAAU;AACZ;AAaO,SAAS,aAAa;AAC3B,QAAM,WAAW,OAAO,WAAW;AAEnC,QAAM,OAAO,IAAI,CAAC;AAClB,QAAM,UAAU,MAAM;AAAE,SAAK;AAAA,EAAQ;AAErC,YAAU,MAAM;AACd,WAAO,iBAAiB,6BAA6B,OAAO;AAAA,EAC9D,CAAC;AAED,cAAY,MAAM;AAChB,WAAO,oBAAoB,6BAA6B,OAAO;AAAA,EACjE,CAAC;AAED,MAAI,UAAU;AACZ,WAAO;AAAA,MACL,YAAY,MAAM;AAAA,MAClB,YAAY,MAAM;AAAA,MAClB,eAAe,OAAO,aAAoC;AAAA,MAAC;AAAA,MAC3D,gBAAgB,MAAM;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AAAA;AAAA,IAEL,YAAY,MAAM;AAChB,WAAK,KAAK;AACV,aAAO,SAAS,WAAW,KAAK;AAAA,IAClC;AAAA;AAAA,IAEA,YAAY,MAAM;AAChB,WAAK,KAAK;AACV,aAAO,SAAS,WAAW,KAAK;AAAA,IAClC;AAAA;AAAA,IAEA,eAAe,CAAC,YACd,SAAS,cAAc,OAAO,KAAK,QAAQ,QAAQ;AAAA;AAAA,IAErD,gBAAgB,MAAM;AACpB,WAAK,KAAK;AACV,aAAO,SAAS,eAAe,KAAK;AAAA,IACtC;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/vue.ts"],"sourcesContent":["/**\n * Vue 3 composable integration for `@consenti/ui`.\n *\n * Import from the `@consenti/ui/vue` subpath to keep this module\n * tree-shaken out of vanilla JS or React bundles.\n *\n * Intended for **Nuxt 3** and any Vue 3 project where you manage the `ConsentiSetup`\n * instance yourself (typically in a `.client.ts` plugin) and want `useConsent()`\n * to be reactive in components.\n *\n * @example\n * ```ts\n * // plugins/consenti.client.ts (Nuxt 3)\n * import { ConsentiSetup } from '@consenti/ui'\n * import { setConsentiWidget } from '@consenti/ui/vue'\n *\n * export default defineNuxtPlugin(() => {\n * const widget = new ConsentiSetup({\n * api: { enabled: true, baseUrl: useRuntimeConfig().public.apiUrl },\n * })\n * setConsentiWidget(widget)\n * })\n *\n * // Any component\n * import { useConsent } from '@consenti/ui/vue'\n *\n * const { hasConsent, consent, showModal } = useConsent()\n * // hasConsent, consent, bannerVisible, modalVisible are Refs — reactive in templates\n * ```\n */\n\nimport { ref, onMounted, onUnmounted } from 'vue'\nimport type { ConsentValue } from './types'\nimport type { ConsentiSetup } from './core/consenti-setup'\n\n/**\n * Module-level singleton — the active `ConsentiSetup` instance.\n * Using a module-level variable (rather than `provide`/`inject`) keeps the integration\n * zero-configuration: no wrapper component is required.\n */\nlet _widget: ConsentiSetup | null = null\n\n/**\n * Registers the active `ConsentiSetup` instance so `useConsent()` can read from it.\n * Call this once after creating your widget, typically in a `.client.ts` Nuxt plugin.\n *\n * @param widget - The `ConsentiSetup` instance to register.\n */\nexport function setConsentiWidget(widget: ConsentiSetup): void {\n _widget = widget\n}\n\n/**\n * Vue 3 composable that exposes consent state, banner/modal visibility, and widget actions.\n *\n * State values (`hasConsent`, `consent`, `consentDate`, `bannerVisible`, `modalVisible`) are\n * Vue `Ref`s — they are reactive in templates and `watch`/`computed` without calling `.value`\n * in the template (Vue auto-unwraps top-level refs).\n *\n * Event listeners are registered in `onMounted` and removed in `onUnmounted`, so this\n * composable is safe to call in components that render on the server (Nuxt SSR): the refs\n * simply hold their initial values (`false` / `null`) during SSR and hydrate correctly.\n *\n * @returns Reactive refs for consent state and plain functions for widget actions.\n */\nexport function useConsent() {\n const hasConsent = ref<boolean>(_widget?.hasConsent() ?? false)\n const consent = ref<ConsentValue | null>(_widget?.getConsent() ?? null)\n const consentDate = ref<Date | false>(_widget?.getConsentDate() ?? false)\n const bannerVisible = ref<'main' | 'gpc' | false>(false)\n const modalVisible = ref<'preference' | false>(false)\n\n const onConsent = () => {\n hasConsent.value = _widget?.hasConsent() ?? false\n consent.value = _widget?.getConsent() ?? null\n consentDate.value = _widget?.getConsentDate() ?? false\n }\n const onBanner = () => { bannerVisible.value = _widget?.bannerVisibility() ?? false }\n const onModal = () => { modalVisible.value = _widget?.modalVisibility() ?? false }\n\n onMounted(() => {\n if (typeof window === 'undefined') return\n window.addEventListener('consenti:consentSubmitted', onConsent)\n window.addEventListener('consenti:bannerVisibility', onBanner)\n window.addEventListener('consenti:modalVisibility', onModal)\n })\n\n onUnmounted(() => {\n if (typeof window === 'undefined') return\n window.removeEventListener('consenti:consentSubmitted', onConsent)\n window.removeEventListener('consenti:bannerVisibility', onBanner)\n window.removeEventListener('consenti:modalVisibility', onModal)\n })\n\n return {\n /** Reactive — `true` once the visitor has saved a valid consent record. */\n hasConsent,\n /** Reactive — the stored consent map (`Record<cookieId, status>`), or `null`. */\n consent,\n /** Reactive — `Date` of the last consent submission, or `false`. */\n consentDate,\n /** Reactive — `'main'`, `'gpc'`, or `false` (banner hidden). */\n bannerVisible,\n /** Reactive — `'preference'` or `false` (modal hidden). */\n modalVisible,\n\n /** Shows the consent banner. Pass `true` to force the GPC variant. */\n showBanner: (gpc?: boolean) => _widget?.showBanner(gpc),\n /** Hides the consent banner. */\n hideBanner: () => _widget?.hideBanner(),\n /** Opens the preference modal. */\n showModal: () => _widget?.showModal(),\n /** Closes the preference modal. */\n hideModal: () => _widget?.hideModal(),\n\n /** Grants all non-mandatory cookies. Pass `true` to grant only mandatory ones and deny the rest. */\n grantAll: (onlyMandatory?: boolean) => _widget?.grantAll(onlyMandatory) ?? Promise.resolve(),\n /** Denies all non-mandatory cookies. Pass `true` to deny mandatory ones too (use with care). */\n denyAll: (includingMandatory?: boolean) => _widget?.denyAll(includingMandatory) ?? Promise.resolve(),\n /** Saves the given partial consent map. */\n submitConsent: (c: Partial<ConsentValue>) => _widget?.submitConsent(c) ?? Promise.resolve(),\n /** Deletes the current consent record and re-shows the banner. */\n reConsent: () => _widget?.reConsent() ?? Promise.resolve(),\n\n /** Returns `true` if the given cookie ID is `'granted'`. */\n isCookieGranted: (id: string) => (_widget?.isCookieGranted(id) ?? false) as boolean,\n /** Returns `true` if every cookie in the given category is `'granted'`. */\n isCategoryGranted: (id: string) => (_widget?.isCategoryGranted(id) ?? false) as boolean,\n /** Switches the active locale and re-renders the banner and modal. */\n switchLocale: (locale: string) => _widget?.switchLocale(locale),\n }\n}\n"],"mappings":"AA+BA,OAAS,OAAAA,EAAK,aAAAC,EAAW,eAAAC,MAAmB,MAS5C,IAAIC,EAAgC,KAQ7B,SAASC,EAAkBC,EAA6B,CAC7DF,EAAUE,CACZ,CAeO,SAASC,GAAa,CAC3B,IAAMC,EAAeP,EAAaG,GAAS,WAAW,GAAK,EAAK,EAC1DK,EAAeR,EAAyBG,GAAS,WAAW,GAAK,IAAI,EACrEM,EAAeT,EAAkBG,GAAS,eAAe,GAAK,EAAK,EACnEO,EAAgBV,EAA4B,EAAK,EACjDW,EAAgBX,EAA0B,EAAK,EAE/CY,EAAY,IAAM,CACtBL,EAAW,MAASJ,GAAS,WAAW,GAAK,GAC7CK,EAAQ,MAAYL,GAAS,WAAW,GAAK,KAC7CM,EAAY,MAAQN,GAAS,eAAe,GAAK,EACnD,EACMU,EAAW,IAAM,CAAEH,EAAc,MAAQP,GAAS,iBAAiB,GAAK,EAAM,EAC9EW,EAAW,IAAM,CAAEH,EAAa,MAASR,GAAS,gBAAgB,GAAK,EAAM,EAEnF,OAAAF,EAAU,IAAM,CACV,OAAO,OAAW,MACtB,OAAO,iBAAiB,4BAA6BW,CAAS,EAC9D,OAAO,iBAAiB,4BAA8BC,CAAQ,EAC9D,OAAO,iBAAiB,2BAA8BC,CAAO,EAC/D,CAAC,EAEDZ,EAAY,IAAM,CACZ,OAAO,OAAW,MACtB,OAAO,oBAAoB,4BAA6BU,CAAS,EACjE,OAAO,oBAAoB,4BAA8BC,CAAQ,EACjE,OAAO,oBAAoB,2BAA8BC,CAAO,EAClE,CAAC,EAEM,CAEL,WAAAP,EAEA,QAAAC,EAEA,YAAAC,EAEA,cAAAC,EAEA,aAAAC,EAGA,WAAaI,GAAkBZ,GAAS,WAAWY,CAAG,EAEtD,WAAY,IAAMZ,GAAS,WAAW,EAEtC,UAAW,IAAMA,GAAS,UAAU,EAEpC,UAAW,IAAMA,GAAS,UAAU,EAGpC,SAAWa,GAA4Bb,GAAS,SAASa,CAAa,GAAK,QAAQ,QAAQ,EAE3F,QAAUC,GAAiCd,GAAS,QAAQc,CAAkB,GAAK,QAAQ,QAAQ,EAEnG,cAAgBC,GAA6Bf,GAAS,cAAce,CAAC,GAAK,QAAQ,QAAQ,EAE1F,UAAW,IAAMf,GAAS,UAAU,GAAK,QAAQ,QAAQ,EAGzD,gBAAkBgB,GAAgBhB,GAAS,gBAAgBgB,CAAE,GAAK,GAElE,kBAAoBA,GAAgBhB,GAAS,kBAAkBgB,CAAE,GAAK,GAEtE,aAAeC,GAAmBjB,GAAS,aAAaiB,CAAM,CAChE,CACF","names":["ref","onMounted","onUnmounted","_widget","setConsentiWidget","widget","useConsent","hasConsent","consent","consentDate","bannerVisible","modalVisible","onConsent","onBanner","onModal","gpc","onlyMandatory","includingMandatory","c","id","locale"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@consenti/ui",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Zero-dependency GDPR cookie consent widget",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -65,17 +65,25 @@
65
65
  ],
66
66
  "scripts": {
67
67
  "build": "tsup && npm run build:css",
68
- "dev": "tsup --watch && npm run build:css",
68
+ "dev:build": "tsup --watch",
69
+ "dev:vite": "vite",
70
+ "dev": "npm run dev:vite & npm run dev:build",
71
+ "watch": "tsup --watch",
69
72
  "typecheck": "tsc --noEmit",
70
- "build:css": "node scripts/build-css.mjs"
73
+ "build:css": "node scripts/build-css.mjs",
74
+ "test": "tsx --test src/__tests__/*.integration.ts"
71
75
  },
72
76
  "devDependencies": {
73
77
  "@consenti/types": "*",
78
+ "@consenti/utils": "*",
79
+ "@types/node": "^22.0.0",
74
80
  "@types/react": "^19.0.0",
81
+ "tsx": "^4.23.0",
75
82
  "vue": "^3.5.0",
76
83
  "sass": "^1.89.2",
77
84
  "tsup": "^8.5.0",
78
- "typescript": "^5.8.3"
85
+ "typescript": "^6.0.3",
86
+ "vite": "^8.1.3"
79
87
  },
80
88
  "peerDependencies": {
81
89
  "react": ">=18.0.0",
@@ -94,4 +102,4 @@
94
102
  "node": ">=20.0.0",
95
103
  "npm": ">=10.0.0"
96
104
  }
97
- }
105
+ }
@@ -1,20 +0,0 @@
1
- // src/utils/http.ts
2
- async function httpRequest(url, options = {}, authToken) {
3
- const headers = {
4
- "Content-Type": "application/json",
5
- ...options.headers
6
- };
7
- if (authToken) {
8
- headers["Authorization"] = `Bearer ${authToken}`;
9
- }
10
- const res = await fetch(url, { ...options, headers });
11
- if (!res.ok) {
12
- throw new Error(`[Consenti] HTTP ${res.status} ${res.statusText} \u2014 ${url}`);
13
- }
14
- return res.json();
15
- }
16
-
17
- export {
18
- httpRequest
19
- };
20
- //# sourceMappingURL=chunk-ARALKXMB.mjs.map
@@ -1,26 +0,0 @@
1
- // src/utils/hmac.ts
2
- async function importHmacKey(rawKey) {
3
- const keyData = new TextEncoder().encode(rawKey);
4
- return crypto.subtle.importKey(
5
- "raw",
6
- keyData,
7
- { name: "HMAC", hash: "SHA-256" },
8
- false,
9
- ["sign", "verify"]
10
- );
11
- }
12
- async function signValue(value, key) {
13
- const cryptoKey = await importHmacKey(key);
14
- const data = new TextEncoder().encode(value);
15
- const signature = await crypto.subtle.sign("HMAC", cryptoKey, data);
16
- return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
17
- }
18
- async function verifyValue(value, signature, key) {
19
- const expected = await signValue(value, key);
20
- return expected === signature;
21
- }
22
- export {
23
- signValue,
24
- verifyValue
25
- };
26
- //# sourceMappingURL=hmac-N6H7F2K2.mjs.map
@@ -1,7 +0,0 @@
1
- import {
2
- httpRequest
3
- } from "./chunk-ARALKXMB.mjs";
4
- export {
5
- httpRequest
6
- };
7
- //# sourceMappingURL=http-VHOGZ6ZJ.mjs.map