@c15t/dev-tools 2.0.0-rc.4 → 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 (75) hide show
  1. package/README.md +12 -1
  2. package/dist/index.cjs +346 -36
  3. package/dist/index.js +346 -36
  4. package/dist/react.cjs +346 -36
  5. package/dist/react.js +346 -36
  6. package/dist/tanstack.cjs +340 -35
  7. package/dist/tanstack.js +340 -35
  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 +0 -1
  13. package/{dist → dist-types}/core/debug-bundle.d.ts +1 -2
  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 +1 -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 +1 -2
  23. package/{dist → dist-types}/core/store-instrumentation.d.ts +1 -2
  24. package/{dist → dist-types}/index.d.ts +0 -1
  25. package/{dist → dist-types}/panels/actions.d.ts +1 -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 +32 -29
  42. package/CHANGELOG.md +0 -163
  43. package/dist/components/dropdown-menu.d.ts.map +0 -1
  44. package/dist/components/index.d.ts.map +0 -1
  45. package/dist/components/panel.d.ts.map +0 -1
  46. package/dist/components/tabs.d.ts.map +0 -1
  47. package/dist/components/ui.d.ts.map +0 -1
  48. package/dist/core/debug-bundle.d.ts.map +0 -1
  49. package/dist/core/devtools.d.ts.map +0 -1
  50. package/dist/core/draggable.d.ts.map +0 -1
  51. package/dist/core/index.d.ts.map +0 -1
  52. package/dist/core/override-storage.d.ts.map +0 -1
  53. package/dist/core/panel-renderer.d.ts.map +0 -1
  54. package/dist/core/renderer.d.ts.map +0 -1
  55. package/dist/core/reset-consents.d.ts.map +0 -1
  56. package/dist/core/state-manager.d.ts.map +0 -1
  57. package/dist/core/store-connector.d.ts.map +0 -1
  58. package/dist/core/store-instrumentation.d.ts.map +0 -1
  59. package/dist/index.d.ts.map +0 -1
  60. package/dist/panels/actions.d.ts.map +0 -1
  61. package/dist/panels/consents.d.ts.map +0 -1
  62. package/dist/panels/dom-scanner.d.ts.map +0 -1
  63. package/dist/panels/events.d.ts.map +0 -1
  64. package/dist/panels/iab.d.ts.map +0 -1
  65. package/dist/panels/index.d.ts.map +0 -1
  66. package/dist/panels/location.d.ts.map +0 -1
  67. package/dist/panels/scripts.d.ts.map +0 -1
  68. package/dist/react.d.ts.map +0 -1
  69. package/dist/styles/index.d.ts.map +0 -1
  70. package/dist/tanstack.d.ts.map +0 -1
  71. package/dist/utils/index.d.ts.map +0 -1
  72. package/dist/utils/preference-trigger.d.ts.map +0 -1
  73. package/dist/version.d.ts +0 -2
  74. package/dist/version.d.ts.map +0 -1
  75. package/tsconfig.json +0 -20
package/dist/index.js CHANGED
@@ -2185,6 +2185,27 @@ panel_module_options.domAPI = styleDomAPI_default();
2185
2185
  panel_module_options.insertStyleElement = insertStyleElement_default();
2186
2186
  injectStylesIntoStyleTag_default()(panel_module.A, panel_module_options);
2187
2187
  const styles_panel_module = panel_module.A && panel_module.A.locals ? panel_module.A.locals : void 0;
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
+ }
2188
2209
  const PREFERENCE_TRIGGER_SELECTORS = '[data-c15t-trigger], [aria-label*="privacy settings" i], [aria-label*="preference" i]';
2189
2210
  const PREVIOUS_DISPLAY_ATTR = 'data-c15t-devtools-prev-display';
2190
2211
  function detectPreferenceTrigger() {
@@ -2221,7 +2242,7 @@ function getPreferenceCenterOpener(namespace = 'c15tStore') {
2221
2242
  }
2222
2243
  return null;
2223
2244
  }
2224
- const version = '2.0.0-rc.4';
2245
+ const version = '2.0.0-rc.5';
2225
2246
  const DEVTOOLS_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 446 445" aria-label="c15t">
