@el7ven/cookie-kit 0.2.21 → 0.3.2
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/package.json +21 -1
- package/src/core/AnalyticsManager.js +400 -0
- package/src/core/ConsentManager.js +710 -0
- package/src/core/ConsentMode.js +109 -0
- package/src/core/FocusTrap.js +130 -0
- package/src/core/GeoDetector.js +144 -0
- package/src/core/ScriptLoader.js +229 -0
- package/src/core/StorageAdapter.js +179 -0
- package/src/core/analytics.js +101 -10
- package/src/core/index.js +7 -7
- package/src/geo/GeoDetector.js +536 -0
- package/src/geo/RegionRules.js +126 -0
- package/src/geo/index.js +16 -0
- package/src/index.js +56 -18
- package/src/js/CookieConsent.js +0 -1
- package/src/locales/en.js +54 -0
- package/src/locales/index.js +20 -0
- package/src/locales/ro.js +54 -0
- package/src/plugins/CMPPlugin.js +187 -0
- package/src/plugins/PluginManager.js +234 -0
- package/src/plugins/index.js +7 -0
- package/src/providers/GoogleConsentModeProvider.js +278 -0
- package/src/providers/index.js +6 -0
- package/src/rewriting/ScriptRewriter.js +278 -0
- package/src/rewriting/index.js +6 -0
- package/src/scripts/ScriptLoader.js +310 -0
- package/src/scripts/ScriptManager.js +278 -0
- package/src/scripts/ScriptRegistry.js +175 -0
- package/src/scripts/ScriptScanner.js +178 -0
- package/src/scripts/index.js +9 -0
- package/src/trackers/TrackerDetector.js +488 -0
- package/src/trackers/TrackerPatterns.js +307 -0
- package/src/trackers/TrackerRegistry.js +172 -0
- package/src/trackers/index.js +15 -0
- package/src/utils/cookies.js +37 -0
- package/src/utils/dom.js +58 -0
- package/src/utils/helpers.js +89 -0
- package/src/vue/CookieConsent.vue +1 -1
- package/src/vue/CookieDrawer.vue +4 -4
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ScriptRegistry — stores and manages discovered scripts
|
|
3
|
+
* @module ScriptRegistry
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class ScriptRegistry {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.scripts = new Map() // id -> script descriptor
|
|
9
|
+
this.categorizedScripts = new Map() // category -> [scripts]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Add script to registry
|
|
14
|
+
* @param {Object} script - Script descriptor
|
|
15
|
+
*/
|
|
16
|
+
add(script) {
|
|
17
|
+
if (!script.id) return
|
|
18
|
+
|
|
19
|
+
// Store by id
|
|
20
|
+
this.scripts.set(script.id, script)
|
|
21
|
+
|
|
22
|
+
// Store by category
|
|
23
|
+
if (script.category) {
|
|
24
|
+
if (!this.categorizedScripts.has(script.category)) {
|
|
25
|
+
this.categorizedScripts.set(script.category, [])
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const categoryScripts = this.categorizedScripts.get(script.category)
|
|
29
|
+
if (!categoryScripts.find(s => s.id === script.id)) {
|
|
30
|
+
categoryScripts.push(script)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Add multiple scripts
|
|
37
|
+
* @param {Array} scripts - Array of script descriptors
|
|
38
|
+
*/
|
|
39
|
+
addMany(scripts) {
|
|
40
|
+
scripts.forEach(script => this.add(script))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get script by id
|
|
45
|
+
* @param {string} id - Script id
|
|
46
|
+
* @returns {Object|null}
|
|
47
|
+
*/
|
|
48
|
+
get(id) {
|
|
49
|
+
return this.scripts.get(id) || null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get all scripts
|
|
54
|
+
* @returns {Array}
|
|
55
|
+
*/
|
|
56
|
+
getAll() {
|
|
57
|
+
return Array.from(this.scripts.values())
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get scripts by category
|
|
62
|
+
* @param {string} category - Category name
|
|
63
|
+
* @returns {Array}
|
|
64
|
+
*/
|
|
65
|
+
getByCategory(category) {
|
|
66
|
+
return this.categorizedScripts.get(category) || []
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get all categories
|
|
71
|
+
* @returns {Array}
|
|
72
|
+
*/
|
|
73
|
+
getCategories() {
|
|
74
|
+
return Array.from(this.categorizedScripts.keys())
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get blocked scripts (not yet activated)
|
|
79
|
+
* @returns {Array}
|
|
80
|
+
*/
|
|
81
|
+
getBlocked() {
|
|
82
|
+
return this.getAll().filter(script => script.isBlocked && !script.isActivated)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get activated scripts
|
|
87
|
+
* @returns {Array}
|
|
88
|
+
*/
|
|
89
|
+
getActivated() {
|
|
90
|
+
return this.getAll().filter(script => script.isActivated)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Mark script as activated
|
|
95
|
+
* @param {string} id - Script id
|
|
96
|
+
*/
|
|
97
|
+
markActivated(id) {
|
|
98
|
+
const script = this.scripts.get(id)
|
|
99
|
+
if (script) {
|
|
100
|
+
script.isActivated = true
|
|
101
|
+
script.activatedAt = new Date().toISOString()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Remove script from registry
|
|
107
|
+
* @param {string} id - Script id
|
|
108
|
+
*/
|
|
109
|
+
remove(id) {
|
|
110
|
+
const script = this.scripts.get(id)
|
|
111
|
+
if (!script) return
|
|
112
|
+
|
|
113
|
+
// Remove from main map
|
|
114
|
+
this.scripts.delete(id)
|
|
115
|
+
|
|
116
|
+
// Remove from category map
|
|
117
|
+
if (script.category) {
|
|
118
|
+
const categoryScripts = this.categorizedScripts.get(script.category)
|
|
119
|
+
if (categoryScripts) {
|
|
120
|
+
const index = categoryScripts.findIndex(s => s.id === id)
|
|
121
|
+
if (index !== -1) {
|
|
122
|
+
categoryScripts.splice(index, 1)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Clear all scripts
|
|
130
|
+
*/
|
|
131
|
+
clear() {
|
|
132
|
+
this.scripts.clear()
|
|
133
|
+
this.categorizedScripts.clear()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get registry stats
|
|
138
|
+
* @returns {Object}
|
|
139
|
+
*/
|
|
140
|
+
getStats() {
|
|
141
|
+
const all = this.getAll()
|
|
142
|
+
return {
|
|
143
|
+
total: all.length,
|
|
144
|
+
blocked: all.filter(s => s.isBlocked && !s.isActivated).length,
|
|
145
|
+
activated: all.filter(s => s.isActivated).length,
|
|
146
|
+
byCategory: Object.fromEntries(
|
|
147
|
+
Array.from(this.categorizedScripts.entries()).map(([cat, scripts]) => [
|
|
148
|
+
cat,
|
|
149
|
+
{
|
|
150
|
+
total: scripts.length,
|
|
151
|
+
blocked: scripts.filter(s => s.isBlocked && !s.isActivated).length,
|
|
152
|
+
activated: scripts.filter(s => s.isActivated).length
|
|
153
|
+
}
|
|
154
|
+
])
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Check if script exists
|
|
161
|
+
* @param {string} id - Script id
|
|
162
|
+
* @returns {boolean}
|
|
163
|
+
*/
|
|
164
|
+
has(id) {
|
|
165
|
+
return this.scripts.has(id)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Get count of scripts
|
|
170
|
+
* @returns {number}
|
|
171
|
+
*/
|
|
172
|
+
count() {
|
|
173
|
+
return this.scripts.size
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ScriptScanner — scans DOM for blocked scripts with data-cookie-category
|
|
3
|
+
* @module ScriptScanner
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class ScriptScanner {
|
|
7
|
+
constructor(config = {}) {
|
|
8
|
+
this.config = {
|
|
9
|
+
attributeName: 'data-cookie-category',
|
|
10
|
+
srcAttributeName: 'data-cookie-src',
|
|
11
|
+
blockedTypes: ['text/plain', 'text/blocked'],
|
|
12
|
+
scanOnInit: true,
|
|
13
|
+
observeDOM: true,
|
|
14
|
+
scanIframes: true,
|
|
15
|
+
...config
|
|
16
|
+
}
|
|
17
|
+
this.observer = null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Scan DOM for blocked scripts
|
|
22
|
+
* @returns {Array} Array of script descriptors
|
|
23
|
+
*/
|
|
24
|
+
scan() {
|
|
25
|
+
const items = []
|
|
26
|
+
|
|
27
|
+
// Find all script tags with data-cookie-category
|
|
28
|
+
const scriptElements = document.querySelectorAll(`script[${this.config.attributeName}]`)
|
|
29
|
+
|
|
30
|
+
scriptElements.forEach((element, index) => {
|
|
31
|
+
const category = element.getAttribute(this.config.attributeName)
|
|
32
|
+
const type = element.getAttribute('type')
|
|
33
|
+
const isBlocked = this.config.blockedTypes.includes(type)
|
|
34
|
+
|
|
35
|
+
// Pre-blocking: use data-cookie-src instead of src
|
|
36
|
+
const cookieSrc = element.getAttribute(this.config.srcAttributeName)
|
|
37
|
+
const regularSrc = element.getAttribute('src')
|
|
38
|
+
const actualSrc = cookieSrc || regularSrc
|
|
39
|
+
|
|
40
|
+
const descriptor = {
|
|
41
|
+
id: `script-${index}-${Date.now()}`,
|
|
42
|
+
elementType: 'script',
|
|
43
|
+
element,
|
|
44
|
+
category,
|
|
45
|
+
type: type || 'text/javascript',
|
|
46
|
+
src: actualSrc || null,
|
|
47
|
+
cookieSrc: cookieSrc || null,
|
|
48
|
+
inline: !actualSrc,
|
|
49
|
+
content: !actualSrc ? element.textContent : null,
|
|
50
|
+
isBlocked,
|
|
51
|
+
isActivated: false,
|
|
52
|
+
attributes: this._getAttributes(element)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
items.push(descriptor)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
// Scan iframes if enabled
|
|
59
|
+
if (this.config.scanIframes) {
|
|
60
|
+
const iframeElements = document.querySelectorAll(`iframe[${this.config.attributeName}]`)
|
|
61
|
+
|
|
62
|
+
iframeElements.forEach((element, index) => {
|
|
63
|
+
const category = element.getAttribute(this.config.attributeName)
|
|
64
|
+
const cookieSrc = element.getAttribute(this.config.srcAttributeName)
|
|
65
|
+
const regularSrc = element.getAttribute('src')
|
|
66
|
+
const actualSrc = cookieSrc || regularSrc
|
|
67
|
+
|
|
68
|
+
const descriptor = {
|
|
69
|
+
id: `iframe-${index}-${Date.now()}`,
|
|
70
|
+
elementType: 'iframe',
|
|
71
|
+
element,
|
|
72
|
+
category,
|
|
73
|
+
src: actualSrc || null,
|
|
74
|
+
cookieSrc: cookieSrc || null,
|
|
75
|
+
isBlocked: true, // iframes always blocked until consent
|
|
76
|
+
isActivated: false,
|
|
77
|
+
attributes: this._getAttributes(element)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
items.push(descriptor)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return items
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Start observing DOM for new scripts
|
|
89
|
+
* @param {Function} callback - Called when new scripts detected
|
|
90
|
+
*/
|
|
91
|
+
observe(callback) {
|
|
92
|
+
if (!this.config.observeDOM || typeof MutationObserver === 'undefined') {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this.observer = new MutationObserver((mutations) => {
|
|
97
|
+
let hasNewScripts = false
|
|
98
|
+
|
|
99
|
+
mutations.forEach((mutation) => {
|
|
100
|
+
mutation.addedNodes.forEach((node) => {
|
|
101
|
+
if (node.nodeType === 1) { // Element node
|
|
102
|
+
// Check if added node is a script
|
|
103
|
+
if (node.tagName === 'SCRIPT' && node.hasAttribute(this.config.attributeName)) {
|
|
104
|
+
hasNewScripts = true
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Check if added node contains scripts
|
|
108
|
+
const scripts = node.querySelectorAll?.(`script[${this.config.attributeName}]`)
|
|
109
|
+
if (scripts?.length > 0) {
|
|
110
|
+
hasNewScripts = true
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
if (hasNewScripts) {
|
|
117
|
+
const newScripts = this.scan()
|
|
118
|
+
callback(newScripts)
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
this.observer.observe(document.documentElement, {
|
|
123
|
+
childList: true,
|
|
124
|
+
subtree: true
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Stop observing DOM
|
|
130
|
+
*/
|
|
131
|
+
disconnect() {
|
|
132
|
+
if (this.observer) {
|
|
133
|
+
this.observer.disconnect()
|
|
134
|
+
this.observer = null
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get all attributes from element (except data-cookie-category)
|
|
140
|
+
* @private
|
|
141
|
+
*/
|
|
142
|
+
_getAttributes(element) {
|
|
143
|
+
const attributes = {}
|
|
144
|
+
const excludeAttrs = [
|
|
145
|
+
this.config.attributeName,
|
|
146
|
+
this.config.srcAttributeName,
|
|
147
|
+
'type',
|
|
148
|
+
'src' // Exclude src to prevent early execution
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
Array.from(element.attributes).forEach((attr) => {
|
|
152
|
+
if (!excludeAttrs.includes(attr.name)) {
|
|
153
|
+
attributes[attr.name] = attr.value
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
return attributes
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Find scripts by category
|
|
162
|
+
* @param {string} category - Category name
|
|
163
|
+
* @returns {Array} Filtered scripts
|
|
164
|
+
*/
|
|
165
|
+
findByCategory(category) {
|
|
166
|
+
return this.scan().filter(script => script.category === category)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Check if script should be blocked
|
|
171
|
+
* @param {HTMLScriptElement} element - Script element
|
|
172
|
+
* @returns {boolean}
|
|
173
|
+
*/
|
|
174
|
+
isBlocked(element) {
|
|
175
|
+
const type = element.getAttribute('type')
|
|
176
|
+
return this.config.blockedTypes.includes(type)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Script Management System — Auto-blocking scripts (Cookiebot-style)
|
|
3
|
+
* @module scripts
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { ScriptScanner } from './ScriptScanner.js'
|
|
7
|
+
export { ScriptRegistry } from './ScriptRegistry.js'
|
|
8
|
+
export { ScriptLoader } from './ScriptLoader.js'
|
|
9
|
+
export { ScriptManager } from './ScriptManager.js'
|