@consenti/ui 0.2.0 → 0.3.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 +255 -66
- package/dist/angular.d.cts +306 -130
- package/dist/angular.d.ts +306 -130
- package/dist/chunk-3EXCD24H.mjs +2 -0
- package/dist/{chunk-K2UN3O67.mjs.map → chunk-3EXCD24H.mjs.map} +1 -1
- package/dist/chunk-J4BKXUD6.mjs +2 -0
- package/dist/chunk-J4BKXUD6.mjs.map +1 -0
- package/dist/http-AQVVUCX6.mjs +2 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +616 -105
- 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-OEZAKEWL.mjs +2 -0
- package/dist/profiles-OEZAKEWL.mjs.map +1 -0
- package/dist/react.d.cts +285 -108
- package/dist/react.d.ts +285 -108
- package/dist/vue.d.cts +257 -57
- package/dist/vue.d.ts +257 -57
- package/package.json +8 -7
- 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,18 @@
|
|
|
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
|
|
|
6
14
|
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"];
|
|
15
|
+
declare const COOKIE_PURPOSE_IDS: readonly ["necessary", "functional", "preferences", "analytics", "marketing"];
|
|
7
16
|
|
|
8
17
|
/**
|
|
9
18
|
* Compliance-related literal types, derived from the regulation/group ID data
|
|
@@ -19,6 +28,13 @@ declare const COMPLIANCE_GROUP_IDS: readonly ["opt-in", "opt-out", "opt-out-stri
|
|
|
19
28
|
*/
|
|
20
29
|
|
|
21
30
|
type ComplianceGroupId = typeof COMPLIANCE_GROUP_IDS[number];
|
|
31
|
+
/**
|
|
32
|
+
* `(string & {})` (rather than plain `string`) keeps IDE autocomplete for the
|
|
33
|
+
* known `ComplianceGroupId` literals while still allowing any other string —
|
|
34
|
+
* used to target a profile authored against a custom (non-built-in)
|
|
35
|
+
* `customComplianceGroup` instead of one of the 8 built-in groups.
|
|
36
|
+
*/
|
|
37
|
+
type ComplianceType = 'auto' | ComplianceGroupId | (string & {}) | Symbol;
|
|
22
38
|
|
|
23
39
|
interface ComplianceMapData {
|
|
24
40
|
version: string;
|
|
@@ -33,24 +49,67 @@ interface CountryComplianceEntry {
|
|
|
33
49
|
description: string;
|
|
34
50
|
}>;
|
|
35
51
|
}
|
|
52
|
+
interface ConsentDbRecord {
|
|
53
|
+
id: string;
|
|
54
|
+
tenantId: string;
|
|
55
|
+
visitorId: string;
|
|
56
|
+
profileId: string;
|
|
57
|
+
locale: string;
|
|
58
|
+
consentJson: ConsentValue;
|
|
59
|
+
gpcDetected: boolean;
|
|
60
|
+
source: 'banner' | 'api' | 'import';
|
|
61
|
+
ageVerified?: boolean;
|
|
62
|
+
parentalConsentToken?: string;
|
|
63
|
+
tcfString?: string;
|
|
64
|
+
/** HMAC-SHA256 signature over the record's core fields, hex-encoded. Only present when
|
|
65
|
+
* `consentSigningKey` is configured — opt-in tamper-evidence for server-stored records,
|
|
66
|
+
* independent of the widget's own cookie-signing (`core.cookieSigningKey`). */
|
|
67
|
+
signature?: string;
|
|
68
|
+
createdAt: string;
|
|
69
|
+
updatedAt: string;
|
|
70
|
+
}
|
|
36
71
|
|
|
37
72
|
type ConsentStatus = 'granted' | 'denied' | 'objected';
|
|
38
|
-
type ConsentAction = 'accept_all' | 'reject_all' | 'custom' | 'update';
|
|
73
|
+
type ConsentAction$1 = 'accept_all' | 'reject_all' | 'custom' | 'update';
|
|
39
74
|
type ConsentValue = Record<string, ConsentStatus>;
|
|
75
|
+
/**
|
|
76
|
+
* Output format for getConsent(type).
|
|
77
|
+
* 'default' → raw ConsentValue (existing behaviour)
|
|
78
|
+
* 'google-gtm' → Google Consent Mode v2 keys + ads_data_redaction, url_passthrough
|
|
79
|
+
* 'category' → consent per CookiePurpose category
|
|
80
|
+
* 'adobe' → { analytics, target, manager, optimizer }
|
|
81
|
+
* 'meta' → { pixel, api, plugins, facebookLogin }
|
|
82
|
+
* 'microsoft-clarity' → { session, heatmaps, performance }
|
|
83
|
+
* 'twilio-segment' → { identify, page, track, group, alias }
|
|
84
|
+
*/
|
|
85
|
+
type ConsentType = 'default' | 'google-gtm' | 'category' | 'adobe' | 'meta' | 'microsoft-clarity' | 'twilio-segment';
|
|
86
|
+
type GpcMode = 'ignore' | 'honor' | 'strict';
|
|
87
|
+
type LegalBasis = 'mandatory' | 'consent' | 'legitimate_interest';
|
|
88
|
+
type CookiePurpose = typeof COOKIE_PURPOSE_IDS[number];
|
|
89
|
+
/**
|
|
90
|
+
* A single consent parameter (tracker/cookie definition).
|
|
91
|
+
* Keyed by its own id inside `Record<string, Cookie>` — the map key IS the id,
|
|
92
|
+
* there is no `id` field on the value itself.
|
|
93
|
+
*/
|
|
40
94
|
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';
|
|
95
|
+
purpose?: CookiePurpose;
|
|
47
96
|
listenGpc?: boolean;
|
|
48
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Pre-grant this parameter's default consent to 'granted' (instead of the
|
|
99
|
+
* compliance-group-driven default) when no stored decision exists yet.
|
|
100
|
+
* Only meaningful when the owning category's `legalBasis === 'consent'` —
|
|
101
|
+
* `mandatory`/`legitimate_interest` categories are already effectively
|
|
102
|
+
* pre-granted regardless of this flag. Never overrides an active GPC signal.
|
|
103
|
+
* Default: false.
|
|
104
|
+
*/
|
|
105
|
+
preGrant?: boolean;
|
|
49
106
|
tcfVendorId?: number;
|
|
50
107
|
tcfPurposes?: number[];
|
|
51
108
|
tcfSpecialFeatures?: number[];
|
|
52
109
|
cpraCategory?: 'sale' | 'sharing' | 'sensitive';
|
|
53
110
|
}
|
|
111
|
+
/** `Cookie` keyed by its own id — the standard shape used everywhere a parameter list is passed around. */
|
|
112
|
+
type CookieMap = Record<string, Cookie>;
|
|
54
113
|
type ButtonStyle = 'primary' | 'secondary' | 'text' | 'accent';
|
|
55
114
|
type ButtonAction = 'submit' | 'manage' | 'close' | 'custom' | 'link';
|
|
56
115
|
interface Button {
|
|
@@ -59,8 +118,11 @@ interface Button {
|
|
|
59
118
|
action: ButtonAction;
|
|
60
119
|
cookies?: string[] | '*' | '!';
|
|
61
120
|
url?: string;
|
|
62
|
-
type?: string;
|
|
63
121
|
}
|
|
122
|
+
/** `Button` keyed by its own id — e.g. `'accept-all'`. The map key IS the id, rendered as the DOM
|
|
123
|
+
* `id` (`consenti-btn-{id}`) so integrators can target specific buttons, and is what
|
|
124
|
+
* `profileOverride`'s `deepMerge` deletes by (`{ 'reject-optional': null }` removes one button). */
|
|
125
|
+
type ButtonMap = Record<string, Button>;
|
|
64
126
|
interface MainBanner {
|
|
65
127
|
position: 'top' | 'bottom' | 'middle' | 'left-bottom' | 'right-bottom';
|
|
66
128
|
overlayOpacity?: number;
|
|
@@ -69,34 +131,50 @@ interface MainBanner {
|
|
|
69
131
|
heading?: string;
|
|
70
132
|
headingTag?: string;
|
|
71
133
|
htmlText: string;
|
|
72
|
-
buttons:
|
|
134
|
+
buttons: ButtonMap;
|
|
135
|
+
/** Stack buttons vertically below this viewport width in px. 0 or undefined = disabled. Default: 576. */
|
|
136
|
+
stackButtonsOnBreakpoint?: number;
|
|
137
|
+
/** Trap keyboard Tab focus within the consent root while this banner is visible. */
|
|
138
|
+
trapFocus?: boolean;
|
|
73
139
|
}
|
|
74
140
|
type GpcBanner = MainBanner;
|
|
141
|
+
/**
|
|
142
|
+
* A consent category — the single source of legal basis for every parameter
|
|
143
|
+
* it lists in `cookies`. Keyed by its own id inside `Record<string, Category>` —
|
|
144
|
+
* the map key IS the id, there is no `id` field on the value itself.
|
|
145
|
+
*
|
|
146
|
+
* A parameter must belong to exactly one category (enforced at authoring time,
|
|
147
|
+
* not by this type) — that relationship is what `getCookieLegalBasis`/
|
|
148
|
+
* `isMandatoryCookie` (`@consenti/utils`) resolve at runtime.
|
|
149
|
+
*/
|
|
75
150
|
interface Category {
|
|
76
|
-
id: string;
|
|
77
151
|
heading: string;
|
|
78
152
|
headingTag?: string;
|
|
79
153
|
htmlText: string;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
description?: string;
|
|
85
|
-
};
|
|
154
|
+
legalBasis: LegalBasis;
|
|
155
|
+
/** Only meaningful when legalBasis === 'legitimate_interest' — the GDPR balancing-test justification shown to visitors. */
|
|
156
|
+
legitimateInterestDescription?: string;
|
|
157
|
+
/** IDs of the parameters (from the profile's `cookies` map) that belong to this category. */
|
|
86
158
|
cookies: string[];
|
|
87
159
|
}
|
|
160
|
+
/** `Category` keyed by its own id — the standard shape used everywhere a category list is passed around. */
|
|
161
|
+
type CategoryMap = Record<string, Category>;
|
|
88
162
|
interface PreferenceModal extends Omit<MainBanner, "position"> {
|
|
89
163
|
position?: 'left' | 'right' | 'center';
|
|
90
164
|
subheading?: string;
|
|
91
|
-
categories:
|
|
165
|
+
categories: CategoryMap;
|
|
92
166
|
persistent?: boolean;
|
|
93
167
|
/** Screen width in px below which the modal expands to full screen. Default: 576. Set to 0 to disable. */
|
|
94
168
|
mobileFullScreenBreakpoint?: number;
|
|
169
|
+
/** Label for the optional consent-receipt download checkbox (shown when `allowReceipt` is true). Falls back to a default when omitted. */
|
|
170
|
+
receiptLabel?: string;
|
|
171
|
+
/** Description shown beneath the consent-receipt checkbox. Falls back to a default when omitted. */
|
|
172
|
+
receiptDescription?: string;
|
|
95
173
|
}
|
|
96
174
|
interface LocaleTranslations {
|
|
97
|
-
mainBanner: MainBanner
|
|
98
|
-
gpcBanner?: GpcBanner
|
|
99
|
-
preferenceModal: PreferenceModal
|
|
175
|
+
mainBanner: DeepPartial<MainBanner>;
|
|
176
|
+
gpcBanner?: DeepPartial<GpcBanner>;
|
|
177
|
+
preferenceModal: DeepPartial<PreferenceModal>;
|
|
100
178
|
}
|
|
101
179
|
interface ProfileTranslations {
|
|
102
180
|
[locale: string]: LocaleTranslations;
|
|
@@ -110,64 +188,127 @@ interface LocaleTextContent {
|
|
|
110
188
|
mainBanner: {
|
|
111
189
|
heading?: string;
|
|
112
190
|
htmlText: string;
|
|
113
|
-
|
|
191
|
+
/** Keyed by the linked UI template's button id — was a positional array matched to
|
|
192
|
+
* `buttons[i]` by index; now matched by key, robust against button reordering. */
|
|
193
|
+
buttonLabels?: Record<string, string>;
|
|
114
194
|
};
|
|
115
195
|
gpcBanner: {
|
|
116
196
|
heading?: string;
|
|
117
197
|
htmlText: string;
|
|
118
|
-
buttonLabels?: string
|
|
198
|
+
buttonLabels?: Record<string, string>;
|
|
119
199
|
};
|
|
120
200
|
preferenceModal: {
|
|
121
201
|
heading: string;
|
|
122
202
|
subheading?: string;
|
|
123
203
|
htmlText?: string;
|
|
124
|
-
buttonLabels?: string
|
|
125
|
-
categories
|
|
126
|
-
|
|
204
|
+
buttonLabels?: Record<string, string>;
|
|
205
|
+
/** `legitimateInterestDescription` is only meaningful for categories whose legalBasis is 'legitimate_interest'; optional GDPR balancing-test text, translated per locale like heading/htmlText. */
|
|
206
|
+
categories: Record<string, {
|
|
127
207
|
heading: string;
|
|
128
208
|
htmlText: string;
|
|
129
|
-
|
|
209
|
+
legitimateInterestDescription?: string;
|
|
210
|
+
}>;
|
|
211
|
+
receiptLabel?: string;
|
|
212
|
+
receiptDescription?: string;
|
|
130
213
|
};
|
|
131
214
|
}
|
|
132
215
|
interface ProfileConfig {
|
|
133
|
-
|
|
216
|
+
id: string;
|
|
217
|
+
cookies?: CookieMap;
|
|
134
218
|
defaultLocale: string;
|
|
219
|
+
/** Days until consent expires and the visitor is asked again (profile-wide). Default: 365. */
|
|
220
|
+
expiryDays?: number;
|
|
135
221
|
translations?: ProfileTranslations;
|
|
136
|
-
|
|
222
|
+
mainBanner: MainBanner;
|
|
223
|
+
gpcBanner?: GpcBanner;
|
|
224
|
+
preferenceModal: PreferenceModal;
|
|
137
225
|
darkMode?: boolean;
|
|
138
226
|
allowedOrigins?: string[];
|
|
139
227
|
dpdpa?: DpdpaConfig;
|
|
140
228
|
regulation?: 'gdpr' | 'ccpa' | 'cpra' | 'dpdpa' | 'uk-gdpr' | 'lgpd' | 'pipeda' | 'popia' | 'pdpa-th' | 'appi' | 'kvkk';
|
|
141
229
|
regulations?: string[];
|
|
142
|
-
|
|
230
|
+
consentTemplateId?: string;
|
|
143
231
|
uiTemplateId?: string;
|
|
144
232
|
localeContents?: Record<string, LocaleTextContent>;
|
|
145
|
-
complianceGroup?:
|
|
146
|
-
/**
|
|
147
|
-
|
|
148
|
-
|
|
233
|
+
complianceGroup?: ComplianceGroupId;
|
|
234
|
+
/**
|
|
235
|
+
* Free-form identifier (lower-kebab-case) for profiles that don't map to one of the
|
|
236
|
+
* built-in `complianceGroup` values — the identifier the widget's `compliance.type`
|
|
237
|
+
* config targets to fetch this profile. Participates in activation, deactivation, and
|
|
238
|
+
* "one active profile per group" conflict detection the same way `complianceGroup` does;
|
|
239
|
+
* no `COMPLIANCE_GROUPS` validation rules or GPC defaults apply to it, since none exist
|
|
240
|
+
* for a free-form name.
|
|
241
|
+
*/
|
|
242
|
+
customComplianceGroup?: string;
|
|
243
|
+
/**
|
|
244
|
+
* Per-profile deltas applied on top of the consent template's authored `Cookie` values
|
|
245
|
+
* (e.g. an overridden `preGrant`) when resolving this profile — see the dashboard's Step 2
|
|
246
|
+
* pre-grant override UX. Keyed by cookie id; only the overridden fields need to be present.
|
|
247
|
+
*/
|
|
248
|
+
cookiesOverride?: Record<string, Partial<Cookie>>;
|
|
249
|
+
/**
|
|
250
|
+
* Reserved for a future phase — stored but not yet applied when resolving a profile.
|
|
251
|
+
* Intended to mirror `cookiesOverride` for per-category deltas.
|
|
252
|
+
*/
|
|
253
|
+
categoriesOverride?: Record<string, Partial<Category>>;
|
|
254
|
+
/**
|
|
255
|
+
* Reserved for a future phase — stored but not yet applied when resolving a profile.
|
|
256
|
+
* Intended to hold per-profile UI-template deltas.
|
|
257
|
+
*/
|
|
258
|
+
uiOverride?: Record<string, unknown>;
|
|
259
|
+
/**
|
|
260
|
+
* When registered via `registerProfile()` and `complianceGroup` matches one of
|
|
261
|
+
* Consenti's built-in groups: `false` (default) fully replaces the built-in
|
|
262
|
+
* embedded profile for that group; `true` deep-merges this config onto the
|
|
263
|
+
* built-in profile instead (only meaningful together with `complianceGroup`).
|
|
264
|
+
*/
|
|
265
|
+
deepMerge?: boolean;
|
|
266
|
+
gpcMode?: GpcMode;
|
|
149
267
|
isActive?: boolean;
|
|
150
268
|
hidePoweredBy?: boolean;
|
|
151
269
|
allowReceipt?: boolean;
|
|
152
270
|
/** Per-compliance extra config (e.g. DPDPA data fiduciary name). */
|
|
153
271
|
complianceConfig?: Record<string, string>;
|
|
272
|
+
/** Show a metadata footer strip in the banner/modal with Consent ID, Date, Version, Privacy Settings link. */
|
|
273
|
+
showFooterMetadata?: boolean;
|
|
274
|
+
/** Apply WCAG 2.1 AA button sizing (44px min-height), visible focus rings, and screen-reader labels. */
|
|
275
|
+
enhanceAccessibility?: boolean;
|
|
154
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Input accepted by `registerProfile()`. Either a complete `ProfileConfig`
|
|
279
|
+
* (used as-is or, if `complianceGroup` matches a built-in group, fully replaces
|
|
280
|
+
* it), or a partial overlay explicitly opted into `deepMerge: true` — merged
|
|
281
|
+
* onto the built-in embedded profile for `complianceGroup` at resolution time.
|
|
282
|
+
*/
|
|
283
|
+
type RegisterableProfileConfig = ProfileConfig | (DeepPartial<ProfileConfig> & {
|
|
284
|
+
complianceGroup: ComplianceGroupId;
|
|
285
|
+
deepMerge: true;
|
|
286
|
+
});
|
|
155
287
|
interface ResolvedProfile {
|
|
156
|
-
id:
|
|
157
|
-
|
|
158
|
-
version
|
|
288
|
+
id: string;
|
|
289
|
+
/** Incremented in place on every save of this profile. Absent for embedded/local profiles that have no server-side version counter. */
|
|
290
|
+
version?: number;
|
|
159
291
|
defaultLocale: string;
|
|
160
292
|
locales?: string[];
|
|
161
|
-
cookies:
|
|
293
|
+
cookies: CookieMap;
|
|
294
|
+
/** Days until consent expires and the visitor is asked again (profile-wide). Default: 365. */
|
|
295
|
+
expiryDays?: number;
|
|
296
|
+
allowReceipt?: boolean;
|
|
162
297
|
mainBanner: MainBanner;
|
|
163
298
|
gpcBanner?: GpcBanner;
|
|
164
299
|
preferenceModal: PreferenceModal;
|
|
165
300
|
cookieSigningKey?: string;
|
|
166
301
|
dpdpa?: DpdpaConfig;
|
|
167
302
|
darkMode?: boolean;
|
|
168
|
-
gpcMode?:
|
|
169
|
-
complianceGroup?:
|
|
303
|
+
gpcMode?: GpcMode;
|
|
304
|
+
complianceGroup?: ComplianceGroupId;
|
|
170
305
|
complianceConfig?: Record<string, string>;
|
|
306
|
+
/** Falls back to `true` (hidden) if neither the widget config nor the profile set it. */
|
|
307
|
+
hidePoweredBy?: boolean;
|
|
308
|
+
/** Show metadata footer strip (Consent ID, Date, Version, Privacy Settings link). */
|
|
309
|
+
showFooterMetadata?: boolean;
|
|
310
|
+
/** Apply WCAG 2.1 AA accessibility enhancements to the widget. */
|
|
311
|
+
enhanceAccessibility?: boolean;
|
|
171
312
|
}
|
|
172
313
|
type WidgetCountryResolverFn = () => Promise<{
|
|
173
314
|
country: string | null;
|
|
@@ -179,12 +320,20 @@ interface AgeGateWidgetConfig {
|
|
|
179
320
|
minimumAge: number;
|
|
180
321
|
requireParentalConsent?: boolean;
|
|
181
322
|
}
|
|
323
|
+
/** Mirrors the server-side `TcfConfig` shape (`@consenti/api`) — `cmpId`/`cmpVersion` must match
|
|
324
|
+
* what the backend uses to encode `tcfString`, since both feed the same simplified TC string. */
|
|
325
|
+
interface TcfWidgetConfig {
|
|
326
|
+
enabled: boolean;
|
|
327
|
+
cmpId: number;
|
|
328
|
+
cmpVersion: number;
|
|
329
|
+
}
|
|
182
330
|
interface ComplianceWidgetConfig {
|
|
183
|
-
type?:
|
|
331
|
+
type?: ComplianceType;
|
|
184
332
|
geoDataProvider?: 'default' | WidgetCountryResolverFn;
|
|
185
333
|
autoComplianceMap?: 'default' | ComplianceMapData | 'auto';
|
|
186
334
|
complianceMapUrl?: string;
|
|
187
335
|
ageGate?: AgeGateWidgetConfig;
|
|
336
|
+
tcf?: TcfWidgetConfig;
|
|
188
337
|
}
|
|
189
338
|
interface GtmConfig {
|
|
190
339
|
containerId?: string;
|
|
@@ -192,6 +341,7 @@ interface GtmConfig {
|
|
|
192
341
|
dataLayer?: string;
|
|
193
342
|
urlPassthrough?: boolean;
|
|
194
343
|
adsDataRedaction?: boolean;
|
|
344
|
+
verbose?: boolean;
|
|
195
345
|
}
|
|
196
346
|
interface UtilsConfig {
|
|
197
347
|
gtm?: GtmConfig;
|
|
@@ -201,7 +351,7 @@ interface ApiConfig {
|
|
|
201
351
|
baseUrl?: string;
|
|
202
352
|
authToken?: string;
|
|
203
353
|
tenantId?: string;
|
|
204
|
-
complianceGroup?:
|
|
354
|
+
complianceGroup?: ComplianceGroupId;
|
|
205
355
|
trustDomain?: boolean;
|
|
206
356
|
}
|
|
207
357
|
interface ThemeConfig {
|
|
@@ -225,8 +375,10 @@ interface ThemeConfig {
|
|
|
225
375
|
}
|
|
226
376
|
interface CoreConfig {
|
|
227
377
|
tenantId?: string;
|
|
228
|
-
autoHonorGPC?: boolean | 'strict';
|
|
229
378
|
locale?: string;
|
|
379
|
+
/** Text direction for the banner/modal root. `'auto'` (default) derives it from `locale`
|
|
380
|
+
* (Arabic, Hebrew, Persian, Urdu, ... → `rtl`); set explicitly to override. */
|
|
381
|
+
dir?: 'ltr' | 'rtl' | 'auto';
|
|
230
382
|
disableCssTemplate?: boolean;
|
|
231
383
|
cookieSigningKey?: string;
|
|
232
384
|
allowReceipt?: boolean;
|
|
@@ -239,7 +391,11 @@ interface CoreConfig {
|
|
|
239
391
|
console?: Array<'info' | 'log' | 'warning' | 'error'>;
|
|
240
392
|
}
|
|
241
393
|
interface ConsentiConfig {
|
|
242
|
-
|
|
394
|
+
verbose?: boolean;
|
|
395
|
+
/** Optional — every field of `CoreConfig` is itself optional, so `new ConsentiSetup({})` and
|
|
396
|
+
* `new ConsentiSetup({ compliance: { type: 'opt-in' } })` (omitting `core` entirely) both work,
|
|
397
|
+
* matching the widget's own "Minimal config" documentation. */
|
|
398
|
+
core?: CoreConfig;
|
|
243
399
|
compliance?: ComplianceWidgetConfig;
|
|
244
400
|
rootEl?: string | HTMLElement;
|
|
245
401
|
darkMode?: boolean;
|
|
@@ -251,10 +407,12 @@ interface ConsentiConfig {
|
|
|
251
407
|
/** When true, suppresses the "Powered by Consenti" footer link in the banner and modal. */
|
|
252
408
|
hidePoweredBy?: boolean;
|
|
253
409
|
}
|
|
254
|
-
type ConsentiEventName = 'bannerInitialized' | 'consenti:bannerInitialized' | 'bannerVisibility' | 'consenti:bannerVisibility' | 'modalVisibility' | 'consenti:modalVisibility' | 'consentBeingSubmitted' | 'consenti:consentBeingSubmitted' | 'consentSubmitted' | 'consenti:consentSubmitted';
|
|
410
|
+
type ConsentiEventName = 'bannerInitialized' | 'consenti:bannerInitialized' | 'bannerVisibility' | 'consenti:bannerVisibility' | 'modalVisibility' | 'consenti:modalVisibility' | 'consentBeingSubmitted' | 'consenti:consentBeingSubmitted' | 'consentSubmitted' | 'consenti:consentSubmitted' | 'parentalConsentRequired' | 'consenti:parentalConsentRequired';
|
|
255
411
|
interface ConsentiWidgetAPI {
|
|
256
412
|
hasConsent(): boolean;
|
|
257
413
|
getConsent(): ConsentValue | null;
|
|
414
|
+
getConsent(type: ConsentType): Record<string, string> | null;
|
|
415
|
+
getConsent(type?: ConsentType): ConsentValue | Record<string, string> | null;
|
|
258
416
|
getConsentDate(): Date | false;
|
|
259
417
|
getGTMConsent(): Record<string, string> | null;
|
|
260
418
|
isCookieGranted(cookieId: string, requestValue?: boolean): boolean | ConsentStatus;
|
|
@@ -267,8 +425,8 @@ interface ConsentiWidgetAPI {
|
|
|
267
425
|
off(event: ConsentiEventName, handler: (data: ConsentEvent) => void): void;
|
|
268
426
|
version(): {
|
|
269
427
|
package: string;
|
|
270
|
-
profileVersion:
|
|
271
|
-
consentVersion:
|
|
428
|
+
profileVersion: string | null;
|
|
429
|
+
consentVersion: string | null;
|
|
272
430
|
};
|
|
273
431
|
bannerVisibility(): 'main' | 'gpc' | false;
|
|
274
432
|
modalVisibility(): 'preference' | false;
|
|
@@ -277,7 +435,7 @@ interface ConsentiWidgetAPI {
|
|
|
277
435
|
hideBanner(): void;
|
|
278
436
|
showModal(triggerEl?: HTMLElement): void;
|
|
279
437
|
hideModal(): void;
|
|
280
|
-
submitConsent(consent: Partial<ConsentValue>): Promise<void>;
|
|
438
|
+
submitConsent(consent: Partial<ConsentValue>): Promise<ConsentDbRecord | void>;
|
|
281
439
|
deleteConsent(): Promise<void>;
|
|
282
440
|
reConsent(): Promise<void>;
|
|
283
441
|
getRootElement(): HTMLElement | null;
|
|
@@ -316,41 +474,67 @@ interface ParsedConsent {
|
|
|
316
474
|
interface ConsentRecord {
|
|
317
475
|
visitorId: string;
|
|
318
476
|
consentId?: string;
|
|
319
|
-
profileId:
|
|
320
|
-
profileVersion: number;
|
|
477
|
+
profileId: string;
|
|
321
478
|
consent: ConsentValue;
|
|
322
479
|
timestamp: string;
|
|
323
480
|
gpc?: boolean;
|
|
324
|
-
action?: ConsentAction;
|
|
481
|
+
action?: ConsentAction$1;
|
|
325
482
|
pageUrl?: string;
|
|
326
483
|
}
|
|
327
484
|
interface ConsentReceipt {
|
|
328
|
-
version:
|
|
485
|
+
version: string;
|
|
329
486
|
issuedAt: string;
|
|
330
487
|
visitorId: string;
|
|
331
|
-
profileId:
|
|
332
|
-
profileVersion: number;
|
|
488
|
+
profileId: string;
|
|
333
489
|
locale: string;
|
|
334
490
|
consent: ConsentValue;
|
|
335
491
|
signature?: string;
|
|
336
492
|
}
|
|
337
|
-
interface
|
|
338
|
-
profileId
|
|
339
|
-
|
|
340
|
-
hasExistingConsent
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
493
|
+
interface BannerInitializedDetail {
|
|
494
|
+
profileId: string;
|
|
495
|
+
complianceGroup?: ComplianceType;
|
|
496
|
+
hasExistingConsent: boolean;
|
|
497
|
+
gpcDetected: boolean;
|
|
498
|
+
willShow: boolean;
|
|
499
|
+
}
|
|
500
|
+
interface BannerVisibilityDetail {
|
|
501
|
+
visible: boolean;
|
|
502
|
+
variant: 'main' | 'gpc';
|
|
503
|
+
action: boolean;
|
|
504
|
+
}
|
|
505
|
+
interface ModalVisibilityDetail {
|
|
506
|
+
visible: boolean;
|
|
507
|
+
action: boolean;
|
|
508
|
+
}
|
|
509
|
+
interface ConsentBeingSubmitted {
|
|
510
|
+
consentId: string;
|
|
511
|
+
visitorId: string;
|
|
512
|
+
profileId: string;
|
|
513
|
+
consentJson: ConsentValue;
|
|
514
|
+
consentAction: ConsentAction$1;
|
|
515
|
+
gpcDetected: boolean;
|
|
516
|
+
pageUrl: string;
|
|
517
|
+
timestamp: number;
|
|
347
518
|
fromBroadcast?: boolean;
|
|
348
|
-
gpcDetected?: boolean;
|
|
349
519
|
}
|
|
520
|
+
interface ConsentSubmittedDetail extends ConsentBeingSubmitted {
|
|
521
|
+
apiResponse: ConsentDbRecord;
|
|
522
|
+
}
|
|
523
|
+
/** Dispatched when the age gate is declined and `requireParentalConsent` is set — see
|
|
524
|
+
* `AgeGateWidgetConfig`. A deny-all consent (mandatory cookies only) has already been
|
|
525
|
+
* submitted with `parentalConsentToken` attached; this event is the hook for the site
|
|
526
|
+
* owner to run their own out-of-band parental-consent verification. */
|
|
527
|
+
interface ParentalConsentRequiredDetail {
|
|
528
|
+
parentalConsentToken: string;
|
|
529
|
+
profileId: string;
|
|
530
|
+
visitorId: string;
|
|
531
|
+
timestamp: number;
|
|
532
|
+
}
|
|
533
|
+
type ConsentEvent = BannerInitializedDetail | BannerVisibilityDetail | ModalVisibilityDetail | ConsentBeingSubmitted | ConsentSubmittedDetail | ParentalConsentRequiredDetail;
|
|
350
534
|
type ConsentiMessage = {
|
|
351
535
|
type: 'consentUpdated';
|
|
352
536
|
consent: ConsentValue;
|
|
353
|
-
profileId:
|
|
537
|
+
profileId: string;
|
|
354
538
|
} | {
|
|
355
539
|
type: 'bannerClosed';
|
|
356
540
|
} | {
|
|
@@ -375,16 +559,30 @@ type ConsentiMessage = {
|
|
|
375
559
|
*/
|
|
376
560
|
|
|
377
561
|
declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
378
|
-
private config;
|
|
379
562
|
private initialized;
|
|
380
563
|
private initializing;
|
|
381
564
|
private profile;
|
|
382
565
|
private resolvedBase;
|
|
566
|
+
/** cookieId → Category lookup, rebuilt whenever `profile` changes. Avoids rescanning categories on every consent action. */
|
|
567
|
+
private categoryIndex;
|
|
568
|
+
/** Watchers created by the declarative `data-consenti-*` DOM scan — destroyed alongside the widget since they have no other owner. */
|
|
569
|
+
private scannedScripts;
|
|
383
570
|
private consentStore;
|
|
571
|
+
/**
|
|
572
|
+
* Stable per-browser identifier. Created lazily the first time a consent decision actually
|
|
573
|
+
* happens (manual submit, GPC auto-response, or relaying a decision already made in another
|
|
574
|
+
* tab) — never minted before that, so an undecided visitor leaves nothing in storage. See
|
|
575
|
+
* `getOrCreateVisitorId()`.
|
|
576
|
+
*/
|
|
577
|
+
private visitorId;
|
|
384
578
|
private eventBus;
|
|
385
579
|
private banner;
|
|
386
580
|
private modal;
|
|
581
|
+
private ageGate;
|
|
387
582
|
private renderer;
|
|
583
|
+
/** Set once the age gate (if enabled) resolves; threaded onto every `submitConsent` call thereafter. */
|
|
584
|
+
private _ageVerified;
|
|
585
|
+
private _parentalConsentToken;
|
|
388
586
|
private broadcastChannel;
|
|
389
587
|
private readyResolve;
|
|
390
588
|
private readyPromise;
|
|
@@ -393,15 +591,23 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
393
591
|
private lastSignature;
|
|
394
592
|
/** Tracks which banner variant is currently visible, or null when hidden. */
|
|
395
593
|
private _bannerVariant;
|
|
594
|
+
/** Tracks which banner variant is currently mounted in the DOM (persists when banner is hidden). */
|
|
595
|
+
private _bannerMounted;
|
|
596
|
+
/** Active focus trap keydown listener — removed when modal closes. */
|
|
597
|
+
private _focusTrapListener;
|
|
396
598
|
/** Maps original handler functions to their DOM-wrapped listeners for on/off bookkeeping. */
|
|
397
599
|
private _eventHandlers;
|
|
600
|
+
/** `core` defaulted to `{}` in the constructor below — every one of its own fields is
|
|
601
|
+
* optional, so this narrows back to non-optional for every other method in this class. */
|
|
602
|
+
private config;
|
|
398
603
|
/**
|
|
399
604
|
* Creates and initialises the consent widget.
|
|
400
605
|
*
|
|
401
606
|
* Construction is synchronous; the async `init()` is launched in the background.
|
|
402
607
|
* Use `await widget.ready` or `widget.onReady(cb)` to run code after init completes.
|
|
403
608
|
*
|
|
404
|
-
* @param config - Widget configuration. See `ConsentiConfig` for all options.
|
|
609
|
+
* @param config - Widget configuration. See `ConsentiConfig` for all options. `core` may be
|
|
610
|
+
* omitted entirely — every one of its own fields is optional too.
|
|
405
611
|
*/
|
|
406
612
|
constructor(config: ConsentiConfig);
|
|
407
613
|
private profileId;
|
|
@@ -411,8 +617,53 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
411
617
|
* to re-initialise the same instance.
|
|
412
618
|
*/
|
|
413
619
|
init(): Promise<void>;
|
|
620
|
+
/**
|
|
621
|
+
* Everything after the "does consent already exist" check — GPC/CCPA/CPRA silent paths,
|
|
622
|
+
* then the normal opt-in banner. Extracted from `init()` so the age gate (when enabled and
|
|
623
|
+
* no consent exists yet) can defer this whole sequence until the visitor answers it via
|
|
624
|
+
* `resolveAgeGate()`, then resume here with `hasExisting` fixed at `false`.
|
|
625
|
+
*/
|
|
626
|
+
private continueInit;
|
|
627
|
+
/** Mounts the age-gate prompt (`compliance.ageGate`) in place of the normal banner flow. */
|
|
628
|
+
private showAgeGate;
|
|
629
|
+
/**
|
|
630
|
+
* Handles the visitor's age-gate answer.
|
|
631
|
+
* - Confirmed → records `ageVerified: true` for all future `submitConsent` calls and
|
|
632
|
+
* resumes the normal init flow via `continueInit()`.
|
|
633
|
+
* - Declined, no parental consent required → immediately submits a deny-all consent
|
|
634
|
+
* (mandatory cookies still granted), mirroring the GPC-strict silent-write pattern.
|
|
635
|
+
* - Declined, parental consent required → same deny-all submission, plus a
|
|
636
|
+
* `parentalConsentToken` and a `consenti:parentalConsentRequired` event so the site
|
|
637
|
+
* owner can wire their own out-of-band verification flow (no email infra exists in
|
|
638
|
+
* this package to do that here).
|
|
639
|
+
*/
|
|
640
|
+
private resolveAgeGate;
|
|
641
|
+
/**
|
|
642
|
+
* Marks the widget ready and runs the declarative DOM-scan for
|
|
643
|
+
* `data-consenti-consent-script`/`data-consenti-category-script` tags. Called from
|
|
644
|
+
* every exit path of `init()` so the scan always runs exactly once per init cycle,
|
|
645
|
+
* whether `init()` was triggered automatically (`autoInit !== false`) or explicitly
|
|
646
|
+
* by the caller (`autoInit: false`) — it never runs before the widget actually has
|
|
647
|
+
* a resolved profile to read consent from.
|
|
648
|
+
*/
|
|
649
|
+
private finishInit;
|
|
650
|
+
/** Sets the `dir` attribute on the root element from `core.dir` (default `'auto'`, derived from `core.locale`). */
|
|
651
|
+
private applyDirection;
|
|
414
652
|
/** Applies the `consenti-root--dark` class based on config or profile flag. */
|
|
415
653
|
private applyDarkMode;
|
|
654
|
+
/** Applies `consenti--enhanced-a11y` class when `profile.enhanceAccessibility` is set. */
|
|
655
|
+
private applyAccessibility;
|
|
656
|
+
/** Builds and appends the metadata footer strip to a banner or modal container. */
|
|
657
|
+
private _appendMetaFooter;
|
|
658
|
+
/**
|
|
659
|
+
* Injects a `<style>` element into the root for `stackButtonsOnBreakpoint`.
|
|
660
|
+
* Called once per profile load; a new style replaces the previous one.
|
|
661
|
+
*/
|
|
662
|
+
private applyStackButtonsBreakpoint;
|
|
663
|
+
/** Installs a keyboard focus trap on `container` while the modal is open. */
|
|
664
|
+
private _installFocusTrap;
|
|
665
|
+
/** Removes the active focus trap keyboard listener. */
|
|
666
|
+
private _removeFocusTrap;
|
|
416
667
|
/**
|
|
417
668
|
* Injects CSS custom property overrides supplied via `core.theme` into the
|
|
418
669
|
* Consenti root element so they cascade down to all widget elements.
|
|
@@ -442,22 +693,23 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
442
693
|
*/
|
|
443
694
|
hasConsent(): boolean;
|
|
444
695
|
/**
|
|
445
|
-
* Returns the stored consent map,
|
|
446
|
-
*
|
|
696
|
+
* Returns the stored consent map, optionally transformed for a specific vendor.
|
|
697
|
+
* Pass `type` to get a vendor-ready object instead of the raw Consenti format.
|
|
698
|
+
* Always returns `null` during SSR or when no consent has been saved.
|
|
699
|
+
*
|
|
700
|
+
* @param type - Vendor format: 'google-gtm', 'category', 'adobe', 'meta',
|
|
701
|
+
* 'microsoft-clarity', 'twilio-segment', or omit for raw format.
|
|
447
702
|
*/
|
|
448
703
|
getConsent(): ConsentValue | null;
|
|
704
|
+
getConsent(type: ConsentType): Record<string, string> | null;
|
|
449
705
|
/**
|
|
450
706
|
* Returns the `Date` when consent was last saved, or `false` if no consent exists.
|
|
451
707
|
* Always returns `false` during SSR.
|
|
452
708
|
*/
|
|
453
709
|
getConsentDate(): Date | false;
|
|
454
710
|
/**
|
|
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).
|
|
711
|
+
* @deprecated Use `getConsent('google-gtm')` instead.
|
|
712
|
+
* Returns the consent map in Google Consent Mode v2 format.
|
|
461
713
|
*/
|
|
462
714
|
getGTMConsent(): Record<string, string> | null;
|
|
463
715
|
/**
|
|
@@ -469,7 +721,7 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
469
721
|
* @param consent - Partial or full map of cookie ID → status.
|
|
470
722
|
* @param gpcDerived - Internal flag set to `true` when called from the GPC strict path.
|
|
471
723
|
*/
|
|
472
|
-
submitConsent(consent: Partial<ConsentValue>, gpcDerived?: boolean): Promise<void>;
|
|
724
|
+
submitConsent(consent: Partial<ConsentValue>, gpcDerived?: boolean, source?: number): Promise<ConsentDbRecord | void>;
|
|
473
725
|
/**
|
|
474
726
|
* Returns the currently visible banner variant, or `false` if no banner is shown.
|
|
475
727
|
* Useful for programmatically checking state before calling `showBanner` / `hideBanner`.
|
|
@@ -638,8 +890,8 @@ declare class ConsentiSetup implements ConsentiWidgetAPI {
|
|
|
638
890
|
*/
|
|
639
891
|
version(): {
|
|
640
892
|
package: string;
|
|
641
|
-
profileVersion:
|
|
642
|
-
consentVersion:
|
|
893
|
+
profileVersion: string;
|
|
894
|
+
consentVersion: string | null;
|
|
643
895
|
};
|
|
644
896
|
/**
|
|
645
897
|
* Toggles or sets dark mode at runtime without re-initialising the widget.
|
|
@@ -762,28 +1014,36 @@ declare abstract class ConsentiPlugin {
|
|
|
762
1014
|
* import { ConsentiProfile, ConsentiSetup } from '@consenti/ui'
|
|
763
1015
|
*
|
|
764
1016
|
* const profile = new ConsentiProfile({
|
|
765
|
-
* cookies:
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
1017
|
+
* cookies: {
|
|
1018
|
+
* necessary: {},
|
|
1019
|
+
* analytics: {},
|
|
1020
|
+
* },
|
|
769
1021
|
* defaultLocale: 'en',
|
|
770
1022
|
* translations: {
|
|
771
1023
|
* en: {
|
|
772
1024
|
* mainBanner: {
|
|
773
1025
|
* position: 'bottom',
|
|
774
1026
|
* htmlText: 'We use cookies.',
|
|
775
|
-
* buttons:
|
|
1027
|
+
* buttons: { 'accept-all': { text: 'Accept All', style: 'primary', action: 'submit', cookies: '*' } },
|
|
776
1028
|
* },
|
|
777
1029
|
* preferenceModal: {
|
|
778
|
-
* categories:
|
|
779
|
-
*
|
|
1030
|
+
* categories: {
|
|
1031
|
+
* necessary: { heading: 'Necessary', htmlText: '...', legalBasis: 'mandatory', cookies: ['necessary'] },
|
|
1032
|
+
* },
|
|
1033
|
+
* buttons: { save: { text: 'Save', style: 'primary', action: 'submit' } },
|
|
780
1034
|
* },
|
|
781
1035
|
* },
|
|
782
1036
|
* },
|
|
783
1037
|
* })
|
|
784
1038
|
*
|
|
785
|
-
* const widget = new ConsentiSetup({ core: { profileId: profile.
|
|
1039
|
+
* const widget = new ConsentiSetup({ core: { profileId: profile.getType() } })
|
|
786
1040
|
* ```
|
|
1041
|
+
*
|
|
1042
|
+
* To instead patch one of Consenti's built-in profiles for a given `complianceGroup`
|
|
1043
|
+
* (rather than defining a full standalone profile), pass `complianceGroup` and
|
|
1044
|
+
* `deepMerge: true` with only the fields you want to override — see
|
|
1045
|
+
* `RegisterableProfileConfig` and the `complianceGroup`/`deepMerge` resolver behavior
|
|
1046
|
+
* in `profile-resolver.ts`.
|
|
787
1047
|
*/
|
|
788
1048
|
|
|
789
1049
|
/**
|
|
@@ -791,15 +1051,17 @@ declare abstract class ConsentiPlugin {
|
|
|
791
1051
|
*/
|
|
792
1052
|
declare class ConsentiProfile {
|
|
793
1053
|
private config;
|
|
794
|
-
private
|
|
1054
|
+
private type;
|
|
795
1055
|
/**
|
|
796
|
-
* @param config - Full profile configuration including cookies, locales, and UI text
|
|
1056
|
+
* @param config - Full profile configuration including cookies, locales, and UI text,
|
|
1057
|
+
* or a `{ complianceGroup, deepMerge: true, ... }` partial overlay to
|
|
1058
|
+
* patch a built-in profile instead of defining a standalone one.
|
|
797
1059
|
*/
|
|
798
|
-
constructor(config:
|
|
1060
|
+
constructor(config: RegisterableProfileConfig);
|
|
799
1061
|
/** Returns the auto-assigned numeric profile ID. Pass this to `core.profileId`. */
|
|
800
|
-
|
|
801
|
-
/** Returns the raw
|
|
802
|
-
toJSON():
|
|
1062
|
+
getType(): Symbol;
|
|
1063
|
+
/** Returns the raw config passed to the constructor. */
|
|
1064
|
+
toJSON(): RegisterableProfileConfig;
|
|
803
1065
|
}
|
|
804
1066
|
|
|
805
1067
|
/**
|
|
@@ -887,37 +1149,248 @@ declare class ConsentScript {
|
|
|
887
1149
|
}
|
|
888
1150
|
|
|
889
1151
|
/**
|
|
890
|
-
*
|
|
891
|
-
*
|
|
1152
|
+
* ConsentAction — runs a callback based on a specific consent parameter's grant status.
|
|
1153
|
+
*
|
|
1154
|
+
* Same lifecycle as `ConsentScript` (evaluates immediately on construction so
|
|
1155
|
+
* existing consent is honoured, re-evaluates on `consenti:consentSubmitted`,
|
|
1156
|
+
* `destroy()` to unbind) but fires `onGrant`/`onDeny` callbacks instead of
|
|
1157
|
+
* injecting a `<script>` element — for integrations that expose their own
|
|
1158
|
+
* `sdk.optIn()`/`sdk.optOut()` API (Segment, Mixpanel, Amplitude, Sentry, etc.)
|
|
1159
|
+
* rather than needing a script tag toggled. Use `ConsentScript` for that case instead.
|
|
1160
|
+
*
|
|
1161
|
+
* @example
|
|
1162
|
+
* ```ts
|
|
1163
|
+
* import { ConsentiSetup, ConsentAction } from '@consenti/ui'
|
|
1164
|
+
*
|
|
1165
|
+
* const widget = new ConsentiSetup({ core: { profileId: 0 } })
|
|
1166
|
+
* await widget.ready
|
|
1167
|
+
*
|
|
1168
|
+
* new ConsentAction({
|
|
1169
|
+
* id: 'analytics_storage',
|
|
1170
|
+
* widget,
|
|
1171
|
+
* onGrant: () => analyticsSdk.optIn(),
|
|
1172
|
+
* onDeny: () => analyticsSdk.optOut(),
|
|
1173
|
+
* })
|
|
1174
|
+
* ```
|
|
1175
|
+
*/
|
|
1176
|
+
|
|
1177
|
+
/** Passed to `onGrant`/`onDeny` — the resolved parameter's metadata plus the full current consent map. */
|
|
1178
|
+
interface ConsentActionParams {
|
|
1179
|
+
cookieId: string;
|
|
1180
|
+
status: ConsentStatus;
|
|
1181
|
+
cookie: Cookie | undefined;
|
|
1182
|
+
consent: ConsentValue | null;
|
|
1183
|
+
}
|
|
1184
|
+
/** Options for constructing a {@link ConsentAction} instance. */
|
|
1185
|
+
interface ConsentActionOptions {
|
|
1186
|
+
/** The consent parameter ID to watch (e.g. `'analytics_storage'`). */
|
|
1187
|
+
id: string;
|
|
1188
|
+
/** The `ConsentiSetup` widget instance to read consent from. */
|
|
1189
|
+
widget: ConsentiSetup;
|
|
1190
|
+
/**
|
|
1191
|
+
* When `true` (default), the callbacks re-fire automatically on every future consent
|
|
1192
|
+
* change. Set to `false` to evaluate consent only once at construction time — no
|
|
1193
|
+
* event listener is attached.
|
|
1194
|
+
*/
|
|
1195
|
+
bind?: boolean;
|
|
1196
|
+
/** Called when the parameter's status transitions to `'granted'`. */
|
|
1197
|
+
onGrant?: (params: ConsentActionParams) => void;
|
|
1198
|
+
/** Called when the parameter's status transitions away from `'granted'` (`'denied'` or `'objected'`). */
|
|
1199
|
+
onDeny?: (params: ConsentActionParams) => void;
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Watches a single consent parameter's grant status and fires `onGrant`/`onDeny`
|
|
1203
|
+
* callbacks on transitions. Call {@link ConsentAction.destroy} when no longer
|
|
1204
|
+
* needed to remove the event listener.
|
|
1205
|
+
*/
|
|
1206
|
+
declare class ConsentAction {
|
|
1207
|
+
private readonly options;
|
|
1208
|
+
private granted;
|
|
1209
|
+
private readonly handler;
|
|
1210
|
+
constructor(options: ConsentActionOptions);
|
|
1211
|
+
private evaluate;
|
|
1212
|
+
/** Removes the event listener (if bound). */
|
|
1213
|
+
destroy(): void;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* CategoryAction — runs a callback based on a category's rollup consent state.
|
|
1218
|
+
*
|
|
1219
|
+
* A category is considered "granted" only when *every* parameter it contains is
|
|
1220
|
+
* `'granted'` — matching the preference modal's tri-state rollup rule. `onDeny`
|
|
1221
|
+
* fires for both a fully-denied category and a partially-granted ("mixed") one,
|
|
1222
|
+
* since neither represents full consent for the category.
|
|
1223
|
+
*
|
|
1224
|
+
* Same lifecycle as `ConsentAction`: evaluates immediately on construction,
|
|
1225
|
+
* re-evaluates on `consenti:consentSubmitted`, `destroy()` to unbind.
|
|
1226
|
+
*
|
|
1227
|
+
* @example
|
|
1228
|
+
* ```ts
|
|
1229
|
+
* import { ConsentiSetup, CategoryAction } from '@consenti/ui'
|
|
1230
|
+
*
|
|
1231
|
+
* const widget = new ConsentiSetup({ core: { profileId: 0 } })
|
|
1232
|
+
* await widget.ready
|
|
1233
|
+
*
|
|
1234
|
+
* new CategoryAction({
|
|
1235
|
+
* id: 'marketing',
|
|
1236
|
+
* widget,
|
|
1237
|
+
* onGrant: () => adSdk.enableAll(),
|
|
1238
|
+
* onDeny: () => adSdk.disableAll(),
|
|
1239
|
+
* })
|
|
1240
|
+
* ```
|
|
1241
|
+
*/
|
|
1242
|
+
|
|
1243
|
+
/** Passed to `onGrant`/`onDeny` — the category's member parameter IDs plus the full current consent map. */
|
|
1244
|
+
interface CategoryActionParams {
|
|
1245
|
+
categoryId: string;
|
|
1246
|
+
cookieIds: string[];
|
|
1247
|
+
consent: ConsentValue | null;
|
|
1248
|
+
}
|
|
1249
|
+
/** Options for constructing a {@link CategoryAction} instance. */
|
|
1250
|
+
interface CategoryActionOptions {
|
|
1251
|
+
/** The category ID to watch (e.g. `'marketing'`). */
|
|
1252
|
+
id: string;
|
|
1253
|
+
/** The `ConsentiSetup` widget instance to read consent from. */
|
|
1254
|
+
widget: ConsentiSetup;
|
|
1255
|
+
/**
|
|
1256
|
+
* When `true` (default), the callbacks re-fire automatically on every future consent
|
|
1257
|
+
* change. Set to `false` to evaluate consent only once at construction time — no
|
|
1258
|
+
* event listener is attached.
|
|
1259
|
+
*/
|
|
1260
|
+
bind?: boolean;
|
|
1261
|
+
/** Called when every parameter in the category transitions to `'granted'`. */
|
|
1262
|
+
onGrant?: (params: CategoryActionParams) => void;
|
|
1263
|
+
/** Called when the category transitions away from fully-granted (any parameter denied/objected). */
|
|
1264
|
+
onDeny?: (params: CategoryActionParams) => void;
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Watches a category's rollup grant status and fires `onGrant`/`onDeny` callbacks
|
|
1268
|
+
* on transitions. Call {@link CategoryAction.destroy} when no longer needed to
|
|
1269
|
+
* remove the event listener.
|
|
1270
|
+
*/
|
|
1271
|
+
declare class CategoryAction {
|
|
1272
|
+
private readonly options;
|
|
1273
|
+
private granted;
|
|
1274
|
+
private readonly handler;
|
|
1275
|
+
constructor(options: CategoryActionOptions);
|
|
1276
|
+
private evaluate;
|
|
1277
|
+
/** Removes the event listener (if bound). */
|
|
1278
|
+
destroy(): void;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* CategoryScript — conditionally loads/unloads a third-party `<script>` tag
|
|
1283
|
+
* based on a whole category's rollup consent state, instead of one parameter.
|
|
1284
|
+
*
|
|
1285
|
+
* A category is considered "granted" only when *every* parameter it contains is
|
|
1286
|
+
* `'granted'` — matching the preference modal's tri-state rollup rule and
|
|
1287
|
+
* `CategoryAction`'s behavior. Injection mechanics (src validation, inline-script
|
|
1288
|
+
* escape hatch, attribute filtering) are identical to `ConsentScript` — both share
|
|
1289
|
+
* the same underlying `injectScript`/`revokeScript` helpers.
|
|
1290
|
+
*
|
|
1291
|
+
* @example
|
|
1292
|
+
* ```ts
|
|
1293
|
+
* import { ConsentiSetup, CategoryScript } from '@consenti/ui'
|
|
1294
|
+
*
|
|
1295
|
+
* const widget = new ConsentiSetup({ core: { profileId: 0 } })
|
|
1296
|
+
* await widget.ready
|
|
1297
|
+
*
|
|
1298
|
+
* new CategoryScript({
|
|
1299
|
+
* categoryId: 'marketing',
|
|
1300
|
+
* widget,
|
|
1301
|
+
* src: 'https://example.com/ad-pixel.js',
|
|
1302
|
+
* })
|
|
1303
|
+
* ```
|
|
1304
|
+
*/
|
|
1305
|
+
|
|
1306
|
+
/** Options for constructing a {@link CategoryScript} instance. */
|
|
1307
|
+
interface CategoryScriptOptions {
|
|
1308
|
+
/** The category ID to watch (e.g. `'marketing'`). */
|
|
1309
|
+
categoryId: string;
|
|
1310
|
+
/** The `ConsentiSetup` widget instance to read consent from. */
|
|
1311
|
+
widget: ConsentiSetup;
|
|
1312
|
+
/** Remote script `src` URL to inject when every parameter in the category is granted. */
|
|
1313
|
+
src?: string;
|
|
1314
|
+
/**
|
|
1315
|
+
* Inline JavaScript to inject when granted (e.g. a GTM snippet).
|
|
1316
|
+
* WARNING: this string is assigned directly to `script.innerHTML` — only
|
|
1317
|
+
* pass a static, trusted literal. Never pass user-supplied or remote content.
|
|
1318
|
+
*/
|
|
1319
|
+
unsafeInnerHTML?: string;
|
|
1320
|
+
/**
|
|
1321
|
+
* Additional HTML attributes applied to the injected `<script>` element.
|
|
1322
|
+
* Set a key to an empty string for boolean attributes (e.g. `{ async: '', defer: '' }`).
|
|
1323
|
+
*/
|
|
1324
|
+
attributes?: Record<string, string>;
|
|
1325
|
+
/** Called after the `<script>` element has been appended to `<head>`. */
|
|
1326
|
+
onLoad?: () => void;
|
|
1327
|
+
/** Called after the `<script>` element has been removed from the DOM. */
|
|
1328
|
+
onRevoke?: () => void;
|
|
1329
|
+
/**
|
|
1330
|
+
* When `true` (default), the script is automatically removed when the category is no
|
|
1331
|
+
* longer fully granted and re-injected when it becomes fully granted again. Set to
|
|
1332
|
+
* `false` to evaluate consent only once at construction time — no event listener is
|
|
1333
|
+
* attached and the script is never auto-removed.
|
|
1334
|
+
*/
|
|
1335
|
+
bind?: boolean;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Conditionally injects and removes a `<script>` element based on a category's
|
|
1339
|
+
* rollup consent status (every member parameter granted).
|
|
1340
|
+
*
|
|
1341
|
+
* Call {@link CategoryScript.destroy} when the trigger is no longer needed
|
|
1342
|
+
* (e.g. on SPA route unmount) to remove the event listener and the injected element.
|
|
1343
|
+
*/
|
|
1344
|
+
declare class CategoryScript {
|
|
1345
|
+
private readonly options;
|
|
1346
|
+
private scriptEl;
|
|
1347
|
+
private readonly handler;
|
|
1348
|
+
constructor(options: CategoryScriptOptions);
|
|
1349
|
+
private evaluate;
|
|
1350
|
+
private inject;
|
|
1351
|
+
private revoke;
|
|
1352
|
+
/**
|
|
1353
|
+
* Removes the event listener and the injected `<script>` element (if present).
|
|
1354
|
+
* Call this when the widget is destroyed or the script is no longer needed.
|
|
1355
|
+
*/
|
|
1356
|
+
destroy(): void;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
/**
|
|
1360
|
+
* BannerTrigger — a pre-built accessible UI element that reopens the Consenti
|
|
1361
|
+
* banner or preference modal when clicked.
|
|
892
1362
|
*
|
|
893
1363
|
* Use this to add a "Cookie Settings" link in your site footer or cookie policy
|
|
894
1364
|
* page without wiring up the click handler manually or importing the widget module
|
|
895
1365
|
* into your layout component.
|
|
896
1366
|
*
|
|
1367
|
+
* (Renamed from `CookieTrigger` — it was never scoped to a specific cookie, it
|
|
1368
|
+
* just opens the banner or modal.)
|
|
1369
|
+
*
|
|
897
1370
|
* @example
|
|
898
1371
|
* ```ts
|
|
899
|
-
* import { ConsentiSetup,
|
|
1372
|
+
* import { ConsentiSetup, BannerTrigger } from '@consenti/ui'
|
|
900
1373
|
*
|
|
901
1374
|
* const widget = new ConsentiSetup({ core: { profileId: 0 } })
|
|
902
1375
|
*
|
|
903
1376
|
* // Attach to an existing element
|
|
904
|
-
* new
|
|
1377
|
+
* new BannerTrigger({ widget, el: '#footer-cookie-settings' })
|
|
905
1378
|
*
|
|
906
1379
|
* // — or — create a new button and place it yourself
|
|
907
|
-
* const trigger = new
|
|
1380
|
+
* const trigger = new BannerTrigger({ widget, label: 'Cookie Settings' })
|
|
908
1381
|
* document.querySelector('.site-footer')?.appendChild(trigger.getElement())
|
|
909
1382
|
* ```
|
|
910
1383
|
*/
|
|
911
1384
|
|
|
912
|
-
/** Options for constructing a {@link
|
|
913
|
-
interface
|
|
1385
|
+
/** Options for constructing a {@link BannerTrigger} instance. */
|
|
1386
|
+
interface BannerTriggerOptions {
|
|
914
1387
|
/** The widget instance to control when the trigger is clicked. */
|
|
915
1388
|
widget: ConsentiSetup;
|
|
916
1389
|
/**
|
|
917
1390
|
* Element to attach the click handler to.
|
|
918
1391
|
* - `HTMLElement` — used directly.
|
|
919
1392
|
* - `string` — treated as a CSS selector; the first matching element is used.
|
|
920
|
-
* - Omitted — a new `<button>` is created. Retrieve it with {@link
|
|
1393
|
+
* - Omitted — a new `<button>` is created. Retrieve it with {@link BannerTrigger.getElement}
|
|
921
1394
|
* and append it to the DOM at the desired location.
|
|
922
1395
|
*/
|
|
923
1396
|
el?: HTMLElement | string;
|
|
@@ -940,12 +1413,12 @@ interface CookieTriggerOptions {
|
|
|
940
1413
|
* The created button uses the `.consenti-btn` and `.consenti-btn--text` classes so
|
|
941
1414
|
* it inherits the widget's theme automatically.
|
|
942
1415
|
*/
|
|
943
|
-
declare class
|
|
1416
|
+
declare class BannerTrigger {
|
|
944
1417
|
private readonly el;
|
|
945
1418
|
private readonly clickHandler;
|
|
946
1419
|
/** Whether this instance created the element (used to decide if `destroy()` removes it). */
|
|
947
1420
|
private readonly created;
|
|
948
|
-
constructor(options:
|
|
1421
|
+
constructor(options: BannerTriggerOptions);
|
|
949
1422
|
/**
|
|
950
1423
|
* Returns the trigger element.
|
|
951
1424
|
* When no `el` was provided, append the returned element to the desired location
|
|
@@ -959,4 +1432,42 @@ declare class CookieTrigger {
|
|
|
959
1432
|
destroy(): void;
|
|
960
1433
|
}
|
|
961
1434
|
|
|
962
|
-
|
|
1435
|
+
/**
|
|
1436
|
+
* Declarative DOM-scan bindings — a zero-JS integration path for gating
|
|
1437
|
+
* third-party scripts via `data-*` attributes instead of hand-written
|
|
1438
|
+
* `ConsentScript`/`CategoryScript` calls.
|
|
1439
|
+
*
|
|
1440
|
+
* ```html
|
|
1441
|
+
* <script type="text/plain" data-consenti-category-script="marketing" src="https://example.com/pixel.js"></script>
|
|
1442
|
+
* <script type="text/plain" data-consenti-consent-script="analytics_storage">/* inline snippet *\/</script>
|
|
1443
|
+
* <script type="text/plain" data-consenti-consent-script="ad_storage" data-consenti-bind="false" src="..."></script>
|
|
1444
|
+
* ```
|
|
1445
|
+
*
|
|
1446
|
+
* Scanned automatically once per `ConsentiSetup.init()` cycle (after `init()`
|
|
1447
|
+
* completes — so it respects `autoInit: false`, only running once the widget is
|
|
1448
|
+
* actually initialized, however `init()` was triggered). The scanned tags are
|
|
1449
|
+
* read-only config sources and stay inert (`type="text/plain"`) in the DOM
|
|
1450
|
+
* permanently — `ConsentScript`/`CategoryScript` inject their own separate
|
|
1451
|
+
* `<script>` element exactly as they do when constructed by hand.
|
|
1452
|
+
*/
|
|
1453
|
+
|
|
1454
|
+
/**
|
|
1455
|
+
* Scans the document for `<script type="text/plain">` tags carrying
|
|
1456
|
+
* `data-consenti-consent-script` or `data-consenti-category-script`, and
|
|
1457
|
+
* instantiates `ConsentScript`/`CategoryScript` for each. Called automatically
|
|
1458
|
+
* by `ConsentiSetup` at the end of every `init()` cycle.
|
|
1459
|
+
*
|
|
1460
|
+
* v1 scans once automatically; scripts injected into the DOM after that point
|
|
1461
|
+
* (e.g. by a late-loading CMS widget) are not picked up automatically — call this
|
|
1462
|
+
* function again manually after adding more tags dynamically if needed. Each element
|
|
1463
|
+
* is only ever scanned once (marked with `data-consenti-scanned`), so calling this
|
|
1464
|
+
* again is safe — it only processes newly-added tags, never re-instantiates a watcher
|
|
1465
|
+
* for one already scanned.
|
|
1466
|
+
*
|
|
1467
|
+
* Returns the created watchers — `ConsentiSetup` holds onto these and calls
|
|
1468
|
+
* `.destroy()` on each when the widget itself is destroyed, since a scanner-created
|
|
1469
|
+
* watcher has no other owner to release its `consenti:consentSubmitted` listener.
|
|
1470
|
+
*/
|
|
1471
|
+
declare function scanConsentScripts(widget: ConsentiSetup): Array<ConsentScript | CategoryScript>;
|
|
1472
|
+
|
|
1473
|
+
export { type AgeGateWidgetConfig, 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 LocaleTranslations, type MainBanner, type ParentalConsentRequiredDetail, type ParsedConsent, type PreferenceModal, type ProfileConfig, type ProfileTranslations, type RegisterableProfileConfig, type ResolvedProfile, type TcfWidgetConfig, type ThemeConfig, type UtilsConfig, scanConsentScripts };
|