@consenti/ui 0.2.0 → 0.4.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 +512 -138
- package/dist/angular.d.cts +610 -151
- package/dist/angular.d.ts +610 -151
- 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-3EXCD24H.mjs +2 -0
- package/dist/{chunk-K2UN3O67.mjs.map → chunk-3EXCD24H.mjs.map} +1 -1
- package/dist/chunk-RDE7CM6T.mjs +2 -0
- package/dist/chunk-RDE7CM6T.mjs.map +1 -0
- package/dist/http-AQVVUCX6.mjs +2 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +971 -125
- 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/profiles-5ZLWWN2L.mjs.map +1 -0
- package/dist/react.d.cts +589 -129
- package/dist/react.d.ts +589 -129
- 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 +562 -79
- package/dist/vue.d.ts +562 -79
- 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 +13 -8
- package/dist/chunk-K2UN3O67.mjs +0 -2
- package/dist/http-UU2NIW6M.mjs +0 -2
- /package/dist/{http-UU2NIW6M.mjs.map → http-AQVVUCX6.mjs.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,44 @@
|
|
|
1
1
|
type NonEmptyArray<T> = [T, ...T[]];
|
|
2
|
+
/**
|
|
3
|
+
* Deep-partial with JSON Merge Patch (RFC 7396) delete semantics: any key may be
|
|
4
|
+
* set to `null` instead of its usual type to signal "delete this key" when the
|
|
5
|
+
* partial is applied with `deepMerge()` — `undefined`/omitted keeps the base
|
|
6
|
+
* value, `null` removes it. Only meaningful for object/map keys (e.g. removing
|
|
7
|
+
* a `CategoryMap`/`CookieMap` entry via `profileOverride`); array elements are
|
|
8
|
+
* merged positionally and don't support deletion this way.
|
|
9
|
+
*/
|
|
2
10
|
type DeepPartial<T> = T extends Function ? T : T extends Array<infer InferredArrayType> ? Array<DeepPartial<InferredArrayType>> : T extends ReadonlyArray<infer InferredReadonlyArrayType> ? ReadonlyArray<DeepPartial<InferredReadonlyArrayType>> : T extends object ? {
|
|
3
|
-
[Key in keyof T]?: DeepPartial<T[Key]
|
|
11
|
+
[Key in keyof T]?: DeepPartial<T[Key]> | null;
|
|
4
12
|
} : T;
|
|
5
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Single source of truth for all compliance groups, regulations, and country mappings.
|
|
16
|
+
*
|
|
17
|
+
* This is DATA, not types. The `Compliance` and `ComplianceGroupId` literal types
|
|
18
|
+
* derived from the ID arrays below live in @consenti/types (packages/types/src/compliance.ts),
|
|
19
|
+
* via a type-only import — that keeps @consenti/types free of runtime code.
|
|
20
|
+
*
|
|
21
|
+
* ─── HOW TO UPDATE ────────────────────────────────────────────────────────────
|
|
22
|
+
*
|
|
23
|
+
* ADD A NEW REGULATION:
|
|
24
|
+
* 1. Add regulation ID string to `COMPLIANCE_REGULATION_IDS` below
|
|
25
|
+
* (the `Compliance` type in @consenti/types auto-updates from it).
|
|
26
|
+
* 2. Add it to the appropriate group's `compliances` array below.
|
|
27
|
+
* 3. Add / update the country entry in `EMBEDDED_COMPLIANCE_MAP` below.
|
|
28
|
+
* That is all — no other files need touching.
|
|
29
|
+
*
|
|
30
|
+
* ADD A NEW COMPLIANCE GROUP:
|
|
31
|
+
* 1. Add the kebab-case ID to `COMPLIANCE_GROUP_IDS` below.
|
|
32
|
+
* 2. Add a full group entry to `COMPLIANCE_GROUPS` below (label, compliances, flags).
|
|
33
|
+
* 3. Add a validation rule set to `COMPLIANCE_VALIDATION_RULES` below.
|
|
34
|
+
* 4. Map affected countries in `EMBEDDED_COMPLIANCE_MAP` to the new group.
|
|
35
|
+
*
|
|
36
|
+
* ADD OR UPDATE A COUNTRY:
|
|
37
|
+
* Edit the entry in `EMBEDDED_COMPLIANCE_MAP.countries` below. That is the ONLY
|
|
38
|
+
* place that needs changing for country-level jurisdiction updates.
|
|
39
|
+
*/
|
|
6
40
|
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"];
|
|
41
|
+
declare const COOKIE_PURPOSE_IDS: readonly ["necessary", "functional", "preferences", "analytics", "marketing"];
|
|
7
42
|
|
|
8
43
|
/**
|
|
9
44
|
* Compliance-related literal types, derived from the regulation/group ID data
|
|
@@ -19,6 +54,13 @@ declare const COMPLIANCE_GROUP_IDS: readonly ["opt-in", "opt-out", "opt-out-stri
|
|
|
19
54
|
*/
|
|
20
55
|
|
|
21
56
|
type ComplianceGroupId = typeof COMPLIANCE_GROUP_IDS[number];
|
|
57
|
+
/**
|
|
58
|
+
* `(string & {})` (rather than plain `string`) keeps IDE autocomplete for the
|
|
59
|
+
* known `ComplianceGroupId` literals while still allowing any other string —
|
|
60
|
+
* used to target a profile authored against a custom (non-built-in)
|
|
61
|
+
* `customComplianceGroup` instead of one of the 8 built-in groups.
|
|
62
|
+
*/
|
|
63
|
+
type ComplianceType = 'auto' | ComplianceGroupId | (string & {}) | Symbol;
|
|
22
64
|
|
|
23
65
|
interface ComplianceMapData {
|
|
24
66
|
version: string;
|
|
@@ -26,31 +68,81 @@ interface ComplianceMapData {
|
|
|
26
68
|
}
|
|
27
69
|
interface CountryComplianceEntry {
|
|
28
70
|
complianceGroup: ComplianceGroupId;
|
|
29
|
-
|
|
30
|
-
|
|
71
|
+
/** Fallback group used when only the country (not the region) is known. Defaults to
|
|
72
|
+
* `complianceGroup` when omitted — only set this explicitly when a region within this
|
|
73
|
+
* country can be stricter than the country-wide baseline (see `overriddenRegions`). */
|
|
74
|
+
default?: ComplianceGroupId;
|
|
75
|
+
description?: string;
|
|
31
76
|
overriddenRegions?: Record<string, {
|
|
32
77
|
complianceGroup: ComplianceGroupId;
|
|
33
|
-
description
|
|
78
|
+
description?: string;
|
|
34
79
|
}>;
|
|
35
80
|
}
|
|
81
|
+
interface ConsentDbRecord {
|
|
82
|
+
id: string;
|
|
83
|
+
tenantId: string;
|
|
84
|
+
visitorId: string;
|
|
85
|
+
profileId: string;
|
|
86
|
+
locale: string;
|
|
87
|
+
consentJson: ConsentValue;
|
|
88
|
+
gpcDetected: boolean;
|
|
89
|
+
source: 'banner' | 'api' | 'import';
|
|
90
|
+
ageVerified?: boolean;
|
|
91
|
+
parentalConsentToken?: string;
|
|
92
|
+
tcfString?: string;
|
|
93
|
+
gppString?: string;
|
|
94
|
+
/** HMAC-SHA256 signature over the record's core fields, hex-encoded — tamper-evidence for
|
|
95
|
+
* server-stored records via `dataSigningHash` (auto-generated when unset), independent of the
|
|
96
|
+
* widget's own cookie-signing (`core.cookieSigningKey`). */
|
|
97
|
+
signature?: string;
|
|
98
|
+
createdAt: string;
|
|
99
|
+
updatedAt: string;
|
|
100
|
+
}
|
|
36
101
|
|
|
37
102
|
type ConsentStatus = 'granted' | 'denied' | 'objected';
|
|
38
|
-
type ConsentAction = 'accept_all' | 'reject_all' | 'custom' | 'update';
|
|
103
|
+
type ConsentAction$1 = 'accept_all' | 'reject_all' | 'custom' | 'update';
|
|
39
104
|
type ConsentValue = Record<string, ConsentStatus>;
|
|
105
|
+
/**
|
|
106
|
+
* Output format for getConsent(type).
|
|
107
|
+
* 'default' → raw ConsentValue, keyed by every cookie parameter ID in the profile (existing behaviour)
|
|
108
|
+
* 'google-gtm' → Google Consent Mode v2 keys + ads_data_redaction, url_passthrough
|
|
109
|
+
* 'purpose' → consent per the fixed CookiePurpose taxonomy (necessary/functional/preferences/analytics/marketing)
|
|
110
|
+
* 'category' → consent per the tenant's own authored preference-modal category, keyed by category ID.
|
|
111
|
+
* 'granted' only when every member parameter is granted; 'denied'/'objected' otherwise
|
|
112
|
+
* (same ConsentStatus values as everything else — see getCategoryConsent for the exact rule)
|
|
113
|
+
* 'adobe' → { analytics, target, manager, optimizer }
|
|
114
|
+
* 'meta' → { pixel, api, plugins, facebookLogin }
|
|
115
|
+
* 'microsoft-clarity' → { session, heatmaps, performance }
|
|
116
|
+
* 'twilio-segment' → { identify, page, track, group, alias }
|
|
117
|
+
*/
|
|
118
|
+
type ConsentType = 'default' | 'google-gtm' | 'purpose' | 'category' | 'adobe' | 'meta' | 'microsoft-clarity' | 'twilio-segment';
|
|
119
|
+
type GpcMode = 'ignore' | 'honor' | 'strict';
|
|
120
|
+
type LegalBasis = 'mandatory' | 'consent' | 'legitimate_interest';
|
|
121
|
+
type CookiePurpose = typeof COOKIE_PURPOSE_IDS[number];
|
|
122
|
+
/**
|
|
123
|
+
* A single consent parameter (tracker/cookie definition).
|
|
124
|
+
* Keyed by its own id inside `Record<string, Cookie>` — the map key IS the id,
|
|
125
|
+
* there is no `id` field on the value itself.
|
|
126
|
+
*/
|
|
40
127
|
interface Cookie {
|
|
41
|
-
|
|
42
|
-
legalBasis?: 'mandatory' | 'consent' | 'legitimate_interest';
|
|
43
|
-
/** @deprecated use legalBasis: 'mandatory' */
|
|
44
|
-
mandatory?: boolean;
|
|
45
|
-
/** @deprecated use legalBasis */
|
|
46
|
-
type?: 'consent' | 'legitimate_interest';
|
|
128
|
+
purpose?: CookiePurpose;
|
|
47
129
|
listenGpc?: boolean;
|
|
48
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Pre-grant this parameter's default consent to 'granted' (instead of the
|
|
132
|
+
* compliance-group-driven default) when no stored decision exists yet.
|
|
133
|
+
* Only meaningful when the owning category's `legalBasis === 'consent'` —
|
|
134
|
+
* `mandatory`/`legitimate_interest` categories are already effectively
|
|
135
|
+
* pre-granted regardless of this flag. Never overrides an active GPC signal.
|
|
136
|
+
* Default: false.
|
|
137
|
+
*/
|
|
138
|
+
preGrant?: boolean;
|
|
49
139
|
tcfVendorId?: number;
|
|
50
140
|
tcfPurposes?: number[];
|
|
51
141
|
tcfSpecialFeatures?: number[];
|
|
52
142
|
cpraCategory?: 'sale' | 'sharing' | 'sensitive';
|
|
53
143
|
}
|
|
144
|
+
/** `Cookie` keyed by its own id — the standard shape used everywhere a parameter list is passed around. */
|
|
145
|
+
type CookieMap = Record<string, Cookie>;
|
|
54
146
|
type ButtonStyle = 'primary' | 'secondary' | 'text' | 'accent';
|
|
55
147
|
type ButtonAction = 'submit' | 'manage' | 'close' | 'custom' | 'link';
|
|
56
148
|
interface Button {
|
|
@@ -59,8 +151,11 @@ interface Button {
|
|
|
59
151
|
action: ButtonAction;
|
|
60
152
|
cookies?: string[] | '*' | '!';
|
|
61
153
|
url?: string;
|
|
62
|
-
type?: string;
|
|
63
154
|
}
|
|
155
|
+
/** `Button` keyed by its own id — e.g. `'accept-all'`. The map key IS the id, rendered as the DOM
|
|
156
|
+
* `id` (`consenti-btn-{id}`) so integrators can target specific buttons, and is what
|
|
157
|
+
* `profileOverride`'s `deepMerge` deletes by (`{ 'reject-optional': null }` removes one button). */
|
|
158
|
+
type ButtonMap = Record<string, Button>;
|
|
64
159
|
interface MainBanner {
|
|
65
160
|
position: 'top' | 'bottom' | 'middle' | 'left-bottom' | 'right-bottom';
|
|
66
161
|
overlayOpacity?: number;
|
|
@@ -69,34 +164,63 @@ interface MainBanner {
|
|
|
69
164
|
heading?: string;
|
|
70
165
|
headingTag?: string;
|
|
71
166
|
htmlText: string;
|
|
72
|
-
buttons:
|
|
167
|
+
buttons: ButtonMap;
|
|
168
|
+
/** Stack buttons vertically below this viewport width in px. 0 or undefined = disabled. Default: 576. */
|
|
169
|
+
stackButtonsOnBreakpoint?: number;
|
|
170
|
+
/** Trap keyboard Tab focus within the consent root while this banner is visible. */
|
|
171
|
+
trapFocus?: boolean;
|
|
73
172
|
}
|
|
74
173
|
type GpcBanner = MainBanner;
|
|
174
|
+
/**
|
|
175
|
+
* A consent category — the single source of legal basis for every parameter
|
|
176
|
+
* it lists in `cookies`. Keyed by its own id inside `Record<string, Category>` —
|
|
177
|
+
* the map key IS the id, there is no `id` field on the value itself.
|
|
178
|
+
*
|
|
179
|
+
* A parameter must belong to exactly one category (enforced at authoring time,
|
|
180
|
+
* not by this type) — that relationship is what `getCookieLegalBasis`/
|
|
181
|
+
* `isMandatoryCookie` (`@consenti/utils`) resolve at runtime.
|
|
182
|
+
*/
|
|
75
183
|
interface Category {
|
|
76
|
-
id: string;
|
|
77
184
|
heading: string;
|
|
78
185
|
headingTag?: string;
|
|
79
186
|
htmlText: string;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
description?: string;
|
|
85
|
-
};
|
|
187
|
+
legalBasis: LegalBasis;
|
|
188
|
+
/** Only meaningful when legalBasis === 'legitimate_interest' — the GDPR balancing-test justification shown to visitors. */
|
|
189
|
+
legitimateInterestDescription?: string;
|
|
190
|
+
/** IDs of the parameters (from the profile's `cookies` map) that belong to this category. */
|
|
86
191
|
cookies: string[];
|
|
87
192
|
}
|
|
193
|
+
/** `Category` keyed by its own id — the standard shape used everywhere a category list is passed around. */
|
|
194
|
+
type CategoryMap = Record<string, Category>;
|
|
88
195
|
interface PreferenceModal extends Omit<MainBanner, "position"> {
|
|
89
196
|
position?: 'left' | 'right' | 'center';
|
|
90
197
|
subheading?: string;
|
|
91
|
-
categories:
|
|
198
|
+
categories: CategoryMap;
|
|
92
199
|
persistent?: boolean;
|
|
93
200
|
/** Screen width in px below which the modal expands to full screen. Default: 576. Set to 0 to disable. */
|
|
94
201
|
mobileFullScreenBreakpoint?: number;
|
|
202
|
+
/** Label for the optional consent-receipt download checkbox (shown when `allowReceipt` is true). Falls back to a default when omitted. */
|
|
203
|
+
receiptLabel?: string;
|
|
204
|
+
/** Description shown beneath the consent-receipt checkbox. Falls back to a default when omitted. */
|
|
205
|
+
receiptDescription?: string;
|
|
206
|
+
/**
|
|
207
|
+
* Renders a "Forget me" control in the modal body, below the categories — only shown to
|
|
208
|
+
* visitors who already have a stored consent decision (nothing to erase otherwise). Wired to
|
|
209
|
+
* the same `DELETE /consent/:visitorId` erasure endpoint as `widget.deleteConsent()`, giving
|
|
210
|
+
* visitors self-service access to GDPR Art. 17 / CCPA-CPRA / LGPD Art. 18 / UK GDPR / DPDPA /
|
|
211
|
+
* KVKK / POPIA / PDPA-TH / APPI erasure-equivalent rights without the host wiring a link
|
|
212
|
+
* themselves. See the "Right to erasure" guide for the full compliance mapping.
|
|
213
|
+
*/
|
|
214
|
+
showForgetMe?: boolean;
|
|
215
|
+
/** Label for the "Forget me" button (shown when `showForgetMe` is true). Falls back to a default when omitted. */
|
|
216
|
+
forgetMeLabel?: string;
|
|
95
217
|
}
|
|
96
218
|
interface LocaleTranslations {
|
|
97
|
-
mainBanner: MainBanner
|
|
98
|
-
gpcBanner?: GpcBanner
|
|
99
|
-
preferenceModal: PreferenceModal
|
|
219
|
+
mainBanner: DeepPartial<MainBanner>;
|
|
220
|
+
gpcBanner?: DeepPartial<GpcBanner>;
|
|
221
|
+
preferenceModal: DeepPartial<PreferenceModal>;
|
|
222
|
+
/** Only meaningful when the profile's `ageGate.enabled` is true. */
|
|
223
|
+
ageGateModal?: DeepPartial<AgeGateModalContent>;
|
|
100
224
|
}
|
|
101
225
|
interface ProfileTranslations {
|
|
102
226
|
[locale: string]: LocaleTranslations;
|
|
@@ -106,85 +230,241 @@ interface DpdpaConfig {
|
|
|
106
230
|
grievanceEmail: string;
|
|
107
231
|
purposeDescription?: string;
|
|
108
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Per-profile age gate — GDPR Art. 8's consent age varies 13–16 by EU member state and DPDPA has
|
|
235
|
+
* its own child-data age rules, so one global age (the old `ConsentiServerConfig.ageGate`) was
|
|
236
|
+
* wrong for a multi-region deployment. Mirrors `dpdpa` exactly: profile-scoped, not global.
|
|
237
|
+
*/
|
|
238
|
+
interface AgeGateConfig {
|
|
239
|
+
enabled: boolean;
|
|
240
|
+
minimumAge: number;
|
|
241
|
+
requireParentalConsent?: boolean;
|
|
242
|
+
}
|
|
243
|
+
/** Per-locale age-gate modal text — translated the same way `mainBanner`/`preferenceModal`
|
|
244
|
+
* content is, unlike the widget's own hardcoded UI chrome (close button, locale switcher). */
|
|
245
|
+
interface AgeGateModalContent {
|
|
246
|
+
heading?: string;
|
|
247
|
+
htmlText: string;
|
|
248
|
+
confirmButtonLabel: string;
|
|
249
|
+
denyButtonLabel: string;
|
|
250
|
+
parentalConsent: {
|
|
251
|
+
heading?: string;
|
|
252
|
+
htmlText: string;
|
|
253
|
+
confirmButtonLabel: string;
|
|
254
|
+
};
|
|
255
|
+
}
|
|
109
256
|
interface LocaleTextContent {
|
|
110
257
|
mainBanner: {
|
|
111
258
|
heading?: string;
|
|
112
259
|
htmlText: string;
|
|
113
|
-
|
|
260
|
+
/** Keyed by the linked UI template's button id — was a positional array matched to
|
|
261
|
+
* `buttons[i]` by index; now matched by key, robust against button reordering. */
|
|
262
|
+
buttonLabels?: Record<string, string>;
|
|
114
263
|
};
|
|
115
264
|
gpcBanner: {
|
|
116
265
|
heading?: string;
|
|
117
266
|
htmlText: string;
|
|
118
|
-
buttonLabels?: string
|
|
267
|
+
buttonLabels?: Record<string, string>;
|
|
119
268
|
};
|
|
120
269
|
preferenceModal: {
|
|
121
270
|
heading: string;
|
|
122
271
|
subheading?: string;
|
|
123
272
|
htmlText?: string;
|
|
124
|
-
buttonLabels?: string
|
|
125
|
-
categories
|
|
126
|
-
|
|
273
|
+
buttonLabels?: Record<string, string>;
|
|
274
|
+
/** `legitimateInterestDescription` is only meaningful for categories whose legalBasis is 'legitimate_interest'; optional GDPR balancing-test text, translated per locale like heading/htmlText. */
|
|
275
|
+
categories: Record<string, {
|
|
127
276
|
heading: string;
|
|
128
277
|
htmlText: string;
|
|
129
|
-
|
|
278
|
+
legitimateInterestDescription?: string;
|
|
279
|
+
}>;
|
|
280
|
+
receiptLabel?: string;
|
|
281
|
+
receiptDescription?: string;
|
|
282
|
+
/** Per-locale override of `PreferenceModal.forgetMeLabel`; only meaningful when `showForgetMe` is true. */
|
|
283
|
+
forgetMeLabel?: string;
|
|
130
284
|
};
|
|
285
|
+
/** Only meaningful when the profile's `ageGate.enabled` is true. */
|
|
286
|
+
ageGateModal?: AgeGateModalContent;
|
|
131
287
|
}
|
|
132
288
|
interface ProfileConfig {
|
|
133
|
-
|
|
289
|
+
id: string;
|
|
290
|
+
cookies?: CookieMap;
|
|
134
291
|
defaultLocale: string;
|
|
292
|
+
/** Days until consent expires and the visitor is asked again (profile-wide). Default: 365. */
|
|
293
|
+
expiryDays?: number;
|
|
135
294
|
translations?: ProfileTranslations;
|
|
136
|
-
|
|
295
|
+
mainBanner: MainBanner;
|
|
296
|
+
gpcBanner?: GpcBanner;
|
|
297
|
+
preferenceModal: PreferenceModal;
|
|
137
298
|
darkMode?: boolean;
|
|
138
299
|
allowedOrigins?: string[];
|
|
139
300
|
dpdpa?: DpdpaConfig;
|
|
301
|
+
ageGate?: AgeGateConfig;
|
|
302
|
+
/** Default locale's age-gate modal text — mirrors `mainBanner`/`preferenceModal` (inline,
|
|
303
|
+
* required-shape-when-present), not `dpdpa` (which has no locale text at all). Every other
|
|
304
|
+
* locale's `ageGateModal` lives in `localeContents`/`LocaleContentInput` like the rest of
|
|
305
|
+
* that locale's content. */
|
|
306
|
+
ageGateModal?: AgeGateModalContent;
|
|
140
307
|
regulation?: 'gdpr' | 'ccpa' | 'cpra' | 'dpdpa' | 'uk-gdpr' | 'lgpd' | 'pipeda' | 'popia' | 'pdpa-th' | 'appi' | 'kvkk';
|
|
141
308
|
regulations?: string[];
|
|
142
|
-
|
|
309
|
+
consentTemplateId?: string;
|
|
143
310
|
uiTemplateId?: string;
|
|
144
311
|
localeContents?: Record<string, LocaleTextContent>;
|
|
145
|
-
complianceGroup?:
|
|
146
|
-
/**
|
|
147
|
-
|
|
148
|
-
|
|
312
|
+
complianceGroup?: ComplianceGroupId;
|
|
313
|
+
/**
|
|
314
|
+
* Free-form identifier (lower-kebab-case) for profiles that don't map to one of the
|
|
315
|
+
* built-in `complianceGroup` values — the identifier the widget's `compliance.type`
|
|
316
|
+
* config targets to fetch this profile. Participates in activation, deactivation, and
|
|
317
|
+
* "one active profile per group" conflict detection the same way `complianceGroup` does;
|
|
318
|
+
* no `COMPLIANCE_GROUPS` validation rules or GPC defaults apply to it, since none exist
|
|
319
|
+
* for a free-form name.
|
|
320
|
+
*/
|
|
321
|
+
customComplianceGroup?: string;
|
|
322
|
+
/**
|
|
323
|
+
* Per-profile deltas applied on top of the consent template's authored `Cookie` values
|
|
324
|
+
* (e.g. an overridden `preGrant`) when resolving this profile — see the dashboard's Step 2
|
|
325
|
+
* pre-grant override UX. Keyed by cookie id; only the overridden fields need to be present.
|
|
326
|
+
*/
|
|
327
|
+
cookiesOverride?: Record<string, Partial<Cookie>>;
|
|
328
|
+
/**
|
|
329
|
+
* Reserved for a future phase — stored but not yet applied when resolving a profile.
|
|
330
|
+
* Intended to mirror `cookiesOverride` for per-category deltas.
|
|
331
|
+
*/
|
|
332
|
+
categoriesOverride?: Record<string, Partial<Category>>;
|
|
333
|
+
/**
|
|
334
|
+
* Reserved for a future phase — stored but not yet applied when resolving a profile.
|
|
335
|
+
* Intended to hold per-profile UI-template deltas.
|
|
336
|
+
*/
|
|
337
|
+
uiOverride?: Record<string, unknown>;
|
|
338
|
+
/**
|
|
339
|
+
* When registered via `registerProfile()` and `complianceGroup` matches one of
|
|
340
|
+
* Consenti's built-in groups: `false` (default) fully replaces the built-in
|
|
341
|
+
* embedded profile for that group; `true` deep-merges this config onto the
|
|
342
|
+
* built-in profile instead (only meaningful together with `complianceGroup`).
|
|
343
|
+
*/
|
|
344
|
+
deepMerge?: boolean;
|
|
345
|
+
gpcMode?: GpcMode;
|
|
149
346
|
isActive?: boolean;
|
|
150
347
|
hidePoweredBy?: boolean;
|
|
151
348
|
allowReceipt?: boolean;
|
|
152
349
|
/** Per-compliance extra config (e.g. DPDPA data fiduciary name). */
|
|
153
350
|
complianceConfig?: Record<string, string>;
|
|
351
|
+
/** Show a metadata footer strip in the banner/modal with Consent ID, Date, Version, Privacy Settings link. */
|
|
352
|
+
showFooterMetadata?: boolean;
|
|
353
|
+
/** Apply WCAG 2.1 AA button sizing (44px min-height), visible focus rings, and screen-reader labels. */
|
|
354
|
+
enhanceAccessibility?: boolean;
|
|
154
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* Input accepted by `registerProfile()`. Either a complete `ProfileConfig`
|
|
358
|
+
* (used as-is or, if `complianceGroup` matches a built-in group, fully replaces
|
|
359
|
+
* it), or a partial overlay explicitly opted into `deepMerge: true` — merged
|
|
360
|
+
* onto the built-in embedded profile for `complianceGroup` at resolution time.
|
|
361
|
+
*/
|
|
362
|
+
type RegisterableProfileConfig = ProfileConfig | (DeepPartial<ProfileConfig> & {
|
|
363
|
+
complianceGroup: ComplianceGroupId;
|
|
364
|
+
deepMerge: true;
|
|
365
|
+
});
|
|
155
366
|
interface ResolvedProfile {
|
|
156
|
-
id:
|
|
157
|
-
|
|
158
|
-
version
|
|
367
|
+
id: string;
|
|
368
|
+
/** Incremented in place on every save of this profile. Absent for embedded/local profiles that have no server-side version counter. */
|
|
369
|
+
version?: number;
|
|
159
370
|
defaultLocale: string;
|
|
160
371
|
locales?: string[];
|
|
161
|
-
cookies:
|
|
372
|
+
cookies: CookieMap;
|
|
373
|
+
/** Days until consent expires and the visitor is asked again (profile-wide). Default: 365. */
|
|
374
|
+
expiryDays?: number;
|
|
375
|
+
allowReceipt?: boolean;
|
|
162
376
|
mainBanner: MainBanner;
|
|
163
377
|
gpcBanner?: GpcBanner;
|
|
164
378
|
preferenceModal: PreferenceModal;
|
|
165
379
|
cookieSigningKey?: string;
|
|
166
380
|
dpdpa?: DpdpaConfig;
|
|
381
|
+
ageGate?: AgeGateConfig;
|
|
382
|
+
ageGateModal?: AgeGateModalContent;
|
|
167
383
|
darkMode?: boolean;
|
|
168
|
-
gpcMode?:
|
|
169
|
-
|
|
384
|
+
gpcMode?: GpcMode;
|
|
385
|
+
/** One of the 8 built-in groups, or a custom group id (via `customComplianceGroup` /
|
|
386
|
+
* `ComplianceType`'s string passthrough) — this is the join key `complianceGroupsOverride`
|
|
387
|
+
* looks up by, so it must reflect whichever group this profile actually resolved against,
|
|
388
|
+
* built-in or custom. */
|
|
389
|
+
complianceGroup?: ComplianceGroupId | (string & {});
|
|
390
|
+
/** Set when the geo-resolved region carries a `requiresSensitiveOptIn` carve-out (e.g.
|
|
391
|
+
* Colorado under `opt-out`) — cookies tagged `cpraCategory: 'sensitive'` default to denied
|
|
392
|
+
* even though the rest of `complianceGroup`'s cookies default to granted. Only ever set by
|
|
393
|
+
* server-side geo resolution (`api.enabled: true` + a geoip/maxmind provider); the
|
|
394
|
+
* client-only timezone heuristic never resolves a region, so this is always unset there. */
|
|
395
|
+
requiresSensitiveOptIn?: boolean;
|
|
170
396
|
complianceConfig?: Record<string, string>;
|
|
397
|
+
/** Falls back to `true` (hidden) if neither the widget config nor the profile set it. */
|
|
398
|
+
hidePoweredBy?: boolean;
|
|
399
|
+
/** Show metadata footer strip (Consent ID, Date, Version, Privacy Settings link). */
|
|
400
|
+
showFooterMetadata?: boolean;
|
|
401
|
+
/** Apply WCAG 2.1 AA accessibility enhancements to the widget. */
|
|
402
|
+
enhanceAccessibility?: boolean;
|
|
171
403
|
}
|
|
172
404
|
type WidgetCountryResolverFn = () => Promise<{
|
|
173
405
|
country: string | null;
|
|
174
406
|
region: string | null;
|
|
175
407
|
confidence: number;
|
|
408
|
+
/** Optional escape hatch: when set, profile resolution uses this compliance group directly
|
|
409
|
+
* instead of computing one from `country`/`region` — mirrors the server-side `GeoResult`'s
|
|
410
|
+
* `complianceGroup` field (`@consenti/types`'s `api.ts`). `country`/`region` are still used for
|
|
411
|
+
* anything that reads them independently of group selection. Optional — omitting it preserves
|
|
412
|
+
* the existing timezone/language-based resolution exactly as before. */
|
|
413
|
+
complianceGroup?: string;
|
|
176
414
|
}>;
|
|
177
|
-
|
|
415
|
+
/** Mirrors the server-side `TcfConfig` shape (`@consenti/api`) — `cmpId`/`cmpVersion` must match
|
|
416
|
+
* what the backend uses to encode `tcfString`, since both feed the same simplified TC string.
|
|
417
|
+
*
|
|
418
|
+
* The client-side `__tcfapi` stub never fetches the Global Vendor List itself (multi-megabyte,
|
|
419
|
+
* and IAB policy requires CMPs to cache their own copy rather than have every visitor's browser
|
|
420
|
+
* fetch it) — `publisherCC`/`vendorListVersion`/`gvlVersion` are therefore operator-supplied
|
|
421
|
+
* config here, not auto-derived. Spec-correct binary TC-string encoding happens server-side in
|
|
422
|
+
* `@consenti/api` (see `compliance.tcf.publisherCC` there); this stub's `tcString` stays the
|
|
423
|
+
* simplified format documented in `@consenti/utils`'s `encodeTcString`. */
|
|
424
|
+
interface TcfWidgetConfig {
|
|
178
425
|
enabled: boolean;
|
|
179
|
-
|
|
180
|
-
|
|
426
|
+
cmpId: number;
|
|
427
|
+
cmpVersion: number;
|
|
428
|
+
/** ISO 3166-1 alpha-2 publisher country code. No honest default exists — leave unset only if
|
|
429
|
+
* you don't rely on this field downstream; ad-tech vendors that read it will see 'AA'
|
|
430
|
+
* (an explicit "not configured" placeholder, not a real country). */
|
|
431
|
+
publisherCC?: string;
|
|
432
|
+
/** Known Global Vendor List version, if you track it. Defaults to 0 ("unknown"). */
|
|
433
|
+
vendorListVersion?: number;
|
|
434
|
+
/** Known GVL specification version, if you track it. Defaults to 0 ("unknown"). */
|
|
435
|
+
gvlVersion?: number;
|
|
436
|
+
}
|
|
437
|
+
/** Mirrors the server-side `GppConfig` shape (`@consenti/api`) — `cmpId`/`cmpVersion` must match
|
|
438
|
+
* what the backend uses to encode `gppString`. Unlike TCF, the GPP US National section needs no
|
|
439
|
+
* Global Vendor List, so both the widget's `window.__gpp` and the server's `gppString` use the
|
|
440
|
+
* same real, spec-correct encoder (the optional `@iabgpp/cmpapi` peer dependency) — there's no
|
|
441
|
+
* "simplified fallback" format the way TCF has, since a non-spec GPP string has no consumer that
|
|
442
|
+
* would accept it. When `@iabgpp/cmpapi` isn't installed, `window.__gpp` is simply not exposed. */
|
|
443
|
+
interface GppWidgetConfig {
|
|
444
|
+
enabled: boolean;
|
|
445
|
+
cmpId: number;
|
|
446
|
+
cmpVersion: number;
|
|
447
|
+
/** MSPA "covered transaction" — whether this deployment's data transactions fall under MSPA
|
|
448
|
+
* signatory obligations. No honest default, so it's required rather than optional. */
|
|
449
|
+
mspaCoveredTransaction: boolean;
|
|
450
|
+
/** IAB's tri-state encoding for both MSPA fields: 0 = not applicable, 1 = yes, 2 = no. */
|
|
451
|
+
mspaOptOutOptionMode: 0 | 1 | 2;
|
|
452
|
+
mspaServiceProviderMode: 0 | 1 | 2;
|
|
181
453
|
}
|
|
182
454
|
interface ComplianceWidgetConfig {
|
|
183
|
-
type?:
|
|
455
|
+
type?: ComplianceType;
|
|
184
456
|
geoDataProvider?: 'default' | WidgetCountryResolverFn;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
457
|
+
/** Only meaningful in standalone mode (no `api.enabled`) — ignored (with a warning) when
|
|
458
|
+
* `api.enabled: true`, since the server resolves the compliance group in that mode.
|
|
459
|
+
* `'default'` (embedded map, the default), a URL to fetch a JSON `ComplianceMapData`
|
|
460
|
+
* document from (the browser's own HTTP cache honors whatever `Cache-Control`/`ETag` the
|
|
461
|
+
* response sends — no custom caching here), or an inline operator-supplied `ComplianceMapData`
|
|
462
|
+
* object. Invalid data from either a URL or an object logs a warning and falls back to
|
|
463
|
+
* `'default'`. Only overrides the country→group mapping — country/region detection itself
|
|
464
|
+
* always uses the embedded geo data. */
|
|
465
|
+
complianceMap?: 'default' | string | ComplianceMapData;
|
|
466
|
+
tcf?: TcfWidgetConfig;
|
|
467
|
+
gpp?: GppWidgetConfig;
|
|
188
468
|
}
|
|
189
469
|
interface GtmConfig {
|
|
190
470
|
containerId?: string;
|
|
@@ -192,6 +472,7 @@ interface GtmConfig {
|
|
|
192
472
|
dataLayer?: string;
|
|
193
473
|
urlPassthrough?: boolean;
|
|
194
474
|
adsDataRedaction?: boolean;
|
|
475
|
+
verbose?: boolean;
|
|
195
476
|
}
|
|
196
477
|
interface UtilsConfig {
|
|
197
478
|
gtm?: GtmConfig;
|
|
@@ -201,45 +482,81 @@ interface ApiConfig {
|
|
|
201
482
|
baseUrl?: string;
|
|
202
483
|
authToken?: string;
|
|
203
484
|
tenantId?: string;
|
|
204
|
-
complianceGroup?:
|
|
485
|
+
complianceGroup?: ComplianceGroupId;
|
|
205
486
|
trustDomain?: boolean;
|
|
206
487
|
}
|
|
488
|
+
/** Field names mirror their `--consenti-*` CSS variable literally (`--consenti-color-primary`
|
|
489
|
+
* → `colorPrimary`) — see `applyTheme()` in `consenti-setup.ts` for the full mapping. */
|
|
207
490
|
interface ThemeConfig {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
491
|
+
colorBg?: string;
|
|
492
|
+
colorText?: string;
|
|
493
|
+
colorTextMuted?: string;
|
|
494
|
+
colorPrimary?: string;
|
|
495
|
+
colorPrimaryText?: string;
|
|
496
|
+
colorSecondary?: string;
|
|
497
|
+
colorSecondaryText?: string;
|
|
498
|
+
colorBorder?: string;
|
|
499
|
+
colorSecondaryBorder?: string;
|
|
500
|
+
colorOverlay?: string;
|
|
501
|
+
colorAccent?: string;
|
|
502
|
+
colorAccentText?: string;
|
|
215
503
|
fontFamily?: string;
|
|
504
|
+
fontFamilyMono?: string;
|
|
216
505
|
fontSizeBase?: string;
|
|
217
506
|
fontSizeHeading?: string;
|
|
218
507
|
fontSizeMultiplier?: string;
|
|
508
|
+
fontWeightHeading?: string;
|
|
509
|
+
lineHeight?: string;
|
|
510
|
+
spacingXs?: string;
|
|
511
|
+
spacingSm?: string;
|
|
512
|
+
spacingMd?: string;
|
|
513
|
+
spacingLg?: string;
|
|
219
514
|
borderRadius?: string;
|
|
220
|
-
|
|
515
|
+
borderRadiusBtn?: string;
|
|
516
|
+
shadow?: string;
|
|
221
517
|
toggleBgOn?: string;
|
|
518
|
+
toggleBgPartial?: string;
|
|
222
519
|
toggleBgOff?: string;
|
|
223
|
-
|
|
224
|
-
|
|
520
|
+
toggleKnob?: string;
|
|
521
|
+
toggleWidth?: string;
|
|
522
|
+
toggleHeight?: string;
|
|
523
|
+
zBanner?: string;
|
|
524
|
+
zOverlay?: string;
|
|
525
|
+
zModal?: string;
|
|
225
526
|
}
|
|
226
527
|
interface CoreConfig {
|
|
227
528
|
tenantId?: string;
|
|
228
|
-
autoHonorGPC?: boolean | 'strict';
|
|
229
529
|
locale?: string;
|
|
530
|
+
/** Text direction for the banner/modal root. `'auto'` (default) derives it from `locale` via
|
|
531
|
+
* `Intl.Locale(...).getTextInfo().direction` (falling back to a hand-maintained RTL-language
|
|
532
|
+
* list on engines without `getTextInfo()` support); set explicitly to override. */
|
|
533
|
+
dir?: 'ltr' | 'rtl' | 'auto';
|
|
230
534
|
disableCssTemplate?: boolean;
|
|
231
535
|
cookieSigningKey?: string;
|
|
232
536
|
allowReceipt?: boolean;
|
|
233
537
|
cookieDomains?: string;
|
|
538
|
+
/** Name of the consent cookie/localStorage key. Default: `'consenti_data'`. Not switched
|
|
539
|
+
* automatically by detected region — set explicitly if you want a different name (e.g.
|
|
540
|
+
* `'euconsent-v2'`, the IAB TCF convention, but only meaningful for operators using the
|
|
541
|
+
* spec-correct binary encoder — `@consenti/api` + the optional `@iabtechlabtcf/core` peer
|
|
542
|
+
* dependency — since the IAB name implies IAB's binary format, not Consenti's own encoding). */
|
|
543
|
+
cookieName?: string;
|
|
234
544
|
storage?: 'cookie' | 'localStorage';
|
|
235
545
|
theme?: ThemeConfig;
|
|
546
|
+
/** Initial logged-in application user ID; empty/anonymous when unset. Prefer `getUserId()`/
|
|
547
|
+
* `setUserId()` (or the `consenti:listener:identify` event) to change it after init — those
|
|
548
|
+
* also handle reconsent when the identity changes on a shared device. */
|
|
236
549
|
userId?: string;
|
|
237
550
|
usePrebuiltProfiles?: 'all' | NonEmptyArray<ComplianceGroupId>;
|
|
238
551
|
cacheResolvedProfiles?: boolean;
|
|
239
552
|
console?: Array<'info' | 'log' | 'warning' | 'error'>;
|
|
240
553
|
}
|
|
241
554
|
interface ConsentiConfig {
|
|
242
|
-
|
|
555
|
+
verbose?: boolean;
|
|
556
|
+
/** Optional — every field of `CoreConfig` is itself optional, so `new ConsentiSetup({})` and
|
|
557
|
+
* `new ConsentiSetup({ compliance: { type: 'opt-in' } })` (omitting `core` entirely) both work,
|
|
558
|
+
* matching the widget's own "Minimal config" documentation. */
|
|
559
|
+
core?: CoreConfig;
|
|
243
560
|
compliance?: ComplianceWidgetConfig;
|
|
244
561
|
rootEl?: string | HTMLElement;
|
|
245
562
|
darkMode?: boolean;
|
|
@@ -248,13 +565,30 @@ interface ConsentiConfig {
|
|
|
248
565
|
utils?: UtilsConfig;
|
|
249
566
|
plugins?: ConsentiPlugin$1[];
|
|
250
567
|
profileOverride?: DeepPartial<ResolvedProfile>;
|
|
568
|
+
/** Per-compliance-group text/button/cookie overrides — applied on top of whichever profile the
|
|
569
|
+
* visitor's resolved group loads, keyed by that group's id (one of the 8 built-in
|
|
570
|
+
* `ComplianceGroupId`s, or any custom group id). Lets you author different copy per country
|
|
571
|
+
* without creating a separate profile (and separate `compliance.type` wiring) for each one —
|
|
572
|
+
* e.g. `{ 'opt-in': { mainBanner: { htmlText: '...' } }, 'my-custom-group': { ... } }`.
|
|
573
|
+
* Applied before `profileOverride`, which still always applies last as the universal catch-all.
|
|
574
|
+
* Works identically in standalone and server (`api.enabled`) mode. */
|
|
575
|
+
complianceGroupsOverride?: Partial<Record<ComplianceGroupId | (string & {}), DeepPartial<ResolvedProfile>>>;
|
|
251
576
|
/** When true, suppresses the "Powered by Consenti" footer link in the banner and modal. */
|
|
252
577
|
hidePoweredBy?: boolean;
|
|
253
578
|
}
|
|
254
|
-
type ConsentiEventName = 'bannerInitialized' | 'consenti:bannerInitialized' | 'bannerVisibility' | 'consenti:bannerVisibility' | 'modalVisibility' | 'consenti:modalVisibility' | 'consentBeingSubmitted' | 'consenti:consentBeingSubmitted' | 'consentSubmitted' | 'consenti:consentSubmitted';
|
|
579
|
+
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';
|
|
580
|
+
/** Snapshot of the current visitor's identity. `visitorId` is `null` until a consent decision
|
|
581
|
+
* has actually happened — it's never minted just to answer this call, see `getVisitor()`. */
|
|
582
|
+
interface VisitorIdentity {
|
|
583
|
+
visitorId: string | null;
|
|
584
|
+
type: 'authenticated' | 'anonymous';
|
|
585
|
+
userId: string | null;
|
|
586
|
+
}
|
|
255
587
|
interface ConsentiWidgetAPI {
|
|
256
588
|
hasConsent(): boolean;
|
|
257
589
|
getConsent(): ConsentValue | null;
|
|
590
|
+
getConsent(type: ConsentType): Record<string, string> | null;
|
|
591
|
+
getConsent(type?: ConsentType): ConsentValue | Record<string, string> | null;
|
|
258
592
|
getConsentDate(): Date | false;
|
|
259
593
|
getGTMConsent(): Record<string, string> | null;
|
|
260
594
|
isCookieGranted(cookieId: string, requestValue?: boolean): boolean | ConsentStatus;
|
|
@@ -267,8 +601,8 @@ interface ConsentiWidgetAPI {
|
|
|
267
601
|
off(event: ConsentiEventName, handler: (data: ConsentEvent) => void): void;
|
|
268
602
|
version(): {
|
|
269
603
|
package: string;
|
|
270
|
-
profileVersion:
|
|
271
|
-
consentVersion:
|
|
604
|
+
profileVersion: string | null;
|
|
605
|
+
consentVersion: string | null;
|
|
272
606
|
};
|
|
273
607
|
bannerVisibility(): 'main' | 'gpc' | false;
|
|
274
608
|
modalVisibility(): 'preference' | false;
|
|
@@ -277,13 +611,28 @@ interface ConsentiWidgetAPI {
|
|
|
277
611
|
hideBanner(): void;
|
|
278
612
|
showModal(triggerEl?: HTMLElement): void;
|
|
279
613
|
hideModal(): void;
|
|
280
|
-
submitConsent(consent: Partial<ConsentValue>): Promise<void>;
|
|
614
|
+
submitConsent(consent: Partial<ConsentValue>): Promise<ConsentDbRecord | void>;
|
|
281
615
|
deleteConsent(): Promise<void>;
|
|
282
616
|
reConsent(): Promise<void>;
|
|
617
|
+
/** Erases the stored consent record (same underlying call as `deleteConsent()`) and
|
|
618
|
+
* re-prompts, dispatching `consenti:forgetMeRequested` / `consenti:forgotten` around it so a
|
|
619
|
+
* host app can hook its own identity-verified erasure workflow. Powers the preference modal's
|
|
620
|
+
* "Forget me" button; also callable directly for a custom placement of the same action. */
|
|
621
|
+
forgetMe(resetAgeGate?: boolean): Promise<void>;
|
|
283
622
|
getRootElement(): HTMLElement | null;
|
|
284
623
|
getBannerElement(): HTMLElement | null;
|
|
285
624
|
getModalElement(): HTMLElement | null;
|
|
286
625
|
switchLocale(locale: string): void;
|
|
626
|
+
getUserId(): string | null;
|
|
627
|
+
/** Sets the logged-in application user ID (`null` for anonymous/logout). When the stored
|
|
628
|
+
* consent record's user differs from the new value, reconsents by default — pass
|
|
629
|
+
* `reConsent: false` to just update the identity without prompting again. No-ops (no
|
|
630
|
+
* reconsent, no warning) when there's no prior consent record to compare against. */
|
|
631
|
+
setUserId(userId: string | null, reConsent?: boolean): Promise<void>;
|
|
632
|
+
/** Snapshot of the current visitor's identity: the stable per-browser `visitorId` (`null` if
|
|
633
|
+
* no consent decision has happened yet — this never creates one), whether they're
|
|
634
|
+
* `authenticated` or `anonymous`, and the app `userId` (same as `getUserId()`). */
|
|
635
|
+
getVisitor(): VisitorIdentity;
|
|
287
636
|
setDarkMode(enable?: boolean): void;
|
|
288
637
|
setTheme(theme: Partial<ThemeConfig>): void;
|
|
289
638
|
setConfig(config: DeepPartial<ConsentiConfig>): void;
|
|
@@ -316,41 +665,102 @@ interface ParsedConsent {
|
|
|
316
665
|
interface ConsentRecord {
|
|
317
666
|
visitorId: string;
|
|
318
667
|
consentId?: string;
|
|
319
|
-
profileId:
|
|
320
|
-
profileVersion: number;
|
|
668
|
+
profileId: string;
|
|
321
669
|
consent: ConsentValue;
|
|
322
670
|
timestamp: string;
|
|
323
671
|
gpc?: boolean;
|
|
324
|
-
action?: ConsentAction;
|
|
672
|
+
action?: ConsentAction$1;
|
|
325
673
|
pageUrl?: string;
|
|
326
674
|
}
|
|
327
675
|
interface ConsentReceipt {
|
|
328
|
-
version:
|
|
676
|
+
version: string;
|
|
329
677
|
issuedAt: string;
|
|
330
678
|
visitorId: string;
|
|
331
|
-
profileId:
|
|
332
|
-
profileVersion: number;
|
|
679
|
+
profileId: string;
|
|
333
680
|
locale: string;
|
|
334
681
|
consent: ConsentValue;
|
|
335
682
|
signature?: string;
|
|
336
683
|
}
|
|
337
|
-
interface
|
|
338
|
-
profileId
|
|
339
|
-
|
|
340
|
-
hasExistingConsent
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
684
|
+
interface BannerInitializedDetail {
|
|
685
|
+
profileId: string;
|
|
686
|
+
complianceGroup?: ComplianceType;
|
|
687
|
+
hasExistingConsent: boolean;
|
|
688
|
+
gpcDetected: boolean;
|
|
689
|
+
willShow: boolean;
|
|
690
|
+
}
|
|
691
|
+
interface BannerVisibilityDetail {
|
|
692
|
+
visible: boolean;
|
|
693
|
+
variant: 'main' | 'gpc';
|
|
694
|
+
action: boolean;
|
|
695
|
+
}
|
|
696
|
+
interface ModalVisibilityDetail {
|
|
697
|
+
visible: boolean;
|
|
698
|
+
action: boolean;
|
|
699
|
+
}
|
|
700
|
+
interface ConsentBeingSubmitted {
|
|
701
|
+
consentId: string;
|
|
702
|
+
visitorId: string;
|
|
703
|
+
profileId: string;
|
|
704
|
+
consentJson: ConsentValue;
|
|
705
|
+
consentAction: ConsentAction$1;
|
|
706
|
+
gpcDetected: boolean;
|
|
707
|
+
pageUrl: string;
|
|
708
|
+
timestamp: number;
|
|
347
709
|
fromBroadcast?: boolean;
|
|
348
|
-
gpcDetected?: boolean;
|
|
349
710
|
}
|
|
711
|
+
interface ConsentSubmittedDetail extends ConsentBeingSubmitted {
|
|
712
|
+
apiResponse: ConsentDbRecord;
|
|
713
|
+
}
|
|
714
|
+
/** Dispatched when the age gate is declined and `requireParentalConsent` is set — see the
|
|
715
|
+
* profile's `AgeGateConfig`. A deny-all consent (mandatory cookies only) has already been
|
|
716
|
+
* submitted with `parentalConsentToken` attached; this event is the hook for the site
|
|
717
|
+
* owner to run their own out-of-band parental-consent verification. `parentalConsentToken` is
|
|
718
|
+
* server-issued (and signed, when `compliance.dataSigningHash` is configured) when `api.enabled`,
|
|
719
|
+
* otherwise a client-generated, unsigned fallback — see `POST /consent/:visitorId/parental-consent-request`. */
|
|
720
|
+
interface ParentalConsentRequiredDetail {
|
|
721
|
+
parentalConsentToken: string;
|
|
722
|
+
profileId: string;
|
|
723
|
+
visitorId: string;
|
|
724
|
+
timestamp: number;
|
|
725
|
+
}
|
|
726
|
+
/** Dispatched by the standalone `resolveParentalConsent()` util (`apps/ui/src/utils/parental-consent.ts`)
|
|
727
|
+
* after `POST /consent/parental-consent-resolve` succeeds — typically from a fresh page/session
|
|
728
|
+
* with no live `ConsentiSetup` instance (the parent's own device, not the child's). A page that
|
|
729
|
+
* does have a live widget instance can listen for this to react (e.g. re-show the banner/modal for
|
|
730
|
+
* the real consent choice); what "resolved" should actually do to consent state is host-defined. */
|
|
731
|
+
interface ParentalConsentGrantedDetail {
|
|
732
|
+
visitorId: string;
|
|
733
|
+
profileId: string;
|
|
734
|
+
}
|
|
735
|
+
/** Detail payload for the inbound `consenti:listener:identify` event — dispatched by the *host*
|
|
736
|
+
* page (not the widget) to tell the widget which application user is logged in, equivalent to
|
|
737
|
+
* calling `setUserId(userId, reConsent)`. `reConsent` defaults to `true`. */
|
|
738
|
+
interface IdentifyEventDetail {
|
|
739
|
+
userId: string | null;
|
|
740
|
+
reConsent?: boolean;
|
|
741
|
+
}
|
|
742
|
+
/** Dispatched by `forgetMe()` right before the erasure call goes out — the hook for a host app
|
|
743
|
+
* to kick off its own identity-verified erasure workflow across other systems (CRM, DMP,
|
|
744
|
+
* analytics). The CMP itself only ever erases its own consent record; see the server-side
|
|
745
|
+
* `consent.erased` eventBus event (fired by `DELETE /consent/:visitorId`) for the same hook on
|
|
746
|
+
* the backend. See the "Right to erasure" guide for the full picture. */
|
|
747
|
+
interface ForgetMeRequestedDetail {
|
|
748
|
+
visitorId: string;
|
|
749
|
+
profileId: string;
|
|
750
|
+
timestamp: number;
|
|
751
|
+
}
|
|
752
|
+
/** Dispatched by `forgetMe()` after the consent record has been erased and the banner/age-gate
|
|
753
|
+
* has been re-prompted (see `reConsent()`, which `forgetMe()` wraps). */
|
|
754
|
+
interface ForgottenDetail {
|
|
755
|
+
visitorId: string;
|
|
756
|
+
profileId: string;
|
|
757
|
+
timestamp: number;
|
|
758
|
+
}
|
|
759
|
+
type ConsentEvent = BannerInitializedDetail | BannerVisibilityDetail | ModalVisibilityDetail | ConsentBeingSubmitted | ConsentSubmittedDetail | ParentalConsentRequiredDetail | ParentalConsentGrantedDetail | ForgetMeRequestedDetail | ForgottenDetail;
|
|
350
760
|
type ConsentiMessage = {
|
|
351
761
|
type: 'consentUpdated';
|
|
352
762
|
consent: ConsentValue;
|
|
353
|
-
profileId:
|
|
763
|
+
profileId: string;
|
|
354
764
|
} | {
|
|
355
765
|
type: 'bannerClosed';
|
|
356
766
|
} | {
|
|
@@ -375,16 +785,30 @@ type ConsentiMessage = {
|
|
|
375
785
|
*/
|
|
376
786
|
|
|
377
787
|
declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
378
|
-
private config;
|
|
379
788
|
private initialized;
|
|
380
789
|
private initializing;
|
|
381
790
|
private profile;
|
|
382
791
|
private resolvedBase;
|
|
792
|
+
/** cookieId → Category lookup, rebuilt whenever `profile` changes. Avoids rescanning categories on every consent action. */
|
|
793
|
+
private categoryIndex;
|
|
794
|
+
/** Watchers created by the declarative `data-consenti-*` DOM scan — destroyed alongside the widget since they have no other owner. */
|
|
795
|
+
private scannedScripts;
|
|
383
796
|
private consentStore;
|
|
797
|
+
/**
|
|
798
|
+
* Stable per-browser identifier. Created lazily the first time a consent decision actually
|
|
799
|
+
* happens (manual submit, GPC auto-response, or relaying a decision already made in another
|
|
800
|
+
* tab) — never minted before that, so an undecided visitor leaves nothing in storage. See
|
|
801
|
+
* `getOrCreateVisitorId()`.
|
|
802
|
+
*/
|
|
803
|
+
private visitorId;
|
|
384
804
|
private eventBus;
|
|
385
805
|
private banner;
|
|
386
806
|
private modal;
|
|
807
|
+
private ageGate;
|
|
387
808
|
private renderer;
|
|
809
|
+
/** Set once the age gate (if enabled) resolves; threaded onto every `submitConsent` call thereafter. */
|
|
810
|
+
private _ageVerified;
|
|
811
|
+
private _parentalConsentToken;
|
|
388
812
|
private broadcastChannel;
|
|
389
813
|
private readyResolve;
|
|
390
814
|
private readyPromise;
|
|
@@ -393,26 +817,118 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
393
817
|
private lastSignature;
|
|
394
818
|
/** Tracks which banner variant is currently visible, or null when hidden. */
|
|
395
819
|
private _bannerVariant;
|
|
820
|
+
/** Tracks which banner variant is currently mounted in the DOM (persists when banner is hidden). */
|
|
821
|
+
private _bannerMounted;
|
|
822
|
+
/** Active focus trap keydown listener — removed when modal closes. */
|
|
823
|
+
private _focusTrapListener;
|
|
824
|
+
/** Inbound `consenti:listener:identify` window listener — installed once per init(), removed on destroy(). */
|
|
825
|
+
private _identifyListener;
|
|
396
826
|
/** Maps original handler functions to their DOM-wrapped listeners for on/off bookkeeping. */
|
|
397
827
|
private _eventHandlers;
|
|
828
|
+
/** `core` defaulted to `{}` in the constructor below — every one of its own fields is
|
|
829
|
+
* optional, so this narrows back to non-optional for every other method in this class. */
|
|
830
|
+
private config;
|
|
398
831
|
/**
|
|
399
832
|
* Creates and initialises the consent widget.
|
|
400
833
|
*
|
|
401
834
|
* Construction is synchronous; the async `init()` is launched in the background.
|
|
402
835
|
* Use `await widget.ready` or `widget.onReady(cb)` to run code after init completes.
|
|
403
836
|
*
|
|
404
|
-
* @param config - Widget configuration. See `ConsentiConfig` for all options.
|
|
837
|
+
* @param config - Widget configuration. See `ConsentiConfig` for all options. `core` may be
|
|
838
|
+
* omitted entirely — every one of its own fields is optional too.
|
|
405
839
|
*/
|
|
406
840
|
constructor(config: ConsentiConfig);
|
|
407
841
|
private profileId;
|
|
842
|
+
/** Patches `base` with `complianceGroupsOverride[base.complianceGroup]`, if both exist — the
|
|
843
|
+
* per-group counterpart to `profileOverride`. Lets an author supply different text/buttons/
|
|
844
|
+
* cookies per compliance group (built-in or custom) without authoring a separate profile for
|
|
845
|
+
* each one. Applied before `profileOverride`, which still always wins as the final catch-all. */
|
|
846
|
+
private applyComplianceGroupOverride;
|
|
847
|
+
/**
|
|
848
|
+
* Whether `window.__tcfapi`/`window.__gpp` should stay uninstalled because the corresponding
|
|
849
|
+
* server-side registration (`compliance.tcf`/`compliance.gpp`) is unconfirmed (cmpId/cmpVersion
|
|
850
|
+
* changed since the dashboard's confirmation checkbox was last checked, or never confirmed).
|
|
851
|
+
* Standalone (no-backend) deployments have no governance layer to check against, so this always
|
|
852
|
+
* resolves `false` there — the client-side config is used as configured, same as before this
|
|
853
|
+
* feature existed. A network failure fails closed (`true`) rather than assuming the
|
|
854
|
+
* unverifiable state is fine.
|
|
855
|
+
*/
|
|
856
|
+
private isRegistrationBlocked;
|
|
408
857
|
/**
|
|
409
858
|
* Starts widget initialisation. Called automatically unless `autoInit: false` is set.
|
|
410
859
|
* Can be called explicitly after construction when `autoInit: false`, or after `destroy()`
|
|
411
860
|
* to re-initialise the same instance.
|
|
412
861
|
*/
|
|
413
862
|
init(): Promise<void>;
|
|
863
|
+
/**
|
|
864
|
+
* Everything after the "does consent already exist" check — GPC/CCPA/CPRA silent paths,
|
|
865
|
+
* then the normal opt-in banner. Extracted from `init()` so the age gate (when enabled and
|
|
866
|
+
* no consent exists yet) can defer this whole sequence until the visitor answers it via
|
|
867
|
+
* `resolveAgeGate()`, then resume here with `hasExisting` fixed at `false`.
|
|
868
|
+
*/
|
|
869
|
+
private continueInit;
|
|
870
|
+
/** Mounts the age-gate prompt (`profile.ageGate`) in place of the normal banner flow. */
|
|
871
|
+
private showAgeGate;
|
|
872
|
+
/**
|
|
873
|
+
* Handles the visitor's age-gate answer.
|
|
874
|
+
* - Confirmed → records `ageVerified: true` for all future `submitConsent` calls and
|
|
875
|
+
* resumes the normal init flow via `continueInit()`.
|
|
876
|
+
* - Declined, no parental consent required → immediately submits a deny-all consent
|
|
877
|
+
* (mandatory cookies still granted), mirroring the GPC-strict silent-write pattern.
|
|
878
|
+
* - Declined, parental consent required → same deny-all submission, plus a
|
|
879
|
+
* `parentalConsentToken` and a `consenti:parentalConsentRequired` event so the site
|
|
880
|
+
* owner can wire their own out-of-band verification flow (no email infra exists in
|
|
881
|
+
* this package to do that here).
|
|
882
|
+
*/
|
|
883
|
+
private resolveAgeGate;
|
|
884
|
+
/**
|
|
885
|
+
* Marks the widget ready and runs the declarative DOM-scan for
|
|
886
|
+
* `data-consenti-consent-script`/`data-consenti-category-script` tags. Called from
|
|
887
|
+
* every exit path of `init()` so the scan always runs exactly once per init cycle,
|
|
888
|
+
* whether `init()` was triggered automatically (`autoInit !== false`) or explicitly
|
|
889
|
+
* by the caller (`autoInit: false`) — it never runs before the widget actually has
|
|
890
|
+
* a resolved profile to read consent from.
|
|
891
|
+
*/
|
|
892
|
+
private finishInit;
|
|
893
|
+
/** Installs the inbound `consenti:listener:identify` window listener — the event-driven
|
|
894
|
+
* counterpart to `setUserId()`. Removes any previously-installed listener first so repeated
|
|
895
|
+
* `init()` calls (e.g. from `switchLocale()`) don't stack up duplicate listeners. */
|
|
896
|
+
private _installIdentifyListener;
|
|
897
|
+
/** Returns the current logged-in application user ID, or `null` for an anonymous visitor. */
|
|
898
|
+
getUserId(): string | null;
|
|
899
|
+
/**
|
|
900
|
+
* Sets the logged-in application user ID (`null` for anonymous/logout). If a stored consent
|
|
901
|
+
* record exists and its user differs from `userId`, this is treated as a different data
|
|
902
|
+
* subject on a shared device: by default it reconsents (deletes the existing record and
|
|
903
|
+
* re-shows the banner) and logs a warning. Pass `reConsent: false` to just update the identity
|
|
904
|
+
* without prompting again (still logs the warning). No-ops entirely — no warning, no
|
|
905
|
+
* reconsent — when there is no prior consent record to compare against (true first-time visitor).
|
|
906
|
+
*/
|
|
907
|
+
setUserId(userId: string | null, reConsent?: boolean): Promise<void>;
|
|
908
|
+
/**
|
|
909
|
+
* Snapshot of the current visitor's identity. `visitorId` is the stable per-browser ID —
|
|
910
|
+
* `null` until a consent decision has actually happened, since this never mints one just to
|
|
911
|
+
* answer the call (see `getOrCreateVisitorId()`). `type` is `'authenticated'` whenever a
|
|
912
|
+
* `userId` is set (via `setUserId()` or `core.userId`), `'anonymous'` otherwise.
|
|
913
|
+
*/
|
|
914
|
+
getVisitor(): VisitorIdentity;
|
|
915
|
+
/** Sets the `dir` attribute on the root element from `core.dir` (default `'auto'`, derived from `core.locale`). */
|
|
916
|
+
private applyDirection;
|
|
414
917
|
/** Applies the `consenti-root--dark` class based on config or profile flag. */
|
|
415
918
|
private applyDarkMode;
|
|
919
|
+
/** Applies `consenti--enhanced-a11y` class when `profile.enhanceAccessibility` is set. */
|
|
920
|
+
private applyAccessibility;
|
|
921
|
+
/** Builds and appends the metadata footer strip to modal container. */
|
|
922
|
+
private _appendMetaFooter;
|
|
923
|
+
/**
|
|
924
|
+
* Injects a `<style>` element into the root for `stackButtonsOnBreakpoint`.
|
|
925
|
+
* Called once per profile load; a new style replaces the previous one.
|
|
926
|
+
*/
|
|
927
|
+
private applyStackButtonsBreakpoint;
|
|
928
|
+
/** Installs a keyboard focus trap on `container` while the modal is open. */
|
|
929
|
+
private _installFocusTrap;
|
|
930
|
+
/** Removes the active focus trap keyboard listener. */
|
|
931
|
+
private _removeFocusTrap;
|
|
416
932
|
/**
|
|
417
933
|
* Injects CSS custom property overrides supplied via `core.theme` into the
|
|
418
934
|
* Consenti root element so they cascade down to all widget elements.
|
|
@@ -442,22 +958,31 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
442
958
|
*/
|
|
443
959
|
hasConsent(): boolean;
|
|
444
960
|
/**
|
|
445
|
-
* Returns the stored consent map,
|
|
446
|
-
*
|
|
961
|
+
* Returns the stored consent map, optionally transformed for a specific vendor.
|
|
962
|
+
* Pass `type` to get a vendor-ready object instead of the raw Consenti format.
|
|
963
|
+
* Always returns `null` during SSR or when no consent has been saved.
|
|
964
|
+
*
|
|
965
|
+
* @param type - Output format:
|
|
966
|
+
* - omit / `'default'` → raw ConsentValue, keyed by every cookie parameter ID in the profile
|
|
967
|
+
* - `'purpose'` → consent per the fixed CookiePurpose taxonomy (necessary/functional/preferences/analytics/marketing)
|
|
968
|
+
* - `'category'` → consent per the tenant's own authored preference-modal category, keyed by category ID
|
|
969
|
+
* ('granted' only when every member parameter is granted; 'denied'/'objected' otherwise)
|
|
970
|
+
* - `'google-gtm'` → Google Consent Mode v2 keys + ads_data_redaction, url_passthrough
|
|
971
|
+
* - `'adobe'` → { analytics, target, manager, optimizer }
|
|
972
|
+
* - `'meta'` → { pixel, api, plugins, facebookLogin }
|
|
973
|
+
* - `'microsoft-clarity'` → { session, heatmaps, performance }
|
|
974
|
+
* - `'twilio-segment'` → { identify, page, track, group, alias }
|
|
447
975
|
*/
|
|
448
976
|
getConsent(): ConsentValue | null;
|
|
977
|
+
getConsent(type: ConsentType): Record<string, string> | null;
|
|
449
978
|
/**
|
|
450
979
|
* Returns the `Date` when consent was last saved, or `false` if no consent exists.
|
|
451
980
|
* Always returns `false` during SSR.
|
|
452
981
|
*/
|
|
453
982
|
getConsentDate(): Date | false;
|
|
454
983
|
/**
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
* Maps Consenti cookie IDs to the seven Google Consent Mode v2 parameters.
|
|
459
|
-
* Cookies whose IDs exactly match a GCM v2 key are forwarded directly.
|
|
460
|
-
* Non-GCM cookies are ignored by this method (they appear in `getConsent()` only).
|
|
984
|
+
* @deprecated Use `getConsent('google-gtm')` instead.
|
|
985
|
+
* Returns the consent map in Google Consent Mode v2 format.
|
|
461
986
|
*/
|
|
462
987
|
getGTMConsent(): Record<string, string> | null;
|
|
463
988
|
/**
|
|
@@ -469,7 +994,7 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
469
994
|
* @param consent - Partial or full map of cookie ID → status.
|
|
470
995
|
* @param gpcDerived - Internal flag set to `true` when called from the GPC strict path.
|
|
471
996
|
*/
|
|
472
|
-
submitConsent(consent: Partial<ConsentValue>, gpcDerived?: boolean): Promise<void>;
|
|
997
|
+
submitConsent(consent: Partial<ConsentValue>, gpcDerived?: boolean, source?: number): Promise<ConsentDbRecord | void>;
|
|
473
998
|
/**
|
|
474
999
|
* Returns the currently visible banner variant, or `false` if no banner is shown.
|
|
475
1000
|
* Useful for programmatically checking state before calling `showBanner` / `hideBanner`.
|
|
@@ -538,8 +1063,30 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
538
1063
|
* method so callers do not need to coordinate the async deletion with the banner display.
|
|
539
1064
|
*
|
|
540
1065
|
* Use this to power "Review my consent" links in footers or privacy dashboards.
|
|
1066
|
+
*
|
|
1067
|
+
* @param resetAgeGate - When `true` (default) and the profile has `ageGate.enabled`, the
|
|
1068
|
+
* age-gate prompt is shown again instead of jumping straight to the
|
|
1069
|
+
* banner — mirroring the original first-visit flow. Pass `false` to
|
|
1070
|
+
* skip it and go straight to the banner, keeping the visitor's prior
|
|
1071
|
+
* age-gate answer.
|
|
541
1072
|
*/
|
|
542
|
-
reConsent(): Promise<void>;
|
|
1073
|
+
reConsent(resetAgeGate?: boolean): Promise<void>;
|
|
1074
|
+
/**
|
|
1075
|
+
* Self-service erasure entry point — GDPR Art. 17 / CCPA-CPRA / LGPD Art. 18 and equivalent
|
|
1076
|
+
* "right to be forgotten" rights, exercised from the widget itself. Wraps `reConsent()` (same
|
|
1077
|
+
* erase-then-reprompt behavior) with `consenti:forgetMeRequested` / `consenti:forgotten`
|
|
1078
|
+
* dispatched around it, so a host app can hook its own identity-verified erasure workflow
|
|
1079
|
+
* across other systems (CRM, DMP, analytics) — the CMP itself only ever erases its own consent
|
|
1080
|
+
* record. See the "Right to erasure" guide for the full picture, including the server-side
|
|
1081
|
+
* `consent:erased` eventBus event fired by `DELETE /consent/:visitorId`.
|
|
1082
|
+
*
|
|
1083
|
+
* Powers the preference modal's "Forget me" button (`preferenceModal.showForgetMe`, only
|
|
1084
|
+
* rendered when the visitor already has a stored consent decision). Also callable directly —
|
|
1085
|
+
* e.g. `widget.forgetMe()` from a custom footer link or privacy-settings page.
|
|
1086
|
+
*
|
|
1087
|
+
* @param resetAgeGate - Forwarded to `reConsent()` — see its docs.
|
|
1088
|
+
*/
|
|
1089
|
+
forgetMe(resetAgeGate?: boolean): Promise<void>;
|
|
543
1090
|
/**
|
|
544
1091
|
* Returns the fully resolved profile for the current session, or `null` during the
|
|
545
1092
|
* async init phase (before the profile has been fetched/resolved).
|
|
@@ -638,8 +1185,8 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
638
1185
|
*/
|
|
639
1186
|
version(): {
|
|
640
1187
|
package: string;
|
|
641
|
-
profileVersion:
|
|
642
|
-
consentVersion:
|
|
1188
|
+
profileVersion: string;
|
|
1189
|
+
consentVersion: string | null;
|
|
643
1190
|
};
|
|
644
1191
|
/**
|
|
645
1192
|
* Toggles or sets dark mode at runtime without re-initialising the widget.
|
|
@@ -762,28 +1309,36 @@ declare abstract class ConsentiPlugin {
|
|
|
762
1309
|
* import { ConsentiProfile, ConsentiSetup } from '@consenti/ui'
|
|
763
1310
|
*
|
|
764
1311
|
* const profile = new ConsentiProfile({
|
|
765
|
-
* cookies:
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
1312
|
+
* cookies: {
|
|
1313
|
+
* necessary: {},
|
|
1314
|
+
* analytics: {},
|
|
1315
|
+
* },
|
|
769
1316
|
* defaultLocale: 'en',
|
|
770
1317
|
* translations: {
|
|
771
1318
|
* en: {
|
|
772
1319
|
* mainBanner: {
|
|
773
1320
|
* position: 'bottom',
|
|
774
1321
|
* htmlText: 'We use cookies.',
|
|
775
|
-
* buttons:
|
|
1322
|
+
* buttons: { 'accept-all': { text: 'Accept All', style: 'primary', action: 'submit', cookies: '*' } },
|
|
776
1323
|
* },
|
|
777
1324
|
* preferenceModal: {
|
|
778
|
-
* categories:
|
|
779
|
-
*
|
|
1325
|
+
* categories: {
|
|
1326
|
+
* necessary: { heading: 'Necessary', htmlText: '...', legalBasis: 'mandatory', cookies: ['necessary'] },
|
|
1327
|
+
* },
|
|
1328
|
+
* buttons: { save: { text: 'Save', style: 'primary', action: 'submit' } },
|
|
780
1329
|
* },
|
|
781
1330
|
* },
|
|
782
1331
|
* },
|
|
783
1332
|
* })
|
|
784
1333
|
*
|
|
785
|
-
* const widget = new ConsentiSetup({ core: { profileId: profile.
|
|
1334
|
+
* const widget = new ConsentiSetup({ core: { profileId: profile.getType() } })
|
|
786
1335
|
* ```
|
|
1336
|
+
*
|
|
1337
|
+
* To instead patch one of Consenti's built-in profiles for a given `complianceGroup`
|
|
1338
|
+
* (rather than defining a full standalone profile), pass `complianceGroup` and
|
|
1339
|
+
* `deepMerge: true` with only the fields you want to override — see
|
|
1340
|
+
* `RegisterableProfileConfig` and the `complianceGroup`/`deepMerge` resolver behavior
|
|
1341
|
+
* in `profile-resolver.ts`.
|
|
787
1342
|
*/
|
|
788
1343
|
|
|
789
1344
|
/**
|
|
@@ -791,15 +1346,17 @@ declare abstract class ConsentiPlugin {
|
|
|
791
1346
|
*/
|
|
792
1347
|
declare class ConsentiProfile {
|
|
793
1348
|
private config;
|
|
794
|
-
private
|
|
1349
|
+
private type;
|
|
795
1350
|
/**
|
|
796
|
-
* @param config - Full profile configuration including cookies, locales, and UI text
|
|
1351
|
+
* @param config - Full profile configuration including cookies, locales, and UI text,
|
|
1352
|
+
* or a `{ complianceGroup, deepMerge: true, ... }` partial overlay to
|
|
1353
|
+
* patch a built-in profile instead of defining a standalone one.
|
|
797
1354
|
*/
|
|
798
|
-
constructor(config:
|
|
1355
|
+
constructor(config: RegisterableProfileConfig);
|
|
799
1356
|
/** Returns the auto-assigned numeric profile ID. Pass this to `core.profileId`. */
|
|
800
|
-
|
|
801
|
-
/** Returns the raw
|
|
802
|
-
toJSON():
|
|
1357
|
+
getType(): Symbol;
|
|
1358
|
+
/** Returns the raw config passed to the constructor. */
|
|
1359
|
+
toJSON(): RegisterableProfileConfig;
|
|
803
1360
|
}
|
|
804
1361
|
|
|
805
1362
|
/**
|
|
@@ -887,37 +1444,248 @@ declare class ConsentScript {
|
|
|
887
1444
|
}
|
|
888
1445
|
|
|
889
1446
|
/**
|
|
890
|
-
*
|
|
891
|
-
*
|
|
1447
|
+
* ConsentAction — runs a callback based on a specific consent parameter's grant status.
|
|
1448
|
+
*
|
|
1449
|
+
* Same lifecycle as `ConsentScript` (evaluates immediately on construction so
|
|
1450
|
+
* existing consent is honoured, re-evaluates on `consenti:consentSubmitted`,
|
|
1451
|
+
* `destroy()` to unbind) but fires `onGrant`/`onDeny` callbacks instead of
|
|
1452
|
+
* injecting a `<script>` element — for integrations that expose their own
|
|
1453
|
+
* `sdk.optIn()`/`sdk.optOut()` API (Segment, Mixpanel, Amplitude, Sentry, etc.)
|
|
1454
|
+
* rather than needing a script tag toggled. Use `ConsentScript` for that case instead.
|
|
1455
|
+
*
|
|
1456
|
+
* @example
|
|
1457
|
+
* ```ts
|
|
1458
|
+
* import { ConsentiSetup, ConsentAction } from '@consenti/ui'
|
|
1459
|
+
*
|
|
1460
|
+
* const widget = new ConsentiSetup({ core: { profileId: 0 } })
|
|
1461
|
+
* await widget.ready
|
|
1462
|
+
*
|
|
1463
|
+
* new ConsentAction({
|
|
1464
|
+
* id: 'analytics_storage',
|
|
1465
|
+
* widget,
|
|
1466
|
+
* onGrant: () => analyticsSdk.optIn(),
|
|
1467
|
+
* onDeny: () => analyticsSdk.optOut(),
|
|
1468
|
+
* })
|
|
1469
|
+
* ```
|
|
1470
|
+
*/
|
|
1471
|
+
|
|
1472
|
+
/** Passed to `onGrant`/`onDeny` — the resolved parameter's metadata plus the full current consent map. */
|
|
1473
|
+
interface ConsentActionParams {
|
|
1474
|
+
cookieId: string;
|
|
1475
|
+
status: ConsentStatus;
|
|
1476
|
+
cookie: Cookie | undefined;
|
|
1477
|
+
consent: ConsentValue | null;
|
|
1478
|
+
}
|
|
1479
|
+
/** Options for constructing a {@link ConsentAction} instance. */
|
|
1480
|
+
interface ConsentActionOptions {
|
|
1481
|
+
/** The consent parameter ID to watch (e.g. `'analytics_storage'`). */
|
|
1482
|
+
id: string;
|
|
1483
|
+
/** The `ConsentiSetup` widget instance to read consent from. */
|
|
1484
|
+
widget: ConsentiSetup;
|
|
1485
|
+
/**
|
|
1486
|
+
* When `true` (default), the callbacks re-fire automatically on every future consent
|
|
1487
|
+
* change. Set to `false` to evaluate consent only once at construction time — no
|
|
1488
|
+
* event listener is attached.
|
|
1489
|
+
*/
|
|
1490
|
+
bind?: boolean;
|
|
1491
|
+
/** Called when the parameter's status transitions to `'granted'`. */
|
|
1492
|
+
onGrant?: (params: ConsentActionParams) => void;
|
|
1493
|
+
/** Called when the parameter's status transitions away from `'granted'` (`'denied'` or `'objected'`). */
|
|
1494
|
+
onDeny?: (params: ConsentActionParams) => void;
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* Watches a single consent parameter's grant status and fires `onGrant`/`onDeny`
|
|
1498
|
+
* callbacks on transitions. Call {@link ConsentAction.destroy} when no longer
|
|
1499
|
+
* needed to remove the event listener.
|
|
1500
|
+
*/
|
|
1501
|
+
declare class ConsentAction {
|
|
1502
|
+
private readonly options;
|
|
1503
|
+
private granted;
|
|
1504
|
+
private readonly handler;
|
|
1505
|
+
constructor(options: ConsentActionOptions);
|
|
1506
|
+
private evaluate;
|
|
1507
|
+
/** Removes the event listener (if bound). */
|
|
1508
|
+
destroy(): void;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
/**
|
|
1512
|
+
* CategoryAction — runs a callback based on a category's rollup consent state.
|
|
1513
|
+
*
|
|
1514
|
+
* A category is considered "granted" only when *every* parameter it contains is
|
|
1515
|
+
* `'granted'` — matching the preference modal's tri-state rollup rule. `onDeny`
|
|
1516
|
+
* fires for both a fully-denied category and a partially-granted ("mixed") one,
|
|
1517
|
+
* since neither represents full consent for the category.
|
|
1518
|
+
*
|
|
1519
|
+
* Same lifecycle as `ConsentAction`: evaluates immediately on construction,
|
|
1520
|
+
* re-evaluates on `consenti:consentSubmitted`, `destroy()` to unbind.
|
|
1521
|
+
*
|
|
1522
|
+
* @example
|
|
1523
|
+
* ```ts
|
|
1524
|
+
* import { ConsentiSetup, CategoryAction } from '@consenti/ui'
|
|
1525
|
+
*
|
|
1526
|
+
* const widget = new ConsentiSetup({ core: { profileId: 0 } })
|
|
1527
|
+
* await widget.ready
|
|
1528
|
+
*
|
|
1529
|
+
* new CategoryAction({
|
|
1530
|
+
* id: 'marketing',
|
|
1531
|
+
* widget,
|
|
1532
|
+
* onGrant: () => adSdk.enableAll(),
|
|
1533
|
+
* onDeny: () => adSdk.disableAll(),
|
|
1534
|
+
* })
|
|
1535
|
+
* ```
|
|
1536
|
+
*/
|
|
1537
|
+
|
|
1538
|
+
/** Passed to `onGrant`/`onDeny` — the category's member parameter IDs plus the full current consent map. */
|
|
1539
|
+
interface CategoryActionParams {
|
|
1540
|
+
categoryId: string;
|
|
1541
|
+
cookieIds: string[];
|
|
1542
|
+
consent: ConsentValue | null;
|
|
1543
|
+
}
|
|
1544
|
+
/** Options for constructing a {@link CategoryAction} instance. */
|
|
1545
|
+
interface CategoryActionOptions {
|
|
1546
|
+
/** The category ID to watch (e.g. `'marketing'`). */
|
|
1547
|
+
id: string;
|
|
1548
|
+
/** The `ConsentiSetup` widget instance to read consent from. */
|
|
1549
|
+
widget: ConsentiSetup;
|
|
1550
|
+
/**
|
|
1551
|
+
* When `true` (default), the callbacks re-fire automatically on every future consent
|
|
1552
|
+
* change. Set to `false` to evaluate consent only once at construction time — no
|
|
1553
|
+
* event listener is attached.
|
|
1554
|
+
*/
|
|
1555
|
+
bind?: boolean;
|
|
1556
|
+
/** Called when every parameter in the category transitions to `'granted'`. */
|
|
1557
|
+
onGrant?: (params: CategoryActionParams) => void;
|
|
1558
|
+
/** Called when the category transitions away from fully-granted (any parameter denied/objected). */
|
|
1559
|
+
onDeny?: (params: CategoryActionParams) => void;
|
|
1560
|
+
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Watches a category's rollup grant status and fires `onGrant`/`onDeny` callbacks
|
|
1563
|
+
* on transitions. Call {@link CategoryAction.destroy} when no longer needed to
|
|
1564
|
+
* remove the event listener.
|
|
1565
|
+
*/
|
|
1566
|
+
declare class CategoryAction {
|
|
1567
|
+
private readonly options;
|
|
1568
|
+
private granted;
|
|
1569
|
+
private readonly handler;
|
|
1570
|
+
constructor(options: CategoryActionOptions);
|
|
1571
|
+
private evaluate;
|
|
1572
|
+
/** Removes the event listener (if bound). */
|
|
1573
|
+
destroy(): void;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
/**
|
|
1577
|
+
* CategoryScript — conditionally loads/unloads a third-party `<script>` tag
|
|
1578
|
+
* based on a whole category's rollup consent state, instead of one parameter.
|
|
1579
|
+
*
|
|
1580
|
+
* A category is considered "granted" only when *every* parameter it contains is
|
|
1581
|
+
* `'granted'` — matching the preference modal's tri-state rollup rule and
|
|
1582
|
+
* `CategoryAction`'s behavior. Injection mechanics (src validation, inline-script
|
|
1583
|
+
* escape hatch, attribute filtering) are identical to `ConsentScript` — both share
|
|
1584
|
+
* the same underlying `injectScript`/`revokeScript` helpers.
|
|
1585
|
+
*
|
|
1586
|
+
* @example
|
|
1587
|
+
* ```ts
|
|
1588
|
+
* import { ConsentiSetup, CategoryScript } from '@consenti/ui'
|
|
1589
|
+
*
|
|
1590
|
+
* const widget = new ConsentiSetup({ core: { profileId: 0 } })
|
|
1591
|
+
* await widget.ready
|
|
1592
|
+
*
|
|
1593
|
+
* new CategoryScript({
|
|
1594
|
+
* categoryId: 'marketing',
|
|
1595
|
+
* widget,
|
|
1596
|
+
* src: 'https://example.com/ad-pixel.js',
|
|
1597
|
+
* })
|
|
1598
|
+
* ```
|
|
1599
|
+
*/
|
|
1600
|
+
|
|
1601
|
+
/** Options for constructing a {@link CategoryScript} instance. */
|
|
1602
|
+
interface CategoryScriptOptions {
|
|
1603
|
+
/** The category ID to watch (e.g. `'marketing'`). */
|
|
1604
|
+
categoryId: string;
|
|
1605
|
+
/** The `ConsentiSetup` widget instance to read consent from. */
|
|
1606
|
+
widget: ConsentiSetup;
|
|
1607
|
+
/** Remote script `src` URL to inject when every parameter in the category is granted. */
|
|
1608
|
+
src?: string;
|
|
1609
|
+
/**
|
|
1610
|
+
* Inline JavaScript to inject when granted (e.g. a GTM snippet).
|
|
1611
|
+
* WARNING: this string is assigned directly to `script.innerHTML` — only
|
|
1612
|
+
* pass a static, trusted literal. Never pass user-supplied or remote content.
|
|
1613
|
+
*/
|
|
1614
|
+
unsafeInnerHTML?: string;
|
|
1615
|
+
/**
|
|
1616
|
+
* Additional HTML attributes applied to the injected `<script>` element.
|
|
1617
|
+
* Set a key to an empty string for boolean attributes (e.g. `{ async: '', defer: '' }`).
|
|
1618
|
+
*/
|
|
1619
|
+
attributes?: Record<string, string>;
|
|
1620
|
+
/** Called after the `<script>` element has been appended to `<head>`. */
|
|
1621
|
+
onLoad?: () => void;
|
|
1622
|
+
/** Called after the `<script>` element has been removed from the DOM. */
|
|
1623
|
+
onRevoke?: () => void;
|
|
1624
|
+
/**
|
|
1625
|
+
* When `true` (default), the script is automatically removed when the category is no
|
|
1626
|
+
* longer fully granted and re-injected when it becomes fully granted again. Set to
|
|
1627
|
+
* `false` to evaluate consent only once at construction time — no event listener is
|
|
1628
|
+
* attached and the script is never auto-removed.
|
|
1629
|
+
*/
|
|
1630
|
+
bind?: boolean;
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Conditionally injects and removes a `<script>` element based on a category's
|
|
1634
|
+
* rollup consent status (every member parameter granted).
|
|
1635
|
+
*
|
|
1636
|
+
* Call {@link CategoryScript.destroy} when the trigger is no longer needed
|
|
1637
|
+
* (e.g. on SPA route unmount) to remove the event listener and the injected element.
|
|
1638
|
+
*/
|
|
1639
|
+
declare class CategoryScript {
|
|
1640
|
+
private readonly options;
|
|
1641
|
+
private scriptEl;
|
|
1642
|
+
private readonly handler;
|
|
1643
|
+
constructor(options: CategoryScriptOptions);
|
|
1644
|
+
private evaluate;
|
|
1645
|
+
private inject;
|
|
1646
|
+
private revoke;
|
|
1647
|
+
/**
|
|
1648
|
+
* Removes the event listener and the injected `<script>` element (if present).
|
|
1649
|
+
* Call this when the widget is destroyed or the script is no longer needed.
|
|
1650
|
+
*/
|
|
1651
|
+
destroy(): void;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
/**
|
|
1655
|
+
* BannerTrigger — a pre-built accessible UI element that reopens the Consenti
|
|
1656
|
+
* banner or preference modal when clicked.
|
|
892
1657
|
*
|
|
893
1658
|
* Use this to add a "Cookie Settings" link in your site footer or cookie policy
|
|
894
1659
|
* page without wiring up the click handler manually or importing the widget module
|
|
895
1660
|
* into your layout component.
|
|
896
1661
|
*
|
|
1662
|
+
* (Renamed from `CookieTrigger` — it was never scoped to a specific cookie, it
|
|
1663
|
+
* just opens the banner or modal.)
|
|
1664
|
+
*
|
|
897
1665
|
* @example
|
|
898
1666
|
* ```ts
|
|
899
|
-
* import { ConsentiSetup,
|
|
1667
|
+
* import { ConsentiSetup, BannerTrigger } from '@consenti/ui'
|
|
900
1668
|
*
|
|
901
1669
|
* const widget = new ConsentiSetup({ core: { profileId: 0 } })
|
|
902
1670
|
*
|
|
903
1671
|
* // Attach to an existing element
|
|
904
|
-
* new
|
|
1672
|
+
* new BannerTrigger({ widget, el: '#footer-cookie-settings' })
|
|
905
1673
|
*
|
|
906
1674
|
* // — or — create a new button and place it yourself
|
|
907
|
-
* const trigger = new
|
|
1675
|
+
* const trigger = new BannerTrigger({ widget, label: 'Cookie Settings' })
|
|
908
1676
|
* document.querySelector('.site-footer')?.appendChild(trigger.getElement())
|
|
909
1677
|
* ```
|
|
910
1678
|
*/
|
|
911
1679
|
|
|
912
|
-
/** Options for constructing a {@link
|
|
913
|
-
interface
|
|
1680
|
+
/** Options for constructing a {@link BannerTrigger} instance. */
|
|
1681
|
+
interface BannerTriggerOptions {
|
|
914
1682
|
/** The widget instance to control when the trigger is clicked. */
|
|
915
1683
|
widget: ConsentiSetup;
|
|
916
1684
|
/**
|
|
917
1685
|
* Element to attach the click handler to.
|
|
918
1686
|
* - `HTMLElement` — used directly.
|
|
919
1687
|
* - `string` — treated as a CSS selector; the first matching element is used.
|
|
920
|
-
* - Omitted — a new `<button>` is created. Retrieve it with {@link
|
|
1688
|
+
* - Omitted — a new `<button>` is created. Retrieve it with {@link BannerTrigger.getElement}
|
|
921
1689
|
* and append it to the DOM at the desired location.
|
|
922
1690
|
*/
|
|
923
1691
|
el?: HTMLElement | string;
|
|
@@ -940,12 +1708,12 @@ interface CookieTriggerOptions {
|
|
|
940
1708
|
* The created button uses the `.consenti-btn` and `.consenti-btn--text` classes so
|
|
941
1709
|
* it inherits the widget's theme automatically.
|
|
942
1710
|
*/
|
|
943
|
-
declare class
|
|
1711
|
+
declare class BannerTrigger {
|
|
944
1712
|
private readonly el;
|
|
945
1713
|
private readonly clickHandler;
|
|
946
1714
|
/** Whether this instance created the element (used to decide if `destroy()` removes it). */
|
|
947
1715
|
private readonly created;
|
|
948
|
-
constructor(options:
|
|
1716
|
+
constructor(options: BannerTriggerOptions);
|
|
949
1717
|
/**
|
|
950
1718
|
* Returns the trigger element.
|
|
951
1719
|
* When no `el` was provided, append the returned element to the desired location
|
|
@@ -959,4 +1727,82 @@ declare class CookieTrigger {
|
|
|
959
1727
|
destroy(): void;
|
|
960
1728
|
}
|
|
961
1729
|
|
|
962
|
-
|
|
1730
|
+
/**
|
|
1731
|
+
* Declarative DOM-scan bindings — a zero-JS integration path for gating
|
|
1732
|
+
* third-party scripts via `data-*` attributes instead of hand-written
|
|
1733
|
+
* `ConsentScript`/`CategoryScript` calls.
|
|
1734
|
+
*
|
|
1735
|
+
* ```html
|
|
1736
|
+
* <script type="text/plain" data-consenti-category-script="marketing" src="https://example.com/pixel.js"></script>
|
|
1737
|
+
* <script type="text/plain" data-consenti-consent-script="analytics_storage">/* inline snippet *\/</script>
|
|
1738
|
+
* <script type="text/plain" data-consenti-consent-script="ad_storage" data-consenti-bind="false" src="..."></script>
|
|
1739
|
+
* ```
|
|
1740
|
+
*
|
|
1741
|
+
* Scanned automatically once per `ConsentiSetup.init()` cycle (after `init()`
|
|
1742
|
+
* completes — so it respects `autoInit: false`, only running once the widget is
|
|
1743
|
+
* actually initialized, however `init()` was triggered). The scanned tags are
|
|
1744
|
+
* read-only config sources and stay inert (`type="text/plain"`) in the DOM
|
|
1745
|
+
* permanently — `ConsentScript`/`CategoryScript` inject their own separate
|
|
1746
|
+
* `<script>` element exactly as they do when constructed by hand.
|
|
1747
|
+
*/
|
|
1748
|
+
|
|
1749
|
+
/**
|
|
1750
|
+
* Scans the document for `<script type="text/plain">` tags carrying
|
|
1751
|
+
* `data-consenti-consent-script` or `data-consenti-category-script`, and
|
|
1752
|
+
* instantiates `ConsentScript`/`CategoryScript` for each. Called automatically
|
|
1753
|
+
* by `ConsentiSetup` at the end of every `init()` cycle.
|
|
1754
|
+
*
|
|
1755
|
+
* v1 scans once automatically; scripts injected into the DOM after that point
|
|
1756
|
+
* (e.g. by a late-loading CMS widget) are not picked up automatically — call this
|
|
1757
|
+
* function again manually after adding more tags dynamically if needed. Each element
|
|
1758
|
+
* is only ever scanned once (marked with `data-consenti-scanned`), so calling this
|
|
1759
|
+
* again is safe — it only processes newly-added tags, never re-instantiates a watcher
|
|
1760
|
+
* for one already scanned.
|
|
1761
|
+
*
|
|
1762
|
+
* Returns the created watchers — `ConsentiSetup` holds onto these and calls
|
|
1763
|
+
* `.destroy()` on each when the widget itself is destroyed, since a scanner-created
|
|
1764
|
+
* watcher has no other owner to release its `consenti:consentSubmitted` listener.
|
|
1765
|
+
*/
|
|
1766
|
+
declare function scanConsentScripts(widget: ConsentiSetup): Array<ConsentScript | CategoryScript>;
|
|
1767
|
+
|
|
1768
|
+
/**
|
|
1769
|
+
* Standalone resolver for the parental-consent hook (see `AgeGate`/`ConsentiSetup.resolveAgeGate`).
|
|
1770
|
+
* Not a `ConsentiSetup` instance method — the parent typically opens the token link (emailed by
|
|
1771
|
+
* the host's own eventBus listener, see `consenti:parentalConsentRequired`) on a fresh page or
|
|
1772
|
+
* even a different device, with no live widget instance around at all.
|
|
1773
|
+
*/
|
|
1774
|
+
|
|
1775
|
+
interface ParentalConsentApiConfig {
|
|
1776
|
+
baseUrl?: string;
|
|
1777
|
+
authToken?: string;
|
|
1778
|
+
}
|
|
1779
|
+
/**
|
|
1780
|
+
* POSTs a parental-consent token to `POST /consent/parental-consent-resolve`. On success,
|
|
1781
|
+
* dispatches `consenti:parentalConsentResolved` on `window` (same mechanism `EventBus.dispatch`
|
|
1782
|
+
* uses) so any page with a live widget instance can react — what "resolved" should actually do to
|
|
1783
|
+
* consent state is left to that listener, matching the "we provide the hook, not the behavior"
|
|
1784
|
+
* scope of this whole feature. Throws on an invalid/expired token or network failure.
|
|
1785
|
+
*/
|
|
1786
|
+
declare function resolveParentalConsent(token: string, apiConfig?: ParentalConsentApiConfig): Promise<ParentalConsentGrantedDetail>;
|
|
1787
|
+
|
|
1788
|
+
/**
|
|
1789
|
+
* Builds a synchronous, dependency-free `<head>` snippet that freezes Google Consent Mode
|
|
1790
|
+
* to denied-by-default the instant a visitor's browser sends the Global Privacy Control (GPC)
|
|
1791
|
+
* signal — before any tag-loading script runs, including GTM/gtag.js itself and Consenti's own
|
|
1792
|
+
* bundle (which only applies GPC once it has loaded, parsed, and initialized asynchronously).
|
|
1793
|
+
*
|
|
1794
|
+
* This is a documentation helper, not something the widget loads itself: paste the returned
|
|
1795
|
+
* string as the very first `<script>` in `<head>`, ahead of GTM/gtag.js and the Consenti bundle.
|
|
1796
|
+
* It only touches `window[dataLayerName]`/`window.gtag` (the same stub-queue pattern
|
|
1797
|
+
* `EventBus.initConsentMode()` uses), so it's safe to run before those exist and harmless to
|
|
1798
|
+
* run again after they do — Consenti's own `gtag('consent', 'default', …)` call on init just
|
|
1799
|
+
* pushes another entry onto the same queue.
|
|
1800
|
+
*
|
|
1801
|
+
* The default values pushed here mirror `getGoogleGTMConsent({})` in `consent-mapper.ts` (safe
|
|
1802
|
+
* defaults for an empty consent map) — keep the two in sync if either changes.
|
|
1803
|
+
*/
|
|
1804
|
+
declare function buildSyncGpcSnippet(options?: {
|
|
1805
|
+
dataLayerName?: string;
|
|
1806
|
+
}): string;
|
|
1807
|
+
|
|
1808
|
+
export { type ApiConfig, BannerTrigger, type BannerTriggerOptions, type Button, type ButtonAction, type ButtonStyle, type Category, CategoryAction, type CategoryActionOptions, type CategoryActionParams, type CategoryMap, CategoryScript, type CategoryScriptOptions, type ComplianceWidgetConfig, ConsentAction, type ConsentActionOptions, type ConsentActionParams, type ConsentAction$1 as ConsentActionType, type ConsentEvent, type ConsentReceipt, type ConsentRecord, ConsentScript, type ConsentScriptOptions, type ConsentStatus, type ConsentValue, type ConsentiConfig, type ConsentiEventName, type ConsentiMessage, ConsentiPlugin, ConsentiProfile, ConsentiSetup, type ConsentiWidgetAPI, type Cookie, type CookieMap, type CookieOptions, type CoreConfig, type GpcBanner, type GtmConfig, type IdentifyEventDetail, type LocaleTranslations, type MainBanner, type ParentalConsentApiConfig, type ParentalConsentGrantedDetail, type ParentalConsentRequiredDetail, type ParsedConsent, type PreferenceModal, type ProfileConfig, type ProfileTranslations, type RegisterableProfileConfig, type ResolvedProfile, type TcfWidgetConfig, type ThemeConfig, type UtilsConfig, type VisitorIdentity, buildSyncGpcSnippet, resolveParentalConsent, scanConsentScripts };
|