@launchdarkly/toolbar 2.1.4 → 2.2.0

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
@@ -32,14 +32,14 @@ instantiating it will keep it disabled in production environments.
32
32
 
33
33
  The Developer Toolbar depends on your LaunchDarkly JS client having a reference to the same `FlagOverridePlugin` and
34
34
  `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.
35
- 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.
36
35
 
37
- ### React Hook (Recommended for React Applications)
36
+ ### React Hook
38
37
 
39
38
  ```tsx
40
39
  import { render } from 'react-dom';
41
40
  import { asyncWithLDProvider } from 'launchdarkly-react-client-sdk';
42
- import { useLaunchDarklyToolbar, FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar';
41
+ import { useLaunchDarklyToolbar } from '@launchdarkly/toolbar/react';
42
+ import { FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar/plugins';
43
43
 
44
44
  const flagOverridePlugin = new FlagOverridePlugin();
45
45
  const eventInterceptionPlugin = new EventInterceptionPlugin();
@@ -90,9 +90,118 @@ const eventInterceptionPlugin = new EventInterceptionPlugin();
90
90
  })();
91
91
  ```
92
92
 
93
- ### CDN Script Tag (Framework-Agnostic)
93
+ ### Vue Composable
94
94
 
95
- Works with any JavaScript framework (Vue, Angular, Svelte, vanilla JS, etc.). Add this script to your `index.html` file.
95
+ ```typescript
96
+ import { onMounted } from 'vue';
97
+ import * as LDClient from 'launchdarkly-js-client-sdk';
98
+ import { useLaunchDarklyToolbar } from '@launchdarkly/toolbar/vue';
99
+ import { FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar/plugins';
100
+
101
+ const flagOverridePlugin = new FlagOverridePlugin();
102
+ const eventInterceptionPlugin = new EventInterceptionPlugin();
103
+
104
+ // Initialize LaunchDarkly client
105
+ const client = LDClient.initialize(
106
+ 'client-side-id-123abc',
107
+ {
108
+ kind: 'user',
109
+ key: 'user-key-123abc',
110
+ name: 'Sandy Smith',
111
+ email: 'sandy@example.com',
112
+ },
113
+ {
114
+ plugins: [flagOverridePlugin, eventInterceptionPlugin],
115
+ },
116
+ );
117
+
118
+ // In your Vue component or setup function
119
+ export default {
120
+ setup() {
121
+ onMounted(async () => {
122
+ await client.waitForInitialization();
123
+ });
124
+
125
+ // Initialize toolbar with the same plugin instances
126
+ useLaunchDarklyToolbar({
127
+ flagOverridePlugin,
128
+ eventInterceptionPlugin,
129
+
130
+ // OR Dev Server Mode
131
+ devServerUrl: 'http://localhost:8080',
132
+ projectKey: 'my-project',
133
+
134
+ position: 'bottom-right',
135
+ enabled: import.meta.env.DEV, // Vite
136
+ // enabled: process.env.NODE_ENV === 'development', // Webpack
137
+ });
138
+
139
+ return {
140
+ // your component data
141
+ };
142
+ },
143
+ };
144
+ ```
145
+
146
+ ### Angular Service
147
+
148
+ ```typescript
149
+ import { Component, OnInit } from '@angular/core';
150
+ import * as LDClient from 'launchdarkly-js-client-sdk';
151
+ import LaunchDarklyToolbarService from '@launchdarkly/toolbar/angular';
152
+ import { FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar/plugins';
153
+ import { environment } from '../environments/environment';
154
+
155
+ @Component({
156
+ selector: 'app-root',
157
+ template: `<router-outlet></router-outlet>`,
158
+ providers: [LaunchDarklyToolbarService],
159
+ })
160
+ export class AppComponent implements OnInit {
161
+ private flagOverridePlugin = new FlagOverridePlugin();
162
+ private eventInterceptionPlugin = new EventInterceptionPlugin();
163
+ private ldClient: LDClient.LDClient;
164
+
165
+ constructor(private toolbarService: LaunchDarklyToolbarService) {
166
+ // Initialize LaunchDarkly client
167
+ this.ldClient = LDClient.initialize(
168
+ 'client-side-id-123abc',
169
+ {
170
+ kind: 'user',
171
+ key: 'user-key-123abc',
172
+ name: 'Sandy Smith',
173
+ email: 'sandy@example.com',
174
+ },
175
+ {
176
+ plugins: [this.flagOverridePlugin, this.eventInterceptionPlugin],
177
+ },
178
+ );
179
+ }
180
+
181
+ async ngOnInit() {
182
+ await this.ldClient.waitForInitialization();
183
+
184
+ // Initialize toolbar with the same plugin instances
185
+ if (!environment.production) {
186
+ await this.toolbarService.initialize({
187
+ flagOverridePlugin: this.flagOverridePlugin,
188
+ eventInterceptionPlugin: this.eventInterceptionPlugin,
189
+
190
+ // OR Dev Server Mode
191
+ devServerUrl: 'http://localhost:8080',
192
+ projectKey: 'my-project',
193
+
194
+ position: 'bottom-right',
195
+ enabled: true,
196
+ });
197
+ }
198
+ }
199
+ }
200
+ ```
201
+
202
+ ### CDN Script Tag
203
+
204
+ Works with any JavaScript framework or vanilla JS. Add this script to your `index.html` file.
96
205
 
97
206
  ```html
98
207
  <script src="https://unpkg.com/@launchdarkly/toolbar@latest/cdn/toolbar.min.js"></script>
@@ -150,6 +259,32 @@ declare global {
150
259
  }
151
260
  ```
152
261
 
262
+ ## Framework Support
263
+
264
+ The toolbar provides first-class support for popular frameworks:
265
+
266
+ ### Import Paths
267
+
268
+ ```typescript
269
+ // Core toolbar (for CDN or vanilla JS)
270
+ import { init } from '@launchdarkly/toolbar';
271
+
272
+ // Plugins (framework-agnostic)
273
+ import { FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar/plugins';
274
+
275
+ // React hook
276
+ import { useLaunchDarklyToolbar } from '@launchdarkly/toolbar/react';
277
+
278
+ // Vue composable
279
+ import { useLaunchDarklyToolbar } from '@launchdarkly/toolbar/vue';
280
+
281
+ // Angular service
282
+ import LaunchDarklyToolbarService from '@launchdarkly/toolbar/angular';
283
+
284
+ // TypeScript types
285
+ import type { InitializationConfig } from '@launchdarkly/toolbar/types';
286
+ ```
287
+
153
288
  ## Package Structure
154
289
 
155
290
  ```
@@ -161,9 +296,13 @@ declare global {
161
296
  │ │ ├── ui/ # UI components (Toolbar, Tabs, List, etc.)
162
297
  │ │ ├── tests/ # Unit tests
163
298
  │ │ └── index.ts # Core entry point (for CDN builds)
164
- │ ├── react/ # React-specific integrations and utilities
299
+ │ ├── react/ # React hook and utilities
165
300
  │ │ ├── useLaunchDarklyToolbar.ts # Main React hook
166
301
  │ │ └── lazyLoadToolbar.ts # Dynamic CDN loading
302
+ │ ├── vue/ # Vue composable
303
+ │ │ └── useLaunchDarklyToolbar.ts # Main Vue composable
304
+ │ ├── angular/ # Angular service
305
+ │ │ └── launchdarkly-toolbar.service.ts # Injectable service
167
306
  │ ├── types/ # TypeScript type definitions
168
307
  │ │ ├── config.ts # Configuration types
169
308
  │ │ ├── events.ts # Event types
@@ -171,9 +310,13 @@ declare global {
171
310
  │ │ └── index.ts # Type exports
172
311
  │ └── index.ts # Main entry point (NPM package)
173
312
  ├── dist/ # NPM package output
174
- │ ├── index.js # ES module build
175
- │ ├── index.cjs # CommonJS build
176
- └── index.d.ts # TypeScript definitions
313
+ │ ├── js/ # ES module builds
314
+ ├── index.js
315
+ │ ├── react.js
316
+ │ │ ├── vue.js
317
+ │ │ └── angular.js
318
+ │ ├── *.cjs # CommonJS builds
319
+ │ └── *.d.ts # TypeScript definitions
177
320
  ├── cdn/ # CDN bundle output
178
321
  │ └── toolbar.min.js # IIFE bundle for script tags
179
322
  ├── .storybook/ # Storybook configuration
@@ -203,7 +346,9 @@ interface ToolbarConfig {
203
346
  }
204
347
  ```
205
348
 
206
- ### React Hook Options
349
+ ### Framework-Specific Options
350
+
351
+ All framework integrations (React, Vue, Angular) support the same configuration options:
207
352
 
208
353
  ```typescript
209
354
  interface UseLaunchDarklyToolbarConfig extends ToolbarConfig {
@@ -212,12 +357,39 @@ interface UseLaunchDarklyToolbarConfig extends ToolbarConfig {
212
357
  }
213
358
  ```
214
359
 
360
+ **Example for local development:**
361
+
362
+ ```typescript
363
+ // React
364
+ useLaunchDarklyToolbar({
365
+ toolbarBundleUrl: 'http://localhost:5764/toolbar.min.js',
366
+ enabled: process.env.NODE_ENV === 'development',
367
+ // ... other options
368
+ });
369
+
370
+ // Vue
371
+ useLaunchDarklyToolbar({
372
+ toolbarBundleUrl: 'http://localhost:5764/toolbar.min.js',
373
+ enabled: import.meta.env.DEV,
374
+ // ... other options
375
+ });
376
+
377
+ // Angular
378
+ await toolbarService.initialize({
379
+ toolbarBundleUrl: 'http://localhost:5764/toolbar.min.js',
380
+ enabled: !environment.production,
381
+ // ... other options
382
+ });
383
+ ```
384
+
215
385
  ## Modes
216
386
 
217
387
  ### Dev Server Mode
218
388
 
219
389
  Connect directly to a LaunchDarkly dev server to manage server-side flags:
220
390
 
391
+ **React:**
392
+
221
393
  ```tsx
222
394
  useLaunchDarklyToolbar({
223
395
  devServerUrl: 'http://localhost:5764',
@@ -226,12 +398,32 @@ useLaunchDarklyToolbar({
226
398
  });
227
399
  ```
228
400
 
229
- or if you are using the CDN script:
401
+ **Vue:**
402
+
403
+ ```typescript
404
+ useLaunchDarklyToolbar({
405
+ devServerUrl: 'http://localhost:5764',
406
+ projectKey: 'my-project',
407
+ position: 'bottom-right',
408
+ });
409
+ ```
410
+
411
+ **Angular:**
412
+
413
+ ```typescript
414
+ await toolbarService.initialize({
415
+ devServerUrl: 'http://localhost:5764',
416
+ projectKey: 'my-project',
417
+ position: 'bottom-right',
418
+ });
419
+ ```
420
+
421
+ **CDN:**
230
422
 
231
423
  ```typescript
232
424
  window.LaunchDarklyToolbar.init({
233
- devServerUrl: 'http://localhost:8080',
234
- projectKey: 'my-project', // Optional
425
+ devServerUrl: 'http://localhost:5764',
426
+ projectKey: 'my-project',
235
427
  position: 'bottom-right',
236
428
  });
237
429
  ```
@@ -245,19 +437,54 @@ window.LaunchDarklyToolbar.init({
245
437
 
246
438
  ### SDK Mode
247
439
 
248
- Integrate with LaunchDarkly React SDK for client-side flag management:
440
+ Integrate with LaunchDarkly JS SDK for client-side flag management:
441
+
442
+ **React:**
249
443
 
250
444
  ```tsx
251
- import { useFlagOverridePlugin, useEventInterceptionPlugin } from './plugins';
445
+ import { FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar/plugins';
446
+
447
+ const flagOverridePlugin = new FlagOverridePlugin();
448
+ const eventInterceptionPlugin = new EventInterceptionPlugin();
449
+
450
+ useLaunchDarklyToolbar({
451
+ flagOverridePlugin,
452
+ eventInterceptionPlugin,
453
+ position: 'bottom-right',
454
+ });
455
+ ```
456
+
457
+ **Vue:**
458
+
459
+ ```typescript
460
+ import { FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar/plugins';
461
+
462
+ const flagOverridePlugin = new FlagOverridePlugin();
463
+ const eventInterceptionPlugin = new EventInterceptionPlugin();
252
464
 
253
465
  useLaunchDarklyToolbar({
254
- flagOverridePlugin: useFlagOverridePlugin(),
255
- eventInterceptionPlugin: useEventInterceptionPlugin(),
466
+ flagOverridePlugin,
467
+ eventInterceptionPlugin,
468
+ position: 'bottom-right',
469
+ });
470
+ ```
471
+
472
+ **Angular:**
473
+
474
+ ```typescript
475
+ import { FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar/plugins';
476
+
477
+ const flagOverridePlugin = new FlagOverridePlugin();
478
+ const eventInterceptionPlugin = new EventInterceptionPlugin();
479
+
480
+ await toolbarService.initialize({
481
+ flagOverridePlugin,
482
+ eventInterceptionPlugin,
256
483
  position: 'bottom-right',
257
484
  });
258
485
  ```
259
486
 
260
- or if you are using the CDN script:
487
+ **CDN:**
261
488
 
262
489
  ```typescript
263
490
  window.LaunchDarklyToolbar.init({
@@ -0,0 +1,104 @@
1
+ import { OnDestroy } from '@angular/core';
2
+ import type { InitializationConfig } from '../types';
3
+ /**
4
+ * Configuration options for the LaunchDarkly Toolbar service.
5
+ * Extends the base InitializationConfig with Angular-specific options.
6
+ */
7
+ export interface LaunchDarklyToolbarConfig extends InitializationConfig {
8
+ /**
9
+ * URL to load the toolbar bundle from.
10
+ * Use this when developing the toolbar itself locally.
11
+ *
12
+ * Example: `'http://localhost:5764/toolbar.min.js'`
13
+ *
14
+ * Default: CDN URL based on package version
15
+ */
16
+ toolbarBundleUrl?: string;
17
+ /**
18
+ * Whether the toolbar should be loaded and displayed.
19
+ *
20
+ * Default: `true`
21
+ */
22
+ enabled?: boolean;
23
+ }
24
+ /**
25
+ * Injectable service for managing the LaunchDarkly Developer Toolbar in Angular applications.
26
+ *
27
+ * This service handles the lifecycle of the toolbar, including initialization,
28
+ * lazy loading, and cleanup. It can be injected into any Angular component or service.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * import { Component, OnInit } from '@angular/core';
33
+ * import { LaunchDarklyToolbarService } from '@launchdarkly/toolbar/angular';
34
+ * import { FlagOverridePlugin, EventInterceptionPlugin } from '@launchdarkly/toolbar/plugins';
35
+ *
36
+ * @Component({
37
+ * selector: 'app-root',
38
+ * standalone: true,
39
+ * providers: [LaunchDarklyToolbarService],
40
+ * template: '<router-outlet />'
41
+ * })
42
+ * export class AppComponent implements OnInit {
43
+ * private flagOverridePlugin = new FlagOverridePlugin();
44
+ * private eventInterceptionPlugin = new EventInterceptionPlugin();
45
+ *
46
+ * constructor(private toolbarService: LaunchDarklyToolbarService) {}
47
+ *
48
+ * ngOnInit() {
49
+ * this.toolbarService.initialize({
50
+ * flagOverridePlugin: this.flagOverridePlugin,
51
+ * eventInterceptionPlugin: this.eventInterceptionPlugin,
52
+ * enabled: true,
53
+ * position: 'bottom-right'
54
+ * });
55
+ * }
56
+ * }
57
+ * ```
58
+ */
59
+ export default class LaunchDarklyToolbarService implements OnDestroy {
60
+ private cleanup?;
61
+ private abortController?;
62
+ private initialized;
63
+ /**
64
+ * Initializes the LaunchDarkly Toolbar with the provided configuration.
65
+ *
66
+ * This method lazy-loads the toolbar bundle from either a custom URL or the CDN,
67
+ * then initializes it with the provided configuration.
68
+ *
69
+ * @param config - Configuration options for the toolbar
70
+ * @returns Promise that resolves when initialization is complete
71
+ *
72
+ * @throws {Error} If initialization fails or toolbar bundle cannot be loaded
73
+ */
74
+ initialize(config: LaunchDarklyToolbarConfig): Promise<void>;
75
+ /**
76
+ * Angular lifecycle hook called when the service is destroyed.
77
+ * Automatically cleans up the toolbar.
78
+ */
79
+ ngOnDestroy(): void;
80
+ /**
81
+ * Manually destroys the toolbar and cleans up resources.
82
+ *
83
+ * This method:
84
+ * - Aborts any pending lazy-load requests
85
+ * - Calls the toolbar's cleanup function
86
+ * - Resets the initialized state
87
+ *
88
+ * After calling destroy(), you can call initialize() again to reinitialize.
89
+ */
90
+ destroy(): void;
91
+ /**
92
+ * Checks if the toolbar has been initialized.
93
+ *
94
+ * @returns true if the toolbar is currently initialized, false otherwise
95
+ */
96
+ isInitialized(): boolean;
97
+ /**
98
+ * Generates the CDN URL for a specific toolbar version.
99
+ *
100
+ * @param version - Toolbar version (defaults to 'latest')
101
+ * @returns CDN URL for the toolbar bundle
102
+ */
103
+ private versionToCdn;
104
+ }