@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.
Files changed (39) hide show
  1. package/package.json +21 -1
  2. package/src/core/AnalyticsManager.js +400 -0
  3. package/src/core/ConsentManager.js +710 -0
  4. package/src/core/ConsentMode.js +109 -0
  5. package/src/core/FocusTrap.js +130 -0
  6. package/src/core/GeoDetector.js +144 -0
  7. package/src/core/ScriptLoader.js +229 -0
  8. package/src/core/StorageAdapter.js +179 -0
  9. package/src/core/analytics.js +101 -10
  10. package/src/core/index.js +7 -7
  11. package/src/geo/GeoDetector.js +536 -0
  12. package/src/geo/RegionRules.js +126 -0
  13. package/src/geo/index.js +16 -0
  14. package/src/index.js +56 -18
  15. package/src/js/CookieConsent.js +0 -1
  16. package/src/locales/en.js +54 -0
  17. package/src/locales/index.js +20 -0
  18. package/src/locales/ro.js +54 -0
  19. package/src/plugins/CMPPlugin.js +187 -0
  20. package/src/plugins/PluginManager.js +234 -0
  21. package/src/plugins/index.js +7 -0
  22. package/src/providers/GoogleConsentModeProvider.js +278 -0
  23. package/src/providers/index.js +6 -0
  24. package/src/rewriting/ScriptRewriter.js +278 -0
  25. package/src/rewriting/index.js +6 -0
  26. package/src/scripts/ScriptLoader.js +310 -0
  27. package/src/scripts/ScriptManager.js +278 -0
  28. package/src/scripts/ScriptRegistry.js +175 -0
  29. package/src/scripts/ScriptScanner.js +178 -0
  30. package/src/scripts/index.js +9 -0
  31. package/src/trackers/TrackerDetector.js +488 -0
  32. package/src/trackers/TrackerPatterns.js +307 -0
  33. package/src/trackers/TrackerRegistry.js +172 -0
  34. package/src/trackers/index.js +15 -0
  35. package/src/utils/cookies.js +37 -0
  36. package/src/utils/dom.js +58 -0
  37. package/src/utils/helpers.js +89 -0
  38. package/src/vue/CookieConsent.vue +1 -1
  39. package/src/vue/CookieDrawer.vue +4 -4
package/src/index.js CHANGED
@@ -1,38 +1,80 @@
1
1
  /**
2
2
  * @el7ven/cookie-kit - Unified Cookie Consent Management
3
3
  * GDPR compliant cookie consent with React and Vue support
4
- * @version 1.0.0-beta.0
4
+ * @version 0.4.0
5
5
  * @author Igor Semionov
6
6
  */
7
7
 
