@autobusal/providers 1.45.2 → 1.45.3
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/Setup/analytics.ts +58 -5
- package/package.json +1 -1
package/Setup/analytics.ts
CHANGED
|
@@ -132,20 +132,73 @@ const analytics = (container: string | null | undefined): void => {
|
|
|
132
132
|
|
|
133
133
|
if (accepted) {
|
|
134
134
|
start();
|
|
135
|
-
|
|
136
|
-
return;
|
|
137
135
|
}
|
|
138
136
|
|
|
139
|
-
|
|
137
|
+
/*
|
|
138
|
+
* Claude - 2026-09-25 (audit): consent can be WITHDRAWN. The listener used
|
|
139
|
+
* to be registered only when nothing was accepted at load, so a visitor
|
|
140
|
+
* who had accepted and later rejected from the card kept being measured
|
|
141
|
+
* for the rest of the visit (and their _ga/_clck cookies stayed). Now it
|
|
142
|
+
* is always registered (still once per page - `armed` above), and pushes a
|
|
143
|
+
* Consent Mode update only when the state actually changes, so repeated
|
|
144
|
+
* events never duplicate the dataLayer entries.
|
|
145
|
+
*/
|
|
146
|
+
let granted = accepted;
|
|
147
|
+
|
|
140
148
|
window.addEventListener(CONSENT_EVENT, (event: Event) => {
|
|
141
|
-
|
|
142
|
-
|
|
149
|
+
const choice = (event as CustomEvent<string>).detail;
|
|
150
|
+
|
|
151
|
+
if (choice === 'accepted') {
|
|
152
|
+
if (!granted) {
|
|
153
|
+
granted = true;
|
|
154
|
+
|
|
155
|
+
consentSignal('update', true);
|
|
156
|
+
}
|
|
143
157
|
|
|
144
158
|
start();
|
|
159
|
+
} else if (choice === 'rejected' && granted) {
|
|
160
|
+
granted = false;
|
|
161
|
+
|
|
162
|
+
// a loaded container cannot be unloaded; denied Consent Mode makes
|
|
163
|
+
// Google's tags stop storing and sending identifiers from here on
|
|
164
|
+
consentSignal('update', false);
|
|
165
|
+
|
|
166
|
+
expireAnalyticsCookies();
|
|
145
167
|
}
|
|
146
168
|
});
|
|
147
169
|
};
|
|
148
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Claude - 2026-09-25 (audit): drop the GA4 and Clarity cookies on rejection.
|
|
173
|
+
* They are set on the current host or on its registrable parent (GA's
|
|
174
|
+
* cookie_domain 'auto' picks the highest one it can write), so both are
|
|
175
|
+
* expired, with and without a leading dot, which is what a browser needs to
|
|
176
|
+
* match the cookie that was written.
|
|
177
|
+
*/
|
|
178
|
+
const ANALYTICS_COOKIE = /^(_ga|_ga_.+|_gid|_clck|_clsk)$/;
|
|
179
|
+
|
|
180
|
+
const expireAnalyticsCookies = (): void => {
|
|
181
|
+
const names = document.cookie
|
|
182
|
+
.split(';')
|
|
183
|
+
.map(pair => pair.split('=')[0].trim())
|
|
184
|
+
.filter(name => ANALYTICS_COOKIE.test(name));
|
|
185
|
+
|
|
186
|
+
if (names.length === 0) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const host = window.location.hostname;
|
|
191
|
+
const parts = host.split('.');
|
|
192
|
+
const parent = parts.length > 2 ? parts.slice(-2).join('.') : host;
|
|
193
|
+
const domains = Array.from(new Set([ '', host, `.${ host }`, parent, `.${ parent }` ]));
|
|
194
|
+
|
|
195
|
+
names.forEach(name => {
|
|
196
|
+
domains.forEach(domain => {
|
|
197
|
+
document.cookie = `${ name }=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/${ domain ? `; domain=${ domain }` : '' }`;
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
|
|
149
202
|
export const pageview = (path: string, title: string): void => {
|
|
150
203
|
window.dataLayer = window.dataLayer || [];
|
|
151
204
|
|