@launchdarkly/toolbar 0.26.0 → 1.0.1-beta.1

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 (148) hide show
  1. package/README.md +276 -161
  2. package/cdn/toolbar.min.js +24 -0
  3. package/cdn/toolbar.min.js.LICENSE.txt +59 -0
  4. package/dist/core/context/Providers.d.ts +9 -0
  5. package/dist/core/context/ReactMountContext.d.ts +2 -0
  6. package/dist/core/context/ShadowRootContext.d.ts +2 -0
  7. package/dist/core/context/defaultConfig.d.ts +3 -0
  8. package/dist/core/index.d.ts +8 -0
  9. package/dist/core/mount.d.ts +2 -0
  10. package/dist/{ui → core/ui}/Toolbar/LaunchDarklyToolbar.d.ts +3 -1
  11. package/dist/{ui → core/ui}/Toolbar/TabContent/EventsTabContent.d.ts +1 -1
  12. package/dist/{ui → core/ui}/Toolbar/TabContent/FlagSdkOverrideTabContent.d.ts +1 -1
  13. package/dist/{ui → core/ui}/Toolbar/components/ExpandedToolbarContent.d.ts +1 -1
  14. package/dist/{ui → core/ui}/Toolbar/components/TabContentRenderer.d.ts +1 -1
  15. package/dist/{ui → core/ui}/Toolbar/context/FlagSdkOverrideProvider.d.ts +1 -1
  16. package/dist/{ui → core/ui}/Toolbar/hooks/useEvents.d.ts +1 -2
  17. package/dist/{ui → core/ui}/Toolbar/hooks/useToolbarState.d.ts +1 -0
  18. package/dist/core/utils/hydrateConfig.d.ts +2 -0
  19. package/dist/{js/plugins/index.js → index.cjs} +278 -133
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/index.d.ts +9 -10
  22. package/dist/js/index.js +226 -7799
  23. package/dist/js/index.js.map +1 -0
  24. package/dist/react/lazyLoadToolbar.d.ts +2 -0
  25. package/dist/react/useLaunchDarklyToolbar.d.ts +20 -0
  26. package/dist/types/analytics.d.ts +1 -0
  27. package/dist/types/config.d.ts +54 -0
  28. package/dist/{hooks → types/hooks}/AfterEvaluationHook.d.ts +1 -1
  29. package/dist/{hooks → types/hooks}/AfterIdentifyHook.d.ts +1 -1
  30. package/dist/{hooks → types/hooks}/AfterTrackHook.d.ts +1 -1
  31. package/dist/{hooks → types/hooks}/EventStore.d.ts +1 -1
  32. package/dist/types/index.d.ts +5 -0
  33. package/dist/{plugins/EventInterceptionPlugin.d.ts → types/plugins/eventInterceptionPlugin.d.ts} +2 -2
  34. package/dist/{plugins/FlagOverridePlugin.d.ts → types/plugins/flagOverridePlugin.d.ts} +1 -1
  35. package/dist/types/plugins/index.d.ts +3 -0
  36. package/dist/types/{plugin.d.ts → plugins/plugins.d.ts} +1 -4
  37. package/dist/types/position.d.ts +2 -0
  38. package/package.json +55 -45
  39. package/LICENSE +0 -13
  40. package/dist/plugins/index.d.ts +0 -4
  41. package/dist/tests/DevServerProvider.test.d.ts +0 -1
  42. package/dist/tests/ExpandedToolbarContent.test.d.ts +0 -1
  43. package/dist/tests/FlagSdkOverrideProvider.test.d.ts +0 -1
  44. package/dist/tests/LaunchDarklyToolbar.test.d.ts +0 -1
  45. package/dist/tests/Tabs.test.d.ts +0 -1
  46. package/dist/tests/hooks/AfterEvaluationHook.test.d.ts +0 -1
  47. package/dist/tests/hooks/AfterIdentifyHook.test.d.ts +0 -1
  48. package/dist/tests/hooks/AfterTrackHook.test.d.ts +0 -1
  49. package/dist/tests/hooks/EventStore.test.d.ts +0 -1
  50. package/dist/tests/plugins/EventInterceptionPlugin.test.d.ts +0 -1
  51. package/dist/vendor/launchpad/Button.d.ts +0 -19
  52. package/dist/vendor/launchpad/Group.d.ts +0 -11
  53. package/dist/vendor/launchpad/Input.d.ts +0 -15
  54. package/dist/vendor/launchpad/ListBox.d.ts +0 -15
  55. package/dist/vendor/launchpad/Popover.d.ts +0 -13
  56. package/dist/vendor/launchpad/SearchField.d.ts +0 -10
  57. package/dist/vendor/launchpad/Select.d.ts +0 -16
  58. package/dist/vendor/launchpad/Switch.d.ts +0 -10
  59. package/dist/vendor/launchpad/TextField.d.ts +0 -10
  60. package/dist/vendor/launchpad/index.d.ts +0 -18
  61. package/dist/vendor/launchpad/utils.d.ts +0 -4
  62. /package/dist/{services → core/services}/DevServerClient.d.ts +0 -0
  63. /package/dist/{services → core/services}/FlagStateManager.d.ts +0 -0
  64. /package/dist/{tests → core/tests}/mocks/flags.d.ts +0 -0
  65. /package/dist/{types → core/types}/devServer.d.ts +0 -0
  66. /package/dist/{ui → core/ui}/List/List.css.d.ts +0 -0
  67. /package/dist/{ui → core/ui}/List/List.d.ts +0 -0
  68. /package/dist/{ui → core/ui}/List/ListItem.d.ts +0 -0
  69. /package/dist/{ui → core/ui}/Tabs/TabButton.d.ts +0 -0
  70. /package/dist/{ui → core/ui}/Tabs/Tabs.css.d.ts +0 -0
  71. /package/dist/{ui → core/ui}/Tabs/Tabs.d.ts +0 -0
  72. /package/dist/{ui → core/ui}/Tabs/useTabsContext.d.ts +0 -0
  73. /package/dist/{ui → core/ui}/Toolbar/Header/Header.css.d.ts +0 -0
  74. /package/dist/{ui → core/ui}/Toolbar/Header/Header.d.ts +0 -0
  75. /package/dist/{ui → core/ui}/Toolbar/Header/components/ActionButtons.d.ts +0 -0
  76. /package/dist/{ui → core/ui}/Toolbar/Header/components/EnvironmentLabel.d.ts +0 -0
  77. /package/dist/{ui → core/ui}/Toolbar/Header/components/LogoSection.d.ts +0 -0
  78. /package/dist/{ui → core/ui}/Toolbar/Header/components/SearchSection.d.ts +0 -0
  79. /package/dist/{ui → core/ui}/Toolbar/Header/components/index.d.ts +0 -0
  80. /package/dist/{ui → core/ui}/Toolbar/LaunchDarklyToolbar.css.d.ts +0 -0
  81. /package/dist/{ui → core/ui}/Toolbar/TabContent/EventsTabContent.css.d.ts +0 -0
  82. /package/dist/{ui → core/ui}/Toolbar/TabContent/FlagDevServerTabContent.css.d.ts +0 -0
  83. /package/dist/{ui → core/ui}/Toolbar/TabContent/FlagDevServerTabContent.d.ts +0 -0
  84. /package/dist/{ui → core/ui}/Toolbar/TabContent/SettingsTab.css.d.ts +0 -0
  85. /package/dist/{ui → core/ui}/Toolbar/TabContent/SettingsTabContent.d.ts +0 -0
  86. /package/dist/{ui → core/ui}/Toolbar/components/ActionButtonsContainer.css.d.ts +0 -0
  87. /package/dist/{ui → core/ui}/Toolbar/components/ActionButtonsContainer.d.ts +0 -0
  88. /package/dist/{ui → core/ui}/Toolbar/components/CircleLogo.d.ts +0 -0
  89. /package/dist/{ui → core/ui}/Toolbar/components/ConnectionStatus.css.d.ts +0 -0
  90. /package/dist/{ui → core/ui}/Toolbar/components/ConnectionStatus.d.ts +0 -0
  91. /package/dist/{ui → core/ui}/Toolbar/components/DoNotTrackWarning.css.d.ts +0 -0
  92. /package/dist/{ui → core/ui}/Toolbar/components/DoNotTrackWarning.d.ts +0 -0
  93. /package/dist/{ui → core/ui}/Toolbar/components/ErrorMessage.css.d.ts +0 -0
  94. /package/dist/{ui → core/ui}/Toolbar/components/ErrorMessage.d.ts +0 -0
  95. /package/dist/{ui → core/ui}/Toolbar/components/FlagControls.css.d.ts +0 -0
  96. /package/dist/{ui → core/ui}/Toolbar/components/FlagControls.d.ts +0 -0
  97. /package/dist/{ui → core/ui}/Toolbar/components/GenericHelpText.css.d.ts +0 -0
  98. /package/dist/{ui → core/ui}/Toolbar/components/GenericHelpText.d.ts +0 -0
  99. /package/dist/{ui → core/ui}/Toolbar/components/IconButton.css.d.ts +0 -0
  100. /package/dist/{ui → core/ui}/Toolbar/components/IconButton.d.ts +0 -0
  101. /package/dist/{ui → core/ui}/Toolbar/components/IconLinkButton.d.ts +0 -0
  102. /package/dist/{ui → core/ui}/Toolbar/components/LocalFlagControls.css.d.ts +0 -0
  103. /package/dist/{ui → core/ui}/Toolbar/components/LocalFlagControls.d.ts +0 -0
  104. /package/dist/{ui → core/ui}/Toolbar/components/OverrideIndicator.css.d.ts +0 -0
  105. /package/dist/{ui → core/ui}/Toolbar/components/OverrideIndicator.d.ts +0 -0
  106. /package/dist/{ui → core/ui}/Toolbar/components/Popover.css.d.ts +0 -0
  107. /package/dist/{ui → core/ui}/Toolbar/components/StatusDot.css.d.ts +0 -0
  108. /package/dist/{ui → core/ui}/Toolbar/components/StatusDot.d.ts +0 -0
  109. /package/dist/{ui → core/ui}/Toolbar/components/icons/AddIcon.d.ts +0 -0
  110. /package/dist/{ui → core/ui}/Toolbar/components/icons/ArrowUndoIcon.d.ts +0 -0
  111. /package/dist/{ui → core/ui}/Toolbar/components/icons/CancelCircleIcon.d.ts +0 -0
  112. /package/dist/{ui → core/ui}/Toolbar/components/icons/CheckIcon.d.ts +0 -0
  113. /package/dist/{ui → core/ui}/Toolbar/components/icons/ChevronDownIcon.d.ts +0 -0
  114. /package/dist/{ui → core/ui}/Toolbar/components/icons/ChevronUpIcon.d.ts +0 -0
  115. /package/dist/{ui → core/ui}/Toolbar/components/icons/DeleteIcon.d.ts +0 -0
  116. /package/dist/{ui → core/ui}/Toolbar/components/icons/EditIcon.d.ts +0 -0
  117. /package/dist/{ui → core/ui}/Toolbar/components/icons/GearIcon.d.ts +0 -0
  118. /package/dist/{ui → core/ui}/Toolbar/components/icons/Icon.css.d.ts +0 -0
  119. /package/dist/{ui → core/ui}/Toolbar/components/icons/LaunchDarklyIcon.d.ts +0 -0
  120. /package/dist/{ui → core/ui}/Toolbar/components/icons/LaunchDarklyLogo.d.ts +0 -0
  121. /package/dist/{ui → core/ui}/Toolbar/components/icons/SearchIcon.d.ts +0 -0
  122. /package/dist/{ui → core/ui}/Toolbar/components/icons/SyncIcon.d.ts +0 -0
  123. /package/dist/{ui → core/ui}/Toolbar/components/icons/ToggleOffIcon.d.ts +0 -0
  124. /package/dist/{ui → core/ui}/Toolbar/components/icons/XIcon.d.ts +0 -0
  125. /package/dist/{ui → core/ui}/Toolbar/components/icons/index.d.ts +0 -0
  126. /package/dist/{ui → core/ui}/Toolbar/components/index.d.ts +0 -0
  127. /package/dist/{ui → core/ui}/Toolbar/constants/animations.d.ts +0 -0
  128. /package/dist/{ui → core/ui}/Toolbar/constants/index.d.ts +0 -0
  129. /package/dist/{ui → core/ui}/Toolbar/constants/virtualization.d.ts +0 -0
  130. /package/dist/{ui → core/ui}/Toolbar/context/AnalyticsProvider.d.ts +0 -0
  131. /package/dist/{ui → core/ui}/Toolbar/context/DevServerProvider.d.ts +0 -0
  132. /package/dist/{ui → core/ui}/Toolbar/context/SearchProvider.d.ts +0 -0
  133. /package/dist/{ui → core/ui}/Toolbar/context/ToolbarUIProvider.d.ts +0 -0
  134. /package/dist/{ui → core/ui}/Toolbar/context/index.d.ts +0 -0
  135. /package/dist/{ui → core/ui}/Toolbar/hooks/index.d.ts +0 -0
  136. /package/dist/{ui → core/ui}/Toolbar/hooks/useCurrentDate.d.ts +0 -0
  137. /package/dist/{ui → core/ui}/Toolbar/hooks/useToolbarAnimations.d.ts +0 -0
  138. /package/dist/{ui → core/ui}/Toolbar/hooks/useToolbarDrag.d.ts +0 -0
  139. /package/dist/{ui → core/ui}/Toolbar/hooks/useToolbarVisibility.d.ts +0 -0
  140. /package/dist/{ui → core/ui}/Toolbar/types/index.d.ts +0 -0
  141. /package/dist/{ui → core/ui}/Toolbar/types/toolbar.d.ts +0 -0
  142. /package/dist/{ui → core/ui}/Toolbar/utils/localStorage.d.ts +0 -0
  143. /package/dist/{ui → core/ui}/constants/zIndex.d.ts +0 -0
  144. /package/dist/{utils → core/utils}/analytics.d.ts +0 -0
  145. /package/dist/{utils → core/utils}/browser.d.ts +0 -0
  146. /package/dist/{utils → core/utils}/deepEqual.d.ts +0 -0
  147. /package/dist/{utils → core/utils}/index.d.ts +0 -0
  148. /package/dist/{hooks → types/hooks}/index.d.ts +0 -0
