@c15t/dev-tools 2.0.0 → 2.0.4

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.
package/README.md CHANGED
@@ -1,187 +1,92 @@
1
- # @c15t/dev-tools
1
+ <p align="center">
2
+ <a href="https://c15t.com?utm_source=npm&utm_medium=readme&utm_campaign=oss_readme&utm_content=%40c15t%2Fdev-tools" target="_blank" rel="noopener noreferrer">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="../../docs/assets/c15t-banner-readme-dark.svg" type="image/svg+xml">
5
+ <img src="../../docs/assets/c15t-banner-readme-light.svg" alt="c15t Banner" type="image/svg+xml">
6
+ </picture>
7
+ </a>
8
+ </p>
2
9
 
3
- Developer tools for debugging and inspecting c15t consent management state.
10
+ # @c15t/dev-tools: Developer Tooling (Work in Progress)
4
11
 
5
- ## Features
12
+ [![GitHub stars](https://img.shields.io/github/stars/c15t/c15t?style=flat-square)](https://github.com/c15t/c15t)
13
+ [![CI](https://img.shields.io/github/actions/workflow/status/c15t/c15t/ci.yml?style=flat-square)](https://github.com/c15t/c15t/actions/workflows/ci.yml)
14
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](https://github.com/c15t/c15t/blob/main/LICENSE.md)
15
+ [![Discord](https://img.shields.io/discord/1312171102268690493?style=flat-square)](https://c15t.link/discord)
16
+ [![npm version](https://img.shields.io/npm/v/%40c15t%2Fdev-tools?style=flat-square)](https://www.npmjs.com/package/@c15t/dev-tools)
17
+ [![Top Language](https://img.shields.io/github/languages/top/c15t/c15t?style=flat-square)](https://github.com/c15t/c15t)
18
+ [![Last Commit](https://img.shields.io/github/last-commit/c15t/c15t?style=flat-square)](https://github.com/c15t/c15t/commits/main)
19
+ [![Open Issues](https://img.shields.io/github/issues/c15t/c15t?style=flat-square)](https://github.com/c15t/c15t/issues)
6
20
 
7
- - **Consents Panel**: View and toggle consent states in real-time
8
- - **Location Panel**: Inspect location and apply geo/language overrides
9
- - **Policy Panel**: Inspect detailed runtime policy-pack decision data
10
- - **Scripts Panel**: Monitor script loading status
11
- - **Actions Panel**: Quick actions for testing consent flows
12
- - **Framework Agnostic**: Pure JavaScript core with React wrapper
13
- - **TanStack DevTools Integration**: Use as a plugin in TanStack DevTools
14
- - **CSS Animations**: Smooth, accessible animations with reduced motion support
15
- - **Dark Mode**: Automatic dark mode support
21
+ A collection of developer tools and utilities for the c15t ecosystem, currently under active development.
16
22
 
17
- ## Installation
23
+ ## Key Features
18
24
 
19
- ```bash
20
- bun add @c15t/dev-tools
21
- ```
22
-
23
- ## Usage
24
-
25
- ### React
26
-
27
- The easiest way to add DevTools to a React application:
28
-
29
- ```tsx
30
- import { DevTools } from '@c15t/dev-tools/react';
31
-
32
- function App() {
33
- return (
34
- <>
35
- <YourApp />
36
- <DevTools position="bottom-right" />
37
- </>
38
- );
39
- }
40
- ```
41
-
42
- #### Props
43
-
44
- | Prop | Type | Default | Description |
45
- |------|------|---------|-------------|
46
- | `namespace` | `string` | `'c15tStore'` | Window namespace for the store |
47
- | `position` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | `'bottom-right'` | Position of the floating button |
48
- | `defaultOpen` | `boolean` | `false` | Whether to start with panel open |
49
- | `disabled` | `boolean` | `false` | Disable DevTools (e.g., in production) |
50
-
51
- #### Production Usage
52
-
53
- ```tsx
54
- <DevTools disabled={process.env.NODE_ENV === 'production'} />
55
- ```
56
-
57
- ### Vanilla JavaScript
58
-
59
- For non-React applications or more control:
60
-
61
- ```typescript
62
- import { createDevTools } from '@c15t/dev-tools';
63
-
64
- const devtools = createDevTools({
65
- namespace: 'c15tStore',
66
- position: 'bottom-right',
67
- });
25
+ - 🚧 Experimental developer utilities
26
+ - React component library with utility tools
27
+ - Radix UI and Tailwind CSS integration
28
+ - State management and UI component helpers
29
+ - Ongoing development and refinement
68
30
 
69
- // Control programmatically
70
- devtools.open();
71
- devtools.close();
72
- devtools.toggle();
31
+ ## Prerequisites
73
32
 
74
- // Cleanup
75
- devtools.destroy();
76
- ```
77
-
78
- ### TanStack DevTools Plugin
79
-
80
- Integrate with TanStack DevTools:
33
+ - Node.js 18.17.0 or later
34
+ - React 16.8.0 or later
35
+ - Familiarity with experimental tooling
81
36
 
82
- ```tsx
83
- import { TanStackDevtools } from '@tanstack/react-devtools';
84
- import { c15tDevtoolsPlugin } from '@c15t/dev-tools/tanstack';
85
-
86
- function App() {
87
- return (
88
- <>
89
- <YourApp />
90
- <TanStackDevtools plugins={[c15tDevtoolsPlugin()]} />
91
- </>
92
- );
93
- }
94
- ```
37
+ ## Manual Installation
95
38
 
96
- ## Console API
97
-
98
- The DevTools expose a global API for quick debugging:
99
-
100
- ```javascript
101
- // Open/close the panel
102
- window.__c15tDevTools.open();
103
- window.__c15tDevTools.close();
104
- window.__c15tDevTools.toggle();
105
-
106
- // Check state
107
- window.__c15tDevTools.getState();
108
- // { isOpen: false, activeTab: 'consents', isConnected: true }
39
+ ```bash
40
+ pnpm add @c15t/dev-tools
109
41
  ```
110
42
 
111
- ## Panels
43
+ ⚠️ **Note:** This package is experimental and may undergo significant changes.
112
44
 
113
- ### Consents
114
-
115
- - View all consent types with enabled/disabled badges
116
- - Toggle individual consents with immediate feedback
117
- - Quick actions: Accept All, Reject All
118
- - Shows consent model (opt-in, opt-out, iab)
119
-
120
- ### Location
121
-
122
- - Detected country, region, and jurisdiction
123
- - Compact active policy summary (policy ID + matcher + snapshot status)
124
- - Set country, region, and language overrides
125
- - View active consent model with description
126
- - Clear all overrides
45
+ ## Usage
127
46
 
128
- ### Policy
47
+ 1. 🚧 Explore the dev tools with caution
48
+ 2. Import and use components carefully
49
+ 3. Expect potential breaking changes
50
+ 4. Feedback and contributions welcome!
129
51
 
130
- - Runtime policy decision details from `/init`
131
- - Policy ID, match strategy, and fingerprint
132
- - Consent model, scope mode, purpose scope
133
- - UI constraints (mode, allowed actions, primary action)
134
- - i18n profile, expiry, and proof-capture summary
135
- - Snapshot token presence indicator
52
+ ## Documentation
136
53
 
137
- ### Scripts
54
+ For further information, guides, and examples visit the [reference documentation](https://c15t.com/docs/dev-tools/overview).
138
55
 
139
- - List configured scripts with consent requirements
140
- - Status badges: Loaded, Pending, Blocked
141
- - Network blocker status
142
- - Summary of loaded vs pending scripts
56
+ ## Support
143
57
 
144
- ### Actions
58
+ - Join our [Discord community](https://c15t.link/discord)
59
+ - Open an issue on our [GitHub repository](https://github.com/c15t/c15t/issues)
60
+ - Visit [inth.com](https://inth.com) and use the chat widget
61
+ - Contact our support team via email [support@inth.com](mailto:support@inth.com)
145
62
 
146
- - Show consent banner
147
- - Open preference center
148
- - Re-fetch banner data
149
- - Reset all consents
150
- - Copy state to clipboard for debugging
63
+ ## Contributing
151
64
 
152
- ## Styling
65
+ - We're open to all community contributions.
66
+ - Read our [Contribution Guidelines](https://c15t.com/docs/oss/contributing)
67
+ - Review our [Code of Conduct](https://c15t.com/docs/oss/code-of-conduct)
68
+ - Fork the repository
69
+ - Create a new branch for your feature
70
+ - Submit a pull request
71
+ - **All contributions, big or small, are welcome and appreciated.**
153
72
 
154
- The DevTools use CSS variables for theming. Variables are prefixed with `--c15t-devtools-`:
73
+ ## Security
155
74
 
156
- ```css
157
- /* Override colors */
158
- :root {
159
- --c15t-devtools-primary: hsl(220, 90%, 50%);
160
- --c15t-devtools-surface: hsl(0, 0%, 100%);
161
- }
162
- ```
75
+ If you believe you have found a security vulnerability in c15t, we encourage you to **_responsibly disclose this and NOT open a public issue_**. We will investigate all legitimate reports.
163
76
 
164
- ### Dark Mode
77
+ Our preference is that you make use of GitHub's private vulnerability reporting feature to disclose potential security vulnerabilities in our open-source software. To do this, please visit [https://github.com/c15t/c15t/security](https://github.com/c15t/c15t/security) and click the "Report a vulnerability" button.
165
78
 
166
- Dark mode is automatically applied when:
167
- - The document has a `.dark` or `.c15t-dark` class
168
- - System preference is dark (`prefers-color-scheme: dark`)
79
+ ### Security Policy
169
80
 
170
- You can also force dark mode:
81
+ - Please do not share security vulnerabilities in public forums, issues, or pull requests
82
+ - Provide detailed information about the potential vulnerability
83
+ - Allow reasonable time for us to address the issue before any public disclosure
84
+ - We are committed to addressing security concerns promptly and transparently
171
85
 
172
- ```css
173
- .my-devtools-container {
174
- @extend .c15t-devtools-dark;
175
- }
176
- ```
177
-
178
- ## Browser Support
86
+ ## License
179
87
 
180
- - Chrome 90+
181
- - Firefox 90+
182
- - Safari 15+
183
- - Edge 90+
88
+ [Apache License 2.0](https://github.com/c15t/c15t/blob/main/LICENSE.md)
184
89
 
185
- ## License
90
+ ---
186
91
 
187
- Apache-2.0
92
+ **Built by [Inth](https://inth.com?utm_source=npm&utm_medium=readme&utm_campaign=oss_readme&utm_content=%40c15t%2Fdev-tools)**
package/dist/379.js CHANGED
@@ -2710,7 +2710,7 @@ function createPanel(options) {
2710
2710
  }
2711
2711
  }));
2712
2712
  footerElement.appendChild(renderer_span({
2713
- text: "v2.0.0"
2713
+ text: "v2.0.4"
2714
2714
  }));
2715
2715
  }
2716
2716
  function renderErrorState(container) {
@@ -6731,6 +6731,133 @@ function createStateCopy(state) {
6731
6731
  loadedScripts: state.loadedScripts
6732
6732
  };
6733
6733
  }
6734
+ const EMBEDDED_TABS = [
6735
+ {
6736
+ id: 'location',
6737
+ label: 'Location'
6738
+ },
6739
+ {
6740
+ id: 'policy',
6741
+ label: 'Policy'
6742
+ },
6743
+ {
6744
+ id: 'consents',
6745
+ label: 'Consents'
6746
+ },
6747
+ {
6748
+ id: "scripts",
6749
+ label: 'Scripts'
6750
+ },
6751
+ {
6752
+ id: 'iab',
6753
+ label: 'IAB'
6754
+ },
6755
+ {
6756
+ id: 'actions',
6757
+ label: 'Actions'
6758
+ },
6759
+ {
6760
+ id: 'events',
6761
+ label: 'Events'
6762
+ }
6763
+ ];
6764
+ const EMBEDDED_THEME_VARIABLES = {
6765
+ '--c15t-surface': '#1f222b',
6766
+ '--c15t-surface-hover': '#272b35',
6767
+ '--c15t-surface-muted': '#252933',
6768
+ '--c15t-border': 'rgba(255, 255, 255, 0.08)',
6769
+ '--c15t-border-hover': 'rgba(255, 255, 255, 0.16)',
6770
+ '--c15t-text': '#eef2ff',
6771
+ '--c15t-text-muted': '#99a2b3',
6772
+ '--c15t-primary': '#8b5cf6',
6773
+ '--c15t-primary-hover': '#7c3aed',
6774
+ '--c15t-text-on-primary': '#f7f3ff',
6775
+ '--c15t-shadow-sm': 'none',
6776
+ '--c15t-shadow-md': 'none',
6777
+ '--c15t-devtools-surface-elevated': '#1f222b',
6778
+ '--c15t-devtools-surface-muted': '#272b35',
6779
+ '--c15t-devtools-surface-subtle': '#181b22',
6780
+ '--c15t-devtools-border-strong': 'rgba(255, 255, 255, 0.08)',
6781
+ '--c15t-devtools-code-surface': '#15181f',
6782
+ '--c15t-devtools-accent-soft': 'rgba(139, 92, 246, 0.18)',
6783
+ '--c15t-devtools-focus-ring': '#8b5cf6',
6784
+ '--c15t-devtools-badge-success-bg': 'rgba(16, 185, 129, 0.16)',
6785
+ '--c15t-devtools-badge-error-bg': 'rgba(248, 113, 113, 0.18)',
6786
+ '--c15t-devtools-badge-warning-bg': 'rgba(251, 191, 36, 0.18)',
6787
+ '--c15t-devtools-badge-info-bg': 'rgba(96, 165, 250, 0.18)',
6788
+ '--c15t-devtools-badge-neutral-bg': 'rgba(148, 163, 184, 0.16)',
6789
+ '--c15t-devtools-embedded-tab-active-border': 'rgba(139, 92, 246, 0.55)'
6790
+ };
6791
+ function createEmbeddedTabs(options) {
6792
+ const { onTabChange, disabledTabs = [] } = options;
6793
+ let activeTab = options.activeTab;
6794
+ const buttons = new Map();
6795
+ const tabList = renderer_div({
6796
+ role: 'tablist',
6797
+ ariaLabel: 'DevTools tabs',
6798
+ style: {
6799
+ display: 'flex',
6800
+ flexWrap: 'wrap',
6801
+ gap: '0.5rem',
6802
+ alignItems: 'center',
6803
+ paddingBottom: '0.25rem',
6804
+ borderBottom: '1px solid var(--c15t-devtools-border-strong, rgba(255, 255, 255, 0.08))'
6805
+ }
6806
+ });
6807
+ function applyButtonState(tab, buttonElement) {
6808
+ const isActive = tab === activeTab;
6809
+ const isDisabled = disabledTabs.includes(tab);
6810
+ buttonElement.disabled = isDisabled;
6811
+ buttonElement.setAttribute('aria-selected', isActive ? 'true' : 'false');
6812
+ buttonElement.style.borderColor = isActive ? 'var(--c15t-devtools-embedded-tab-active-border, rgba(139, 92, 246, 0.55))' : 'transparent';
6813
+ buttonElement.style.backgroundColor = isActive ? 'var(--c15t-devtools-accent-soft, rgba(139, 92, 246, 0.18))' : 'transparent';
6814
+ buttonElement.style.color = isActive ? 'var(--c15t-text, #eef2ff)' : 'var(--c15t-text-muted, #99a2b3)';
6815
+ buttonElement.style.opacity = isDisabled ? '0.45' : '1';
6816
+ buttonElement.style.cursor = isDisabled ? 'not-allowed' : 'pointer';
6817
+ buttonElement.style.boxShadow = isActive ? 'inset 0 0 0 1px var(--c15t-devtools-embedded-tab-active-border, rgba(139, 92, 246, 0.55))' : 'none';
6818
+ }
6819
+ for (const tab of EMBEDDED_TABS){
6820
+ const buttonElement = renderer_button({
6821
+ role: 'tab',
6822
+ text: tab.label,
6823
+ onClick: ()=>{
6824
+ if (disabledTabs.includes(tab.id)) return;
6825
+ activeTab = tab.id;
6826
+ for (const [tabId, tabButton] of buttons)applyButtonState(tabId, tabButton);
6827
+ onTabChange(tab.id);
6828
+ },
6829
+ style: {
6830
+ display: 'inline-flex',
6831
+ alignItems: 'center',
6832
+ justifyContent: 'center',
6833
+ minHeight: '1.875rem',
6834
+ padding: '0.3125rem 0.75rem',
6835
+ border: '1px solid transparent',
6836
+ borderRadius: '999px',
6837
+ backgroundColor: 'transparent',
6838
+ fontFamily: 'inherit',
6839
+ fontSize: 'var(--c15t-devtools-font-size-xs, 0.75rem)',
6840
+ fontWeight: '500',
6841
+ lineHeight: '1.25',
6842
+ transition: 'background-color var(--c15t-duration-fast, 100ms) var(--c15t-easing, cubic-bezier(0.4, 0, 0.2, 1)), border-color var(--c15t-duration-fast, 100ms) var(--c15t-easing, cubic-bezier(0.4, 0, 0.2, 1)), box-shadow var(--c15t-duration-fast, 100ms) var(--c15t-easing, cubic-bezier(0.4, 0, 0.2, 1)), color var(--c15t-duration-fast, 100ms) var(--c15t-easing, cubic-bezier(0.4, 0, 0.2, 1))'
6843
+ }
6844
+ });
6845
+ if ('iab' === tab.id) buttonElement.title = 'Available when IAB TCF mode is enabled';
6846
+ applyButtonState(tab.id, buttonElement);
6847
+ buttons.set(tab.id, buttonElement);
6848
+ tabList.appendChild(buttonElement);
6849
+ }
6850
+ return {
6851
+ element: tabList,
6852
+ setActiveTab: (tab)=>{
6853
+ activeTab = tab;
6854
+ for (const [tabId, tabButton] of buttons)applyButtonState(tabId, tabButton);
6855
+ },
6856
+ destroy: ()=>{
6857
+ buttons.clear();
6858
+ }
6859
+ };
6860
+ }
6734
6861
  function scriptDebugEventToLogEntry(event) {
6735
6862
  return {
6736
6863
  type: "script",
@@ -6914,9 +7041,11 @@ function createDevTools(options = {}) {
6914
7041
  return instance;
6915
7042
  }
6916
7043
  function createDevToolsPanel(options) {
6917
- const { namespace = 'c15tStore' } = options;
7044
+ const { namespace = 'c15tStore', mode = 'standalone' } = options;
7045
+ const isEmbedded = 'embedded' === mode;
6918
7046
  let detachInstrumentation = null;
6919
7047
  let detachScriptDebug = null;
7048
+ let contentArea = null;
6920
7049
  const stateManager = createStateManager({
6921
7050
  isOpen: true
6922
7051
  });
@@ -6944,6 +7073,7 @@ function createDevToolsPanel(options) {
6944
7073
  gpc: persistedOverrides.gpc
6945
7074
  });
6946
7075
  }
7076
+ renderActivePanel();
6947
7077
  },
6948
7078
  onDisconnect: ()=>{
6949
7079
  stateManager.setConnected(false);
@@ -6951,6 +7081,7 @@ function createDevToolsPanel(options) {
6951
7081
  detachInstrumentation = null;
6952
7082
  detachScriptDebug?.();
6953
7083
  detachScriptDebug = null;
7084
+ renderActivePanel();
6954
7085
  }
6955
7086
  });
6956
7087
  const panelRenderer = createPanelRenderer({
@@ -6983,25 +7114,33 @@ function createDevToolsPanel(options) {
6983
7114
  display: 'flex',
6984
7115
  flexDirection: 'column',
6985
7116
  height: '100%',
6986
- fontFamily: 'var(--c15t-devtools-font-family)',
7117
+ boxSizing: 'border-box',
7118
+ gap: '0.75rem',
7119
+ padding: '0.75rem',
7120
+ fontFamily: 'inherit',
6987
7121
  fontSize: 'var(--c15t-devtools-font-size-sm)',
6988
- color: 'var(--c15t-devtools-text)',
6989
- backgroundColor: 'var(--c15t-devtools-surface)'
7122
+ color: isEmbedded ? 'var(--c15t-text, #eef2ff)' : 'inherit',
7123
+ backgroundColor: 'transparent',
7124
+ colorScheme: isEmbedded ? 'dark' : void 0,
7125
+ ...isEmbedded ? EMBEDDED_THEME_VARIABLES : {}
6990
7126
  }
6991
7127
  });
6992
- const contentArea = renderer_div({
7128
+ contentArea = renderer_div({
6993
7129
  style: {
6994
7130
  flex: '1',
7131
+ minHeight: '0',
6995
7132
  overflowY: 'auto',
6996
- overscrollBehavior: 'contain'
7133
+ overscrollBehavior: 'contain',
7134
+ backgroundColor: 'transparent'
6997
7135
  }
6998
7136
  });
6999
7137
  function renderActivePanel() {
7138
+ if (!contentArea) return;
7000
7139
  const activeTab = syncTabs();
7001
7140
  panelRenderer.renderPanel(contentArea, activeTab);
7002
7141
  }
7003
7142
  let tabsInstance = null;
7004
- let iabDisabled = true;
7143
+ let disabledTabsKey = '';
7005
7144
  function getDisabledTabs() {
7006
7145
  const disabledTabs = [];
7007
7146
  const storeState = storeConnector.getState();
@@ -7010,16 +7149,16 @@ function createDevToolsPanel(options) {
7010
7149
  }
7011
7150
  function syncTabs() {
7012
7151
  const disabledTabs = getDisabledTabs();
7013
- const nextIabDisabled = disabledTabs.includes('iab');
7152
+ const nextDisabledTabsKey = disabledTabs.join('|');
7014
7153
  let activeTab = stateManager.getState().activeTab;
7015
7154
  if (disabledTabs.includes(activeTab)) {
7016
7155
  activeTab = 'consents';
7017
7156
  stateManager.setActiveTab(activeTab);
7018
7157
  }
7019
- if (tabsInstance && iabDisabled === nextIabDisabled) tabsInstance.setActiveTab(activeTab);
7158
+ if (tabsInstance && disabledTabsKey === nextDisabledTabsKey) tabsInstance.setActiveTab(activeTab);
7020
7159
  else {
7021
7160
  tabsInstance?.destroy();
7022
- tabsInstance = createTabs({
7161
+ tabsInstance = createEmbeddedTabs({
7023
7162
  activeTab,
7024
7163
  onTabChange: (tab)=>{
7025
7164
  stateManager.setActiveTab(tab);
@@ -7027,8 +7166,9 @@ function createDevToolsPanel(options) {
7027
7166
  },
7028
7167
  disabledTabs
7029
7168
  });
7030
- iabDisabled = nextIabDisabled;
7031
- if (!tabsInstance.element.parentElement) container.appendChild(tabsInstance.element);
7169
+ disabledTabsKey = nextDisabledTabsKey;
7170
+ if (!tabsInstance.element.parentElement) if (contentArea?.parentElement === container) container.insertBefore(tabsInstance.element, contentArea);
7171
+ else container.appendChild(tabsInstance.element);
7032
7172
  }
7033
7173
  return activeTab;
7034
7174
  }