@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/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.replace(/[^a-z0-9._-]+/gi, "-").toLowerCase();
316
- const sanitizedVersion = versionRaw.replace(/[^a-z0-9._-]+/gi, "-").toLowerCase();
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: typeof window !== "undefined" ? window.location.protocol === "https:" : false,
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.6.3";
432
+ var LIBRARY_VERSION = "0.7.0";
416
433
  function ensureDataLayer() {
417
- if (typeof window === "undefined") return;
418
- if (!window.dataLayer) {
419
- window.dataLayer = [];
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 (typeof window === "undefined") return;
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 (typeof window === "undefined") return;
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 || {}, ...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.find((d) => d.name === desc.name)) result.push(desc);
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.find((d) => d.name === "cookieConsent")) {
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 (typeof window === "undefined") return false;
1069
+ if (globalThis.window === void 0) return false;
1054
1070
  try {
1055
- const reactSymbols = Object.getOwnPropertySymbols(window).map((sym) => String(sym)).filter((name) => name.includes("react"));
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 (typeof window === "undefined") return null;
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 (typeof window === "undefined") {
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 = Array.from(/* @__PURE__ */ new Set([...props.categories.enabledCategories ?? []]));
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. A lib aplicar\xE1 um padr\xE3o seguro, mas recomenda-se definir 'categories.enabledCategories' explicitamente para clareza e auditoria."
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 = Array.from(/* @__PURE__ */ new Set([...cat.enabledCategories ?? []]));
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((v) => String(v)).join(", ")} \u2014 remova ou corrija os IDs de categoria`
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 || "analytics";
1433
+ const cat = assigned ?? "analytics";
1418
1434
  out[cat] = out[cat] || [];
1419
- if (!out[cat].find((x) => x.name === d.name)) out[cat].push(d);
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 CategoriesProvider. Certifique-se de que o ConsentProvider est\xE1 envolvendo seu componente."
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
- }, [state.preferences, state.consented, state.source, isHydrated]);
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" && typeof window !== "undefined" && !didWarnAboutMissingUI.current && !CookieBannerComponent && !FloatingPreferencesButtonComponent && (() => {
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
- blocking,
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 new Error("useConsentState must be used within ConsentProvider");
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 new Error("useConsentActions must be used within ConsentProvider");
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
- for (const [k, v] of Object.entries(attrs)) s.setAttribute(k, v);
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 (typeof window !== "undefined" && typeof window.dispatchEvent === "function") {
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.allCategories.map((cat) => cat.id);
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
- integration.attrs
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
- await loadScript(integration.id, integration.src, integration.category, integration.attrs);
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 (typeof window !== "undefined") {
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 (typeof window !== "undefined") {
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": (/* @__PURE__ */ new Date()).getTime(), event: "gtm.js" });
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 (typeof window !== "undefined") {
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 (typeof window !== "undefined") {
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 (typeof window !== "undefined") {
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 (typeof window !== "undefined") {
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 (typeof window !== "undefined" && typeof config.upload !== "undefined") {
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 (typeof window !== "undefined") {
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 (typeof window !== "undefined") {
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.6.3",
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
  }