@absmartly/sdk-plugins 1.1.2 → 1.2.2
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/absmartly-cookie.min.js +1 -1
- package/dist/absmartly-dom-changes-core.min.js +1 -1
- package/dist/absmartly-dom-changes-lite.min.js +1 -1
- package/dist/absmartly-overrides-full.min.js +1 -1
- package/dist/absmartly-overrides-lite.min.js +1 -1
- package/dist/absmartly-sdk-plugins.min.js +1 -1
- package/dist/absmartly-vitals.min.js +1 -1
- package/es/cookies/cookieUtils.js +2 -1
- package/es/cookies/cookieUtils.js.map +1 -1
- package/es/core/DOMChangesPluginLite.js +195 -221
- package/es/core/DOMChangesPluginLite.js.map +1 -1
- package/es/core/DOMManipulatorLite.js +76 -10
- package/es/core/DOMManipulatorLite.js.map +1 -1
- package/es/core/ExposureTracker.js +136 -11
- package/es/core/ExposureTracker.js.map +1 -1
- package/es/core/PendingChangeManager.js +14 -14
- package/es/core/PendingChangeManager.js.map +1 -1
- package/es/entries/dom-with-overrides-lite.js +3 -0
- package/es/entries/dom-with-overrides-lite.js.map +1 -1
- package/es/generated/buildInfo.js +3 -0
- package/es/generated/buildInfo.js.map +1 -0
- package/es/index.js +9 -2
- package/es/index.js.map +1 -1
- package/es/overrides/OverridesPlugin.js +2 -2
- package/es/overrides/OverridesPlugin.js.map +1 -1
- package/es/overrides/OverridesPluginLite.js +29 -1
- package/es/overrides/OverridesPluginLite.js.map +1 -1
- package/es/overrides/overridesUtils.js +27 -18
- package/es/overrides/overridesUtils.js.map +1 -1
- package/es/parsers/VariantExtractor.js +14 -7
- package/es/parsers/VariantExtractor.js.map +1 -1
- package/es/url-redirect/URLRedirectExtractor.js +185 -0
- package/es/url-redirect/URLRedirectExtractor.js.map +1 -0
- package/es/url-redirect/URLRedirectMatcher.js +116 -0
- package/es/url-redirect/URLRedirectMatcher.js.map +1 -0
- package/es/url-redirect/URLRedirectPlugin.js +351 -0
- package/es/url-redirect/URLRedirectPlugin.js.map +1 -0
- package/es/url-redirect/index.js +5 -0
- package/es/url-redirect/index.js.map +1 -0
- package/es/url-redirect/types.js +2 -0
- package/es/url-redirect/types.js.map +1 -0
- package/es/utils/URLMatcher.js +4 -3
- package/es/utils/URLMatcher.js.map +1 -1
- package/es/utils/debug.js +4 -3
- package/es/utils/debug.js.map +1 -1
- package/es/utils/persistence.js +278 -0
- package/es/utils/persistence.js.map +1 -0
- package/es/utils/plugin-registry.js +47 -0
- package/es/utils/plugin-registry.js.map +1 -0
- package/lib/cookies/cookieUtils.d.ts +0 -4
- package/lib/cookies/cookieUtils.js +6 -5
- package/lib/cookies/cookieUtils.js.map +1 -1
- package/lib/core/DOMChangesPluginLite.d.ts +10 -7
- package/lib/core/DOMChangesPluginLite.js +195 -221
- package/lib/core/DOMChangesPluginLite.js.map +1 -1
- package/lib/core/DOMManipulatorLite.js +76 -10
- package/lib/core/DOMManipulatorLite.js.map +1 -1
- package/lib/core/ExposureTracker.d.ts +6 -0
- package/lib/core/ExposureTracker.js +136 -11
- package/lib/core/ExposureTracker.js.map +1 -1
- package/lib/core/PendingChangeManager.d.ts +0 -1
- package/lib/core/PendingChangeManager.js +14 -14
- package/lib/core/PendingChangeManager.js.map +1 -1
- package/lib/entries/dom-with-overrides-lite.d.ts +2 -0
- package/lib/entries/dom-with-overrides-lite.js +3 -1
- package/lib/entries/dom-with-overrides-lite.js.map +1 -1
- package/lib/generated/buildInfo.d.ts +2 -0
- package/lib/generated/buildInfo.js +6 -0
- package/lib/generated/buildInfo.js.map +1 -0
- package/lib/index.d.ts +8 -2
- package/lib/index.js +17 -1
- package/lib/index.js.map +1 -1
- package/lib/overrides/OverridesPlugin.js +2 -2
- package/lib/overrides/OverridesPlugin.js.map +1 -1
- package/lib/overrides/OverridesPluginLite.d.ts +8 -0
- package/lib/overrides/OverridesPluginLite.js +29 -1
- package/lib/overrides/OverridesPluginLite.js.map +1 -1
- package/lib/overrides/overridesUtils.d.ts +10 -5
- package/lib/overrides/overridesUtils.js +28 -18
- package/lib/overrides/overridesUtils.js.map +1 -1
- package/lib/parsers/VariantExtractor.js +14 -7
- package/lib/parsers/VariantExtractor.js.map +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/url-redirect/URLRedirectExtractor.d.ts +16 -0
- package/lib/url-redirect/URLRedirectExtractor.js +188 -0
- package/lib/url-redirect/URLRedirectExtractor.js.map +1 -0
- package/lib/url-redirect/URLRedirectMatcher.d.ts +8 -0
- package/lib/url-redirect/URLRedirectMatcher.js +119 -0
- package/lib/url-redirect/URLRedirectMatcher.js.map +1 -0
- package/lib/url-redirect/URLRedirectPlugin.d.ts +21 -0
- package/lib/url-redirect/URLRedirectPlugin.js +354 -0
- package/lib/url-redirect/URLRedirectPlugin.js.map +1 -0
- package/lib/url-redirect/index.d.ts +4 -0
- package/lib/url-redirect/index.js +25 -0
- package/lib/url-redirect/index.js.map +1 -0
- package/lib/url-redirect/types.d.ts +29 -0
- package/lib/url-redirect/types.js +3 -0
- package/lib/url-redirect/types.js.map +1 -0
- package/lib/utils/URLMatcher.js +4 -3
- package/lib/utils/URLMatcher.js.map +1 -1
- package/lib/utils/debug.d.ts +1 -1
- package/lib/utils/debug.js +4 -3
- package/lib/utils/debug.js.map +1 -1
- package/lib/utils/persistence.d.ts +23 -0
- package/lib/utils/persistence.js +281 -0
- package/lib/utils/persistence.js.map +1 -0
- package/lib/utils/plugin-registry.d.ts +40 -0
- package/lib/utils/plugin-registry.js +53 -0
- package/lib/utils/plugin-registry.js.map +1 -0
- package/package.json +64 -6
- package/types/cookies/cookieUtils.d.ts +0 -4
- package/types/core/DOMChangesPluginLite.d.ts +10 -7
- package/types/core/ExposureTracker.d.ts +6 -0
- package/types/core/PendingChangeManager.d.ts +0 -1
- package/types/entries/dom-with-overrides-lite.d.ts +2 -0
- package/types/generated/buildInfo.d.ts +2 -0
- package/types/index.d.ts +8 -2
- package/types/overrides/OverridesPluginLite.d.ts +8 -0
- package/types/overrides/overridesUtils.d.ts +10 -5
- package/types/types/index.d.ts +1 -0
- package/types/url-redirect/URLRedirectExtractor.d.ts +16 -0
- package/types/url-redirect/URLRedirectMatcher.d.ts +8 -0
- package/types/url-redirect/URLRedirectPlugin.d.ts +21 -0
- package/types/url-redirect/index.d.ts +4 -0
- package/types/url-redirect/types.d.ts +29 -0
- package/types/utils/debug.d.ts +1 -1
- package/types/utils/persistence.d.ts +23 -0
- package/types/utils/plugin-registry.d.ts +40 -0
|
@@ -82,6 +82,9 @@ var ExposureTracker_1 = require("./ExposureTracker");
|
|
|
82
82
|
var HTMLInjector_1 = require("./HTMLInjector");
|
|
83
83
|
var debug_1 = require("../utils/debug");
|
|
84
84
|
var URLMatcher_1 = require("../utils/URLMatcher");
|
|
85
|
+
var persistence_1 = require("../utils/persistence");
|
|
86
|
+
var plugin_registry_1 = require("../utils/plugin-registry");
|
|
87
|
+
var buildInfo_1 = require("../generated/buildInfo");
|
|
85
88
|
var DOMChangesPluginLite = /** @class */ (function () {
|
|
86
89
|
function DOMChangesPluginLite(config) {
|
|
87
90
|
var _this = this;
|
|
@@ -91,11 +94,7 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
91
94
|
this.eventListeners = new Map();
|
|
92
95
|
this.styleManagers = new Map();
|
|
93
96
|
this.initialized = false;
|
|
94
|
-
this.
|
|
95
|
-
this.persistenceObserver = null;
|
|
96
|
-
this.reapplyingElements = new Set();
|
|
97
|
-
this.reapplyLogThrottle = new Map();
|
|
98
|
-
this.appliedChanges = new Map();
|
|
97
|
+
this.persistenceManager = null;
|
|
99
98
|
this.antiFlickerTimeout = null;
|
|
100
99
|
this.antiFlickerStyleId = 'absmartly-antiflicker';
|
|
101
100
|
this.config = {
|
|
@@ -120,6 +119,17 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
120
119
|
this.variantExtractor = new VariantExtractor_1.VariantExtractor(this.config.context, this.config.variableName, this.config.debug);
|
|
121
120
|
this.exposureTracker = new ExposureTracker_1.ExposureTracker(this.config.context, this.config.debug);
|
|
122
121
|
this.htmlInjector = new HTMLInjector_1.HTMLInjector(this.config.debug);
|
|
122
|
+
this.persistenceManager = new persistence_1.DOMPersistenceManager({
|
|
123
|
+
debug: this.config.debug,
|
|
124
|
+
onReapply: function (change, experimentName) {
|
|
125
|
+
(0, debug_1.logDebug)('[DOMChangesPluginLite] Re-applying change due to mutation', {
|
|
126
|
+
experimentName: experimentName,
|
|
127
|
+
selector: change.selector,
|
|
128
|
+
type: change.type,
|
|
129
|
+
});
|
|
130
|
+
_this.domManipulator.applyChange(change, experimentName);
|
|
131
|
+
},
|
|
132
|
+
});
|
|
123
133
|
// Auto-initialize when context is ready
|
|
124
134
|
this.readyPromise = this.config.context
|
|
125
135
|
.ready()
|
|
@@ -163,9 +173,14 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
163
173
|
case 1:
|
|
164
174
|
_a.trys.push([1, 4, , 5]);
|
|
165
175
|
if (this.config.spa) {
|
|
176
|
+
// SPA mode: observe body for React/Vue hydration recovery
|
|
177
|
+
// and listen for URL changes to re-apply changes on navigation
|
|
166
178
|
this.setupMutationObserver();
|
|
167
179
|
this.setupURLChangeListener();
|
|
168
180
|
}
|
|
181
|
+
else {
|
|
182
|
+
(0, debug_1.logDebug)('[DOMChangesPluginLite] SPA mode disabled - skipping body observer');
|
|
183
|
+
}
|
|
169
184
|
if (!this.config.autoApply) return [3 /*break*/, 3];
|
|
170
185
|
// Apply HTML injections and DOM changes in parallel to minimize flickering
|
|
171
186
|
return [4 /*yield*/, this.applyInjectionsAndChanges()];
|
|
@@ -176,6 +191,7 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
176
191
|
case 3:
|
|
177
192
|
this.initialized = true;
|
|
178
193
|
this.registerWithContext();
|
|
194
|
+
this.registerGlobally();
|
|
179
195
|
this.emit('initialized');
|
|
180
196
|
duration = performance.now() - startTime;
|
|
181
197
|
(0, debug_1.logPerformance)('Plugin initialization', duration);
|
|
@@ -201,10 +217,12 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
201
217
|
if (mutation.type === 'childList') {
|
|
202
218
|
// Check if any added nodes match our applied change selectors
|
|
203
219
|
mutation.addedNodes.forEach(function (node) {
|
|
220
|
+
var _a;
|
|
204
221
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
205
222
|
var element_1 = node;
|
|
206
223
|
// Check all experiments with applied changes (not just style changes)
|
|
207
|
-
_this.
|
|
224
|
+
var appliedChanges = ((_a = _this.persistenceManager) === null || _a === void 0 ? void 0 : _a.getAppliedChanges()) || new Map();
|
|
225
|
+
appliedChanges.forEach(function (changes, experimentName) {
|
|
208
226
|
changes.forEach(function (change) {
|
|
209
227
|
try {
|
|
210
228
|
// Check if this new element or any of its descendants match the selector
|
|
@@ -234,11 +252,30 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
234
252
|
}
|
|
235
253
|
});
|
|
236
254
|
});
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
255
|
+
// Wait for document.body to exist before observing
|
|
256
|
+
// This prevents "parameter 1 is not of type 'Node'" errors when SDK loads in <head>
|
|
257
|
+
var startObserving = function () {
|
|
258
|
+
observer.observe(document.body, {
|
|
259
|
+
childList: true,
|
|
260
|
+
subtree: true,
|
|
261
|
+
});
|
|
262
|
+
_this.mutationObserver = observer;
|
|
263
|
+
(0, debug_1.logDebug)('[DOMChangesPluginLite] MutationObserver started on document.body');
|
|
264
|
+
};
|
|
265
|
+
if (document.body) {
|
|
266
|
+
startObserving();
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// Use MutationObserver on documentElement to detect when body is added
|
|
270
|
+
var bodyObserver = new MutationObserver(function (_mutations, obs) {
|
|
271
|
+
if (document.body) {
|
|
272
|
+
obs.disconnect();
|
|
273
|
+
startObserving();
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
bodyObserver.observe(document.documentElement, { childList: true });
|
|
277
|
+
(0, debug_1.logDebug)('[DOMChangesPluginLite] Waiting for document.body...');
|
|
278
|
+
}
|
|
242
279
|
};
|
|
243
280
|
/**
|
|
244
281
|
* Set up URL change listener for SPA mode
|
|
@@ -305,7 +342,9 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
305
342
|
// The stylesheets will be reused or cleared on next applyChanges
|
|
306
343
|
this.styleManagers.clear();
|
|
307
344
|
// Clear applied changes
|
|
308
|
-
this.
|
|
345
|
+
if (this.persistenceManager) {
|
|
346
|
+
this.persistenceManager.clearAll();
|
|
347
|
+
}
|
|
309
348
|
// Clear HTML injections
|
|
310
349
|
this.htmlInjector.destroy();
|
|
311
350
|
// Clear variant extractor cache to force re-extraction
|
|
@@ -422,22 +461,46 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
422
461
|
allExperiments = this.getAllExperimentsData();
|
|
423
462
|
totalApplied = 0;
|
|
424
463
|
experimentStats = new Map();
|
|
425
|
-
(0, debug_1.logDebug)('[
|
|
426
|
-
|
|
464
|
+
(0, debug_1.logDebug)('[APPLY-CHANGES] Experiments found with DOM changes:', {
|
|
465
|
+
experimentNames: Array.from(allExperiments.keys()),
|
|
466
|
+
totalCount: allExperiments.size,
|
|
467
|
+
currentURL: currentURL,
|
|
468
|
+
});
|
|
469
|
+
if (allExperiments.size === 0) {
|
|
470
|
+
(0, debug_1.logDebug)('[APPLY-CHANGES] ⚠️ No experiments found with DOM changes - nothing to process');
|
|
471
|
+
}
|
|
427
472
|
try {
|
|
428
473
|
for (allExperiments_1 = __values(allExperiments), allExperiments_1_1 = allExperiments_1.next(); !allExperiments_1_1.done; allExperiments_1_1 = allExperiments_1.next()) {
|
|
429
474
|
_a = __read(allExperiments_1_1.value, 2), expName = _a[0], experimentData = _a[1];
|
|
475
|
+
(0, debug_1.logDebug)("[APPLY-CHANGES] [".concat(expName, "] Starting to process experiment"), {
|
|
476
|
+
experimentName: expName,
|
|
477
|
+
currentURL: currentURL,
|
|
478
|
+
});
|
|
430
479
|
// Skip if filtering by specific experiment
|
|
431
480
|
if (experimentName && expName !== experimentName) {
|
|
481
|
+
(0, debug_1.logDebug)("[APPLY-CHANGES] [".concat(expName, "] \u23ED\uFE0F Skipping - filtering for different experiment"), {
|
|
482
|
+
filteringFor: experimentName,
|
|
483
|
+
});
|
|
432
484
|
continue;
|
|
433
485
|
}
|
|
434
486
|
currentVariant = this.config.context.peek(expName);
|
|
487
|
+
if (currentVariant === undefined || currentVariant === null) {
|
|
488
|
+
(0, debug_1.logDebug)("[APPLY-CHANGES] [".concat(expName, "] \u23ED\uFE0F Skipping - no variant assigned (peek returned ").concat(currentVariant, ")"), {
|
|
489
|
+
experimentName: expName,
|
|
490
|
+
});
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
(0, debug_1.logDebug)("[APPLY-CHANGES] [".concat(expName, "] User assigned to variant ").concat(currentVariant));
|
|
435
494
|
variantData = experimentData.variantData, urlFilter = experimentData.urlFilter, globalDefaults = experimentData.globalDefaults;
|
|
436
495
|
anyVariantMatchesURL = this.variantExtractor.anyVariantMatchesURL(expName, currentURL);
|
|
437
496
|
if (!anyVariantMatchesURL) {
|
|
438
|
-
(0, debug_1.logDebug)("[
|
|
497
|
+
(0, debug_1.logDebug)("[APPLY-CHANGES] [".concat(expName, "] \u23ED\uFE0F Skipping - no variant matches URL: ").concat(currentURL), {
|
|
498
|
+
experimentName: expName,
|
|
499
|
+
currentURL: currentURL,
|
|
500
|
+
});
|
|
439
501
|
continue;
|
|
440
502
|
}
|
|
503
|
+
(0, debug_1.logDebug)("[APPLY-CHANGES] [".concat(expName, "] \u2713 At least one variant matches current URL"));
|
|
441
504
|
shouldApplyVisualChanges = this.shouldApplyVisualChanges(variantData, urlFilter, currentURL);
|
|
442
505
|
changes = this.extractChangesFromData(variantData, globalDefaults);
|
|
443
506
|
allVariantChanges = this.extractAllVariantChanges(expName);
|
|
@@ -451,7 +514,9 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
451
514
|
}
|
|
452
515
|
stats = { total: (changes === null || changes === void 0 ? void 0 : changes.length) || 0, success: 0, pending: 0 };
|
|
453
516
|
if (this.config.debug) {
|
|
454
|
-
(0, debug_1.logDebug)("[ABsmartly] Processing experiment '".concat(expName, "'
|
|
517
|
+
(0, debug_1.logDebug)("[ABsmartly] Processing experiment '".concat(expName, "' - User is in variant ").concat(currentVariant, ":"), {
|
|
518
|
+
experimentName: expName,
|
|
519
|
+
userVariant: currentVariant,
|
|
455
520
|
urlMatches: shouldApplyVisualChanges,
|
|
456
521
|
changeCount: (changes === null || changes === void 0 ? void 0 : changes.length) || 0,
|
|
457
522
|
userVariantHasChanges: ((changes === null || changes === void 0 ? void 0 : changes.length) || 0) > 0,
|
|
@@ -462,11 +527,28 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
462
527
|
}); })) || [],
|
|
463
528
|
});
|
|
464
529
|
}
|
|
530
|
+
// Log if user is in control variant (no changes)
|
|
531
|
+
if (!changes || changes.length === 0) {
|
|
532
|
+
if (this.config.debug) {
|
|
533
|
+
(0, debug_1.logDebug)("[ABsmartly] User is in control variant ".concat(currentVariant, " with no changes, but will still track for SRM prevention"), {
|
|
534
|
+
experimentName: expName,
|
|
535
|
+
currentVariant: currentVariant,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
465
539
|
// Apply visual changes only if URL matches for user's variant AND user has changes
|
|
466
540
|
if (shouldApplyVisualChanges && changes && changes.length > 0) {
|
|
467
541
|
try {
|
|
468
542
|
for (changes_1 = (e_2 = void 0, __values(changes)), changes_1_1 = changes_1.next(); !changes_1_1.done; changes_1_1 = changes_1.next()) {
|
|
469
543
|
change = changes_1_1.value;
|
|
544
|
+
// Skip delete changes with viewport triggers - they must be applied AFTER exposure
|
|
545
|
+
// Otherwise the element is removed before it can be observed
|
|
546
|
+
if (change.type === 'delete' && change.trigger_on_view) {
|
|
547
|
+
if (this.config.debug) {
|
|
548
|
+
(0, debug_1.logDebug)("[ABsmartly] Deferring delete change until after viewport trigger for '".concat(expName, "'"), { selector: change.selector });
|
|
549
|
+
}
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
470
552
|
success = this.domManipulator.applyChange(change, expName);
|
|
471
553
|
if (success) {
|
|
472
554
|
totalApplied++;
|
|
@@ -584,14 +666,41 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
584
666
|
finally { if (e_3) throw e_3.error; }
|
|
585
667
|
}
|
|
586
668
|
if (this.config.debug) {
|
|
587
|
-
(0, debug_1.logDebug)("[
|
|
669
|
+
(0, debug_1.logDebug)("[TRIGGER-DETECTION] [".concat(expName, "] Final trigger decision for '").concat(expName, "':"), {
|
|
670
|
+
experimentName: expName,
|
|
671
|
+
userVariant: currentVariant,
|
|
672
|
+
hasImmediateTrigger: hasAnyImmediateTriggerInAnyVariant,
|
|
673
|
+
hasViewportTrigger: hasAnyViewportTriggerInAnyVariant,
|
|
674
|
+
willRegisterExperiment: hasAnyViewportTriggerInAnyVariant || hasAnyImmediateTriggerInAnyVariant,
|
|
675
|
+
userChangesCount: (changes === null || changes === void 0 ? void 0 : changes.length) || 0,
|
|
676
|
+
allVariantsChangesCount: allVariantChanges.map(function (vc) { return vc.length; }),
|
|
677
|
+
});
|
|
588
678
|
}
|
|
589
679
|
// CRITICAL: Always register experiment for tracking if ANY variant has ANY trigger type
|
|
590
680
|
// This prevents SRM even when user's variant doesn't match URL filter
|
|
591
681
|
// Pass the URL-filtered trigger flags to ExposureTracker
|
|
592
682
|
if (hasAnyViewportTriggerInAnyVariant || hasAnyImmediateTriggerInAnyVariant) {
|
|
683
|
+
(0, debug_1.logDebug)("[TRIGGER-DETECTION] [".concat(expName, "] \u2713 REGISTERING EXPERIMENT - Calling exposureTracker.registerExperiment()"), {
|
|
684
|
+
experimentName: expName,
|
|
685
|
+
userVariant: currentVariant,
|
|
686
|
+
hasImmediateTrigger: hasAnyImmediateTriggerInAnyVariant,
|
|
687
|
+
hasViewportTrigger: hasAnyViewportTriggerInAnyVariant,
|
|
688
|
+
changesForUser: (changes === null || changes === void 0 ? void 0 : changes.length) || 0,
|
|
689
|
+
allVariantCounts: allVariantChanges.map(function (vc, idx) { return ({
|
|
690
|
+
variant: idx,
|
|
691
|
+
count: vc.length,
|
|
692
|
+
}); }),
|
|
693
|
+
});
|
|
593
694
|
this.exposureTracker.registerExperiment(expName, currentVariant || 0, changes || [], allVariantChanges, hasAnyImmediateTriggerInAnyVariant, hasAnyViewportTriggerInAnyVariant);
|
|
594
695
|
}
|
|
696
|
+
else {
|
|
697
|
+
(0, debug_1.logDebug)("[TRIGGER-DETECTION] [".concat(expName, "] \u26A0\uFE0F No triggers detected - experiment will NOT be registered!"), {
|
|
698
|
+
experimentName: expName,
|
|
699
|
+
userVariant: currentVariant,
|
|
700
|
+
hasAnyChangesInAnyVariant: hasAnyChangesInAnyVariant,
|
|
701
|
+
allVariantsChangesCount: allVariantChanges.map(function (vc) { return vc.length; }),
|
|
702
|
+
});
|
|
703
|
+
}
|
|
595
704
|
// Note: We do NOT call treatment() here anymore to avoid duplicate calls.
|
|
596
705
|
// The ExposureTracker.registerExperiment() will call triggerExposure() internally
|
|
597
706
|
// when hasImmediateTrigger is true (see ExposureTracker line 169-174).
|
|
@@ -634,6 +743,7 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
634
743
|
if (this.config.hideUntilReady) {
|
|
635
744
|
this.showContent();
|
|
636
745
|
}
|
|
746
|
+
(0, debug_1.logDebug)('[ABsmartly] DOM changes applied');
|
|
637
747
|
this.emit('changes-applied', { count: totalApplied, experimentName: experimentName });
|
|
638
748
|
return [2 /*return*/];
|
|
639
749
|
}
|
|
@@ -647,18 +757,43 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
647
757
|
var e_5, _a;
|
|
648
758
|
var experiments = new Map();
|
|
649
759
|
var allVariants = this.variantExtractor.extractAllChanges();
|
|
760
|
+
(0, debug_1.logDebug)('[GET-EXPERIMENTS] Extracting experiment data from context', {
|
|
761
|
+
experimentsWithChanges: Array.from(allVariants.keys()),
|
|
762
|
+
totalCount: allVariants.size,
|
|
763
|
+
});
|
|
650
764
|
try {
|
|
651
765
|
for (var allVariants_1 = __values(allVariants), allVariants_1_1 = allVariants_1.next(); !allVariants_1_1.done; allVariants_1_1 = allVariants_1.next()) {
|
|
652
766
|
var _b = __read(allVariants_1_1.value, 1), expName = _b[0];
|
|
653
767
|
var currentVariant = this.config.context.peek(expName);
|
|
768
|
+
(0, debug_1.logDebug)("[GET-EXPERIMENTS] [".concat(expName, "] Checking experiment"), {
|
|
769
|
+
experimentName: expName,
|
|
770
|
+
currentVariant: currentVariant,
|
|
771
|
+
variantIsValid: currentVariant !== undefined && currentVariant !== null,
|
|
772
|
+
});
|
|
654
773
|
if (currentVariant === undefined || currentVariant === null) {
|
|
774
|
+
(0, debug_1.logDebug)("[GET-EXPERIMENTS] [".concat(expName, "] \u23ED\uFE0F Skipping - context.peek() returned ").concat(currentVariant));
|
|
655
775
|
continue;
|
|
656
776
|
}
|
|
657
777
|
var variantsData = this.variantExtractor.getAllVariantsData(expName);
|
|
658
778
|
var variantData = variantsData.get(currentVariant);
|
|
779
|
+
if (this.config.debug) {
|
|
780
|
+
(0, debug_1.logDebug)("[GET-EXPERIMENTS] [".concat(expName, "] Variant data lookup:"), {
|
|
781
|
+
experimentName: expName,
|
|
782
|
+
userVariant: currentVariant,
|
|
783
|
+
variantDataExists: !!variantData,
|
|
784
|
+
allVariantsInMap: Array.from(variantsData.keys()),
|
|
785
|
+
userVariantInMap: variantsData.has(currentVariant),
|
|
786
|
+
});
|
|
787
|
+
}
|
|
659
788
|
if (!variantData) {
|
|
660
|
-
|
|
789
|
+
(0, debug_1.logDebug)("[GET-EXPERIMENTS] [".concat(expName, "] \u26A0\uFE0F User's variant ").concat(currentVariant, " has no DOM changes (control variant)"), {
|
|
790
|
+
availableVariants: Array.from(variantsData.keys()),
|
|
791
|
+
note: 'Will still track for SRM prevention',
|
|
792
|
+
});
|
|
793
|
+
// Don't skip! Include experiments even if user's variant has no changes
|
|
794
|
+
// This is critical for SRM prevention - we need to track ALL experiments
|
|
661
795
|
}
|
|
796
|
+
(0, debug_1.logDebug)("[GET-EXPERIMENTS] [".concat(expName, "] \u2713 Including experiment (variant ").concat(currentVariant, ")"));
|
|
662
797
|
// Extract URL filter and global defaults if using wrapped format
|
|
663
798
|
var urlFilter = null;
|
|
664
799
|
var globalDefaults = {};
|
|
@@ -691,12 +826,15 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
691
826
|
* Extract changes from DOMChangesData and apply global defaults
|
|
692
827
|
*/
|
|
693
828
|
DOMChangesPluginLite.prototype.extractChangesFromData = function (data, globalDefaults) {
|
|
829
|
+
if (!data) {
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
694
832
|
var changes = null;
|
|
695
833
|
// Extract changes array
|
|
696
834
|
if (Array.isArray(data)) {
|
|
697
835
|
changes = data;
|
|
698
836
|
}
|
|
699
|
-
else if (
|
|
837
|
+
else if (typeof data === 'object' && 'changes' in data) {
|
|
700
838
|
changes = data.changes;
|
|
701
839
|
}
|
|
702
840
|
if (!changes || changes.length === 0) {
|
|
@@ -753,6 +891,10 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
753
891
|
* Determine if visual changes should be applied based on URL filter
|
|
754
892
|
*/
|
|
755
893
|
DOMChangesPluginLite.prototype.shouldApplyVisualChanges = function (variantData, urlFilter, url) {
|
|
894
|
+
// No data for this variant - no changes to apply
|
|
895
|
+
if (!variantData) {
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
756
898
|
// Legacy array format has no URL filter - always apply
|
|
757
899
|
if (Array.isArray(variantData)) {
|
|
758
900
|
return true;
|
|
@@ -886,9 +1028,9 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
886
1028
|
this.mutationObserver.disconnect();
|
|
887
1029
|
this.mutationObserver = null;
|
|
888
1030
|
}
|
|
889
|
-
if (this.
|
|
890
|
-
this.
|
|
891
|
-
this.
|
|
1031
|
+
if (this.persistenceManager) {
|
|
1032
|
+
this.persistenceManager.destroy();
|
|
1033
|
+
this.persistenceManager = null;
|
|
892
1034
|
}
|
|
893
1035
|
// Clean up anti-flicker timeout and style
|
|
894
1036
|
if (this.antiFlickerTimeout !== null) {
|
|
@@ -901,11 +1043,8 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
901
1043
|
}
|
|
902
1044
|
this.eventListeners.clear();
|
|
903
1045
|
this.exposedExperiments.clear();
|
|
904
|
-
this.watchedElements = new WeakMap();
|
|
905
|
-
this.appliedChanges.clear();
|
|
906
|
-
this.reapplyingElements.clear();
|
|
907
|
-
this.reapplyLogThrottle.clear();
|
|
908
1046
|
this.unregisterFromContext();
|
|
1047
|
+
this.unregisterGlobally();
|
|
909
1048
|
this.initialized = false;
|
|
910
1049
|
if (this.config.debug) {
|
|
911
1050
|
(0, debug_1.logDebug)('[ABsmartly] DOM Changes Plugin Lite destroyed');
|
|
@@ -944,6 +1083,31 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
944
1083
|
}
|
|
945
1084
|
}
|
|
946
1085
|
};
|
|
1086
|
+
/**
|
|
1087
|
+
* Register plugin in global registry for detection
|
|
1088
|
+
*/
|
|
1089
|
+
DOMChangesPluginLite.prototype.registerGlobally = function () {
|
|
1090
|
+
(0, plugin_registry_1.registerPlugin)('dom', {
|
|
1091
|
+
name: 'DOMChangesPluginLite',
|
|
1092
|
+
version: DOMChangesPluginLite.VERSION,
|
|
1093
|
+
initialized: true,
|
|
1094
|
+
timestamp: Date.now(),
|
|
1095
|
+
capabilities: ['spa', 'visibility', 'auto-apply'],
|
|
1096
|
+
instance: this,
|
|
1097
|
+
});
|
|
1098
|
+
if (this.config.debug) {
|
|
1099
|
+
(0, debug_1.logDebug)('[ABsmartly] DOMChangesPluginLite registered in global window.__ABSMARTLY_PLUGINS__');
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
/**
|
|
1103
|
+
* Unregister plugin from global registry
|
|
1104
|
+
*/
|
|
1105
|
+
DOMChangesPluginLite.prototype.unregisterGlobally = function () {
|
|
1106
|
+
(0, plugin_registry_1.unregisterPlugin)('dom');
|
|
1107
|
+
if (this.config.debug) {
|
|
1108
|
+
(0, debug_1.logDebug)('[ABsmartly] DOMChangesPluginLite unregistered from global registry');
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
947
1111
|
/**
|
|
948
1112
|
* Hide content to prevent flicker before experiments are applied
|
|
949
1113
|
*/
|
|
@@ -1023,206 +1187,16 @@ var DOMChangesPluginLite = /** @class */ (function () {
|
|
|
1023
1187
|
}
|
|
1024
1188
|
};
|
|
1025
1189
|
DOMChangesPluginLite.prototype.watchElement = function (element, experimentName, change) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
experiments = new Set();
|
|
1029
|
-
this.watchedElements.set(element, experiments);
|
|
1030
|
-
}
|
|
1031
|
-
experiments.add(experimentName);
|
|
1032
|
-
// Store the applied change for this experiment (ALL types: style, class, attribute, html, text, etc.)
|
|
1033
|
-
if (!this.appliedChanges.has(experimentName)) {
|
|
1034
|
-
this.appliedChanges.set(experimentName, []);
|
|
1035
|
-
}
|
|
1036
|
-
var changes = this.appliedChanges.get(experimentName);
|
|
1037
|
-
var isNewWatch = !changes.includes(change);
|
|
1038
|
-
if (isNewWatch) {
|
|
1039
|
-
changes.push(change);
|
|
1040
|
-
// Only log when actually adding a new watch, not on every reapply
|
|
1041
|
-
if (this.config.debug) {
|
|
1042
|
-
var currentStyles_1 = {};
|
|
1043
|
-
if (change.value && typeof change.value === 'object') {
|
|
1044
|
-
Object.keys(change.value).forEach(function (prop) {
|
|
1045
|
-
var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
1046
|
-
currentStyles_1[cssProp] = element.style.getPropertyValue(cssProp);
|
|
1047
|
-
});
|
|
1048
|
-
}
|
|
1049
|
-
(0, debug_1.logDebug)('[WATCH-ELEMENT] Started watching element for persistence/hydration recovery', {
|
|
1050
|
-
experimentName: experimentName,
|
|
1051
|
-
selector: change.selector,
|
|
1052
|
-
element: element.tagName,
|
|
1053
|
-
changeType: change.type,
|
|
1054
|
-
value: change.value,
|
|
1055
|
-
currentStyles: change.type === 'style' ? currentStyles_1 : undefined,
|
|
1056
|
-
timestamp: Date.now(),
|
|
1057
|
-
});
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
if (!this.persistenceObserver) {
|
|
1061
|
-
this.setupPersistenceObserver();
|
|
1190
|
+
if (this.persistenceManager) {
|
|
1191
|
+
this.persistenceManager.watchElement(element, experimentName, change);
|
|
1062
1192
|
}
|
|
1063
1193
|
};
|
|
1064
1194
|
DOMChangesPluginLite.prototype.unwatchElement = function (element, experimentName) {
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
experiments.delete(experimentName);
|
|
1068
|
-
if (experiments.size === 0) {
|
|
1069
|
-
this.watchedElements.delete(element);
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
};
|
|
1073
|
-
DOMChangesPluginLite.prototype.setupPersistenceObserver = function () {
|
|
1074
|
-
var _this = this;
|
|
1075
|
-
if (this.persistenceObserver)
|
|
1076
|
-
return;
|
|
1077
|
-
if (this.config.debug) {
|
|
1078
|
-
(0, debug_1.logDebug)('[PERSISTENCE-OBSERVER] Setting up persistence observer', {
|
|
1079
|
-
timestamp: Date.now(),
|
|
1080
|
-
watchedElementsCount: this.watchedElements ? 'has WeakMap' : 'no WeakMap',
|
|
1081
|
-
});
|
|
1082
|
-
}
|
|
1083
|
-
this.persistenceObserver = new MutationObserver(function (mutations) {
|
|
1084
|
-
if (_this.config.debug) {
|
|
1085
|
-
(0, debug_1.logDebug)('[MUTATION-DETECTED] Persistence observer detected mutations', {
|
|
1086
|
-
mutationCount: mutations.length,
|
|
1087
|
-
timestamp: Date.now(),
|
|
1088
|
-
mutations: mutations.map(function (m) {
|
|
1089
|
-
var _a;
|
|
1090
|
-
return ({
|
|
1091
|
-
target: m.target.tagName,
|
|
1092
|
-
oldValue: (_a = m.oldValue) === null || _a === void 0 ? void 0 : _a.substring(0, 100),
|
|
1093
|
-
});
|
|
1094
|
-
}),
|
|
1095
|
-
});
|
|
1096
|
-
}
|
|
1097
|
-
mutations.forEach(function (mutation) {
|
|
1098
|
-
var element = mutation.target;
|
|
1099
|
-
if (_this.reapplyingElements.has(element)) {
|
|
1100
|
-
if (_this.config.debug) {
|
|
1101
|
-
(0, debug_1.logDebug)('[MUTATION-SKIP] Skipping mutation - currently reapplying', {
|
|
1102
|
-
element: element.tagName,
|
|
1103
|
-
});
|
|
1104
|
-
}
|
|
1105
|
-
return;
|
|
1106
|
-
}
|
|
1107
|
-
var experiments = _this.watchedElements.get(element);
|
|
1108
|
-
if (experiments) {
|
|
1109
|
-
// Throttle mutation detection logs to once per 5 seconds per element
|
|
1110
|
-
if (_this.config.debug) {
|
|
1111
|
-
var elementKey = "mutation:".concat(element.tagName, ":").concat(element.getAttribute('name') || element.className);
|
|
1112
|
-
var now = Date.now();
|
|
1113
|
-
var lastLogged = _this.reapplyLogThrottle.get(elementKey) || 0;
|
|
1114
|
-
if (now - lastLogged > 5000) {
|
|
1115
|
-
(0, debug_1.logDebug)('[MUTATION-ON-WATCHED] Style mutation detected on watched element', {
|
|
1116
|
-
element: element.tagName,
|
|
1117
|
-
selector: element.getAttribute('name') || element.className,
|
|
1118
|
-
oldValue: mutation.oldValue,
|
|
1119
|
-
newValue: element.getAttribute('style'),
|
|
1120
|
-
experiments: Array.from(experiments),
|
|
1121
|
-
});
|
|
1122
|
-
_this.reapplyLogThrottle.set(elementKey, now);
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
experiments.forEach(function (experimentName) {
|
|
1126
|
-
var appliedChanges = _this.appliedChanges.get(experimentName);
|
|
1127
|
-
if (appliedChanges) {
|
|
1128
|
-
appliedChanges.forEach(function (change) {
|
|
1129
|
-
var e_7, _a;
|
|
1130
|
-
// Skip the .matches() check - we already know this element should have this change
|
|
1131
|
-
// because we added it to watchedElements when we applied it successfully.
|
|
1132
|
-
// The .matches() check fails for complex selectors with parent relationships (e.g., "div > p")
|
|
1133
|
-
if (change.type === 'style') {
|
|
1134
|
-
var needsReapply = _this.checkStyleOverwritten(element, change.value);
|
|
1135
|
-
if (needsReapply) {
|
|
1136
|
-
_this.reapplyingElements.add(element);
|
|
1137
|
-
var logKey = "".concat(experimentName, "-").concat(change.selector);
|
|
1138
|
-
var now = Date.now();
|
|
1139
|
-
var lastLogged = _this.reapplyLogThrottle.get(logKey) || 0;
|
|
1140
|
-
if (_this.config.debug && now - lastLogged > 5000) {
|
|
1141
|
-
(0, debug_1.logDebug)('[REAPPLY-TRIGGERED] Reapplying style after mutation (React/framework conflict detected)', {
|
|
1142
|
-
experimentName: experimentName,
|
|
1143
|
-
selector: change.selector,
|
|
1144
|
-
element: element.tagName,
|
|
1145
|
-
timestamp: now,
|
|
1146
|
-
note: 'This happens when the page framework (React/Vue/etc) fights with DOM changes',
|
|
1147
|
-
});
|
|
1148
|
-
_this.reapplyLogThrottle.set(logKey, now);
|
|
1149
|
-
// Cleanup old throttle entries to prevent memory leak
|
|
1150
|
-
if (_this.reapplyLogThrottle.size > 100) {
|
|
1151
|
-
var oldestAllowed = now - 60000; // 1 minute
|
|
1152
|
-
try {
|
|
1153
|
-
for (var _b = __values(_this.reapplyLogThrottle.entries()), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
1154
|
-
var _d = __read(_c.value, 2), key = _d[0], time = _d[1];
|
|
1155
|
-
if (time < oldestAllowed) {
|
|
1156
|
-
_this.reapplyLogThrottle.delete(key);
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
1161
|
-
finally {
|
|
1162
|
-
try {
|
|
1163
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
1164
|
-
}
|
|
1165
|
-
finally { if (e_7) throw e_7.error; }
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
_this.domManipulator.applyChange(change, experimentName);
|
|
1170
|
-
setTimeout(function () {
|
|
1171
|
-
_this.reapplyingElements.delete(element);
|
|
1172
|
-
}, 0);
|
|
1173
|
-
}
|
|
1174
|
-
else if (_this.config.debug) {
|
|
1175
|
-
(0, debug_1.logDebug)('[MUTATION-NO-REAPPLY] Style mutation detected but no reapply needed', {
|
|
1176
|
-
experimentName: experimentName,
|
|
1177
|
-
selector: change.selector,
|
|
1178
|
-
});
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
});
|
|
1182
|
-
}
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
|
-
});
|
|
1186
|
-
});
|
|
1187
|
-
this.persistenceObserver.observe(document.body, {
|
|
1188
|
-
attributes: true,
|
|
1189
|
-
attributeFilter: ['style'],
|
|
1190
|
-
subtree: true,
|
|
1191
|
-
attributeOldValue: true,
|
|
1192
|
-
});
|
|
1193
|
-
if (this.config.debug) {
|
|
1194
|
-
(0, debug_1.logDebug)('[PERSISTENCE-OBSERVER] Setup complete - now observing style mutations', {
|
|
1195
|
-
target: 'document.body',
|
|
1196
|
-
attributeFilter: ['style'],
|
|
1197
|
-
subtree: true,
|
|
1198
|
-
attributeOldValue: true,
|
|
1199
|
-
timestamp: Date.now(),
|
|
1200
|
-
});
|
|
1201
|
-
}
|
|
1202
|
-
};
|
|
1203
|
-
DOMChangesPluginLite.prototype.checkStyleOverwritten = function (element, expectedStyles) {
|
|
1204
|
-
var e_8, _a;
|
|
1205
|
-
try {
|
|
1206
|
-
for (var _b = __values(Object.entries(expectedStyles)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
1207
|
-
var _d = __read(_c.value, 2), prop = _d[0], value = _d[1];
|
|
1208
|
-
var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
1209
|
-
var currentValue = element.style.getPropertyValue(cssProp);
|
|
1210
|
-
var currentPriority = element.style.getPropertyPriority(cssProp);
|
|
1211
|
-
if (currentValue !== value || (value.includes('!important') && !currentPriority)) {
|
|
1212
|
-
return true;
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
|
1217
|
-
finally {
|
|
1218
|
-
try {
|
|
1219
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
1220
|
-
}
|
|
1221
|
-
finally { if (e_8) throw e_8.error; }
|
|
1195
|
+
if (this.persistenceManager) {
|
|
1196
|
+
this.persistenceManager.unwatchElement(element, experimentName);
|
|
1222
1197
|
}
|
|
1223
|
-
return false;
|
|
1224
1198
|
};
|
|
1225
|
-
DOMChangesPluginLite.VERSION =
|
|
1199
|
+
DOMChangesPluginLite.VERSION = buildInfo_1.BUILD_VERSION;
|
|
1226
1200
|
return DOMChangesPluginLite;
|
|
1227
1201
|
}());
|
|
1228
1202
|
exports.DOMChangesPluginLite = DOMChangesPluginLite;
|