@cookieyes/core 0.1.1 → 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 +421 -47
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +507 -49
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -19,8 +19,82 @@ type ConsentChecker = (category: ConsentCategory) => boolean;
|
|
|
19
19
|
declare function installNetworkBlocker(config: NetworkBlockerConfig, hasConsent: ConsentChecker): () => void;
|
|
20
20
|
declare function uninstallNetworkBlocker(): void;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* A tool that can be stopped (and optionally resumed) at runtime when consent
|
|
24
|
+
* for its category changes — no page reload needed. `stop()` is called when the
|
|
25
|
+
* category is revoked; `resume()` (if provided) when it's re-granted.
|
|
26
|
+
*
|
|
27
|
+
* If `stop()` throws, that tool is treated as "couldn't be stopped cleanly" and
|
|
28
|
+
* falls back to the reload notice for that one tool — it never breaks the page.
|
|
29
|
+
*/
|
|
30
|
+
type StopHandler = {
|
|
31
|
+
id: string;
|
|
32
|
+
category: ConsentCategory;
|
|
33
|
+
stop: () => void;
|
|
34
|
+
resume?: (() => void) | undefined;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* A tool with no known clean runtime stop — revoking its category can only be
|
|
38
|
+
* fully applied by reloading the page. Registering one means "if this category
|
|
39
|
+
* is revoked, show the visitor the reload notice."
|
|
40
|
+
*/
|
|
41
|
+
type ReloadOnlyHandler = {
|
|
42
|
+
id: string;
|
|
43
|
+
category: ConsentCategory;
|
|
44
|
+
needsReload: true;
|
|
45
|
+
};
|
|
46
|
+
type AnyStopHandler = StopHandler | ReloadOnlyHandler;
|
|
47
|
+
/**
|
|
48
|
+
* Built-in, first-party integrations. Each maps to either a clean stop-handler
|
|
49
|
+
* or a reload-only marker (see the audit in the README).
|
|
50
|
+
*
|
|
51
|
+
* Note: Google Analytics 4 and Google Tag Manager are **not** listed here.
|
|
52
|
+
* They're governed by Google Consent Mode v2, which the SDK broadcasts
|
|
53
|
+
* automatically whenever a `dataLayer` is present (see google-consent-mode.ts)
|
|
54
|
+
* — on load and on every consent change, derived from each category's `gcm`
|
|
55
|
+
* mapping. So you don't register them as integrations; just add the standard
|
|
56
|
+
* Consent Mode default snippet and the SDK owns the updates.
|
|
57
|
+
*
|
|
58
|
+
* VERIFIED clean-stop vendors (documented, stable runtime opt-out):
|
|
59
|
+
* - `meta` — `fbq('consent','revoke'|'grant')`, Meta's official consent API.
|
|
60
|
+
*
|
|
61
|
+
* The rest have no confident, documented runtime stop, so they're modelled as
|
|
62
|
+
* reload-only (Story 1's honest answer). Upgrading any of them to a clean-stop
|
|
63
|
+
* later is a one-line change here once a real API is confirmed.
|
|
64
|
+
*/
|
|
65
|
+
type BuiltInIntegration = {
|
|
66
|
+
vendor: "meta";
|
|
67
|
+
category?: ConsentCategory | undefined;
|
|
68
|
+
} | {
|
|
69
|
+
vendor: "tiktok";
|
|
70
|
+
category?: ConsentCategory | undefined;
|
|
71
|
+
} | {
|
|
72
|
+
vendor: "linkedin";
|
|
73
|
+
category?: ConsentCategory | undefined;
|
|
74
|
+
} | {
|
|
75
|
+
vendor: "hotjar";
|
|
76
|
+
category?: ConsentCategory | undefined;
|
|
77
|
+
} | {
|
|
78
|
+
vendor: "segment";
|
|
79
|
+
category?: ConsentCategory | undefined;
|
|
80
|
+
};
|
|
81
|
+
declare function resolveBuiltInIntegration(cfg: BuiltInIntegration): AnyStopHandler;
|
|
82
|
+
declare function registerStopHandler(handler: AnyStopHandler): void;
|
|
83
|
+
/** Test-only: reset registry + transition state between cases. */
|
|
84
|
+
declare function _clearStopHandlers(): void;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A consent category id. The five built-in ids are offered for autocomplete,
|
|
88
|
+
* but any string is valid — customers can define their own taxonomy via
|
|
89
|
+
* `categories` (see {@link CategoryDef}).
|
|
90
|
+
*/
|
|
91
|
+
type ConsentCategory = "necessary" | "functional" | "analytics" | "performance" | "advertisement" | (string & {});
|
|
23
92
|
type Regulation = "GDPR" | "CCPA" | "DEFAULT";
|
|
93
|
+
/** Display text for one consent category. */
|
|
94
|
+
type CategoryText = {
|
|
95
|
+
label: string;
|
|
96
|
+
description: string;
|
|
97
|
+
};
|
|
24
98
|
type TranslationMap = {
|
|
25
99
|
bannerTitle: string;
|
|
26
100
|
bannerDescription: string;
|
|
@@ -35,27 +109,12 @@ type TranslationMap = {
|
|
|
35
109
|
preferencesTitle: string;
|
|
36
110
|
preferencesIntro: string;
|
|
37
111
|
categories: {
|
|
38
|
-
necessary:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
description: string;
|
|
45
|
-
};
|
|
46
|
-
analytics: {
|
|
47
|
-
label: string;
|
|
48
|
-
description: string;
|
|
49
|
-
};
|
|
50
|
-
performance: {
|
|
51
|
-
label: string;
|
|
52
|
-
description: string;
|
|
53
|
-
};
|
|
54
|
-
advertisement: {
|
|
55
|
-
label: string;
|
|
56
|
-
description: string;
|
|
57
|
-
};
|
|
58
|
-
};
|
|
112
|
+
necessary: CategoryText;
|
|
113
|
+
functional: CategoryText;
|
|
114
|
+
analytics: CategoryText;
|
|
115
|
+
performance: CategoryText;
|
|
116
|
+
advertisement: CategoryText;
|
|
117
|
+
} & Record<string, CategoryText>;
|
|
59
118
|
optOut: {
|
|
60
119
|
title: string;
|
|
61
120
|
description: string;
|
|
@@ -63,6 +122,24 @@ type TranslationMap = {
|
|
|
63
122
|
successText: string;
|
|
64
123
|
successCountdown: string;
|
|
65
124
|
};
|
|
125
|
+
reloadNotice: {
|
|
126
|
+
message: string;
|
|
127
|
+
reloadButton: string;
|
|
128
|
+
dismissButton: string;
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
/** A subset of TranslationMap — lets a customer override just a few strings. */
|
|
132
|
+
type DeepPartial<T> = T extends object ? {
|
|
133
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
134
|
+
} : T;
|
|
135
|
+
type PartialTranslations = DeepPartial<TranslationMap>;
|
|
136
|
+
/** Reading direction of a language. */
|
|
137
|
+
type TextDirection = "ltr" | "rtl";
|
|
138
|
+
/** The active language, its reading direction, and the languages currently loaded. */
|
|
139
|
+
type LanguageInfo = {
|
|
140
|
+
language: string;
|
|
141
|
+
direction: TextDirection;
|
|
142
|
+
languages: string[];
|
|
66
143
|
};
|
|
67
144
|
type ThemeConfig = {
|
|
68
145
|
primaryColor?: string | undefined;
|
|
@@ -83,29 +160,79 @@ type ScriptEntry = {
|
|
|
83
160
|
onLoad?: (() => void) | undefined;
|
|
84
161
|
};
|
|
85
162
|
type I18nConfig = {
|
|
86
|
-
|
|
163
|
+
/** Translations per language. Each may be partial — missing text falls back to English. */
|
|
164
|
+
messages?: Record<string, PartialTranslations> | undefined;
|
|
87
165
|
locale?: string | undefined;
|
|
88
166
|
detectBrowserLanguage?: boolean | undefined;
|
|
167
|
+
/**
|
|
168
|
+
* Called when a language is switched to that isn't already in `messages` —
|
|
169
|
+
* return its translations (fetch them from your own URL, import them, etc.).
|
|
170
|
+
* Lets you load languages on demand instead of bundling them all upfront.
|
|
171
|
+
*/
|
|
172
|
+
loadLanguage?: ((tag: string) => PartialTranslations | Promise<PartialTranslations>) | undefined;
|
|
89
173
|
};
|
|
90
174
|
type ConsentConfig = {
|
|
91
175
|
apiUrl?: string | undefined;
|
|
92
176
|
apiKey?: string | undefined;
|
|
93
177
|
backend?: ConsentBackend | undefined;
|
|
94
178
|
regulation?: Regulation | undefined;
|
|
179
|
+
/**
|
|
180
|
+
* Define your own category taxonomy. Omit to get the built-in five
|
|
181
|
+
* (necessary, functional, analytics, performance, advertisement) unchanged.
|
|
182
|
+
* At least one category must be `{ required: true }`. Invalid configs fall
|
|
183
|
+
* back to the built-in five with a console warning. See {@link CategoryDef}.
|
|
184
|
+
*/
|
|
185
|
+
categories?: CategoryDef[] | undefined;
|
|
95
186
|
theme?: ThemeConfig | undefined;
|
|
96
|
-
colorScheme?:
|
|
187
|
+
colorScheme?: ColorScheme | undefined;
|
|
97
188
|
reloadOnRevoke?: boolean | undefined;
|
|
189
|
+
/**
|
|
190
|
+
* Built-in, first-party integrations to stop cleanly (no reload) when their
|
|
191
|
+
* category is revoked — e.g. `{ vendor: "meta" }`. (Google Analytics/Tag
|
|
192
|
+
* Manager are handled automatically via the Consent Mode broadcast — no entry
|
|
193
|
+
* needed.) Integrations with no clean runtime stop fall back to the reload notice.
|
|
194
|
+
*/
|
|
195
|
+
integrations?: BuiltInIntegration[] | undefined;
|
|
196
|
+
/**
|
|
197
|
+
* Your own scripts' stop instructions, for anything without a built-in
|
|
198
|
+
* integration. A handler that can stop cleanly provides `stop()`; one that
|
|
199
|
+
* can't should be registered as a reload-only handler instead so revoking it
|
|
200
|
+
* shows the reload notice rather than silently continuing to track.
|
|
201
|
+
*/
|
|
202
|
+
customStopHandlers?: StopHandler[] | undefined;
|
|
98
203
|
onConsentReady?: ((state: ConsentSnapshot) => void) | undefined;
|
|
99
204
|
onConsentUpdate?: ((state: ConsentSnapshot) => void) | undefined;
|
|
100
205
|
};
|
|
206
|
+
/**
|
|
207
|
+
* Surfaced when a revoked tool has no clean runtime stop and can only be fully
|
|
208
|
+
* applied by reloading. `required` is false once dismissed; `reasons` lists the
|
|
209
|
+
* handler ids that triggered it (e.g. `["hotjar"]`).
|
|
210
|
+
*/
|
|
211
|
+
type ReloadNoticeState = {
|
|
212
|
+
required: boolean;
|
|
213
|
+
reasons: string[];
|
|
214
|
+
};
|
|
101
215
|
type ConsentSnapshot = {
|
|
102
216
|
consentId: string;
|
|
103
217
|
hasActed: boolean;
|
|
104
|
-
|
|
218
|
+
/** Category id → granted. Keys are the configured taxonomy's ids. */
|
|
219
|
+
categories: Record<string, boolean>;
|
|
105
220
|
regulation: Regulation;
|
|
106
221
|
lastRenewed?: number | undefined;
|
|
222
|
+
/**
|
|
223
|
+
* Signature of the category taxonomy in effect when this consent was
|
|
224
|
+
* recorded. Lets us (and the customer) tell what a returning visitor
|
|
225
|
+
* actually agreed to, and drives re-request when the taxonomy changes.
|
|
226
|
+
*/
|
|
227
|
+
taxonomyHash?: string | undefined;
|
|
107
228
|
};
|
|
108
229
|
type ConsentManager = ConsentSnapshot & {
|
|
230
|
+
/**
|
|
231
|
+
* Consent in effect — changes only on a real decision (accept / reject / save
|
|
232
|
+
* / reset), never on a dialog toggle. Gate scripts/embeds on this. (`categories`
|
|
233
|
+
* is the live value that drives the dialog checkboxes.)
|
|
234
|
+
*/
|
|
235
|
+
committedCategories: Record<string, boolean>;
|
|
109
236
|
acceptAll: () => void;
|
|
110
237
|
rejectAll: () => void;
|
|
111
238
|
acceptSelected: (categories: ConsentCategory[]) => void;
|
|
@@ -117,9 +244,13 @@ type ConsentManager = ConsentSnapshot & {
|
|
|
117
244
|
isPreferencesOpen: boolean;
|
|
118
245
|
subscribe: (listener: (state: ConsentSnapshot) => void) => () => void;
|
|
119
246
|
registerScript: (entry: ScriptEntry) => void;
|
|
247
|
+
/** Current reload-notice state (see {@link ReloadNoticeState}). */
|
|
248
|
+
reloadNotice: ReloadNoticeState;
|
|
249
|
+
/** Dismiss the reload notice; it won't reappear until a new revoke needs one. */
|
|
250
|
+
dismissReloadNotice: () => void;
|
|
120
251
|
};
|
|
121
252
|
/**
|
|
122
|
-
* Shape of the JSON body POSTed to the customer's `
|
|
253
|
+
* Shape of the JSON body POSTed to the customer's `apiUrl`
|
|
123
254
|
* on every consent decision (Accept All / Reject All / Save Preferences).
|
|
124
255
|
*
|
|
125
256
|
* Customers building a TypeScript backend can import this type to get
|
|
@@ -127,7 +258,7 @@ type ConsentManager = ConsentSnapshot & {
|
|
|
127
258
|
*/
|
|
128
259
|
type ConsentPayload = {
|
|
129
260
|
consentId: string;
|
|
130
|
-
categories: Record<
|
|
261
|
+
categories: Record<string, boolean>;
|
|
131
262
|
regulation: Regulation;
|
|
132
263
|
domain: string;
|
|
133
264
|
};
|
|
@@ -135,7 +266,7 @@ type ConsentPayload = {
|
|
|
135
266
|
* Customer-implemented adapter that decides how a consent decision
|
|
136
267
|
* reaches their backend. Provide this when `mode: "self-hosted"` and you
|
|
137
268
|
* need full control over the request shape, headers, auth, transport,
|
|
138
|
-
* batching, retries, etc. — anything you can't express with `
|
|
269
|
+
* batching, retries, etc. — anything you can't express with `apiUrl`.
|
|
139
270
|
*
|
|
140
271
|
* The SDK hands you a standardised `ConsentPayload`; you transform and
|
|
141
272
|
* dispatch it however your backend expects.
|
|
@@ -143,69 +274,396 @@ type ConsentPayload = {
|
|
|
143
274
|
interface ConsentBackend {
|
|
144
275
|
persist(payload: ConsentPayload): Promise<void> | void;
|
|
145
276
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
277
|
+
/**
|
|
278
|
+
* @deprecated Use `"cookie-only"` instead — identical behavior, clearer name.
|
|
279
|
+
* `"offline"` still works but will be removed in a future release.
|
|
280
|
+
*/
|
|
281
|
+
type DeprecatedOfflineMode = "offline";
|
|
282
|
+
type ConsentRuntimeMode = "self-hosted" | "cookie-only" | DeprecatedOfflineMode;
|
|
283
|
+
type ColorScheme = "light" | "dark" | "system";
|
|
284
|
+
/**
|
|
285
|
+
* Fields shared by every {@link CookieYesConfig} regardless of `mode`.
|
|
286
|
+
* This is the one canonical config surface — both `@cookieyes/core` and
|
|
287
|
+
* `@cookieyes/react` consume the exact same object, so a config is
|
|
288
|
+
* copy-pasteable between them with zero edits.
|
|
289
|
+
*/
|
|
290
|
+
type CookieYesConfigCommon = {
|
|
291
|
+
/**
|
|
292
|
+
* Which privacy regulation applies. Top-level and identical across every
|
|
293
|
+
* package (replaces the builder's `.regulation()` and core's former
|
|
294
|
+
* nested `overrides.regulation`).
|
|
295
|
+
*/
|
|
296
|
+
regulation?: Regulation | undefined;
|
|
297
|
+
colorScheme?: ColorScheme | undefined;
|
|
158
298
|
theme?: ThemeConfig | undefined;
|
|
299
|
+
i18n?: I18nConfig | undefined;
|
|
300
|
+
consentCategories?: ConsentCategory[] | undefined;
|
|
301
|
+
/**
|
|
302
|
+
* Define your own category taxonomy. Omit to get the built-in five
|
|
303
|
+
* (necessary, functional, analytics, performance, advertisement) unchanged.
|
|
304
|
+
* At least one category must be `{ required: true }`. Invalid configs fall
|
|
305
|
+
* back to the built-in five with a console warning. See {@link CategoryDef}.
|
|
306
|
+
*/
|
|
307
|
+
categories?: CategoryDef[] | undefined;
|
|
159
308
|
networkBlocker?: NetworkBlockerConfig | undefined;
|
|
160
309
|
reloadOnRevoke?: boolean | undefined;
|
|
310
|
+
/**
|
|
311
|
+
* Built-in, first-party integrations to stop cleanly (no reload) when their
|
|
312
|
+
* category is revoked — e.g. `{ vendor: "meta" }`. (Google Analytics/Tag
|
|
313
|
+
* Manager are handled automatically via the Consent Mode broadcast — no entry
|
|
314
|
+
* needed.) Integrations with no clean runtime stop fall back to the reload notice.
|
|
315
|
+
*/
|
|
316
|
+
integrations?: BuiltInIntegration[] | undefined;
|
|
317
|
+
/**
|
|
318
|
+
* Your own scripts' stop instructions, for anything without a built-in
|
|
319
|
+
* integration. A handler that can stop cleanly provides `stop()`; one that
|
|
320
|
+
* can't should be registered as a reload-only handler instead so revoking it
|
|
321
|
+
* shows the reload notice rather than silently continuing to track.
|
|
322
|
+
*/
|
|
323
|
+
customStopHandlers?: StopHandler[] | undefined;
|
|
324
|
+
/** Low-level: fires once, after the runtime's initial state is known (e.g. to conditionally load analytics on first load). For ongoing updates, use `consentStore.subscribeToConsentChanges` instead. */
|
|
161
325
|
onConsentReady?: ((state: ConsentSnapshot) => void) | undefined;
|
|
326
|
+
/** Low-level: fires on every saved consent change, for the lifetime of this config. If you need to subscribe/unsubscribe dynamically after mount, use `consentStore.getState().subscribeToConsentChanges` instead. */
|
|
162
327
|
onConsentUpdate?: ((state: ConsentSnapshot) => void) | undefined;
|
|
328
|
+
/**
|
|
329
|
+
* @deprecated Set `regulation` at the top level instead. This nested form
|
|
330
|
+
* still works and maps to the top-level field; if both are given, the
|
|
331
|
+
* top-level `regulation` wins. Retained for back-compat and removed after
|
|
332
|
+
* three release cycles, per the SDK deprecation policy.
|
|
333
|
+
*/
|
|
334
|
+
overrides?: {
|
|
335
|
+
regulation?: Regulation | undefined;
|
|
336
|
+
} | undefined;
|
|
337
|
+
};
|
|
338
|
+
/**
|
|
339
|
+
* Cookie-only mode — consent is stored client-side only; no backend keys are
|
|
340
|
+
* permitted (they fail at the type level). `mode: "cookie-only"` is the
|
|
341
|
+
* canonical value; `mode: "offline"` is a deprecated alias with identical
|
|
342
|
+
* behavior that emits a one-time-per-page-load deprecation warning.
|
|
343
|
+
*/
|
|
344
|
+
type CookieYesOfflineConfig = CookieYesConfigCommon & {
|
|
345
|
+
mode: "cookie-only" | DeprecatedOfflineMode;
|
|
163
346
|
};
|
|
347
|
+
/** Self-hosted mode — consent decisions are persisted to your own backend. */
|
|
348
|
+
type CookieYesSelfHostedConfig = CookieYesConfigCommon & {
|
|
349
|
+
mode: "self-hosted";
|
|
350
|
+
/** Endpoint the {@link ConsentPayload} is POSTed to. Canonical key. */
|
|
351
|
+
apiUrl?: string | undefined;
|
|
352
|
+
apiKey?: string | undefined;
|
|
353
|
+
/** Custom persistence adapter — full control over transport/headers/retries. */
|
|
354
|
+
backend?: ConsentBackend | undefined;
|
|
355
|
+
/**
|
|
356
|
+
* @deprecated Renamed to `apiUrl`. This alias still works and maps to
|
|
357
|
+
* `apiUrl`; if both are given, `apiUrl` wins. Retained for back-compat and
|
|
358
|
+
* removed after three release cycles, per the SDK deprecation policy.
|
|
359
|
+
*/
|
|
360
|
+
backendURL?: string | undefined;
|
|
361
|
+
};
|
|
362
|
+
/**
|
|
363
|
+
* The canonical configuration object for the CookieYes SDK, discriminated on
|
|
364
|
+
* `mode`. Passed identically to `initCookieYes()` /
|
|
365
|
+
* `getOrCreateConsentRuntime()` in `@cookieyes/core` and `initCookieYes()` in
|
|
366
|
+
* `@cookieyes/react`.
|
|
367
|
+
*
|
|
368
|
+
* The discriminated union guarantees invalid combinations fail at compile time
|
|
369
|
+
* — e.g. supplying `apiUrl`/`backend` under `mode: "cookie-only"` is a type error.
|
|
370
|
+
*/
|
|
371
|
+
type CookieYesConfig = CookieYesOfflineConfig | CookieYesSelfHostedConfig;
|
|
372
|
+
/**
|
|
373
|
+
* @deprecated Renamed to {@link CookieYesConfig}. Retained as a type alias for
|
|
374
|
+
* back-compat and removed after three release cycles, per the SDK deprecation
|
|
375
|
+
* policy.
|
|
376
|
+
*/
|
|
377
|
+
type ConsentRuntimeOptions = CookieYesConfig;
|
|
164
378
|
type ConsentChangePayload = {
|
|
165
379
|
allowedCategories: ConsentCategory[];
|
|
166
380
|
deniedCategories: ConsentCategory[];
|
|
167
381
|
};
|
|
382
|
+
/** Which consent event to listen for. See {@link ConsentStore.on}. */
|
|
383
|
+
type ConsentEventType = "save" | "change";
|
|
384
|
+
type ConsentEventPayload = {
|
|
385
|
+
/** The full committed consent map in effect when the event fired. */
|
|
386
|
+
categories: Record<string, boolean>;
|
|
387
|
+
/** Categories whose value differed from before. Empty on the initial replay. */
|
|
388
|
+
changedCategories: ConsentCategory[];
|
|
389
|
+
/**
|
|
390
|
+
* `true` when this is the one-off replay a listener gets on attach (here's
|
|
391
|
+
* the current state), `false` when the visitor actually just acted.
|
|
392
|
+
*/
|
|
393
|
+
isInitial: boolean;
|
|
394
|
+
};
|
|
395
|
+
type ConsentEventListener = (payload: ConsentEventPayload) => void;
|
|
396
|
+
/** Restrict a listener to a single category (fires only when it changes). */
|
|
397
|
+
type ConsentEventOptions = {
|
|
398
|
+
category?: ConsentCategory;
|
|
399
|
+
};
|
|
168
400
|
type ActiveUI = "banner" | "dialog" | null;
|
|
169
401
|
type ConsentStoreState = ConsentSnapshot & {
|
|
170
402
|
activeUI: ActiveUI;
|
|
171
|
-
|
|
403
|
+
/** Live/working values — reflect in-progress dialog toggles. Drive checkboxes. */
|
|
404
|
+
consents: Record<string, boolean>;
|
|
405
|
+
/**
|
|
406
|
+
* Consent in effect — changes only on a saved decision, not a toggle. Gate
|
|
407
|
+
* scripts/embeds on this (or {@link ConsentStoreState.has}).
|
|
408
|
+
*/
|
|
409
|
+
committedConsents: Record<string, boolean>;
|
|
410
|
+
/** True when `category` is committed-granted (a saved decision), not just toggled. */
|
|
172
411
|
has: (category: ConsentCategory) => boolean;
|
|
173
412
|
saveConsents: (target: "all" | "necessary" | ConsentCategory[]) => Promise<void>;
|
|
174
413
|
setConsent: (category: ConsentCategory, value: boolean) => void;
|
|
414
|
+
/** Low-level: fires only on *saved* preference changes, not transient UI toggles — see `ConsentStore.subscribe` for the recommended, general-purpose subscription. */
|
|
175
415
|
subscribeToConsentChanges: (listener: (payload: ConsentChangePayload) => void) => () => void;
|
|
176
416
|
};
|
|
417
|
+
/**
|
|
418
|
+
* The recommended way to read consent state outside React. `subscribe` fires
|
|
419
|
+
* on every state change (including transient UI toggles, e.g. a checkbox
|
|
420
|
+
* flip before saving); for saved-changes-only, see
|
|
421
|
+
* `ConsentStoreState.subscribeToConsentChanges`.
|
|
422
|
+
*/
|
|
177
423
|
type ConsentStore = {
|
|
178
424
|
subscribe: (listener: (state: ConsentStoreState) => void) => () => void;
|
|
179
425
|
getState: () => ConsentStoreState;
|
|
426
|
+
/** Text for the active language (English fills gaps). Swaps on `setLanguage`. */
|
|
427
|
+
translations: TranslationMap;
|
|
428
|
+
/** The active language, its reading direction, and the languages loaded. */
|
|
429
|
+
getLanguageInfo: () => LanguageInfo;
|
|
430
|
+
/**
|
|
431
|
+
* Switch language live (no reload) — `subscribe` listeners fire so a custom UI
|
|
432
|
+
* can re-render. Loads the language via `i18n.loadLanguage` if not bundled.
|
|
433
|
+
*/
|
|
434
|
+
setLanguage: (tag: string) => Promise<void>;
|
|
435
|
+
/** Customer-provided text for a category in the active language, if any. */
|
|
436
|
+
getCategoryText: (id: string) => Partial<CategoryText> | undefined;
|
|
437
|
+
/**
|
|
438
|
+
* The category taxonomy in effect (custom list or the built-in five) — its
|
|
439
|
+
* ids, which are `required`, etc. Use it to render categories in a custom UI
|
|
440
|
+
* so it follows whatever taxonomy is configured.
|
|
441
|
+
*/
|
|
442
|
+
categories: ResolvedCategories;
|
|
443
|
+
/**
|
|
444
|
+
* React to consent decisions. `"save"` fires on every save (even an
|
|
445
|
+
* unchanged re-confirm); `"change"` fires only when a category actually
|
|
446
|
+
* differs — use it to (re)load a script without re-running on a re-confirm.
|
|
447
|
+
* The listener fires once immediately with the current state
|
|
448
|
+
* (`isInitial: true`). Pass `{ category }` to only hear about one category.
|
|
449
|
+
* Returns an unsubscribe function.
|
|
450
|
+
*/
|
|
451
|
+
on: (type: ConsentEventType, listener: ConsentEventListener, options?: ConsentEventOptions) => () => void;
|
|
180
452
|
};
|
|
181
453
|
type ConsentRuntime = {
|
|
182
454
|
consentManager: ConsentManager;
|
|
183
455
|
consentStore: ConsentStore;
|
|
184
456
|
};
|
|
185
457
|
|
|
458
|
+
/**
|
|
459
|
+
* Google Consent Mode v2 storage/signal types. A category can declare which of
|
|
460
|
+
* these it represents via {@link CategoryDef.gcm}; the SDK then broadcasts them
|
|
461
|
+
* (see google-consent-mode.ts). `security_storage` is always granted and is
|
|
462
|
+
* handled by the broadcast itself, so it never needs to be mapped.
|
|
463
|
+
*/
|
|
464
|
+
type GoogleConsentSignal = "ad_storage" | "ad_user_data" | "ad_personalization" | "analytics_storage" | "functionality_storage" | "personalization_storage" | "security_storage";
|
|
465
|
+
/**
|
|
466
|
+
* A single consent category. `id` is the stable key stored in the cookie and
|
|
467
|
+
* used everywhere (banner, preferences, read APIs, integrations). Exactly one
|
|
468
|
+
* category should be marked `required` — the always-on, non-optional one (like
|
|
469
|
+
* the default "necessary") — flagged explicitly here, never inferred from a
|
|
470
|
+
* name, so it survives full renaming.
|
|
471
|
+
*/
|
|
472
|
+
type CategoryDef = {
|
|
473
|
+
id: ConsentCategory;
|
|
474
|
+
/** The always-on, non-optional category. At least one is required. */
|
|
475
|
+
required?: boolean | undefined;
|
|
476
|
+
/** Display label. Falls back to the translation for built-in ids. */
|
|
477
|
+
label?: string | undefined;
|
|
478
|
+
/** Display description. Falls back to the translation for built-in ids. */
|
|
479
|
+
description?: string | undefined;
|
|
480
|
+
/** Google Consent Mode signals this category governs (see {@link GoogleConsentSignal}). */
|
|
481
|
+
gcm?: GoogleConsentSignal[] | undefined;
|
|
482
|
+
};
|
|
483
|
+
/**
|
|
484
|
+
* The built-in five, used verbatim when a customer configures nothing. GCM
|
|
485
|
+
* mapping mirrors production's `_ckySetGoogleConsentMode` (analytics →
|
|
486
|
+
* analytics_storage, advertisement → the ad_* signals, functional →
|
|
487
|
+
* functionality/personalization; performance maps to nothing; security_storage
|
|
488
|
+
* is always granted by the broadcast).
|
|
489
|
+
*/
|
|
490
|
+
declare const DEFAULT_CATEGORIES: CategoryDef[];
|
|
491
|
+
type ResolvedCategories = {
|
|
492
|
+
/** Ordered category definitions actually in effect. */
|
|
493
|
+
list: CategoryDef[];
|
|
494
|
+
/** Ordered ids (fast access). */
|
|
495
|
+
ids: ConsentCategory[];
|
|
496
|
+
/** Ids marked `required` (always granted, never toggleable). */
|
|
497
|
+
requiredIds: Set<ConsentCategory>;
|
|
498
|
+
/** Stable signature of this taxonomy; a change here re-requests consent. */
|
|
499
|
+
taxonomyHash: string;
|
|
500
|
+
/** True when the built-in five are in effect (configured or fallback). */
|
|
501
|
+
isDefault: boolean;
|
|
502
|
+
};
|
|
503
|
+
/**
|
|
504
|
+
* Resolve the category list from config. Returns the built-in five when nothing
|
|
505
|
+
* is configured. On an invalid custom config (empty, duplicate/reserved ids, or
|
|
506
|
+
* no `required` category) it warns and falls back to the built-in five, rather
|
|
507
|
+
* than leaving the visitor a broken/empty or unprotected setup.
|
|
508
|
+
*/
|
|
509
|
+
declare function resolveCategories(defs?: CategoryDef[]): ResolvedCategories;
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* The canonical config with every deprecated alias already collapsed into its
|
|
513
|
+
* top-level key. Both `@cookieyes/core` and `@cookieyes/react` consume the
|
|
514
|
+
* output of {@link _normalizeConfig}, so alias resolution lives in exactly one
|
|
515
|
+
* place and the two packages can never drift.
|
|
516
|
+
*
|
|
517
|
+
* @internal
|
|
518
|
+
*/
|
|
519
|
+
type _NormalizedConfig = {
|
|
520
|
+
mode: ConsentRuntimeMode;
|
|
521
|
+
regulation?: Regulation | undefined;
|
|
522
|
+
colorScheme?: ColorScheme | undefined;
|
|
523
|
+
theme?: ThemeConfig | undefined;
|
|
524
|
+
i18n?: I18nConfig | undefined;
|
|
525
|
+
consentCategories?: ConsentCategory[] | undefined;
|
|
526
|
+
categories?: CategoryDef[] | undefined;
|
|
527
|
+
networkBlocker?: NetworkBlockerConfig | undefined;
|
|
528
|
+
reloadOnRevoke?: boolean | undefined;
|
|
529
|
+
integrations?: BuiltInIntegration[] | undefined;
|
|
530
|
+
customStopHandlers?: StopHandler[] | undefined;
|
|
531
|
+
onConsentReady?: ((state: ConsentSnapshot) => void) | undefined;
|
|
532
|
+
onConsentUpdate?: ((state: ConsentSnapshot) => void) | undefined;
|
|
533
|
+
apiUrl?: string | undefined;
|
|
534
|
+
apiKey?: string | undefined;
|
|
535
|
+
backend?: ConsentBackend | undefined;
|
|
536
|
+
};
|
|
537
|
+
/**
|
|
538
|
+
* Resolve a public {@link CookieYesConfig} into its canonical internal form.
|
|
539
|
+
*
|
|
540
|
+
* Deprecated aliases map silently to their canonical key when used alone; when
|
|
541
|
+
* an alias and its canonical key are both present, the canonical key wins and
|
|
542
|
+
* exactly one warning is logged for that collision.
|
|
543
|
+
*
|
|
544
|
+
* - `overrides.regulation` → `regulation`
|
|
545
|
+
* - `backendURL` → `apiUrl`
|
|
546
|
+
*
|
|
547
|
+
* @internal
|
|
548
|
+
*/
|
|
549
|
+
declare function _normalizeConfig(config: CookieYesConfig): _NormalizedConfig;
|
|
550
|
+
|
|
186
551
|
type RawCookieFields = {
|
|
187
552
|
consentid?: string;
|
|
188
553
|
consent?: string;
|
|
189
554
|
action?: string;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
analytics?: string;
|
|
193
|
-
performance?: string;
|
|
194
|
-
advertisement?: string;
|
|
555
|
+
/** Taxonomy signature stored with the consent (see ResolvedCategories.taxonomyHash). */
|
|
556
|
+
tax?: string;
|
|
195
557
|
lastRenewedDate?: string;
|
|
558
|
+
/** Every non-meta pair: category id → "yes" | "no". */
|
|
559
|
+
categories: Record<string, string>;
|
|
196
560
|
};
|
|
197
561
|
declare function parseCookie(raw: string): RawCookieFields;
|
|
198
562
|
declare function serializeCookie(snapshot: ConsentSnapshot): string;
|
|
199
563
|
declare function generateConsentId(): string;
|
|
200
564
|
|
|
565
|
+
/**
|
|
566
|
+
* One-time-per-page-load console warning for `mode: "offline"`.
|
|
567
|
+
* Both @cookieyes/core and @cookieyes/react call this so the wording and the
|
|
568
|
+
* "once" behavior stay identical no matter which package reads the setting.
|
|
569
|
+
*/
|
|
570
|
+
declare function _warnOfflineModeDeprecated(): void;
|
|
571
|
+
/** @internal test-only — resets the one-time warning guard between test cases. */
|
|
572
|
+
declare function _resetOfflineModeWarning(): void;
|
|
573
|
+
|
|
574
|
+
type ConsentEmitter = {
|
|
575
|
+
/**
|
|
576
|
+
* Listen for consent events. `"save"` fires on every saved decision (even an
|
|
577
|
+
* unchanged re-confirm); `"change"` fires only when a category actually
|
|
578
|
+
* differs. The listener fires once immediately with the current state
|
|
579
|
+
* (`isInitial: true`) so a late listener isn't blind to earlier choices.
|
|
580
|
+
* Pass `{ category }` to only be called when that one category changes.
|
|
581
|
+
* Returns an unsubscribe function.
|
|
582
|
+
*/
|
|
583
|
+
on: (type: ConsentEventType, listener: ConsentEventListener, options?: ConsentEventOptions) => () => void;
|
|
584
|
+
/** Feed in the committed categories after a save; the emitter fans out events. */
|
|
585
|
+
push: (categories: Record<string, boolean>) => void;
|
|
586
|
+
};
|
|
587
|
+
/**
|
|
588
|
+
* The consent event fan-out, shared by the core and React runtimes so both
|
|
589
|
+
* behave identically. `getCommitted` returns the consent currently in effect,
|
|
590
|
+
* used for the immediate replay a new listener receives.
|
|
591
|
+
*/
|
|
592
|
+
declare function createConsentEmitter(getCommitted: () => Record<string, boolean>): ConsentEmitter;
|
|
593
|
+
|
|
594
|
+
type GcmValue = "granted" | "denied";
|
|
595
|
+
/**
|
|
596
|
+
* Compute the granted/denied value for every GCM signal from the current
|
|
597
|
+
* category consent, using each category's `gcm` mapping.
|
|
598
|
+
*
|
|
599
|
+
* - A signal is `granted` if *any* granted category maps to it.
|
|
600
|
+
* - `security_storage` is always `granted` (it's strictly necessary and not
|
|
601
|
+
* consentable — this mirrors production's behaviour).
|
|
602
|
+
* - A signal that no category maps to defaults to `denied`.
|
|
603
|
+
*/
|
|
604
|
+
declare function computeGoogleConsent(resolved: ResolvedCategories, categories: Record<string, boolean>): Record<GoogleConsentSignal, GcmValue>;
|
|
605
|
+
/**
|
|
606
|
+
* Push a Consent Mode `update` for all seven signals onto the dataLayer, if one
|
|
607
|
+
* is present. Safe to call on load and on every consent change; a no-op when no
|
|
608
|
+
* Google service is on the page.
|
|
609
|
+
*
|
|
610
|
+
* The customer is responsible for the Consent Mode *default* (the gtag snippet
|
|
611
|
+
* that must run before their Google tags, typically denying everything). This
|
|
612
|
+
* function owns the *update* that reflects the visitor's actual choice.
|
|
613
|
+
*/
|
|
614
|
+
declare function broadcastGoogleConsent(resolved: ResolvedCategories, categories: Record<string, boolean>): void;
|
|
615
|
+
|
|
201
616
|
declare const en: TranslationMap;
|
|
202
617
|
|
|
618
|
+
/** The base subtag of a language tag, lowercased: "en-GB" → "en". */
|
|
619
|
+
declare function primaryOf(tag: string): string;
|
|
620
|
+
/** Reading direction for a language tag, e.g. "ar" or "ar-EG" → "rtl". */
|
|
621
|
+
declare function getTextDirection(tag: string): TextDirection;
|
|
622
|
+
/** Deep-merge a (possibly partial) override onto a complete base map. */
|
|
623
|
+
declare function mergeTranslations(base: TranslationMap, override?: PartialTranslations): TranslationMap;
|
|
624
|
+
/**
|
|
625
|
+
* The language to start in, resolved in order: explicit `locale`, then the
|
|
626
|
+
* browser's language, then English. Only returns one we actually have text for
|
|
627
|
+
* (others can be brought in later via `loadLanguage`).
|
|
628
|
+
*/
|
|
629
|
+
declare function pickLanguage(i18n?: I18nConfig): string;
|
|
630
|
+
/** Full translations for the resolved starting language, English filling any gaps. */
|
|
203
631
|
declare function resolveTranslations(i18n?: I18nConfig): TranslationMap;
|
|
204
632
|
|
|
633
|
+
type LanguageController = {
|
|
634
|
+
/** Text for the active language (English fills any gaps). */
|
|
635
|
+
getTranslations: () => TranslationMap;
|
|
636
|
+
getLanguageInfo: () => LanguageInfo;
|
|
637
|
+
/** Switch language live; loads via `i18n.loadLanguage` if not already present. */
|
|
638
|
+
setLanguage: (tag: string) => Promise<void>;
|
|
639
|
+
/**
|
|
640
|
+
* The customer's own text for a category in the *active* language, if they
|
|
641
|
+
* provided it — kept separate from the English defaults so a translation can
|
|
642
|
+
* win over a category's config label without the English default masking it.
|
|
643
|
+
*/
|
|
644
|
+
getCategoryText: (id: string) => Partial<CategoryText> | undefined;
|
|
645
|
+
};
|
|
646
|
+
/**
|
|
647
|
+
* Owns the active language: which one is showing, its (English-filled) text,
|
|
648
|
+
* and switching to another — loading it on demand when a loader is provided.
|
|
649
|
+
* `onChange` runs after every switch so the UI can re-render.
|
|
650
|
+
*
|
|
651
|
+
* Framework-agnostic: used by both the core and React runtimes, so they behave
|
|
652
|
+
* identically.
|
|
653
|
+
*/
|
|
654
|
+
declare function createLanguageController(i18n: I18nConfig | undefined, onChange: () => void): LanguageController;
|
|
655
|
+
|
|
205
656
|
declare function createConsentManager(config: ConsentConfig): ConsentManager;
|
|
206
657
|
|
|
207
|
-
declare function getOrCreateConsentRuntime(
|
|
658
|
+
declare function getOrCreateConsentRuntime(config: CookieYesConfig): ConsentRuntime;
|
|
659
|
+
/**
|
|
660
|
+
* Canonical setup entry point. Alias of {@link getOrCreateConsentRuntime} that
|
|
661
|
+
* accepts the same {@link CookieYesConfig} and returns the same process-wide
|
|
662
|
+
* singleton — provided so documentation can use one setup name (`initCookieYes`)
|
|
663
|
+
* across every package.
|
|
664
|
+
*/
|
|
665
|
+
declare function initCookieYes(config: CookieYesConfig): ConsentRuntime;
|
|
208
666
|
declare function resetConsentRuntime(): void;
|
|
209
667
|
|
|
210
|
-
export { createConsentManager, en as defaultTranslations, generateConsentId, getOrCreateConsentRuntime, installNetworkBlocker, parseCookie, resetConsentRuntime, resolveTranslations, serializeCookie, uninstallNetworkBlocker };
|
|
211
|
-
export type { ActiveUI, BlockedRequestInfo, ConsentBackend, ConsentCategory, ConsentChangePayload, ConsentConfig, ConsentManager, ConsentPayload, ConsentRuntime, ConsentRuntimeMode, ConsentRuntimeOptions, ConsentSnapshot, ConsentStore, ConsentStoreState, I18nConfig, NetworkBlockerConfig, NetworkBlockerRule, Regulation, ScriptEntry, ThemeConfig, TranslationMap };
|
|
668
|
+
export { DEFAULT_CATEGORIES, _clearStopHandlers, _normalizeConfig, _resetOfflineModeWarning, _warnOfflineModeDeprecated, broadcastGoogleConsent, computeGoogleConsent, createConsentEmitter, createConsentManager, createLanguageController, en as defaultTranslations, generateConsentId, getOrCreateConsentRuntime, getTextDirection, initCookieYes, installNetworkBlocker, mergeTranslations, parseCookie, pickLanguage, primaryOf, registerStopHandler, resetConsentRuntime, resolveBuiltInIntegration, resolveCategories, resolveTranslations, serializeCookie, uninstallNetworkBlocker };
|
|
669
|
+
export type { ActiveUI, AnyStopHandler, BlockedRequestInfo, BuiltInIntegration, CategoryDef, CategoryText, ColorScheme, ConsentBackend, ConsentCategory, ConsentChangePayload, ConsentConfig, ConsentEmitter, ConsentEventListener, ConsentEventOptions, ConsentEventPayload, ConsentEventType, ConsentManager, ConsentPayload, ConsentRuntime, ConsentRuntimeMode, ConsentRuntimeOptions, ConsentSnapshot, ConsentStore, ConsentStoreState, CookieYesConfig, CookieYesOfflineConfig, CookieYesSelfHostedConfig, GoogleConsentSignal, I18nConfig, LanguageController, LanguageInfo, NetworkBlockerConfig, NetworkBlockerRule, PartialTranslations, Regulation, ReloadNoticeState, ReloadOnlyHandler, ResolvedCategories, ScriptEntry, StopHandler, TextDirection, ThemeConfig, TranslationMap, _NormalizedConfig };
|