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