@c15t/dev-tools 2.0.0-rc.1 → 2.0.0-rc.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +3 -3
  3. package/dist/__tests__/core/override-storage.test.d.ts +2 -0
  4. package/dist/__tests__/core/override-storage.test.d.ts.map +1 -0
  5. package/dist/__tests__/core/store-connector.test.d.ts +2 -0
  6. package/dist/__tests__/core/store-connector.test.d.ts.map +1 -0
  7. package/dist/__tests__/panels/events.test.d.ts +2 -0
  8. package/dist/__tests__/panels/events.test.d.ts.map +1 -0
  9. package/dist/__tests__/panels/iab.test.d.ts +2 -0
  10. package/dist/__tests__/panels/iab.test.d.ts.map +1 -0
  11. package/dist/__tests__/panels/scripts.test.d.ts +2 -0
  12. package/dist/__tests__/panels/scripts.test.d.ts.map +1 -0
  13. package/dist/__tests__/utils/preference-trigger.test.d.ts +2 -0
  14. package/dist/__tests__/utils/preference-trigger.test.d.ts.map +1 -0
  15. package/dist/components/panel.d.ts +1 -0
  16. package/dist/components/panel.d.ts.map +1 -1
  17. package/dist/core/devtools.d.ts.map +1 -1
  18. package/dist/core/override-storage.d.ts +7 -0
  19. package/dist/core/override-storage.d.ts.map +1 -0
  20. package/dist/core/panel-renderer.d.ts.map +1 -1
  21. package/dist/core/state-manager.d.ts +1 -1
  22. package/dist/core/state-manager.d.ts.map +1 -1
  23. package/dist/core/store-connector.d.ts +4 -0
  24. package/dist/core/store-connector.d.ts.map +1 -1
  25. package/dist/index.cjs +1092 -244
  26. package/dist/index.js +1092 -244
  27. package/dist/panels/dom-scanner.d.ts.map +1 -1
  28. package/dist/panels/events.d.ts.map +1 -1
  29. package/dist/panels/iab.d.ts +6 -0
  30. package/dist/panels/iab.d.ts.map +1 -1
  31. package/dist/panels/location.d.ts +9 -6
  32. package/dist/panels/location.d.ts.map +1 -1
  33. package/dist/panels/scripts.d.ts +2 -0
  34. package/dist/panels/scripts.d.ts.map +1 -1
  35. package/dist/react.cjs +1020 -239
  36. package/dist/react.d.ts +8 -7
  37. package/dist/react.d.ts.map +1 -1
  38. package/dist/react.js +1016 -238
  39. package/dist/tanstack.cjs +810 -201
  40. package/dist/tanstack.js +810 -201
  41. package/dist/utils/preference-trigger.d.ts +2 -2
  42. package/dist/utils/preference-trigger.d.ts.map +1 -1
  43. package/dist/version.d.ts +2 -0
  44. package/dist/version.d.ts.map +1 -0
  45. package/package.json +10 -8
