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,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(() => {
|
|
4
|
+
__webpack_require__.d = function (exports1, definition) {
|
|
5
|
+
for (var key in definition)
|
|
6
|
+
if (
|
|
7
|
+
__webpack_require__.o(definition, key) &&
|
|
8
|
+
!__webpack_require__.o(exports1, key)
|
|
9
|
+
)
|
|
10
|
+
Object.defineProperty(exports1, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: definition[key],
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
})();
|
|
16
|
+
(() => {
|
|
17
|
+
__webpack_require__.o = function (obj, prop) {
|
|
18
|
+
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
19
|
+
};
|
|
20
|
+
})();
|
|
21
|
+
(() => {
|
|
22
|
+
__webpack_require__.r = function (exports1) {
|
|
23
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag)
|
|
24
|
+
Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
25
|
+
value: 'Module',
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
28
|
+
value: true,
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
})();
|
|
32
|
+
var __webpack_exports__ = {};
|
|
33
|
+
__webpack_require__.r(__webpack_exports__);
|
|
34
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
35
|
+
consentTypes: () => external_gdpr_cjs_namespaceObject.consentTypes,
|
|
36
|
+
});
|
|
37
|
+
const external_gdpr_cjs_namespaceObject = require('./gdpr.cjs');
|
|
38
|
+
var __webpack_export_target__ = exports;
|
|
39
|
+
for (var __webpack_i__ in __webpack_exports__)
|
|
40
|
+
__webpack_export_target__[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
41
|
+
if (__webpack_exports__.__esModule)
|
|
42
|
+
Object.defineProperty(__webpack_export_target__, '__esModule', {
|
|
43
|
+
value: true,
|
|
44
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Central export point for all consent management types and interfaces.
|
|
4
|
+
* This module aggregates and re-exports all type definitions needed for implementing
|
|
5
|
+
* GDPR-compliant consent management.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* @module
|
|
9
|
+
* Compliance and Privacy Types
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* Exports types related to privacy compliance and consent management:
|
|
13
|
+
* - Region-specific compliance settings
|
|
14
|
+
* - Consent state tracking
|
|
15
|
+
* - Privacy preferences
|
|
16
|
+
* - Namespace configuration
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* Import compliance-related types:
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import type {
|
|
22
|
+
* ComplianceRegion,
|
|
23
|
+
* ComplianceSettings,
|
|
24
|
+
* PrivacySettings
|
|
25
|
+
* } from 'c15t/types';
|
|
26
|
+
*
|
|
27
|
+
* const euSettings: ComplianceSettings = {
|
|
28
|
+
* enabled: true,
|
|
29
|
+
* appliesGlobally: false,
|
|
30
|
+
* applies: true
|
|
31
|
+
* };
|
|
32
|
+
*
|
|
33
|
+
* const region: ComplianceRegion = 'gdpr';
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
import type {
|
|
37
|
+
ComplianceRegion,
|
|
38
|
+
ComplianceSettings,
|
|
39
|
+
ConsentState,
|
|
40
|
+
HasConsentedProps,
|
|
41
|
+
NamespaceProps,
|
|
42
|
+
PrivacySettings,
|
|
43
|
+
} from './compliance';
|
|
44
|
+
export type {
|
|
45
|
+
ConsentState,
|
|
46
|
+
ComplianceRegion,
|
|
47
|
+
ComplianceSettings,
|
|
48
|
+
PrivacySettings,
|
|
49
|
+
HasConsentedProps,
|
|
50
|
+
NamespaceProps,
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* @module
|
|
54
|
+
* GDPR Consent Types
|
|
55
|
+
*
|
|
56
|
+
* @remarks
|
|
57
|
+
* Exports types and constants for GDPR-specific consent management:
|
|
58
|
+
* - Consent category definitions
|
|
59
|
+
* - Consent type configurations
|
|
60
|
+
* - Predefined consent settings
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* Import and use GDPR-related types:
|
|
64
|
+
* ```typescript
|
|
65
|
+
* import {
|
|
66
|
+
* type AllConsentNames,
|
|
67
|
+
* type ConsentType,
|
|
68
|
+
* consentTypes
|
|
69
|
+
* } from 'c15t/types';
|
|
70
|
+
*
|
|
71
|
+
* function isOptionalConsent(type: AllConsentNames): boolean {
|
|
72
|
+
* const config = consentTypes.find(c => c.name === type);
|
|
73
|
+
* return config ? !config.disabled && !config.defaultValue : false;
|
|
74
|
+
* }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
import { type AllConsentNames, type ConsentType, consentTypes } from './gdpr';
|
|
78
|
+
export { consentTypes };
|
|
79
|
+
export type { AllConsentNames, ConsentType };
|
|
80
|
+
/**
|
|
81
|
+
* @module
|
|
82
|
+
* Callback Types
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* Exports types for consent management callbacks and event handlers:
|
|
86
|
+
* - Generic callback function type
|
|
87
|
+
* - Consent-specific callback configurations
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* Import and use callback types:
|
|
91
|
+
* ```typescript
|
|
92
|
+
* import type {
|
|
93
|
+
* CallbackFunction,
|
|
94
|
+
* Callbacks
|
|
95
|
+
* } from 'c15t/types';
|
|
96
|
+
*
|
|
97
|
+
* const callbacks: Callbacks = {
|
|
98
|
+
* onConsentGiven: () => {
|
|
99
|
+
* console.log('Consent granted');
|
|
100
|
+
* initializeAnalytics();
|
|
101
|
+
* },
|
|
102
|
+
* onError: (error) => {
|
|
103
|
+
* console.error('Consent error:', error);
|
|
104
|
+
* }
|
|
105
|
+
* };
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* Create typed callback functions:
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const errorHandler: CallbackFunction<string> =
|
|
112
|
+
* (message) => console.error(message);
|
|
113
|
+
*
|
|
114
|
+
* const readyHandler: CallbackFunction =
|
|
115
|
+
* () => console.log('System ready');
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
import type { CallbackFunction, Callbacks } from './callbacks';
|
|
119
|
+
export type { CallbackFunction, Callbacks };
|
|
120
|
+
/**
|
|
121
|
+
* @module
|
|
122
|
+
* Translation Types
|
|
123
|
+
*
|
|
124
|
+
* @remarks
|
|
125
|
+
* Exports types for translation configuration and translations:
|
|
126
|
+
* - Translation configuration
|
|
127
|
+
* - Translation types
|
|
128
|
+
* - Cookie banner translations
|
|
129
|
+
* - Consent manager dialog translations
|
|
130
|
+
* - Consent manager widget translations
|
|
131
|
+
*/
|
|
132
|
+
export type {
|
|
133
|
+
ConsentManagerDialogTranslations,
|
|
134
|
+
ConsentManagerWidgetTranslations,
|
|
135
|
+
ConsentTypeTranslations,
|
|
136
|
+
ConsentTypesTranslations,
|
|
137
|
+
CookieBannerTranslations,
|
|
138
|
+
TranslationConfig,
|
|
139
|
+
Translations,
|
|
140
|
+
} from './translations';
|
|
141
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,KAAK,EACX,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,MAAM,cAAc,CAAC;AAEtB,YAAY,EACX,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,cAAc,GACd,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAE9E,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE/D,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC;AAE5C;;;;;;;;;;;GAWG;AAEH,YAAY,EACX,gCAAgC,EAChC,gCAAgC,EAChC,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,iBAAiB,EACjB,YAAY,GACZ,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(() => {
|
|
4
|
+
__webpack_require__.r = function (exports1) {
|
|
5
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag)
|
|
6
|
+
Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
7
|
+
value: 'Module',
|
|
8
|
+
});
|
|
9
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
10
|
+
value: true,
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
})();
|
|
14
|
+
var __webpack_exports__ = {};
|
|
15
|
+
__webpack_require__.r(__webpack_exports__);
|
|
16
|
+
var __webpack_export_target__ = exports;
|
|
17
|
+
for (var __webpack_i__ in __webpack_exports__)
|
|
18
|
+
__webpack_export_target__[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
19
|
+
if (__webpack_exports__.__esModule)
|
|
20
|
+
Object.defineProperty(__webpack_export_target__, '__esModule', {
|
|
21
|
+
value: true,
|
|
22
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ConsentType } from './gdpr';
|
|
2
|
+
export interface CookieBannerTranslations {
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
acceptAll: string;
|
|
6
|
+
rejectAll: string;
|
|
7
|
+
customize: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ConsentManagerDialogTranslations {
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
save: string;
|
|
13
|
+
acceptAll: string;
|
|
14
|
+
rejectAll: string;
|
|
15
|
+
close: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ConsentTypeTranslations {
|
|
18
|
+
title: string;
|
|
19
|
+
description: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ConsentManagerWidgetTranslations {
|
|
22
|
+
title: string;
|
|
23
|
+
description: string;
|
|
24
|
+
save: string;
|
|
25
|
+
acceptAll: string;
|
|
26
|
+
rejectAll: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Maps consent type names to their respective translations.
|
|
30
|
+
* Uses the name property from ConsentType to ensure type safety.
|
|
31
|
+
*/
|
|
32
|
+
export type ConsentTypesTranslations = {
|
|
33
|
+
[key in ConsentType['name']]: ConsentTypeTranslations;
|
|
34
|
+
};
|
|
35
|
+
export interface CompleteTranslations {
|
|
36
|
+
cookieBanner: CookieBannerTranslations;
|
|
37
|
+
consentManagerDialog: ConsentManagerDialogTranslations;
|
|
38
|
+
consentManagerWidget: ConsentManagerWidgetTranslations;
|
|
39
|
+
consentTypes: ConsentTypesTranslations;
|
|
40
|
+
}
|
|
41
|
+
export interface Translations {
|
|
42
|
+
cookieBanner: Partial<CookieBannerTranslations>;
|
|
43
|
+
consentManagerDialog: Partial<ConsentManagerDialogTranslations>;
|
|
44
|
+
consentManagerWidget: Partial<ConsentManagerWidgetTranslations>;
|
|
45
|
+
consentTypes: Partial<ConsentTypesTranslations>;
|
|
46
|
+
}
|
|
47
|
+
export interface TranslationConfig {
|
|
48
|
+
translations: Record<string, Partial<Translations>>;
|
|
49
|
+
defaultLanguage?: string;
|
|
50
|
+
disableAutoLanguageSwitch?: boolean;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=translations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translations.d.ts","sourceRoot":"","sources":["../../src/types/translations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,MAAM,WAAW,wBAAwB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gCAAgC;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gCAAgC;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;KACrC,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,GAAG,uBAAuB;CACrD,CAAC;AAGF,MAAM,WAAW,oBAAoB;IACpC,YAAY,EAAE,wBAAwB,CAAC;IACvC,oBAAoB,EAAE,gCAAgC,CAAC;IACvD,oBAAoB,EAAE,gCAAgC,CAAC;IACvD,YAAY,EAAE,wBAAwB,CAAC;CACvC;AAGD,MAAM,WAAW,YAAY;IAC5B,YAAY,EAAE,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAChD,oBAAoB,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAChE,oBAAoB,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAChE,YAAY,EAAE,OAAO,CAAC,wBAAwB,CAAC,CAAC;CAChD;AACD,MAAM,WAAW,iBAAiB;IACjC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;IACpD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACpC"}
|
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "c15t",
|
|
3
|
+
"version": "0.0.1-rc.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"browserslist": [
|
|
9
|
+
">0.2%",
|
|
10
|
+
"not dead",
|
|
11
|
+
"not op_mini all"
|
|
12
|
+
],
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"zustand": "^5.0.3"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"happy-dom": "^17.1.0",
|
|
18
|
+
"@c15t/typescript-config": "0.0.1-beta.1"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "rslib build",
|
|
25
|
+
"check-types": "tsc --noEmit",
|
|
26
|
+
"dev": "rslib build --watch",
|
|
27
|
+
"fmt": "pnpm biome format --write .",
|
|
28
|
+
"lint": "pnpm biome lint ./src",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"test:coverage": "vitest run --coverage"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/rslib.config.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { pluginReact } from '@rsbuild/plugin-react';
|
|
2
|
+
import { defineConfig } from '@rslib/core';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
source: {
|
|
6
|
+
entry: {
|
|
7
|
+
index: ['./src/**'],
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
lib: [
|
|
11
|
+
{
|
|
12
|
+
bundle: false,
|
|
13
|
+
dts: true,
|
|
14
|
+
format: 'esm',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
bundle: false,
|
|
18
|
+
dts: true,
|
|
19
|
+
format: 'cjs',
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
output: {
|
|
23
|
+
target: 'web',
|
|
24
|
+
|
|
25
|
+
cleanDistPath: true,
|
|
26
|
+
},
|
|
27
|
+
plugins: [pluginReact()],
|
|
28
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Re-export store
|
|
2
|
+
export { createConsentManagerStore } from './store';
|
|
3
|
+
export type { PrivacyConsentState } from './store.type';
|
|
4
|
+
// Re-export all utilities
|
|
5
|
+
export * from './libs/consent-utils';
|
|
6
|
+
export { createTrackingBlocker } from './libs/tracking-blocker';
|
|
7
|
+
export type { TrackingBlockerConfig } from './libs/tracking-blocker';
|
|
8
|
+
|
|
9
|
+
// Re-export types and constants
|
|
10
|
+
export { consentTypes } from './types';
|
|
11
|
+
export type {
|
|
12
|
+
CallbackFunction,
|
|
13
|
+
Callbacks,
|
|
14
|
+
AllConsentNames,
|
|
15
|
+
ConsentType,
|
|
16
|
+
ConsentState,
|
|
17
|
+
ComplianceRegion,
|
|
18
|
+
ComplianceSettings,
|
|
19
|
+
PrivacySettings,
|
|
20
|
+
HasConsentedProps,
|
|
21
|
+
NamespaceProps,
|
|
22
|
+
TranslationConfig,
|
|
23
|
+
Translations,
|
|
24
|
+
CookieBannerTranslations,
|
|
25
|
+
ConsentManagerDialogTranslations,
|
|
26
|
+
ConsentManagerWidgetTranslations,
|
|
27
|
+
ConsentTypeTranslations,
|
|
28
|
+
ConsentTypesTranslations,
|
|
29
|
+
} from './types';
|
|
30
|
+
|
|
31
|
+
export { defaultTranslationConfig } from './translations';
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import {
|
|
2
|
+
afterAll,
|
|
3
|
+
beforeAll,
|
|
4
|
+
beforeEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
test,
|
|
8
|
+
vi,
|
|
9
|
+
} from 'vitest';
|
|
10
|
+
import { createTrackingBlocker } from '../tracking-blocker';
|
|
11
|
+
|
|
12
|
+
const BLOCKED_CONSENT = {
|
|
13
|
+
experience: false,
|
|
14
|
+
functionality: false,
|
|
15
|
+
marketing: false,
|
|
16
|
+
measurement: false,
|
|
17
|
+
necessary: true,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const ALLOWED_CONSENT = {
|
|
21
|
+
...BLOCKED_CONSENT,
|
|
22
|
+
measurement: true,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
describe('TrackingBlocker', () => {
|
|
26
|
+
// Store original globals
|
|
27
|
+
const originalFetch = global.fetch;
|
|
28
|
+
const originalXHR = global.XMLHttpRequest;
|
|
29
|
+
|
|
30
|
+
// Set up test environment before all tests
|
|
31
|
+
beforeAll(() => {
|
|
32
|
+
// Mock fetch to simulate a successful response
|
|
33
|
+
global.fetch = vi
|
|
34
|
+
.fn()
|
|
35
|
+
.mockImplementation(() => Promise.resolve(new Response()));
|
|
36
|
+
|
|
37
|
+
// We'll use the real XMLHttpRequest instead of mocking it
|
|
38
|
+
if (!global.XMLHttpRequest) {
|
|
39
|
+
global.XMLHttpRequest = originalXHR;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Clean up test environment after all tests
|
|
44
|
+
afterAll(() => {
|
|
45
|
+
// Restore globals
|
|
46
|
+
global.fetch = originalFetch;
|
|
47
|
+
global.XMLHttpRequest = originalXHR;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
// Reset all mocks and spies
|
|
52
|
+
vi.clearAllMocks();
|
|
53
|
+
vi.restoreAllMocks();
|
|
54
|
+
|
|
55
|
+
// Reset fetch to a fresh mock for each test
|
|
56
|
+
global.fetch = vi
|
|
57
|
+
.fn()
|
|
58
|
+
.mockImplementation(() => Promise.resolve(new Response()));
|
|
59
|
+
window.fetch = global.fetch;
|
|
60
|
+
|
|
61
|
+
// Reset XMLHttpRequest to original
|
|
62
|
+
window.XMLHttpRequest = originalXHR;
|
|
63
|
+
|
|
64
|
+
// Mock document.dispatchEvent since it's not included in the global setup
|
|
65
|
+
vi.spyOn(document, 'dispatchEvent');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('blocks fetch requests to tracking domains when consent not granted', async () => {
|
|
69
|
+
// Create tracking blocker with default consents (all false except necessary)
|
|
70
|
+
const trackingBlocker = createTrackingBlocker({}, BLOCKED_CONSENT);
|
|
71
|
+
|
|
72
|
+
// Try to fetch from a tracking domain (Google Analytics)
|
|
73
|
+
await expect(
|
|
74
|
+
fetch('https://www.google-analytics.com/analytics.js')
|
|
75
|
+
).rejects.toThrow(
|
|
76
|
+
'Request to https://www.google-analytics.com/analytics.js blocked due to missing consent'
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Verify blocked event was dispatched
|
|
80
|
+
expect(document.dispatchEvent).toHaveBeenCalledWith(
|
|
81
|
+
expect.objectContaining({
|
|
82
|
+
type: 'ConsentBlockedRequest',
|
|
83
|
+
detail: {
|
|
84
|
+
url: 'https://www.google-analytics.com/analytics.js',
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('blocks XMLHttpRequest to tracking domains when consent not granted', () => {
|
|
91
|
+
// Create tracking blocker with default consents
|
|
92
|
+
const trackingBlocker = createTrackingBlocker({}, BLOCKED_CONSENT);
|
|
93
|
+
// Create new XMLHttpRequest
|
|
94
|
+
const xhr = new XMLHttpRequest();
|
|
95
|
+
|
|
96
|
+
// Try to open request to tracking domain
|
|
97
|
+
expect(() => {
|
|
98
|
+
xhr.open('GET', 'https://www.google-analytics.com/analytics.js');
|
|
99
|
+
}).toThrow(
|
|
100
|
+
'Request to https://www.google-analytics.com/analytics.js blocked due to missing consent'
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Verify blocked event was dispatched
|
|
104
|
+
expect(document.dispatchEvent).toHaveBeenCalledWith(
|
|
105
|
+
expect.objectContaining({
|
|
106
|
+
type: 'ConsentBlockedRequest',
|
|
107
|
+
detail: {
|
|
108
|
+
url: 'https://www.google-analytics.com/analytics.js',
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('allows fetch requests to tracking domains after consent granted', async () => {
|
|
115
|
+
// Reset fetch to ensure we start with a clean state
|
|
116
|
+
window.fetch = global.fetch;
|
|
117
|
+
|
|
118
|
+
// Create tracking blocker with consent granted
|
|
119
|
+
const trackingBlocker = createTrackingBlocker({}, ALLOWED_CONSENT);
|
|
120
|
+
|
|
121
|
+
// Create a spy on window.fetch after tracking blocker has overridden it
|
|
122
|
+
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
123
|
+
|
|
124
|
+
// Try fetch request - should now be allowed
|
|
125
|
+
await fetch('https://www.google-analytics.com/analytics.js');
|
|
126
|
+
|
|
127
|
+
// Verify fetch was called with correct URL
|
|
128
|
+
expect(fetchSpy).toHaveBeenCalledWith(
|
|
129
|
+
'https://www.google-analytics.com/analytics.js'
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Clean up
|
|
133
|
+
trackingBlocker.destroy();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('allows XMLHttpRequest to tracking domains after consent granted', () => {
|
|
137
|
+
// Create tracking blocker with default consents
|
|
138
|
+
const trackingBlocker = createTrackingBlocker({}, ALLOWED_CONSENT);
|
|
139
|
+
|
|
140
|
+
// Create new XMLHttpRequest
|
|
141
|
+
const xhr = new XMLHttpRequest();
|
|
142
|
+
|
|
143
|
+
// Should not throw error now that consent is granted
|
|
144
|
+
expect(() => {
|
|
145
|
+
xhr.open('GET', 'https://www.google-analytics.com/analytics.js');
|
|
146
|
+
}).not.toThrow();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('allows requests to non-tracking domains regardless of consent', async () => {
|
|
150
|
+
const trackingBlocker = createTrackingBlocker({}, BLOCKED_CONSENT);
|
|
151
|
+
|
|
152
|
+
// Try fetch to non-tracking domain
|
|
153
|
+
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
154
|
+
await fetch('https://api.example.com/data');
|
|
155
|
+
expect(fetchSpy).toHaveBeenCalledWith('https://api.example.com/data');
|
|
156
|
+
|
|
157
|
+
// Try XMLHttpRequest to non-tracking domain
|
|
158
|
+
const xhr = new XMLHttpRequest();
|
|
159
|
+
expect(() => {
|
|
160
|
+
xhr.open('GET', 'https://api.example.com/data');
|
|
161
|
+
}).not.toThrow();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test('handles custom domain consent map', async () => {
|
|
165
|
+
// Create tracking blocker with custom domain map
|
|
166
|
+
const trackingBlocker = createTrackingBlocker(
|
|
167
|
+
{
|
|
168
|
+
overrideDomainConsentMap: true,
|
|
169
|
+
domainConsentMap: {
|
|
170
|
+
'custom-analytics.example.com': 'measurement',
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
BLOCKED_CONSENT
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Should block request to custom domain
|
|
177
|
+
await expect(
|
|
178
|
+
fetch('https://custom-analytics.example.com/track')
|
|
179
|
+
).rejects.toThrow(
|
|
180
|
+
'Request to https://custom-analytics.example.com/track blocked due to missing consent'
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// Update consent
|
|
184
|
+
trackingBlocker.updateConsents({
|
|
185
|
+
experience: false,
|
|
186
|
+
functionality: false,
|
|
187
|
+
marketing: false,
|
|
188
|
+
measurement: true,
|
|
189
|
+
necessary: true,
|
|
190
|
+
});
|
|
191
|
+
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
192
|
+
|
|
193
|
+
// Should now allow request
|
|
194
|
+
await fetch('https://custom-analytics.example.com/track');
|
|
195
|
+
expect(fetchSpy).toHaveBeenCalledWith(
|
|
196
|
+
'https://custom-analytics.example.com/track'
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('handles subdomains correctly', async () => {
|
|
201
|
+
const trackingBlocker = createTrackingBlocker({}, BLOCKED_CONSENT);
|
|
202
|
+
|
|
203
|
+
// Should block request to subdomain of google-analytics.com
|
|
204
|
+
await expect(
|
|
205
|
+
fetch('https://subdomain.google-analytics.com/track')
|
|
206
|
+
).rejects.toThrow(
|
|
207
|
+
'Request to https://subdomain.google-analytics.com/track blocked due to missing consent'
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('can be disabled via config', async () => {
|
|
212
|
+
// Create tracking blocker with automatic blocking disabled
|
|
213
|
+
const trackingBlocker = createTrackingBlocker(
|
|
214
|
+
{
|
|
215
|
+
disableAutomaticBlocking: true,
|
|
216
|
+
},
|
|
217
|
+
BLOCKED_CONSENT
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// Should allow all requests regardless of consent
|
|
221
|
+
await fetch('https://www.google-analytics.com/analytics.js');
|
|
222
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
223
|
+
'https://www.google-analytics.com/analytics.js'
|
|
224
|
+
);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test('cleanup restores original fetch and XMLHttpRequest functionality', async () => {
|
|
228
|
+
// Create tracking blocker which should wrap the implementations
|
|
229
|
+
const trackingBlocker = createTrackingBlocker({}, BLOCKED_CONSENT);
|
|
230
|
+
|
|
231
|
+
// Verify tracking is active by trying a blocked request
|
|
232
|
+
await expect(
|
|
233
|
+
fetch('https://www.google-analytics.com/analytics.js')
|
|
234
|
+
).rejects.toThrow();
|
|
235
|
+
|
|
236
|
+
// Destroy tracking blocker
|
|
237
|
+
trackingBlocker.destroy();
|
|
238
|
+
|
|
239
|
+
// After cleanup, the blocked request should work
|
|
240
|
+
await fetch('https://www.google-analytics.com/analytics.js');
|
|
241
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
242
|
+
'https://www.google-analytics.com/analytics.js'
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
// Verify XMLHttpRequest also works after cleanup
|
|
246
|
+
const xhr = new XMLHttpRequest();
|
|
247
|
+
expect(() => {
|
|
248
|
+
xhr.open('GET', 'https://www.google-analytics.com/analytics.js');
|
|
249
|
+
}).not.toThrow();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test('handles multiple concurrent requests correctly', async () => {
|
|
253
|
+
createTrackingBlocker({}, BLOCKED_CONSENT);
|
|
254
|
+
|
|
255
|
+
// Create multiple concurrent requests
|
|
256
|
+
const requests = Promise.all([
|
|
257
|
+
expect(
|
|
258
|
+
fetch('https://www.google-analytics.com/analytics.js')
|
|
259
|
+
).rejects.toThrow(),
|
|
260
|
+
expect(
|
|
261
|
+
fetch('https://www.google-analytics.com/collect')
|
|
262
|
+
).rejects.toThrow(),
|
|
263
|
+
fetch('https://api.example.com/data'), // Should succeed
|
|
264
|
+
]);
|
|
265
|
+
await requests;
|
|
266
|
+
|
|
267
|
+
// Verify correct number of blocked events
|
|
268
|
+
// 6 blocked events for the 3 requests due to retries
|
|
269
|
+
expect(document.dispatchEvent).toHaveBeenCalledTimes(6);
|
|
270
|
+
});
|
|
271
|
+
});
|