@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.cjs CHANGED
@@ -333,21 +333,41 @@ function setDebugLogging(enabled, level = 2 /* INFO */) {
333
333
  // src/utils/cookieUtils.ts
334
334
  var DEFAULT_STORAGE_NAMESPACE = "lgpd-consent";
335
335
  var DEFAULT_STORAGE_VERSION = "1";
336
+ var DEFAULT_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
336
337
  function buildConsentStorageKey(options) {
337
338
  const namespaceRaw = options?.namespace?.trim() || DEFAULT_STORAGE_NAMESPACE;
338
339
  const versionRaw = options?.version?.trim() || DEFAULT_STORAGE_VERSION;
339
- const sanitizedNamespace = namespaceRaw.replace(/[^a-z0-9._-]+/gi, "-").toLowerCase();
340
- const sanitizedVersion = versionRaw.replace(/[^a-z0-9._-]+/gi, "-").toLowerCase();
340
+ const sanitizedNamespace = namespaceRaw.replaceAll(/[^a-z0-9._-]+/gi, "-").toLowerCase();
341
+ const sanitizedVersion = versionRaw.replaceAll(/[^a-z0-9._-]+/gi, "-").toLowerCase();
341
342
  return `${sanitizedNamespace}__v${sanitizedVersion}`;
342
343
  }
343
344
  var DEFAULT_COOKIE_OPTS = {
344
345
  name: "cookieConsent",
346
+ maxAge: DEFAULT_MAX_AGE_SECONDS,
345
347
  maxAgeDays: 365,
346
348
  sameSite: "Lax",
347
- secure: typeof window !== "undefined" ? window.location.protocol === "https:" : false,
349
+ secure: globalThis.window === void 0 ? false : globalThis.window.location.protocol === "https:",
348
350
  path: "/",
349
351
  domain: void 0
350
352
  };
353
+ function resolveCookieOptions(opts) {
354
+ const protocols = [
355
+ typeof globalThis.window !== "undefined" ? globalThis.window?.location?.protocol : void 0,
356
+ typeof globalThis.location !== "undefined" ? globalThis.location?.protocol : void 0
357
+ ].filter(Boolean);
358
+ const forceHttps = globalThis.__LGPD_FORCE_HTTPS__ === true;
359
+ const isHttps = forceHttps || protocols.includes("https:");
360
+ const maxAgeSecondsFromDays = typeof opts?.maxAgeDays === "number" ? Math.max(0, opts.maxAgeDays * 24 * 60 * 60) : null;
361
+ const maxAgeSeconds = typeof opts?.maxAge === "number" ? Math.max(0, opts.maxAge) : maxAgeSecondsFromDays ?? DEFAULT_MAX_AGE_SECONDS;
362
+ return {
363
+ name: opts?.name ?? DEFAULT_COOKIE_OPTS.name,
364
+ maxAge: maxAgeSeconds,
365
+ sameSite: opts?.sameSite ?? DEFAULT_COOKIE_OPTS.sameSite ?? "Lax",
366
+ secure: typeof opts?.secure === "boolean" ? opts.secure : isHttps ? true : DEFAULT_COOKIE_OPTS.secure ?? false,
367
+ path: opts?.path ?? DEFAULT_COOKIE_OPTS.path ?? "/",
368
+ domain: opts?.domain ?? DEFAULT_COOKIE_OPTS.domain ?? void 0
369
+ };
370
+ }
351
371
  var COOKIE_SCHEMA_VERSION = "1.0";
352
372
  function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
353
373
  logger.debug("Reading consent cookie", { name });
@@ -363,6 +383,10 @@ function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
363
383
  try {
364
384
  const data = JSON.parse(raw);
365
385
  logger.cookieOperation("read", name, data);
386
+ if (!data || typeof data !== "object") {
387
+ logger.warn("Consent cookie malformed: payload is not an object");
388
+ return null;
389
+ }
366
390
  if (!data.version) {
367
391
  logger.debug("Migrating legacy cookie format");
368
392
  return migrateLegacyCookie(data);
@@ -371,7 +395,11 @@ function readConsentCookie(name = DEFAULT_COOKIE_OPTS.name) {
371
395
  logger.warn(`Cookie version mismatch: ${data.version} != ${COOKIE_SCHEMA_VERSION}`);
372
396
  return null;
373
397
  }
374
- return data;
398
+ const preferences = data && typeof data.preferences === "object" ? data.preferences : { necessary: true };
399
+ return {
400
+ ...data,
401
+ preferences: ensureNecessaryAlwaysOn(preferences)
402
+ };
375
403
  } catch (error) {
376
404
  logger.error("Error parsing consent cookie", error);
377
405
  return null;
@@ -394,12 +422,12 @@ function migrateLegacyCookie(legacyData) {
394
422
  }
395
423
  }
396
424
  function writeConsentCookie(state, config, opts, source = "banner") {
397
- if (typeof document === "undefined") {
425
+ if (typeof document === "undefined" || typeof window === "undefined" || globalThis.__LGPD_SSR__ === true) {
398
426
  logger.debug("Cookie write skipped: server-side environment");
399
427
  return;
400
428
  }
401
429
  const now = (/* @__PURE__ */ new Date()).toISOString();
402
- const o = { ...DEFAULT_COOKIE_OPTS, ...opts };
430
+ const o = resolveCookieOptions(opts);
403
431
  const preferences = ensureNecessaryAlwaysOn(state.preferences);
404
432
  const cookieData = {
405
433
  version: COOKIE_SCHEMA_VERSION,
@@ -411,8 +439,9 @@ function writeConsentCookie(state, config, opts, source = "banner") {
411
439
  projectConfig: config
412
440
  };
413
441
  logger.cookieOperation("write", o.name, cookieData);
442
+ const expires = new Date(Date.now() + o.maxAge * 1e3);
414
443
  Cookies__default.default.set(o.name, JSON.stringify(cookieData), {
415
- expires: o.maxAgeDays,
444
+ expires,
416
445
  sameSite: o.sameSite,
417
446
  secure: o.secure,
418
447
  path: o.path,
@@ -424,38 +453,55 @@ function writeConsentCookie(state, config, opts, source = "banner") {
424
453
  preferencesCount: Object.keys(cookieData.preferences).length
425
454
  });
426
455
  }
456
+ function createConsentAuditEntry(state, params) {
457
+ const preferences = ensureNecessaryAlwaysOn(state.preferences);
458
+ const now = (/* @__PURE__ */ new Date()).toISOString();
459
+ return {
460
+ action: params.action,
461
+ storageKey: params.storageKey,
462
+ consentVersion: params.consentVersion?.trim() || "1",
463
+ timestamp: now,
464
+ consentDate: state.consentDate,
465
+ lastUpdate: state.lastUpdate,
466
+ consented: state.consented,
467
+ preferences,
468
+ version: state.version,
469
+ source: params.origin ?? state.source,
470
+ projectConfig: state.projectConfig
471
+ };
472
+ }
427
473
  function removeConsentCookie(opts) {
428
474
  if (typeof document === "undefined") {
429
475
  logger.debug("Cookie removal skipped: server-side environment");
430
476
  return;
431
477
  }
432
- const o = { ...DEFAULT_COOKIE_OPTS, ...opts };
478
+ const o = resolveCookieOptions(opts);
433
479
  logger.cookieOperation("delete", o.name);
434
480
  Cookies__default.default.remove(o.name, { path: o.path, domain: o.domain });
435
481
  logger.info("Consent cookie removed");
436
482
  }
437
483
 
438
484
  // src/utils/dataLayerEvents.ts
439
- var LIBRARY_VERSION = "0.6.3";
485
+ var LIBRARY_VERSION = "0.7.1";
440
486
  function ensureDataLayer() {
441
- if (typeof window === "undefined") return;
442
- if (!window.dataLayer) {
443
- window.dataLayer = [];
444
- }
487
+ var _a;
488
+ if (globalThis.window === void 0) return;
489
+ (_a = globalThis.window).dataLayer ?? (_a.dataLayer = []);
445
490
  }
446
491
  function pushConsentInitializedEvent(categories) {
447
- if (typeof window === "undefined") return;
492
+ if (globalThis.window === void 0) return;
448
493
  ensureDataLayer();
449
494
  const event = {
450
495
  event: "consent_initialized",
451
496
  consent_version: LIBRARY_VERSION,
452
497
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
453
- categories
498
+ categories,
499
+ preferences: categories
454
500
  };
455
- window.dataLayer?.push(event);
501
+ globalThis.window.dataLayer?.push(event);
456
502
  }
457
503
  function pushConsentUpdatedEvent(categories, origin, previousCategories) {
458
- if (typeof window === "undefined") return;
504
+ if (globalThis.window === void 0) return;
459
505
  ensureDataLayer();
460
506
  const changedCategories = previousCategories ? Object.keys(categories).filter((key) => categories[key] !== previousCategories[key]) : [];
461
507
  const event = {
@@ -464,9 +510,10 @@ function pushConsentUpdatedEvent(categories, origin, previousCategories) {
464
510
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
465
511
  origin,
466
512
  categories,
513
+ preferences: categories,
467
514
  changed_categories: changedCategories
468
515
  };
469
- window.dataLayer?.push(event);
516
+ globalThis.window.dataLayer?.push(event);
470
517
  }
471
518
  function useDataLayerEvents() {
472
519
  return {
@@ -655,10 +702,10 @@ var COOKIE_CATALOG_OVERRIDES = {};
655
702
  var COOKIE_CATEGORY_OVERRIDES = {};
656
703
  function setCookieCatalogOverrides(overrides) {
657
704
  COOKIE_CATALOG_OVERRIDES = {
658
- byCategory: { ...COOKIE_CATALOG_OVERRIDES.byCategory || {}, ...overrides.byCategory || {} },
705
+ byCategory: { ...COOKIE_CATALOG_OVERRIDES.byCategory, ...overrides.byCategory },
659
706
  byIntegration: {
660
- ...COOKIE_CATALOG_OVERRIDES.byIntegration || {},
661
- ...overrides.byIntegration || {}
707
+ ...COOKIE_CATALOG_OVERRIDES.byIntegration,
708
+ ...overrides.byIntegration
662
709
  }
663
710
  };
664
711
  }
@@ -680,7 +727,7 @@ function getCookiesInfoForCategory(categoryId, usedIntegrations) {
680
727
  ([pattern]) => matchPattern(desc.name, pattern)
681
728
  )?.[1];
682
729
  const finalCat = overrideCat ?? defaultCat;
683
- if (finalCat === categoryId && !result.find((d) => d.name === desc.name)) result.push(desc);
730
+ if (finalCat === categoryId && !result.some((d) => d.name === desc.name)) result.push(desc);
684
731
  });
685
732
  });
686
733
  const catOverride = COOKIE_CATALOG_OVERRIDES.byCategory?.[categoryId];
@@ -692,7 +739,7 @@ function getCookiesInfoForCategory(categoryId, usedIntegrations) {
692
739
  });
693
740
  }
694
741
  if (categoryId === "necessary") {
695
- if (!result.find((d) => d.name === "cookieConsent")) {
742
+ if (!result.some((d) => d.name === "cookieConsent")) {
696
743
  result.push({
697
744
  name: "cookieConsent",
698
745
  purpose: "Armazena suas prefer\xEAncias de consentimento",
@@ -1073,58 +1120,8 @@ var GUIDANCE_PRESETS = {
1073
1120
  };
1074
1121
 
1075
1122
  // src/utils/peerDepsCheck.ts
1076
- function detectMultipleReactInstances() {
1077
- if (typeof window === "undefined") return false;
1078
- try {
1079
- const reactSymbols = Object.getOwnPropertySymbols(window).map((sym) => String(sym)).filter((name) => name.includes("react"));
1080
- if (reactSymbols.length > 1) {
1081
- return true;
1082
- }
1083
- const ReactModule = window.React;
1084
- if (ReactModule && Array.isArray(ReactModule)) {
1085
- return true;
1086
- }
1087
- const hasMultipleVersions = window.__REACT_DEVTOOLS_GLOBAL_HOOK__?.renderers?.size > 1;
1088
- return hasMultipleVersions || false;
1089
- } catch {
1090
- return false;
1091
- }
1092
- }
1093
- function getPackageVersion(packageName) {
1094
- if (typeof window === "undefined") return null;
1095
- try {
1096
- const pkg = window[packageName];
1097
- if (pkg?.version) return pkg.version;
1098
- const React6 = window.React;
1099
- if (packageName === "react" && React6?.version) {
1100
- return React6.version;
1101
- }
1102
- return null;
1103
- } catch {
1104
- return null;
1105
- }
1106
- }
1107
- function isVersionInRange(version, minMajor, maxMajor) {
1108
- const major = parseInt(version.split(".")[0], 10);
1109
- return major >= minMajor && major <= maxMajor;
1110
- }
1111
- function checkPeerDeps(options = {}) {
1112
- const { skipInProduction = true, logWarnings = true } = options;
1113
- const result = {
1114
- ok: true,
1115
- warnings: [],
1116
- errors: []
1117
- };
1118
- const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
1119
- if (skipInProduction && isProduction) {
1120
- return result;
1121
- }
1122
- if (typeof window === "undefined") {
1123
- return result;
1124
- }
1125
- if (detectMultipleReactInstances()) {
1126
- result.ok = false;
1127
- const errorMsg = `
1123
+ var MESSAGES_PT_BR = {
1124
+ MULTIPLE_REACT_INSTANCES: `
1128
1125
  \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
1129
1126
  \u2551 \u26A0\uFE0F ERRO: M\xFAltiplas inst\xE2ncias de React detectadas \u2551
1130
1127
  \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
@@ -1186,22 +1183,13 @@ function checkPeerDeps(options = {}) {
1186
1183
  https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#multiple-react-instances
1187
1184
 
1188
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
1189
- `;
1190
- result.errors.push(errorMsg);
1191
- if (logWarnings) {
1192
- console.error(errorMsg);
1193
- }
1194
- }
1195
- const reactVersion = getPackageVersion("react");
1196
- if (reactVersion) {
1197
- if (!isVersionInRange(reactVersion, 18, 19)) {
1198
- result.ok = false;
1199
- const errorMsg = `
1186
+ `,
1187
+ UNSUPPORTED_REACT_VERSION: (version) => `
1200
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
1201
1189
  \u2551 \u26A0\uFE0F AVISO: Vers\xE3o do React n\xE3o suportada \u2551
1202
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
1203
1191
 
1204
- \u{1F4E6} Vers\xE3o detectada: React ${reactVersion}
1192
+ \u{1F4E6} Vers\xE3o detectada: React ${version}
1205
1193
  \u2705 Vers\xF5es suportadas: React 18.x ou 19.x
1206
1194
 
1207
1195
  \u{1F50D} O react-lgpd-consent requer React 18.2.0+ ou React 19.x
@@ -1219,27 +1207,13 @@ function checkPeerDeps(options = {}) {
1219
1207
  https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#react-version
1220
1208
 
1221
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
1222
- `;
1223
- result.errors.push(errorMsg);
1224
- if (logWarnings) {
1225
- console.error(errorMsg);
1226
- }
1227
- }
1228
- }
1229
- const muiVersion = window["@mui/material"]?.version;
1230
- if (muiVersion) {
1231
- if (!isVersionInRange(muiVersion, 5, 7)) {
1232
- result.warnings.push(
1233
- `MUI vers\xE3o ${muiVersion} detectada. Vers\xF5es suportadas: 5.15.0+, 6.x ou 7.x. Alguns componentes podem n\xE3o funcionar corretamente.`
1234
- );
1235
- if (logWarnings) {
1236
- logger.warn(
1237
- `
1210
+ `,
1211
+ UNSUPPORTED_MUI_VERSION: (version) => `
1238
1212
  \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
1239
1213
  \u2551 \u26A0\uFE0F AVISO: Vers\xE3o do Material-UI fora do range recomendado \u2551
1240
1214
  \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
1241
1215
 
1242
- \u{1F4E6} Vers\xE3o detectada: @mui/material ${muiVersion}
1216
+ \u{1F4E6} Vers\xE3o detectada: @mui/material ${version}
1243
1217
  \u2705 Vers\xF5es suportadas: 5.15.0+, 6.x, 7.x
1244
1218
 
1245
1219
  \u{1F50D} Componentes de UI (@react-lgpd-consent/mui) podem apresentar problemas.
@@ -1257,8 +1231,227 @@ function checkPeerDeps(options = {}) {
1257
1231
  https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#mui-version
1258
1232
 
1259
1233
  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1260
- `
1261
- );
1234
+ `,
1235
+ 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.`
1236
+ };
1237
+ var MESSAGES_EN = {
1238
+ MULTIPLE_REACT_INSTANCES: `
1239
+ \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
1240
+ \u2551 \u26A0\uFE0F ERROR: Multiple React instances detected \u2551
1241
+ \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
1242
+
1243
+ \u{1F534} Problem:
1244
+ Your project is loading more than one copy of React, causing the error:
1245
+ "Invalid hook call. Hooks can only be called inside of the body of a
1246
+ function component."
1247
+
1248
+ \u{1F50D} Probable cause:
1249
+ \u2022 pnpm/Yarn PnP without proper peer dependency hoisting
1250
+ \u2022 node_modules with duplicate React (classic npm/yarn)
1251
+ \u2022 Webpack/Vite with multiple resolutions of the same package
1252
+
1253
+ \u2705 Solutions:
1254
+
1255
+ \u{1F4E6} PNPM (RECOMMENDED):
1256
+ Add to root package.json:
1257
+ {
1258
+ "pnpm": {
1259
+ "overrides": {
1260
+ "react": "$react",
1261
+ "react-dom": "$react-dom"
1262
+ }
1263
+ }
1264
+ }
1265
+ Run: pnpm install
1266
+
1267
+ \u{1F4E6} NPM/Yarn:
1268
+ Add to root package.json:
1269
+ {
1270
+ "overrides": {
1271
+ "react": "^18.2.0 || ^19.0.0",
1272
+ "react-dom": "^18.2.0 || ^19.0.0"
1273
+ }
1274
+ }
1275
+ Run: npm install (or yarn install)
1276
+
1277
+ \u{1F527} Webpack:
1278
+ Add to webpack.config.js:
1279
+ module.exports = {
1280
+ resolve: {
1281
+ alias: {
1282
+ react: path.resolve('./node_modules/react'),
1283
+ 'react-dom': path.resolve('./node_modules/react-dom'),
1284
+ }
1285
+ }
1286
+ }
1287
+
1288
+ \u26A1 Vite:
1289
+ Add to vite.config.js:
1290
+ export default {
1291
+ resolve: {
1292
+ dedupe: ['react', 'react-dom']
1293
+ }
1294
+ }
1295
+
1296
+ \u{1F4DA} Documentation:
1297
+ https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#multiple-react-instances
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_REACT_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: Unsupported React version \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: React ${version}
1307
+ \u2705 Supported versions: React 18.x or 19.x
1308
+
1309
+ \u{1F50D} react-lgpd-consent requires React 18.2.0+ or React 19.x
1310
+
1311
+ \u2705 Solution:
1312
+ Update React to a supported version:
1313
+
1314
+ npm install react@^18.2.0 react-dom@^18.2.0
1315
+
1316
+ or
1317
+
1318
+ npm install react@^19.0.0 react-dom@^19.0.0
1319
+
1320
+ \u{1F4DA} Documentation:
1321
+ https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#react-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
+ UNSUPPORTED_MUI_VERSION: (version) => `
1326
+ \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
1327
+ \u2551 \u26A0\uFE0F WARNING: Material-UI version out of recommended range \u2551
1328
+ \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
1329
+
1330
+ \u{1F4E6} Detected version: @mui/material ${version}
1331
+ \u2705 Supported versions: 5.15.0+, 6.x, 7.x
1332
+
1333
+ \u{1F50D} UI components (@react-lgpd-consent/mui) may have issues.
1334
+
1335
+ \u2705 Solution:
1336
+ Update MUI to a supported version:
1337
+
1338
+ npm install @mui/material@^7.0.0 @emotion/react @emotion/styled
1339
+
1340
+ or keep 5.15.0+:
1341
+
1342
+ npm install @mui/material@^5.15.0 @emotion/react @emotion/styled
1343
+
1344
+ \u{1F4DA} Documentation:
1345
+ https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#mui-version
1346
+
1347
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1348
+ `,
1349
+ 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.`
1350
+ };
1351
+ var MESSAGES_BY_LOCALE = {
1352
+ "pt-BR": MESSAGES_PT_BR,
1353
+ en: MESSAGES_EN
1354
+ };
1355
+ var currentLocale = "pt-BR";
1356
+ var customMessages = {};
1357
+ function setPeerDepsLocale(locale) {
1358
+ currentLocale = locale;
1359
+ }
1360
+ function getPeerDepsLocale() {
1361
+ return currentLocale;
1362
+ }
1363
+ function setPeerDepsMessages(messages) {
1364
+ customMessages = { ...customMessages, ...messages };
1365
+ }
1366
+ function resetPeerDepsMessages() {
1367
+ customMessages = {};
1368
+ }
1369
+ function getMessages() {
1370
+ const baseMessages = MESSAGES_BY_LOCALE[currentLocale];
1371
+ if (Object.keys(customMessages).length === 0) {
1372
+ return baseMessages;
1373
+ }
1374
+ return {
1375
+ MULTIPLE_REACT_INSTANCES: customMessages.MULTIPLE_REACT_INSTANCES ?? baseMessages.MULTIPLE_REACT_INSTANCES,
1376
+ UNSUPPORTED_REACT_VERSION: customMessages.UNSUPPORTED_REACT_VERSION ?? baseMessages.UNSUPPORTED_REACT_VERSION,
1377
+ UNSUPPORTED_MUI_VERSION: customMessages.UNSUPPORTED_MUI_VERSION ?? baseMessages.UNSUPPORTED_MUI_VERSION,
1378
+ MUI_OUT_OF_RANGE: customMessages.MUI_OUT_OF_RANGE ?? baseMessages.MUI_OUT_OF_RANGE
1379
+ };
1380
+ }
1381
+ function detectMultipleReactInstances() {
1382
+ if (globalThis.window === void 0) return false;
1383
+ try {
1384
+ const reactSymbols = Object.getOwnPropertySymbols(globalThis.window).map(String).filter((name) => name.includes("react"));
1385
+ if (reactSymbols.length > 1) {
1386
+ return true;
1387
+ }
1388
+ const ReactModule = window.React;
1389
+ if (ReactModule && Array.isArray(ReactModule)) {
1390
+ return true;
1391
+ }
1392
+ const hasMultipleVersions = window.__REACT_DEVTOOLS_GLOBAL_HOOK__?.renderers?.size > 1;
1393
+ return hasMultipleVersions || false;
1394
+ } catch {
1395
+ return false;
1396
+ }
1397
+ }
1398
+ function getPackageVersion(packageName) {
1399
+ if (globalThis.window === void 0) return null;
1400
+ try {
1401
+ const pkg = window[packageName];
1402
+ if (pkg?.version) return pkg.version;
1403
+ const React6 = window.React;
1404
+ if (packageName === "react" && React6?.version) {
1405
+ return React6.version;
1406
+ }
1407
+ return null;
1408
+ } catch {
1409
+ return null;
1410
+ }
1411
+ }
1412
+ function isVersionInRange(version, minMajor, maxMajor) {
1413
+ const major = Number.parseInt(version.split(".")[0], 10);
1414
+ return major >= minMajor && major <= maxMajor;
1415
+ }
1416
+ function checkPeerDeps(options = {}) {
1417
+ const { skipInProduction = true, logWarnings = true } = options;
1418
+ const result = {
1419
+ ok: true,
1420
+ warnings: [],
1421
+ errors: []
1422
+ };
1423
+ const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
1424
+ if (skipInProduction && isProduction) {
1425
+ return result;
1426
+ }
1427
+ if (globalThis.window === void 0) {
1428
+ return result;
1429
+ }
1430
+ const messages = getMessages();
1431
+ if (detectMultipleReactInstances()) {
1432
+ result.ok = false;
1433
+ result.errors.push(messages.MULTIPLE_REACT_INSTANCES);
1434
+ if (logWarnings) {
1435
+ console.error(messages.MULTIPLE_REACT_INSTANCES);
1436
+ }
1437
+ }
1438
+ const reactVersion = getPackageVersion("react");
1439
+ if (reactVersion) {
1440
+ if (!isVersionInRange(reactVersion, 18, 19)) {
1441
+ result.ok = false;
1442
+ const errorMsg = messages.UNSUPPORTED_REACT_VERSION(reactVersion);
1443
+ result.errors.push(errorMsg);
1444
+ if (logWarnings) {
1445
+ console.error(errorMsg);
1446
+ }
1447
+ }
1448
+ }
1449
+ const muiVersion = window["@mui/material"]?.version;
1450
+ if (muiVersion) {
1451
+ if (!isVersionInRange(muiVersion, 5, 7)) {
1452
+ result.warnings.push(messages.MUI_OUT_OF_RANGE(muiVersion));
1453
+ if (logWarnings) {
1454
+ logger.warn(messages.UNSUPPORTED_MUI_VERSION(muiVersion));
1262
1455
  }
1263
1456
  }
1264
1457
  }
@@ -1281,7 +1474,7 @@ function validateConsentProviderProps(props) {
1281
1474
  const sanitized = {};
1282
1475
  if (!isDev()) {
1283
1476
  if (props.categories) {
1284
- const enabled = Array.from(/* @__PURE__ */ new Set([...props.categories.enabledCategories ?? []]));
1477
+ const enabled = [...new Set(props.categories.enabledCategories ?? [])];
1285
1478
  const sanitizedEnabled = enabled.filter((c) => c !== "necessary");
1286
1479
  sanitized.categories = {
1287
1480
  enabledCategories: sanitizedEnabled,
@@ -1318,11 +1511,11 @@ function validateConsentProviderProps(props) {
1318
1511
  }
1319
1512
  if (!props.categories) {
1320
1513
  warnings.push(
1321
- "Prop 'categories' n\xE3o fornecida. A lib aplicar\xE1 um padr\xE3o seguro, mas recomenda-se definir 'categories.enabledCategories' explicitamente para clareza e auditoria."
1514
+ "Prop 'categories' n\xE3o fornecida \u2014 o ConsentProvider requer configura\xE7\xE3o de categorias."
1322
1515
  );
1323
1516
  } else {
1324
1517
  const cat = props.categories;
1325
- const enabled = Array.from(/* @__PURE__ */ new Set([...cat.enabledCategories ?? []]));
1518
+ const enabled = [...new Set(cat.enabledCategories ?? [])];
1326
1519
  if (enabled.includes("necessary")) {
1327
1520
  warnings.push("'necessary' \xE9 sempre inclu\xEDda automaticamente \u2014 remova de enabledCategories.");
1328
1521
  }
@@ -1330,7 +1523,7 @@ function validateConsentProviderProps(props) {
1330
1523
  const invalidEnabled = sanitizedEnabled.filter((c) => typeof c !== "string" || c.trim() === "");
1331
1524
  if (invalidEnabled.length > 0) {
1332
1525
  warnings.push(
1333
- `enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map((v) => String(v)).join(", ")} \u2014 remova ou corrija os IDs de categoria`
1526
+ `enabledCategories cont\xE9m valores inv\xE1lidos: ${invalidEnabled.map(String).join(", ")} \u2014 remova ou corrija os IDs de categoria`
1334
1527
  );
1335
1528
  }
1336
1529
  const custom = cat.customCategories ?? [];
@@ -1424,13 +1617,13 @@ function detectConsentCookieName() {
1424
1617
  }
1425
1618
  return null;
1426
1619
  }
1620
+ function matchPattern2(name, pattern) {
1621
+ if (pattern.endsWith("*")) return name.startsWith(pattern.slice(0, -1));
1622
+ return name === pattern;
1623
+ }
1427
1624
  function categorizeDiscoveredCookies(discovered, registerOverrides = false) {
1428
1625
  const list = discovered || globalThis.__LGPD_DISCOVERED_COOKIES__ || [];
1429
1626
  const out = {};
1430
- function matchPattern2(name, pattern) {
1431
- if (pattern.endsWith("*")) return name.startsWith(pattern.slice(0, -1));
1432
- return name === pattern;
1433
- }
1434
1627
  list.filter((d) => d.name && d.name !== "cookieConsent").forEach((d) => {
1435
1628
  let assigned = null;
1436
1629
  Object.keys(COOKIE_PATTERNS_BY_CATEGORY).forEach((cat2) => {
@@ -1438,9 +1631,9 @@ function categorizeDiscoveredCookies(discovered, registerOverrides = false) {
1438
1631
  const patterns = COOKIE_PATTERNS_BY_CATEGORY[cat2] || [];
1439
1632
  if (patterns.some((p) => matchPattern2(d.name, p))) assigned = cat2;
1440
1633
  });
1441
- const cat = assigned || "analytics";
1634
+ const cat = assigned ?? "analytics";
1442
1635
  out[cat] = out[cat] || [];
1443
- if (!out[cat].find((x) => x.name === d.name)) out[cat].push(d);
1636
+ if (!out[cat].some((x) => x.name === d.name)) out[cat].push(d);
1444
1637
  });
1445
1638
  if (registerOverrides) {
1446
1639
  const byCategory = {};
@@ -1517,7 +1710,7 @@ function useCategories() {
1517
1710
  const context = React4__namespace.useContext(CategoriesContext);
1518
1711
  if (!context) {
1519
1712
  throw new Error(
1520
- "useCategories deve ser usado dentro de CategoriesProvider. Certifique-se de que o ConsentProvider est\xE1 envolvendo seu componente."
1713
+ "[react-lgpd-consent] useCategories deve ser usado dentro de <ConsentProvider>. Adicione o provider ao redor da sua \xE1rvore antes de chamar o hook."
1521
1714
  );
1522
1715
  }
1523
1716
  return context;
@@ -1668,6 +1861,11 @@ var StateCtx = React4__namespace.createContext(null);
1668
1861
  var ActionsCtx = React4__namespace.createContext(null);
1669
1862
  var TextsCtx = React4__namespace.createContext(DEFAULT_TEXTS);
1670
1863
  var HydrationCtx = React4__namespace.createContext(false);
1864
+ function buildProviderError(hookName) {
1865
+ return new Error(
1866
+ `[react-lgpd-consent] ${hookName} deve ser usado dentro de <ConsentProvider>. Envolva seu componente com o provider ou use o wrapper @react-lgpd-consent/mui.`
1867
+ );
1868
+ }
1671
1869
  function ConsentProvider({
1672
1870
  initialState,
1673
1871
  categories,
@@ -1691,7 +1889,10 @@ function ConsentProvider({
1691
1889
  disableDeveloperGuidance,
1692
1890
  guidanceConfig,
1693
1891
  children,
1694
- disableDiscoveryLog
1892
+ disableDiscoveryLog,
1893
+ onConsentInit,
1894
+ onConsentChange,
1895
+ onAuditLog
1695
1896
  }) {
1696
1897
  const texts = React4__namespace.useMemo(() => ({ ...DEFAULT_TEXTS, ...textsProp ?? {} }), [textsProp]);
1697
1898
  const cookie = React4__namespace.useMemo(() => {
@@ -1705,6 +1906,14 @@ function ConsentProvider({
1705
1906
  }
1706
1907
  return base;
1707
1908
  }, [cookieOpts, storage?.domain, storage?.namespace, storage?.version]);
1909
+ const consentVersion = storage?.version?.trim() || "1";
1910
+ React4__namespace.useEffect(() => {
1911
+ try {
1912
+ ;
1913
+ globalThis.__LGPD_CONSENT_COOKIE__ = cookie.name;
1914
+ } catch {
1915
+ }
1916
+ }, [cookie.name]);
1708
1917
  const finalCategoriesConfig = React4__namespace.useMemo(() => {
1709
1918
  const isProd = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
1710
1919
  if (!categories) return DEFAULT_PROJECT_CATEGORIES;
@@ -1751,6 +1960,8 @@ function ConsentProvider({
1751
1960
  const skipCookiePersistRef = React4__namespace.useRef(false);
1752
1961
  const [isHydrated, setIsHydrated] = React4__namespace.useState(false);
1753
1962
  const previousPreferencesRef = React4__namespace.useRef(state.preferences);
1963
+ const auditInitEmittedRef = React4__namespace.useRef(false);
1964
+ const previousConsentedAuditRef = React4__namespace.useRef(state.consented);
1754
1965
  React4__namespace.useEffect(() => {
1755
1966
  if (!initialState) {
1756
1967
  const saved = readConsentCookie(cookie.name);
@@ -1799,13 +2010,44 @@ function ConsentProvider({
1799
2010
  logger.info("DataLayer: consent_initialized event dispatched", {
1800
2011
  preferences: state.preferences
1801
2012
  });
2013
+ if (onConsentInit) onConsentInit(state);
1802
2014
  }
1803
2015
  }, [isHydrated]);
2016
+ React4__namespace.useEffect(() => {
2017
+ if (!isHydrated) return;
2018
+ if (!onAuditLog) return;
2019
+ if (auditInitEmittedRef.current) return;
2020
+ onAuditLog(
2021
+ createConsentAuditEntry(state, {
2022
+ action: "init",
2023
+ storageKey: cookie.name,
2024
+ consentVersion
2025
+ })
2026
+ );
2027
+ auditInitEmittedRef.current = true;
2028
+ }, [isHydrated, onAuditLog, state, cookie.name, consentVersion]);
1804
2029
  React4__namespace.useEffect(() => {
1805
2030
  if (!state.consented) return;
1806
2031
  if (skipCookiePersistRef.current) return;
1807
2032
  writeConsentCookie(state, finalCategoriesConfig, cookie);
1808
2033
  }, [state, cookie, finalCategoriesConfig]);
2034
+ React4__namespace.useEffect(() => {
2035
+ if (!onAuditLog) {
2036
+ previousConsentedAuditRef.current = state.consented;
2037
+ return;
2038
+ }
2039
+ if (previousConsentedAuditRef.current && !state.consented) {
2040
+ onAuditLog(
2041
+ createConsentAuditEntry(state, {
2042
+ action: "reset",
2043
+ storageKey: cookie.name,
2044
+ consentVersion,
2045
+ origin: "reset"
2046
+ })
2047
+ );
2048
+ }
2049
+ previousConsentedAuditRef.current = state.consented;
2050
+ }, [state, onAuditLog, cookie.name, consentVersion]);
1809
2051
  const prevConsented = React4__namespace.useRef(state.consented);
1810
2052
  React4__namespace.useEffect(() => {
1811
2053
  if (!prevConsented.current && state.consented && onConsentGiven) {
@@ -1826,9 +2068,32 @@ function ConsentProvider({
1826
2068
  preferences: state.preferences,
1827
2069
  consented: state.consented
1828
2070
  });
2071
+ if (onConsentChange) {
2072
+ onConsentChange(state, { origin });
2073
+ }
2074
+ if (onAuditLog) {
2075
+ onAuditLog(
2076
+ createConsentAuditEntry(state, {
2077
+ action: "update",
2078
+ storageKey: cookie.name,
2079
+ consentVersion,
2080
+ origin
2081
+ })
2082
+ );
2083
+ }
1829
2084
  previousPreferencesRef.current = state.preferences;
1830
2085
  }
1831
- }, [state.preferences, state.consented, state.source, isHydrated]);
2086
+ }, [
2087
+ state,
2088
+ state.preferences,
2089
+ state.consented,
2090
+ state.source,
2091
+ isHydrated,
2092
+ onConsentChange,
2093
+ onAuditLog,
2094
+ cookie.name,
2095
+ consentVersion
2096
+ ]);
1832
2097
  const api = React4__namespace.useMemo(() => {
1833
2098
  const acceptAll = () => dispatch({ type: "ACCEPT_ALL", config: finalCategoriesConfig });
1834
2099
  const rejectAll = () => dispatch({ type: "REJECT_ALL", config: finalCategoriesConfig });
@@ -1879,6 +2144,14 @@ function ConsentProvider({
1879
2144
  if (typeof backdrop === "string") return backdrop;
1880
2145
  return "rgba(0, 0, 0, 0.4)";
1881
2146
  }, [designTokens]);
2147
+ const cookieBannerPropsWithDefaults = React4__namespace.useMemo(() => {
2148
+ const incoming = cookieBannerProps ?? {};
2149
+ return {
2150
+ ...incoming,
2151
+ blocking: incoming.blocking === void 0 ? blocking : Boolean(incoming.blocking),
2152
+ hideBranding: incoming.hideBranding === void 0 ? _hideBranding : Boolean(incoming.hideBranding)
2153
+ };
2154
+ }, [cookieBannerProps, blocking, _hideBranding]);
1882
2155
  const content = /* @__PURE__ */ jsxRuntime.jsx(StateCtx.Provider, { value: state, children: /* @__PURE__ */ jsxRuntime.jsx(ActionsCtx.Provider, { value: api, children: /* @__PURE__ */ jsxRuntime.jsx(TextsCtx.Provider, { value: texts, children: /* @__PURE__ */ jsxRuntime.jsx(HydrationCtx.Provider, { value: isHydrated, children: /* @__PURE__ */ jsxRuntime.jsx(DesignProvider, { tokens: designTokens, children: /* @__PURE__ */ jsxRuntime.jsxs(
1883
2156
  CategoriesProvider,
1884
2157
  {
@@ -1899,7 +2172,7 @@ function ConsentProvider({
1899
2172
  }
1900
2173
  ) : (
1901
2174
  // Aviso de desenvolvimento: usuário pode estar esquecendo de fornecer componentes UI
1902
- process.env.NODE_ENV === "development" && typeof window !== "undefined" && !didWarnAboutMissingUI.current && !CookieBannerComponent && !FloatingPreferencesButtonComponent && (() => {
2175
+ process.env.NODE_ENV === "development" && globalThis.window !== void 0 && !didWarnAboutMissingUI.current && !CookieBannerComponent && !FloatingPreferencesButtonComponent && (() => {
1903
2176
  didWarnAboutMissingUI.current = true;
1904
2177
  console.warn(
1905
2178
  "%c[@react-lgpd-consent/core] Aviso: Nenhum componente UI fornecido",
@@ -1961,8 +2234,7 @@ function ConsentProvider({
1961
2234
  rejectAll: api.rejectAll,
1962
2235
  openPreferences: api.openPreferences,
1963
2236
  texts,
1964
- blocking,
1965
- ...cookieBannerProps
2237
+ ...cookieBannerPropsWithDefaults
1966
2238
  }
1967
2239
  ),
1968
2240
  state.consented && !disableFloatingPreferencesButton && FloatingPreferencesButtonComponent && /* @__PURE__ */ jsxRuntime.jsx(
@@ -1980,12 +2252,12 @@ function ConsentProvider({
1980
2252
  }
1981
2253
  function useConsentStateInternal() {
1982
2254
  const ctx = React4__namespace.useContext(StateCtx);
1983
- if (!ctx) throw new Error("useConsentState must be used within ConsentProvider");
2255
+ if (!ctx) throw buildProviderError("useConsentState");
1984
2256
  return ctx;
1985
2257
  }
1986
2258
  function useConsentActionsInternal() {
1987
2259
  const ctx = React4__namespace.useContext(ActionsCtx);
1988
- if (!ctx) throw new Error("useConsentActions must be used within ConsentProvider");
2260
+ if (!ctx) throw buildProviderError("useConsentActions");
1989
2261
  return ctx;
1990
2262
  }
1991
2263
  function useConsentTextsInternal() {
@@ -2004,45 +2276,99 @@ function ConsentGate(props) {
2004
2276
 
2005
2277
  // src/utils/scriptLoader.ts
2006
2278
  var LOADING_SCRIPTS = /* @__PURE__ */ new Map();
2007
- function loadScript(id, src, category = null, attrs = {}) {
2279
+ var DEFAULT_POLL_INTERVAL = 100;
2280
+ function resolveCookieNames(preferred) {
2281
+ const inferred = globalThis.__LGPD_CONSENT_COOKIE__ ?? null;
2282
+ const names = [preferred, inferred, "cookieConsent", "lgpd-consent__v1"].filter(
2283
+ Boolean
2284
+ );
2285
+ return Array.from(new Set(names));
2286
+ }
2287
+ function parseConsentFromCookie(names) {
2288
+ const raw = document.cookie;
2289
+ if (!raw) return null;
2290
+ const cookies = raw.split("; ").reduce((acc, part) => {
2291
+ const [k, ...rest] = part.split("=");
2292
+ acc[k] = rest.join("=");
2293
+ return acc;
2294
+ }, {});
2295
+ for (const name of names) {
2296
+ const value = cookies[name];
2297
+ if (!value) continue;
2298
+ try {
2299
+ const parsed = JSON.parse(decodeURIComponent(value));
2300
+ if (!parsed.consented || parsed.isModalOpen) continue;
2301
+ return parsed;
2302
+ } catch {
2303
+ continue;
2304
+ }
2305
+ }
2306
+ return null;
2307
+ }
2308
+ function hasCategoryConsent(snapshot, category) {
2309
+ if (!snapshot.consented || snapshot.isModalOpen) return false;
2310
+ if (category === null) return true;
2311
+ return Boolean(snapshot.preferences?.[category]);
2312
+ }
2313
+ function loadScript(id, src, category = null, attrs = {}, nonce, options) {
2008
2314
  if (typeof document === "undefined") return Promise.resolve();
2009
2315
  if (document.getElementById(id)) return Promise.resolve();
2010
2316
  const existingPromise = LOADING_SCRIPTS.get(id);
2011
2317
  if (existingPromise) return existingPromise;
2318
+ const pollInterval = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL;
2319
+ const names = resolveCookieNames(options?.cookieName);
2320
+ const mergedAttrs = { ...attrs };
2012
2321
  const promise = new Promise((resolve, reject) => {
2322
+ const inject = () => {
2323
+ const s = document.createElement("script");
2324
+ s.id = id;
2325
+ s.src = src;
2326
+ s.async = mergedAttrs.async !== "false";
2327
+ const scriptNonce = mergedAttrs.nonce || nonce;
2328
+ if (scriptNonce) {
2329
+ s.nonce = scriptNonce;
2330
+ mergedAttrs.nonce = scriptNonce;
2331
+ }
2332
+ for (const [k, v] of Object.entries(mergedAttrs)) s.setAttribute(k, v);
2333
+ s.onload = () => {
2334
+ LOADING_SCRIPTS.delete(id);
2335
+ resolve();
2336
+ };
2337
+ s.onerror = () => {
2338
+ LOADING_SCRIPTS.delete(id);
2339
+ reject(new Error(`Failed to load script: ${src}`));
2340
+ };
2341
+ document.body.appendChild(s);
2342
+ };
2343
+ const snapshot = options?.consentSnapshot;
2344
+ const skipChecks = options?.skipConsentCheck === true;
2345
+ if (skipChecks) {
2346
+ inject();
2347
+ return;
2348
+ }
2349
+ if (snapshot) {
2350
+ if (!hasCategoryConsent(snapshot, category)) {
2351
+ reject(
2352
+ new Error(
2353
+ `Consent not granted for category '${category ?? "none"}' when attempting to load ${id}`
2354
+ )
2355
+ );
2356
+ return;
2357
+ }
2358
+ inject();
2359
+ return;
2360
+ }
2013
2361
  const checkConsent = () => {
2014
- const consentCookie = document.cookie.split("; ").find((row) => row.startsWith("cookieConsent="))?.split("=")[1];
2015
- if (!consentCookie) {
2016
- setTimeout(checkConsent, 100);
2362
+ const consent = parseConsentFromCookie(names);
2363
+ if (!consent) {
2364
+ setTimeout(checkConsent, pollInterval);
2017
2365
  return;
2018
2366
  }
2019
- try {
2020
- const consent = JSON.parse(decodeURIComponent(consentCookie));
2021
- if (!consent.consented || consent.isModalOpen) {
2022
- setTimeout(checkConsent, 100);
2023
- return;
2024
- }
2025
- if (category && !consent.preferences[category]) {
2026
- setTimeout(checkConsent, 100);
2027
- return;
2028
- }
2029
- const s = document.createElement("script");
2030
- s.id = id;
2031
- s.src = src;
2032
- s.async = true;
2033
- for (const [k, v] of Object.entries(attrs)) s.setAttribute(k, v);
2034
- s.onload = () => {
2035
- LOADING_SCRIPTS.delete(id);
2036
- resolve();
2037
- };
2038
- s.onerror = () => {
2039
- LOADING_SCRIPTS.delete(id);
2040
- reject(new Error(`Failed to load script: ${src}`));
2041
- };
2042
- document.body.appendChild(s);
2043
- } catch {
2044
- setTimeout(checkConsent, 100);
2367
+ if (!hasCategoryConsent(consent, category)) {
2368
+ setTimeout(checkConsent, pollInterval);
2369
+ return;
2045
2370
  }
2371
+ inject();
2046
2372
  };
2047
2373
  checkConsent();
2048
2374
  });
@@ -2206,13 +2532,107 @@ function validateNecessaryClassification(integrations, enabledCategories) {
2206
2532
  }
2207
2533
 
2208
2534
  // src/utils/ConsentScriptLoader.tsx
2535
+ var scriptRegistry = /* @__PURE__ */ new Map();
2536
+ var queueListeners = /* @__PURE__ */ new Set();
2537
+ function notifyQueue() {
2538
+ queueListeners.forEach((listener) => {
2539
+ try {
2540
+ listener();
2541
+ } catch {
2542
+ }
2543
+ });
2544
+ }
2545
+ function subscribeQueue(listener) {
2546
+ queueListeners.add(listener);
2547
+ return () => {
2548
+ queueListeners.delete(listener);
2549
+ };
2550
+ }
2551
+ function createInternalScript(def) {
2552
+ return {
2553
+ ...def,
2554
+ status: "pending",
2555
+ lastAllowed: false,
2556
+ registeredAt: Date.now(),
2557
+ token: Date.now() + Math.random(),
2558
+ priority: def.priority ?? 0,
2559
+ allowReload: def.allowReload ?? false,
2560
+ onConsentUpdate: def.onConsentUpdate
2561
+ };
2562
+ }
2563
+ function registerScript(def) {
2564
+ const entry = createInternalScript(def);
2565
+ scriptRegistry.set(def.id, entry);
2566
+ notifyQueue();
2567
+ return () => {
2568
+ const current = scriptRegistry.get(def.id);
2569
+ if (current && current.token === entry.token) {
2570
+ scriptRegistry.delete(def.id);
2571
+ notifyQueue();
2572
+ }
2573
+ };
2574
+ }
2575
+ function getExecutableScripts(consent) {
2576
+ const allowedScripts = [];
2577
+ scriptRegistry.forEach((script) => {
2578
+ const categoryAllowed = script.category === "necessary" || consent.consented && Boolean(consent.preferences?.[script.category]);
2579
+ if (!categoryAllowed) {
2580
+ script.lastAllowed = false;
2581
+ return;
2582
+ }
2583
+ if (script.status === "running") return;
2584
+ if (script.status === "executed" && !script.allowReload) return;
2585
+ if (script.status === "executed" && script.allowReload && script.lastAllowed) return;
2586
+ script.lastAllowed = true;
2587
+ allowedScripts.push(script);
2588
+ });
2589
+ return allowedScripts.sort((a, b) => {
2590
+ if (a.category === "necessary" && b.category !== "necessary") return -1;
2591
+ if (b.category === "necessary" && a.category !== "necessary") return 1;
2592
+ if (a.category !== b.category) return a.category.localeCompare(b.category);
2593
+ if (a.priority !== b.priority) return (b.priority ?? 0) - (a.priority ?? 0);
2594
+ return a.registeredAt - b.registeredAt;
2595
+ });
2596
+ }
2597
+ async function processQueue(consent, devLogging) {
2598
+ const scripts = getExecutableScripts(consent);
2599
+ let order = 0;
2600
+ for (const script of scripts) {
2601
+ order += 1;
2602
+ script.status = "running";
2603
+ if (devLogging) {
2604
+ logger.info("[ConsentScriptLoader] executando script", {
2605
+ id: script.id,
2606
+ category: script.category,
2607
+ priority: script.priority ?? 0,
2608
+ order
2609
+ });
2610
+ }
2611
+ try {
2612
+ await Promise.resolve(script.execute());
2613
+ } catch (error) {
2614
+ logger.error(`\u274C Failed to execute script ${script.id}`, error);
2615
+ } finally {
2616
+ script.status = "executed";
2617
+ if (script.onConsentUpdate) {
2618
+ script.onConsentUpdate(consent);
2619
+ }
2620
+ }
2621
+ }
2622
+ }
2209
2623
  function ConsentScriptLoader({
2210
2624
  integrations,
2211
- reloadOnChange = false
2625
+ reloadOnChange = false,
2626
+ nonce
2212
2627
  }) {
2213
2628
  const { preferences, consented } = useConsent();
2629
+ const isHydrated = useConsentHydration();
2214
2630
  const categories = useCategories();
2215
- const loadedScripts = React4__namespace.useRef(/* @__PURE__ */ new Set());
2631
+ const [queueVersion, bumpQueueVersion] = React4__namespace.useState(0);
2632
+ React4__namespace.useEffect(() => {
2633
+ const unsubscribe = subscribeQueue(() => bumpQueueVersion((v) => v + 1));
2634
+ return unsubscribe;
2635
+ }, []);
2216
2636
  React4__namespace.useEffect(() => {
2217
2637
  try {
2218
2638
  const ids = (integrations || []).map((i) => i.id);
@@ -2241,8 +2661,8 @@ function ConsentScriptLoader({
2241
2661
  const current = Array.isArray(gt.__LGPD_REQUIRED_CATEGORIES__) ? gt.__LGPD_REQUIRED_CATEGORIES__ : [];
2242
2662
  const merged = Array.from(/* @__PURE__ */ new Set([...current, ...required]));
2243
2663
  gt.__LGPD_REQUIRED_CATEGORIES__ = merged;
2244
- if (typeof window !== "undefined" && typeof window.dispatchEvent === "function") {
2245
- window.dispatchEvent(new CustomEvent("lgpd:requiredCategories"));
2664
+ if (globalThis.window !== void 0 && typeof globalThis.window.dispatchEvent === "function") {
2665
+ globalThis.window.dispatchEvent(new CustomEvent("lgpd:requiredCategories"));
2246
2666
  }
2247
2667
  } catch {
2248
2668
  }
@@ -2250,7 +2670,7 @@ function ConsentScriptLoader({
2250
2670
  React4__namespace.useEffect(() => {
2251
2671
  const isDev2 = process.env.NODE_ENV !== "production";
2252
2672
  if (!isDev2 || integrations.length === 0) return;
2253
- const enabledCategories = categories.allCategories.map((cat) => cat.id);
2673
+ const enabledCategories = categories.config.enabledCategories ?? [];
2254
2674
  const isValid = validateIntegrationCategories(integrations, enabledCategories);
2255
2675
  if (!isValid) {
2256
2676
  autoConfigureCategories({ enabledCategories }, integrations, {
@@ -2273,38 +2693,99 @@ function ConsentScriptLoader({
2273
2693
  console.groupEnd();
2274
2694
  }
2275
2695
  }, [integrations, categories]);
2696
+ const processedIntegrationsRef = React4__namespace.useRef(/* @__PURE__ */ new Map());
2276
2697
  React4__namespace.useEffect(() => {
2277
- if (!consented) return;
2278
- const timeoutId = setTimeout(async () => {
2279
- for (const integration of integrations) {
2280
- const shouldLoad = preferences[integration.category];
2281
- const alreadyLoaded = loadedScripts.current.has(integration.id);
2282
- if (shouldLoad && (!alreadyLoaded || reloadOnChange)) {
2283
- try {
2698
+ const cleanups = [];
2699
+ const currentIds = /* @__PURE__ */ new Set();
2700
+ integrations.forEach((integration) => {
2701
+ currentIds.add(integration.id);
2702
+ const structuralHash = JSON.stringify({
2703
+ category: integration.category,
2704
+ src: integration.src,
2705
+ priority: integration.priority,
2706
+ hasBootstrap: Boolean(integration.bootstrap),
2707
+ hasInit: Boolean(integration.init),
2708
+ hasOnConsentUpdate: Boolean(integration.onConsentUpdate)
2709
+ });
2710
+ const existingHash = processedIntegrationsRef.current.get(integration.id);
2711
+ if (existingHash === structuralHash && scriptRegistry.has(integration.id)) {
2712
+ return;
2713
+ }
2714
+ processedIntegrationsRef.current.set(integration.id, structuralHash);
2715
+ if (integration.bootstrap) {
2716
+ cleanups.push(
2717
+ registerScript({
2718
+ id: `${integration.id}__bootstrap`,
2719
+ category: "necessary",
2720
+ priority: (integration.priority ?? 0) + 1e3,
2721
+ execute: integration.bootstrap
2722
+ })
2723
+ );
2724
+ }
2725
+ cleanups.push(
2726
+ registerScript({
2727
+ id: integration.id,
2728
+ category: integration.category,
2729
+ priority: integration.priority,
2730
+ allowReload: reloadOnChange,
2731
+ onConsentUpdate: integration.onConsentUpdate,
2732
+ execute: async () => {
2733
+ const mergedAttrs = integration.attrs ? { ...integration.attrs } : {};
2734
+ const scriptNonce = integration.nonce ?? nonce;
2735
+ if (scriptNonce && !mergedAttrs.nonce) mergedAttrs.nonce = scriptNonce;
2284
2736
  await loadScript(
2285
2737
  integration.id,
2286
2738
  integration.src,
2287
2739
  integration.category,
2288
- integration.attrs
2740
+ mergedAttrs,
2741
+ scriptNonce,
2742
+ { skipConsentCheck: true }
2289
2743
  );
2290
2744
  if (integration.init) {
2291
2745
  integration.init();
2292
2746
  }
2293
- loadedScripts.current.add(integration.id);
2294
- } catch (error) {
2295
- logger.error(`\u274C Failed to load script: ${integration.id}`, error);
2296
2747
  }
2748
+ })
2749
+ );
2750
+ });
2751
+ processedIntegrationsRef.current.forEach((_, id) => {
2752
+ if (!currentIds.has(id)) {
2753
+ processedIntegrationsRef.current.delete(id);
2754
+ const script = scriptRegistry.get(id);
2755
+ if (script) {
2756
+ scriptRegistry.delete(id);
2757
+ }
2758
+ const bootstrapScript = scriptRegistry.get(`${id}__bootstrap`);
2759
+ if (bootstrapScript) {
2760
+ scriptRegistry.delete(`${id}__bootstrap`);
2297
2761
  }
2298
2762
  }
2299
- }, 0);
2300
- return () => clearTimeout(timeoutId);
2301
- }, [preferences, consented, integrations, reloadOnChange]);
2763
+ });
2764
+ return () => cleanups.forEach((fn) => fn());
2765
+ }, [integrations, reloadOnChange, nonce]);
2766
+ React4__namespace.useEffect(() => {
2767
+ if (!isHydrated) return;
2768
+ void processQueue({ consented, preferences }, process.env.NODE_ENV !== "production");
2769
+ }, [consented, preferences, isHydrated, queueVersion]);
2770
+ React4__namespace.useEffect(() => {
2771
+ if (!isHydrated) return;
2772
+ scriptRegistry.forEach((script) => {
2773
+ if (script.status !== "executed") return;
2774
+ if (typeof script.onConsentUpdate !== "function") return;
2775
+ script.onConsentUpdate({ consented, preferences });
2776
+ });
2777
+ }, [consented, preferences, isHydrated]);
2302
2778
  return null;
2303
2779
  }
2304
2780
  function useConsentScriptLoader() {
2305
2781
  const { preferences, consented } = useConsent();
2782
+ const isHydrated = useConsentHydration();
2306
2783
  return React4__namespace.useCallback(
2307
- async (integration) => {
2784
+ async (integration, nonce) => {
2785
+ if (!isHydrated) {
2786
+ logger.warn(`\u26A0\uFE0F Cannot load script ${integration.id}: Consent not hydrated yet`);
2787
+ return false;
2788
+ }
2308
2789
  if (!consented) {
2309
2790
  logger.warn(`\u26A0\uFE0F Cannot load script ${integration.id}: No consent given`);
2310
2791
  return false;
@@ -2317,7 +2798,20 @@ function useConsentScriptLoader() {
2317
2798
  return false;
2318
2799
  }
2319
2800
  try {
2320
- await loadScript(integration.id, integration.src, integration.category, integration.attrs);
2801
+ const mergedAttrs = integration.attrs ? { ...integration.attrs } : {};
2802
+ const scriptNonce = integration.nonce ?? nonce;
2803
+ if (scriptNonce && !mergedAttrs.nonce) mergedAttrs.nonce = scriptNonce;
2804
+ await loadScript(
2805
+ integration.id,
2806
+ integration.src,
2807
+ integration.category,
2808
+ mergedAttrs,
2809
+ scriptNonce,
2810
+ {
2811
+ consentSnapshot: { consented, preferences },
2812
+ skipConsentCheck: true
2813
+ }
2814
+ );
2321
2815
  if (integration.init) {
2322
2816
  integration.init();
2323
2817
  }
@@ -2327,11 +2821,62 @@ function useConsentScriptLoader() {
2327
2821
  return false;
2328
2822
  }
2329
2823
  },
2330
- [preferences, consented]
2824
+ [preferences, consented, isHydrated]
2331
2825
  );
2332
2826
  }
2333
2827
 
2334
2828
  // src/utils/scriptIntegrations.ts
2829
+ function buildConsentModeSignals(preferences) {
2830
+ const analytics = preferences.analytics ? "granted" : "denied";
2831
+ const marketing = preferences.marketing ? "granted" : "denied";
2832
+ return {
2833
+ ad_storage: marketing,
2834
+ ad_user_data: marketing,
2835
+ ad_personalization: marketing,
2836
+ analytics_storage: analytics
2837
+ };
2838
+ }
2839
+ function pushToLayer(entry, dataLayerName) {
2840
+ if (typeof globalThis.window === "undefined") return;
2841
+ const registry = globalThis.window;
2842
+ const name = dataLayerName ?? "dataLayer";
2843
+ const layer = registry[name] ?? [];
2844
+ registry[name] = layer;
2845
+ layer.push(entry);
2846
+ }
2847
+ function ensureGtag(dataLayerName = "dataLayer") {
2848
+ if (typeof globalThis.window === "undefined") return null;
2849
+ const w = window;
2850
+ const registry = w;
2851
+ const layer = registry[dataLayerName] ?? [];
2852
+ registry[dataLayerName] = layer;
2853
+ if (typeof w.gtag !== "function") {
2854
+ const gtag = (...args) => {
2855
+ layer.push(args);
2856
+ };
2857
+ w.gtag = gtag;
2858
+ }
2859
+ return w.gtag;
2860
+ }
2861
+ function applyDefaultConsentMode(dataLayerName) {
2862
+ const payload = buildConsentModeSignals({
2863
+ analytics: false,
2864
+ marketing: false
2865
+ });
2866
+ const gtag = ensureGtag(dataLayerName);
2867
+ if (gtag) {
2868
+ gtag("consent", "default", payload);
2869
+ }
2870
+ pushToLayer(["consent", "default", payload], dataLayerName);
2871
+ }
2872
+ function applyConsentModeUpdate(preferences, dataLayerName) {
2873
+ const payload = buildConsentModeSignals(preferences);
2874
+ const gtag = ensureGtag(dataLayerName);
2875
+ if (gtag) {
2876
+ gtag("consent", "update", payload);
2877
+ }
2878
+ pushToLayer(["consent", "update", payload], dataLayerName);
2879
+ }
2335
2880
  function createGoogleAnalyticsIntegration(config) {
2336
2881
  const src = config.scriptUrl ?? `https://www.googletagmanager.com/gtag/js?id=${config.measurementId}`;
2337
2882
  return {
@@ -2359,17 +2904,17 @@ function createGoogleAnalyticsIntegration(config) {
2359
2904
  provider: "Google Analytics"
2360
2905
  }
2361
2906
  ],
2907
+ bootstrap: () => {
2908
+ applyDefaultConsentMode();
2909
+ },
2910
+ onConsentUpdate: ({ preferences }) => {
2911
+ applyConsentModeUpdate(preferences);
2912
+ },
2362
2913
  init: () => {
2363
- if (typeof window !== "undefined") {
2364
- const w = window;
2365
- w.dataLayer = w.dataLayer ?? [];
2366
- const gtag = (...args) => {
2367
- w.dataLayer.push(...args);
2368
- };
2369
- w.gtag = gtag;
2370
- gtag("js", /* @__PURE__ */ new Date());
2371
- gtag("config", config.measurementId, config.config ?? {});
2372
- }
2914
+ const gtag = ensureGtag();
2915
+ if (!gtag) return;
2916
+ gtag("js", /* @__PURE__ */ new Date());
2917
+ gtag("config", config.measurementId, config.config ?? {});
2373
2918
  },
2374
2919
  attrs: { async: "true" }
2375
2920
  };
@@ -2381,13 +2926,19 @@ function createGoogleTagManagerIntegration(config) {
2381
2926
  category: "analytics",
2382
2927
  src,
2383
2928
  cookies: ["_gcl_au"],
2929
+ bootstrap: () => {
2930
+ applyDefaultConsentMode(config.dataLayerName);
2931
+ },
2932
+ onConsentUpdate: ({ preferences }) => {
2933
+ applyConsentModeUpdate(preferences, config.dataLayerName);
2934
+ },
2384
2935
  init: () => {
2385
- if (typeof window !== "undefined") {
2936
+ if (globalThis.window !== void 0) {
2386
2937
  const dataLayerName = config.dataLayerName || "dataLayer";
2387
2938
  const w = window;
2388
2939
  const layer = w[dataLayerName] ?? [];
2389
2940
  w[dataLayerName] = layer;
2390
- layer.push({ "gtm.start": (/* @__PURE__ */ new Date()).getTime(), event: "gtm.js" });
2941
+ layer.push({ "gtm.start": Date.now(), event: "gtm.js" });
2391
2942
  }
2392
2943
  }
2393
2944
  };
@@ -2400,7 +2951,7 @@ function createUserWayIntegration(config) {
2400
2951
  src,
2401
2952
  cookies: ["_userway_*"],
2402
2953
  init: () => {
2403
- if (typeof window !== "undefined") {
2954
+ if (globalThis.window !== void 0) {
2404
2955
  const w = window;
2405
2956
  w.UserWayWidgetApp = w.UserWayWidgetApp || {};
2406
2957
  w.UserWayWidgetApp.accountId = config.accountId;
@@ -2422,7 +2973,7 @@ function createFacebookPixelIntegration(config) {
2422
2973
  src,
2423
2974
  cookies: ["_fbp", "fr"],
2424
2975
  init: () => {
2425
- if (typeof window !== "undefined") {
2976
+ if (globalThis.window !== void 0) {
2426
2977
  const w = window;
2427
2978
  if (!w.fbq) {
2428
2979
  const fbq = (...args) => {
@@ -2489,7 +3040,7 @@ function createHotjarIntegration(config) {
2489
3040
  }
2490
3041
  ],
2491
3042
  init: () => {
2492
- if (typeof window !== "undefined") {
3043
+ if (globalThis.window !== void 0) {
2493
3044
  const w = window;
2494
3045
  w._hjSettings = { hjid: config.siteId, hjsv: v };
2495
3046
  if (!w.hj) {
@@ -2522,7 +3073,7 @@ function createMixpanelIntegration(config) {
2522
3073
  }
2523
3074
  ],
2524
3075
  init: () => {
2525
- if (typeof window !== "undefined") {
3076
+ if (globalThis.window !== void 0) {
2526
3077
  const w = window;
2527
3078
  w.mixpanel = w.mixpanel || { init: () => void 0 };
2528
3079
  if (w.mixpanel && typeof w.mixpanel.init === "function") {
@@ -2546,7 +3097,7 @@ function createClarityIntegration(config) {
2546
3097
  src,
2547
3098
  cookies: ["_clck", "_clsk", "CLID", "ANONCHK", "MR", "MUID", "SM"],
2548
3099
  init: () => {
2549
- if (typeof window !== "undefined" && typeof config.upload !== "undefined") {
3100
+ if (globalThis.window !== void 0 && typeof config.upload !== "undefined") {
2550
3101
  const w = window;
2551
3102
  if (typeof w.clarity === "function") {
2552
3103
  try {
@@ -2569,7 +3120,7 @@ function createIntercomIntegration(config) {
2569
3120
  src,
2570
3121
  cookies: ["intercom-id-*", "intercom-session-*"],
2571
3122
  init: () => {
2572
- if (typeof window !== "undefined") {
3123
+ if (globalThis.window !== void 0) {
2573
3124
  const w = window;
2574
3125
  if (typeof w.Intercom === "function") {
2575
3126
  try {
@@ -2592,7 +3143,7 @@ function createZendeskChatIntegration(config) {
2592
3143
  src,
2593
3144
  cookies: ["__zlcmid", "_zendesk_shared_session"],
2594
3145
  init: () => {
2595
- if (typeof window !== "undefined") {
3146
+ if (globalThis.window !== void 0) {
2596
3147
  const w = window;
2597
3148
  if (typeof w.zE === "function") {
2598
3149
  try {
@@ -2656,6 +3207,68 @@ function suggestCategoryForScript(name) {
2656
3207
  return ["analytics"];
2657
3208
  }
2658
3209
 
3210
+ // src/utils/categoryPresets.ts
3211
+ var ANPD_CATEGORY_PRESETS = {
3212
+ necessary: {
3213
+ id: "necessary",
3214
+ name: "Necess\xE1rios",
3215
+ description: "Essenciais para funcionamento do site e seguran\xE7a. Sempre ativos.",
3216
+ essential: true,
3217
+ cookies: []
3218
+ },
3219
+ analytics: {
3220
+ id: "analytics",
3221
+ name: "Analytics",
3222
+ description: "Mede desempenho e uso para melhorar a experi\xEAncia.",
3223
+ essential: false,
3224
+ cookies: ["_ga", "_ga_*", "_gid"]
3225
+ },
3226
+ functional: {
3227
+ id: "functional",
3228
+ name: "Funcionais",
3229
+ description: "Habilitam recursos adicionais e prefer\xEAncias do usu\xE1rio.",
3230
+ essential: false,
3231
+ cookies: []
3232
+ },
3233
+ marketing: {
3234
+ id: "marketing",
3235
+ name: "Marketing",
3236
+ description: "Personaliza an\xFAncios e campanhas baseadas no seu perfil.",
3237
+ essential: false,
3238
+ cookies: ["_fbp", "fr"]
3239
+ },
3240
+ social: {
3241
+ id: "social",
3242
+ name: "Social",
3243
+ description: "Integra\xE7\xF5es sociais, compartilhamento e widgets de redes.",
3244
+ essential: false,
3245
+ cookies: []
3246
+ },
3247
+ personalization: {
3248
+ id: "personalization",
3249
+ name: "Personaliza\xE7\xE3o",
3250
+ description: "Personaliza conte\xFAdo e recomenda\xE7\xF5es.",
3251
+ essential: false,
3252
+ cookies: []
3253
+ }
3254
+ };
3255
+ function createAnpdCategoriesConfig(options = {}) {
3256
+ const include = options.include && options.include.length > 0 ? options.include : ["analytics", "functional", "marketing"];
3257
+ const enabledCategories = include.filter((cat) => cat !== "necessary");
3258
+ const customCategories = include.filter((cat) => cat === "necessary").map((cat) => {
3259
+ const base = ANPD_CATEGORY_PRESETS[cat];
3260
+ return {
3261
+ ...base,
3262
+ name: options.names?.[cat] ?? base.name,
3263
+ description: options.descriptions?.[cat] ?? base.description
3264
+ };
3265
+ });
3266
+ return {
3267
+ enabledCategories,
3268
+ customCategories: customCategories.length ? customCategories : void 0
3269
+ };
3270
+ }
3271
+
2659
3272
  // src/types/advancedTexts.ts
2660
3273
  var EXPANDED_DEFAULT_TEXTS = {
2661
3274
  // Textos adicionais
@@ -2867,6 +3480,7 @@ var TEXT_TEMPLATES = {
2867
3480
  }
2868
3481
  };
2869
3482
 
3483
+ exports.ANPD_CATEGORY_PRESETS = ANPD_CATEGORY_PRESETS;
2870
3484
  exports.COMMON_INTEGRATIONS = COMMON_INTEGRATIONS;
2871
3485
  exports.ConsentGate = ConsentGate;
2872
3486
  exports.ConsentProvider = ConsentProvider;
@@ -2884,7 +3498,9 @@ exports.autoConfigureCategories = autoConfigureCategories;
2884
3498
  exports.buildConsentStorageKey = buildConsentStorageKey;
2885
3499
  exports.categorizeDiscoveredCookies = categorizeDiscoveredCookies;
2886
3500
  exports.checkPeerDeps = checkPeerDeps;
3501
+ exports.createAnpdCategoriesConfig = createAnpdCategoriesConfig;
2887
3502
  exports.createClarityIntegration = createClarityIntegration;
3503
+ exports.createConsentAuditEntry = createConsentAuditEntry;
2888
3504
  exports.createCorporateIntegrations = createCorporateIntegrations;
2889
3505
  exports.createECommerceIntegrations = createECommerceIntegrations;
2890
3506
  exports.createFacebookPixelIntegration = createFacebookPixelIntegration;
@@ -2904,17 +3520,22 @@ exports.ensureNecessaryAlwaysOn = ensureNecessaryAlwaysOn;
2904
3520
  exports.extractCategoriesFromIntegrations = extractCategoriesFromIntegrations;
2905
3521
  exports.getAllProjectCategories = getAllProjectCategories;
2906
3522
  exports.getCookiesInfoForCategory = getCookiesInfoForCategory;
3523
+ exports.getPeerDepsLocale = getPeerDepsLocale;
2907
3524
  exports.loadScript = loadScript;
2908
3525
  exports.logDeveloperGuidance = logDeveloperGuidance;
2909
3526
  exports.logger = logger;
2910
3527
  exports.openPreferencesModal = openPreferencesModal;
2911
3528
  exports.pushConsentInitializedEvent = pushConsentInitializedEvent;
2912
3529
  exports.pushConsentUpdatedEvent = pushConsentUpdatedEvent;
3530
+ exports.registerScript = registerScript;
3531
+ exports.resetPeerDepsMessages = resetPeerDepsMessages;
2913
3532
  exports.resolveTexts = resolveTexts;
2914
3533
  exports.runPeerDepsCheck = runPeerDepsCheck;
2915
3534
  exports.setCookieCatalogOverrides = setCookieCatalogOverrides;
2916
3535
  exports.setCookieCategoryOverrides = setCookieCategoryOverrides;
2917
3536
  exports.setDebugLogging = setDebugLogging;
3537
+ exports.setPeerDepsLocale = setPeerDepsLocale;
3538
+ exports.setPeerDepsMessages = setPeerDepsMessages;
2918
3539
  exports.suggestCategoryForScript = suggestCategoryForScript;
2919
3540
  exports.useCategories = useCategories;
2920
3541
  exports.useCategoryStatus = useCategoryStatus;