c15t 0.0.1-rc.3
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/.turbo/turbo-build.log +54 -0
- package/.turbo/turbo-fmt.log +6 -0
- package/.turbo/turbo-lint.log +288 -0
- package/.turbo/turbo-test.log +33 -0
- package/CHANGELOG.md +20 -0
- package/LICENSE.md +595 -0
- package/README.md +28 -0
- package/dist/index.cjs +118 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/libs/__tests__/tracking-blocker.test.cjs +269 -0
- package/dist/libs/__tests__/tracking-blocker.test.d.ts +2 -0
- package/dist/libs/__tests__/tracking-blocker.test.d.ts.map +1 -0
- package/dist/libs/__tests__/tracking-blocker.test.js +267 -0
- package/dist/libs/consent-utils.cjs +68 -0
- package/dist/libs/consent-utils.d.ts +49 -0
- package/dist/libs/consent-utils.d.ts.map +1 -0
- package/dist/libs/consent-utils.js +23 -0
- package/dist/libs/tracking-blocker.cjs +167 -0
- package/dist/libs/tracking-blocker.d.ts +33 -0
- package/dist/libs/tracking-blocker.d.ts.map +1 -0
- package/dist/libs/tracking-blocker.js +108 -0
- package/dist/libs/tracking-domains.cjs +188 -0
- package/dist/libs/tracking-domains.d.ts +7 -0
- package/dist/libs/tracking-domains.d.ts.map +1 -0
- package/dist/libs/tracking-domains.js +146 -0
- package/dist/store.cjs +248 -0
- package/dist/store.d.ts +58 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.initial-state.cjs +105 -0
- package/dist/store.initial-state.d.ts +43 -0
- package/dist/store.initial-state.d.ts.map +1 -0
- package/dist/store.initial-state.js +66 -0
- package/dist/store.js +219 -0
- package/dist/store.type.cjs +22 -0
- package/dist/store.type.d.ts +159 -0
- package/dist/store.type.d.ts.map +1 -0
- package/dist/store.type.js +0 -0
- package/dist/translations/en.cjs +96 -0
- package/dist/translations/en.d.ts +3 -0
- package/dist/translations/en.d.ts.map +1 -0
- package/dist/translations/en.js +54 -0
- package/dist/translations/index.cjs +51 -0
- package/dist/translations/index.d.ts +3 -0
- package/dist/translations/index.d.ts.map +1 -0
- package/dist/translations/index.js +9 -0
- package/dist/types/callbacks.cjs +22 -0
- package/dist/types/callbacks.d.ts +146 -0
- package/dist/types/callbacks.d.ts.map +1 -0
- package/dist/types/callbacks.js +0 -0
- package/dist/types/compliance.cjs +22 -0
- package/dist/types/compliance.d.ts +196 -0
- package/dist/types/compliance.d.ts.map +1 -0
- package/dist/types/compliance.js +0 -0
- package/dist/types/gdpr.cjs +86 -0
- package/dist/types/gdpr.d.ts +168 -0
- package/dist/types/gdpr.d.ts.map +1 -0
- package/dist/types/gdpr.js +44 -0
- package/dist/types/index.cjs +44 -0
- package/dist/types/index.d.ts +141 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/translations.cjs +22 -0
- package/dist/types/translations.d.ts +52 -0
- package/dist/types/translations.d.ts.map +1 -0
- package/dist/types/translations.js +0 -0
- package/package.json +33 -0
- package/rslib.config.ts +28 -0
- package/src/index.ts +31 -0
- package/src/libs/__tests__/tracking-blocker.test.ts +271 -0
- package/src/libs/consent-utils.ts +70 -0
- package/src/libs/tracking-blocker.ts +202 -0
- package/src/libs/tracking-domains.ts +158 -0
- package/src/store.initial-state.ts +123 -0
- package/src/store.ts +450 -0
- package/src/store.type.ts +187 -0
- package/src/translations/en.ts +55 -0
- package/src/translations/index.ts +10 -0
- package/src/types/callbacks.ts +152 -0
- package/src/types/compliance.ts +205 -0
- package/src/types/gdpr.ts +217 -0
- package/src/types/index.ts +148 -0
- package/src/types/translations.ts +60 -0
- package/tsconfig.json +12 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { AllConsentNames, ConsentState } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Determines the effective consents based on the user's Do Not Track setting.
|
|
5
|
+
*
|
|
6
|
+
* @param consents - The current state of user consents.
|
|
7
|
+
* @param honorDoNotTrack - Whether to respect the user's Do Not Track setting.
|
|
8
|
+
* @returns The effective consents after considering Do Not Track.
|
|
9
|
+
*/
|
|
10
|
+
export function getEffectiveConsents(
|
|
11
|
+
consents: ConsentState,
|
|
12
|
+
honorDoNotTrack: boolean
|
|
13
|
+
): ConsentState {
|
|
14
|
+
if (
|
|
15
|
+
honorDoNotTrack &&
|
|
16
|
+
typeof window !== 'undefined' &&
|
|
17
|
+
window.navigator.doNotTrack === '1'
|
|
18
|
+
) {
|
|
19
|
+
return Object.keys(consents).reduce((acc, key) => {
|
|
20
|
+
if (key in consents) {
|
|
21
|
+
acc[key as AllConsentNames] = key === 'necessary';
|
|
22
|
+
}
|
|
23
|
+
return acc;
|
|
24
|
+
}, {} as ConsentState);
|
|
25
|
+
}
|
|
26
|
+
return consents;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Checks if the user has given consent for a specific type.
|
|
31
|
+
*
|
|
32
|
+
* @param consentType - The type of consent to check.
|
|
33
|
+
* @param consents - The current state of user consents.
|
|
34
|
+
* @param honorDoNotTrack - Whether to respect the user's Do Not Track setting.
|
|
35
|
+
* @returns True if consent is given, false otherwise.
|
|
36
|
+
*/
|
|
37
|
+
export function hasConsentFor(
|
|
38
|
+
consentType: AllConsentNames,
|
|
39
|
+
consents: ConsentState,
|
|
40
|
+
honorDoNotTrack: boolean
|
|
41
|
+
): boolean {
|
|
42
|
+
const effectiveConsents = getEffectiveConsents(consents, honorDoNotTrack);
|
|
43
|
+
return effectiveConsents[consentType] || false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Determines if the user has consented based on consent information.
|
|
48
|
+
*
|
|
49
|
+
* @param consentInfo - The consent information.
|
|
50
|
+
* @returns True if the user has consented, false otherwise.
|
|
51
|
+
*/
|
|
52
|
+
export function hasConsented(
|
|
53
|
+
consentInfo: { time: number; type: 'all' | 'custom' | 'necessary' } | null
|
|
54
|
+
): boolean {
|
|
55
|
+
return consentInfo !== null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Checks if a specific consent type is enabled.
|
|
60
|
+
*
|
|
61
|
+
* @param consentType - The type of consent to check.
|
|
62
|
+
* @param consents - The current state of user consents.
|
|
63
|
+
* @returns True if the consent type is enabled, false otherwise.
|
|
64
|
+
*/
|
|
65
|
+
export function isConsentEnabled(
|
|
66
|
+
consentType: AllConsentNames,
|
|
67
|
+
consents: ConsentState
|
|
68
|
+
): boolean {
|
|
69
|
+
return consents[consentType] || false;
|
|
70
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Implements automatic blocking of tracking scripts and network requests until user consent is granted.
|
|
4
|
+
*
|
|
5
|
+
* IMPORTANT: This module overrides global `fetch` and `XMLHttpRequest` APIs to enforce consent requirements.
|
|
6
|
+
* While this approach is necessary for proper consent management, it may conflict with other libraries that
|
|
7
|
+
* also modify these APIs. This implementation takes precedence to ensure compliance.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { AllConsentNames, ConsentState } from '../types';
|
|
11
|
+
import DEFAULT_DOMAIN_CONSENT_MAP from './tracking-domains';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration options for the tracking blocker
|
|
15
|
+
*/
|
|
16
|
+
export interface TrackingBlockerConfig {
|
|
17
|
+
/** Whether to disable automatic blocking (defaults to false) */
|
|
18
|
+
disableAutomaticBlocking?: boolean;
|
|
19
|
+
|
|
20
|
+
/** Override the default domain consent map */
|
|
21
|
+
overrideDomainConsentMap?: boolean;
|
|
22
|
+
|
|
23
|
+
/** Map of domains to their required consent types */
|
|
24
|
+
domainConsentMap?: Record<string, AllConsentNames>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create default consent state with all consents set to their default values
|
|
29
|
+
*/
|
|
30
|
+
function createDefaultConsentState(): ConsentState {
|
|
31
|
+
return {
|
|
32
|
+
experience: false,
|
|
33
|
+
functionality: false,
|
|
34
|
+
marketing: false,
|
|
35
|
+
measurement: false,
|
|
36
|
+
necessary: true,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface TrackingBlocker {
|
|
41
|
+
updateConsents: (newConsents: ConsentState) => void;
|
|
42
|
+
destroy: () => void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates a tracking blocker instance that handles blocking of tracking scripts and network requests
|
|
47
|
+
*/
|
|
48
|
+
export function createTrackingBlocker(
|
|
49
|
+
config: TrackingBlockerConfig = {},
|
|
50
|
+
initialConsents?: ConsentState
|
|
51
|
+
): TrackingBlocker {
|
|
52
|
+
const blockerConfig = {
|
|
53
|
+
disableAutomaticBlocking: false,
|
|
54
|
+
...config,
|
|
55
|
+
domainConsentMap: config.overrideDomainConsentMap
|
|
56
|
+
? config.domainConsentMap
|
|
57
|
+
: { ...DEFAULT_DOMAIN_CONSENT_MAP, ...config.domainConsentMap },
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
let consents = initialConsents || createDefaultConsentState();
|
|
61
|
+
const originalFetch = window.fetch;
|
|
62
|
+
const originalXHR = window.XMLHttpRequest;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Normalize a domain by removing 'www.' prefix and ensuring consistent format
|
|
66
|
+
*/
|
|
67
|
+
function normalizeDomain(domain: string): string {
|
|
68
|
+
return domain
|
|
69
|
+
.toLowerCase()
|
|
70
|
+
.replace(/^www\./, '')
|
|
71
|
+
.replace(/:\d+$/, '') // Remove port numbers
|
|
72
|
+
.trim();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Check if a domain matches any entry in the domain map, including subdomains
|
|
77
|
+
*/
|
|
78
|
+
function findMatchingDomain(
|
|
79
|
+
domain: string,
|
|
80
|
+
domainMap: Record<string, AllConsentNames>
|
|
81
|
+
): AllConsentNames | undefined {
|
|
82
|
+
const normalizedDomain = normalizeDomain(domain);
|
|
83
|
+
|
|
84
|
+
// First try exact match
|
|
85
|
+
const directMatch = domainMap[normalizedDomain];
|
|
86
|
+
if (directMatch) {
|
|
87
|
+
return directMatch;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Then try matching as a subdomain
|
|
91
|
+
for (const [mapDomain, consent] of Object.entries(domainMap)) {
|
|
92
|
+
const normalizedMapDomain = normalizeDomain(mapDomain);
|
|
93
|
+
if (
|
|
94
|
+
normalizedDomain.endsWith(`.${normalizedMapDomain}`) ||
|
|
95
|
+
normalizedDomain === normalizedMapDomain
|
|
96
|
+
) {
|
|
97
|
+
return consent;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if a URL requires consent and if that consent has been granted
|
|
106
|
+
*/
|
|
107
|
+
function isRequestAllowed(url: string): boolean {
|
|
108
|
+
try {
|
|
109
|
+
const domain = new URL(url).hostname;
|
|
110
|
+
const requiredConsent = findMatchingDomain(
|
|
111
|
+
domain,
|
|
112
|
+
blockerConfig.domainConsentMap || {}
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (!requiredConsent) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const isAllowed = consents[requiredConsent] === true;
|
|
120
|
+
return isAllowed;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Dispatch an event when a request is blocked due to missing consent
|
|
128
|
+
*/
|
|
129
|
+
function dispatchConsentBlockedEvent(url: string): void {
|
|
130
|
+
document.dispatchEvent(
|
|
131
|
+
new CustomEvent('ConsentBlockedRequest', { detail: { url } })
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Intercept and potentially block network requests
|
|
137
|
+
*/
|
|
138
|
+
function interceptNetworkRequests(): void {
|
|
139
|
+
// Override fetch only if it hasn't been modified by another script
|
|
140
|
+
if (window.fetch === originalFetch) {
|
|
141
|
+
window.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
142
|
+
const url = input instanceof Request ? input.url : input.toString();
|
|
143
|
+
if (!isRequestAllowed(url)) {
|
|
144
|
+
dispatchConsentBlockedEvent(url);
|
|
145
|
+
return Promise.reject(
|
|
146
|
+
new Error(`Request to ${url} blocked due to missing consent`)
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return await originalFetch.call(window, input, init);
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Override XMLHttpRequest only if it hasn't been modified
|
|
155
|
+
if (window.XMLHttpRequest === originalXHR) {
|
|
156
|
+
window.XMLHttpRequest = class extends originalXHR {
|
|
157
|
+
override open(
|
|
158
|
+
method: string,
|
|
159
|
+
url: string | URL,
|
|
160
|
+
async = true,
|
|
161
|
+
username?: string,
|
|
162
|
+
password?: string
|
|
163
|
+
) {
|
|
164
|
+
if (!isRequestAllowed(url.toString())) {
|
|
165
|
+
dispatchConsentBlockedEvent(url.toString());
|
|
166
|
+
throw new Error(`Request to ${url} blocked due to missing consent`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
super.open(method, url, async, username, password);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Safe restoration of fetch and XHR
|
|
177
|
+
*/
|
|
178
|
+
function restoreOriginalRequests(): void {
|
|
179
|
+
// Restore fetch if it has been overridden
|
|
180
|
+
if (window.fetch !== originalFetch) {
|
|
181
|
+
window.fetch = originalFetch;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (window.XMLHttpRequest !== originalXHR) {
|
|
185
|
+
window.XMLHttpRequest = originalXHR;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Initialize if automatic blocking is enabled
|
|
190
|
+
if (!blockerConfig.disableAutomaticBlocking) {
|
|
191
|
+
interceptNetworkRequests();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
updateConsents: (newConsents: ConsentState) => {
|
|
196
|
+
consents = newConsents;
|
|
197
|
+
},
|
|
198
|
+
destroy: () => {
|
|
199
|
+
restoreOriginalRequests();
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { AllConsentNames } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default tracking domains that require specific consent types
|
|
5
|
+
*/
|
|
6
|
+
const DEFAULT_DOMAIN_CONSENT_MAP: Record<string, AllConsentNames> = {
|
|
7
|
+
// Analytics/Measurement domains
|
|
8
|
+
'www.google-analytics.com': 'measurement',
|
|
9
|
+
'analytics.google.com': 'measurement',
|
|
10
|
+
'www.googletagmanager.com': 'measurement',
|
|
11
|
+
'stats.g.doubleclick.net': 'measurement',
|
|
12
|
+
'ampcid.google.com': 'measurement',
|
|
13
|
+
'analytics.twitter.com': 'measurement',
|
|
14
|
+
'analytics.pinterest.com': 'measurement',
|
|
15
|
+
'dc.services.visualstudio.com': 'measurement',
|
|
16
|
+
'www.clarity.ms': 'measurement',
|
|
17
|
+
'www.hotjar.com': 'measurement',
|
|
18
|
+
'static.hotjar.com': 'measurement',
|
|
19
|
+
'script.hotjar.com': 'measurement',
|
|
20
|
+
'insights.hotjar.com': 'measurement',
|
|
21
|
+
'mouseflow.com': 'measurement',
|
|
22
|
+
'api.mouseflow.com': 'measurement',
|
|
23
|
+
'tools.mouseflow.com': 'measurement',
|
|
24
|
+
'cdn.heapanalytics.com': 'measurement',
|
|
25
|
+
'plausible.io': 'measurement',
|
|
26
|
+
'matomo.cloud': 'measurement',
|
|
27
|
+
'matomo.org': 'measurement',
|
|
28
|
+
'mixpanel.com': 'measurement',
|
|
29
|
+
'api.mixpanel.com': 'measurement',
|
|
30
|
+
'sentry.io': 'measurement',
|
|
31
|
+
'browser.sentry-cdn.com': 'measurement',
|
|
32
|
+
'js.monitor.azure.com': 'measurement',
|
|
33
|
+
'stats.wp.com': 'measurement',
|
|
34
|
+
'pixel.wp.com': 'measurement',
|
|
35
|
+
'analytics.amplitude.com': 'measurement',
|
|
36
|
+
'api2.amplitude.com': 'measurement',
|
|
37
|
+
'cdn.amplitude.com': 'measurement',
|
|
38
|
+
'api.segment.io': 'measurement',
|
|
39
|
+
'cdn.segment.com': 'measurement',
|
|
40
|
+
'api.segment.com': 'measurement',
|
|
41
|
+
'pendo.io': 'measurement',
|
|
42
|
+
'data.pendo.io': 'measurement',
|
|
43
|
+
'cdn.pendo.io': 'measurement',
|
|
44
|
+
|
|
45
|
+
// Marketing/Advertising domains
|
|
46
|
+
'connect.facebook.net': 'marketing',
|
|
47
|
+
'platform.twitter.com': 'marketing',
|
|
48
|
+
'platform.linkedin.com': 'marketing',
|
|
49
|
+
'www.googleadservices.com': 'marketing',
|
|
50
|
+
'doubleclick.net': 'marketing',
|
|
51
|
+
'googleads.g.doubleclick.net': 'marketing',
|
|
52
|
+
'ad.doubleclick.net': 'marketing',
|
|
53
|
+
'www.facebook.com': 'marketing',
|
|
54
|
+
'ads.linkedin.com': 'marketing',
|
|
55
|
+
'ads-api.tiktok.com': 'marketing',
|
|
56
|
+
'analytics.tiktok.com': 'marketing',
|
|
57
|
+
'business.tiktok.com': 'marketing',
|
|
58
|
+
'ads.pinterest.com': 'marketing',
|
|
59
|
+
'log.pinterest.com': 'marketing',
|
|
60
|
+
'ads-twitter.com': 'marketing',
|
|
61
|
+
'static.ads-twitter.com': 'marketing',
|
|
62
|
+
'advertising.twitter.com': 'marketing',
|
|
63
|
+
'ads.yahoo.com': 'marketing',
|
|
64
|
+
'sp.analytics.yahoo.com': 'marketing',
|
|
65
|
+
'gemini.yahoo.com': 'marketing',
|
|
66
|
+
'adroll.com': 'marketing',
|
|
67
|
+
'a.adroll.com': 'marketing',
|
|
68
|
+
'd.adroll.com': 'marketing',
|
|
69
|
+
's.adroll.com': 'marketing',
|
|
70
|
+
'adform.net': 'marketing',
|
|
71
|
+
'track.adform.net': 'marketing',
|
|
72
|
+
'dmp.adform.net': 'marketing',
|
|
73
|
+
'criteo.com': 'marketing',
|
|
74
|
+
'static.criteo.net': 'marketing',
|
|
75
|
+
'bidder.criteo.com': 'marketing',
|
|
76
|
+
'dynamic.criteo.com': 'marketing',
|
|
77
|
+
'gum.criteo.com': 'marketing',
|
|
78
|
+
'taboola.com': 'marketing',
|
|
79
|
+
'cdn.taboola.com': 'marketing',
|
|
80
|
+
'trc.taboola.com': 'marketing',
|
|
81
|
+
'outbrain.com': 'marketing',
|
|
82
|
+
'widgets.outbrain.com': 'marketing',
|
|
83
|
+
'tr.outbrain.com': 'marketing',
|
|
84
|
+
'amplify.outbrain.com': 'marketing',
|
|
85
|
+
'bing.com': 'marketing',
|
|
86
|
+
'bat.bing.com': 'marketing',
|
|
87
|
+
'clarity.ms': 'marketing',
|
|
88
|
+
'quantserve.com': 'marketing',
|
|
89
|
+
'secure.quantserve.com': 'marketing',
|
|
90
|
+
'pixel.quantserve.com': 'marketing',
|
|
91
|
+
'exelator.com': 'marketing',
|
|
92
|
+
'load.exelator.com': 'marketing',
|
|
93
|
+
'api.exelator.com': 'marketing',
|
|
94
|
+
'ad.360yield.com': 'marketing',
|
|
95
|
+
'match.360yield.com': 'marketing',
|
|
96
|
+
'ad.turn.com': 'marketing',
|
|
97
|
+
'r.turn.com': 'marketing',
|
|
98
|
+
'd.turn.com': 'marketing',
|
|
99
|
+
|
|
100
|
+
// Functionality domains
|
|
101
|
+
'cdn.jsdelivr.net': 'functionality',
|
|
102
|
+
'ajax.googleapis.com': 'functionality',
|
|
103
|
+
'fonts.googleapis.com': 'functionality',
|
|
104
|
+
'maps.googleapis.com': 'functionality',
|
|
105
|
+
'www.recaptcha.net': 'functionality',
|
|
106
|
+
'recaptcha.net': 'functionality',
|
|
107
|
+
'www.gstatic.com': 'functionality',
|
|
108
|
+
'fonts.gstatic.com': 'functionality',
|
|
109
|
+
'cdnjs.cloudflare.com': 'functionality',
|
|
110
|
+
'unpkg.com': 'functionality',
|
|
111
|
+
'code.jquery.com': 'functionality',
|
|
112
|
+
'maxcdn.bootstrapcdn.com': 'functionality',
|
|
113
|
+
'cdn.datatables.net': 'functionality',
|
|
114
|
+
'js.stripe.com': 'functionality',
|
|
115
|
+
'api.stripe.com': 'functionality',
|
|
116
|
+
'checkout.stripe.com': 'functionality',
|
|
117
|
+
'js.braintreegateway.com': 'functionality',
|
|
118
|
+
'api.braintreegateway.com': 'functionality',
|
|
119
|
+
'cdn.shopify.com': 'functionality',
|
|
120
|
+
'js.intercomcdn.com': 'functionality',
|
|
121
|
+
'widget.intercom.io': 'functionality',
|
|
122
|
+
'cdn.auth0.com': 'functionality',
|
|
123
|
+
'js.pusher.com': 'functionality',
|
|
124
|
+
'sockjs.pusher.com': 'functionality',
|
|
125
|
+
|
|
126
|
+
// Experience/UX domains
|
|
127
|
+
'app.optimizely.com': 'experience',
|
|
128
|
+
'cdn.optimizely.com': 'experience',
|
|
129
|
+
'logx.optimizely.com': 'experience',
|
|
130
|
+
'cdn.mouseflow.com': 'experience',
|
|
131
|
+
'fullstory.com': 'experience',
|
|
132
|
+
'rs.fullstory.com': 'experience',
|
|
133
|
+
'edge.fullstory.com': 'experience',
|
|
134
|
+
'vwo.com': 'experience',
|
|
135
|
+
'dev.visualwebsiteoptimizer.com': 'experience',
|
|
136
|
+
'assets.adobedtm.com': 'experience',
|
|
137
|
+
'cdn.tt.omtrdc.net': 'experience',
|
|
138
|
+
'demdex.net': 'experience',
|
|
139
|
+
'sc.omtrdc.net': 'experience',
|
|
140
|
+
'crazyegg.com': 'experience',
|
|
141
|
+
'script.crazyegg.com': 'experience',
|
|
142
|
+
'tracking.crazyegg.com': 'experience',
|
|
143
|
+
'luckyorange.com': 'experience',
|
|
144
|
+
'cdn.luckyorange.com': 'experience',
|
|
145
|
+
'w1.luckyorange.com': 'experience',
|
|
146
|
+
'upload.luckyorange.com': 'experience',
|
|
147
|
+
'clicktale.net': 'experience',
|
|
148
|
+
'cdn.clicktale.net': 'experience',
|
|
149
|
+
'conductor.clicktale.net': 'experience',
|
|
150
|
+
'userzoom.com': 'experience',
|
|
151
|
+
'cdn.userzoom.com': 'experience',
|
|
152
|
+
'api.userzoom.com': 'experience',
|
|
153
|
+
'contentsquare.net': 'experience',
|
|
154
|
+
't.contentsquare.net': 'experience',
|
|
155
|
+
'app.contentsquare.com': 'experience',
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export default DEFAULT_DOMAIN_CONSENT_MAP;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Provides the default initial state configuration for the consent management store.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { PrivacyConsentState } from './store.type';
|
|
7
|
+
import { defaultTranslationConfig } from './translations';
|
|
8
|
+
import { type ConsentState, consentTypes } from './types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Default initial state for the consent management store.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* This configuration establishes the baseline state for the consent manager,
|
|
15
|
+
* including default consent values, compliance settings, and privacy preferences.
|
|
16
|
+
*
|
|
17
|
+
* Notable defaults include:
|
|
18
|
+
* - All consents start with their type-specific default values
|
|
19
|
+
* - GDPR compliance is globally enabled
|
|
20
|
+
* - CCPA compliance is enabled for US users only
|
|
21
|
+
* - Do Not Track is respected by default
|
|
22
|
+
* - Only necessary and marketing consents are included in gdprTypes
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* Using the initial state:
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const store = createConsentManagerStore();
|
|
28
|
+
*
|
|
29
|
+
* // Reset to initial state
|
|
30
|
+
* store.setState(initialState);
|
|
31
|
+
*
|
|
32
|
+
* // Extend initial state
|
|
33
|
+
* const customState = {
|
|
34
|
+
* ...initialState,
|
|
35
|
+
* privacySettings: {
|
|
36
|
+
* honorDoNotTrack: false
|
|
37
|
+
* }
|
|
38
|
+
* };
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export const initialState: Omit<
|
|
44
|
+
PrivacyConsentState,
|
|
45
|
+
'getEffectiveConsents' | 'hasConsentFor'
|
|
46
|
+
> = {
|
|
47
|
+
/** Initial consent states based on default values from consent types */
|
|
48
|
+
consents: consentTypes.reduce((acc, consent) => {
|
|
49
|
+
acc[consent.name] = consent.defaultValue;
|
|
50
|
+
return acc;
|
|
51
|
+
}, {} as ConsentState),
|
|
52
|
+
|
|
53
|
+
/** No consent information stored initially */
|
|
54
|
+
consentInfo: null,
|
|
55
|
+
|
|
56
|
+
/** Show consent popup by default */
|
|
57
|
+
showPopup: true,
|
|
58
|
+
|
|
59
|
+
/** Default GDPR consent types to include */
|
|
60
|
+
gdprTypes: ['necessary', 'marketing'],
|
|
61
|
+
|
|
62
|
+
/** Privacy dialog starts closed */
|
|
63
|
+
isPrivacyDialogOpen: false,
|
|
64
|
+
|
|
65
|
+
/** Default compliance settings per region */
|
|
66
|
+
complianceSettings: {
|
|
67
|
+
/** GDPR: Enabled globally by default */
|
|
68
|
+
gdpr: { enabled: true, appliesGlobally: true, applies: true },
|
|
69
|
+
|
|
70
|
+
/** CCPA: Enabled for US only */
|
|
71
|
+
ccpa: { enabled: true, appliesGlobally: false, applies: undefined },
|
|
72
|
+
|
|
73
|
+
/** LGPD: Disabled by default */
|
|
74
|
+
lgpd: { enabled: false, appliesGlobally: false, applies: undefined },
|
|
75
|
+
|
|
76
|
+
/** US State Privacy: Enabled for US only */
|
|
77
|
+
usStatePrivacy: {
|
|
78
|
+
enabled: true,
|
|
79
|
+
appliesGlobally: false,
|
|
80
|
+
applies: undefined,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
/** Empty callbacks object - should be populated by implementation */
|
|
85
|
+
callbacks: {},
|
|
86
|
+
|
|
87
|
+
/** Default to US if no country detected */
|
|
88
|
+
detectedCountry: 'US',
|
|
89
|
+
|
|
90
|
+
/** Default privacy settings */
|
|
91
|
+
privacySettings: {
|
|
92
|
+
/** Respect Do Not Track by default */
|
|
93
|
+
honorDoNotTrack: true,
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/** Default translation configuration */
|
|
97
|
+
translationConfig: defaultTranslationConfig,
|
|
98
|
+
|
|
99
|
+
/** Don't include non-displayed consents by default */
|
|
100
|
+
includeNonDisplayedConsents: false,
|
|
101
|
+
|
|
102
|
+
/** Use predefined consent types */
|
|
103
|
+
consentTypes: consentTypes,
|
|
104
|
+
|
|
105
|
+
// Initialize all methods as no-ops
|
|
106
|
+
setConsent: () => {},
|
|
107
|
+
setShowPopup: () => {},
|
|
108
|
+
setIsPrivacyDialogOpen: () => {},
|
|
109
|
+
saveConsents: () => {},
|
|
110
|
+
resetConsents: () => {},
|
|
111
|
+
setGdprTypes: () => {},
|
|
112
|
+
setComplianceSetting: () => {},
|
|
113
|
+
resetComplianceSettings: () => {},
|
|
114
|
+
setCallback: () => {},
|
|
115
|
+
setDetectedCountry: () => {},
|
|
116
|
+
getDisplayedConsents: () => [],
|
|
117
|
+
hasConsented: () => false,
|
|
118
|
+
setTranslationConfig: () => {},
|
|
119
|
+
clearAllData: () => {},
|
|
120
|
+
updateConsentMode: () => {},
|
|
121
|
+
setPrivacySettings: () => {},
|
|
122
|
+
setIncludeNonDisplayedConsents: () => {},
|
|
123
|
+
};
|