@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/react.cjs CHANGED
@@ -2205,6 +2205,27 @@ var __webpack_exports__ = {};
2205
2205
  panel_module_options.insertStyleElement = insertStyleElement_default();
2206
2206
  injectStylesIntoStyleTag_default()(panel_module.A, panel_module_options);
2207
2207
  const styles_panel_module = panel_module.A && panel_module.A.locals ? panel_module.A.locals : void 0;
2208
+ function formatInitSource(source, detail) {
2209
+ const label = (()=>{
2210
+ switch(source){
2211
+ case 'ssr':
2212
+ return 'SSR Prefetch';
2213
+ case 'backend':
2214
+ return 'Backend';
2215
+ case 'backend-cache-hit':
2216
+ return 'Backend (Cache Hit)';
2217
+ case 'offline-fallback':
2218
+ return 'Offline Fallback';
2219
+ case 'offline-mode':
2220
+ return 'Offline Mode';
2221
+ case 'custom':
2222
+ return 'Custom Client';
2223
+ default:
2224
+ return '—';
2225
+ }
2226
+ })();
2227
+ return detail ? `${label} [${detail}]` : label;
2228
+ }
2208
2229
  const PREFERENCE_TRIGGER_SELECTORS = '[data-c15t-trigger], [aria-label*="privacy settings" i], [aria-label*="preference" i]';
2209
2230
  const PREVIOUS_DISPLAY_ATTR = 'data-c15t-devtools-prev-display';
2210
2231
  function detectPreferenceTrigger() {
@@ -2241,7 +2262,7 @@ var __webpack_exports__ = {};
2241
2262
  }
2242
2263
  return null;
2243
2264
  }
2244
- const version = '2.0.0-rc.4';
2265
+ const version = '2.0.0-rc.5';
2245
2266
  const DEVTOOLS_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 446 445" aria-label="c15t">
2246
2267
  <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"/>
