@react-lgpd-consent/core 0.7.0 → 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/CHANGELOG.md +205 -0
- package/README.md +16 -1
- package/dist/index.cjs +602 -154
- package/dist/index.d.cts +167 -13
- package/dist/index.d.ts +167 -13
- package/dist/index.js +598 -155
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -333,6 +333,7 @@ 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;
|
|
@@ -342,12 +343,31 @@ function buildConsentStorageKey(options) {
|
|
|
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
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
|
-
|
|
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 =
|
|
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
|
|
444
|
+
expires,
|
|
416
445
|
sameSite: o.sameSite,
|
|
417
446
|
secure: o.secure,
|
|
418
447
|
path: o.path,
|
|
@@ -446,14 +475,14 @@ function removeConsentCookie(opts) {
|
|
|
446
475
|
logger.debug("Cookie removal skipped: server-side environment");
|
|
447
476
|
return;
|
|
448
477
|
}
|
|
449
|
-
const o =
|
|
478
|
+
const o = resolveCookieOptions(opts);
|
|
450
479
|
logger.cookieOperation("delete", o.name);
|
|
451
480
|
Cookies__default.default.remove(o.name, { path: o.path, domain: o.domain });
|
|
452
481
|
logger.info("Consent cookie removed");
|
|
453
482
|
}
|
|
454
483
|
|
|
455
484
|
// src/utils/dataLayerEvents.ts
|
|
456
|
-
var LIBRARY_VERSION = "0.7.
|
|
485
|
+
var LIBRARY_VERSION = "0.7.1";
|
|
457
486
|
function ensureDataLayer() {
|
|
458
487
|
var _a;
|
|
459
488
|
if (globalThis.window === void 0) return;
|
|
@@ -466,7 +495,8 @@ function pushConsentInitializedEvent(categories) {
|
|
|
466
495
|
event: "consent_initialized",
|
|
467
496
|
consent_version: LIBRARY_VERSION,
|
|
468
497
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
469
|
-
categories
|
|
498
|
+
categories,
|
|
499
|
+
preferences: categories
|
|
470
500
|
};
|
|
471
501
|
globalThis.window.dataLayer?.push(event);
|
|
472
502
|
}
|
|
@@ -480,6 +510,7 @@ function pushConsentUpdatedEvent(categories, origin, previousCategories) {
|
|
|
480
510
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
481
511
|
origin,
|
|
482
512
|
categories,
|
|
513
|
+
preferences: categories,
|
|
483
514
|
changed_categories: changedCategories
|
|
484
515
|
};
|
|
485
516
|
globalThis.window.dataLayer?.push(event);
|
|
@@ -1089,58 +1120,8 @@ var GUIDANCE_PRESETS = {
|
|
|
1089
1120
|
};
|
|
1090
1121
|
|
|
1091
1122
|
// src/utils/peerDepsCheck.ts
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
try {
|
|
1095
|
-
const reactSymbols = Object.getOwnPropertySymbols(globalThis.window).map(String).filter((name) => name.includes("react"));
|
|
1096
|
-
if (reactSymbols.length > 1) {
|
|
1097
|
-
return true;
|
|
1098
|
-
}
|
|
1099
|
-
const ReactModule = window.React;
|
|
1100
|
-
if (ReactModule && Array.isArray(ReactModule)) {
|
|
1101
|
-
return true;
|
|
1102
|
-
}
|
|
1103
|
-
const hasMultipleVersions = window.__REACT_DEVTOOLS_GLOBAL_HOOK__?.renderers?.size > 1;
|
|
1104
|
-
return hasMultipleVersions || false;
|
|
1105
|
-
} catch {
|
|
1106
|
-
return false;
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
function getPackageVersion(packageName) {
|
|
1110
|
-
if (globalThis.window === void 0) return null;
|
|
1111
|
-
try {
|
|
1112
|
-
const pkg = window[packageName];
|
|
1113
|
-
if (pkg?.version) return pkg.version;
|
|
1114
|
-
const React6 = window.React;
|
|
1115
|
-
if (packageName === "react" && React6?.version) {
|
|
1116
|
-
return React6.version;
|
|
1117
|
-
}
|
|
1118
|
-
return null;
|
|
1119
|
-
} catch {
|
|
1120
|
-
return null;
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
function isVersionInRange(version, minMajor, maxMajor) {
|
|
1124
|
-
const major = Number.parseInt(version.split(".")[0], 10);
|
|
1125
|
-
return major >= minMajor && major <= maxMajor;
|
|
1126
|
-
}
|
|
1127
|
-
function checkPeerDeps(options = {}) {
|
|
1128
|
-
const { skipInProduction = true, logWarnings = true } = options;
|
|
1129
|
-
const result = {
|
|
1130
|
-
ok: true,
|
|
1131
|
-
warnings: [],
|
|
1132
|
-
errors: []
|
|
1133
|
-
};
|
|
1134
|
-
const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
1135
|
-
if (skipInProduction && isProduction) {
|
|
1136
|
-
return result;
|
|
1137
|
-
}
|
|
1138
|
-
if (globalThis.window === void 0) {
|
|
1139
|
-
return result;
|
|
1140
|
-
}
|
|
1141
|
-
if (detectMultipleReactInstances()) {
|
|
1142
|
-
result.ok = false;
|
|
1143
|
-
const errorMsg = `
|
|
1123
|
+
var MESSAGES_PT_BR = {
|
|
1124
|
+
MULTIPLE_REACT_INSTANCES: `
|
|
1144
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
|
|
1145
1126
|
\u2551 \u26A0\uFE0F ERRO: M\xFAltiplas inst\xE2ncias de React detectadas \u2551
|
|
1146
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
|
|
@@ -1202,22 +1183,13 @@ function checkPeerDeps(options = {}) {
|
|
|
1202
1183
|
https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#multiple-react-instances
|
|
1203
1184
|
|
|
1204
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
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
if (logWarnings) {
|
|
1208
|
-
console.error(errorMsg);
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
const reactVersion = getPackageVersion("react");
|
|
1212
|
-
if (reactVersion) {
|
|
1213
|
-
if (!isVersionInRange(reactVersion, 18, 19)) {
|
|
1214
|
-
result.ok = false;
|
|
1215
|
-
const errorMsg = `
|
|
1186
|
+
`,
|
|
1187
|
+
UNSUPPORTED_REACT_VERSION: (version) => `
|
|
1216
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
|
|
1217
1189
|
\u2551 \u26A0\uFE0F AVISO: Vers\xE3o do React n\xE3o suportada \u2551
|
|
1218
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
|
|
1219
1191
|
|
|
1220
|
-
\u{1F4E6} Vers\xE3o detectada: React ${
|
|
1192
|
+
\u{1F4E6} Vers\xE3o detectada: React ${version}
|
|
1221
1193
|
\u2705 Vers\xF5es suportadas: React 18.x ou 19.x
|
|
1222
1194
|
|
|
1223
1195
|
\u{1F50D} O react-lgpd-consent requer React 18.2.0+ ou React 19.x
|
|
@@ -1235,27 +1207,13 @@ function checkPeerDeps(options = {}) {
|
|
|
1235
1207
|
https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#react-version
|
|
1236
1208
|
|
|
1237
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
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
if (logWarnings) {
|
|
1241
|
-
console.error(errorMsg);
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
const muiVersion = window["@mui/material"]?.version;
|
|
1246
|
-
if (muiVersion) {
|
|
1247
|
-
if (!isVersionInRange(muiVersion, 5, 7)) {
|
|
1248
|
-
result.warnings.push(
|
|
1249
|
-
`MUI vers\xE3o ${muiVersion} detectada. Vers\xF5es suportadas: 5.15.0+, 6.x ou 7.x. Alguns componentes podem n\xE3o funcionar corretamente.`
|
|
1250
|
-
);
|
|
1251
|
-
if (logWarnings) {
|
|
1252
|
-
logger.warn(
|
|
1253
|
-
`
|
|
1210
|
+
`,
|
|
1211
|
+
UNSUPPORTED_MUI_VERSION: (version) => `
|
|
1254
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
|
|
1255
1213
|
\u2551 \u26A0\uFE0F AVISO: Vers\xE3o do Material-UI fora do range recomendado \u2551
|
|
1256
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
|
|
1257
1215
|
|
|
1258
|
-
\u{1F4E6} Vers\xE3o detectada: @mui/material ${
|
|
1216
|
+
\u{1F4E6} Vers\xE3o detectada: @mui/material ${version}
|
|
1259
1217
|
\u2705 Vers\xF5es suportadas: 5.15.0+, 6.x, 7.x
|
|
1260
1218
|
|
|
1261
1219
|
\u{1F50D} Componentes de UI (@react-lgpd-consent/mui) podem apresentar problemas.
|
|
@@ -1273,8 +1231,227 @@ function checkPeerDeps(options = {}) {
|
|
|
1273
1231
|
https://github.com/lucianoedipo/react-lgpd-consent/blob/main/TROUBLESHOOTING.md#mui-version
|
|
1274
1232
|
|
|
1275
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
|
|
1276
|
-
|
|
1277
|
-
|
|
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));
|
|
1278
1455
|
}
|
|
1279
1456
|
}
|
|
1280
1457
|
}
|
|
@@ -1730,6 +1907,13 @@ function ConsentProvider({
|
|
|
1730
1907
|
return base;
|
|
1731
1908
|
}, [cookieOpts, storage?.domain, storage?.namespace, storage?.version]);
|
|
1732
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]);
|
|
1733
1917
|
const finalCategoriesConfig = React4__namespace.useMemo(() => {
|
|
1734
1918
|
const isProd = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
1735
1919
|
if (!categories) return DEFAULT_PROJECT_CATEGORIES;
|
|
@@ -2092,51 +2276,99 @@ function ConsentGate(props) {
|
|
|
2092
2276
|
|
|
2093
2277
|
// src/utils/scriptLoader.ts
|
|
2094
2278
|
var LOADING_SCRIPTS = /* @__PURE__ */ new Map();
|
|
2095
|
-
|
|
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) {
|
|
2096
2314
|
if (typeof document === "undefined") return Promise.resolve();
|
|
2097
2315
|
if (document.getElementById(id)) return Promise.resolve();
|
|
2098
2316
|
const existingPromise = LOADING_SCRIPTS.get(id);
|
|
2099
2317
|
if (existingPromise) return existingPromise;
|
|
2318
|
+
const pollInterval = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL;
|
|
2319
|
+
const names = resolveCookieNames(options?.cookieName);
|
|
2320
|
+
const mergedAttrs = { ...attrs };
|
|
2100
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
|
+
}
|
|
2101
2361
|
const checkConsent = () => {
|
|
2102
|
-
const
|
|
2103
|
-
if (!
|
|
2104
|
-
setTimeout(checkConsent,
|
|
2362
|
+
const consent = parseConsentFromCookie(names);
|
|
2363
|
+
if (!consent) {
|
|
2364
|
+
setTimeout(checkConsent, pollInterval);
|
|
2105
2365
|
return;
|
|
2106
2366
|
}
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
setTimeout(checkConsent, 100);
|
|
2111
|
-
return;
|
|
2112
|
-
}
|
|
2113
|
-
if (category && !consent.preferences[category]) {
|
|
2114
|
-
setTimeout(checkConsent, 100);
|
|
2115
|
-
return;
|
|
2116
|
-
}
|
|
2117
|
-
const s = document.createElement("script");
|
|
2118
|
-
s.id = id;
|
|
2119
|
-
s.src = src;
|
|
2120
|
-
s.async = true;
|
|
2121
|
-
const mergedAttrs = { ...attrs };
|
|
2122
|
-
const scriptNonce = mergedAttrs.nonce || nonce;
|
|
2123
|
-
if (scriptNonce) {
|
|
2124
|
-
s.nonce = scriptNonce;
|
|
2125
|
-
mergedAttrs.nonce = scriptNonce;
|
|
2126
|
-
}
|
|
2127
|
-
for (const [k, v] of Object.entries(mergedAttrs)) s.setAttribute(k, v);
|
|
2128
|
-
s.onload = () => {
|
|
2129
|
-
LOADING_SCRIPTS.delete(id);
|
|
2130
|
-
resolve();
|
|
2131
|
-
};
|
|
2132
|
-
s.onerror = () => {
|
|
2133
|
-
LOADING_SCRIPTS.delete(id);
|
|
2134
|
-
reject(new Error(`Failed to load script: ${src}`));
|
|
2135
|
-
};
|
|
2136
|
-
document.body.appendChild(s);
|
|
2137
|
-
} catch {
|
|
2138
|
-
setTimeout(checkConsent, 100);
|
|
2367
|
+
if (!hasCategoryConsent(consent, category)) {
|
|
2368
|
+
setTimeout(checkConsent, pollInterval);
|
|
2369
|
+
return;
|
|
2139
2370
|
}
|
|
2371
|
+
inject();
|
|
2140
2372
|
};
|
|
2141
2373
|
checkConsent();
|
|
2142
2374
|
});
|
|
@@ -2300,14 +2532,107 @@ function validateNecessaryClassification(integrations, enabledCategories) {
|
|
|
2300
2532
|
}
|
|
2301
2533
|
|
|
2302
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
|
+
}
|
|
2303
2623
|
function ConsentScriptLoader({
|
|
2304
2624
|
integrations,
|
|
2305
2625
|
reloadOnChange = false,
|
|
2306
2626
|
nonce
|
|
2307
2627
|
}) {
|
|
2308
2628
|
const { preferences, consented } = useConsent();
|
|
2629
|
+
const isHydrated = useConsentHydration();
|
|
2309
2630
|
const categories = useCategories();
|
|
2310
|
-
const
|
|
2631
|
+
const [queueVersion, bumpQueueVersion] = React4__namespace.useState(0);
|
|
2632
|
+
React4__namespace.useEffect(() => {
|
|
2633
|
+
const unsubscribe = subscribeQueue(() => bumpQueueVersion((v) => v + 1));
|
|
2634
|
+
return unsubscribe;
|
|
2635
|
+
}, []);
|
|
2311
2636
|
React4__namespace.useEffect(() => {
|
|
2312
2637
|
try {
|
|
2313
2638
|
const ids = (integrations || []).map((i) => i.id);
|
|
@@ -2368,15 +2693,44 @@ function ConsentScriptLoader({
|
|
|
2368
2693
|
console.groupEnd();
|
|
2369
2694
|
}
|
|
2370
2695
|
}, [integrations, categories]);
|
|
2696
|
+
const processedIntegrationsRef = React4__namespace.useRef(/* @__PURE__ */ new Map());
|
|
2371
2697
|
React4__namespace.useEffect(() => {
|
|
2372
|
-
|
|
2373
|
-
const
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
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 } : {};
|
|
2380
2734
|
const scriptNonce = integration.nonce ?? nonce;
|
|
2381
2735
|
if (scriptNonce && !mergedAttrs.nonce) mergedAttrs.nonce = scriptNonce;
|
|
2382
2736
|
await loadScript(
|
|
@@ -2384,26 +2738,54 @@ function ConsentScriptLoader({
|
|
|
2384
2738
|
integration.src,
|
|
2385
2739
|
integration.category,
|
|
2386
2740
|
mergedAttrs,
|
|
2387
|
-
scriptNonce
|
|
2741
|
+
scriptNonce,
|
|
2742
|
+
{ skipConsentCheck: true }
|
|
2388
2743
|
);
|
|
2389
2744
|
if (integration.init) {
|
|
2390
2745
|
integration.init();
|
|
2391
2746
|
}
|
|
2392
|
-
loadedScripts.current.add(integration.id);
|
|
2393
|
-
} catch (error) {
|
|
2394
|
-
logger.error(`\u274C Failed to load script: ${integration.id}`, error);
|
|
2395
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`);
|
|
2396
2761
|
}
|
|
2397
2762
|
}
|
|
2398
|
-
}
|
|
2399
|
-
return () =>
|
|
2400
|
-
}, [
|
|
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]);
|
|
2401
2778
|
return null;
|
|
2402
2779
|
}
|
|
2403
2780
|
function useConsentScriptLoader() {
|
|
2404
2781
|
const { preferences, consented } = useConsent();
|
|
2782
|
+
const isHydrated = useConsentHydration();
|
|
2405
2783
|
return React4__namespace.useCallback(
|
|
2406
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
|
+
}
|
|
2407
2789
|
if (!consented) {
|
|
2408
2790
|
logger.warn(`\u26A0\uFE0F Cannot load script ${integration.id}: No consent given`);
|
|
2409
2791
|
return false;
|
|
@@ -2424,7 +2806,11 @@ function useConsentScriptLoader() {
|
|
|
2424
2806
|
integration.src,
|
|
2425
2807
|
integration.category,
|
|
2426
2808
|
mergedAttrs,
|
|
2427
|
-
scriptNonce
|
|
2809
|
+
scriptNonce,
|
|
2810
|
+
{
|
|
2811
|
+
consentSnapshot: { consented, preferences },
|
|
2812
|
+
skipConsentCheck: true
|
|
2813
|
+
}
|
|
2428
2814
|
);
|
|
2429
2815
|
if (integration.init) {
|
|
2430
2816
|
integration.init();
|
|
@@ -2435,11 +2821,62 @@ function useConsentScriptLoader() {
|
|
|
2435
2821
|
return false;
|
|
2436
2822
|
}
|
|
2437
2823
|
},
|
|
2438
|
-
[preferences, consented]
|
|
2824
|
+
[preferences, consented, isHydrated]
|
|
2439
2825
|
);
|
|
2440
2826
|
}
|
|
2441
2827
|
|
|
2442
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
|
+
}
|
|
2443
2880
|
function createGoogleAnalyticsIntegration(config) {
|
|
2444
2881
|
const src = config.scriptUrl ?? `https://www.googletagmanager.com/gtag/js?id=${config.measurementId}`;
|
|
2445
2882
|
return {
|
|
@@ -2467,17 +2904,17 @@ function createGoogleAnalyticsIntegration(config) {
|
|
|
2467
2904
|
provider: "Google Analytics"
|
|
2468
2905
|
}
|
|
2469
2906
|
],
|
|
2907
|
+
bootstrap: () => {
|
|
2908
|
+
applyDefaultConsentMode();
|
|
2909
|
+
},
|
|
2910
|
+
onConsentUpdate: ({ preferences }) => {
|
|
2911
|
+
applyConsentModeUpdate(preferences);
|
|
2912
|
+
},
|
|
2470
2913
|
init: () => {
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
w.dataLayer.push(...args);
|
|
2476
|
-
};
|
|
2477
|
-
w.gtag = gtag;
|
|
2478
|
-
gtag("js", /* @__PURE__ */ new Date());
|
|
2479
|
-
gtag("config", config.measurementId, config.config ?? {});
|
|
2480
|
-
}
|
|
2914
|
+
const gtag = ensureGtag();
|
|
2915
|
+
if (!gtag) return;
|
|
2916
|
+
gtag("js", /* @__PURE__ */ new Date());
|
|
2917
|
+
gtag("config", config.measurementId, config.config ?? {});
|
|
2481
2918
|
},
|
|
2482
2919
|
attrs: { async: "true" }
|
|
2483
2920
|
};
|
|
@@ -2489,6 +2926,12 @@ function createGoogleTagManagerIntegration(config) {
|
|
|
2489
2926
|
category: "analytics",
|
|
2490
2927
|
src,
|
|
2491
2928
|
cookies: ["_gcl_au"],
|
|
2929
|
+
bootstrap: () => {
|
|
2930
|
+
applyDefaultConsentMode(config.dataLayerName);
|
|
2931
|
+
},
|
|
2932
|
+
onConsentUpdate: ({ preferences }) => {
|
|
2933
|
+
applyConsentModeUpdate(preferences, config.dataLayerName);
|
|
2934
|
+
},
|
|
2492
2935
|
init: () => {
|
|
2493
2936
|
if (globalThis.window !== void 0) {
|
|
2494
2937
|
const dataLayerName = config.dataLayerName || "dataLayer";
|
|
@@ -3077,17 +3520,22 @@ exports.ensureNecessaryAlwaysOn = ensureNecessaryAlwaysOn;
|
|
|
3077
3520
|
exports.extractCategoriesFromIntegrations = extractCategoriesFromIntegrations;
|
|
3078
3521
|
exports.getAllProjectCategories = getAllProjectCategories;
|
|
3079
3522
|
exports.getCookiesInfoForCategory = getCookiesInfoForCategory;
|
|
3523
|
+
exports.getPeerDepsLocale = getPeerDepsLocale;
|
|
3080
3524
|
exports.loadScript = loadScript;
|
|
3081
3525
|
exports.logDeveloperGuidance = logDeveloperGuidance;
|
|
3082
3526
|
exports.logger = logger;
|
|
3083
3527
|
exports.openPreferencesModal = openPreferencesModal;
|
|
3084
3528
|
exports.pushConsentInitializedEvent = pushConsentInitializedEvent;
|
|
3085
3529
|
exports.pushConsentUpdatedEvent = pushConsentUpdatedEvent;
|
|
3530
|
+
exports.registerScript = registerScript;
|
|
3531
|
+
exports.resetPeerDepsMessages = resetPeerDepsMessages;
|
|
3086
3532
|
exports.resolveTexts = resolveTexts;
|
|
3087
3533
|
exports.runPeerDepsCheck = runPeerDepsCheck;
|
|
3088
3534
|
exports.setCookieCatalogOverrides = setCookieCatalogOverrides;
|
|
3089
3535
|
exports.setCookieCategoryOverrides = setCookieCategoryOverrides;
|
|
3090
3536
|
exports.setDebugLogging = setDebugLogging;
|
|
3537
|
+
exports.setPeerDepsLocale = setPeerDepsLocale;
|
|
3538
|
+
exports.setPeerDepsMessages = setPeerDepsMessages;
|
|
3091
3539
|
exports.suggestCategoryForScript = suggestCategoryForScript;
|
|
3092
3540
|
exports.useCategories = useCategories;
|
|
3093
3541
|
exports.useCategoryStatus = useCategoryStatus;
|