@launchdarkly/toolbar 0.12.0-beta.1 → 0.13.0-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.
- package/README.md +17 -13
- package/dist/hooks/AfterEvaluationHook.d.ts +17 -0
- package/dist/hooks/AfterIdentifyHook.d.ts +18 -0
- package/dist/hooks/AfterTrackHook.d.ts +17 -0
- package/dist/hooks/EventStore.d.ts +11 -0
- package/dist/hooks/index.d.ts +7 -0
- package/dist/index.d.ts +6 -1
- package/dist/js/index.js +1822 -813
- package/dist/js/plugins/FlagOverridePlugin.js +3 -0
- package/dist/js/plugins/index.js +296 -1
- package/dist/plugins/EventInterceptionPlugin.d.ts +30 -0
- package/dist/plugins/FlagOverridePlugin.d.ts +8 -3
- package/dist/plugins/index.d.ts +2 -0
- package/dist/tests/hooks/AfterEvaluationHook.test.d.ts +1 -0
- package/dist/tests/hooks/AfterIdentifyHook.test.d.ts +1 -0
- package/dist/tests/hooks/AfterTrackHook.test.d.ts +1 -0
- package/dist/tests/hooks/EventStore.test.d.ts +1 -0
- package/dist/types/events.d.ts +64 -0
- package/dist/types/plugin.d.ts +21 -0
- package/dist/ui/Toolbar/LaunchDarklyToolbar.d.ts +4 -2
- package/dist/ui/Toolbar/TabContent/EventsTabContent.css.d.ts +18 -0
- package/dist/ui/Toolbar/TabContent/EventsTabContent.d.ts +6 -1
- package/dist/ui/Toolbar/components/DoNotTrackWarning.css.d.ts +5 -0
- package/dist/ui/Toolbar/components/DoNotTrackWarning.d.ts +1 -0
- package/dist/ui/Toolbar/components/ExpandedToolbarContent.d.ts +3 -2
- package/dist/ui/Toolbar/components/TabContentRenderer.d.ts +3 -2
- package/dist/ui/Toolbar/components/index.d.ts +1 -0
- package/dist/ui/Toolbar/constants/animations.d.ts +27 -0
- package/dist/ui/Toolbar/hooks/index.d.ts +2 -0
- package/dist/ui/Toolbar/hooks/useCurrentDate.d.ts +5 -0
- package/dist/ui/Toolbar/hooks/useEvents.d.ts +13 -0
- package/dist/ui/Toolbar/types/toolbar.d.ts +3 -3
- package/dist/utils/browser.d.ts +7 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +2 -3
package/dist/js/plugins/index.js
CHANGED
|
@@ -13,6 +13,9 @@ class FlagOverridePlugin {
|
|
|
13
13
|
name: 'FlagOverridePlugin'
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
+
getHooks(_metadata) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
16
19
|
register(ldClient) {
|
|
17
20
|
this.ldClient = ldClient;
|
|
18
21
|
}
|
|
@@ -127,4 +130,296 @@ class FlagOverridePlugin {
|
|
|
127
130
|
}
|
|
128
131
|
}
|
|
129
132
|
}
|
|
130
|
-
|
|
133
|
+
const MAX_EVENTS = 100;
|
|
134
|
+
class EventStore {
|
|
135
|
+
events = [];
|
|
136
|
+
listeners = new Set();
|
|
137
|
+
addEvent(event) {
|
|
138
|
+
try {
|
|
139
|
+
this.events.push(event);
|
|
140
|
+
if (this.events.length > MAX_EVENTS) this.events.splice(0, this.events.length - MAX_EVENTS);
|
|
141
|
+
this.notifyListeners();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.warn('Event store error:', error);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
getEvents() {
|
|
147
|
+
return [
|
|
148
|
+
...this.events
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
subscribe(listener) {
|
|
152
|
+
this.listeners.add(listener);
|
|
153
|
+
listener();
|
|
154
|
+
return ()=>this.listeners.delete(listener);
|
|
155
|
+
}
|
|
156
|
+
clear() {
|
|
157
|
+
this.events = [];
|
|
158
|
+
this.notifyListeners();
|
|
159
|
+
}
|
|
160
|
+
destroy() {
|
|
161
|
+
this.listeners.clear();
|
|
162
|
+
this.events = [];
|
|
163
|
+
}
|
|
164
|
+
notifyListeners() {
|
|
165
|
+
this.listeners.forEach((listener)=>{
|
|
166
|
+
try {
|
|
167
|
+
listener();
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.warn('Listener error:', error);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
class AfterTrackHook {
|
|
175
|
+
config;
|
|
176
|
+
idCounter = 0;
|
|
177
|
+
constructor(config = {}){
|
|
178
|
+
this.config = {
|
|
179
|
+
filter: config.filter,
|
|
180
|
+
onNewEvent: config.onNewEvent
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
getMetadata() {
|
|
184
|
+
return {
|
|
185
|
+
name: 'AfterTrackHook'
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
afterTrack(hookContext) {
|
|
189
|
+
try {
|
|
190
|
+
const syntheticContext = {
|
|
191
|
+
kind: 'custom',
|
|
192
|
+
key: hookContext.key,
|
|
193
|
+
context: hookContext.context,
|
|
194
|
+
data: hookContext.data,
|
|
195
|
+
metricValue: hookContext.metricValue,
|
|
196
|
+
creationDate: Date.now(),
|
|
197
|
+
url: 'undefined' != typeof window ? window.location.href : void 0
|
|
198
|
+
};
|
|
199
|
+
if (!this.shouldProcessEvent()) return;
|
|
200
|
+
const processedEvent = this.processEvent(syntheticContext);
|
|
201
|
+
this.config.onNewEvent?.(processedEvent);
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.warn('Event processing error in AfterTrackHook:', error);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
shouldProcessEvent() {
|
|
207
|
+
const filter = this.config.filter;
|
|
208
|
+
if (!filter) return true;
|
|
209
|
+
return !(filter.kinds && !filter.kinds.includes('custom')) && !(filter.categories && !filter.categories.includes('custom'));
|
|
210
|
+
}
|
|
211
|
+
processEvent(context) {
|
|
212
|
+
const timestamp = Date.now();
|
|
213
|
+
this.idCounter = (this.idCounter + 1) % 999999;
|
|
214
|
+
const randomPart = Math.random().toString(36).substring(2, 8);
|
|
215
|
+
const id = `${context.kind}-${timestamp}-${this.idCounter.toString().padStart(6, '0')}-${randomPart}`;
|
|
216
|
+
return {
|
|
217
|
+
id,
|
|
218
|
+
kind: context.kind,
|
|
219
|
+
key: context.key,
|
|
220
|
+
timestamp,
|
|
221
|
+
context,
|
|
222
|
+
displayName: `Custom: ${context.key || 'unknown'}`,
|
|
223
|
+
category: 'custom',
|
|
224
|
+
metadata: this.extractMetadata(context)
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
extractMetadata(context) {
|
|
228
|
+
return {
|
|
229
|
+
data: context.data,
|
|
230
|
+
metricValue: context.metricValue,
|
|
231
|
+
url: context.url
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
class AfterIdentifyHook {
|
|
236
|
+
config;
|
|
237
|
+
idCounter = 0;
|
|
238
|
+
constructor(config = {}){
|
|
239
|
+
this.config = {
|
|
240
|
+
filter: config.filter,
|
|
241
|
+
onNewEvent: config.onNewEvent
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
getMetadata() {
|
|
245
|
+
return {
|
|
246
|
+
name: 'AfterIdentifyHook'
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
afterIdentify(hookContext, data, result) {
|
|
250
|
+
try {
|
|
251
|
+
if ('completed' !== result.status) return data;
|
|
252
|
+
const syntheticContext = {
|
|
253
|
+
kind: 'identify',
|
|
254
|
+
context: hookContext.context,
|
|
255
|
+
creationDate: Date.now(),
|
|
256
|
+
contextKind: this.determineContextKind(hookContext.context)
|
|
257
|
+
};
|
|
258
|
+
if (!this.shouldProcessEvent()) return data;
|
|
259
|
+
const processedEvent = this.processEvent(syntheticContext);
|
|
260
|
+
this.config.onNewEvent?.(processedEvent);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.warn('Event processing error in AfterIdentifyHook:', error);
|
|
263
|
+
}
|
|
264
|
+
return data;
|
|
265
|
+
}
|
|
266
|
+
determineContextKind(context) {
|
|
267
|
+
if (context && 'object' == typeof context) {
|
|
268
|
+
if ('kind' in context && context.kind) return context.kind;
|
|
269
|
+
if (context.anonymous) return 'anonymousUser';
|
|
270
|
+
}
|
|
271
|
+
return 'user';
|
|
272
|
+
}
|
|
273
|
+
shouldProcessEvent() {
|
|
274
|
+
const filter = this.config.filter;
|
|
275
|
+
if (!filter) return true;
|
|
276
|
+
return !(filter.kinds && !filter.kinds.includes('identify')) && !(filter.categories && !filter.categories.includes('identify'));
|
|
277
|
+
}
|
|
278
|
+
processEvent(context) {
|
|
279
|
+
const timestamp = Date.now();
|
|
280
|
+
this.idCounter = (this.idCounter + 1) % 999999;
|
|
281
|
+
const randomPart = Math.random().toString(36).substring(2, 8);
|
|
282
|
+
const id = `${context.kind}-${timestamp}-${this.idCounter.toString().padStart(6, '0')}-${randomPart}`;
|
|
283
|
+
return {
|
|
284
|
+
id,
|
|
285
|
+
kind: context.kind,
|
|
286
|
+
key: context.key,
|
|
287
|
+
timestamp,
|
|
288
|
+
context,
|
|
289
|
+
displayName: `Identify: ${context.context?.key || 'anonymous'}`,
|
|
290
|
+
category: 'identify',
|
|
291
|
+
metadata: this.extractMetadata(context)
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
extractMetadata(context) {
|
|
295
|
+
return {
|
|
296
|
+
contextKind: context.contextKind
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
class AfterEvaluationHook {
|
|
301
|
+
config;
|
|
302
|
+
idCounter = 0;
|
|
303
|
+
constructor(config = {}){
|
|
304
|
+
this.config = {
|
|
305
|
+
filter: config.filter,
|
|
306
|
+
onNewEvent: config.onNewEvent
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
getMetadata() {
|
|
310
|
+
return {
|
|
311
|
+
name: 'AfterEvaluationHook'
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
afterEvaluation(hookContext, data, detail) {
|
|
315
|
+
try {
|
|
316
|
+
const syntheticContext = {
|
|
317
|
+
kind: 'feature',
|
|
318
|
+
key: hookContext.flagKey,
|
|
319
|
+
context: hookContext.context,
|
|
320
|
+
value: detail.value,
|
|
321
|
+
variation: detail.variationIndex,
|
|
322
|
+
default: hookContext.defaultValue,
|
|
323
|
+
reason: detail.reason,
|
|
324
|
+
creationDate: Date.now()
|
|
325
|
+
};
|
|
326
|
+
if (!this.shouldProcessEvent(syntheticContext)) return data;
|
|
327
|
+
const processedEvent = this.processEvent(syntheticContext);
|
|
328
|
+
this.config.onNewEvent?.(processedEvent);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.warn('Event processing error in AfterEvaluationHook:', error);
|
|
331
|
+
}
|
|
332
|
+
return data;
|
|
333
|
+
}
|
|
334
|
+
shouldProcessEvent(context) {
|
|
335
|
+
const filter = this.config.filter;
|
|
336
|
+
if (!filter) return true;
|
|
337
|
+
return !(filter.kinds && !filter.kinds.includes('feature')) && !(filter.categories && !filter.categories.includes('flag')) && !(filter.flagKeys && context.key && !filter.flagKeys.includes(context.key));
|
|
338
|
+
}
|
|
339
|
+
processEvent(context) {
|
|
340
|
+
const timestamp = Date.now();
|
|
341
|
+
this.idCounter = (this.idCounter + 1) % 999999;
|
|
342
|
+
const randomPart = Math.random().toString(36).substring(2, 8);
|
|
343
|
+
const id = `${context.kind}-${timestamp}-${this.idCounter.toString().padStart(6, '0')}-${randomPart}`;
|
|
344
|
+
return {
|
|
345
|
+
id,
|
|
346
|
+
kind: context.kind,
|
|
347
|
+
key: context.key,
|
|
348
|
+
timestamp,
|
|
349
|
+
context,
|
|
350
|
+
displayName: `Flag: ${context.key || 'unknown'}`,
|
|
351
|
+
category: 'flag',
|
|
352
|
+
metadata: this.extractMetadata(context)
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
extractMetadata(context) {
|
|
356
|
+
return {
|
|
357
|
+
flagVersion: context.version,
|
|
358
|
+
variation: context.variation,
|
|
359
|
+
trackEvents: context.trackEvents,
|
|
360
|
+
reason: context.reason,
|
|
361
|
+
defaultValue: context.default
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
class EventInterceptionPlugin {
|
|
366
|
+
afterTrackHook;
|
|
367
|
+
afterIdentifyHook;
|
|
368
|
+
afterEvaluationHook;
|
|
369
|
+
eventStore;
|
|
370
|
+
config;
|
|
371
|
+
constructor(config = {}){
|
|
372
|
+
this.config = {
|
|
373
|
+
enableLogging: true,
|
|
374
|
+
...config
|
|
375
|
+
};
|
|
376
|
+
this.eventStore = new EventStore();
|
|
377
|
+
const onNewEvent = (event)=>{
|
|
378
|
+
if (this.config.enableLogging) console.log('🎯 Event intercepted:', {
|
|
379
|
+
kind: event.kind,
|
|
380
|
+
key: event.key,
|
|
381
|
+
category: event.category,
|
|
382
|
+
displayName: event.displayName
|
|
383
|
+
});
|
|
384
|
+
this.eventStore.addEvent(event);
|
|
385
|
+
};
|
|
386
|
+
this.afterTrackHook = new AfterTrackHook({
|
|
387
|
+
filter: config.filter,
|
|
388
|
+
onNewEvent
|
|
389
|
+
});
|
|
390
|
+
this.afterIdentifyHook = new AfterIdentifyHook({
|
|
391
|
+
filter: config.filter,
|
|
392
|
+
onNewEvent
|
|
393
|
+
});
|
|
394
|
+
this.afterEvaluationHook = new AfterEvaluationHook({
|
|
395
|
+
filter: config.filter,
|
|
396
|
+
onNewEvent
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
getMetadata() {
|
|
400
|
+
return {
|
|
401
|
+
name: 'EventInterceptionPlugin'
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
getHooks(_metadata) {
|
|
405
|
+
return [
|
|
406
|
+
this.afterTrackHook,
|
|
407
|
+
this.afterIdentifyHook,
|
|
408
|
+
this.afterEvaluationHook
|
|
409
|
+
];
|
|
410
|
+
}
|
|
411
|
+
register(_client) {}
|
|
412
|
+
getEvents() {
|
|
413
|
+
return this.eventStore.getEvents();
|
|
414
|
+
}
|
|
415
|
+
subscribe(listener) {
|
|
416
|
+
return this.eventStore.subscribe(listener);
|
|
417
|
+
}
|
|
418
|
+
clearEvents() {
|
|
419
|
+
this.eventStore.clear();
|
|
420
|
+
}
|
|
421
|
+
destroy() {
|
|
422
|
+
this.eventStore.destroy();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
export { EventInterceptionPlugin, FlagOverridePlugin };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Hook, LDClient, LDPluginEnvironmentMetadata, LDPluginMetadata } from 'launchdarkly-js-client-sdk';
|
|
2
|
+
import type { EventFilter, ProcessedEvent } from '../types/events';
|
|
3
|
+
import type { IEventInterceptionPlugin } from '../types/plugin';
|
|
4
|
+
/**
|
|
5
|
+
* Configuration options for the EventInterceptionPlugin
|
|
6
|
+
*/
|
|
7
|
+
export interface EventInterceptionPluginConfig {
|
|
8
|
+
/** Configuration for event filtering */
|
|
9
|
+
filter?: EventFilter;
|
|
10
|
+
/** Enable console logging for debugging */
|
|
11
|
+
enableLogging?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Plugin dedicated to intercepting and processing LaunchDarkly events
|
|
15
|
+
*/
|
|
16
|
+
export declare class EventInterceptionPlugin implements IEventInterceptionPlugin {
|
|
17
|
+
private afterTrackHook;
|
|
18
|
+
private afterIdentifyHook;
|
|
19
|
+
private afterEvaluationHook;
|
|
20
|
+
private eventStore;
|
|
21
|
+
private config;
|
|
22
|
+
constructor(config?: EventInterceptionPluginConfig);
|
|
23
|
+
getMetadata(): LDPluginMetadata;
|
|
24
|
+
getHooks(_metadata: LDPluginEnvironmentMetadata): Hook[];
|
|
25
|
+
register(_client: LDClient): void;
|
|
26
|
+
getEvents(): ProcessedEvent[];
|
|
27
|
+
subscribe(listener: () => void): () => void;
|
|
28
|
+
clearEvents(): void;
|
|
29
|
+
destroy(): void;
|
|
30
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { LDClient,
|
|
1
|
+
import type { LDClient, LDDebugOverride, LDPluginMetadata, LDFlagSet, Hook, LDPluginEnvironmentMetadata } from 'launchdarkly-js-client-sdk';
|
|
2
|
+
import type { IFlagOverridePlugin } from '../types/plugin';
|
|
2
3
|
/**
|
|
3
4
|
* Configuration options for the FlagOverridePlugin
|
|
4
5
|
*/
|
|
@@ -6,7 +7,7 @@ export type FlagOverridePluginConfig = {
|
|
|
6
7
|
/** Namespace for localStorage keys. Defaults to 'ld-flag-override' */
|
|
7
8
|
storageNamespace?: string;
|
|
8
9
|
};
|
|
9
|
-
export declare class FlagOverridePlugin implements
|
|
10
|
+
export declare class FlagOverridePlugin implements IFlagOverridePlugin {
|
|
10
11
|
private debugOverride?;
|
|
11
12
|
private config;
|
|
12
13
|
private ldClient;
|
|
@@ -15,6 +16,10 @@ export declare class FlagOverridePlugin implements LDPlugin {
|
|
|
15
16
|
* Returns plugin metadata
|
|
16
17
|
*/
|
|
17
18
|
getMetadata(): LDPluginMetadata;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the hooks for the plugin
|
|
21
|
+
*/
|
|
22
|
+
getHooks(_metadata: LDPluginEnvironmentMetadata): Hook[];
|
|
18
23
|
/**
|
|
19
24
|
* Called when the plugin is registered with the LaunchDarkly client
|
|
20
25
|
*/
|
|
@@ -44,7 +49,7 @@ export declare class FlagOverridePlugin implements LDPlugin {
|
|
|
44
49
|
* Returns all currently active feature flag overrides
|
|
45
50
|
* @returns Record of flag keys to their override values
|
|
46
51
|
*/
|
|
47
|
-
getAllOverrides():
|
|
52
|
+
getAllOverrides(): LDFlagSet;
|
|
48
53
|
/**
|
|
49
54
|
* Returns the LaunchDarkly client instance
|
|
50
55
|
* @returns The LaunchDarkly client
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { FlagOverridePlugin } from './FlagOverridePlugin';
|
|
2
2
|
export type { FlagOverridePluginConfig } from './FlagOverridePlugin';
|
|
3
|
+
export { EventInterceptionPlugin } from './EventInterceptionPlugin';
|
|
4
|
+
export type { EventInterceptionPluginConfig } from './EventInterceptionPlugin';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export interface SyntheticEventContext {
|
|
2
|
+
readonly kind: EventKind;
|
|
3
|
+
readonly key?: string;
|
|
4
|
+
readonly context?: object;
|
|
5
|
+
readonly creationDate: number;
|
|
6
|
+
readonly data?: unknown;
|
|
7
|
+
readonly metricValue?: number;
|
|
8
|
+
readonly url?: string;
|
|
9
|
+
readonly value?: any;
|
|
10
|
+
readonly variation?: number | null;
|
|
11
|
+
readonly default?: any;
|
|
12
|
+
readonly reason?: object;
|
|
13
|
+
readonly version?: number;
|
|
14
|
+
readonly trackEvents?: boolean;
|
|
15
|
+
readonly debugEventsUntilDate?: number;
|
|
16
|
+
readonly contextKind?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Valid event kinds that can be emitted by the LaunchDarkly SDK
|
|
20
|
+
*/
|
|
21
|
+
declare const VALID_EVENT_KINDS: readonly ["identify", "feature", "custom", "debug", "summary", "diagnostic"];
|
|
22
|
+
/**
|
|
23
|
+
* Valid event categories used for organizing events
|
|
24
|
+
*/
|
|
25
|
+
declare const VALID_EVENT_CATEGORIES: readonly ["flag", "custom", "identify", "debug"];
|
|
26
|
+
/**
|
|
27
|
+
* Strict typing for event kinds based on LaunchDarkly's event system
|
|
28
|
+
*/
|
|
29
|
+
export type EventKind = (typeof VALID_EVENT_KINDS)[number];
|
|
30
|
+
/**
|
|
31
|
+
* Event categories for UI organization
|
|
32
|
+
*/
|
|
33
|
+
export type EventCategory = (typeof VALID_EVENT_CATEGORIES)[number];
|
|
34
|
+
/**
|
|
35
|
+
* Enhanced processed event
|
|
36
|
+
*/
|
|
37
|
+
export interface ProcessedEvent {
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly kind: EventKind;
|
|
40
|
+
readonly key?: string;
|
|
41
|
+
readonly timestamp: number;
|
|
42
|
+
readonly context: SyntheticEventContext;
|
|
43
|
+
readonly displayName: string;
|
|
44
|
+
readonly category: EventCategory;
|
|
45
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Event filter configuration
|
|
49
|
+
*/
|
|
50
|
+
export interface EventFilter {
|
|
51
|
+
readonly kinds?: ReadonlyArray<EventKind>;
|
|
52
|
+
readonly categories?: ReadonlyArray<EventCategory>;
|
|
53
|
+
readonly flagKeys?: ReadonlyArray<string>;
|
|
54
|
+
readonly timeRange?: {
|
|
55
|
+
readonly start: number;
|
|
56
|
+
readonly end: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Type guards for event validation
|
|
61
|
+
*/
|
|
62
|
+
export declare function isValidEventKind(kind: string): kind is EventKind;
|
|
63
|
+
export declare function isValidEventCategory(category: string): category is EventCategory;
|
|
64
|
+
export {};
|
package/dist/types/plugin.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LDClient, LDDebugOverride, LDFlagSet, LDFlagValue, LDPlugin } from 'launchdarkly-js-client-sdk';
|
|
2
|
+
import type { ProcessedEvent } from './events';
|
|
2
3
|
/**
|
|
3
4
|
* Interface for flag override plugins that can be used with the LaunchDarkly Toolbar
|
|
4
5
|
*/
|
|
@@ -29,3 +30,23 @@ export interface IFlagOverridePlugin extends LDPlugin, LDDebugOverride {
|
|
|
29
30
|
*/
|
|
30
31
|
getClient(): LDClient | null;
|
|
31
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Interface for event interception plugins that can be used with the LaunchDarkly Toolbar
|
|
35
|
+
*/
|
|
36
|
+
export interface IEventInterceptionPlugin extends LDPlugin {
|
|
37
|
+
/**
|
|
38
|
+
* Gets all intercepted events from the event store
|
|
39
|
+
* @returns Array of processed events
|
|
40
|
+
*/
|
|
41
|
+
getEvents(): ProcessedEvent[];
|
|
42
|
+
/**
|
|
43
|
+
* Subscribes to event store changes
|
|
44
|
+
* @param listener - Callback function to be called when events change
|
|
45
|
+
* @returns Unsubscribe function
|
|
46
|
+
*/
|
|
47
|
+
subscribe(listener: () => void): () => void;
|
|
48
|
+
/**
|
|
49
|
+
* Clears all events from the event store
|
|
50
|
+
*/
|
|
51
|
+
clearEvents(): void;
|
|
52
|
+
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { ToolbarMode, ToolbarPosition } from './types/toolbar';
|
|
2
|
-
import type { IFlagOverridePlugin } from '../../types/plugin';
|
|
2
|
+
import type { IEventInterceptionPlugin, IFlagOverridePlugin } from '../../types/plugin';
|
|
3
3
|
export interface LdToolbarProps {
|
|
4
|
-
flagOverridePlugin?: IFlagOverridePlugin;
|
|
5
4
|
mode: ToolbarMode;
|
|
5
|
+
flagOverridePlugin?: IFlagOverridePlugin;
|
|
6
|
+
eventInterceptionPlugin?: IEventInterceptionPlugin;
|
|
6
7
|
}
|
|
7
8
|
export declare function LdToolbar(props: LdToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
8
9
|
export interface LaunchDarklyToolbarProps {
|
|
9
10
|
devServerUrl?: string;
|
|
10
11
|
projectKey?: string;
|
|
11
12
|
flagOverridePlugin?: IFlagOverridePlugin;
|
|
13
|
+
eventInterceptionPlugin?: IEventInterceptionPlugin;
|
|
12
14
|
pollIntervalInMs?: number;
|
|
13
15
|
position?: ToolbarPosition;
|
|
14
16
|
}
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
export declare const statsHeader: string;
|
|
2
|
+
export declare const statsText: string;
|
|
1
3
|
export declare const eventInfo: string;
|
|
2
4
|
export declare const eventName: string;
|
|
3
5
|
export declare const eventMeta: string;
|
|
6
|
+
export declare const eventBadge: string;
|
|
7
|
+
export declare const eventBadgeFeature: string;
|
|
8
|
+
export declare const eventBadgeIdentify: string;
|
|
9
|
+
export declare const eventBadgeCustom: string;
|
|
10
|
+
export declare const eventBadgeDebug: string;
|
|
11
|
+
export declare const eventBadgeSummary: string;
|
|
12
|
+
export declare const eventBadgeDiagnostic: string;
|
|
13
|
+
export declare const eventBadgeDefault: string;
|
|
14
|
+
export declare const virtualContainer: string;
|
|
15
|
+
export declare const virtualInner: string;
|
|
16
|
+
export declare const virtualItem: string;
|
|
17
|
+
export declare const liveTailContainer: string;
|
|
18
|
+
export declare const liveTailIndicator: string;
|
|
19
|
+
export declare const liveTailDot: string;
|
|
20
|
+
export declare const liveTailText: string;
|
|
21
|
+
export declare const liveTailSubtext: string;
|
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { IEventInterceptionPlugin } from '../../../types/plugin';
|
|
2
|
+
interface EventsTabContentProps {
|
|
3
|
+
eventInterceptionPlugin?: IEventInterceptionPlugin;
|
|
4
|
+
}
|
|
5
|
+
export declare function EventsTabContent(props: EventsTabContentProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function DoNotTrackWarning(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Dispatch, SetStateAction } from 'react';
|
|
2
2
|
import { ActiveTabId, ToolbarMode } from '../types';
|
|
3
|
-
import type { IFlagOverridePlugin } from '../../../types/plugin';
|
|
3
|
+
import type { IFlagOverridePlugin, IEventInterceptionPlugin } from '../../../types/plugin';
|
|
4
4
|
interface ExpandedToolbarContentProps {
|
|
5
5
|
isExpanded: boolean;
|
|
6
6
|
activeTab: ActiveTabId;
|
|
@@ -11,8 +11,9 @@ interface ExpandedToolbarContentProps {
|
|
|
11
11
|
onClose: () => void;
|
|
12
12
|
onTabChange: (tabId: string) => void;
|
|
13
13
|
setSearchIsExpanded: Dispatch<SetStateAction<boolean>>;
|
|
14
|
-
flagOverridePlugin?: IFlagOverridePlugin;
|
|
15
14
|
mode: ToolbarMode;
|
|
15
|
+
flagOverridePlugin?: IFlagOverridePlugin;
|
|
16
|
+
eventInterceptionPlugin?: IEventInterceptionPlugin;
|
|
16
17
|
}
|
|
17
18
|
export declare function ExpandedToolbarContent(props: ExpandedToolbarContentProps): import("react/jsx-runtime").JSX.Element;
|
|
18
19
|
export {};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { TabId, ToolbarMode } from '../types';
|
|
2
|
-
import type { IFlagOverridePlugin } from '../../../types/plugin';
|
|
2
|
+
import type { IFlagOverridePlugin, IEventInterceptionPlugin } from '../../../types/plugin';
|
|
3
3
|
interface TabContentRendererProps {
|
|
4
4
|
activeTab: TabId;
|
|
5
5
|
slideDirection: number;
|
|
6
|
-
flagOverridePlugin?: IFlagOverridePlugin;
|
|
7
6
|
mode: ToolbarMode;
|
|
7
|
+
flagOverridePlugin?: IFlagOverridePlugin;
|
|
8
|
+
eventInterceptionPlugin?: IEventInterceptionPlugin;
|
|
8
9
|
}
|
|
9
10
|
export declare function TabContentRenderer(props: TabContentRendererProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
11
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { ActionButtonsContainer } from './ActionButtonsContainer';
|
|
2
2
|
export { CircleLogo } from './CircleLogo';
|
|
3
3
|
export { ConnectionStatus } from './ConnectionStatus';
|
|
4
|
+
export { DoNotTrackWarning } from './DoNotTrackWarning';
|
|
4
5
|
export { ExpandedToolbarContent } from './ExpandedToolbarContent';
|
|
5
6
|
export { LaunchDarklyIcon } from './icons/LaunchDarklyIcon';
|
|
6
7
|
export { StatusDot } from './StatusDot';
|
|
@@ -75,6 +75,33 @@ export declare const ANIMATION_CONFIG: {
|
|
|
75
75
|
};
|
|
76
76
|
readonly delay: 0.3;
|
|
77
77
|
};
|
|
78
|
+
readonly eventList: {
|
|
79
|
+
readonly liveTail: {
|
|
80
|
+
readonly dot: {
|
|
81
|
+
readonly scale: number[];
|
|
82
|
+
readonly opacity: number[];
|
|
83
|
+
readonly transition: {
|
|
84
|
+
readonly duration: 1.5;
|
|
85
|
+
readonly repeat: number;
|
|
86
|
+
readonly ease: "easeInOut";
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
readonly container: {
|
|
90
|
+
readonly initial: {
|
|
91
|
+
readonly opacity: 0;
|
|
92
|
+
readonly y: 20;
|
|
93
|
+
};
|
|
94
|
+
readonly animate: {
|
|
95
|
+
readonly opacity: 1;
|
|
96
|
+
readonly y: 0;
|
|
97
|
+
};
|
|
98
|
+
readonly transition: {
|
|
99
|
+
readonly duration: 0.4;
|
|
100
|
+
readonly ease: readonly [0.25, 0.46, 0.45, 0.94];
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
};
|
|
78
105
|
};
|
|
79
106
|
export declare const DIMENSIONS: {
|
|
80
107
|
readonly collapsed: {
|
|
@@ -3,3 +3,5 @@ export { useToolbarAnimations } from './useToolbarAnimations';
|
|
|
3
3
|
export { useToolbarVisibility } from './useToolbarVisibility';
|
|
4
4
|
export { useToolbarDrag } from './useToolbarDrag';
|
|
5
5
|
export { useKeyPressed } from './useKeyPressed';
|
|
6
|
+
export { useEvents } from './useEvents';
|
|
7
|
+
export { useCurrentDate } from './useCurrentDate';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ProcessedEvent } from '../../../types/events';
|
|
2
|
+
import { IEventInterceptionPlugin } from '../../../types/plugin';
|
|
3
|
+
interface EventStats {
|
|
4
|
+
totalEvents: number;
|
|
5
|
+
eventsByKind: Record<string, number>;
|
|
6
|
+
eventsByFlag: Record<string, number>;
|
|
7
|
+
}
|
|
8
|
+
interface UseEventsReturn {
|
|
9
|
+
events: ProcessedEvent[];
|
|
10
|
+
eventStats: EventStats;
|
|
11
|
+
}
|
|
12
|
+
export declare function useEvents(eventInterceptionPlugin: IEventInterceptionPlugin | undefined, searchTerm?: string): UseEventsReturn;
|
|
13
|
+
export {};
|