@virtu3d/event-manager 0.2.7

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.
@@ -0,0 +1,631 @@
1
+ /**
2
+ * Base telemetry event structure
3
+ */
4
+ interface TelemetryEvent {
5
+ /** Event name e.g., 'button_click', 'checkout', 'page_view' */
6
+ name: string;
7
+ /** Event payload - any key-value data */
8
+ payload: Record<string, unknown>;
9
+ /** ISO timestamp - auto-generated if not provided */
10
+ timestamp?: string;
11
+ /** Optional metadata */
12
+ meta?: {
13
+ sessionId?: string;
14
+ userId?: string;
15
+ orgId?: string;
16
+ traceId?: string;
17
+ spanId?: string;
18
+ [key: string]: unknown;
19
+ };
20
+ }
21
+ /**
22
+ * User identification event
23
+ */
24
+ interface IdentifyEvent {
25
+ userId: string;
26
+ traits?: Record<string, unknown>;
27
+ timestamp?: string;
28
+ }
29
+ /**
30
+ * Page view event
31
+ */
32
+ interface PageEvent {
33
+ name?: string;
34
+ properties?: Record<string, unknown>;
35
+ timestamp?: string;
36
+ }
37
+ /**
38
+ * Connector types
39
+ */
40
+ type ConnectorType = 'observability' | 'analytics' | 'metrics' | 'custom';
41
+ /**
42
+ * Connector interface - all connectors must implement this
43
+ */
44
+ interface Connector {
45
+ /** Unique connector name e.g., 'otel', 'mixpanel', 'cloudwatch-emf' */
46
+ name: string;
47
+ /** Connector category */
48
+ type: ConnectorType;
49
+ /** Initialize connector (load scripts, setup clients) */
50
+ init?(): Promise<void> | void;
51
+ /** Handle track events */
52
+ track(event: TelemetryEvent): Promise<void> | void;
53
+ /** Handle identify events */
54
+ identify?(event: IdentifyEvent): Promise<void> | void;
55
+ /** Handle page view events */
56
+ page?(event: PageEvent): Promise<void> | void;
57
+ /** Cleanup resources */
58
+ shutdown?(): Promise<void> | void;
59
+ /** Check if connector is ready */
60
+ isReady?(): boolean;
61
+ }
62
+ /**
63
+ * Connector configuration base
64
+ */
65
+ interface ConnectorConfig {
66
+ /** Enable/disable connector */
67
+ enabled?: boolean;
68
+ /** Debug mode */
69
+ debug?: boolean;
70
+ }
71
+ /**
72
+ * Factory interface for creating connectors
73
+ */
74
+ interface ConnectorFactory<TConfig extends ConnectorConfig = ConnectorConfig> {
75
+ /** Factory identifier */
76
+ name: string;
77
+ /** Factory type */
78
+ type: ConnectorType;
79
+ /** Create a connector instance */
80
+ create(config: TConfig): Connector;
81
+ }
82
+ /**
83
+ * Router configuration
84
+ */
85
+ interface RouterConfig {
86
+ /** Application name */
87
+ app?: string;
88
+ /** Debug mode - logs all events to console */
89
+ debug?: boolean;
90
+ /** Global metadata added to all events */
91
+ globalMeta?: Record<string, unknown>;
92
+ /** Plugins/middleware */
93
+ plugins?: RouterPlugin[];
94
+ }
95
+ /**
96
+ * Plugin interface for middleware functionality
97
+ */
98
+ interface RouterPlugin {
99
+ name: string;
100
+ /** Called before event is dispatched to connectors */
101
+ beforeDispatch?(event: TelemetryEvent): TelemetryEvent | null;
102
+ /** Called after all connectors have processed */
103
+ afterDispatch?(event: TelemetryEvent, results: DispatchResult[]): void;
104
+ }
105
+ /**
106
+ * Result of dispatching to a single connector
107
+ */
108
+ interface DispatchResult {
109
+ connector: string;
110
+ success: boolean;
111
+ error?: Error;
112
+ duration?: number;
113
+ }
114
+ /**
115
+ * Result of dispatching to all connectors
116
+ */
117
+ interface DispatchResults {
118
+ event: TelemetryEvent;
119
+ results: DispatchResult[];
120
+ timestamp: string;
121
+ }
122
+
123
+ declare abstract class BaseConnector implements Connector {
124
+ abstract name: string;
125
+ abstract type: ConnectorType;
126
+ protected config: ConnectorConfig;
127
+ protected ready: boolean;
128
+ constructor(config?: ConnectorConfig);
129
+ init(): Promise<void>;
130
+ /**
131
+ * Override this to implement connector-specific setup
132
+ */
133
+ protected abstract setup(): Promise<void> | void;
134
+ abstract track(event: TelemetryEvent): Promise<void> | void;
135
+ identify?(event: IdentifyEvent): Promise<void> | void;
136
+ page?(event: PageEvent): Promise<void> | void;
137
+ shutdown(): Promise<void>;
138
+ isReady(): boolean;
139
+ protected log(message: string, data?: unknown): void;
140
+ }
141
+
142
+ /**
143
+ * Browser OpenTelemetry Connector
144
+ *
145
+ * Provides OTEL tracing capabilities for browser environments.
146
+ * Uses @opentelemetry/sdk-trace-web for browser-optimized tracing.
147
+ */
148
+
149
+ interface BrowserOtelConnectorConfig extends ConnectorConfig {
150
+ /** Service name for this application */
151
+ serviceName: string;
152
+ /** OTEL collector endpoint for sending traces */
153
+ collectorUrl?: string;
154
+ /** URLs to propagate trace context to (supports strings and RegExp) */
155
+ propagateToUrls?: (string | RegExp)[];
156
+ /** Additional resource attributes */
157
+ resourceAttributes?: Record<string, string>;
158
+ /** Whether to auto-instrument fetch/XHR (default: false - use interceptors instead) */
159
+ autoInstrument?: boolean;
160
+ }
161
+ /**
162
+ * Browser-optimized OpenTelemetry connector
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * const connector = new BrowserOtelConnector({
167
+ * serviceName: 'my-web-app',
168
+ * collectorUrl: 'http://localhost:4318/v1/traces',
169
+ * propagateToUrls: [/api\.example\.com/, /localhost:3000/],
170
+ * });
171
+ * ```
172
+ */
173
+ declare class BrowserOtelConnector extends BaseConnector {
174
+ name: string;
175
+ type: "observability";
176
+ private tracer;
177
+ private provider;
178
+ private otelConfig;
179
+ constructor(config: BrowserOtelConnectorConfig);
180
+ protected setup(): Promise<void>;
181
+ track(event: TelemetryEvent): void;
182
+ identify(event: IdentifyEvent): void;
183
+ page(event: PageEvent): void;
184
+ shutdown(): Promise<void>;
185
+ /**
186
+ * Get the underlying tracer for advanced use cases
187
+ */
188
+ getTracer(): any;
189
+ /**
190
+ * Get the provider for advanced configuration
191
+ */
192
+ getProvider(): any;
193
+ }
194
+ /**
195
+ * Factory function to create a BrowserOtelConnector
196
+ */
197
+ declare function createBrowserOtelConnector(config: BrowserOtelConnectorConfig): BrowserOtelConnector;
198
+
199
+ /**
200
+ * Browser HTTP Interceptors
201
+ *
202
+ * Provides fetch and XMLHttpRequest interceptors for automatic
203
+ * trace context propagation in browser environments.
204
+ */
205
+ /**
206
+ * Configuration for the fetch interceptor
207
+ */
208
+ interface FetchInterceptorConfig {
209
+ /** URLs to propagate trace context to (matches if URL contains string or matches RegExp) */
210
+ propagateToUrls: (string | RegExp)[];
211
+ /** URLs to exclude from trace propagation (matches if URL contains string or matches RegExp) */
212
+ excludeUrls?: (string | RegExp)[];
213
+ /** Original fetch function (defaults to globalThis.fetch) */
214
+ originalFetch?: typeof fetch;
215
+ /** Whether to create spans for fetch requests (requires OTEL to be initialized) */
216
+ createSpans?: boolean;
217
+ /** Service name for span creation */
218
+ serviceName?: string;
219
+ }
220
+ /**
221
+ * Create a traced fetch function that automatically injects trace context headers.
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * const tracedFetch = createTracedFetch({
226
+ * propagateToUrls: [/api\.example\.com/, 'localhost:3000'],
227
+ * });
228
+ *
229
+ * // Use directly
230
+ * const response = await tracedFetch('/api/data');
231
+ *
232
+ * // Or replace global fetch
233
+ * globalThis.fetch = tracedFetch;
234
+ * ```
235
+ */
236
+ declare function createTracedFetch(config: FetchInterceptorConfig): typeof fetch;
237
+ /**
238
+ * Install the fetch interceptor globally.
239
+ * This replaces `globalThis.fetch` with a traced version.
240
+ *
241
+ * @example
242
+ * ```typescript
243
+ * installFetchInterceptor({
244
+ * propagateToUrls: [/api\.example\.com/, 'localhost:3000'],
245
+ * excludeUrls: [/google-analytics/, /sentry\.io/],
246
+ * createSpans: true,
247
+ * });
248
+ *
249
+ * // All subsequent fetch calls will have trace context
250
+ * const response = await fetch('/api/data');
251
+ * ```
252
+ */
253
+ declare function installFetchInterceptor(config: FetchInterceptorConfig): void;
254
+ /**
255
+ * Restore the original fetch function.
256
+ * Call this to uninstall the fetch interceptor.
257
+ *
258
+ * @param originalFetch - Optional: pass the original fetch function.
259
+ * If not provided, uses the stored original from installFetchInterceptor.
260
+ */
261
+ declare function uninstallFetchInterceptor(originalFetch?: typeof fetch): void;
262
+ /**
263
+ * Configuration for XMLHttpRequest interceptor
264
+ */
265
+ interface XHRInterceptorConfig {
266
+ /** URLs to propagate trace context to */
267
+ propagateToUrls: (string | RegExp)[];
268
+ /** URLs to exclude from trace propagation */
269
+ excludeUrls?: (string | RegExp)[];
270
+ /** Whether to create spans for XHR requests */
271
+ createSpans?: boolean;
272
+ /** Service name for span creation */
273
+ serviceName?: string;
274
+ }
275
+ /**
276
+ * Install XMLHttpRequest interceptor for automatic trace context propagation.
277
+ *
278
+ * @example
279
+ * ```typescript
280
+ * installXHRInterceptor({
281
+ * propagateToUrls: [/api\.example\.com/],
282
+ * });
283
+ *
284
+ * const xhr = new XMLHttpRequest();
285
+ * xhr.open('GET', 'https://api.example.com/data');
286
+ * xhr.send(); // Trace headers will be automatically added
287
+ * ```
288
+ */
289
+ declare function installXHRInterceptor(config: XHRInterceptorConfig): void;
290
+ /**
291
+ * Configuration for axios interceptor
292
+ */
293
+ interface AxiosInterceptorConfig {
294
+ /** URLs to propagate trace context to (matches if URL contains string or matches RegExp) */
295
+ propagateToUrls: (string | RegExp)[];
296
+ /** URLs to exclude from trace propagation (matches if URL contains string or matches RegExp) */
297
+ excludeUrls?: (string | RegExp)[];
298
+ }
299
+ /**
300
+ * Create an axios interceptor for trace context propagation.
301
+ * Use this with axios.interceptors.request.use()
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * import axios from 'axios';
306
+ *
307
+ * axios.interceptors.request.use(
308
+ * createAxiosTraceInterceptor({
309
+ * propagateToUrls: [/api\.example\.com/, 'localhost:3000'],
310
+ * excludeUrls: [/google-analytics/, /sentry\.io/],
311
+ * })
312
+ * );
313
+ * ```
314
+ */
315
+ declare function createAxiosTraceInterceptor(config: AxiosInterceptorConfig): (axiosConfig: any) => Promise<any>;
316
+ /**
317
+ * Install axios interceptor globally on an axios instance.
318
+ * Convenience function that wraps createAxiosTraceInterceptor.
319
+ *
320
+ * @example
321
+ * ```typescript
322
+ * import axios from 'axios';
323
+ *
324
+ * installAxiosInterceptor(axios, {
325
+ * propagateToUrls: [/api\.example\.com/],
326
+ * excludeUrls: [/google-analytics/],
327
+ * });
328
+ * ```
329
+ */
330
+ declare function installAxiosInterceptor(axiosInstance: {
331
+ interceptors: {
332
+ request: {
333
+ use: (fn: (config: any) => Promise<any>) => number;
334
+ };
335
+ };
336
+ }, config: AxiosInterceptorConfig): number;
337
+ /**
338
+ * Create headers with trace context for manual injection.
339
+ * Useful when you need to add trace context to custom HTTP clients.
340
+ *
341
+ * @example
342
+ * ```typescript
343
+ * const headers = await getTracedHeaders({ 'Content-Type': 'application/json' });
344
+ * // headers now includes traceparent and any existing headers
345
+ * ```
346
+ */
347
+ declare function getTracedHeaders(existingHeaders?: Record<string, string>): Promise<Record<string, string>>;
348
+
349
+ /**
350
+ * Context Propagation Utilities
351
+ *
352
+ * Works in both Node.js and Browser environments.
353
+ * Uses @opentelemetry/api for trace context propagation.
354
+ */
355
+ /**
356
+ * Trace context structure
357
+ */
358
+ interface TraceContext {
359
+ traceId: string;
360
+ spanId: string;
361
+ traceFlags: number;
362
+ }
363
+ /**
364
+ * Get current trace headers for manual injection into HTTP requests.
365
+ * Returns headers like { traceparent: '00-abc123...', tracestate: '...' }
366
+ *
367
+ * If there's an active OTEL span, uses its context.
368
+ * Otherwise, generates a new traceparent to enable backend trace correlation.
369
+ *
370
+ * @example
371
+ * ```typescript
372
+ * const headers = getTraceHeaders();
373
+ * fetch('/api/data', { headers });
374
+ * ```
375
+ */
376
+ declare function getTraceHeaders(): Promise<Record<string, string>>;
377
+ /**
378
+ * Synchronous version of getTraceHeaders (requires OTEL to be pre-loaded)
379
+ * Use this when you know OTEL is already initialized.
380
+ *
381
+ * If there's an active OTEL span, uses its context.
382
+ * Otherwise, generates a new traceparent to enable backend trace correlation.
383
+ */
384
+ declare function getTraceHeadersSync(): Record<string, string>;
385
+ /**
386
+ * Extract trace context from incoming headers.
387
+ * Use this in middleware to link incoming requests to their parent trace.
388
+ *
389
+ * @example
390
+ * ```typescript
391
+ * // Express middleware
392
+ * app.use((req, res, next) => {
393
+ * const traceContext = extractTraceContext(req.headers);
394
+ * if (traceContext) {
395
+ * req.traceId = traceContext.traceId;
396
+ * }
397
+ * next();
398
+ * });
399
+ * ```
400
+ */
401
+ declare function extractTraceContext(headers: Record<string, string | string[] | undefined>): Promise<TraceContext | null>;
402
+ /**
403
+ * Run a function within an extracted trace context.
404
+ * This ensures any spans created within the function are linked to the parent trace.
405
+ *
406
+ * @example
407
+ * ```typescript
408
+ * await withTraceContext(req.headers, async () => {
409
+ * // Any spans created here will be children of the incoming trace
410
+ * await processRequest();
411
+ * });
412
+ * ```
413
+ */
414
+ declare function withTraceContext<T>(headers: Record<string, string | string[] | undefined>, fn: () => T | Promise<T>): Promise<T>;
415
+ /**
416
+ * Create a new span for tracking an operation.
417
+ * The span will automatically be linked to the current trace context.
418
+ *
419
+ * @example
420
+ * ```typescript
421
+ * const span = await startSpan('fetch-user-data');
422
+ * try {
423
+ * const user = await fetchUser(id);
424
+ * span.setAttribute('user.id', id);
425
+ * span.setStatus({ code: SpanStatusCode.OK });
426
+ * } catch (error) {
427
+ * span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
428
+ * throw error;
429
+ * } finally {
430
+ * span.end();
431
+ * }
432
+ * ```
433
+ */
434
+ declare function startSpan(name: string, serviceName?: string): Promise<any>;
435
+ /**
436
+ * Parse a traceparent header string into its components.
437
+ * Format: version-traceId-spanId-traceFlags (e.g., "00-abc123...-def456...-01")
438
+ */
439
+ declare function parseTraceparent(traceparent: string): {
440
+ version: string;
441
+ traceId: string;
442
+ spanId: string;
443
+ traceFlags: number;
444
+ } | null;
445
+ /**
446
+ * Generate a traceparent header string.
447
+ * Useful for creating custom trace contexts.
448
+ */
449
+ declare function generateTraceparent(traceId: string, spanId: string, traceFlags?: number): string;
450
+ /**
451
+ * Generate a random trace ID (32 hex characters)
452
+ */
453
+ declare function generateTraceId(): string;
454
+ /**
455
+ * Generate a random span ID (16 hex characters)
456
+ */
457
+ declare function generateSpanId(): string;
458
+
459
+ /**
460
+ * Connector Factory Registry
461
+ *
462
+ * Maps connector type strings to their factory functions.
463
+ * This allows the router to auto-instantiate connectors from config.
464
+ */
465
+
466
+ /**
467
+ * Factory function type
468
+ */
469
+ type ConnectorFactoryFn<TConfig extends ConnectorConfig = ConnectorConfig> = (config: TConfig) => Connector;
470
+ /**
471
+ * Provider configuration for router
472
+ */
473
+ interface ProviderConfig {
474
+ /** Unique name for this provider instance */
475
+ name: string;
476
+ /** Provider type - maps to factory */
477
+ type: ConnectorTypeName;
478
+ /** Enable/disable this provider */
479
+ enabled?: boolean;
480
+ /** Provider-specific configuration */
481
+ config?: ConnectorConfig;
482
+ }
483
+ /**
484
+ * Built-in connector type names
485
+ */
486
+ type ConnectorTypeName = 'console' | 'otel' | 'otel-browser' | 'cloudwatch-emf' | 'mixpanel' | 'posthog';
487
+ /**
488
+ * Register a connector factory
489
+ */
490
+ declare function registerFactory<TConfig extends ConnectorConfig>(typeName: string, factory: ConnectorFactoryFn<TConfig>): void;
491
+ /**
492
+ * Get a factory by type name
493
+ */
494
+ declare function getFactory(typeName: string): ConnectorFactoryFn | undefined;
495
+ /**
496
+ * Check if a factory is registered
497
+ */
498
+ declare function hasFactory(typeName: string): boolean;
499
+ /**
500
+ * Create a connector from type and config
501
+ */
502
+ declare function createConnector(typeName: string, config: ConnectorConfig): Connector;
503
+
504
+ /**
505
+ * Extended router config with providers support
506
+ */
507
+ interface TelemetryRouterConfig extends RouterConfig {
508
+ /** Provider configurations - auto-registered on construction */
509
+ providers?: ProviderConfig[];
510
+ }
511
+ declare class TelemetryRouter {
512
+ private connectors;
513
+ private plugins;
514
+ private config;
515
+ private initialized;
516
+ constructor(config?: TelemetryRouterConfig);
517
+ /**
518
+ * Initialize all registered connectors
519
+ */
520
+ init(): Promise<void>;
521
+ /**
522
+ * Register a connector instance directly
523
+ */
524
+ registerConnector(connector: Connector): this;
525
+ /**
526
+ * Register connector using a factory
527
+ */
528
+ use<TConfig extends ConnectorConfig>(factory: ConnectorFactory<TConfig>, config: TConfig): this;
529
+ /**
530
+ * Unregister a connector by name
531
+ */
532
+ unregisterConnector(name: string): this;
533
+ /**
534
+ * Add a plugin
535
+ */
536
+ addPlugin(plugin: RouterPlugin): this;
537
+ /**
538
+ * Track a custom event
539
+ */
540
+ track(eventName: string, payload?: Record<string, unknown>): Promise<DispatchResults>;
541
+ /**
542
+ * Identify a user
543
+ */
544
+ identify(userId: string, traits?: Record<string, unknown>): Promise<DispatchResults>;
545
+ /**
546
+ * Track a page view
547
+ */
548
+ page(name?: string, properties?: Record<string, unknown>): Promise<DispatchResults>;
549
+ /**
550
+ * Core dispatch method - sends to all connectors in parallel
551
+ */
552
+ private dispatch;
553
+ /**
554
+ * Get all registered connector names
555
+ */
556
+ getConnectors(): string[];
557
+ /**
558
+ * Get connectors by type
559
+ */
560
+ getConnectorsByType(type: Connector['type']): string[];
561
+ /**
562
+ * Shutdown all connectors
563
+ */
564
+ shutdown(): Promise<void>;
565
+ /**
566
+ * Internal logger
567
+ */
568
+ private log;
569
+ }
570
+ /**
571
+ * Create a new TelemetryRouter instance
572
+ */
573
+ declare function createTelemetryRouter(config?: RouterConfig): TelemetryRouter;
574
+
575
+ interface ConsoleConnectorConfig extends ConnectorConfig {
576
+ prefix?: string;
577
+ }
578
+ /**
579
+ * Console connector for debugging during development
580
+ */
581
+ declare class ConsoleConnector extends BaseConnector {
582
+ name: string;
583
+ type: "custom";
584
+ private prefix;
585
+ constructor(config?: ConsoleConnectorConfig);
586
+ protected setup(): void;
587
+ track(event: TelemetryEvent): void;
588
+ identify(event: IdentifyEvent): void;
589
+ page(event: PageEvent): void;
590
+ }
591
+ declare function createConsoleConnector(config?: ConsoleConnectorConfig): ConsoleConnector;
592
+
593
+ /**
594
+ * Telemetry Utilities
595
+ *
596
+ * Common helper functions for telemetry operations.
597
+ */
598
+ /**
599
+ * Detect current environment (browser or node)
600
+ */
601
+ declare function detectEnvironment(): 'browser' | 'node';
602
+ /**
603
+ * Generate a unique session ID
604
+ */
605
+ declare function generateSessionId(): string;
606
+ /**
607
+ * Generate a unique event ID
608
+ */
609
+ declare function generateEventId(): string;
610
+ /**
611
+ * Safely stringify an object (handles circular references)
612
+ */
613
+ declare function safeStringify(obj: unknown, space?: number): string;
614
+ /**
615
+ * Deep merge two objects
616
+ */
617
+ declare function deepMerge<T extends object>(target: T, source: Partial<T>): T;
618
+ /**
619
+ * Check if value is a plain object
620
+ */
621
+ declare function isObject(value: unknown): value is Record<string, unknown>;
622
+ /**
623
+ * Sanitize sensitive fields from payload
624
+ */
625
+ declare function sanitizePayload(payload: Record<string, unknown>, sensitiveFields?: string[]): Record<string, unknown>;
626
+ /**
627
+ * Debounce a function
628
+ */
629
+ declare function debounce<T extends (...args: any[]) => any>(fn: T, delay: number): (...args: Parameters<T>) => void;
630
+
631
+ export { type AxiosInterceptorConfig, BaseConnector, BrowserOtelConnector, type BrowserOtelConnectorConfig, type Connector, type ConnectorConfig, type ConnectorFactoryFn, type ConnectorType, ConsoleConnector, type ConsoleConnectorConfig, type DispatchResult, type DispatchResults, type FetchInterceptorConfig, type IdentifyEvent, type PageEvent, type ProviderConfig, type RouterConfig, type RouterPlugin, type TelemetryEvent, TelemetryRouter, type TelemetryRouterConfig, type TraceContext, type XHRInterceptorConfig, createAxiosTraceInterceptor, createBrowserOtelConnector, createConnector, createConsoleConnector, createTelemetryRouter, createTracedFetch, debounce, deepMerge, detectEnvironment, extractTraceContext, generateEventId, generateSessionId, generateSpanId, generateTraceId, generateTraceparent, getFactory, getTraceHeaders, getTraceHeadersSync, getTracedHeaders, hasFactory, installAxiosInterceptor, installFetchInterceptor, installXHRInterceptor, isObject, parseTraceparent, registerFactory, safeStringify, sanitizePayload, startSpan, uninstallFetchInterceptor, withTraceContext };