package/README.md CHANGED
@@ -1,238 +1,353 @@
1
1
  # LaunchDarkly Toolbar
2
2
 
3
- A React component that provides a developer-friendly toolbar for interacting with LaunchDarkly during development. The toolbar supports two modes:
3
+ A developer-friendly React component that provides real-time feature flag management and debugging capabilities during development. The toolbar integrates seamlessly with LaunchDarkly, allowing developers to inspect, override, and test feature flags without leaving their application.
4
4
 
5
- - **SDK Mode**: Integrate with your LaunchDarkly SDK for local flag overrides and testing (recommended)
6
- - **Dev Server Mode**: Connect to a LaunchDarkly CLI dev server for flag browsing and real-time updates
5
+ ## Features
6
+
7
+ - 🎯 **Dual Mode Operation**: Works with both LaunchDarkly Dev Server and SDK
8
+ - 🔄 **Real-time Flag Management**: View and toggle feature flags instantly
9
+ - 🎨 **Shadow DOM Isolation**: Zero CSS conflicts with your application
10
+ - 📍 **Flexible Positioning**: Place toolbar in any corner of your screen
11
+ - 🔌 **Plugin System**: Extend functionality with custom plugins
12
+ - 📊 **Event Monitoring**: Track and inspect LaunchDarkly events
13
+ - 🔍 **Search & Filter**: Quickly find flags in large projects
14
+ - ⚡ **Hot Reload Support**: Automatically reflects flag changes
7
15
 
