@ecomconsult/consentkit 0.5.8 → 0.5.9

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.
@@ -28,7 +28,7 @@ export function undecidedState() {
28
28
  */
29
29
  export function createStub() {
30
30
  const stub = {
31
- version: '0.5.8',
31
+ version: '0.5.9',
32
32
  config: {},
33
33
  init: function () { return undecidedState(); },
34
34
  allowed: function (cat) { return cat === 'necessary'; },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecomconsult/consentkit",
3
- "version": "0.5.8",
3
+ "version": "0.5.9",
4
4
  "description": "GDPR cookie consent core with blocking engine, Shadow DOM UI and Google Consent Mode v2. Zero dependencies, no build step.",
5
5
  "repository": {
6
6
  "type": "git",
package/src/ck-core.js CHANGED
@@ -46,7 +46,7 @@
46
46
  // Bare entries are used ONLY for domains dedicated entirely to tracking;
47
47
  // where a parent domain also serves ordinary site assets (CDNs, fonts,
48
48
  // images) the specific tracking subdomain is listed instead.
49
- // Snapshot: 2026-08. Not exhaustive — extended as new trackers appear.
49
+ // Snapshot: 2026-09. Not exhaustive — extended as new trackers appear.
50
50
  var HOST_DB = {
51
51
  // --- analytics -----------------------------------------------------
52
52
  'google-analytics.com': 'analytics',
@@ -77,6 +77,7 @@
77
77
  'nr-data.net': 'analytics', // New Relic beacon
78
78
  'datadoghq.com': 'analytics', // RUM
79
79
  'datadoghq-browser-agent.com': 'analytics',
80
+ 'vercel-insights.com': 'analytics', // Vercel Web Analytics
80
81
  // Cloudflare Web Analytics. Subdomain only, and deliberately NOT in
81
82
  // INFRA_DB: the rest of Cloudflare's edge is infrastructure, but this one
82
83
  // beacon is a measurement product (§8 names it by hand for that reason).
@@ -116,6 +117,15 @@
116
117
  'redditstatic.com': 'marketing',
117
118
  'q.quora.com': 'marketing', // subdomain: quora.com is a normal site
118
119
  'amazon-adsystem.com': 'marketing',
120
+ // Embedded video and social plugins. The player/plugin sets the vendor's own
121
+ // advertising cookies on play or render, which is an ad-profile decision the
122
+ // visitor has to make — not a feature the site owner merely switched on.
123
+ 'youtube.com': 'marketing', // the player sets Google ad cookies on play
124
+ 'youtube-nocookie.com': 'marketing', // "privacy-enhanced" still sets them once played
125
+ 'facebook.com': 'marketing', // like/page/comments plugins and iframes
126
+ 'instagram.com': 'marketing', // post and profile embeds
127
+ 'cdninstagram.com': 'marketing', // the embed's own asset host
128
+ 'sendpulse.com': 'marketing', // email/push marketing automation
119
129
 
120
130
  // --- functional ----------------------------------------------------
121
131
  'intercom.io': 'functional',
@@ -161,12 +171,72 @@
161
171
  'places.googleapis.com': 'functional',
162
172
  'maps.gstatic.com': 'functional',
163
173
 
174
+ // Vimeo — an embedded player. Unlike YouTube it does not feed an ad
175
+ // profile by default, so a visitor who declines functional loses the video
176
+ // and nothing else. player.vimeo.com is redundant under the bare entry
177
+ // (suffix matching covers it) and is named anyway, the way
178
+ // static.tildacdn.one and fonts.gstatic.com are: the embed fixtures and the
179
+ // docs both refer to it by its full host.
180
+ 'vimeo.com': 'functional',
181
+ 'player.vimeo.com': 'functional',
182
+ 'vimeocdn.com': 'functional', // the player's own asset host
183
+ // Freshworks — support chat and helpdesk widgets. The widget IS the support
184
+ // channel, so declining functional costs the visitor the feature, not a
185
+ // measurement they were unaware of.
186
+ 'freshworks.com': 'functional',
187
+ 'freshchat.com': 'functional',
188
+ 'freshdesk.com': 'functional',
189
+ // Messenger buttons and chat widgets a shop puts on its own pages. The
190
+ // Moldovan/Romanian market runs on these the way the western one runs on
191
+ // Intercom, and each is a feature the owner chose.
192
+ 'viber.com': 'functional',
193
+ 'telegram.org': 'functional',
194
+ 't.me': 'functional',
195
+ // CRM widgets: callback forms, chat and lead capture embedded on the site.
196
+ // Every regional TLD is named in full — hostMatches is plain suffix
197
+ // matching with no pattern form, so bitrix24.ru does not cover
198
+ // bitrix24.com.
199
+ 'bitrix24.ru': 'functional',
200
+ 'bitrix24.com': 'functional',
201
+ 'bitrix24.eu': 'functional',
202
+ 'amocrm.ru': 'functional',
203
+ 'amocrm.com': 'functional',
204
+ // Booking and form embeds — the visitor came to the page to use them.
205
+ 'calendly.com': 'functional',
206
+ 'typeform.com': 'functional',
207
+ // 999.md — the Moldovan classifieds platform. Shops embed its listing
208
+ // widgets; simpalsmedia.com is the group's asset host that serves them.
209
+ '999.md': 'functional',
210
+ 'simpalsmedia.com': 'functional',
211
+
164
212
  // --- necessary -----------------------------------------------------
165
213
  // recaptcha.net is Google's alternate reCAPTCHA domain, served for regions
166
214
  // where google.com is unreachable. Unlike the two path-scoped Google hosts
167
215
  // in PATH_DB, this domain hosts NOTHING but the captcha, so the whole host
168
216
  // is the right scope.
169
- 'recaptcha.net': 'necessary'
217
+ 'recaptcha.net': 'necessary',
218
+ // Payment, error reporting and the page builder's own runtime. A
219
+ // `necessary` category is never held — allowed('necessary') is always true,
220
+ // so shouldBlock() lets these through before strict mode is ever consulted.
221
+ // What the entry buys is a NAME: the audit stops filing a checkout form or
222
+ // a crash reporter under «сторонние подключения без категории». This is why
223
+ // js.stripe.com can stay in BASE_ALLOW and gain a category here without
224
+ // contradiction — the allowlist decides strict mode, the category decides
225
+ // the report, and both answers are «let it through».
226
+ 'sentry.io': 'necessary', // crash reporting: no visitor profile
227
+ 'ingest.sentry.io': 'necessary', // redundant under the line above, named
228
+ // because the DSN host is what an owner
229
+ // actually sees in a report
230
+ 'sentry-cdn.com': 'necessary',
231
+ 'paypal.com': 'necessary',
232
+ 'paypalobjects.com': 'necessary', // PayPal button assets
233
+ 'paynet.md': 'necessary', // Moldovan payment gateway
234
+ 'maib.md': 'necessary', // MAIB card processing
235
+ 'maibank.md': 'necessary',
236
+ 'stripe.com': 'necessary',
237
+ 'js.stripe.com': 'necessary', // also in BASE_ALLOW; see the note above
238
+ 'stripe.network': 'necessary',
239
+ 'elementor.com': 'necessary' // the WordPress builder's own runtime
170
240
  };
171
241
 
172
242
  // Runtime overrides fed in by ConsentKit._extendHostDb(map) — the SaaS
@@ -416,6 +486,20 @@
416
486
  // Google-hosted halves are path-scoped in BASE_ALLOW_PATH below, since
417
487
  // www.google.com and www.gstatic.com cannot be waved through wholesale.
418
488
  'hcaptcha.com',
489
+ // --- hosting platforms (continued) -----------------------------------
490
+ // Vercel and Netlify serve the site's own build output. Vercel's MEASUREMENT
491
+ // product is vercel-insights.com, a separate registrable domain filed above
492
+ // as analytics — so neither entry here shadows it (the §8 invariant that an
493
+ // infra host must carry no category still holds).
494
+ 'vercel.app',
495
+ 'vercel.com',
496
+ 'netlify.app',
497
+ 'netlify.com',
498
+ // YouTube thumbnails and player static assets. The PLAYER is marketing and
499
+ // sits in HOST_DB on youtube.com; this host serves only the poster image
500
+ // and sprites, sets nothing, and a held placeholder still wants its
501
+ // thumbnail.
502
+ 'ytimg.com',
419
503
  // --- our own service -------------------------------------------------
420
504
  // The consent tool must not report itself as an unnamed third party.
421
505
  'consent.ecomconsult.net'
@@ -1857,7 +1941,7 @@
1857
1941
  // Public API
1858
1942
  // ---------------------------------------------------------------------------
1859
1943
  var ConsentKit = {
1860
- version: '0.5.8',
1944
+ version: '0.5.9',
1861
1945
  config: config,
1862
1946
 
1863
1947
  init: function (userConfig) {
package/src/ck-debug.js CHANGED
@@ -173,7 +173,7 @@
173
173
  /* A `necessary` host is never held — allowed('necessary') is always true —
174
174
  so it appears in no `blocked` record, and every note below would be a
175
175
  lie about it: «раньше строки баннера» (we never wanted to hold it) or
176
- «Consent Mode: без cookie» (it is not a Consent Mode decision). §4 files
176
+ «Consent Mode: без cookie, но адрес…» (it is not a Consent Mode decision). §4 files
177
177
  necessary under `ok`, and §3's four notes have no slot for it, so it
178
178
  gets what an after-consent row gets: nothing. Sending the owner off to
179
179
  chase __cf_bm is exactly the noise §3 exists to remove. */
@@ -286,7 +286,7 @@
286
286
  // SPEC V1.12 §3 — пометка словами на каждой строке «до согласия»:
287
287
  // что именно случилось и можно ли было это остановить.
288
288
  whyEarly: 'раньше строки баннера — задержать не можем',
289
- whyGcm: 'Consent Mode: без cookie',
289
+ whyGcm: 'Consent Mode: без cookie, но адрес страницы и тип браузера уходят',
290
290
  whyHeld: 'задержан баннером',
291
291
  whyDead: 'не ожил после согласия — проверьте, что тег помечен type="text/plain"',
292
292
  cabinet: 'Что с этим делать — в кабинете',
@@ -352,7 +352,7 @@
352
352
  strict: 'strict',
353
353
  notRevived: ' — did not come back after consent',
354
354
  whyEarly: 'loaded before the banner line — we cannot hold it',
355
- whyGcm: 'Consent Mode: no cookies',
355
+ whyGcm: 'Consent Mode: no cookies, but the page address and browser type are sent',
356
356
  whyHeld: 'held back by the banner',
357
357
  whyDead: 'did not come back after consent — check the tag is marked type="text/plain"',
358
358
  cabinet: 'What to do about it — in your account',
@@ -423,7 +423,7 @@
423
423
  strict: 'strict',
424
424
  notRevived: ' — nu a repornit după consimțământ',
425
425
  whyEarly: 'încărcat înaintea liniei bannerului — nu îl putem opri',
426
- whyGcm: 'Consent Mode: fără cookie-uri',
426
+ whyGcm: 'Consent Mode: fără cookie, dar adresa paginii și tipul browserului pleacă',
427
427
  whyHeld: 'reținut de banner',
428
428
  whyDead: 'nu a repornit după consimțământ — verificați că eticheta are type="text/plain"',
429
429
  cabinet: 'Ce este de făcut — în contul dumneavoastră',
package/src/ck-ui.js CHANGED
@@ -440,9 +440,13 @@
440
440
  'border:1px solid var(--ck-line);border-radius:var(--ck-radius-card);overflow:hidden}',
441
441
  '.ck-panel__head{display:flex;align-items:flex-start;gap:16px;padding:22px 24px 14px;',
442
442
  'border-bottom:1px solid var(--ck-line)}',
443
+ // The text block takes the width and the close button sits at the padding
444
+ // edge, flush with the switches below it: without flex:1 the button
445
+ // followed the text's own wrapped width and floated short of the edge.
446
+ '.ck-panel__head>div{flex:1 1 auto;min-width:0}',
443
447
  '.ck-panel__head h2{margin:0 0 4px;font-size:18px;font-weight:600;letter-spacing:-.01em}',
444
448
  '.ck-panel__head p{margin:0;font-size:14px;color:var(--ck-muted)}',
445
- '.ck-x{flex:none;width:36px;height:36px;border-radius:var(--ck-radius-btn);border:1px solid var(--ck-line);',
449
+ '.ck-x{flex:none;margin-left:auto;width:36px;height:36px;border-radius:var(--ck-radius-btn);border:1px solid var(--ck-line);',
446
450
  'background:transparent;display:inline-flex;align-items:center;justify-content:center;color:var(--ck-muted)}',
447
451
  '.ck-panel__body{overflow:auto;padding:6px 24px 10px;-webkit-overflow-scrolling:touch}',
448
452
  '.ck-panel__foot{display:flex;gap:10px;flex-wrap:wrap;padding:16px 24px;',