@c15t/dev-tools 2.0.0-rc.3 → 2.0.0-rc.5

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 (95) hide show
  1. package/README.md +12 -1
  2. package/dist/index.cjs +2039 -953
  3. package/dist/index.js +2042 -956
  4. package/dist/react.cjs +1975 -803
  5. package/dist/react.js +1978 -806
  6. package/dist/tanstack.cjs +1862 -524
  7. package/dist/tanstack.js +1865 -527
  8. package/{dist → dist-types}/components/dropdown-menu.d.ts +0 -1
  9. package/{dist → dist-types}/components/index.d.ts +0 -1
  10. package/{dist → dist-types}/components/panel.d.ts +0 -1
  11. package/{dist → dist-types}/components/tabs.d.ts +0 -1
  12. package/{dist → dist-types}/components/ui.d.ts +8 -1
  13. package/dist-types/core/debug-bundle.d.ts +13 -0
  14. package/{dist → dist-types}/core/devtools.d.ts +0 -1
  15. package/{dist → dist-types}/core/draggable.d.ts +0 -1
  16. package/{dist → dist-types}/core/index.d.ts +0 -1
  17. package/{dist → dist-types}/core/override-storage.d.ts +1 -2
  18. package/{dist → dist-types}/core/panel-renderer.d.ts +6 -2
  19. package/{dist → dist-types}/core/renderer.d.ts +0 -1
  20. package/{dist → dist-types}/core/reset-consents.d.ts +1 -2
  21. package/{dist → dist-types}/core/state-manager.d.ts +1 -2
  22. package/{dist → dist-types}/core/store-connector.d.ts +17 -2
  23. package/dist-types/core/store-instrumentation.d.ts +12 -0
  24. package/{dist → dist-types}/index.d.ts +0 -1
  25. package/{dist → dist-types}/panels/actions.d.ts +2 -2
  26. package/{dist → dist-types}/panels/consents.d.ts +1 -2
  27. package/{dist → dist-types}/panels/dom-scanner.d.ts +1 -2
  28. package/{dist → dist-types}/panels/events.d.ts +0 -1
  29. package/{dist → dist-types}/panels/iab.d.ts +1 -2
  30. package/{dist → dist-types}/panels/index.d.ts +1 -1
  31. package/{dist → dist-types}/panels/location.d.ts +1 -2
  32. package/dist-types/panels/policy.d.ts +12 -0
  33. package/{dist → dist-types}/panels/scripts.d.ts +1 -2
  34. package/{dist → dist-types}/react.d.ts +0 -1
  35. package/{dist → dist-types}/styles/index.d.ts +0 -1
  36. package/{dist → dist-types}/tanstack.d.ts +0 -1
  37. package/{dist → dist-types}/utils/index.d.ts +1 -1
  38. package/dist-types/utils/init-source.d.ts +2 -0
  39. package/{dist → dist-types}/utils/preference-trigger.d.ts +0 -1
  40. package/dist-types/version.d.ts +1 -0
  41. package/package.json +35 -32
  42. package/CHANGELOG.md +0 -154
  43. package/dist/__tests__/components/ui.test.d.ts +0 -2
  44. package/dist/__tests__/components/ui.test.d.ts.map +0 -1
  45. package/dist/__tests__/core/override-storage.test.d.ts +0 -2
  46. package/dist/__tests__/core/override-storage.test.d.ts.map +0 -1
  47. package/dist/__tests__/core/renderer.test.d.ts +0 -2
  48. package/dist/__tests__/core/renderer.test.d.ts.map +0 -1
  49. package/dist/__tests__/core/reset-consents.test.d.ts +0 -2
  50. package/dist/__tests__/core/reset-consents.test.d.ts.map +0 -1
  51. package/dist/__tests__/core/state-manager.test.d.ts +0 -2
  52. package/dist/__tests__/core/state-manager.test.d.ts.map +0 -1
  53. package/dist/__tests__/core/store-connector.test.d.ts +0 -2
  54. package/dist/__tests__/core/store-connector.test.d.ts.map +0 -1
  55. package/dist/__tests__/panels/dom-scanner.test.d.ts +0 -2
  56. package/dist/__tests__/panels/dom-scanner.test.d.ts.map +0 -1
  57. package/dist/__tests__/panels/events.test.d.ts +0 -2
  58. package/dist/__tests__/panels/events.test.d.ts.map +0 -1
  59. package/dist/__tests__/panels/iab.test.d.ts +0 -2
  60. package/dist/__tests__/panels/iab.test.d.ts.map +0 -1
  61. package/dist/__tests__/panels/scripts.test.d.ts +0 -2
  62. package/dist/__tests__/panels/scripts.test.d.ts.map +0 -1
  63. package/dist/__tests__/utils/preference-trigger.test.d.ts +0 -2
  64. package/dist/__tests__/utils/preference-trigger.test.d.ts.map +0 -1
  65. package/dist/components/dropdown-menu.d.ts.map +0 -1
  66. package/dist/components/index.d.ts.map +0 -1
  67. package/dist/components/panel.d.ts.map +0 -1
  68. package/dist/components/tabs.d.ts.map +0 -1
  69. package/dist/components/ui.d.ts.map +0 -1
  70. package/dist/core/devtools.d.ts.map +0 -1
  71. package/dist/core/draggable.d.ts.map +0 -1
  72. package/dist/core/index.d.ts.map +0 -1
  73. package/dist/core/override-storage.d.ts.map +0 -1
  74. package/dist/core/panel-renderer.d.ts.map +0 -1
  75. package/dist/core/renderer.d.ts.map +0 -1
  76. package/dist/core/reset-consents.d.ts.map +0 -1
  77. package/dist/core/state-manager.d.ts.map +0 -1
  78. package/dist/core/store-connector.d.ts.map +0 -1
  79. package/dist/index.d.ts.map +0 -1
  80. package/dist/panels/actions.d.ts.map +0 -1
  81. package/dist/panels/consents.d.ts.map +0 -1
  82. package/dist/panels/dom-scanner.d.ts.map +0 -1
  83. package/dist/panels/events.d.ts.map +0 -1
  84. package/dist/panels/iab.d.ts.map +0 -1
  85. package/dist/panels/index.d.ts.map +0 -1
  86. package/dist/panels/location.d.ts.map +0 -1
  87. package/dist/panels/scripts.d.ts.map +0 -1
  88. package/dist/react.d.ts.map +0 -1
  89. package/dist/styles/index.d.ts.map +0 -1
  90. package/dist/tanstack.d.ts.map +0 -1
  91. package/dist/utils/index.d.ts.map +0 -1
  92. package/dist/utils/preference-trigger.d.ts.map +0 -1
  93. package/dist/version.d.ts +0 -2
  94. package/dist/version.d.ts.map +0 -1
  95. package/tsconfig.json +0 -12