8
16
  ## Installation
9
17
 
10
18
  ```bash
11
- # npm
12
- npm install @launchdarkly/toolbar@next
19
+ npm install @launchdarkly/toolbar
20
+ # or
21
+ pnpm add @launchdarkly/toolbar
22
+ # or
23
+ yarn add @launchdarkly/toolbar
24
+ ```
13
25
 
14
- # yarn
15
- yarn add @launchdarkly/toolbar@next
26
+ ## Usage
16
27
 
17
- # pnpm
18
- pnpm add @launchdarkly/toolbar@next
19
- ```
28
+ The Developer Toolbar is intended for use during local development. As such, you should ensure that the way you are
29
+ instantiating it will keep it disabled in production environments.
20
30
 
21
- ## Quick Start
31
+ The Developer Toolbar depends on your LaunchDarkly JS client having a reference to the same `FlagOverridePlugin` and
32
+ `EventInterceptionPlugin` that you pass into the Developer Toolbar. As such, ensure that you instantiate the Developer Toolbar at the same time or immediately after the LaunchDarkly JS client is instantiated.
33
+ Below are a few examples on how to instantiate the toolbar, one using the `useLaunchDarklyToolbar` react hook, and one using the CDN hosted toolbar script.
22
34
 
23
- **SDK Mode** (recommended - integrates with your LaunchDarkly SDK):
35
+ ### React Hook (Recommended for React developers)
24
36
 
25
37
  ```tsx
