@consenti/ui 0.3.0 → 0.5.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/README.md +324 -98
- package/dist/angular.d.cts +335 -43
- package/dist/angular.d.ts +335 -43
- package/dist/angular.js +1 -1
- package/dist/angular.js.map +1 -1
- package/dist/angular.mjs +1 -1
- package/dist/angular.mjs.map +1 -1
- package/dist/chunk-RDE7CM6T.mjs +2 -0
- package/dist/chunk-RDE7CM6T.mjs.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +386 -42
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/profiles-5ZLWWN2L.mjs +2 -0
- package/dist/react.d.cts +335 -43
- package/dist/react.d.ts +335 -43
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +1 -1
- package/dist/react.mjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/dist/testing.mjs.map +1 -1
- package/dist/vue.d.cts +335 -43
- package/dist/vue.d.ts +335 -43
- package/dist/vue.js +1 -1
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +1 -1
- package/dist/vue.mjs.map +1 -1
- package/package.json +12 -8
- package/dist/chunk-J4BKXUD6.mjs +0 -2
- package/dist/chunk-J4BKXUD6.mjs.map +0 -1
- package/dist/profiles-OEZAKEWL.mjs +0 -2
- /package/dist/{profiles-OEZAKEWL.mjs.map → profiles-5ZLWWN2L.mjs.map} +0 -0
package/dist/vue.d.ts
CHANGED
|
@@ -13,6 +13,32 @@ type DeepPartial<T> = T extends Function ? T : T extends Array<infer InferredArr
|
|
|
13
13
|
[Key in keyof T]?: DeepPartial<T[Key]> | null;
|
|
14
14
|
} : T;
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Single source of truth for all compliance groups, regulations, and country mappings.
|
|
18
|
+
*
|
|
19
|
+
* This is DATA, not types. The `Compliance` and `ComplianceGroupId` literal types
|
|
20
|
+
* derived from the ID arrays below live in @consenti/types (packages/types/src/compliance.ts),
|
|
21
|
+
* via a type-only import — that keeps @consenti/types free of runtime code.
|
|
22
|
+
*
|
|
23
|
+
* ─── HOW TO UPDATE ────────────────────────────────────────────────────────────
|
|
24
|
+
*
|
|
25
|
+
* ADD A NEW REGULATION:
|
|
26
|
+
* 1. Add regulation ID string to `COMPLIANCE_REGULATION_IDS` below
|
|
27
|
+
* (the `Compliance` type in @consenti/types auto-updates from it).
|
|
28
|
+
* 2. Add it to the appropriate group's `compliances` array below.
|
|
29
|
+
* 3. Add / update the country entry in `EMBEDDED_COMPLIANCE_MAP` below.
|
|
30
|
+
* That is all — no other files need touching.
|
|
31
|
+
*
|
|
32
|
+
* ADD A NEW COMPLIANCE GROUP:
|
|
33
|
+
* 1. Add the kebab-case ID to `COMPLIANCE_GROUP_IDS` below.
|
|
34
|
+
* 2. Add a full group entry to `COMPLIANCE_GROUPS` below (label, compliances, flags).
|
|
35
|
+
* 3. Add a validation rule set to `COMPLIANCE_VALIDATION_RULES` below.
|
|
36
|
+
* 4. Map affected countries in `EMBEDDED_COMPLIANCE_MAP` to the new group.
|
|
37
|
+
*
|
|
38
|
+
* ADD OR UPDATE A COUNTRY:
|
|
39
|
+
* Edit the entry in `EMBEDDED_COMPLIANCE_MAP.countries` below. That is the ONLY
|
|
40
|
+
* place that needs changing for country-level jurisdiction updates.
|
|
41
|
+
*/
|
|
16
42
|
declare const COMPLIANCE_GROUP_IDS: readonly ["opt-in", "opt-out", "opt-out-strict", "opt-in-dpdpa", "opt-in-china", "opt-in-brazil", "general-privacy-consent", "notice-only"];
|
|
17
43
|
declare const COOKIE_PURPOSE_IDS: readonly ["necessary", "functional", "preferences", "analytics", "marketing"];
|
|
18
44
|
|
|
@@ -44,11 +70,14 @@ interface ComplianceMapData {
|
|
|
44
70
|
}
|
|
45
71
|
interface CountryComplianceEntry {
|
|
46
72
|
complianceGroup: ComplianceGroupId;
|
|
47
|
-
|
|
48
|
-
|
|
73
|
+
/** Fallback group used when only the country (not the region) is known. Defaults to
|
|
74
|
+
* `complianceGroup` when omitted — only set this explicitly when a region within this
|
|
75
|
+
* country can be stricter than the country-wide baseline (see `overriddenRegions`). */
|
|
76
|
+
default?: ComplianceGroupId;
|
|
77
|
+
description?: string;
|
|
49
78
|
overriddenRegions?: Record<string, {
|
|
50
79
|
complianceGroup: ComplianceGroupId;
|
|
51
|
-
description
|
|
80
|
+
description?: string;
|
|
52
81
|
}>;
|
|
53
82
|
}
|
|
54
83
|
interface ConsentDbRecord {
|
|
@@ -63,9 +92,10 @@ interface ConsentDbRecord {
|
|
|
63
92
|
ageVerified?: boolean;
|
|
64
93
|
parentalConsentToken?: string;
|
|
65
94
|
tcfString?: string;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
*
|
|
95
|
+
gppString?: string;
|
|
96
|
+
/** HMAC-SHA256 signature over the record's core fields, hex-encoded — tamper-evidence for
|
|
97
|
+
* server-stored records via `dataSigningHash` (auto-generated when unset), independent of the
|
|
98
|
+
* widget's own cookie-signing (`core.cookieSigningKey`). */
|
|
69
99
|
signature?: string;
|
|
70
100
|
createdAt: string;
|
|
71
101
|
updatedAt: string;
|
|
@@ -76,15 +106,18 @@ type ConsentAction = 'accept_all' | 'reject_all' | 'custom' | 'update';
|
|
|
76
106
|
type ConsentValue = Record<string, ConsentStatus>;
|
|
77
107
|
/**
|
|
78
108
|
* Output format for getConsent(type).
|
|
79
|
-
* 'default' → raw ConsentValue (existing behaviour)
|
|
109
|
+
* 'default' → raw ConsentValue, keyed by every cookie parameter ID in the profile (existing behaviour)
|
|
80
110
|
* 'google-gtm' → Google Consent Mode v2 keys + ads_data_redaction, url_passthrough
|
|
81
|
-
* '
|
|
111
|
+
* 'purpose' → consent per the fixed CookiePurpose taxonomy (necessary/functional/preferences/analytics/marketing)
|
|
112
|
+
* 'category' → consent per the tenant's own authored preference-modal category, keyed by category ID.
|
|
113
|
+
* 'granted' only when every member parameter is granted; 'denied'/'objected' otherwise
|
|
114
|
+
* (same ConsentStatus values as everything else — see getCategoryConsent for the exact rule)
|
|
82
115
|
* 'adobe' → { analytics, target, manager, optimizer }
|
|
83
116
|
* 'meta' → { pixel, api, plugins, facebookLogin }
|
|
84
117
|
* 'microsoft-clarity' → { session, heatmaps, performance }
|
|
85
118
|
* 'twilio-segment' → { identify, page, track, group, alias }
|
|
86
119
|
*/
|
|
87
|
-
type ConsentType = 'default' | 'google-gtm' | 'category' | 'adobe' | 'meta' | 'microsoft-clarity' | 'twilio-segment';
|
|
120
|
+
type ConsentType = 'default' | 'google-gtm' | 'purpose' | 'category' | 'adobe' | 'meta' | 'microsoft-clarity' | 'twilio-segment';
|
|
88
121
|
type GpcMode = 'ignore' | 'honor' | 'strict';
|
|
89
122
|
type LegalBasis = 'mandatory' | 'consent' | 'legitimate_interest';
|
|
90
123
|
type CookiePurpose = typeof COOKIE_PURPOSE_IDS[number];
|
|
@@ -172,12 +205,46 @@ interface PreferenceModal extends Omit<MainBanner, "position"> {
|
|
|
172
205
|
receiptLabel?: string;
|
|
173
206
|
/** Description shown beneath the consent-receipt checkbox. Falls back to a default when omitted. */
|
|
174
207
|
receiptDescription?: string;
|
|
208
|
+
/**
|
|
209
|
+
* Renders a "Forget me" control in the modal body, below the categories — only shown to
|
|
210
|
+
* visitors who already have a stored consent decision (nothing to erase otherwise). Wired to
|
|
211
|
+
* the same `DELETE /consent/:visitorId` erasure endpoint as `widget.deleteConsent()`, giving
|
|
212
|
+
* visitors self-service access to GDPR Art. 17 / CCPA-CPRA / LGPD Art. 18 / UK GDPR / DPDPA /
|
|
213
|
+
* KVKK / POPIA / PDPA-TH / APPI erasure-equivalent rights without the host wiring a link
|
|
214
|
+
* themselves. See the "Right to erasure" guide for the full compliance mapping.
|
|
215
|
+
*/
|
|
216
|
+
showForgetMe?: boolean;
|
|
217
|
+
/** Label for the "Forget me" button (shown when `showForgetMe` is true). Falls back to a default when omitted. */
|
|
218
|
+
forgetMeLabel?: string;
|
|
175
219
|
}
|
|
176
220
|
interface DpdpaConfig {
|
|
177
221
|
dataFiduciary: string;
|
|
178
222
|
grievanceEmail: string;
|
|
179
223
|
purposeDescription?: string;
|
|
180
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Per-profile age gate — GDPR Art. 8's consent age varies 13–16 by EU member state and DPDPA has
|
|
227
|
+
* its own child-data age rules, so one global age (the old `ConsentiServerConfig.ageGate`) was
|
|
228
|
+
* wrong for a multi-region deployment. Mirrors `dpdpa` exactly: profile-scoped, not global.
|
|
229
|
+
*/
|
|
230
|
+
interface AgeGateConfig {
|
|
231
|
+
enabled: boolean;
|
|
232
|
+
minimumAge: number;
|
|
233
|
+
requireParentalConsent?: boolean;
|
|
234
|
+
}
|
|
235
|
+
/** Per-locale age-gate modal text — translated the same way `mainBanner`/`preferenceModal`
|
|
236
|
+
* content is, unlike the widget's own hardcoded UI chrome (close button, locale switcher). */
|
|
237
|
+
interface AgeGateModalContent {
|
|
238
|
+
heading?: string;
|
|
239
|
+
htmlText: string;
|
|
240
|
+
confirmButtonLabel: string;
|
|
241
|
+
denyButtonLabel: string;
|
|
242
|
+
parentalConsent: {
|
|
243
|
+
heading?: string;
|
|
244
|
+
htmlText: string;
|
|
245
|
+
confirmButtonLabel: string;
|
|
246
|
+
};
|
|
247
|
+
}
|
|
181
248
|
interface ResolvedProfile {
|
|
182
249
|
id: string;
|
|
183
250
|
/** Incremented in place on every save of this profile. Absent for embedded/local profiles that have no server-side version counter. */
|
|
@@ -193,9 +260,21 @@ interface ResolvedProfile {
|
|
|
193
260
|
preferenceModal: PreferenceModal;
|
|
194
261
|
cookieSigningKey?: string;
|
|
195
262
|
dpdpa?: DpdpaConfig;
|
|
263
|
+
ageGate?: AgeGateConfig;
|
|
264
|
+
ageGateModal?: AgeGateModalContent;
|
|
196
265
|
darkMode?: boolean;
|
|
197
266
|
gpcMode?: GpcMode;
|
|
198
|
-
|
|
267
|
+
/** One of the 8 built-in groups, or a custom group id (via `customComplianceGroup` /
|
|
268
|
+
* `ComplianceType`'s string passthrough) — this is the join key `complianceGroupsOverride`
|
|
269
|
+
* looks up by, so it must reflect whichever group this profile actually resolved against,
|
|
270
|
+
* built-in or custom. */
|
|
271
|
+
complianceGroup?: ComplianceGroupId | (string & {});
|
|
272
|
+
/** Set when the geo-resolved region carries a `requiresSensitiveOptIn` carve-out (e.g.
|
|
273
|
+
* Colorado under `opt-out`) — cookies tagged `cpraCategory: 'sensitive'` default to denied
|
|
274
|
+
* even though the rest of `complianceGroup`'s cookies default to granted. Only ever set by
|
|
275
|
+
* server-side geo resolution (`api.enabled: true` + a geoip/maxmind provider); the
|
|
276
|
+
* client-only timezone heuristic never resolves a region, so this is always unset there. */
|
|
277
|
+
requiresSensitiveOptIn?: boolean;
|
|
199
278
|
complianceConfig?: Record<string, string>;
|
|
200
279
|
/** Falls back to `true` (hidden) if neither the widget config nor the profile set it. */
|
|
201
280
|
hidePoweredBy?: boolean;
|
|
@@ -208,26 +287,66 @@ type WidgetCountryResolverFn = () => Promise<{
|
|
|
208
287
|
country: string | null;
|
|
209
288
|
region: string | null;
|
|
210
289
|
confidence: number;
|
|
290
|
+
/** Optional escape hatch: when set, profile resolution uses this compliance group directly
|
|
291
|
+
* instead of computing one from `country`/`region` — mirrors the server-side `GeoResult`'s
|
|
292
|
+
* `complianceGroup` field (`@consenti/types`'s `api.ts`). `country`/`region` are still used for
|
|
293
|
+
* anything that reads them independently of group selection. Optional — omitting it preserves
|
|
294
|
+
* the existing timezone/language-based resolution exactly as before. */
|
|
295
|
+
complianceGroup?: string;
|
|
211
296
|
}>;
|
|
212
|
-
interface AgeGateWidgetConfig {
|
|
213
|
-
enabled: boolean;
|
|
214
|
-
minimumAge: number;
|
|
215
|
-
requireParentalConsent?: boolean;
|
|
216
|
-
}
|
|
217
297
|
/** Mirrors the server-side `TcfConfig` shape (`@consenti/api`) — `cmpId`/`cmpVersion` must match
|
|
218
|
-
* what the backend uses to encode `tcfString`, since both feed the same simplified TC string.
|
|
298
|
+
* what the backend uses to encode `tcfString`, since both feed the same simplified TC string.
|
|
299
|
+
*
|
|
300
|
+
* The client-side `__tcfapi` stub never fetches the Global Vendor List itself (multi-megabyte,
|
|
301
|
+
* and IAB policy requires CMPs to cache their own copy rather than have every visitor's browser
|
|
302
|
+
* fetch it) — `publisherCC`/`vendorListVersion`/`gvlVersion` are therefore operator-supplied
|
|
303
|
+
* config here, not auto-derived. Spec-correct binary TC-string encoding happens server-side in
|
|
304
|
+
* `@consenti/api` (see `compliance.tcf.publisherCC` there); this stub's `tcString` stays the
|
|
305
|
+
* simplified format documented in `@consenti/utils`'s `encodeTcString`. */
|
|
219
306
|
interface TcfWidgetConfig {
|
|
220
307
|
enabled: boolean;
|
|
221
308
|
cmpId: number;
|
|
222
309
|
cmpVersion: number;
|
|
310
|
+
/** ISO 3166-1 alpha-2 publisher country code. No honest default exists — leave unset only if
|
|
311
|
+
* you don't rely on this field downstream; ad-tech vendors that read it will see 'AA'
|
|
312
|
+
* (an explicit "not configured" placeholder, not a real country). */
|
|
313
|
+
publisherCC?: string;
|
|
314
|
+
/** Known Global Vendor List version, if you track it. Defaults to 0 ("unknown"). */
|
|
315
|
+
vendorListVersion?: number;
|
|
316
|
+
/** Known GVL specification version, if you track it. Defaults to 0 ("unknown"). */
|
|
317
|
+
gvlVersion?: number;
|
|
318
|
+
}
|
|
319
|
+
/** Mirrors the server-side `GppConfig` shape (`@consenti/api`) — `cmpId`/`cmpVersion` must match
|
|
320
|
+
* what the backend uses to encode `gppString`. Unlike TCF, the GPP US National section needs no
|
|
321
|
+
* Global Vendor List, so both the widget's `window.__gpp` and the server's `gppString` use the
|
|
322
|
+
* same real, spec-correct encoder (the optional `@iabgpp/cmpapi` peer dependency) — there's no
|
|
323
|
+
* "simplified fallback" format the way TCF has, since a non-spec GPP string has no consumer that
|
|
324
|
+
* would accept it. When `@iabgpp/cmpapi` isn't installed, `window.__gpp` is simply not exposed. */
|
|
325
|
+
interface GppWidgetConfig {
|
|
326
|
+
enabled: boolean;
|
|
327
|
+
cmpId: number;
|
|
328
|
+
cmpVersion: number;
|
|
329
|
+
/** MSPA "covered transaction" — whether this deployment's data transactions fall under MSPA
|
|
330
|
+
* signatory obligations. No honest default, so it's required rather than optional. */
|
|
331
|
+
mspaCoveredTransaction: boolean;
|
|
332
|
+
/** IAB's tri-state encoding for both MSPA fields: 0 = not applicable, 1 = yes, 2 = no. */
|
|
333
|
+
mspaOptOutOptionMode: 0 | 1 | 2;
|
|
334
|
+
mspaServiceProviderMode: 0 | 1 | 2;
|
|
223
335
|
}
|
|
224
336
|
interface ComplianceWidgetConfig {
|
|
225
337
|
type?: ComplianceType;
|
|
226
338
|
geoDataProvider?: 'default' | WidgetCountryResolverFn;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
339
|
+
/** Only meaningful in standalone mode (no `api.enabled`) — ignored (with a warning) when
|
|
340
|
+
* `api.enabled: true`, since the server resolves the compliance group in that mode.
|
|
341
|
+
* `'default'` (embedded map, the default), a URL to fetch a JSON `ComplianceMapData`
|
|
342
|
+
* document from (the browser's own HTTP cache honors whatever `Cache-Control`/`ETag` the
|
|
343
|
+
* response sends — no custom caching here), or an inline operator-supplied `ComplianceMapData`
|
|
344
|
+
* object. Invalid data from either a URL or an object logs a warning and falls back to
|
|
345
|
+
* `'default'`. Only overrides the country→group mapping — country/region detection itself
|
|
346
|
+
* always uses the embedded geo data. */
|
|
347
|
+
complianceMap?: 'default' | string | ComplianceMapData;
|
|
230
348
|
tcf?: TcfWidgetConfig;
|
|
349
|
+
gpp?: GppWidgetConfig;
|
|
231
350
|
}
|
|
232
351
|
interface GtmConfig {
|
|
233
352
|
containerId?: string;
|
|
@@ -248,37 +367,67 @@ interface ApiConfig {
|
|
|
248
367
|
complianceGroup?: ComplianceGroupId;
|
|
249
368
|
trustDomain?: boolean;
|
|
250
369
|
}
|
|
370
|
+
/** Field names mirror their `--consenti-*` CSS variable literally (`--consenti-color-primary`
|
|
371
|
+
* → `colorPrimary`) — see `applyTheme()` in `consenti-setup.ts` for the full mapping. */
|
|
251
372
|
interface ThemeConfig {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
373
|
+
colorBg?: string;
|
|
374
|
+
colorText?: string;
|
|
375
|
+
colorTextMuted?: string;
|
|
376
|
+
colorPrimary?: string;
|
|
377
|
+
colorPrimaryText?: string;
|
|
378
|
+
colorSecondary?: string;
|
|
379
|
+
colorSecondaryText?: string;
|
|
380
|
+
colorBorder?: string;
|
|
381
|
+
colorSecondaryBorder?: string;
|
|
382
|
+
colorOverlay?: string;
|
|
383
|
+
colorAccent?: string;
|
|
384
|
+
colorAccentText?: string;
|
|
259
385
|
fontFamily?: string;
|
|
386
|
+
fontFamilyMono?: string;
|
|
260
387
|
fontSizeBase?: string;
|
|
261
388
|
fontSizeHeading?: string;
|
|
262
389
|
fontSizeMultiplier?: string;
|
|
390
|
+
fontWeightHeading?: string;
|
|
391
|
+
lineHeight?: string;
|
|
392
|
+
spacingXs?: string;
|
|
393
|
+
spacingSm?: string;
|
|
394
|
+
spacingMd?: string;
|
|
395
|
+
spacingLg?: string;
|
|
263
396
|
borderRadius?: string;
|
|
264
|
-
|
|
397
|
+
borderRadiusBtn?: string;
|
|
398
|
+
shadow?: string;
|
|
265
399
|
toggleBgOn?: string;
|
|
400
|
+
toggleBgPartial?: string;
|
|
266
401
|
toggleBgOff?: string;
|
|
267
|
-
|
|
268
|
-
|
|
402
|
+
toggleKnob?: string;
|
|
403
|
+
toggleWidth?: string;
|
|
404
|
+
toggleHeight?: string;
|
|
405
|
+
zBanner?: string;
|
|
406
|
+
zOverlay?: string;
|
|
407
|
+
zModal?: string;
|
|
269
408
|
}
|
|
270
409
|
interface CoreConfig {
|
|
271
410
|
tenantId?: string;
|
|
272
411
|
locale?: string;
|
|
273
|
-
/** Text direction for the banner/modal root. `'auto'` (default) derives it from `locale`
|
|
274
|
-
* (
|
|
412
|
+
/** Text direction for the banner/modal root. `'auto'` (default) derives it from `locale` via
|
|
413
|
+
* `Intl.Locale(...).getTextInfo().direction` (falling back to a hand-maintained RTL-language
|
|
414
|
+
* list on engines without `getTextInfo()` support); set explicitly to override. */
|
|
275
415
|
dir?: 'ltr' | 'rtl' | 'auto';
|
|
276
416
|
disableCssTemplate?: boolean;
|
|
277
417
|
cookieSigningKey?: string;
|
|
278
418
|
allowReceipt?: boolean;
|
|
279
419
|
cookieDomains?: string;
|
|
420
|
+
/** Name of the consent cookie/localStorage key. Default: `'consenti_data'`. Not switched
|
|
421
|
+
* automatically by detected region — set explicitly if you want a different name (e.g.
|
|
422
|
+
* `'euconsent-v2'`, the IAB TCF convention, but only meaningful for operators using the
|
|
423
|
+
* spec-correct binary encoder — `@consenti/api` + the optional `@iabtechlabtcf/core` peer
|
|
424
|
+
* dependency — since the IAB name implies IAB's binary format, not Consenti's own encoding). */
|
|
425
|
+
cookieName?: string;
|
|
280
426
|
storage?: 'cookie' | 'localStorage';
|
|
281
427
|
theme?: ThemeConfig;
|
|
428
|
+
/** Initial logged-in application user ID; empty/anonymous when unset. Prefer `getUserId()`/
|
|
429
|
+
* `setUserId()` (or the `consenti:listener:identify` event) to change it after init — those
|
|
430
|
+
* also handle reconsent when the identity changes on a shared device. */
|
|
282
431
|
userId?: string;
|
|
283
432
|
usePrebuiltProfiles?: 'all' | NonEmptyArray<ComplianceGroupId>;
|
|
284
433
|
cacheResolvedProfiles?: boolean;
|
|
@@ -298,10 +447,25 @@ interface ConsentiConfig {
|
|
|
298
447
|
utils?: UtilsConfig;
|
|
299
448
|
plugins?: ConsentiPlugin[];
|
|
300
449
|
profileOverride?: DeepPartial<ResolvedProfile>;
|
|
450
|
+
/** Per-compliance-group text/button/cookie overrides — applied on top of whichever profile the
|
|
451
|
+
* visitor's resolved group loads, keyed by that group's id (one of the 8 built-in
|
|
452
|
+
* `ComplianceGroupId`s, or any custom group id). Lets you author different copy per country
|
|
453
|
+
* without creating a separate profile (and separate `compliance.type` wiring) for each one —
|
|
454
|
+
* e.g. `{ 'opt-in': { mainBanner: { htmlText: '...' } }, 'my-custom-group': { ... } }`.
|
|
455
|
+
* Applied before `profileOverride`, which still always applies last as the universal catch-all.
|
|
456
|
+
* Works identically in standalone and server (`api.enabled`) mode. */
|
|
457
|
+
complianceGroupsOverride?: Partial<Record<ComplianceGroupId | (string & {}), DeepPartial<ResolvedProfile>>>;
|
|
301
458
|
/** When true, suppresses the "Powered by Consenti" footer link in the banner and modal. */
|
|
302
459
|
hidePoweredBy?: boolean;
|
|
303
460
|
}
|
|
304
|
-
type ConsentiEventName = 'bannerInitialized' | 'consenti:bannerInitialized' | 'bannerVisibility' | 'consenti:bannerVisibility' | 'modalVisibility' | 'consenti:modalVisibility' | 'consentBeingSubmitted' | 'consenti:consentBeingSubmitted' | 'consentSubmitted' | 'consenti:consentSubmitted' | 'parentalConsentRequired' | 'consenti:parentalConsentRequired';
|
|
461
|
+
type ConsentiEventName = 'bannerInitialized' | 'consenti:bannerInitialized' | 'bannerVisibility' | 'consenti:bannerVisibility' | 'modalVisibility' | 'consenti:modalVisibility' | 'consentBeingSubmitted' | 'consenti:consentBeingSubmitted' | 'consentSubmitted' | 'consenti:consentSubmitted' | 'parentalConsentRequired' | 'consenti:parentalConsentRequired' | 'forgetMeRequested' | 'consenti:forgetMeRequested' | 'forgotten' | 'consenti:forgotten';
|
|
462
|
+
/** Snapshot of the current visitor's identity. `visitorId` is `null` until a consent decision
|
|
463
|
+
* has actually happened — it's never minted just to answer this call, see `getVisitor()`. */
|
|
464
|
+
interface VisitorIdentity {
|
|
465
|
+
visitorId: string | null;
|
|
466
|
+
type: 'authenticated' | 'anonymous';
|
|
467
|
+
userId: string | null;
|
|
468
|
+
}
|
|
305
469
|
interface ConsentiWidgetAPI {
|
|
306
470
|
hasConsent(): boolean;
|
|
307
471
|
getConsent(): ConsentValue | null;
|
|
@@ -332,10 +496,25 @@ interface ConsentiWidgetAPI {
|
|
|
332
496
|
submitConsent(consent: Partial<ConsentValue>): Promise<ConsentDbRecord | void>;
|
|
333
497
|
deleteConsent(): Promise<void>;
|
|
334
498
|
reConsent(): Promise<void>;
|
|
499
|
+
/** Erases the stored consent record (same underlying call as `deleteConsent()`) and
|
|
500
|
+
* re-prompts, dispatching `consenti:forgetMeRequested` / `consenti:forgotten` around it so a
|
|
501
|
+
* host app can hook its own identity-verified erasure workflow. Powers the preference modal's
|
|
502
|
+
* "Forget me" button; also callable directly for a custom placement of the same action. */
|
|
503
|
+
forgetMe(resetAgeGate?: boolean): Promise<void>;
|
|
335
504
|
getRootElement(): HTMLElement | null;
|
|
336
505
|
getBannerElement(): HTMLElement | null;
|
|
337
506
|
getModalElement(): HTMLElement | null;
|
|
338
507
|
switchLocale(locale: string): void;
|
|
508
|
+
getUserId(): string | null;
|
|
509
|
+
/** Sets the logged-in application user ID (`null` for anonymous/logout). When the stored
|
|
510
|
+
* consent record's user differs from the new value, reconsents by default — pass
|
|
511
|
+
* `reConsent: false` to just update the identity without prompting again. No-ops (no
|
|
512
|
+
* reconsent, no warning) when there's no prior consent record to compare against. */
|
|
513
|
+
setUserId(userId: string | null, reConsent?: boolean): Promise<void>;
|
|
514
|
+
/** Snapshot of the current visitor's identity: the stable per-browser `visitorId` (`null` if
|
|
515
|
+
* no consent decision has happened yet — this never creates one), whether they're
|
|
516
|
+
* `authenticated` or `anonymous`, and the app `userId` (same as `getUserId()`). */
|
|
517
|
+
getVisitor(): VisitorIdentity;
|
|
339
518
|
setDarkMode(enable?: boolean): void;
|
|
340
519
|
setTheme(theme: Partial<ThemeConfig>): void;
|
|
341
520
|
setConfig(config: DeepPartial<ConsentiConfig>): void;
|
|
@@ -383,17 +562,45 @@ interface ConsentBeingSubmitted {
|
|
|
383
562
|
interface ConsentSubmittedDetail extends ConsentBeingSubmitted {
|
|
384
563
|
apiResponse: ConsentDbRecord;
|
|
385
564
|
}
|
|
386
|
-
/** Dispatched when the age gate is declined and `requireParentalConsent` is set — see
|
|
387
|
-
* `
|
|
565
|
+
/** Dispatched when the age gate is declined and `requireParentalConsent` is set — see the
|
|
566
|
+
* profile's `AgeGateConfig`. A deny-all consent (mandatory cookies only) has already been
|
|
388
567
|
* submitted with `parentalConsentToken` attached; this event is the hook for the site
|
|
389
|
-
* owner to run their own out-of-band parental-consent verification.
|
|
568
|
+
* owner to run their own out-of-band parental-consent verification. `parentalConsentToken` is
|
|
569
|
+
* server-issued (and signed, when `compliance.dataSigningHash` is configured) when `api.enabled`,
|
|
570
|
+
* otherwise a client-generated, unsigned fallback — see `POST /consent/:visitorId/parental-consent-request`. */
|
|
390
571
|
interface ParentalConsentRequiredDetail {
|
|
391
572
|
parentalConsentToken: string;
|
|
392
573
|
profileId: string;
|
|
393
574
|
visitorId: string;
|
|
394
575
|
timestamp: number;
|
|
395
576
|
}
|
|
396
|
-
|
|
577
|
+
/** Dispatched by the standalone `resolveParentalConsent()` util (`apps/ui/src/utils/parental-consent.ts`)
|
|
578
|
+
* after `POST /consent/parental-consent-resolve` succeeds — typically from a fresh page/session
|
|
579
|
+
* with no live `ConsentiSetup` instance (the parent's own device, not the child's). A page that
|
|
580
|
+
* does have a live widget instance can listen for this to react (e.g. re-show the banner/modal for
|
|
581
|
+
* the real consent choice); what "resolved" should actually do to consent state is host-defined. */
|
|
582
|
+
interface ParentalConsentGrantedDetail {
|
|
583
|
+
visitorId: string;
|
|
584
|
+
profileId: string;
|
|
585
|
+
}
|
|
586
|
+
/** Dispatched by `forgetMe()` right before the erasure call goes out — the hook for a host app
|
|
587
|
+
* to kick off its own identity-verified erasure workflow across other systems (CRM, DMP,
|
|
588
|
+
* analytics). The CMP itself only ever erases its own consent record; see the server-side
|
|
589
|
+
* `consent.erased` eventBus event (fired by `DELETE /consent/:visitorId`) for the same hook on
|
|
590
|
+
* the backend. See the "Right to erasure" guide for the full picture. */
|
|
591
|
+
interface ForgetMeRequestedDetail {
|
|
592
|
+
visitorId: string;
|
|
593
|
+
profileId: string;
|
|
594
|
+
timestamp: number;
|
|
595
|
+
}
|
|
596
|
+
/** Dispatched by `forgetMe()` after the consent record has been erased and the banner/age-gate
|
|
597
|
+
* has been re-prompted (see `reConsent()`, which `forgetMe()` wraps). */
|
|
598
|
+
interface ForgottenDetail {
|
|
599
|
+
visitorId: string;
|
|
600
|
+
profileId: string;
|
|
601
|
+
timestamp: number;
|
|
602
|
+
}
|
|
603
|
+
type ConsentEvent = BannerInitializedDetail | BannerVisibilityDetail | ModalVisibilityDetail | ConsentBeingSubmitted | ConsentSubmittedDetail | ParentalConsentRequiredDetail | ParentalConsentGrantedDetail | ForgetMeRequestedDetail | ForgottenDetail;
|
|
397
604
|
|
|
398
605
|
/**
|
|
399
606
|
* Main entry point for the Consenti widget.
|
|
@@ -417,6 +624,7 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
417
624
|
private initializing;
|
|
418
625
|
private profile;
|
|
419
626
|
private resolvedBase;
|
|
627
|
+
private profilePatches;
|
|
420
628
|
/** cookieId → Category lookup, rebuilt whenever `profile` changes. Avoids rescanning categories on every consent action. */
|
|
421
629
|
private categoryIndex;
|
|
422
630
|
/** Watchers created by the declarative `data-consenti-*` DOM scan — destroyed alongside the widget since they have no other owner. */
|
|
@@ -449,6 +657,8 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
449
657
|
private _bannerMounted;
|
|
450
658
|
/** Active focus trap keydown listener — removed when modal closes. */
|
|
451
659
|
private _focusTrapListener;
|
|
660
|
+
/** Inbound `consenti:listener:identify` window listener — installed once per init(), removed on destroy(). */
|
|
661
|
+
private _identifyListener;
|
|
452
662
|
/** Maps original handler functions to their DOM-wrapped listeners for on/off bookkeeping. */
|
|
453
663
|
private _eventHandlers;
|
|
454
664
|
/** `core` defaulted to `{}` in the constructor below — every one of its own fields is
|
|
@@ -465,6 +675,29 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
465
675
|
*/
|
|
466
676
|
constructor(config: ConsentiConfig);
|
|
467
677
|
private profileId;
|
|
678
|
+
/** Patches `base` with `complianceGroupsOverride[base.complianceGroup]`, if both exist — the
|
|
679
|
+
* per-group counterpart to `profileOverride`. Lets an author supply different text/buttons/
|
|
680
|
+
* cookies per compliance group (built-in or custom) without authoring a separate profile for
|
|
681
|
+
* each one. Applied before `profileOverride`, which still always wins as the final catch-all. */
|
|
682
|
+
private applyComplianceGroupOverride;
|
|
683
|
+
/**
|
|
684
|
+
* Applied in order: compliance-group override → `config.profileOverride` → each `setProfile()`
|
|
685
|
+
* patch. The `setProfile()` patches are kept as a list and replayed, not folded into one
|
|
686
|
+
* object, because folding runs `deepMerge` patch-onto-patch, which consumes `null`/`'*': null`
|
|
687
|
+
* delete markers before they ever reach the profile they were meant to delete from.
|
|
688
|
+
*/
|
|
689
|
+
private applyProfileOverrides;
|
|
690
|
+
private warnIfAcceptOnly;
|
|
691
|
+
/**
|
|
692
|
+
* Whether `window.__tcfapi`/`window.__gpp` should stay uninstalled because the corresponding
|
|
693
|
+
* server-side registration (`compliance.tcf`/`compliance.gpp`) is unconfirmed (cmpId/cmpVersion
|
|
694
|
+
* changed since the dashboard's confirmation checkbox was last checked, or never confirmed).
|
|
695
|
+
* Standalone (no-backend) deployments have no governance layer to check against, so this always
|
|
696
|
+
* resolves `false` there — the client-side config is used as configured, same as before this
|
|
697
|
+
* feature existed. A network failure fails closed (`true`) rather than assuming the
|
|
698
|
+
* unverifiable state is fine.
|
|
699
|
+
*/
|
|
700
|
+
private isRegistrationBlocked;
|
|
468
701
|
/**
|
|
469
702
|
* Starts widget initialisation. Called automatically unless `autoInit: false` is set.
|
|
470
703
|
* Can be called explicitly after construction when `autoInit: false`, or after `destroy()`
|
|
@@ -478,7 +711,7 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
478
711
|
* `resolveAgeGate()`, then resume here with `hasExisting` fixed at `false`.
|
|
479
712
|
*/
|
|
480
713
|
private continueInit;
|
|
481
|
-
/** Mounts the age-gate prompt (`
|
|
714
|
+
/** Mounts the age-gate prompt (`profile.ageGate`) in place of the normal banner flow. */
|
|
482
715
|
private showAgeGate;
|
|
483
716
|
/**
|
|
484
717
|
* Handles the visitor's age-gate answer.
|
|
@@ -501,13 +734,35 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
501
734
|
* a resolved profile to read consent from.
|
|
502
735
|
*/
|
|
503
736
|
private finishInit;
|
|
737
|
+
/** Installs the inbound `consenti:listener:identify` window listener — the event-driven
|
|
738
|
+
* counterpart to `setUserId()`. Removes any previously-installed listener first so repeated
|
|
739
|
+
* `init()` calls (e.g. from `switchLocale()`) don't stack up duplicate listeners. */
|
|
740
|
+
private _installIdentifyListener;
|
|
741
|
+
/** Returns the current logged-in application user ID, or `null` for an anonymous visitor. */
|
|
742
|
+
getUserId(): string | null;
|
|
743
|
+
/**
|
|
744
|
+
* Sets the logged-in application user ID (`null` for anonymous/logout). If a stored consent
|
|
745
|
+
* record exists and its user differs from `userId`, this is treated as a different data
|
|
746
|
+
* subject on a shared device: by default it reconsents (deletes the existing record and
|
|
747
|
+
* re-shows the banner) and logs a warning. Pass `reConsent: false` to just update the identity
|
|
748
|
+
* without prompting again (still logs the warning). No-ops entirely — no warning, no
|
|
749
|
+
* reconsent — when there is no prior consent record to compare against (true first-time visitor).
|
|
750
|
+
*/
|
|
751
|
+
setUserId(userId: string | null, reConsent?: boolean): Promise<void>;
|
|
752
|
+
/**
|
|
753
|
+
* Snapshot of the current visitor's identity. `visitorId` is the stable per-browser ID —
|
|
754
|
+
* `null` until a consent decision has actually happened, since this never mints one just to
|
|
755
|
+
* answer the call (see `getOrCreateVisitorId()`). `type` is `'authenticated'` whenever a
|
|
756
|
+
* `userId` is set (via `setUserId()` or `core.userId`), `'anonymous'` otherwise.
|
|
757
|
+
*/
|
|
758
|
+
getVisitor(): VisitorIdentity;
|
|
504
759
|
/** Sets the `dir` attribute on the root element from `core.dir` (default `'auto'`, derived from `core.locale`). */
|
|
505
760
|
private applyDirection;
|
|
506
761
|
/** Applies the `consenti-root--dark` class based on config or profile flag. */
|
|
507
762
|
private applyDarkMode;
|
|
508
763
|
/** Applies `consenti--enhanced-a11y` class when `profile.enhanceAccessibility` is set. */
|
|
509
764
|
private applyAccessibility;
|
|
510
|
-
/** Builds and appends the metadata footer strip to
|
|
765
|
+
/** Builds and appends the metadata footer strip to modal container. */
|
|
511
766
|
private _appendMetaFooter;
|
|
512
767
|
/**
|
|
513
768
|
* Injects a `<style>` element into the root for `stackButtonsOnBreakpoint`.
|
|
@@ -551,8 +806,16 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
551
806
|
* Pass `type` to get a vendor-ready object instead of the raw Consenti format.
|
|
552
807
|
* Always returns `null` during SSR or when no consent has been saved.
|
|
553
808
|
*
|
|
554
|
-
* @param type -
|
|
555
|
-
*
|
|
809
|
+
* @param type - Output format:
|
|
810
|
+
* - omit / `'default'` → raw ConsentValue, keyed by every cookie parameter ID in the profile
|
|
811
|
+
* - `'purpose'` → consent per the fixed CookiePurpose taxonomy (necessary/functional/preferences/analytics/marketing)
|
|
812
|
+
* - `'category'` → consent per the tenant's own authored preference-modal category, keyed by category ID
|
|
813
|
+
* ('granted' only when every member parameter is granted; 'denied'/'objected' otherwise)
|
|
814
|
+
* - `'google-gtm'` → Google Consent Mode v2 keys + ads_data_redaction, url_passthrough
|
|
815
|
+
* - `'adobe'` → { analytics, target, manager, optimizer }
|
|
816
|
+
* - `'meta'` → { pixel, api, plugins, facebookLogin }
|
|
817
|
+
* - `'microsoft-clarity'` → { session, heatmaps, performance }
|
|
818
|
+
* - `'twilio-segment'` → { identify, page, track, group, alias }
|
|
556
819
|
*/
|
|
557
820
|
getConsent(): ConsentValue | null;
|
|
558
821
|
getConsent(type: ConsentType): Record<string, string> | null;
|
|
@@ -644,8 +907,30 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
644
907
|
* method so callers do not need to coordinate the async deletion with the banner display.
|
|
645
908
|
*
|
|
646
909
|
* Use this to power "Review my consent" links in footers or privacy dashboards.
|
|
910
|
+
*
|
|
911
|
+
* @param resetAgeGate - When `true` (default) and the profile has `ageGate.enabled`, the
|
|
912
|
+
* age-gate prompt is shown again instead of jumping straight to the
|
|
913
|
+
* banner — mirroring the original first-visit flow. Pass `false` to
|
|
914
|
+
* skip it and go straight to the banner, keeping the visitor's prior
|
|
915
|
+
* age-gate answer.
|
|
647
916
|
*/
|
|
648
|
-
reConsent(): Promise<void>;
|
|
917
|
+
reConsent(resetAgeGate?: boolean): Promise<void>;
|
|
918
|
+
/**
|
|
919
|
+
* Self-service erasure entry point — GDPR Art. 17 / CCPA-CPRA / LGPD Art. 18 and equivalent
|
|
920
|
+
* "right to be forgotten" rights, exercised from the widget itself. Wraps `reConsent()` (same
|
|
921
|
+
* erase-then-reprompt behavior) with `consenti:forgetMeRequested` / `consenti:forgotten`
|
|
922
|
+
* dispatched around it, so a host app can hook its own identity-verified erasure workflow
|
|
923
|
+
* across other systems (CRM, DMP, analytics) — the CMP itself only ever erases its own consent
|
|
924
|
+
* record. See the "Right to erasure" guide for the full picture, including the server-side
|
|
925
|
+
* `consent:erased` eventBus event fired by `DELETE /consent/:visitorId`.
|
|
926
|
+
*
|
|
927
|
+
* Powers the preference modal's "Forget me" button (`preferenceModal.showForgetMe`, only
|
|
928
|
+
* rendered when the visitor already has a stored consent decision). Also callable directly —
|
|
929
|
+
* e.g. `widget.forgetMe()` from a custom footer link or privacy-settings page.
|
|
930
|
+
*
|
|
931
|
+
* @param resetAgeGate - Forwarded to `reConsent()` — see its docs.
|
|
932
|
+
*/
|
|
933
|
+
forgetMe(resetAgeGate?: boolean): Promise<void>;
|
|
649
934
|
/**
|
|
650
935
|
* Returns the fully resolved profile for the current session, or `null` during the
|
|
651
936
|
* async init phase (before the profile has been fetched/resolved).
|
|
@@ -824,14 +1109,21 @@ declare function useConsent(): {
|
|
|
824
1109
|
denyAll: (includingMandatory?: boolean) => Promise<void>;
|
|
825
1110
|
/** Saves the given partial consent map. */
|
|
826
1111
|
submitConsent: (c: Partial<ConsentValue>) => Promise<void | ConsentDbRecord>;
|
|
827
|
-
/** Deletes the current consent record and re-shows the banner.
|
|
828
|
-
|
|
1112
|
+
/** Deletes the current consent record and re-shows the banner. Pass `false` to skip
|
|
1113
|
+
* re-showing the age-gate prompt (if the profile has one) and go straight to the banner. */
|
|
1114
|
+
reConsent: (resetAgeGate?: boolean) => Promise<void>;
|
|
829
1115
|
/** Returns `true` if the given cookie ID is `'granted'`. */
|
|
830
1116
|
isCookieGranted: (id: string) => boolean;
|
|
831
1117
|
/** Returns `true` if every cookie in the given category is `'granted'`. */
|
|
832
1118
|
isCategoryGranted: (id: string) => boolean;
|
|
833
1119
|
/** Switches the active locale and re-renders the banner and modal. */
|
|
834
1120
|
switchLocale: (locale: string) => void | undefined;
|
|
1121
|
+
/** Returns the current logged-in application user ID, or `null` if anonymous. */
|
|
1122
|
+
getUserId: () => string | null;
|
|
1123
|
+
/** Sets the logged-in application user ID; reconsents by default when it changes. */
|
|
1124
|
+
setUserId: (userId: string | null, reConsent?: boolean) => Promise<void>;
|
|
1125
|
+
/** Snapshot of the current visitor's identity (`visitorId`, `type`, `userId`). */
|
|
1126
|
+
getVisitor: () => VisitorIdentity;
|
|
835
1127
|
};
|
|
836
1128
|
|
|
837
1129
|
export { setConsentiWidget, useConsent };
|
package/dist/vue.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var r=Object.defineProperty;var
|
|
1
|
+
"use strict";var r=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var w=(t,o)=>{for(var l in o)r(t,l,{get:o[l],enumerable:!0})},v=(t,o,l,a)=>{if(o&&typeof o=="object"||typeof o=="function")for(let i of b(o))!C.call(t,i)&&i!==l&&r(t,i,{get:()=>o[i],enumerable:!(a=m(o,i))||a.enumerable});return t};var g=t=>v(r({},"__esModule",{value:!0}),t);var V={};w(V,{setConsentiWidget:()=>y,useConsent:()=>p});module.exports=g(V);var s=require("vue"),e=null;function y(t){e=t}function p(){let t=(0,s.ref)(e?.hasConsent()??!1),o=(0,s.ref)(e?.getConsent()??null),l=(0,s.ref)(e?.getConsentDate()??!1),a=(0,s.ref)(!1),i=(0,s.ref)(!1),d=()=>{t.value=e?.hasConsent()??!1,o.value=e?.getConsent()??null,l.value=e?.getConsentDate()??!1},u=()=>{a.value=e?.bannerVisibility()??!1},c=()=>{i.value=e?.modalVisibility()??!1};return(0,s.onMounted)(()=>{typeof window>"u"||(window.addEventListener("consenti:consentSubmitted",d),window.addEventListener("consenti:bannerVisibility",u),window.addEventListener("consenti:modalVisibility",c))}),(0,s.onUnmounted)(()=>{typeof window>"u"||(window.removeEventListener("consenti:consentSubmitted",d),window.removeEventListener("consenti:bannerVisibility",u),window.removeEventListener("consenti:modalVisibility",c))}),{hasConsent:t,consent:o,consentDate:l,bannerVisible:a,modalVisible:i,showBanner:n=>e?.showBanner(n),hideBanner:()=>e?.hideBanner(),showModal:()=>e?.showModal(),hideModal:()=>e?.hideModal(),grantAll:n=>e?.grantAll(n)??Promise.resolve(),denyAll:n=>e?.denyAll(n)??Promise.resolve(),submitConsent:n=>e?.submitConsent(n)??Promise.resolve(),reConsent:n=>e?.reConsent(n)??Promise.resolve(),isCookieGranted:n=>e?.isCookieGranted(n)??!1,isCategoryGranted:n=>e?.isCategoryGranted(n)??!1,switchLocale:n=>e?.switchLocale(n),getUserId:()=>e?.getUserId()??null,setUserId:(n,f)=>e?.setUserId(n,f)??Promise.resolve(),getVisitor:()=>e?.getVisitor()??{visitorId:null,type:"anonymous",userId:null}}}
|
|
2
2
|
//# sourceMappingURL=vue.js.map
|
package/dist/vue.js.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({\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":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,uBAAAE,EAAA,eAAAC,IAAA,eAAAC,EAAAJ,GA+BA,IAAAK,EAA4C,eASxCC,EAAgC,KAQ7B,SAASJ,EAAkBK,EAA6B,CAC7DD,EAAUC,CACZ,CAeO,SAASJ,GAAa,CAC3B,IAAMK,KAAe,OAAaF,GAAS,WAAW,GAAK,EAAK,EAC1DG,KAAe,OAAyBH,GAAS,WAAW,GAAK,IAAI,EACrEI,KAAe,OAAkBJ,GAAS,eAAe,GAAK,EAAK,EACnEK,KAAgB,OAA4B,EAAK,EACjDC,KAAgB,OAA0B,EAAK,EAE/CC,EAAY,IAAM,CACtBL,EAAW,MAASF,GAAS,WAAW,GAAK,GAC7CG,EAAQ,MAAYH,GAAS,WAAW,GAAK,KAC7CI,EAAY,MAAQJ,GAAS,eAAe,GAAK,EACnD,EACMQ,EAAW,IAAM,CAAEH,EAAc,MAAQL,GAAS,iBAAiB,GAAK,EAAM,EAC9ES,EAAW,IAAM,CAAEH,EAAa,MAASN,GAAS,gBAAgB,GAAK,EAAM,EAEnF,sBAAU,IAAM,CACV,OAAO,OAAW,MACtB,OAAO,iBAAiB,4BAA6BO,CAAS,EAC9D,OAAO,iBAAiB,4BAA8BC,CAAQ,EAC9D,OAAO,iBAAiB,2BAA8BC,CAAO,EAC/D,CAAC,KAED,eAAY,IAAM,CACZ,OAAO,OAAW,MACtB,OAAO,oBAAoB,4BAA6BF,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,GAAkBV,GAAS,WAAWU,CAAG,EAEtD,WAAY,IAAMV,GAAS,WAAW,EAEtC,UAAW,IAAMA,GAAS,UAAU,EAEpC,UAAW,IAAMA,GAAS,UAAU,EAGpC,SAAWW,GAA4BX,GAAS,SAASW,CAAa,GAAK,QAAQ,QAAQ,EAE3F,QAAUC,GAAiCZ,GAAS,QAAQY,CAAkB,GAAK,QAAQ,QAAQ,EAEnG,cAAgBC,GAA6Bb,GAAS,cAAca,CAAC,GAAK,QAAQ,QAAQ,
|
|
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, VisitorIdentity } 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. Pass `false` to skip\n * re-showing the age-gate prompt (if the profile has one) and go straight to the banner. */\n reConsent: (resetAgeGate?: boolean) => _widget?.reConsent(resetAgeGate) ?? 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 /** Returns the current logged-in application user ID, or `null` if anonymous. */\n getUserId: () => _widget?.getUserId() ?? null,\n /** Sets the logged-in application user ID; reconsents by default when it changes. */\n setUserId: (userId: string | null, reConsent?: boolean) => _widget?.setUserId(userId, reConsent) ?? Promise.resolve(),\n /** Snapshot of the current visitor's identity (`visitorId`, `type`, `userId`). */\n getVisitor: () => _widget?.getVisitor() ?? ({ visitorId: null, type: 'anonymous', userId: null } as VisitorIdentity),\n }\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,uBAAAE,EAAA,eAAAC,IAAA,eAAAC,EAAAJ,GA+BA,IAAAK,EAA4C,eASxCC,EAAgC,KAQ7B,SAASJ,EAAkBK,EAA6B,CAC7DD,EAAUC,CACZ,CAeO,SAASJ,GAAa,CAC3B,IAAMK,KAAe,OAAaF,GAAS,WAAW,GAAK,EAAK,EAC1DG,KAAe,OAAyBH,GAAS,WAAW,GAAK,IAAI,EACrEI,KAAe,OAAkBJ,GAAS,eAAe,GAAK,EAAK,EACnEK,KAAgB,OAA4B,EAAK,EACjDC,KAAgB,OAA0B,EAAK,EAE/CC,EAAY,IAAM,CACtBL,EAAW,MAASF,GAAS,WAAW,GAAK,GAC7CG,EAAQ,MAAYH,GAAS,WAAW,GAAK,KAC7CI,EAAY,MAAQJ,GAAS,eAAe,GAAK,EACnD,EACMQ,EAAW,IAAM,CAAEH,EAAc,MAAQL,GAAS,iBAAiB,GAAK,EAAM,EAC9ES,EAAW,IAAM,CAAEH,EAAa,MAASN,GAAS,gBAAgB,GAAK,EAAM,EAEnF,sBAAU,IAAM,CACV,OAAO,OAAW,MACtB,OAAO,iBAAiB,4BAA6BO,CAAS,EAC9D,OAAO,iBAAiB,4BAA8BC,CAAQ,EAC9D,OAAO,iBAAiB,2BAA8BC,CAAO,EAC/D,CAAC,KAED,eAAY,IAAM,CACZ,OAAO,OAAW,MACtB,OAAO,oBAAoB,4BAA6BF,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,GAAkBV,GAAS,WAAWU,CAAG,EAEtD,WAAY,IAAMV,GAAS,WAAW,EAEtC,UAAW,IAAMA,GAAS,UAAU,EAEpC,UAAW,IAAMA,GAAS,UAAU,EAGpC,SAAWW,GAA4BX,GAAS,SAASW,CAAa,GAAK,QAAQ,QAAQ,EAE3F,QAAUC,GAAiCZ,GAAS,QAAQY,CAAkB,GAAK,QAAQ,QAAQ,EAEnG,cAAgBC,GAA6Bb,GAAS,cAAca,CAAC,GAAK,QAAQ,QAAQ,EAG1F,UAAYC,GAA2Bd,GAAS,UAAUc,CAAY,GAAK,QAAQ,QAAQ,EAG3F,gBAAkBC,GAAgBf,GAAS,gBAAgBe,CAAE,GAAK,GAElE,kBAAoBA,GAAgBf,GAAS,kBAAkBe,CAAE,GAAK,GAEtE,aAAeC,GAAmBhB,GAAS,aAAagB,CAAM,EAE9D,UAAW,IAAMhB,GAAS,UAAU,GAAK,KAEzC,UAAW,CAACiB,EAAuBC,IAAwBlB,GAAS,UAAUiB,EAAQC,CAAS,GAAK,QAAQ,QAAQ,EAEpH,WAAY,IAAMlB,GAAS,WAAW,GAAM,CAAE,UAAW,KAAM,KAAM,YAAa,OAAQ,IAAK,CACjG,CACF","names":["vue_exports","__export","setConsentiWidget","useConsent","__toCommonJS","import_vue","_widget","widget","hasConsent","consent","consentDate","bannerVisible","modalVisible","onConsent","onBanner","onModal","gpc","onlyMandatory","includingMandatory","c","resetAgeGate","id","locale","userId","reConsent"]}
|