2226
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"/>
2227
2248
  </svg>`;
@@ -2605,6 +2626,7 @@ function createPanel(options) {
2605
2626
  const storeState = storeConnector.getState();
2606
2627
  const isLoading = storeState?.isLoadingConsentInfo ?? false;
2607
2628
  const diagnostics = storeConnector.getDiagnostics();
2629
+ const initSource = formatInitSource(storeState?.initDataSource ?? null, storeState?.initDataSourceDetail ?? null);
2608
2630
  const statusChildren = [
2609
2631
  renderer_span({
2610
2632
  className: `${styles_panel_module.statusDot} ${isConnected ? styles_panel_module.statusConnected : styles_panel_module.statusDisconnected}`
@@ -2621,6 +2643,10 @@ function createPanel(options) {
2621
2643
  className: styles_panel_module.footerMeta,
2622
2644
  text: `· ${diagnostics.namespace} · retry ${diagnostics.reconnectAttempts} · next ${formatRetryDelay(diagnostics.nextRetryInMs)}`
2623
2645
  }));
2646
+ if (isConnected) statusChildren.push(renderer_span({
2647
+ className: styles_panel_module.footerMeta,
2648
+ text: `· Init: ${initSource}`
2649
+ }));
2624
2650
  footerElement.appendChild(renderer_div({
2625
2651
  className: styles_panel_module.footerStatus,
2626
2652
  children: statusChildren
@@ -2788,6 +2814,11 @@ const LOCATION_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 2
2788
2814
  <line x1="2" y1="12" x2="22" y2="12"></line>
2789
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>
2790
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>`;
2791
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">
2792
2823
  <polyline points="16 18 22 12 16 6"></polyline>
2793
2824
  <polyline points="8 6 2 12 8 18"></polyline>
@@ -2815,6 +2846,11 @@ const TABS = [
2815
2846
  label: 'Location',
2816
2847
  icon: LOCATION_ICON
2817
2848
  },