8
- // Core functionality
8
+ // ─── Core (lite) ───
9
9
  export { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
10
10
 
11
- // Analytics integration
12
- export { createAnalyticsManager, initGoogleConsentMode, updateGoogleConsent, loadGTM, loadGA4, loadMetaPixel, loadYandexMetrica, manageScriptBlocking } from './core/analytics.js'
11
+ // ─── Core (full) ───
12
+ export { ConsentManager } from './core/ConsentManager.js'
13
+ export { StorageAdapter } from './core/StorageAdapter.js'
14
+ export { ConsentMode, CONSENT_MODE_DEFAULTS, CATEGORY_MAPPING } from './core/ConsentMode.js'
15
+ export { FocusTrap } from './core/FocusTrap.js'
16
+ export { ScriptLoader } from './core/ScriptLoader.js'
17
+ export { AnalyticsManager, ANALYTICS_PROVIDERS } from './core/AnalyticsManager.js'
18
+ export { GeoDetector as CoreGeoDetector } from './core/GeoDetector.js'
13
19
 
14
- // Import for default export
20
+ // ─── Analytics helpers ───
21
+ export { createAnalyticsManager, initGoogleConsentMode, updateGoogleConsent, loadGTM, loadGA4, loadMetaPixel, loadYandexMetrica, blockScriptsBeforeConsent, unblockConsentedScripts, manageScriptBlocking } from './core/analytics.js'
22
+
23
+ // ─── Geo detection ───
24
+ export { GeoDetector } from './geo/GeoDetector.js'
25
+ export { REGION_RULES, isEU, isEEA, isUK, requiresGDPR, getRegion, requiresConsentBanner, getRegulation, isEssentialOnly } from './geo/RegionRules.js'
26
+
27
+ // ─── Locales / i18n ───
28
+ export { locales, getLocale } from './locales/index.js'
29
+
30
+ // ─── Providers ───
31
+ export { GoogleConsentModeProvider } from './providers/GoogleConsentModeProvider.js'
32
+
33
+ // ─── Plugins ───
34
+ export { CMPPlugin } from './plugins/CMPPlugin.js'
35
+ export { PluginManager } from './plugins/PluginManager.js'
36
+
37
+ // ─── Trackers ───
38
+ export { TrackerDetector } from './trackers/TrackerDetector.js'
39
+ export { TrackerRegistry } from './trackers/TrackerRegistry.js'
40
+
41
+ // ─── Script rewriting ───
42
+ export { ScriptRewriter } from './rewriting/ScriptRewriter.js'
43
+
44
+ // ─── Scripts (advanced) ───
45
+ export { ScriptLoader as AdvancedScriptLoader } from './scripts/ScriptLoader.js'
46
+ export { ScriptManager } from './scripts/ScriptManager.js'
47
+ export { ScriptRegistry } from './scripts/ScriptRegistry.js'
48
+ export { ScriptScanner } from './scripts/ScriptScanner.js'
49
+
50
+ // ─── Utils ───
51
+ export { getCookie, setCookie, deleteCookie, getAllCookies } from './utils/cookies.js'
52
+ export { getFocusableElements, trapFocus, lockBodyScroll, unlockBodyScroll, onEscape } from './utils/dom.js'
53
+ export { generateUUID, debounce, throttle, deepMerge, isSSR, isMobile, getRegionFromTimezone } from './utils/helpers.js'
54
+
55
+ // ─── Imports for default export ───
15
56
  import { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
16
57
  import { createAnalyticsManager } from './core/analytics.js'
58
+ import { ConsentManager } from './core/ConsentManager.js'
17
59
  import { initCookieKit } from './js/index.js'
18
60
  import { VERSION } from './core/version.js'
19
61
 
20
- // Vanilla JS components
62
+ // ─── Vanilla JS components ───
21
63
  export { initCookieKit, mountCookieConsent } from './js/index.js'
22
64
 
23
- // React components
65
+ // ─── React components ───
24
66
  export * from './react/index.js'
25
67
 
26
- // Vue components
68
+ // ─── Vue components ───
27
69
  export * from './vue/index.js'
28
70
 
29
- // Vue composable
71
+ // ─── Vue composable ───
30
72
  export { useCookieConsent } from './vue/composables/useCookieConsent.js'
31
73
 
32
- // Version info
74
+ // ─── Version info ───
33
75
  export { VERSION, getVersion, getVersionInfo, logVersion } from './core/version.js'
34
76
 
35
- // Unified factory function
77
+ // ─── Unified factory ───
36
78
  export function createCookieConsent(config = {}) {
37
79
  const { framework = 'js', ...restConfig } = config
38
80
 
@@ -46,23 +88,18 @@ export function createCookieConsent(config = {}) {
46
88
  }
47
89
  }
48
90
 
49
- // Auto-detect framework and create appropriate instance
91
+ // Auto-detect framework
50
92
  export function autoCookieConsent(config = {}) {
51
- // Detect React
52
93
  if (typeof window !== 'undefined' && window.React) {
53
94
  return createCookieConsent({ ...config, framework: 'react' })
54
95
  }
55
-
56
- // Detect Vue
57
96
  if (typeof window !== 'undefined' && window.Vue) {
58
97
  return createCookieConsent({ ...config, framework: 'vue' })
59
98
  }
60
-
61
- // Default to vanilla JS
62
99
  return createCookieConsent({ ...config, framework: 'js' })
63
100
  }
64
101
 
65
- // Default export for convenience
102
+ // Default export
66
103
  export default {
67
104
  createCookieKit,
68
105
  createCookieConsent,
@@ -70,6 +107,7 @@ export default {
70
107
  autoCookieConsent,
71
108
  initCookieKit,
72
109
  CookieKitCore,
110
+ ConsentManager,
73
111
  DEFAULT_CONFIG,
74
112
  VERSION
75
113
  }
@@ -386,7 +386,6 @@ class CookieConsent extends HTMLElement {
386
386
  /* Header */
387
387
  .cookie-drawer__header {
388
388
  padding: 24px 24px 16px;
389
- border-bottom: 1px solid var(--ck-border);
390
389
  display: flex;
391
390
  justify-content: space-between;
392
391
  align-items: flex-start;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * English translations
3
+ */
4
+
5
+ export default {
6
+ essential: {
7
+ title: 'Cookies',
8
+ message: 'We use cookies to improve your experience on our site.',
9
+ button: 'I understand'
10
+ },
11
+ gdpr: {
12
+ title: 'Cookie Preferences',
13
+ message: 'We use cookies to provide you with the best experience. Choose which types of cookies you accept.',
14
+ buttons: {
15
+ acceptAll: 'Accept all',
16
+ rejectAll: 'Reject all',
17
+ acceptSelection: 'Accept selection',
18
+ settings: 'Settings'
19
+ }
20
+ },
21
+ settings: {
22
+ title: 'Cookie Settings',
23
+ tabs: {
24
+ privacy: 'Privacy'
25
+ },
26
+ buttons: {
27
+ acceptAll: 'Accept all',
28
+ rejectAll: 'Reject all',
29
+ acceptSelection: 'Save selection'
30
+ },
31
+ links: {
32
+ moreInfo: 'More information',
33
+ cookieDetails: 'Cookie details'
34
+ }
35
+ },
36
+ categories: {
37
+ necessary: {
38
+ label: 'Necessary',
39
+ description: 'Essential cookies for site functionality'
40
+ },
41
+ analytics: {
42
+ label: 'Analytics',
43
+ description: 'Cookies for traffic and user behavior analysis'
44
+ },
45
+ marketing: {
46
+ label: 'Marketing',
47
+ description: 'Cookies for personalized advertising'
48
+ },
49
+ preferences: {
50
+ label: 'Preferences',
51
+ description: 'Cookies for saving user preferences'
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * i18n support for cookie consent
3
+ */
4
+
5
+ import en from './en.js'
6
+ import ro from './ro.js'
7
+
8
+ export const locales = {
9
+ en,
10
+ ro
11
+ }
12
+
13
+ export function getLocale(lang = 'ro') {
14
+ return locales[lang] || locales.ro
15
+ }
16
+
17
+ export default {
18
+ locales,
19
+ getLocale
20
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Romanian translations
3
+ */
4
+
5
+ export default {
6
+ essential: {
7
+ title: 'Cookie-uri',
8
+ message: 'Folosim cookie-uri pentru a îmbunătăți experiența ta pe site.',
9
+ button: 'Am înțeles'
10
+ },
11
+ gdpr: {
12
+ title: 'Preferințe Cookie-uri',
13
+ message: 'Folosim cookie-uri pentru a-ți oferi cea mai bună experiență. Alege ce tipuri de cookie-uri accepți.',
14
+ buttons: {
15
+ acceptAll: 'Acceptă toate',
16
+ rejectAll: 'Respinge toate',
17
+ acceptSelection: 'Acceptă selecția',
18
+ settings: 'Setări'
19
+ }
20
+ },
21
+ settings: {
22
+ title: 'Setări Cookie-uri',
23
+ tabs: {
24
+ privacy: 'Confidențialitate'
25
+ },
26
+ buttons: {
27
+ acceptAll: 'Acceptă toate',
28
+ rejectAll: 'Respinge toate',
29
+ acceptSelection: 'Salvează selecția'
30
+ },
31
+ links: {
32
+ moreInfo: 'Mai multe informații',
33
+ cookieDetails: 'Detalii cookie-uri'
34
+ }
35
+ },
36
+ categories: {
37
+ necessary: {
38
+ label: 'Necesare',
39
+ description: 'Cookie-uri esențiale pentru funcționarea site-ului'
40
+ },
41
+ analytics: {
42
+ label: 'Analiză',
43
+ description: 'Cookie-uri pentru analiza traficului și comportamentului utilizatorilor'
44
+ },
45
+ marketing: {
46
+ label: 'Marketing',
47
+ description: 'Cookie-uri pentru publicitate personalizată'
48
+ },
49
+ preferences: {
50
+ label: 'Preferințe',
51
+ description: 'Cookie-uri pentru salvarea preferințelor utilizatorului'
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * CMP Plugin Base Class
3
+ * @module CMPPlugin
4
+ *
5
+ * Base class for all CMP plugins
6
+ * Plugins can extend CMP functionality without modifying core
7
+ */
8
+
9
+ export class CMPPlugin {
10
+ constructor(config = {}) {
11
+ this.config = config
12
+ this.cmp = null
13
+ this.isInitialized = false
14
+ }
15
+
16
+ /**
17
+ * Get plugin name
18
+ * @returns {string}
19
+ */
20
+ get name() {
21
+ return this.constructor.name
22
+ }
23
+
24
+ /**
25
+ * Get plugin version
26
+ * @returns {string}
27
+ */
28
+ get version() {
29
+ return '1.0.0'
30
+ }
31
+
32
+ /**
33
+ * Initialize plugin
34
+ * Called when plugin is registered
35
+ * @param {Object} cmpInstance - CMP instance
36
+ */
37
+ init(cmpInstance) {
38
+ this.cmp = cmpInstance
39
+ this.isInitialized = true
40
+ this._debug('Plugin initialized')
41
+ }
42
+
43
+ /**
44
+ * Lifecycle: Before CMP initialization
45
+ */
46
+ beforeInit() {
47
+ // Override in subclass
48
+ }
49
+
50
+ /**
51
+ * Lifecycle: After CMP initialization
52
+ */
53
+ afterInit() {
54
+ // Override in subclass
55
+ }
56
+
57
+ /**
58
+ * Lifecycle: Before consent banner shown
59
+ */
60
+ beforeBannerShow() {
61
+ // Override in subclass
62
+ }
63
+
64
+ /**
65
+ * Lifecycle: After consent banner shown
66
+ */
67
+ afterBannerShow() {
68
+ // Override in subclass
69
+ }
70
+
71
+ /**
72
+ * Lifecycle: Before consent saved
73
+ * @param {Object} consent - Consent data
74
+ * @returns {Object} Modified consent (or original)
75
+ */
76
+ beforeConsentSave(consent) {
77
+ // Override in subclass
78
+ return consent
79
+ }
80
+
81
+ /**
82
+ * Lifecycle: After consent saved
83
+ * @param {Object} consent - Saved consent data
84
+ */
85
+ afterConsentSave(consent) {
86
+ // Override in subclass
87
+ }
88
+
89
+ /**
90
+ * Event: Consent changed
91
+ * @param {Object} data - { consent, categories }
92
+ */
93
+ onConsentChange(data) {
94
+ // Override in subclass
95
+ }
96
+
97
+ /**
98
+ * Event: Consent accepted
99
+ * @param {Object} data - { consent, categories }
100
+ */
101
+ onConsentAccepted(data) {
102
+ // Override in subclass
103
+ }
104
+
105
+ /**
106
+ * Event: Consent rejected
107
+ * @param {Object} data - { consent, categories }
108
+ */
109
+ onConsentRejected(data) {
110
+ // Override in subclass
111
+ }
112
+
113
+ /**
114
+ * Event: Consent expired
115
+ */
116
+ onConsentExpired() {
117
+ // Override in subclass
118
+ }
119
+
120
+ /**
121
+ * Event: Script loaded
122
+ * @param {Object} script - Script info
123
+ */
124
+ onScriptLoaded(script) {
125
+ // Override in subclass
126
+ }
127
+
128
+ /**
129
+ * Event: Tracker detected
130
+ * @param {Object} tracker - Tracker info
131
+ */
132
+ onTrackerDetected(tracker) {
133
+ // Override in subclass
134
+ }
135
+
136
+ /**
137
+ * Cleanup plugin
138
+ * Called when plugin is unregistered
139
+ */
140
+ destroy() {
141
+ this.isInitialized = false
142
+ this.cmp = null
143
+ this._debug('Plugin destroyed')
144
+ }
145
+
146
+ /**
147
+ * Get CMP API
148
+ * @returns {Object}
149
+ */
150
+ getAPI() {
151
+ return this.cmp?.api || {}
152
+ }
153
+
154
+ /**
155
+ * Get consent
156
+ * @returns {Object|null}
157
+ */
158
+ getConsent() {
159
+ return this.cmp?.getConsent() || null
160
+ }
161
+
162
+ /**
163
+ * Check category consent
164
+ * @param {string} category
165
+ * @returns {boolean}
166
+ */
167
+ hasCategoryConsent(category) {
168
+ return this.cmp?.hasCategoryConsent(category) || false
169
+ }
170
+
171
+ /**
172
+ * Emit custom event
173
+ * @param {string} eventName
174
+ * @param {Object} data
175
+ */
176
+ emit(eventName, data = {}) {
177
+ if (typeof window !== 'undefined') {
178
+ window.dispatchEvent(new CustomEvent(`cmp:plugin:${eventName}`, {
179
+ detail: { plugin: this.name, ...data }
180
+ }))
181
+ }
182
+ }
183
+
184
+ _debug(...args) {
185
+ // Debug disabled
186
+ }
187
+ }
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Plugin Manager
3
+ * @module PluginManager
4
+ *
5
+ * Manages CMP plugins lifecycle and events
6
+ */
7
+
8
+ export class PluginManager {
9
+ constructor(cmpInstance) {
10
+ this.cmp = cmpInstance
11
+ this.plugins = new Map() // name -> plugin instance
12
+ this.hooks = {
13
+ beforeInit: [],
14
+ afterInit: [],
15
+ beforeBannerShow: [],
16
+ afterBannerShow: [],
17
+ beforeConsentSave: [],
18
+ afterConsentSave: []
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Register plugin
24
+ * @param {CMPPlugin} plugin - Plugin instance
25
+ * @returns {boolean}
26
+ */
27
+ register(plugin) {
28
+ if (!plugin || !plugin.name) return false
29
+ if (this.plugins.has(plugin.name)) return false
30
+
31
+ // Initialize plugin
32
+ plugin.init(this.cmp)
33
+
34
+ // Store plugin
35
+ this.plugins.set(plugin.name, plugin)
36
+
37
+ // Register lifecycle hooks
38
+ this._registerHooks(plugin)
39
+
40
+ // Setup event listeners
41
+ this._setupEventListeners(plugin)
42
+
43
+ this._debug(`Plugin "${plugin.name}" registered`)
44
+ return true
45
+ }
46
+
47
+ /**
48
+ * Unregister plugin
49
+ * @param {string} pluginName
50
+ * @returns {boolean}
51
+ */
52
+ unregister(pluginName) {
53
+ const plugin = this.plugins.get(pluginName)
54
+ if (!plugin) {
55
+ return false
56
+ }
57
+
58
+ // Cleanup plugin
59
+ plugin.destroy()
60
+
61
+ // Remove from hooks
62
+ this._unregisterHooks(plugin)
63
+
64
+ // Remove plugin
65
+ this.plugins.delete(pluginName)
66
+
67
+ this._debug(`Plugin "${pluginName}" unregistered`)
68
+ return true
69
+ }
70
+
71
+ /**
72
+ * Get plugin by name
73
+ * @param {string} pluginName
74
+ * @returns {CMPPlugin|null}
75
+ */
76
+ get(pluginName) {
77
+ return this.plugins.get(pluginName) || null
78
+ }
79
+
80
+ /**
81
+ * Get all plugins
82
+ * @returns {Array}
83
+ */
84
+ getAll() {
85
+ return Array.from(this.plugins.values())
86
+ }
87
+
88
+ /**
89
+ * Check if plugin is registered
90
+ * @param {string} pluginName
91
+ * @returns {boolean}
92
+ */
93
+ has(pluginName) {
94
+ return this.plugins.has(pluginName)
95
+ }
96
+
97
+ /**
98
+ * Execute lifecycle hook
99
+ * @param {string} hookName
100
+ * @param {*} data
101
+ * @returns {*}
102
+ */
103
+ async executeHook(hookName, data = null) {
104
+ const hooks = this.hooks[hookName] || []
105
+
106
+ let result = data
107
+
108
+ for (const hook of hooks) {
109
+ try {
110
+ const hookResult = await hook(result)
111
+ // For beforeConsentSave, allow modification
112
+ if (hookName === 'beforeConsentSave' && hookResult !== undefined) {
113
+ result = hookResult
114
+ }
115
+ } catch (error) {
116
+ // Silent error
117
+ }
118
+ }
119
+
120
+ return result
121
+ }
122
+
123
+ /**
124
+ * Register plugin hooks
125
+ * @private
126
+ */
127
+ _registerHooks(plugin) {
128
+ // beforeInit
129
+ if (typeof plugin.beforeInit === 'function') {
130
+ this.hooks.beforeInit.push(() => plugin.beforeInit())
131
+ }
132
+
133
+ // afterInit
134
+ if (typeof plugin.afterInit === 'function') {
135
+ this.hooks.afterInit.push(() => plugin.afterInit())
136
+ }
137
+
138
+ // beforeBannerShow
139
+ if (typeof plugin.beforeBannerShow === 'function') {
140
+ this.hooks.beforeBannerShow.push(() => plugin.beforeBannerShow())
141
+ }
142
+
143
+ // afterBannerShow
144
+ if (typeof plugin.afterBannerShow === 'function') {
145
+ this.hooks.afterBannerShow.push(() => plugin.afterBannerShow())
146
+ }
147
+
148
+ // beforeConsentSave
149
+ if (typeof plugin.beforeConsentSave === 'function') {
150
+ this.hooks.beforeConsentSave.push((consent) => plugin.beforeConsentSave(consent))
151
+ }
152
+
153
+ // afterConsentSave
154
+ if (typeof plugin.afterConsentSave === 'function') {
155
+ this.hooks.afterConsentSave.push((consent) => plugin.afterConsentSave(consent))
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Unregister plugin hooks
161
+ * @private
162
+ */
163
+ _unregisterHooks(plugin) {
164
+ Object.keys(this.hooks).forEach(hookName => {
165
+ this.hooks[hookName] = this.hooks[hookName].filter(hook => {
166
+ // Remove hooks that belong to this plugin
167
+ return hook.toString().indexOf(plugin.name) === -1
168
+ })
169
+ })
170
+ }
171
+
172
+ /**
173
+ * Setup event listeners for plugin
174
+ * @private
175
+ */
176
+ _setupEventListeners(plugin) {
177
+ // Consent changed
178
+ if (typeof plugin.onConsentChange === 'function') {
179
+ this.cmp.on('consentChanged', (data) => plugin.onConsentChange(data))
180
+ }
181
+
182
+ // Consent accepted
183
+ if (typeof plugin.onConsentAccepted === 'function') {
184
+ this.cmp.on('consentAccepted', (data) => plugin.onConsentAccepted(data))
185
+ }
186
+
187
+ // Consent rejected
188
+ if (typeof plugin.onConsentRejected === 'function') {
189
+ this.cmp.on('consentRejected', (data) => plugin.onConsentRejected(data))
190
+ }
191
+
192
+ // Consent expired
193
+ if (typeof plugin.onConsentExpired === 'function') {
194
+ this.cmp.on('consentExpired', () => plugin.onConsentExpired())
195
+ }
196
+
197
+ // Script loaded
198
+ if (typeof plugin.onScriptLoaded === 'function') {
199
+ if (typeof window !== 'undefined') {
200
+ window.addEventListener('cookie-consent:script-loaded', (e) => {
201
+ plugin.onScriptLoaded(e.detail)
202
+ })
203
+ }
204
+ }
205
+
206
+ // Tracker detected
207
+ if (typeof plugin.onTrackerDetected === 'function') {
208
+ if (typeof window !== 'undefined') {
209
+ window.addEventListener('cookie-consent:tracker-detected', (e) => {
210
+ plugin.onTrackerDetected(e.detail)
211
+ })
212
+ }
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Get plugin stats
218
+ * @returns {Object}
219
+ */
220
+ getStats() {
221
+ return {
222
+ total: this.plugins.size,
223
+ plugins: this.getAll().map(p => ({
224
+ name: p.name,
225
+ version: p.version,
226
+ initialized: p.isInitialized
227
+ }))
228
+ }
229
+ }
230
+
231
+ _debug(...args) {
232
+ // Debug disabled
233
+ }
234
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Plugin System
3
+ * @module plugins
4
+ */
5
+
6
+ export { CMPPlugin } from './CMPPlugin.js'
7
+ export { PluginManager } from './PluginManager.js'