@react-lgpd-consent/core 0.6.3 → 0.7.1

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
@@ -309,21 +309,41 @@ function setDebugLogging(enabled, level = 2 /* INFO */) {
309
309
  // src/utils/cookieUtils.ts
310
310
  var DEFAULT_STORAGE_NAMESPACE = "lgpd-consent";
311
311
  var DEFAULT_STORAGE_VERSION = "1";
312
+ var DEFAULT_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
312
313
  function buildConsentStorageKey(options) {
313
314
  const namespaceRaw = options?.namespace?.trim() || DEFAULT_STORAGE_NAMESPACE;
314
315
  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();
316
+ const sanitizedNamespace = namespaceRaw.replaceAll(/[^a-z0-9._-]+/gi, "-").toLowerCase();
317
+ const sanitizedVersion = versionRaw.replaceAll(/[^a-z0-9._-]+/gi, "-").toLowerCase();
317
318
  return `${sanitizedNamespace}__v${sanitizedVersion}`;
318
319
  }
319
320
  var DEFAULT_COOKIE_OPTS = {
320
321
  name: "cookieConsent",
322
+ maxAge: DEFAULT_MAX_AGE_SECONDS,
321
323
  maxAgeDays: 365,
322
324
  sameSite: "Lax",
323
- secure: typeof window !== "undefined" ? window.location.protocol === "https:" : false,
325
+ secure: globalThis.window === void 0 ? false : globalThis.window.location.protocol === "https:",
324
326
  path: "/",
325
327
  domain: void 0
326
328
  };
329
+ function resolveCookieOptions(opts) {
330
+ const protocols = [
331
+ typeof globalThis.window !== "undefined" ? globalThis.window?.location?.protocol : void 0,
332
+ typeof globalThis.location !== "undefined" ? globalThis.location?.protocol : void 0
333
+ ].filter(Boolean);
334
+ const forceHttps = globalThis.__LGPD_FORCE_HTTPS__ === true;
335
+ const isHttps = forceHttps || protocols.includes("https:");
336
+ const maxAgeSecondsFromDays = typeof opts?.maxAgeDays === "number" ? Math.max(0, opts.maxAgeDays * 24 * 60 * 60) : null;
337
+ const maxAgeSeconds = typeof opts?.maxAge === "number" ? Math.max(0, opts.maxAge) : maxAgeSecondsFromDays ?? DEFAULT_MAX_AGE_SECONDS;
338
+ return {
339
+ name: opts?.name ?? DEFAULT_COOKIE_OPTS.name,
340
+ maxAge: maxAgeSeconds,
341
+ sameSite: opts?.sameSite ?? DEFAULT_COOKIE_OPTS.sameSite ?? "Lax",
342
+ secure: typeof opts?.secure === "boolean" ? opts.secure : isHttps ? true : DEFAULT_COOKIE_OPTS.secure ?? false,
343
+ path: opts?.path ?? DEFAULT_COOKIE_OPTS.path ?? "/",
344
+ domain: opts?.domain ?? DEFAULT_COOKIE_OPTS.domain ?? void 0
345
+ };
346
+ }
327
347
  var COOKIE_SCHEMA_VERSION = "1.0";
328
348
  function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
329
349
  logger.debug("Reading consent cookie", { name });
@@ -339,6 +359,10 @@ function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
339
359
  try {
340
360
  const data = JSON.parse(raw);
341
361
  logger.cookieOperation("read", name, data);
362
+ if (!data || typeof data !== "object") {
363
+ logger.warn("Consent cookie malformed: payload is not an object");
364
+ return null;
365
+ }
342
366
  if (!data.version) {
343
367
  logger.debug("Migrating legacy cookie format");
344
368
  return migrateLegacyCookie(data);
@@ -347,7 +371,11 @@ function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
347
371
  logger.warn(`Cookie version mismatch: ${data.version} != ${COOKIE_SCHEMA_VERSION}`);
348
372
  return null;
349
373
  }
350
- return data;
374
+ const preferences = data && typeof data.preferences === "object" ? data.preferences : { necessary: true };
375
+ return {
376
+ ...data,
377
+ preferences: ensureNecessaryAlwaysOn(preferences)
378
+ };
351
379
  } catch (error) {
352
380
  logger.error("Error parsing consent cookie", error);
353
381
  return null;
@@ -370,12 +398,12 @@ function migrateLegacyCookie(legacyData) {
370
398
  }
371
399
  }
372
400
  function writeConsentCookie(state, config, opts, source = "banner") {
373
- if (typeof document === "undefined") {
401
+ if (typeof document === "undefined" || typeof window === "undefined" || globalThis.__LGPD_SSR__ === true) {
374
402
  logger.debug("Cookie write skipped: server-side environment");
375
403
  return;
376
404
  }
377
405
  const now = (/* @__PURE__ */ new Date()).toISOString();
378
- const o = { ...DEFAULT_COOKIE_OPTS, ...opts };
406
+ const o = resolveCookieOptions(opts);
379
407
  const preferences = ensureNecessaryAlwaysOn(state.preferences);
380
408
  const cookieData = {
381
409
  version: COOKIE_SCHEMA_VERSION,
@@ -387,8 +415,9 @@ function writeConsentCookie(state, config, opts, source = "banner") {
387
415
  projectConfig: config
388
416
  };
389
417
  logger.cookieOperation("write", o.name, cookieData);
418
+ const expires = new Date(Date.now() + o.maxAge * 1e3);
390
419
  Cookies.set(o.name, JSON.stringify(cookieData), {
391
- expires: o.maxAgeDays,
420
+ expires,
392
421
  sameSite: o.sameSite,
393
422
  secure: o.secure,
394
423
  path: o.path,
@@ -400,38 +429,55 @@ function writeConsentCookie(state, config, opts, source = "banner") {
400
429
  preferencesCount: Object.keys(cookieData.preferences).length
401
430
  });
402
431
  }
432
+ function createConsentAuditEntry(state, params) {
433
+ const preferences = ensureNecessaryAlwaysOn(state.preferences);
434
+ const now = (/* @__PURE__ */ new Date()).toISOString();
435
+ return {
436
+ action: params.action,
437
+ storageKey: params.storageKey,
438
+ consentVersion: params.consentVersion?.trim() || "1",
439
+ timestamp: now,
440
+ consentDate: state.consentDate,
441
+ lastUpdate: state.lastUpdate,
442
+ consented: state.consented,
443
+ preferences,
444
+ version: state.version,
445
+ source: params.origin ?? state.source,
446
+ projectConfig: state.projectConfig
447
+ };
448
+ }
403
449
  function removeConsentCookie(opts) {
404
450
  if (typeof document === "undefined") {
405
451
  logger.debug("Cookie removal skipped: server-side environment");
406
452
  return;
407
453
  }
408
- const o = { ...DEFAULT_COOKIE_OPTS, ...opts };
454
+ const o = resolveCookieOptions(opts);
409
455
  logger.cookieOperation("delete", o.name);
410
456
  Cookies.remove(o.name, { path: o.path, domain: o.domain });
411
457
  logger.info("Consent cookie removed");
412
458
  }
413
459
 
414
460
  // src/utils/dataLayerEvents.ts
415
- var LIBRARY_VERSION = "0.6.3";
461
+ var LIBRARY_VERSION = "0.7.1";
416
462
  function ensureDataLayer() {
417
- if (typeof window === "undefined") return;
418
- if (!window.dataLayer) {
419
- window.dataLayer = [];
420
- }
463
+ var _a;
464
+ if (globalThis.window === void 0) return;
465
+ (_a = globalThis.window).dataLayer ?? (_a.dataLayer = []);
421
466
  }
422
467
  function pushConsentInitializedEvent(categories) {
423
- if (typeof window === "undefined") return;
468
+ if (globalThis.window === void 0) return;
424
469
  ensureDataLayer();
425
470
  const event = {
426
471
  event: "consent_initialized",
427
472
  consent_version: LIBRARY_VERSION,
428
473
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
429
- categories
474
+ categories,
475
+ preferences: categories
430
476
  };
431
- window.dataLayer?.push(event);
477
+ globalThis.window.dataLayer?.push(event);
432
478
  }
433
479
  function pushConsentUpdatedEvent(categories, origin, previousCategories) {
434
- if (typeof window === "undefined") return;
480
+ if (globalThis.window === void 0) return;
435
481
  ensureDataLayer();
436
482
  const changedCategories = previousCategories ? Object.keys(categories).filter((key) => categories[key] !== previousCategories[key]) : [];
437
483
  const event = {
@@ -440,9 +486,10 @@ function pushConsentUpdatedEvent(categories, origin, previousCategories) {
440
486
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
441
487
  origin,
442
488
  categories,
489
+ preferences: categories,
443
490
  changed_categories: changedCategories
444
491
  };
445
- window.dataLayer?.push(event);
492
+ globalThis.window.dataLayer?.push(event);
446
493
  }
447
494
  function useDataLayerEvents() {
448
495
  return {
@@ -631,10 +678,10 @@ var COOKIE_CATALOG_OVERRIDES = {};
631
678
  var COOKIE_CATEGORY_OVERRIDES = {};
632
679
  function setCookieCatalogOverrides(overrides) {
633
680
  COOKIE_CATALOG_OVERRIDES = {
634
- byCategory: { ...COOKIE_CATALOG_OVERRIDES.byCategory || {}, ...overrides.byCategory || {} },
681
+ byCategory: { ...COOKIE_CATALOG_OVERRIDES.byCategory, ...overrides.byCategory },
635
682
  byIntegration: {
636
- ...COOKIE_CATALOG_OVERRIDES.byIntegration || {},
637
- ...overrides.byIntegration || {}
683
+ ...COOKIE_CATALOG_OVERRIDES.byIntegration,
684
+ ...overrides.byIntegration
638
685
  }
639
686
  };
640
687
  }
@@ -656,7 +703,7 @@ function getCookiesInfoForCategory(categoryId, usedIntegrations) {
656
703
  ([pattern]) => matchPattern(desc.name, pattern)
657
704
  )?.[1];
658
705
  const finalCat = overrideCat ?? defaultCat;
659
- if (finalCat === categoryId && !result.find((d) => d.name === desc.name)) result.push(desc);
706
+ if (finalCat === categoryId && !result.some((d) => d.name === desc.name)) result.push(desc);
660
707
  });
661
708
  });
662
709
  const catOverride = COOKIE_CATALOG_OVERRIDES.byCategory?.[categoryId];
@@ -668,7 +715,7 @@ function getCookiesInfoForCategory(categoryId, usedIntegrations) {
668
715
  });
669
716
  }
670
717
  if (categoryId === "necessary") {
671
- if (!result.find((d) => d.name === "cookieConsent")) {
718
+ if (!result.some((d) => d.name === "cookieConsent")) {
672
719
  result.push({
673
720
  name: "cookieConsent",
674
721
  purpose: "Armazena suas prefer\xEAncias de consentimento",
@@ -1049,58 +1096,8 @@ var GUIDANCE_PRESETS = {
1049
1096
  };
1050
1097
 
1051
1098
  // src/utils/peerDepsCheck.ts
1052
- function detectMultipleReactInstances() {
1053
- if (typeof window === "undefined") return false;
1054
- try {
1055
- const reactSymbols = Object.getOwnPropertySymbols(window).map((sym) => String(sym)).filter((name) => name.includes("react"));
1056
- if (reactSymbols.length > 1) {
1057
- return true;
1058
- }
1059
- const ReactModule = window.React;
1060
- if (ReactModule && Array.isArray(ReactModule)) {
1061
- return true;
1062
- }
1063
- const hasMultipleVersions = window.__REACT_DEVTOOLS_GLOBAL_HOOK__?.renderers?.size > 1;
1064
- return hasMultipleVersions || false;
1065
- } catch {
1066
- return false;
1067
- }
1068
- }
1069
- function getPackageVersion(packageName) {
1070
- if (typeof window === "undefined") return null;
1071
- try {
1072
- const pkg = window[packageName];
1073
- if (pkg?.version) return pkg.version;
1074
- const React6 = window.React;
1075
- if (packageName === "react" && React6?.version) {
1076
- return React6.version;
1077
- }
1078
- return null;
1079
- } catch {
1080
- return null;
1081
- }
1082
- }
1083
- function isVersionInRange(version, minMajor, maxMajor) {
1084
- const major = parseInt(version.split(".")[0], 10);
1085
- return major >= minMajor && major <= maxMajor;
1086
- }
1087
- function checkPeerDeps(options = {}) {
1088
- const { skipInProduction = true, logWarnings = true } = options;
1089
- const result = {
1090
- ok: true,
1091
- warnings: [],
1092
- errors: []
1093
- };
1094
- const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
1095
- if (skipInProduction && isProduction) {
1096
- return result;
1097
- }
1098
- if (typeof window === "undefined") {
1099
- return result;
1100
- }
1101
- if (detectMultipleReactInstances()) {
1102
- result.ok = false;
1103
- const errorMsg = `
1099
+ var MESSAGES_PT_BR = {
1100
+ MULTIPLE_REACT_INSTANCES: `
1104
1101
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
1105
1102
  \u2551 \u26A0\uFE0F ERRO: M\xFAltiplas inst\xE2ncias de React detectadas \u2551
1106
1103
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
@@ -1162,22 +1159,13 @@ function checkPeerDeps(options = {}) {
1162
1159
  https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#multiple-react-instances
1163
1160
 
1164
1161
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1165
- `;
1166
- result.errors.push(errorMsg);
1167
- if (logWarnings) {
1168
- console.error(errorMsg);
1169
- }
1170
- }
1171
- const reactVersion = getPackageVersion("react");
1172
- if (reactVersion) {
1173
- if (!isVersionInRange(reactVersion, 18, 19)) {
1174
- result.ok = false;
1175
- const errorMsg = `
1162
+ `,
1163
+ UNSUPPORTED_REACT_VERSION: (version) => `
1176
1164
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
1177
1165
  \u2551 \u26A0\uFE0F AVISO: Vers\xE3o do React n\xE3o suportada \u2551
1178
1166
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1179
1167
 
1180
- \u{1F4E6} Vers\xE3o detectada: React ${reactVersion}
1168
+ \u{1F4E6} Vers\xE3o detectada: React ${version}
1181
1169
  \u2705 Vers\xF5es suportadas: React 18.x ou 19.x
1182
1170
 
1183
1171
  \u{1F50D} O react-lgpd-consent requer React 18.2.0+ ou React 19.x
@@ -1195,27 +1183,13 @@ function checkPeerDeps(options = {}) {
1195
1183
  https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#react-version
1196
1184
 
1197
1185
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1198
- `;
1199
- result.errors.push(errorMsg);
1200
- if (logWarnings) {
1201
- console.error(errorMsg);
1202
- }
1203
- }
1204
- }
1205
- const muiVersion = window["@mui/material"]?.version;
1206
- if (muiVersion) {
1207
- if (!isVersionInRange(muiVersion, 5, 7)) {
1208
- result.warnings.push(
1209
- `MUI vers\xE3o ${muiVersion} detectada. Vers\xF5es suportadas: 5.15.0+, 6.x ou 7.x. Alguns componentes podem n\xE3o funcionar corretamente.`
1210
- );
1211
- if (logWarnings) {
1212
- logger.warn(
1213
- `
1186
+ `,
1187
+ UNSUPPORTED_MUI_VERSION: (version) => `
1214
1188
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
1215
1189
  \u2551 \u26A0\uFE0F AVISO: Vers\xE3o do Material-UI fora do range recomendado \u2551
1216
1190
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1217
1191
 
1218
- \u{1F4E6} Vers\xE3o detectada: @mui/material ${muiVersion}
1192
+ \u{1F4E6} Vers\xE3o detectada: @mui/material ${version}
1219
1193
  \u2705 Vers\xF5es suportadas: 5.15.0+, 6.x, 7.x
1220
1194
 
1221
1195
  \u{1F50D} Componentes de UI (@react-lgpd-consent/mui) podem apresentar problemas.
@@ -1233,8 +1207,227 @@ function checkPeerDeps(options = {}) {
1233
1207
  https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#mui-version
1234
1208
 
1235
1209
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1236
- `
1237
- );
1210
+ `,
1211
+ MUI_OUT_OF_RANGE: (version) => `MUI vers\xE3o ${version} detectada. Vers\xF5es suportadas: 5.15.0+, 6.x ou 7.x. Alguns componentes podem n\xE3o funcionar corretamente.`
1212
+ };
1213
+ var MESSAGES_EN = {
1214
+ MULTIPLE_REACT_INSTANCES: `
1215
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
1216
+ \u2551 \u26A0\uFE0F ERROR: Multiple React instances detected \u2551
1217
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1218
+
1219
+ \u{1F534} Problem:
1220
+ Your project is loading more than one copy of React, causing the error:
1221
+ "Invalid hook call. Hooks can only be called inside of the body of a
1222
+ function component."
1223
+
1224
+ \u{1F50D} Probable cause:
1225
+ \u2022 pnpm/Yarn PnP without proper peer dependency hoisting
1226
+ \u2022 node_modules with duplicate React (classic npm/yarn)
1227
+ \u2022 Webpack/Vite with multiple resolutions of the same package
1228
+
1229
+ \u2705 Solutions:
1230
+
1231
+ \u{1F4E6} PNPM (RECOMMENDED):
1232
+ Add to root package.json:
1233
+ {
1234
+ "pnpm": {
1235
+ "overrides": {
1236
+ "react": "$react",
1237
+ "react-dom": "$react-dom"
1238
+ }
1239
+ }
1240
+ }
1241
+ Run: pnpm install
1242
+
1243
+ \u{1F4E6} NPM/Yarn:
1244
+ Add to root package.json:
1245
+ {
1246
+ "overrides": {
1247
+ "react": "^18.2.0 || ^19.0.0",
1248
+ "react-dom": "^18.2.0 || ^19.0.0"
1249
+ }
1250
+ }
1251
+ Run: npm install (or yarn install)
1252
+
1253
+ \u{1F527} Webpack:
1254
+ Add to webpack.config.js:
1255
+ module.exports = {
1256
+ resolve: {
1257
+ alias: {
1258
+ react: path.resolve('./node_modules/react'),
1259
+ 'react-dom': path.resolve('./node_modules/react-dom'),
1260
+ }
1261
+ }
1262
+ }
1263
+
1264
+ \u26A1 Vite:
1265
+ Add to vite.config.js:
1266
+ export default {
1267
+ resolve: {
1268
+ dedupe: ['react', 'react-dom']
1269
+ }
1270
+ }
1271
+
1272
+ \u{1F4DA} Documentation:
1273
+ https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#multiple-react-instances
1274
+
1275
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1276
+ `,
1277
+ UNSUPPORTED_REACT_VERSION: (version) => `
1278
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
1279
+ \u2551 \u26A0\uFE0F WARNING: Unsupported React version \u2551
1280
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1281
+
1282
+ \u{1F4E6} Detected version: React ${version}
1283
+ \u2705 Supported versions: React 18.x or 19.x
1284
+
1285
+ \u{1F50D} react-lgpd-consent requires React 18.2.0+ or React 19.x
1286
+
1287
+ \u2705 Solution:
1288
+ Update React to a supported version:
1289
+
1290
+ npm install react@^18.2.0 react-dom@^18.2.0
1291
+
1292
+ or
1293
+
1294
+ npm install react@^19.0.0 react-dom@^19.0.0
1295
+
1296
+ \u{1F4DA} Documentation:
1297
+ https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#react-version
1298
+
1299
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1300
+ `,
1301
+ UNSUPPORTED_MUI_VERSION: (version) => `
1302
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
1303
+ \u2551 \u26A0\uFE0F WARNING: Material-UI version out of recommended range \u2551
1304
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1305
+
1306
+ \u{1F4E6} Detected version: @mui/material ${version}
1307
+ \u2705 Supported versions: 5.15.0+, 6.x, 7.x
1308
+
1309
+ \u{1F50D} UI components (@react-lgpd-consent/mui) may have issues.
1310
+
1311
+ \u2705 Solution:
1312
+ Update MUI to a supported version:
1313
+
1314
+ npm install @mui/material@^7.0.0 @emotion/react @emotion/styled
1315
+
1316
+ or keep 5.15.0+:
1317
+
1318
+ npm install @mui/material@^5.15.0 @emotion/react @emotion/styled
1319
+
1320
+ \u{1F4DA} Documentation:
1321
+ https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#mui-version
1322
+
1323
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1324
+ `,
1325
+ MUI_OUT_OF_RANGE: (version) => `MUI version ${version} detected. Supported versions: 5.15.0+, 6.x or 7.x. Some components may not work properly.`
1326
+ };
1327
+ var MESSAGES_BY_LOCALE = {
1328
+ "pt-BR": MESSAGES_PT_BR,
1329
+ en: MESSAGES_EN
1330
+ };
1331
+ var currentLocale = "pt-BR";
1332
+ var customMessages = {};
1333
+ function setPeerDepsLocale(locale) {
1334
+ currentLocale = locale;
1335
+ }
1336
+ function getPeerDepsLocale() {
1337
+ return currentLocale;
1338
+ }
1339
+ function setPeerDepsMessages(messages) {
1340
+ customMessages = { ...customMessages, ...messages };
1341
+ }
1342
+ function resetPeerDepsMessages() {
1343
+ customMessages = {};
1344
+ }
1345
+ function getMessages() {
1346
+ const baseMessages = MESSAGES_BY_LOCALE[currentLocale];
1347
+ if (Object.keys(customMessages).length === 0) {
1348
+ return baseMessages;
1349
+ }
1350
+ return {
1351
+ MULTIPLE_REACT_INSTANCES: customMessages.MULTIPLE_REACT_INSTANCES ?? baseMessages.MULTIPLE_REACT_INSTANCES,
1352
+ UNSUPPORTED_REACT_VERSION: customMessages.UNSUPPORTED_REACT_VERSION ?? baseMessages.UNSUPPORTED_REACT_VERSION,
1353
+ UNSUPPORTED_MUI_VERSION: customMessages.UNSUPPORTED_MUI_VERSION ?? baseMessages.UNSUPPORTED_MUI_VERSION,
1354
+ MUI_OUT_OF_RANGE: customMessages.MUI_OUT_OF_RANGE ?? baseMessages.MUI_OUT_OF_RANGE
1355
+ };
1356
+ }
1357
+ function detectMultipleReactInstances() {
1358
+ if (globalThis.window === void 0) return false;
1359
+ try {
1360
+ const reactSymbols = Object.getOwnPropertySymbols(globalThis.window).map(String).filter((name) => name.includes("react"));
1361
+ if (reactSymbols.length > 1) {
1362
+ return true;
1363
+ }
1364
+ const ReactModule = window.React;
1365
+ if (ReactModule && Array.isArray(ReactModule)) {
1366
+ return true;
1367
+ }
1368
+ const hasMultipleVersions = window.__REACT_DEVTOOLS_GLOBAL_HOOK__?.renderers?.size > 1;
1369
+ return hasMultipleVersions || false;
1370
+ } catch {
1371
+ return false;
1372
+ }
1373
+ }
1374
+ function getPackageVersion(packageName) {
1375
+ if (globalThis.window === void 0) return null;
1376
+ try {
1377
+ const pkg = window[packageName];
1378
+ if (pkg?.version) return pkg.version;
1379
+ const React6 = window.React;
1380
+ if (packageName === "react" && React6?.version) {
1381
+ return React6.version;
1382
+ }
1383
+ return null;
1384
+ } catch {
1385
+ return null;
1386
+ }
1387
+ }
1388
+ function isVersionInRange(version, minMajor, maxMajor) {
1389
+ const major = Number.parseInt(version.split(".")[0], 10);
1390
+ return major >= minMajor && major <= maxMajor;
1391
+ }
1392
+ function checkPeerDeps(options = {}) {
1393
+ const { skipInProduction = true, logWarnings = true } = options;
1394
+ const result = {
1395
+ ok: true,
1396
+ warnings: [],
1397
+ errors: []
1398
+ };
1399
+ const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
1400
+ if (skipInProduction && isProduction) {
1401
+ return result;
1402
+ }
1403
+ if (globalThis.window === void 0) {
1404
+ return result;
1405
+ }
1406
+ const messages = getMessages();
1407
+ if (detectMultipleReactInstances()) {
1408
+ result.ok = false;
1409
+ result.errors.push(messages.MULTIPLE_REACT_INSTANCES);
1410
+ if (logWarnings) {
1411
+ console.error(messages.MULTIPLE_REACT_INSTANCES);
1412
+ }
1413
+ }
1414
+ const reactVersion = getPackageVersion("react");
1415
+ if (reactVersion) {
1416
+ if (!isVersionInRange(reactVersion, 18, 19)) {
1417
+ result.ok = false;
1418
+ const errorMsg = messages.UNSUPPORTED_REACT_VERSION(reactVersion);
1419
+ result.errors.push(errorMsg);
1420
+ if (logWarnings) {
1421
+ console.error(errorMsg);
1422
+ }
1423
+ }
1424
+ }
1425
+ const muiVersion = window["@mui/material"]?.version;
1426
+ if (muiVersion) {
1427
+ if (!isVersionInRange(muiVersion, 5, 7)) {
1428
+ result.warnings.push(messages.MUI_OUT_OF_RANGE(muiVersion));
1429
+ if (logWarnings) {
1430
+ logger.warn(messages.UNSUPPORTED_MUI_VERSION(muiVersion));
1238
1431
  }
1239
1432
  }
1240
1433
  }
@@ -1257,7 +1450,7 @@ function validateConsentProviderProps(props) {
1257
1450
  const sanitized = {};
1258
1451
  if (!isDev()) {
1259
1452
  if (props.categories) {
1260
- const enabled = Array.from(/* @__PURE__ */ new Set([...props.categories.enabledCategories ?? []]));
1453
+ const enabled = [...new Set(props.categories.enabledCategories ?? [])];
1261
1454
  const sanitizedEnabled = enabled.filter((c) => c !== "necessary");
1262
1455
  sanitized.categories = {
1263
1456
  enabledCategories: sanitizedEnabled,
@@ -1294,11 +1487,11 @@ function validateConsentProviderProps(props) {
1294
1487
  }
1295
1488
  if (!props.categories) {
1296
1489
  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."
1490
+ "Prop 'categories' n\xE3o fornecida \u2014 o ConsentProvider requer configura\xE7\xE3o de categorias."
1298
1491
  );
1299
1492
  } else {
1300
1493
  const cat = props.categories;
1301
- const enabled = Array.from(/* @__PURE__ */ new Set([...cat.enabledCategories ?? []]));
1494
+ const enabled = [...new Set(cat.enabledCategories ?? [])];
1302
1495
  if (enabled.includes("necessary")) {
1303
1496
  warnings.push("'necessary' \xE9 sempre inclu\xEDda automaticamente \u2014 remova de enabledCategories.");
1304
1497
  }
@@ -1306,7 +1499,7 @@ function validateConsentProviderProps(props) {
1306
1499
  const invalidEnabled = sanitizedEnabled.filter((c) => typeof c !== "string" || c.trim() === "");
1307
1500
  if (invalidEnabled.length > 0) {
1308
1501
  warnings.push(
1309
- `enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map((v) => String(v)).join(", ")} \u2014 remova ou corrija os IDs de categoria`
1502
+ `enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map(String).join(", ")} \u2014 remova ou corrija os IDs de categoria`
1310
1503
  );
1311
1504
  }
1312
1505
  const custom = cat.customCategories ?? [];
@@ -1400,13 +1593,13 @@ function detectConsentCookieName() {
1400
1593
  }
1401
1594
  return null;
1402
1595
  }
1596
+ function matchPattern2(name, pattern) {
1597
+ if (pattern.endsWith("*")) return name.startsWith(pattern.slice(0, -1));
1598
+ return name === pattern;
1599
+ }
1403
1600
  function categorizeDiscoveredCookies(discovered, registerOverrides = false) {
1404
1601
  const list = discovered || globalThis.__LGPD_DISCOVERED_COOKIES__ || [];
1405
1602
  const out = {};
1406
- function matchPattern2(name, pattern) {
1407
- if (pattern.endsWith("*")) return name.startsWith(pattern.slice(0, -1));
1408
- return name === pattern;
1409
- }
1410
1603
  list.filter((d) => d.name && d.name !== "cookieConsent").forEach((d) => {
1411
1604
  let assigned = null;
1412
1605
  Object.keys(COOKIE_PATTERNS_BY_CATEGORY).forEach((cat2) => {
@@ -1414,9 +1607,9 @@ function categorizeDiscoveredCookies(discovered, registerOverrides = false) {
1414
1607
  const patterns = COOKIE_PATTERNS_BY_CATEGORY[cat2] || [];
1415
1608
  if (patterns.some((p) => matchPattern2(d.name, p))) assigned = cat2;
1416
1609
  });
1417
- const cat = assigned || "analytics";
1610
+ const cat = assigned ?? "analytics";
1418
1611
  out[cat] = out[cat] || [];
1419
- if (!out[cat].find((x) => x.name === d.name)) out[cat].push(d);
1612
+ if (!out[cat].some((x) => x.name === d.name)) out[cat].push(d);
1420
1613
  });
1421
1614
  if (registerOverrides) {
1422
1615
  const byCategory = {};
@@ -1493,7 +1686,7 @@ function useCategories() {
1493
1686
  const context = React4.useContext(CategoriesContext);
1494
1687
  if (!context) {
1495
1688
  throw new Error(
1496
- "useCategories deve ser usado dentro de CategoriesProvider. Certifique-se de que o ConsentProvider est\xE1 envolvendo seu componente."
1689
+ "[react-lgpd-consent] useCategories deve ser usado dentro de <ConsentProvider>. Adicione o provider ao redor da sua \xE1rvore antes de chamar o hook."
1497
1690
  );
1498
1691
  }
1499
1692
  return context;
@@ -1644,6 +1837,11 @@ var StateCtx = React4.createContext(null);
1644
1837
  var ActionsCtx = React4.createContext(null);
1645
1838
  var TextsCtx = React4.createContext(DEFAULT_TEXTS);
1646
1839
  var HydrationCtx = React4.createContext(false);
1840
+ function buildProviderError(hookName) {
1841
+ return new Error(
1842
+ `[react-lgpd-consent] ${hookName} deve ser usado dentro de <ConsentProvider>. Envolva seu componente com o provider ou use o wrapper @react-lgpd-consent/mui.`
1843
+ );
1844
+ }
1647
1845
  function ConsentProvider({
1648
1846
  initialState,
1649
1847
  categories,
@@ -1667,7 +1865,10 @@ function ConsentProvider({
1667
1865
  disableDeveloperGuidance,
1668
1866
  guidanceConfig,
1669
1867
  children,
1670
- disableDiscoveryLog
1868
+ disableDiscoveryLog,
1869
+ onConsentInit,
1870
+ onConsentChange,
1871
+ onAuditLog
1671
1872
  }) {
1672
1873
  const texts = React4.useMemo(() => ({ ...DEFAULT_TEXTS, ...textsProp ?? {} }), [textsProp]);
1673
1874
  const cookie = React4.useMemo(() => {
@@ -1681,6 +1882,14 @@ function ConsentProvider({
1681
1882
  }
1682
1883
  return base;
1683
1884
  }, [cookieOpts, storage?.domain, storage?.namespace, storage?.version]);
1885
+ const consentVersion = storage?.version?.trim() || "1";
1886
+ React4.useEffect(() => {
1887
+ try {
1888
+ ;
1889
+ globalThis.__LGPD_CONSENT_COOKIE__ = cookie.name;
1890
+ } catch {
1891
+ }
1892
+ }, [cookie.name]);
1684
1893
  const finalCategoriesConfig = React4.useMemo(() => {
1685
1894
  const isProd = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
1686
1895
  if (!categories) return DEFAULT_PROJECT_CATEGORIES;
@@ -1727,6 +1936,8 @@ function ConsentProvider({
1727
1936
  const skipCookiePersistRef = React4.useRef(false);
1728
1937
  const [isHydrated, setIsHydrated] = React4.useState(false);
1729
1938
  const previousPreferencesRef = React4.useRef(state.preferences);
1939
+ const auditInitEmittedRef = React4.useRef(false);
1940
+ const previousConsentedAuditRef = React4.useRef(state.consented);
1730
1941
  React4.useEffect(() => {
1731
1942
  if (!initialState) {
1732
1943
  const saved = readConsentCookie(cookie.name);
@@ -1775,13 +1986,44 @@ function ConsentProvider({
1775
1986
  logger.info("DataLayer: consent_initialized event dispatched", {
1776
1987
  preferences: state.preferences
1777
1988
  });
1989
+ if (onConsentInit) onConsentInit(state);
1778
1990
  }
1779
1991
  }, [isHydrated]);
1992
+ React4.useEffect(() => {
1993
+ if (!isHydrated) return;
1994
+ if (!onAuditLog) return;
1995
+ if (auditInitEmittedRef.current) return;
1996
+ onAuditLog(
1997
+ createConsentAuditEntry(state, {
1998
+ action: "init",
1999
+ storageKey: cookie.name,
2000
+ consentVersion
2001
+ })
2002
+ );
2003
+ auditInitEmittedRef.current = true;
2004
+ }, [isHydrated, onAuditLog, state, cookie.name, consentVersion]);
1780
2005
  React4.useEffect(() => {
1781
2006
  if (!state.consented) return;
1782
2007
  if (skipCookiePersistRef.current) return;
1783
2008
  writeConsentCookie(state, finalCategoriesConfig, cookie);
1784
2009
  }, [state, cookie, finalCategoriesConfig]);
2010
+ React4.useEffect(() => {
2011
+ if (!onAuditLog) {
2012
+ previousConsentedAuditRef.current = state.consented;
2013
+ return;
2014
+ }
2015
+ if (previousConsentedAuditRef.current && !state.consented) {
2016
+ onAuditLog(
2017
+ createConsentAuditEntry(state, {
2018
+ action: "reset",
2019
+ storageKey: cookie.name,
2020
+ consentVersion,
2021
+ origin: "reset"
2022
+ })
2023
+ );
2024
+ }
2025
+ previousConsentedAuditRef.current = state.consented;
2026
+ }, [state, onAuditLog, cookie.name, consentVersion]);
1785
2027
  const prevConsented = React4.useRef(state.consented);
1786
2028
  React4.useEffect(() => {
1787
2029
  if (!prevConsented.current && state.consented && onConsentGiven) {
@@ -1802,9 +2044,32 @@ function ConsentProvider({
1802
2044
  preferences: state.preferences,
1803
2045
  consented: state.consented
1804
2046
  });
2047
+ if (onConsentChange) {
2048
+ onConsentChange(state, { origin });
2049
+ }
2050
+ if (onAuditLog) {
2051
+ onAuditLog(
2052
+ createConsentAuditEntry(state, {
2053
+ action: "update",
2054
+ storageKey: cookie.name,
2055
+ consentVersion,
2056
+ origin
2057
+ })
2058
+ );
2059
+ }
1805
2060
  previousPreferencesRef.current = state.preferences;
1806
2061
  }
1807
- }, [state.preferences, state.consented, state.source, isHydrated]);
2062
+ }, [
2063
+ state,
2064
+ state.preferences,
2065
+ state.consented,
2066
+ state.source,
2067
+ isHydrated,
2068
+ onConsentChange,
2069
+ onAuditLog,
2070
+ cookie.name,
2071
+ consentVersion
2072
+ ]);
1808
2073
  const api = React4.useMemo(() => {
1809
2074
  const acceptAll = () => dispatch({ type: "ACCEPT_ALL", config: finalCategoriesConfig });
1810
2075
  const rejectAll = () => dispatch({ type: "REJECT_ALL", config: finalCategoriesConfig });
@@ -1855,6 +2120,14 @@ function ConsentProvider({
1855
2120
  if (typeof backdrop === "string") return backdrop;
1856
2121
  return "rgba(0, 0, 0, 0.4)";
1857
2122
  }, [designTokens]);
2123
+ const cookieBannerPropsWithDefaults = React4.useMemo(() => {
2124
+ const incoming = cookieBannerProps ?? {};
2125
+ return {
2126
+ ...incoming,
2127
+ blocking: incoming.blocking === void 0 ? blocking : Boolean(incoming.blocking),
2128
+ hideBranding: incoming.hideBranding === void 0 ? _hideBranding : Boolean(incoming.hideBranding)
2129
+ };
2130
+ }, [cookieBannerProps, blocking, _hideBranding]);
1858
2131
  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
2132
  CategoriesProvider,
1860
2133
  {
@@ -1875,7 +2148,7 @@ function ConsentProvider({
1875
2148
  }
1876
2149
  ) : (
1877
2150
  // 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 && (() => {
2151
+ process.env.NODE_ENV === "development" && globalThis.window !== void 0 && !didWarnAboutMissingUI.current && !CookieBannerComponent && !FloatingPreferencesButtonComponent && (() => {
1879
2152
  didWarnAboutMissingUI.current = true;
1880
2153
  console.warn(
1881
2154
  "%c[@react-lgpd-consent/core] Aviso: Nenhum componente UI fornecido",
@@ -1937,8 +2210,7 @@ function ConsentProvider({
1937
2210
  rejectAll: api.rejectAll,
1938
2211
  openPreferences: api.openPreferences,
1939
2212
  texts,
1940
- blocking,
1941
- ...cookieBannerProps
2213
+ ...cookieBannerPropsWithDefaults
1942
2214
  }
1943
2215
  ),
1944
2216
  state.consented && !disableFloatingPreferencesButton && FloatingPreferencesButtonComponent && /* @__PURE__ */ jsx(
@@ -1956,12 +2228,12 @@ function ConsentProvider({
1956
2228
  }
1957
2229
  function useConsentStateInternal() {
1958
2230
  const ctx = React4.useContext(StateCtx);
1959
- if (!ctx) throw new Error("useConsentState must be used within ConsentProvider");
2231
+ if (!ctx) throw buildProviderError("useConsentState");
1960
2232
  return ctx;
1961
2233
  }
1962
2234
  function useConsentActionsInternal() {
1963
2235
  const ctx = React4.useContext(ActionsCtx);
1964
- if (!ctx) throw new Error("useConsentActions must be used within ConsentProvider");
2236
+ if (!ctx) throw buildProviderError("useConsentActions");
1965
2237
  return ctx;
1966
2238
  }
1967
2239
  function useConsentTextsInternal() {
@@ -1980,45 +2252,99 @@ function ConsentGate(props) {
1980
2252
 
1981
2253
  // src/utils/scriptLoader.ts
1982
2254
  var LOADING_SCRIPTS = /* @__PURE__ */ new Map();
1983
- function loadScript(id, src, category = null, attrs = {}) {
2255
+ var DEFAULT_POLL_INTERVAL = 100;
2256
+ function resolveCookieNames(preferred) {
2257
+ const inferred = globalThis.__LGPD_CONSENT_COOKIE__ ?? null;
2258
+ const names = [preferred, inferred, "cookieConsent", "lgpd-consent__v1"].filter(
2259
+ Boolean
2260
+ );
2261
+ return Array.from(new Set(names));
2262
+ }
2263
+ function parseConsentFromCookie(names) {
2264
+ const raw = document.cookie;
2265
+ if (!raw) return null;
2266
+ const cookies = raw.split("; ").reduce((acc, part) => {
2267
+ const [k, ...rest] = part.split("=");
2268
+ acc[k] = rest.join("=");
2269
+ return acc;
2270
+ }, {});
2271
+ for (const name of names) {
2272
+ const value = cookies[name];
2273
+ if (!value) continue;
2274
+ try {
2275
+ const parsed = JSON.parse(decodeURIComponent(value));
2276
+ if (!parsed.consented || parsed.isModalOpen) continue;
2277
+ return parsed;
2278
+ } catch {
2279
+ continue;
2280
+ }
2281
+ }
2282
+ return null;
2283
+ }
2284
+ function hasCategoryConsent(snapshot, category) {
2285
+ if (!snapshot.consented || snapshot.isModalOpen) return false;
2286
+ if (category === null) return true;
2287
+ return Boolean(snapshot.preferences?.[category]);
2288
+ }
2289
+ function loadScript(id, src, category = null, attrs = {}, nonce, options) {
1984
2290
  if (typeof document === "undefined") return Promise.resolve();
1985
2291
  if (document.getElementById(id)) return Promise.resolve();
1986
2292
  const existingPromise = LOADING_SCRIPTS.get(id);
1987
2293
  if (existingPromise) return existingPromise;
2294
+ const pollInterval = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL;
2295
+ const names = resolveCookieNames(options?.cookieName);
2296
+ const mergedAttrs = { ...attrs };
1988
2297
  const promise = new Promise((resolve, reject) => {
2298
+ const inject = () => {
2299
+ const s = document.createElement("script");
2300
+ s.id = id;
2301
+ s.src = src;
2302
+ s.async = mergedAttrs.async !== "false";
2303
+ const scriptNonce = mergedAttrs.nonce || nonce;
2304
+ if (scriptNonce) {
2305
+ s.nonce = scriptNonce;
2306
+ mergedAttrs.nonce = scriptNonce;
2307
+ }
2308
+ for (const [k, v] of Object.entries(mergedAttrs)) s.setAttribute(k, v);
2309
+ s.onload = () => {
2310
+ LOADING_SCRIPTS.delete(id);
2311
+ resolve();
2312
+ };
2313
+ s.onerror = () => {
2314
+ LOADING_SCRIPTS.delete(id);
2315
+ reject(new Error(`Failed to load script: ${src}`));
2316
+ };
2317
+ document.body.appendChild(s);
2318
+ };
2319
+ const snapshot = options?.consentSnapshot;
2320
+ const skipChecks = options?.skipConsentCheck === true;
2321
+ if (skipChecks) {
2322
+ inject();
2323
+ return;
2324
+ }
2325
+ if (snapshot) {
2326
+ if (!hasCategoryConsent(snapshot, category)) {
2327
+ reject(
2328
+ new Error(
2329
+ `Consent not granted for category '${category ?? "none"}' when attempting to load ${id}`
2330
+ )
2331
+ );
2332
+ return;
2333
+ }
2334
+ inject();
2335
+ return;
2336
+ }
1989
2337
  const checkConsent = () => {
1990
- const consentCookie = document.cookie.split("; ").find((row) => row.startsWith("cookieConsent="))?.split("=")[1];
1991
- if (!consentCookie) {
1992
- setTimeout(checkConsent, 100);
2338
+ const consent = parseConsentFromCookie(names);
2339
+ if (!consent) {
2340
+ setTimeout(checkConsent, pollInterval);
1993
2341
  return;
1994
2342
  }
1995
- try {
1996
- const consent = JSON.parse(decodeURIComponent(consentCookie));
1997
- if (!consent.consented || consent.isModalOpen) {
1998
- setTimeout(checkConsent, 100);
1999
- return;
2000
- }
2001
- if (category && !consent.preferences[category]) {
2002
- setTimeout(checkConsent, 100);
2003
- return;
2004
- }
2005
- const s = document.createElement("script");
2006
- s.id = id;
2007
- s.src = src;
2008
- s.async = true;
2009
- for (const [k, v] of Object.entries(attrs)) s.setAttribute(k, v);
2010
- s.onload = () => {
2011
- LOADING_SCRIPTS.delete(id);
2012
- resolve();
2013
- };
2014
- s.onerror = () => {
2015
- LOADING_SCRIPTS.delete(id);
2016
- reject(new Error(`Failed to load script: ${src}`));
2017
- };
2018
- document.body.appendChild(s);
2019
- } catch {
2020
- setTimeout(checkConsent, 100);
2343
+ if (!hasCategoryConsent(consent, category)) {
2344
+ setTimeout(checkConsent, pollInterval);
2345
+ return;
2021
2346
  }
2347
+ inject();
2022
2348
  };
2023
2349
  checkConsent();
2024
2350
  });
@@ -2182,13 +2508,107 @@ function validateNecessaryClassification(integrations, enabledCategories) {
2182
2508
  }
2183
2509
 
2184
2510
  // src/utils/ConsentScriptLoader.tsx
2511
+ var scriptRegistry = /* @__PURE__ */ new Map();
2512
+ var queueListeners = /* @__PURE__ */ new Set();
2513
+ function notifyQueue() {
2514
+ queueListeners.forEach((listener) => {
2515
+ try {
2516
+ listener();
2517
+ } catch {
2518
+ }
2519
+ });
2520
+ }
2521
+ function subscribeQueue(listener) {
2522
+ queueListeners.add(listener);
2523
+ return () => {
2524
+ queueListeners.delete(listener);
2525
+ };
2526
+ }
2527
+ function createInternalScript(def) {
2528
+ return {
2529
+ ...def,
2530
+ status: "pending",
2531
+ lastAllowed: false,
2532
+ registeredAt: Date.now(),
2533
+ token: Date.now() + Math.random(),
2534
+ priority: def.priority ?? 0,
2535
+ allowReload: def.allowReload ?? false,
2536
+ onConsentUpdate: def.onConsentUpdate
2537
+ };
2538
+ }
2539
+ function registerScript(def) {
2540
+ const entry = createInternalScript(def);
2541
+ scriptRegistry.set(def.id, entry);
2542
+ notifyQueue();
2543
+ return () => {
2544
+ const current = scriptRegistry.get(def.id);
2545
+ if (current && current.token === entry.token) {
2546
+ scriptRegistry.delete(def.id);
2547
+ notifyQueue();
2548
+ }
2549
+ };
2550
+ }
2551
+ function getExecutableScripts(consent) {
2552
+ const allowedScripts = [];
2553
+ scriptRegistry.forEach((script) => {
2554
+ const categoryAllowed = script.category === "necessary" || consent.consented && Boolean(consent.preferences?.[script.category]);
2555
+ if (!categoryAllowed) {
2556
+ script.lastAllowed = false;
2557
+ return;
2558
+ }
2559
+ if (script.status === "running") return;
2560
+ if (script.status === "executed" && !script.allowReload) return;
2561
+ if (script.status === "executed" && script.allowReload && script.lastAllowed) return;
2562
+ script.lastAllowed = true;
2563
+ allowedScripts.push(script);
2564
+ });
2565
+ return allowedScripts.sort((a, b) => {
2566
+ if (a.category === "necessary" && b.category !== "necessary") return -1;
2567
+ if (b.category === "necessary" && a.category !== "necessary") return 1;
2568
+ if (a.category !== b.category) return a.category.localeCompare(b.category);
2569
+ if (a.priority !== b.priority) return (b.priority ?? 0) - (a.priority ?? 0);
2570
+ return a.registeredAt - b.registeredAt;
2571
+ });
2572
+ }
2573
+ async function processQueue(consent, devLogging) {
2574
+ const scripts = getExecutableScripts(consent);
2575
+ let order = 0;
2576
+ for (const script of scripts) {
2577
+ order += 1;
2578
+ script.status = "running";
2579
+ if (devLogging) {
2580
+ logger.info("[ConsentScriptLoader] executando script", {
2581
+ id: script.id,
2582
+ category: script.category,
2583
+ priority: script.priority ?? 0,
2584
+ order
2585
+ });
2586
+ }
2587
+ try {
2588
+ await Promise.resolve(script.execute());
2589
+ } catch (error) {
2590
+ logger.error(`\u274C Failed to execute script ${script.id}`, error);
2591
+ } finally {
2592
+ script.status = "executed";
2593
+ if (script.onConsentUpdate) {
2594
+ script.onConsentUpdate(consent);
2595
+ }
2596
+ }
2597
+ }
2598
+ }
2185
2599
  function ConsentScriptLoader({
2186
2600
  integrations,
2187
- reloadOnChange = false
2601
+ reloadOnChange = false,
2602
+ nonce
2188
2603
  }) {
2189
2604
  const { preferences, consented } = useConsent();
2605
+ const isHydrated = useConsentHydration();
2190
2606
  const categories = useCategories();
2191
- const loadedScripts = React4.useRef(/* @__PURE__ */ new Set());
2607
+ const [queueVersion, bumpQueueVersion] = React4.useState(0);
2608
+ React4.useEffect(() => {
2609
+ const unsubscribe = subscribeQueue(() => bumpQueueVersion((v) => v + 1));
2610
+ return unsubscribe;
2611
+ }, []);
2192
2612
  React4.useEffect(() => {
2193
2613
  try {
2194
2614
  const ids = (integrations || []).map((i) => i.id);
@@ -2217,8 +2637,8 @@ function ConsentScriptLoader({
2217
2637
  const current = Array.isArray(gt.__LGPD_REQUIRED_CATEGORIES__) ? gt.__LGPD_REQUIRED_CATEGORIES__ : [];
2218
2638
  const merged = Array.from(/* @__PURE__ */ new Set([...current, ...required]));
2219
2639
  gt.__LGPD_REQUIRED_CATEGORIES__ = merged;
2220
- if (typeof window !== "undefined" && typeof window.dispatchEvent === "function") {
2221
- window.dispatchEvent(new CustomEvent("lgpd:requiredCategories"));
2640
+ if (globalThis.window !== void 0 && typeof globalThis.window.dispatchEvent === "function") {
2641
+ globalThis.window.dispatchEvent(new CustomEvent("lgpd:requiredCategories"));
2222
2642
  }
2223
2643
  } catch {
2224
2644
  }
@@ -2226,7 +2646,7 @@ function ConsentScriptLoader({
2226
2646
  React4.useEffect(() => {
2227
2647
  const isDev2 = process.env.NODE_ENV !== "production";
2228
2648
  if (!isDev2 || integrations.length === 0) return;
2229
- const enabledCategories = categories.allCategories.map((cat) => cat.id);
2649
+ const enabledCategories = categories.config.enabledCategories ?? [];
2230
2650
  const isValid = validateIntegrationCategories(integrations, enabledCategories);
2231
2651
  if (!isValid) {
2232
2652
  autoConfigureCategories({ enabledCategories }, integrations, {
@@ -2249,38 +2669,99 @@ function ConsentScriptLoader({
2249
2669
  console.groupEnd();
2250
2670
  }
2251
2671
  }, [integrations, categories]);
2672
+ const processedIntegrationsRef = React4.useRef(/* @__PURE__ */ new Map());
2252
2673
  React4.useEffect(() => {
2253
- if (!consented) return;
2254
- const timeoutId = setTimeout(async () => {
2255
- for (const integration of integrations) {
2256
- const shouldLoad = preferences[integration.category];
2257
- const alreadyLoaded = loadedScripts.current.has(integration.id);
2258
- if (shouldLoad && (!alreadyLoaded || reloadOnChange)) {
2259
- try {
2674
+ const cleanups = [];
2675
+ const currentIds = /* @__PURE__ */ new Set();
2676
+ integrations.forEach((integration) => {
2677
+ currentIds.add(integration.id);
2678
+ const structuralHash = JSON.stringify({
2679
+ category: integration.category,
2680
+ src: integration.src,
2681
+ priority: integration.priority,
2682
+ hasBootstrap: Boolean(integration.bootstrap),
2683
+ hasInit: Boolean(integration.init),
2684
+ hasOnConsentUpdate: Boolean(integration.onConsentUpdate)
2685
+ });
2686
+ const existingHash = processedIntegrationsRef.current.get(integration.id);
2687
+ if (existingHash === structuralHash && scriptRegistry.has(integration.id)) {
2688
+ return;
2689
+ }
2690
+ processedIntegrationsRef.current.set(integration.id, structuralHash);
2691
+ if (integration.bootstrap) {
2692
+ cleanups.push(
2693
+ registerScript({
2694
+ id: `${integration.id}__bootstrap`,
2695
+ category: "necessary",
2696
+ priority: (integration.priority ?? 0) + 1e3,
2697
+ execute: integration.bootstrap
2698
+ })
2699
+ );
2700
+ }
2701
+ cleanups.push(
2702
+ registerScript({
2703
+ id: integration.id,
2704
+ category: integration.category,
2705
+ priority: integration.priority,
2706
+ allowReload: reloadOnChange,
2707
+ onConsentUpdate: integration.onConsentUpdate,
2708
+ execute: async () => {
2709
+ const mergedAttrs = integration.attrs ? { ...integration.attrs } : {};
2710
+ const scriptNonce = integration.nonce ?? nonce;
2711
+ if (scriptNonce && !mergedAttrs.nonce) mergedAttrs.nonce = scriptNonce;
2260
2712
  await loadScript(
2261
2713
  integration.id,
2262
2714
  integration.src,
2263
2715
  integration.category,
2264
- integration.attrs
2716
+ mergedAttrs,
2717
+ scriptNonce,
2718
+ { skipConsentCheck: true }
2265
2719
  );
2266
2720
  if (integration.init) {
2267
2721
  integration.init();
2268
2722
  }
2269
- loadedScripts.current.add(integration.id);
2270
- } catch (error) {
2271
- logger.error(`\u274C Failed to load script: ${integration.id}`, error);
2272
2723
  }
2724
+ })
2725
+ );
2726
+ });
2727
+ processedIntegrationsRef.current.forEach((_, id) => {
2728
+ if (!currentIds.has(id)) {
2729
+ processedIntegrationsRef.current.delete(id);
2730
+ const script = scriptRegistry.get(id);
2731
+ if (script) {
2732
+ scriptRegistry.delete(id);
2733
+ }
2734
+ const bootstrapScript = scriptRegistry.get(`${id}__bootstrap`);
2735
+ if (bootstrapScript) {
2736
+ scriptRegistry.delete(`${id}__bootstrap`);
2273
2737
  }
2274
2738
  }
2275
- }, 0);
2276
- return () => clearTimeout(timeoutId);
2277
- }, [preferences, consented, integrations, reloadOnChange]);
2739
+ });
2740
+ return () => cleanups.forEach((fn) => fn());
2741
+ }, [integrations, reloadOnChange, nonce]);
2742
+ React4.useEffect(() => {
2743
+ if (!isHydrated) return;
2744
+ void processQueue({ consented, preferences }, process.env.NODE_ENV !== "production");
2745
+ }, [consented, preferences, isHydrated, queueVersion]);
2746
+ React4.useEffect(() => {
2747
+ if (!isHydrated) return;
2748
+ scriptRegistry.forEach((script) => {
2749
+ if (script.status !== "executed") return;
2750
+ if (typeof script.onConsentUpdate !== "function") return;
2751
+ script.onConsentUpdate({ consented, preferences });
2752
+ });
2753
+ }, [consented, preferences, isHydrated]);
2278
2754
  return null;
2279
2755
  }
2280
2756
  function useConsentScriptLoader() {
2281
2757
  const { preferences, consented } = useConsent();
2758
+ const isHydrated = useConsentHydration();
2282
2759
  return React4.useCallback(
2283
- async (integration) => {
2760
+ async (integration, nonce) => {
2761
+ if (!isHydrated) {
2762
+ logger.warn(`\u26A0\uFE0F Cannot load script ${integration.id}: Consent not hydrated yet`);
2763
+ return false;
2764
+ }
2284
2765
  if (!consented) {
2285
2766
  logger.warn(`\u26A0\uFE0F Cannot load script ${integration.id}: No consent given`);
2286
2767
  return false;
@@ -2293,7 +2774,20 @@ function useConsentScriptLoader() {
2293
2774
  return false;
2294
2775
  }
2295
2776
  try {
2296
- await loadScript(integration.id, integration.src, integration.category, integration.attrs);
2777
+ const mergedAttrs = integration.attrs ? { ...integration.attrs } : {};
2778
+ const scriptNonce = integration.nonce ?? nonce;
2779
+ if (scriptNonce && !mergedAttrs.nonce) mergedAttrs.nonce = scriptNonce;
2780
+ await loadScript(
2781
+ integration.id,
2782
+ integration.src,
2783
+ integration.category,
2784
+ mergedAttrs,
2785
+ scriptNonce,
2786
+ {
2787
+ consentSnapshot: { consented, preferences },
2788
+ skipConsentCheck: true
2789
+ }
2790
+ );
2297
2791
  if (integration.init) {
2298
2792
  integration.init();
2299
2793
  }
@@ -2303,11 +2797,62 @@ function useConsentScriptLoader() {
2303
2797
  return false;
2304
2798
  }
2305
2799
  },
2306
- [preferences, consented]
2800
+ [preferences, consented, isHydrated]
2307
2801
  );
2308
2802
  }
2309
2803
 
2310
2804
  // src/utils/scriptIntegrations.ts
2805
+ function buildConsentModeSignals(preferences) {
2806
+ const analytics = preferences.analytics ? "granted" : "denied";
2807
+ const marketing = preferences.marketing ? "granted" : "denied";
2808
+ return {
2809
+ ad_storage: marketing,
2810
+ ad_user_data: marketing,
2811
+ ad_personalization: marketing,
2812
+ analytics_storage: analytics
2813
+ };
2814
+ }
2815
+ function pushToLayer(entry, dataLayerName) {
2816
+ if (typeof globalThis.window === "undefined") return;
2817
+ const registry = globalThis.window;
2818
+ const name = dataLayerName ?? "dataLayer";
2819
+ const layer = registry[name] ?? [];
2820
+ registry[name] = layer;
2821
+ layer.push(entry);
2822
+ }
2823
+ function ensureGtag(dataLayerName = "dataLayer") {
2824
+ if (typeof globalThis.window === "undefined") return null;
2825
+ const w = window;
2826
+ const registry = w;
2827
+ const layer = registry[dataLayerName] ?? [];
2828
+ registry[dataLayerName] = layer;
2829
+ if (typeof w.gtag !== "function") {
2830
+ const gtag = (...args) => {
2831
+ layer.push(args);
2832
+ };
2833
+ w.gtag = gtag;
2834
+ }
2835
+ return w.gtag;
2836
+ }
2837
+ function applyDefaultConsentMode(dataLayerName) {
2838
+ const payload = buildConsentModeSignals({
2839
+ analytics: false,
2840
+ marketing: false
2841
+ });
2842
+ const gtag = ensureGtag(dataLayerName);
2843
+ if (gtag) {
2844
+ gtag("consent", "default", payload);
2845
+ }
2846
+ pushToLayer(["consent", "default", payload], dataLayerName);
2847
+ }
2848
+ function applyConsentModeUpdate(preferences, dataLayerName) {
2849
+ const payload = buildConsentModeSignals(preferences);
2850
+ const gtag = ensureGtag(dataLayerName);
2851
+ if (gtag) {
2852
+ gtag("consent", "update", payload);
2853
+ }
2854
+ pushToLayer(["consent", "update", payload], dataLayerName);
2855
+ }
2311
2856
  function createGoogleAnalyticsIntegration(config) {
2312
2857
  const src = config.scriptUrl ?? `https://www.googletagmanager.com/gtag/js?id=${config.measurementId}`;
2313
2858
  return {
@@ -2335,17 +2880,17 @@ function createGoogleAnalyticsIntegration(config) {
2335
2880
  provider: "Google Analytics"
2336
2881
  }
2337
2882
  ],
2883
+ bootstrap: () => {
2884
+ applyDefaultConsentMode();
2885
+ },
2886
+ onConsentUpdate: ({ preferences }) => {
2887
+ applyConsentModeUpdate(preferences);
2888
+ },
2338
2889
  init: () => {
2339
- if (typeof window !== "undefined") {
2340
- const w = window;
2341
- w.dataLayer = w.dataLayer ?? [];
2342
- const gtag = (...args) => {
2343
- w.dataLayer.push(...args);
2344
- };
2345
- w.gtag = gtag;
2346
- gtag("js", /* @__PURE__ */ new Date());
2347
- gtag("config", config.measurementId, config.config ?? {});
2348
- }
2890
+ const gtag = ensureGtag();
2891
+ if (!gtag) return;
2892
+ gtag("js", /* @__PURE__ */ new Date());
2893
+ gtag("config", config.measurementId, config.config ?? {});
2349
2894
  },
2350
2895
  attrs: { async: "true" }
2351
2896
  };
@@ -2357,13 +2902,19 @@ function createGoogleTagManagerIntegration(config) {
2357
2902
  category: "analytics",
2358
2903
  src,
2359
2904
  cookies: ["_gcl_au"],
2905
+ bootstrap: () => {
2906
+ applyDefaultConsentMode(config.dataLayerName);
2907
+ },
2908
+ onConsentUpdate: ({ preferences }) => {
2909
+ applyConsentModeUpdate(preferences, config.dataLayerName);
2910
+ },
2360
2911
  init: () => {
2361
- if (typeof window !== "undefined") {
2912
+ if (globalThis.window !== void 0) {
2362
2913
  const dataLayerName = config.dataLayerName || "dataLayer";
2363
2914
  const w = window;
2364
2915
  const layer = w[dataLayerName] ?? [];
2365
2916
  w[dataLayerName] = layer;
2366
- layer.push({ "gtm.start": (/* @__PURE__ */ new Date()).getTime(), event: "gtm.js" });
2917
+ layer.push({ "gtm.start": Date.now(), event: "gtm.js" });
2367
2918
  }
2368
2919
  }
2369
2920
  };
@@ -2376,7 +2927,7 @@ function createUserWayIntegration(config) {
2376
2927
  src,
2377
2928
  cookies: ["_userway_*"],
2378
2929
  init: () => {
2379
- if (typeof window !== "undefined") {
2930
+ if (globalThis.window !== void 0) {
2380
2931
  const w = window;
2381
2932
  w.UserWayWidgetApp = w.UserWayWidgetApp || {};
2382
2933
  w.UserWayWidgetApp.accountId = config.accountId;
@@ -2398,7 +2949,7 @@ function createFacebookPixelIntegration(config) {
2398
2949
  src,
2399
2950
  cookies: ["_fbp", "fr"],
2400
2951
  init: () => {
2401
- if (typeof window !== "undefined") {
2952
+ if (globalThis.window !== void 0) {
2402
2953
  const w = window;
2403
2954
  if (!w.fbq) {
2404
2955
  const fbq = (...args) => {
@@ -2465,7 +3016,7 @@ function createHotjarIntegration(config) {
2465
3016
  }
2466
3017
  ],
2467
3018
  init: () => {
2468
- if (typeof window !== "undefined") {
3019
+ if (globalThis.window !== void 0) {
2469
3020
  const w = window;
2470
3021
  w._hjSettings = { hjid: config.siteId, hjsv: v };
2471
3022
  if (!w.hj) {
@@ -2498,7 +3049,7 @@ function createMixpanelIntegration(config) {
2498
3049
  }
2499
3050
  ],
2500
3051
  init: () => {
2501
- if (typeof window !== "undefined") {
3052
+ if (globalThis.window !== void 0) {
2502
3053
  const w = window;
2503
3054
  w.mixpanel = w.mixpanel || { init: () => void 0 };
2504
3055
  if (w.mixpanel && typeof w.mixpanel.init === "function") {
@@ -2522,7 +3073,7 @@ function createClarityIntegration(config) {
2522
3073
  src,
2523
3074
  cookies: ["_clck", "_clsk", "CLID", "ANONCHK", "MR", "MUID", "SM"],
2524
3075
  init: () => {
2525
- if (typeof window !== "undefined" && typeof config.upload !== "undefined") {
3076
+ if (globalThis.window !== void 0 && typeof config.upload !== "undefined") {
2526
3077
  const w = window;
2527
3078
  if (typeof w.clarity === "function") {
2528
3079
  try {
@@ -2545,7 +3096,7 @@ function createIntercomIntegration(config) {
2545
3096
  src,
2546
3097
  cookies: ["intercom-id-*", "intercom-session-*"],
2547
3098
  init: () => {
2548
- if (typeof window !== "undefined") {
3099
+ if (globalThis.window !== void 0) {
2549
3100
  const w = window;
2550
3101
  if (typeof w.Intercom === "function") {
2551
3102
  try {
@@ -2568,7 +3119,7 @@ function createZendeskChatIntegration(config) {
2568
3119
  src,
2569
3120
  cookies: ["__zlcmid", "_zendesk_shared_session"],
2570
3121
  init: () => {
2571
- if (typeof window !== "undefined") {
3122
+ if (globalThis.window !== void 0) {
2572
3123
  const w = window;
2573
3124
  if (typeof w.zE === "function") {
2574
3125
  try {
@@ -2632,6 +3183,68 @@ function suggestCategoryForScript(name) {
2632
3183
  return ["analytics"];
2633
3184
  }
2634
3185
 
3186
+ // src/utils/categoryPresets.ts
3187
+ var ANPD_CATEGORY_PRESETS = {
3188
+ necessary: {
3189
+ id: "necessary",
3190
+ name: "Necess\xE1rios",
3191
+ description: "Essenciais para funcionamento do site e seguran\xE7a. Sempre ativos.",
3192
+ essential: true,
3193
+ cookies: []
3194
+ },
3195
+ analytics: {
3196
+ id: "analytics",
3197
+ name: "Analytics",
3198
+ description: "Mede desempenho e uso para melhorar a experi\xEAncia.",
3199
+ essential: false,
3200
+ cookies: ["_ga", "_ga_*", "_gid"]
3201
+ },
3202
+ functional: {
3203
+ id: "functional",
3204
+ name: "Funcionais",
3205
+ description: "Habilitam recursos adicionais e prefer\xEAncias do usu\xE1rio.",
3206
+ essential: false,
3207
+ cookies: []
3208
+ },
3209
+ marketing: {
3210
+ id: "marketing",
3211
+ name: "Marketing",
3212
+ description: "Personaliza an\xFAncios e campanhas baseadas no seu perfil.",
3213
+ essential: false,
3214
+ cookies: ["_fbp", "fr"]
3215
+ },
3216
+ social: {
3217
+ id: "social",
3218
+ name: "Social",
3219
+ description: "Integra\xE7\xF5es sociais, compartilhamento e widgets de redes.",
3220
+ essential: false,
3221
+ cookies: []
3222
+ },
3223
+ personalization: {
3224
+ id: "personalization",
3225
+ name: "Personaliza\xE7\xE3o",
3226
+ description: "Personaliza conte\xFAdo e recomenda\xE7\xF5es.",
3227
+ essential: false,
3228
+ cookies: []
3229
+ }
3230
+ };
3231
+ function createAnpdCategoriesConfig(options = {}) {
3232
+ const include = options.include && options.include.length > 0 ? options.include : ["analytics", "functional", "marketing"];
3233
+ const enabledCategories = include.filter((cat) => cat !== "necessary");
3234
+ const customCategories = include.filter((cat) => cat === "necessary").map((cat) => {
3235
+ const base = ANPD_CATEGORY_PRESETS[cat];
3236
+ return {
3237
+ ...base,
3238
+ name: options.names?.[cat] ?? base.name,
3239
+ description: options.descriptions?.[cat] ?? base.description
3240
+ };
3241
+ });
3242
+ return {
3243
+ enabledCategories,
3244
+ customCategories: customCategories.length ? customCategories : void 0
3245
+ };
3246
+ }
3247
+
2635
3248
  // src/types/advancedTexts.ts
2636
3249
  var EXPANDED_DEFAULT_TEXTS = {
2637
3250
  // Textos adicionais
@@ -2843,4 +3456,4 @@ var TEXT_TEMPLATES = {
2843
3456
  }
2844
3457
  };
2845
3458
 
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 };
3459
+ 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, getPeerDepsLocale, loadScript, logDeveloperGuidance, logger, openPreferencesModal, pushConsentInitializedEvent, pushConsentUpdatedEvent, registerScript, resetPeerDepsMessages, resolveTexts, runPeerDepsCheck, setCookieCatalogOverrides, setCookieCategoryOverrides, setDebugLogging, setPeerDepsLocale, setPeerDepsMessages, suggestCategoryForScript, useCategories, useCategoryStatus, useConsent, useConsentHydration, useConsentScriptLoader, useConsentTexts, useDataLayerEvents, useDesignTokens, useDeveloperGuidance, useOpenPreferencesModal, validateIntegrationCategories, validateNecessaryClassification, validateProjectPreferences };