@consentera/consent-sdk 2.0.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/CHANGELOG.md +245 -0
- package/LICENSE +21 -0
- package/README.md +489 -0
- package/dist/consentera-consent.cjs +4919 -0
- package/dist/consentera-consent.cjs.map +1 -0
- package/dist/consentera-consent.min.js +2 -0
- package/dist/consentera-consent.min.js.map +1 -0
- package/dist/consentera-consent.mjs +4864 -0
- package/dist/consentera-consent.mjs.map +1 -0
- package/dist/react/index.cjs +2731 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.mjs +2724 -0
- package/dist/react/index.mjs.map +1 -0
- package/dist/types/consent/CallbackHandler.d.ts +246 -0
- package/dist/types/consent/ConsentManager.d.ts +128 -0
- package/dist/types/consent/ConsentSession.d.ts +127 -0
- package/dist/types/consent/ConsentValidator.d.ts +63 -0
- package/dist/types/consent/artifactRead.d.ts +48 -0
- package/dist/types/consent/consentPopup.d.ts +115 -0
- package/dist/types/core/ConsentEraClient.d.ts +106 -0
- package/dist/types/core/ConsenteraConsent.d.ts +163 -0
- package/dist/types/core/errors.d.ts +108 -0
- package/dist/types/core/http.d.ts +176 -0
- package/dist/types/core/version.d.ts +36 -0
- package/dist/types/df/DFConfigClient.d.ts +59 -0
- package/dist/types/gcm/ConsentModeBridge.d.ts +54 -0
- package/dist/types/gpp/GPPManager.d.ts +62 -0
- package/dist/types/index.d.mts +5 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/principal/PrincipalClient.d.ts +34 -0
- package/dist/types/react/ConsentEraProvider.d.ts +58 -0
- package/dist/types/react/ConsentGate.d.ts +40 -0
- package/dist/types/react/index.d.mts +4 -0
- package/dist/types/react/index.d.ts +10 -0
- package/dist/types/react/useConsentEra.d.ts +65 -0
- package/dist/types/react/useConsentValidation.d.ts +23 -0
- package/dist/types/storage/ConsentStorage.d.ts +39 -0
- package/dist/types/tcf/TCFManager.d.ts +46 -0
- package/dist/types/types/consent-lifecycle.d.ts +804 -0
- package/dist/types/types/index.d.ts +311 -0
- package/dist/types/ui/ConsentBanner.d.ts +22 -0
- package/dist/types/ui/PreferenceCenter.d.ts +24 -0
- package/dist/types/utils/EventEmitter.d.ts +32 -0
- package/dist/types/utils/Logger.d.ts +16 -0
- package/dist/types/utils/browserStorage.d.ts +35 -0
- package/dist/types/utils/context.d.ts +81 -0
- package/dist/types/utils/helpers.d.ts +48 -0
- package/package.json +132 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConsentEra Consent SDK Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
export interface ConsentEraConfig {
|
|
5
|
+
/** Secret API key for server-side use (tiq_live_*). REFUSED in a browser. */
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
/** Public site key for frontend use (tiq_pub_*). This is what the browser carries. */
|
|
8
|
+
siteKey?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Allow a SECRET `apiKey` although a `window` exists. Refused by default —
|
|
11
|
+
* the cookie-consent plane needs only a public site key, and a secret in a
|
|
12
|
+
* bundle is a secret published to every visitor. Every request then warns.
|
|
13
|
+
*/
|
|
14
|
+
unsafeAllowSecretKeyInBrowser?: boolean;
|
|
15
|
+
tenantId: string;
|
|
16
|
+
/**
|
|
17
|
+
* Your Consentera API origin, e.g. the host your tenant was provisioned on.
|
|
18
|
+
* REQUIRED — there is no default server, and the constructor refuses a
|
|
19
|
+
* missing or blank value with `ENDPOINT_REQUIRED`. The SDK calls
|
|
20
|
+
* `${apiEndpoint}/api/v1/cookie-consent/*`.
|
|
21
|
+
*/
|
|
22
|
+
apiEndpoint: string;
|
|
23
|
+
autoShow?: boolean;
|
|
24
|
+
language?: string;
|
|
25
|
+
region?: 'IN' | 'EU' | 'US' | 'GLOBAL';
|
|
26
|
+
regulations?: RegulationType[];
|
|
27
|
+
theme?: ThemeConfig;
|
|
28
|
+
callbacks?: ConsentCallbacks;
|
|
29
|
+
tcf?: TCFConfig;
|
|
30
|
+
gpp?: GPPConfig;
|
|
31
|
+
storage?: StorageConfig;
|
|
32
|
+
}
|
|
33
|
+
export type RegulationType = 'DPDP' | 'GDPR' | 'CCPA' | 'LGPD' | 'TCF' | 'GPP';
|
|
34
|
+
export interface ThemeConfig {
|
|
35
|
+
position?: 'bottom' | 'top' | 'center' | 'bottom-left' | 'bottom-right';
|
|
36
|
+
type?: 'banner' | 'modal' | 'popup';
|
|
37
|
+
primaryColor?: string;
|
|
38
|
+
secondaryColor?: string;
|
|
39
|
+
backgroundColor?: string;
|
|
40
|
+
textColor?: string;
|
|
41
|
+
fontFamily?: string;
|
|
42
|
+
borderRadius?: string;
|
|
43
|
+
showLogo?: boolean;
|
|
44
|
+
logoUrl?: string;
|
|
45
|
+
customCss?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface ConsentCallbacks {
|
|
48
|
+
/**
|
|
49
|
+
* The consent decision could NOT be recorded by the platform. The banner has
|
|
50
|
+
* been left up and nothing was stored locally: the visitor has not consented
|
|
51
|
+
* and must be asked again. Before 2.0.0 this case was invisible — the SDK
|
|
52
|
+
* reported success and kept a local-only record.
|
|
53
|
+
*/
|
|
54
|
+
onSyncFailed?: (error: Error) => void;
|
|
55
|
+
onReady?: () => void;
|
|
56
|
+
onConsentGiven?: (consent: ConsentData) => void;
|
|
57
|
+
onConsentWithdrawn?: (purposes: string[]) => void;
|
|
58
|
+
onPreferencesUpdated?: (preferences: ConsentPreferences) => void;
|
|
59
|
+
onBannerShown?: () => void;
|
|
60
|
+
onBannerClosed?: () => void;
|
|
61
|
+
onError?: (error: Error) => void;
|
|
62
|
+
}
|
|
63
|
+
export interface TCFConfig {
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
cmpId?: number;
|
|
66
|
+
cmpVersion?: number;
|
|
67
|
+
publisherCountryCode?: string;
|
|
68
|
+
gdprApplies?: boolean;
|
|
69
|
+
}
|
|
70
|
+
export interface GPPConfig {
|
|
71
|
+
enabled: boolean;
|
|
72
|
+
sections?: string[];
|
|
73
|
+
}
|
|
74
|
+
export interface StorageConfig {
|
|
75
|
+
type?: 'cookie' | 'localStorage' | 'sessionStorage';
|
|
76
|
+
cookieName?: string;
|
|
77
|
+
cookieDomain?: string;
|
|
78
|
+
cookieExpiry?: number;
|
|
79
|
+
cookiePath?: string;
|
|
80
|
+
secure?: boolean;
|
|
81
|
+
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
82
|
+
}
|
|
83
|
+
export interface ConsentData {
|
|
84
|
+
consentId: string;
|
|
85
|
+
timestamp: string;
|
|
86
|
+
version: string;
|
|
87
|
+
purposes: ConsentPurpose[];
|
|
88
|
+
vendors?: ConsentVendor[];
|
|
89
|
+
legalBasis: LegalBasis;
|
|
90
|
+
regulation: RegulationType;
|
|
91
|
+
dataPrincipal?: DataPrincipalInfo;
|
|
92
|
+
metadata?: ConsentMetadata;
|
|
93
|
+
}
|
|
94
|
+
export interface ConsentPurpose {
|
|
95
|
+
id: string;
|
|
96
|
+
name: string;
|
|
97
|
+
description?: string;
|
|
98
|
+
category: PurposeCategory;
|
|
99
|
+
required: boolean;
|
|
100
|
+
consented: boolean;
|
|
101
|
+
legalBasis?: LegalBasis;
|
|
102
|
+
retentionPeriod?: string;
|
|
103
|
+
}
|
|
104
|
+
export type PurposeCategory = 'essential' | 'functional' | 'analytics' | 'marketing' | 'personalization' | 'advertising' | 'social_media' | 'third_party';
|
|
105
|
+
export interface ConsentVendor {
|
|
106
|
+
id: string;
|
|
107
|
+
name: string;
|
|
108
|
+
purposes: string[];
|
|
109
|
+
consented: boolean;
|
|
110
|
+
policyUrl?: string;
|
|
111
|
+
}
|
|
112
|
+
export type LegalBasis = 'consent' | 'contract' | 'legal_obligation' | 'vital_interests' | 'public_task' | 'legitimate_interest';
|
|
113
|
+
export interface DataPrincipalInfo {
|
|
114
|
+
id?: string;
|
|
115
|
+
email?: string;
|
|
116
|
+
hash?: string;
|
|
117
|
+
type?: 'registered' | 'anonymous' | 'child' | 'guardian';
|
|
118
|
+
}
|
|
119
|
+
export interface ConsentMetadata {
|
|
120
|
+
ipAddress?: string;
|
|
121
|
+
userAgent?: string;
|
|
122
|
+
pageUrl?: string;
|
|
123
|
+
referrer?: string;
|
|
124
|
+
device?: DeviceInfo;
|
|
125
|
+
geo?: GeoInfo;
|
|
126
|
+
}
|
|
127
|
+
export interface DeviceInfo {
|
|
128
|
+
type: 'desktop' | 'mobile' | 'tablet';
|
|
129
|
+
os?: string;
|
|
130
|
+
browser?: string;
|
|
131
|
+
}
|
|
132
|
+
export interface GeoInfo {
|
|
133
|
+
country?: string;
|
|
134
|
+
region?: string;
|
|
135
|
+
city?: string;
|
|
136
|
+
}
|
|
137
|
+
export interface ConsentPreferences {
|
|
138
|
+
essential: boolean;
|
|
139
|
+
functional: boolean;
|
|
140
|
+
analytics: boolean;
|
|
141
|
+
marketing: boolean;
|
|
142
|
+
personalization: boolean;
|
|
143
|
+
advertising: boolean;
|
|
144
|
+
thirdParty: boolean;
|
|
145
|
+
[key: string]: boolean;
|
|
146
|
+
}
|
|
147
|
+
export interface BannerConfig {
|
|
148
|
+
title?: string;
|
|
149
|
+
description?: string;
|
|
150
|
+
acceptAllText?: string;
|
|
151
|
+
rejectAllText?: string;
|
|
152
|
+
customizeText?: string;
|
|
153
|
+
saveText?: string;
|
|
154
|
+
privacyPolicyUrl?: string;
|
|
155
|
+
cookiePolicyUrl?: string;
|
|
156
|
+
showRejectAll?: boolean;
|
|
157
|
+
showCustomize?: boolean;
|
|
158
|
+
showPrivacyPolicy?: boolean;
|
|
159
|
+
blockerMode?: boolean;
|
|
160
|
+
purposes?: PurposeConfig[];
|
|
161
|
+
}
|
|
162
|
+
export interface PurposeConfig {
|
|
163
|
+
id: string;
|
|
164
|
+
name: string;
|
|
165
|
+
description: string;
|
|
166
|
+
required: boolean;
|
|
167
|
+
defaultEnabled?: boolean;
|
|
168
|
+
category: PurposeCategory;
|
|
169
|
+
cookies?: CookieInfo[];
|
|
170
|
+
}
|
|
171
|
+
export interface CookieInfo {
|
|
172
|
+
name: string;
|
|
173
|
+
provider: string;
|
|
174
|
+
purpose: string;
|
|
175
|
+
expiry: string;
|
|
176
|
+
type: 'first_party' | 'third_party';
|
|
177
|
+
}
|
|
178
|
+
export interface ConsentEvent {
|
|
179
|
+
type: ConsentEventType;
|
|
180
|
+
timestamp: string;
|
|
181
|
+
data?: any;
|
|
182
|
+
}
|
|
183
|
+
export type ConsentEventType = 'banner_shown' | 'banner_closed' | 'consent_given' | 'consent_withdrawn' | 'preferences_opened' | 'preferences_saved' | 'accept_all' | 'reject_all' | 'category_toggled';
|
|
184
|
+
export interface ConsentResponse {
|
|
185
|
+
success: boolean;
|
|
186
|
+
consentId?: string;
|
|
187
|
+
message?: string;
|
|
188
|
+
error?: string;
|
|
189
|
+
}
|
|
190
|
+
export interface ConfigResponse {
|
|
191
|
+
tenantId: string;
|
|
192
|
+
banner: BannerConfig;
|
|
193
|
+
purposes: PurposeConfig[];
|
|
194
|
+
theme: ThemeConfig;
|
|
195
|
+
regulations: RegulationType[];
|
|
196
|
+
languages: string[];
|
|
197
|
+
}
|
|
198
|
+
export interface CookieConsentCategory {
|
|
199
|
+
key: string;
|
|
200
|
+
name: string;
|
|
201
|
+
description: string;
|
|
202
|
+
mandatory: boolean;
|
|
203
|
+
sort_order: number;
|
|
204
|
+
known_cookies?: string[];
|
|
205
|
+
}
|
|
206
|
+
export interface CookieConsentUIOptions {
|
|
207
|
+
accept_all: boolean;
|
|
208
|
+
reject_all: boolean;
|
|
209
|
+
customize: boolean;
|
|
210
|
+
}
|
|
211
|
+
export interface CookieConsentBannerConfig {
|
|
212
|
+
layout: string;
|
|
213
|
+
position: string;
|
|
214
|
+
messaging: Record<string, string>;
|
|
215
|
+
theme: Record<string, string>;
|
|
216
|
+
}
|
|
217
|
+
export interface CookieConsentGeoIntelligence {
|
|
218
|
+
enabled: boolean;
|
|
219
|
+
detected_country?: string;
|
|
220
|
+
detected_regulation?: string;
|
|
221
|
+
require_consent: boolean;
|
|
222
|
+
require_explicit_consent: boolean;
|
|
223
|
+
allow_implied_consent: boolean;
|
|
224
|
+
}
|
|
225
|
+
export interface CookieConsentConfigResponse {
|
|
226
|
+
tenant_id: string;
|
|
227
|
+
policy_version: string;
|
|
228
|
+
language_code: string;
|
|
229
|
+
categories: CookieConsentCategory[];
|
|
230
|
+
ui_options: CookieConsentUIOptions;
|
|
231
|
+
banner?: CookieConsentBannerConfig;
|
|
232
|
+
geo_intelligence?: CookieConsentGeoIntelligence;
|
|
233
|
+
consent_mode_map?: Record<string, Record<string, string>>;
|
|
234
|
+
age_gate_enabled: boolean;
|
|
235
|
+
age_gate_prompt?: string;
|
|
236
|
+
}
|
|
237
|
+
export interface CookieConsentSubmitResponse {
|
|
238
|
+
status: string;
|
|
239
|
+
cookie_consent_id: string;
|
|
240
|
+
effective_at: string;
|
|
241
|
+
effective_selections: Record<string, boolean>;
|
|
242
|
+
expires_at?: string;
|
|
243
|
+
tc_string?: string;
|
|
244
|
+
tcf_policy_version?: number;
|
|
245
|
+
}
|
|
246
|
+
export interface TCFData {
|
|
247
|
+
cmpId: number;
|
|
248
|
+
cmpVersion: number;
|
|
249
|
+
gdprApplies: boolean;
|
|
250
|
+
tcString: string;
|
|
251
|
+
tcfPolicyVersion: number;
|
|
252
|
+
isServiceSpecific: boolean;
|
|
253
|
+
useNonStandardStacks: boolean;
|
|
254
|
+
purposeOneTreatment: boolean;
|
|
255
|
+
publisherCC: string;
|
|
256
|
+
vendorConsents: {
|
|
257
|
+
[vendorId: number]: boolean;
|
|
258
|
+
};
|
|
259
|
+
vendorLegitimateInterests: {
|
|
260
|
+
[vendorId: number]: boolean;
|
|
261
|
+
};
|
|
262
|
+
purposeConsents: {
|
|
263
|
+
[purposeId: number]: boolean;
|
|
264
|
+
};
|
|
265
|
+
purposeLegitimateInterests: {
|
|
266
|
+
[purposeId: number]: boolean;
|
|
267
|
+
};
|
|
268
|
+
specialFeatureOptins: {
|
|
269
|
+
[featureId: number]: boolean;
|
|
270
|
+
};
|
|
271
|
+
publisherRestrictions: PublisherRestriction[];
|
|
272
|
+
}
|
|
273
|
+
export interface PublisherRestriction {
|
|
274
|
+
purposeId: number;
|
|
275
|
+
restrictionType: 0 | 1 | 2;
|
|
276
|
+
vendorIds: number[];
|
|
277
|
+
}
|
|
278
|
+
export interface GPPData {
|
|
279
|
+
gppString: string;
|
|
280
|
+
sectionIds: number[];
|
|
281
|
+
applicableSections: number[];
|
|
282
|
+
}
|
|
283
|
+
declare global {
|
|
284
|
+
interface Window {
|
|
285
|
+
ConsentEra?: ConsentEraConsent;
|
|
286
|
+
__tcfapi?: (command: string, version: number, callback: (...args: any[]) => void, parameter?: any) => void;
|
|
287
|
+
__gpp?: (command: string, callback: (...args: any[]) => void, parameter?: any) => void;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
export interface ConsentEraConsent {
|
|
291
|
+
init(): Promise<void>;
|
|
292
|
+
showBanner(): void;
|
|
293
|
+
hideBanner(): void;
|
|
294
|
+
showPreferences(): void;
|
|
295
|
+
hidePreferences(): void;
|
|
296
|
+
acceptAll(): Promise<ConsentResponse>;
|
|
297
|
+
rejectAll(): Promise<ConsentResponse>;
|
|
298
|
+
savePreferences(preferences: ConsentPreferences): Promise<ConsentResponse>;
|
|
299
|
+
getConsent(): ConsentData | null;
|
|
300
|
+
hasConsent(): boolean;
|
|
301
|
+
withdrawConsent(purposes?: string[]): Promise<ConsentResponse>;
|
|
302
|
+
isConsentGiven(purpose: string): boolean;
|
|
303
|
+
getPreferences(): ConsentPreferences;
|
|
304
|
+
setLanguage(language: string): void;
|
|
305
|
+
setAgeDeclaration(isAdult: boolean): void;
|
|
306
|
+
isAgeGateEnabled(): boolean;
|
|
307
|
+
getAgeGatePrompt(): string | undefined;
|
|
308
|
+
on(event: ConsentEventType, callback: (...args: any[]) => void): void;
|
|
309
|
+
off(event: ConsentEventType, callback: (...args: any[]) => void): void;
|
|
310
|
+
destroy(): void;
|
|
311
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consent Banner UI Component
|
|
3
|
+
*/
|
|
4
|
+
import { ConfigResponse, ThemeConfig, ConsentEraConsent as ConsentEraConsentType } from '../types';
|
|
5
|
+
export declare class ConsentBanner {
|
|
6
|
+
private config;
|
|
7
|
+
private theme;
|
|
8
|
+
private sdk;
|
|
9
|
+
private container;
|
|
10
|
+
private isVisible;
|
|
11
|
+
constructor(config: ConfigResponse, theme: ThemeConfig, sdk: ConsentEraConsentType);
|
|
12
|
+
show(): void;
|
|
13
|
+
hide(): void;
|
|
14
|
+
private createBanner;
|
|
15
|
+
private getBannerHTML;
|
|
16
|
+
private getDefaultLogo;
|
|
17
|
+
private attachEventListeners;
|
|
18
|
+
private handleKeyDown;
|
|
19
|
+
private injectStyles;
|
|
20
|
+
private getStyles;
|
|
21
|
+
destroy(): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preference Center UI Component
|
|
3
|
+
*/
|
|
4
|
+
import { ConfigResponse, ThemeConfig, ConsentEraConsent as ConsentEraConsentType } from '../types';
|
|
5
|
+
export declare class PreferenceCenter {
|
|
6
|
+
private config;
|
|
7
|
+
private theme;
|
|
8
|
+
private sdk;
|
|
9
|
+
private container;
|
|
10
|
+
private overlay;
|
|
11
|
+
private isVisible;
|
|
12
|
+
private preferences;
|
|
13
|
+
constructor(config: ConfigResponse, theme: ThemeConfig, sdk: ConsentEraConsentType);
|
|
14
|
+
show(): void;
|
|
15
|
+
hide(): void;
|
|
16
|
+
private createPreferenceCenter;
|
|
17
|
+
private getPreferenceCenterHTML;
|
|
18
|
+
private attachEventListeners;
|
|
19
|
+
private handleKeyDown;
|
|
20
|
+
private savePreferences;
|
|
21
|
+
private injectStyles;
|
|
22
|
+
private getStyles;
|
|
23
|
+
destroy(): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple Event Emitter
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* A listener. Typed as a variadic rather than `Function` so that
|
|
6
|
+
* `no-unsafe-function-type` passes and, more usefully, so a caller passing a
|
|
7
|
+
* non-callable is a compile error rather than a runtime one.
|
|
8
|
+
*/
|
|
9
|
+
export type EventListener = (...args: any[]) => void;
|
|
10
|
+
export declare class EventEmitter {
|
|
11
|
+
private events;
|
|
12
|
+
/**
|
|
13
|
+
* Register event listener
|
|
14
|
+
*/
|
|
15
|
+
on(event: string, callback: EventListener): void;
|
|
16
|
+
/**
|
|
17
|
+
* Remove event listener
|
|
18
|
+
*/
|
|
19
|
+
off(event: string, callback: EventListener): void;
|
|
20
|
+
/**
|
|
21
|
+
* Emit event
|
|
22
|
+
*/
|
|
23
|
+
emit(event: string, ...args: any[]): void;
|
|
24
|
+
/**
|
|
25
|
+
* Register one-time event listener
|
|
26
|
+
*/
|
|
27
|
+
once(event: string, callback: EventListener): void;
|
|
28
|
+
/**
|
|
29
|
+
* Remove all listeners
|
|
30
|
+
*/
|
|
31
|
+
removeAllListeners(event?: string): void;
|
|
32
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger utility
|
|
3
|
+
*/
|
|
4
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
5
|
+
export declare class Logger {
|
|
6
|
+
private level;
|
|
7
|
+
private prefix;
|
|
8
|
+
constructor(level?: LogLevel);
|
|
9
|
+
private shouldLog;
|
|
10
|
+
debug(...args: unknown[]): void;
|
|
11
|
+
info(...args: unknown[]): void;
|
|
12
|
+
warn(...args: unknown[]): void;
|
|
13
|
+
error(...args: unknown[]): void;
|
|
14
|
+
setLevel(level: LogLevel): void;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consentera Consent SDK — guarded browser storage.
|
|
3
|
+
*
|
|
4
|
+
* EVERY ACCESS IS WRAPPED, AND THAT IS NOT DEFENSIVENESS. `localStorage` and
|
|
5
|
+
* `sessionStorage` THROW rather than return null in ordinary, common
|
|
6
|
+
* configurations: Safari's private browsing on old versions, a site with
|
|
7
|
+
* cookies blocked, a sandboxed iframe without `allow-same-origin`, a quota that
|
|
8
|
+
* is full. Before 2.0.0 `ConsentStorage.save()` called `localStorage.setItem`
|
|
9
|
+
* bare, so a visitor with storage blocked did not get a degraded banner — they
|
|
10
|
+
* got an exception out of the middle of a consent write.
|
|
11
|
+
*
|
|
12
|
+
* ONE implementation, so the "did we remember to try/catch this one" question
|
|
13
|
+
* is asked once. `ConsenteraConsent.getOrCreateDeviceId` already had the right
|
|
14
|
+
* shape; it was the only place that did.
|
|
15
|
+
*
|
|
16
|
+
* When storage is unavailable the SDK degrades to a per-page memory map: the
|
|
17
|
+
* flow still works within the page, it just does not survive a reload. That is
|
|
18
|
+
* the correct trade for a consent handshake, which is short-lived.
|
|
19
|
+
*/
|
|
20
|
+
export type StorageKind = 'local' | 'session';
|
|
21
|
+
/** The one place key names are spelled, so a reader and a writer cannot drift. */
|
|
22
|
+
export declare const storageKeys: {
|
|
23
|
+
session: (id: string) => string;
|
|
24
|
+
callback: (id: string) => string;
|
|
25
|
+
pendingSync: string;
|
|
26
|
+
deviceId: string;
|
|
27
|
+
};
|
|
28
|
+
/** True when the real browser store is usable; false when we are on memory. */
|
|
29
|
+
export declare function storageAvailable(kind: StorageKind): boolean;
|
|
30
|
+
export declare function readStored(kind: StorageKind, key: string): string | null;
|
|
31
|
+
/** Returns false when the value could not be persisted anywhere durable. */
|
|
32
|
+
export declare function writeStored(kind: StorageKind, key: string, value: string): boolean;
|
|
33
|
+
export declare function removeStored(kind: StorageKind, key: string): void;
|
|
34
|
+
/** Test seam: drop the memory fallback between cases. */
|
|
35
|
+
export declare function __resetMemoryStorage(): void;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConsentEra Consent SDK — Context Helpers
|
|
3
|
+
* Build client context and affirmative action payloads
|
|
4
|
+
*/
|
|
5
|
+
import { AffirmativeAction, ClientContext, DataPrincipalIdentifiers } from '../types/consent-lifecycle';
|
|
6
|
+
/**
|
|
7
|
+
* How much of the browser's environment goes to the platform with a consent
|
|
8
|
+
* mutation.
|
|
9
|
+
*
|
|
10
|
+
* DEFAULT IS `minimal`, AND THAT IS A CHANGE IN 2.0.0. Before it, every
|
|
11
|
+
* update / withdraw / renew carried `page_url: window.location.href`, the
|
|
12
|
+
* document referrer, the raw User-Agent, the screen resolution and the IANA
|
|
13
|
+
* timezone — with no way to turn any of it off. A real site's URL routinely
|
|
14
|
+
* carries an order id, a search term, a reset token, sometimes an email in a
|
|
15
|
+
* query parameter, so the SDK was shipping the host's own PII to us as a side
|
|
16
|
+
* effect of recording a consent; and UA + screen + timezone is a standard
|
|
17
|
+
* fingerprinting triple, collected with nothing stated about the basis for it.
|
|
18
|
+
*
|
|
19
|
+
* - `none` omit `client_context` entirely.
|
|
20
|
+
* - `minimal` (default) the coarse facts an audit trail actually uses:
|
|
21
|
+
* platform, device type, browser family, OS family. No versions,
|
|
22
|
+
* no UA string, no screen, no timezone, no URL, no referrer —
|
|
23
|
+
* nothing that narrows to a person or carries the host's data.
|
|
24
|
+
* - `full` everything above plus the UA string, versions, screen,
|
|
25
|
+
* timezone, referrer and the page URL WITH ITS QUERY AND FRAGMENT
|
|
26
|
+
* REMOVED. The query is stripped even here: a Data Fiduciary who
|
|
27
|
+
* has decided it needs the query adds it in `beforeSend`, which
|
|
28
|
+
* makes that a decision someone took rather than a default.
|
|
29
|
+
*/
|
|
30
|
+
export type ContextMode = 'none' | 'minimal' | 'full';
|
|
31
|
+
/**
|
|
32
|
+
* Build client context from the current browser environment.
|
|
33
|
+
*
|
|
34
|
+
* @param sessionId optional consent session to correlate against
|
|
35
|
+
* @param mode how much to collect; see {@link ContextMode}. Default `minimal`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildClientContext(sessionId?: string, mode?: ContextMode): ClientContext | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Build an affirmative action payload.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildAffirmativeAction(uiEventId: string, type?: 'button' | 'toggle' | 'checkbox'): AffirmativeAction;
|
|
42
|
+
/**
|
|
43
|
+
* `PrincipalRef` — the ONE way this SDK names a person on a consent lifecycle
|
|
44
|
+
* road, and the ONE place that shape is declared.
|
|
45
|
+
*
|
|
46
|
+
* ─── WHY A TYPE AND A HELPER RATHER THAN A STRING PARAMETER ───────────────
|
|
47
|
+
*
|
|
48
|
+
* The roads used to take `dataPrincipalRef: string` and put it on the wire as
|
|
49
|
+
* `data_principal_ref`. That field is REFUSED OUTRIGHT since the owner ruling
|
|
50
|
+
* of 2026-09-21 (consent/lifecycle_identity.go:8-11) — there is no transition
|
|
51
|
+
* period — so a string parameter can only build a request the API answers 400.
|
|
52
|
+
*
|
|
53
|
+
* Making it a union means a caller cannot express the refused request at all:
|
|
54
|
+
* naming nobody, or naming somebody the old way, is a COMPILE error here
|
|
55
|
+
* instead of a round trip.
|
|
56
|
+
*
|
|
57
|
+
* ONE IMPLEMENTATION ON PURPOSE. validate, bulk validate and every other
|
|
58
|
+
* find-only lifecycle road ask the identical question, and the API answers it
|
|
59
|
+
* through a single resolve (`resolveLifecyclePrincipal`,
|
|
60
|
+
* lifecycle_identity.go). A second copy of this shape in a second file is the
|
|
61
|
+
* thing that drifts.
|
|
62
|
+
*/
|
|
63
|
+
export type PrincipalRef = {
|
|
64
|
+
data_principal_id: string;
|
|
65
|
+
data_principal_identifiers?: never;
|
|
66
|
+
} | {
|
|
67
|
+
data_principal_identifiers: DataPrincipalIdentifiers;
|
|
68
|
+
data_principal_id?: never;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Turn a {@link PrincipalRef} into the request-body fields that name the
|
|
72
|
+
* person. Sends exactly ONE of the two keys, never both and never an empty
|
|
73
|
+
* object.
|
|
74
|
+
*
|
|
75
|
+
* NEVER BOTH, and that is not tidiness: the API refuses a request carrying
|
|
76
|
+
* `data_principal_ref` even when `data_principal_id` is also present, for the
|
|
77
|
+
* stated reason that two fields naming a person can disagree and the caller
|
|
78
|
+
* would never learn which one the answer was about. Sending one key keeps this
|
|
79
|
+
* SDK on the right side of that rule by construction.
|
|
80
|
+
*/
|
|
81
|
+
export declare function principalBody(who: PrincipalRef): Record<string, unknown>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility helper functions
|
|
3
|
+
*/
|
|
4
|
+
import { DeviceInfo, GeoInfo } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Generate a unique consent ID
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateConsentId(): string;
|
|
9
|
+
/**
|
|
10
|
+
* Get device information
|
|
11
|
+
*/
|
|
12
|
+
export declare function getDeviceInfo(): DeviceInfo;
|
|
13
|
+
/**
|
|
14
|
+
* Get geo information (placeholder - would typically use IP-based service)
|
|
15
|
+
*/
|
|
16
|
+
export declare function getGeoInfo(): GeoInfo;
|
|
17
|
+
/**
|
|
18
|
+
* Debounce function
|
|
19
|
+
*/
|
|
20
|
+
export declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Throttle function
|
|
23
|
+
*/
|
|
24
|
+
export declare function throttle<T extends (...args: any[]) => any>(func: T, limit: number): (...args: Parameters<T>) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Deep merge objects
|
|
27
|
+
*/
|
|
28
|
+
export declare function deepMerge<T extends object>(target: T, ...sources: Partial<T>[]): T;
|
|
29
|
+
/**
|
|
30
|
+
* Parse cookie string
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseCookies(cookieString: string): Record<string, string>;
|
|
33
|
+
/**
|
|
34
|
+
* Check if running in browser
|
|
35
|
+
*/
|
|
36
|
+
export declare function isBrowser(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Check if third-party cookies are supported
|
|
39
|
+
*/
|
|
40
|
+
export declare function checkThirdPartyCookies(): Promise<boolean>;
|
|
41
|
+
/**
|
|
42
|
+
* Get language from browser
|
|
43
|
+
*/
|
|
44
|
+
export declare function getBrowserLanguage(): string;
|
|
45
|
+
/**
|
|
46
|
+
* Format date for display
|
|
47
|
+
*/
|
|
48
|
+
export declare function formatDate(date: Date | string): string;
|