@freshjuice/zest 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/zest.d.ts ADDED
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Type definitions for `@freshjuice/zest` (full build with UI).
3
+ *
4
+ * The full build ships the consent engine plus a Shadow-DOM banner,
5
+ * settings modal, and floating widget. It auto-initialises on script
6
+ * load when included via `<script>`, or you can drive it manually via
7
+ * `Zest.init()`.
8
+ *
9
+ * For a logic-only build without UI, import from
10
+ * `@freshjuice/zest/headless` instead.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import Zest from '@freshjuice/zest';
15
+ *
16
+ * Zest.init({
17
+ * position: 'bottom-right',
18
+ * theme: 'auto',
19
+ * accentColor: '#0071e3',
20
+ * policyUrl: '/privacy'
21
+ * });
22
+ * ```
23
+ */
24
+
25
+ /** Built-in consent categories. */
26
+ export type ConsentCategory =
27
+ | 'essential'
28
+ | 'functional'
29
+ | 'analytics'
30
+ | 'marketing';
31
+
32
+ /**
33
+ * Per-category boolean consent state. `essential` is always `true` —
34
+ * consent for it cannot be revoked because it covers strictly-necessary
35
+ * processing.
36
+ */
37
+ export type ConsentState =
38
+ & Partial<Record<ConsentCategory, boolean>>
39
+ & { essential: true };
40
+
41
+ /** Snapshot returned by `init()`. */
42
+ export interface InitSnapshot {
43
+ consent: ConsentState;
44
+ hasDecision: boolean;
45
+ dntApplied: boolean;
46
+ }
47
+
48
+ /** Tamper-evident proof of the user's last consent decision. */
49
+ export interface ConsentProof {
50
+ version: string;
51
+ timestamp: number;
52
+ categories: ConsentState;
53
+ }
54
+
55
+ /** Output of `getDNTDetails()`. */
56
+ export interface DNTDetails {
57
+ dnt: boolean;
58
+ gpc: boolean;
59
+ doNotTrack: string | null;
60
+ globalPrivacyControl: boolean;
61
+ }
62
+
63
+ /** Behaviour when DNT / GPC is detected at init time. */
64
+ export type DNTBehavior = 'reject' | 'preselect' | 'ignore';
65
+
66
+ /** Banner position on the page. */
67
+ export type BannerPosition = 'bottom' | 'bottom-left' | 'bottom-right' | 'top';
68
+
69
+ /** UI theme. `auto` follows `prefers-color-scheme`. */
70
+ export type ZestTheme = 'light' | 'dark' | 'auto';
71
+
72
+ /** Script-blocking strictness. */
73
+ export type ZestMode = 'manual' | 'safe' | 'strict' | 'doomsday';
74
+
75
+ /**
76
+ * Optional consumer callbacks. Each is wrapped in a try/catch internally
77
+ * so a thrown error never breaks the consent pipeline.
78
+ */
79
+ export interface ZestCallbacks {
80
+ onAccept?: (consent: ConsentState) => void;
81
+ onReject?: (consent: ConsentState) => void;
82
+ onChange?: (consent: ConsentState) => void;
83
+ onReady?: (consent: ConsentState) => void;
84
+ }
85
+
86
+ /** Configuration accepted by `init()` and `window.ZestConfig`. */
87
+ export interface InitOptions {
88
+ /** Display language. `'auto'` detects from `<html lang>` / browser. */
89
+ lang?:
90
+ | 'auto'
91
+ | 'en' | 'de' | 'es' | 'fr' | 'it' | 'pt'
92
+ | 'nl' | 'pl' | 'uk' | 'ru' | 'ja' | 'zh';
93
+ /** Banner position. Default `'bottom'`. */
94
+ position?: BannerPosition;
95
+ /** UI theme. Default `'auto'`. */
96
+ theme?: ZestTheme;
97
+ /** Hex accent color for buttons (e.g. `'#0071e3'`). */
98
+ accentColor?: string;
99
+ /** Link to the host site's privacy policy. */
100
+ policyUrl?: string;
101
+ /** Show floating "manage cookies" widget after a decision. Default `true`. */
102
+ showWidget?: boolean;
103
+ /** Cookie expiration in days. Default `365`. */
104
+ expiration?: number;
105
+ /** Script-blocking mode. Default `'safe'`. */
106
+ mode?: ZestMode;
107
+ /** Auto-initialise on script load. Default `true` for the UI build. */
108
+ autoInit?: boolean;
109
+ /** Respect Do Not Track / Global Privacy Control. Default `true`. */
110
+ respectDNT?: boolean;
111
+ /** What to do when DNT/GPC is on. Default `'reject'`. */
112
+ dntBehavior?: DNTBehavior;
113
+ /** Consumer callbacks. */
114
+ callbacks?: ZestCallbacks;
115
+ /** Anything else — Zest tolerates unknown keys at runtime. */
116
+ [key: string]: unknown;
117
+ }
118
+
119
+ /** Event names emitted on `document.documentElement`. */
120
+ export interface ZestEvents {
121
+ READY: 'zest:ready';
122
+ CONSENT: 'zest:consent';
123
+ REJECT: 'zest:reject';
124
+ CHANGE: 'zest:change';
125
+ SHOW: 'zest:show';
126
+ HIDE: 'zest:hide';
127
+ }
128
+
129
+ export type ZestEventName = ZestEvents[keyof ZestEvents];
130
+
131
+ /** Detail payload of consent events. */
132
+ export interface ZestEventDetail {
133
+ consent: ConsentState;
134
+ previous?: ConsentState;
135
+ }
136
+
137
+ declare const Zest: {
138
+ /** Initialise. Auto-called when the script loads unless `autoInit: false`. */
139
+ init(options?: InitOptions): InitSnapshot;
140
+
141
+ /** Show the consent banner. */
142
+ show(): void;
143
+
144
+ /** Hide the consent banner. */
145
+ hide(): void;
146
+
147
+ /** Open the per-category settings modal. */
148
+ showSettings(): void;
149
+
150
+ /** Close the settings modal. */
151
+ hideSettings(): void;
152
+
153
+ /** Show the persistent "manage cookies" widget. */
154
+ showWidget(): void;
155
+
156
+ /** Hide the widget without removing it. */
157
+ hideWidget(): void;
158
+
159
+ /** Current consent state (clone, safe to mutate). */
160
+ getConsent(): ConsentState;
161
+
162
+ /** Has the user granted consent for `category`? */
163
+ hasConsent(category: ConsentCategory): boolean;
164
+
165
+ /** Has the user made any consent decision yet? */
166
+ hasConsentDecision(): boolean;
167
+
168
+ /** Tamper-evident snapshot of the last consent decision. */
169
+ getConsentProof(): ConsentProof | null;
170
+
171
+ /** Grant consent for every category and run accept callbacks. */
172
+ acceptAll(): void;
173
+
174
+ /** Revoke consent for every non-essential category and run reject callbacks. */
175
+ rejectAll(): void;
176
+
177
+ /** Wipe all consent state and reshow the banner. */
178
+ reset(): void;
179
+
180
+ /** True if the browser is sending DNT or GPC. */
181
+ isDoNotTrackEnabled(): boolean;
182
+
183
+ /** Why `isDoNotTrackEnabled()` returned what it did. */
184
+ getDNTDetails(): DNTDetails;
185
+
186
+ /** Subscribe to a consent event. Returns an unsubscribe function. */
187
+ on(
188
+ eventName: ZestEventName,
189
+ handler: (event: CustomEvent<ZestEventDetail>) => void
190
+ ): () => void;
191
+
192
+ /** Subscribe once; auto-unsubscribes after the first call. */
193
+ once(
194
+ eventName: ZestEventName,
195
+ handler: (event: CustomEvent<ZestEventDetail>) => void
196
+ ): () => void;
197
+
198
+ /** Constants for `on()` / `once()`. */
199
+ EVENTS: ZestEvents;
200
+
201
+ /** Active configuration after `init()`. */
202
+ getConfig(): InitOptions | null;
203
+ };
204
+
205
+ export default Zest;
206
+
207
+ declare global {
208
+ interface Window {
209
+ /** Set before loading `zest.min.js` to configure auto-initialisation. */
210
+ ZestConfig?: InitOptions;
211
+ /** The Zest singleton, attached after auto-init. */
212
+ Zest?: typeof Zest;
213
+ }
214
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Type definitions for `@freshjuice/zest/headless`.
3
+ *
4
+ * The headless build ships the consent engine without any UI: no Shadow
5
+ * DOM, no styles, no DOM mounting. You bring your own banner / modal /
6
+ * settings markup and call into Zest for the consent state.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import Zest from '@freshjuice/zest/headless';
11
+ *
12
+ * Zest.init({ respectDNT: true, expiration: 365 });
13
+ *
14
+ * if (!Zest.hasConsentDecision()) myBanner.show();
15
+ *
16
+ * acceptBtn.addEventListener('click', () => Zest.acceptAll());
17
+ * rejectBtn.addEventListener('click', () => Zest.rejectAll());
18
+ * ```
19
+ */
20
+
21
+ /** Built-in consent categories. */
22
+ export type ConsentCategory =
23
+ | 'essential'
24
+ | 'functional'
25
+ | 'analytics'
26
+ | 'marketing';
27
+
28
+ /**
29
+ * Per-category boolean consent state. `essential` is always `true` —
30
+ * consent for it cannot be revoked because it covers strictly-necessary
31
+ * processing.
32
+ */
33
+ export type ConsentState =
34
+ & Partial<Record<ConsentCategory, boolean>>
35
+ & { essential: true };
36
+
37
+ /** Snapshot returned by `init()`. */
38
+ export interface InitSnapshot {
39
+ consent: ConsentState;
40
+ hasDecision: boolean;
41
+ dntApplied: boolean;
42
+ }
43
+
44
+ /** Tamper-evident proof of the user's last consent decision. */
45
+ export interface ConsentProof {
46
+ version: string;
47
+ timestamp: number;
48
+ categories: ConsentState;
49
+ }
50
+
51
+ /** Output of `getDNTDetails()`. */
52
+ export interface DNTDetails {
53
+ dnt: boolean;
54
+ gpc: boolean;
55
+ doNotTrack: string | null;
56
+ globalPrivacyControl: boolean;
57
+ }
58
+
59
+ /** Behaviour when DNT / GPC is detected at init time. */
60
+ export type DNTBehavior = 'reject' | 'preselect' | 'ignore';
61
+
62
+ /**
63
+ * Optional consumer callbacks. Each is wrapped in a try/catch internally
64
+ * so a thrown error never breaks the consent pipeline.
65
+ */
66
+ export interface ZestCallbacks {
67
+ onAccept?: (consent: ConsentState) => void;
68
+ onReject?: (consent: ConsentState) => void;
69
+ onChange?: (consent: ConsentState) => void;
70
+ onReady?: (consent: ConsentState) => void;
71
+ }
72
+
73
+ /** Configuration accepted by `init()`. */
74
+ export interface InitOptions {
75
+ /** Respect Do Not Track / Global Privacy Control. Default `true`. */
76
+ respectDNT?: boolean;
77
+ /** What to do when DNT/GPC is on. Default `'reject'`. */
78
+ dntBehavior?: DNTBehavior;
79
+ /** Cookie expiration in days. Default `365`. */
80
+ expiration?: number;
81
+ /** Consumer callbacks. */
82
+ callbacks?: ZestCallbacks;
83
+ /** Anything else — Zest tolerates unknown keys at runtime. */
84
+ [key: string]: unknown;
85
+ }
86
+
87
+ /** Event names emitted on the `window` `document.documentElement`. */
88
+ export interface ZestEvents {
89
+ READY: 'zest:ready';
90
+ CONSENT: 'zest:consent';
91
+ REJECT: 'zest:reject';
92
+ CHANGE: 'zest:change';
93
+ SHOW: 'zest:show';
94
+ HIDE: 'zest:hide';
95
+ }
96
+
97
+ export type ZestEventName = ZestEvents[keyof ZestEvents];
98
+
99
+ /** Detail payload of the consent-change event. */
100
+ export interface ZestEventDetail {
101
+ consent: ConsentState;
102
+ previous?: ConsentState;
103
+ }
104
+
105
+ declare const Zest: {
106
+ /** Initialise the consent engine. Must be called before any other API. */
107
+ init(options?: InitOptions): InitSnapshot;
108
+
109
+ /** Current consent state (clone, safe to mutate). */
110
+ getConsent(): ConsentState;
111
+
112
+ /** Has the user granted consent for `category`? */
113
+ hasConsent(category: ConsentCategory): boolean;
114
+
115
+ /** Has the user made any consent decision yet (accept, reject, or
116
+ * partial)? */
117
+ hasConsentDecision(): boolean;
118
+
119
+ /** Tamper-evident snapshot of the last consent decision. */
120
+ getConsentProof(): ConsentProof | null;
121
+
122
+ /** Grant consent for every category. */
123
+ acceptAll(): ConsentState | null;
124
+
125
+ /** Revoke consent for every non-essential category. */
126
+ rejectAll(): ConsentState | null;
127
+
128
+ /** Set per-category consent. Missing keys are left untouched. */
129
+ updateConsent(
130
+ selections: Partial<Record<ConsentCategory, boolean>>
131
+ ): ConsentState | null;
132
+
133
+ /** Wipe all consent state. Useful for "I changed my mind" flows. */
134
+ reset(): void;
135
+
136
+ /** True if the browser is sending DNT or GPC. */
137
+ isDoNotTrackEnabled(): boolean;
138
+
139
+ /** Why `isDoNotTrackEnabled()` returned what it did. */
140
+ getDNTDetails(): DNTDetails;
141
+
142
+ /** Subscribe to a consent event. Returns an unsubscribe function. */
143
+ on(
144
+ eventName: ZestEventName,
145
+ handler: (event: CustomEvent<ZestEventDetail>) => void
146
+ ): () => void;
147
+
148
+ /** Subscribe once; auto-unsubscribes after the first call. */
149
+ once(
150
+ eventName: ZestEventName,
151
+ handler: (event: CustomEvent<ZestEventDetail>) => void
152
+ ): () => void;
153
+
154
+ /** Constants for `on()` / `once()`. */
155
+ EVENTS: ZestEvents;
156
+
157
+ /** Active configuration after `init()`. */
158
+ getConfig(): InitOptions | null;
159
+ };
160
+
161
+ export default Zest;
162
+
163
+ // Named tree-shake-friendly exports.
164
+ export const init: typeof Zest.init;
165
+ export const acceptAll: typeof Zest.acceptAll;
166
+ export const rejectAll: typeof Zest.rejectAll;
167
+ export const updateConsent: typeof Zest.updateConsent;
168
+ export const reset: typeof Zest.reset;
169
+ export const getConsent: typeof Zest.getConsent;
170
+ export const hasConsent: typeof Zest.hasConsent;
171
+ export const hasConsentDecision: typeof Zest.hasConsentDecision;
172
+ export const getConsentProof: typeof Zest.getConsentProof;
173
+ export const isDoNotTrackEnabled: typeof Zest.isDoNotTrackEnabled;
174
+ export const getDNTDetails: typeof Zest.getDNTDetails;
175
+ export const on: typeof Zest.on;
176
+ export const once: typeof Zest.once;
177
+ export const EVENTS: ZestEvents;
178
+ export const getConfig: typeof Zest.getConfig;
package/package.json CHANGED
@@ -1,20 +1,26 @@
1
1
  {
2
2
  "name": "@freshjuice/zest",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "description": "Lightweight cookie consent toolkit for GDPR/CCPA compliance",
6
6
  "main": "dist/zest.min.js",
7
7
  "module": "dist/zest.esm.min.js",
8
+ "types": "dist/zest.d.ts",
8
9
  "exports": {
9
10
  ".": {
11
+ "types": "./dist/zest.d.ts",
10
12
  "import": "./dist/zest.esm.min.js",
11
13
  "default": "./dist/zest.min.js"
12
14
  },
13
15
  "./headless": {
16
+ "types": "./dist/zest.headless.d.ts",
14
17
  "import": "./dist/zest.headless.esm.min.js",
15
18
  "default": "./dist/zest.headless.esm.min.js"
16
19
  },
17
- "./src/headless": "./src/headless.js",
20
+ "./src/headless": {
21
+ "types": "./dist/zest.headless.d.ts",
22
+ "default": "./src/headless.js"
23
+ },
18
24
  "./src/*": "./src/*.js"
19
25
  },
20
26
  "files": [
@@ -26,6 +32,7 @@
26
32
  "scripts": {
27
33
  "prebuild": "node scripts/build-langs.js",
28
34
  "build": "rollup -c",
35
+ "postbuild": "node scripts/copy-types.js",
29
36
  "build:watch": "rollup -c -w",
30
37
  "dev": "rollup -c -w",
31
38
  "test": "vitest",
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Type definitions for `@freshjuice/zest` (full build with UI).
3
+ *
4
+ * The full build ships the consent engine plus a Shadow-DOM banner,
5
+ * settings modal, and floating widget. It auto-initialises on script
6
+ * load when included via `<script>`, or you can drive it manually via
7
+ * `Zest.init()`.
8
+ *
9
+ * For a logic-only build without UI, import from
10
+ * `@freshjuice/zest/headless` instead.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import Zest from '@freshjuice/zest';
15
+ *
16
+ * Zest.init({
17
+ * position: 'bottom-right',
18
+ * theme: 'auto',
19
+ * accentColor: '#0071e3',
20
+ * policyUrl: '/privacy'
21
+ * });
22
+ * ```
23
+ */
24
+
25
+ /** Built-in consent categories. */
26
+ export type ConsentCategory =
27
+ | 'essential'
28
+ | 'functional'
29
+ | 'analytics'
30
+ | 'marketing';
31
+
32
+ /**
33
+ * Per-category boolean consent state. `essential` is always `true` —
34
+ * consent for it cannot be revoked because it covers strictly-necessary
35
+ * processing.
36
+ */
37
+ export type ConsentState =
38
+ & Partial<Record<ConsentCategory, boolean>>
39
+ & { essential: true };
40
+
41
+ /** Snapshot returned by `init()`. */
42
+ export interface InitSnapshot {
43
+ consent: ConsentState;
44
+ hasDecision: boolean;
45
+ dntApplied: boolean;
46
+ }
47
+
48
+ /** Tamper-evident proof of the user's last consent decision. */
49
+ export interface ConsentProof {
50
+ version: string;
51
+ timestamp: number;
52
+ categories: ConsentState;
53
+ }
54
+
55
+ /** Output of `getDNTDetails()`. */
56
+ export interface DNTDetails {
57
+ dnt: boolean;
58
+ gpc: boolean;
59
+ doNotTrack: string | null;
60
+ globalPrivacyControl: boolean;
61
+ }
62
+
63
+ /** Behaviour when DNT / GPC is detected at init time. */
64
+ export type DNTBehavior = 'reject' | 'preselect' | 'ignore';
65
+
66
+ /** Banner position on the page. */
67
+ export type BannerPosition = 'bottom' | 'bottom-left' | 'bottom-right' | 'top';
68
+
69
+ /** UI theme. `auto` follows `prefers-color-scheme`. */
70
+ export type ZestTheme = 'light' | 'dark' | 'auto';
71
+
72
+ /** Script-blocking strictness. */
73
+ export type ZestMode = 'manual' | 'safe' | 'strict' | 'doomsday';
74
+
75
+ /**
76
+ * Optional consumer callbacks. Each is wrapped in a try/catch internally
77
+ * so a thrown error never breaks the consent pipeline.
78
+ */
79
+ export interface ZestCallbacks {
80
+ onAccept?: (consent: ConsentState) => void;
81
+ onReject?: (consent: ConsentState) => void;
82
+ onChange?: (consent: ConsentState) => void;
83
+ onReady?: (consent: ConsentState) => void;
84
+ }
85
+
86
+ /** Configuration accepted by `init()` and `window.ZestConfig`. */
87
+ export interface InitOptions {
88
+ /** Display language. `'auto'` detects from `<html lang>` / browser. */
89
+ lang?:
90
+ | 'auto'
91
+ | 'en' | 'de' | 'es' | 'fr' | 'it' | 'pt'
92
+ | 'nl' | 'pl' | 'uk' | 'ru' | 'ja' | 'zh';
93
+ /** Banner position. Default `'bottom'`. */
94
+ position?: BannerPosition;
95
+ /** UI theme. Default `'auto'`. */
96
+ theme?: ZestTheme;
97
+ /** Hex accent color for buttons (e.g. `'#0071e3'`). */
98
+ accentColor?: string;
99
+ /** Link to the host site's privacy policy. */
100
+ policyUrl?: string;
101
+ /** Show floating "manage cookies" widget after a decision. Default `true`. */
102
+ showWidget?: boolean;
103
+ /** Cookie expiration in days. Default `365`. */
104
+ expiration?: number;
105
+ /** Script-blocking mode. Default `'safe'`. */
106
+ mode?: ZestMode;
107
+ /** Auto-initialise on script load. Default `true` for the UI build. */
108
+ autoInit?: boolean;
109
+ /** Respect Do Not Track / Global Privacy Control. Default `true`. */
110
+ respectDNT?: boolean;
111
+ /** What to do when DNT/GPC is on. Default `'reject'`. */
112
+ dntBehavior?: DNTBehavior;
113
+ /** Consumer callbacks. */
114
+ callbacks?: ZestCallbacks;
115
+ /** Anything else — Zest tolerates unknown keys at runtime. */
116
+ [key: string]: unknown;
117
+ }
118
+
119
+ /** Event names emitted on `document.documentElement`. */
120
+ export interface ZestEvents {
121
+ READY: 'zest:ready';
122
+ CONSENT: 'zest:consent';
123
+ REJECT: 'zest:reject';
124
+ CHANGE: 'zest:change';
125
+ SHOW: 'zest:show';
126
+ HIDE: 'zest:hide';
127
+ }
128
+
129
+ export type ZestEventName = ZestEvents[keyof ZestEvents];
130
+
131
+ /** Detail payload of consent events. */
132
+ export interface ZestEventDetail {
133
+ consent: ConsentState;
134
+ previous?: ConsentState;
135
+ }
136
+
137
+ declare const Zest: {
138
+ /** Initialise. Auto-called when the script loads unless `autoInit: false`. */
139
+ init(options?: InitOptions): InitSnapshot;
140
+
141
+ /** Show the consent banner. */
142
+ show(): void;
143
+
144
+ /** Hide the consent banner. */
145
+ hide(): void;
146
+
147
+ /** Open the per-category settings modal. */
148
+ showSettings(): void;
149
+
150
+ /** Close the settings modal. */
151
+ hideSettings(): void;
152
+
153
+ /** Show the persistent "manage cookies" widget. */
154
+ showWidget(): void;
155
+
156
+ /** Hide the widget without removing it. */
157
+ hideWidget(): void;
158
+
159
+ /** Current consent state (clone, safe to mutate). */
160
+ getConsent(): ConsentState;
161
+
162
+ /** Has the user granted consent for `category`? */
163
+ hasConsent(category: ConsentCategory): boolean;
164
+
165
+ /** Has the user made any consent decision yet? */
166
+ hasConsentDecision(): boolean;
167
+
168
+ /** Tamper-evident snapshot of the last consent decision. */
169
+ getConsentProof(): ConsentProof | null;
170
+
171
+ /** Grant consent for every category and run accept callbacks. */
172
+ acceptAll(): void;
173
+
174
+ /** Revoke consent for every non-essential category and run reject callbacks. */
175
+ rejectAll(): void;
176
+
177
+ /** Wipe all consent state and reshow the banner. */
178
+ reset(): void;
179
+
180
+ /** True if the browser is sending DNT or GPC. */
181
+ isDoNotTrackEnabled(): boolean;
182
+
183
+ /** Why `isDoNotTrackEnabled()` returned what it did. */
184
+ getDNTDetails(): DNTDetails;
185
+
186
+ /** Subscribe to a consent event. Returns an unsubscribe function. */
187
+ on(
188
+ eventName: ZestEventName,
189
+ handler: (event: CustomEvent<ZestEventDetail>) => void
190
+ ): () => void;
191
+
192
+ /** Subscribe once; auto-unsubscribes after the first call. */
193
+ once(
194
+ eventName: ZestEventName,
195
+ handler: (event: CustomEvent<ZestEventDetail>) => void
196
+ ): () => void;
197
+
198
+ /** Constants for `on()` / `once()`. */
199
+ EVENTS: ZestEvents;
200
+
201
+ /** Active configuration after `init()`. */
202
+ getConfig(): InitOptions | null;
203
+ };
204
+
205
+ export default Zest;
206
+
207
+ declare global {
208
+ interface Window {
209
+ /** Set before loading `zest.min.js` to configure auto-initialisation. */
210
+ ZestConfig?: InitOptions;
211
+ /** The Zest singleton, attached after auto-init. */
212
+ Zest?: typeof Zest;
213
+ }
214
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Type definitions for `@freshjuice/zest/headless`.
3
+ *
4
+ * The headless build ships the consent engine without any UI: no Shadow
5
+ * DOM, no styles, no DOM mounting. You bring your own banner / modal /
6
+ * settings markup and call into Zest for the consent state.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import Zest from '@freshjuice/zest/headless';
11
+ *
12
+ * Zest.init({ respectDNT: true, expiration: 365 });
13
+ *
14
+ * if (!Zest.hasConsentDecision()) myBanner.show();
15
+ *
16
+ * acceptBtn.addEventListener('click', () => Zest.acceptAll());
17
+ * rejectBtn.addEventListener('click', () => Zest.rejectAll());
18
+ * ```
19
+ */
20
+
21
+ /** Built-in consent categories. */
22
+ export type ConsentCategory =
23
+ | 'essential'
24
+ | 'functional'
25
+ | 'analytics'
26
+ | 'marketing';
27
+
28
+ /**
29
+ * Per-category boolean consent state. `essential` is always `true` —
30
+ * consent for it cannot be revoked because it covers strictly-necessary
31
+ * processing.
32
+ */
33
+ export type ConsentState =
34
+ & Partial<Record<ConsentCategory, boolean>>
35
+ & { essential: true };
36
+
37
+ /** Snapshot returned by `init()`. */
38
+ export interface InitSnapshot {
39
+ consent: ConsentState;
40
+ hasDecision: boolean;
41
+ dntApplied: boolean;
42
+ }
43
+
44
+ /** Tamper-evident proof of the user's last consent decision. */
45
+ export interface ConsentProof {
46
+ version: string;
47
+ timestamp: number;
48
+ categories: ConsentState;
49
+ }
50
+
51
+ /** Output of `getDNTDetails()`. */
52
+ export interface DNTDetails {
53
+ dnt: boolean;
54
+ gpc: boolean;
55
+ doNotTrack: string | null;
56
+ globalPrivacyControl: boolean;
57
+ }
58
+
59
+ /** Behaviour when DNT / GPC is detected at init time. */
60
+ export type DNTBehavior = 'reject' | 'preselect' | 'ignore';
61
+
62
+ /**
63
+ * Optional consumer callbacks. Each is wrapped in a try/catch internally
64
+ * so a thrown error never breaks the consent pipeline.
65
+ */
66
+ export interface ZestCallbacks {
67
+ onAccept?: (consent: ConsentState) => void;
68
+ onReject?: (consent: ConsentState) => void;
69
+ onChange?: (consent: ConsentState) => void;
70
+ onReady?: (consent: ConsentState) => void;
71
+ }
72
+
73
+ /** Configuration accepted by `init()`. */
74
+ export interface InitOptions {
75
+ /** Respect Do Not Track / Global Privacy Control. Default `true`. */
76
+ respectDNT?: boolean;
77
+ /** What to do when DNT/GPC is on. Default `'reject'`. */
78
+ dntBehavior?: DNTBehavior;
79
+ /** Cookie expiration in days. Default `365`. */
80
+ expiration?: number;
81
+ /** Consumer callbacks. */
82
+ callbacks?: ZestCallbacks;
83
+ /** Anything else — Zest tolerates unknown keys at runtime. */
84
+ [key: string]: unknown;
85
+ }
86
+
87
+ /** Event names emitted on the `window` `document.documentElement`. */
88
+ export interface ZestEvents {
89
+ READY: 'zest:ready';
90
+ CONSENT: 'zest:consent';
91
+ REJECT: 'zest:reject';
92
+ CHANGE: 'zest:change';
93
+ SHOW: 'zest:show';
94
+ HIDE: 'zest:hide';
95
+ }
96
+
97
+ export type ZestEventName = ZestEvents[keyof ZestEvents];
98
+
99
+ /** Detail payload of the consent-change event. */
100
+ export interface ZestEventDetail {
101
+ consent: ConsentState;
102
+ previous?: ConsentState;
103
+ }
104
+
105
+ declare const Zest: {
106
+ /** Initialise the consent engine. Must be called before any other API. */
107
+ init(options?: InitOptions): InitSnapshot;
108
+
109
+ /** Current consent state (clone, safe to mutate). */
110
+ getConsent(): ConsentState;
111
+
112
+ /** Has the user granted consent for `category`? */
113
+ hasConsent(category: ConsentCategory): boolean;
114
+
115
+ /** Has the user made any consent decision yet (accept, reject, or
116
+ * partial)? */
117
+ hasConsentDecision(): boolean;
118
+
119
+ /** Tamper-evident snapshot of the last consent decision. */
120
+ getConsentProof(): ConsentProof | null;
121
+
122
+ /** Grant consent for every category. */
123
+ acceptAll(): ConsentState | null;
124
+
125
+ /** Revoke consent for every non-essential category. */
126
+ rejectAll(): ConsentState | null;
127
+
128
+ /** Set per-category consent. Missing keys are left untouched. */
129
+ updateConsent(
130
+ selections: Partial<Record<ConsentCategory, boolean>>
131
+ ): ConsentState | null;
132
+
133
+ /** Wipe all consent state. Useful for "I changed my mind" flows. */
134
+ reset(): void;
135
+
136
+ /** True if the browser is sending DNT or GPC. */
137
+ isDoNotTrackEnabled(): boolean;
138
+
139
+ /** Why `isDoNotTrackEnabled()` returned what it did. */
140
+ getDNTDetails(): DNTDetails;
141
+
142
+ /** Subscribe to a consent event. Returns an unsubscribe function. */
143
+ on(
144
+ eventName: ZestEventName,
145
+ handler: (event: CustomEvent<ZestEventDetail>) => void
146
+ ): () => void;
147
+
148
+ /** Subscribe once; auto-unsubscribes after the first call. */
149
+ once(
150
+ eventName: ZestEventName,
151
+ handler: (event: CustomEvent<ZestEventDetail>) => void
152
+ ): () => void;
153
+
154
+ /** Constants for `on()` / `once()`. */
155
+ EVENTS: ZestEvents;
156
+
157
+ /** Active configuration after `init()`. */
158
+ getConfig(): InitOptions | null;
159
+ };
160
+
161
+ export default Zest;
162
+
163
+ // Named tree-shake-friendly exports.
164
+ export const init: typeof Zest.init;
165
+ export const acceptAll: typeof Zest.acceptAll;
166
+ export const rejectAll: typeof Zest.rejectAll;
167
+ export const updateConsent: typeof Zest.updateConsent;
168
+ export const reset: typeof Zest.reset;
169
+ export const getConsent: typeof Zest.getConsent;
170
+ export const hasConsent: typeof Zest.hasConsent;
171
+ export const hasConsentDecision: typeof Zest.hasConsentDecision;
172
+ export const getConsentProof: typeof Zest.getConsentProof;
173
+ export const isDoNotTrackEnabled: typeof Zest.isDoNotTrackEnabled;
174
+ export const getDNTDetails: typeof Zest.getDNTDetails;
175
+ export const on: typeof Zest.on;
176
+ export const once: typeof Zest.once;
177
+ export const EVENTS: ZestEvents;
178
+ export const getConfig: typeof Zest.getConfig;