@react-lgpd-consent/core 0.6.3 → 0.7.0
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/CHANGELOG.md +141 -2
- package/README.md +46 -0
- package/dist/index.cjs +233 -60
- package/dist/index.d.cts +118 -5
- package/dist/index.d.ts +118 -5
- package/dist/index.js +231 -61
- package/package.json +2 -3
package/dist/index.js
CHANGED
|
@@ -312,15 +312,15 @@ var DEFAULT_STORAGE_VERSION = "1";
|
|
|
312
312
|
function buildConsentStorageKey(options) {
|
|
313
313
|
const namespaceRaw = options?.namespace?.trim() || DEFAULT_STORAGE_NAMESPACE;
|
|
314
314
|
const versionRaw = options?.version?.trim() || DEFAULT_STORAGE_VERSION;
|
|
315
|
-
const sanitizedNamespace = namespaceRaw.
|
|
316
|
-
const sanitizedVersion = versionRaw.
|
|
315
|
+
const sanitizedNamespace = namespaceRaw.replaceAll(/[^a-z0-9._-]+/gi, "-").toLowerCase();
|
|
316
|
+
const sanitizedVersion = versionRaw.replaceAll(/[^a-z0-9._-]+/gi, "-").toLowerCase();
|
|
317
317
|
return `${sanitizedNamespace}__v${sanitizedVersion}`;
|
|
318
318
|
}
|
|
319
319
|
var DEFAULT_COOKIE_OPTS = {
|
|
320
320
|
name: "cookieConsent",
|
|
321
321
|
maxAgeDays: 365,
|
|
322
322
|
sameSite: "Lax",
|
|
323
|
-
secure:
|
|
323
|
+
secure: globalThis.window === void 0 ? false : globalThis.window.location.protocol === "https:",
|
|
324
324
|
path: "/",
|
|
325
325
|
domain: void 0
|
|
326
326
|
};
|
|
@@ -400,6 +400,23 @@ function writeConsentCookie(state, config, opts, source = "banner") {
|
|
|
400
400
|
preferencesCount: Object.keys(cookieData.preferences).length
|
|
401
401
|
});
|
|
402
402
|
}
|
|
403
|
+
function createConsentAuditEntry(state, params) {
|
|
404
|
+
const preferences = ensureNecessaryAlwaysOn(state.preferences);
|
|
405
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
406
|
+
return {
|
|
407
|
+
action: params.action,
|
|
408
|
+
storageKey: params.storageKey,
|
|
409
|
+
consentVersion: params.consentVersion?.trim() || "1",
|
|
410
|
+
timestamp: now,
|
|
411
|
+
consentDate: state.consentDate,
|
|
412
|
+
lastUpdate: state.lastUpdate,
|
|
413
|
+
consented: state.consented,
|
|
414
|
+
preferences,
|
|
415
|
+
version: state.version,
|
|
416
|
+
source: params.origin ?? state.source,
|
|
417
|
+
projectConfig: state.projectConfig
|
|
418
|
+
};
|
|
419
|
+
}
|
|
403
420
|
function removeConsentCookie(opts) {
|
|
404
421
|
if (typeof document === "undefined") {
|
|
405
422
|
logger.debug("Cookie removal skipped: server-side environment");
|
|
@@ -412,15 +429,14 @@ function removeConsentCookie(opts) {
|
|
|
412
429
|
}
|
|
413
430
|
|
|
414
431
|
// src/utils/dataLayerEvents.ts
|
|
415
|
-
var LIBRARY_VERSION = "0.
|
|
432
|
+
var LIBRARY_VERSION = "0.7.0";
|
|
416
433
|
function ensureDataLayer() {
|
|
417
|
-
|
|
418
|
-
if (
|
|
419
|
-
|
|
420
|
-
}
|
|
434
|
+
var _a;
|
|
435
|
+
if (globalThis.window === void 0) return;
|
|
436
|
+
(_a = globalThis.window).dataLayer ?? (_a.dataLayer = []);
|
|
421
437
|
}
|
|
422
438
|
function pushConsentInitializedEvent(categories) {
|
|
423
|
-
if (
|
|
439
|
+
if (globalThis.window === void 0) return;
|
|
424
440
|
ensureDataLayer();
|
|
425
441
|
const event = {
|
|
426
442
|
event: "consent_initialized",
|
|
@@ -428,10 +444,10 @@ function pushConsentInitializedEvent(categories) {
|
|
|
428
444
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
429
445
|
categories
|
|
430
446
|
};
|
|
431
|
-
window.dataLayer?.push(event);
|
|
447
|
+
globalThis.window.dataLayer?.push(event);
|
|
432
448
|
}
|
|
433
449
|
function pushConsentUpdatedEvent(categories, origin, previousCategories) {
|
|
434
|
-
if (
|
|
450
|
+
if (globalThis.window === void 0) return;
|
|
435
451
|
ensureDataLayer();
|
|
436
452
|
const changedCategories = previousCategories ? Object.keys(categories).filter((key) => categories[key] !== previousCategories[key]) : [];
|
|
437
453
|
const event = {
|
|
@@ -442,7 +458,7 @@ function pushConsentUpdatedEvent(categories, origin, previousCategories) {
|
|
|
442
458
|
categories,
|
|
443
459
|
changed_categories: changedCategories
|
|
444
460
|
};
|
|
445
|
-
window.dataLayer?.push(event);
|
|
461
|
+
globalThis.window.dataLayer?.push(event);
|
|
446
462
|
}
|
|
447
463
|
function useDataLayerEvents() {
|
|
448
464
|
return {
|
|
@@ -631,10 +647,10 @@ var COOKIE_CATALOG_OVERRIDES = {};
|
|
|
631
647
|
var COOKIE_CATEGORY_OVERRIDES = {};
|
|
632
648
|
function setCookieCatalogOverrides(overrides) {
|
|
633
649
|
COOKIE_CATALOG_OVERRIDES = {
|
|
634
|
-
byCategory: { ...COOKIE_CATALOG_OVERRIDES.byCategory
|
|
650
|
+
byCategory: { ...COOKIE_CATALOG_OVERRIDES.byCategory, ...overrides.byCategory },
|
|
635
651
|
byIntegration: {
|
|
636
|
-
...COOKIE_CATALOG_OVERRIDES.byIntegration
|
|
637
|
-
...overrides.byIntegration
|
|
652
|
+
...COOKIE_CATALOG_OVERRIDES.byIntegration,
|
|
653
|
+
...overrides.byIntegration
|
|
638
654
|
}
|
|
639
655
|
};
|
|
640
656
|
}
|
|
@@ -656,7 +672,7 @@ function getCookiesInfoForCategory(categoryId, usedIntegrations) {
|
|
|
656
672
|
([pattern]) => matchPattern(desc.name, pattern)
|
|
657
673
|
)?.[1];
|
|
658
674
|
const finalCat = overrideCat ?? defaultCat;
|
|
659
|
-
if (finalCat === categoryId && !result.
|
|
675
|
+
if (finalCat === categoryId && !result.some((d) => d.name === desc.name)) result.push(desc);
|
|
660
676
|
});
|
|
661
677
|
});
|
|
662
678
|
const catOverride = COOKIE_CATALOG_OVERRIDES.byCategory?.[categoryId];
|
|
@@ -668,7 +684,7 @@ function getCookiesInfoForCategory(categoryId, usedIntegrations) {
|
|
|
668
684
|
});
|
|
669
685
|
}
|
|
670
686
|
if (categoryId === "necessary") {
|
|
671
|
-
if (!result.
|
|
687
|
+
if (!result.some((d) => d.name === "cookieConsent")) {
|
|
672
688
|
result.push({
|
|
673
689
|
name: "cookieConsent",
|
|
674
690
|
purpose: "Armazena suas prefer\xEAncias de consentimento",
|
|
@@ -1050,9 +1066,9 @@ var GUIDANCE_PRESETS = {
|
|
|
1050
1066
|
|
|
1051
1067
|
// src/utils/peerDepsCheck.ts
|
|
1052
1068
|
function detectMultipleReactInstances() {
|
|
1053
|
-
if (
|
|
1069
|
+
if (globalThis.window === void 0) return false;
|
|
1054
1070
|
try {
|
|
1055
|
-
const reactSymbols = Object.getOwnPropertySymbols(window).map(
|
|
1071
|
+
const reactSymbols = Object.getOwnPropertySymbols(globalThis.window).map(String).filter((name) => name.includes("react"));
|
|
1056
1072
|
if (reactSymbols.length > 1) {
|
|
1057
1073
|
return true;
|
|
1058
1074
|
}
|
|
@@ -1067,7 +1083,7 @@ function detectMultipleReactInstances() {
|
|
|
1067
1083
|
}
|
|
1068
1084
|
}
|
|
1069
1085
|
function getPackageVersion(packageName) {
|
|
1070
|
-
if (
|
|
1086
|
+
if (globalThis.window === void 0) return null;
|
|
1071
1087
|
try {
|
|
1072
1088
|
const pkg = window[packageName];
|
|
1073
1089
|
if (pkg?.version) return pkg.version;
|
|
@@ -1081,7 +1097,7 @@ function getPackageVersion(packageName) {
|
|
|
1081
1097
|
}
|
|
1082
1098
|
}
|
|
1083
1099
|
function isVersionInRange(version, minMajor, maxMajor) {
|
|
1084
|
-
const major = parseInt(version.split(".")[0], 10);
|
|
1100
|
+
const major = Number.parseInt(version.split(".")[0], 10);
|
|
1085
1101
|
return major >= minMajor && major <= maxMajor;
|
|
1086
1102
|
}
|
|
1087
1103
|
function checkPeerDeps(options = {}) {
|
|
@@ -1095,7 +1111,7 @@ function checkPeerDeps(options = {}) {
|
|
|
1095
1111
|
if (skipInProduction && isProduction) {
|
|
1096
1112
|
return result;
|
|
1097
1113
|
}
|
|
1098
|
-
if (
|
|
1114
|
+
if (globalThis.window === void 0) {
|
|
1099
1115
|
return result;
|
|
1100
1116
|
}
|
|
1101
1117
|
if (detectMultipleReactInstances()) {
|
|
@@ -1257,7 +1273,7 @@ function validateConsentProviderProps(props) {
|
|
|
1257
1273
|
const sanitized = {};
|
|
1258
1274
|
if (!isDev()) {
|
|
1259
1275
|
if (props.categories) {
|
|
1260
|
-
const enabled =
|
|
1276
|
+
const enabled = [...new Set(props.categories.enabledCategories ?? [])];
|
|
1261
1277
|
const sanitizedEnabled = enabled.filter((c) => c !== "necessary");
|
|
1262
1278
|
sanitized.categories = {
|
|
1263
1279
|
enabledCategories: sanitizedEnabled,
|
|
@@ -1294,11 +1310,11 @@ function validateConsentProviderProps(props) {
|
|
|
1294
1310
|
}
|
|
1295
1311
|
if (!props.categories) {
|
|
1296
1312
|
warnings.push(
|
|
1297
|
-
"Prop 'categories' n\xE3o fornecida
|
|
1313
|
+
"Prop 'categories' n\xE3o fornecida \u2014 o ConsentProvider requer configura\xE7\xE3o de categorias."
|
|
1298
1314
|
);
|
|
1299
1315
|
} else {
|
|
1300
1316
|
const cat = props.categories;
|
|
1301
|
-
const enabled =
|
|
1317
|
+
const enabled = [...new Set(cat.enabledCategories ?? [])];
|
|
1302
1318
|
if (enabled.includes("necessary")) {
|
|
1303
1319
|
warnings.push("'necessary' \xE9 sempre inclu\xEDda automaticamente \u2014 remova de enabledCategories.");
|
|
1304
1320
|
}
|
|
@@ -1306,7 +1322,7 @@ function validateConsentProviderProps(props) {
|
|
|
1306
1322
|
const invalidEnabled = sanitizedEnabled.filter((c) => typeof c !== "string" || c.trim() === "");
|
|
1307
1323
|
if (invalidEnabled.length > 0) {
|
|
1308
1324
|
warnings.push(
|
|
1309
|
-
`enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map(
|
|
1325
|
+
`enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map(String).join(", ")} \u2014 remova ou corrija os IDs de categoria`
|
|
1310
1326
|
);
|
|
1311
1327
|
}
|
|
1312
1328
|
const custom = cat.customCategories ?? [];
|
|
@@ -1400,13 +1416,13 @@ function detectConsentCookieName() {
|
|
|
1400
1416
|
}
|
|
1401
1417
|
return null;
|
|
1402
1418
|
}
|
|
1419
|
+
function matchPattern2(name, pattern) {
|
|
1420
|
+
if (pattern.endsWith("*")) return name.startsWith(pattern.slice(0, -1));
|
|
1421
|
+
return name === pattern;
|
|
1422
|
+
}
|
|
1403
1423
|
function categorizeDiscoveredCookies(discovered, registerOverrides = false) {
|
|
1404
1424
|
const list = discovered || globalThis.__LGPD_DISCOVERED_COOKIES__ || [];
|
|
1405
1425
|
const out = {};
|
|
1406
|
-
function matchPattern2(name, pattern) {
|
|
1407
|
-
if (pattern.endsWith("*")) return name.startsWith(pattern.slice(0, -1));
|
|
1408
|
-
return name === pattern;
|
|
1409
|
-
}
|
|
1410
1426
|
list.filter((d) => d.name && d.name !== "cookieConsent").forEach((d) => {
|
|
1411
1427
|
let assigned = null;
|
|
1412
1428
|
Object.keys(COOKIE_PATTERNS_BY_CATEGORY).forEach((cat2) => {
|
|
@@ -1414,9 +1430,9 @@ function categorizeDiscoveredCookies(discovered, registerOverrides = false) {
|
|
|
1414
1430
|
const patterns = COOKIE_PATTERNS_BY_CATEGORY[cat2] || [];
|
|
1415
1431
|
if (patterns.some((p) => matchPattern2(d.name, p))) assigned = cat2;
|
|
1416
1432
|
});
|
|
1417
|
-
const cat = assigned
|
|
1433
|
+
const cat = assigned ?? "analytics";
|
|
1418
1434
|
out[cat] = out[cat] || [];
|
|
1419
|
-
if (!out[cat].
|
|
1435
|
+
if (!out[cat].some((x) => x.name === d.name)) out[cat].push(d);
|
|
1420
1436
|
});
|
|
1421
1437
|
if (registerOverrides) {
|
|
1422
1438
|
const byCategory = {};
|
|
@@ -1493,7 +1509,7 @@ function useCategories() {
|
|
|
1493
1509
|
const context = React4.useContext(CategoriesContext);
|
|
1494
1510
|
if (!context) {
|
|
1495
1511
|
throw new Error(
|
|
1496
|
-
"useCategories deve ser usado dentro de
|
|
1512
|
+
"[react-lgpd-consent] useCategories deve ser usado dentro de <ConsentProvider>. Adicione o provider ao redor da sua \xE1rvore antes de chamar o hook."
|
|
1497
1513
|
);
|
|
1498
1514
|
}
|
|
1499
1515
|
return context;
|
|
@@ -1644,6 +1660,11 @@ var StateCtx = React4.createContext(null);
|
|
|
1644
1660
|
var ActionsCtx = React4.createContext(null);
|
|
1645
1661
|
var TextsCtx = React4.createContext(DEFAULT_TEXTS);
|
|
1646
1662
|
var HydrationCtx = React4.createContext(false);
|
|
1663
|
+
function buildProviderError(hookName) {
|
|
1664
|
+
return new Error(
|
|
1665
|
+
`[react-lgpd-consent] ${hookName} deve ser usado dentro de <ConsentProvider>. Envolva seu componente com o provider ou use o wrapper @react-lgpd-consent/mui.`
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1647
1668
|
function ConsentProvider({
|
|
1648
1669
|
initialState,
|
|
1649
1670
|
categories,
|
|
@@ -1667,7 +1688,10 @@ function ConsentProvider({
|
|
|
1667
1688
|
disableDeveloperGuidance,
|
|
1668
1689
|
guidanceConfig,
|
|
1669
1690
|
children,
|
|
1670
|
-
disableDiscoveryLog
|
|
1691
|
+
disableDiscoveryLog,
|
|
1692
|
+
onConsentInit,
|
|
1693
|
+
onConsentChange,
|
|
1694
|
+
onAuditLog
|
|
1671
1695
|
}) {
|
|
1672
1696
|
const texts = React4.useMemo(() => ({ ...DEFAULT_TEXTS, ...textsProp ?? {} }), [textsProp]);
|
|
1673
1697
|
const cookie = React4.useMemo(() => {
|
|
@@ -1681,6 +1705,7 @@ function ConsentProvider({
|
|
|
1681
1705
|
}
|
|
1682
1706
|
return base;
|
|
1683
1707
|
}, [cookieOpts, storage?.domain, storage?.namespace, storage?.version]);
|
|
1708
|
+
const consentVersion = storage?.version?.trim() || "1";
|
|
1684
1709
|
const finalCategoriesConfig = React4.useMemo(() => {
|
|
1685
1710
|
const isProd = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
1686
1711
|
if (!categories) return DEFAULT_PROJECT_CATEGORIES;
|
|
@@ -1727,6 +1752,8 @@ function ConsentProvider({
|
|
|
1727
1752
|
const skipCookiePersistRef = React4.useRef(false);
|
|
1728
1753
|
const [isHydrated, setIsHydrated] = React4.useState(false);
|
|
1729
1754
|
const previousPreferencesRef = React4.useRef(state.preferences);
|
|
1755
|
+
const auditInitEmittedRef = React4.useRef(false);
|
|
1756
|
+
const previousConsentedAuditRef = React4.useRef(state.consented);
|
|
1730
1757
|
React4.useEffect(() => {
|
|
1731
1758
|
if (!initialState) {
|
|
1732
1759
|
const saved = readConsentCookie(cookie.name);
|
|
@@ -1775,13 +1802,44 @@ function ConsentProvider({
|
|
|
1775
1802
|
logger.info("DataLayer: consent_initialized event dispatched", {
|
|
1776
1803
|
preferences: state.preferences
|
|
1777
1804
|
});
|
|
1805
|
+
if (onConsentInit) onConsentInit(state);
|
|
1778
1806
|
}
|
|
1779
1807
|
}, [isHydrated]);
|
|
1808
|
+
React4.useEffect(() => {
|
|
1809
|
+
if (!isHydrated) return;
|
|
1810
|
+
if (!onAuditLog) return;
|
|
1811
|
+
if (auditInitEmittedRef.current) return;
|
|
1812
|
+
onAuditLog(
|
|
1813
|
+
createConsentAuditEntry(state, {
|
|
1814
|
+
action: "init",
|
|
1815
|
+
storageKey: cookie.name,
|
|
1816
|
+
consentVersion
|
|
1817
|
+
})
|
|
1818
|
+
);
|
|
1819
|
+
auditInitEmittedRef.current = true;
|
|
1820
|
+
}, [isHydrated, onAuditLog, state, cookie.name, consentVersion]);
|
|
1780
1821
|
React4.useEffect(() => {
|
|
1781
1822
|
if (!state.consented) return;
|
|
1782
1823
|
if (skipCookiePersistRef.current) return;
|
|
1783
1824
|
writeConsentCookie(state, finalCategoriesConfig, cookie);
|
|
1784
1825
|
}, [state, cookie, finalCategoriesConfig]);
|
|
1826
|
+
React4.useEffect(() => {
|
|
1827
|
+
if (!onAuditLog) {
|
|
1828
|
+
previousConsentedAuditRef.current = state.consented;
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
if (previousConsentedAuditRef.current && !state.consented) {
|
|
1832
|
+
onAuditLog(
|
|
1833
|
+
createConsentAuditEntry(state, {
|
|
1834
|
+
action: "reset",
|
|
1835
|
+
storageKey: cookie.name,
|
|
1836
|
+
consentVersion,
|
|
1837
|
+
origin: "reset"
|
|
1838
|
+
})
|
|
1839
|
+
);
|
|
1840
|
+
}
|
|
1841
|
+
previousConsentedAuditRef.current = state.consented;
|
|
1842
|
+
}, [state, onAuditLog, cookie.name, consentVersion]);
|
|
1785
1843
|
const prevConsented = React4.useRef(state.consented);
|
|
1786
1844
|
React4.useEffect(() => {
|
|
1787
1845
|
if (!prevConsented.current && state.consented && onConsentGiven) {
|
|
@@ -1802,9 +1860,32 @@ function ConsentProvider({
|
|
|
1802
1860
|
preferences: state.preferences,
|
|
1803
1861
|
consented: state.consented
|
|
1804
1862
|
});
|
|
1863
|
+
if (onConsentChange) {
|
|
1864
|
+
onConsentChange(state, { origin });
|
|
1865
|
+
}
|
|
1866
|
+
if (onAuditLog) {
|
|
1867
|
+
onAuditLog(
|
|
1868
|
+
createConsentAuditEntry(state, {
|
|
1869
|
+
action: "update",
|
|
1870
|
+
storageKey: cookie.name,
|
|
1871
|
+
consentVersion,
|
|
1872
|
+
origin
|
|
1873
|
+
})
|
|
1874
|
+
);
|
|
1875
|
+
}
|
|
1805
1876
|
previousPreferencesRef.current = state.preferences;
|
|
1806
1877
|
}
|
|
1807
|
-
}, [
|
|
1878
|
+
}, [
|
|
1879
|
+
state,
|
|
1880
|
+
state.preferences,
|
|
1881
|
+
state.consented,
|
|
1882
|
+
state.source,
|
|
1883
|
+
isHydrated,
|
|
1884
|
+
onConsentChange,
|
|
1885
|
+
onAuditLog,
|
|
1886
|
+
cookie.name,
|
|
1887
|
+
consentVersion
|
|
1888
|
+
]);
|
|
1808
1889
|
const api = React4.useMemo(() => {
|
|
1809
1890
|
const acceptAll = () => dispatch({ type: "ACCEPT_ALL", config: finalCategoriesConfig });
|
|
1810
1891
|
const rejectAll = () => dispatch({ type: "REJECT_ALL", config: finalCategoriesConfig });
|
|
@@ -1855,6 +1936,14 @@ function ConsentProvider({
|
|
|
1855
1936
|
if (typeof backdrop === "string") return backdrop;
|
|
1856
1937
|
return "rgba(0, 0, 0, 0.4)";
|
|
1857
1938
|
}, [designTokens]);
|
|
1939
|
+
const cookieBannerPropsWithDefaults = React4.useMemo(() => {
|
|
1940
|
+
const incoming = cookieBannerProps ?? {};
|
|
1941
|
+
return {
|
|
1942
|
+
...incoming,
|
|
1943
|
+
blocking: incoming.blocking === void 0 ? blocking : Boolean(incoming.blocking),
|
|
1944
|
+
hideBranding: incoming.hideBranding === void 0 ? _hideBranding : Boolean(incoming.hideBranding)
|
|
1945
|
+
};
|
|
1946
|
+
}, [cookieBannerProps, blocking, _hideBranding]);
|
|
1858
1947
|
const content = /* @__PURE__ */ jsx(StateCtx.Provider, { value: state, children: /* @__PURE__ */ jsx(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ jsx(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ jsx(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ jsx(DesignProvider, { tokens: designTokens, children: /* @__PURE__ */ jsxs(
|
|
1859
1948
|
CategoriesProvider,
|
|
1860
1949
|
{
|
|
@@ -1875,7 +1964,7 @@ function ConsentProvider({
|
|
|
1875
1964
|
}
|
|
1876
1965
|
) : (
|
|
1877
1966
|
// Aviso de desenvolvimento: usuário pode estar esquecendo de fornecer componentes UI
|
|
1878
|
-
process.env.NODE_ENV === "development" &&
|
|
1967
|
+
process.env.NODE_ENV === "development" && globalThis.window !== void 0 && !didWarnAboutMissingUI.current && !CookieBannerComponent && !FloatingPreferencesButtonComponent && (() => {
|
|
1879
1968
|
didWarnAboutMissingUI.current = true;
|
|
1880
1969
|
console.warn(
|
|
1881
1970
|
"%c[@react-lgpd-consent/core] Aviso: Nenhum componente UI fornecido",
|
|
@@ -1937,8 +2026,7 @@ function ConsentProvider({
|
|
|
1937
2026
|
rejectAll: api.rejectAll,
|
|
1938
2027
|
openPreferences: api.openPreferences,
|
|
1939
2028
|
texts,
|
|
1940
|
-
|
|
1941
|
-
...cookieBannerProps
|
|
2029
|
+
...cookieBannerPropsWithDefaults
|
|
1942
2030
|
}
|
|
1943
2031
|
),
|
|
1944
2032
|
state.consented && !disableFloatingPreferencesButton && FloatingPreferencesButtonComponent && /* @__PURE__ */ jsx(
|
|
@@ -1956,12 +2044,12 @@ function ConsentProvider({
|
|
|
1956
2044
|
}
|
|
1957
2045
|
function useConsentStateInternal() {
|
|
1958
2046
|
const ctx = React4.useContext(StateCtx);
|
|
1959
|
-
if (!ctx) throw
|
|
2047
|
+
if (!ctx) throw buildProviderError("useConsentState");
|
|
1960
2048
|
return ctx;
|
|
1961
2049
|
}
|
|
1962
2050
|
function useConsentActionsInternal() {
|
|
1963
2051
|
const ctx = React4.useContext(ActionsCtx);
|
|
1964
|
-
if (!ctx) throw
|
|
2052
|
+
if (!ctx) throw buildProviderError("useConsentActions");
|
|
1965
2053
|
return ctx;
|
|
1966
2054
|
}
|
|
1967
2055
|
function useConsentTextsInternal() {
|
|
@@ -1980,7 +2068,7 @@ function ConsentGate(props) {
|
|
|
1980
2068
|
|
|
1981
2069
|
// src/utils/scriptLoader.ts
|
|
1982
2070
|
var LOADING_SCRIPTS = /* @__PURE__ */ new Map();
|
|
1983
|
-
function loadScript(id, src, category = null, attrs = {}) {
|
|
2071
|
+
function loadScript(id, src, category = null, attrs = {}, nonce) {
|
|
1984
2072
|
if (typeof document === "undefined") return Promise.resolve();
|
|
1985
2073
|
if (document.getElementById(id)) return Promise.resolve();
|
|
1986
2074
|
const existingPromise = LOADING_SCRIPTS.get(id);
|
|
@@ -2006,7 +2094,13 @@ function loadScript(id, src, category = null, attrs = {}) {
|
|
|
2006
2094
|
s.id = id;
|
|
2007
2095
|
s.src = src;
|
|
2008
2096
|
s.async = true;
|
|
2009
|
-
|
|
2097
|
+
const mergedAttrs = { ...attrs };
|
|
2098
|
+
const scriptNonce = mergedAttrs.nonce || nonce;
|
|
2099
|
+
if (scriptNonce) {
|
|
2100
|
+
s.nonce = scriptNonce;
|
|
2101
|
+
mergedAttrs.nonce = scriptNonce;
|
|
2102
|
+
}
|
|
2103
|
+
for (const [k, v] of Object.entries(mergedAttrs)) s.setAttribute(k, v);
|
|
2010
2104
|
s.onload = () => {
|
|
2011
2105
|
LOADING_SCRIPTS.delete(id);
|
|
2012
2106
|
resolve();
|
|
@@ -2184,7 +2278,8 @@ function validateNecessaryClassification(integrations, enabledCategories) {
|
|
|
2184
2278
|
// src/utils/ConsentScriptLoader.tsx
|
|
2185
2279
|
function ConsentScriptLoader({
|
|
2186
2280
|
integrations,
|
|
2187
|
-
reloadOnChange = false
|
|
2281
|
+
reloadOnChange = false,
|
|
2282
|
+
nonce
|
|
2188
2283
|
}) {
|
|
2189
2284
|
const { preferences, consented } = useConsent();
|
|
2190
2285
|
const categories = useCategories();
|
|
@@ -2217,8 +2312,8 @@ function ConsentScriptLoader({
|
|
|
2217
2312
|
const current = Array.isArray(gt.__LGPD_REQUIRED_CATEGORIES__) ? gt.__LGPD_REQUIRED_CATEGORIES__ : [];
|
|
2218
2313
|
const merged = Array.from(/* @__PURE__ */ new Set([...current, ...required]));
|
|
2219
2314
|
gt.__LGPD_REQUIRED_CATEGORIES__ = merged;
|
|
2220
|
-
if (
|
|
2221
|
-
window.dispatchEvent(new CustomEvent("lgpd:requiredCategories"));
|
|
2315
|
+
if (globalThis.window !== void 0 && typeof globalThis.window.dispatchEvent === "function") {
|
|
2316
|
+
globalThis.window.dispatchEvent(new CustomEvent("lgpd:requiredCategories"));
|
|
2222
2317
|
}
|
|
2223
2318
|
} catch {
|
|
2224
2319
|
}
|
|
@@ -2226,7 +2321,7 @@ function ConsentScriptLoader({
|
|
|
2226
2321
|
React4.useEffect(() => {
|
|
2227
2322
|
const isDev2 = process.env.NODE_ENV !== "production";
|
|
2228
2323
|
if (!isDev2 || integrations.length === 0) return;
|
|
2229
|
-
const enabledCategories = categories.
|
|
2324
|
+
const enabledCategories = categories.config.enabledCategories ?? [];
|
|
2230
2325
|
const isValid = validateIntegrationCategories(integrations, enabledCategories);
|
|
2231
2326
|
if (!isValid) {
|
|
2232
2327
|
autoConfigureCategories({ enabledCategories }, integrations, {
|
|
@@ -2257,11 +2352,15 @@ function ConsentScriptLoader({
|
|
|
2257
2352
|
const alreadyLoaded = loadedScripts.current.has(integration.id);
|
|
2258
2353
|
if (shouldLoad && (!alreadyLoaded || reloadOnChange)) {
|
|
2259
2354
|
try {
|
|
2355
|
+
const mergedAttrs = integration.attrs ?? {};
|
|
2356
|
+
const scriptNonce = integration.nonce ?? nonce;
|
|
2357
|
+
if (scriptNonce && !mergedAttrs.nonce) mergedAttrs.nonce = scriptNonce;
|
|
2260
2358
|
await loadScript(
|
|
2261
2359
|
integration.id,
|
|
2262
2360
|
integration.src,
|
|
2263
2361
|
integration.category,
|
|
2264
|
-
|
|
2362
|
+
mergedAttrs,
|
|
2363
|
+
scriptNonce
|
|
2265
2364
|
);
|
|
2266
2365
|
if (integration.init) {
|
|
2267
2366
|
integration.init();
|
|
@@ -2274,13 +2373,13 @@ function ConsentScriptLoader({
|
|
|
2274
2373
|
}
|
|
2275
2374
|
}, 0);
|
|
2276
2375
|
return () => clearTimeout(timeoutId);
|
|
2277
|
-
}, [preferences, consented, integrations, reloadOnChange]);
|
|
2376
|
+
}, [preferences, consented, integrations, reloadOnChange, nonce]);
|
|
2278
2377
|
return null;
|
|
2279
2378
|
}
|
|
2280
2379
|
function useConsentScriptLoader() {
|
|
2281
2380
|
const { preferences, consented } = useConsent();
|
|
2282
2381
|
return React4.useCallback(
|
|
2283
|
-
async (integration) => {
|
|
2382
|
+
async (integration, nonce) => {
|
|
2284
2383
|
if (!consented) {
|
|
2285
2384
|
logger.warn(`\u26A0\uFE0F Cannot load script ${integration.id}: No consent given`);
|
|
2286
2385
|
return false;
|
|
@@ -2293,7 +2392,16 @@ function useConsentScriptLoader() {
|
|
|
2293
2392
|
return false;
|
|
2294
2393
|
}
|
|
2295
2394
|
try {
|
|
2296
|
-
|
|
2395
|
+
const mergedAttrs = integration.attrs ? { ...integration.attrs } : {};
|
|
2396
|
+
const scriptNonce = integration.nonce ?? nonce;
|
|
2397
|
+
if (scriptNonce && !mergedAttrs.nonce) mergedAttrs.nonce = scriptNonce;
|
|
2398
|
+
await loadScript(
|
|
2399
|
+
integration.id,
|
|
2400
|
+
integration.src,
|
|
2401
|
+
integration.category,
|
|
2402
|
+
mergedAttrs,
|
|
2403
|
+
scriptNonce
|
|
2404
|
+
);
|
|
2297
2405
|
if (integration.init) {
|
|
2298
2406
|
integration.init();
|
|
2299
2407
|
}
|
|
@@ -2336,7 +2444,7 @@ function createGoogleAnalyticsIntegration(config) {
|
|
|
2336
2444
|
}
|
|
2337
2445
|
],
|
|
2338
2446
|
init: () => {
|
|
2339
|
-
if (
|
|
2447
|
+
if (globalThis.window !== void 0) {
|
|
2340
2448
|
const w = window;
|
|
2341
2449
|
w.dataLayer = w.dataLayer ?? [];
|
|
2342
2450
|
const gtag = (...args) => {
|
|
@@ -2358,12 +2466,12 @@ function createGoogleTagManagerIntegration(config) {
|
|
|
2358
2466
|
src,
|
|
2359
2467
|
cookies: ["_gcl_au"],
|
|
2360
2468
|
init: () => {
|
|
2361
|
-
if (
|
|
2469
|
+
if (globalThis.window !== void 0) {
|
|
2362
2470
|
const dataLayerName = config.dataLayerName || "dataLayer";
|
|
2363
2471
|
const w = window;
|
|
2364
2472
|
const layer = w[dataLayerName] ?? [];
|
|
2365
2473
|
w[dataLayerName] = layer;
|
|
2366
|
-
layer.push({ "gtm.start":
|
|
2474
|
+
layer.push({ "gtm.start": Date.now(), event: "gtm.js" });
|
|
2367
2475
|
}
|
|
2368
2476
|
}
|
|
2369
2477
|
};
|
|
@@ -2376,7 +2484,7 @@ function createUserWayIntegration(config) {
|
|
|
2376
2484
|
src,
|
|
2377
2485
|
cookies: ["_userway_*"],
|
|
2378
2486
|
init: () => {
|
|
2379
|
-
if (
|
|
2487
|
+
if (globalThis.window !== void 0) {
|
|
2380
2488
|
const w = window;
|
|
2381
2489
|
w.UserWayWidgetApp = w.UserWayWidgetApp || {};
|
|
2382
2490
|
w.UserWayWidgetApp.accountId = config.accountId;
|
|
@@ -2398,7 +2506,7 @@ function createFacebookPixelIntegration(config) {
|
|
|
2398
2506
|
src,
|
|
2399
2507
|
cookies: ["_fbp", "fr"],
|
|
2400
2508
|
init: () => {
|
|
2401
|
-
if (
|
|
2509
|
+
if (globalThis.window !== void 0) {
|
|
2402
2510
|
const w = window;
|
|
2403
2511
|
if (!w.fbq) {
|
|
2404
2512
|
const fbq = (...args) => {
|
|
@@ -2465,7 +2573,7 @@ function createHotjarIntegration(config) {
|
|
|
2465
2573
|
}
|
|
2466
2574
|
],
|
|
2467
2575
|
init: () => {
|
|
2468
|
-
if (
|
|
2576
|
+
if (globalThis.window !== void 0) {
|
|
2469
2577
|
const w = window;
|
|
2470
2578
|
w._hjSettings = { hjid: config.siteId, hjsv: v };
|
|
2471
2579
|
if (!w.hj) {
|
|
@@ -2498,7 +2606,7 @@ function createMixpanelIntegration(config) {
|
|
|
2498
2606
|
}
|
|
2499
2607
|
],
|
|
2500
2608
|
init: () => {
|
|
2501
|
-
if (
|
|
2609
|
+
if (globalThis.window !== void 0) {
|
|
2502
2610
|
const w = window;
|
|
2503
2611
|
w.mixpanel = w.mixpanel || { init: () => void 0 };
|
|
2504
2612
|
if (w.mixpanel && typeof w.mixpanel.init === "function") {
|
|
@@ -2522,7 +2630,7 @@ function createClarityIntegration(config) {
|
|
|
2522
2630
|
src,
|
|
2523
2631
|
cookies: ["_clck", "_clsk", "CLID", "ANONCHK", "MR", "MUID", "SM"],
|
|
2524
2632
|
init: () => {
|
|
2525
|
-
if (
|
|
2633
|
+
if (globalThis.window !== void 0 && typeof config.upload !== "undefined") {
|
|
2526
2634
|
const w = window;
|
|
2527
2635
|
if (typeof w.clarity === "function") {
|
|
2528
2636
|
try {
|
|
@@ -2545,7 +2653,7 @@ function createIntercomIntegration(config) {
|
|
|
2545
2653
|
src,
|
|
2546
2654
|
cookies: ["intercom-id-*", "intercom-session-*"],
|
|
2547
2655
|
init: () => {
|
|
2548
|
-
if (
|
|
2656
|
+
if (globalThis.window !== void 0) {
|
|
2549
2657
|
const w = window;
|
|
2550
2658
|
if (typeof w.Intercom === "function") {
|
|
2551
2659
|
try {
|
|
@@ -2568,7 +2676,7 @@ function createZendeskChatIntegration(config) {
|
|
|
2568
2676
|
src,
|
|
2569
2677
|
cookies: ["__zlcmid", "_zendesk_shared_session"],
|
|
2570
2678
|
init: () => {
|
|
2571
|
-
if (
|
|
2679
|
+
if (globalThis.window !== void 0) {
|
|
2572
2680
|
const w = window;
|
|
2573
2681
|
if (typeof w.zE === "function") {
|
|
2574
2682
|
try {
|
|
@@ -2632,6 +2740,68 @@ function suggestCategoryForScript(name) {
|
|
|
2632
2740
|
return ["analytics"];
|
|
2633
2741
|
}
|
|
2634
2742
|
|
|
2743
|
+
// src/utils/categoryPresets.ts
|
|
2744
|
+
var ANPD_CATEGORY_PRESETS = {
|
|
2745
|
+
necessary: {
|
|
2746
|
+
id: "necessary",
|
|
2747
|
+
name: "Necess\xE1rios",
|
|
2748
|
+
description: "Essenciais para funcionamento do site e seguran\xE7a. Sempre ativos.",
|
|
2749
|
+
essential: true,
|
|
2750
|
+
cookies: []
|
|
2751
|
+
},
|
|
2752
|
+
analytics: {
|
|
2753
|
+
id: "analytics",
|
|
2754
|
+
name: "Analytics",
|
|
2755
|
+
description: "Mede desempenho e uso para melhorar a experi\xEAncia.",
|
|
2756
|
+
essential: false,
|
|
2757
|
+
cookies: ["_ga", "_ga_*", "_gid"]
|
|
2758
|
+
},
|
|
2759
|
+
functional: {
|
|
2760
|
+
id: "functional",
|
|
2761
|
+
name: "Funcionais",
|
|
2762
|
+
description: "Habilitam recursos adicionais e prefer\xEAncias do usu\xE1rio.",
|
|
2763
|
+
essential: false,
|
|
2764
|
+
cookies: []
|
|
2765
|
+
},
|
|
2766
|
+
marketing: {
|
|
2767
|
+
id: "marketing",
|
|
2768
|
+
name: "Marketing",
|
|
2769
|
+
description: "Personaliza an\xFAncios e campanhas baseadas no seu perfil.",
|
|
2770
|
+
essential: false,
|
|
2771
|
+
cookies: ["_fbp", "fr"]
|
|
2772
|
+
},
|
|
2773
|
+
social: {
|
|
2774
|
+
id: "social",
|
|
2775
|
+
name: "Social",
|
|
2776
|
+
description: "Integra\xE7\xF5es sociais, compartilhamento e widgets de redes.",
|
|
2777
|
+
essential: false,
|
|
2778
|
+
cookies: []
|
|
2779
|
+
},
|
|
2780
|
+
personalization: {
|
|
2781
|
+
id: "personalization",
|
|
2782
|
+
name: "Personaliza\xE7\xE3o",
|
|
2783
|
+
description: "Personaliza conte\xFAdo e recomenda\xE7\xF5es.",
|
|
2784
|
+
essential: false,
|
|
2785
|
+
cookies: []
|
|
2786
|
+
}
|
|
2787
|
+
};
|
|
2788
|
+
function createAnpdCategoriesConfig(options = {}) {
|
|
2789
|
+
const include = options.include && options.include.length > 0 ? options.include : ["analytics", "functional", "marketing"];
|
|
2790
|
+
const enabledCategories = include.filter((cat) => cat !== "necessary");
|
|
2791
|
+
const customCategories = include.filter((cat) => cat === "necessary").map((cat) => {
|
|
2792
|
+
const base = ANPD_CATEGORY_PRESETS[cat];
|
|
2793
|
+
return {
|
|
2794
|
+
...base,
|
|
2795
|
+
name: options.names?.[cat] ?? base.name,
|
|
2796
|
+
description: options.descriptions?.[cat] ?? base.description
|
|
2797
|
+
};
|
|
2798
|
+
});
|
|
2799
|
+
return {
|
|
2800
|
+
enabledCategories,
|
|
2801
|
+
customCategories: customCategories.length ? customCategories : void 0
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2635
2805
|
// src/types/advancedTexts.ts
|
|
2636
2806
|
var EXPANDED_DEFAULT_TEXTS = {
|
|
2637
2807
|
// Textos adicionais
|
|
@@ -2843,4 +3013,4 @@ var TEXT_TEMPLATES = {
|
|
|
2843
3013
|
}
|
|
2844
3014
|
};
|
|
2845
3015
|
|
|
2846
|
-
export { COMMON_INTEGRATIONS, ConsentGate, ConsentProvider, ConsentScriptLoader, DEFAULT_PROJECT_CATEGORIES, DesignProvider, EXPANDED_DEFAULT_TEXTS, GUIDANCE_PRESETS, INTEGRATION_TEMPLATES, LogLevel, TEXT_TEMPLATES, analyzeDeveloperConfiguration, analyzeIntegrationCategories, autoConfigureCategories, buildConsentStorageKey, categorizeDiscoveredCookies, checkPeerDeps, createClarityIntegration, createCorporateIntegrations, createECommerceIntegrations, createFacebookPixelIntegration, createGoogleAnalyticsIntegration, createGoogleTagManagerIntegration, createHotjarIntegration, createIntercomIntegration, createMixpanelIntegration, createProjectPreferences, createSaaSIntegrations, createUserWayIntegration, createZendeskChatIntegration, defaultTexts, detectConsentCookieName, discoverRuntimeCookies, ensureNecessaryAlwaysOn, extractCategoriesFromIntegrations, getAllProjectCategories, getCookiesInfoForCategory, loadScript, logDeveloperGuidance, logger, openPreferencesModal, pushConsentInitializedEvent, pushConsentUpdatedEvent, resolveTexts, runPeerDepsCheck, setCookieCatalogOverrides, setCookieCategoryOverrides, setDebugLogging, suggestCategoryForScript, useCategories, useCategoryStatus, useConsent, useConsentHydration, useConsentScriptLoader, useConsentTexts, useDataLayerEvents, useDesignTokens, useDeveloperGuidance, useOpenPreferencesModal, validateIntegrationCategories, validateNecessaryClassification, validateProjectPreferences };
|
|
3016
|
+
export { ANPD_CATEGORY_PRESETS, COMMON_INTEGRATIONS, ConsentGate, ConsentProvider, ConsentScriptLoader, DEFAULT_PROJECT_CATEGORIES, DesignProvider, EXPANDED_DEFAULT_TEXTS, GUIDANCE_PRESETS, INTEGRATION_TEMPLATES, LogLevel, TEXT_TEMPLATES, analyzeDeveloperConfiguration, analyzeIntegrationCategories, autoConfigureCategories, buildConsentStorageKey, categorizeDiscoveredCookies, checkPeerDeps, createAnpdCategoriesConfig, createClarityIntegration, createConsentAuditEntry, createCorporateIntegrations, createECommerceIntegrations, createFacebookPixelIntegration, createGoogleAnalyticsIntegration, createGoogleTagManagerIntegration, createHotjarIntegration, createIntercomIntegration, createMixpanelIntegration, createProjectPreferences, createSaaSIntegrations, createUserWayIntegration, createZendeskChatIntegration, defaultTexts, detectConsentCookieName, discoverRuntimeCookies, ensureNecessaryAlwaysOn, extractCategoriesFromIntegrations, getAllProjectCategories, getCookiesInfoForCategory, loadScript, logDeveloperGuidance, logger, openPreferencesModal, pushConsentInitializedEvent, pushConsentUpdatedEvent, resolveTexts, runPeerDepsCheck, setCookieCatalogOverrides, setCookieCategoryOverrides, setDebugLogging, suggestCategoryForScript, useCategories, useCategoryStatus, useConsent, useConsentHydration, useConsentScriptLoader, useConsentTexts, useDataLayerEvents, useDesignTokens, useDeveloperGuidance, useOpenPreferencesModal, validateIntegrationCategories, validateNecessaryClassification, validateProjectPreferences };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-lgpd-consent/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Núcleo da biblioteca de consentimento LGPD para React - Estado, hooks e utilitários sem dependências de UI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lgpd",
|
|
@@ -71,7 +71,6 @@
|
|
|
71
71
|
"lint:ci": "eslint \"src/**/*.{ts,tsx}\" --cache --max-warnings=0",
|
|
72
72
|
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
|
|
73
73
|
"type-check": "tsc --noEmit",
|
|
74
|
-
"test": "jest --config ../../jest.config.mjs"
|
|
75
|
-
"docs:generate": "echo \"No docs generation for core yet\""
|
|
74
|
+
"test": "jest --config ../../jest.config.mjs"
|
|
76
75
|
}
|
|
77
76
|
}
|