package/dist/react.js CHANGED
@@ -261,21 +261,21 @@ var __webpack_modules__ = {
261
261
  module.id,
262
262
  `.toggle-bPZtik {
263
263
  border-radius: var(--c15t-radius-full, 9999px);
264
- background-color: var(--c15t-switch-track, #ccc);
264
+ background-color: var(--c15t-switch-track, #d9d9d9);
265
265
  cursor: pointer;
266
- width: 36px;
267
- height: 20px;
268
- transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
266
+ width: 2rem;
267
+ height: 1.25rem;
268
+ transition: background-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));
269
269
  border: none;
270
270
  align-items: center;
271
- padding: 0;
271
+ padding: .125rem;
272
272
  display: inline-flex;
273
273
  position: relative;
274
274
  }
275
275
 
276
276
  .toggle-bPZtik:focus-visible {
277
- outline: 2px solid var(--c15t-primary, #335cff);
278
- outline-offset: 2px;
277
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
278
+ outline: none;
279
279
  }
280
280
 
281
281
  .toggleActive-Ldlasg {
@@ -285,16 +285,16 @@ var __webpack_modules__ = {
285
285
  .toggleThumb-hjGfoX {
286
286
  border-radius: var(--c15t-radius-full, 9999px);
287
287
  background-color: var(--c15t-switch-thumb, #fff);
288
- width: 16px;
289
- height: 16px;
290
- transition: transform var(--c15t-duration-fast, .1s) var(--c15t-easing-spring, cubic-bezier(.34, 1.56, .64, 1));
288
+ width: .75rem;
289
+ height: .75rem;
290
+ box-shadow: 0 0 0 1px var(--c15t-border, #e3e3e3);
291
+ transition: transform var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
291
292
  position: absolute;
292
293
  left: 2px;
293
- box-shadow: 0 1px 2px #0003;
294
294
  }
295
295
 
296
296
  .toggleActive-Ldlasg .toggleThumb-hjGfoX {
297
- transform: translateX(16px);
297
+ transform: translateX(1rem);
298
298
  }
299
299
 
300
300
  .toggle-bPZtik:disabled, .toggleDisabled-ZcD8nZ {
@@ -307,13 +307,14 @@ var __webpack_modules__ = {
307
307
  }
308
308
 
309
309
  .badge-yA0giZ {
310
- border-radius: var(--c15t-radius-sm, .25rem);
310
+ border-radius: var(--c15t-radius-full, 9999px);
311
311
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
312
312
  font-weight: var(--c15t-font-weight-medium, 500);
313
+ line-height: var(--c15t-line-height-tight, 1.25);
313
314
  white-space: nowrap;
315
+ justify-content: center;
314
316
  align-items: center;
315
- padding: 2px 6px;
316
- line-height: 1;
317
+ padding: .1875rem .4375rem;
317
318
  display: inline-flex;
318
319
  }
319
320
 
@@ -346,35 +347,36 @@ var __webpack_modules__ = {
346
347
  justify-content: center;
347
348
  align-items: center;
348
349
  gap: var(--c15t-space-xs, .25rem);
349
- border: 1px solid var(--c15t-border, #e3e3e3);
350
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
350
351
  border-radius: var(--c15t-radius-md, .5rem);
351
- background-color: var(--c15t-surface, #fff);
352
- min-height: 30px;
352
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
353
+ min-height: 2rem;
353
354
  color: var(--c15t-text, #171717);
354
- font-family: inherit;
355
- font-size: 12px;
355
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
356
+ font-size: var(--c15t-font-size-sm, .875rem);
356
357
  font-weight: var(--c15t-font-weight-medium, 500);
358
+ line-height: var(--c15t-line-height-tight, 1.25);
359
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d);
357
360
  cursor: pointer;
358
361
  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;
362
+ padding: .375rem .625rem;
361
363
  display: inline-flex;
362
- box-shadow: 0 1px 1px #0000000a;
363
364
  }
364
365
 
365
366
  .btn-evRVlh:hover {
366
- background-color: var(--c15t-surface-hover, #f7f7f7);
367
+ background-color: var(--c15t-devtools-surface-subtle, #f7f7f7);
367
368
  border-color: var(--c15t-border-hover, #c9c9c9);
368
- box-shadow: 0 2px 6px #00000014;
369
+ box-shadow: var(--c15t-shadow-md, 0 4px 12px #00000014);
369
370
  }
370
371
 
371
372
  .btn-evRVlh:focus-visible {
372
- outline: 2px solid var(--c15t-primary, #335cff);
373
- outline-offset: 1px;
373
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d), 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
374
+ outline: none;
374
375
  }
375
376
 
376
377
  .btn-evRVlh:active {
377
- box-shadow: 0 1px 2px #00000014;
378
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d);
379
+ transform: scale(.98);
378
380
  }
379
381
 
380
382
  .btn-evRVlh:disabled {
@@ -387,6 +389,7 @@ var __webpack_modules__ = {
387
389
  background-color: var(--c15t-primary, #335cff);
388
390
  border-color: var(--c15t-primary, #335cff);
389
391
  color: var(--c15t-text-on-primary, #fff);
392
+ box-shadow: none;
390
393
  }
391
394
 
392
395
  .btnPrimary-dA6nqY:hover {
@@ -398,6 +401,7 @@ var __webpack_modules__ = {
398
401
  background-color: var(--c15t-devtools-badge-error, #ef4343);
399
402
  border-color: var(--c15t-devtools-badge-error, #ef4343);
400
403
  color: var(--c15t-text-on-primary, #fff);
404
+ box-shadow: none;
401
405
  }
402
406
 
403
407
  .btnDanger-eDnqOX:hover {
@@ -406,10 +410,10 @@ var __webpack_modules__ = {
406
410
  }
407
411
 
408
412
  .btnSmall-TjXoqZ {
413
+ min-height: 1.75rem;
414
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
409
415
  border-radius: var(--c15t-radius-sm, .375rem);
410
- min-height: 26px;
411
- padding: 3px 8px;
412
- font-size: 11px;
416
+ padding: .25rem .5rem;
413
417
  }
414
418
 
415
419
  .btnIcon-fiYQAh {
@@ -419,19 +423,22 @@ var __webpack_modules__ = {
419
423
  }
420
424
 
421
425
  .input-IeTcCs {
422
- width: 100%;
423
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
424
- border: 1px solid var(--c15t-border, #e3e3e3);
426
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
425
427
  border-radius: var(--c15t-radius-md, .5rem);
426
- background-color: var(--c15t-surface, #fff);
428
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
429
+ width: 100%;
430
+ min-height: 2rem;
427
431
  color: var(--c15t-text, #171717);
428
- font-family: inherit;
429
- font-size: var(--c15t-font-size-sm, .875rem);
430
- transition: border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
432
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
433
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
434
+ line-height: var(--c15t-line-height-tight, 1.25);
435
+ transition: 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));
436
+ padding: .375rem .625rem;
431
437
  }
432
438
 
433
439
  .input-IeTcCs:focus {
434
- border-color: var(--c15t-primary, #335cff);
440
+ border-color: var(--c15t-devtools-focus-ring, #335cff);
441
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--c15t-devtools-focus-ring, #335cff) 25%, transparent);
435
442
  outline: none;
436
443
  }
437
444
 
@@ -440,30 +447,35 @@ var __webpack_modules__ = {
440
447
  }
441
448
 
442
449
  .inputSmall-pJyXcL {
443
- padding: 2px var(--c15t-space-xs, .25rem);
450
+ min-height: 1.625rem;
444
451
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
452
+ padding: .25rem .4375rem;
445
453
  }
446
454
 
447
455
  .select-byJ1WM {
448
- width: 100%;
449
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
450
- border: 1px solid var(--c15t-border, #e3e3e3);
456
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
451
457
  border-radius: var(--c15t-radius-md, .5rem);
452
- background-color: var(--c15t-surface, #fff);
458
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
459
+ width: 100%;
460
+ min-height: 2rem;
453
461
  color: var(--c15t-text, #171717);
454
- font-family: inherit;
462
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
455
463
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
464
+ line-height: var(--c15t-line-height-tight, 1.25);
456
465
  cursor: pointer;
466
+ transition: 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));
467
+ padding: .375rem .625rem;
457
468
  }
458
469
 
459
470
  .select-byJ1WM:focus {
460
- border-color: var(--c15t-primary, #335cff);
471
+ border-color: var(--c15t-devtools-focus-ring, #335cff);
472
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--c15t-devtools-focus-ring, #335cff) 25%, transparent);
461
473
  outline: none;
462
474
  }
463
475
 
464
476
  .grid-LlrmEz {
465
477
  gap: var(--c15t-space-sm, .5rem);
466
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, 1rem);
478
+ padding: var(--c15t-space-md, 1rem);
467
479
  display: grid;
468
480
  }
469
481
 
@@ -476,42 +488,51 @@ var __webpack_modules__ = {
476
488
  }
477
489
 
478
490
  .gridCard-Qm5xxI {
479
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, .75rem);
480
- border: 1px solid var(--c15t-border, #e3e3e3);
481
- border-radius: var(--c15t-radius-md, .5rem);
482
- background-color: var(--c15t-surface, #fff);
483
- transition: border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
484
491
  justify-content: space-between;
485
492
  align-items: center;
493
+ gap: var(--c15t-space-sm, .5rem);
494
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
495
+ border-radius: var(--c15t-radius-md, .5rem);
496
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
497
+ min-height: 2.75rem;
498
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d);
499
+ transition: border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
500
+ padding: .5625rem .75rem;
486
501
  display: flex;
487
502
  }
488
503
 
489
504
  .gridCard-Qm5xxI:hover {
490
505
  border-color: var(--c15t-border-hover, #c9c9c9);
506
+ background-color: var(--c15t-devtools-surface-subtle, #fafafa);
491
507
  }
492
508
 
493
509
  .gridCardTitle-HjXETp {
494
510
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
495
511
  font-weight: var(--c15t-font-weight-medium, 500);
496
512
  color: var(--c15t-text, #171717);
513
+ line-height: var(--c15t-line-height-tight, 1.25);
497
514
  }
498
515
 
499
516
  .listItem-XUKGIo {
500
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-md, 1rem);
501
- border-bottom: 1px solid var(--c15t-border, #e3e3e3);
502
517
  justify-content: space-between;
503
518
  align-items: center;
519
+ gap: var(--c15t-space-sm, .5rem);
520
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
521
+ border-radius: var(--c15t-radius-md, .5rem);
522
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
523
+ margin-bottom: .375rem;
524
+ padding: .625rem .75rem;
504
525
  display: flex;
505
526
  }
506
527
 
507
528
  .listItem-XUKGIo:last-child {
508
- border-bottom: none;
529
+ margin-bottom: 0;
509
530
  }
510
531
 
511
532
  .listItemContent-WDBF1N {
512
533
  flex-direction: column;
513
534
  flex: 1;
514
- gap: 2px;
535
+ gap: .1875rem;
515
536
  min-width: 0;
516
537
  display: flex;
517
538
  }
@@ -525,6 +546,7 @@ var __webpack_modules__ = {
525
546
  .listItemDescription-E6JHyZ {
526
547
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
527
548
  color: var(--c15t-text-muted, #737373);
549
+ line-height: var(--c15t-line-height-tight, 1.25);
528
550
  text-overflow: ellipsis;
529
551
  white-space: nowrap;
530
552
  overflow: hidden;
@@ -538,8 +560,8 @@ var __webpack_modules__ = {
538
560
  }
539
561
 
540
562
  .section-a197cB {
541
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, 1rem);
542
- border-bottom: 1px solid var(--c15t-border, #e3e3e3);
563
+ border-bottom: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
564
+ padding: .75rem 1rem;
543
565
  }
544
566
 
545
567
  .section-a197cB:last-child {
@@ -547,9 +569,10 @@ var __webpack_modules__ = {
547
569
  }
548
570
 
549
571
  .sectionHeader-Xcljcw {
550
- margin-bottom: var(--c15t-space-sm, .5rem);
551
572
  justify-content: space-between;
552
573
  align-items: center;
574
+ gap: .5rem;
575
+ margin-bottom: .625rem;
553
576
  display: flex;
554
577
  }
555
578
 
@@ -558,47 +581,49 @@ var __webpack_modules__ = {
558
581
  font-weight: var(--c15t-font-weight-semibold, 600);
559
582
  color: var(--c15t-text-muted, #737373);
560
583
  text-transform: uppercase;
561
- letter-spacing: .5px;
584
+ letter-spacing: .04em;
562
585
  }
563
586
 
564
587
  .overrideField-keNdpJ {
565
588
  flex-direction: column;
566
- gap: 3px;
589
+ gap: .3125rem;
567
590
  margin-bottom: 0;
568
591
  display: flex;
569
592
  }
570
593
 
571
594
  .overrideLabel-ApMoTw {
595
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
596
+ font-weight: var(--c15t-font-weight-semibold, 600);
572
597
  color: var(--c15t-text-muted, #737373);
573
- font-size: 11px;
574
- font-weight: 600;
598
+ line-height: var(--c15t-line-height-tight, 1.25);
575
599
  }
576
600
 
577
601
  .overrideHint-yCfwGt {
578
- color: var(--c15t-devtools-text-muted, #737373);
579
- margin-top: 6px;
580
- font-size: 11px;
602
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
603
+ color: var(--c15t-text-muted, #737373);
604
+ line-height: var(--c15t-line-height-tight, 1.25);
605
+ margin-top: .5rem;
581
606
  }
582
607
 
583
608
  .overrideActions-imdcn7 {
584
- border-top: 1px dashed var(--c15t-border, #e3e3e3);
609
+ border-top: 1px dashed var(--c15t-devtools-border-strong, #e3e3e3);
585
610
  justify-content: space-between;
586
611
  align-items: center;
587
- gap: 8px;
588
- margin-top: 8px;
589
- padding-top: 8px;
612
+ gap: .5rem;
613
+ margin-top: .625rem;
614
+ padding-top: .625rem;
590
615
  display: flex;
591
616
  }
592
617
 
593
618
  .overrideActionButtons-gYOx1e {
594
619
  flex-wrap: wrap;
595
- gap: 6px;
620
+ gap: .375rem;
596
621
  display: flex;
597
622
  }
598
623
 
599
624
  .overrideStatus-sty_qS {
625
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
600
626
  color: var(--c15t-text-muted, #737373);
601
- font-size: 11px;
602
627
  }
603
628
 
604
629
  .overrideStatusDirty-OUdDMw {
@@ -606,9 +631,10 @@ var __webpack_modules__ = {
606
631
  }
607
632
 
608
633
  .infoRow-RlB_0h {
609
- padding: var(--c15t-space-xs, .25rem) 0;
610
634
  justify-content: space-between;
611
635
  align-items: center;
636
+ gap: .5rem;
637
+ padding: .25rem 0;
612
638
  display: flex;
613
639
  }
614
640
 
@@ -621,6 +647,7 @@ var __webpack_modules__ = {
621
647
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
622
648
  font-weight: var(--c15t-font-weight-medium, 500);
623
649
  color: var(--c15t-text, #171717);
650
+ font-variant-numeric: tabular-nums;
624
651
  font-family: ui-monospace, Cascadia Code, Source Code Pro, Menlo, Consolas, DejaVu Sans Mono, monospace;
625
652
  }
626
653
 
@@ -631,18 +658,27 @@ var __webpack_modules__ = {
631
658
  flex-direction: column;
632
659
  justify-content: center;
633
660
  align-items: center;
661
+ gap: .375rem;
634
662
  display: flex;
635
663
  }
636
664
 
637
665
  .emptyStateIcon-WHFkX8 {
666
+ opacity: .55;
638
667
  width: 32px;
639
668
  height: 32px;
640
- margin-bottom: var(--c15t-space-sm, .5rem);
641
- opacity: .5;
642
669
  }
643
670
 
644
671
  .emptyStateText-TaLvAJ {
645
672
  font-size: var(--c15t-font-size-sm, .875rem);
673
+ line-height: var(--c15t-line-height-normal, 1.5);
674
+ }
675
+
676
+ .disconnectedState-dOtZBG {
677
+ padding: var(--c15t-space-xl, 2rem);
678
+ text-align: center;
679
+ font-size: var(--c15t-font-size-sm, .875rem);
680
+ color: var(--c15t-text-muted, #737373);
681
+ line-height: var(--c15t-line-height-normal, 1.5);
646
682
  }
647
683
 
648
684
  @media (prefers-reduced-motion: reduce) {
@@ -709,7 +745,8 @@ var __webpack_modules__ = {
709
745
  infoValue: "infoValue-flMl_e",
710
746
  emptyState: "emptyState-QcmzTQ",
711
747
  emptyStateIcon: "emptyStateIcon-WHFkX8",
712
- emptyStateText: "emptyStateText-TaLvAJ"
748
+ emptyStateText: "emptyStateText-TaLvAJ",
749
+ disconnectedState: "disconnectedState-dOtZBG"
713
750
  };
714
751
  const __rspack_default_export = ___CSS_LOADER_EXPORT___;
715
752
  },
@@ -738,9 +775,9 @@ var __webpack_modules__ = {
738
775
  .floatingButton-Gw8MtJ {
739
776
  width: var(--c15t-devtools-button-size, 40px);
740
777
  height: var(--c15t-devtools-button-size, 40px);
741
- border: 1px solid var(--c15t-border, #e3e3e3);
778
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
742
779
  border-radius: var(--c15t-radius-full, 9999px);
743
- background-color: var(--c15t-surface, #fff);
780
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
744
781
  box-shadow: var(--c15t-shadow-lg, 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a);
745
782
  cursor: grab;
746
783
  z-index: var(--c15t-devtools-z-index, 99999);
@@ -768,13 +805,13 @@ var __webpack_modules__ = {
768
805
  }
769
806
 
770
807
  .floatingButton-Gw8MtJ:focus-visible {
771
- outline: 2px solid var(--c15t-primary, #335cff);
772
- outline-offset: 2px;
808
+ box-shadow: var(--c15t-shadow-lg, 0 8px 24px #0000001f), 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
809
+ outline: none;
773
810
  }
774
811
 
775
812
  .floatingButton-Gw8MtJ:active {
776
813
  cursor: grabbing;
777
- transform: scale(1.02);
814
+ transform: scale(.98);
778
815
  }
779
816
 
780
817
  .floatingButtonIcon-cHWefk {
@@ -815,6 +852,7 @@ var __webpack_modules__ = {
815
852
 
816
853
  .backdrop-LhVMB5 {
817
854
  background-color: var(--c15t-overlay, #00000080);
855
+ backdrop-filter: blur(1px);
818
856
  z-index: calc(var(--c15t-devtools-z-index, 99999) + 1);
819
857
  position: fixed;
820
858
  inset: 0;
@@ -823,10 +861,10 @@ var __webpack_modules__ = {
823
861
  .panel-jtWove {
824
862
  width: var(--c15t-devtools-panel-width, 480px);
825
863
  max-height: var(--c15t-devtools-panel-max-height, 560px);
826
- background-color: var(--c15t-surface, #fff);
827
- border: 1px solid var(--c15t-border, #e3e3e3);
864
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
865
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
828
866
  border-radius: var(--c15t-radius-lg, .75rem);
829
- box-shadow: var(--c15t-shadow-lg, 0 8px 24px #0000001f);
867
+ box-shadow: var(--c15t-shadow-lg, 0 10px 28px #00000029);
830
868
  z-index: calc(var(--c15t-devtools-z-index, 99999) + 2);
831
869
  flex-direction: column;
832
870
  display: flex;
@@ -859,11 +897,11 @@ var __webpack_modules__ = {
859
897
  }
860
898
 
861
899
  .header-xluoTr {
862
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, 1rem);
863
- border-bottom: 1px solid var(--c15t-border, #e3e3e3);
900
+ border-bottom: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
864
901
  background-color: var(--c15t-devtools-surface-muted, #f5f5f5);
865
902
  justify-content: space-between;
866
903
  align-items: center;
904
+ padding: .6875rem .875rem;
867
905
  display: flex;
868
906
  }
869
907
 
@@ -872,6 +910,7 @@ var __webpack_modules__ = {
872
910
  gap: var(--c15t-space-sm, .5rem);
873
911
  font-size: var(--c15t-font-size-sm, .875rem);
874
912
  font-weight: var(--c15t-font-weight-semibold, 600);
913
+ line-height: var(--c15t-line-height-tight, 1.25);
875
914
  color: var(--c15t-text, #171717);
876
915
  display: flex;
877
916
  }
@@ -883,9 +922,9 @@ var __webpack_modules__ = {
883
922
  }
884
923
 
885
924
  .closeButton-Yto0Nb {
886
- border-radius: var(--c15t-radius-sm, .25rem);
887
- width: 28px;
888
- height: 28px;
925
+ border-radius: var(--c15t-radius-md, .5rem);
926
+ width: 2rem;
927
+ height: 2rem;
889
928
  color: var(--c15t-text-muted, #737373);
890
929
  cursor: pointer;
891
930
  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));
@@ -898,13 +937,13 @@ var __webpack_modules__ = {
898
937
  }
899
938
 
900
939
  .closeButton-Yto0Nb:hover {
901
- background-color: var(--c15t-surface-hover, #f7f7f7);
940
+ background-color: var(--c15t-devtools-surface-subtle, #f7f7f7);
902
941
  color: var(--c15t-text, #171717);
903
942
  }
904
943
 
905
944
  .closeButton-Yto0Nb:focus-visible {
906
- outline: 2px solid var(--c15t-primary, #335cff);
907
- outline-offset: 1px;
945
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
946
+ outline: none;
908
947
  }
909
948
 
910
949
  .closeButtonIcon-fVlR1I {
@@ -912,33 +951,71 @@ var __webpack_modules__ = {
912
951
  height: 16px;
913
952
  }
914
953
 
954
+ .inlineActionButton-Ky8BmN {
955
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
956
+ border-radius: var(--c15t-radius-sm, .375rem);
957
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
958
+ min-height: 1.625rem;
959
+ color: var(--c15t-text, #171717);
960
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
961
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
962
+ font-weight: var(--c15t-font-weight-medium, 500);
963
+ line-height: var(--c15t-line-height-tight, 1.25);
964
+ cursor: pointer;
965
+ 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));
966
+ justify-content: center;
967
+ align-items: center;
968
+ padding: .25rem .5rem;
969
+ display: inline-flex;
970
+ }
971
+
972
+ .inlineActionButton-Ky8BmN:hover {
973
+ background-color: var(--c15t-devtools-surface-subtle, #f7f7f7);
974
+ border-color: var(--c15t-border-hover, #c9c9c9);
975
+ }
976
+
977
+ .inlineActionButton-Ky8BmN:focus-visible {
978
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
979
+ outline: none;
980
+ }
981
+
915
982
  .content-yDMYfG {
983
+ scrollbar-gutter: stable;
916
984
  overscroll-behavior: contain;
917
985
  -webkit-overflow-scrolling: touch;
986
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
918
987
  flex: auto;
919
988
  min-height: 200px;
920
- overflow: hidden auto;
989
+ overflow: hidden scroll;
921
990
  }
922
991
 
923
992
  .footer-ESbmwQ {
924
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-md, 1rem);
925
- border-top: 1px solid var(--c15t-border, #e3e3e3);
993
+ border-top: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
926
994
  background-color: var(--c15t-devtools-surface-muted, #f5f5f5);
927
995
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
928
996
  color: var(--c15t-text-muted, #737373);
929
997
  justify-content: space-between;
930
998
  align-items: center;
999
+ gap: .5rem;
1000
+ padding: .5rem .75rem;
931
1001
  display: flex;
932
1002
  }
933
1003
 
934
1004
  .footerStatus-rlb99A {
935
1005
  align-items: center;
936
- gap: var(--c15t-space-xs, .25rem);
1006
+ gap: .375rem;
1007
+ min-width: 0;
937
1008
  display: flex;
938
1009
  }
939
1010
 
1011
+ .footerMeta-Vdtxdk {
1012
+ opacity: .75;
1013
+ white-space: nowrap;
1014
+ }
1015
+
940
1016
  .statusDot-hYJoej {
941
1017
  border-radius: var(--c15t-radius-full, 9999px);
1018
+ flex-shrink: 0;
942
1019
  width: 6px;
943
1020
  height: 6px;
944
1021
  }
@@ -977,6 +1054,7 @@ var __webpack_modules__ = {
977
1054
  font-size: var(--c15t-font-size-sm, .875rem);
978
1055
  color: var(--c15t-text-muted, #737373);
979
1056
  max-width: 280px;
1057
+ line-height: var(--c15t-line-height-normal, 1.5);
980
1058
  }
981
1059
 
982
1060
  @media (prefers-reduced-motion: reduce) {
@@ -993,17 +1071,17 @@ var __webpack_modules__ = {
993
1071
  }
994
1072
 
995
1073
  .dropdownMenu-aKK18l {
996
- min-width: 200px;
997
- padding: var(--c15t-space-xs, .25rem);
998
- border: 1px solid var(--c15t-border, #e3e3e3);
1074
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
999
1075
  border-radius: var(--c15t-radius-lg, .75rem);
1000
- background-color: var(--c15t-surface, #fff);
1076
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
1077
+ min-width: 200px;
1001
1078
  box-shadow: var(--c15t-shadow-lg, 0 8px 24px #0000001f);
1002
1079
  z-index: calc(var(--c15t-devtools-z-index, 99999) + 1);
1003
1080
  opacity: 0;
1004
1081
  transform-origin: 0 100%;
1005
1082
  pointer-events: none;
1006
1083
  transition: opacity var(--c15t-duration-fast, .1s) var(--c15t-easing-out, cubic-bezier(.215, .61, .355, 1)), transform var(--c15t-duration-fast, .1s) var(--c15t-easing-out, cubic-bezier(.215, .61, .355, 1));
1084
+ padding: .375rem;
1007
1085
  position: fixed;
1008
1086
  transform: scale(.95)translateY(8px);
1009
1087
  }
@@ -1031,34 +1109,35 @@ var __webpack_modules__ = {
1031
1109
  }
1032
1110
 
1033
1111
  .menuItem-kBbHRP {
1034
- align-items: center;
1035
- gap: var(--c15t-space-sm, .5rem);
1036
- width: 100%;
1037
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, .75rem);
1038
1112
  border-radius: var(--c15t-radius-md, .5rem);
1113
+ width: 100%;
1039
1114
  color: var(--c15t-text, #171717);
1040
- font-size: var(--c15t-font-size-sm, .875rem);
1115
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
1041
1116
  font-weight: var(--c15t-font-weight-medium, 500);
1117
+ line-height: var(--c15t-line-height-tight, 1.25);
1042
1118
  text-align: left;
1043
1119
  cursor: pointer;
1044
1120
  transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1045
1121
  background: none;
1046
1122
  border: none;
1123
+ align-items: center;
1124
+ gap: .625rem;
1125
+ padding: .5rem .625rem;
1047
1126
  display: flex;
1048
1127
  }
1049
1128
 
1050
1129
  .menuItem-kBbHRP:hover {
1051
- background-color: var(--c15t-surface-hover, #f2f2f2);
1130
+ background-color: var(--c15t-devtools-surface-subtle, #f2f2f2);
1052
1131
  }
1053
1132
 
1054
1133
  .menuItem-kBbHRP:focus-visible {
1055
- outline: 2px solid var(--c15t-primary, #335cff);
1056
- outline-offset: -2px;
1134
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
1135
+ outline: none;
1057
1136
  }
1058
1137
 
1059
1138
  .menuItemIcon-P3pP5K {
1060
- width: 20px;
1061
- height: 20px;
1139
+ width: 1rem;
1140
+ height: 1rem;
1062
1141
  color: var(--c15t-text-muted, #737373);
1063
1142
  flex-shrink: 0;
1064
1143
  }
@@ -1071,6 +1150,7 @@ var __webpack_modules__ = {
1071
1150
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
1072
1151
  color: var(--c15t-text-muted, #737373);
1073
1152
  font-weight: var(--c15t-font-weight-normal, 400);
1153
+ margin-top: .125rem;
1074
1154
  }
1075
1155
 
1076
1156
  .menuItemContent-hBlruV {
@@ -1086,8 +1166,8 @@ var __webpack_modules__ = {
1086
1166
  .menuItemToggleTrack-gDp_f3 {
1087
1167
  background-color: var(--c15t-switch-track, #d9d9d9);
1088
1168
  border-radius: var(--c15t-radius-full, 9999px);
1089
- width: 36px;
1090
- height: 20px;
1169
+ width: 2rem;
1170
+ height: 1.25rem;
1091
1171
  transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1092
1172
  position: relative;
1093
1173
  }
@@ -1095,21 +1175,22 @@ var __webpack_modules__ = {
1095
1175
  .menuItemToggleThumb-ioqqyc {
1096
1176
  background-color: var(--c15t-switch-thumb, #fff);
1097
1177
  border-radius: var(--c15t-radius-full, 9999px);
1098
- width: 16px;
1099
- height: 16px;
1100
- box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000001a);
1178
+ width: .75rem;
1179
+ height: .75rem;
1180
+ box-shadow: 0 0 0 1px var(--c15t-border, #e3e3e3);
1101
1181
  transition: transform var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1102
1182
  position: absolute;
1103
- top: 2px;
1183
+ top: 50%;
1104
1184
  left: 2px;
1185
+ transform: translateY(-50%);
1105
1186
  }
1106
1187
 
1107
1188
  .menuItemToggleChecked-K3BPtk .menuItemToggleTrack-gDp_f3 {
1108
- background-color: var(--c15t-switch-track-checked, #335cff);
1189
+ background-color: var(--c15t-switch-track-active, #335cff);
1109
1190
  }
1110
1191
 
1111
1192
  .menuItemToggleChecked-K3BPtk .menuItemToggleThumb-ioqqyc {
1112
- transform: translateX(16px);
1193
+ transform: translate(1rem, -50%);
1113
1194
  }
1114
1195
 
1115
1196
  .menuDivider-JIBdhU {
@@ -1145,9 +1226,11 @@ var __webpack_modules__ = {
1145
1226
  headerLogo: "headerLogo-PxJ_w1",
1146
1227
  closeButton: "closeButton-Yto0Nb",
1147
1228
  closeButtonIcon: "closeButtonIcon-fVlR1I",
1229
+ inlineActionButton: "inlineActionButton-Ky8BmN",
1148
1230
  content: "content-yDMYfG",
1149
1231
  footer: "footer-ESbmwQ",
1150
1232
  footerStatus: "footerStatus-rlb99A",
1233
+ footerMeta: "footerMeta-Vdtxdk",
1151
1234
  statusDot: "statusDot-hYJoej",
1152
1235
  statusConnected: "statusConnected-hPSUgS",
1153
1236
  statusDisconnected: "statusDisconnected-HIpcee",
@@ -1186,62 +1269,63 @@ var __webpack_modules__ = {
1186
1269
  ___CSS_LOADER_EXPORT___.push([
1187
1270
  module.id,
1188
1271
  `.tabList-IyuiBE {
1272
+ border-bottom: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
1273
+ background-color: var(--c15t-devtools-surface-subtle, #fafafa);
1189
1274
  align-items: center;
1190
- gap: var(--c15t-space-xs, .25rem);
1191
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-sm, .5rem);
1192
- border-bottom: 1px solid var(--c15t-border, #e3e3e3);
1193
- background-color: var(--c15t-surface, #fff);
1194
- scrollbar-width: none;
1195
- -ms-overflow-style: none;
1196
- scroll-padding-inline-end: var(--c15t-space-sm, .5rem);
1275
+ gap: .375rem;
1276
+ padding: .75rem;
1197
1277
  display: flex;
1198
- overflow-x: auto;
1199
1278
  }
1200
1279
 
1201
- .tabList-IyuiBE:after {
1202
- content: "";
1203
- flex: 0 0 var(--c15t-space-sm, .5rem);
1204
- }
1205
-
1206
- .tabList-IyuiBE::-webkit-scrollbar {
1207
- display: none;
1280
+ .tabStrip-_KrWe4 {
1281
+ align-items: center;
1282
+ gap: var(--c15t-space-xs, .25rem);
1283
+ flex: auto;
1284
+ min-width: 0;
1285
+ display: flex;
1286
+ overflow: hidden;
1208
1287
  }
1209
1288
 
1210
1289
  .tab-yfDEqg {
1211
- align-items: center;
1212
- gap: var(--c15t-space-xs, .25rem);
1213
1290
  border-radius: var(--c15t-radius-md, .5rem);
1291
+ min-height: 1.875rem;
1214
1292
  color: var(--c15t-text-muted, #737373);
1215
- font-family: inherit;
1216
- font-size: 11px;
1293
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
1294
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
1217
1295
  font-weight: var(--c15t-font-weight-medium, 500);
1296
+ line-height: var(--c15t-line-height-tight, 1.25);
1218
1297
  cursor: pointer;
1219
1298
  white-space: nowrap;
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));
1299
+ 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)), 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));
1221
1300
  background-color: #0000;
1222
- border: none;
1223
- padding: 3px 7px;
1301
+ border: 1px solid #0000;
1302
+ flex-shrink: 0;
1303
+ align-items: center;
1304
+ gap: .375rem;
1305
+ padding: .25rem .625rem;
1224
1306
  display: flex;
1225
1307
  }
1226
1308
 
