@uniformdev/insights 20.7.1-alpha.102

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.js ADDED
@@ -0,0 +1,828 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ BackendInsightsProxyHandler: () => BackendInsightsProxyHandler,
34
+ createBackendInsightsProxyHandler: () => createBackendInsightsProxyHandler,
35
+ createInsightsPlugin: () => createInsightsPlugin,
36
+ createInsightsStorage: () => createInsightsStorage,
37
+ createMemoryStorage: () => createMemoryStorage,
38
+ enableUniformInsights: () => createInsightsPlugin
39
+ });
40
+ module.exports = __toCommonJS(src_exports);
41
+
42
+ // src/batching.ts
43
+ var import_p_limit = __toESM(require("p-limit"));
44
+ var DEFAULT_BATCH_CONFIG = {
45
+ maxBatchSize: 50,
46
+ maxBatchDelayMs: 2e3,
47
+ maxPayloadSizeBytes: 1024 * 1024,
48
+ // 1MB
49
+ maxRequestsPerSecond: 1
50
+ };
51
+ var createEventHash = (action, pageViewId, payload) => {
52
+ const payloadStr = JSON.stringify(payload);
53
+ return `${action}:${pageViewId}:${payloadStr}`;
54
+ };
55
+ var isDuplicateEvent = (deduplicationMap, hash, deduplicationWindowMs = 5 * 60 * 1e3) => {
56
+ const now = Date.now();
57
+ const existing = deduplicationMap.get(hash);
58
+ if (existing && now - existing.timestamp < deduplicationWindowMs) {
59
+ return true;
60
+ }
61
+ for (const [key, entry] of deduplicationMap.entries()) {
62
+ if (now - entry.timestamp >= deduplicationWindowMs) {
63
+ deduplicationMap.delete(key);
64
+ }
65
+ }
66
+ deduplicationMap.set(hash, { timestamp: now, hash });
67
+ return false;
68
+ };
69
+ var getEventPriority = (action) => {
70
+ switch (action) {
71
+ case "session_start":
72
+ return 3;
73
+ // Highest priority, as session start has to be the first for correct attribution in Insights
74
+ case "page_hit":
75
+ return 2;
76
+ // Medium priority, has to come right after session start for correct attribution in Insights
77
+ default:
78
+ return 1;
79
+ }
80
+ };
81
+ var sortEventsByPriority = (events) => {
82
+ return events.sort((a, b) => {
83
+ if (b.priority !== a.priority) {
84
+ return b.priority - a.priority;
85
+ }
86
+ return a.timestamp - b.timestamp;
87
+ });
88
+ };
89
+ var adjustTimestampsForOrder = (events) => {
90
+ const sortedEvents = sortEventsByPriority(events);
91
+ const baseTime = Date.now();
92
+ const timeIncrement = 100;
93
+ return sortedEvents.map((event, index) => ({
94
+ ...event.message,
95
+ timestamp: new Date(baseTime + index * timeIncrement).toISOString()
96
+ }));
97
+ };
98
+ var buildEndpointUrl = (endpoint) => {
99
+ if (endpoint.type === "api") {
100
+ const url = new URL(endpoint.host);
101
+ url.pathname = `/v0/events`;
102
+ if (endpoint.host.includes("tinybird.co")) {
103
+ url.pathname = "/v0/events";
104
+ }
105
+ url.searchParams.set("name", "events");
106
+ return url.toString();
107
+ } else {
108
+ return endpoint.path;
109
+ }
110
+ };
111
+ var sendBatchToEndpoint = async (messages, endpoint) => {
112
+ const endpointUrl = buildEndpointUrl(endpoint);
113
+ const ndjson = messages.map((msg) => JSON.stringify(msg)).join("\n");
114
+ const headers = {
115
+ "Content-Type": "application/x-ndjson"
116
+ };
117
+ if (endpoint.type === "api" && endpoint.apiKey) {
118
+ headers.Authorization = `Bearer ${endpoint.apiKey}`;
119
+ }
120
+ const response = await fetch(endpointUrl, {
121
+ method: "POST",
122
+ headers,
123
+ body: ndjson
124
+ });
125
+ if (!response.ok) {
126
+ throw new Error(`Failed to send batch: ${response.statusText}`);
127
+ }
128
+ const json = await response.json();
129
+ return json;
130
+ };
131
+ var createBatchProcessor = (config, endpoint) => {
132
+ let eventQueue = [];
133
+ let batchTimeout = null;
134
+ const limit = (0, import_p_limit.default)(config.maxRequestsPerSecond);
135
+ const processBatch = async () => {
136
+ if (eventQueue.length === 0) return;
137
+ const messages = adjustTimestampsForOrder(eventQueue);
138
+ const batches = [];
139
+ let currentBatch = [];
140
+ let currentBatchSize = 0;
141
+ for (const message of messages) {
142
+ const messageSize = JSON.stringify(message).length;
143
+ if (currentBatch.length >= config.maxBatchSize || currentBatchSize + messageSize > config.maxPayloadSizeBytes) {
144
+ if (currentBatch.length > 0) {
145
+ batches.push(currentBatch);
146
+ }
147
+ currentBatch = [message];
148
+ currentBatchSize = messageSize;
149
+ } else {
150
+ currentBatch.push(message);
151
+ currentBatchSize += messageSize;
152
+ }
153
+ }
154
+ if (currentBatch.length > 0) {
155
+ batches.push(currentBatch);
156
+ }
157
+ const sendPromises = batches.map(
158
+ (batch) => limit(async () => {
159
+ try {
160
+ await sendBatchToEndpoint(batch, endpoint);
161
+ } catch (error) {
162
+ console.warn("Failed to send batch:", error);
163
+ }
164
+ })
165
+ );
166
+ await Promise.all(sendPromises);
167
+ eventQueue = [];
168
+ batchTimeout = null;
169
+ };
170
+ const scheduleBatch = () => {
171
+ if (batchTimeout) return;
172
+ batchTimeout = setTimeout(() => {
173
+ processBatch();
174
+ }, config.maxBatchDelayMs);
175
+ };
176
+ const addEvent = (message) => {
177
+ const priority = getEventPriority(message.action);
178
+ const timestamp = new Date(message.timestamp).getTime();
179
+ eventQueue.push({ message, priority, timestamp });
180
+ if (eventQueue.length >= config.maxBatchSize) {
181
+ if (batchTimeout) {
182
+ clearTimeout(batchTimeout);
183
+ batchTimeout = null;
184
+ }
185
+ processBatch();
186
+ } else {
187
+ scheduleBatch();
188
+ }
189
+ };
190
+ const flush = () => {
191
+ if (batchTimeout) {
192
+ clearTimeout(batchTimeout);
193
+ batchTimeout = null;
194
+ }
195
+ processBatch();
196
+ };
197
+ const clear = () => {
198
+ if (batchTimeout) {
199
+ clearTimeout(batchTimeout);
200
+ batchTimeout = null;
201
+ }
202
+ eventQueue = [];
203
+ };
204
+ return { addEvent, flush, clear };
205
+ };
206
+ var createDeduplicationManager = () => {
207
+ const deduplicationMap = /* @__PURE__ */ new Map();
208
+ return {
209
+ isDuplicate: (message) => {
210
+ const hash = createEventHash(message.action, message.page_view_id, message.payload);
211
+ return isDuplicateEvent(deduplicationMap, hash);
212
+ },
213
+ clear: () => {
214
+ deduplicationMap.clear();
215
+ }
216
+ };
217
+ };
218
+
219
+ // src/utils.ts
220
+ var getWebMetadata = () => {
221
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
222
+ const locale = navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.userLanguage || navigator.language || navigator.browserLanguage || "en";
223
+ return {
224
+ "user-agent": window.navigator.userAgent,
225
+ locale,
226
+ location: timeZone,
227
+ referrer: document.referrer,
228
+ pathname: window.location.pathname,
229
+ href: window.location.href
230
+ };
231
+ };
232
+ var generateVisitorId = async () => {
233
+ return `visitor_${generalRandomId()}`;
234
+ };
235
+ var generateSessionId = async () => {
236
+ return `session_${generalRandomId()}`;
237
+ };
238
+ var generatePageId = () => {
239
+ return `page_${generalRandomId()}`;
240
+ };
241
+ var generalRandomId = () => {
242
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
243
+ const id = crypto.randomUUID();
244
+ return id.replaceAll("-", "").toLowerCase();
245
+ }
246
+ return Math.random().toString(32).substring(2);
247
+ };
248
+ var convertUniformMetadataToInsightsMetadata = (uniformMetadata) => {
249
+ return uniformMetadata ? {
250
+ composition_id: uniformMetadata.compositionId,
251
+ pm_node_path: uniformMetadata.matchedRoute,
252
+ dynamic_inputs: uniformMetadata.dynamicInputs
253
+ } : void 0;
254
+ };
255
+
256
+ // src/events/enrichment.ts
257
+ var buildEnrichmentUpdatedMessage = ({
258
+ sessionId,
259
+ visitorId,
260
+ pageId,
261
+ projectId,
262
+ enrichmentId,
263
+ key,
264
+ strength,
265
+ compositionData
266
+ }) => ({
267
+ action: "enrichment_updated",
268
+ version: "2",
269
+ session_id: sessionId,
270
+ visitor_id: visitorId,
271
+ page_view_id: pageId,
272
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
273
+ project_id: projectId,
274
+ payload: {
275
+ id: enrichmentId,
276
+ key,
277
+ strength
278
+ },
279
+ web_metadata: getWebMetadata(),
280
+ uniform: compositionData || {}
281
+ });
282
+
283
+ // src/events/goal.ts
284
+ var buildGoalConvertMessage = (sessionId, visitorId, pageId, projectId, goalId, compositionData) => ({
285
+ action: "goal_convert",
286
+ version: "2",
287
+ session_id: sessionId,
288
+ visitor_id: visitorId,
289
+ page_view_id: pageId,
290
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
291
+ project_id: projectId,
292
+ payload: {
293
+ goal_id: goalId
294
+ },
295
+ web_metadata: getWebMetadata(),
296
+ uniform: compositionData || {}
297
+ });
298
+
299
+ // src/events/page.ts
300
+ var buildPageHitMessage = (sessionId, visitorId, pageId, projectId, compositionData) => ({
301
+ action: "page_hit",
302
+ version: "2",
303
+ session_id: sessionId,
304
+ visitor_id: visitorId,
305
+ page_view_id: pageId,
306
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
307
+ project_id: projectId,
308
+ payload: {},
309
+ web_metadata: getWebMetadata(),
310
+ uniform: compositionData || {}
311
+ });
312
+
313
+ // src/events/personalization.ts
314
+ var buildPersonalizationResultMessage = (sessionId, visitorId, pageId, projectId, result, variant, compositionData) => ({
315
+ action: "personalization_result",
316
+ version: "2",
317
+ session_id: sessionId,
318
+ visitor_id: visitorId,
319
+ page_view_id: pageId,
320
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
321
+ project_id: projectId,
322
+ payload: {
323
+ name: result.name,
324
+ variantId: variant.id,
325
+ control: variant.control || result.control,
326
+ changed: result.changed
327
+ },
328
+ web_metadata: getWebMetadata(),
329
+ uniform: compositionData || {}
330
+ });
331
+
332
+ // src/events/segment.ts
333
+ var buildSegmentUpdatedMessage = ({
334
+ sessionId,
335
+ visitorId,
336
+ pageId,
337
+ projectId,
338
+ segmentId,
339
+ value,
340
+ compositionData
341
+ }) => ({
342
+ action: "segment_updated",
343
+ version: "2",
344
+ session_id: sessionId,
345
+ visitor_id: visitorId,
346
+ page_view_id: pageId,
347
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
348
+ project_id: projectId,
349
+ payload: {
350
+ id: segmentId,
351
+ value
352
+ },
353
+ web_metadata: getWebMetadata(),
354
+ uniform: compositionData || {}
355
+ });
356
+
357
+ // src/events/session.ts
358
+ var buildSessionStartMessage = (sessionId, visitorId, pageId, projectId, previousSessionId, compositionData) => ({
359
+ action: "session_start",
360
+ version: "2",
361
+ session_id: sessionId,
362
+ visitor_id: visitorId,
363
+ page_view_id: pageId,
364
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
365
+ project_id: projectId,
366
+ payload: {
367
+ previous_session_id: previousSessionId
368
+ },
369
+ web_metadata: getWebMetadata(),
370
+ uniform: compositionData || {}
371
+ });
372
+
373
+ // src/events/test.ts
374
+ var buildTestResultMessage = (sessionId, visitorId, pageId, projectId, result, compositionData) => ({
375
+ action: "test_result",
376
+ version: "2",
377
+ session_id: sessionId,
378
+ visitor_id: visitorId,
379
+ page_view_id: pageId,
380
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
381
+ project_id: projectId,
382
+ payload: {
383
+ name: result.name,
384
+ variantId: result.variantId,
385
+ control: result.control,
386
+ variantAssigned: result.variantAssigned
387
+ },
388
+ web_metadata: getWebMetadata(),
389
+ uniform: compositionData || {}
390
+ });
391
+
392
+ // src/storage.ts
393
+ var createInsightsStorage = (customStorage) => {
394
+ if (customStorage) {
395
+ return customStorage;
396
+ }
397
+ const STORAGE_KEY = "ufin";
398
+ return {
399
+ get: () => {
400
+ if (typeof localStorage === "undefined") {
401
+ return void 0;
402
+ }
403
+ const data = localStorage.getItem(STORAGE_KEY);
404
+ if (!data) {
405
+ return void 0;
406
+ }
407
+ try {
408
+ return JSON.parse(data);
409
+ } catch (e) {
410
+ return void 0;
411
+ }
412
+ },
413
+ set: (data) => {
414
+ if (typeof localStorage === "undefined") {
415
+ return;
416
+ }
417
+ const toSet = {
418
+ ...data,
419
+ updated: Date.now()
420
+ };
421
+ try {
422
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(toSet));
423
+ } catch (e) {
424
+ }
425
+ },
426
+ clear: () => {
427
+ if (typeof localStorage === "undefined") {
428
+ return;
429
+ }
430
+ try {
431
+ localStorage.removeItem(STORAGE_KEY);
432
+ } catch (e) {
433
+ }
434
+ }
435
+ };
436
+ };
437
+ var createMemoryStorage = () => {
438
+ let data;
439
+ return {
440
+ get: () => data,
441
+ set: (newData) => {
442
+ data = {
443
+ ...newData,
444
+ updated: Date.now()
445
+ };
446
+ },
447
+ clear: () => {
448
+ data = void 0;
449
+ }
450
+ };
451
+ };
452
+
453
+ // src/plugin.ts
454
+ var createInsightsCore = (options) => {
455
+ if (options.endpoint.type === "api" && !options.endpoint.host) {
456
+ throw new Error("Insights context plugin requires API host");
457
+ }
458
+ if (options.endpoint.type === "api" && !options.endpoint.apiKey) {
459
+ throw new Error("Insights context plugin requires API key");
460
+ }
461
+ if (!options.endpoint.projectId) {
462
+ throw new Error("Insights context plugin requires project ID");
463
+ }
464
+ const {
465
+ endpoint,
466
+ storage: customStorage,
467
+ batchConfig,
468
+ sessionDurationSeconds = 30 * 60,
469
+ getVisitorId = generateVisitorId,
470
+ getSessionId = generateSessionId
471
+ } = options;
472
+ const storage = createInsightsStorage(customStorage);
473
+ let storageData;
474
+ let pageId = generatePageId();
475
+ let previousUrl = void 0;
476
+ const batchProcessor = batchConfig ? createBatchProcessor({ ...DEFAULT_BATCH_CONFIG, ...batchConfig }, endpoint) : null;
477
+ const deduplicationManager = batchConfig ? createDeduplicationManager() : null;
478
+ const sendEventDirectly = async (message) => {
479
+ if (typeof window !== "undefined" && window.__UNIFORM_CONTEXTUAL_EDITING__) {
480
+ return;
481
+ }
482
+ try {
483
+ const endpointUrl = endpoint.type === "api" ? `${endpoint.host}/v0/events?name=events` : endpoint.path;
484
+ const headers = {
485
+ "Content-Type": "application/x-ndjson"
486
+ };
487
+ if (endpoint.type === "api" && endpoint.apiKey) {
488
+ headers.Authorization = `Bearer ${endpoint.apiKey}`;
489
+ }
490
+ await fetch(endpointUrl, {
491
+ method: "POST",
492
+ headers,
493
+ body: JSON.stringify(message)
494
+ });
495
+ } catch (error) {
496
+ console.warn("Failed to send event:", error);
497
+ }
498
+ };
499
+ const addEvent = (message) => {
500
+ if (typeof window !== "undefined" && window.__UNIFORM_CONTEXTUAL_EDITING__) {
501
+ return;
502
+ }
503
+ if (batchProcessor && deduplicationManager) {
504
+ if (!deduplicationManager.isDuplicate(message)) {
505
+ batchProcessor.addEvent(message);
506
+ }
507
+ } else {
508
+ sendEventDirectly(message);
509
+ }
510
+ };
511
+ return {
512
+ init: async (context) => {
513
+ storageData = storage.get();
514
+ if (!storageData || Date.now() - storageData.updated > sessionDurationSeconds * 1e3) {
515
+ const previousSessionId = storageData == null ? void 0 : storageData.sessionId;
516
+ let visitorId;
517
+ if (storageData == null ? void 0 : storageData.visitorId) {
518
+ visitorId = storageData.visitorId;
519
+ } else {
520
+ visitorId = await getVisitorId({
521
+ context,
522
+ previousVisitorId: storageData == null ? void 0 : storageData.visitorId,
523
+ previousSessionId
524
+ });
525
+ }
526
+ const sessionId = await getSessionId({ context, visitorId, previousSessionId });
527
+ const newStorageData = {
528
+ visitorId,
529
+ sessionId,
530
+ updated: Date.now()
531
+ };
532
+ storage.set(newStorageData);
533
+ storageData = newStorageData;
534
+ const message = buildSessionStartMessage(
535
+ storageData.sessionId,
536
+ storageData.visitorId,
537
+ pageId,
538
+ endpoint.projectId,
539
+ previousSessionId
540
+ );
541
+ addEvent(message);
542
+ } else if (storageData) {
543
+ storage.set(storageData);
544
+ }
545
+ },
546
+ pageHit: (compositionData) => {
547
+ if (!storageData) {
548
+ return;
549
+ }
550
+ if (typeof window !== "undefined" && previousUrl === window.location.href) {
551
+ return;
552
+ }
553
+ if (typeof window !== "undefined") {
554
+ previousUrl = window.location.href;
555
+ }
556
+ pageId = generatePageId();
557
+ const message = buildPageHitMessage(
558
+ storageData.sessionId,
559
+ storageData.visitorId,
560
+ pageId,
561
+ endpoint.projectId,
562
+ compositionData
563
+ );
564
+ addEvent(message);
565
+ },
566
+ testResult: (result, compositionData) => {
567
+ if (!storageData) {
568
+ return;
569
+ }
570
+ const message = buildTestResultMessage(
571
+ storageData.sessionId,
572
+ storageData.visitorId,
573
+ pageId,
574
+ endpoint.projectId,
575
+ result,
576
+ compositionData
577
+ );
578
+ addEvent(message);
579
+ },
580
+ personalizationResult: (result, compositionData) => {
581
+ if (!storageData) {
582
+ return;
583
+ }
584
+ result.variantIds.forEach((variant) => {
585
+ const message = buildPersonalizationResultMessage(
586
+ storageData.sessionId,
587
+ storageData.visitorId,
588
+ pageId,
589
+ endpoint.projectId,
590
+ result,
591
+ variant,
592
+ compositionData
593
+ );
594
+ addEvent(message);
595
+ });
596
+ },
597
+ goalConvert: (goalId, compositionData) => {
598
+ if (!storageData) {
599
+ return;
600
+ }
601
+ const message = buildGoalConvertMessage(
602
+ storageData.sessionId,
603
+ storageData.visitorId,
604
+ pageId,
605
+ endpoint.projectId,
606
+ goalId,
607
+ compositionData
608
+ );
609
+ addEvent(message);
610
+ },
611
+ segmentUpdated: (segmentId, value, compositionData) => {
612
+ if (!storageData) {
613
+ return;
614
+ }
615
+ const message = buildSegmentUpdatedMessage({
616
+ sessionId: storageData.sessionId,
617
+ visitorId: storageData.visitorId,
618
+ pageId,
619
+ projectId: endpoint.projectId,
620
+ segmentId,
621
+ value,
622
+ compositionData
623
+ });
624
+ addEvent(message);
625
+ },
626
+ enrichmentUpdated: (enrichmentId, key, strength, compositionData) => {
627
+ if (!storageData) {
628
+ return;
629
+ }
630
+ const message = buildEnrichmentUpdatedMessage({
631
+ sessionId: storageData.sessionId,
632
+ visitorId: storageData.visitorId,
633
+ pageId,
634
+ projectId: endpoint.projectId,
635
+ enrichmentId,
636
+ key,
637
+ strength,
638
+ compositionData
639
+ });
640
+ addEvent(message);
641
+ },
642
+ forget: () => {
643
+ storage.clear();
644
+ storageData = void 0;
645
+ deduplicationManager == null ? void 0 : deduplicationManager.clear();
646
+ batchProcessor == null ? void 0 : batchProcessor.flush();
647
+ },
648
+ get sessionId() {
649
+ return storageData == null ? void 0 : storageData.sessionId;
650
+ }
651
+ };
652
+ };
653
+ var createInsightsPlugin = (options) => {
654
+ const insights = createInsightsCore(options);
655
+ let previousUrl = void 0;
656
+ let isInitialized = false;
657
+ let eventQueue = [];
658
+ let contextInstance = void 0;
659
+ const processQueuedEvents = () => {
660
+ if (isInitialized && eventQueue.length > 0) {
661
+ eventQueue.forEach((event) => event());
662
+ eventQueue = [];
663
+ }
664
+ };
665
+ const queueEvent = (eventFn) => {
666
+ if (isInitialized) {
667
+ eventFn();
668
+ } else {
669
+ eventQueue.push(eventFn);
670
+ }
671
+ };
672
+ const previousScores = {};
673
+ const handleScoreUpdates = (updatedScores, compositionData) => {
674
+ if (!contextInstance) {
675
+ return;
676
+ }
677
+ Object.entries(updatedScores).forEach(([scoreKey, value]) => {
678
+ var _a, _b;
679
+ if (previousScores[scoreKey] === value) {
680
+ return;
681
+ }
682
+ const aggregateDimension = contextInstance.manifest.getAggregateDimensionByKey(scoreKey);
683
+ const signalDimension = (_b = (_a = contextInstance.manifest.data.project.pz) == null ? void 0 : _a.sig) == null ? void 0 : _b[scoreKey];
684
+ if (aggregateDimension || signalDimension) {
685
+ insights.segmentUpdated(scoreKey, value, compositionData);
686
+ previousScores[scoreKey] = value;
687
+ }
688
+ });
689
+ };
690
+ return {
691
+ init: (context) => {
692
+ if (typeof window === "undefined") {
693
+ return () => {
694
+ };
695
+ }
696
+ contextInstance = context;
697
+ const consentChanged = () => {
698
+ if (context.storage.data.consent) {
699
+ insights.init(context).then(() => {
700
+ isInitialized = true;
701
+ processQueuedEvents();
702
+ });
703
+ } else {
704
+ insights.forget();
705
+ isInitialized = false;
706
+ }
707
+ };
708
+ const handlePersonalizationResult = (data) => {
709
+ queueEvent(() => {
710
+ insights.personalizationResult(
711
+ data,
712
+ convertUniformMetadataToInsightsMetadata(data.compositionMetadata)
713
+ );
714
+ });
715
+ };
716
+ const handleTestResult = (result) => {
717
+ queueEvent(() => {
718
+ insights.testResult(result, convertUniformMetadataToInsightsMetadata(result.compositionMetadata));
719
+ });
720
+ };
721
+ const handleGoalConvert = (result) => {
722
+ const compositionMetadata = context.getCompositionMetadata();
723
+ queueEvent(() => {
724
+ insights.goalConvert(result.goalId, convertUniformMetadataToInsightsMetadata(compositionMetadata));
725
+ });
726
+ };
727
+ const handleCanvasDataUpdated = (data) => {
728
+ if (data) {
729
+ queueEvent(() => {
730
+ insights.pageHit(convertUniformMetadataToInsightsMetadata(data));
731
+ });
732
+ }
733
+ };
734
+ context.storage.events.on("goalConverted", handleGoalConvert);
735
+ context.storage.events.on("consentUpdated", consentChanged);
736
+ context.events.on("personalizationResult", handlePersonalizationResult);
737
+ context.events.on("testResult", handleTestResult);
738
+ context.events.on("canvasDataUpdated", handleCanvasDataUpdated);
739
+ if (context.storage.data.consent) {
740
+ consentChanged();
741
+ }
742
+ return () => {
743
+ context.storage.events.off("consentUpdated", consentChanged);
744
+ context.storage.events.off("goalConverted", handleGoalConvert);
745
+ context.events.off("personalizationResult", handlePersonalizationResult);
746
+ context.events.off("testResult", handleTestResult);
747
+ context.events.off("canvasDataUpdated", handleCanvasDataUpdated);
748
+ };
749
+ },
750
+ update: (updatedData, recalculatedScores) => {
751
+ var _a;
752
+ const compositionMetadata = convertUniformMetadataToInsightsMetadata(
753
+ (_a = updatedData.compositionMetadata) != null ? _a : contextInstance == null ? void 0 : contextInstance.getCompositionMetadata()
754
+ );
755
+ if (updatedData.url && updatedData.url.toString() !== previousUrl) {
756
+ previousUrl = updatedData.url.toString();
757
+ queueEvent(() => {
758
+ insights.pageHit(compositionMetadata);
759
+ });
760
+ }
761
+ if (updatedData.enrichments && updatedData.enrichments.length > 0) {
762
+ queueEvent(() => {
763
+ updatedData.enrichments.forEach((enrichmentData) => {
764
+ insights.enrichmentUpdated(
765
+ enrichmentData.cat,
766
+ enrichmentData.key,
767
+ enrichmentData.str,
768
+ compositionMetadata
769
+ );
770
+ });
771
+ });
772
+ }
773
+ if (recalculatedScores) {
774
+ queueEvent(() => {
775
+ handleScoreUpdates(recalculatedScores, compositionMetadata);
776
+ });
777
+ }
778
+ },
779
+ forget: () => {
780
+ insights.forget();
781
+ isInitialized = false;
782
+ eventQueue = [];
783
+ }
784
+ };
785
+ };
786
+
787
+ // src/proxy.ts
788
+ var BackendInsightsProxyHandler = class {
789
+ constructor(config) {
790
+ this.config = config;
791
+ }
792
+ /**
793
+ * Handle a proxy request with only the body payload
794
+ * @param body - The request body to forward
795
+ * @returns Promise resolving to the API response
796
+ */
797
+ async handleRequest(originalBody) {
798
+ try {
799
+ const targetUrl = new URL("/v0/events", this.config.apiHost);
800
+ targetUrl.searchParams.set("name", "events");
801
+ return fetch(targetUrl.toString(), {
802
+ method: "POST",
803
+ headers: {
804
+ Authorization: `Bearer ${this.config.apiKey}`,
805
+ "Content-Type": "application/x-ndjson",
806
+ Accept: "application/json"
807
+ },
808
+ body: originalBody
809
+ });
810
+ } catch (error) {
811
+ throw new Error(
812
+ `Backend proxy request failed: ${error instanceof Error ? error.message : "Unknown error"}`
813
+ );
814
+ }
815
+ }
816
+ };
817
+ function createBackendInsightsProxyHandler(config) {
818
+ return new BackendInsightsProxyHandler(config);
819
+ }
820
+ // Annotate the CommonJS export names for ESM import in node:
821
+ 0 && (module.exports = {
822
+ BackendInsightsProxyHandler,
823
+ createBackendInsightsProxyHandler,
824
+ createInsightsPlugin,
825
+ createInsightsStorage,
826
+ createMemoryStorage,
827
+ enableUniformInsights
828
+ });