package/dist/react.cjs CHANGED
@@ -346,22 +346,26 @@ var __webpack_modules__ = {
346
346
  justify-content: center;
347
347
  align-items: center;
348
348
  gap: var(--c15t-space-xs, .25rem);
349
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
350
349
  border: 1px solid var(--c15t-border, #e3e3e3);
351
350
  border-radius: var(--c15t-radius-md, .5rem);
352
351
  background-color: var(--c15t-surface, #fff);
352
+ min-height: 30px;
353
353
  color: var(--c15t-text, #171717);
354
354
  font-family: inherit;
355
- font-size: var(--c15t-devtools-font-size-xs, .75rem);
355
+ font-size: 12px;
356
356
  font-weight: var(--c15t-font-weight-medium, 500);
357
357
  cursor: pointer;
358
- transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
358
+ transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), box-shadow var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
359
+ padding: 5px 10px;
360
+ line-height: 1;
359
361
  display: inline-flex;
362
+ box-shadow: 0 1px 1px #0000000a;
360
363
  }
361
364
 
362
365
  .btn-evRVlh:hover {
363
366
  background-color: var(--c15t-surface-hover, #f7f7f7);
364
367
  border-color: var(--c15t-border-hover, #c9c9c9);
368
+ box-shadow: 0 2px 6px #00000014;
365
369
  }
366
370
 
367
371
  .btn-evRVlh:focus-visible {
@@ -369,9 +373,14 @@ var __webpack_modules__ = {
369
373
  outline-offset: 1px;
370
374
  }
371
375
 
376
+ .btn-evRVlh:active {
377
+ box-shadow: 0 1px 2px #00000014;
378
+ }
379
+
372
380
  .btn-evRVlh:disabled {
373
381
  opacity: .5;
374
382
  cursor: not-allowed;
383
+ box-shadow: none;
375
384
  }
376
385
 
377
386
  .btnPrimary-dA6nqY {
@@ -397,8 +406,10 @@ var __webpack_modules__ = {
397
406
  }
398
407
 
399
408
  .btnSmall-TjXoqZ {
400
- padding: 2px var(--c15t-space-xs, .25rem);
401
- font-size: 10px;
409
+ border-radius: var(--c15t-radius-sm, .375rem);
410
+ min-height: 26px;
411
+ padding: 3px 8px;
412
+ font-size: 11px;
402
413
  }
403
414
 
404
415
  .btnIcon-fiYQAh {
@@ -550,6 +561,50 @@ var __webpack_modules__ = {
550
561
  letter-spacing: .5px;
551
562
  }
552
563
 
564
+ .overrideField-keNdpJ {
565
+ flex-direction: column;
566
+ gap: 3px;
567
+ margin-bottom: 0;
568
+ display: flex;
569
+ }
570
+
571
+ .overrideLabel-ApMoTw {
572
+ color: var(--c15t-text-muted, #737373);
573
+ font-size: 11px;
574
+ font-weight: 600;
575
+ }
576
+
577
+ .overrideHint-yCfwGt {
578
+ color: var(--c15t-devtools-text-muted, #737373);
579
+ margin-top: 6px;
580
+ font-size: 11px;
581
+ }
582
+
583
+ .overrideActions-imdcn7 {
584
+ border-top: 1px dashed var(--c15t-border, #e3e3e3);
585
+ justify-content: space-between;
586
+ align-items: center;
587
+ gap: 8px;
588
+ margin-top: 8px;
589
+ padding-top: 8px;
590
+ display: flex;
591
+ }
592
+
593
+ .overrideActionButtons-gYOx1e {
594
+ flex-wrap: wrap;
595
+ gap: 6px;
596
+ display: flex;
597
+ }
598
+
599
+ .overrideStatus-sty_qS {
600
+ color: var(--c15t-text-muted, #737373);
601
+ font-size: 11px;
602
+ }
603
+
604
+ .overrideStatusDirty-OUdDMw {
605
+ color: var(--c15t-devtools-badge-warning, #f59f0a);
606
+ }
607
+
553
608
  .infoRow-RlB_0h {
554
609
  padding: var(--c15t-space-xs, .25rem) 0;
555
610
  justify-content: space-between;
@@ -642,6 +697,13 @@ var __webpack_modules__ = {
642
697
  section: "section-a197cB",
643
698
  sectionHeader: "sectionHeader-Xcljcw",
644
699
  sectionTitle: "sectionTitle-RUiFld",
700
+ overrideField: "overrideField-keNdpJ",
701
+ overrideLabel: "overrideLabel-ApMoTw",
702
+ overrideHint: "overrideHint-yCfwGt",
703
+ overrideActions: "overrideActions-imdcn7",
704
+ overrideActionButtons: "overrideActionButtons-gYOx1e",
705
+ overrideStatus: "overrideStatus-sty_qS",
706
+ overrideStatusDirty: "overrideStatusDirty-OUdDMw",
645
707
  infoRow: "infoRow-RlB_0h",
646
708
  infoLabel: "infoLabel-_pbK33",
647
709
  infoValue: "infoValue-flMl_e",
@@ -1124,16 +1186,23 @@ var __webpack_modules__ = {
1124
1186
  ___CSS_LOADER_EXPORT___.push([
1125
1187
  module.id,
1126
1188
  `.tabList-IyuiBE {
1189
+ align-items: center;
1127
1190
  gap: var(--c15t-space-xs, .25rem);
1128
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, 1rem);
1191
+ padding: var(--c15t-space-sm, .5rem) var(--c15t-space-sm, .5rem);
1129
1192
  border-bottom: 1px solid var(--c15t-border, #e3e3e3);
1130
1193
  background-color: var(--c15t-surface, #fff);
1131
1194
  scrollbar-width: none;
1132
1195
  -ms-overflow-style: none;
1196
+ scroll-padding-inline-end: var(--c15t-space-sm, .5rem);
1133
1197
  display: flex;
1134
1198
  overflow-x: auto;
1135
1199
  }
1136
1200
 
1201
+ .tabList-IyuiBE:after {
1202
+ content: "";
1203
+ flex: 0 0 var(--c15t-space-sm, .5rem);
1204
+ }
1205
+
1137
1206
  .tabList-IyuiBE::-webkit-scrollbar {
1138
1207
  display: none;
1139
1208
  }
@@ -1141,17 +1210,17 @@ var __webpack_modules__ = {
1141
1210
  .tab-yfDEqg {
1142
1211
  align-items: center;
1143
1212
  gap: var(--c15t-space-xs, .25rem);
1144
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
1145
1213
  border-radius: var(--c15t-radius-md, .5rem);
1146
1214
  color: var(--c15t-text-muted, #737373);
1147
1215
  font-family: inherit;
1148
- font-size: var(--c15t-devtools-font-size-xs, .75rem);
1216
+ font-size: 11px;
1149
1217
  font-weight: var(--c15t-font-weight-medium, 500);
1150
1218
  cursor: pointer;
1151
1219
  white-space: nowrap;
1152
1220
  transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1153
1221
  background-color: #0000;
1154
1222
  border: none;
1223
+ padding: 3px 7px;
1155
1224
  display: flex;
1156
1225
  }
1157
1226
 
@@ -1548,7 +1617,8 @@ var __webpack_exports__ = {};
1548
1617
  (()=>{
1549
1618
  __webpack_require__.r(__webpack_exports__);
1550
1619
  __webpack_require__.d(__webpack_exports__, {
1551
- C15TDevTools: ()=>C15TDevTools
1620
+ C15TDevTools: ()=>C15TDevTools,
1621
+ DevTools: ()=>C15TDevTools
1552
1622
  });
1553
1623
  const external_react_namespaceObject = require("react");
1554
1624
  const DEVTOOLS_STORAGE_KEY = 'c15t-devtools-position';
@@ -1883,9 +1953,9 @@ var __webpack_exports__ = {};
1883
1953
  const elements = getPreferenceTriggerElements();
1884
1954
  for (const el of elements)el.style.display = visible ? '' : 'none';
1885
1955
  }
1886
- function getPreferenceCenterOpener() {
1956
+ function getPreferenceCenterOpener(namespace = 'c15tStore') {
1887
1957
  const win = window;
1888
- const store = win.c15tStore;
1958
+ const store = win[namespace];
1889
1959
  if (store && 'function' == typeof store.getState) {
1890
1960
  const state = store.getState();
1891
1961
  if ('function' == typeof state.setActiveUI) return ()=>{
@@ -1894,6 +1964,7 @@ var __webpack_exports__ = {};
1894
1964
  }
1895
1965
  return null;
1896
1966
  }
1967
+ const version = '2.0.0-rc.3';
1897
1968
  const DEVTOOLS_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 446 445" aria-label="c15t">
1898
1969
  <path fill="currentColor" d="M223.178.313c39.064 0 70.732 31.668 70.732 70.732-.001 39.064-31.668 70.731-70.732 70.731-12.181 0-23.642-3.079-33.649-8.502l-55.689 55.689a70.267 70.267 0 0 1 5.574 13.441h167.531c8.695-29.217 35.762-50.523 67.804-50.523 39.064 0 70.731 31.668 70.731 70.732s-31.668 70.732-70.731 70.732c-32.042 0-59.108-21.306-67.803-50.523H139.413a70.417 70.417 0 0 1-7.888 17.396l54.046 54.046c10.893-6.851 23.786-10.815 37.605-10.815 39.064 0 70.732 31.669 70.732 70.733 0 39.064-31.668 70.731-70.732 70.731s-70.732-31.667-70.732-70.731c0-10.518 2.296-20.499 6.414-29.471l-57.78-57.78c-8.972 4.117-18.952 6.414-29.47 6.414-39.063 0-70.731-31.668-70.732-70.732 0-39.064 31.669-70.732 70.733-70.732 12.18 0 23.642 3.079 33.649 8.502l55.688-55.688c-5.423-10.007-8.502-21.469-8.502-33.65 0-39.064 31.668-70.733 70.732-70.733Zm0 343.555c-16.742 0-30.314 13.572-30.314 30.314 0 16.741 13.572 30.313 30.314 30.313s30.314-13.572 30.314-30.313c0-16.742-13.572-30.314-30.314-30.314ZM71.611 192.299c-16.742 0-30.315 13.572-30.315 30.314s13.573 30.314 30.315 30.314c16.741 0 30.313-13.572 30.313-30.314 0-16.741-13.572-30.314-30.313-30.314Zm303.138 0c-16.729 0-30.294 13.551-30.315 30.275l.001.039-.001.038c.021 16.725 13.586 30.276 30.315 30.276 16.741 0 30.313-13.572 30.313-30.314 0-16.741-13.572-30.314-30.313-30.314ZM223.178 40.73c-16.742 0-30.314 13.573-30.314 30.315s13.573 30.313 30.314 30.313c16.742 0 30.313-13.572 30.314-30.313 0-16.742-13.572-30.314-30.314-30.315Z"/>
1899
1970
  </svg>`;
@@ -2097,7 +2168,7 @@ var __webpack_exports__ = {};
2097
2168
  }
2098
2169
  }
2099
2170
  function createPanel(options) {
2100
- const { stateManager, storeConnector, onRenderContent, enableUnifiedMode = true } = options;
2171
+ const { stateManager, storeConnector, onRenderContent, namespace = 'c15tStore', enableUnifiedMode = true } = options;
2101
2172
  let removePortal = null;
2102
2173
  let isAnimatingOut = false;
2103
2174
  let draggable = null;
@@ -2126,7 +2197,7 @@ var __webpack_exports__ = {};
2126
2197
  return;
2127
2198
  }
2128
2199
  hasPreferenceTrigger = detectPreferenceTrigger();
2129
- const preferenceCenterOpener = getPreferenceCenterOpener();
2200
+ const preferenceCenterOpener = getPreferenceCenterOpener(namespace);
2130
2201
  useUnifiedMode = hasPreferenceTrigger && null !== preferenceCenterOpener;
2131
2202
  if (useUnifiedMode && !dropdownMenu) {
2132
2203
  dropdownMenu = createDropdownMenu({
@@ -2146,7 +2217,7 @@ var __webpack_exports__ = {};
2146
2217
  description: 'Open privacy settings',
2147
2218
  icon: PREFERENCES_ICON,
2148
2219
  onClick: ()=>{
2149
- const opener = getPreferenceCenterOpener();
2220
+ const opener = getPreferenceCenterOpener(namespace);
2150
2221
  if (opener) opener();
2151
2222
  }
2152
2223
  },
@@ -2202,6 +2273,7 @@ var __webpack_exports__ = {};
2202
2273
  let panelElement = null;
2203
2274
  let backdropElement = null;
2204
2275
  let contentContainer = null;
2276
+ let footerElement = null;
2205
2277
  function createPanelElement() {
2206
2278
  const corner = draggable?.getCorner() ?? stateManager.getState().position;
2207
2279
  const positionClass = getPositionClass(corner);
@@ -2253,33 +2325,53 @@ var __webpack_exports__ = {};
2253
2325
  contentContainer = renderer_div({
2254
2326
  className: styles_panel_module.content
2255
2327
  });
2256
- const isConnected = storeConnector.isConnected();
2257
- const footer = renderer_div({
2258
- className: styles_panel_module.footer,
2259
- children: [
2260
- renderer_div({
2261
- className: styles_panel_module.footerStatus,
2262
- children: [
2263
- span({
2264
- className: `${styles_panel_module.statusDot} ${isConnected ? styles_panel_module.statusConnected : styles_panel_module.statusDisconnected}`
2265
- }),
2266
- span({
2267
- text: isConnected ? 'Connected' : 'Disconnected'
2268
- })
2269
- ]
2270
- }),
2271
- span({
2272
- text: 'v1.8.3'
2273
- })
2274
- ]
2328
+ footerElement = renderer_div({
2329
+ className: styles_panel_module.footer
2275
2330
  });
2331
+ updateFooter();
2276
2332
  panel.appendChild(header);
2277
2333
  panel.appendChild(contentContainer);
2278
- panel.appendChild(footer);
2279
- if (isConnected) onRenderContent(contentContainer);
2334
+ panel.appendChild(footerElement);
2335
+ if (storeConnector.isConnected()) onRenderContent(contentContainer);
2280
2336
  else renderErrorState(contentContainer);
2281
2337
  return panel;
2282
2338
  }
2339
+ function updateFooter() {
2340
+ if (!footerElement) return;
2341
+ clearElement(footerElement);
2342
+ const isConnected = storeConnector.isConnected();
2343
+ const storeState = storeConnector.getState();
2344
+ const isLoading = storeState?.isLoadingConsentInfo ?? false;
2345
+ const statusChildren = [
2346
+ span({
2347
+ className: `${styles_panel_module.statusDot} ${isConnected ? styles_panel_module.statusConnected : styles_panel_module.statusDisconnected}`
2348
+ }),
2349
+ span({
2350
+ text: isConnected ? 'Connected' : 'Disconnected'
2351
+ })
2352
+ ];
2353
+ if (isLoading) statusChildren.push(span({
2354
+ style: {
2355
+ marginLeft: '4px',
2356
+ opacity: '0.7'
2357
+ },
2358
+ text: '\u00b7 Fetching /init\u2026'
2359
+ }));
2360
+ footerElement.appendChild(renderer_div({
2361
+ className: styles_panel_module.footerStatus,
2362
+ children: statusChildren
2363
+ }));
2364
+ if (!isConnected) footerElement.appendChild(renderer_button({
2365
+ className: styles_panel_module.closeButton,
2366
+ text: 'Retry',
2367
+ onClick: ()=>{
2368
+ storeConnector.retryConnection();
2369
+ }
2370
+ }));
2371
+ footerElement.appendChild(span({
2372
+ text: `v${version}`
2373
+ }));
2374
+ }
2283
2375
  function renderErrorState(container) {
2284
2376
  clearElement(container);
2285
2377
  const errorState = renderer_div({
@@ -2302,6 +2394,13 @@ var __webpack_exports__ = {};
2302
2394
  renderer_div({
2303
2395
  className: styles_panel_module.errorMessage,
2304
2396
  text: 'c15t consent manager is not initialized. Make sure you have set up the ConsentManagerProvider in your app.'
2397
+ }),
2398
+ renderer_button({
2399
+ className: styles_panel_module.closeButton,
2400
+ text: 'Retry Connection',
2401
+ onClick: ()=>{
2402
+ storeConnector.retryConnection();
2403
+ }
2305
2404
  })
2306
2405
  ]
2307
2406
  });
@@ -2337,6 +2436,7 @@ var __webpack_exports__ = {};
2337
2436
  panelElement = null;
2338
2437
  }
2339
2438
  contentContainer = null;
2439
+ footerElement = null;
2340
2440
  isAnimatingOut = false;
2341
2441
  floatingButton.style.display = '';
2342
2442
  stateManager.setOpen(false);
@@ -2355,6 +2455,7 @@ var __webpack_exports__ = {};
2355
2455
  update();
2356
2456
  });
2357
2457
  const unsubscribeStore = storeConnector.subscribe(()=>{
2458
+ updateFooter();
2358
2459
  if (contentContainer) if (storeConnector.isConnected()) onRenderContent(contentContainer);
2359
2460
  else renderErrorState(contentContainer);
2360
2461
  });
@@ -3010,13 +3111,13 @@ var __webpack_exports__ = {};
3010
3111
  },
3011
3112
  children: [
3012
3113
  createButton({
3013
- text: 'All',
3114
+ text: 'Accept',
3014
3115
  variant: 'primary',
3015
3116
  small: true,
3016
3117
  onClick: onAcceptAll
3017
3118
  }),
3018
3119
  createButton({
3019
- text: 'None',
3120
+ text: 'Reject',
3020
3121
  variant: 'default',
3021
3122
  small: true,
3022
3123
  onClick: onRejectAll
@@ -3064,16 +3165,22 @@ var __webpack_exports__ = {};
3064
3165
  function formatConsentName(name) {
3065
3166
  return name.replace(/_/g, ' ').replace(/\b\w/g, (l)=>l.toUpperCase());
3066
3167
  }
3168
+ let activeFilter = 'all';
3169
+ let selectedEventId = null;
3067
3170
  function events_renderEventsPanel(container, options) {
3068
3171
  const { getEvents, onClear } = options;
3069
3172
  clearElement(container);
3070
- const events = getEvents();
3173
+ const allEvents = getEvents();
3174
+ const events = allEvents.filter((event)=>matchesFilter(event, activeFilter));
3175
+ if (!events.some((event)=>event.id === selectedEventId)) selectedEventId = events[0]?.id ?? null;
3176
+ const selectedEvent = events.find((event)=>event.id === selectedEventId) ?? null;
3071
3177
  const header = renderer_div({
3072
3178
  style: {
3073
3179
  display: 'flex',
3074
3180
  alignItems: 'center',
3075
3181
  justifyContent: 'space-between',
3076
- padding: '12px 16px 8px'
3182
+ padding: '12px 16px 8px',
3183
+ gap: '8px'
3077
3184
  },
3078
3185
  children: [
3079
3186
  span({
@@ -3084,44 +3191,130 @@ var __webpack_exports__ = {};
3084
3191
  textTransform: 'uppercase',
3085
3192
  letterSpacing: '0.5px'
3086
3193
  },
3087
- text: `Events (${events.length})`
3194
+ text: `Events (${events.length}/${allEvents.length})`
3088
3195
  }),
3089
- createButton({
3090
- text: 'Clear',
3091
- small: true,
3092
- onClick: onClear
3196
+ renderer_div({
3197
+ style: {
3198
+ display: 'flex',
3199
+ gap: '6px'
3200
+ },
3201
+ children: [
3202
+ createButton({
3203
+ text: 'Export',
3204
+ small: true,
3205
+ onClick: ()=>exportEvents(allEvents)
3206
+ }),
3207
+ createButton({
3208
+ text: 'Clear',
3209
+ small: true,
3210
+ onClick: ()=>{
3211
+ onClear();
3212
+ selectedEventId = null;
3213
+ events_renderEventsPanel(container, options);
3214
+ }
3215
+ })
3216
+ ]
3093
3217
  })
3094
3218
  ]
3095
3219
  });
3096
3220
  container.appendChild(header);
3221
+ container.appendChild(renderer_div({
3222
+ style: {
3223
+ display: 'flex',
3224
+ flexWrap: 'wrap',
3225
+ gap: '6px',
3226
+ padding: '0 16px 8px'
3227
+ },
3228
+ children: EVENT_FILTERS.map((filter)=>createFilterButton(filter, filter === activeFilter, ()=>{
3229
+ activeFilter = filter;
3230
+ selectedEventId = null;
3231
+ events_renderEventsPanel(container, options);
3232
+ }))
3233
+ }));
3097
3234
  const eventList = renderer_div({
3098
3235
  style: {
3099
3236
  display: 'flex',
3100
3237
  flexDirection: 'column',
3101
3238
  gap: '4px',
3102
3239
  padding: '0 12px 12px',
3103
- maxHeight: '400px',
3240
+ maxHeight: '300px',
3104
3241
  overflowY: 'auto'
3105
3242
  }
3106
3243
  });
3107
- if (0 === events.length) {
3108
- const emptyState = renderer_div({
3109
- style: {
3110
- padding: '32px 16px',
3111
- textAlign: 'center',
3112
- color: 'var(--c15t-text-muted)',
3113
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3114
- },
3115
- text: 'No events recorded yet'
3116
- });
3117
- eventList.appendChild(emptyState);
3118
- } else for (const event of events){
3119
- const eventItem = createEventItem(event);
3120
- eventList.appendChild(eventItem);
3121
- }
3244
+ if (0 === events.length) eventList.appendChild(renderer_div({
3245
+ style: {
3246
+ padding: '20px 16px',
3247
+ textAlign: 'center',
3248
+ color: 'var(--c15t-text-muted)',
3249
+ fontSize: 'var(--c15t-devtools-font-size-sm)'
3250
+ },
3251
+ text: 'No events match this filter'
3252
+ }));
3253
+ else for (const event of events)eventList.appendChild(createEventItem(event, event.id === selectedEventId, ()=>{
3254
+ selectedEventId = event.id;
3255
+ events_renderEventsPanel(container, options);
3256
+ }));
3122
3257
  container.appendChild(eventList);
3258
+ container.appendChild(createPayloadSection(selectedEvent));
3259
+ }
3260
+ const EVENT_FILTERS = [
3261
+ 'all',
3262
+ 'error',
3263
+ 'consent',
3264
+ 'network',
3265
+ 'iab'
3266
+ ];
3267
+ function createFilterButton(filter, active, onClick) {
3268
+ return createButton({
3269
+ text: filter.toUpperCase(),
3270
+ small: true,
3271
+ variant: active ? 'primary' : 'default',
3272
+ onClick
3273
+ });
3274
+ }
3275
+ function matchesFilter(event, filter) {
3276
+ if ('all' === filter) return true;
3277
+ if ('error' === filter) return 'error' === event.type;
3278
+ if ('consent' === filter) return 'consent_set' === event.type || 'consent_save' === event.type || 'consent_reset' === event.type;
3279
+ if ('network' === filter) return 'network' === event.type;
3280
+ return 'iab' === event.type;
3281
+ }
3282
+ function createPayloadSection(event) {
3283
+ const payload = event?.data ? JSON.stringify(event.data, null, 2) : null;
3284
+ return renderer_div({
3285
+ style: {
3286
+ padding: '0 12px 12px'
3287
+ },
3288
+ children: [
3289
+ renderer_div({
3290
+ style: {
3291
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
3292
+ fontWeight: '600',
3293
+ color: 'var(--c15t-text-muted)',
3294
+ textTransform: 'uppercase',
3295
+ letterSpacing: '0.5px',
3296
+ marginBottom: '6px'
3297
+ },
3298
+ text: 'Payload'
3299
+ }),
3300
+ renderer_div({
3301
+ className: styles_components_module.gridCard ?? '',
3302
+ style: {
3303
+ padding: '8px',
3304
+ fontFamily: 'ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace',
3305
+ fontSize: '11px',
3306
+ color: 'var(--c15t-text-muted)',
3307
+ maxHeight: '140px',
3308
+ overflowY: 'auto',
3309
+ whiteSpace: 'pre-wrap',
3310
+ wordBreak: 'break-word'
3311
+ },
3312
+ text: payload || 'Select an event with payload data'
3313
+ })
3314
+ ]
3315
+ });
3123
3316
  }
3124
- function createEventItem(event) {
3317
+ function createEventItem(event, selected, onSelect) {
3125
3318
  const time = formatTime(event.timestamp);
3126
3319
  const icon = getEventIcon(event.type);
3127
3320
  const color = getEventColor(event.type);
@@ -3132,8 +3325,11 @@ var __webpack_exports__ = {};
3132
3325
  alignItems: 'center',
3133
3326
  gap: '8px',
3134
3327
  padding: '6px 10px',
3135
- fontSize: 'var(--c15t-devtools-font-size-xs)'
3328
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
3329
+ cursor: 'pointer',
3330
+ borderColor: selected ? 'var(--c15t-devtools-badge-info, #3b82f6)' : 'var(--c15t-border)'
3136
3331
  },
3332
+ onClick: onSelect,
3137
3333
  children: [
3138
3334
  span({
3139
3335
  style: {
@@ -3162,6 +3358,21 @@ var __webpack_exports__ = {};
3162
3358
  ]
3163
3359
  });
3164
3360
  }
3361
+ function exportEvents(events) {
3362
+ const json = JSON.stringify(events, null, 2);
3363
+ const blob = new Blob([
3364
+ json
3365
+ ], {
3366
+ type: 'application/json'
3367
+ });
3368
+ const url = URL.createObjectURL(blob);
3369
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
3370
+ const a = document.createElement('a');
3371
+ a.href = url;
3372
+ a.download = `c15t-events-${timestamp}.json`;
3373
+ a.click();
3374
+ URL.revokeObjectURL(url);
3375
+ }
3165
3376
  function formatTime(timestamp) {
3166
3377
  const date = new Date(timestamp);
3167
3378
  return date.toLocaleTimeString('en-US', {
@@ -3180,7 +3391,10 @@ var __webpack_exports__ = {};
3180
3391
  return '○';
3181
3392
  case 'error':
3182
3393
  return '✕';
3183
- case 'info':
3394
+ case 'network':
3395
+ return '◉';
3396
+ case 'iab':
3397
+ return '◆';
3184
3398
  default:
3185
3399
  return '○';
3186
3400
  }
@@ -3194,13 +3408,16 @@ var __webpack_exports__ = {};
3194
3408
  return 'var(--c15t-devtools-badge-warning, #f59e0b)';
3195
3409
  case 'error':
3196
3410
  return 'var(--c15t-devtools-badge-error, #ef4444)';
3197
- case 'info':
3411
+ case 'network':
3412
+ return 'var(--c15t-devtools-badge-warning, #f59e0b)';
3413
+ case 'iab':
3414
+ return 'var(--c15t-devtools-badge-info, #3b82f6)';
3198
3415
  default:
3199
3416
  return 'var(--c15t-text-muted)';
3200
3417
  }
3201
3418
  }
3202
3419
  function iab_renderIabPanel(container, options) {
3203
- const { getState, onReset } = options;
3420
+ const { getState, onSetPurposeConsent, onSetVendorConsent, onSetSpecialFeatureOptIn, onAcceptAll, onRejectAll, onSave, onReset } = options;
3204
3421
  clearElement(container);
3205
3422
  const state = getState();
3206
3423
  if (!state) return void container.appendChild(renderer_div({
@@ -3278,7 +3495,9 @@ var __webpack_exports__ = {};
3278
3495
  for (const [purposeId, consent] of purposeEntries){
3279
3496
  const purposeInfo = purposes[purposeId];
3280
3497
  const purposeName = purposeInfo?.name || `Purpose ${purposeId}`;
3281
- purposeList.appendChild(createPurposeRow(purposeId, purposeName, Boolean(consent)));
3498
+ purposeList.appendChild(createPurposeRow(purposeId, purposeName, Boolean(consent), (value)=>{
3499
+ onSetPurposeConsent(Number(purposeId), value);
3500
+ }));
3282
3501
  }
3283
3502
  const purposesSection = createSection({
3284
3503
  title: `Purposes (${purposeEntries.length})`,
@@ -3304,7 +3523,9 @@ var __webpack_exports__ = {};
3304
3523
  for (const [featureId, optIn] of specialFeatureEntries){
3305
3524
  const featureInfo = specialFeatures[featureId];
3306
3525
  const featureName = featureInfo?.name || `Special Feature ${featureId}`;
3307
- specialFeatureList.appendChild(createPurposeRow(featureId, featureName, Boolean(optIn)));
3526
+ specialFeatureList.appendChild(createPurposeRow(featureId, featureName, Boolean(optIn), (value)=>{
3527
+ onSetSpecialFeatureOptIn(Number(featureId), value);
3528
+ }, 'feature'));
3308
3529
  }
3309
3530
  const specialFeaturesSection = createSection({
3310
3531
  title: `Special Features (${specialFeatureEntries.length})`,
@@ -3344,7 +3565,9 @@ var __webpack_exports__ = {};
3344
3565
  overflowY: 'auto'
3345
3566
  }
3346
3567
  });
3347
- for (const [vendorId, consent, vendorName] of iabVendors)vendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'iab'));
3568
+ for (const [vendorId, consent, vendorName] of iabVendors)vendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'iab', (value)=>{
3569
+ onSetVendorConsent(Number(vendorId), value);
3570
+ }));
3348
3571
  const vendorsSection = createSection({
3349
3572
  title: `IAB Vendors (${iabVendors.length})`,
3350
3573
  children: [
@@ -3363,7 +3586,9 @@ var __webpack_exports__ = {};
3363
3586
  overflowY: 'auto'
3364
3587
  }
3365
3588
  });
3366
- for (const [vendorId, consent, vendorName] of customVendors)customVendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'custom'));
3589
+ for (const [vendorId, consent, vendorName] of customVendors)customVendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'custom', (value)=>{
3590
+ onSetVendorConsent(vendorId, value);
3591
+ }));
3367
3592
  const customVendorsSection = createSection({
3368
3593
  title: `Custom Vendors (${customVendors.length})`,
3369
3594
  children: [
@@ -3385,15 +3610,40 @@ var __webpack_exports__ = {};
3385
3610
  style: {
3386
3611
  display: 'flex',
3387
3612
  alignItems: 'center',
3388
- justifyContent: 'flex-end',
3613
+ justifyContent: 'space-between',
3389
3614
  padding: '12px 16px',
3390
3615
  marginTop: 'auto',
3391
3616
  borderTop: '1px solid var(--c15t-border)',
3392
3617
  backgroundColor: 'var(--c15t-surface)'
3393
3618
  },
3394
3619
  children: [
3620
+ renderer_div({
3621
+ style: {
3622
+ display: 'flex',
3623
+ gap: '6px'
3624
+ },
3625
+ children: [
3626
+ createButton({
3627
+ text: 'Accept All',
3628
+ variant: 'primary',
3629
+ small: true,
3630
+ onClick: onAcceptAll
3631
+ }),
3632
+ createButton({
3633
+ text: 'Reject All',
3634
+ small: true,
3635
+ onClick: onRejectAll
3636
+ }),
3637
+ createButton({
3638
+ text: 'Save',
3639
+ variant: 'primary',
3640
+ small: true,
3641
+ onClick: onSave
3642
+ })
3643
+ ]
3644
+ }),
3395
3645
  createButton({
3396
- text: 'Reset All',
3646
+ text: 'Reset',
3397
3647
  variant: 'danger',
3398
3648
  small: true,
3399
3649
  onClick: onReset
@@ -3402,7 +3652,7 @@ var __webpack_exports__ = {};
3402
3652
  });
3403
3653
  container.appendChild(footer);
3404
3654
  }
3405
- function createPurposeRow(id, name, consent) {
3655
+ function createPurposeRow(id, name, consent, onChange, ariaKind = 'purpose') {
3406
3656
  return renderer_div({
3407
3657
  style: {
3408
3658
  display: 'flex',
@@ -3425,14 +3675,28 @@ var __webpack_exports__ = {};
3425
3675
  text: `${id}. ${name}`,
3426
3676
  title: name
3427
3677
  }),
3428
- createBadge({
3429
- text: consent ? '✓' : '✕',
3430
- variant: consent ? 'success' : 'error'
3678
+ renderer_div({
3679
+ style: {
3680
+ display: 'flex',
3681
+ alignItems: 'center',
3682
+ gap: '6px'
3683
+ },
3684
+ children: [
3685
+ createBadge({
3686
+ text: consent ? '✓' : '✕',
3687
+ variant: consent ? 'success' : 'error'
3688
+ }),
3689
+ createToggle({
3690
+ checked: consent,
3691
+ onChange,
3692
+ ariaLabel: `Toggle ${ariaKind} ${id}`
3693
+ })
3694
+ ]
3431
3695
  })
3432
3696
  ]
3433
3697
  });
3434
3698
  }
3435
- function createVendorRow(id, name, consent, type) {
3699
+ function createVendorRow(id, name, consent, type, onChange) {
3436
3700
  return renderer_div({
3437
3701
  style: {
3438
3702
  display: 'flex',
@@ -3479,16 +3743,21 @@ var __webpack_exports__ = {};
3479
3743
  createBadge({
3480
3744
  text: consent ? '✓' : '✕',
3481
3745
  variant: consent ? 'success' : 'error'
3746
+ }),
3747
+ createToggle({
3748
+ checked: consent,
3749
+ onChange,
3750
+ ariaLabel: `Toggle vendor ${id}`
3482
3751
  })
3483
3752
  ]
3484
3753
  });
3485
3754
  }
3486
3755
  function truncateText(text, maxLength) {
3487
3756
  if (text.length <= maxLength) return text;
3488
- return text.slice(0, maxLength - 3) + '...';
3757
+ return `${text.slice(0, maxLength - 3)}...`;
3489
3758
  }
3490
3759
  function location_renderLocationPanel(container, options) {
3491
- const { getState, onSetOverrides, onClearOverrides } = options;
3760
+ const { getState, onApplyOverrides, onClearOverrides } = options;
3492
3761
  clearElement(container);
3493
3762
  const state = getState();
3494
3763
  if (!state) return void container.appendChild(renderer_div({
@@ -3509,145 +3778,230 @@ var __webpack_exports__ = {};
3509
3778
  createCompactInfoCard('Jurisdiction', locationInfo?.jurisdiction || '—'),
3510
3779
  createCompactInfoCard('Language', translationConfig?.defaultLanguage || '—')
3511
3780
  ];
3781
+ gridItems.push(createCompactInfoCard('GPC', getEffectiveGpcLabel(overrides?.gpc)));
3512
3782
  if (state.model) gridItems.push(createCompactInfoCard('Model', getModelLabel(state.model)));
3513
3783
  const locationGrid = createGrid({
3514
- columns: 2,
3784
+ columns: 3,
3515
3785
  children: gridItems
3516
3786
  });
3517
3787
  container.appendChild(locationGrid);
3788
+ const initialDraft = getDraftFromOverrides(overrides);
3789
+ let appliedOverrides = normalizeOverrideDraft(initialDraft);
3790
+ let isSubmitting = false;
3791
+ const countryField = createOverrideSelect({
3792
+ label: 'Country',
3793
+ selectOptions: COUNTRY_OPTIONS,
3794
+ value: initialDraft.country
3795
+ });
3796
+ const regionField = createOverrideInput({
3797
+ label: 'Region',
3798
+ placeholder: 'e.g., CA, NY, BE',
3799
+ value: initialDraft.region
3800
+ });
3801
+ const languageField = createOverrideInput({
3802
+ label: 'Language',
3803
+ placeholder: 'e.g., de, fr, en-US',
3804
+ value: initialDraft.language
3805
+ });
3806
+ const gpcField = createOverrideSelect({
3807
+ label: 'GPC',
3808
+ selectOptions: GPC_OPTIONS,
3809
+ value: initialDraft.gpc
3810
+ });
3811
+ const formStatus = span({
3812
+ className: styles_components_module.overrideStatus,
3813
+ text: 'In sync'
3814
+ });
3815
+ const applyButton = createButton({
3816
+ text: 'Apply',
3817
+ variant: 'primary',
3818
+ small: true,
3819
+ disabled: true,
3820
+ onClick: ()=>{
3821
+ applyDraft();
3822
+ }
3823
+ });
3824
+ const revertButton = createButton({
3825
+ text: 'Revert',
3826
+ small: true,
3827
+ disabled: true,
3828
+ onClick: ()=>{
3829
+ setDraftValues(getDraftFromOverrides(appliedOverrides));
3830
+ updateFormState();
3831
+ }
3832
+ });
3833
+ const clearButton = createButton({
3834
+ text: 'Clear',
3835
+ small: true,
3836
+ onClick: ()=>{
3837
+ clearDraftAndOverrides();
3838
+ }
3839
+ });
3840
+ const overrideFieldsGrid = renderer_div({
3841
+ style: {
3842
+ display: 'grid',
3843
+ gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
3844
+ gap: '8px 10px'
3845
+ },
3846
+ children: [
3847
+ countryField.element,
3848
+ regionField.element,
3849
+ languageField.element,
3850
+ gpcField.element
3851
+ ]
3852
+ });
3518
3853
  const overrideSection = createSection({
3519
3854
  title: 'Override Settings',
3520
- actions: [
3521
- createButton({
3522
- text: 'Clear',
3523
- small: true,
3524
- onClick: onClearOverrides
3525
- })
3526
- ],
3527
3855
  children: [
3528
- createOverrideSelect({
3529
- label: 'Country',
3530
- selectOptions: COUNTRY_OPTIONS,
3531
- value: overrides?.country || '',
3532
- onChange: (value)=>onSetOverrides({
3533
- country: value || void 0
3534
- })
3535
- }),
3536
- createOverrideInput({
3537
- label: 'Region',
3538
- placeholder: 'e.g., CA, NY, BE',
3539
- value: overrides?.region || '',
3540
- onChange: (value)=>onSetOverrides({
3541
- region: value || void 0
3542
- })
3856
+ overrideFieldsGrid,
3857
+ span({
3858
+ className: styles_components_module.overrideHint,
3859
+ text: 'GPC override only affects opt-out or unregulated jurisdictions.'
3543
3860
  }),
3544
- createOverrideInput({
3545
- label: 'Language',
3546
- placeholder: 'e.g., de, fr, en',
3547
- value: overrides?.language || '',
3548
- onChange: (value)=>onSetOverrides({
3549
- language: value || void 0
3550
- })
3861
+ renderer_div({
3862
+ className: styles_components_module.overrideActions,
3863
+ children: [
3864
+ renderer_div({
3865
+ className: styles_components_module.overrideActionButtons,
3866
+ children: [
3867
+ revertButton,
3868
+ applyButton,
3869
+ clearButton
3870
+ ]
3871
+ }),
3872
+ formStatus
3873
+ ]
3551
3874
  })
3552
3875
  ]
3553
3876
  });
3554
3877
  container.appendChild(overrideSection);
3555
- const hasOverrides = overrides && (overrides.country || overrides.region || overrides.language);
3556
- if (hasOverrides) {
3557
- const overrideBanner = renderer_div({
3558
- style: {
3559
- padding: '8px 16px',
3560
- backgroundColor: 'var(--c15t-devtools-badge-info-bg)',
3561
- color: 'var(--c15t-devtools-badge-info)',
3562
- fontSize: 'var(--c15t-devtools-font-size-xs)',
3563
- borderTop: '1px solid var(--c15t-devtools-border)'
3564
- },
3565
- text: 'Overrides are active. This may affect consent behavior.'
3878
+ countryField.control.addEventListener('change', updateFormState);
3879
+ regionField.control.addEventListener('input', updateFormState);
3880
+ languageField.control.addEventListener('input', updateFormState);
3881
+ gpcField.control.addEventListener('change', updateFormState);
3882
+ updateFormState();
3883
+ async function applyDraft() {
3884
+ if (isSubmitting) return;
3885
+ const draftOverrides = getDraftOverrides();
3886
+ if (overridesEqual(draftOverrides, appliedOverrides)) return;
3887
+ isSubmitting = true;
3888
+ updateFormState();
3889
+ try {
3890
+ await onApplyOverrides(draftOverrides);
3891
+ appliedOverrides = draftOverrides;
3892
+ } finally{
3893
+ isSubmitting = false;
3894
+ updateFormState();
3895
+ }
3896
+ }
3897
+ async function clearDraftAndOverrides() {
3898
+ if (isSubmitting) return;
3899
+ isSubmitting = true;
3900
+ updateFormState();
3901
+ try {
3902
+ await onClearOverrides();
3903
+ appliedOverrides = {};
3904
+ setDraftValues(getDraftFromOverrides(void 0));
3905
+ } finally{
3906
+ isSubmitting = false;
3907
+ updateFormState();
3908
+ }
3909
+ }
3910
+ function getDraftOverrides() {
3911
+ return normalizeOverrideDraft({
3912
+ country: countryField.control.value,
3913
+ region: regionField.control.value,
3914
+ language: languageField.control.value,
3915
+ gpc: gpcField.control.value
3566
3916
  });
3567
- container.appendChild(overrideBanner);
3917
+ }
3918
+ function setDraftValues(draft) {
3919
+ countryField.control.value = draft.country;
3920
+ regionField.control.value = draft.region;
3921
+ languageField.control.value = draft.language;
3922
+ gpcField.control.value = draft.gpc;
3923
+ }
3924
+ function updateFormState() {
3925
+ const draftOverrides = getDraftOverrides();
3926
+ const hasDraftChanges = !overridesEqual(draftOverrides, appliedOverrides);
3927
+ applyButton.disabled = !hasDraftChanges || isSubmitting;
3928
+ revertButton.disabled = !hasDraftChanges || isSubmitting;
3929
+ clearButton.disabled = isSubmitting;
3930
+ formStatus.textContent = isSubmitting ? 'Applying...' : hasDraftChanges ? 'Unsaved changes' : hasOverridesValue(appliedOverrides) ? 'Overrides active' : 'No overrides';
3931
+ if (styles_components_module.overrideStatusDirty) formStatus.classList.toggle(styles_components_module.overrideStatusDirty, !isSubmitting && hasDraftChanges);
3568
3932
  }
3569
3933
  }
3570
3934
  function createOverrideInput(options) {
3571
- const { label, placeholder, value, onChange } = options;
3572
- let debounceTimer = null;
3935
+ const { label, placeholder, value } = options;
3573
3936
  const inputField = input({
3574
3937
  className: `${styles_components_module.input ?? ''} ${styles_components_module.inputSmall ?? ''}`.trim(),
3575
3938
  placeholder,
3576
- value,
3577
- onInput: (e)=>{
3578
- const target = e.target;
3579
- if (debounceTimer) clearTimeout(debounceTimer);
3580
- debounceTimer = setTimeout(()=>{
3581
- onChange(target.value);
3582
- }, 500);
3583
- }
3584
- });
3585
- return renderer_div({
3586
- style: {
3587
- display: 'flex',
3588
- alignItems: 'center',
3589
- justifyContent: 'space-between',
3590
- gap: '8px',
3591
- marginBottom: '8px'
3592
- },
3593
- children: [
3594
- renderer_div({
3595
- style: {
3596
- fontSize: 'var(--c15t-devtools-font-size-xs)',
3597
- color: 'var(--c15t-devtools-text-muted)',
3598
- minWidth: '60px'
3599
- },
3600
- text: label
3601
- }),
3602
- renderer_div({
3603
- style: {
3604
- flex: '1'
3605
- },
3606
- children: [
3607
- inputField
3608
- ]
3609
- })
3610
- ]
3939
+ value
3611
3940
  });
3941
+ return {
3942
+ element: renderer_div({
3943
+ className: styles_components_module.overrideField,
3944
+ children: [
3945
+ span({
3946
+ className: styles_components_module.overrideLabel,
3947
+ text: label
3948
+ }),
3949
+ inputField
3950
+ ]
3951
+ }),
3952
+ control: inputField
3953
+ };
3612
3954
  }
3613
3955
  function createOverrideSelect(options) {
3614
- const { label, selectOptions, value, onChange } = options;
3956
+ const { label, selectOptions, value } = options;
3615
3957
  const selectField = renderer_select({
3616
3958
  className: `${styles_components_module.input ?? ''} ${styles_components_module.inputSmall ?? ''}`.trim(),
3617
3959
  options: selectOptions,
3618
- selectedValue: value,
3619
- onChange: (e)=>{
3620
- const target = e.target;
3621
- onChange(target.value);
3622
- }
3623
- });
3624
- return renderer_div({
3625
- style: {
3626
- display: 'flex',
3627
- alignItems: 'center',
3628
- justifyContent: 'space-between',
3629
- gap: '8px',
3630
- marginBottom: '8px'
3631
- },
3632
- children: [
3633
- renderer_div({
3634
- style: {
3635
- fontSize: 'var(--c15t-devtools-font-size-xs)',
3636
- color: 'var(--c15t-devtools-text-muted)',
3637
- minWidth: '60px'
3638
- },
3639
- text: label
3640
- }),
3641
- renderer_div({
3642
- style: {
3643
- flex: '1'
3644
- },
3645
- children: [
3646
- selectField
3647
- ]
3648
- })
3649
- ]
3960
+ selectedValue: value
3650
3961
  });
3962
+ return {
3963
+ element: renderer_div({
3964
+ className: styles_components_module.overrideField,
3965
+ children: [
3966
+ span({
3967
+ className: styles_components_module.overrideLabel,
3968
+ text: label
3969
+ }),
3970
+ selectField
3971
+ ]
3972
+ }),
3973
+ control: selectField
3974
+ };
3975
+ }
3976
+ function getDraftFromOverrides(overrides) {
3977
+ return {
3978
+ country: overrides?.country ?? '',
3979
+ region: overrides?.region ?? '',
3980
+ language: overrides?.language ?? '',
3981
+ gpc: overrides?.gpc === true ? 'true' : overrides?.gpc === false ? 'false' : ''
3982
+ };
3983
+ }
3984
+ function normalizeOverrideDraft(draft) {
3985
+ return {
3986
+ country: normalizeAlphaCode(draft.country),
3987
+ region: normalizeAlphaCode(draft.region),
3988
+ language: normalizeLanguageCode(draft.language),
3989
+ gpc: 'true' === draft.gpc ? true : 'false' === draft.gpc ? false : void 0
3990
+ };
3991
+ }
3992
+ function normalizeAlphaCode(value) {
3993
+ const normalized = value.trim().toUpperCase();
3994
+ return normalized || void 0;
3995
+ }
3996
+ function normalizeLanguageCode(value) {
3997
+ const normalized = value.trim();
3998
+ return normalized || void 0;
3999
+ }
4000
+ function overridesEqual(a, b) {
4001
+ return a.country === b.country && a.region === b.region && a.language === b.language && a.gpc === b.gpc;
4002
+ }
4003
+ function hasOverridesValue(overrides) {
4004
+ return Boolean(overrides.country || overrides.region || overrides.language || void 0 !== overrides.gpc);
3651
4005
  }
3652
4006
  const COUNTRY_OPTIONS = [
3653
4007
  {
@@ -3771,6 +4125,32 @@ var __webpack_exports__ = {};
3771
4125
  label: 'ZA - South Africa'
3772
4126
  }
3773
4127
  ];
4128
+ const GPC_OPTIONS = [
4129
+ {
4130
+ value: '',
4131
+ label: '-- Browser Default --'
4132
+ },
4133
+ {
4134
+ value: 'true',
4135
+ label: 'Force On (Simulated)'
4136
+ },
4137
+ {
4138
+ value: 'false',
4139
+ label: 'Force Off (Simulated)'
4140
+ }
4141
+ ];
4142
+ function getEffectiveGpcLabel(gpcOverride) {
4143
+ if (true === gpcOverride) return 'On (Override)';
4144
+ if (false === gpcOverride) return 'Off (Override)';
4145
+ if ('undefined' == typeof window || 'undefined' == typeof navigator) return 'Unknown';
4146
+ try {
4147
+ const nav = navigator;
4148
+ const value = nav.globalPrivacyControl;
4149
+ return true === value || '1' === value ? 'Active' : 'Inactive';
4150
+ } catch {
4151
+ return 'Unknown';
4152
+ }
4153
+ }
3774
4154
  function getModelLabel(model) {
3775
4155
  switch(model){
3776
4156
  case 'opt-in':
@@ -3787,9 +4167,11 @@ var __webpack_exports__ = {};
3787
4167
  return renderer_div({
3788
4168
  className: styles_components_module.gridCard ?? '',
3789
4169
  style: {
4170
+ padding: '6px 8px',
4171
+ minHeight: 'auto',
3790
4172
  flexDirection: 'column',
3791
4173
  alignItems: 'flex-start',
3792
- gap: '2px'
4174
+ gap: '1px'
3793
4175
  },
3794
4176
  children: [
3795
4177
  span({
@@ -3814,34 +4196,38 @@ var __webpack_exports__ = {};
3814
4196
  function scanDOM(state) {
3815
4197
  const results = [];
3816
4198
  const configuredScripts = state.scripts || [];
3817
- const managedDomains = new Map();
4199
+ const managedResources = [];
3818
4200
  for (const script of configuredScripts)if (script.src) try {
3819
4201
  const url = new URL(script.src, window.location.origin);
3820
- if (url.hostname !== window.location.hostname) managedDomains.set(url.hostname, script.id);
4202
+ if (url.hostname !== window.location.hostname) managedResources.push({
4203
+ scriptId: script.id,
4204
+ domain: url.hostname,
4205
+ pathPrefix: normalizePathname(url.pathname)
4206
+ });
3821
4207
  } catch {}
3822
4208
  const scriptElements = document.querySelectorAll("script[src]");
3823
4209
  for (const el of scriptElements){
3824
4210
  const src = el.getAttribute('src');
3825
4211
  if (!src) continue;
3826
- const resource = checkResource(src, "script", managedDomains);
4212
+ const resource = checkResource(src, "script", managedResources);
3827
4213
  if (resource) results.push(resource);
3828
4214
  }
3829
4215
  const iframeElements = document.querySelectorAll('iframe[src]');
3830
4216
  for (const el of iframeElements){
3831
4217
  const src = el.getAttribute('src');
3832
4218
  if (!src) continue;
3833
- const resource = checkResource(src, 'iframe', managedDomains);
4219
+ const resource = checkResource(src, 'iframe', managedResources);
3834
4220
  if (resource) results.push(resource);
3835
4221
  }
3836
4222
  return results;
3837
4223
  }
3838
- function checkResource(src, type, managedDomains) {
4224
+ function checkResource(src, type, managedResources) {
3839
4225
  try {
3840
4226
  const url = new URL(src, window.location.origin);
3841
4227
  const domain = url.hostname;
3842
4228
  if (domain === window.location.hostname) return null;
3843
4229
  if ('data:' === url.protocol || 'blob:' === url.protocol) return null;
3844
- const managedBy = managedDomains.get(domain);
4230
+ const managedBy = findManagedScriptId(url, managedResources);
3845
4231
  const isManaged = Boolean(managedBy);
3846
4232
  return {
3847
4233
  type,
@@ -3853,6 +4239,21 @@ var __webpack_exports__ = {};
3853
4239
  } catch {}
3854
4240
  return null;
3855
4241
  }
4242
+ function findManagedScriptId(url, managedResources) {
4243
+ const domain = url.hostname;
4244
+ const path = normalizePathname(url.pathname);
4245
+ let bestMatch = null;
4246
+ for (const matcher of managedResources)if (matcher.domain === domain) {
4247
+ if ('/' === matcher.pathPrefix || path.startsWith(matcher.pathPrefix)) {
4248
+ if (!bestMatch || matcher.pathPrefix.length > bestMatch.pathPrefix.length) bestMatch = matcher;
4249
+ }
4250
+ }
4251
+ return bestMatch?.scriptId;
4252
+ }
4253
+ function normalizePathname(pathname) {
4254
+ const trimmed = pathname.trim();
4255
+ return trimmed.length > 0 ? trimmed : '/';
4256
+ }
3856
4257
  function createDomScannerSection(state) {
3857
4258
  let resultsContainer = null;
3858
4259
  let lastScanResults = [];
@@ -4017,7 +4418,7 @@ var __webpack_exports__ = {};
4017
4418
  <polyline points="8 6 2 12 8 18"></polyline>
4018
4419
  </svg>`;
4019
4420
  function scripts_renderScriptsPanel(container, options) {
4020
- const { getState } = options;
4421
+ const { getState, getEvents } = options;
4021
4422
  clearElement(container);
4022
4423
  const state = getState();
4023
4424
  if (!state) return void container.appendChild(renderer_div({
@@ -4032,6 +4433,7 @@ var __webpack_exports__ = {};
4032
4433
  const scripts = state.scripts || [];
4033
4434
  const loadedScripts = state.loadedScripts || {};
4034
4435
  const networkBlocker = state.networkBlocker;
4436
+ const events = getEvents?.() ?? [];
4035
4437
  if (0 === scripts.length) {
4036
4438
  const scriptsSection = createSection({
4037
4439
  title: 'Configured Scripts',
@@ -4114,6 +4516,20 @@ var __webpack_exports__ = {};
4114
4516
  ]
4115
4517
  });
4116
4518
  container.appendChild(networkSection);
4519
+ const blockedRequestEvents = events.filter((event)=>'network' === event.type);
4520
+ const networkEventsSection = createSection({
4521
+ title: `Blocked Requests (${blockedRequestEvents.length})`,
4522
+ children: 0 === blockedRequestEvents.length ? [
4523
+ renderer_div({
4524
+ style: {
4525
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
4526
+ color: 'var(--c15t-devtools-text-muted)'
4527
+ },
4528
+ text: 'No blocked network requests recorded in this session'
4529
+ })
4530
+ ] : createBlockedRequestContent(blockedRequestEvents)
4531
+ });
4532
+ container.appendChild(networkEventsSection);
4117
4533
  const loadedCount = Object.values(loadedScripts).filter(Boolean).length;
4118
4534
  const totalCount = scripts.length;
4119
4535
  const summarySection = createSection({
@@ -4139,12 +4555,127 @@ var __webpack_exports__ = {};
4139
4555
  }
4140
4556
  function checkScriptConsent(state, category) {
4141
4557
  if (!category) return true;
4558
+ if ('function' == typeof state.has) try {
4559
+ return state.has(category);
4560
+ } catch {}
4142
4561
  if ('string' == typeof category) {
4143
4562
  const consents = state.consents || {};
4144
4563
  return true === consents[category];
4145
4564
  }
4146
4565
  return false;
4147
4566
  }
4567
+ function createBlockedRequestContent(events) {
4568
+ const stats = new Map();
4569
+ for (const event of events){
4570
+ const ruleId = getEventRuleId(event) ?? 'unknown';
4571
+ stats.set(ruleId, (stats.get(ruleId) ?? 0) + 1);
4572
+ }
4573
+ const statsList = renderer_div({
4574
+ style: {
4575
+ display: 'flex',
4576
+ flexDirection: 'column',
4577
+ gap: '4px',
4578
+ marginBottom: '8px'
4579
+ },
4580
+ children: [
4581
+ ...stats.entries()
4582
+ ].sort((a, b)=>b[1] - a[1]).map(([ruleId, count])=>createInfoRow({
4583
+ label: 'unknown' === ruleId ? 'Unknown Rule' : `Rule: ${ruleId}`,
4584
+ value: `${count}`
4585
+ }))
4586
+ });
4587
+ const latestEvents = events.slice(0, 5);
4588
+ const latestList = renderer_div({
4589
+ style: {
4590
+ display: 'flex',
4591
+ flexDirection: 'column',
4592
+ gap: '4px'
4593
+ },
4594
+ children: latestEvents.map((event)=>createInfoRow({
4595
+ label: `${formatEventTime(event.timestamp)} ${getEventMethod(event)}`,
4596
+ value: scripts_truncateText(getEventUrl(event), 38)
4597
+ }))
4598
+ });
4599
+ return [
4600
+ statsList,
4601
+ latestList
4602
+ ];
4603
+ }
4604
+ function getEventRuleId(event) {
4605
+ const data = event.data;
4606
+ const rule = data?.rule;
4607
+ const ruleId = rule?.id ?? data?.ruleId;
4608
+ return 'string' == typeof ruleId || 'number' == typeof ruleId ? String(ruleId) : void 0;
4609
+ }
4610
+ function getEventMethod(event) {
4611
+ const data = event.data;
4612
+ const method = data?.method;
4613
+ return 'string' == typeof method ? method.toUpperCase() : 'REQ';
4614
+ }
4615
+ function getEventUrl(event) {
4616
+ const data = event.data;
4617
+ const url = data?.url;
4618
+ return 'string' == typeof url ? url : event.message;
4619
+ }
4620
+ function formatEventTime(timestamp) {
4621
+ return new Date(timestamp).toLocaleTimeString('en-US', {
4622
+ hour12: false,
4623
+ hour: '2-digit',
4624
+ minute: '2-digit',
4625
+ second: '2-digit'
4626
+ });
4627
+ }
4628
+ function scripts_truncateText(text, maxLength) {
4629
+ if (text.length <= maxLength) return text;
4630
+ return `${text.slice(0, maxLength - 3)}...`;
4631
+ }
4632
+ const DEVTOOLS_OVERRIDES_STORAGE_KEY = 'c15t-devtools-overrides';
4633
+ function normalizeStringValue(value) {
4634
+ if ('string' != typeof value) return;
4635
+ const normalized = value.trim();
4636
+ return normalized.length > 0 ? normalized : void 0;
4637
+ }
4638
+ function normalizeBooleanValue(value) {
4639
+ return 'boolean' == typeof value ? value : void 0;
4640
+ }
4641
+ function normalizeOverrides(value) {
4642
+ if (!value || 'object' != typeof value) return null;
4643
+ const source = value;
4644
+ const overrides = {
4645
+ country: normalizeStringValue(source.country),
4646
+ region: normalizeStringValue(source.region),
4647
+ language: normalizeStringValue(source.language),
4648
+ gpc: normalizeBooleanValue(source.gpc)
4649
+ };
4650
+ return hasPersistedOverrides(overrides) ? overrides : null;
4651
+ }
4652
+ function hasPersistedOverrides(overrides) {
4653
+ return Boolean(overrides.country || overrides.region || overrides.language || void 0 !== overrides.gpc);
4654
+ }
4655
+ function override_storage_loadPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
4656
+ if ('undefined' == typeof window) return null;
4657
+ try {
4658
+ const stored = localStorage.getItem(storageKey);
4659
+ if (!stored) return null;
4660
+ const parsed = JSON.parse(stored);
4661
+ return normalizeOverrides(parsed);
4662
+ } catch {
4663
+ return null;
4664
+ }
4665
+ }
4666
+ function override_storage_persistOverrides(overrides, storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
4667
+ if ('undefined' == typeof window) return;
4668
+ try {
4669
+ if (!hasPersistedOverrides(overrides)) return void localStorage.removeItem(storageKey);
4670
+ localStorage.setItem(storageKey, JSON.stringify(overrides));
4671
+ } catch {}
4672
+ }
4673
+ function override_storage_clearPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
4674
+ if ('undefined' == typeof window) return;
4675
+ try {
4676
+ localStorage.removeItem(storageKey);
4677
+ } catch {}
4678
+ }
4148
4679
  const STORAGE_KEYS = {
4149
4680
  C15T: 'c15t',
4150
4681
  PENDING_SYNC: 'c15t:pending-consent-sync',
@@ -4282,12 +4813,37 @@ var __webpack_exports__ = {};
4282
4813
  const { namespace = 'c15tStore', onConnect, onStateChange, onDisconnect } = options;
4283
4814
  let store = null;
4284
4815
  let unsubscribe = null;
4285
- let pollInterval = null;
4816
+ let reconnectTimeout = null;
4817
+ let reconnectAttempts = 0;
4818
+ let hasNotifiedDisconnect = false;
4286
4819
  const listeners = new Set();
4820
+ const INITIAL_RETRY_DELAY_MS = 100;
4821
+ const MAX_RETRY_DELAY_MS = 2000;
4822
+ const DISCONNECT_NOTIFY_ATTEMPTS = 5;
4823
+ function clearReconnectTimer() {
4824
+ if (reconnectTimeout) {
4825
+ clearTimeout(reconnectTimeout);
4826
+ reconnectTimeout = null;
4827
+ }
4828
+ }
4829
+ function resetReconnectState() {
4830
+ reconnectAttempts = 0;
4831
+ hasNotifiedDisconnect = false;
4832
+ }
4833
+ function notifyDisconnectedOnce() {
4834
+ if (hasNotifiedDisconnect) return;
4835
+ hasNotifiedDisconnect = true;
4836
+ onDisconnect?.();
4837
+ }
4287
4838
  function tryConnect() {
4288
4839
  if ('undefined' == typeof window) return false;
4289
4840
  const storeInstance = window[namespace];
4290
4841
  if (storeInstance && 'function' == typeof storeInstance.getState) {
4842
+ if (store === storeInstance && unsubscribe) return true;
4843
+ if (unsubscribe) {
4844
+ unsubscribe();
4845
+ unsubscribe = null;
4846
+ }
4291
4847
  store = storeInstance;
4292
4848
  unsubscribe = store.subscribe((state)=>{
4293
4849
  onStateChange?.(state);
@@ -4295,30 +4851,26 @@ var __webpack_exports__ = {};
4295
4851
  });
4296
4852
  const currentState = store.getState();
4297
4853
  onConnect?.(currentState, store);
4298
- if (pollInterval) {
4299
- clearInterval(pollInterval);
4300
- pollInterval = null;
4301
- }
4854
+ clearReconnectTimer();
4855
+ resetReconnectState();
4302
4856
  return true;
4303
4857
  }
4304
4858
  return false;
4305
4859
  }
4860
+ function scheduleReconnect(immediate = false) {
4861
+ if (store || reconnectTimeout) return;
4862
+ const delay = immediate ? 0 : Math.min(INITIAL_RETRY_DELAY_MS * 2 ** Math.min(reconnectAttempts, 5), MAX_RETRY_DELAY_MS);
4863
+ reconnectTimeout = setTimeout(()=>{
4864
+ reconnectTimeout = null;
4865
+ reconnectAttempts++;
4866
+ if (tryConnect()) return;
4867
+ if (reconnectAttempts >= DISCONNECT_NOTIFY_ATTEMPTS) notifyDisconnectedOnce();
4868
+ scheduleReconnect();
4869
+ }, delay);
4870
+ }
4306
4871
  function startPolling() {
4307
- if (pollInterval) return;
4308
4872
  if (tryConnect()) return;
4309
- let attempts = 0;
4310
- const maxAttempts = 50;
4311
- pollInterval = setInterval(()=>{
4312
- attempts++;
4313
- if (tryConnect()) return;
4314
- if (attempts >= maxAttempts) {
4315
- if (pollInterval) {
4316
- clearInterval(pollInterval);
4317
- pollInterval = null;
4318
- }
4319
- onDisconnect?.();
4320
- }
4321
- }, 100);
4873
+ scheduleReconnect(true);
4322
4874
  }
4323
4875
  startPolling();
4324
4876
  return {
@@ -4332,11 +4884,13 @@ var __webpack_exports__ = {};
4332
4884
  listeners.delete(listener);
4333
4885
  };
4334
4886
  },
4887
+ retryConnection: ()=>{
4888
+ if (store) return;
4889
+ resetReconnectState();
4890
+ scheduleReconnect(true);
4891
+ },
4335
4892
  destroy: ()=>{
4336
- if (pollInterval) {
4337
- clearInterval(pollInterval);
4338
- pollInterval = null;
4339
- }
4893
+ clearReconnectTimer();
4340
4894
  if (unsubscribe) {
4341
4895
  unsubscribe();
4342
4896
  unsubscribe = null;
@@ -4355,6 +4909,86 @@ var __webpack_exports__ = {};
4355
4909
  tokens_options.insertStyleElement = insertStyleElement_default();
4356
4910
  injectStylesIntoStyleTag_default()(tokens.A, tokens_options);
4357
4911
  tokens.A && tokens.A.locals && tokens.A.locals;
4912
+ const PANEL_HEIGHT_TRANSITION = 'height var(--c15t-duration-normal, 200ms) var(--c15t-easing, cubic-bezier(0.4, 0, 0.2, 1))';
4913
+ const PANEL_HEIGHT_TRANSITION_MS = 200;
4914
+ const PANEL_HEIGHT_TRANSITION_BUFFER_MS = 80;
4915
+ function normalizeOverridesForPersistence(overrides) {
4916
+ return {
4917
+ country: overrides?.country?.trim() || void 0,
4918
+ region: overrides?.region?.trim() || void 0,
4919
+ language: overrides?.language?.trim() || void 0,
4920
+ gpc: overrides?.gpc
4921
+ };
4922
+ }
4923
+ function persistedOverridesEqual(a, b) {
4924
+ return a.country === b.country && a.region === b.region && a.language === b.language && a.gpc === b.gpc;
4925
+ }
4926
+ function getBlockedRequestMessage(payload) {
4927
+ const data = payload;
4928
+ const method = 'string' == typeof data?.method ? data.method.toUpperCase() : 'REQUEST';
4929
+ const url = 'string' == typeof data?.url ? data.url : 'unknown-url';
4930
+ return `Network blocked: ${method} ${url}`;
4931
+ }
4932
+ function prefersReducedMotion() {
4933
+ return 'undefined' != typeof window && 'function' == typeof window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
4934
+ }
4935
+ function createPanelHeightAnimator() {
4936
+ let activePanel = null;
4937
+ let frameId = null;
4938
+ let timeoutId = null;
4939
+ let removeTransitionListener = null;
4940
+ function clearAnimationState() {
4941
+ if (null !== frameId) {
4942
+ window.cancelAnimationFrame(frameId);
4943
+ frameId = null;
4944
+ }
4945
+ if (null !== timeoutId) {
4946
+ clearTimeout(timeoutId);
4947
+ timeoutId = null;
4948
+ }
4949
+ if (removeTransitionListener) {
4950
+ removeTransitionListener();
4951
+ removeTransitionListener = null;
4952
+ }
4953
+ if (activePanel) {
4954
+ activePanel.style.height = '';
4955
+ activePanel.style.transition = '';
4956
+ activePanel.style.willChange = '';
4957
+ activePanel = null;
4958
+ }
4959
+ }
4960
+ function animate(panel, previousHeight) {
4961
+ if (!Number.isFinite(previousHeight) || prefersReducedMotion()) return;
4962
+ const nextHeight = panel.getBoundingClientRect().height;
4963
+ if (!Number.isFinite(nextHeight) || Math.abs(nextHeight - previousHeight) < 1) return;
4964
+ clearAnimationState();
4965
+ activePanel = panel;
4966
+ panel.style.height = `${previousHeight}px`;
4967
+ panel.style.willChange = 'height';
4968
+ panel.getBoundingClientRect();
4969
+ const handleTransitionEnd = (event)=>{
4970
+ const transitionEvent = event;
4971
+ if ('string' == typeof transitionEvent.propertyName && transitionEvent.propertyName && 'height' !== transitionEvent.propertyName) return;
4972
+ clearAnimationState();
4973
+ };
4974
+ panel.addEventListener('transitionend', handleTransitionEnd);
4975
+ removeTransitionListener = ()=>{
4976
+ panel.removeEventListener('transitionend', handleTransitionEnd);
4977
+ };
4978
+ frameId = window.requestAnimationFrame(()=>{
4979
+ frameId = null;
4980
+ panel.style.transition = PANEL_HEIGHT_TRANSITION;
4981
+ panel.style.height = `${nextHeight}px`;
4982
+ });
4983
+ timeoutId = setTimeout(()=>{
4984
+ clearAnimationState();
4985
+ }, PANEL_HEIGHT_TRANSITION_MS + PANEL_HEIGHT_TRANSITION_BUFFER_MS);
4986
+ }
4987
+ return {
4988
+ animate,
4989
+ destroy: clearAnimationState
4990
+ };
4991
+ }
4358
4992
  function createDevTools(options = {}) {
4359
4993
  const { namespace = 'c15tStore', position = 'bottom-right', defaultOpen = false } = options;
4360
4994
  const stateManager = state_manager_createStateManager({
@@ -4362,6 +4996,8 @@ var __webpack_exports__ = {};
4362
4996
  isOpen: defaultOpen
4363
4997
  });
4364
4998
  let originalCallbacks = {};
4999
+ let originalNetworkBlockedCallback;
5000
+ let hasWrappedNetworkBlockerCallback = false;
4365
5001
  const storeConnector = store_connector_createStoreConnector({
4366
5002
  namespace,
4367
5003
  onConnect: (state, store)=>{
@@ -4405,6 +5041,48 @@ var __webpack_exports__ = {};
4405
5041
  });
4406
5042
  if ('function' == typeof originalCallbacks.onBeforeConsentRevocationReload) originalCallbacks.onBeforeConsentRevocationReload(payload);
4407
5043
  });
5044
+ const currentNetworkBlocker = store.getState().networkBlocker;
5045
+ if (currentNetworkBlocker && !hasWrappedNetworkBlockerCallback) {
5046
+ originalNetworkBlockedCallback = currentNetworkBlocker.onRequestBlocked;
5047
+ hasWrappedNetworkBlockerCallback = true;
5048
+ store.getState().setNetworkBlocker({
5049
+ ...currentNetworkBlocker,
5050
+ onRequestBlocked: (payload)=>{
5051
+ stateManager.addEvent({
5052
+ type: 'network',
5053
+ message: getBlockedRequestMessage(payload),
5054
+ data: payload
5055
+ });
5056
+ if ('function' == typeof originalNetworkBlockedCallback) originalNetworkBlockedCallback(payload);
5057
+ }
5058
+ });
5059
+ }
5060
+ const persistedOverrides = override_storage_loadPersistedOverrides();
5061
+ if (persistedOverrides) {
5062
+ const currentOverrides = normalizeOverridesForPersistence(store.getState().overrides);
5063
+ if (!persistedOverridesEqual(persistedOverrides, currentOverrides)) store.getState().setOverrides({
5064
+ country: persistedOverrides.country,
5065
+ region: persistedOverrides.region,
5066
+ language: persistedOverrides.language,
5067
+ gpc: persistedOverrides.gpc
5068
+ }).then(()=>{
5069
+ stateManager.addEvent({
5070
+ type: 'info',
5071
+ message: 'Applied persisted devtools overrides',
5072
+ data: {
5073
+ country: persistedOverrides.country,
5074
+ region: persistedOverrides.region,
5075
+ language: persistedOverrides.language,
5076
+ gpc: persistedOverrides.gpc
5077
+ }
5078
+ });
5079
+ }).catch(()=>{
5080
+ stateManager.addEvent({
5081
+ type: 'error',
5082
+ message: 'Failed to apply persisted devtools overrides'
5083
+ });
5084
+ });
5085
+ }
4408
5086
  },
4409
5087
  onDisconnect: ()=>{
4410
5088
  stateManager.setConnected(false);
@@ -4416,14 +5094,18 @@ var __webpack_exports__ = {};
4416
5094
  onStateChange: ()=>{}
4417
5095
  });
4418
5096
  let tabsInstance = null;
5097
+ const panelHeightAnimator = createPanelHeightAnimator();
4419
5098
  const panelInstance = createPanel({
4420
5099
  stateManager,
4421
5100
  storeConnector,
5101
+ namespace,
4422
5102
  onRenderContent: (container)=>{
4423
5103
  renderContent(container, stateManager, storeConnector);
4424
5104
  }
4425
5105
  });
4426
5106
  function renderContent(container, stateManager, storeConnector) {
5107
+ const panel = container.parentElement;
5108
+ const previousPanelHeight = panel?.getBoundingClientRect().height ?? 0;
4427
5109
  clearElement(container);
4428
5110
  const storeState = storeConnector.getState();
4429
5111
  const disabledTabs = [];
@@ -4505,38 +5187,46 @@ var __webpack_exports__ = {};
4505
5187
  case 'location':
4506
5188
  location_renderLocationPanel(panelContent, {
4507
5189
  getState: getStoreState,
4508
- onSetOverrides: async (overrides)=>{
5190
+ onApplyOverrides: async (overrides)=>{
4509
5191
  const store = storeConnector.getStore();
4510
5192
  if (store) {
4511
- const currentOverrides = store.getState().overrides || {};
4512
5193
  await store.getState().setOverrides({
4513
- ...currentOverrides,
4514
- ...overrides
5194
+ country: overrides.country,
5195
+ region: overrides.region,
5196
+ language: overrides.language,
5197
+ gpc: overrides.gpc
4515
5198
  });
4516
- stateManager.addEvent({
4517
- type: 'info',
4518
- message: 'Overrides updated',
4519
- data: overrides
5199
+ override_storage_persistOverrides({
5200
+ country: overrides.country,
5201
+ region: overrides.region,
5202
+ language: overrides.language,
5203
+ gpc: overrides.gpc
4520
5204
  });
4521
- await store.getState().initConsentManager();
4522
5205
  stateManager.addEvent({
4523
5206
  type: 'info',
4524
- message: 'Consent manager re-initialized with new overrides'
5207
+ message: 'Overrides updated',
5208
+ data: {
5209
+ country: overrides.country,
5210
+ region: overrides.region,
5211
+ language: overrides.language,
5212
+ gpc: overrides.gpc
5213
+ }
4525
5214
  });
4526
5215
  }
4527
5216
  },
4528
5217
  onClearOverrides: async ()=>{
4529
5218
  const store = storeConnector.getStore();
4530
5219
  if (store) {
4531
- await store.getState().setOverrides(void 0);
4532
- stateManager.addEvent({
4533
- type: 'info',
4534
- message: 'Overrides cleared'
5220
+ await store.getState().setOverrides({
5221
+ country: void 0,
5222
+ region: void 0,
5223
+ language: void 0,
5224
+ gpc: void 0
4535
5225
  });
4536
- await store.getState().initConsentManager();
5226
+ override_storage_clearPersistedOverrides();
4537
5227
  stateManager.addEvent({
4538
5228
  type: 'info',
4539
- message: 'Consent manager re-initialized'
5229
+ message: 'Overrides cleared'
4540
5230
  });
4541
5231
  }
4542
5232
  }
@@ -4544,12 +5234,85 @@ var __webpack_exports__ = {};
4544
5234
  break;
4545
5235
  case "scripts":
4546
5236
  scripts_renderScriptsPanel(panelContent, {
4547
- getState: getStoreState
5237
+ getState: getStoreState,
5238
+ getEvents: ()=>stateManager.getState().eventLog
4548
5239
  });
4549
5240
  break;
4550
5241
  case 'iab':
4551
5242
  iab_renderIabPanel(panelContent, {
4552
5243
  getState: getStoreState,
5244
+ onSetPurposeConsent: (purposeId, value)=>{
5245
+ const iab = storeConnector.getStore()?.getState().iab;
5246
+ if (!iab) return;
5247
+ iab.setPurposeConsent(purposeId, value);
5248
+ stateManager.addEvent({
5249
+ type: 'iab',
5250
+ message: `IAB purpose ${purposeId} set to ${value}`,
5251
+ data: {
5252
+ purposeId,
5253
+ value
5254
+ }
5255
+ });
5256
+ },
5257
+ onSetVendorConsent: (vendorId, value)=>{
5258
+ const iab = storeConnector.getStore()?.getState().iab;
5259
+ if (!iab) return;
5260
+ iab.setVendorConsent(vendorId, value);
5261
+ stateManager.addEvent({
5262
+ type: 'iab',
5263
+ message: `IAB vendor ${vendorId} set to ${value}`,
5264
+ data: {
5265
+ vendorId,
5266
+ value
5267
+ }
5268
+ });
5269
+ },
5270
+ onSetSpecialFeatureOptIn: (featureId, value)=>{
5271
+ const iab = storeConnector.getStore()?.getState().iab;
5272
+ if (!iab) return;
5273
+ iab.setSpecialFeatureOptIn(featureId, value);
5274
+ stateManager.addEvent({
5275
+ type: 'iab',
5276
+ message: `IAB feature ${featureId} set to ${value}`,
5277
+ data: {
5278
+ featureId,
5279
+ value
5280
+ }
5281
+ });
5282
+ },
5283
+ onAcceptAll: ()=>{
5284
+ const iab = storeConnector.getStore()?.getState().iab;
5285
+ if (!iab) return;
5286
+ iab.acceptAll();
5287
+ stateManager.addEvent({
5288
+ type: 'iab',
5289
+ message: 'IAB accept all selected'
5290
+ });
5291
+ },
5292
+ onRejectAll: ()=>{
5293
+ const iab = storeConnector.getStore()?.getState().iab;
5294
+ if (!iab) return;
5295
+ iab.rejectAll();
5296
+ stateManager.addEvent({
5297
+ type: 'iab',
5298
+ message: 'IAB reject all selected'
5299
+ });
5300
+ },
5301
+ onSave: ()=>{
5302
+ const iab = storeConnector.getStore()?.getState().iab;
5303
+ if (!iab) return;
5304
+ iab.save().then(()=>{
5305
+ stateManager.addEvent({
5306
+ type: 'iab',
5307
+ message: 'IAB preferences saved'
5308
+ });
5309
+ }).catch((error)=>{
5310
+ stateManager.addEvent({
5311
+ type: 'error',
5312
+ message: `Failed to save IAB preferences: ${String(error)}`
5313
+ });
5314
+ });
5315
+ },
4553
5316
  onReset: async ()=>{
4554
5317
  const store = storeConnector.getStore();
4555
5318
  if (store) await reset_consents_resetAllConsents(store, stateManager);
@@ -4637,6 +5400,7 @@ var __webpack_exports__ = {};
4637
5400
  });
4638
5401
  break;
4639
5402
  }
5403
+ if (panel) panelHeightAnimator.animate(panel, previousPanelHeight);
4640
5404
  }
4641
5405
  storeConnector.subscribe(()=>{
4642
5406
  panelInstance.update();
@@ -4654,6 +5418,21 @@ var __webpack_exports__ = {};
4654
5418
  };
4655
5419
  },
4656
5420
  destroy: ()=>{
5421
+ const store = storeConnector.getStore();
5422
+ if (store) {
5423
+ store.getState().setCallback('onBannerFetched', originalCallbacks.onBannerFetched);
5424
+ store.getState().setCallback('onConsentSet', originalCallbacks.onConsentSet);
5425
+ store.getState().setCallback('onError', originalCallbacks.onError);
5426
+ store.getState().setCallback('onBeforeConsentRevocationReload', originalCallbacks.onBeforeConsentRevocationReload);
5427
+ if (hasWrappedNetworkBlockerCallback) {
5428
+ const currentNetworkBlocker = store.getState().networkBlocker;
5429
+ if (currentNetworkBlocker) store.getState().setNetworkBlocker({
5430
+ ...currentNetworkBlocker,
5431
+ onRequestBlocked: originalNetworkBlockedCallback
5432
+ });
5433
+ }
5434
+ }
5435
+ panelHeightAnimator.destroy();
4657
5436
  tabsInstance?.destroy();
4658
5437
  panelInstance.destroy();
4659
5438
  storeConnector.destroy();
@@ -4688,8 +5467,10 @@ var __webpack_exports__ = {};
4688
5467
  }
4689
5468
  })();
4690
5469
  exports.C15TDevTools = __webpack_exports__.C15TDevTools;
5470
+ exports.DevTools = __webpack_exports__.DevTools;
4691
5471
  for(var __rspack_i in __webpack_exports__)if (-1 === [
4692
- "C15TDevTools"
5472
+ "C15TDevTools",
5473
+ "DevTools"
4693
5474
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
4694
5475
  Object.defineProperty(exports, '__esModule', {
4695
5476
  value: true