2849
+ {
2850
+ id: 'policy',
2851
+ label: 'Policy',
2852
+ icon: POLICY_ICON
2853
+ },
2818
2854
  {
2819
2855
  id: 'consents',
2820
2856
  label: 'Consents',
@@ -2975,6 +3011,7 @@ function createTabs(options) {
2975
3011
  const forcedOverflowTab = showOverflowSecondTabInStrip ? preferredSecondTab : overflowSecondTab;
2976
3012
  const layoutTabIds = [
2977
3013
  'location',
3014
+ 'policy',
2978
3015
  stripSecondTab,
2979
3016
  "scripts",
2980
3017
  'actions',
@@ -3639,7 +3676,6 @@ function createIconWrapper(icon, size) {
3639
3676
  function getNamespace(state) {
3640
3677
  return state.config?.meta?.namespace || 'c15tStore';
3641
3678
  }
3642
- const consentSearchByContainer = new WeakMap();
3643
3679
  function renderConsentsPanel(container, options) {
3644
3680
  const { getState, onConsentChange, onSave, onAcceptAll, onRejectAll, onReset } = options;
3645
3681
  clearElement(container);
@@ -3658,40 +3694,15 @@ function renderConsentsPanel(container, options) {
3658
3694
  ct.name,
3659
3695
  ct
3660
3696
  ]));
3661
- const searchQuery = consentSearchByContainer.get(container) ?? '';
3662
3697
  const consentEntries = Object.entries(displayConsents);
3663
- const filteredConsentEntries = consentEntries.filter(([name])=>{
3664
- if (!searchQuery) return true;
3665
- const consentType = consentTypeMap.get(name);
3666
- const displayName = consentType?.name || name;
3667
- return `${name} ${displayName}`.toLowerCase().includes(searchQuery);
3668
- });
3669
- const showSearchInput = consentEntries.length > 4;
3670
- if (showSearchInput) container.appendChild(renderer_div({
3671
- style: {
3672
- padding: '8px 0 10px'
3673
- },
3674
- children: [
3675
- createInput({
3676
- value: searchQuery,
3677
- placeholder: 'Filter consents…',
3678
- ariaLabel: 'Filter consents',
3679
- small: true,
3680
- onInput: (value)=>{
3681
- consentSearchByContainer.set(container, value.trim().toLowerCase());
3682
- renderConsentsPanel(container, options);
3683
- }
3684
- })
3685
- ]
3686
- }));
3687
- if (0 === filteredConsentEntries.length) container.appendChild(renderer_div({
3698
+ if (0 === consentEntries.length) container.appendChild(renderer_div({
3688
3699
  style: {
3689
3700
  padding: '24px',
3690
3701
  textAlign: 'center',
3691
3702
  color: 'var(--c15t-devtools-text-muted)',
3692
3703
  fontSize: 'var(--c15t-devtools-font-size-sm)'
3693
3704
  },
3694
- text: 0 === consentEntries.length ? 'No consents configured' : 'No matching consents'
3705
+ text: 'No consents configured'
3695
3706
  }));
3696
3707
  else {
3697
3708
  if (isIabMode) {
@@ -3709,7 +3720,7 @@ function renderConsentsPanel(container, options) {
3709
3720
  container.appendChild(iabNotice);
3710
3721
  }
3711
3722
  const gridCards = [];
3712
- for (const [name, value] of filteredConsentEntries){
3723
+ for (const [name, value] of consentEntries){
3713
3724
  const consentType = consentTypeMap.get(name);
3714
3725
  const isNecessary = 'necessary' === name;
3715
3726
  const displayName = consentType?.name || name;
@@ -4468,11 +4479,15 @@ function renderLocationPanel(container, options) {
4468
4479
  const locationInfo = state.locationInfo;
4469
4480
  const overrides = state.overrides;
4470
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);
4471
4486
  const gridItems = [
4472
4487
  createCompactInfoCard('Country', locationInfo?.countryCode || '—'),
4473
4488
  createCompactInfoCard('Region', locationInfo?.regionCode || '—'),
4474
- createCompactInfoCard('Jurisdiction', locationInfo?.jurisdiction || '—'),
4475
- createCompactInfoCard('Language', translationConfig?.defaultLanguage || '—')
4489
+ createCompactInfoCard('Language', translationConfig?.defaultLanguage || '—'),
4490
+ createCompactInfoCard('Init Source', initSource)
4476
4491
  ];
4477
4492
  gridItems.push(createCompactInfoCard('GPC', getEffectiveGpcLabel(overrides?.gpc)));
4478
4493
  if (state.model) gridItems.push(createCompactInfoCard('Model', getModelLabel(state.model)));
@@ -4480,7 +4495,6 @@ function renderLocationPanel(container, options) {
4480
4495
  columns: 3,
4481
4496
  children: gridItems
4482
4497
  });
4483
- container.appendChild(locationGrid);
4484
4498
  const initialDraft = getDraftFromOverrides(overrides);
4485
4499
  let appliedOverrides = normalizeOverrideDraft(initialDraft);
4486
4500
  let isSubmitting = false;
@@ -4571,6 +4585,12 @@ function renderLocationPanel(container, options) {
4571
4585
  ]
4572
4586
  });
4573
4587
  container.appendChild(overrideSection);
4588
+ container.appendChild(locationGrid);
4589
+ container.appendChild(createActivePolicySummarySection({
4590
+ policy: activePolicy,
4591
+ policyDecision,
4592
+ policySnapshotToken: initData?.policySnapshotToken
4593
+ }));
4574
4594
  countryField.control.addEventListener('change', updateFormState);
4575
4595
  regionField.control.addEventListener('input', updateFormState);
4576
4596
  languageField.control.addEventListener('input', updateFormState);
@@ -4859,15 +4879,53 @@ function getModelLabel(model) {
4859
4879
  return 'None';
4860
4880
  }
4861
4881
  }
4882
+ function createActivePolicySummarySection(options) {
4883
+ const { policy, policyDecision, policySnapshotToken } = options;
4884
+ if (!policy && !policyDecision) return createSection({
4885
+ title: 'Active Policy',
4886
+ children: [
4887
+ renderer_div({
4888
+ style: {
4889
+ padding: '10px 12px',
4890
+ fontSize: 'var(--c15t-devtools-font-size-sm)',
4891
+ color: 'var(--c15t-text-muted)'
4892
+ },
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
+ }
4862
4920
  function createCompactInfoCard(label, value) {
4863
4921
  return renderer_div({
4864
4922
  className: styles_components_module.gridCard ?? '',
4865
4923
  style: {
4866
- padding: '6px 8px',
4924
+ padding: '8px 10px',
4867
4925
  minHeight: 'auto',
4868
4926
  flexDirection: 'column',
4869
4927
  alignItems: 'flex-start',
4870
- gap: '1px'
4928
+ gap: '2px'
4871
4929
  },
4872
4930
  children: [
4873
4931
  renderer_span({
@@ -4888,6 +4946,253 @@ function createCompactInfoCard(label, value) {
4888
4946
  ]
4889
4947
  });
4890
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
+ },
5175
+ text: value
5176
+ })
5177
+ ]
5178
+ });
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
+ }
4891
5196
  const dismissedResources = new Set();
4892
5197
  function scanDOM(state) {
4893
5198
  const results = [];
@@ -5526,6 +5831,11 @@ function createPanelRenderer(config) {
5526
5831
  }
5527
5832
  });
5528
5833
  break;
5834
+ case 'policy':
5835
+ renderPolicyPanel(container, {
5836
+ getState: getStoreState
5837
+ });
5838
+ break;
5529
5839
  case "scripts":
5530
5840
  renderScriptsPanel(container, {
5531
5841
  getState: getStoreState,
@@ -5662,7 +5972,7 @@ function persistEvents(events) {
5662
5972
  } catch {}
5663
5973
  }
5664
5974
  function isDevToolsTab(value) {
5665
- return 'consents' === value || 'location' === value || "scripts" === value || 'iab' === value || 'events' === value || 'actions' === value;
5975
+ return 'consents' === value || 'location' === value || 'policy' === value || "scripts" === value || 'iab' === value || 'events' === value || 'actions' === value;
5666
5976
  }
5667
5977
  function loadPersistedActiveTab() {
5668
5978
  if ('undefined' == typeof window) return null;