26
- import { useEffect, useState } from 'react';
38
+ import { render } from 'react-dom';
27
39
  import { asyncWithLDProvider } from 'launchdarkly-react-client-sdk';
28
- import { LaunchDarklyToolbar, FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar';
40
+ import { useLaunchDarklyToolbar, FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar';
29
41
 
30
- // Create the plugin instances
31
42
  const flagOverridePlugin = new FlagOverridePlugin();
32
43
  const eventInterceptionPlugin = new EventInterceptionPlugin();
33
44
 
34
- function App() {
35
- const [LDProvider, setLDProvider] = useState(null);
36
-
37
- useEffect(() => {
38
- const initializeLD = async () => {
39
- const Provider = await asyncWithLDProvider({
40
- clientSideID: 'your-client-side-id',
41
- context: { key: 'user-key', name: 'User Name' },
42
- options: {
43
- // Pass the plugins to the SDK
44
- plugins: [flagOverridePlugin, eventInterceptionPlugin],
45
- },
46
- });
47
- setLDProvider(() => Provider);
48
- };
49
-
50
- initializeLD();
51
- }, []);
52
-
53
- if (!LDProvider) {
54
- return <div>Loading LaunchDarkly...</div>;
45
+ (async () => {
46
+ const LDProvider = await asyncWithLDProvider({
47
+ clientSideID: 'client-side-id-123abc',
48
+ context: {
49
+ kind: 'user',
50
+ key: 'user-key-123abc',
51
+ name: 'Sandy Smith',
52
+ email: 'sandy@example.com',
53
+ },
54
+ options: {
55
+ plugins: [
56
+ flagOverridePlugin,
57
+ eventInterceptionPlugin,
58
+ // other plugins...
59
+ ],
60
+ // other options...
61
+ },
62
+ });
63
+
64
+ function App() {
65
+ // Initialize toolbar with the same plugin instances
66
+ useLaunchDarklyToolbar({
67
+ flagOverridePlugin, // For flag overrides (SDK Mode only)
68
+ eventInterceptionPlugin, // For event monitoring (works in both modes)
69
+
70
+ // OR Dev Server Mode: Connect to LaunchDarkly dev server
71
+ devServerUrl: 'http://localhost:8080',
72
+ projectKey: 'my-project', // Optional: auto-detects if not provided
73
+
74
+ // Common options
75
+ position: 'bottom-right',
76
+ enabled: process.env.NODE_ENV === 'development',
77
+ });
78
+
79
+ return <YourApp />;
55
80
  }
56
81
 
57
- return (
82
+ render(
58
83
  <LDProvider>
59
- <div>
60
- <h1>My App</h1>
61
- {/* Pass the same plugin instances to the toolbar */}
62
- <LaunchDarklyToolbar
63
- flagOverridePlugin={flagOverridePlugin}
64
- eventInterceptionPlugin={eventInterceptionPlugin}
65
- />
66
- </div>
67
- </LDProvider>
84
+ <App />
85
+ </LDProvider>,
86
+ document.getElementById('root'),
68
87
  );
69
- }
88
+ })();
70
89
  ```
71
90
 
72
- **Dev Server Mode** (connects to LaunchDarkly CLI dev server):
73
-
74
- ```tsx
75
- import { LaunchDarklyToolbar } from '@launchdarkly/toolbar';
76
-
77
- function App() {
78
- return (
79
- <div>
80
- <h1>My App</h1>
81
- <LaunchDarklyToolbar devServerUrl="http://localhost:8765" />
82
- </div>
83
- );
84
- }
85
- ```
91
+ ### CDN Script Tag
86
92
 
87
- ## Props
93
+ Add this script to your `index.html` file.
88
94
 
89
- | Prop | Type | Default | Description |
90
- | ------------------------- | -------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------- |
91
- | `flagOverridePlugin` | `IFlagOverridePlugin` | `undefined` | Flag override plugin for SDK Mode. Enables flag overrides and testing |
92
- | `eventInterceptionPlugin` | `IEventInterceptionPlugin` | `undefined` | Event interception plugin for SDK Mode. Enables Events tab functionality |
93
- | `devServerUrl` | `string` (optional) | `undefined` | URL of your LaunchDarkly dev server. If provided, enables Dev Server Mode |
94
- | `position` | `"bottom-left" \| "bottom-right" \| "top-left" \| "top-right"` | `"bottom-right"` | Corner position of the toolbar |
95
- | `projectKey` | `string` (optional) | `undefined` | Optional project key for multi-project setups (Dev Server Mode only) |
96
- | `pollIntervalInMs` | `number` (optional) | `5000` | Polling interval for dev server updates (Dev Server Mode only) |
95
+ ```html
96
+ <script src="https://unpkg.com/@launchdarkly/toolbar@latest/cdn/toolbar.min.js"></script>
97
+ ```
97
98
 
98
- ## Configuration
99
+ In your corresponding code, wherever you instantiate your LaunchDarkly JS client, be sure to pass in the following plugins:
99
100
 
100
- ### Mode Determination
101
+ ```typescript
102
+ import * as LDClient from 'launchdarkly-js-client-sdk';
103
+ import { FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar';
101
104
 
102
- The toolbar automatically determines its mode:
105
+ const flagOverridePlugin = new FlagOverridePlugin();
106
+ const eventInterceptionPlugin = new EventInterceptionPlugin();
103
107
 
104
- - **SDK Mode**: When `flagOverridePlugin` is provided (recommended for most use cases)
105
- - **Dev Server Mode**: When `devServerUrl` is provided
108
+ const context: LDClient.LDContext = {
109
+ kind: 'user',
110
+ key: 'context-key-123abc',
111
+ };
112
+
113
+ const client = LDClient.initialize('client-side-id-123abc', context, {
114
+ plugins: [
115
+ // any other plugins you might want
116
+ flagOverridePlugin,
117
+ eventInterceptionPlugin,
118
+ ],
119
+ });
106
120
 
107
- ### Available Features by Mode
121
+ try {
122
+ await client.waitForInitialization(5);
123
+ // initialization succeeded, flag values are now available
124
+ handleInitializedClient(client);
125
+ } catch (err) {
126
+ // initialization failed or did not complete before timeout
127
+ }
108
128
 
109
- | Mode | Available Tabs |
110
- | ------------------- | ------------------------------------------------------------------------------------------------------ |
111
- | **SDK Mode** | Overrides (if `flagOverridePlugin` provided), Events (if `eventInterceptionPlugin` provided), Settings |
112
- | **Dev Server Mode** | Flags, Settings |
129
+ if (process.env.NODE_ENV === 'development' && window.LaunchDarklyToolbar) {
130
+ window.LaunchDarklyToolbar.init({
131
+ flagOverridePlugin,
132
+ eventInterceptionPlugin,
133
+ position: 'bottom-right',
134
+ });
135
+ }
136
+ ```
113
137
 
114
- ## Setup
138
+ Note: if you are using typescript and want type safety for the `window.LaunchDarklyToolbar.init` call,
139
+ you can add a `window.d.ts` file to your application with the following:
115
140
 
116
- ### SDK Mode (Recommended)
141
+ ```typescript
142
+ import type { LaunchDarklyToolbar } from '@launchdarkly/toolbar';
117
143
 
118
- SDK Mode integrates directly with your LaunchDarkly client, allowing you to:
144
+ declare global {
145
+ interface Window {
146
+ LaunchDarklyToolbar?: LaunchDarklyToolbar;
147
+ }
148
+ }
149
+ ```
119
150
 
120
- - Override flag values locally without affecting other users
121
- - Test different flag variations instantly
122
- - Work offline or with any LaunchDarkly environment
123
- - Maintain full type safety with your existing SDK setup
151
+ ## Package Structure
124
152
 
125
- Setup is straightforward:
153
+ ```
154
+ @launchdarkly/toolbar/
155
+ ├── src/
156
+ │ ├── core/ # Framework-agnostic toolbar implementation
157
+ │ │ ├── context/ # React context providers
158
+ │ │ ├── services/ # Business logic (DevServerClient, FlagStateManager)
159
+ │ │ ├── ui/ # UI components (Toolbar, Tabs, List, etc.)
160
+ │ │ ├── tests/ # Unit tests
161
+ │ │ └── index.ts # Core entry point (for CDN builds)
162
+ │ ├── react/ # React-specific integrations and utilities
163
+ │ │ ├── useLaunchDarklyToolbar.ts # Main React hook
164
+ │ │ └── lazyLoadToolbar.ts # Dynamic CDN loading
165
+ │ ├── types/ # TypeScript type definitions
166
+ │ │ ├── config.ts # Configuration types
167
+ │ │ ├── events.ts # Event types
168
+ │ │ ├── plugins.ts # Plugin interfaces
169
+ │ │ └── index.ts # Type exports
170
+ │ └── index.ts # Main entry point (NPM package)
171
+ ├── dist/ # NPM package output
172
+ │ ├── index.js # ES module build
173
+ │ ├── index.cjs # CommonJS build
174
+ │ └── index.d.ts # TypeScript definitions
175
+ ├── cdn/ # CDN bundle output
176
+ │ └── toolbar.min.js # IIFE bundle for script tags
177
+ ├── .storybook/ # Storybook configuration
178
+ └── stories/ # Component documentation
179
+ ```
126
180
 
127
- 1. Create a `FlagOverridePlugin` instance
128
- 2. Pass the plugin to your LaunchDarkly SDK's `plugins` array
129
- 3. Pass the same plugin instance to the toolbar component
130
- 4. Wrap your app with the LaunchDarkly provider
181
+ ## Configuration Options
131
182
 
132
- ```tsx
133
- import { useEffect, useState } from 'react';
134
- import { asyncWithLDProvider } from 'launchdarkly-react-client-sdk';
135
- import { LaunchDarklyToolbar, FlagOverridePlugin } from '@launchdarkly/toolbar';
183
+ ### Common Options
136
184
 
137
- // Create the plugin instance (outside component to avoid recreating)
138
- const flagOverridePlugin = new FlagOverridePlugin({
139
- storageNamespace: 'my-app-overrides', // Optional: customize storage key
140
- });
185
+ ```typescript
186
+ interface ToolbarConfig {
187
+ // LaunchDarkly configuration
188
+ baseUrl?: string; // LaunchDarkly API base URL
189
+ projectKey?: string; // Project key (auto-detected if not provided)
141
190
 
142
- function App() {
143
- const [LDProvider, setLDProvider] = useState(null);
191
+ // Dev Server Mode
192
+ devServerUrl?: string; // URL to LaunchDarkly dev server
144
193
 
145
- useEffect(() => {
146
- const initializeLD = async () => {
147
- const Provider = await asyncWithLDProvider({
148
- clientSideID: 'your-client-side-id',
149
- context: { key: 'user-key', name: 'User Name' },
150
- options: {
151
- plugins: [flagOverridePlugin], // Add plugin to SDK
152
- },
153
- });
154
- setLDProvider(() => Provider);
155
- };
194
+ // SDK Mode Plugins
195
+ flagOverridePlugin?: IFlagOverridePlugin; // Enable flag overrides
196
+ eventInterceptionPlugin?: IEventInterceptionPlugin; // Monitor events
156
197
 
157
- initializeLD();
158
- }, []);
198
+ // UI Configuration
199
+ position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
200
+ pollIntervalInMs?: number; // Polling interval (default: 1000ms)
201
+ }
202
+ ```
159
203
 
160
- if (!LDProvider) return <div>Loading...</div>;
204
+ ### React Hook Options
161
205
 
162
- return (
163
- <LDProvider>
164
- <YourAppContent />
165
- <LaunchDarklyToolbar flagOverridePlugin={flagOverridePlugin} />
166
- </LDProvider>
167
- );
206
+ ```typescript
207
+ interface UseLaunchDarklyToolbarConfig extends ToolbarConfig {
208
+ toolbarBundleUrl?: string; // Custom CDN URL for local development
209
+ enabled?: boolean; // Toggle toolbar on/off (default: true)
168
210
  }
169
211
  ```
170
212
 
171
- #### Event Interception Plugin
213
+ ## Modes
172
214
 
173
- To track and display LaunchDarkly events (flag evaluations, custom events, etc.), add the `EventInterceptionPlugin`:
215
+ ### Dev Server Mode
216
+
217
+ Connect directly to a LaunchDarkly dev server to manage server-side flags:
174
218
 
175
219
  ```tsx
176
- import { EventInterceptionPlugin } from '@launchdarkly/toolbar';
220
+ useLaunchDarklyToolbar({
221
+ devServerUrl: 'http://localhost:8080',
222
+ projectKey: 'my-project', // Optional
223
+ position: 'bottom-right',
224
+ });
225
+ ```
226
+
227
+ or if you are using the CDN script:
177
228
 
178
- // Create plugin with optional configuration
179
- const eventInterceptionPlugin = new EventInterceptionPlugin({
180
- eventCapacity: 250, // Maximum events to store (default: 100)
181
- enableLogging: true, // Console logging for debugging (default: false)
229
+ ```typescript
230
+ window.LaunchDarklyToolbar.init({
231
+ devServerUrl: 'http://localhost:8080',
232
+ projectKey: 'my-project', // Optional
233
+ position: 'bottom-right',
182
234
  });
235
+ ```
236
+
237
+ **Features:**
238
+
239
+ - View all flags from your LaunchDarkly project
240
+ - Set flag overrides that persist in dev server
241
+ - Changes visible to all connected clients
242
+ - Ideal for backend/full-stack development
243
+
244
+ ### SDK Mode
245
+
246
+ Integrate with LaunchDarkly React SDK for client-side flag management:
247
+
248
+ ```tsx
249
+ import { useFlagOverridePlugin, useEventInterceptionPlugin } from './plugins';
183
250
 
184
- // Add to both SDK and toolbar
185
- const Provider = await asyncWithLDProvider({
186
- // ... other config
187
- options: {
188
- plugins: [flagOverridePlugin, eventInterceptionPlugin],
189
- },
251
+ useLaunchDarklyToolbar({
252
+ flagOverridePlugin: useFlagOverridePlugin(),
253
+ eventInterceptionPlugin: useEventInterceptionPlugin(),
254
+ position: 'bottom-right',
190
255
  });
256
+ ```
191
257
 
192
- // Pass to toolbar
193
- <LaunchDarklyToolbar flagOverridePlugin={flagOverridePlugin} eventInterceptionPlugin={eventInterceptionPlugin} />;
258
+ or if you are using the CDN script:
259
+
260
+ ```typescript
261
+ window.LaunchDarklyToolbar.init({
262
+ flagOverridePlugin: new FlagOverridePlugin(),
263
+ eventInterceptionPlugin: new EventInterceptionPlugin(),
264
+ position: 'bottom-right',
265
+ });
194
266
  ```
195
267
 
196
- ### Dev Server Mode
268
+ **Features:**
197
269
 
198
- For teams using the LaunchDarkly CLI dev server, start it with CORS enabled:
270
+ - Local flag overrides (client-side only)
271
+ - Event monitoring and inspection
272
+ - No dev server required
273
+ - Ideal for frontend development
199
274
 
200
- ```bash
201
- ldcli dev-server start --project your-project --cors-enabled true
275
+ ## Plugin System
276
+
277
+ ### Flag Override Plugin
278
+
279
+ ```typescript
280
+ interface IFlagOverridePlugin {
281
+ getAllFlags(): Record<string, any>;
282
+ setOverride(flagKey: string, value: any): void;
283
+ clearOverride(flagKey: string): void;
284
+ clearAllOverrides(): void;
285
+ onFlagsChange(callback: (flags: Record<string, any>) => void): () => void;
286
+ }
202
287
  ```
203
288
 
204
- Then connect the toolbar:
289
+ ### Event Interception Plugin
205
290
 
206
- ```tsx
207
- <LaunchDarklyToolbar devServerUrl="http://localhost:8765" />
291
+ ```typescript
292
+ interface IEventInterceptionPlugin {
293
+ getEvents(): ProcessedEvent[];
294
+ clearEvents(): void;
295
+ onEvent(callback: (event: ProcessedEvent) => void): () => void;
296
+ }
208
297
  ```
209
298
 
210
- ## Visibility Control
299
+ ## Development
300
+
301
+ ### Building
211
302
 
212
- The toolbar provides a global API for show/hide control:
303
+ ```bash
304
+ # Build both NPM and CDN outputs
305
+ pnpm build
213
306
 
214
- ```javascript
215
- // Toggle visibility
216
- window.ldToolbar.toggle();
307
+ # Build only NPM package
308
+ pnpm build:lib
217
309
 
218
- // Enable/disable explicitly
219
- window.ldToolbar.enable();
220
- window.ldToolbar.disable();
310
+ # Build only CDN bundle
311
+ pnpm build:cdn
221
312
 
222
- // Check current status
223
- window.ldToolbar.status(); // returns true/false
313
+ # Watch mode for development
314
+ pnpm dev
224
315
  ```
225
316
 
226
- Visibility preferences are automatically saved to localStorage.
317
+ ### Testing
227
318
 
228
- ## TypeScript
319
+ ```bash
320
+ # Run unit tests
321
+ pnpm test
229
322
 
230
- The package includes complete TypeScript definitions. No additional `@types` packages needed.
323
+ # Run tests in watch mode
324
+ pnpm test:watch
325
+ ```
231
326
 
232
- ```tsx
233
- import type { LaunchDarklyToolbarProps, IFlagOverridePlugin, IEventInterceptionPlugin } from '@launchdarkly/toolbar';
327
+ ### Storybook
328
+
329
+ ```bash
330
+ # Start Storybook dev server
331
+ pnpm storybook
332
+
333
+ # Build Storybook for deployment
334
+ pnpm build:storybook
234
335
  ```
235
336
 
236
- ---
337
+ ## Browser Support
338
+
339
+ - Chrome 90+
340
+ - Firefox 88+
341
+ - Safari 14+
342
+ - Edge 90+
343
+
344
+ ## License
345
+
346
+ Apache-2.0
347
+
348
+ ## Links
237
349
 
238
- Built with ❤️ for the LaunchDarkly developer community.
350
+ - [Documentation](https://launchdarkly.com/docs/home/getting-started/dev-toolbar)
351
+ - [GitHub Repository](https://github.com/launchdarkly/launchdarkly-toolbar)
352
+ - [npm Package](https://www.npmjs.com/package/@launchdarkly/toolbar)
353
+ - [Issue Tracker](https://github.com/launchdarkly/launchdarkly-toolbar/issues)