@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.
package/dist/index.mjs ADDED
@@ -0,0 +1,999 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/connectors/base.connector.ts
9
+ var BaseConnector = class {
10
+ constructor(config = {}) {
11
+ this.ready = false;
12
+ this.config = {
13
+ enabled: true,
14
+ debug: false,
15
+ ...config
16
+ };
17
+ }
18
+ async init() {
19
+ if (!this.config.enabled) {
20
+ this.log("Connector disabled, skipping init");
21
+ return;
22
+ }
23
+ await this.setup();
24
+ this.ready = true;
25
+ }
26
+ async shutdown() {
27
+ this.ready = false;
28
+ }
29
+ isReady() {
30
+ return this.ready && (this.config.enabled ?? true);
31
+ }
32
+ log(message, data) {
33
+ if (this.config.debug) {
34
+ console.log(`[${this.name}] ${message}`, data || "");
35
+ }
36
+ }
37
+ };
38
+
39
+ // src/connectors/console.connector.ts
40
+ var ConsoleConnector = class extends BaseConnector {
41
+ constructor(config = {}) {
42
+ super(config);
43
+ this.name = "console";
44
+ this.type = "custom";
45
+ this.prefix = config.prefix || "[Telemetry]";
46
+ }
47
+ setup() {
48
+ }
49
+ track(event) {
50
+ console.log(`${this.prefix} TRACK:`, event.name, event.payload);
51
+ }
52
+ identify(event) {
53
+ console.log(`${this.prefix} IDENTIFY:`, event.userId, event.traits);
54
+ }
55
+ page(event) {
56
+ console.log(`${this.prefix} PAGE:`, event.name, event.properties);
57
+ }
58
+ };
59
+ function createConsoleConnector(config) {
60
+ return new ConsoleConnector(config);
61
+ }
62
+
63
+ // src/connectors/otel.connector.ts
64
+ var OtelConnector = class extends BaseConnector {
65
+ constructor(config) {
66
+ super(config);
67
+ this.name = "otel";
68
+ this.type = "observability";
69
+ this.serviceName = config.serviceName;
70
+ this.attributesExtractor = config.attributesExtractor;
71
+ }
72
+ async setup() {
73
+ const api = await import('@opentelemetry/api');
74
+ this.tracer = api.trace.getTracer(this.serviceName);
75
+ this.context = api.context;
76
+ this.log("OTEL tracer initialized");
77
+ }
78
+ track(event) {
79
+ if (!this.tracer) {
80
+ this.log("Tracer not initialized");
81
+ return;
82
+ }
83
+ const span = this.tracer.startSpan(event.name, {}, this.context.active());
84
+ span.setAttribute("event.name", event.name);
85
+ span.setAttribute("event.timestamp", event.timestamp || (/* @__PURE__ */ new Date()).toISOString());
86
+ if (this.attributesExtractor) {
87
+ const customAttrs = this.attributesExtractor(event);
88
+ Object.entries(customAttrs).forEach(([key, value]) => {
89
+ span.setAttribute(key, value);
90
+ });
91
+ }
92
+ Object.entries(event.payload).forEach(([key, value]) => {
93
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
94
+ span.setAttribute(`payload.${key}`, value);
95
+ }
96
+ });
97
+ if (event.meta) {
98
+ Object.entries(event.meta).forEach(([key, value]) => {
99
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
100
+ span.setAttribute(`meta.${key}`, value);
101
+ }
102
+ });
103
+ }
104
+ span.end();
105
+ this.log("Span created", { name: event.name });
106
+ }
107
+ identify(event) {
108
+ this.log("Identify received", { userId: event.userId });
109
+ }
110
+ page(event) {
111
+ this.track({
112
+ name: "page_view",
113
+ payload: { pageName: event.name, ...event.properties },
114
+ timestamp: event.timestamp
115
+ });
116
+ }
117
+ };
118
+ function createOtelConnector(config) {
119
+ return new OtelConnector(config);
120
+ }
121
+
122
+ // src/connectors/cloudwatch-emf.connector.ts
123
+ var CloudWatchEmfConnector = class extends BaseConnector {
124
+ constructor(config) {
125
+ super(config);
126
+ this.name = "cloudwatch-emf";
127
+ this.type = "metrics";
128
+ this.namespace = config.namespace;
129
+ this.serviceName = config.serviceName;
130
+ this.region = config.region || process.env.AWS_REGION || "us-east-1";
131
+ this.metricMappings = config.metricMappings || {};
132
+ }
133
+ setup() {
134
+ this.log("CloudWatch EMF connector initialized", {
135
+ namespace: this.namespace,
136
+ serviceName: this.serviceName,
137
+ mappedEvents: Object.keys(this.metricMappings)
138
+ });
139
+ }
140
+ track(event) {
141
+ const mapping = this.metricMappings[event.name];
142
+ const metricConfig = mapping || {
143
+ metricName: this.toMetricName(event.name),
144
+ unit: "Count",
145
+ dimensions: ["service"]
146
+ };
147
+ const metricValue = metricConfig.valueField ? Number(event.payload[metricConfig.valueField]) || 1 : 1;
148
+ const dimensions = {
149
+ service: this.serviceName
150
+ };
151
+ if (metricConfig.dimensions) {
152
+ for (const dim of metricConfig.dimensions) {
153
+ if (dim !== "service" && event.payload[dim] !== void 0) {
154
+ dimensions[dim] = String(event.payload[dim]);
155
+ }
156
+ }
157
+ }
158
+ if (event.meta?.userId) dimensions["userId"] = String(event.meta.userId);
159
+ if (event.meta?.orgId) dimensions["orgId"] = String(event.meta.orgId);
160
+ const emfLog = {
161
+ _aws: {
162
+ Timestamp: Date.now(),
163
+ CloudWatchMetrics: [
164
+ {
165
+ Namespace: this.namespace,
166
+ Dimensions: [Object.keys(dimensions)],
167
+ Metrics: [
168
+ {
169
+ Name: metricConfig.metricName,
170
+ Unit: metricConfig.unit
171
+ }
172
+ ]
173
+ }
174
+ ]
175
+ },
176
+ // Dimensions as top-level fields
177
+ ...dimensions,
178
+ // Metric value
179
+ [metricConfig.metricName]: metricValue,
180
+ // Additional context (not dimensions, just for log inspection)
181
+ eventName: event.name,
182
+ timestamp: event.timestamp,
183
+ payload: event.payload
184
+ };
185
+ console.log(JSON.stringify(emfLog));
186
+ this.log("EMF metric emitted", {
187
+ metric: metricConfig.metricName,
188
+ value: metricValue,
189
+ dimensions
190
+ });
191
+ }
192
+ identify(event) {
193
+ const emfLog = {
194
+ _aws: {
195
+ Timestamp: Date.now(),
196
+ CloudWatchMetrics: [
197
+ {
198
+ Namespace: this.namespace,
199
+ Dimensions: [["service"]],
200
+ Metrics: [
201
+ {
202
+ Name: "UserIdentified",
203
+ Unit: "Count"
204
+ }
205
+ ]
206
+ }
207
+ ]
208
+ },
209
+ service: this.serviceName,
210
+ UserIdentified: 1,
211
+ userId: event.userId,
212
+ traits: event.traits
213
+ };
214
+ console.log(JSON.stringify(emfLog));
215
+ }
216
+ /**
217
+ * Convert event name to CloudWatch metric name
218
+ * e.g., 'ai_chat_completed' -> 'AiChatCompleted'
219
+ */
220
+ toMetricName(eventName) {
221
+ return eventName.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
222
+ }
223
+ };
224
+ function createCloudWatchEmfConnector(config) {
225
+ return new CloudWatchEmfConnector(config);
226
+ }
227
+
228
+ // src/factories/index.ts
229
+ var factoryRegistry = /* @__PURE__ */ new Map();
230
+ function registerFactory(typeName, factory) {
231
+ factoryRegistry.set(typeName, factory);
232
+ }
233
+ function getFactory(typeName) {
234
+ return factoryRegistry.get(typeName);
235
+ }
236
+ function hasFactory(typeName) {
237
+ return factoryRegistry.has(typeName);
238
+ }
239
+ function getRegisteredFactories() {
240
+ return Array.from(factoryRegistry.keys());
241
+ }
242
+ function createConnector(typeName, config) {
243
+ const factory = factoryRegistry.get(typeName);
244
+ if (!factory) {
245
+ throw new Error(
246
+ `Unknown connector type: "${typeName}". Registered types: ${getRegisteredFactories().join(", ")}`
247
+ );
248
+ }
249
+ return factory(config);
250
+ }
251
+ function createConnectorsFromConfig(providers) {
252
+ return providers.filter((p) => p.enabled !== false).map((provider) => {
253
+ const connector = createConnector(provider.type, provider.config || {});
254
+ if (provider.name && provider.name !== connector.name) {
255
+ connector.name = provider.name;
256
+ }
257
+ return connector;
258
+ });
259
+ }
260
+ registerFactory("console", (config) => new ConsoleConnector(config));
261
+ registerFactory("otel", (config) => new OtelConnector(config));
262
+ registerFactory("cloudwatch-emf", (config) => new CloudWatchEmfConnector(config));
263
+ registerFactory("mixpanel", (config) => {
264
+ try {
265
+ const dynamicRequire = new Function("modulePath", "return require(modulePath)");
266
+ const { MixpanelConnector: MixpanelConnector2 } = dynamicRequire("../connectors/mixpanel.connector");
267
+ return new MixpanelConnector2(config);
268
+ } catch (err) {
269
+ throw new Error(
270
+ 'Mixpanel connector requires Node.js environment and the "mixpanel" package. Install with: npm install mixpanel'
271
+ );
272
+ }
273
+ });
274
+ registerFactory("posthog", (config) => {
275
+ try {
276
+ const dynamicRequire = new Function("modulePath", "return require(modulePath)");
277
+ const { PostHogConnector: PostHogConnector2 } = dynamicRequire("../connectors/posthog.connector");
278
+ return new PostHogConnector2(config);
279
+ } catch (err) {
280
+ throw new Error(
281
+ 'PostHog connector requires Node.js environment and the "posthog-node" package. Install with: npm install posthog-node'
282
+ );
283
+ }
284
+ });
285
+
286
+ // src/core/router.ts
287
+ var TelemetryRouter = class {
288
+ constructor(config = {}) {
289
+ this.connectors = /* @__PURE__ */ new Map();
290
+ this.plugins = [];
291
+ this.initialized = false;
292
+ this.config = {
293
+ debug: false,
294
+ globalMeta: {},
295
+ ...config
296
+ };
297
+ this.plugins = config.plugins || [];
298
+ if (config.providers && config.providers.length > 0) {
299
+ try {
300
+ const connectors = createConnectorsFromConfig(config.providers);
301
+ for (const connector of connectors) {
302
+ this.registerConnector(connector);
303
+ }
304
+ } catch (error) {
305
+ this.log("Failed to auto-register providers", error);
306
+ }
307
+ }
308
+ }
309
+ /**
310
+ * Initialize all registered connectors
311
+ */
312
+ async init() {
313
+ if (this.initialized) return;
314
+ const initPromises = Array.from(this.connectors.values()).map(
315
+ async (connector) => {
316
+ try {
317
+ await connector.init?.();
318
+ this.log(`Connector initialized: ${connector.name}`);
319
+ } catch (error) {
320
+ this.log(`Failed to initialize connector: ${connector.name}`, error);
321
+ }
322
+ }
323
+ );
324
+ await Promise.allSettled(initPromises);
325
+ this.initialized = true;
326
+ }
327
+ /**
328
+ * Register a connector instance directly
329
+ */
330
+ registerConnector(connector) {
331
+ if (this.connectors.has(connector.name)) {
332
+ this.log(`Connector "${connector.name}" already registered, replacing...`);
333
+ }
334
+ this.connectors.set(connector.name, connector);
335
+ this.log(`Connector registered: ${connector.name} (${connector.type})`);
336
+ return this;
337
+ }
338
+ /**
339
+ * Register connector using a factory
340
+ */
341
+ use(factory, config) {
342
+ const connector = factory.create(config);
343
+ return this.registerConnector(connector);
344
+ }
345
+ /**
346
+ * Unregister a connector by name
347
+ */
348
+ unregisterConnector(name) {
349
+ const connector = this.connectors.get(name);
350
+ if (connector) {
351
+ connector.shutdown?.();
352
+ this.connectors.delete(name);
353
+ this.log(`Connector unregistered: ${name}`);
354
+ }
355
+ return this;
356
+ }
357
+ /**
358
+ * Add a plugin
359
+ */
360
+ addPlugin(plugin) {
361
+ this.plugins.push(plugin);
362
+ this.log(`Plugin added: ${plugin.name}`);
363
+ return this;
364
+ }
365
+ /**
366
+ * Track a custom event
367
+ */
368
+ async track(eventName, payload = {}) {
369
+ const event = {
370
+ name: eventName,
371
+ payload,
372
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
373
+ meta: { ...this.config.globalMeta }
374
+ };
375
+ return this.dispatch("track", event);
376
+ }
377
+ /**
378
+ * Identify a user
379
+ */
380
+ async identify(userId, traits = {}) {
381
+ const event = {
382
+ userId,
383
+ traits,
384
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
385
+ };
386
+ const telemetryEvent = {
387
+ name: "identify",
388
+ payload: { userId, traits },
389
+ timestamp: event.timestamp,
390
+ meta: { ...this.config.globalMeta, userId }
391
+ };
392
+ return this.dispatch("identify", telemetryEvent, event);
393
+ }
394
+ /**
395
+ * Track a page view
396
+ */
397
+ async page(name, properties = {}) {
398
+ const event = {
399
+ name,
400
+ properties,
401
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
402
+ };
403
+ const telemetryEvent = {
404
+ name: "page_view",
405
+ payload: { pageName: name, ...properties },
406
+ timestamp: event.timestamp,
407
+ meta: { ...this.config.globalMeta }
408
+ };
409
+ return this.dispatch("page", telemetryEvent, event);
410
+ }
411
+ /**
412
+ * Core dispatch method - sends to all connectors in parallel
413
+ */
414
+ async dispatch(method, event, originalEvent) {
415
+ let processedEvent = event;
416
+ for (const plugin of this.plugins) {
417
+ if (plugin.beforeDispatch) {
418
+ processedEvent = plugin.beforeDispatch(processedEvent);
419
+ if (!processedEvent) {
420
+ this.log(`Event blocked by plugin: ${plugin.name}`);
421
+ return {
422
+ event,
423
+ results: [],
424
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
425
+ };
426
+ }
427
+ }
428
+ }
429
+ const connectors = Array.from(this.connectors.values());
430
+ const startTime = Date.now();
431
+ const settledResults = await Promise.allSettled(
432
+ connectors.map(async (connector) => {
433
+ const connectorStart = Date.now();
434
+ try {
435
+ switch (method) {
436
+ case "track":
437
+ await connector.track(processedEvent);
438
+ break;
439
+ case "identify":
440
+ await connector.identify?.(originalEvent);
441
+ break;
442
+ case "page":
443
+ await connector.page?.(originalEvent);
444
+ break;
445
+ }
446
+ return {
447
+ connector: connector.name,
448
+ success: true,
449
+ duration: Date.now() - connectorStart
450
+ };
451
+ } catch (error) {
452
+ return {
453
+ connector: connector.name,
454
+ success: false,
455
+ error: error instanceof Error ? error : new Error(String(error)),
456
+ duration: Date.now() - connectorStart
457
+ };
458
+ }
459
+ })
460
+ );
461
+ const results = settledResults.map((result) => {
462
+ if (result.status === "fulfilled") {
463
+ return result.value;
464
+ }
465
+ return {
466
+ connector: "unknown",
467
+ success: false,
468
+ error: result.reason
469
+ };
470
+ });
471
+ this.log(`Event dispatched: ${event.name}`, {
472
+ duration: Date.now() - startTime,
473
+ results: results.map((r) => ({
474
+ connector: r.connector,
475
+ success: r.success
476
+ }))
477
+ });
478
+ for (const plugin of this.plugins) {
479
+ plugin.afterDispatch?.(processedEvent, results);
480
+ }
481
+ return {
482
+ event: processedEvent,
483
+ results,
484
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
485
+ };
486
+ }
487
+ /**
488
+ * Get all registered connector names
489
+ */
490
+ getConnectors() {
491
+ return Array.from(this.connectors.keys());
492
+ }
493
+ /**
494
+ * Get connectors by type
495
+ */
496
+ getConnectorsByType(type) {
497
+ return Array.from(this.connectors.values()).filter((c) => c.type === type).map((c) => c.name);
498
+ }
499
+ /**
500
+ * Shutdown all connectors
501
+ */
502
+ async shutdown() {
503
+ const shutdownPromises = Array.from(this.connectors.values()).map(
504
+ async (connector) => {
505
+ try {
506
+ await connector.shutdown?.();
507
+ this.log(`Connector shutdown: ${connector.name}`);
508
+ } catch (error) {
509
+ this.log(`Failed to shutdown connector: ${connector.name}`, error);
510
+ }
511
+ }
512
+ );
513
+ await Promise.allSettled(shutdownPromises);
514
+ this.connectors.clear();
515
+ this.initialized = false;
516
+ }
517
+ /**
518
+ * Internal logger
519
+ */
520
+ log(message, data) {
521
+ if (this.config.debug) {
522
+ console.log(`[TelemetryRouter] ${message}`, data || "");
523
+ }
524
+ }
525
+ };
526
+ function createTelemetryRouter(config) {
527
+ return new TelemetryRouter(config);
528
+ }
529
+
530
+ // src/core/config.ts
531
+ function validateConfig(config) {
532
+ if (!config.app) {
533
+ throw new Error('TelemetryConfig: "app" is required');
534
+ }
535
+ if (config.analytics.provider !== "none") {
536
+ const providerConfig = config.analytics[config.analytics.provider];
537
+ if (!providerConfig) {
538
+ throw new Error(
539
+ `TelemetryConfig: Missing config for analytics provider "${config.analytics.provider}"`
540
+ );
541
+ }
542
+ }
543
+ if (config.observability.provider !== "none") {
544
+ const providerConfig = config.observability[config.observability.provider];
545
+ if (!providerConfig) {
546
+ throw new Error(
547
+ `TelemetryConfig: Missing config for observability provider "${config.observability.provider}"`
548
+ );
549
+ }
550
+ }
551
+ if (config.metrics?.provider && config.metrics.provider !== "none") {
552
+ const key = config.metrics.provider === "cloudwatch-emf" ? "cloudwatchEmf" : config.metrics.provider;
553
+ const providerConfig = config.metrics[key];
554
+ if (!providerConfig) {
555
+ throw new Error(
556
+ `TelemetryConfig: Missing config for metrics provider "${config.metrics.provider}"`
557
+ );
558
+ }
559
+ }
560
+ }
561
+
562
+ // src/context/index.ts
563
+ async function getTraceHeaders() {
564
+ try {
565
+ const { context, propagation, trace } = await import('@opentelemetry/api');
566
+ const headers = {};
567
+ propagation.inject(context.active(), headers);
568
+ if (!headers["traceparent"]) {
569
+ const traceId = generateTraceId();
570
+ const spanId = generateSpanId();
571
+ headers["traceparent"] = generateTraceparent(traceId, spanId, 1);
572
+ }
573
+ return headers;
574
+ } catch {
575
+ const traceId = generateTraceId();
576
+ const spanId = generateSpanId();
577
+ return {
578
+ traceparent: generateTraceparent(traceId, spanId, 1)
579
+ };
580
+ }
581
+ }
582
+ function getTraceHeadersSync() {
583
+ try {
584
+ const { context, propagation } = __require("@opentelemetry/api");
585
+ const headers = {};
586
+ propagation.inject(context.active(), headers);
587
+ if (!headers["traceparent"]) {
588
+ const traceId = generateTraceId();
589
+ const spanId = generateSpanId();
590
+ headers["traceparent"] = generateTraceparent(traceId, spanId, 1);
591
+ }
592
+ return headers;
593
+ } catch {
594
+ const traceId = generateTraceId();
595
+ const spanId = generateSpanId();
596
+ return {
597
+ traceparent: generateTraceparent(traceId, spanId, 1)
598
+ };
599
+ }
600
+ }
601
+ async function extractTraceContext(headers) {
602
+ try {
603
+ const { trace, context, propagation, isSpanContextValid } = await import('@opentelemetry/api');
604
+ const normalizedHeaders = {};
605
+ for (const [key, value] of Object.entries(headers)) {
606
+ const lowerKey = key.toLowerCase();
607
+ if (typeof value === "string") {
608
+ normalizedHeaders[lowerKey] = value;
609
+ } else if (Array.isArray(value)) {
610
+ normalizedHeaders[lowerKey] = value[0] || "";
611
+ }
612
+ }
613
+ const extractedContext = propagation.extract(context.active(), normalizedHeaders);
614
+ const spanContext = trace.getSpanContext(extractedContext);
615
+ if (!spanContext || !isSpanContextValid(spanContext)) {
616
+ const traceparent = normalizedHeaders["traceparent"];
617
+ if (traceparent) {
618
+ const parsed = parseTraceparent(traceparent);
619
+ if (parsed) {
620
+ return {
621
+ traceId: parsed.traceId,
622
+ spanId: parsed.spanId,
623
+ traceFlags: parsed.traceFlags
624
+ };
625
+ }
626
+ }
627
+ return null;
628
+ }
629
+ return {
630
+ traceId: spanContext.traceId,
631
+ spanId: spanContext.spanId,
632
+ traceFlags: spanContext.traceFlags
633
+ };
634
+ } catch {
635
+ const traceparent = headers["traceparent"] || headers["Traceparent"];
636
+ if (traceparent) {
637
+ const value = typeof traceparent === "string" ? traceparent : traceparent[0];
638
+ const parsed = parseTraceparent(value || "");
639
+ if (parsed) {
640
+ return {
641
+ traceId: parsed.traceId,
642
+ spanId: parsed.spanId,
643
+ traceFlags: parsed.traceFlags
644
+ };
645
+ }
646
+ }
647
+ return null;
648
+ }
649
+ }
650
+ async function withTraceContext(headers, fn) {
651
+ try {
652
+ const { context, propagation } = await import('@opentelemetry/api');
653
+ const normalizedHeaders = {};
654
+ for (const [key, value] of Object.entries(headers)) {
655
+ if (typeof value === "string") {
656
+ normalizedHeaders[key] = value;
657
+ } else if (Array.isArray(value)) {
658
+ normalizedHeaders[key] = value[0] || "";
659
+ }
660
+ }
661
+ const extractedContext = propagation.extract(context.active(), normalizedHeaders);
662
+ return context.with(extractedContext, fn);
663
+ } catch {
664
+ return fn();
665
+ }
666
+ }
667
+ async function startSpan(name, serviceName = "telemetry") {
668
+ try {
669
+ const { trace } = await import('@opentelemetry/api');
670
+ const tracer = trace.getTracer(serviceName);
671
+ return tracer.startSpan(name);
672
+ } catch {
673
+ return {
674
+ setAttribute: () => {
675
+ },
676
+ setStatus: () => {
677
+ },
678
+ addEvent: () => {
679
+ },
680
+ end: () => {
681
+ },
682
+ spanContext: () => ({ traceId: "", spanId: "", traceFlags: 0 })
683
+ };
684
+ }
685
+ }
686
+ function parseTraceparent(traceparent) {
687
+ if (!traceparent) return null;
688
+ const parts = traceparent.split("-");
689
+ if (parts.length !== 4) return null;
690
+ const [version, traceId, spanId, flags] = parts;
691
+ if (version.length !== 2 || traceId.length !== 32 || spanId.length !== 16 || flags.length !== 2) {
692
+ return null;
693
+ }
694
+ return {
695
+ version,
696
+ traceId,
697
+ spanId,
698
+ traceFlags: parseInt(flags, 16)
699
+ };
700
+ }
701
+ function generateTraceparent(traceId, spanId, traceFlags = 1) {
702
+ const flagsHex = traceFlags.toString(16).padStart(2, "0");
703
+ return `00-${traceId}-${spanId}-${flagsHex}`;
704
+ }
705
+ function generateTraceId() {
706
+ const bytes = new Uint8Array(16);
707
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
708
+ crypto.getRandomValues(bytes);
709
+ } else {
710
+ for (let i = 0; i < bytes.length; i++) {
711
+ bytes[i] = Math.floor(Math.random() * 256);
712
+ }
713
+ }
714
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
715
+ }
716
+ function generateSpanId() {
717
+ const bytes = new Uint8Array(8);
718
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
719
+ crypto.getRandomValues(bytes);
720
+ } else {
721
+ for (let i = 0; i < bytes.length; i++) {
722
+ bytes[i] = Math.floor(Math.random() * 256);
723
+ }
724
+ }
725
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
726
+ }
727
+
728
+ // src/utils/index.ts
729
+ function detectEnvironment() {
730
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
731
+ return "browser";
732
+ }
733
+ return "node";
734
+ }
735
+ function generateSessionId() {
736
+ const timestamp = Date.now().toString(36);
737
+ const randomPart = Math.random().toString(36).substring(2, 10);
738
+ return `${timestamp}-${randomPart}`;
739
+ }
740
+ function generateEventId() {
741
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
742
+ }
743
+ function safeStringify(obj, space) {
744
+ const seen = /* @__PURE__ */ new WeakSet();
745
+ return JSON.stringify(
746
+ obj,
747
+ (key, value) => {
748
+ if (typeof value === "object" && value !== null) {
749
+ if (seen.has(value)) {
750
+ return "[Circular]";
751
+ }
752
+ seen.add(value);
753
+ }
754
+ if (typeof value === "bigint") {
755
+ return value.toString();
756
+ }
757
+ if (value instanceof Error) {
758
+ return {
759
+ name: value.name,
760
+ message: value.message,
761
+ stack: value.stack
762
+ };
763
+ }
764
+ return value;
765
+ },
766
+ space
767
+ );
768
+ }
769
+ function deepMerge(target, source) {
770
+ const result = { ...target };
771
+ for (const key in source) {
772
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
773
+ const sourceValue = source[key];
774
+ const targetValue = result[key];
775
+ if (isObject(sourceValue) && isObject(targetValue)) {
776
+ result[key] = deepMerge(targetValue, sourceValue);
777
+ } else if (sourceValue !== void 0) {
778
+ result[key] = sourceValue;
779
+ }
780
+ }
781
+ }
782
+ return result;
783
+ }
784
+ function isObject(value) {
785
+ return value !== null && typeof value === "object" && !Array.isArray(value);
786
+ }
787
+ function sanitizePayload(payload, sensitiveFields = ["password", "token", "secret", "apiKey", "api_key", "authorization"]) {
788
+ const result = {};
789
+ for (const [key, value] of Object.entries(payload)) {
790
+ const lowerKey = key.toLowerCase();
791
+ if (sensitiveFields.some((field) => lowerKey.includes(field.toLowerCase()))) {
792
+ result[key] = "[REDACTED]";
793
+ } else if (isObject(value)) {
794
+ result[key] = sanitizePayload(value, sensitiveFields);
795
+ } else {
796
+ result[key] = value;
797
+ }
798
+ }
799
+ return result;
800
+ }
801
+ function extractFields(obj, fields) {
802
+ const result = {};
803
+ for (const field of fields) {
804
+ if (field in obj) {
805
+ result[field] = obj[field];
806
+ }
807
+ }
808
+ return result;
809
+ }
810
+ function flattenObject(obj, prefix = "") {
811
+ const result = {};
812
+ for (const [key, value] of Object.entries(obj)) {
813
+ const newKey = prefix ? `${prefix}.${key}` : key;
814
+ if (isObject(value) && Object.keys(value).length > 0) {
815
+ Object.assign(result, flattenObject(value, newKey));
816
+ } else {
817
+ result[newKey] = value;
818
+ }
819
+ }
820
+ return result;
821
+ }
822
+ async function retryWithBackoff(fn, options = {}) {
823
+ const { maxRetries = 3, initialDelay = 100, maxDelay = 5e3, factor = 2 } = options;
824
+ let lastError;
825
+ let delay = initialDelay;
826
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
827
+ try {
828
+ return await fn();
829
+ } catch (error) {
830
+ lastError = error instanceof Error ? error : new Error(String(error));
831
+ if (attempt === maxRetries) {
832
+ break;
833
+ }
834
+ await sleep(delay);
835
+ delay = Math.min(delay * factor, maxDelay);
836
+ }
837
+ }
838
+ throw lastError;
839
+ }
840
+ function sleep(ms) {
841
+ return new Promise((resolve) => setTimeout(resolve, ms));
842
+ }
843
+ function debounce(fn, delay) {
844
+ let timeoutId = null;
845
+ return (...args) => {
846
+ if (timeoutId) {
847
+ clearTimeout(timeoutId);
848
+ }
849
+ timeoutId = setTimeout(() => {
850
+ fn(...args);
851
+ timeoutId = null;
852
+ }, delay);
853
+ };
854
+ }
855
+ async function processBatch(items, processor, batchSize = 10) {
856
+ const results = [];
857
+ for (let i = 0; i < items.length; i += batchSize) {
858
+ const batch = items.slice(i, i + batchSize);
859
+ const result = await processor(batch);
860
+ results.push(result);
861
+ }
862
+ return results;
863
+ }
864
+ function createCache(defaultTtl = 6e4) {
865
+ const cache = /* @__PURE__ */ new Map();
866
+ return {
867
+ get(key) {
868
+ const entry = cache.get(key);
869
+ if (!entry) return void 0;
870
+ if (Date.now() > entry.expires) {
871
+ cache.delete(key);
872
+ return void 0;
873
+ }
874
+ return entry.value;
875
+ },
876
+ set(key, value, ttl = defaultTtl) {
877
+ cache.set(key, { value, expires: Date.now() + ttl });
878
+ },
879
+ delete(key) {
880
+ return cache.delete(key);
881
+ },
882
+ clear() {
883
+ cache.clear();
884
+ },
885
+ size() {
886
+ return cache.size;
887
+ }
888
+ };
889
+ }
890
+
891
+ // src/connectors/mixpanel.connector.ts
892
+ var MixpanelConnector = class extends BaseConnector {
893
+ constructor(config) {
894
+ super(config);
895
+ this.name = "mixpanel";
896
+ this.type = "analytics";
897
+ this.token = config.token;
898
+ this.trackFields = config.trackFields;
899
+ }
900
+ async setup() {
901
+ const Mixpanel = await import('mixpanel');
902
+ this.client = Mixpanel.init(this.token);
903
+ this.log("Mixpanel client initialized");
904
+ }
905
+ track(event) {
906
+ if (!this.client) {
907
+ this.log("Client not initialized");
908
+ return;
909
+ }
910
+ let properties = event.payload;
911
+ if (this.trackFields && this.trackFields.length > 0) {
912
+ properties = {};
913
+ this.trackFields.forEach((field) => {
914
+ if (event.payload[field] !== void 0) {
915
+ properties[field] = event.payload[field];
916
+ }
917
+ });
918
+ }
919
+ const mixpanelProps = {
920
+ ...properties,
921
+ distinct_id: event.meta?.userId,
922
+ time: event.timestamp ? new Date(event.timestamp).getTime() / 1e3 : void 0
923
+ };
924
+ this.client.track(event.name, mixpanelProps);
925
+ this.log("Event tracked", { name: event.name });
926
+ }
927
+ identify(event) {
928
+ if (!this.client) return;
929
+ this.client.people.set(event.userId, {
930
+ ...event.traits,
931
+ $last_seen: (/* @__PURE__ */ new Date()).toISOString()
932
+ });
933
+ this.log("User identified", { userId: event.userId });
934
+ }
935
+ page(event) {
936
+ this.track({
937
+ name: "Page View",
938
+ payload: { page: event.name, ...event.properties },
939
+ timestamp: event.timestamp
940
+ });
941
+ }
942
+ };
943
+ function createMixpanelConnector(config) {
944
+ return new MixpanelConnector(config);
945
+ }
946
+
947
+ // src/connectors/posthog.connector.ts
948
+ var PostHogConnector = class extends BaseConnector {
949
+ constructor(config) {
950
+ super(config);
951
+ this.name = "posthog";
952
+ this.type = "analytics";
953
+ this.apiKey = config.apiKey;
954
+ this.host = config.host || "https://app.posthog.com";
955
+ }
956
+ async setup() {
957
+ const { PostHog } = await import('posthog-node');
958
+ this.client = new PostHog(this.apiKey, { host: this.host });
959
+ this.log("PostHog client initialized");
960
+ }
961
+ track(event) {
962
+ if (!this.client) return;
963
+ this.client.capture({
964
+ distinctId: event.meta?.userId || event.payload.user_id || "anonymous",
965
+ event: event.name,
966
+ properties: event.payload,
967
+ timestamp: event.timestamp ? new Date(event.timestamp) : void 0
968
+ });
969
+ this.log("Event captured", { name: event.name });
970
+ this.client.flush().catch(() => {
971
+ });
972
+ }
973
+ identify(event) {
974
+ if (!this.client) return;
975
+ this.client.identify({
976
+ distinctId: event.userId,
977
+ properties: event.traits
978
+ });
979
+ this.log("User identified", { userId: event.userId });
980
+ }
981
+ page(event) {
982
+ this.track({
983
+ name: "$pageview",
984
+ payload: { $current_url: event.name, ...event.properties },
985
+ timestamp: event.timestamp
986
+ });
987
+ }
988
+ async shutdown() {
989
+ await this.client?.shutdown();
990
+ await super.shutdown();
991
+ }
992
+ };
993
+ function createPostHogConnector(config) {
994
+ return new PostHogConnector(config);
995
+ }
996
+
997
+ export { BaseConnector, CloudWatchEmfConnector, ConsoleConnector, MixpanelConnector, OtelConnector, PostHogConnector, TelemetryRouter, createCache, createCloudWatchEmfConnector, createConnector, createConnectorsFromConfig, createConsoleConnector, createMixpanelConnector, createOtelConnector, createPostHogConnector, createTelemetryRouter, debounce, deepMerge, detectEnvironment, extractFields, extractTraceContext, factoryRegistry, flattenObject, generateEventId, generateSessionId, generateSpanId, generateTraceId, generateTraceparent, getFactory, getRegisteredFactories, getTraceHeaders, getTraceHeadersSync, hasFactory, isObject, parseTraceparent, processBatch, registerFactory, retryWithBackoff, safeStringify, sanitizePayload, sleep, startSpan, validateConfig, withTraceContext };
998
+ //# sourceMappingURL=index.mjs.map
999
+ //# sourceMappingURL=index.mjs.map