@solvenza/cookies-compliance 1.2.1 → 1.5.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/README.md +960 -36
- package/bin/audit-cli.js +134 -13
- package/dist/audit.cjs +811 -0
- package/dist/audit.cjs.map +1 -0
- package/dist/audit.d.cts +60 -0
- package/dist/audit.d.ts +60 -0
- package/dist/audit.js +380 -0
- package/dist/audit.js.map +1 -0
- package/dist/chunk-C5QPXHTH.js +3557 -0
- package/dist/chunk-C5QPXHTH.js.map +1 -0
- package/dist/chunk-OHOHIAK6.js +442 -0
- package/dist/chunk-OHOHIAK6.js.map +1 -0
- package/dist/chunk-Q3FZFXQE.js +89 -0
- package/dist/chunk-UQU54ANZ.js +225 -0
- package/dist/chunk-UQU54ANZ.js.map +1 -0
- package/dist/chunk-W5MG56VI.js +269 -0
- package/dist/chunk-W5MG56VI.js.map +1 -0
- package/dist/consent.esm.cjs +2195 -84
- package/dist/consent.esm.cjs.map +1 -1
- package/dist/consent.esm.d.cts +173 -6
- package/dist/consent.esm.d.ts +173 -6
- package/dist/consent.esm.js +57 -23
- package/dist/consent.esm.js.map +1 -1
- package/dist/consent.min.js +437 -55
- package/dist/consent.min.js.map +1 -1
- package/dist/presets.cjs +495 -0
- package/dist/presets.cjs.map +1 -0
- package/dist/presets.d.cts +51 -0
- package/dist/presets.d.ts +51 -0
- package/dist/presets.js +16 -0
- package/dist/presets.js.map +1 -0
- package/dist/types--kyI7OOR.d.cts +314 -0
- package/dist/types--kyI7OOR.d.ts +314 -0
- package/dist/wrappers/angular.cjs +2341 -65
- package/dist/wrappers/angular.cjs.map +1 -1
- package/dist/wrappers/angular.d.cts +85 -5
- package/dist/wrappers/angular.d.ts +85 -5
- package/dist/wrappers/angular.js +217 -3
- package/dist/wrappers/angular.js.map +1 -1
- package/dist/wrappers/next.cjs +2353 -103
- package/dist/wrappers/next.cjs.map +1 -1
- package/dist/wrappers/next.d.cts +25 -1
- package/dist/wrappers/next.d.ts +25 -1
- package/dist/wrappers/next.js +30 -5
- package/dist/wrappers/next.js.map +1 -1
- package/dist/wrappers/nuxt.cjs +4171 -0
- package/dist/wrappers/nuxt.cjs.map +1 -0
- package/dist/wrappers/nuxt.d.cts +33 -0
- package/dist/wrappers/nuxt.d.ts +33 -0
- package/dist/wrappers/nuxt.js +51 -0
- package/dist/wrappers/nuxt.js.map +1 -0
- package/dist/wrappers/react.cjs +2336 -141
- package/dist/wrappers/react.cjs.map +1 -1
- package/dist/wrappers/react.d.cts +87 -1
- package/dist/wrappers/react.d.ts +87 -1
- package/dist/wrappers/react.js +21 -51
- package/dist/wrappers/react.js.map +1 -1
- package/dist/wrappers/vue.cjs +4163 -0
- package/dist/wrappers/vue.cjs.map +1 -0
- package/dist/wrappers/vue.d.cts +144 -0
- package/dist/wrappers/vue.d.ts +144 -0
- package/dist/wrappers/vue.js +28 -0
- package/dist/wrappers/vue.js.map +1 -0
- package/dist/wrappers/wordpress.js +1 -1
- package/package.json +26 -5
- package/schema.json +143 -4
- package/dist/chunk-DDAAVRWG.js +0 -25
- package/dist/chunk-FBRP4MSA.js +0 -1907
- package/dist/chunk-FBRP4MSA.js.map +0 -1
- package/dist/consent-engine-DOMyEKfk.d.cts +0 -193
- package/dist/consent-engine-DOMyEKfk.d.ts +0 -193
- /package/dist/{chunk-DDAAVRWG.js.map → chunk-Q3FZFXQE.js.map} +0 -0
package/dist/consent.esm.cjs
CHANGED
|
@@ -20,6 +20,18 @@ var __spreadValues = (a, b) => {
|
|
|
20
20
|
return a;
|
|
21
21
|
};
|
|
22
22
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
23
|
+
var __objRest = (source, exclude) => {
|
|
24
|
+
var target = {};
|
|
25
|
+
for (var prop in source)
|
|
26
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
27
|
+
target[prop] = source[prop];
|
|
28
|
+
if (source != null && __getOwnPropSymbols)
|
|
29
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
30
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
31
|
+
target[prop] = source[prop];
|
|
32
|
+
}
|
|
33
|
+
return target;
|
|
34
|
+
};
|
|
23
35
|
var __export = (target, all) => {
|
|
24
36
|
for (var name in all)
|
|
25
37
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -37,12 +49,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
37
49
|
// src/index.ts
|
|
38
50
|
var src_exports = {};
|
|
39
51
|
__export(src_exports, {
|
|
52
|
+
BUILTIN_TRANSLATIONS: () => BUILTIN_TRANSLATIONS,
|
|
40
53
|
ConfigValidationError: () => ConfigValidationError,
|
|
41
54
|
Consent: () => Consent,
|
|
42
55
|
ConsentConfigBuilder: () => ConsentConfigBuilder,
|
|
43
56
|
ConsentEngine: () => ConsentEngine,
|
|
44
57
|
CookieStorageProvider: () => CookieStorageProvider,
|
|
45
58
|
CookieStore: () => CookieStore,
|
|
59
|
+
FloatingBadge: () => FloatingBadge,
|
|
46
60
|
GoogleConsentAdapter: () => GoogleConsentAdapter,
|
|
47
61
|
I18nEngine: () => I18nEngine,
|
|
48
62
|
IframeGate: () => IframeGate,
|
|
@@ -53,13 +67,22 @@ __export(src_exports, {
|
|
|
53
67
|
PolicyGenerator: () => PolicyGenerator,
|
|
54
68
|
ResourceGate: () => ResourceGate,
|
|
55
69
|
ResourceScanner: () => ResourceScanner,
|
|
70
|
+
SERVICE_PRESETS: () => SERVICE_PRESETS,
|
|
56
71
|
ScriptGate: () => ScriptGate,
|
|
57
72
|
ScriptResourceBlocker: () => ScriptResourceBlocker,
|
|
73
|
+
StorageCleaner: () => StorageCleaner,
|
|
58
74
|
StorageFactory: () => StorageFactory,
|
|
75
|
+
applyGpcChoices: () => applyGpcChoices,
|
|
59
76
|
computeReceiptSignature: () => computeReceiptSignature,
|
|
60
77
|
createReceipt: () => createReceipt,
|
|
78
|
+
defineServices: () => defineServices,
|
|
79
|
+
detectGpcSignal: () => detectGpcSignal,
|
|
80
|
+
getPreset: () => getPreset,
|
|
81
|
+
hasPreset: () => hasPreset,
|
|
61
82
|
isReceiptExpired: () => isReceiptExpired,
|
|
62
83
|
parseReceipt: () => parseReceipt,
|
|
84
|
+
resolveConfigPresets: () => resolveConfigPresets,
|
|
85
|
+
resolveGpcConfig: () => resolveGpcConfig,
|
|
63
86
|
sanitizeHtml: () => sanitizeHtml,
|
|
64
87
|
validateConfig: () => validateConfig,
|
|
65
88
|
verifyReceiptIntegrity: () => verifyReceiptIntegrity
|
|
@@ -108,14 +131,15 @@ function validateConfig(config) {
|
|
|
108
131
|
}
|
|
109
132
|
if (config.services && typeof config.services === "object") {
|
|
110
133
|
for (const [serviceId, serviceConfig] of Object.entries(config.services)) {
|
|
111
|
-
|
|
134
|
+
const category = serviceConfig.category;
|
|
135
|
+
if (!category) {
|
|
112
136
|
throw new ConfigValidationError(
|
|
113
137
|
`Service '${serviceId}' missing 'category' reference.`
|
|
114
138
|
);
|
|
115
139
|
}
|
|
116
|
-
if (!config.categories[
|
|
140
|
+
if (!config.categories[category]) {
|
|
117
141
|
throw new ConfigValidationError(
|
|
118
|
-
`Service '${serviceId}' references non-existent category '${
|
|
142
|
+
`Service '${serviceId}' references non-existent category '${category}'.`
|
|
119
143
|
);
|
|
120
144
|
}
|
|
121
145
|
}
|
|
@@ -134,17 +158,21 @@ var StateManager = class {
|
|
|
134
158
|
};
|
|
135
159
|
this.config = null;
|
|
136
160
|
}
|
|
137
|
-
init(config, choices, receipt) {
|
|
138
|
-
var _a;
|
|
161
|
+
init(config, choices, receipt, gpc) {
|
|
162
|
+
var _a, _b;
|
|
139
163
|
this.config = config;
|
|
140
164
|
this.state = {
|
|
141
165
|
initialized: true,
|
|
142
166
|
policyVersion: config.policyVersion,
|
|
143
167
|
locale: ((_a = config.locale) == null ? void 0 : _a.default) || "es",
|
|
144
168
|
receipt,
|
|
145
|
-
choices
|
|
169
|
+
choices,
|
|
170
|
+
gpc: (_b = gpc != null ? gpc : receipt == null ? void 0 : receipt.gpc) != null ? _b : false
|
|
146
171
|
};
|
|
147
172
|
}
|
|
173
|
+
setLocale(locale) {
|
|
174
|
+
this.state.locale = locale;
|
|
175
|
+
}
|
|
148
176
|
getConfig() {
|
|
149
177
|
return this.config;
|
|
150
178
|
}
|
|
@@ -163,7 +191,7 @@ var StateManager = class {
|
|
|
163
191
|
hasService(serviceId) {
|
|
164
192
|
if (!this.config || !this.config.services) return false;
|
|
165
193
|
const service = this.config.services[serviceId];
|
|
166
|
-
if (!service) return false;
|
|
194
|
+
if (!service || !service.category) return false;
|
|
167
195
|
return this.hasCategory(service.category);
|
|
168
196
|
}
|
|
169
197
|
updateChoices(receipt) {
|
|
@@ -556,6 +584,178 @@ var MemoryStore = {
|
|
|
556
584
|
clear: () => new MemoryStorageProvider().clear()
|
|
557
585
|
};
|
|
558
586
|
|
|
587
|
+
// src/storage/storage-cleaner.ts
|
|
588
|
+
var StorageCleaner = class {
|
|
589
|
+
/**
|
|
590
|
+
* Evaluates if a given storage key or cookie name matches a pattern.
|
|
591
|
+
* Supports:
|
|
592
|
+
* - Wildcard glob: "*", "_ga*", "ph_*_posthog", "*session*"
|
|
593
|
+
* - Exact string match (case-insensitive)
|
|
594
|
+
*/
|
|
595
|
+
static matchesPattern(key, pattern) {
|
|
596
|
+
if (!key || !pattern) return false;
|
|
597
|
+
if (pattern === "*" || key === pattern) return true;
|
|
598
|
+
if (pattern.includes("*")) {
|
|
599
|
+
const escaped = pattern.split("*").map((segment) => segment.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&")).join(".*");
|
|
600
|
+
try {
|
|
601
|
+
const regex = new RegExp(`^${escaped}$`, "i");
|
|
602
|
+
return regex.test(key);
|
|
603
|
+
} catch (e) {
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return key.toLowerCase() === pattern.toLowerCase();
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Purges keys from window.localStorage that match any of the provided patterns.
|
|
611
|
+
* Safe in SSR, sandboxed iframes, and private browsing modes.
|
|
612
|
+
*/
|
|
613
|
+
static purgeLocalStorage(patterns) {
|
|
614
|
+
if (typeof window === "undefined" || !patterns || patterns.length === 0) return [];
|
|
615
|
+
try {
|
|
616
|
+
if (typeof window.localStorage === "undefined") return [];
|
|
617
|
+
const keysToRemove = [];
|
|
618
|
+
const len = window.localStorage.length;
|
|
619
|
+
for (let i = 0; i < len; i++) {
|
|
620
|
+
const key = window.localStorage.key(i);
|
|
621
|
+
if (key && patterns.some((p) => this.matchesPattern(key, p))) {
|
|
622
|
+
keysToRemove.push(key);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
for (const key of keysToRemove) {
|
|
626
|
+
window.localStorage.removeItem(key);
|
|
627
|
+
}
|
|
628
|
+
return keysToRemove;
|
|
629
|
+
} catch (e) {
|
|
630
|
+
return [];
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Purges keys from window.sessionStorage that match any of the provided patterns.
|
|
635
|
+
* Safe in SSR, sandboxed iframes, and private browsing modes.
|
|
636
|
+
*/
|
|
637
|
+
static purgeSessionStorage(patterns) {
|
|
638
|
+
if (typeof window === "undefined" || !patterns || patterns.length === 0) return [];
|
|
639
|
+
try {
|
|
640
|
+
if (typeof window.sessionStorage === "undefined") return [];
|
|
641
|
+
const keysToRemove = [];
|
|
642
|
+
const len = window.sessionStorage.length;
|
|
643
|
+
for (let i = 0; i < len; i++) {
|
|
644
|
+
const key = window.sessionStorage.key(i);
|
|
645
|
+
if (key && patterns.some((p) => this.matchesPattern(key, p))) {
|
|
646
|
+
keysToRemove.push(key);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
for (const key of keysToRemove) {
|
|
650
|
+
window.sessionStorage.removeItem(key);
|
|
651
|
+
}
|
|
652
|
+
return keysToRemove;
|
|
653
|
+
} catch (e) {
|
|
654
|
+
return [];
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Purges cookies declared for services, supporting wildcard glob names (e.g. "_ga_*").
|
|
659
|
+
*/
|
|
660
|
+
static purgeCookies(cookieDeclarations, defaultPath = "/", defaultDomain) {
|
|
661
|
+
if (typeof document === "undefined" || !cookieDeclarations || cookieDeclarations.length === 0) {
|
|
662
|
+
return [];
|
|
663
|
+
}
|
|
664
|
+
const removedCookies = [];
|
|
665
|
+
const allExistingCookies = this.getAllCookieNames();
|
|
666
|
+
for (const cookieItem of cookieDeclarations) {
|
|
667
|
+
const targetDomain = cookieItem.domain || defaultDomain;
|
|
668
|
+
if (cookieItem.name.includes("*")) {
|
|
669
|
+
for (const existingName of allExistingCookies) {
|
|
670
|
+
if (this.matchesPattern(existingName, cookieItem.name)) {
|
|
671
|
+
CookieStore.remove(existingName, defaultPath, targetDomain);
|
|
672
|
+
if (!removedCookies.includes(existingName)) {
|
|
673
|
+
removedCookies.push(existingName);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
} else {
|
|
678
|
+
CookieStore.remove(cookieItem.name, defaultPath, targetDomain);
|
|
679
|
+
if (!removedCookies.includes(cookieItem.name)) {
|
|
680
|
+
removedCookies.push(cookieItem.name);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return removedCookies;
|
|
685
|
+
}
|
|
686
|
+
static getAllCookieNames() {
|
|
687
|
+
if (typeof document === "undefined") return [];
|
|
688
|
+
try {
|
|
689
|
+
return document.cookie.split(";").map((c) => c.trim().split("=")[0]).filter((n) => !!n);
|
|
690
|
+
} catch (e) {
|
|
691
|
+
return [];
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Purges all cookies, localStorage, and sessionStorage keys associated with a category.
|
|
696
|
+
*/
|
|
697
|
+
static purgeCategory(config, category) {
|
|
698
|
+
var _a, _b, _c;
|
|
699
|
+
const report = {
|
|
700
|
+
category,
|
|
701
|
+
purgedCookies: [],
|
|
702
|
+
purgedLocalStorage: [],
|
|
703
|
+
purgedSessionStorage: []
|
|
704
|
+
};
|
|
705
|
+
if (!config) return report;
|
|
706
|
+
const path = ((_a = config.storage) == null ? void 0 : _a.path) || "/";
|
|
707
|
+
const defaultDomain = (_b = config.storage) == null ? void 0 : _b.domain;
|
|
708
|
+
const cookiesToPurge = [];
|
|
709
|
+
const localStoragePatterns = /* @__PURE__ */ new Set();
|
|
710
|
+
const sessionStoragePatterns = /* @__PURE__ */ new Set();
|
|
711
|
+
const catConfig = (_c = config.categories) == null ? void 0 : _c[category];
|
|
712
|
+
if (catConfig) {
|
|
713
|
+
if (catConfig.storageKeys) {
|
|
714
|
+
catConfig.storageKeys.forEach((k) => {
|
|
715
|
+
localStoragePatterns.add(k);
|
|
716
|
+
sessionStoragePatterns.add(k);
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
if (catConfig.localStorage) {
|
|
720
|
+
catConfig.localStorage.forEach((k) => localStoragePatterns.add(k));
|
|
721
|
+
}
|
|
722
|
+
if (catConfig.sessionStorage) {
|
|
723
|
+
catConfig.sessionStorage.forEach((k) => sessionStoragePatterns.add(k));
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (config.services) {
|
|
727
|
+
for (const service of Object.values(config.services)) {
|
|
728
|
+
if (service.category === category) {
|
|
729
|
+
if (service.cookies) {
|
|
730
|
+
for (const cookieItem of service.cookies) {
|
|
731
|
+
cookiesToPurge.push({
|
|
732
|
+
name: cookieItem.name,
|
|
733
|
+
domain: cookieItem.domain || defaultDomain
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (service.storageKeys) {
|
|
738
|
+
service.storageKeys.forEach((k) => {
|
|
739
|
+
localStoragePatterns.add(k);
|
|
740
|
+
sessionStoragePatterns.add(k);
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
if (service.localStorage) {
|
|
744
|
+
service.localStorage.forEach((k) => localStoragePatterns.add(k));
|
|
745
|
+
}
|
|
746
|
+
if (service.sessionStorage) {
|
|
747
|
+
service.sessionStorage.forEach((k) => sessionStoragePatterns.add(k));
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
report.purgedCookies = this.purgeCookies(cookiesToPurge, path, defaultDomain);
|
|
753
|
+
report.purgedLocalStorage = this.purgeLocalStorage(Array.from(localStoragePatterns));
|
|
754
|
+
report.purgedSessionStorage = this.purgeSessionStorage(Array.from(sessionStoragePatterns));
|
|
755
|
+
return report;
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
|
|
559
759
|
// src/blocker/script-gate.ts
|
|
560
760
|
var ScriptResourceBlocker = class {
|
|
561
761
|
constructor() {
|
|
@@ -1320,6 +1520,152 @@ function injectStyles(nonce) {
|
|
|
1320
1520
|
flex-direction: row;
|
|
1321
1521
|
}
|
|
1322
1522
|
}
|
|
1523
|
+
|
|
1524
|
+
/* Floating Revocation & Preference Badge */
|
|
1525
|
+
.consent-floating-badge {
|
|
1526
|
+
position: fixed;
|
|
1527
|
+
z-index: 2147483640;
|
|
1528
|
+
font-family: var(--consent-font);
|
|
1529
|
+
opacity: 0;
|
|
1530
|
+
transform: scale(0.85);
|
|
1531
|
+
pointer-events: none;
|
|
1532
|
+
transition: opacity 0.28s cubic-bezier(0.16, 1, 0.3, 1), transform 0.28s cubic-bezier(0.16, 1, 0.3, 1);
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
.consent-floating-badge.is-visible {
|
|
1536
|
+
opacity: 1;
|
|
1537
|
+
transform: scale(1);
|
|
1538
|
+
pointer-events: auto;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
.consent-floating-badge--bottom-left {
|
|
1542
|
+
bottom: 1.25rem;
|
|
1543
|
+
left: 1.25rem;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
.consent-floating-badge--bottom-right {
|
|
1547
|
+
bottom: 1.25rem;
|
|
1548
|
+
right: 1.25rem;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
.consent-floating-badge--top-left {
|
|
1552
|
+
top: 1.25rem;
|
|
1553
|
+
left: 1.25rem;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
.consent-floating-badge--top-right {
|
|
1557
|
+
top: 1.25rem;
|
|
1558
|
+
right: 1.25rem;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
.consent-floating-badge-inner {
|
|
1562
|
+
position: relative;
|
|
1563
|
+
display: inline-flex;
|
|
1564
|
+
align-items: center;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
.consent-floating-badge-btn {
|
|
1568
|
+
display: inline-flex;
|
|
1569
|
+
align-items: center;
|
|
1570
|
+
justify-content: center;
|
|
1571
|
+
gap: 0.5rem;
|
|
1572
|
+
width: 46px;
|
|
1573
|
+
height: 46px;
|
|
1574
|
+
min-width: 46px;
|
|
1575
|
+
border-radius: 9999px;
|
|
1576
|
+
background: var(--consent-bg);
|
|
1577
|
+
color: var(--consent-fg);
|
|
1578
|
+
border: 1px solid var(--consent-border);
|
|
1579
|
+
box-shadow: 0 10px 25px -5px rgba(15, 23, 42, 0.15), 0 4px 6px -2px rgba(15, 23, 42, 0.05);
|
|
1580
|
+
cursor: pointer;
|
|
1581
|
+
padding: 0;
|
|
1582
|
+
margin: 0;
|
|
1583
|
+
transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s ease, border-color 0.2s ease, color 0.2s ease;
|
|
1584
|
+
outline: none;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
.consent-floating-badge-btn.has-label {
|
|
1588
|
+
width: auto;
|
|
1589
|
+
padding: 0 1rem;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
.consent-floating-badge-btn:hover {
|
|
1593
|
+
transform: translateY(-2px);
|
|
1594
|
+
box-shadow: 0 14px 28px -6px rgba(15, 23, 42, 0.2), 0 6px 10px -3px rgba(15, 23, 42, 0.08);
|
|
1595
|
+
border-color: var(--consent-accent);
|
|
1596
|
+
color: var(--consent-accent);
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
.consent-floating-badge-btn:active {
|
|
1600
|
+
transform: translateY(0) scale(0.96);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
.consent-floating-badge-btn:focus-visible {
|
|
1604
|
+
box-shadow: 0 0 0 3px var(--consent-focus-ring), 0 10px 25px -5px rgba(15, 23, 42, 0.15);
|
|
1605
|
+
border-color: var(--consent-accent);
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
.consent-floating-badge-icon {
|
|
1609
|
+
display: inline-flex;
|
|
1610
|
+
align-items: center;
|
|
1611
|
+
justify-content: center;
|
|
1612
|
+
width: 22px;
|
|
1613
|
+
height: 22px;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
.consent-floating-badge-text {
|
|
1617
|
+
font-size: 0.85rem;
|
|
1618
|
+
font-weight: 600;
|
|
1619
|
+
white-space: nowrap;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
.consent-floating-badge-tooltip {
|
|
1623
|
+
position: absolute;
|
|
1624
|
+
white-space: nowrap;
|
|
1625
|
+
pointer-events: none;
|
|
1626
|
+
opacity: 0;
|
|
1627
|
+
visibility: hidden;
|
|
1628
|
+
background: var(--consent-primary);
|
|
1629
|
+
color: var(--consent-primary-fg);
|
|
1630
|
+
font-size: 0.76rem;
|
|
1631
|
+
font-weight: 500;
|
|
1632
|
+
padding: 0.4rem 0.75rem;
|
|
1633
|
+
border-radius: 8px;
|
|
1634
|
+
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18);
|
|
1635
|
+
transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
|
|
1636
|
+
z-index: 2147483641;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
.consent-floating-badge--bottom-left .consent-floating-badge-tooltip {
|
|
1640
|
+
bottom: calc(100% + 8px);
|
|
1641
|
+
left: 0;
|
|
1642
|
+
transform: translateY(4px);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
.consent-floating-badge--bottom-right .consent-floating-badge-tooltip {
|
|
1646
|
+
bottom: calc(100% + 8px);
|
|
1647
|
+
right: 0;
|
|
1648
|
+
transform: translateY(4px);
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
.consent-floating-badge--top-left .consent-floating-badge-tooltip {
|
|
1652
|
+
top: calc(100% + 8px);
|
|
1653
|
+
left: 0;
|
|
1654
|
+
transform: translateY(-4px);
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
.consent-floating-badge--top-right .consent-floating-badge-tooltip {
|
|
1658
|
+
top: calc(100% + 8px);
|
|
1659
|
+
right: 0;
|
|
1660
|
+
transform: translateY(-4px);
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
.consent-floating-badge-inner:hover .consent-floating-badge-tooltip,
|
|
1664
|
+
.consent-floating-badge-btn:focus-visible + .consent-floating-badge-tooltip {
|
|
1665
|
+
opacity: 1;
|
|
1666
|
+
visibility: visible;
|
|
1667
|
+
transform: translateY(0);
|
|
1668
|
+
}
|
|
1323
1669
|
`;
|
|
1324
1670
|
document.head.appendChild(styleEl);
|
|
1325
1671
|
}
|
|
@@ -1342,6 +1688,9 @@ var ConsentBanner = class {
|
|
|
1342
1688
|
const acceptText = sanitizeHtml(bannerConfig.accept || "Aceptar todas");
|
|
1343
1689
|
const rejectText = sanitizeHtml(bannerConfig.reject || "Rechazar todas");
|
|
1344
1690
|
const configureText = sanitizeHtml(bannerConfig.configure || "Configurar");
|
|
1691
|
+
const cookiesPolicyText = sanitizeHtml(bannerConfig.cookiesPolicy || "Pol\xEDtica de cookies");
|
|
1692
|
+
const privacyPolicyText = sanitizeHtml(bannerConfig.privacyPolicy || "Pol\xEDtica de privacidad");
|
|
1693
|
+
const bannerAriaLabel = sanitizeHtml(bannerConfig.ariaLabel || "Gesti\xF3n de consentimiento de privacidad");
|
|
1345
1694
|
const privacyUrl = sanitizeUrl(((_c = config.policy) == null ? void 0 : _c.privacyUrl) || "/politica-privacidad");
|
|
1346
1695
|
const cookiesUrl = sanitizeUrl(((_d = config.policy) == null ? void 0 : _d.cookiesUrl) || "/politica-cookies");
|
|
1347
1696
|
const wrapper = document.createElement("div");
|
|
@@ -1349,7 +1698,7 @@ var ConsentBanner = class {
|
|
|
1349
1698
|
wrapper.setAttribute("role", "region");
|
|
1350
1699
|
wrapper.setAttribute(
|
|
1351
1700
|
"aria-label",
|
|
1352
|
-
|
|
1701
|
+
bannerAriaLabel
|
|
1353
1702
|
);
|
|
1354
1703
|
wrapper.innerHTML = `
|
|
1355
1704
|
<div class="consent-banner-container">
|
|
@@ -1364,8 +1713,8 @@ var ConsentBanner = class {
|
|
|
1364
1713
|
</h2>
|
|
1365
1714
|
<p class="consent-banner-desc">${descText}</p>
|
|
1366
1715
|
<div class="consent-banner-links">
|
|
1367
|
-
<a href="${cookiesUrl}" target="_blank" rel="noopener"
|
|
1368
|
-
<a href="${privacyUrl}" target="_blank" rel="noopener"
|
|
1716
|
+
<a href="${cookiesUrl}" target="_blank" rel="noopener">${cookiesPolicyText}</a>
|
|
1717
|
+
<a href="${privacyUrl}" target="_blank" rel="noopener">${privacyPolicyText}</a>
|
|
1369
1718
|
</div>
|
|
1370
1719
|
</div>
|
|
1371
1720
|
<div class="consent-banner-actions">
|
|
@@ -1395,6 +1744,9 @@ var ConsentBanner = class {
|
|
|
1395
1744
|
document.body.appendChild(wrapper);
|
|
1396
1745
|
this.element = wrapper;
|
|
1397
1746
|
}
|
|
1747
|
+
getIsVisible() {
|
|
1748
|
+
return this.element !== null;
|
|
1749
|
+
}
|
|
1398
1750
|
remove() {
|
|
1399
1751
|
if (this.element && this.element.parentNode) {
|
|
1400
1752
|
this.element.parentNode.removeChild(this.element);
|
|
@@ -1417,9 +1769,19 @@ var PreferencesModal = class {
|
|
|
1417
1769
|
this.lastFocusedElement = document.activeElement;
|
|
1418
1770
|
const prefConfig = ((_b = config.ui) == null ? void 0 : _b.preferences) || {};
|
|
1419
1771
|
const modalTitle = sanitizeHtml(prefConfig.title || "Preferencias de privacidad");
|
|
1772
|
+
const modalSubtitle = sanitizeHtml(
|
|
1773
|
+
prefConfig.subtitle || "Gestiona tus permisos de almacenamiento por finalidad (LSSI art. 22.2 & RGPD)."
|
|
1774
|
+
);
|
|
1420
1775
|
const saveText = sanitizeHtml(prefConfig.save || "Guardar selecci\xF3n");
|
|
1421
1776
|
const acceptAllText = sanitizeHtml(prefConfig.acceptAll || "Permitir todas");
|
|
1422
1777
|
const rejectAllText = sanitizeHtml(prefConfig.rejectAll || "Rechazar opcionales");
|
|
1778
|
+
const closeLabel = sanitizeHtml(prefConfig.closeLabel || "Cerrar ventana");
|
|
1779
|
+
const requiredBadge = sanitizeHtml(prefConfig.requiredBadge || "Requerida");
|
|
1780
|
+
const optionalBadge = sanitizeHtml(prefConfig.optionalBadge || "Opcional");
|
|
1781
|
+
const servicesLabel = sanitizeHtml(prefConfig.servicesLabel || "Servicios incluidos");
|
|
1782
|
+
const viewServices = sanitizeHtml(prefConfig.viewServices || "Ver servicios");
|
|
1783
|
+
const hideServices = sanitizeHtml(prefConfig.hideServices || "Ocultar servicios");
|
|
1784
|
+
const thirdParty = sanitizeHtml(prefConfig.thirdParty || "Terceros");
|
|
1423
1785
|
const backdrop = document.createElement("div");
|
|
1424
1786
|
backdrop.className = "consent-dialog-backdrop";
|
|
1425
1787
|
const dialog = document.createElement("div");
|
|
@@ -1433,10 +1795,10 @@ var PreferencesModal = class {
|
|
|
1433
1795
|
<div>
|
|
1434
1796
|
<h2 class="consent-dialog-title" id="consent-dialog-title-id">${modalTitle}</h2>
|
|
1435
1797
|
<p style="margin: 0.2rem 0 0 0; font-size: 0.84rem; color: var(--consent-muted); font-weight: 400;">
|
|
1436
|
-
|
|
1798
|
+
${modalSubtitle}
|
|
1437
1799
|
</p>
|
|
1438
1800
|
</div>
|
|
1439
|
-
<button type="button" class="consent-dialog-close" aria-label="
|
|
1801
|
+
<button type="button" class="consent-dialog-close" aria-label="${closeLabel}">
|
|
1440
1802
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
|
|
1441
1803
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
1442
1804
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
@@ -1457,14 +1819,14 @@ var PreferencesModal = class {
|
|
|
1457
1819
|
servicesHtml = `
|
|
1458
1820
|
<div class="consent-category-services" id="cat-services-${catId}" style="display: none; margin-top: 0.75rem; padding-top: 0.6rem; border-top: 1px dashed var(--consent-divider); font-size: 0.82rem;">
|
|
1459
1821
|
<div style="font-weight: 600; color: var(--consent-muted); margin-bottom: 0.4rem; font-size: 0.75rem; letter-spacing: 0.02em;">
|
|
1460
|
-
|
|
1822
|
+
${servicesLabel} (${associatedServices.length})
|
|
1461
1823
|
</div>
|
|
1462
1824
|
<div style="display: flex; flex-direction: column; gap: 0.3rem;">
|
|
1463
1825
|
${associatedServices.map(
|
|
1464
1826
|
([srvId, srv]) => `
|
|
1465
1827
|
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0.2rem 0;">
|
|
1466
1828
|
<span style="font-weight: 500;">${sanitizeHtml(srv.label || srvId)}</span>
|
|
1467
|
-
<span style="color: var(--consent-muted); font-size: 0.78rem;">${sanitizeHtml(srv.provider ||
|
|
1829
|
+
<span style="color: var(--consent-muted); font-size: 0.78rem;">${sanitizeHtml(srv.provider || thirdParty)}</span>
|
|
1468
1830
|
</div>
|
|
1469
1831
|
`
|
|
1470
1832
|
).join("")}
|
|
@@ -1477,11 +1839,11 @@ var PreferencesModal = class {
|
|
|
1477
1839
|
<div style="flex: 1; padding-right: 1rem;">
|
|
1478
1840
|
<div style="display: flex; align-items: center; gap: 0.4rem;">
|
|
1479
1841
|
<span class="consent-category-name">${sanitizeHtml(catConfig.label)}</span>
|
|
1480
|
-
${isRequired ?
|
|
1842
|
+
${isRequired ? `<span class="consent-badge consent-badge-required">${requiredBadge}</span>` : `<span class="consent-badge consent-badge-optional">${optionalBadge}</span>`}
|
|
1481
1843
|
</div>
|
|
1482
1844
|
<p class="consent-category-desc">${sanitizeHtml(catConfig.description)}</p>
|
|
1483
1845
|
${associatedServices.length > 0 ? `<button type="button" class="consent-toggle-services-btn" data-target="cat-services-${catId}">
|
|
1484
|
-
|
|
1846
|
+
${viewServices} (${associatedServices.length}) \u25BE
|
|
1485
1847
|
</button>` : ""}
|
|
1486
1848
|
</div>
|
|
1487
1849
|
<label class="consent-toggle">
|
|
@@ -1510,7 +1872,7 @@ var PreferencesModal = class {
|
|
|
1510
1872
|
if (targetEl) {
|
|
1511
1873
|
const isHidden = targetEl.style.display === "none";
|
|
1512
1874
|
targetEl.style.display = isHidden ? "block" : "none";
|
|
1513
|
-
toggleServicesBtn.textContent = isHidden ?
|
|
1875
|
+
toggleServicesBtn.textContent = isHidden ? `${hideServices} (${associatedServices.length}) \u25B4` : `${viewServices} (${associatedServices.length}) \u25BE`;
|
|
1514
1876
|
}
|
|
1515
1877
|
}
|
|
1516
1878
|
});
|
|
@@ -1540,6 +1902,12 @@ var PreferencesModal = class {
|
|
|
1540
1902
|
handlers.onClose();
|
|
1541
1903
|
this.close();
|
|
1542
1904
|
});
|
|
1905
|
+
backdrop.addEventListener("click", (e) => {
|
|
1906
|
+
if (e.target === backdrop) {
|
|
1907
|
+
handlers.onClose();
|
|
1908
|
+
this.close();
|
|
1909
|
+
}
|
|
1910
|
+
});
|
|
1543
1911
|
(_e = footer.querySelector("#consent-pref-reject")) == null ? void 0 : _e.addEventListener("click", () => {
|
|
1544
1912
|
handlers.onRejectAll();
|
|
1545
1913
|
this.close();
|
|
@@ -1584,6 +1952,9 @@ var PreferencesModal = class {
|
|
|
1584
1952
|
const firstFocusable = dialog.querySelector("button");
|
|
1585
1953
|
firstFocusable == null ? void 0 : firstFocusable.focus();
|
|
1586
1954
|
}
|
|
1955
|
+
getIsOpen() {
|
|
1956
|
+
return this.backdrop !== null;
|
|
1957
|
+
}
|
|
1587
1958
|
close() {
|
|
1588
1959
|
if (this._keyListener) {
|
|
1589
1960
|
document.removeEventListener("keydown", this._keyListener);
|
|
@@ -1600,6 +1971,109 @@ var PreferencesModal = class {
|
|
|
1600
1971
|
}
|
|
1601
1972
|
};
|
|
1602
1973
|
|
|
1974
|
+
// src/ui/floating-badge.ts
|
|
1975
|
+
var FloatingBadge = class {
|
|
1976
|
+
constructor() {
|
|
1977
|
+
this.element = null;
|
|
1978
|
+
this.isVisible = false;
|
|
1979
|
+
}
|
|
1980
|
+
getIconSvg(icon) {
|
|
1981
|
+
switch (icon) {
|
|
1982
|
+
case "shield":
|
|
1983
|
+
return `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
1984
|
+
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
|
|
1985
|
+
<path d="m9 12 2 2 4-4"/>
|
|
1986
|
+
</svg>`;
|
|
1987
|
+
case "settings":
|
|
1988
|
+
return `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
1989
|
+
<circle cx="12" cy="12" r="3"/>
|
|
1990
|
+
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
|
1991
|
+
</svg>`;
|
|
1992
|
+
case "cookie":
|
|
1993
|
+
default:
|
|
1994
|
+
return `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
1995
|
+
<path d="M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5"/>
|
|
1996
|
+
<path d="M8.5 8.5v.01"/>
|
|
1997
|
+
<path d="M16 15.5v.01"/>
|
|
1998
|
+
<path d="M12 12v.01"/>
|
|
1999
|
+
<path d="M11 17v.01"/>
|
|
2000
|
+
<path d="M7 13v.01"/>
|
|
2001
|
+
</svg>`;
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
render(config, handlers) {
|
|
2005
|
+
var _a, _b, _c;
|
|
2006
|
+
if (typeof document === "undefined") return;
|
|
2007
|
+
this.remove();
|
|
2008
|
+
injectStyles((_a = config.csp) == null ? void 0 : _a.nonce);
|
|
2009
|
+
const badgeConfig = typeof ((_b = config.ui) == null ? void 0 : _b.floatingBadge) === "object" && ((_c = config.ui) == null ? void 0 : _c.floatingBadge) !== null ? config.ui.floatingBadge : {};
|
|
2010
|
+
const position = badgeConfig.position || "bottom-left";
|
|
2011
|
+
const labelText = badgeConfig.label ? sanitizeHtml(badgeConfig.label) : "";
|
|
2012
|
+
const ariaLabel = badgeConfig.ariaLabel ? sanitizeHtml(badgeConfig.ariaLabel) : labelText || "Configuraci\xF3n y revocaci\xF3n de cookies";
|
|
2013
|
+
const tooltipText = badgeConfig.tooltip ? sanitizeHtml(badgeConfig.tooltip) : labelText || "Configurar o declinar cookies";
|
|
2014
|
+
const showLabel = badgeConfig.showLabel === true && !!labelText;
|
|
2015
|
+
const iconSvg = this.getIconSvg(badgeConfig.icon);
|
|
2016
|
+
const container = document.createElement("div");
|
|
2017
|
+
container.className = `consent-floating-badge consent-floating-badge--${position}`;
|
|
2018
|
+
container.setAttribute("role", "complementary");
|
|
2019
|
+
container.setAttribute("aria-label", ariaLabel);
|
|
2020
|
+
container.innerHTML = `
|
|
2021
|
+
<div class="consent-floating-badge-inner">
|
|
2022
|
+
<button
|
|
2023
|
+
type="button"
|
|
2024
|
+
class="consent-floating-badge-btn ${showLabel ? "has-label" : ""}"
|
|
2025
|
+
id="consent-floating-trigger"
|
|
2026
|
+
data-consent-open
|
|
2027
|
+
aria-label="${ariaLabel}"
|
|
2028
|
+
>
|
|
2029
|
+
<span class="consent-floating-badge-icon" aria-hidden="true">
|
|
2030
|
+
${iconSvg}
|
|
2031
|
+
</span>
|
|
2032
|
+
${showLabel ? `<span class="consent-floating-badge-text">${labelText}</span>` : ""}
|
|
2033
|
+
</button>
|
|
2034
|
+
<div class="consent-floating-badge-tooltip" role="tooltip" aria-hidden="true">
|
|
2035
|
+
${tooltipText}
|
|
2036
|
+
</div>
|
|
2037
|
+
</div>
|
|
2038
|
+
`;
|
|
2039
|
+
const button = container.querySelector("#consent-floating-trigger");
|
|
2040
|
+
button == null ? void 0 : button.addEventListener("click", (e) => {
|
|
2041
|
+
e.preventDefault();
|
|
2042
|
+
handlers.onClick();
|
|
2043
|
+
});
|
|
2044
|
+
document.body.appendChild(container);
|
|
2045
|
+
this.element = container;
|
|
2046
|
+
}
|
|
2047
|
+
show() {
|
|
2048
|
+
if (this.element) {
|
|
2049
|
+
this.element.classList.add("is-visible");
|
|
2050
|
+
this.isVisible = true;
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
hide() {
|
|
2054
|
+
if (this.element) {
|
|
2055
|
+
this.element.classList.remove("is-visible");
|
|
2056
|
+
this.isVisible = false;
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
getIsVisible() {
|
|
2060
|
+
return this.isVisible;
|
|
2061
|
+
}
|
|
2062
|
+
hasElement() {
|
|
2063
|
+
return this.element !== null;
|
|
2064
|
+
}
|
|
2065
|
+
getElement() {
|
|
2066
|
+
return this.element;
|
|
2067
|
+
}
|
|
2068
|
+
remove() {
|
|
2069
|
+
if (this.element && this.element.parentNode) {
|
|
2070
|
+
this.element.parentNode.removeChild(this.element);
|
|
2071
|
+
this.element = null;
|
|
2072
|
+
this.isVisible = false;
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
2076
|
+
|
|
1603
2077
|
// src/diagnostics/resource-scanner.ts
|
|
1604
2078
|
var ResourceScanner = class _ResourceScanner {
|
|
1605
2079
|
static runDiagnostic(_config, isConsentGiven) {
|
|
@@ -1626,42 +2100,194 @@ var ResourceScanner = class _ResourceScanner {
|
|
|
1626
2100
|
|
|
1627
2101
|
// src/ui/policy-generator.ts
|
|
1628
2102
|
var PolicyGenerator = class {
|
|
1629
|
-
|
|
2103
|
+
/**
|
|
2104
|
+
* Extract all cookie and storage key details across categories and services (including presets).
|
|
2105
|
+
*/
|
|
2106
|
+
static extractCookieRows(config) {
|
|
2107
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
2108
|
+
const rows = [];
|
|
2109
|
+
if (config.services) {
|
|
2110
|
+
for (const [srvId, srv] of Object.entries(config.services)) {
|
|
2111
|
+
const cat = config.categories[srv.category || "necessary"] || { label: srv.category || "General" };
|
|
2112
|
+
const providerName = srv.provider || srv.label || srvId;
|
|
2113
|
+
if (srv.cookies && srv.cookies.length > 0) {
|
|
2114
|
+
for (const c of srv.cookies) {
|
|
2115
|
+
rows.push({
|
|
2116
|
+
name: c.name,
|
|
2117
|
+
type: "Cookie",
|
|
2118
|
+
provider: providerName,
|
|
2119
|
+
purpose: c.purpose || srv.description || cat.description || "Funcionalidad del servicio",
|
|
2120
|
+
duration: c.duration || "Persistente",
|
|
2121
|
+
categoryLabel: cat.label,
|
|
2122
|
+
policyUrl: srv.policyUrl
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
if (srv.storageKeys && srv.storageKeys.length > 0) {
|
|
2127
|
+
for (const k of srv.storageKeys) {
|
|
2128
|
+
rows.push({
|
|
2129
|
+
name: k,
|
|
2130
|
+
type: "localStorage",
|
|
2131
|
+
provider: providerName,
|
|
2132
|
+
purpose: srv.description || cat.description || "Almacenamiento de estado y preferencias",
|
|
2133
|
+
duration: "Persistente",
|
|
2134
|
+
categoryLabel: cat.label,
|
|
2135
|
+
policyUrl: srv.policyUrl
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
if (srv.localStorage && srv.localStorage.length > 0) {
|
|
2140
|
+
for (const k of srv.localStorage) {
|
|
2141
|
+
rows.push({
|
|
2142
|
+
name: k,
|
|
2143
|
+
type: "localStorage",
|
|
2144
|
+
provider: providerName,
|
|
2145
|
+
purpose: srv.description || cat.description || "Almacenamiento web local",
|
|
2146
|
+
duration: "Persistente",
|
|
2147
|
+
categoryLabel: cat.label,
|
|
2148
|
+
policyUrl: srv.policyUrl
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
if (srv.sessionStorage && srv.sessionStorage.length > 0) {
|
|
2153
|
+
for (const k of srv.sessionStorage) {
|
|
2154
|
+
rows.push({
|
|
2155
|
+
name: k,
|
|
2156
|
+
type: "sessionStorage",
|
|
2157
|
+
provider: providerName,
|
|
2158
|
+
purpose: srv.description || cat.description || "Almacenamiento temporal de sesi\xF3n",
|
|
2159
|
+
duration: "Sesi\xF3n",
|
|
2160
|
+
categoryLabel: cat.label,
|
|
2161
|
+
policyUrl: srv.policyUrl
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
if (!((_a = srv.cookies) == null ? void 0 : _a.length) && !((_b = srv.storageKeys) == null ? void 0 : _b.length) && !((_c = srv.localStorage) == null ? void 0 : _c.length) && !((_d = srv.sessionStorage) == null ? void 0 : _d.length)) {
|
|
2166
|
+
rows.push({
|
|
2167
|
+
name: srvId,
|
|
2168
|
+
type: "Cookie",
|
|
2169
|
+
provider: providerName,
|
|
2170
|
+
purpose: srv.description || cat.description || "Servicio integrado",
|
|
2171
|
+
duration: "Variable",
|
|
2172
|
+
categoryLabel: cat.label,
|
|
2173
|
+
policyUrl: srv.policyUrl
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
if (config.categories) {
|
|
2179
|
+
for (const [, cat] of Object.entries(config.categories)) {
|
|
2180
|
+
if (cat.storageKeys) {
|
|
2181
|
+
for (const k of cat.storageKeys) {
|
|
2182
|
+
if (!rows.some((r) => r.name === k)) {
|
|
2183
|
+
rows.push({
|
|
2184
|
+
name: k,
|
|
2185
|
+
type: "localStorage",
|
|
2186
|
+
provider: "Propia / Sitio Web",
|
|
2187
|
+
purpose: cat.description,
|
|
2188
|
+
duration: "Persistente",
|
|
2189
|
+
categoryLabel: cat.label
|
|
2190
|
+
});
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
if (cat.localStorage) {
|
|
2195
|
+
for (const k of cat.localStorage) {
|
|
2196
|
+
if (!rows.some((r) => r.name === k)) {
|
|
2197
|
+
rows.push({
|
|
2198
|
+
name: k,
|
|
2199
|
+
type: "localStorage",
|
|
2200
|
+
provider: "Propia / Sitio Web",
|
|
2201
|
+
purpose: cat.description,
|
|
2202
|
+
duration: "Persistente",
|
|
2203
|
+
categoryLabel: cat.label
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
if (cat.sessionStorage) {
|
|
2209
|
+
for (const k of cat.sessionStorage) {
|
|
2210
|
+
if (!rows.some((r) => r.name === k)) {
|
|
2211
|
+
rows.push({
|
|
2212
|
+
name: k,
|
|
2213
|
+
type: "sessionStorage",
|
|
2214
|
+
provider: "Propia / Sitio Web",
|
|
2215
|
+
purpose: cat.description,
|
|
2216
|
+
duration: "Sesi\xF3n",
|
|
2217
|
+
categoryLabel: cat.label
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
const consentCookieName = ((_e = config.storage) == null ? void 0 : _e.name) || "site_consent";
|
|
2225
|
+
if (!rows.some((r) => r.name === consentCookieName)) {
|
|
2226
|
+
rows.unshift({
|
|
2227
|
+
name: consentCookieName,
|
|
2228
|
+
type: ((_f = config.storage) == null ? void 0 : _f.type) === "memory" ? "localStorage" : "Cookie",
|
|
2229
|
+
provider: "Propia (Solvenza Cookies Compliance)",
|
|
2230
|
+
purpose: "Guarda las preferencias y recibo firmado de consentimiento del usuario.",
|
|
2231
|
+
duration: `${(_h = (_g = config.consent) == null ? void 0 : _g.maxAgeDays) != null ? _h : 365} d\xEDas`,
|
|
2232
|
+
categoryLabel: ((_j = (_i = config.categories) == null ? void 0 : _i.necessary) == null ? void 0 : _j.label) || "Necesarias"
|
|
2233
|
+
});
|
|
2234
|
+
}
|
|
2235
|
+
return rows;
|
|
2236
|
+
}
|
|
2237
|
+
/**
|
|
2238
|
+
* Render stylized table of cookies and storage keys.
|
|
2239
|
+
*/
|
|
2240
|
+
static renderTable(config, options = {}) {
|
|
2241
|
+
const isDark = options.theme === "dark";
|
|
2242
|
+
const bgHeader = isDark ? "#1e293b" : "#f8fafc";
|
|
2243
|
+
const borderCol = isDark ? "#334155" : "#e2e8f0";
|
|
2244
|
+
const textCol = isDark ? "#f8fafc" : "#0f172a";
|
|
2245
|
+
const mutedCol = isDark ? "#94a3b8" : "#64748b";
|
|
2246
|
+
const rowAltBg = isDark ? "#0f172a" : "#ffffff";
|
|
2247
|
+
const rowBg = isDark ? "#1e293b" : "#f8fafc";
|
|
1630
2248
|
let html = `
|
|
1631
|
-
<div class="
|
|
1632
|
-
<table style="width: 100%; border-collapse: collapse; text-align: left;
|
|
2249
|
+
<div class="solvenza-policy-table-wrapper" style="overflow-x: auto; margin: 1.5rem 0; border: 1px solid ${borderCol}; border-radius: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); font-family: system-ui, -apple-system, sans-serif;">
|
|
2250
|
+
<table style="width: 100%; border-collapse: collapse; text-align: left; font-size: 0.88rem; color: ${textCol};">
|
|
1633
2251
|
<thead>
|
|
1634
|
-
<tr style="background:
|
|
1635
|
-
<th style="padding: 0.
|
|
1636
|
-
<th style="padding: 0.
|
|
1637
|
-
<th style="padding: 0.
|
|
1638
|
-
<th style="padding: 0.
|
|
2252
|
+
<tr style="background: ${bgHeader}; border-bottom: 2px solid ${borderCol};">
|
|
2253
|
+
<th style="padding: 0.85rem 1rem; font-weight: 700;">Nombre / Clave</th>
|
|
2254
|
+
<th style="padding: 0.85rem 1rem; font-weight: 700;">Tipo</th>
|
|
2255
|
+
<th style="padding: 0.85rem 1rem; font-weight: 700;">Categor\xEDa</th>
|
|
2256
|
+
<th style="padding: 0.85rem 1rem; font-weight: 700;">Proveedor</th>
|
|
2257
|
+
<th style="padding: 0.85rem 1rem; font-weight: 700;">Finalidad</th>
|
|
2258
|
+
<th style="padding: 0.85rem 1rem; font-weight: 700;">Duraci\xF3n</th>
|
|
1639
2259
|
</tr>
|
|
1640
2260
|
</thead>
|
|
1641
2261
|
<tbody>
|
|
1642
2262
|
`;
|
|
1643
|
-
|
|
1644
|
-
|
|
2263
|
+
const rows = this.extractCookieRows(config);
|
|
2264
|
+
if (rows.length === 0) {
|
|
1645
2265
|
html += `
|
|
1646
|
-
<tr
|
|
1647
|
-
<td style="padding:
|
|
1648
|
-
|
|
2266
|
+
<tr>
|
|
2267
|
+
<td colspan="6" style="padding: 1.5rem; text-align: center; color: ${mutedCol};">
|
|
2268
|
+
No se han registrado cookies ni elementos de almacenamiento en la configuraci\xF3n.
|
|
2269
|
+
</td>
|
|
1649
2270
|
</tr>
|
|
1650
2271
|
`;
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
2272
|
+
} else {
|
|
2273
|
+
rows.forEach((r, idx) => {
|
|
2274
|
+
const bg = idx % 2 === 0 ? rowAltBg : rowBg;
|
|
2275
|
+
const providerHtml = r.policyUrl ? `<a href="${sanitizeHtml(r.policyUrl)}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${sanitizeHtml(r.provider)} \u2197</a>` : sanitizeHtml(r.provider);
|
|
2276
|
+
html += `
|
|
2277
|
+
<tr style="background: ${bg}; border-bottom: 1px solid ${borderCol};">
|
|
2278
|
+
<td style="padding: 0.75rem 1rem; font-family: monospace; font-weight: 600; color: #2563eb;">${sanitizeHtml(r.name)}</td>
|
|
2279
|
+
<td style="padding: 0.75rem 1rem;">
|
|
2280
|
+
<span style="display: inline-block; padding: 0.15rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-weight: 600; background: ${r.type === "Cookie" ? "#e0e7ff" : "#fef3c7"}; color: ${r.type === "Cookie" ? "#3730a3" : "#92400e"};">
|
|
2281
|
+
${r.type}
|
|
2282
|
+
</span>
|
|
2283
|
+
</td>
|
|
2284
|
+
<td style="padding: 0.75rem 1rem; font-weight: 500;">${sanitizeHtml(r.categoryLabel)}</td>
|
|
2285
|
+
<td style="padding: 0.75rem 1rem;">${providerHtml}</td>
|
|
2286
|
+
<td style="padding: 0.75rem 1rem; color: ${mutedCol};">${sanitizeHtml(r.purpose)}</td>
|
|
2287
|
+
<td style="padding: 0.75rem 1rem; white-space: nowrap;">${sanitizeHtml(r.duration)}</td>
|
|
2288
|
+
</tr>
|
|
2289
|
+
`;
|
|
2290
|
+
});
|
|
1665
2291
|
}
|
|
1666
2292
|
html += `
|
|
1667
2293
|
</tbody>
|
|
@@ -1670,8 +2296,1164 @@ var PolicyGenerator = class {
|
|
|
1670
2296
|
`;
|
|
1671
2297
|
return html;
|
|
1672
2298
|
}
|
|
2299
|
+
/**
|
|
2300
|
+
* Render complete legal Cookie Policy document adapted to LSSI art. 22.2 and AEPD 2024.
|
|
2301
|
+
*/
|
|
2302
|
+
static renderCookiePolicy(config, options = {}) {
|
|
2303
|
+
var _a, _b, _c;
|
|
2304
|
+
if (options.view === "table-only") {
|
|
2305
|
+
return this.renderTable(config, options);
|
|
2306
|
+
}
|
|
2307
|
+
const companyName = ((_a = config.legalEntity) == null ? void 0 : _a.tradeName) || ((_b = config.legalEntity) == null ? void 0 : _b.name) || "el Titular del Sitio Web";
|
|
2308
|
+
const lastUpdated = ((_c = config.legalNotice) == null ? void 0 : _c.lastUpdated) || config.policyVersion || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2309
|
+
const isDark = options.theme === "dark";
|
|
2310
|
+
const textCol = isDark ? "#f8fafc" : "#0f172a";
|
|
2311
|
+
const mutedCol = isDark ? "#94a3b8" : "#475569";
|
|
2312
|
+
const cardBg = isDark ? "#1e293b" : "#ffffff";
|
|
2313
|
+
const borderCol = isDark ? "#334155" : "#e2e8f0";
|
|
2314
|
+
const tableHtml = this.renderTable(config, options);
|
|
2315
|
+
let html = `
|
|
2316
|
+
<article class="solvenza-cookie-policy-document ${options.className || ""}" style="font-family: system-ui, -apple-system, sans-serif; color: ${textCol}; line-height: 1.7; max-width: 900px; margin: 0 auto; padding: 1rem 0;">
|
|
2317
|
+
<header style="margin-bottom: 2rem; border-bottom: 1px solid ${borderCol}; padding-bottom: 1.5rem;">
|
|
2318
|
+
<h1 style="font-size: 1.85rem; font-weight: 800; margin: 0 0 0.5rem 0; color: ${textCol};">Pol\xEDtica de Cookies</h1>
|
|
2319
|
+
<p style="margin: 0; font-size: 0.9rem; color: ${mutedCol};">
|
|
2320
|
+
Conforme al art\xEDculo 22.2 de la Ley 34/2002 (LSSI-CE), el RGPD (UE 2016/679) y la Gu\xEDa sobre el uso de cookies de la AEPD.
|
|
2321
|
+
<br><em>\xDAltima actualizaci\xF3n: ${sanitizeHtml(lastUpdated)}</em>
|
|
2322
|
+
</p>
|
|
2323
|
+
</header>
|
|
2324
|
+
|
|
2325
|
+
<section style="margin-bottom: 2rem;">
|
|
2326
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">1. \xBFQu\xE9 son las cookies y tecnolog\xEDas de almacenamiento local?</h2>
|
|
2327
|
+
<p style="color: ${mutedCol};">
|
|
2328
|
+
Este sitio web, titularidad de <strong>${sanitizeHtml(companyName)}</strong>, utiliza cookies y tecnolog\xEDas de almacenamiento similares (tales como <code>localStorage</code>, <code>sessionStorage</code>, p\xEDxeles de seguimiento y etiquetas) para garantizar el funcionamiento t\xE9cnico del sitio, optimizar la experiencia de navegaci\xF3n, medir el uso de la web y, en su caso, mostrar contenidos personalizados o multimedia.
|
|
2329
|
+
</p>
|
|
2330
|
+
<p style="color: ${mutedCol};">
|
|
2331
|
+
Una <strong>cookie</strong> es un peque\xF1o fichero de texto que se descarga y almacena en el navegador del usuario al acceder a determinadas p\xE1ginas web. Permite a una p\xE1gina web, entre otras cosas, recordar las preferencias de navegaci\xF3n, almacenar y recuperar informaci\xF3n sobre los h\xE1bitos de visita y reconocer al usuario en visitas posteriores.
|
|
2332
|
+
</p>
|
|
2333
|
+
</section>
|
|
2334
|
+
|
|
2335
|
+
<section style="margin-bottom: 2rem;">
|
|
2336
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">2. Tipos de cookies y finalidades utilizadas</h2>
|
|
2337
|
+
<p style="color: ${mutedCol};">
|
|
2338
|
+
En funci\xF3n de su finalidad, titularidad y plazo de permanencia, en este sitio web se utilizan las siguientes categor\xEDas:
|
|
2339
|
+
</p>
|
|
2340
|
+
<ul style="color: ${mutedCol}; padding-left: 1.5rem; margin-bottom: 1.5rem;">
|
|
2341
|
+
`;
|
|
2342
|
+
for (const [, cat] of Object.entries(config.categories)) {
|
|
2343
|
+
const isReq = cat.required === true;
|
|
2344
|
+
html += `
|
|
2345
|
+
<li style="margin-bottom: 0.6rem;">
|
|
2346
|
+
<strong>${sanitizeHtml(cat.label)}</strong> (${isReq ? "T\xE9cnicas / Exentas de consentimiento" : "Opcionales / Sujetas a consentimiento"}):
|
|
2347
|
+
${sanitizeHtml(cat.description)}
|
|
2348
|
+
</li>
|
|
2349
|
+
`;
|
|
2350
|
+
}
|
|
2351
|
+
html += `
|
|
2352
|
+
</ul>
|
|
2353
|
+
|
|
2354
|
+
<h3 style="font-size: 1.1rem; font-weight: 700; color: ${textCol}; margin-top: 1.5rem;">Inventario detallado de cookies y almacenamiento web</h3>
|
|
2355
|
+
<p style="color: ${mutedCol}; font-size: 0.9rem;">
|
|
2356
|
+
A continuaci\xF3n se detallan de forma transparente todas las cookies y claves de almacenamiento registradas en la aplicaci\xF3n:
|
|
2357
|
+
</p>
|
|
2358
|
+
${tableHtml}
|
|
2359
|
+
</section>
|
|
2360
|
+
|
|
2361
|
+
<section style="margin-bottom: 2rem; background: ${cardBg}; border: 1px solid ${borderCol}; border-radius: 12px; padding: 1.5rem; box-shadow: 0 2px 4px rgba(0,0,0,0.03);">
|
|
2362
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol}; margin-top: 0;">3. Gesti\xF3n, configuraci\xF3n y revocaci\xF3n del consentimiento</h2>
|
|
2363
|
+
<p style="color: ${mutedCol};">
|
|
2364
|
+
De acuerdo con las directrices de la Agencia Espa\xF1ola de Protecci\xF3n de Datos (AEPD), retirar o modificar el consentimiento debe ser tan f\xE1cil como otorgarlo. Puedes modificar tus preferencias o revocar el consentimiento en cualquier momento:
|
|
2365
|
+
</p>
|
|
2366
|
+
<div style="display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.25rem;">
|
|
2367
|
+
<button
|
|
2368
|
+
type="button"
|
|
2369
|
+
data-consent-open
|
|
2370
|
+
onclick="if(window.Consent) window.Consent.openPreferences()"
|
|
2371
|
+
style="background: #0f172a; color: #ffffff; border: none; padding: 0.65rem 1.3rem; border-radius: 8px; font-weight: 600; font-size: 0.9rem; cursor: pointer; display: inline-flex; align-items: center; gap: 0.5rem;"
|
|
2372
|
+
>
|
|
2373
|
+
\u2699\uFE0F Abrir panel de preferencias de cookies
|
|
2374
|
+
</button>
|
|
2375
|
+
<button
|
|
2376
|
+
type="button"
|
|
2377
|
+
onclick="if(window.Consent) window.Consent.withdraw()"
|
|
2378
|
+
style="background: #ffffff; color: #dc2626; border: 1px solid #fca5a5; padding: 0.65rem 1.3rem; border-radius: 8px; font-weight: 600; font-size: 0.9rem; cursor: pointer; display: inline-flex; align-items: center; gap: 0.5rem;"
|
|
2379
|
+
>
|
|
2380
|
+
\u{1F504} Revocar consentimiento y purgar datos
|
|
2381
|
+
</button>
|
|
2382
|
+
</div>
|
|
2383
|
+
</section>
|
|
2384
|
+
|
|
2385
|
+
<section style="margin-bottom: 2rem;">
|
|
2386
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">4. C\xF3mo deshabilitar o eliminar las cookies en los navegadores</h2>
|
|
2387
|
+
<p style="color: ${mutedCol};">
|
|
2388
|
+
El usuario puede permitir, bloquear o eliminar las cookies instaladas en su equipo mediante la configuraci\xF3n de las opciones de su navegador web:
|
|
2389
|
+
</p>
|
|
2390
|
+
<ul style="color: #2563eb; padding-left: 1.5rem;">
|
|
2391
|
+
<li style="margin-bottom: 0.4rem;"><a href="https://support.google.com/chrome/answer/95647" target="_blank" rel="noopener noreferrer" style="color: inherit; text-decoration: underline;">Google Chrome</a></li>
|
|
2392
|
+
<li style="margin-bottom: 0.4rem;"><a href="https://support.mozilla.org/es/kb/habilitar-y-deshabilitar-cookies-sitios-web-rastrear-preferencias" target="_blank" rel="noopener noreferrer" style="color: inherit; text-decoration: underline;">Mozilla Firefox</a></li>
|
|
2393
|
+
<li style="margin-bottom: 0.4rem;"><a href="https://support.apple.com/es-es/guide/safari/sfri11471/mac" target="_blank" rel="noopener noreferrer" style="color: inherit; text-decoration: underline;">Apple Safari</a></li>
|
|
2394
|
+
<li style="margin-bottom: 0.4rem;"><a href="https://support.microsoft.com/es-es/microsoft-edge/eliminar-las-cookies-en-microsoft-edge-63947406-40ac-c3b8-57b9-2a946a29ae09" target="_blank" rel="noopener noreferrer" style="color: inherit; text-decoration: underline;">Microsoft Edge</a></li>
|
|
2395
|
+
<li style="margin-bottom: 0.4rem;"><a href="https://help.opera.com/en/latest/web-preferences/#cookies" target="_blank" rel="noopener noreferrer" style="color: inherit; text-decoration: underline;">Opera Browser</a></li>
|
|
2396
|
+
</ul>
|
|
2397
|
+
</section>
|
|
2398
|
+
|
|
2399
|
+
<section style="margin-bottom: 2rem;">
|
|
2400
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">5. Reconocimiento de Global Privacy Control (GPC)</h2>
|
|
2401
|
+
<p style="color: ${mutedCol};">
|
|
2402
|
+
Este sitio web est\xE1 adaptado al est\xE1ndar <strong>Global Privacy Control (GPC)</strong> y a la cabecera <code>Do Not Track (DNT)</code>. Si tu navegador emite una se\xF1al universal de no seguimiento, nuestro sistema desactivar\xE1 autom\xE1ticamente todas las cookies no necesarias sin requerir interacci\xF3n manual.
|
|
2403
|
+
</p>
|
|
2404
|
+
</section>
|
|
2405
|
+
|
|
2406
|
+
<section style="margin-bottom: 2rem;">
|
|
2407
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">6. Transferencias internacionales de datos</h2>
|
|
2408
|
+
<p style="color: ${mutedCol};">
|
|
2409
|
+
Determinadas cookies de terceros (tales como Google Analytics o Meta) pueden implicar la transferencia internacional de datos a servidores ubicados en Estados Unidos u otros pa\xEDses fuera del Espacio Econ\xF3mico Europeo (EEE). Dichas transferencias se encuentran amparadas bajo el Marco de Privacidad de Datos UE-EE.UU. (Data Privacy Framework) o Cl\xE1usulas Contractuales Tipo aprobadas por la Comisi\xF3n Europea.
|
|
2410
|
+
</p>
|
|
2411
|
+
</section>
|
|
2412
|
+
</article>
|
|
2413
|
+
`;
|
|
2414
|
+
return html;
|
|
2415
|
+
}
|
|
2416
|
+
/**
|
|
2417
|
+
* Render complete legal notice (Aviso Legal) conforming to LSSI-CE Art. 10.
|
|
2418
|
+
*/
|
|
2419
|
+
static renderLegalNotice(config, options = {}) {
|
|
2420
|
+
var _a, _b, _c;
|
|
2421
|
+
const entity = config.legalEntity || {
|
|
2422
|
+
name: "[Raz\xF3n Social del Titular]",
|
|
2423
|
+
taxId: "[NIF / CIF]",
|
|
2424
|
+
address: "[Domicilio Social]",
|
|
2425
|
+
email: "[Email de Contacto]"
|
|
2426
|
+
};
|
|
2427
|
+
const law = ((_a = config.legalNotice) == null ? void 0 : _a.applicableLaw) || "Legislaci\xF3n espa\xF1ola (LSSI-CE, LOPDGDD) y Reglamento General de Protecci\xF3n de Datos (RGPD UE 2016/679)";
|
|
2428
|
+
const jurisdiction = ((_b = config.legalNotice) == null ? void 0 : _b.jurisdiction) || "Juzgados y Tribunales competentes conforme a la normativa de consumidores y usuarios";
|
|
2429
|
+
const lastUpdated = ((_c = config.legalNotice) == null ? void 0 : _c.lastUpdated) || config.policyVersion || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2430
|
+
const isDark = options.theme === "dark";
|
|
2431
|
+
const textCol = isDark ? "#f8fafc" : "#0f172a";
|
|
2432
|
+
const mutedCol = isDark ? "#94a3b8" : "#475569";
|
|
2433
|
+
const borderCol = isDark ? "#334155" : "#e2e8f0";
|
|
2434
|
+
return `
|
|
2435
|
+
<article class="solvenza-legal-notice-document ${options.className || ""}" style="font-family: system-ui, -apple-system, sans-serif; color: ${textCol}; line-height: 1.7; max-width: 900px; margin: 0 auto; padding: 1rem 0;">
|
|
2436
|
+
<header style="margin-bottom: 2rem; border-bottom: 1px solid ${borderCol}; padding-bottom: 1.5rem;">
|
|
2437
|
+
<h1 style="font-size: 1.85rem; font-weight: 800; margin: 0 0 0.5rem 0; color: ${textCol};">Aviso Legal</h1>
|
|
2438
|
+
<p style="margin: 0; font-size: 0.9rem; color: ${mutedCol};">
|
|
2439
|
+
En cumplimiento del art\xEDculo 10 de la Ley 34/2002, de 11 de julio, de Servicios de la Sociedad de la Informaci\xF3n y de Comercio Electr\xF3nico (LSSI-CE).
|
|
2440
|
+
<br><em>\xDAltima actualizaci\xF3n: ${sanitizeHtml(lastUpdated)}</em>
|
|
2441
|
+
</p>
|
|
2442
|
+
</header>
|
|
2443
|
+
|
|
2444
|
+
<section style="margin-bottom: 2rem;">
|
|
2445
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">1. Datos identificativos del titular</h2>
|
|
2446
|
+
<table style="width: 100%; border-collapse: collapse; margin-top: 1rem; border: 1px solid ${borderCol};">
|
|
2447
|
+
<tbody>
|
|
2448
|
+
<tr style="border-bottom: 1px solid ${borderCol};">
|
|
2449
|
+
<td style="padding: 0.75rem 1rem; font-weight: 600; width: 30%;">Raz\xF3n Social:</td>
|
|
2450
|
+
<td style="padding: 0.75rem 1rem; color: ${mutedCol};">${sanitizeHtml(entity.name)}</td>
|
|
2451
|
+
</tr>
|
|
2452
|
+
${entity.tradeName ? `<tr style="border-bottom: 1px solid ${borderCol};"><td style="padding: 0.75rem 1rem; font-weight: 600;">Nombre Comercial:</td><td style="padding: 0.75rem 1rem; color: ${mutedCol};">${sanitizeHtml(entity.tradeName)}</td></tr>` : ""}
|
|
2453
|
+
<tr style="border-bottom: 1px solid ${borderCol};">
|
|
2454
|
+
<td style="padding: 0.75rem 1rem; font-weight: 600;">NIF / CIF:</td>
|
|
2455
|
+
<td style="padding: 0.75rem 1rem; color: ${mutedCol};">${sanitizeHtml(entity.taxId || "-")}</td>
|
|
2456
|
+
</tr>
|
|
2457
|
+
<tr style="border-bottom: 1px solid ${borderCol};">
|
|
2458
|
+
<td style="padding: 0.75rem 1rem; font-weight: 600;">Domicilio Social:</td>
|
|
2459
|
+
<td style="padding: 0.75rem 1rem; color: ${mutedCol};">${sanitizeHtml(entity.address || "-")}</td>
|
|
2460
|
+
</tr>
|
|
2461
|
+
<tr style="border-bottom: 1px solid ${borderCol};">
|
|
2462
|
+
<td style="padding: 0.75rem 1rem; font-weight: 600;">Correo Electr\xF3nico:</td>
|
|
2463
|
+
<td style="padding: 0.75rem 1rem; color: ${mutedCol};"><a href="mailto:${sanitizeHtml(entity.email || "")}" style="color: #2563eb;">${sanitizeHtml(entity.email || "-")}</a></td>
|
|
2464
|
+
</tr>
|
|
2465
|
+
${entity.phone ? `<tr style="border-bottom: 1px solid ${borderCol};"><td style="padding: 0.75rem 1rem; font-weight: 600;">Tel\xE9fono:</td><td style="padding: 0.75rem 1rem; color: ${mutedCol};">${sanitizeHtml(entity.phone)}</td></tr>` : ""}
|
|
2466
|
+
${entity.registryData ? `<tr style="border-bottom: 1px solid ${borderCol};"><td style="padding: 0.75rem 1rem; font-weight: 600;">Datos Registrales:</td><td style="padding: 0.75rem 1rem; color: ${mutedCol};">${sanitizeHtml(entity.registryData)}</td></tr>` : ""}
|
|
2467
|
+
${entity.dpoEmail ? `<tr><td style="padding: 0.75rem 1rem; font-weight: 600;">Delegado de Protecci\xF3n de Datos (DPO):</td><td style="padding: 0.75rem 1rem; color: ${mutedCol};"><a href="mailto:${sanitizeHtml(entity.dpoEmail)}" style="color: #2563eb;">${sanitizeHtml(entity.dpoEmail)}</a></td></tr>` : ""}
|
|
2468
|
+
</tbody>
|
|
2469
|
+
</table>
|
|
2470
|
+
</section>
|
|
2471
|
+
|
|
2472
|
+
<section style="margin-bottom: 2rem;">
|
|
2473
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">2. Condiciones generales de uso</h2>
|
|
2474
|
+
<p style="color: ${mutedCol};">
|
|
2475
|
+
El acceso y/o uso de este sitio web atribuye la condici\xF3n de usuario, que acepta, desde dicho acceso y/o uso, las presentes condiciones generales. El usuario se compromete a hacer un uso adecuado de los contenidos y servicios que el titular ofrece a trav\xE9s de su sitio web y a no emplearlos para incurrir en actividades il\xEDcitas o contrarias a la buena fe y al orden p\xFAblico.
|
|
2476
|
+
</p>
|
|
2477
|
+
</section>
|
|
2478
|
+
|
|
2479
|
+
<section style="margin-bottom: 2rem;">
|
|
2480
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">3. Propiedad intelectual e industrial</h2>
|
|
2481
|
+
<p style="color: ${mutedCol};">
|
|
2482
|
+
Todos los derechos de propiedad intelectual e industrial sobre el dise\xF1o, marcas, logotipos, textos, c\xF3digo fuente e ilustraciones de este sitio web corresponden al titular o a sus leg\xEDtimos licenciantes. Queda expresamente prohibida la reproducci\xF3n, distribuci\xF3n o comunicaci\xF3n p\xFAblica de la totalidad o parte de los contenidos sin autorizaci\xF3n previa y por escrito.
|
|
2483
|
+
</p>
|
|
2484
|
+
</section>
|
|
2485
|
+
|
|
2486
|
+
<section style="margin-bottom: 2rem;">
|
|
2487
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">4. Exclusi\xF3n de garant\xEDas y responsabilidad</h2>
|
|
2488
|
+
<p style="color: ${mutedCol};">
|
|
2489
|
+
El titular no se hace responsable, en ning\xFAn caso, de los da\xF1os y perjuicios de cualquier naturaleza que pudieran ocasionar errores u omisiones en los contenidos, falta de disponibilidad del portal o la transmisi\xF3n de virus o programas maliciosos, a pesar de haber adoptado todas las medidas tecnol\xF3gicas necesarias para evitarlo.
|
|
2490
|
+
</p>
|
|
2491
|
+
</section>
|
|
2492
|
+
|
|
2493
|
+
<section style="margin-bottom: 2rem;">
|
|
2494
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">5. Legislaci\xF3n aplicable y jurisdicci\xF3n</h2>
|
|
2495
|
+
<p style="color: ${mutedCol};">
|
|
2496
|
+
Las relaciones entre el titular y el usuario se regir\xE1n por la <strong>${sanitizeHtml(law)}</strong>. Para la resoluci\xF3n de cualquier controversia, las partes se someten a los <strong>${sanitizeHtml(jurisdiction)}</strong>, sin perjuicio de los fueros imperativos legales aplicables.
|
|
2497
|
+
</p>
|
|
2498
|
+
</section>
|
|
2499
|
+
</article>
|
|
2500
|
+
`;
|
|
2501
|
+
}
|
|
2502
|
+
/**
|
|
2503
|
+
* Render Privacy Policy document (Política de Privacidad RGPD).
|
|
2504
|
+
*/
|
|
2505
|
+
static renderPrivacyPolicy(config, options = {}) {
|
|
2506
|
+
const entity = config.legalEntity || {
|
|
2507
|
+
name: "[Raz\xF3n Social del Responsable]",
|
|
2508
|
+
taxId: "[NIF / CIF]",
|
|
2509
|
+
address: "[Domicilio]",
|
|
2510
|
+
email: "privacidad@solvenza.es"
|
|
2511
|
+
};
|
|
2512
|
+
const isDark = options.theme === "dark";
|
|
2513
|
+
const textCol = isDark ? "#f8fafc" : "#0f172a";
|
|
2514
|
+
const mutedCol = isDark ? "#94a3b8" : "#475569";
|
|
2515
|
+
const borderCol = isDark ? "#334155" : "#e2e8f0";
|
|
2516
|
+
return `
|
|
2517
|
+
<article class="solvenza-privacy-policy-document ${options.className || ""}" style="font-family: system-ui, -apple-system, sans-serif; color: ${textCol}; line-height: 1.7; max-width: 900px; margin: 0 auto; padding: 1rem 0;">
|
|
2518
|
+
<header style="margin-bottom: 2rem; border-bottom: 1px solid ${borderCol}; padding-bottom: 1.5rem;">
|
|
2519
|
+
<h1 style="font-size: 1.85rem; font-weight: 800; margin: 0 0 0.5rem 0; color: ${textCol};">Pol\xEDtica de Privacidad y Protecci\xF3n de Datos</h1>
|
|
2520
|
+
<p style="margin: 0; font-size: 0.9rem; color: ${mutedCol};">
|
|
2521
|
+
Conforme al Reglamento General de Protecci\xF3n de Datos (RGPD UE 2016/679) y la Ley Org\xE1nica 3/2018 (LOPDGDD).
|
|
2522
|
+
</p>
|
|
2523
|
+
</header>
|
|
2524
|
+
|
|
2525
|
+
<section style="margin-bottom: 2rem;">
|
|
2526
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">1. Responsable del tratamiento</h2>
|
|
2527
|
+
<p style="color: ${mutedCol};">
|
|
2528
|
+
<strong>Identidad:</strong> ${sanitizeHtml(entity.name)}<br>
|
|
2529
|
+
<strong>NIF / CIF:</strong> ${sanitizeHtml(entity.taxId || "-")}<br>
|
|
2530
|
+
<strong>Direcci\xF3n:</strong> ${sanitizeHtml(entity.address || "-")}<br>
|
|
2531
|
+
<strong>Correo electr\xF3nico:</strong> <a href="mailto:${sanitizeHtml(entity.email || "")}" style="color: #2563eb;">${sanitizeHtml(entity.email || "-")}</a><br>
|
|
2532
|
+
${entity.dpoEmail ? `<strong>Contacto DPO:</strong> <a href="mailto:${sanitizeHtml(entity.dpoEmail)}" style="color: #2563eb;">${sanitizeHtml(entity.dpoEmail)}</a>` : ""}
|
|
2533
|
+
</p>
|
|
2534
|
+
</section>
|
|
2535
|
+
|
|
2536
|
+
<section style="margin-bottom: 2rem;">
|
|
2537
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">2. Finalidad del tratamiento y base jur\xEDdica</h2>
|
|
2538
|
+
<p style="color: ${mutedCol};">
|
|
2539
|
+
Tratamos los datos facilitados por los usuarios con las finalidades de gestionar sus solicitudes, prestar los servicios contratados y, en su caso, analizar el rendimiento de la web y remitir comunicaciones comerciales sobre la base de su <strong>consentimiento expl\xEDcito</strong> (art. 6.1.a RGPD) o en la <strong>ejecuci\xF3n contractual</strong> (art. 6.1.b RGPD).
|
|
2540
|
+
</p>
|
|
2541
|
+
</section>
|
|
2542
|
+
|
|
2543
|
+
<section style="margin-bottom: 2rem;">
|
|
2544
|
+
<h2 style="font-size: 1.3rem; font-weight: 700; color: ${textCol};">3. Derechos del interesado</h2>
|
|
2545
|
+
<p style="color: ${mutedCol};">
|
|
2546
|
+
Cualquier persona tiene derecho a obtener confirmaci\xF3n sobre si estamos tratando datos personales que le conciernen. Los interesados tienen derecho a acceder a sus datos personales, solicitar la rectificaci\xF3n de los datos inexactos o, en su caso, solicitar su supresi\xF3n cuando los datos ya no sean necesarios para los fines que fueron recogidos.
|
|
2547
|
+
</p>
|
|
2548
|
+
<p style="color: ${mutedCol};">
|
|
2549
|
+
Puedes ejercer tus derechos de Acceso, Rectificaci\xF3n, Supresi\xF3n, Limitaci\xF3n, Portabilidad y Oposici\xF3n enviando un correo a <a href="mailto:${sanitizeHtml(entity.email || "")}" style="color: #2563eb;">${sanitizeHtml(entity.email || "")}</a>. Asimismo, puedes presentar una reclamaci\xF3n ante la Agencia Espa\xF1ola de Protecci\xF3n de Datos (<a href="https://www.aepd.es" target="_blank" rel="noopener noreferrer" style="color: #2563eb;">www.aepd.es</a>).
|
|
2550
|
+
</p>
|
|
2551
|
+
</section>
|
|
2552
|
+
</article>
|
|
2553
|
+
`;
|
|
2554
|
+
}
|
|
1673
2555
|
};
|
|
1674
2556
|
|
|
2557
|
+
// src/i18n/engine.ts
|
|
2558
|
+
var BUILTIN_TRANSLATIONS = {
|
|
2559
|
+
es: {
|
|
2560
|
+
ui: {
|
|
2561
|
+
banner: {
|
|
2562
|
+
title: "Tu privacidad, bajo tu control",
|
|
2563
|
+
description: "Usamos tecnolog\xEDas necesarias para el funcionamiento del sitio. Con tu permiso, tambi\xE9n podemos utilizar anal\xEDtica y marketing.",
|
|
2564
|
+
accept: "Aceptar todas",
|
|
2565
|
+
reject: "Rechazar todas",
|
|
2566
|
+
configure: "Configurar",
|
|
2567
|
+
cookiesPolicy: "Pol\xEDtica de cookies",
|
|
2568
|
+
privacyPolicy: "Pol\xEDtica de privacidad",
|
|
2569
|
+
ariaLabel: "Gesti\xF3n de consentimiento de privacidad"
|
|
2570
|
+
},
|
|
2571
|
+
preferences: {
|
|
2572
|
+
title: "Preferencias de privacidad",
|
|
2573
|
+
subtitle: "Gestiona tus permisos de almacenamiento por finalidad (LSSI art. 22.2 & RGPD).",
|
|
2574
|
+
save: "Guardar selecci\xF3n",
|
|
2575
|
+
acceptAll: "Permitir todas",
|
|
2576
|
+
rejectAll: "Rechazar opcionales",
|
|
2577
|
+
closeLabel: "Cerrar ventana",
|
|
2578
|
+
requiredBadge: "Requerida",
|
|
2579
|
+
optionalBadge: "Opcional",
|
|
2580
|
+
servicesLabel: "Servicios incluidos",
|
|
2581
|
+
viewServices: "Ver servicios",
|
|
2582
|
+
hideServices: "Ocultar servicios",
|
|
2583
|
+
thirdParty: "Terceros"
|
|
2584
|
+
},
|
|
2585
|
+
floatingBadge: {
|
|
2586
|
+
label: "Cookies",
|
|
2587
|
+
ariaLabel: "Configuraci\xF3n y revocaci\xF3n de cookies",
|
|
2588
|
+
tooltip: "Configurar o declinar cookies"
|
|
2589
|
+
}
|
|
2590
|
+
},
|
|
2591
|
+
categories: {
|
|
2592
|
+
necessary: {
|
|
2593
|
+
label: "Cookies T\xE9cnicas y Necesarias",
|
|
2594
|
+
description: "Imprescindibles para que el sitio web funcione y no pueden ser desactivadas."
|
|
2595
|
+
},
|
|
2596
|
+
analytics: {
|
|
2597
|
+
label: "Medici\xF3n y Rendimiento",
|
|
2598
|
+
description: "Nos permiten analizar las visitas y fuentes de tr\xE1fico para optimizar el sitio."
|
|
2599
|
+
},
|
|
2600
|
+
marketing: {
|
|
2601
|
+
label: "Publicidad Personalizada",
|
|
2602
|
+
description: "Utilizadas para mostrar anuncios relevantes seg\xFAn tus intereses y navegaci\xF3n."
|
|
2603
|
+
},
|
|
2604
|
+
preferences: {
|
|
2605
|
+
label: "Preferencias y Personalizaci\xF3n",
|
|
2606
|
+
description: "Permiten recordar informaci\xF3n que cambia el aspecto o comportamiento del sitio."
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
},
|
|
2610
|
+
en: {
|
|
2611
|
+
ui: {
|
|
2612
|
+
banner: {
|
|
2613
|
+
title: "Your privacy, under your control",
|
|
2614
|
+
description: "We use essential technologies for our website to function. With your consent, we may also use analytics and marketing technologies.",
|
|
2615
|
+
accept: "Accept all",
|
|
2616
|
+
reject: "Reject all",
|
|
2617
|
+
configure: "Customize",
|
|
2618
|
+
cookiesPolicy: "Cookie policy",
|
|
2619
|
+
privacyPolicy: "Privacy policy",
|
|
2620
|
+
ariaLabel: "Privacy consent management"
|
|
2621
|
+
},
|
|
2622
|
+
preferences: {
|
|
2623
|
+
title: "Privacy Preferences",
|
|
2624
|
+
subtitle: "Manage your storage permissions by purpose (GDPR & ePrivacy compliant).",
|
|
2625
|
+
save: "Save preferences",
|
|
2626
|
+
acceptAll: "Allow all",
|
|
2627
|
+
rejectAll: "Reject optional",
|
|
2628
|
+
closeLabel: "Close dialog",
|
|
2629
|
+
requiredBadge: "Required",
|
|
2630
|
+
optionalBadge: "Optional",
|
|
2631
|
+
servicesLabel: "Included services",
|
|
2632
|
+
viewServices: "View services",
|
|
2633
|
+
hideServices: "Hide services",
|
|
2634
|
+
thirdParty: "Third-party"
|
|
2635
|
+
},
|
|
2636
|
+
floatingBadge: {
|
|
2637
|
+
label: "Cookies",
|
|
2638
|
+
ariaLabel: "Cookie preferences and revocation",
|
|
2639
|
+
tooltip: "Customize or decline cookies"
|
|
2640
|
+
}
|
|
2641
|
+
},
|
|
2642
|
+
categories: {
|
|
2643
|
+
necessary: {
|
|
2644
|
+
label: "Strictly Necessary Cookies",
|
|
2645
|
+
description: "Essential for the website to function properly and cannot be deactivated."
|
|
2646
|
+
},
|
|
2647
|
+
analytics: {
|
|
2648
|
+
label: "Performance & Analytics",
|
|
2649
|
+
description: "Help us understand visitor behavior and traffic sources to optimize performance."
|
|
2650
|
+
},
|
|
2651
|
+
marketing: {
|
|
2652
|
+
label: "Targeted Advertising",
|
|
2653
|
+
description: "Used to deliver relevant ads and track campaign effectiveness across websites."
|
|
2654
|
+
},
|
|
2655
|
+
preferences: {
|
|
2656
|
+
label: "Preferences & Personalization",
|
|
2657
|
+
description: "Enable the website to remember user choices like language and layout settings."
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
},
|
|
2661
|
+
ca: {
|
|
2662
|
+
ui: {
|
|
2663
|
+
banner: {
|
|
2664
|
+
title: "La teva privacitat, sota el teu control",
|
|
2665
|
+
description: "Utilitzem tecnologies necess\xE0ries per al funcionament del lloc. Amb el teu perm\xEDs, tamb\xE9 podem utilitzar anal\xEDtica i m\xE0rqueting.",
|
|
2666
|
+
accept: "Acceptar-les totes",
|
|
2667
|
+
reject: "Rebutjar-les totes",
|
|
2668
|
+
configure: "Configurar",
|
|
2669
|
+
cookiesPolicy: "Pol\xEDtica de cookies",
|
|
2670
|
+
privacyPolicy: "Pol\xEDtica de privacitat",
|
|
2671
|
+
ariaLabel: "Gesti\xF3 de consentiment de privacitat"
|
|
2672
|
+
},
|
|
2673
|
+
preferences: {
|
|
2674
|
+
title: "Prefer\xE8ncies de privacitat",
|
|
2675
|
+
subtitle: "Gestiona els teus permisos d'emmagatzematge per finalitat (LSSI art. 22.2 & RGPD).",
|
|
2676
|
+
save: "Desar selecci\xF3",
|
|
2677
|
+
acceptAll: "Permetre-les totes",
|
|
2678
|
+
rejectAll: "Rebutjar opcionals",
|
|
2679
|
+
closeLabel: "Tancar finestra",
|
|
2680
|
+
requiredBadge: "Requerida",
|
|
2681
|
+
optionalBadge: "Opcional",
|
|
2682
|
+
servicesLabel: "Serveis inclosos",
|
|
2683
|
+
viewServices: "Veure serveis",
|
|
2684
|
+
hideServices: "Amagar serveis",
|
|
2685
|
+
thirdParty: "Tercers"
|
|
2686
|
+
},
|
|
2687
|
+
floatingBadge: {
|
|
2688
|
+
label: "Cookies",
|
|
2689
|
+
ariaLabel: "Configuraci\xF3 i revocaci\xF3 de cookies",
|
|
2690
|
+
tooltip: "Configurar o declinar cookies"
|
|
2691
|
+
}
|
|
2692
|
+
},
|
|
2693
|
+
categories: {
|
|
2694
|
+
necessary: {
|
|
2695
|
+
label: "Cookies T\xE8cniques i Necess\xE0ries",
|
|
2696
|
+
description: "Imprescindibles perqu\xE8 el lloc web funcioni correctament i no es poden desactivar."
|
|
2697
|
+
},
|
|
2698
|
+
analytics: {
|
|
2699
|
+
label: "Mesurament i Rendiment",
|
|
2700
|
+
description: "Ens permeten analitzar les visites i fonts de tr\xE0nsit per optimitzar el lloc."
|
|
2701
|
+
},
|
|
2702
|
+
marketing: {
|
|
2703
|
+
label: "Publicidad Personalitzada",
|
|
2704
|
+
description: "Utilitzades per mostrar anuncis rellevants segons els teus interessos i navegaci\xF3."
|
|
2705
|
+
},
|
|
2706
|
+
preferences: {
|
|
2707
|
+
label: "Prefer\xE8ncies i Personalitzaci\xF3",
|
|
2708
|
+
description: "Permeten recordar informaci\xF3 que canvia l'aspecte o comportament del lloc."
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
},
|
|
2712
|
+
eu: {
|
|
2713
|
+
ui: {
|
|
2714
|
+
banner: {
|
|
2715
|
+
title: "Zure pribatutasuna, zure kontrolpean",
|
|
2716
|
+
description: "Webguneak funtzionatzeko beharrezkoak diren teknologiak erabiltzen ditugu. Zure baimenarekin, analitika eta marketina ere erabil ditzakegu.",
|
|
2717
|
+
accept: "Onartu guztiak",
|
|
2718
|
+
reject: "Baztertu guztiak",
|
|
2719
|
+
configure: "Konfiguratu",
|
|
2720
|
+
cookiesPolicy: "Cookie politika",
|
|
2721
|
+
privacyPolicy: "Pribatutasun politika",
|
|
2722
|
+
ariaLabel: "Pribatutasun-baimenen kudeaketa"
|
|
2723
|
+
},
|
|
2724
|
+
preferences: {
|
|
2725
|
+
title: "Pribatutasun-hobespenak",
|
|
2726
|
+
subtitle: "Kudeatu zure biltegiratze-baimenak helburuaren arabera (RGPD).",
|
|
2727
|
+
save: "Gorde hautapena",
|
|
2728
|
+
acceptAll: "Onartu guztiak",
|
|
2729
|
+
rejectAll: "Baztertu aukerakoak",
|
|
2730
|
+
closeLabel: "Itxi leihoa",
|
|
2731
|
+
requiredBadge: "Beharrezkoa",
|
|
2732
|
+
optionalBadge: "Aukerakoa",
|
|
2733
|
+
servicesLabel: "Barne dauden zerbitzuak",
|
|
2734
|
+
viewServices: "Ikusi zerbitzuak",
|
|
2735
|
+
hideServices: "Ezkutatu zerbitzuak",
|
|
2736
|
+
thirdParty: "Hirugarrenak"
|
|
2737
|
+
},
|
|
2738
|
+
floatingBadge: {
|
|
2739
|
+
label: "Cookieak",
|
|
2740
|
+
ariaLabel: "Cookien ezarpenak eta ezeztapena",
|
|
2741
|
+
tooltip: "Konfiguratu edo baztertu cookieak"
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
},
|
|
2745
|
+
gl: {
|
|
2746
|
+
ui: {
|
|
2747
|
+
banner: {
|
|
2748
|
+
title: "A t\xFAa privacidade, baixo o teu control",
|
|
2749
|
+
description: "Empregamos tecnolox\xEDas necesarias para o funcionamento do sitio. Co teu permiso, tam\xE9n podemos utilizar anal\xEDtica e m\xE1rketing.",
|
|
2750
|
+
accept: "Aceptar todas",
|
|
2751
|
+
reject: "Rexeitar todas",
|
|
2752
|
+
configure: "Configurar",
|
|
2753
|
+
cookiesPolicy: "Pol\xEDtica de cookies",
|
|
2754
|
+
privacyPolicy: "Pol\xEDtica de privacidade",
|
|
2755
|
+
ariaLabel: "Xesti\xF3n de consentimento de privacidade"
|
|
2756
|
+
},
|
|
2757
|
+
preferences: {
|
|
2758
|
+
title: "Preferencias de privacidade",
|
|
2759
|
+
subtitle: "Xestiona os teus permisos de almacenamento por finalidade (LSSI art. 22.2 & RGPD).",
|
|
2760
|
+
save: "Gardar selecci\xF3n",
|
|
2761
|
+
acceptAll: "Permitir todas",
|
|
2762
|
+
rejectAll: "Rexeitar opcionais",
|
|
2763
|
+
closeLabel: "Pechar xanela",
|
|
2764
|
+
requiredBadge: "Requirida",
|
|
2765
|
+
optionalBadge: "Opcional",
|
|
2766
|
+
servicesLabel: "Servizos inclu\xEDdos",
|
|
2767
|
+
viewServices: "Ver servizos",
|
|
2768
|
+
hideServices: "Ocultar servizos",
|
|
2769
|
+
thirdParty: "Terceiros"
|
|
2770
|
+
},
|
|
2771
|
+
floatingBadge: {
|
|
2772
|
+
label: "Cookies",
|
|
2773
|
+
ariaLabel: "Configuraci\xF3n e revocaci\xF3n de cookies",
|
|
2774
|
+
tooltip: "Configurar ou declinar cookies"
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
};
|
|
2779
|
+
var I18nEngine = class {
|
|
2780
|
+
constructor(defaultLocale = "es") {
|
|
2781
|
+
this.locale = "es";
|
|
2782
|
+
this.locale = defaultLocale;
|
|
2783
|
+
}
|
|
2784
|
+
setLocale(locale) {
|
|
2785
|
+
this.locale = locale.toLowerCase();
|
|
2786
|
+
}
|
|
2787
|
+
getLocale() {
|
|
2788
|
+
return this.locale;
|
|
2789
|
+
}
|
|
2790
|
+
detectBrowserLocale(supportedLocales) {
|
|
2791
|
+
if (typeof navigator !== "undefined" && navigator.language) {
|
|
2792
|
+
const detected = navigator.language.split("-")[0].toLowerCase();
|
|
2793
|
+
if (supportedLocales && supportedLocales.length > 0) {
|
|
2794
|
+
const normalized = supportedLocales.map((l) => l.toLowerCase());
|
|
2795
|
+
if (normalized.includes(detected)) {
|
|
2796
|
+
return detected;
|
|
2797
|
+
}
|
|
2798
|
+
return normalized[0];
|
|
2799
|
+
}
|
|
2800
|
+
return detected;
|
|
2801
|
+
}
|
|
2802
|
+
return "es";
|
|
2803
|
+
}
|
|
2804
|
+
isLocaleSupported(locale, config) {
|
|
2805
|
+
var _a, _b;
|
|
2806
|
+
const clean = locale.toLowerCase();
|
|
2807
|
+
if (((_a = config == null ? void 0 : config.locale) == null ? void 0 : _a.supported) && config.locale.supported.length > 0) {
|
|
2808
|
+
return config.locale.supported.map((s) => s.toLowerCase()).includes(clean);
|
|
2809
|
+
}
|
|
2810
|
+
if ((config == null ? void 0 : config.translations) && config.translations[clean]) {
|
|
2811
|
+
return true;
|
|
2812
|
+
}
|
|
2813
|
+
if (BUILTIN_TRANSLATIONS[clean]) {
|
|
2814
|
+
return true;
|
|
2815
|
+
}
|
|
2816
|
+
return clean === (((_b = config == null ? void 0 : config.locale) == null ? void 0 : _b.default) || "es").toLowerCase();
|
|
2817
|
+
}
|
|
2818
|
+
detectParentLocale(config) {
|
|
2819
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2820
|
+
const supported = (_a = config == null ? void 0 : config.locale) == null ? void 0 : _a.supported;
|
|
2821
|
+
const defaultLocale = (((_b = config == null ? void 0 : config.locale) == null ? void 0 : _b.default) || "es").toLowerCase();
|
|
2822
|
+
if (((_c = config == null ? void 0 : config.locale) == null ? void 0 : _c.syncHtmlLang) !== false && typeof document !== "undefined" && document.documentElement) {
|
|
2823
|
+
const htmlLang = document.documentElement.lang;
|
|
2824
|
+
if (htmlLang && htmlLang.trim().length > 0) {
|
|
2825
|
+
const clean = htmlLang.split("-")[0].toLowerCase().trim();
|
|
2826
|
+
if (this.isLocaleSupported(clean, config)) {
|
|
2827
|
+
return clean;
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
if (((_d = config == null ? void 0 : config.locale) == null ? void 0 : _d.syncUrl) !== false && typeof window !== "undefined" && window.location) {
|
|
2832
|
+
const pathSegments = window.location.pathname.split("/").filter(Boolean);
|
|
2833
|
+
if (pathSegments.length > 0) {
|
|
2834
|
+
const potentialLang = pathSegments[0].toLowerCase();
|
|
2835
|
+
if (this.isLocaleSupported(potentialLang, config)) {
|
|
2836
|
+
return potentialLang;
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
try {
|
|
2840
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
2841
|
+
const queryLang = (_e = urlParams.get("lang") || urlParams.get("locale")) == null ? void 0 : _e.toLowerCase();
|
|
2842
|
+
if (queryLang && this.isLocaleSupported(queryLang, config)) {
|
|
2843
|
+
return queryLang;
|
|
2844
|
+
}
|
|
2845
|
+
} catch (e) {
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
if ((_f = config == null ? void 0 : config.locale) == null ? void 0 : _f.autoDetect) {
|
|
2849
|
+
return this.detectBrowserLocale(supported);
|
|
2850
|
+
}
|
|
2851
|
+
return defaultLocale;
|
|
2852
|
+
}
|
|
2853
|
+
startParentSync(config, onLocaleChange) {
|
|
2854
|
+
var _a, _b;
|
|
2855
|
+
const cleanups = [];
|
|
2856
|
+
if (((_a = config.locale) == null ? void 0 : _a.syncHtmlLang) !== false && typeof document !== "undefined" && typeof MutationObserver !== "undefined" && document.documentElement) {
|
|
2857
|
+
const observer = new MutationObserver((mutations) => {
|
|
2858
|
+
for (const mutation of mutations) {
|
|
2859
|
+
if (mutation.type === "attributes" && mutation.attributeName === "lang") {
|
|
2860
|
+
const rawLang = document.documentElement.lang;
|
|
2861
|
+
if (rawLang && rawLang.trim().length > 0) {
|
|
2862
|
+
const clean = rawLang.split("-")[0].toLowerCase().trim();
|
|
2863
|
+
if (this.isLocaleSupported(clean, config) && clean !== this.locale) {
|
|
2864
|
+
onLocaleChange(clean);
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
});
|
|
2870
|
+
observer.observe(document.documentElement, {
|
|
2871
|
+
attributes: true,
|
|
2872
|
+
attributeFilter: ["lang"]
|
|
2873
|
+
});
|
|
2874
|
+
cleanups.push(() => observer.disconnect());
|
|
2875
|
+
}
|
|
2876
|
+
if (((_b = config.locale) == null ? void 0 : _b.autoDetect) && typeof window !== "undefined") {
|
|
2877
|
+
const handleLangChange = () => {
|
|
2878
|
+
var _a2;
|
|
2879
|
+
const detected = this.detectBrowserLocale((_a2 = config.locale) == null ? void 0 : _a2.supported);
|
|
2880
|
+
if (detected !== this.locale) {
|
|
2881
|
+
onLocaleChange(detected);
|
|
2882
|
+
}
|
|
2883
|
+
};
|
|
2884
|
+
window.addEventListener("languagechange", handleLangChange);
|
|
2885
|
+
cleanups.push(() => window.removeEventListener("languagechange", handleLangChange));
|
|
2886
|
+
}
|
|
2887
|
+
return () => {
|
|
2888
|
+
cleanups.forEach((cleanup) => cleanup());
|
|
2889
|
+
};
|
|
2890
|
+
}
|
|
2891
|
+
resolveConfig(config, targetLocale) {
|
|
2892
|
+
var _a, _b;
|
|
2893
|
+
const baseLocale = (((_a = config.locale) == null ? void 0 : _a.default) || "es").toLowerCase();
|
|
2894
|
+
const locale = (targetLocale || this.locale || baseLocale).toLowerCase();
|
|
2895
|
+
const resolved = JSON.parse(JSON.stringify(config));
|
|
2896
|
+
const builtin = BUILTIN_TRANSLATIONS[locale];
|
|
2897
|
+
if (builtin) {
|
|
2898
|
+
const isBaseLocale = locale === baseLocale;
|
|
2899
|
+
this.applyTranslation(resolved, builtin, !isBaseLocale);
|
|
2900
|
+
}
|
|
2901
|
+
const custom = (_b = config.translations) == null ? void 0 : _b[locale];
|
|
2902
|
+
if (custom) {
|
|
2903
|
+
this.applyTranslation(resolved, custom, true);
|
|
2904
|
+
}
|
|
2905
|
+
return resolved;
|
|
2906
|
+
}
|
|
2907
|
+
applyTranslation(target, translation, overwriteExisting) {
|
|
2908
|
+
if (translation.policy) {
|
|
2909
|
+
if (!target.policy) target.policy = {};
|
|
2910
|
+
if (translation.policy.privacyUrl && (overwriteExisting || !target.policy.privacyUrl)) {
|
|
2911
|
+
target.policy.privacyUrl = translation.policy.privacyUrl;
|
|
2912
|
+
}
|
|
2913
|
+
if (translation.policy.cookiesUrl && (overwriteExisting || !target.policy.cookiesUrl)) {
|
|
2914
|
+
target.policy.cookiesUrl = translation.policy.cookiesUrl;
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
if (translation.ui) {
|
|
2918
|
+
if (!target.ui) target.ui = {};
|
|
2919
|
+
if (translation.ui.banner) {
|
|
2920
|
+
if (!target.ui.banner) target.ui.banner = {};
|
|
2921
|
+
for (const [key, value] of Object.entries(this.filterDefined(translation.ui.banner))) {
|
|
2922
|
+
if (overwriteExisting || !target.ui.banner[key]) {
|
|
2923
|
+
target.ui.banner[key] = value;
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
if (translation.ui.preferences) {
|
|
2928
|
+
if (!target.ui.preferences) target.ui.preferences = {};
|
|
2929
|
+
for (const [key, value] of Object.entries(this.filterDefined(translation.ui.preferences))) {
|
|
2930
|
+
if (overwriteExisting || !target.ui.preferences[key]) {
|
|
2931
|
+
target.ui.preferences[key] = value;
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
if (translation.ui.floatingBadge) {
|
|
2936
|
+
if (typeof target.ui.floatingBadge === "object" && target.ui.floatingBadge !== null) {
|
|
2937
|
+
for (const [key, value] of Object.entries(this.filterDefined(translation.ui.floatingBadge))) {
|
|
2938
|
+
if (overwriteExisting || !target.ui.floatingBadge[key]) {
|
|
2939
|
+
target.ui.floatingBadge[key] = value;
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
} else if (target.ui.floatingBadge === true) {
|
|
2943
|
+
target.ui.floatingBadge = __spreadValues({
|
|
2944
|
+
enabled: true,
|
|
2945
|
+
position: "bottom-left",
|
|
2946
|
+
icon: "cookie"
|
|
2947
|
+
}, this.filterDefined(translation.ui.floatingBadge));
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
if (translation.categories && target.categories) {
|
|
2952
|
+
for (const [catId, catTrans] of Object.entries(translation.categories)) {
|
|
2953
|
+
if (target.categories[catId]) {
|
|
2954
|
+
if (catTrans.label && (overwriteExisting || !target.categories[catId].label)) {
|
|
2955
|
+
target.categories[catId].label = catTrans.label;
|
|
2956
|
+
}
|
|
2957
|
+
if (catTrans.description && (overwriteExisting || !target.categories[catId].description)) {
|
|
2958
|
+
target.categories[catId].description = catTrans.description;
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
if (translation.services && target.services) {
|
|
2964
|
+
for (const [srvId, srvTrans] of Object.entries(translation.services)) {
|
|
2965
|
+
if (target.services[srvId]) {
|
|
2966
|
+
if (srvTrans.label && (overwriteExisting || !target.services[srvId].label)) {
|
|
2967
|
+
target.services[srvId].label = srvTrans.label;
|
|
2968
|
+
}
|
|
2969
|
+
if (srvTrans.provider && (overwriteExisting || !target.services[srvId].provider)) {
|
|
2970
|
+
target.services[srvId].provider = srvTrans.provider;
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
filterDefined(obj) {
|
|
2977
|
+
const result = {};
|
|
2978
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
2979
|
+
if (value !== void 0 && value !== null) {
|
|
2980
|
+
result[key] = value;
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
return result;
|
|
2984
|
+
}
|
|
2985
|
+
};
|
|
2986
|
+
|
|
2987
|
+
// src/presets/presets-catalog.ts
|
|
2988
|
+
var SERVICE_PRESETS = {
|
|
2989
|
+
// --- ANALYTICS ---
|
|
2990
|
+
ga4: {
|
|
2991
|
+
id: "ga4",
|
|
2992
|
+
category: "analytics",
|
|
2993
|
+
label: "Google Analytics 4",
|
|
2994
|
+
provider: "Google LLC",
|
|
2995
|
+
description: "Medici\xF3n de visitas, p\xE1ginas vistas, eventos y comportamiento de navegaci\xF3n del usuario.",
|
|
2996
|
+
policyUrl: "https://policies.google.com/privacy",
|
|
2997
|
+
cookies: [
|
|
2998
|
+
{ name: "_ga", duration: "2 a\xF1os", purpose: "Distinguir a los usuarios \xFAnicos en el sitio web." },
|
|
2999
|
+
{ name: "_ga_*", duration: "2 a\xF1os", purpose: "Mantener el estado de la sesi\xF3n de Google Analytics 4." },
|
|
3000
|
+
{ name: "_gid", duration: "24 horas", purpose: "Distinguir a los usuarios durante un \xFAnico d\xEDa." },
|
|
3001
|
+
{ name: "_gat*", duration: "1 minuto", purpose: "Limitar el porcentaje de solicitudes a Google Analytics." }
|
|
3002
|
+
],
|
|
3003
|
+
storageKeys: ["_ga_*", "google_analytics_*"],
|
|
3004
|
+
localStorage: ["_ga_*", "google_analytics_*"]
|
|
3005
|
+
},
|
|
3006
|
+
google_analytics: {
|
|
3007
|
+
id: "google_analytics",
|
|
3008
|
+
category: "analytics",
|
|
3009
|
+
label: "Google Analytics (Universal / GA4)",
|
|
3010
|
+
provider: "Google LLC",
|
|
3011
|
+
description: "Medici\xF3n de visitas y estad\xEDsticas an\xF3nimas de tr\xE1fico web.",
|
|
3012
|
+
policyUrl: "https://policies.google.com/privacy",
|
|
3013
|
+
cookies: [
|
|
3014
|
+
{ name: "_ga", duration: "2 a\xF1os", purpose: "Distinguir usuarios." },
|
|
3015
|
+
{ name: "_ga_*", duration: "2 a\xF1os", purpose: "Estado de la sesi\xF3n GA4." },
|
|
3016
|
+
{ name: "_gid", duration: "24 horas", purpose: "Identificador diario." }
|
|
3017
|
+
],
|
|
3018
|
+
storageKeys: ["_ga_*"]
|
|
3019
|
+
},
|
|
3020
|
+
posthog: {
|
|
3021
|
+
id: "posthog",
|
|
3022
|
+
category: "analytics",
|
|
3023
|
+
label: "PostHog Analytics",
|
|
3024
|
+
provider: "PostHog, Inc.",
|
|
3025
|
+
description: "Anal\xEDtica de producto, registro de sesiones, mapas de ruta y embudos de interacci\xF3n.",
|
|
3026
|
+
policyUrl: "https://posthog.com/privacy",
|
|
3027
|
+
cookies: [
|
|
3028
|
+
{ name: "ph_*_posthog", duration: "1 a\xF1o", purpose: "Persistencia de usuario e identificaci\xF3n de sesiones en PostHog." }
|
|
3029
|
+
],
|
|
3030
|
+
storageKeys: ["ph_*_posthog"],
|
|
3031
|
+
localStorage: ["ph_*_posthog"],
|
|
3032
|
+
sessionStorage: ["ph_*_posthog"]
|
|
3033
|
+
},
|
|
3034
|
+
hotjar: {
|
|
3035
|
+
id: "hotjar",
|
|
3036
|
+
category: "analytics",
|
|
3037
|
+
label: "Hotjar Heatmaps & Feedback",
|
|
3038
|
+
provider: "Hotjar Ltd.",
|
|
3039
|
+
description: "Mapas de calor de clics, desplazamientos, grabaciones de comportamiento y encuestas.",
|
|
3040
|
+
policyUrl: "https://www.hotjar.com/legal/policies/privacy/",
|
|
3041
|
+
cookies: [
|
|
3042
|
+
{ name: "_hjSession*", duration: "30 minutos", purpose: "Mantener los datos de la sesi\xF3n actual del usuario en Hotjar." },
|
|
3043
|
+
{ name: "_hjSessionUser*", duration: "1 a\xF1o", purpose: "Mantener el ID de usuario an\xF3nimo en el navegador." },
|
|
3044
|
+
{ name: "_hjIncludedIn*", duration: "Sesi\xF3n", purpose: "Determinar si el usuario est\xE1 incluido en el muestreo de datos." },
|
|
3045
|
+
{ name: "_hjAbsoluteCanvasUrl", duration: "Sesi\xF3n", purpose: "Almacenar la URL can\xF3nica de visualizaci\xF3n." },
|
|
3046
|
+
{ name: "_hjTLDTest", duration: "Sesi\xF3n", purpose: "Verificar el nivel de dominio para cookies." }
|
|
3047
|
+
],
|
|
3048
|
+
storageKeys: ["_hj*", "hj*"],
|
|
3049
|
+
localStorage: ["_hj*"],
|
|
3050
|
+
sessionStorage: ["_hj*"]
|
|
3051
|
+
},
|
|
3052
|
+
clarity: {
|
|
3053
|
+
id: "clarity",
|
|
3054
|
+
category: "analytics",
|
|
3055
|
+
label: "Microsoft Clarity",
|
|
3056
|
+
provider: "Microsoft Corporation",
|
|
3057
|
+
description: "Grabaci\xF3n de navegaci\xF3n y mapas t\xE9rmicos de interacci\xF3n sin datos personales.",
|
|
3058
|
+
policyUrl: "https://privacy.microsoft.com/privacystatement",
|
|
3059
|
+
cookies: [
|
|
3060
|
+
{ name: "_clck", duration: "1 a\xF1o", purpose: "Persistir el ID de usuario Clarity y sus preferencias de p\xE1gina." },
|
|
3061
|
+
{ name: "_clsk", duration: "24 horas", purpose: "Conectar m\xFAltiples visitas de p\xE1gina en una \xFAnica sesi\xF3n." },
|
|
3062
|
+
{ name: "CLID", duration: "1 a\xF1o", purpose: "Identificador de navegador para Clarity." },
|
|
3063
|
+
{ name: "MUID", duration: "1 a\xF1o", purpose: "Identificador de usuario \xFAnico de Microsoft." }
|
|
3064
|
+
],
|
|
3065
|
+
storageKeys: ["_cl*"],
|
|
3066
|
+
localStorage: ["_cl*"]
|
|
3067
|
+
},
|
|
3068
|
+
matomo: {
|
|
3069
|
+
id: "matomo",
|
|
3070
|
+
category: "analytics",
|
|
3071
|
+
label: "Matomo Analytics",
|
|
3072
|
+
provider: "InnoCraft Ltd.",
|
|
3073
|
+
description: "Plataforma de anal\xEDtica web local-first y centrada en la privacidad.",
|
|
3074
|
+
policyUrl: "https://matomo.org/privacy-policy/",
|
|
3075
|
+
cookies: [
|
|
3076
|
+
{ name: "_pk_id*", duration: "13 meses", purpose: "Almacenar datos de usuario \xFAnicos como el ID de visitante." },
|
|
3077
|
+
{ name: "_pk_ses*", duration: "30 minutos", purpose: "Almacenar datos temporales de la sesi\xF3n de navegaci\xF3n." },
|
|
3078
|
+
{ name: "_pk_ref*", duration: "6 meses", purpose: "Almacenar la informaci\xF3n de atribuci\xF3n de procedencia." }
|
|
3079
|
+
],
|
|
3080
|
+
storageKeys: ["_pk_*"],
|
|
3081
|
+
localStorage: ["_pk_*"]
|
|
3082
|
+
},
|
|
3083
|
+
plausible: {
|
|
3084
|
+
id: "plausible",
|
|
3085
|
+
category: "analytics",
|
|
3086
|
+
label: "Plausible Analytics",
|
|
3087
|
+
provider: "Plausible Insights O\xDC",
|
|
3088
|
+
description: "Anal\xEDtica web ligera y respetuosa con la privacidad, 100% libre de cookies.",
|
|
3089
|
+
policyUrl: "https://plausible.io/data-policy",
|
|
3090
|
+
cookies: [],
|
|
3091
|
+
storageKeys: []
|
|
3092
|
+
},
|
|
3093
|
+
// --- MARKETING & ADVERTISING ---
|
|
3094
|
+
meta_pixel: {
|
|
3095
|
+
id: "meta_pixel",
|
|
3096
|
+
category: "marketing",
|
|
3097
|
+
label: "Meta Pixel (Facebook)",
|
|
3098
|
+
provider: "Meta Platforms Ireland Ltd.",
|
|
3099
|
+
description: "Medici\xF3n de conversiones, personalizaci\xF3n y optimizaci\xF3n de campa\xF1as publicitarias en Facebook e Instagram.",
|
|
3100
|
+
policyUrl: "https://www.facebook.com/privacy/policy",
|
|
3101
|
+
cookies: [
|
|
3102
|
+
{ name: "_fbp", duration: "90 d\xEDas", purpose: "Almacenar y rastrear visitas en los sitios web para segmentaci\xF3n publicitaria." },
|
|
3103
|
+
{ name: "_fbc", duration: "90 d\xEDas", purpose: "Guardar el \xFAltimo clic en un anuncio de Facebook (par\xE1metro fbclid)." },
|
|
3104
|
+
{ name: "fr", duration: "90 d\xEDas", purpose: "Cookie de publicidad comportamental de Facebook." },
|
|
3105
|
+
{ name: "tr", duration: "Sesi\xF3n", purpose: "P\xEDxel de seguimiento de eventos en tiempo real." },
|
|
3106
|
+
{ name: "datr", duration: "2 a\xF1os", purpose: "Identificaci\xF3n del navegador web para seguridad y anal\xEDtica publicitaria." }
|
|
3107
|
+
],
|
|
3108
|
+
storageKeys: ["_fbp*"],
|
|
3109
|
+
localStorage: ["_fbp*"]
|
|
3110
|
+
},
|
|
3111
|
+
facebook_pixel: {
|
|
3112
|
+
id: "facebook_pixel",
|
|
3113
|
+
category: "marketing",
|
|
3114
|
+
label: "Meta Pixel (Facebook)",
|
|
3115
|
+
provider: "Meta Platforms Ireland Ltd.",
|
|
3116
|
+
description: "Medici\xF3n de conversiones y retargeting en Meta/Facebook.",
|
|
3117
|
+
policyUrl: "https://www.facebook.com/privacy/policy",
|
|
3118
|
+
cookies: [
|
|
3119
|
+
{ name: "_fbp", duration: "90 d\xEDas", purpose: "Rastreo de conversiones y atribuci\xF3n de campa\xF1as." },
|
|
3120
|
+
{ name: "_fbc", duration: "90 d\xEDas", purpose: "Identificador de clic de anuncio." }
|
|
3121
|
+
],
|
|
3122
|
+
storageKeys: ["_fbp*"]
|
|
3123
|
+
},
|
|
3124
|
+
google_ads: {
|
|
3125
|
+
id: "google_ads",
|
|
3126
|
+
category: "marketing",
|
|
3127
|
+
label: "Google Ads & Remarketing",
|
|
3128
|
+
provider: "Google LLC",
|
|
3129
|
+
description: "Medici\xF3n de conversiones publicitarias y campa\xF1as de retargeting de Google Ads.",
|
|
3130
|
+
policyUrl: "https://policies.google.com/technologies/ads",
|
|
3131
|
+
cookies: [
|
|
3132
|
+
{ name: "_gcl_au", duration: "90 d\xEDas", purpose: "Medici\xF3n de conversiones publicitarias de Google AdSense y Ads." },
|
|
3133
|
+
{ name: "_gcl_aw", duration: "90 d\xEDas", purpose: "Conversiones procedentes de clics en anuncios de Google Ads." },
|
|
3134
|
+
{ name: "IDE", duration: "1 a\xF1o", purpose: "Publicidad dirigida y medici\xF3n de rendimiento de DoubleClick." },
|
|
3135
|
+
{ name: "DSID", duration: "2 semanas", purpose: "Identificar usuario conectado en sitios web ajenos a Google." },
|
|
3136
|
+
{ name: "RUL", duration: "1 a\xF1o", purpose: "Audiencias de remarketing de Google Ads." }
|
|
3137
|
+
],
|
|
3138
|
+
storageKeys: ["_gcl_*"]
|
|
3139
|
+
},
|
|
3140
|
+
tiktok_pixel: {
|
|
3141
|
+
id: "tiktok_pixel",
|
|
3142
|
+
category: "marketing",
|
|
3143
|
+
label: "TikTok Pixel",
|
|
3144
|
+
provider: "TikTok Technology Limited",
|
|
3145
|
+
description: "Medici\xF3n de rendimiento y segmentaci\xF3n de campa\xF1as publicitarias en TikTok.",
|
|
3146
|
+
policyUrl: "https://www.tiktok.com/legal/privacy-policy-eea",
|
|
3147
|
+
cookies: [
|
|
3148
|
+
{ name: "_tt_enable_cookie", duration: "13 meses", purpose: "Habilitar la medici\xF3n de conversiones del p\xEDxel de TikTok." },
|
|
3149
|
+
{ name: "_ttp", duration: "13 meses", purpose: "Medir y mejorar el rendimiento de las campa\xF1as publicitarias en TikTok." }
|
|
3150
|
+
],
|
|
3151
|
+
storageKeys: ["tt_*", "_ttp*"]
|
|
3152
|
+
},
|
|
3153
|
+
linkedin_insight: {
|
|
3154
|
+
id: "linkedin_insight",
|
|
3155
|
+
category: "marketing",
|
|
3156
|
+
label: "LinkedIn Insight Tag",
|
|
3157
|
+
provider: "LinkedIn Ireland Unlimited Company",
|
|
3158
|
+
description: "Informes de conversiones y atribuci\xF3n de campa\xF1as profesionales B2B en LinkedIn.",
|
|
3159
|
+
policyUrl: "https://www.linkedin.com/legal/privacy-policy",
|
|
3160
|
+
cookies: [
|
|
3161
|
+
{ name: "li_sugr", duration: "90 d\xEDas", purpose: "Identificador probabil\xEDstico de navegador en LinkedIn." },
|
|
3162
|
+
{ name: "bcookie", duration: "1 a\xF1o", purpose: "Identificador de sesi\xF3n de navegador para servicios de LinkedIn." },
|
|
3163
|
+
{ name: "lidc", duration: "24 horas", purpose: "Enrutamiento de centros de datos para LinkedIn." },
|
|
3164
|
+
{ name: "UserMatchHistory", duration: "30 d\xEDas", purpose: "Sincronizaci\xF3n de identificadores de publicidad de LinkedIn." }
|
|
3165
|
+
]
|
|
3166
|
+
},
|
|
3167
|
+
twitter_pixel: {
|
|
3168
|
+
id: "twitter_pixel",
|
|
3169
|
+
category: "marketing",
|
|
3170
|
+
label: "X / Twitter Ads Pixel",
|
|
3171
|
+
provider: "X Corp.",
|
|
3172
|
+
description: "Medici\xF3n de conversiones e interacci\xF3n con campa\xF1as publicitarias en X (Twitter).",
|
|
3173
|
+
policyUrl: "https://twitter.com/privacy",
|
|
3174
|
+
cookies: [
|
|
3175
|
+
{ name: "personalization_id", duration: "2 a\xF1os", purpose: "Personalizaci\xF3n de publicidad y medici\xF3n de eventos en X." },
|
|
3176
|
+
{ name: "muc_ads", duration: "2 a\xF1os", purpose: "Seguimiento de conversiones publicitarias en X." }
|
|
3177
|
+
]
|
|
3178
|
+
},
|
|
3179
|
+
hubspot: {
|
|
3180
|
+
id: "hubspot",
|
|
3181
|
+
category: "marketing",
|
|
3182
|
+
label: "HubSpot CRM & Tracking",
|
|
3183
|
+
provider: "HubSpot, Inc.",
|
|
3184
|
+
description: "Anal\xEDtica de leads, formularios inteligentes y seguimiento de clientes potenciales.",
|
|
3185
|
+
policyUrl: "https://legal.hubspot.com/privacy-policy",
|
|
3186
|
+
cookies: [
|
|
3187
|
+
{ name: "__hstc", duration: "6 meses", purpose: "Rastreo de visitantes \xFAnicos, sesiones y marcas de tiempo." },
|
|
3188
|
+
{ name: "hubspotutk", duration: "6 meses", purpose: "Rastreo de identidad de visitante pasado a formularios." },
|
|
3189
|
+
{ name: "__hssc", duration: "30 minutos", purpose: "Rastreo de sesiones activas en HubSpot." },
|
|
3190
|
+
{ name: "__hssrc", duration: "Sesi\xF3n", purpose: "Determinar si el usuario ha reiniciado su navegador." }
|
|
3191
|
+
],
|
|
3192
|
+
storageKeys: ["__hs*", "hubspot*"]
|
|
3193
|
+
},
|
|
3194
|
+
// --- EMBEDDED MEDIA ---
|
|
3195
|
+
youtube: {
|
|
3196
|
+
id: "youtube",
|
|
3197
|
+
category: "marketing",
|
|
3198
|
+
label: "YouTube Video Player",
|
|
3199
|
+
provider: "Google LLC",
|
|
3200
|
+
description: "Reproducci\xF3n de contenidos de v\xEDdeo integrados y almacenamiento de preferencias del reproductor.",
|
|
3201
|
+
policyUrl: "https://policies.google.com/privacy",
|
|
3202
|
+
cookies: [
|
|
3203
|
+
{ name: "VISITOR_INFO1_LIVE", duration: "6 meses", purpose: "Estimar el ancho de banda del usuario en p\xE1ginas con v\xEDdeos de YouTube." },
|
|
3204
|
+
{ name: "YSC", duration: "Sesi\xF3n", purpose: "Registrar estad\xEDsticas de visualizaciones de v\xEDdeo de YouTube." },
|
|
3205
|
+
{ name: "PREF", duration: "8 meses", purpose: "Almacenar preferencias de configuraci\xF3n del reproductor." },
|
|
3206
|
+
{ name: "GPS", duration: "30 minutos", purpose: "Rastrear ubicaci\xF3n en dispositivos m\xF3viles." }
|
|
3207
|
+
],
|
|
3208
|
+
storageKeys: ["yt-*", "yt-remote-*"],
|
|
3209
|
+
localStorage: ["yt-*", "yt-remote-*"]
|
|
3210
|
+
},
|
|
3211
|
+
vimeo: {
|
|
3212
|
+
id: "vimeo",
|
|
3213
|
+
category: "marketing",
|
|
3214
|
+
label: "Vimeo Video Player",
|
|
3215
|
+
provider: "Vimeo, Inc.",
|
|
3216
|
+
description: "Reproducci\xF3n de v\xEDdeos interactivos alojados en Vimeo y estad\xEDsticas de visualizaci\xF3n.",
|
|
3217
|
+
policyUrl: "https://vimeo.com/privacy",
|
|
3218
|
+
cookies: [
|
|
3219
|
+
{ name: "vuid", duration: "2 a\xF1os", purpose: "Almacenar el historial de reproducciones de v\xEDdeo del usuario en Vimeo." },
|
|
3220
|
+
{ name: "player", duration: "1 a\xF1o", purpose: "Guardar las preferencias de volumen y resoluci\xF3n del reproductor." }
|
|
3221
|
+
],
|
|
3222
|
+
storageKeys: ["vimeo*"]
|
|
3223
|
+
},
|
|
3224
|
+
spotify: {
|
|
3225
|
+
id: "spotify",
|
|
3226
|
+
category: "marketing",
|
|
3227
|
+
label: "Spotify Player",
|
|
3228
|
+
provider: "Spotify AB",
|
|
3229
|
+
description: "Reproducci\xF3n embebida de canciones, podcasts y listas de reproducci\xF3n de Spotify.",
|
|
3230
|
+
policyUrl: "https://www.spotify.com/legal/privacy-policy/",
|
|
3231
|
+
cookies: [
|
|
3232
|
+
{ name: "sp_t", duration: "1 a\xF1o", purpose: "Identificador de usuario \xFAnico de Spotify para contenido embebido." },
|
|
3233
|
+
{ name: "sp_m", duration: "1 a\xF1o", purpose: "Preferencias de reproducci\xF3n y cookies de sesi\xF3n." }
|
|
3234
|
+
]
|
|
3235
|
+
},
|
|
3236
|
+
// --- CHAT & CUSTOMER SUPPORT ---
|
|
3237
|
+
intercom: {
|
|
3238
|
+
id: "intercom",
|
|
3239
|
+
category: "marketing",
|
|
3240
|
+
label: "Intercom Messenger",
|
|
3241
|
+
provider: "Intercom R&D Unlimited Company",
|
|
3242
|
+
description: "Widget de mensajer\xEDa, soporte al cliente en tiempo real y asistencia guiada.",
|
|
3243
|
+
policyUrl: "https://www.intercom.com/legal/privacy",
|
|
3244
|
+
cookies: [
|
|
3245
|
+
{ name: "intercom-id-*", duration: "9 meses", purpose: "Identificador an\xF3nimo de visitante para conversaciones en Intercom." },
|
|
3246
|
+
{ name: "intercom-session-*", duration: "7 d\xEDas", purpose: "Persistir la sesi\xF3n de chat activa." },
|
|
3247
|
+
{ name: "intercom-device-id-*", duration: "9 meses", purpose: "Identificador del dispositivo del visitante." }
|
|
3248
|
+
],
|
|
3249
|
+
storageKeys: ["intercom*"]
|
|
3250
|
+
},
|
|
3251
|
+
crisp: {
|
|
3252
|
+
id: "crisp",
|
|
3253
|
+
category: "marketing",
|
|
3254
|
+
label: "Crisp Live Chat",
|
|
3255
|
+
provider: "Crisp IM SARL",
|
|
3256
|
+
description: "Chat en vivo de soporte y mensajer\xEDa multicanal para visitantes.",
|
|
3257
|
+
policyUrl: "https://crisp.chat/privacy",
|
|
3258
|
+
cookies: [
|
|
3259
|
+
{ name: "crisp-client/*", duration: "6 meses", purpose: "Identificador de sesi\xF3n de chat en Crisp." }
|
|
3260
|
+
],
|
|
3261
|
+
storageKeys: ["crisp-client*"]
|
|
3262
|
+
},
|
|
3263
|
+
// --- NECESSARY / TECHNICAL / SECURITY ---
|
|
3264
|
+
gtm: {
|
|
3265
|
+
id: "gtm",
|
|
3266
|
+
category: "necessary",
|
|
3267
|
+
label: "Google Tag Manager",
|
|
3268
|
+
provider: "Google LLC",
|
|
3269
|
+
description: "Contenedor t\xE9cnico para la inyecci\xF3n y gesti\xF3n centralizada de scripts del sitio web.",
|
|
3270
|
+
policyUrl: "https://policies.google.com/privacy",
|
|
3271
|
+
cookies: [
|
|
3272
|
+
{ name: "_gtm_*", duration: "Sesi\xF3n", purpose: "Depuraci\xF3n t\xE9cnica de contenedores de Google Tag Manager." }
|
|
3273
|
+
]
|
|
3274
|
+
},
|
|
3275
|
+
google_recaptcha: {
|
|
3276
|
+
id: "google_recaptcha",
|
|
3277
|
+
category: "necessary",
|
|
3278
|
+
label: "Google reCAPTCHA",
|
|
3279
|
+
provider: "Google LLC",
|
|
3280
|
+
description: "Protecci\xF3n contra bots automatizados, ataques de fuerza bruta y spam en formularios.",
|
|
3281
|
+
policyUrl: "https://policies.google.com/privacy",
|
|
3282
|
+
cookies: [
|
|
3283
|
+
{ name: "_GRECAPTCHA", duration: "6 meses", purpose: "Evaluaci\xF3n de riesgo de bots para protecci\xF3n de formularios." },
|
|
3284
|
+
{ name: "rc::a", duration: "Persistente", purpose: "Distinguir entre humanos y bots automatizados." },
|
|
3285
|
+
{ name: "rc::b", duration: "Sesi\xF3n", purpose: "Distinguir entre humanos y bots automatizados." },
|
|
3286
|
+
{ name: "rc::c", duration: "Sesi\xF3n", purpose: "Distinguir entre humanos y bots automatizados." }
|
|
3287
|
+
]
|
|
3288
|
+
},
|
|
3289
|
+
cloudflare: {
|
|
3290
|
+
id: "cloudflare",
|
|
3291
|
+
category: "necessary",
|
|
3292
|
+
label: "Cloudflare Security & Turnstile",
|
|
3293
|
+
provider: "Cloudflare, Inc.",
|
|
3294
|
+
description: "Mitigaci\xF3n de ataques DDoS, balanceo de carga CDN y validaci\xF3n de seguridad Turnstile.",
|
|
3295
|
+
policyUrl: "https://www.cloudflare.com/privacypolicy/",
|
|
3296
|
+
cookies: [
|
|
3297
|
+
{ name: "__cf_bm", duration: "30 minutos", purpose: "Gesti\xF3n de bots y mitigaci\xF3n de tr\xE1fico malicioso en Cloudflare." },
|
|
3298
|
+
{ name: "cf_clearance", duration: "1 a\xF1o", purpose: "Autorizaci\xF3n de paso tras superar desaf\xEDo de seguridad Turnstile/Cloudflare." }
|
|
3299
|
+
]
|
|
3300
|
+
},
|
|
3301
|
+
stripe: {
|
|
3302
|
+
id: "stripe",
|
|
3303
|
+
category: "necessary",
|
|
3304
|
+
label: "Stripe Payments & Fraud Prevention",
|
|
3305
|
+
provider: "Stripe, Inc.",
|
|
3306
|
+
description: "Procesamiento seguro de transacciones bancarias, tarjetas y prevenci\xF3n de fraude financiero.",
|
|
3307
|
+
policyUrl: "https://stripe.com/privacy",
|
|
3308
|
+
cookies: [
|
|
3309
|
+
{ name: "__stripe_mid", duration: "1 a\xF1o", purpose: "Prevenci\xF3n de fraude y autenticaci\xF3n de pagos en Stripe." },
|
|
3310
|
+
{ name: "__stripe_sid", duration: "30 minutos", purpose: "Identificador de sesi\xF3n de transacci\xF3n en Stripe." },
|
|
3311
|
+
{ name: "m", duration: "2 a\xF1os", purpose: "Detecci\xF3n de fraude financiero en la pasarela de pagos Stripe." }
|
|
3312
|
+
],
|
|
3313
|
+
storageKeys: ["__stripe_*"],
|
|
3314
|
+
localStorage: ["__stripe_*"]
|
|
3315
|
+
},
|
|
3316
|
+
paypal: {
|
|
3317
|
+
id: "paypal",
|
|
3318
|
+
category: "necessary",
|
|
3319
|
+
label: "PayPal Checkout",
|
|
3320
|
+
provider: "PayPal (Europe) S.\xE0 r.l. et Cie, S.C.A.",
|
|
3321
|
+
description: "Procesamiento de pagos y pasarela de cobro segura de PayPal.",
|
|
3322
|
+
policyUrl: "https://www.paypal.com/webapps/mpp/ua/privacy-full",
|
|
3323
|
+
cookies: [
|
|
3324
|
+
{ name: "ts", duration: "3 a\xF1os", purpose: "Gesti\xF3n segura de pagos y prevenci\xF3n de fraude en PayPal." },
|
|
3325
|
+
{ name: "ts_c", duration: "3 a\xF1os", purpose: "Autenticaci\xF3n segura de usuario en la pasarela PayPal." }
|
|
3326
|
+
]
|
|
3327
|
+
}
|
|
3328
|
+
};
|
|
3329
|
+
|
|
3330
|
+
// src/presets/index.ts
|
|
3331
|
+
function hasPreset(presetId) {
|
|
3332
|
+
return Object.prototype.hasOwnProperty.call(SERVICE_PRESETS, presetId);
|
|
3333
|
+
}
|
|
3334
|
+
function getPreset(presetId, overrides) {
|
|
3335
|
+
const preset = SERVICE_PRESETS[presetId];
|
|
3336
|
+
if (!preset) {
|
|
3337
|
+
throw new Error(
|
|
3338
|
+
`[ConsentSDK] Unknown service preset: '${presetId}'. Available presets: ${Object.keys(
|
|
3339
|
+
SERVICE_PRESETS
|
|
3340
|
+
).join(", ")}`
|
|
3341
|
+
);
|
|
3342
|
+
}
|
|
3343
|
+
const base = {
|
|
3344
|
+
category: preset.category,
|
|
3345
|
+
label: preset.label,
|
|
3346
|
+
provider: preset.provider,
|
|
3347
|
+
policyUrl: preset.policyUrl,
|
|
3348
|
+
description: preset.description,
|
|
3349
|
+
cookies: preset.cookies ? [...preset.cookies] : void 0,
|
|
3350
|
+
storageKeys: preset.storageKeys ? [...preset.storageKeys] : void 0,
|
|
3351
|
+
localStorage: preset.localStorage ? [...preset.localStorage] : void 0,
|
|
3352
|
+
sessionStorage: preset.sessionStorage ? [...preset.sessionStorage] : void 0
|
|
3353
|
+
};
|
|
3354
|
+
if (!overrides) {
|
|
3355
|
+
return base;
|
|
3356
|
+
}
|
|
3357
|
+
return __spreadProps(__spreadValues(__spreadValues({}, base), overrides), {
|
|
3358
|
+
cookies: overrides.cookies || base.cookies,
|
|
3359
|
+
storageKeys: overrides.storageKeys || base.storageKeys,
|
|
3360
|
+
localStorage: overrides.localStorage || base.localStorage,
|
|
3361
|
+
sessionStorage: overrides.sessionStorage || base.sessionStorage
|
|
3362
|
+
});
|
|
3363
|
+
}
|
|
3364
|
+
function defineServices(definitions) {
|
|
3365
|
+
const result = {};
|
|
3366
|
+
for (const [key, def] of Object.entries(definitions)) {
|
|
3367
|
+
if (typeof def === "string") {
|
|
3368
|
+
result[key] = getPreset(def);
|
|
3369
|
+
} else if (def && typeof def === "object") {
|
|
3370
|
+
if (def.preset) {
|
|
3371
|
+
const _a = def, { preset } = _a, overrides = __objRest(_a, ["preset"]);
|
|
3372
|
+
result[key] = getPreset(preset, overrides);
|
|
3373
|
+
} else if (hasPreset(key)) {
|
|
3374
|
+
result[key] = getPreset(key, def);
|
|
3375
|
+
} else {
|
|
3376
|
+
result[key] = def;
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3380
|
+
return result;
|
|
3381
|
+
}
|
|
3382
|
+
function resolveConfigPresets(config) {
|
|
3383
|
+
if (!config || !config.services || typeof config.services !== "object") {
|
|
3384
|
+
return config;
|
|
3385
|
+
}
|
|
3386
|
+
const hydratedServices = {};
|
|
3387
|
+
for (const [serviceKey, serviceDef] of Object.entries(config.services)) {
|
|
3388
|
+
if (!serviceDef || typeof serviceDef !== "object") {
|
|
3389
|
+
hydratedServices[serviceKey] = serviceDef;
|
|
3390
|
+
continue;
|
|
3391
|
+
}
|
|
3392
|
+
const presetName = serviceDef.preset || (hasPreset(serviceKey) && !serviceDef.category ? serviceKey : void 0);
|
|
3393
|
+
if (presetName && hasPreset(presetName)) {
|
|
3394
|
+
const preset = SERVICE_PRESETS[presetName];
|
|
3395
|
+
hydratedServices[serviceKey] = __spreadValues({
|
|
3396
|
+
category: serviceDef.category || preset.category,
|
|
3397
|
+
label: serviceDef.label || preset.label,
|
|
3398
|
+
provider: serviceDef.provider || preset.provider,
|
|
3399
|
+
policyUrl: serviceDef.policyUrl || preset.policyUrl,
|
|
3400
|
+
description: serviceDef.description || preset.description,
|
|
3401
|
+
cookies: serviceDef.cookies || (preset.cookies ? [...preset.cookies] : void 0),
|
|
3402
|
+
storageKeys: serviceDef.storageKeys || (preset.storageKeys ? [...preset.storageKeys] : void 0),
|
|
3403
|
+
localStorage: serviceDef.localStorage || (preset.localStorage ? [...preset.localStorage] : void 0),
|
|
3404
|
+
sessionStorage: serviceDef.sessionStorage || (preset.sessionStorage ? [...preset.sessionStorage] : void 0)
|
|
3405
|
+
}, serviceDef);
|
|
3406
|
+
} else {
|
|
3407
|
+
hydratedServices[serviceKey] = serviceDef;
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
return __spreadProps(__spreadValues({}, config), {
|
|
3411
|
+
services: hydratedServices
|
|
3412
|
+
});
|
|
3413
|
+
}
|
|
3414
|
+
|
|
3415
|
+
// src/core/gpc.ts
|
|
3416
|
+
function detectGpcSignal() {
|
|
3417
|
+
var _a, _b, _c, _d;
|
|
3418
|
+
if (typeof window === "undefined" && typeof navigator === "undefined" && typeof globalThis === "undefined") {
|
|
3419
|
+
return false;
|
|
3420
|
+
}
|
|
3421
|
+
const nav = typeof navigator !== "undefined" ? navigator : null;
|
|
3422
|
+
const win = typeof window !== "undefined" ? window : null;
|
|
3423
|
+
const glob = typeof globalThis !== "undefined" ? globalThis : null;
|
|
3424
|
+
if ((nav == null ? void 0 : nav.globalPrivacyControl) === true || (win == null ? void 0 : win.globalPrivacyControl) === true || ((_a = win == null ? void 0 : win.navigator) == null ? void 0 : _a.globalPrivacyControl) === true || ((_b = glob == null ? void 0 : glob.navigator) == null ? void 0 : _b.globalPrivacyControl) === true || (glob == null ? void 0 : glob.globalPrivacyControl) === true) {
|
|
3425
|
+
return true;
|
|
3426
|
+
}
|
|
3427
|
+
if ((nav == null ? void 0 : nav.doNotTrack) === "1" || (win == null ? void 0 : win.doNotTrack) === "1" || ((_c = win == null ? void 0 : win.navigator) == null ? void 0 : _c.doNotTrack) === "1" || ((_d = glob == null ? void 0 : glob.navigator) == null ? void 0 : _d.doNotTrack) === "1" || (glob == null ? void 0 : glob.doNotTrack) === "1" || (nav == null ? void 0 : nav.msDoNotTrack) === "1" || (win == null ? void 0 : win.external) && typeof win.external.msTrackingProtectionEnabled === "function" && win.external.msTrackingProtectionEnabled()) {
|
|
3428
|
+
return true;
|
|
3429
|
+
}
|
|
3430
|
+
return false;
|
|
3431
|
+
}
|
|
3432
|
+
function resolveGpcConfig(config) {
|
|
3433
|
+
const gpc = config == null ? void 0 : config.gpc;
|
|
3434
|
+
return {
|
|
3435
|
+
enabled: (gpc == null ? void 0 : gpc.enabled) !== false,
|
|
3436
|
+
respectSignal: (gpc == null ? void 0 : gpc.respectSignal) !== false,
|
|
3437
|
+
mode: (gpc == null ? void 0 : gpc.mode) || "auto-reject",
|
|
3438
|
+
categories: (gpc == null ? void 0 : gpc.categories) || [],
|
|
3439
|
+
noticeText: (gpc == null ? void 0 : gpc.noticeText) || "Se\xF1al de Privacidad Global (GPC) detectada: cookies no esenciales desactivadas."
|
|
3440
|
+
};
|
|
3441
|
+
}
|
|
3442
|
+
function applyGpcChoices(config, baseChoices) {
|
|
3443
|
+
const result = __spreadValues({}, baseChoices || {});
|
|
3444
|
+
const gpcOptions = resolveGpcConfig(config);
|
|
3445
|
+
for (const [catId, catConfig] of Object.entries(config.categories)) {
|
|
3446
|
+
if (catConfig.required || catId === "necessary") {
|
|
3447
|
+
result[catId] = true;
|
|
3448
|
+
} else {
|
|
3449
|
+
if (gpcOptions.categories.length === 0 || gpcOptions.categories.includes(catId)) {
|
|
3450
|
+
result[catId] = false;
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
return result;
|
|
3455
|
+
}
|
|
3456
|
+
|
|
1675
3457
|
// src/core/consent-engine.ts
|
|
1676
3458
|
var ConsentEngine = class {
|
|
1677
3459
|
constructor() {
|
|
@@ -1680,6 +3462,9 @@ var ConsentEngine = class {
|
|
|
1680
3462
|
this.blockerRegistry = new BlockerRegistry();
|
|
1681
3463
|
this.banner = new ConsentBanner();
|
|
1682
3464
|
this.preferencesModal = new PreferencesModal();
|
|
3465
|
+
this.floatingBadge = new FloatingBadge();
|
|
3466
|
+
this.i18n = new I18nEngine();
|
|
3467
|
+
this.stopLocaleSync = null;
|
|
1683
3468
|
this.initPromise = null;
|
|
1684
3469
|
this.resolveReady = null;
|
|
1685
3470
|
this.readyPromise = new Promise((resolve) => {
|
|
@@ -1689,7 +3474,7 @@ var ConsentEngine = class {
|
|
|
1689
3474
|
async init(configInput) {
|
|
1690
3475
|
if (this.initPromise) return this.initPromise;
|
|
1691
3476
|
this.initPromise = (async () => {
|
|
1692
|
-
var _a, _b, _c;
|
|
3477
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
1693
3478
|
let config;
|
|
1694
3479
|
if (typeof configInput === "string") {
|
|
1695
3480
|
const response = await fetch(configInput);
|
|
@@ -1702,16 +3487,72 @@ var ConsentEngine = class {
|
|
|
1702
3487
|
} else {
|
|
1703
3488
|
config = configInput;
|
|
1704
3489
|
}
|
|
3490
|
+
config = resolveConfigPresets(config);
|
|
1705
3491
|
validateConfig(config);
|
|
1706
|
-
const
|
|
1707
|
-
|
|
3492
|
+
const initialLocale = this.i18n.detectParentLocale(config);
|
|
3493
|
+
this.i18n.setLocale(initialLocale);
|
|
3494
|
+
(_a = this.stopLocaleSync) == null ? void 0 : _a.call(this);
|
|
3495
|
+
this.stopLocaleSync = this.i18n.startParentSync(config, (newLocale) => {
|
|
3496
|
+
this.setLocale(newLocale);
|
|
3497
|
+
});
|
|
3498
|
+
const cookieName = ((_b = config.storage) == null ? void 0 : _b.name) || "site_consent";
|
|
3499
|
+
const rawReceipt = ((_c = config.storage) == null ? void 0 : _c.type) === "memory" ? MemoryStore.get(cookieName) : CookieStore.get(cookieName);
|
|
1708
3500
|
const savedReceipt = rawReceipt ? parseReceipt(rawReceipt) : null;
|
|
1709
3501
|
const evalResult = evaluatePolicy(config, savedReceipt);
|
|
1710
|
-
const
|
|
1711
|
-
|
|
3502
|
+
const isGpcDetected = detectGpcSignal();
|
|
3503
|
+
const gpcConfig = resolveGpcConfig(config);
|
|
3504
|
+
const isGpcActive = isGpcDetected && gpcConfig.enabled && gpcConfig.respectSignal;
|
|
3505
|
+
let activeReceipt = evalResult.isValid ? savedReceipt : null;
|
|
3506
|
+
let activeChoices = evalResult.choices;
|
|
3507
|
+
let autoAppliedGpc = false;
|
|
3508
|
+
if (!evalResult.isValid && isGpcActive) {
|
|
3509
|
+
if (gpcConfig.mode !== "notice-only") {
|
|
3510
|
+
activeChoices = applyGpcChoices(config);
|
|
3511
|
+
activeReceipt = createReceipt(
|
|
3512
|
+
config.policyVersion,
|
|
3513
|
+
activeChoices,
|
|
3514
|
+
"gpc",
|
|
3515
|
+
null,
|
|
3516
|
+
(_d = config.security) == null ? void 0 : _d.secretKey
|
|
3517
|
+
);
|
|
3518
|
+
activeReceipt.gpc = true;
|
|
3519
|
+
autoAppliedGpc = true;
|
|
3520
|
+
const receiptJson = JSON.stringify(activeReceipt);
|
|
3521
|
+
if (((_e = config.storage) == null ? void 0 : _e.type) === "memory") {
|
|
3522
|
+
MemoryStore.set(cookieName, receiptJson);
|
|
3523
|
+
} else {
|
|
3524
|
+
CookieStore.set(cookieName, receiptJson, {
|
|
3525
|
+
path: ((_f = config.storage) == null ? void 0 : _f.path) || "/",
|
|
3526
|
+
maxAgeDays: (_h = (_g = config.consent) == null ? void 0 : _g.maxAgeDays) != null ? _h : 365,
|
|
3527
|
+
sameSite: ((_i = config.storage) == null ? void 0 : _i.sameSite) || "Lax",
|
|
3528
|
+
secure: (_j = config.storage) == null ? void 0 : _j.secure,
|
|
3529
|
+
domain: (_k = config.storage) == null ? void 0 : _k.domain
|
|
3530
|
+
});
|
|
3531
|
+
}
|
|
3532
|
+
for (const [catId, allowed] of Object.entries(activeChoices)) {
|
|
3533
|
+
if (!allowed && catId !== "necessary") {
|
|
3534
|
+
StorageCleaner.purgeCategory(config, catId);
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
this.stateManager.init(config, activeChoices, activeReceipt, isGpcDetected);
|
|
3540
|
+
this.stateManager.setLocale(initialLocale);
|
|
3541
|
+
if (isGpcDetected) {
|
|
3542
|
+
this.eventBus.emit("gpc:detected", {
|
|
3543
|
+
signal: true,
|
|
3544
|
+
autoApplied: autoAppliedGpc,
|
|
3545
|
+
choices: activeChoices
|
|
3546
|
+
});
|
|
3547
|
+
this.dispatchDomEvent("solvenza:gpc", {
|
|
3548
|
+
signal: true,
|
|
3549
|
+
autoApplied: autoAppliedGpc,
|
|
3550
|
+
choices: activeChoices
|
|
3551
|
+
});
|
|
3552
|
+
}
|
|
1712
3553
|
GoogleConsentAdapter.initDefault();
|
|
1713
|
-
if (evalResult.isValid) {
|
|
1714
|
-
GoogleConsentAdapter.update(
|
|
3554
|
+
if (evalResult.isValid || autoAppliedGpc) {
|
|
3555
|
+
GoogleConsentAdapter.update(activeChoices);
|
|
1715
3556
|
this.dispatchDomEvent("solvenza:restored", { state: this.getConsent() });
|
|
1716
3557
|
}
|
|
1717
3558
|
this.blockerRegistry.init(
|
|
@@ -1729,9 +3570,19 @@ var ConsentEngine = class {
|
|
|
1729
3570
|
}
|
|
1730
3571
|
);
|
|
1731
3572
|
this.setupGlobalRevocationTrigger();
|
|
1732
|
-
|
|
3573
|
+
const resolvedConfig = this.getResolvedConfig() || config;
|
|
3574
|
+
const badgeConfig = this.resolveFloatingBadgeConfig(resolvedConfig);
|
|
3575
|
+
if (badgeConfig.enabled) {
|
|
3576
|
+
this.floatingBadge.render(resolvedConfig, {
|
|
3577
|
+
onClick: () => this.openPreferences()
|
|
3578
|
+
});
|
|
3579
|
+
if (evalResult.isValid || autoAppliedGpc || badgeConfig.visibility === "always") {
|
|
3580
|
+
this.showFloatingBadge();
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
(_l = this.resolveReady) == null ? void 0 : _l.call(this);
|
|
1733
3584
|
this.eventBus.emit("ready", { state: this.getConsent() });
|
|
1734
|
-
if (!evalResult.isValid) {
|
|
3585
|
+
if (!evalResult.isValid && !autoAppliedGpc) {
|
|
1735
3586
|
this.showBanner();
|
|
1736
3587
|
}
|
|
1737
3588
|
})();
|
|
@@ -1783,13 +3634,24 @@ var ConsentEngine = class {
|
|
|
1783
3634
|
this.saveChoices(sanitizedChoices, "preferences");
|
|
1784
3635
|
}
|
|
1785
3636
|
openPreferences() {
|
|
1786
|
-
const config = this.
|
|
3637
|
+
const config = this.getResolvedConfig();
|
|
1787
3638
|
if (!config) return;
|
|
3639
|
+
this.hideFloatingBadge();
|
|
1788
3640
|
this.preferencesModal.render(config, this.stateManager.getChoices(), {
|
|
1789
|
-
onSave: (choices) =>
|
|
1790
|
-
|
|
1791
|
-
|
|
3641
|
+
onSave: (choices) => {
|
|
3642
|
+
this.setPreferences(choices);
|
|
3643
|
+
this.restoreFloatingBadgeIfNeeded();
|
|
3644
|
+
},
|
|
3645
|
+
onAcceptAll: () => {
|
|
3646
|
+
this.acceptAll();
|
|
3647
|
+
this.restoreFloatingBadgeIfNeeded();
|
|
3648
|
+
},
|
|
3649
|
+
onRejectAll: () => {
|
|
3650
|
+
this.rejectAll();
|
|
3651
|
+
this.restoreFloatingBadgeIfNeeded();
|
|
3652
|
+
},
|
|
1792
3653
|
onClose: () => {
|
|
3654
|
+
this.restoreFloatingBadgeIfNeeded();
|
|
1793
3655
|
this.eventBus.emit("preferences:closed", void 0);
|
|
1794
3656
|
}
|
|
1795
3657
|
});
|
|
@@ -1797,6 +3659,82 @@ var ConsentEngine = class {
|
|
|
1797
3659
|
}
|
|
1798
3660
|
closePreferences() {
|
|
1799
3661
|
this.preferencesModal.close();
|
|
3662
|
+
this.restoreFloatingBadgeIfNeeded();
|
|
3663
|
+
this.eventBus.emit("preferences:closed", void 0);
|
|
3664
|
+
}
|
|
3665
|
+
getLocale() {
|
|
3666
|
+
return this.i18n.getLocale();
|
|
3667
|
+
}
|
|
3668
|
+
setLocale(locale) {
|
|
3669
|
+
const previousLocale = this.i18n.getLocale();
|
|
3670
|
+
if (locale.toLowerCase() === previousLocale.toLowerCase()) return;
|
|
3671
|
+
this.i18n.setLocale(locale);
|
|
3672
|
+
this.stateManager.setLocale(locale);
|
|
3673
|
+
const config = this.getResolvedConfig();
|
|
3674
|
+
if (!config) return;
|
|
3675
|
+
if (this.banner.getIsVisible()) {
|
|
3676
|
+
this.banner.render(config, {
|
|
3677
|
+
onAcceptAll: () => this.acceptAll(),
|
|
3678
|
+
onRejectAll: () => this.rejectAll(),
|
|
3679
|
+
onConfigure: () => this.openPreferences()
|
|
3680
|
+
});
|
|
3681
|
+
}
|
|
3682
|
+
if (this.preferencesModal.getIsOpen()) {
|
|
3683
|
+
this.preferencesModal.render(config, this.stateManager.getChoices(), {
|
|
3684
|
+
onSave: (choices) => {
|
|
3685
|
+
this.setPreferences(choices);
|
|
3686
|
+
this.restoreFloatingBadgeIfNeeded();
|
|
3687
|
+
},
|
|
3688
|
+
onAcceptAll: () => {
|
|
3689
|
+
this.acceptAll();
|
|
3690
|
+
this.restoreFloatingBadgeIfNeeded();
|
|
3691
|
+
},
|
|
3692
|
+
onRejectAll: () => {
|
|
3693
|
+
this.rejectAll();
|
|
3694
|
+
this.restoreFloatingBadgeIfNeeded();
|
|
3695
|
+
},
|
|
3696
|
+
onClose: () => {
|
|
3697
|
+
this.restoreFloatingBadgeIfNeeded();
|
|
3698
|
+
this.eventBus.emit("preferences:closed", void 0);
|
|
3699
|
+
}
|
|
3700
|
+
});
|
|
3701
|
+
}
|
|
3702
|
+
const badgeConfig = this.resolveFloatingBadgeConfig(config);
|
|
3703
|
+
if (badgeConfig.enabled) {
|
|
3704
|
+
const wasVisible = this.floatingBadge.getIsVisible();
|
|
3705
|
+
this.floatingBadge.render(config, {
|
|
3706
|
+
onClick: () => this.openPreferences()
|
|
3707
|
+
});
|
|
3708
|
+
if (wasVisible) {
|
|
3709
|
+
this.floatingBadge.show();
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
this.eventBus.emit("locale:changed", { locale, previousLocale });
|
|
3713
|
+
this.dispatchDomEvent("solvenza:locale:changed", { locale, previousLocale });
|
|
3714
|
+
}
|
|
3715
|
+
/**
|
|
3716
|
+
* Synchronize active locale with parent application i18n state.
|
|
3717
|
+
*/
|
|
3718
|
+
syncLocale(locale) {
|
|
3719
|
+
this.setLocale(locale);
|
|
3720
|
+
}
|
|
3721
|
+
/**
|
|
3722
|
+
* Check if Global Privacy Control (GPC) or Do Not Track (DNT) signal is active.
|
|
3723
|
+
*/
|
|
3724
|
+
isGpcActive() {
|
|
3725
|
+
return detectGpcSignal();
|
|
3726
|
+
}
|
|
3727
|
+
restoreFloatingBadgeIfNeeded() {
|
|
3728
|
+
const config = this.getResolvedConfig();
|
|
3729
|
+
if (!config) return;
|
|
3730
|
+
const badgeConfig = this.resolveFloatingBadgeConfig(config);
|
|
3731
|
+
if (!badgeConfig.enabled) return;
|
|
3732
|
+
this.showFloatingBadge();
|
|
3733
|
+
}
|
|
3734
|
+
getResolvedConfig() {
|
|
3735
|
+
const rawConfig = this.stateManager.getConfig();
|
|
3736
|
+
if (!rawConfig) return null;
|
|
3737
|
+
return this.i18n.resolveConfig(rawConfig, this.getLocale());
|
|
1800
3738
|
}
|
|
1801
3739
|
withdraw() {
|
|
1802
3740
|
var _a, _b, _c, _d;
|
|
@@ -1811,15 +3749,76 @@ var ConsentEngine = class {
|
|
|
1811
3749
|
}
|
|
1812
3750
|
for (const catId of Object.keys(config.categories)) {
|
|
1813
3751
|
if (catId !== "necessary") {
|
|
1814
|
-
|
|
3752
|
+
this.purgeCategory(catId);
|
|
1815
3753
|
}
|
|
1816
3754
|
}
|
|
1817
3755
|
this.stateManager.clearChoices();
|
|
1818
3756
|
GoogleConsentAdapter.update(this.stateManager.getChoices());
|
|
1819
3757
|
this.eventBus.emit("consent:withdrawn", { previousChoices });
|
|
1820
3758
|
this.dispatchDomEvent("solvenza:updated", { choices: this.stateManager.getChoices() });
|
|
3759
|
+
const badgeConfig = this.resolveFloatingBadgeConfig(this.getResolvedConfig() || config);
|
|
3760
|
+
if (badgeConfig.enabled && badgeConfig.visibility !== "always") {
|
|
3761
|
+
this.hideFloatingBadge();
|
|
3762
|
+
}
|
|
1821
3763
|
this.showBanner();
|
|
1822
3764
|
}
|
|
3765
|
+
purgeCategory(category) {
|
|
3766
|
+
const config = this.stateManager.getConfig();
|
|
3767
|
+
if (!config) {
|
|
3768
|
+
return {
|
|
3769
|
+
category,
|
|
3770
|
+
purgedCookies: [],
|
|
3771
|
+
purgedLocalStorage: [],
|
|
3772
|
+
purgedSessionStorage: []
|
|
3773
|
+
};
|
|
3774
|
+
}
|
|
3775
|
+
const report = StorageCleaner.purgeCategory(config, category);
|
|
3776
|
+
this.eventBus.emit("storage:purged", { category, report });
|
|
3777
|
+
this.dispatchDomEvent("solvenza:storage:purged", { category, report });
|
|
3778
|
+
return report;
|
|
3779
|
+
}
|
|
3780
|
+
purgeStorage(categoryOrService) {
|
|
3781
|
+
var _a, _b;
|
|
3782
|
+
const config = this.stateManager.getConfig();
|
|
3783
|
+
if (!config) return [];
|
|
3784
|
+
if (categoryOrService) {
|
|
3785
|
+
if ((_a = config.categories) == null ? void 0 : _a[categoryOrService]) {
|
|
3786
|
+
return [this.purgeCategory(categoryOrService)];
|
|
3787
|
+
}
|
|
3788
|
+
const service = (_b = config.services) == null ? void 0 : _b[categoryOrService];
|
|
3789
|
+
if (service == null ? void 0 : service.category) {
|
|
3790
|
+
return [this.purgeCategory(service.category)];
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3793
|
+
const reports = [];
|
|
3794
|
+
const currentChoices = this.stateManager.getChoices();
|
|
3795
|
+
for (const [catId, allowed] of Object.entries(currentChoices)) {
|
|
3796
|
+
if (!allowed && catId !== "necessary") {
|
|
3797
|
+
reports.push(this.purgeCategory(catId));
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
return reports;
|
|
3801
|
+
}
|
|
3802
|
+
showFloatingBadge() {
|
|
3803
|
+
const config = this.getResolvedConfig();
|
|
3804
|
+
if (!config) return;
|
|
3805
|
+
const badgeConfig = this.resolveFloatingBadgeConfig(config);
|
|
3806
|
+
if (!badgeConfig.enabled) return;
|
|
3807
|
+
const el = this.floatingBadge.getElement();
|
|
3808
|
+
if (!el || !el.parentNode) {
|
|
3809
|
+
this.floatingBadge.render(config, {
|
|
3810
|
+
onClick: () => this.openPreferences()
|
|
3811
|
+
});
|
|
3812
|
+
}
|
|
3813
|
+
this.floatingBadge.show();
|
|
3814
|
+
this.eventBus.emit("floating-badge:shown", void 0);
|
|
3815
|
+
this.dispatchDomEvent("solvenza:badge:shown", void 0);
|
|
3816
|
+
}
|
|
3817
|
+
hideFloatingBadge() {
|
|
3818
|
+
this.floatingBadge.hide();
|
|
3819
|
+
this.eventBus.emit("floating-badge:hidden", void 0);
|
|
3820
|
+
this.dispatchDomEvent("solvenza:badge:hidden", void 0);
|
|
3821
|
+
}
|
|
1823
3822
|
when(categoryOrService, callback) {
|
|
1824
3823
|
return CustomServiceAdapter.createWhen(
|
|
1825
3824
|
this.eventBus,
|
|
@@ -1841,15 +3840,56 @@ var ConsentEngine = class {
|
|
|
1841
3840
|
const isGiven = !!this.getReceipt();
|
|
1842
3841
|
return ResourceScanner.runDiagnostic(config, isGiven);
|
|
1843
3842
|
}
|
|
1844
|
-
mountPolicy(targetContainer) {
|
|
1845
|
-
const config = this.stateManager.getConfig();
|
|
3843
|
+
mountPolicy(targetContainer, options) {
|
|
3844
|
+
const config = this.getResolvedConfig() || this.stateManager.getConfig();
|
|
3845
|
+
if (!config) {
|
|
3846
|
+
throw new Error("[ConsentSDK] SDK not initialized.");
|
|
3847
|
+
}
|
|
3848
|
+
const container = typeof targetContainer === "string" ? document.querySelector(targetContainer) : targetContainer;
|
|
3849
|
+
if (container) {
|
|
3850
|
+
container.innerHTML = PolicyGenerator.renderCookiePolicy(config, options);
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
renderPolicyHtml(options) {
|
|
3854
|
+
const config = this.getResolvedConfig() || this.stateManager.getConfig();
|
|
3855
|
+
if (!config) {
|
|
3856
|
+
throw new Error("[ConsentSDK] SDK not initialized.");
|
|
3857
|
+
}
|
|
3858
|
+
return PolicyGenerator.renderCookiePolicy(config, options);
|
|
3859
|
+
}
|
|
3860
|
+
mountLegalNotice(targetContainer, options) {
|
|
3861
|
+
const config = this.getResolvedConfig() || this.stateManager.getConfig();
|
|
3862
|
+
if (!config) {
|
|
3863
|
+
throw new Error("[ConsentSDK] SDK not initialized.");
|
|
3864
|
+
}
|
|
3865
|
+
const container = typeof targetContainer === "string" ? document.querySelector(targetContainer) : targetContainer;
|
|
3866
|
+
if (container) {
|
|
3867
|
+
container.innerHTML = PolicyGenerator.renderLegalNotice(config, options);
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
renderLegalNoticeHtml(options) {
|
|
3871
|
+
const config = this.getResolvedConfig() || this.stateManager.getConfig();
|
|
3872
|
+
if (!config) {
|
|
3873
|
+
throw new Error("[ConsentSDK] SDK not initialized.");
|
|
3874
|
+
}
|
|
3875
|
+
return PolicyGenerator.renderLegalNotice(config, options);
|
|
3876
|
+
}
|
|
3877
|
+
mountPrivacyPolicy(targetContainer, options) {
|
|
3878
|
+
const config = this.getResolvedConfig() || this.stateManager.getConfig();
|
|
1846
3879
|
if (!config) {
|
|
1847
3880
|
throw new Error("[ConsentSDK] SDK not initialized.");
|
|
1848
3881
|
}
|
|
1849
3882
|
const container = typeof targetContainer === "string" ? document.querySelector(targetContainer) : targetContainer;
|
|
1850
3883
|
if (container) {
|
|
1851
|
-
container.innerHTML = PolicyGenerator.
|
|
3884
|
+
container.innerHTML = PolicyGenerator.renderPrivacyPolicy(config, options);
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
renderPrivacyPolicyHtml(options) {
|
|
3888
|
+
const config = this.getResolvedConfig() || this.stateManager.getConfig();
|
|
3889
|
+
if (!config) {
|
|
3890
|
+
throw new Error("[ConsentSDK] SDK not initialized.");
|
|
1852
3891
|
}
|
|
3892
|
+
return PolicyGenerator.renderPrivacyPolicy(config, options);
|
|
1853
3893
|
}
|
|
1854
3894
|
saveChoices(choices, source) {
|
|
1855
3895
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
@@ -1862,10 +3902,13 @@ var ConsentEngine = class {
|
|
|
1862
3902
|
this.stateManager.getReceipt(),
|
|
1863
3903
|
(_a = config.security) == null ? void 0 : _a.secretKey
|
|
1864
3904
|
);
|
|
3905
|
+
if (this.isGpcActive()) {
|
|
3906
|
+
receipt.gpc = true;
|
|
3907
|
+
}
|
|
1865
3908
|
this.stateManager.updateChoices(receipt);
|
|
1866
3909
|
for (const [catId, isAllowed] of Object.entries(choices)) {
|
|
1867
3910
|
if (!isAllowed) {
|
|
1868
|
-
|
|
3911
|
+
this.purgeCategory(catId);
|
|
1869
3912
|
}
|
|
1870
3913
|
}
|
|
1871
3914
|
const cookieName = ((_b = config.storage) == null ? void 0 : _b.name) || "site_consent";
|
|
@@ -1898,12 +3941,21 @@ var ConsentEngine = class {
|
|
|
1898
3941
|
}
|
|
1899
3942
|
}
|
|
1900
3943
|
this.banner.remove();
|
|
3944
|
+
const resolvedConfig = this.getResolvedConfig() || config;
|
|
3945
|
+
const badgeConfig = this.resolveFloatingBadgeConfig(resolvedConfig);
|
|
3946
|
+
if (badgeConfig.enabled) {
|
|
3947
|
+
this.showFloatingBadge();
|
|
3948
|
+
}
|
|
1901
3949
|
this.eventBus.emit("consent:changed", { choices, receipt });
|
|
1902
3950
|
this.dispatchDomEvent("solvenza:updated", { choices, receipt });
|
|
1903
3951
|
}
|
|
1904
3952
|
showBanner() {
|
|
1905
|
-
const config = this.stateManager.getConfig();
|
|
3953
|
+
const config = this.getResolvedConfig() || this.stateManager.getConfig();
|
|
1906
3954
|
if (!config) return;
|
|
3955
|
+
const badgeConfig = this.resolveFloatingBadgeConfig(config);
|
|
3956
|
+
if (badgeConfig.enabled && badgeConfig.visibility !== "always") {
|
|
3957
|
+
this.hideFloatingBadge();
|
|
3958
|
+
}
|
|
1907
3959
|
this.banner.render(config, {
|
|
1908
3960
|
onAcceptAll: () => this.acceptAll(),
|
|
1909
3961
|
onRejectAll: () => this.rejectAll(),
|
|
@@ -1927,6 +3979,45 @@ var ConsentEngine = class {
|
|
|
1927
3979
|
document.addEventListener("solvenza:preferences", () => {
|
|
1928
3980
|
this.openPreferences();
|
|
1929
3981
|
});
|
|
3982
|
+
document.addEventListener("solvenza:badge:show", () => {
|
|
3983
|
+
this.showFloatingBadge();
|
|
3984
|
+
});
|
|
3985
|
+
document.addEventListener("solvenza:badge:hide", () => {
|
|
3986
|
+
this.hideFloatingBadge();
|
|
3987
|
+
});
|
|
3988
|
+
document.addEventListener("solvenza:locale", (e) => {
|
|
3989
|
+
var _a;
|
|
3990
|
+
if ((_a = e == null ? void 0 : e.detail) == null ? void 0 : _a.locale) {
|
|
3991
|
+
this.setLocale(e.detail.locale);
|
|
3992
|
+
}
|
|
3993
|
+
});
|
|
3994
|
+
}
|
|
3995
|
+
resolveFloatingBadgeConfig(config) {
|
|
3996
|
+
var _a;
|
|
3997
|
+
const raw = (_a = config == null ? void 0 : config.ui) == null ? void 0 : _a.floatingBadge;
|
|
3998
|
+
if (raw === false) {
|
|
3999
|
+
return { enabled: false };
|
|
4000
|
+
}
|
|
4001
|
+
if (raw === true || raw === void 0) {
|
|
4002
|
+
return {
|
|
4003
|
+
enabled: true,
|
|
4004
|
+
position: "bottom-left",
|
|
4005
|
+
icon: "cookie",
|
|
4006
|
+
visibility: "after-consent"
|
|
4007
|
+
};
|
|
4008
|
+
}
|
|
4009
|
+
if (typeof raw === "object" && raw !== null) {
|
|
4010
|
+
return {
|
|
4011
|
+
enabled: raw.enabled !== false,
|
|
4012
|
+
position: raw.position || "bottom-left",
|
|
4013
|
+
label: raw.label,
|
|
4014
|
+
ariaLabel: raw.ariaLabel,
|
|
4015
|
+
showLabel: raw.showLabel,
|
|
4016
|
+
icon: raw.icon || "cookie",
|
|
4017
|
+
visibility: raw.visibility || "after-consent"
|
|
4018
|
+
};
|
|
4019
|
+
}
|
|
4020
|
+
return { enabled: true, position: "bottom-left", icon: "cookie", visibility: "after-consent" };
|
|
1930
4021
|
}
|
|
1931
4022
|
dispatchDomEvent(name, detail) {
|
|
1932
4023
|
if (typeof document === "undefined") return;
|
|
@@ -1964,17 +4055,44 @@ var ConsentConfigBuilder = class {
|
|
|
1964
4055
|
this.config.policyVersion = version;
|
|
1965
4056
|
return this;
|
|
1966
4057
|
}
|
|
4058
|
+
setLegalEntity(entity) {
|
|
4059
|
+
this.config.legalEntity = entity;
|
|
4060
|
+
return this;
|
|
4061
|
+
}
|
|
4062
|
+
setLegalNotice(notice) {
|
|
4063
|
+
this.config.legalNotice = notice;
|
|
4064
|
+
return this;
|
|
4065
|
+
}
|
|
1967
4066
|
setPolicyUrls(privacyUrl, cookiesUrl) {
|
|
1968
4067
|
this.config.policy = { privacyUrl, cookiesUrl };
|
|
1969
4068
|
return this;
|
|
1970
4069
|
}
|
|
1971
|
-
setLocale(defaultLocale, autoDetect = true) {
|
|
4070
|
+
setLocale(defaultLocale, autoDetect = true, supported) {
|
|
1972
4071
|
this.config.locale = {
|
|
1973
4072
|
default: defaultLocale,
|
|
1974
|
-
autoDetect
|
|
4073
|
+
autoDetect,
|
|
4074
|
+
supported
|
|
1975
4075
|
};
|
|
1976
4076
|
return this;
|
|
1977
4077
|
}
|
|
4078
|
+
setTranslations(translations) {
|
|
4079
|
+
this.config.translations = translations;
|
|
4080
|
+
return this;
|
|
4081
|
+
}
|
|
4082
|
+
addTranslation(locale, translation) {
|
|
4083
|
+
if (!this.config.translations) {
|
|
4084
|
+
this.config.translations = {};
|
|
4085
|
+
}
|
|
4086
|
+
this.config.translations[locale.toLowerCase()] = translation;
|
|
4087
|
+
return this;
|
|
4088
|
+
}
|
|
4089
|
+
setFloatingBadge(badgeConfig) {
|
|
4090
|
+
if (!this.config.ui) {
|
|
4091
|
+
this.config.ui = {};
|
|
4092
|
+
}
|
|
4093
|
+
this.config.ui.floatingBadge = badgeConfig;
|
|
4094
|
+
return this;
|
|
4095
|
+
}
|
|
1978
4096
|
addCategory(id, category) {
|
|
1979
4097
|
if (!this.config.categories) {
|
|
1980
4098
|
this.config.categories = {};
|
|
@@ -2021,25 +4139,6 @@ var StorageFactory = class {
|
|
|
2021
4139
|
}
|
|
2022
4140
|
};
|
|
2023
4141
|
|
|
2024
|
-
// src/i18n/engine.ts
|
|
2025
|
-
var I18nEngine = class {
|
|
2026
|
-
constructor() {
|
|
2027
|
-
this.locale = "es";
|
|
2028
|
-
}
|
|
2029
|
-
setLocale(locale) {
|
|
2030
|
-
this.locale = locale;
|
|
2031
|
-
}
|
|
2032
|
-
getLocale() {
|
|
2033
|
-
return this.locale;
|
|
2034
|
-
}
|
|
2035
|
-
detectBrowserLocale() {
|
|
2036
|
-
if (typeof navigator !== "undefined" && navigator.language) {
|
|
2037
|
-
return navigator.language.split("-")[0].toLowerCase();
|
|
2038
|
-
}
|
|
2039
|
-
return "es";
|
|
2040
|
-
}
|
|
2041
|
-
};
|
|
2042
|
-
|
|
2043
4142
|
// src/index.ts
|
|
2044
4143
|
if (typeof window !== "undefined") {
|
|
2045
4144
|
window.Consent = Consent;
|
|
@@ -2049,6 +4148,7 @@ if (typeof window !== "undefined") {
|
|
|
2049
4148
|
ConsentConfigBuilder,
|
|
2050
4149
|
validateConfig,
|
|
2051
4150
|
PolicyGenerator,
|
|
4151
|
+
FloatingBadge,
|
|
2052
4152
|
ResourceScanner
|
|
2053
4153
|
};
|
|
2054
4154
|
}
|
|
@@ -2070,12 +4170,14 @@ if (typeof document !== "undefined") {
|
|
|
2070
4170
|
}
|
|
2071
4171
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2072
4172
|
0 && (module.exports = {
|
|
4173
|
+
BUILTIN_TRANSLATIONS,
|
|
2073
4174
|
ConfigValidationError,
|
|
2074
4175
|
Consent,
|
|
2075
4176
|
ConsentConfigBuilder,
|
|
2076
4177
|
ConsentEngine,
|
|
2077
4178
|
CookieStorageProvider,
|
|
2078
4179
|
CookieStore,
|
|
4180
|
+
FloatingBadge,
|
|
2079
4181
|
GoogleConsentAdapter,
|
|
2080
4182
|
I18nEngine,
|
|
2081
4183
|
IframeGate,
|
|
@@ -2086,13 +4188,22 @@ if (typeof document !== "undefined") {
|
|
|
2086
4188
|
PolicyGenerator,
|
|
2087
4189
|
ResourceGate,
|
|
2088
4190
|
ResourceScanner,
|
|
4191
|
+
SERVICE_PRESETS,
|
|
2089
4192
|
ScriptGate,
|
|
2090
4193
|
ScriptResourceBlocker,
|
|
4194
|
+
StorageCleaner,
|
|
2091
4195
|
StorageFactory,
|
|
4196
|
+
applyGpcChoices,
|
|
2092
4197
|
computeReceiptSignature,
|
|
2093
4198
|
createReceipt,
|
|
4199
|
+
defineServices,
|
|
4200
|
+
detectGpcSignal,
|
|
4201
|
+
getPreset,
|
|
4202
|
+
hasPreset,
|
|
2094
4203
|
isReceiptExpired,
|
|
2095
4204
|
parseReceipt,
|
|
4205
|
+
resolveConfigPresets,
|
|
4206
|
+
resolveGpcConfig,
|
|
2096
4207
|
sanitizeHtml,
|
|
2097
4208
|
validateConfig,
|
|
2098
4209
|
verifyReceiptIntegrity
|