1227
1309
  .tab-yfDEqg:hover {
1228
- background-color: var(--c15t-surface-hover, #f7f7f7);
1310
+ background-color: var(--c15t-devtools-surface-muted, #f7f7f7);
1229
1311
  color: var(--c15t-text, #171717);
1230
1312
  }
1231
1313
 
1232
1314
  .tab-yfDEqg:focus-visible {
1233
- outline: 2px solid var(--c15t-primary, #335cff);
1234
- outline-offset: 1px;
1315
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
1316
+ outline: none;
1235
1317
  }
1236
1318
 
1237
1319
  .tabActive-r4hing {
1238
- background-color: var(--c15t-primary, #335cff);
1239
- color: var(--c15t-text-on-primary, #fff);
1320
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
1321
+ border-color: var(--c15t-devtools-border-strong, #e3e3e3);
1322
+ color: var(--c15t-text, #171717);
1323
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d);
1240
1324
  }
1241
1325
 
1242
1326
  .tabActive-r4hing:hover {
1243
- background-color: var(--c15t-primary-hover, #03f);
1244
- color: var(--c15t-text-on-primary, #fff);
1327
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
1328
+ color: var(--c15t-text, #171717);
1245
1329
  }
1246
1330
 
1247
1331
  .tabIcon-U9tnu0 {
@@ -1250,6 +1334,131 @@ var __webpack_modules__ = {
1250
1334
  height: 14px;
1251
1335
  }
1252
1336
 
1337
+ .tabHidden-HBXYSd {
1338
+ display: none;
1339
+ }
1340
+
1341
+ .overflowContainer-TTw9DO {
1342
+ flex-shrink: 0;
1343
+ position: relative;
1344
+ }
1345
+
1346
+ .overflowContainerHidden-sQa_XZ {
1347
+ display: none;
1348
+ }
1349
+
1350
+ .overflowButton-tKq4FF {
1351
+ border-radius: var(--c15t-radius-md, .5rem);
1352
+ width: 1.875rem;
1353
+ height: 1.875rem;
1354
+ color: var(--c15t-text-muted, #737373);
1355
+ cursor: pointer;
1356
+ 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)), border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1357
+ background-color: #0000;
1358
+ border: 1px solid #0000;
1359
+ justify-content: center;
1360
+ align-items: center;
1361
+ padding: 0;
1362
+ display: inline-flex;
1363
+ }
1364
+
1365
+ .overflowButton-tKq4FF:hover {
1366
+ background-color: var(--c15t-devtools-surface-muted, #f7f7f7);
1367
+ color: var(--c15t-text, #171717);
1368
+ }
1369
+
1370
+ .overflowButton-tKq4FF:focus-visible {
1371
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
1372
+ outline: none;
1373
+ }
1374
+
1375
+ .overflowButtonIcon-FSurfC {
1376
+ justify-content: center;
1377
+ align-items: center;
1378
+ width: 14px;
1379
+ height: 14px;
1380
+ display: inline-flex;
1381
+ }
1382
+
1383
+ .overflowMenu-TST0eZ {
1384
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
1385
+ border-radius: var(--c15t-radius-md, .5rem);
1386
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
1387
+ min-width: 10rem;
1388
+ box-shadow: var(--c15t-shadow-md, 0 4px 12px #00000014);
1389
+ opacity: 0;
1390
+ transform-origin: 100% 0;
1391
+ pointer-events: none;
1392
+ z-index: 10;
1393
+ transition: opacity var(--c15t-duration-fast, .1s) var(--c15t-easing-out, cubic-bezier(.215, .61, .355, 1)), transform var(--c15t-duration-fast, .1s) var(--c15t-easing-out, cubic-bezier(.215, .61, .355, 1));
1394
+ flex-direction: column;
1395
+ gap: .125rem;
1396
+ padding: .3125rem;
1397
+ display: flex;
1398
+ position: absolute;
1399
+ top: calc(100% + .375rem);
1400
+ right: 0;
1401
+ transform: translateY(-4px)scale(.98);
1402
+ }
1403
+
1404
+ .overflowMenu-TST0eZ[data-state="open"] {
1405
+ opacity: 1;
1406
+ pointer-events: auto;
1407
+ transform: translateY(0)scale(1);
1408
+ }
1409
+
1410
+ .overflowItem-y5Pz7k {
1411
+ border-radius: var(--c15t-radius-sm, .375rem);
1412
+ min-height: 1.75rem;
1413
+ color: var(--c15t-text, #171717);
1414
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
1415
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
1416
+ font-weight: var(--c15t-font-weight-medium, 500);
1417
+ line-height: var(--c15t-line-height-tight, 1.25);
1418
+ text-align: left;
1419
+ cursor: pointer;
1420
+ white-space: nowrap;
1421
+ 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));
1422
+ background-color: #0000;
1423
+ border: none;
1424
+ align-items: center;
1425
+ gap: .5rem;
1426
+ padding: .3125rem .5rem;
1427
+ display: inline-flex;
1428
+ }
1429
+
1430
+ .overflowItem-y5Pz7k:hover {
1431
+ background-color: var(--c15t-devtools-surface-subtle, #fafafa);
1432
+ }
1433
+
1434
+ .overflowItem-y5Pz7k:focus-visible {
1435
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
1436
+ outline: none;
1437
+ }
1438
+
1439
+ .overflowItemActive-mzVG1T {
1440
+ background-color: var(--c15t-devtools-accent-soft, #ebefff);
1441
+ color: var(--c15t-text, #171717);
1442
+ }
1443
+
1444
+ .overflowItemDisabled-dcHX3K {
1445
+ opacity: .5;
1446
+ cursor: not-allowed;
1447
+ }
1448
+
1449
+ .overflowItemIcon-fz291V {
1450
+ flex-shrink: 0;
1451
+ justify-content: center;
1452
+ align-items: center;
1453
+ width: 14px;
1454
+ height: 14px;
1455
+ display: inline-flex;
1456
+ }
1457
+
1458
+ .overflowItemHidden-k4aawi {
1459
+ display: none;
1460
+ }
1461
+
1253
1462
  .tabDisabled-lDuv5l {
1254
1463
  opacity: .5;
1255
1464
  cursor: not-allowed;
@@ -1270,7 +1479,7 @@ var __webpack_modules__ = {
1270
1479
  }
1271
1480
 
1272
1481
  @media (prefers-reduced-motion: reduce) {
1273
- .tab-yfDEqg {
1482
+ .tab-yfDEqg, .overflowButton-tKq4FF, .overflowMenu-TST0eZ, .overflowItem-y5Pz7k {
1274
1483
  transition: none;
1275
1484
  }
1276
1485
  }
@@ -1286,9 +1495,21 @@ var __webpack_modules__ = {
1286
1495
  ]);
1287
1496
  ___CSS_LOADER_EXPORT___.locals = {
1288
1497
  tabList: "tabList-IyuiBE",
1498
+ tabStrip: "tabStrip-_KrWe4",
1289
1499
  tab: "tab-yfDEqg",
1290
1500
  tabActive: "tabActive-r4hing",
1291
1501
  tabIcon: "tabIcon-U9tnu0",
1502
+ tabHidden: "tabHidden-HBXYSd",
1503
+ overflowContainer: "overflowContainer-TTw9DO",
1504
+ overflowContainerHidden: "overflowContainerHidden-sQa_XZ",
1505
+ overflowButton: "overflowButton-tKq4FF",
1506
+ overflowButtonIcon: "overflowButtonIcon-FSurfC",
1507
+ overflowMenu: "overflowMenu-TST0eZ",
1508
+ overflowItem: "overflowItem-y5Pz7k",
1509
+ overflowItemActive: "overflowItemActive-mzVG1T",
1510
+ overflowItemDisabled: "overflowItemDisabled-dcHX3K",
1511
+ overflowItemIcon: "overflowItemIcon-fz291V",
1512
+ overflowItemHidden: "overflowItemHidden-k4aawi",
1292
1513
  tabDisabled: "tabDisabled-lDuv5l",
1293
1514
  tabPanel: "tabPanel-QKO8FX",
1294
1515
  tabPanelActive: "tabPanelActive-mrNlGE"
@@ -1312,6 +1533,15 @@ var __webpack_modules__ = {
1312
1533
  --c15t-devtools-button-size: 40px;
1313
1534
  --c15t-devtools-z-index: 99999;
1314
1535
  --c15t-devtools-surface-muted: var(--c15t-surface-hover, #f7f7f7);
1536
+ --c15t-devtools-surface-subtle: #fafafa;
1537
+ --c15t-devtools-surface-elevated: var(--c15t-surface, #fff);
1538
+ --c15t-devtools-border-strong: var(--c15t-border, #e3e3e3);
1539
+ --c15t-devtools-code-surface: #f7f7f7;
1540
+ --c15t-devtools-accent-soft: #ebefff;
1541
+ --c15t-devtools-focus-ring: var(--c15t-primary, #335cff);
1542
+ --c15t-devtools-text-muted: var(--c15t-text-muted, #737373);
1543
+ --c15t-devtools-font-size-sm: var(--c15t-font-size-sm, .875rem);
1544
+ --c15t-surface-muted: var(--c15t-devtools-surface-muted, #f7f7f7);
1315
1545
  --c15t-devtools-font-size-xs: .75rem;
1316
1546
  --c15t-devtools-badge-success: #21c45d;
1317
1547
  --c15t-devtools-badge-success-bg: #e4fbed;
@@ -1325,8 +1555,37 @@ var __webpack_modules__ = {
1325
1555
  --c15t-devtools-badge-neutral-bg: #f0f0f0;
1326
1556
  }
1327
1557
 
1558
+ :is(:global(.c15t-light), :global(.light)) {
1559
+ --c15t-devtools-surface-muted: var(--c15t-surface-hover, #f7f7f7);
1560
+ --c15t-devtools-surface-subtle: #fafafa;
1561
+ --c15t-devtools-surface-elevated: var(--c15t-surface, #fff);
1562
+ --c15t-devtools-border-strong: var(--c15t-border, #e3e3e3);
1563
+ --c15t-devtools-code-surface: #f7f7f7;
1564
+ --c15t-devtools-accent-soft: #ebefff;
1565
+ --c15t-devtools-badge-success-bg: #e4fbed;
1566
+ --c15t-devtools-badge-error-bg: #fde7e7;
1567
+ --c15t-devtools-badge-warning-bg: #fef7dc;
1568
+ --c15t-devtools-badge-info-bg: #dcebfe;
1569
+ --c15t-devtools-badge-neutral-bg: #f0f0f0;
1570
+ }
1571
+
1572
+ @supports (color: color-mix(in srgb, white, black)) {
1573
+ :root {
1574
+ --c15t-devtools-surface-muted: color-mix(in srgb, var(--c15t-surface-hover, #f7f7f7) 85%, var(--c15t-surface, #fff));
1575
+ --c15t-devtools-surface-subtle: color-mix(in srgb, var(--c15t-surface-hover, #f7f7f7) 55%, var(--c15t-surface, #fff));
1576
+ --c15t-devtools-border-strong: color-mix(in srgb, var(--c15t-border, #e3e3e3) 80%, var(--c15t-text-muted, #737373));
1577
+ --c15t-devtools-code-surface: color-mix(in srgb, var(--c15t-surface-hover, #f7f7f7) 70%, var(--c15t-surface, #fff));
1578
+ --c15t-devtools-accent-soft: color-mix(in srgb, var(--c15t-primary, #335cff) 12%, transparent);
1579
+ }
1580
+ }
1581
+
1328
1582
  :is(:global(.c15t-dark), :global(.dark)) {
1329
1583
  --c15t-devtools-surface-muted: var(--c15t-surface-hover, #292929);
1584
+ --c15t-devtools-surface-subtle: #242424;
1585
+ --c15t-devtools-surface-elevated: var(--c15t-surface, #1a1a1a);
1586
+ --c15t-devtools-border-strong: var(--c15t-border, #3d3d3d);
1587
+ --c15t-devtools-code-surface: #212121;
1588
+ --c15t-devtools-accent-soft: #335cff33;
1330
1589
  --c15t-devtools-badge-success-bg: #21c45d33;
1331
1590
  --c15t-devtools-badge-error-bg: #ef434333;
1332
1591
  --c15t-devtools-badge-warning-bg: #f59f0a33;
@@ -1335,8 +1594,13 @@ var __webpack_modules__ = {
1335
1594
  }
1336
1595
 
1337
1596
  @media (prefers-color-scheme: dark) {
1338
- :root {
1597
+ :global(:root:not(.light):not(.c15t-light)) {
1339
1598
  --c15t-devtools-surface-muted: var(--c15t-surface-hover, #292929);
1599
+ --c15t-devtools-surface-subtle: #242424;
1600
+ --c15t-devtools-surface-elevated: var(--c15t-surface, #1a1a1a);
1601
+ --c15t-devtools-border-strong: var(--c15t-border, #3d3d3d);
1602
+ --c15t-devtools-code-surface: #212121;
1603
+ --c15t-devtools-accent-soft: #335cff33;
1340
1604
  --c15t-devtools-badge-success-bg: #21c45d33;
1341
1605
  --c15t-devtools-badge-error-bg: #ef434333;
1342
1606
  --c15t-devtools-badge-warning-bg: #f59f0a33;
@@ -1844,7 +2108,7 @@ function renderer_button(options = {}) {
1844
2108
  type: options.type ?? 'button'
1845
2109
  });
1846
2110
  }
1847
- function span(options = {}) {
2111
+ function renderer_span(options = {}) {
1848
2112
  return createElement({
1849
2113
  ...options,
1850
2114
  tag: 'span'
@@ -1923,7 +2187,29 @@ panel_module_options.domAPI = styleDomAPI_default();
1923
2187
  panel_module_options.insertStyleElement = insertStyleElement_default();
1924
2188
  injectStylesIntoStyleTag_default()(panel_module.A, panel_module_options);
1925
2189
  const styles_panel_module = panel_module.A && panel_module.A.locals ? panel_module.A.locals : void 0;
1926
- const PREFERENCE_TRIGGER_SELECTORS = '[data-c15t-trigger], [aria-label*="privacy settings"], [aria-label*="preference"]';
2190
+ function formatInitSource(source, detail) {
2191
+ const label = (()=>{
2192
+ switch(source){
2193
+ case 'ssr':
2194
+ return 'SSR Prefetch';
2195
+ case 'backend':
2196
+ return 'Backend';
2197
+ case 'backend-cache-hit':
2198
+ return 'Backend (Cache Hit)';
2199
+ case 'offline-fallback':
2200
+ return 'Offline Fallback';
2201
+ case 'offline-mode':
2202
+ return 'Offline Mode';
2203
+ case 'custom':
2204
+ return 'Custom Client';
2205
+ default:
2206
+ return '—';
2207
+ }
2208
+ })();
2209
+ return detail ? `${label} [${detail}]` : label;
2210
+ }
2211
+ const PREFERENCE_TRIGGER_SELECTORS = '[data-c15t-trigger], [aria-label*="privacy settings" i], [aria-label*="preference" i]';
2212
+ const PREVIOUS_DISPLAY_ATTR = 'data-c15t-devtools-prev-display';
1927
2213
  function detectPreferenceTrigger() {
1928
2214
  const triggers = document.querySelectorAll(PREFERENCE_TRIGGER_SELECTORS);
1929
2215
  return triggers.length > 0;
@@ -1933,7 +2219,19 @@ function getPreferenceTriggerElements() {
1933
2219
  }
1934
2220
  function setPreferenceTriggerVisibility(visible) {
1935
2221
  const elements = getPreferenceTriggerElements();
1936
- for (const el of elements)el.style.display = visible ? '' : 'none';
2222
+ for (const el of elements){
2223
+ if (visible) {
2224
+ const previousDisplay = el.getAttribute(PREVIOUS_DISPLAY_ATTR);
2225
+ if (null === previousDisplay) el.style.removeProperty('display');
2226
+ else {
2227
+ el.style.display = previousDisplay;
2228
+ el.removeAttribute(PREVIOUS_DISPLAY_ATTR);
2229
+ }
2230
+ continue;
2231
+ }
2232
+ if (!el.hasAttribute(PREVIOUS_DISPLAY_ATTR)) el.setAttribute(PREVIOUS_DISPLAY_ATTR, el.style.display);
2233
+ el.style.display = 'none';
2234
+ }
1937
2235
  }
1938
2236
  function getPreferenceCenterOpener(namespace = 'c15tStore') {
1939
2237
  const win = window;
@@ -1946,7 +2244,7 @@ function getPreferenceCenterOpener(namespace = 'c15tStore') {
1946
2244
  }
1947
2245
  return null;
1948
2246
  }
1949
- const version = '2.0.0-rc.3';
2247
+ const version = '2.0.0-rc.5';
1950
2248
  const DEVTOOLS_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 446 445" aria-label="c15t">
1951
2249
  <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"/>
1952
2250
  </svg>`;
@@ -2027,7 +2325,7 @@ function createDropdownMenu(options) {
2027
2325
  const labelContainer = renderer_div({
2028
2326
  className: styles_panel_module.menuItemContent ?? ''
2029
2327
  });
2030
- const label = span({
2328
+ const label = renderer_span({
2031
2329
  className: styles_panel_module.menuItemLabel ?? '',
2032
2330
  text: item.label
2033
2331
  });
@@ -2149,6 +2447,11 @@ function getPositionClass(position) {
2149
2447
  return styles_panel_module.positionTopLeft ?? '';
2150
2448
  }
2151
2449
  }
2450
+ function formatRetryDelay(delayMs) {
2451
+ if (null === delayMs) return 'n/a';
2452
+ if (delayMs < 1000) return `${delayMs}ms`;
2453
+ return `${(delayMs / 1000).toFixed(1)}s`;
2454
+ }
2152
2455
  function createPanel(options) {
2153
2456
  const { stateManager, storeConnector, onRenderContent, namespace = 'c15tStore', enableUnifiedMode = true } = options;
2154
2457
  let removePortal = null;
@@ -2280,7 +2583,7 @@ function createPanel(options) {
2280
2583
  }));
2281
2584
  return logoWrapper;
2282
2585
  })(),
2283
- span({
2586
+ renderer_span({
2284
2587
  text: 'c15t DevTools'
2285
2588
  })
2286
2589
  ]
@@ -2324,38 +2627,46 @@ function createPanel(options) {
2324
2627
  const isConnected = storeConnector.isConnected();
2325
2628
  const storeState = storeConnector.getState();
2326
2629
  const isLoading = storeState?.isLoadingConsentInfo ?? false;
2630
+ const diagnostics = storeConnector.getDiagnostics();
2631
+ const initSource = formatInitSource(storeState?.initDataSource ?? null, storeState?.initDataSourceDetail ?? null);
2327
2632
  const statusChildren = [
2328
- span({
2633
+ renderer_span({
2329
2634
  className: `${styles_panel_module.statusDot} ${isConnected ? styles_panel_module.statusConnected : styles_panel_module.statusDisconnected}`
2330
2635
  }),
2331
- span({
2636
+ renderer_span({
2332
2637
  text: isConnected ? 'Connected' : 'Disconnected'
2333
2638
  })
2334
2639
  ];
2335
- if (isLoading) statusChildren.push(span({
2336
- style: {
2337
- marginLeft: '4px',
2338
- opacity: '0.7'
2339
- },
2640
+ if (isLoading) statusChildren.push(renderer_span({
2641
+ className: styles_panel_module.footerMeta,
2340
2642
  text: '\u00b7 Fetching /init\u2026'
2341
2643
  }));
2644
+ else if (!isConnected) statusChildren.push(renderer_span({
2645
+ className: styles_panel_module.footerMeta,
2646
+ text: `· ${diagnostics.namespace} · retry ${diagnostics.reconnectAttempts} · next ${formatRetryDelay(diagnostics.nextRetryInMs)}`
2647
+ }));
2648
+ if (isConnected) statusChildren.push(renderer_span({
2649
+ className: styles_panel_module.footerMeta,
2650
+ text: `· Init: ${initSource}`
2651
+ }));
2342
2652
  footerElement.appendChild(renderer_div({
2343
2653
  className: styles_panel_module.footerStatus,
2344
2654
  children: statusChildren
2345
2655
  }));
2346
2656
  if (!isConnected) footerElement.appendChild(renderer_button({
2347
- className: styles_panel_module.closeButton,
2657
+ className: styles_panel_module.inlineActionButton,
2348
2658
  text: 'Retry',
2349
2659
  onClick: ()=>{
2350
2660
  storeConnector.retryConnection();
2351
2661
  }
2352
2662
  }));
2353
- footerElement.appendChild(span({
2663
+ footerElement.appendChild(renderer_span({
2354
2664
  text: `v${version}`
2355
2665
  }));
2356
2666
  }
2357
2667
  function renderErrorState(container) {
2358
2668
  clearElement(container);
2669
+ const diagnostics = storeConnector.getDiagnostics();
2359
2670
  const errorState = renderer_div({
2360
2671
  className: styles_panel_module.errorState,
2361
2672
  children: [
@@ -2377,8 +2688,25 @@ function createPanel(options) {
2377
2688
  className: styles_panel_module.errorMessage,
2378
2689
  text: 'c15t consent manager is not initialized. Make sure you have set up the ConsentManagerProvider in your app.'
2379
2690
  }),
2691
+ renderer_div({
2692
+ className: styles_panel_module.errorMessage,
2693
+ style: {
2694
+ marginTop: '4px',
2695
+ fontSize: 'var(--c15t-devtools-font-size-xs)'
2696
+ },
2697
+ text: `Namespace: ${diagnostics.namespace} · Retries: ${diagnostics.reconnectAttempts} · Next retry: ${formatRetryDelay(diagnostics.nextRetryInMs)}`
2698
+ }),
2699
+ diagnostics.lastError ? renderer_div({
2700
+ className: styles_panel_module.errorMessage,
2701
+ style: {
2702
+ marginTop: '4px',
2703
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
2704
+ color: 'var(--c15t-text-muted)'
2705
+ },
2706
+ text: `Last error: ${diagnostics.lastError}`
2707
+ }) : null,
2380
2708
  renderer_button({
2381
- className: styles_panel_module.closeButton,
2709
+ className: styles_panel_module.inlineActionButton,
2382
2710
  text: 'Retry Connection',
2383
2711
  onClick: ()=>{
2384
2712
  storeConnector.retryConnection();
@@ -2441,6 +2769,10 @@ function createPanel(options) {
2441
2769
  if (contentContainer) if (storeConnector.isConnected()) onRenderContent(contentContainer);
2442
2770
  else renderErrorState(contentContainer);
2443
2771
  });
2772
+ const unsubscribeDiagnostics = storeConnector.subscribeDiagnostics(()=>{
2773
+ updateFooter();
2774
+ if (contentContainer && !storeConnector.isConnected()) renderErrorState(contentContainer);
2775
+ });
2444
2776
  container.appendChild(floatingButton);
2445
2777
  removePortal = createPortal(container);
2446
2778
  return {
@@ -2450,6 +2782,7 @@ function createPanel(options) {
2450
2782
  destroy: ()=>{
2451
2783
  unsubscribeState();
2452
2784
  unsubscribeStore();
2785
+ unsubscribeDiagnostics();
2453
2786
  if (dropdownMenu) {
2454
2787
  dropdownMenu.destroy();
2455
2788
  dropdownMenu = null;
@@ -2483,6 +2816,11 @@ const LOCATION_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 2
2483
2816
  <line x1="2" y1="12" x2="22" y2="12"></line>
2484
2817
  <path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
2485
2818
  </svg>`;
2819
+ const POLICY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2820
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
2821
+ <path d="M9 12h6"></path>
2822
+ <path d="M12 9v6"></path>
2823
+ </svg>`;
2486
2824
  const SCRIPTS_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2487
2825
  <polyline points="16 18 22 12 16 6"></polyline>
2488
2826
  <polyline points="8 6 2 12 8 18"></polyline>
@@ -2499,12 +2837,22 @@ const EVENTS_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
2499
2837
  <path d="M12 20h9"></path>
2500
2838
  <path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"></path>
2501
2839
  </svg>`;
2840
+ const MORE_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
2841
+ <circle cx="12" cy="5" r="1.75"></circle>
2842
+ <circle cx="12" cy="12" r="1.75"></circle>
2843
+ <circle cx="12" cy="19" r="1.75"></circle>
2844
+ </svg>`;
2502
2845
  const TABS = [
2503
2846
  {
2504
2847
  id: 'location',
2505
2848
  label: 'Location',
2506
2849
  icon: LOCATION_ICON
2507
2850
  },
2851
+ {
2852
+ id: 'policy',
2853
+ label: 'Policy',
2854
+ icon: POLICY_ICON
2855
+ },
2508
2856
  {
2509
2857
  id: 'consents',
2510
2858
  label: 'Consents',
@@ -2534,12 +2882,56 @@ const TABS = [
2534
2882
  function tabs_createTabs(options) {
2535
2883
  const { onTabChange, disabledTabs = [] } = options;
2536
2884
  let activeTab = options.activeTab;
2885
+ let isOverflowMenuOpen = false;
2886
+ let visibleTabIds = [];
2887
+ let hiddenTabIds = [];
2537
2888
  const tabButtons = new Map();
2889
+ const overflowButtons = new Map();
2538
2890
  const tabList = renderer_div({
2539
- className: styles_tabs_module.tabList,
2891
+ className: styles_tabs_module.tabList
2892
+ });
2893
+ const tabStrip = renderer_div({
2894
+ className: styles_tabs_module.tabStrip,
2540
2895
  role: 'tablist',
2541
2896
  ariaLabel: 'DevTools tabs'
2542
2897
  });
2898
+ tabList.appendChild(tabStrip);
2899
+ const overflowMenu = renderer_div({
2900
+ className: styles_tabs_module.overflowMenu,
2901
+ role: 'menu',
2902
+ ariaLabel: 'All tabs'
2903
+ });
2904
+ overflowMenu.dataset.state = 'closed';
2905
+ const overflowButton = renderer_button({
2906
+ className: styles_tabs_module.overflowButton,
2907
+ ariaLabel: 'More tabs',
2908
+ ariaExpanded: 'false',
2909
+ onClick: ()=>toggleOverflowMenu(),
2910
+ onKeyDown: (e)=>{
2911
+ if ('ArrowDown' === e.key || 'Enter' === e.key || ' ' === e.key) {
2912
+ e.preventDefault();
2913
+ openOverflowMenu();
2914
+ focusFirstEnabledOverflowItem();
2915
+ }
2916
+ }
2917
+ });
2918
+ overflowButton.setAttribute('aria-haspopup', 'menu');
2919
+ const overflowIcon = renderer_div({
2920
+ className: styles_tabs_module.overflowButtonIcon
2921
+ });
2922
+ overflowIcon.appendChild(createSvgElement(MORE_ICON, {
2923
+ width: 14,
2924
+ height: 14
2925
+ }));
2926
+ overflowButton.appendChild(overflowIcon);
2927
+ const overflowContainer = renderer_div({
2928
+ className: styles_tabs_module.overflowContainer,
2929
+ children: [
2930
+ overflowButton,
2931
+ overflowMenu
2932
+ ]
2933
+ });
2934
+ tabList.appendChild(overflowContainer);
2543
2935
  for (const tab of TABS){
2544
2936
  const isActive = tab.id === activeTab;
2545
2937
  const isDisabled = disabledTabs.includes(tab.id);
@@ -2553,6 +2945,7 @@ function tabs_createTabs(options) {
2553
2945
  disabled: isDisabled,
2554
2946
  onClick: ()=>{
2555
2947
  if (!isDisabled) {
2948
+ closeOverflowMenu();
2556
2949
  setActiveTab(tab.id);
2557
2950
  onTabChange(tab.id);
2558
2951
  }
@@ -2569,14 +2962,192 @@ function tabs_createTabs(options) {
2569
2962
  tabButton.appendChild(iconWrapper);
2570
2963
  tabButton.appendChild(document.createTextNode(tab.label));
2571
2964
  tabButtons.set(tab.id, tabButton);
2572
- tabList.appendChild(tabButton);
2573
- }
2574
- function handleKeyDown(e, currentTab) {
2575
- const tabIds = TABS.map((t)=>t.id);
2576
- const enabledTabIds = tabIds.filter((id)=>!disabledTabs.includes(id));
2577
- const currentIndex = enabledTabIds.indexOf(currentTab);
2578
- let newIndex = currentIndex;
2579
- switch(e.key){
2965
+ tabStrip.appendChild(tabButton);
2966
+ const overflowItem = renderer_button({
2967
+ className: `${styles_tabs_module.overflowItem} ${isActive ? styles_tabs_module.overflowItemActive : ''} ${isDisabled ? styles_tabs_module.overflowItemDisabled : ''}`,
2968
+ role: 'menuitemradio',
2969
+ ariaChecked: isActive ? 'true' : 'false',
2970
+ disabled: isDisabled,
2971
+ onClick: ()=>{
2972
+ if (!isDisabled) {
2973
+ setActiveTab(tab.id);
2974
+ onTabChange(tab.id);
2975
+ closeOverflowMenu();
2976
+ tabButtons.get(tab.id)?.focus();
2977
+ }
2978
+ },
2979
+ onKeyDown: (e)=>handleOverflowKeyDown(e, tab.id)
2980
+ });
2981
+ const overflowItemIcon = renderer_div({
2982
+ className: styles_tabs_module.overflowItemIcon
2983
+ });
2984
+ overflowItemIcon.appendChild(createSvgElement(tab.icon, {
2985
+ width: 14,
2986
+ height: 14
2987
+ }));
2988
+ overflowItem.appendChild(overflowItemIcon);
2989
+ overflowItem.appendChild(document.createTextNode(tab.label));
2990
+ overflowButtons.set(tab.id, overflowItem);
2991
+ overflowMenu.appendChild(overflowItem);
2992
+ }
2993
+ function applyActiveState(tab) {
2994
+ for (const [tabId, tabButton] of tabButtons){
2995
+ const isActive = tabId === tab;
2996
+ if (styles_tabs_module.tabActive) tabButton.classList.toggle(styles_tabs_module.tabActive, isActive);
2997
+ tabButton.setAttribute('aria-selected', isActive ? 'true' : 'false');
2998
+ tabButton.tabIndex = isActive ? 0 : -1;
2999
+ }
3000
+ for (const [tabId, overflowItem] of overflowButtons){
3001
+ const isActive = tabId === tab;
3002
+ if (styles_tabs_module.overflowItemActive) overflowItem.classList.toggle(styles_tabs_module.overflowItemActive, isActive);
3003
+ overflowItem.setAttribute('aria-checked', isActive ? 'true' : 'false');
3004
+ }
3005
+ }
3006
+ function updateVisibleTabs() {
3007
+ const allTabIds = TABS.map((t)=>t.id);
3008
+ const iabEnabled = !disabledTabs.includes('iab');
3009
+ const preferredSecondTab = iabEnabled ? 'iab' : 'consents';
3010
+ const overflowSecondTab = iabEnabled ? 'consents' : 'iab';
3011
+ const showOverflowSecondTabInStrip = activeTab === overflowSecondTab;
3012
+ const stripSecondTab = showOverflowSecondTabInStrip ? overflowSecondTab : preferredSecondTab;
3013
+ const forcedOverflowTab = showOverflowSecondTabInStrip ? preferredSecondTab : overflowSecondTab;
3014
+ const layoutTabIds = [
3015
+ 'location',
3016
+ 'policy',
3017
+ stripSecondTab,
3018
+ "scripts",
3019
+ 'actions',
3020
+ 'events',
3021
+ forcedOverflowTab
3022
+ ];
3023
+ const forcedOverflowTabIds = new Set();
3024
+ forcedOverflowTabIds.add(forcedOverflowTab);
3025
+ for (const [index, tabId] of layoutTabIds.entries()){
3026
+ const tabButton = tabButtons.get(tabId);
3027
+ if (tabButton) tabButton.style.order = String(index);
3028
+ const overflowItem = overflowButtons.get(tabId);
3029
+ if (overflowItem) overflowItem.style.order = String(index);
3030
+ }
3031
+ for (const tabId of allTabIds){
3032
+ const tabButton = tabButtons.get(tabId);
3033
+ if (tabButton && styles_tabs_module.tabHidden) tabButton.classList.remove(styles_tabs_module.tabHidden);
3034
+ }
3035
+ if (styles_tabs_module.overflowContainerHidden) overflowContainer.classList.remove(styles_tabs_module.overflowContainerHidden);
3036
+ const stripGap = Number.parseFloat(getComputedStyle(tabStrip).gap || '0');
3037
+ const calculateVisibleTabs = (availableWidth)=>{
3038
+ if (availableWidth <= 0) return [];
3039
+ const nextVisible = [];
3040
+ let usedWidth = 0;
3041
+ for (const tabId of layoutTabIds){
3042
+ if (forcedOverflowTabIds.has(tabId)) continue;
3043
+ const tabButton = tabButtons.get(tabId);
3044
+ if (!tabButton) continue;
3045
+ const width = tabButton.getBoundingClientRect().width;
3046
+ const nextUsed = 0 === nextVisible.length ? width : usedWidth + stripGap + width;
3047
+ if (nextUsed <= availableWidth) {
3048
+ nextVisible.push(tabId);
3049
+ usedWidth = nextUsed;
3050
+ } else break;
3051
+ }
3052
+ return nextVisible;
3053
+ };
3054
+ const measureStripWidth = ()=>tabStrip.getBoundingClientRect().width;
3055
+ const showOverflowContainer = ()=>{
3056
+ if (styles_tabs_module.overflowContainerHidden) overflowContainer.classList.remove(styles_tabs_module.overflowContainerHidden);
3057
+ };
3058
+ const hideOverflowContainer = ()=>{
3059
+ if (styles_tabs_module.overflowContainerHidden) overflowContainer.classList.add(styles_tabs_module.overflowContainerHidden);
3060
+ };
3061
+ const measureVisibleWidth = (tabIds)=>{
3062
+ let width = 0;
3063
+ for (const [index, tabId] of tabIds.entries()){
3064
+ const tabButton = tabButtons.get(tabId);
3065
+ if (tabButton) {
3066
+ width += tabButton.getBoundingClientRect().width;
3067
+ if (index > 0) width += stripGap;
3068
+ }
3069
+ }
3070
+ return width;
3071
+ };
3072
+ if (0 === forcedOverflowTabIds.size) {
3073
+ hideOverflowContainer();
3074
+ const visibleWithoutOverflow = calculateVisibleTabs(measureStripWidth());
3075
+ if (visibleWithoutOverflow.length === layoutTabIds.length) visibleTabIds = visibleWithoutOverflow;
3076
+ else {
3077
+ showOverflowContainer();
3078
+ visibleTabIds = calculateVisibleTabs(measureStripWidth());
3079
+ }
3080
+ } else {
3081
+ showOverflowContainer();
3082
+ const withOverflow = calculateVisibleTabs(measureStripWidth());
3083
+ visibleTabIds = withOverflow.length > 0 ? withOverflow : [
3084
+ activeTab
3085
+ ];
3086
+ }
3087
+ if (!visibleTabIds.includes(activeTab) && !disabledTabs.includes(activeTab)) if (visibleTabIds.length > 0) visibleTabIds[visibleTabIds.length - 1] = activeTab;
3088
+ else visibleTabIds = [
3089
+ activeTab
3090
+ ];
3091
+ visibleTabIds = [
3092
+ ...new Set(visibleTabIds)
3093
+ ];
3094
+ const maxStripWidth = measureStripWidth();
3095
+ while(visibleTabIds.length > 1 && measureVisibleWidth(visibleTabIds) > maxStripWidth + 0.5){
3096
+ let removeIndex = visibleTabIds.length - 1;
3097
+ if (visibleTabIds[removeIndex] === activeTab) removeIndex = Math.max(0, removeIndex - 1);
3098
+ visibleTabIds.splice(removeIndex, 1);
3099
+ }
3100
+ hiddenTabIds = layoutTabIds.filter((tabId)=>!visibleTabIds.includes(tabId) || forcedOverflowTabIds.has(tabId) && tabId !== activeTab);
3101
+ for (const tabId of allTabIds){
3102
+ const tabButton = tabButtons.get(tabId);
3103
+ if (tabButton) {
3104
+ if (styles_tabs_module.tabHidden) tabButton.classList.toggle(styles_tabs_module.tabHidden, hiddenTabIds.includes(tabId));
3105
+ }
3106
+ }
3107
+ for (const tabId of allTabIds){
3108
+ const overflowItem = overflowButtons.get(tabId);
3109
+ if (overflowItem) {
3110
+ if (styles_tabs_module.overflowItemHidden) overflowItem.classList.toggle(styles_tabs_module.overflowItemHidden, !hiddenTabIds.includes(tabId));
3111
+ }
3112
+ }
3113
+ if (styles_tabs_module.overflowContainerHidden) overflowContainer.classList.toggle(styles_tabs_module.overflowContainerHidden, 0 === hiddenTabIds.length);
3114
+ if (0 === hiddenTabIds.length) closeOverflowMenu();
3115
+ }
3116
+ function focusFirstEnabledOverflowItem() {
3117
+ const firstEnabled = hiddenTabIds.find((tabId)=>!disabledTabs.includes(tabId));
3118
+ if (firstEnabled) overflowButtons.get(firstEnabled)?.focus();
3119
+ }
3120
+ function openOverflowMenu() {
3121
+ if (isOverflowMenuOpen || 0 === hiddenTabIds.length) return;
3122
+ isOverflowMenuOpen = true;
3123
+ overflowMenu.dataset.state = 'open';
3124
+ overflowButton.setAttribute('aria-expanded', 'true');
3125
+ document.addEventListener('click', handleOutsideClick);
3126
+ document.addEventListener('keydown', handleEscapeKey);
3127
+ }
3128
+ function closeOverflowMenu() {
3129
+ if (!isOverflowMenuOpen) return;
3130
+ isOverflowMenuOpen = false;
3131
+ overflowMenu.dataset.state = 'closed';
3132
+ overflowButton.setAttribute('aria-expanded', 'false');
3133
+ document.removeEventListener('click', handleOutsideClick);
3134
+ document.removeEventListener('keydown', handleEscapeKey);
3135
+ }
3136
+ function toggleOverflowMenu() {
3137
+ if (isOverflowMenuOpen) closeOverflowMenu();
3138
+ else openOverflowMenu();
3139
+ }
3140
+ function handleOutsideClick(e) {
3141
+ if (!overflowContainer.contains(e.target)) closeOverflowMenu();
3142
+ }
3143
+ function handleEscapeKey(e) {
3144
+ if ('Escape' === e.key) closeOverflowMenu();
3145
+ }
3146
+ function handleKeyDown(e, currentTab) {
3147
+ const enabledTabIds = visibleTabIds.filter((tabId)=>!disabledTabs.includes(tabId));
3148
+ const currentIndex = enabledTabIds.indexOf(currentTab);
3149
+ let newIndex = currentIndex;
3150
+ switch(e.key){
2580
3151
  case 'ArrowLeft':
2581
3152
  newIndex = currentIndex > 0 ? currentIndex - 1 : enabledTabIds.length - 1;
2582
3153
  break;
@@ -2600,23 +3171,152 @@ function tabs_createTabs(options) {
2600
3171
  tabButtons.get(newTab)?.focus();
2601
3172
  }
2602
3173
  }
3174
+ function handleOverflowKeyDown(e, currentTab) {
3175
+ const enabledTabIds = hiddenTabIds.filter((tabId)=>!disabledTabs.includes(tabId));
3176
+ const currentIndex = enabledTabIds.indexOf(currentTab);
3177
+ if ('Escape' === e.key) {
3178
+ e.preventDefault();
3179
+ closeOverflowMenu();
3180
+ overflowButton.focus();
3181
+ return;
3182
+ }
3183
+ let newIndex = currentIndex;
3184
+ switch(e.key){
3185
+ case 'ArrowDown':
3186
+ newIndex = (currentIndex + 1) % enabledTabIds.length;
3187
+ break;
3188
+ case 'ArrowUp':
3189
+ newIndex = currentIndex > 0 ? currentIndex - 1 : enabledTabIds.length - 1;
3190
+ break;
3191
+ default:
3192
+ return;
3193
+ }
3194
+ e.preventDefault();
3195
+ const newTab = enabledTabIds[newIndex];
3196
+ if (newTab) overflowButtons.get(newTab)?.focus();
3197
+ }
2603
3198
  function setActiveTab(tab) {
2604
3199
  activeTab = tab;
2605
- for (const [tabId, tabButton] of tabButtons){
2606
- const isActive = tabId === tab;
2607
- if (styles_tabs_module.tabActive) tabButton.classList.toggle(styles_tabs_module.tabActive, isActive);
2608
- tabButton.setAttribute('aria-selected', isActive ? 'true' : 'false');
2609
- tabButton.tabIndex = isActive ? 0 : -1;
2610
- }
3200
+ applyActiveState(tab);
3201
+ updateVisibleTabs();
2611
3202
  }
3203
+ const handleWindowResize = ()=>{
3204
+ updateVisibleTabs();
3205
+ };
3206
+ let resizeObserver = null;
3207
+ if ('undefined' != typeof ResizeObserver) {
3208
+ resizeObserver = new ResizeObserver(()=>{
3209
+ updateVisibleTabs();
3210
+ });
3211
+ resizeObserver.observe(tabList);
3212
+ } else window.addEventListener('resize', handleWindowResize);
3213
+ applyActiveState(activeTab);
3214
+ requestAnimationFrame(()=>{
3215
+ updateVisibleTabs();
3216
+ });
2612
3217
  return {
2613
3218
  element: tabList,
2614
3219
  setActiveTab,
2615
3220
  destroy: ()=>{
3221
+ closeOverflowMenu();
3222
+ if (resizeObserver) {
3223
+ resizeObserver.disconnect();
3224
+ resizeObserver = null;
3225
+ } else window.removeEventListener('resize', handleWindowResize);
2616
3226
  tabButtons.clear();
3227
+ overflowButtons.clear();
2617
3228
  }
2618
3229
  };
2619
3230
  }
3231
+ function debug_bundle_createDebugBundle(payload) {
3232
+ const { namespace, devToolsState, connection, recentEvents, storeState } = payload;
3233
+ const bundle = {
3234
+ generatedAt: new Date().toISOString(),
3235
+ namespace,
3236
+ devToolsState,
3237
+ connection,
3238
+ recentEvents,
3239
+ storeState,
3240
+ overrides: storeState?.overrides ?? null,
3241
+ iab: storeState?.iab ? {
3242
+ tcString: (storeState?.iab).tcString ?? null,
3243
+ purposeCount: Object.keys((storeState?.iab).purposeConsents ?? {}).length,
3244
+ vendorCount: Object.keys((storeState?.iab).vendorConsents ?? {}).length
3245
+ } : null
3246
+ };
3247
+ return JSON.stringify(bundle, null, 2);
3248
+ }
3249
+ function debug_bundle_sanitizeStoreState(state) {
3250
+ if (!state) return null;
3251
+ try {
3252
+ return JSON.parse(JSON.stringify(state, (_key, value)=>'function' == typeof value ? void 0 : value));
3253
+ } catch {
3254
+ return {
3255
+ error: 'Unable to serialize store state'
3256
+ };
3257
+ }
3258
+ }
3259
+ function debug_bundle_downloadDebugBundle(content) {
3260
+ const blob = new Blob([
3261
+ content
3262
+ ], {
3263
+ type: 'application/json'
3264
+ });
3265
+ const url = URL.createObjectURL(blob);
3266
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
3267
+ const anchor = document.createElement('a');
3268
+ anchor.href = url;
3269
+ anchor.download = `c15t-debug-bundle-${timestamp}.json`;
3270
+ anchor.click();
3271
+ URL.revokeObjectURL(url);
3272
+ }
3273
+ const DEVTOOLS_OVERRIDES_STORAGE_KEY = 'c15t-devtools-overrides';
3274
+ function normalizeStringValue(value) {
3275
+ if ('string' != typeof value) return;
3276
+ const normalized = value.trim();
3277
+ return normalized.length > 0 ? normalized : void 0;
3278
+ }
3279
+ function normalizeBooleanValue(value) {
3280
+ return 'boolean' == typeof value ? value : void 0;
3281
+ }
3282
+ function normalizeOverrides(value) {
3283
+ if (!value || 'object' != typeof value) return null;
3284
+ const source = value;
3285
+ const overrides = {
3286
+ country: normalizeStringValue(source.country),
3287
+ region: normalizeStringValue(source.region),
3288
+ language: normalizeStringValue(source.language),
3289
+ gpc: normalizeBooleanValue(source.gpc)
3290
+ };
3291
+ return hasPersistedOverrides(overrides) ? overrides : null;
3292
+ }
3293
+ function hasPersistedOverrides(overrides) {
3294
+ return Boolean(overrides.country || overrides.region || overrides.language || void 0 !== overrides.gpc);
3295
+ }
3296
+ function override_storage_loadPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
3297
+ if ('undefined' == typeof window) return null;
3298
+ try {
3299
+ const stored = localStorage.getItem(storageKey);
3300
+ if (!stored) return null;
3301
+ const parsed = JSON.parse(stored);
3302
+ return normalizeOverrides(parsed);
3303
+ } catch {
3304
+ return null;
3305
+ }
3306
+ }
3307
+ function override_storage_persistOverrides(overrides, storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
3308
+ if ('undefined' == typeof window) return;
3309
+ try {
3310
+ if (!hasPersistedOverrides(overrides)) return void localStorage.removeItem(storageKey);
3311
+ localStorage.setItem(storageKey, JSON.stringify(overrides));
3312
+ } catch {}
3313
+ }
3314
+ function override_storage_clearPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
3315
+ if ('undefined' == typeof window) return;
3316
+ try {
3317
+ localStorage.removeItem(storageKey);
3318
+ } catch {}
3319
+ }
2620
3320
  var components_module = __webpack_require__("../../node_modules/.bun/@rsbuild+core@1.6.12/node_modules/@rsbuild/core/compiled/css-loader/index.js??ruleSet[1].rules[1].use[1]!builtin:lightningcss-loader??ruleSet[1].rules[1].use[2]!./src/styles/components.module.css");
2621
3321
  var components_module_options = {};
2622
3322
  components_module_options.styleTagTransform = styleTagTransform_default();
@@ -2653,7 +3353,7 @@ function createBadge(options) {
2653
3353
  info: styles_components_module.badgeInfo,
2654
3354
  neutral: styles_components_module.badgeNeutral
2655
3355
  }[variant];
2656
- return span({
3356
+ return renderer_span({
2657
3357
  className: `${styles_components_module.badge} ${variantClass}`,
2658
3358
  text
2659
3359
  });
@@ -2684,31 +3384,19 @@ function createButton(options) {
2684
3384
  btn.appendChild(document.createTextNode(text));
2685
3385
  return btn;
2686
3386
  }
2687
- function createListItem(options) {
2688
- const { title, description, actions = [] } = options;
2689
- const content = renderer_div({
2690
- className: styles_components_module.listItemContent,
2691
- children: [
2692
- span({
2693
- className: styles_components_module.listItemTitle,
2694
- text: title
2695
- }),
2696
- description ? span({
2697
- className: styles_components_module.listItemDescription,
2698
- text: description
2699
- }) : null
2700
- ]
2701
- });
2702
- const actionsContainer = renderer_div({
2703
- className: styles_components_module.listItemActions,
2704
- children: actions
2705
- });
2706
- return renderer_div({
2707
- className: styles_components_module.listItem,
2708
- children: [
2709
- content,
2710
- actionsContainer
2711
- ]
3387
+ function createInput(options) {
3388
+ const { value, placeholder, ariaLabel, small = false, onInput } = options;
3389
+ const sizeClass = small ? styles_components_module.inputSmall : '';
3390
+ return input({
3391
+ className: `${styles_components_module.input} ${sizeClass}`.trim(),
3392
+ type: 'text',
3393
+ value,
3394
+ placeholder,
3395
+ ariaLabel,
3396
+ onInput: (event)=>{
3397
+ const target = event.target;
3398
+ onInput?.(target?.value ?? '');
3399
+ }
2712
3400
  });
2713
3401
  }
2714
3402
  function createSection(options) {
@@ -2716,7 +3404,7 @@ function createSection(options) {
2716
3404
  const header = renderer_div({
2717
3405
  className: styles_components_module.sectionHeader,
2718
3406
  children: [
2719
- span({
3407
+ renderer_span({
2720
3408
  className: styles_components_module.sectionTitle,
2721
3409
  text: title
2722
3410
  }),
@@ -2736,11 +3424,11 @@ function createInfoRow(options) {
2736
3424
  return renderer_div({
2737
3425
  className: styles_components_module.infoRow,
2738
3426
  children: [
2739
- span({
3427
+ renderer_span({
2740
3428
  className: styles_components_module.infoLabel,
2741
3429
  text: label
2742
3430
  }),
2743
- span({
3431
+ renderer_span({
2744
3432
  className: styles_components_module.infoValue,
2745
3433
  text: value
2746
3434
  })
@@ -2760,7 +3448,7 @@ function createEmptyState(options) {
2760
3448
  }));
2761
3449
  children.push(iconWrapper);
2762
3450
  }
2763
- children.push(span({
3451
+ children.push(renderer_span({
2764
3452
  className: styles_components_module.emptyStateText,
2765
3453
  text
2766
3454
  }));
@@ -2780,7 +3468,7 @@ function createGrid(options) {
2780
3468
  function createGridCard(options) {
2781
3469
  const { title, action } = options;
2782
3470
  const children = [
2783
- span({
3471
+ renderer_span({
2784
3472
  className: styles_components_module.gridCardTitle,
2785
3473
  text: title
2786
3474
  })
@@ -2791,6 +3479,18 @@ function createGridCard(options) {
2791
3479
  children
2792
3480
  });
2793
3481
  }
3482
+ function createDisconnectedState(message = 'Store not connected') {
3483
+ return renderer_div({
3484
+ className: styles_components_module.disconnectedState,
3485
+ style: {
3486
+ padding: '24px',
3487
+ textAlign: 'center',
3488
+ color: 'var(--c15t-text-muted)',
3489
+ fontSize: 'var(--c15t-devtools-font-size-sm)'
3490
+ },
3491
+ text: message
3492
+ });
3493
+ }
2794
3494
  const REFRESH_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2795
3495
  <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path>
2796
3496
  <path d="M21 3v5h-5"></path>
@@ -2818,19 +3518,11 @@ const TERMINAL_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 2
2818
3518
  <polyline points="4 17 10 11 4 5"></polyline>
2819
3519
  <line x1="12" y1="19" x2="20" y2="19"></line>
2820
3520
  </svg>`;
2821
- function actions_renderActionsPanel(container, options) {
2822
- const { getState, onResetConsents, onRefetchBanner, onShowBanner, onOpenPreferences, onCopyState } = options;
3521
+ function renderActionsPanel(container, options) {
3522
+ const { getState, onResetConsents, onRefetchBanner, onShowBanner, onOpenPreferences, onCopyState, onExportDebugBundle } = options;
2823
3523
  clearElement(container);
2824
3524
  const state = getState();
2825
- if (!state) return void container.appendChild(renderer_div({
2826
- style: {
2827
- padding: '24px',
2828
- textAlign: 'center',
2829
- color: 'var(--c15t-text-muted)',
2830
- fontSize: 'var(--c15t-devtools-font-size-sm)'
2831
- },
2832
- text: 'Store not connected'
2833
- }));
3525
+ if (!state) return void container.appendChild(createDisconnectedState());
2834
3526
  const actionCards = [
2835
3527
  createActionCard({
2836
3528
  icon: actions_EYE_ICON,
@@ -2851,6 +3543,12 @@ function actions_renderActionsPanel(container, options) {
2851
3543
  icon: COPY_ICON,
2852
3544
  label: 'Copy State',
2853
3545
  onClick: onCopyState
3546
+ }),
3547
+ createActionCard({
3548
+ icon: REFRESH_ICON,
3549
+ label: 'Export Debug',
3550
+ onClick: ()=>onExportDebugBundle?.(),
3551
+ disabled: !onExportDebugBundle
2854
3552
  })
2855
3553
  ];
2856
3554
  const grid = createGrid({
@@ -2888,7 +3586,7 @@ function actions_renderActionsPanel(container, options) {
2888
3586
  },
2889
3587
  children: [
2890
3588
  createIconWrapper(TERMINAL_ICON, 14),
2891
- span({
3589
+ renderer_span({
2892
3590
  style: {
2893
3591
  fontSize: 'var(--c15t-devtools-font-size-xs)',
2894
3592
  fontWeight: '600',
@@ -2911,10 +3609,10 @@ function actions_renderActionsPanel(container, options) {
2911
3609
  color: 'var(--c15t-text-muted)'
2912
3610
  },
2913
3611
  children: [
2914
- span({
3612
+ renderer_span({
2915
3613
  text: `window.${getNamespace(state)}.getState()`
2916
3614
  }),
2917
- span({
3615
+ renderer_span({
2918
3616
  text: 'window.__c15tDevTools.open()'
2919
3617
  })
2920
3618
  ]
@@ -2924,7 +3622,7 @@ function actions_renderActionsPanel(container, options) {
2924
3622
  container.appendChild(consoleSection);
2925
3623
  }
2926
3624
  function createActionCard(options) {
2927
- const { icon, label, onClick } = options;
3625
+ const { icon, label, onClick, disabled = false } = options;
2928
3626
  const card = renderer_div({
2929
3627
  className: styles_components_module.gridCard ?? '',
2930
3628
  style: {
@@ -2935,11 +3633,12 @@ function createActionCard(options) {
2935
3633
  gap: '6px',
2936
3634
  padding: '16px 8px',
2937
3635
  cursor: 'pointer',
2938
- transition: 'background-color var(--c15t-duration-fast) var(--c15t-easing)'
3636
+ transition: 'background-color var(--c15t-duration-fast) var(--c15t-easing)',
3637
+ opacity: disabled ? '0.55' : '1'
2939
3638
  },
2940
3639
  children: [
2941
3640
  createIconWrapper(icon, 20),
2942
- span({
3641
+ renderer_span({
2943
3642
  style: {
2944
3643
  fontSize: 'var(--c15t-devtools-font-size-xs)',
2945
3644
  fontWeight: '500',
@@ -2950,13 +3649,15 @@ function createActionCard(options) {
2950
3649
  })
2951
3650
  ]
2952
3651
  });
2953
- card.addEventListener('click', onClick);
2954
- card.addEventListener('mouseenter', ()=>{
2955
- card.style.backgroundColor = 'var(--c15t-surface-hover)';
2956
- });
2957
- card.addEventListener('mouseleave', ()=>{
2958
- card.style.backgroundColor = '';
2959
- });
3652
+ if (!disabled) {
3653
+ card.addEventListener('click', onClick);
3654
+ card.addEventListener('mouseenter', ()=>{
3655
+ card.style.backgroundColor = 'var(--c15t-surface-hover)';
3656
+ });
3657
+ card.addEventListener('mouseleave', ()=>{
3658
+ card.style.backgroundColor = '';
3659
+ });
3660
+ }
2960
3661
  return card;
2961
3662
  }
2962
3663
  function createIconWrapper(icon, size) {
@@ -2977,19 +3678,11 @@ function createIconWrapper(icon, size) {
2977
3678
  function getNamespace(state) {
2978
3679
  return state.config?.meta?.namespace || 'c15tStore';
2979
3680
  }
2980
- function consents_renderConsentsPanel(container, options) {
3681
+ function renderConsentsPanel(container, options) {
2981
3682
  const { getState, onConsentChange, onSave, onAcceptAll, onRejectAll, onReset } = options;
2982
3683
  clearElement(container);
2983
3684
  const state = getState();
2984
- if (!state) return void container.appendChild(renderer_div({
2985
- style: {
2986
- padding: '24px',
2987
- textAlign: 'center',
2988
- color: 'var(--c15t-text-muted)',
2989
- fontSize: 'var(--c15t-devtools-font-size-sm)'
2990
- },
2991
- text: 'Store not connected'
2992
- }));
3685
+ if (!state) return void container.appendChild(createDisconnectedState());
2993
3686
  const isIabMode = 'iab' === state.model;
2994
3687
  const savedConsents = state.consents || {};
2995
3688
  const selectedConsents = state.selectedConsents || {};
@@ -3119,7 +3812,7 @@ function consents_renderConsentsPanel(container, options) {
3119
3812
  gap: '8px'
3120
3813
  },
3121
3814
  children: [
3122
- span({
3815
+ renderer_span({
3123
3816
  style: {
3124
3817
  fontSize: 'var(--c15t-devtools-font-size-xs)',
3125
3818
  color: 'var(--c15t-devtools-badge-warning)'
@@ -3133,7 +3826,7 @@ function consents_renderConsentsPanel(container, options) {
3133
3826
  onClick: onSave
3134
3827
  })
3135
3828
  ]
3136
- }) : span({
3829
+ }) : renderer_span({
3137
3830
  style: {
3138
3831
  fontSize: 'var(--c15t-devtools-font-size-xs)',
3139
3832
  color: 'var(--c15t-text-muted)'
@@ -3147,15 +3840,26 @@ function consents_renderConsentsPanel(container, options) {
3147
3840
  function formatConsentName(name) {
3148
3841
  return name.replace(/_/g, ' ').replace(/\b\w/g, (l)=>l.toUpperCase());
3149
3842
  }
3150
- let activeFilter = 'all';
3151
- let selectedEventId = null;
3152
- function events_renderEventsPanel(container, options) {
3843
+ const panelStateByContainer = new WeakMap();
3844
+ function getPanelState(container) {
3845
+ const existing = panelStateByContainer.get(container);
3846
+ if (existing) return existing;
3847
+ const initialState = {
3848
+ activeFilter: 'all',
3849
+ selectedEventId: null,
3850
+ searchQuery: ''
3851
+ };
3852
+ panelStateByContainer.set(container, initialState);
3853
+ return initialState;
3854
+ }
3855
+ function renderEventsPanel(container, options) {
3153
3856
  const { getEvents, onClear } = options;
3857
+ const panelState = getPanelState(container);
3154
3858
  clearElement(container);
3155
3859
  const allEvents = getEvents();
3156
- const events = allEvents.filter((event)=>matchesFilter(event, activeFilter));
3157
- if (!events.some((event)=>event.id === selectedEventId)) selectedEventId = events[0]?.id ?? null;
3158
- const selectedEvent = events.find((event)=>event.id === selectedEventId) ?? null;
3860
+ const events = allEvents.filter((event)=>matchesFilter(event, panelState.activeFilter)).filter((event)=>matchesSearch(event, panelState.searchQuery));
3861
+ if (!events.some((event)=>event.id === panelState.selectedEventId)) panelState.selectedEventId = events[0]?.id ?? null;
3862
+ const selectedEvent = events.find((event)=>event.id === panelState.selectedEventId) ?? null;
3159
3863
  const header = renderer_div({
3160
3864
  style: {
3161
3865
  display: 'flex',
@@ -3165,7 +3869,7 @@ function events_renderEventsPanel(container, options) {
3165
3869
  gap: '8px'
3166
3870
  },
3167
3871
  children: [
3168
- span({
3872
+ renderer_span({
3169
3873
  style: {
3170
3874
  fontSize: 'var(--c15t-devtools-font-size-xs)',
3171
3875
  fontWeight: '600',
@@ -3191,8 +3895,8 @@ function events_renderEventsPanel(container, options) {
3191
3895
  small: true,
3192
3896
  onClick: ()=>{
3193
3897
  onClear();
3194
- selectedEventId = null;
3195
- events_renderEventsPanel(container, options);
3898
+ panelState.selectedEventId = null;
3899
+ renderEventsPanel(container, options);
3196
3900
  }
3197
3901
  })
3198
3902
  ]
@@ -3207,12 +3911,30 @@ function events_renderEventsPanel(container, options) {
3207
3911
  gap: '6px',
3208
3912
  padding: '0 16px 8px'
3209
3913
  },
3210
- children: EVENT_FILTERS.map((filter)=>createFilterButton(filter, filter === activeFilter, ()=>{
3211
- activeFilter = filter;
3212
- selectedEventId = null;
3213
- events_renderEventsPanel(container, options);
3914
+ children: EVENT_FILTERS.map((filter)=>createFilterButton(filter, filter === panelState.activeFilter, ()=>{
3915
+ panelState.activeFilter = filter;
3916
+ panelState.selectedEventId = null;
3917
+ renderEventsPanel(container, options);
3214
3918
  }))
3215
3919
  }));
3920
+ container.appendChild(renderer_div({
3921
+ style: {
3922
+ padding: '0 16px 8px'
3923
+ },
3924
+ children: [
3925
+ createInput({
3926
+ value: panelState.searchQuery,
3927
+ placeholder: 'Search events…',
3928
+ ariaLabel: 'Search events',
3929
+ small: true,
3930
+ onInput: (value)=>{
3931
+ panelState.searchQuery = value.trim().toLowerCase();
3932
+ panelState.selectedEventId = null;
3933
+ renderEventsPanel(container, options);
3934
+ }
3935
+ })
3936
+ ]
3937
+ }));
3216
3938
  const eventList = renderer_div({
3217
3939
  style: {
3218
3940
  display: 'flex',
@@ -3232,9 +3954,9 @@ function events_renderEventsPanel(container, options) {
3232
3954
  },
3233
3955
  text: 'No events match this filter'
3234
3956
  }));
3235
- else for (const event of events)eventList.appendChild(createEventItem(event, event.id === selectedEventId, ()=>{
3236
- selectedEventId = event.id;
3237
- events_renderEventsPanel(container, options);
3957
+ else for (const event of events)eventList.appendChild(createEventItem(event, event.id === panelState.selectedEventId, ()=>{
3958
+ panelState.selectedEventId = event.id;
3959
+ renderEventsPanel(container, options);
3238
3960
  }));
3239
3961
  container.appendChild(eventList);
3240
3962
  container.appendChild(createPayloadSection(selectedEvent));
@@ -3261,6 +3983,11 @@ function matchesFilter(event, filter) {
3261
3983
  if ('network' === filter) return 'network' === event.type;
3262
3984
  return 'iab' === event.type;
3263
3985
  }
3986
+ function matchesSearch(event, query) {
3987
+ if (!query) return true;
3988
+ const haystack = `${event.type} ${event.message} ${JSON.stringify(event.data ?? {})}`;
3989
+ return haystack.toLowerCase().includes(query);
3990
+ }
3264
3991
  function createPayloadSection(event) {
3265
3992
  const payload = event?.data ? JSON.stringify(event.data, null, 2) : null;
3266
3993
  return renderer_div({
@@ -3313,7 +4040,7 @@ function createEventItem(event, selected, onSelect) {
3313
4040
  },
3314
4041
  onClick: onSelect,
3315
4042
  children: [
3316
- span({
4043
+ renderer_span({
3317
4044
  style: {
3318
4045
  color,
3319
4046
  fontSize: '8px',
@@ -3321,7 +4048,7 @@ function createEventItem(event, selected, onSelect) {
3321
4048
  },
3322
4049
  text: icon
3323
4050
  }),
3324
- span({
4051
+ renderer_span({
3325
4052
  style: {
3326
4053
  color: 'var(--c15t-text-muted)',
3327
4054
  fontFamily: 'monospace',
@@ -3330,7 +4057,7 @@ function createEventItem(event, selected, onSelect) {
3330
4057
  },
3331
4058
  text: time
3332
4059
  }),
3333
- span({
4060
+ renderer_span({
3334
4061
  style: {
3335
4062
  color: 'var(--c15t-text)',
3336
4063
  flex: '1'
@@ -3398,38 +4125,15 @@ function getEventColor(type) {
3398
4125
  return 'var(--c15t-text-muted)';
3399
4126
  }
3400
4127
  }
3401
- function iab_renderIabPanel(container, options) {
4128
+ const iabSearchByContainer = new WeakMap();
4129
+ function renderIabPanel(container, options) {
3402
4130
  const { getState, onSetPurposeConsent, onSetVendorConsent, onSetSpecialFeatureOptIn, onAcceptAll, onRejectAll, onSave, onReset } = options;
3403
4131
  clearElement(container);
3404
4132
  const state = getState();
3405
- if (!state) return void container.appendChild(renderer_div({
3406
- style: {
3407
- padding: '24px',
3408
- textAlign: 'center',
3409
- color: 'var(--c15t-text-muted)',
3410
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3411
- },
3412
- text: 'Store not connected'
3413
- }));
3414
- if ('iab' !== state.model) return void container.appendChild(renderer_div({
3415
- style: {
3416
- padding: '24px',
3417
- textAlign: 'center',
3418
- color: 'var(--c15t-text-muted)',
3419
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3420
- },
3421
- text: 'IAB TCF mode is not configured'
3422
- }));
4133
+ if (!state) return void container.appendChild(createDisconnectedState());
4134
+ if ('iab' !== state.model) return void container.appendChild(createDisconnectedState('IAB TCF mode is not configured'));
3423
4135
  const iabState = state.iab;
3424
- if (!iabState) return void container.appendChild(renderer_div({
3425
- style: {
3426
- padding: '24px',
3427
- textAlign: 'center',
3428
- color: 'var(--c15t-text-muted)',
3429
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3430
- },
3431
- text: 'IAB state not available'
3432
- }));
4136
+ if (!iabState) return void container.appendChild(createDisconnectedState('IAB state not available'));
3433
4137
  const tcString = iabState.tcString;
3434
4138
  const tcStringSection = createSection({
3435
4139
  title: 'TC String',
@@ -3461,9 +4165,30 @@ function iab_renderIabPanel(container, options) {
3461
4165
  });
3462
4166
  container.appendChild(tcStringSection);
3463
4167
  const gvl = iabState.gvl;
4168
+ const searchQuery = iabSearchByContainer.get(container) ?? '';
4169
+ container.appendChild(createSection({
4170
+ title: 'Filter',
4171
+ children: [
4172
+ createInput({
4173
+ value: searchQuery,
4174
+ placeholder: 'Filter purposes or vendors…',
4175
+ ariaLabel: 'Filter IAB purposes and vendors',
4176
+ small: true,
4177
+ onInput: (value)=>{
4178
+ iabSearchByContainer.set(container, value.trim().toLowerCase());
4179
+ renderIabPanel(container, options);
4180
+ }
4181
+ })
4182
+ ]
4183
+ }));
3464
4184
  const purposeConsents = iabState.purposeConsents || {};
3465
4185
  const purposes = gvl?.purposes || {};
3466
- const purposeEntries = Object.entries(purposeConsents);
4186
+ const purposeEntries = Object.entries(purposeConsents).filter(([purposeId])=>{
4187
+ if (!searchQuery) return true;
4188
+ const purposeInfo = purposes[purposeId];
4189
+ const purposeName = purposeInfo?.name || `Purpose ${purposeId}`;
4190
+ return `${purposeId} ${purposeName}`.toLowerCase().includes(searchQuery);
4191
+ });
3467
4192
  if (purposeEntries.length > 0) {
3468
4193
  const purposeList = renderer_div({
3469
4194
  style: {
@@ -3491,7 +4216,12 @@ function iab_renderIabPanel(container, options) {
3491
4216
  }
3492
4217
  const specialFeatureOptIns = iabState.specialFeatureOptIns || {};
3493
4218
  const specialFeatures = gvl?.specialFeatures || {};
3494
- const specialFeatureEntries = Object.entries(specialFeatureOptIns);
4219
+ const specialFeatureEntries = Object.entries(specialFeatureOptIns).filter(([featureId])=>{
4220
+ if (!searchQuery) return true;
4221
+ const featureInfo = specialFeatures[featureId];
4222
+ const featureName = featureInfo?.name || `Special Feature ${featureId}`;
4223
+ return `${featureId} ${featureName}`.toLowerCase().includes(searchQuery);
4224
+ });
3495
4225
  if (specialFeatureEntries.length > 0) {
3496
4226
  const specialFeatureList = renderer_div({
3497
4227
  style: {
@@ -3519,7 +4249,12 @@ function iab_renderIabPanel(container, options) {
3519
4249
  }
3520
4250
  const vendorConsents = iabState.vendorConsents || {};
3521
4251
  const vendors = gvl?.vendors || {};
3522
- const vendorEntries = Object.entries(vendorConsents);
4252
+ const vendorEntries = Object.entries(vendorConsents).filter(([vendorId])=>{
4253
+ if (!searchQuery) return true;
4254
+ const vendorInfo = vendors[vendorId];
4255
+ const vendorName = vendorInfo?.name || `Vendor ${vendorId}`;
4256
+ return `${vendorId} ${vendorName}`.toLowerCase().includes(searchQuery);
4257
+ });
3523
4258
  const iabVendors = [];
3524
4259
  const customVendors = [];
3525
4260
  for (const [vendorId, consent] of vendorEntries){
@@ -3645,7 +4380,7 @@ function createPurposeRow(id, name, consent, onChange, ariaKind = 'purpose') {
3645
4380
  borderBottom: '1px solid var(--c15t-border)'
3646
4381
  },
3647
4382
  children: [
3648
- span({
4383
+ renderer_span({
3649
4384
  style: {
3650
4385
  color: 'var(--c15t-text)',
3651
4386
  overflow: 'hidden',
@@ -3699,7 +4434,7 @@ function createVendorRow(id, name, consent, type, onChange) {
3699
4434
  marginRight: '8px'
3700
4435
  },
3701
4436
  children: [
3702
- 'custom' === type ? span({
4437
+ 'custom' === type ? renderer_span({
3703
4438
  style: {
3704
4439
  fontSize: '9px',
3705
4440
  padding: '1px 4px',
@@ -3710,7 +4445,7 @@ function createVendorRow(id, name, consent, type, onChange) {
3710
4445
  },
3711
4446
  text: 'CUSTOM'
3712
4447
  }) : null,
3713
- span({
4448
+ renderer_span({
3714
4449
  style: {
3715
4450
  color: 'var(--c15t-text)',
3716
4451
  overflow: 'hidden',
@@ -3738,27 +4473,23 @@ function truncateText(text, maxLength) {
3738
4473
  if (text.length <= maxLength) return text;
3739
4474
  return `${text.slice(0, maxLength - 3)}...`;
3740
4475
  }
3741
- function location_renderLocationPanel(container, options) {
4476
+ function renderLocationPanel(container, options) {
3742
4477
  const { getState, onApplyOverrides, onClearOverrides } = options;
3743
4478
  clearElement(container);
3744
4479
  const state = getState();
3745
- if (!state) return void container.appendChild(renderer_div({
3746
- style: {
3747
- padding: '24px',
3748
- textAlign: 'center',
3749
- color: 'var(--c15t-text-muted)',
3750
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3751
- },
3752
- text: 'Store not connected'
3753
- }));
4480
+ if (!state) return void container.appendChild(createDisconnectedState());
3754
4481
  const locationInfo = state.locationInfo;
3755
4482
  const overrides = state.overrides;
3756
4483
  const translationConfig = state.translationConfig;
4484
+ const initData = state.lastBannerFetchData;
4485
+ const activePolicy = initData?.policy;
4486
+ const policyDecision = initData?.policyDecision;
4487
+ const initSource = formatInitSource(state.initDataSource, state.initDataSourceDetail);
3757
4488
  const gridItems = [
3758
4489
  createCompactInfoCard('Country', locationInfo?.countryCode || '—'),
3759
4490
  createCompactInfoCard('Region', locationInfo?.regionCode || '—'),
3760
- createCompactInfoCard('Jurisdiction', locationInfo?.jurisdiction || '—'),
3761
- createCompactInfoCard('Language', translationConfig?.defaultLanguage || '—')
4491
+ createCompactInfoCard('Language', translationConfig?.defaultLanguage || '—'),
4492
+ createCompactInfoCard('Init Source', initSource)
3762
4493
  ];
3763
4494
  gridItems.push(createCompactInfoCard('GPC', getEffectiveGpcLabel(overrides?.gpc)));
3764
4495
  if (state.model) gridItems.push(createCompactInfoCard('Model', getModelLabel(state.model)));
@@ -3766,7 +4497,6 @@ function location_renderLocationPanel(container, options) {
3766
4497
  columns: 3,
3767
4498
  children: gridItems
3768
4499
  });
3769
- container.appendChild(locationGrid);
3770
4500
  const initialDraft = getDraftFromOverrides(overrides);
3771
4501
  let appliedOverrides = normalizeOverrideDraft(initialDraft);
3772
4502
  let isSubmitting = false;
@@ -3790,7 +4520,7 @@ function location_renderLocationPanel(container, options) {
3790
4520
  selectOptions: GPC_OPTIONS,
3791
4521
  value: initialDraft.gpc
3792
4522
  });
3793
- const formStatus = span({
4523
+ const formStatus = renderer_span({
3794
4524
  className: styles_components_module.overrideStatus,
3795
4525
  text: 'In sync'
3796
4526
  });
@@ -3836,7 +4566,7 @@ function location_renderLocationPanel(container, options) {
3836
4566
  title: 'Override Settings',
3837
4567
  children: [
3838
4568
  overrideFieldsGrid,
3839
- span({
4569
+ renderer_span({
3840
4570
  className: styles_components_module.overrideHint,
3841
4571
  text: 'GPC override only affects opt-out or unregulated jurisdictions.'
3842
4572
  }),
@@ -3857,6 +4587,12 @@ function location_renderLocationPanel(container, options) {
3857
4587
  ]
3858
4588
  });
3859
4589
  container.appendChild(overrideSection);
4590
+ container.appendChild(locationGrid);
4591
+ container.appendChild(createActivePolicySummarySection({
4592
+ policy: activePolicy,
4593
+ policyDecision,
4594
+ policySnapshotToken: initData?.policySnapshotToken
4595
+ }));
3860
4596
  countryField.control.addEventListener('change', updateFormState);
3861
4597
  regionField.control.addEventListener('input', updateFormState);
3862
4598
  languageField.control.addEventListener('input', updateFormState);
@@ -3924,7 +4660,7 @@ function createOverrideInput(options) {
3924
4660
  element: renderer_div({
3925
4661
  className: styles_components_module.overrideField,
3926
4662
  children: [
3927
- span({
4663
+ renderer_span({
3928
4664
  className: styles_components_module.overrideLabel,
3929
4665
  text: label
3930
4666
  }),
@@ -3945,7 +4681,7 @@ function createOverrideSelect(options) {
3945
4681
  element: renderer_div({
3946
4682
  className: styles_components_module.overrideField,
3947
4683
  children: [
3948
- span({
4684
+ renderer_span({
3949
4685
  className: styles_components_module.overrideLabel,
3950
4686
  text: label
3951
4687
  }),
@@ -4145,35 +4881,320 @@ function getModelLabel(model) {
4145
4881
  return 'None';
4146
4882
  }
4147
4883
  }
4148
- function createCompactInfoCard(label, value) {
4149
- return renderer_div({
4150
- className: styles_components_module.gridCard ?? '',
4151
- style: {
4152
- padding: '6px 8px',
4153
- minHeight: 'auto',
4154
- flexDirection: 'column',
4155
- alignItems: 'flex-start',
4156
- gap: '1px'
4157
- },
4884
+ function createActivePolicySummarySection(options) {
4885
+ const { policy, policyDecision, policySnapshotToken } = options;
4886
+ if (!policy && !policyDecision) return createSection({
4887
+ title: 'Active Policy',
4158
4888
  children: [
4159
- span({
4889
+ renderer_div({
4160
4890
  style: {
4161
- fontSize: 'var(--c15t-devtools-font-size-xs)',
4891
+ padding: '10px 12px',
4892
+ fontSize: 'var(--c15t-devtools-font-size-sm)',
4162
4893
  color: 'var(--c15t-text-muted)'
4163
4894
  },
4164
- text: label
4165
- }),
4166
- span({
4167
- style: {
4168
- fontSize: 'var(--c15t-font-size-sm)',
4169
- fontWeight: '500',
4170
- fontFamily: 'ui-monospace, monospace'
4171
- },
4895
+ text: 'No active policy matched.'
4896
+ })
4897
+ ]
4898
+ });
4899
+ const cards = [
4900
+ createCompactInfoCard('Policy ID', policy?.id ?? policyDecision?.policyId ?? '—'),
4901
+ createCompactInfoCard('Matched By', policyDecision?.matchedBy ?? '—'),
4902
+ createCompactInfoCard('Snapshot Token', policySnapshotToken ? 'present' : 'missing')
4903
+ ];
4904
+ return createSection({
4905
+ title: 'Active Policy',
4906
+ children: [
4907
+ renderer_div({
4908
+ style: {
4909
+ display: 'grid',
4910
+ gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
4911
+ gap: 'var(--c15t-space-sm, 0.5rem)'
4912
+ },
4913
+ children: cards
4914
+ }),
4915
+ renderer_span({
4916
+ className: styles_components_module.overrideHint,
4917
+ text: 'Open the Policy tab for full policy-pack diagnostics.'
4918
+ })
4919
+ ]
4920
+ });
4921
+ }
4922
+ function createCompactInfoCard(label, value) {
4923
+ return renderer_div({
4924
+ className: styles_components_module.gridCard ?? '',
4925
+ style: {
4926
+ padding: '8px 10px',
4927
+ minHeight: 'auto',
4928
+ flexDirection: 'column',
4929
+ alignItems: 'flex-start',
4930
+ gap: '2px'
4931
+ },
4932
+ children: [
4933
+ renderer_span({
4934
+ style: {
4935
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
4936
+ color: 'var(--c15t-text-muted)'
4937
+ },
4938
+ text: label
4939
+ }),
4940
+ renderer_span({
4941
+ style: {
4942
+ fontSize: 'var(--c15t-font-size-sm)',
4943
+ fontWeight: '500',
4944
+ fontFamily: 'ui-monospace, monospace'
4945
+ },
4946
+ text: value
4947
+ })
4948
+ ]
4949
+ });
4950
+ }
4951
+ function renderPolicyPanel(container, options) {
4952
+ const { getState } = options;
4953
+ clearElement(container);
4954
+ const state = getState();
4955
+ if (!state) return void container.appendChild(createDisconnectedState());
4956
+ const initData = state.lastBannerFetchData;
4957
+ const activePolicy = initData?.policy;
4958
+ const policyDecision = initData?.policyDecision;
4959
+ const initSource = formatInitSource(state.initDataSource, state.initDataSourceDetail);
4960
+ container.appendChild(createMatchTraceSection({
4961
+ policyDecision,
4962
+ policyId: activePolicy?.id ?? policyDecision?.policyId
4963
+ }));
4964
+ if (!activePolicy && !policyDecision) return void container.appendChild(createSection({
4965
+ title: 'Policy',
4966
+ children: [
4967
+ renderer_div({
4968
+ style: {
4969
+ padding: '10px 12px',
4970
+ fontSize: 'var(--c15t-devtools-font-size-sm)',
4971
+ color: 'var(--c15t-text-muted)'
4972
+ },
4973
+ text: 'No active policy matched for this request.'
4974
+ }),
4975
+ createHint(`Init Source: ${initSource}`)
4976
+ ]
4977
+ }));
4978
+ container.appendChild(createSection({
4979
+ title: 'Policy',
4980
+ children: [
4981
+ policy_createGrid(3, [
4982
+ createCard('ID', activePolicy?.id ?? policyDecision?.policyId ?? '—'),
4983
+ createCard('Model', policy_getModelLabel(activePolicy?.model)),
4984
+ createCard('Scope', getScopeModeLabel(activePolicy?.consent?.scopeMode ?? state.policyScopeMode)),
4985
+ createCard('Categories', formatList(state.policyCategories ?? activePolicy?.consent?.categories)),
4986
+ createCard('Preselected', formatList(activePolicy?.consent?.preselectedCategories)),
4987
+ createCard('Expiry', 'number' == typeof activePolicy?.consent?.expiryDays ? `${activePolicy.consent.expiryDays}d` : '—')
4988
+ ]),
4989
+ createHint(`${initSource} · ${formatFingerprint(policyDecision?.fingerprint)}`)
4990
+ ]
4991
+ }));
4992
+ const uiMode = activePolicy?.ui?.mode;
4993
+ if (uiMode && 'none' !== uiMode) {
4994
+ const bannerCards = buildSurfaceCards('Banner', activePolicy?.ui?.banner, state.policyBanner);
4995
+ const dialogCards = buildSurfaceCards('Dialog', activePolicy?.ui?.dialog, state.policyDialog);
4996
+ if (bannerCards.length > 0 || dialogCards.length > 0) container.appendChild(createSection({
4997
+ title: `UI · ${uiMode}`,
4998
+ children: [
4999
+ policy_createGrid(3, [
5000
+ ...bannerCards,
5001
+ ...dialogCards
5002
+ ])
5003
+ ]
5004
+ }));
5005
+ }
5006
+ const proofLabel = formatProofSummary(activePolicy?.proof);
5007
+ const snapshotLabel = initData?.policySnapshotToken ? 'present' : 'missing';
5008
+ container.appendChild(createSection({
5009
+ title: 'Proof & Snapshot',
5010
+ children: [
5011
+ policy_createGrid(3, [
5012
+ createCard('Proof', proofLabel),
5013
+ createCard('Snapshot', snapshotLabel),
5014
+ createCard('I18n', activePolicy?.i18n?.messageProfile ?? activePolicy?.i18n?.language ?? '—')
5015
+ ])
5016
+ ]
5017
+ }));
5018
+ }
5019
+ function buildSurfaceCards(prefix, policySurface, storeSurface) {
5020
+ const policyLayout = Array.isArray(policySurface?.layout) && 0 === policySurface.layout.length ? null : policySurface?.layout ?? null;
5021
+ const storeLayout = Array.isArray(storeSurface.layout) && 0 === storeSurface.layout.length ? null : storeSurface.layout ?? null;
5022
+ const actions = formatList(policySurface?.allowedActions ?? storeSurface.allowedActions);
5023
+ const primary = policySurface?.primaryAction ?? storeSurface.primaryAction ?? null;
5024
+ const layout = policyLayout ?? storeLayout;
5025
+ const direction = policySurface?.direction ?? storeSurface.direction ?? null;
5026
+ const profile = policySurface?.uiProfile ?? storeSurface.uiProfile ?? null;
5027
+ const scrollLock = policySurface?.scrollLock ?? storeSurface.scrollLock ?? null;
5028
+ if ('—' === actions && !primary && !layout && !direction && !profile && null === scrollLock) return [];
5029
+ const cards = [
5030
+ createCard(`${prefix} Actions`, actions)
5031
+ ];
5032
+ if (primary) cards.push(createCard(`${prefix} Primary`, primary));
5033
+ if (layout) cards.push(createCard(`${prefix} Layout`, Array.isArray(layout) ? layout.map((group)=>Array.isArray(group) ? `[${group.join(', ')}]` : group).join(' / ') : layout));
5034
+ if (direction) cards.push(createCard(`${prefix} Direction`, direction));
5035
+ if (profile) cards.push(createCard(`${prefix} Profile`, profile));
5036
+ if (null !== scrollLock) cards.push(createCard(`${prefix} Scroll Lock`, scrollLock ? 'on' : 'off'));
5037
+ return cards;
5038
+ }
5039
+ function createMatchTraceSection(options) {
5040
+ const { policyDecision, policyId } = options;
5041
+ const entries = buildTraceEntries(policyDecision, policyId);
5042
+ return createSection({
5043
+ title: 'Match Trace',
5044
+ children: [
5045
+ renderer_div({
5046
+ style: {
5047
+ display: 'grid',
5048
+ gridTemplateColumns: '1fr',
5049
+ gap: '4px'
5050
+ },
5051
+ children: entries.map((entry)=>renderer_div({
5052
+ className: styles_components_module.gridCard ?? '',
5053
+ style: {
5054
+ padding: '6px 10px',
5055
+ display: 'flex',
5056
+ alignItems: 'center',
5057
+ justifyContent: 'space-between',
5058
+ gap: '10px'
5059
+ },
5060
+ children: [
5061
+ renderer_span({
5062
+ style: {
5063
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5064
+ color: 'var(--c15t-text-muted)',
5065
+ fontFamily: 'ui-monospace, monospace'
5066
+ },
5067
+ text: entry.step
5068
+ }),
5069
+ renderer_span({
5070
+ style: {
5071
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5072
+ fontFamily: 'ui-monospace, monospace'
5073
+ },
5074
+ text: entry.result
5075
+ })
5076
+ ]
5077
+ }))
5078
+ }),
5079
+ createHint('region → country → default · fallback on geo failure · Simulate via Location tab')
5080
+ ]
5081
+ });
5082
+ }
5083
+ function buildTraceEntries(decision, policyId) {
5084
+ if (!decision) return [
5085
+ {
5086
+ step: 'decision metadata',
5087
+ result: 'UNAVAILABLE'
5088
+ }
5089
+ ];
5090
+ const country = decision.country ?? 'n/a';
5091
+ const regionKey = decision.country && decision.region ? `${decision.country}-${decision.region}` : 'n/a';
5092
+ const resolved = policyId ?? decision.policyId ?? 'unknown';
5093
+ const matched = decision.matchedBy;
5094
+ return [
5095
+ {
5096
+ step: `region(${regionKey})`,
5097
+ result: 'region' === matched ? `MATCH → ${resolved}` : 'MISS'
5098
+ },
5099
+ {
5100
+ step: `country(${country})`,
5101
+ result: 'country' === matched ? `MATCH → ${resolved}` : 'region' === matched ? 'SKIPPED' : 'MISS'
5102
+ },
5103
+ {
5104
+ step: 'fallback(geo-fail)',
5105
+ result: 'fallback' === matched ? `MATCH → ${resolved}` : 'SKIPPED'
5106
+ },
5107
+ {
5108
+ step: 'default(catch-all)',
5109
+ result: 'default' === matched ? `MATCH → ${resolved}` : 'SKIPPED'
5110
+ }
5111
+ ];
5112
+ }
5113
+ function policy_getModelLabel(model) {
5114
+ switch(model){
5115
+ case 'opt-in':
5116
+ return 'Opt-In';
5117
+ case 'opt-out':
5118
+ return 'Opt-Out';
5119
+ case 'iab':
5120
+ return 'IAB TCF';
5121
+ default:
5122
+ return 'None';
5123
+ }
5124
+ }
5125
+ function getScopeModeLabel(mode) {
5126
+ switch(mode){
5127
+ case 'strict':
5128
+ return 'Strict';
5129
+ case 'permissive':
5130
+ return 'Permissive';
5131
+ default:
5132
+ return '—';
5133
+ }
5134
+ }
5135
+ function formatList(items) {
5136
+ if (!items || 0 === items.length) return '—';
5137
+ if (items.includes('*')) return '* (all)';
5138
+ return items.join(', ');
5139
+ }
5140
+ function formatProofSummary(proof) {
5141
+ if (!proof) return '—';
5142
+ const parts = [];
5143
+ if (proof.storeIp) parts.push('IP');
5144
+ if (proof.storeUserAgent) parts.push('UA');
5145
+ if (proof.storeLanguage) parts.push('Lang');
5146
+ return parts.length > 0 ? parts.join(', ') : 'none';
5147
+ }
5148
+ function formatFingerprint(fingerprint) {
5149
+ if (!fingerprint) return 'no fingerprint';
5150
+ if (fingerprint.length <= 12) return fingerprint;
5151
+ return `${fingerprint.slice(0, 8)}…${fingerprint.slice(-4)}`;
5152
+ }
5153
+ function createCard(label, value) {
5154
+ return renderer_div({
5155
+ className: styles_components_module.gridCard ?? '',
5156
+ style: {
5157
+ padding: '8px 10px',
5158
+ minHeight: 'auto',
5159
+ flexDirection: 'column',
5160
+ alignItems: 'flex-start',
5161
+ gap: '2px'
5162
+ },
5163
+ children: [
5164
+ renderer_span({
5165
+ style: {
5166
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5167
+ color: 'var(--c15t-text-muted)'
5168
+ },
5169
+ text: label
5170
+ }),
5171
+ renderer_span({
5172
+ style: {
5173
+ fontSize: 'var(--c15t-font-size-sm)',
5174
+ fontWeight: '500',
5175
+ fontFamily: 'ui-monospace, monospace'
5176
+ },
4172
5177
  text: value
4173
5178
  })
4174
5179
  ]
4175
5180
  });
4176
5181
  }
5182
+ function policy_createGrid(columns, children) {
5183
+ return renderer_div({
5184
+ style: {
5185
+ display: 'grid',
5186
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
5187
+ gap: 'var(--c15t-space-sm, 0.5rem)'
5188
+ },
5189
+ children
5190
+ });
5191
+ }
5192
+ function createHint(text) {
5193
+ return renderer_span({
5194
+ className: styles_components_module.overrideHint,
5195
+ text
5196
+ });
5197
+ }
4177
5198
  const dismissedResources = new Set();
4178
5199
  function scanDOM(state) {
4179
5200
  const results = [];
@@ -4339,21 +5360,21 @@ function createResourceRow(resource, variant, onDismiss) {
4339
5360
  borderBottom: '1px solid var(--c15t-border)'
4340
5361
  },
4341
5362
  children: [
4342
- span({
5363
+ renderer_span({
4343
5364
  style: {
4344
5365
  color: iconColor,
4345
5366
  flexShrink: '0'
4346
5367
  },
4347
5368
  text: icon
4348
5369
  }),
4349
- span({
5370
+ renderer_span({
4350
5371
  style: {
4351
5372
  color: 'var(--c15t-text-muted)',
4352
5373
  flexShrink: '0'
4353
5374
  },
4354
5375
  text: `${resource.type}:`
4355
5376
  }),
4356
- span({
5377
+ renderer_span({
4357
5378
  style: {
4358
5379
  fontWeight: '500',
4359
5380
  color: 'var(--c15t-text)',
@@ -4399,23 +5420,37 @@ const CODE_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" f
4399
5420
  <polyline points="16 18 22 12 16 6"></polyline>
4400
5421
  <polyline points="8 6 2 12 8 18"></polyline>
4401
5422
  </svg>`;
4402
- function scripts_renderScriptsPanel(container, options) {
5423
+ const scriptsSearchByContainer = new WeakMap();
5424
+ function renderScriptsPanel(container, options) {
4403
5425
  const { getState, getEvents } = options;
4404
5426
  clearElement(container);
4405
5427
  const state = getState();
4406
- if (!state) return void container.appendChild(renderer_div({
4407
- style: {
4408
- padding: '24px',
4409
- textAlign: 'center',
4410
- color: 'var(--c15t-text-muted)',
4411
- fontSize: 'var(--c15t-devtools-font-size-sm)'
4412
- },
4413
- text: 'Store not connected'
4414
- }));
5428
+ if (!state) return void container.appendChild(createDisconnectedState());
4415
5429
  const scripts = state.scripts || [];
4416
5430
  const loadedScripts = state.loadedScripts || {};
4417
5431
  const networkBlocker = state.networkBlocker;
4418
5432
  const events = getEvents?.() ?? [];
5433
+ const searchQuery = scriptsSearchByContainer.get(container) ?? '';
5434
+ const filteredScripts = scripts.filter((script)=>{
5435
+ if (!searchQuery) return true;
5436
+ const category = 'string' == typeof script.category ? script.category : JSON.stringify(script.category);
5437
+ return `${script.id} ${category}`.toLowerCase().includes(searchQuery);
5438
+ });
5439
+ if (scripts.length > 4) container.appendChild(createSection({
5440
+ title: 'Filter',
5441
+ children: [
5442
+ createInput({
5443
+ value: searchQuery,
5444
+ placeholder: "Filter scripts…",
5445
+ ariaLabel: "Filter scripts",
5446
+ small: true,
5447
+ onInput: (value)=>{
5448
+ scriptsSearchByContainer.set(container, value.trim().toLowerCase());
5449
+ renderScriptsPanel(container, options);
5450
+ }
5451
+ })
5452
+ ]
5453
+ }));
4419
5454
  if (0 === scripts.length) {
4420
5455
  const scriptsSection = createSection({
4421
5456
  title: 'Configured Scripts',
@@ -4432,10 +5467,19 @@ function scripts_renderScriptsPanel(container, options) {
4432
5467
  style: {
4433
5468
  display: 'flex',
4434
5469
  flexDirection: 'column',
4435
- gap: '4px'
5470
+ borderTop: '1px solid var(--c15t-border)',
5471
+ borderBottom: '1px solid var(--c15t-border)'
4436
5472
  }
4437
5473
  });
4438
- for (const script of scripts){
5474
+ if (0 === filteredScripts.length) scriptsList.appendChild(renderer_div({
5475
+ style: {
5476
+ padding: '10px 0',
5477
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5478
+ color: 'var(--c15t-text-muted)'
5479
+ },
5480
+ text: "No matching scripts"
5481
+ }));
5482
+ for (const script of filteredScripts){
4439
5483
  const scriptId = script.id;
4440
5484
  const isLoaded = true === loadedScripts[scriptId];
4441
5485
  const category = script.category;
@@ -4459,17 +5503,64 @@ function scripts_renderScriptsPanel(container, options) {
4459
5503
  text: status.charAt(0).toUpperCase() + status.slice(1),
4460
5504
  variant: statusVariant
4461
5505
  });
4462
- const item = createListItem({
4463
- title: scriptId,
4464
- description: `Category: ${categoryDisplay}`,
4465
- actions: [
4466
- badge
5506
+ const row = renderer_div({
5507
+ style: {
5508
+ display: 'flex',
5509
+ alignItems: 'center',
5510
+ justifyContent: 'space-between',
5511
+ gap: '8px',
5512
+ padding: '8px 0',
5513
+ borderBottom: '1px solid var(--c15t-border)'
5514
+ },
5515
+ children: [
5516
+ renderer_div({
5517
+ style: {
5518
+ display: 'flex',
5519
+ flexDirection: 'column',
5520
+ gap: '2px',
5521
+ minWidth: '0',
5522
+ flex: '1'
5523
+ },
5524
+ children: [
5525
+ renderer_div({
5526
+ style: {
5527
+ fontSize: 'var(--c15t-font-size-sm)',
5528
+ fontWeight: '500',
5529
+ color: 'var(--c15t-text)',
5530
+ overflow: 'hidden',
5531
+ textOverflow: 'ellipsis',
5532
+ whiteSpace: 'nowrap'
5533
+ },
5534
+ text: scriptId
5535
+ }),
5536
+ renderer_div({
5537
+ style: {
5538
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5539
+ color: 'var(--c15t-text-muted)',
5540
+ overflow: 'hidden',
5541
+ textOverflow: 'ellipsis',
5542
+ whiteSpace: 'nowrap'
5543
+ },
5544
+ text: `Category: ${categoryDisplay}`
5545
+ })
5546
+ ]
5547
+ }),
5548
+ renderer_div({
5549
+ style: {
5550
+ flexShrink: '0'
5551
+ },
5552
+ children: [
5553
+ badge
5554
+ ]
5555
+ })
4467
5556
  ]
4468
5557
  });
4469
- scriptsList.appendChild(item);
5558
+ scriptsList.appendChild(row);
4470
5559
  }
5560
+ const lastRow = scriptsList.lastElementChild;
5561
+ if (lastRow) lastRow.style.borderBottom = 'none';
4471
5562
  const scriptsSection = createSection({
4472
- title: `Configured Scripts (${scripts.length})`,
5563
+ title: `Configured Scripts (${filteredScripts.length}/${scripts.length})`,
4473
5564
  children: [
4474
5565
  scriptsList
4475
5566
  ]
@@ -4611,53 +5702,6 @@ function scripts_truncateText(text, maxLength) {
4611
5702
  if (text.length <= maxLength) return text;
4612
5703
  return `${text.slice(0, maxLength - 3)}...`;
4613
5704
  }
4614
- const DEVTOOLS_OVERRIDES_STORAGE_KEY = 'c15t-devtools-overrides';
4615
- function normalizeStringValue(value) {
4616
- if ('string' != typeof value) return;
4617
- const normalized = value.trim();
4618
- return normalized.length > 0 ? normalized : void 0;
4619
- }
4620
- function normalizeBooleanValue(value) {
4621
- return 'boolean' == typeof value ? value : void 0;
4622
- }
4623
- function normalizeOverrides(value) {
4624
- if (!value || 'object' != typeof value) return null;
4625
- const source = value;
4626
- const overrides = {
4627
- country: normalizeStringValue(source.country),
4628
- region: normalizeStringValue(source.region),
4629
- language: normalizeStringValue(source.language),
4630
- gpc: normalizeBooleanValue(source.gpc)
4631
- };
4632
- return hasPersistedOverrides(overrides) ? overrides : null;
4633
- }
4634
- function hasPersistedOverrides(overrides) {
4635
- return Boolean(overrides.country || overrides.region || overrides.language || void 0 !== overrides.gpc);
4636
- }
4637
- function override_storage_loadPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
4638
- if ('undefined' == typeof window) return null;
4639
- try {
4640
- const stored = localStorage.getItem(storageKey);
4641
- if (!stored) return null;
4642
- const parsed = JSON.parse(stored);
4643
- return normalizeOverrides(parsed);
4644
- } catch {
4645
- return null;
4646
- }
4647
- }
4648
- function override_storage_persistOverrides(overrides, storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
4649
- if ('undefined' == typeof window) return;
4650
- try {
4651
- if (!hasPersistedOverrides(overrides)) return void localStorage.removeItem(storageKey);
4652
- localStorage.setItem(storageKey, JSON.stringify(overrides));
4653
- } catch {}
4654
- }
4655
- function override_storage_clearPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
4656
- if ('undefined' == typeof window) return;
4657
- try {
4658
- localStorage.removeItem(storageKey);
4659
- } catch {}
4660
- }
4661
5705
  const STORAGE_KEYS = {
4662
5706
  C15T: 'c15t',
4663
5707
  PENDING_SYNC: 'c15t:pending-consent-sync',
@@ -4683,7 +5727,7 @@ function clearAllLocalStorage() {
4683
5727
  localStorage.removeItem(STORAGE_KEYS.EUCONSENT);
4684
5728
  } catch {}
4685
5729
  }
4686
- async function reset_consents_resetAllConsents(store, stateManager) {
5730
+ async function resetAllConsents(store, stateManager) {
4687
5731
  const storeState = store.getState();
4688
5732
  storeState.resetConsents();
4689
5733
  clearAllCookies();
@@ -4694,52 +5738,290 @@ async function reset_consents_resetAllConsents(store, stateManager) {
4694
5738
  message: 'All consents reset (storage cleared)'
4695
5739
  });
4696
5740
  }
4697
- const STORAGE_KEY = 'c15t-devtools-events';
4698
- function loadPersistedEvents() {
4699
- if ('undefined' == typeof window) return [];
4700
- try {
4701
- const stored = sessionStorage.getItem(STORAGE_KEY);
4702
- if (stored) return JSON.parse(stored);
4703
- } catch {}
4704
- return [];
4705
- }
4706
- function persistEvents(events) {
4707
- if ('undefined' == typeof window) return;
4708
- try {
4709
- sessionStorage.setItem(STORAGE_KEY, JSON.stringify(events));
4710
- } catch {}
4711
- }
4712
- function state_manager_createStateManager(initialState = {}) {
4713
- const persistedEvents = loadPersistedEvents();
4714
- let state = {
4715
- isOpen: false,
4716
- activeTab: 'location',
4717
- position: 'bottom-right',
4718
- isConnected: false,
4719
- eventLog: persistedEvents,
4720
- maxEventLogSize: 100,
4721
- ...initialState
5741
+ function panel_renderer_createPanelRenderer(config) {
5742
+ const { storeConnector, stateManager, enableEventLogging = true, onPersistOverrides, onClearPersistedOverrides, onCopyState, onExportDebugBundle } = config;
5743
+ const getStoreState = ()=>storeConnector.getState();
5744
+ const logEvent = (type, message, data)=>{
5745
+ if (enableEventLogging) stateManager.addEvent({
5746
+ type,
5747
+ message,
5748
+ data
5749
+ });
4722
5750
  };
4723
- const listeners = new Set();
4724
- function notify(prevState) {
4725
- for (const listener of listeners)listener(state, prevState);
4726
- }
4727
- function setState(partial) {
4728
- const prevState = state;
4729
- state = {
4730
- ...state,
4731
- ...partial
4732
- };
4733
- notify(prevState);
4734
- }
4735
- return {
4736
- getState: ()=>state,
4737
- subscribe: (listener)=>{
4738
- listeners.add(listener);
4739
- return ()=>{
4740
- listeners.delete(listener);
4741
- };
4742
- },
5751
+ const resetConsents = async ()=>{
5752
+ const store = storeConnector.getStore();
5753
+ if (store) await resetAllConsents(store, enableEventLogging ? stateManager : void 0);
5754
+ };
5755
+ const renderPanel = (container, tab)=>{
5756
+ switch(tab){
5757
+ case 'consents':
5758
+ renderConsentsPanel(container, {
5759
+ getState: getStoreState,
5760
+ onConsentChange: (name, value)=>{
5761
+ const store = storeConnector.getStore();
5762
+ if (store) {
5763
+ const consentName = String(name);
5764
+ store.getState().setSelectedConsent(consentName, value);
5765
+ logEvent('info', `${consentName} toggled to ${value} (not saved)`, {
5766
+ name: consentName,
5767
+ value
5768
+ });
5769
+ }
5770
+ },
5771
+ onSave: ()=>{
5772
+ const store = storeConnector.getStore();
5773
+ if (store) {
5774
+ store.getState().saveConsents('custom');
5775
+ logEvent('consent_save', 'Saved consent preferences');
5776
+ }
5777
+ },
5778
+ onAcceptAll: ()=>{
5779
+ const store = storeConnector.getStore();
5780
+ if (store) {
5781
+ store.getState().saveConsents('all');
5782
+ logEvent('consent_save', 'Accepted all consents');
5783
+ }
5784
+ },
5785
+ onRejectAll: ()=>{
5786
+ const store = storeConnector.getStore();
5787
+ if (store) {
5788
+ store.getState().saveConsents('necessary');
5789
+ logEvent('consent_save', 'Rejected all optional consents');
5790
+ }
5791
+ },
5792
+ onReset: resetConsents
5793
+ });
5794
+ break;
5795
+ case 'location':
5796
+ renderLocationPanel(container, {
5797
+ getState: getStoreState,
5798
+ onApplyOverrides: async (overrides)=>{
5799
+ const store = storeConnector.getStore();
5800
+ if (store) {
5801
+ await store.getState().setOverrides({
5802
+ country: overrides.country,
5803
+ region: overrides.region,
5804
+ language: overrides.language,
5805
+ gpc: overrides.gpc
5806
+ });
5807
+ logEvent('info', 'Overrides updated', {
5808
+ country: overrides.country,
5809
+ region: overrides.region,
5810
+ language: overrides.language,
5811
+ gpc: overrides.gpc
5812
+ });
5813
+ onPersistOverrides?.({
5814
+ country: overrides.country,
5815
+ region: overrides.region,
5816
+ language: overrides.language,
5817
+ gpc: overrides.gpc
5818
+ });
5819
+ }
5820
+ },
5821
+ onClearOverrides: async ()=>{
5822
+ const store = storeConnector.getStore();
5823
+ if (store) {
5824
+ await store.getState().setOverrides({
5825
+ country: void 0,
5826
+ region: void 0,
5827
+ language: void 0,
5828
+ gpc: void 0
5829
+ });
5830
+ logEvent('info', 'Overrides cleared');
5831
+ onClearPersistedOverrides?.();
5832
+ }
5833
+ }
5834
+ });
5835
+ break;
5836
+ case 'policy':
5837
+ renderPolicyPanel(container, {
5838
+ getState: getStoreState
5839
+ });
5840
+ break;
5841
+ case "scripts":
5842
+ renderScriptsPanel(container, {
5843
+ getState: getStoreState,
5844
+ getEvents: ()=>stateManager.getState().eventLog
5845
+ });
5846
+ break;
5847
+ case 'iab':
5848
+ renderIabPanel(container, {
5849
+ getState: getStoreState,
5850
+ onSetPurposeConsent: (purposeId, value)=>{
5851
+ const iab = storeConnector.getStore()?.getState().iab;
5852
+ if (!iab) return;
5853
+ iab.setPurposeConsent(purposeId, value);
5854
+ logEvent('iab', `IAB purpose ${purposeId} set to ${value}`);
5855
+ },
5856
+ onSetVendorConsent: (vendorId, value)=>{
5857
+ const iab = storeConnector.getStore()?.getState().iab;
5858
+ if (!iab) return;
5859
+ iab.setVendorConsent(vendorId, value);
5860
+ logEvent('iab', `IAB vendor ${vendorId} set to ${value}`);
5861
+ },
5862
+ onSetSpecialFeatureOptIn: (featureId, value)=>{
5863
+ const iab = storeConnector.getStore()?.getState().iab;
5864
+ if (!iab) return;
5865
+ iab.setSpecialFeatureOptIn(featureId, value);
5866
+ logEvent('iab', `IAB feature ${featureId} set to ${value}`);
5867
+ },
5868
+ onAcceptAll: ()=>{
5869
+ const iab = storeConnector.getStore()?.getState().iab;
5870
+ if (!iab) return;
5871
+ iab.acceptAll();
5872
+ logEvent('iab', 'IAB accept all selected');
5873
+ },
5874
+ onRejectAll: ()=>{
5875
+ const iab = storeConnector.getStore()?.getState().iab;
5876
+ if (!iab) return;
5877
+ iab.rejectAll();
5878
+ logEvent('iab', 'IAB reject all selected');
5879
+ },
5880
+ onSave: ()=>{
5881
+ const iab = storeConnector.getStore()?.getState().iab;
5882
+ if (!iab) return;
5883
+ iab.save().then(()=>logEvent('iab', 'IAB preferences saved')).catch((error)=>{
5884
+ logEvent('error', `Failed to save IAB preferences: ${String(error)}`);
5885
+ });
5886
+ },
5887
+ onReset: resetConsents
5888
+ });
5889
+ break;
5890
+ case 'events':
5891
+ renderEventsPanel(container, {
5892
+ getEvents: ()=>stateManager.getState().eventLog,
5893
+ onClear: ()=>{
5894
+ stateManager.clearEventLog();
5895
+ logEvent('info', 'Event log cleared');
5896
+ }
5897
+ });
5898
+ break;
5899
+ case 'actions':
5900
+ renderActionsPanel(container, {
5901
+ getState: getStoreState,
5902
+ onResetConsents: resetConsents,
5903
+ onRefetchBanner: async ()=>{
5904
+ const store = storeConnector.getStore();
5905
+ if (store) {
5906
+ await store.getState().initConsentManager();
5907
+ logEvent('info', 'Banner data refetched');
5908
+ }
5909
+ },
5910
+ onShowBanner: ()=>{
5911
+ const store = storeConnector.getStore();
5912
+ if (store) {
5913
+ store.getState().setActiveUI('banner', {
5914
+ force: true
5915
+ });
5916
+ logEvent('info', 'Banner shown');
5917
+ }
5918
+ },
5919
+ onOpenPreferences: ()=>{
5920
+ const store = storeConnector.getStore();
5921
+ if (store) {
5922
+ store.getState().setActiveUI('dialog');
5923
+ logEvent('info', 'Preferences dialog opened');
5924
+ }
5925
+ },
5926
+ onCopyState: ()=>{
5927
+ const state = getStoreState();
5928
+ if (state) if (onCopyState) {
5929
+ const result = onCopyState(state);
5930
+ if (result instanceof Promise) result.then((ok)=>{
5931
+ logEvent(ok ? 'info' : 'error', ok ? 'State copied to clipboard' : 'Failed to copy state');
5932
+ }).catch(()=>{
5933
+ logEvent('error', 'Failed to copy state');
5934
+ });
5935
+ else logEvent(result ? 'info' : 'error', result ? 'State copied to clipboard' : 'Failed to copy state');
5936
+ } else navigator.clipboard.writeText(JSON.stringify(state, null, 2)).then(()=>{
5937
+ logEvent('info', 'State copied to clipboard');
5938
+ }).catch(()=>{
5939
+ logEvent('error', 'Failed to copy state');
5940
+ });
5941
+ },
5942
+ onExportDebugBundle: onExportDebugBundle ? ()=>{
5943
+ try {
5944
+ onExportDebugBundle();
5945
+ logEvent('info', 'Debug bundle exported');
5946
+ } catch {
5947
+ logEvent('error', 'Failed to export debug bundle');
5948
+ }
5949
+ } : void 0
5950
+ });
5951
+ break;
5952
+ }
5953
+ };
5954
+ return {
5955
+ renderPanel,
5956
+ getStoreState,
5957
+ resetConsents
5958
+ };
5959
+ }
5960
+ const STORAGE_KEY = 'c15t-devtools-events';
5961
+ const ACTIVE_TAB_STORAGE_KEY = 'c15t-devtools-active-tab';
5962
+ function loadPersistedEvents() {
5963
+ if ('undefined' == typeof window) return [];
5964
+ try {
5965
+ const stored = sessionStorage.getItem(STORAGE_KEY);
5966
+ if (stored) return JSON.parse(stored);
5967
+ } catch {}
5968
+ return [];
5969
+ }
5970
+ function persistEvents(events) {
5971
+ if ('undefined' == typeof window) return;
5972
+ try {
5973
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify(events));
5974
+ } catch {}
5975
+ }
5976
+ function isDevToolsTab(value) {
5977
+ return 'consents' === value || 'location' === value || 'policy' === value || "scripts" === value || 'iab' === value || 'events' === value || 'actions' === value;
5978
+ }
5979
+ function loadPersistedActiveTab() {
5980
+ if ('undefined' == typeof window) return null;
5981
+ try {
5982
+ const stored = localStorage.getItem(ACTIVE_TAB_STORAGE_KEY);
5983
+ if (isDevToolsTab(stored)) return stored;
5984
+ } catch {}
5985
+ return null;
5986
+ }
5987
+ function persistActiveTab(tab) {
5988
+ if ('undefined' == typeof window) return;
5989
+ try {
5990
+ localStorage.setItem(ACTIVE_TAB_STORAGE_KEY, tab);
5991
+ } catch {}
5992
+ }
5993
+ function state_manager_createStateManager(initialState = {}) {
5994
+ const persistedEvents = loadPersistedEvents();
5995
+ const persistedActiveTab = loadPersistedActiveTab();
5996
+ let state = {
5997
+ isOpen: false,
5998
+ activeTab: persistedActiveTab ?? 'location',
5999
+ position: 'bottom-right',
6000
+ isConnected: false,
6001
+ eventLog: persistedEvents,
6002
+ maxEventLogSize: 100,
6003
+ ...initialState
6004
+ };
6005
+ const listeners = new Set();
6006
+ function notify(prevState) {
6007
+ for (const listener of listeners)listener(state, prevState);
6008
+ }
6009
+ function setState(partial) {
6010
+ const prevState = state;
6011
+ state = {
6012
+ ...state,
6013
+ ...partial
6014
+ };
6015
+ notify(prevState);
6016
+ }
6017
+ return {
6018
+ getState: ()=>state,
6019
+ subscribe: (listener)=>{
6020
+ listeners.add(listener);
6021
+ return ()=>{
6022
+ listeners.delete(listener);
6023
+ };
6024
+ },
4743
6025
  setOpen: (isOpen)=>{
4744
6026
  setState({
4745
6027
  isOpen
@@ -4754,6 +6036,7 @@ function state_manager_createStateManager(initialState = {}) {
4754
6036
  setState({
4755
6037
  activeTab: tab
4756
6038
  });
6039
+ persistActiveTab(tab);
4757
6040
  },
4758
6041
  setPosition: (position)=>{
4759
6042
  setState({
@@ -4799,22 +6082,52 @@ function store_connector_createStoreConnector(options = {}) {
4799
6082
  let reconnectAttempts = 0;
4800
6083
  let hasNotifiedDisconnect = false;
4801
6084
  const listeners = new Set();
6085
+ const diagnosticsListeners = new Set();
6086
+ let diagnostics = {
6087
+ namespace,
6088
+ reconnectAttempts: 0,
6089
+ nextRetryInMs: null,
6090
+ lastError: null,
6091
+ isPolling: false,
6092
+ disconnectNotified: false
6093
+ };
4802
6094
  const INITIAL_RETRY_DELAY_MS = 100;
4803
6095
  const MAX_RETRY_DELAY_MS = 2000;
4804
6096
  const DISCONNECT_NOTIFY_ATTEMPTS = 5;
6097
+ function updateDiagnostics(partial, notify = true) {
6098
+ diagnostics = {
6099
+ ...diagnostics,
6100
+ ...partial
6101
+ };
6102
+ if (!notify) return;
6103
+ for (const listener of diagnosticsListeners)listener(diagnostics);
6104
+ }
4805
6105
  function clearReconnectTimer() {
4806
6106
  if (reconnectTimeout) {
4807
6107
  clearTimeout(reconnectTimeout);
4808
6108
  reconnectTimeout = null;
6109
+ updateDiagnostics({
6110
+ isPolling: false,
6111
+ nextRetryInMs: null
6112
+ });
4809
6113
  }
4810
6114
  }
4811
6115
  function resetReconnectState() {
4812
6116
  reconnectAttempts = 0;
4813
6117
  hasNotifiedDisconnect = false;
6118
+ updateDiagnostics({
6119
+ reconnectAttempts: 0,
6120
+ nextRetryInMs: null,
6121
+ lastError: null,
6122
+ disconnectNotified: false
6123
+ });
4814
6124
  }
4815
6125
  function notifyDisconnectedOnce() {
4816
6126
  if (hasNotifiedDisconnect) return;
4817
6127
  hasNotifiedDisconnect = true;
6128
+ updateDiagnostics({
6129
+ disconnectNotified: true
6130
+ });
4818
6131
  onDisconnect?.();
4819
6132
  }
4820
6133
  function tryConnect() {
@@ -4835,16 +6148,31 @@ function store_connector_createStoreConnector(options = {}) {
4835
6148
  onConnect?.(currentState, store);
4836
6149
  clearReconnectTimer();
4837
6150
  resetReconnectState();
6151
+ updateDiagnostics({
6152
+ lastError: null
6153
+ });
4838
6154
  return true;
4839
6155
  }
6156
+ updateDiagnostics({
6157
+ lastError: `Store "${namespace}" not found on window`
6158
+ });
4840
6159
  return false;
4841
6160
  }
4842
6161
  function scheduleReconnect(immediate = false) {
4843
6162
  if (store || reconnectTimeout) return;
4844
6163
  const delay = immediate ? 0 : Math.min(INITIAL_RETRY_DELAY_MS * 2 ** Math.min(reconnectAttempts, 5), MAX_RETRY_DELAY_MS);
6164
+ updateDiagnostics({
6165
+ isPolling: true,
6166
+ nextRetryInMs: delay,
6167
+ reconnectAttempts
6168
+ });
4845
6169
  reconnectTimeout = setTimeout(()=>{
4846
6170
  reconnectTimeout = null;
4847
6171
  reconnectAttempts++;
6172
+ updateDiagnostics({
6173
+ reconnectAttempts,
6174
+ nextRetryInMs: null
6175
+ });
4848
6176
  if (tryConnect()) return;
4849
6177
  if (reconnectAttempts >= DISCONNECT_NOTIFY_ATTEMPTS) notifyDisconnectedOnce();
4850
6178
  scheduleReconnect();
@@ -4866,6 +6194,14 @@ function store_connector_createStoreConnector(options = {}) {
4866
6194
  listeners.delete(listener);
4867
6195
  };
4868
6196
  },
6197
+ getDiagnostics: ()=>diagnostics,
6198
+ subscribeDiagnostics: (listener)=>{
6199
+ diagnosticsListeners.add(listener);
6200
+ listener(diagnostics);
6201
+ return ()=>{
6202
+ diagnosticsListeners.delete(listener);
6203
+ };
6204
+ },
4869
6205
  retryConnection: ()=>{
4870
6206
  if (store) return;
4871
6207
  resetReconnectState();
@@ -4879,6 +6215,134 @@ function store_connector_createStoreConnector(options = {}) {
4879
6215
  }
4880
6216
  store = null;
4881
6217
  listeners.clear();
6218
+ diagnosticsListeners.clear();
6219
+ }
6220
+ };
6221
+ }
6222
+ const REGISTRY_KEY = '__c15tDevToolsInstrumentationRegistry';
6223
+ let fallbackRegistry = null;
6224
+ function getRegistry() {
6225
+ if ('undefined' == typeof window) {
6226
+ if (!fallbackRegistry) fallbackRegistry = new Map();
6227
+ return fallbackRegistry;
6228
+ }
6229
+ const host = window;
6230
+ const existing = host[REGISTRY_KEY];
6231
+ if (existing) return existing;
6232
+ const registry = new Map();
6233
+ host[REGISTRY_KEY] = registry;
6234
+ return registry;
6235
+ }
6236
+ function getBlockedRequestMessage(payload) {
6237
+ const data = payload;
6238
+ const method = 'string' == typeof data?.method ? data.method.toUpperCase() : 'REQUEST';
6239
+ const url = 'string' == typeof data?.url ? data.url : 'unknown-url';
6240
+ return `Network blocked: ${method} ${url}`;
6241
+ }
6242
+ function emitEvent(entry, event) {
6243
+ for (const listener of entry.listeners)listener(event);
6244
+ }
6245
+ function ensureNetworkBlockerWrapped(entry) {
6246
+ const blocker = entry.store.getState().networkBlocker;
6247
+ if (!blocker) return;
6248
+ if (blocker.onRequestBlocked === entry.wrappedNetworkBlockedCallback) return;
6249
+ entry.originalNetworkBlockedCallback = blocker.onRequestBlocked;
6250
+ entry.wrappedNetworkBlockedCallback = (payload)=>{
6251
+ emitEvent(entry, {
6252
+ type: 'network',
6253
+ message: getBlockedRequestMessage(payload),
6254
+ data: payload
6255
+ });
6256
+ if ('function' == typeof entry.originalNetworkBlockedCallback) entry.originalNetworkBlockedCallback(payload);
6257
+ };
6258
+ entry.store.getState().setNetworkBlocker({
6259
+ ...blocker,
6260
+ onRequestBlocked: entry.wrappedNetworkBlockedCallback
6261
+ });
6262
+ }
6263
+ function restoreInstrumentation(entry) {
6264
+ entry.stopWatchingStore?.();
6265
+ entry.stopWatchingStore = null;
6266
+ const state = entry.store.getState();
6267
+ state.setCallback('onBannerFetched', entry.originalCallbacks.onBannerFetched);
6268
+ state.setCallback('onConsentSet', entry.originalCallbacks.onConsentSet);
6269
+ state.setCallback('onError', entry.originalCallbacks.onError);
6270
+ state.setCallback('onBeforeConsentRevocationReload', entry.originalCallbacks.onBeforeConsentRevocationReload);
6271
+ const blocker = state.networkBlocker;
6272
+ if (blocker && blocker.onRequestBlocked === entry.wrappedNetworkBlockedCallback) state.setNetworkBlocker({
6273
+ ...blocker,
6274
+ onRequestBlocked: entry.originalNetworkBlockedCallback
6275
+ });
6276
+ entry.wrappedNetworkBlockedCallback = null;
6277
+ }
6278
+ function createInstrumentationEntry(store) {
6279
+ const entry = {
6280
+ store,
6281
+ listeners: new Set(),
6282
+ originalCallbacks: {
6283
+ ...store.getState().callbacks
6284
+ },
6285
+ originalNetworkBlockedCallback: store.getState().networkBlocker?.onRequestBlocked,
6286
+ wrappedNetworkBlockedCallback: null,
6287
+ stopWatchingStore: null
6288
+ };
6289
+ store.getState().setCallback('onBannerFetched', (payload)=>{
6290
+ const jurisdiction = payload.jurisdiction;
6291
+ emitEvent(entry, {
6292
+ type: 'info',
6293
+ message: `Banner fetched: ${String(jurisdiction)}`,
6294
+ data: payload
6295
+ });
6296
+ if ('function' == typeof entry.originalCallbacks.onBannerFetched) entry.originalCallbacks.onBannerFetched(payload);
6297
+ });
6298
+ store.getState().setCallback('onConsentSet', (payload)=>{
6299
+ emitEvent(entry, {
6300
+ type: 'consent_set',
6301
+ message: 'Consent preferences updated',
6302
+ data: payload
6303
+ });
6304
+ if ('function' == typeof entry.originalCallbacks.onConsentSet) entry.originalCallbacks.onConsentSet(payload);
6305
+ });
6306
+ store.getState().setCallback('onError', (payload)=>{
6307
+ const errorMessage = payload.error;
6308
+ emitEvent(entry, {
6309
+ type: 'error',
6310
+ message: `Error: ${String(errorMessage)}`,
6311
+ data: payload
6312
+ });
6313
+ if ('function' == typeof entry.originalCallbacks.onError) entry.originalCallbacks.onError(payload);
6314
+ });
6315
+ store.getState().setCallback('onBeforeConsentRevocationReload', (payload)=>{
6316
+ emitEvent(entry, {
6317
+ type: 'info',
6318
+ message: 'Consent revocation - page will reload',
6319
+ data: payload
6320
+ });
6321
+ if ('function' == typeof entry.originalCallbacks.onBeforeConsentRevocationReload) entry.originalCallbacks.onBeforeConsentRevocationReload(payload);
6322
+ });
6323
+ ensureNetworkBlockerWrapped(entry);
6324
+ entry.stopWatchingStore = store.subscribe(()=>{
6325
+ ensureNetworkBlockerWrapped(entry);
6326
+ });
6327
+ return entry;
6328
+ }
6329
+ function store_instrumentation_registerStoreInstrumentation(options) {
6330
+ const { namespace, store, onEvent } = options;
6331
+ const registry = getRegistry();
6332
+ let entry = registry.get(namespace);
6333
+ if (!entry || entry.store !== store) {
6334
+ if (entry) restoreInstrumentation(entry);
6335
+ entry = createInstrumentationEntry(store);
6336
+ registry.set(namespace, entry);
6337
+ }
6338
+ entry.listeners.add(onEvent);
6339
+ return ()=>{
6340
+ const current = registry.get(namespace);
6341
+ if (!current) return;
6342
+ current.listeners.delete(onEvent);
6343
+ if (0 === current.listeners.size) {
6344
+ restoreInstrumentation(current);
6345
+ registry.delete(namespace);
4882
6346
  }
4883
6347
  };
4884
6348
  }
@@ -4905,12 +6369,6 @@ function normalizeOverridesForPersistence(overrides) {
4905
6369
  function persistedOverridesEqual(a, b) {
4906
6370
  return a.country === b.country && a.region === b.region && a.language === b.language && a.gpc === b.gpc;
4907
6371
  }
4908
- function getBlockedRequestMessage(payload) {
4909
- const data = payload;
4910
- const method = 'string' == typeof data?.method ? data.method.toUpperCase() : 'REQUEST';
4911
- const url = 'string' == typeof data?.url ? data.url : 'unknown-url';
4912
- return `Network blocked: ${method} ${url}`;
4913
- }
4914
6372
  function prefersReducedMotion() {
4915
6373
  return 'undefined' != typeof window && 'function' == typeof window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
4916
6374
  }
@@ -4971,74 +6429,43 @@ function createPanelHeightAnimator() {
4971
6429
  destroy: clearAnimationState
4972
6430
  };
4973
6431
  }
6432
+ function createStateCopy(state) {
6433
+ return {
6434
+ consents: state.consents,
6435
+ selectedConsents: state.selectedConsents,
6436
+ consentInfo: state.consentInfo,
6437
+ locationInfo: state.locationInfo,
6438
+ model: state.model,
6439
+ overrides: state.overrides,
6440
+ scripts: state.scripts?.map((script)=>({
6441
+ id: script.id
6442
+ })),
6443
+ loadedScripts: state.loadedScripts
6444
+ };
6445
+ }
4974
6446
  function createDevTools(options = {}) {
4975
6447
  const { namespace = 'c15tStore', position = 'bottom-right', defaultOpen = false } = options;
4976
6448
  const stateManager = state_manager_createStateManager({
4977
6449
  position,
4978
6450
  isOpen: defaultOpen
4979
6451
  });
4980
- let originalCallbacks = {};
4981
- let originalNetworkBlockedCallback;
4982
- let hasWrappedNetworkBlockerCallback = false;
6452
+ let detachInstrumentation = null;
4983
6453
  const storeConnector = store_connector_createStoreConnector({
4984
6454
  namespace,
4985
- onConnect: (state, store)=>{
6455
+ onConnect: (_state, store)=>{
6456
+ detachInstrumentation?.();
6457
+ detachInstrumentation = store_instrumentation_registerStoreInstrumentation({
6458
+ namespace,
6459
+ store,
6460
+ onEvent: (event)=>{
6461
+ stateManager.addEvent(event);
6462
+ }
6463
+ });
4986
6464
  stateManager.setConnected(true);
4987
6465
  stateManager.addEvent({
4988
6466
  type: 'info',
4989
6467
  message: 'Connected to c15tStore'
4990
6468
  });
4991
- originalCallbacks = {
4992
- ...state.callbacks
4993
- };
4994
- store.getState().setCallback('onBannerFetched', (payload)=>{
4995
- stateManager.addEvent({
4996
- type: 'info',
4997
- message: `Banner fetched: ${String(payload.jurisdiction)}`,
4998
- data: payload
4999
- });
5000
- if ('function' == typeof originalCallbacks.onBannerFetched) originalCallbacks.onBannerFetched(payload);
5001
- });
5002
- store.getState().setCallback('onConsentSet', (payload)=>{
5003
- stateManager.addEvent({
5004
- type: 'consent_set',
5005
- message: 'Consent preferences updated',
5006
- data: payload
5007
- });
5008
- if ('function' == typeof originalCallbacks.onConsentSet) originalCallbacks.onConsentSet(payload);
5009
- });
5010
- store.getState().setCallback('onError', (payload)=>{
5011
- stateManager.addEvent({
5012
- type: 'error',
5013
- message: `Error: ${payload.error}`,
5014
- data: payload
5015
- });
5016
- if ('function' == typeof originalCallbacks.onError) originalCallbacks.onError(payload);
5017
- });
5018
- store.getState().setCallback('onBeforeConsentRevocationReload', (payload)=>{
5019
- stateManager.addEvent({
5020
- type: 'info',
5021
- message: 'Consent revocation - page will reload',
5022
- data: payload
5023
- });
5024
- if ('function' == typeof originalCallbacks.onBeforeConsentRevocationReload) originalCallbacks.onBeforeConsentRevocationReload(payload);
5025
- });
5026
- const currentNetworkBlocker = store.getState().networkBlocker;
5027
- if (currentNetworkBlocker && !hasWrappedNetworkBlockerCallback) {
5028
- originalNetworkBlockedCallback = currentNetworkBlocker.onRequestBlocked;
5029
- hasWrappedNetworkBlockerCallback = true;
5030
- store.getState().setNetworkBlocker({
5031
- ...currentNetworkBlocker,
5032
- onRequestBlocked: (payload)=>{
5033
- stateManager.addEvent({
5034
- type: 'network',
5035
- message: getBlockedRequestMessage(payload),
5036
- data: payload
5037
- });
5038
- if ('function' == typeof originalNetworkBlockedCallback) originalNetworkBlockedCallback(payload);
5039
- }
5040
- });
5041
- }
5042
6469
  const persistedOverrides = override_storage_loadPersistedOverrides();
5043
6470
  if (persistedOverrides) {
5044
6471
  const currentOverrides = normalizeOverridesForPersistence(store.getState().overrides);
@@ -5068,6 +6495,8 @@ function createDevTools(options = {}) {
5068
6495
  },
5069
6496
  onDisconnect: ()=>{
5070
6497
  stateManager.setConnected(false);
6498
+ detachInstrumentation?.();
6499
+ detachInstrumentation = null;
5071
6500
  stateManager.addEvent({
5072
6501
  type: 'error',
5073
6502
  message: 'Disconnected from c15tStore'
@@ -5075,6 +6504,31 @@ function createDevTools(options = {}) {
5075
6504
  },
5076
6505
  onStateChange: ()=>{}
5077
6506
  });
6507
+ const panelRenderer = panel_renderer_createPanelRenderer({
6508
+ storeConnector,
6509
+ stateManager,
6510
+ enableEventLogging: true,
6511
+ onPersistOverrides: override_storage_persistOverrides,
6512
+ onClearPersistedOverrides: override_storage_clearPersistedOverrides,
6513
+ onCopyState: async (state)=>{
6514
+ try {
6515
+ await navigator.clipboard.writeText(JSON.stringify(createStateCopy(state), null, 2));
6516
+ return true;
6517
+ } catch {
6518
+ return false;
6519
+ }
6520
+ },
6521
+ onExportDebugBundle: ()=>{
6522
+ const bundle = debug_bundle_createDebugBundle({
6523
+ namespace,
6524
+ devToolsState: stateManager.getState(),
6525
+ connection: storeConnector.getDiagnostics(),
6526
+ recentEvents: stateManager.getState().eventLog.slice(0, 100),
6527
+ storeState: debug_bundle_sanitizeStoreState(storeConnector.getState())
6528
+ });
6529
+ debug_bundle_downloadDebugBundle(bundle);
6530
+ }
6531
+ });
5078
6532
  let tabsInstance = null;
5079
6533
  const panelHeightAnimator = createPanelHeightAnimator();
5080
6534
  const panelInstance = createPanel({
@@ -5082,19 +6536,24 @@ function createDevTools(options = {}) {
5082
6536
  storeConnector,
5083
6537
  namespace,
5084
6538
  onRenderContent: (container)=>{
5085
- renderContent(container, stateManager, storeConnector);
6539
+ renderContent(container);
5086
6540
  }
5087
6541
  });
5088
- function renderContent(container, stateManager, storeConnector) {
6542
+ function renderContent(container) {
5089
6543
  const panel = container.parentElement;
5090
6544
  const previousPanelHeight = panel?.getBoundingClientRect().height ?? 0;
5091
6545
  clearElement(container);
5092
6546
  const storeState = storeConnector.getState();
5093
6547
  const disabledTabs = [];
5094
6548
  if (!storeState || 'iab' !== storeState.model) disabledTabs.push('iab');
6549
+ let currentActiveTab = stateManager.getState().activeTab;
6550
+ if (disabledTabs.includes(currentActiveTab)) {
6551
+ stateManager.setActiveTab('consents');
6552
+ currentActiveTab = 'consents';
6553
+ }
5095
6554
  if (tabsInstance) tabsInstance.destroy();
5096
6555
  tabsInstance = tabs_createTabs({
5097
- activeTab: stateManager.getState().activeTab,
6556
+ activeTab: currentActiveTab,
5098
6557
  onTabChange: (tab)=>{
5099
6558
  stateManager.setActiveTab(tab);
5100
6559
  },
@@ -5109,284 +6568,9 @@ function createDevTools(options = {}) {
5109
6568
  }
5110
6569
  });
5111
6570
  container.appendChild(panelContent);
5112
- const state = stateManager.getState();
5113
- const getStoreState = ()=>storeConnector.getState();
5114
- switch(state.activeTab){
5115
- case 'consents':
5116
- consents_renderConsentsPanel(panelContent, {
5117
- getState: getStoreState,
5118
- onConsentChange: (name, value)=>{
5119
- const store = storeConnector.getStore();
5120
- if (store) {
5121
- const consentName = String(name);
5122
- store.getState().setSelectedConsent(consentName, value);
5123
- stateManager.addEvent({
5124
- type: 'info',
5125
- message: `${consentName} toggled to ${value} (not saved)`,
5126
- data: {
5127
- name: consentName,
5128
- value
5129
- }
5130
- });
5131
- }
5132
- },
5133
- onSave: ()=>{
5134
- const store = storeConnector.getStore();
5135
- if (store) {
5136
- store.getState().saveConsents('custom');
5137
- stateManager.addEvent({
5138
- type: 'consent_save',
5139
- message: 'Saved consent preferences'
5140
- });
5141
- }
5142
- },
5143
- onAcceptAll: ()=>{
5144
- const store = storeConnector.getStore();
5145
- if (store) {
5146
- store.getState().saveConsents('all');
5147
- stateManager.addEvent({
5148
- type: 'consent_save',
5149
- message: 'Accepted all consents'
5150
- });
5151
- }
5152
- },
5153
- onRejectAll: ()=>{
5154
- const store = storeConnector.getStore();
5155
- if (store) {
5156
- store.getState().saveConsents('necessary');
5157
- stateManager.addEvent({
5158
- type: 'consent_save',
5159
- message: 'Rejected all optional consents'
5160
- });
5161
- }
5162
- },
5163
- onReset: async ()=>{
5164
- const store = storeConnector.getStore();
5165
- if (store) await reset_consents_resetAllConsents(store, stateManager);
5166
- }
5167
- });
5168
- break;
5169
- case 'location':
5170
- location_renderLocationPanel(panelContent, {
5171
- getState: getStoreState,
5172
- onApplyOverrides: async (overrides)=>{
5173
- const store = storeConnector.getStore();
5174
- if (store) {
5175
- await store.getState().setOverrides({
5176
- country: overrides.country,
5177
- region: overrides.region,
5178
- language: overrides.language,
5179
- gpc: overrides.gpc
5180
- });
5181
- override_storage_persistOverrides({
5182
- country: overrides.country,
5183
- region: overrides.region,
5184
- language: overrides.language,
5185
- gpc: overrides.gpc
5186
- });
5187
- stateManager.addEvent({
5188
- type: 'info',
5189
- message: 'Overrides updated',
5190
- data: {
5191
- country: overrides.country,
5192
- region: overrides.region,
5193
- language: overrides.language,
5194
- gpc: overrides.gpc
5195
- }
5196
- });
5197
- }
5198
- },
5199
- onClearOverrides: async ()=>{
5200
- const store = storeConnector.getStore();
5201
- if (store) {
5202
- await store.getState().setOverrides({
5203
- country: void 0,
5204
- region: void 0,
5205
- language: void 0,
5206
- gpc: void 0
5207
- });
5208
- override_storage_clearPersistedOverrides();
5209
- stateManager.addEvent({
5210
- type: 'info',
5211
- message: 'Overrides cleared'
5212
- });
5213
- }
5214
- }
5215
- });
5216
- break;
5217
- case "scripts":
5218
- scripts_renderScriptsPanel(panelContent, {
5219
- getState: getStoreState,
5220
- getEvents: ()=>stateManager.getState().eventLog
5221
- });
5222
- break;
5223
- case 'iab':
5224
- iab_renderIabPanel(panelContent, {
5225
- getState: getStoreState,
5226
- onSetPurposeConsent: (purposeId, value)=>{
5227
- const iab = storeConnector.getStore()?.getState().iab;
5228
- if (!iab) return;
5229
- iab.setPurposeConsent(purposeId, value);
5230
- stateManager.addEvent({
5231
- type: 'iab',
5232
- message: `IAB purpose ${purposeId} set to ${value}`,
5233
- data: {
5234
- purposeId,
5235
- value
5236
- }
5237
- });
5238
- },
5239
- onSetVendorConsent: (vendorId, value)=>{
5240
- const iab = storeConnector.getStore()?.getState().iab;
5241
- if (!iab) return;
5242
- iab.setVendorConsent(vendorId, value);
5243
- stateManager.addEvent({
5244
- type: 'iab',
5245
- message: `IAB vendor ${vendorId} set to ${value}`,
5246
- data: {
5247
- vendorId,
5248
- value
5249
- }
5250
- });
5251
- },
5252
- onSetSpecialFeatureOptIn: (featureId, value)=>{
5253
- const iab = storeConnector.getStore()?.getState().iab;
5254
- if (!iab) return;
5255
- iab.setSpecialFeatureOptIn(featureId, value);
5256
- stateManager.addEvent({
5257
- type: 'iab',
5258
- message: `IAB feature ${featureId} set to ${value}`,
5259
- data: {
5260
- featureId,
5261
- value
5262
- }
5263
- });
5264
- },
5265
- onAcceptAll: ()=>{
5266
- const iab = storeConnector.getStore()?.getState().iab;
5267
- if (!iab) return;
5268
- iab.acceptAll();
5269
- stateManager.addEvent({
5270
- type: 'iab',
5271
- message: 'IAB accept all selected'
5272
- });
5273
- },
5274
- onRejectAll: ()=>{
5275
- const iab = storeConnector.getStore()?.getState().iab;
5276
- if (!iab) return;
5277
- iab.rejectAll();
5278
- stateManager.addEvent({
5279
- type: 'iab',
5280
- message: 'IAB reject all selected'
5281
- });
5282
- },
5283
- onSave: ()=>{
5284
- const iab = storeConnector.getStore()?.getState().iab;
5285
- if (!iab) return;
5286
- iab.save().then(()=>{
5287
- stateManager.addEvent({
5288
- type: 'iab',
5289
- message: 'IAB preferences saved'
5290
- });
5291
- }).catch((error)=>{
5292
- stateManager.addEvent({
5293
- type: 'error',
5294
- message: `Failed to save IAB preferences: ${String(error)}`
5295
- });
5296
- });
5297
- },
5298
- onReset: async ()=>{
5299
- const store = storeConnector.getStore();
5300
- if (store) await reset_consents_resetAllConsents(store, stateManager);
5301
- }
5302
- });
5303
- break;
5304
- case 'events':
5305
- events_renderEventsPanel(panelContent, {
5306
- getEvents: ()=>stateManager.getState().eventLog,
5307
- onClear: ()=>{
5308
- stateManager.clearEventLog();
5309
- stateManager.addEvent({
5310
- type: 'info',
5311
- message: 'Event log cleared'
5312
- });
5313
- }
5314
- });
5315
- break;
5316
- case 'actions':
5317
- actions_renderActionsPanel(panelContent, {
5318
- getState: getStoreState,
5319
- onResetConsents: async ()=>{
5320
- const store = storeConnector.getStore();
5321
- if (store) await reset_consents_resetAllConsents(store, stateManager);
5322
- },
5323
- onRefetchBanner: async ()=>{
5324
- const store = storeConnector.getStore();
5325
- if (store) {
5326
- await store.getState().initConsentManager();
5327
- stateManager.addEvent({
5328
- type: 'info',
5329
- message: 'Banner data refetched'
5330
- });
5331
- }
5332
- },
5333
- onShowBanner: ()=>{
5334
- const store = storeConnector.getStore();
5335
- if (store) {
5336
- store.getState().setActiveUI('banner', {
5337
- force: true
5338
- });
5339
- stateManager.addEvent({
5340
- type: 'info',
5341
- message: 'Banner shown'
5342
- });
5343
- }
5344
- },
5345
- onOpenPreferences: ()=>{
5346
- const store = storeConnector.getStore();
5347
- if (store) {
5348
- store.getState().setActiveUI('dialog');
5349
- stateManager.addEvent({
5350
- type: 'info',
5351
- message: 'Preference center opened'
5352
- });
5353
- }
5354
- },
5355
- onCopyState: ()=>{
5356
- const state = storeConnector.getState();
5357
- if (state) {
5358
- const stateCopy = {
5359
- consents: state.consents,
5360
- consentInfo: state.consentInfo,
5361
- locationInfo: state.locationInfo,
5362
- model: state.model,
5363
- overrides: state.overrides,
5364
- scripts: state.scripts?.map((s)=>({
5365
- id: s.id
5366
- })),
5367
- loadedScripts: state.loadedScripts
5368
- };
5369
- navigator.clipboard.writeText(JSON.stringify(stateCopy, null, 2)).then(()=>{
5370
- stateManager.addEvent({
5371
- type: 'info',
5372
- message: 'State copied to clipboard'
5373
- });
5374
- }).catch(()=>{
5375
- stateManager.addEvent({
5376
- type: 'error',
5377
- message: 'Failed to copy state'
5378
- });
5379
- });
5380
- }
5381
- }
5382
- });
5383
- break;
5384
- }
6571
+ panelRenderer.renderPanel(panelContent, currentActiveTab);
5385
6572
  if (panel) panelHeightAnimator.animate(panel, previousPanelHeight);
5386
6573
  }
5387
- storeConnector.subscribe(()=>{
5388
- panelInstance.update();
5389
- });
5390
6574
  const instance = {
5391
6575
  open: ()=>stateManager.setOpen(true),
5392
6576
  close: ()=>stateManager.setOpen(false),
@@ -5400,20 +6584,8 @@ function createDevTools(options = {}) {
5400
6584
  };
5401
6585
  },
5402
6586
  destroy: ()=>{
5403
- const store = storeConnector.getStore();
5404
- if (store) {
5405
- store.getState().setCallback('onBannerFetched', originalCallbacks.onBannerFetched);
5406
- store.getState().setCallback('onConsentSet', originalCallbacks.onConsentSet);
5407
- store.getState().setCallback('onError', originalCallbacks.onError);
5408
- store.getState().setCallback('onBeforeConsentRevocationReload', originalCallbacks.onBeforeConsentRevocationReload);
5409
- if (hasWrappedNetworkBlockerCallback) {
5410
- const currentNetworkBlocker = store.getState().networkBlocker;
5411
- if (currentNetworkBlocker) store.getState().setNetworkBlocker({
5412
- ...currentNetworkBlocker,
5413
- onRequestBlocked: originalNetworkBlockedCallback
5414
- });
5415
- }
5416
- }
6587
+ detachInstrumentation?.();
6588
+ detachInstrumentation = null;
5417
6589
  panelHeightAnimator.destroy();
5418
6590
  tabsInstance?.destroy();
5419
6591
  panelInstance.destroy();