@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.
Files changed (48) hide show
  1. package/CHANGELOG.md +245 -0
  2. package/LICENSE +21 -0
  3. package/README.md +489 -0
  4. package/dist/consentera-consent.cjs +4919 -0
  5. package/dist/consentera-consent.cjs.map +1 -0
  6. package/dist/consentera-consent.min.js +2 -0
  7. package/dist/consentera-consent.min.js.map +1 -0
  8. package/dist/consentera-consent.mjs +4864 -0
  9. package/dist/consentera-consent.mjs.map +1 -0
  10. package/dist/react/index.cjs +2731 -0
  11. package/dist/react/index.cjs.map +1 -0
  12. package/dist/react/index.mjs +2724 -0
  13. package/dist/react/index.mjs.map +1 -0
  14. package/dist/types/consent/CallbackHandler.d.ts +246 -0
  15. package/dist/types/consent/ConsentManager.d.ts +128 -0
  16. package/dist/types/consent/ConsentSession.d.ts +127 -0
  17. package/dist/types/consent/ConsentValidator.d.ts +63 -0
  18. package/dist/types/consent/artifactRead.d.ts +48 -0
  19. package/dist/types/consent/consentPopup.d.ts +115 -0
  20. package/dist/types/core/ConsentEraClient.d.ts +106 -0
  21. package/dist/types/core/ConsenteraConsent.d.ts +163 -0
  22. package/dist/types/core/errors.d.ts +108 -0
  23. package/dist/types/core/http.d.ts +176 -0
  24. package/dist/types/core/version.d.ts +36 -0
  25. package/dist/types/df/DFConfigClient.d.ts +59 -0
  26. package/dist/types/gcm/ConsentModeBridge.d.ts +54 -0
  27. package/dist/types/gpp/GPPManager.d.ts +62 -0
  28. package/dist/types/index.d.mts +5 -0
  29. package/dist/types/index.d.ts +28 -0
  30. package/dist/types/principal/PrincipalClient.d.ts +34 -0
  31. package/dist/types/react/ConsentEraProvider.d.ts +58 -0
  32. package/dist/types/react/ConsentGate.d.ts +40 -0
  33. package/dist/types/react/index.d.mts +4 -0
  34. package/dist/types/react/index.d.ts +10 -0
  35. package/dist/types/react/useConsentEra.d.ts +65 -0
  36. package/dist/types/react/useConsentValidation.d.ts +23 -0
  37. package/dist/types/storage/ConsentStorage.d.ts +39 -0
  38. package/dist/types/tcf/TCFManager.d.ts +46 -0
  39. package/dist/types/types/consent-lifecycle.d.ts +804 -0
  40. package/dist/types/types/index.d.ts +311 -0
  41. package/dist/types/ui/ConsentBanner.d.ts +22 -0
  42. package/dist/types/ui/PreferenceCenter.d.ts +24 -0
  43. package/dist/types/utils/EventEmitter.d.ts +32 -0
  44. package/dist/types/utils/Logger.d.ts +16 -0
  45. package/dist/types/utils/browserStorage.d.ts +35 -0
  46. package/dist/types/utils/context.d.ts +81 -0
  47. package/dist/types/utils/helpers.d.ts +48 -0
  48. 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;