2247
2268
  </svg>`;
@@ -2625,6 +2646,7 @@ var __webpack_exports__ = {};
2625
2646
  const storeState = storeConnector.getState();
2626
2647
  const isLoading = storeState?.isLoadingConsentInfo ?? false;
2627
2648
  const diagnostics = storeConnector.getDiagnostics();
2649
+ const initSource = formatInitSource(storeState?.initDataSource ?? null, storeState?.initDataSourceDetail ?? null);
2628
2650
  const statusChildren = [
2629
2651
  renderer_span({
2630
2652
  className: `${styles_panel_module.statusDot} ${isConnected ? styles_panel_module.statusConnected : styles_panel_module.statusDisconnected}`
@@ -2641,6 +2663,10 @@ var __webpack_exports__ = {};
2641
2663
  className: styles_panel_module.footerMeta,
2642
2664
  text: `· ${diagnostics.namespace} · retry ${diagnostics.reconnectAttempts} · next ${formatRetryDelay(diagnostics.nextRetryInMs)}`
2643
2665
  }));
2666
+ if (isConnected) statusChildren.push(renderer_span({
2667
+ className: styles_panel_module.footerMeta,
2668
+ text: `· Init: ${initSource}`
2669
+ }));
2644
2670
  footerElement.appendChild(renderer_div({
2645
2671
  className: styles_panel_module.footerStatus,
2646
2672
  children: statusChildren
@@ -2807,6 +2833,11 @@ var __webpack_exports__ = {};
2807
2833
  <circle cx="12" cy="12" r="10"></circle>
2808
2834
  <line x1="2" y1="12" x2="22" y2="12"></line>
2809
2835
  <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>
2836
+ </svg>`;
2837
+ 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">
2838
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
2839
+ <path d="M9 12h6"></path>
2840
+ <path d="M12 9v6"></path>
2810
2841
  </svg>`;
2811
2842
  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">
2812
2843
  <polyline points="16 18 22 12 16 6"></polyline>
@@ -2835,6 +2866,11 @@ var __webpack_exports__ = {};
2835
2866
  label: 'Location',
2836
2867
  icon: LOCATION_ICON
2837
2868
  },
2869
+ {
2870
+ id: 'policy',
2871
+ label: 'Policy',
2872
+ icon: POLICY_ICON
2873
+ },
2838
2874
  {
2839
2875
  id: 'consents',
2840
2876
  label: 'Consents',
@@ -2995,6 +3031,7 @@ var __webpack_exports__ = {};
2995
3031
  const forcedOverflowTab = showOverflowSecondTabInStrip ? preferredSecondTab : overflowSecondTab;
2996
3032
  const layoutTabIds = [
2997
3033
  'location',
3034
+ 'policy',
2998
3035
  stripSecondTab,
2999
3036
  "scripts",
3000
3037
  'actions',
@@ -3659,7 +3696,6 @@ var __webpack_exports__ = {};
3659
3696
  function getNamespace(state) {
3660
3697
  return state.config?.meta?.namespace || 'c15tStore';
3661
3698
  }
3662
- const consentSearchByContainer = new WeakMap();
3663
3699
  function renderConsentsPanel(container, options) {
3664
3700
  const { getState, onConsentChange, onSave, onAcceptAll, onRejectAll, onReset } = options;
3665
3701
  clearElement(container);
@@ -3678,40 +3714,15 @@ var __webpack_exports__ = {};
3678
3714
  ct.name,
3679
3715
  ct
3680
3716
  ]));
3681
- const searchQuery = consentSearchByContainer.get(container) ?? '';
3682
3717
  const consentEntries = Object.entries(displayConsents);
3683
- const filteredConsentEntries = consentEntries.filter(([name])=>{
3684
- if (!searchQuery) return true;
3685
- const consentType = consentTypeMap.get(name);
3686
- const displayName = consentType?.name || name;
3687
- return `${name} ${displayName}`.toLowerCase().includes(searchQuery);
3688
- });
3689
- const showSearchInput = consentEntries.length > 4;
3690
- if (showSearchInput) container.appendChild(renderer_div({
3691
- style: {
3692
- padding: '8px 0 10px'
3693
- },
3694
- children: [
3695
- createInput({
3696
- value: searchQuery,
3697
- placeholder: 'Filter consents…',
3698
- ariaLabel: 'Filter consents',
3699
- small: true,
3700
- onInput: (value)=>{
3701
- consentSearchByContainer.set(container, value.trim().toLowerCase());
3702
- renderConsentsPanel(container, options);
3703
- }
3704
- })
3705
- ]
3706
- }));
3707
- if (0 === filteredConsentEntries.length) container.appendChild(renderer_div({
3718
+ if (0 === consentEntries.length) container.appendChild(renderer_div({
3708
3719
  style: {
3709
3720
  padding: '24px',
3710
3721
  textAlign: 'center',
3711
3722
  color: 'var(--c15t-devtools-text-muted)',
3712
3723
  fontSize: 'var(--c15t-devtools-font-size-sm)'
3713
3724
  },
3714
- text: 0 === consentEntries.length ? 'No consents configured' : 'No matching consents'
3725
+ text: 'No consents configured'
3715
3726
  }));
3716
3727
  else {
3717
3728
  if (isIabMode) {
@@ -3729,7 +3740,7 @@ var __webpack_exports__ = {};
3729
3740
  container.appendChild(iabNotice);
3730
3741
  }
3731
3742
  const gridCards = [];
3732
- for (const [name, value] of filteredConsentEntries){
3743
+ for (const [name, value] of consentEntries){
3733
3744
  const consentType = consentTypeMap.get(name);
3734
3745
  const isNecessary = 'necessary' === name;
3735
3746
  const displayName = consentType?.name || name;
@@ -4488,11 +4499,15 @@ var __webpack_exports__ = {};
4488
4499
  const locationInfo = state.locationInfo;
4489
4500
  const overrides = state.overrides;
4490
4501
  const translationConfig = state.translationConfig;
4502
+ const initData = state.lastBannerFetchData;
4503
+ const activePolicy = initData?.policy;
4504
+ const policyDecision = initData?.policyDecision;
4505
+ const initSource = formatInitSource(state.initDataSource, state.initDataSourceDetail);
4491
4506
  const gridItems = [
4492
4507
  createCompactInfoCard('Country', locationInfo?.countryCode || '—'),
4493
4508
  createCompactInfoCard('Region', locationInfo?.regionCode || '—'),
4494
- createCompactInfoCard('Jurisdiction', locationInfo?.jurisdiction || '—'),
4495
- createCompactInfoCard('Language', translationConfig?.defaultLanguage || '—')
4509
+ createCompactInfoCard('Language', translationConfig?.defaultLanguage || '—'),
4510
+ createCompactInfoCard('Init Source', initSource)
4496
4511
  ];
4497
4512
  gridItems.push(createCompactInfoCard('GPC', getEffectiveGpcLabel(overrides?.gpc)));
4498
4513
  if (state.model) gridItems.push(createCompactInfoCard('Model', getModelLabel(state.model)));
@@ -4500,7 +4515,6 @@ var __webpack_exports__ = {};
4500
4515
  columns: 3,
4501
4516
  children: gridItems
4502
4517
  });
4503
- container.appendChild(locationGrid);
4504
4518
  const initialDraft = getDraftFromOverrides(overrides);
4505
4519
  let appliedOverrides = normalizeOverrideDraft(initialDraft);
4506
4520
  let isSubmitting = false;
@@ -4591,6 +4605,12 @@ var __webpack_exports__ = {};
4591
4605
  ]
4592
4606
  });
4593
4607
  container.appendChild(overrideSection);
4608
+ container.appendChild(locationGrid);
4609
+ container.appendChild(createActivePolicySummarySection({
4610
+ policy: activePolicy,
4611
+ policyDecision,
4612
+ policySnapshotToken: initData?.policySnapshotToken
4613
+ }));
4594
4614
  countryField.control.addEventListener('change', updateFormState);
4595
4615
  regionField.control.addEventListener('input', updateFormState);
4596
4616
  languageField.control.addEventListener('input', updateFormState);
@@ -4879,15 +4899,53 @@ var __webpack_exports__ = {};
4879
4899
  return 'None';
4880
4900
  }
4881
4901
  }
4902
+ function createActivePolicySummarySection(options) {
4903
+ const { policy, policyDecision, policySnapshotToken } = options;
4904
+ if (!policy && !policyDecision) return createSection({
4905
+ title: 'Active Policy',
4906
+ children: [
4907
+ renderer_div({
4908
+ style: {
4909
+ padding: '10px 12px',
4910
+ fontSize: 'var(--c15t-devtools-font-size-sm)',
4911
+ color: 'var(--c15t-text-muted)'
4912
+ },
4913
+ text: 'No active policy matched.'
4914
+ })
4915
+ ]
4916
+ });
4917
+ const cards = [
4918
+ createCompactInfoCard('Policy ID', policy?.id ?? policyDecision?.policyId ?? '—'),
4919
+ createCompactInfoCard('Matched By', policyDecision?.matchedBy ?? '—'),
4920
+ createCompactInfoCard('Snapshot Token', policySnapshotToken ? 'present' : 'missing')
4921
+ ];
4922
+ return createSection({
4923
+ title: 'Active Policy',
4924
+ children: [
4925
+ renderer_div({
4926
+ style: {
4927
+ display: 'grid',
4928
+ gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
4929
+ gap: 'var(--c15t-space-sm, 0.5rem)'
4930
+ },
4931
+ children: cards
4932
+ }),
4933
+ renderer_span({
4934
+ className: styles_components_module.overrideHint,
4935
+ text: 'Open the Policy tab for full policy-pack diagnostics.'
4936
+ })
4937
+ ]
4938
+ });
4939
+ }
4882
4940
  function createCompactInfoCard(label, value) {
4883
4941
  return renderer_div({
4884
4942
  className: styles_components_module.gridCard ?? '',
4885
4943
  style: {
4886
- padding: '6px 8px',
4944
+ padding: '8px 10px',
4887
4945
  minHeight: 'auto',
4888
4946
  flexDirection: 'column',
4889
4947
  alignItems: 'flex-start',
4890
- gap: '1px'
4948
+ gap: '2px'
4891
4949
  },
4892
4950
  children: [
4893
4951
  renderer_span({
@@ -4908,6 +4966,253 @@ var __webpack_exports__ = {};
4908
4966
  ]
4909
4967
  });
4910
4968
  }
4969
+ function renderPolicyPanel(container, options) {
4970
+ const { getState } = options;
4971
+ clearElement(container);
4972
+ const state = getState();
4973
+ if (!state) return void container.appendChild(createDisconnectedState());
4974
+ const initData = state.lastBannerFetchData;
4975
+ const activePolicy = initData?.policy;
4976
+ const policyDecision = initData?.policyDecision;
4977
+ const initSource = formatInitSource(state.initDataSource, state.initDataSourceDetail);
4978
+ container.appendChild(createMatchTraceSection({
4979
+ policyDecision,
4980
+ policyId: activePolicy?.id ?? policyDecision?.policyId
4981
+ }));
4982
+ if (!activePolicy && !policyDecision) return void container.appendChild(createSection({
4983
+ title: 'Policy',
4984
+ children: [
4985
+ renderer_div({
4986
+ style: {
4987
+ padding: '10px 12px',
4988
+ fontSize: 'var(--c15t-devtools-font-size-sm)',
4989
+ color: 'var(--c15t-text-muted)'
4990
+ },
4991
+ text: 'No active policy matched for this request.'
4992
+ }),
4993
+ createHint(`Init Source: ${initSource}`)
4994
+ ]
4995
+ }));
4996
+ container.appendChild(createSection({
4997
+ title: 'Policy',
4998
+ children: [
4999
+ policy_createGrid(3, [
5000
+ createCard('ID', activePolicy?.id ?? policyDecision?.policyId ?? '—'),
5001
+ createCard('Model', policy_getModelLabel(activePolicy?.model)),
5002
+ createCard('Scope', getScopeModeLabel(activePolicy?.consent?.scopeMode ?? state.policyScopeMode)),
5003
+ createCard('Categories', formatList(state.policyCategories ?? activePolicy?.consent?.categories)),
5004
+ createCard('Preselected', formatList(activePolicy?.consent?.preselectedCategories)),
5005
+ createCard('Expiry', 'number' == typeof activePolicy?.consent?.expiryDays ? `${activePolicy.consent.expiryDays}d` : '—')
5006
+ ]),
5007
+ createHint(`${initSource} · ${formatFingerprint(policyDecision?.fingerprint)}`)
5008
+ ]
5009
+ }));
5010
+ const uiMode = activePolicy?.ui?.mode;
5011
+ if (uiMode && 'none' !== uiMode) {
5012
+ const bannerCards = buildSurfaceCards('Banner', activePolicy?.ui?.banner, state.policyBanner);
5013
+ const dialogCards = buildSurfaceCards('Dialog', activePolicy?.ui?.dialog, state.policyDialog);
5014
+ if (bannerCards.length > 0 || dialogCards.length > 0) container.appendChild(createSection({
5015
+ title: `UI · ${uiMode}`,
5016
+ children: [
5017
+ policy_createGrid(3, [
5018
+ ...bannerCards,
5019
+ ...dialogCards
5020
+ ])
5021
+ ]
5022
+ }));
5023
+ }
5024
+ const proofLabel = formatProofSummary(activePolicy?.proof);
5025
+ const snapshotLabel = initData?.policySnapshotToken ? 'present' : 'missing';
5026
+ container.appendChild(createSection({
5027
+ title: 'Proof & Snapshot',
5028
+ children: [
5029
+ policy_createGrid(3, [
5030
+ createCard('Proof', proofLabel),
5031
+ createCard('Snapshot', snapshotLabel),
5032
+ createCard('I18n', activePolicy?.i18n?.messageProfile ?? activePolicy?.i18n?.language ?? '—')
5033
+ ])
5034
+ ]
5035
+ }));
5036
+ }
5037
+ function buildSurfaceCards(prefix, policySurface, storeSurface) {
5038
+ const policyLayout = Array.isArray(policySurface?.layout) && 0 === policySurface.layout.length ? null : policySurface?.layout ?? null;
5039
+ const storeLayout = Array.isArray(storeSurface.layout) && 0 === storeSurface.layout.length ? null : storeSurface.layout ?? null;
5040
+ const actions = formatList(policySurface?.allowedActions ?? storeSurface.allowedActions);
5041
+ const primary = policySurface?.primaryAction ?? storeSurface.primaryAction ?? null;
5042
+ const layout = policyLayout ?? storeLayout;
5043
+ const direction = policySurface?.direction ?? storeSurface.direction ?? null;
5044
+ const profile = policySurface?.uiProfile ?? storeSurface.uiProfile ?? null;
5045
+ const scrollLock = policySurface?.scrollLock ?? storeSurface.scrollLock ?? null;
5046
+ if ('—' === actions && !primary && !layout && !direction && !profile && null === scrollLock) return [];
5047
+ const cards = [
5048
+ createCard(`${prefix} Actions`, actions)
5049
+ ];
5050
+ if (primary) cards.push(createCard(`${prefix} Primary`, primary));
5051
+ if (layout) cards.push(createCard(`${prefix} Layout`, Array.isArray(layout) ? layout.map((group)=>Array.isArray(group) ? `[${group.join(', ')}]` : group).join(' / ') : layout));
5052
+ if (direction) cards.push(createCard(`${prefix} Direction`, direction));
5053
+ if (profile) cards.push(createCard(`${prefix} Profile`, profile));
5054
+ if (null !== scrollLock) cards.push(createCard(`${prefix} Scroll Lock`, scrollLock ? 'on' : 'off'));
5055
+ return cards;
5056
+ }
5057
+ function createMatchTraceSection(options) {
5058
+ const { policyDecision, policyId } = options;
5059
+ const entries = buildTraceEntries(policyDecision, policyId);
5060
+ return createSection({
5061
+ title: 'Match Trace',
5062
+ children: [
5063
+ renderer_div({
5064
+ style: {
5065
+ display: 'grid',
5066
+ gridTemplateColumns: '1fr',
5067
+ gap: '4px'
5068
+ },
5069
+ children: entries.map((entry)=>renderer_div({
5070
+ className: styles_components_module.gridCard ?? '',
5071
+ style: {
5072
+ padding: '6px 10px',
5073
+ display: 'flex',
5074
+ alignItems: 'center',
5075
+ justifyContent: 'space-between',
5076
+ gap: '10px'
5077
+ },
5078
+ children: [
5079
+ renderer_span({
5080
+ style: {
5081
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5082
+ color: 'var(--c15t-text-muted)',
5083
+ fontFamily: 'ui-monospace, monospace'
5084
+ },
5085
+ text: entry.step
5086
+ }),
5087
+ renderer_span({
5088
+ style: {
5089
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5090
+ fontFamily: 'ui-monospace, monospace'
5091
+ },
5092
+ text: entry.result
5093
+ })
5094
+ ]
5095
+ }))
5096
+ }),
5097
+ createHint('region → country → default · fallback on geo failure · Simulate via Location tab')
5098
+ ]
5099
+ });
5100
+ }
5101
+ function buildTraceEntries(decision, policyId) {
5102
+ if (!decision) return [
5103
+ {
5104
+ step: 'decision metadata',
5105
+ result: 'UNAVAILABLE'
5106
+ }
5107
+ ];
5108
+ const country = decision.country ?? 'n/a';
5109
+ const regionKey = decision.country && decision.region ? `${decision.country}-${decision.region}` : 'n/a';
5110
+ const resolved = policyId ?? decision.policyId ?? 'unknown';
5111
+ const matched = decision.matchedBy;
5112
+ return [
5113
+ {
5114
+ step: `region(${regionKey})`,
5115
+ result: 'region' === matched ? `MATCH → ${resolved}` : 'MISS'
5116
+ },
5117
+ {
5118
+ step: `country(${country})`,
5119
+ result: 'country' === matched ? `MATCH → ${resolved}` : 'region' === matched ? 'SKIPPED' : 'MISS'
5120
+ },
5121
+ {
5122
+ step: 'fallback(geo-fail)',
5123
+ result: 'fallback' === matched ? `MATCH → ${resolved}` : 'SKIPPED'
5124
+ },
5125
+ {
5126
+ step: 'default(catch-all)',
5127
+ result: 'default' === matched ? `MATCH → ${resolved}` : 'SKIPPED'
5128
+ }
5129
+ ];
5130
+ }
5131
+ function policy_getModelLabel(model) {
5132
+ switch(model){
5133
+ case 'opt-in':
5134
+ return 'Opt-In';
5135
+ case 'opt-out':
5136
+ return 'Opt-Out';
5137
+ case 'iab':
5138
+ return 'IAB TCF';
5139
+ default:
5140
+ return 'None';
5141
+ }
5142
+ }
5143
+ function getScopeModeLabel(mode) {
5144
+ switch(mode){
5145
+ case 'strict':
5146
+ return 'Strict';
5147
+ case 'permissive':
5148
+ return 'Permissive';
5149
+ default:
5150
+ return '—';
5151
+ }
5152
+ }
5153
+ function formatList(items) {
5154
+ if (!items || 0 === items.length) return '—';
5155
+ if (items.includes('*')) return '* (all)';
5156
+ return items.join(', ');
5157
+ }
5158
+ function formatProofSummary(proof) {
5159
+ if (!proof) return '—';
5160
+ const parts = [];
5161
+ if (proof.storeIp) parts.push('IP');
5162
+ if (proof.storeUserAgent) parts.push('UA');
5163
+ if (proof.storeLanguage) parts.push('Lang');
5164
+ return parts.length > 0 ? parts.join(', ') : 'none';
5165
+ }
5166
+ function formatFingerprint(fingerprint) {
5167
+ if (!fingerprint) return 'no fingerprint';
5168
+ if (fingerprint.length <= 12) return fingerprint;
5169
+ return `${fingerprint.slice(0, 8)}…${fingerprint.slice(-4)}`;
5170
+ }
5171
+ function createCard(label, value) {
5172
+ return renderer_div({
5173
+ className: styles_components_module.gridCard ?? '',
5174
+ style: {
5175
+ padding: '8px 10px',
5176
+ minHeight: 'auto',
5177
+ flexDirection: 'column',
5178
+ alignItems: 'flex-start',
5179
+ gap: '2px'
5180
+ },
5181
+ children: [
5182
+ renderer_span({
5183
+ style: {
5184
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5185
+ color: 'var(--c15t-text-muted)'
5186
+ },
5187
+ text: label
5188
+ }),
5189
+ renderer_span({
5190
+ style: {
5191
+ fontSize: 'var(--c15t-font-size-sm)',
5192
+ fontWeight: '500',
5193
+ fontFamily: 'ui-monospace, monospace'
5194
+ },
5195
+ text: value
5196
+ })
5197
+ ]
5198
+ });
5199
+ }
5200
+ function policy_createGrid(columns, children) {
5201
+ return renderer_div({
5202
+ style: {
5203
+ display: 'grid',
5204
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
5205
+ gap: 'var(--c15t-space-sm, 0.5rem)'
5206
+ },
5207
+ children
5208
+ });
5209
+ }
5210
+ function createHint(text) {
5211
+ return renderer_span({
5212
+ className: styles_components_module.overrideHint,
5213
+ text
5214
+ });
5215
+ }
4911
5216
  const dismissedResources = new Set();
4912
5217
  function scanDOM(state) {
4913
5218
  const results = [];
@@ -5546,6 +5851,11 @@ var __webpack_exports__ = {};
5546
5851
  }
5547
5852
  });
5548
5853
  break;
5854
+ case 'policy':
5855
+ renderPolicyPanel(container, {
5856
+ getState: getStoreState
5857
+ });
5858
+ break;
5549
5859
  case "scripts":
5550
5860
  renderScriptsPanel(container, {
5551
5861
  getState: getStoreState,
@@ -5682,7 +5992,7 @@ var __webpack_exports__ = {};
5682
5992
  } catch {}
5683
5993
  }
5684
5994
  function isDevToolsTab(value) {
5685
- return 'consents' === value || 'location' === value || "scripts" === value || 'iab' === value || 'events' === value || 'actions' === value;
5995
+ return 'consents' === value || 'location' === value || 'policy' === value || "scripts" === value || 'iab' === value || 'events' === value || 'actions' === value;
5686
5996
  }
5687
5997
  function loadPersistedActiveTab() {
5688
5998
  if ('undefined' == typeof window) return null;