@absmartly/sdk-plugins 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/README.md +1101 -0
  2. package/dist/absmartly-cookie.min.js +1 -0
  3. package/dist/absmartly-dom-changes-core.min.js +1 -0
  4. package/dist/absmartly-dom-changes-lite.min.js +1 -0
  5. package/dist/absmartly-overrides-full.min.js +1 -0
  6. package/dist/absmartly-overrides-lite.min.js +1 -0
  7. package/dist/absmartly-sdk-plugins.min.js +1 -0
  8. package/dist/absmartly-vitals.min.js +1 -0
  9. package/es/cookies/CookiePlugin.js +410 -0
  10. package/es/cookies/CookiePlugin.js.map +1 -0
  11. package/es/cookies/index.js +2 -0
  12. package/es/cookies/index.js.map +1 -0
  13. package/es/core/DOMChangesPluginLite.js +1124 -0
  14. package/es/core/DOMChangesPluginLite.js.map +1 -0
  15. package/es/core/DOMManipulatorLite.js +410 -0
  16. package/es/core/DOMManipulatorLite.js.map +1 -0
  17. package/es/core/ExposureTracker.js +501 -0
  18. package/es/core/ExposureTracker.js.map +1 -0
  19. package/es/core/HTMLInjector.js +333 -0
  20. package/es/core/HTMLInjector.js.map +1 -0
  21. package/es/core/PendingChangeManager.js +440 -0
  22. package/es/core/PendingChangeManager.js.map +1 -0
  23. package/es/core/StyleSheetManager.js +78 -0
  24. package/es/core/StyleSheetManager.js.map +1 -0
  25. package/es/entries/cookie-only.js +10 -0
  26. package/es/entries/cookie-only.js.map +1 -0
  27. package/es/entries/dom-only.js +13 -0
  28. package/es/entries/dom-only.js.map +1 -0
  29. package/es/entries/dom-with-overrides-full.js +19 -0
  30. package/es/entries/dom-with-overrides-full.js.map +1 -0
  31. package/es/entries/dom-with-overrides-lite.js +15 -0
  32. package/es/entries/dom-with-overrides-lite.js.map +1 -0
  33. package/es/entries/overrides-full-only.js +15 -0
  34. package/es/entries/overrides-full-only.js.map +1 -0
  35. package/es/entries/overrides-lite-only.js +12 -0
  36. package/es/entries/overrides-lite-only.js.map +1 -0
  37. package/es/entries/vitals-only.js +10 -0
  38. package/es/entries/vitals-only.js.map +1 -0
  39. package/es/index.js +17 -0
  40. package/es/index.js.map +1 -0
  41. package/es/overrides/BrowserCookieAdapter.js +76 -0
  42. package/es/overrides/BrowserCookieAdapter.js.map +1 -0
  43. package/es/overrides/OverridesPlugin.js +903 -0
  44. package/es/overrides/OverridesPlugin.js.map +1 -0
  45. package/es/overrides/OverridesPluginFull.js +32 -0
  46. package/es/overrides/OverridesPluginFull.js.map +1 -0
  47. package/es/overrides/OverridesPluginLite.js +352 -0
  48. package/es/overrides/OverridesPluginLite.js.map +1 -0
  49. package/es/overrides/index.js +4 -0
  50. package/es/overrides/index.js.map +1 -0
  51. package/es/overrides/types.js +2 -0
  52. package/es/overrides/types.js.map +1 -0
  53. package/es/parsers/VariantExtractor.js +570 -0
  54. package/es/parsers/VariantExtractor.js.map +1 -0
  55. package/es/types/index.js +2 -0
  56. package/es/types/index.js.map +1 -0
  57. package/es/utils/URLMatcher.js +114 -0
  58. package/es/utils/URLMatcher.js.map +1 -0
  59. package/es/utils/debug.js +184 -0
  60. package/es/utils/debug.js.map +1 -0
  61. package/es/vitals/WebVitalsPlugin.js +379 -0
  62. package/es/vitals/WebVitalsPlugin.js.map +1 -0
  63. package/es/vitals/index.js +2 -0
  64. package/es/vitals/index.js.map +1 -0
  65. package/lib/cookies/CookiePlugin.d.ts +55 -0
  66. package/lib/cookies/CookiePlugin.js +413 -0
  67. package/lib/cookies/CookiePlugin.js.map +1 -0
  68. package/lib/cookies/index.d.ts +2 -0
  69. package/lib/cookies/index.js +6 -0
  70. package/lib/cookies/index.js.map +1 -0
  71. package/lib/core/DOMChangesPluginLite.d.ts +89 -0
  72. package/lib/core/DOMChangesPluginLite.js +1127 -0
  73. package/lib/core/DOMChangesPluginLite.js.map +1 -0
  74. package/lib/core/DOMManipulatorLite.d.ts +21 -0
  75. package/lib/core/DOMManipulatorLite.js +413 -0
  76. package/lib/core/DOMManipulatorLite.js.map +1 -0
  77. package/lib/core/ExposureTracker.d.ts +81 -0
  78. package/lib/core/ExposureTracker.js +504 -0
  79. package/lib/core/ExposureTracker.js.map +1 -0
  80. package/lib/core/HTMLInjector.d.ts +19 -0
  81. package/lib/core/HTMLInjector.js +336 -0
  82. package/lib/core/HTMLInjector.js.map +1 -0
  83. package/lib/core/PendingChangeManager.d.ts +31 -0
  84. package/lib/core/PendingChangeManager.js +443 -0
  85. package/lib/core/PendingChangeManager.js.map +1 -0
  86. package/lib/core/StyleSheetManager.d.ts +16 -0
  87. package/lib/core/StyleSheetManager.js +81 -0
  88. package/lib/core/StyleSheetManager.js.map +1 -0
  89. package/lib/entries/cookie-only.d.ts +8 -0
  90. package/lib/entries/cookie-only.js +12 -0
  91. package/lib/entries/cookie-only.js.map +1 -0
  92. package/lib/entries/dom-only.d.ts +9 -0
  93. package/lib/entries/dom-only.js +29 -0
  94. package/lib/entries/dom-only.js.map +1 -0
  95. package/lib/entries/dom-with-overrides-full.d.ts +15 -0
  96. package/lib/entries/dom-with-overrides-full.js +39 -0
  97. package/lib/entries/dom-with-overrides-full.js.map +1 -0
  98. package/lib/entries/dom-with-overrides-lite.d.ts +11 -0
  99. package/lib/entries/dom-with-overrides-lite.js +32 -0
  100. package/lib/entries/dom-with-overrides-lite.js.map +1 -0
  101. package/lib/entries/overrides-full-only.d.ts +11 -0
  102. package/lib/entries/overrides-full-only.js +33 -0
  103. package/lib/entries/overrides-full-only.js.map +1 -0
  104. package/lib/entries/overrides-lite-only.d.ts +8 -0
  105. package/lib/entries/overrides-lite-only.js +28 -0
  106. package/lib/entries/overrides-lite-only.js.map +1 -0
  107. package/lib/entries/vitals-only.d.ts +8 -0
  108. package/lib/entries/vitals-only.js +12 -0
  109. package/lib/entries/vitals-only.js.map +1 -0
  110. package/lib/index.d.ts +13 -0
  111. package/lib/index.js +34 -0
  112. package/lib/index.js.map +1 -0
  113. package/lib/overrides/BrowserCookieAdapter.d.ts +6 -0
  114. package/lib/overrides/BrowserCookieAdapter.js +79 -0
  115. package/lib/overrides/BrowserCookieAdapter.js.map +1 -0
  116. package/lib/overrides/OverridesPlugin.d.ts +33 -0
  117. package/lib/overrides/OverridesPlugin.js +906 -0
  118. package/lib/overrides/OverridesPlugin.js.map +1 -0
  119. package/lib/overrides/OverridesPluginFull.d.ts +9 -0
  120. package/lib/overrides/OverridesPluginFull.js +35 -0
  121. package/lib/overrides/OverridesPluginFull.js.map +1 -0
  122. package/lib/overrides/OverridesPluginLite.d.ts +27 -0
  123. package/lib/overrides/OverridesPluginLite.js +355 -0
  124. package/lib/overrides/OverridesPluginLite.js.map +1 -0
  125. package/lib/overrides/index.d.ts +3 -0
  126. package/lib/overrides/index.js +23 -0
  127. package/lib/overrides/index.js.map +1 -0
  128. package/lib/overrides/types.d.ts +43 -0
  129. package/lib/overrides/types.js +3 -0
  130. package/lib/overrides/types.js.map +1 -0
  131. package/lib/parsers/VariantExtractor.d.ts +49 -0
  132. package/lib/parsers/VariantExtractor.js +573 -0
  133. package/lib/parsers/VariantExtractor.js.map +1 -0
  134. package/lib/types/index.d.ts +177 -0
  135. package/lib/types/index.js +3 -0
  136. package/lib/types/index.js.map +1 -0
  137. package/lib/utils/URLMatcher.d.ts +20 -0
  138. package/lib/utils/URLMatcher.js +117 -0
  139. package/lib/utils/URLMatcher.js.map +1 -0
  140. package/lib/utils/debug.d.ts +41 -0
  141. package/lib/utils/debug.js +195 -0
  142. package/lib/utils/debug.js.map +1 -0
  143. package/lib/vitals/WebVitalsPlugin.d.ts +37 -0
  144. package/lib/vitals/WebVitalsPlugin.js +382 -0
  145. package/lib/vitals/WebVitalsPlugin.js.map +1 -0
  146. package/lib/vitals/index.d.ts +2 -0
  147. package/lib/vitals/index.js +6 -0
  148. package/lib/vitals/index.js.map +1 -0
  149. package/package.json +94 -0
  150. package/types/cookies/CookiePlugin.d.ts +55 -0
  151. package/types/cookies/index.d.ts +2 -0
  152. package/types/core/DOMChangesPluginLite.d.ts +89 -0
  153. package/types/core/DOMManipulatorLite.d.ts +21 -0
  154. package/types/core/ExposureTracker.d.ts +81 -0
  155. package/types/core/HTMLInjector.d.ts +19 -0
  156. package/types/core/PendingChangeManager.d.ts +31 -0
  157. package/types/core/StyleSheetManager.d.ts +16 -0
  158. package/types/entries/cookie-only.d.ts +8 -0
  159. package/types/entries/dom-only.d.ts +9 -0
  160. package/types/entries/dom-with-overrides-full.d.ts +15 -0
  161. package/types/entries/dom-with-overrides-lite.d.ts +11 -0
  162. package/types/entries/overrides-full-only.d.ts +11 -0
  163. package/types/entries/overrides-lite-only.d.ts +8 -0
  164. package/types/entries/vitals-only.d.ts +8 -0
  165. package/types/index.d.ts +13 -0
  166. package/types/overrides/BrowserCookieAdapter.d.ts +6 -0
  167. package/types/overrides/OverridesPlugin.d.ts +33 -0
  168. package/types/overrides/OverridesPluginFull.d.ts +9 -0
  169. package/types/overrides/OverridesPluginLite.d.ts +27 -0
  170. package/types/overrides/index.d.ts +3 -0
  171. package/types/overrides/types.d.ts +43 -0
  172. package/types/parsers/VariantExtractor.d.ts +49 -0
  173. package/types/types/index.d.ts +177 -0
  174. package/types/utils/URLMatcher.d.ts +20 -0
  175. package/types/utils/debug.d.ts +41 -0
  176. package/types/vitals/WebVitalsPlugin.d.ts +37 -0
  177. package/types/vitals/index.d.ts +2 -0
@@ -0,0 +1,1127 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __values = (this && this.__values) || function(o) {
50
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
51
+ if (m) return m.call(o);
52
+ if (o && typeof o.length === "number") return {
53
+ next: function () {
54
+ if (o && i >= o.length) o = void 0;
55
+ return { value: o && o[i++], done: !o };
56
+ }
57
+ };
58
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
59
+ };
60
+ var __read = (this && this.__read) || function (o, n) {
61
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
62
+ if (!m) return o;
63
+ var i = m.call(o), r, ar = [], e;
64
+ try {
65
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
66
+ }
67
+ catch (error) { e = { error: error }; }
68
+ finally {
69
+ try {
70
+ if (r && !r.done && (m = i["return"])) m.call(i);
71
+ }
72
+ finally { if (e) throw e.error; }
73
+ }
74
+ return ar;
75
+ };
76
+ Object.defineProperty(exports, "__esModule", { value: true });
77
+ exports.DOMChangesPluginLite = void 0;
78
+ var DOMManipulatorLite_1 = require("./DOMManipulatorLite");
79
+ var VariantExtractor_1 = require("../parsers/VariantExtractor");
80
+ var StyleSheetManager_1 = require("./StyleSheetManager");
81
+ var ExposureTracker_1 = require("./ExposureTracker");
82
+ var HTMLInjector_1 = require("./HTMLInjector");
83
+ var debug_1 = require("../utils/debug");
84
+ var URLMatcher_1 = require("../utils/URLMatcher");
85
+ var DOMChangesPluginLite = /** @class */ (function () {
86
+ function DOMChangesPluginLite(config) {
87
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
88
+ this.mutationObserver = null;
89
+ this.exposedExperiments = new Set();
90
+ this.eventListeners = new Map();
91
+ this.styleManagers = new Map();
92
+ this.initialized = false;
93
+ this.watchedElements = new WeakMap();
94
+ this.persistenceObserver = null;
95
+ this.reapplyingElements = new Set();
96
+ this.reapplyLogThrottle = new Map();
97
+ this.appliedStyleChanges = new Map();
98
+ this.antiFlickerTimeout = null;
99
+ this.antiFlickerStyleId = 'absmartly-antiflicker';
100
+ this.config = {
101
+ context: config.context,
102
+ autoApply: (_a = config.autoApply) !== null && _a !== void 0 ? _a : true,
103
+ spa: (_b = config.spa) !== null && _b !== void 0 ? _b : true,
104
+ visibilityTracking: (_c = config.visibilityTracking) !== null && _c !== void 0 ? _c : true,
105
+ extensionBridge: false, // Always false for lite version
106
+ dataSource: (_d = config.dataSource) !== null && _d !== void 0 ? _d : 'variable',
107
+ dataFieldName: (_e = config.dataFieldName) !== null && _e !== void 0 ? _e : '__dom_changes',
108
+ debug: (_f = config.debug) !== null && _f !== void 0 ? _f : false,
109
+ hideUntilReady: (_g = config.hideUntilReady) !== null && _g !== void 0 ? _g : false,
110
+ hideTimeout: (_h = config.hideTimeout) !== null && _h !== void 0 ? _h : 3000,
111
+ hideSelector: (_j = config.hideSelector) !== null && _j !== void 0 ? _j : '[data-absmartly-hide]',
112
+ hideTransition: (_k = config.hideTransition) !== null && _k !== void 0 ? _k : false,
113
+ };
114
+ if (!this.config.context) {
115
+ throw new Error('[ABsmartly] Context is required');
116
+ }
117
+ // Apply anti-flicker hiding immediately if enabled
118
+ if (this.config.hideUntilReady) {
119
+ this.hideContent();
120
+ }
121
+ this.domManipulator = new DOMManipulatorLite_1.DOMManipulatorLite(this.config.debug, this);
122
+ this.variantExtractor = new VariantExtractor_1.VariantExtractor(this.config.context, this.config.dataSource, this.config.dataFieldName, this.config.debug);
123
+ this.exposureTracker = new ExposureTracker_1.ExposureTracker(this.config.context, this.config.debug);
124
+ this.htmlInjector = new HTMLInjector_1.HTMLInjector(this.config.debug);
125
+ }
126
+ DOMChangesPluginLite.prototype.ready = function () {
127
+ return __awaiter(this, void 0, void 0, function () {
128
+ var startTime, duration, error_1;
129
+ return __generator(this, function (_a) {
130
+ switch (_a.label) {
131
+ case 0:
132
+ if (this.initialized) {
133
+ (0, debug_1.logDebug)('Plugin already initialized');
134
+ return [2 /*return*/];
135
+ }
136
+ startTime = performance.now();
137
+ (0, debug_1.logDebug)('Initializing ABsmartly DOM Changes Plugin Lite', {
138
+ version: DOMChangesPluginLite.VERSION,
139
+ config: {
140
+ autoApply: this.config.autoApply,
141
+ spa: this.config.spa,
142
+ visibilityTracking: this.config.visibilityTracking,
143
+ dataSource: this.config.dataSource,
144
+ DEBUG: debug_1.DEBUG,
145
+ },
146
+ });
147
+ _a.label = 1;
148
+ case 1:
149
+ _a.trys.push([1, 4, , 5]);
150
+ if (this.config.spa) {
151
+ this.setupMutationObserver();
152
+ this.setupURLChangeListener();
153
+ }
154
+ if (!this.config.autoApply) return [3 /*break*/, 3];
155
+ // Apply HTML injections and DOM changes in parallel to minimize flickering
156
+ return [4 /*yield*/, this.applyInjectionsAndChanges()];
157
+ case 2:
158
+ // Apply HTML injections and DOM changes in parallel to minimize flickering
159
+ _a.sent();
160
+ _a.label = 3;
161
+ case 3:
162
+ this.initialized = true;
163
+ this.registerWithContext();
164
+ this.emit('initialized');
165
+ duration = performance.now() - startTime;
166
+ (0, debug_1.logPerformance)('Plugin initialization', duration);
167
+ (0, debug_1.logDebug)("[ABsmartly] DOM plugin lite loaded successfully (v".concat(DOMChangesPluginLite.VERSION, ")"));
168
+ if (this.config.debug) {
169
+ (0, debug_1.logDebug)('[ABsmartly] DOM Changes Plugin Lite initialized with debug mode');
170
+ }
171
+ return [3 /*break*/, 5];
172
+ case 4:
173
+ error_1 = _a.sent();
174
+ (0, debug_1.logDebug)('[ABsmartly] Failed to initialize plugin:', error_1);
175
+ throw error_1;
176
+ case 5: return [2 /*return*/];
177
+ }
178
+ });
179
+ });
180
+ };
181
+ DOMChangesPluginLite.prototype.initialize = function () {
182
+ return __awaiter(this, void 0, void 0, function () {
183
+ return __generator(this, function (_a) {
184
+ return [2 /*return*/, this.ready()];
185
+ });
186
+ });
187
+ };
188
+ DOMChangesPluginLite.prototype.setupMutationObserver = function () {
189
+ var observer = new MutationObserver(function () {
190
+ // Check for pending changes that might now be applicable
191
+ // Note: We don't have a centralized pending changes store in lite version,
192
+ // the PendingChangeManager handles this internally
193
+ });
194
+ observer.observe(document.body, {
195
+ childList: true,
196
+ subtree: true,
197
+ });
198
+ this.mutationObserver = observer;
199
+ };
200
+ /**
201
+ * Set up URL change listener for SPA mode
202
+ * Re-evaluates URL filters when URL changes and applies/removes changes accordingly
203
+ */
204
+ DOMChangesPluginLite.prototype.setupURLChangeListener = function () {
205
+ var _this = this;
206
+ var handleURLChange = function () { return __awaiter(_this, void 0, void 0, function () {
207
+ var newURL;
208
+ return __generator(this, function (_a) {
209
+ switch (_a.label) {
210
+ case 0:
211
+ newURL = window.location.href;
212
+ (0, debug_1.logDebug)('[ABsmartly] URL changed, re-evaluating experiments:', newURL);
213
+ // Remove all current changes
214
+ return [4 /*yield*/, this.removeAllChanges()];
215
+ case 1:
216
+ // Remove all current changes
217
+ _a.sent();
218
+ // Re-apply changes and injections with new URL (in parallel)
219
+ return [4 /*yield*/, this.applyInjectionsAndChanges()];
220
+ case 2:
221
+ // Re-apply changes and injections with new URL (in parallel)
222
+ _a.sent();
223
+ return [2 /*return*/];
224
+ }
225
+ });
226
+ }); };
227
+ // Listen to popstate (back/forward navigation)
228
+ window.addEventListener('popstate', handleURLChange);
229
+ // Intercept pushState and replaceState
230
+ var originalPushState = history.pushState;
231
+ var originalReplaceState = history.replaceState;
232
+ history.pushState = function () {
233
+ var args = [];
234
+ for (var _i = 0; _i < arguments.length; _i++) {
235
+ args[_i] = arguments[_i];
236
+ }
237
+ originalPushState.apply(history, args);
238
+ handleURLChange();
239
+ };
240
+ history.replaceState = function () {
241
+ var args = [];
242
+ for (var _i = 0; _i < arguments.length; _i++) {
243
+ args[_i] = arguments[_i];
244
+ }
245
+ originalReplaceState.apply(history, args);
246
+ handleURLChange();
247
+ };
248
+ if (this.config.debug) {
249
+ (0, debug_1.logDebug)('[ABsmartly] URL change listener set up for SPA mode');
250
+ }
251
+ };
252
+ /**
253
+ * Remove all currently applied changes
254
+ * Used when URL changes in SPA mode
255
+ */
256
+ DOMChangesPluginLite.prototype.removeAllChanges = function () {
257
+ return __awaiter(this, void 0, void 0, function () {
258
+ return __generator(this, function (_a) {
259
+ // Clear exposed experiments - ExposureTracker will re-register on next applyChanges
260
+ this.exposedExperiments.clear();
261
+ // Clear style managers - StyleSheetManager doesn't have a remove method
262
+ // The stylesheets will be reused or cleared on next applyChanges
263
+ this.styleManagers.clear();
264
+ // Clear applied style changes
265
+ this.appliedStyleChanges.clear();
266
+ // Clear HTML injections
267
+ this.htmlInjector.destroy();
268
+ // Clear variant extractor cache to force re-extraction
269
+ this.variantExtractor.clearCache();
270
+ if (this.config.debug) {
271
+ (0, debug_1.logDebug)('[ABsmartly] All change tracking cleared for URL change');
272
+ }
273
+ return [2 /*return*/];
274
+ });
275
+ });
276
+ };
277
+ /**
278
+ * Apply HTML injections and DOM changes in parallel to minimize flickering
279
+ */
280
+ DOMChangesPluginLite.prototype.applyInjectionsAndChanges = function () {
281
+ return __awaiter(this, void 0, void 0, function () {
282
+ var startTime, currentURL, error_2, allInjectHTML, duration;
283
+ return __generator(this, function (_a) {
284
+ switch (_a.label) {
285
+ case 0:
286
+ startTime = performance.now();
287
+ currentURL = window.location.href;
288
+ _a.label = 1;
289
+ case 1:
290
+ _a.trys.push([1, 3, , 4]);
291
+ return [4 /*yield*/, this.config.context.ready()];
292
+ case 2:
293
+ _a.sent();
294
+ return [3 /*break*/, 4];
295
+ case 3:
296
+ error_2 = _a.sent();
297
+ (0, debug_1.logDebug)('[ABsmartly] Failed to wait for context ready:', error_2);
298
+ return [2 /*return*/];
299
+ case 4:
300
+ allInjectHTML = this.variantExtractor.extractAllInjectHTML();
301
+ // Apply injections and DOM changes in parallel for minimal flickering
302
+ return [4 /*yield*/, Promise.all([this.applyHTMLInjections(allInjectHTML, currentURL), this.applyChanges()])];
303
+ case 5:
304
+ // Apply injections and DOM changes in parallel for minimal flickering
305
+ _a.sent();
306
+ duration = performance.now() - startTime;
307
+ (0, debug_1.logPerformance)('Apply injections and changes (parallel)', duration);
308
+ if (this.config.debug) {
309
+ (0, debug_1.logDebug)('[ABsmartly] HTML injections and DOM changes applied in parallel', {
310
+ duration: "".concat(duration.toFixed(2), "ms"),
311
+ currentURL: currentURL,
312
+ });
313
+ }
314
+ return [2 /*return*/];
315
+ }
316
+ });
317
+ });
318
+ };
319
+ /**
320
+ * Apply HTML injections from all variants
321
+ */
322
+ DOMChangesPluginLite.prototype.applyHTMLInjections = function (allInjectHTML_1) {
323
+ return __awaiter(this, arguments, void 0, function (allInjectHTML, currentUrl) {
324
+ var injectionsByLocation;
325
+ if (currentUrl === void 0) { currentUrl = window.location.href; }
326
+ return __generator(this, function (_a) {
327
+ if (allInjectHTML.size === 0) {
328
+ if (this.config.debug) {
329
+ (0, debug_1.logDebug)('[ABsmartly] No HTML injections found');
330
+ }
331
+ return [2 /*return*/];
332
+ }
333
+ injectionsByLocation = this.htmlInjector.collectInjections(allInjectHTML, currentUrl);
334
+ this.htmlInjector.inject(injectionsByLocation);
335
+ if (this.config.debug) {
336
+ (0, debug_1.logDebug)('[ABsmartly] HTML injections complete', {
337
+ experimentsWithInjections: allInjectHTML.size,
338
+ totalLocations: injectionsByLocation.size,
339
+ currentUrl: currentUrl,
340
+ });
341
+ }
342
+ return [2 /*return*/];
343
+ });
344
+ });
345
+ };
346
+ DOMChangesPluginLite.prototype.applyChanges = function (experimentName) {
347
+ return __awaiter(this, void 0, void 0, function () {
348
+ var startTime, currentURL, error_3, allExperiments, totalApplied, experimentStats, allExperiments_1, allExperiments_1_1, _a, expName, experimentData, currentVariant, variantData, urlFilter, globalDefaults, anyVariantMatchesURL, shouldApplyVisualChanges, changes, allVariantChanges, hasAnyChangesInAnyVariant, stats, hasImmediateTrigger, hasViewportTrigger, changes_1, changes_1_1, change, success, elements, changes_2, changes_2_1, change, hasAnyViewportTriggerInAnyVariant, hasAnyImmediateTriggerInAnyVariant, allVariantChanges_1, allVariantChanges_1_1, variantChanges, variantChanges_1, variantChanges_1_1, change, duration;
349
+ var e_1, _b, e_2, _c, e_3, _d, e_4, _e, e_5, _f;
350
+ return __generator(this, function (_g) {
351
+ switch (_g.label) {
352
+ case 0:
353
+ startTime = performance.now();
354
+ currentURL = window.location.href;
355
+ (0, debug_1.logDebug)('Starting to apply changes', {
356
+ specificExperiment: experimentName || 'all',
357
+ url: currentURL,
358
+ action: 'apply_start',
359
+ });
360
+ if (this.config.debug) {
361
+ (0, debug_1.logDebug)('[ABsmartly] === DOM Changes Application Starting ===');
362
+ (0, debug_1.logDebug)('[ABsmartly] Target:', experimentName || 'all experiments');
363
+ (0, debug_1.logDebug)('[ABsmartly] Current URL:', currentURL);
364
+ (0, debug_1.logDebug)('[ABsmartly] Context ready:', true);
365
+ }
366
+ _g.label = 1;
367
+ case 1:
368
+ _g.trys.push([1, 3, , 4]);
369
+ return [4 /*yield*/, this.config.context.ready()];
370
+ case 2:
371
+ _g.sent();
372
+ return [3 /*break*/, 4];
373
+ case 3:
374
+ error_3 = _g.sent();
375
+ (0, debug_1.logDebug)('[ABsmartly] Failed to wait for context ready:', error_3);
376
+ return [2 /*return*/];
377
+ case 4:
378
+ this.variantExtractor.clearCache();
379
+ allExperiments = this.getAllExperimentsData();
380
+ totalApplied = 0;
381
+ experimentStats = new Map();
382
+ (0, debug_1.logDebug)('[ABsmartly] Experiments to process:', Array.from(allExperiments.keys()));
383
+ (0, debug_1.logDebug)('[ABsmartly] Total experiments with changes:', allExperiments.size);
384
+ try {
385
+ for (allExperiments_1 = __values(allExperiments), allExperiments_1_1 = allExperiments_1.next(); !allExperiments_1_1.done; allExperiments_1_1 = allExperiments_1.next()) {
386
+ _a = __read(allExperiments_1_1.value, 2), expName = _a[0], experimentData = _a[1];
387
+ // Skip if filtering by specific experiment
388
+ if (experimentName && expName !== experimentName) {
389
+ continue;
390
+ }
391
+ currentVariant = this.config.context.peek(expName);
392
+ variantData = experimentData.variantData, urlFilter = experimentData.urlFilter, globalDefaults = experimentData.globalDefaults;
393
+ anyVariantMatchesURL = this.variantExtractor.anyVariantMatchesURL(expName, currentURL);
394
+ if (!anyVariantMatchesURL) {
395
+ (0, debug_1.logDebug)("[ABsmartly] Skipping experiment '".concat(expName, "' - no variant matches URL: ").concat(currentURL));
396
+ continue;
397
+ }
398
+ shouldApplyVisualChanges = this.shouldApplyVisualChanges(variantData, urlFilter, currentURL);
399
+ changes = this.extractChangesFromData(variantData, globalDefaults);
400
+ allVariantChanges = this.extractAllVariantChanges(expName);
401
+ hasAnyChangesInAnyVariant = allVariantChanges.some(function (variantChanges) { return variantChanges && variantChanges.length > 0; });
402
+ if (!hasAnyChangesInAnyVariant) {
403
+ // If NO variant has ANY changes, skip the entire experiment
404
+ if (this.config.debug) {
405
+ (0, debug_1.logDebug)("[ABsmartly] Skipping experiment '".concat(expName, "' - no variants have changes"));
406
+ }
407
+ continue;
408
+ }
409
+ stats = { total: (changes === null || changes === void 0 ? void 0 : changes.length) || 0, success: 0, pending: 0 };
410
+ if (this.config.debug) {
411
+ (0, debug_1.logDebug)("[ABsmartly] Processing experiment '".concat(expName, "' (variant ").concat(currentVariant, "):"), {
412
+ urlMatches: shouldApplyVisualChanges,
413
+ changeCount: (changes === null || changes === void 0 ? void 0 : changes.length) || 0,
414
+ userVariantHasChanges: ((changes === null || changes === void 0 ? void 0 : changes.length) || 0) > 0,
415
+ changes: (changes === null || changes === void 0 ? void 0 : changes.map(function (c) { return ({
416
+ type: c.type,
417
+ selector: c.selector,
418
+ trigger: c.trigger_on_view ? 'viewport' : 'immediate',
419
+ }); })) || [],
420
+ });
421
+ }
422
+ hasImmediateTrigger = false;
423
+ hasViewportTrigger = false;
424
+ // Apply visual changes only if URL matches for user's variant AND user has changes
425
+ if (shouldApplyVisualChanges && changes && changes.length > 0) {
426
+ try {
427
+ 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()) {
428
+ change = changes_1_1.value;
429
+ success = this.domManipulator.applyChange(change, expName);
430
+ if (success) {
431
+ totalApplied++;
432
+ stats.success++;
433
+ if (change.trigger_on_view) {
434
+ hasViewportTrigger = true;
435
+ }
436
+ else {
437
+ hasImmediateTrigger = true;
438
+ }
439
+ }
440
+ else if (change.type !== 'create' && change.type !== 'styleRules') {
441
+ // Track pending changes for stats
442
+ try {
443
+ elements = document.querySelectorAll(change.selector);
444
+ if (elements.length === 0 && (this.config.spa || change.waitForElement)) {
445
+ stats.pending++;
446
+ if (change.trigger_on_view) {
447
+ hasViewportTrigger = true;
448
+ }
449
+ }
450
+ }
451
+ catch (error) {
452
+ if (this.config.debug) {
453
+ (0, debug_1.logDebug)("[ABsmartly] Invalid selector: ".concat(change.selector), error);
454
+ }
455
+ }
456
+ }
457
+ }
458
+ }
459
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
460
+ finally {
461
+ try {
462
+ if (changes_1_1 && !changes_1_1.done && (_c = changes_1.return)) _c.call(changes_1);
463
+ }
464
+ finally { if (e_2) throw e_2.error; }
465
+ }
466
+ }
467
+ else if (changes && changes.length > 0) {
468
+ try {
469
+ // URL doesn't match for user's variant OR user has no changes
470
+ // Check if user's changes have viewport trigger (if they exist)
471
+ // We still need to set up tracking for SRM prevention
472
+ for (changes_2 = (e_3 = void 0, __values(changes)), changes_2_1 = changes_2.next(); !changes_2_1.done; changes_2_1 = changes_2.next()) {
473
+ change = changes_2_1.value;
474
+ if (change.trigger_on_view) {
475
+ hasViewportTrigger = true;
476
+ }
477
+ else {
478
+ hasImmediateTrigger = true;
479
+ }
480
+ }
481
+ }
482
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
483
+ finally {
484
+ try {
485
+ if (changes_2_1 && !changes_2_1.done && (_d = changes_2.return)) _d.call(changes_2);
486
+ }
487
+ finally { if (e_3) throw e_3.error; }
488
+ }
489
+ (0, debug_1.logDebug)("[ABsmartly] Experiment '".concat(expName, "' variant ").concat(currentVariant, " doesn't match URL filter or has no changes, but setting up tracking for SRM prevention"));
490
+ }
491
+ hasAnyViewportTriggerInAnyVariant = hasViewportTrigger;
492
+ hasAnyImmediateTriggerInAnyVariant = hasImmediateTrigger;
493
+ if (!hasViewportTrigger || !hasImmediateTrigger) {
494
+ try {
495
+ for (allVariantChanges_1 = (e_4 = void 0, __values(allVariantChanges)), allVariantChanges_1_1 = allVariantChanges_1.next(); !allVariantChanges_1_1.done; allVariantChanges_1_1 = allVariantChanges_1.next()) {
496
+ variantChanges = allVariantChanges_1_1.value;
497
+ if (variantChanges && variantChanges.length > 0) {
498
+ try {
499
+ for (variantChanges_1 = (e_5 = void 0, __values(variantChanges)), variantChanges_1_1 = variantChanges_1.next(); !variantChanges_1_1.done; variantChanges_1_1 = variantChanges_1.next()) {
500
+ change = variantChanges_1_1.value;
501
+ if (change.trigger_on_view) {
502
+ hasAnyViewportTriggerInAnyVariant = true;
503
+ }
504
+ else {
505
+ hasAnyImmediateTriggerInAnyVariant = true;
506
+ }
507
+ // Early exit if we found both types
508
+ if (hasAnyViewportTriggerInAnyVariant && hasAnyImmediateTriggerInAnyVariant) {
509
+ break;
510
+ }
511
+ }
512
+ }
513
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
514
+ finally {
515
+ try {
516
+ if (variantChanges_1_1 && !variantChanges_1_1.done && (_f = variantChanges_1.return)) _f.call(variantChanges_1);
517
+ }
518
+ finally { if (e_5) throw e_5.error; }
519
+ }
520
+ }
521
+ if (hasAnyViewportTriggerInAnyVariant && hasAnyImmediateTriggerInAnyVariant) {
522
+ break;
523
+ }
524
+ }
525
+ }
526
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
527
+ finally {
528
+ try {
529
+ if (allVariantChanges_1_1 && !allVariantChanges_1_1.done && (_e = allVariantChanges_1.return)) _e.call(allVariantChanges_1);
530
+ }
531
+ finally { if (e_4) throw e_4.error; }
532
+ }
533
+ }
534
+ // CRITICAL: Always register experiment for tracking if ANY variant has ANY trigger type
535
+ // This prevents SRM even when user's variant doesn't match URL filter
536
+ if (hasAnyViewportTriggerInAnyVariant || hasAnyImmediateTriggerInAnyVariant) {
537
+ this.exposureTracker.registerExperiment(expName, currentVariant || 0, changes || [], allVariantChanges);
538
+ }
539
+ // Note: We do NOT call treatment() here anymore to avoid duplicate calls.
540
+ // The ExposureTracker.registerExperiment() will call triggerExposure() internally
541
+ // when hasImmediateTrigger is true (see ExposureTracker line 169-174).
542
+ // This prevents double treatment() calls that were causing test failures.
543
+ experimentStats.set(expName, stats);
544
+ (0, debug_1.logExperimentSummary)(expName, stats.total, stats.success, stats.pending);
545
+ }
546
+ }
547
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
548
+ finally {
549
+ try {
550
+ if (allExperiments_1_1 && !allExperiments_1_1.done && (_b = allExperiments_1.return)) _b.call(allExperiments_1);
551
+ }
552
+ finally { if (e_1) throw e_1.error; }
553
+ }
554
+ duration = performance.now() - startTime;
555
+ (0, debug_1.logPerformance)('Apply changes', duration, {
556
+ totalApplied: totalApplied,
557
+ experiments: experimentStats.size,
558
+ });
559
+ if (this.config.debug) {
560
+ (0, debug_1.logDebug)('[ABsmartly] === DOM Changes Application Complete ===');
561
+ (0, debug_1.logDebug)('[ABsmartly] Summary:', {
562
+ totalChangesApplied: totalApplied,
563
+ experimentsProcessed: experimentStats.size,
564
+ duration: "".concat(duration.toFixed(2), "ms"),
565
+ experiments: Array.from(experimentStats.entries()).map(function (_a) {
566
+ var _b = __read(_a, 2), name = _b[0], stats = _b[1];
567
+ return ({
568
+ name: name,
569
+ total: stats.total,
570
+ success: stats.success,
571
+ pending: stats.pending,
572
+ pendingReason: stats.pending > 0 ? 'Elements not found yet (SPA mode will retry)' : undefined,
573
+ });
574
+ }),
575
+ });
576
+ }
577
+ // Show hidden content after changes are applied
578
+ if (this.config.hideUntilReady) {
579
+ this.showContent();
580
+ }
581
+ this.emit('changes-applied', { count: totalApplied, experimentName: experimentName });
582
+ return [2 /*return*/];
583
+ }
584
+ });
585
+ });
586
+ };
587
+ /**
588
+ * Get all experiments with their variant data and metadata
589
+ */
590
+ DOMChangesPluginLite.prototype.getAllExperimentsData = function () {
591
+ var e_6, _a;
592
+ var experiments = new Map();
593
+ var allVariants = this.variantExtractor.extractAllChanges();
594
+ try {
595
+ for (var allVariants_1 = __values(allVariants), allVariants_1_1 = allVariants_1.next(); !allVariants_1_1.done; allVariants_1_1 = allVariants_1.next()) {
596
+ var _b = __read(allVariants_1_1.value, 1), expName = _b[0];
597
+ var currentVariant = this.config.context.peek(expName);
598
+ if (currentVariant === undefined || currentVariant === null) {
599
+ continue;
600
+ }
601
+ var variantsData = this.variantExtractor.getAllVariantsData(expName);
602
+ var variantData = variantsData.get(currentVariant);
603
+ if (!variantData) {
604
+ continue;
605
+ }
606
+ // Extract URL filter and global defaults if using wrapped format
607
+ var urlFilter = null;
608
+ var globalDefaults = {};
609
+ if (variantData &&
610
+ typeof variantData === 'object' &&
611
+ !Array.isArray(variantData) &&
612
+ 'changes' in variantData) {
613
+ var config = variantData;
614
+ urlFilter = config.urlFilter;
615
+ globalDefaults = {
616
+ waitForElement: config.waitForElement,
617
+ persistStyle: config.persistStyle,
618
+ important: config.important,
619
+ observerRoot: config.observerRoot,
620
+ };
621
+ }
622
+ experiments.set(expName, { variantData: variantData, urlFilter: urlFilter, globalDefaults: globalDefaults });
623
+ }
624
+ }
625
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
626
+ finally {
627
+ try {
628
+ if (allVariants_1_1 && !allVariants_1_1.done && (_a = allVariants_1.return)) _a.call(allVariants_1);
629
+ }
630
+ finally { if (e_6) throw e_6.error; }
631
+ }
632
+ return experiments;
633
+ };
634
+ /**
635
+ * Extract changes from DOMChangesData and apply global defaults
636
+ */
637
+ DOMChangesPluginLite.prototype.extractChangesFromData = function (data, globalDefaults) {
638
+ var changes = null;
639
+ // Extract changes array
640
+ if (Array.isArray(data)) {
641
+ changes = data;
642
+ }
643
+ else if (data && typeof data === 'object' && 'changes' in data) {
644
+ changes = data.changes;
645
+ }
646
+ if (!changes || changes.length === 0) {
647
+ return null;
648
+ }
649
+ // Apply global defaults to each change
650
+ return changes.map(function (change) {
651
+ var _a, _b, _c, _d;
652
+ return (__assign(__assign({}, change), { waitForElement: (_a = change.waitForElement) !== null && _a !== void 0 ? _a : globalDefaults.waitForElement, persistStyle: (_b = change.persistStyle) !== null && _b !== void 0 ? _b : globalDefaults.persistStyle, important: (_c = change.important) !== null && _c !== void 0 ? _c : globalDefaults.important, observerRoot: (_d = change.observerRoot) !== null && _d !== void 0 ? _d : globalDefaults.observerRoot }));
653
+ });
654
+ };
655
+ /**
656
+ * Extract all variant changes for cross-variant tracking
657
+ */
658
+ DOMChangesPluginLite.prototype.extractAllVariantChanges = function (experimentName) {
659
+ var allVariantChanges = this.variantExtractor.getAllVariantChanges(experimentName);
660
+ var variantsData = this.variantExtractor.getAllVariantsData(experimentName);
661
+ // Apply global defaults to each variant's changes
662
+ var processedVariants = [];
663
+ var _loop_1 = function (i) {
664
+ var variantChanges = allVariantChanges[i];
665
+ var variantData = variantsData.get(i);
666
+ if (!variantChanges || variantChanges.length === 0) {
667
+ processedVariants.push([]);
668
+ return "continue";
669
+ }
670
+ // Extract global defaults if using wrapped format
671
+ var globalDefaults = {};
672
+ if (variantData &&
673
+ typeof variantData === 'object' &&
674
+ !Array.isArray(variantData) &&
675
+ 'changes' in variantData) {
676
+ var config = variantData;
677
+ globalDefaults = {
678
+ waitForElement: config.waitForElement,
679
+ persistStyle: config.persistStyle,
680
+ important: config.important,
681
+ observerRoot: config.observerRoot,
682
+ };
683
+ }
684
+ // Apply global defaults
685
+ var processedChanges = variantChanges.map(function (change) {
686
+ var _a, _b, _c, _d;
687
+ return (__assign(__assign({}, change), { waitForElement: (_a = change.waitForElement) !== null && _a !== void 0 ? _a : globalDefaults.waitForElement, persistStyle: (_b = change.persistStyle) !== null && _b !== void 0 ? _b : globalDefaults.persistStyle, important: (_c = change.important) !== null && _c !== void 0 ? _c : globalDefaults.important, observerRoot: (_d = change.observerRoot) !== null && _d !== void 0 ? _d : globalDefaults.observerRoot }));
688
+ });
689
+ processedVariants.push(processedChanges);
690
+ };
691
+ for (var i = 0; i < allVariantChanges.length; i++) {
692
+ _loop_1(i);
693
+ }
694
+ return processedVariants;
695
+ };
696
+ /**
697
+ * Determine if visual changes should be applied based on URL filter
698
+ */
699
+ DOMChangesPluginLite.prototype.shouldApplyVisualChanges = function (variantData, urlFilter, url) {
700
+ // Legacy array format has no URL filter - always apply
701
+ if (Array.isArray(variantData)) {
702
+ return true;
703
+ }
704
+ // Wrapped format without URL filter - always apply
705
+ if (!urlFilter) {
706
+ return true;
707
+ }
708
+ // Check URL filter
709
+ return URLMatcher_1.URLMatcher.matches(urlFilter, url);
710
+ };
711
+ DOMChangesPluginLite.prototype.hasChanges = function (experimentName) {
712
+ return this.domManipulator.hasChanges(experimentName);
713
+ };
714
+ DOMChangesPluginLite.prototype.applyChange = function (change, experimentName) {
715
+ (0, debug_1.logDebug)('Applying single change via public API', {
716
+ experimentName: experimentName,
717
+ selector: change.selector,
718
+ changeType: change.type,
719
+ });
720
+ try {
721
+ var success = this.domManipulator.applyChange(change, experimentName);
722
+ if (success) {
723
+ this.emit('change_applied', {
724
+ experimentName: experimentName,
725
+ change: change,
726
+ });
727
+ }
728
+ return success;
729
+ }
730
+ catch (error) {
731
+ if (this.config.debug) {
732
+ (0, debug_1.logDebug)('[ABsmartly] Error applying change:', error);
733
+ }
734
+ return false;
735
+ }
736
+ };
737
+ DOMChangesPluginLite.prototype.on = function (event, callback) {
738
+ var listeners = this.eventListeners.get(event) || [];
739
+ listeners.push(callback);
740
+ this.eventListeners.set(event, listeners);
741
+ };
742
+ DOMChangesPluginLite.prototype.off = function (event, callback) {
743
+ if (!callback) {
744
+ this.eventListeners.delete(event);
745
+ }
746
+ else {
747
+ var listeners = this.eventListeners.get(event) || [];
748
+ var index = listeners.indexOf(callback);
749
+ if (index !== -1) {
750
+ listeners.splice(index, 1);
751
+ }
752
+ }
753
+ };
754
+ DOMChangesPluginLite.prototype.emit = function (event, data) {
755
+ var e_7, _a;
756
+ var listeners = this.eventListeners.get(event) || [];
757
+ try {
758
+ for (var listeners_1 = __values(listeners), listeners_1_1 = listeners_1.next(); !listeners_1_1.done; listeners_1_1 = listeners_1.next()) {
759
+ var callback = listeners_1_1.value;
760
+ try {
761
+ callback(data);
762
+ }
763
+ catch (error) {
764
+ (0, debug_1.logDebug)("[ABsmartly] Error in event listener for ".concat(event, ":"), error);
765
+ }
766
+ }
767
+ }
768
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
769
+ finally {
770
+ try {
771
+ if (listeners_1_1 && !listeners_1_1.done && (_a = listeners_1.return)) _a.call(listeners_1);
772
+ }
773
+ finally { if (e_7) throw e_7.error; }
774
+ }
775
+ };
776
+ DOMChangesPluginLite.prototype.getStyleManager = function (experimentName) {
777
+ var id = "absmartly-styles-".concat(experimentName);
778
+ var manager = this.styleManagers.get(experimentName);
779
+ if (!manager) {
780
+ manager = new StyleSheetManager_1.StyleSheetManager(id, this.config.debug);
781
+ this.styleManagers.set(experimentName, manager);
782
+ }
783
+ return manager;
784
+ };
785
+ DOMChangesPluginLite.prototype.buildCssRule = function (selector, properties, important) {
786
+ if (important === void 0) { important = true; }
787
+ var declarations = Object.entries(properties)
788
+ .map(function (_a) {
789
+ var _b = __read(_a, 2), prop = _b[0], value = _b[1];
790
+ var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
791
+ var bang = important ? ' !important' : '';
792
+ return " ".concat(cssProp, ": ").concat(value).concat(bang, ";");
793
+ })
794
+ .join('\n');
795
+ return "".concat(selector, " {\n").concat(declarations, "\n}");
796
+ };
797
+ DOMChangesPluginLite.prototype.buildStateRules = function (selector, states, important) {
798
+ if (important === void 0) { important = true; }
799
+ var rules = [];
800
+ if (states.normal) {
801
+ rules.push(this.buildCssRule(selector, states.normal, important));
802
+ }
803
+ if (states.hover) {
804
+ rules.push(this.buildCssRule("".concat(selector, ":hover"), states.hover, important));
805
+ }
806
+ if (states.active) {
807
+ rules.push(this.buildCssRule("".concat(selector, ":active"), states.active, important));
808
+ }
809
+ if (states.focus) {
810
+ rules.push(this.buildCssRule("".concat(selector, ":focus"), states.focus, important));
811
+ }
812
+ return rules.join('\n\n');
813
+ };
814
+ DOMChangesPluginLite.prototype.refreshExperiments = function () {
815
+ if (this.config.debug) {
816
+ (0, debug_1.logDebug)('[ABsmartly] Refreshing experiments and clearing cache');
817
+ }
818
+ this.variantExtractor.clearCache();
819
+ if (this.config.autoApply) {
820
+ this.applyInjectionsAndChanges();
821
+ }
822
+ };
823
+ DOMChangesPluginLite.prototype.destroy = function () {
824
+ this.domManipulator.destroy();
825
+ this.exposureTracker.destroy();
826
+ this.htmlInjector.destroy();
827
+ this.styleManagers.forEach(function (manager) { return manager.destroy(); });
828
+ this.styleManagers.clear();
829
+ if (this.mutationObserver) {
830
+ this.mutationObserver.disconnect();
831
+ this.mutationObserver = null;
832
+ }
833
+ if (this.persistenceObserver) {
834
+ this.persistenceObserver.disconnect();
835
+ this.persistenceObserver = null;
836
+ }
837
+ // Clean up anti-flicker timeout and style
838
+ if (this.antiFlickerTimeout !== null) {
839
+ clearTimeout(this.antiFlickerTimeout);
840
+ this.antiFlickerTimeout = null;
841
+ }
842
+ var antiFlickerStyle = document.getElementById(this.antiFlickerStyleId);
843
+ if (antiFlickerStyle) {
844
+ antiFlickerStyle.remove();
845
+ }
846
+ this.eventListeners.clear();
847
+ this.exposedExperiments.clear();
848
+ this.watchedElements = new WeakMap();
849
+ this.appliedStyleChanges.clear();
850
+ this.reapplyingElements.clear();
851
+ this.reapplyLogThrottle.clear();
852
+ this.unregisterFromContext();
853
+ this.initialized = false;
854
+ if (this.config.debug) {
855
+ (0, debug_1.logDebug)('[ABsmartly] DOM Changes Plugin Lite destroyed');
856
+ }
857
+ };
858
+ DOMChangesPluginLite.prototype.registerWithContext = function () {
859
+ if (this.config.context) {
860
+ if (!this.config.context.__plugins) {
861
+ this.config.context.__plugins = {};
862
+ }
863
+ this.config.context.__plugins.domPlugin = {
864
+ name: 'DOMChangesPluginLite',
865
+ version: DOMChangesPluginLite.VERSION,
866
+ initialized: true,
867
+ capabilities: ['spa', 'visibility'],
868
+ instance: this,
869
+ timestamp: Date.now(),
870
+ };
871
+ this.config.context.__domPlugin = this.config.context.__plugins.domPlugin;
872
+ if (this.config.debug) {
873
+ (0, debug_1.logDebug)('[ABsmartly] DOMChangesPluginLite registered with context at __plugins.domPlugin');
874
+ }
875
+ }
876
+ };
877
+ DOMChangesPluginLite.prototype.unregisterFromContext = function () {
878
+ var _a;
879
+ if (this.config.context) {
880
+ if ((_a = this.config.context.__plugins) === null || _a === void 0 ? void 0 : _a.domPlugin) {
881
+ delete this.config.context.__plugins.domPlugin;
882
+ }
883
+ if (this.config.context.__domPlugin) {
884
+ delete this.config.context.__domPlugin;
885
+ }
886
+ if (this.config.debug) {
887
+ (0, debug_1.logDebug)('[ABsmartly] DOMChangesPluginLite unregistered from context');
888
+ }
889
+ }
890
+ };
891
+ /**
892
+ * Hide content to prevent flicker before experiments are applied
893
+ */
894
+ DOMChangesPluginLite.prototype.hideContent = function () {
895
+ var _this = this;
896
+ var mode = this.config.hideUntilReady;
897
+ if (!mode)
898
+ return;
899
+ // Check if style already exists (prevent duplicate injection)
900
+ if (document.getElementById(this.antiFlickerStyleId)) {
901
+ return;
902
+ }
903
+ var style = document.createElement('style');
904
+ style.id = this.antiFlickerStyleId;
905
+ var hasTransition = this.config.hideTransition !== false;
906
+ var selector = mode === 'body' ? 'body' : this.config.hideSelector || '[data-absmartly-hide]';
907
+ if (hasTransition) {
908
+ // Use both visibility:hidden and opacity:0 for smooth transition
909
+ style.textContent = "\n ".concat(selector, " {\n visibility: hidden !important;\n opacity: 0 !important;\n }\n ");
910
+ }
911
+ else {
912
+ // Use only visibility:hidden for instant reveal (no layout shift)
913
+ style.textContent = "\n ".concat(selector, " {\n visibility: hidden !important;\n }\n ");
914
+ }
915
+ document.head.appendChild(style);
916
+ // Set timeout to show content even if experiments fail to load
917
+ this.antiFlickerTimeout = window.setTimeout(function () {
918
+ if (_this.config.debug) {
919
+ (0, debug_1.logDebug)("[ABsmartly] Anti-flicker timeout reached (".concat(_this.config.hideTimeout, "ms), showing content"));
920
+ }
921
+ _this.showContent();
922
+ }, this.config.hideTimeout);
923
+ if (this.config.debug) {
924
+ (0, debug_1.logDebug)("[ABsmartly] Anti-flicker enabled (mode: ".concat(mode, ", transition: ").concat(hasTransition ? this.config.hideTransition : 'none', ", timeout: ").concat(this.config.hideTimeout, "ms)"));
925
+ }
926
+ };
927
+ /**
928
+ * Show hidden content after experiments are applied
929
+ */
930
+ DOMChangesPluginLite.prototype.showContent = function () {
931
+ var _this = this;
932
+ // Clear timeout if still pending
933
+ if (this.antiFlickerTimeout !== null) {
934
+ clearTimeout(this.antiFlickerTimeout);
935
+ this.antiFlickerTimeout = null;
936
+ }
937
+ var style = document.getElementById(this.antiFlickerStyleId);
938
+ if (!style)
939
+ return;
940
+ var hasTransition = this.config.hideTransition !== false;
941
+ if (hasTransition) {
942
+ // Smooth fade-in: remove visibility, add transition, then animate opacity
943
+ var mode = this.config.hideUntilReady;
944
+ var selector = mode === 'body' ? 'body' : this.config.hideSelector || '[data-absmartly-hide]';
945
+ // Step 1: Remove visibility:hidden, keep opacity:0, add transition
946
+ style.textContent = "\n ".concat(selector, " {\n opacity: 0 !important;\n transition: opacity ").concat(this.config.hideTransition, " !important;\n }\n ");
947
+ // Step 2: Force reflow to ensure transition applies
948
+ style.offsetHeight;
949
+ // Step 3: Trigger fade-in by setting opacity to 1
950
+ style.textContent = "\n ".concat(selector, " {\n opacity: 1 !important;\n transition: opacity ").concat(this.config.hideTransition, " !important;\n }\n ");
951
+ // Step 4: Remove style after transition completes
952
+ var transitionDuration = parseFloat(this.config.hideTransition) * 1000;
953
+ setTimeout(function () {
954
+ style.remove();
955
+ if (_this.config.debug) {
956
+ (0, debug_1.logDebug)('[ABsmartly] Anti-flicker fade-in complete, style removed');
957
+ }
958
+ }, transitionDuration);
959
+ if (this.config.debug) {
960
+ (0, debug_1.logDebug)("[ABsmartly] Anti-flicker fading in with transition: ".concat(this.config.hideTransition));
961
+ }
962
+ }
963
+ else {
964
+ // Instant reveal: just remove the style
965
+ style.remove();
966
+ if (this.config.debug) {
967
+ (0, debug_1.logDebug)('[ABsmartly] Anti-flicker removed, content now visible');
968
+ }
969
+ }
970
+ };
971
+ DOMChangesPluginLite.prototype.watchElement = function (element, experimentName, change) {
972
+ var experiments = this.watchedElements.get(element);
973
+ if (!experiments) {
974
+ experiments = new Set();
975
+ this.watchedElements.set(element, experiments);
976
+ }
977
+ experiments.add(experimentName);
978
+ // Store the applied style change for this experiment
979
+ if (!this.appliedStyleChanges.has(experimentName)) {
980
+ this.appliedStyleChanges.set(experimentName, []);
981
+ }
982
+ var changes = this.appliedStyleChanges.get(experimentName);
983
+ var isNewWatch = !changes.includes(change);
984
+ if (isNewWatch) {
985
+ changes.push(change);
986
+ // Only log when actually adding a new watch, not on every reapply
987
+ if (this.config.debug) {
988
+ (0, debug_1.logDebug)('[ABsmartly] Watching element for style persistence', {
989
+ experimentName: experimentName,
990
+ selector: change.selector,
991
+ element: element.tagName,
992
+ });
993
+ }
994
+ }
995
+ if (!this.persistenceObserver) {
996
+ this.setupPersistenceObserver();
997
+ }
998
+ };
999
+ DOMChangesPluginLite.prototype.unwatchElement = function (element, experimentName) {
1000
+ var experiments = this.watchedElements.get(element);
1001
+ if (experiments) {
1002
+ experiments.delete(experimentName);
1003
+ if (experiments.size === 0) {
1004
+ this.watchedElements.delete(element);
1005
+ }
1006
+ }
1007
+ };
1008
+ DOMChangesPluginLite.prototype.setupPersistenceObserver = function () {
1009
+ var _this = this;
1010
+ if (this.persistenceObserver)
1011
+ return;
1012
+ this.persistenceObserver = new MutationObserver(function (mutations) {
1013
+ mutations.forEach(function (mutation) {
1014
+ var element = mutation.target;
1015
+ if (_this.reapplyingElements.has(element)) {
1016
+ return;
1017
+ }
1018
+ var experiments = _this.watchedElements.get(element);
1019
+ if (experiments) {
1020
+ // Throttle mutation detection logs to once per 5 seconds per element
1021
+ if (_this.config.debug) {
1022
+ var elementKey = "mutation:".concat(element.tagName, ":").concat(element.getAttribute('name') || element.className);
1023
+ var now = Date.now();
1024
+ var lastLogged = _this.reapplyLogThrottle.get(elementKey) || 0;
1025
+ if (now - lastLogged > 5000) {
1026
+ (0, debug_1.logDebug)('[ABsmartly] Style mutation detected on watched element', {
1027
+ element: element.tagName,
1028
+ selector: element.getAttribute('name') || element.className,
1029
+ oldValue: mutation.oldValue,
1030
+ });
1031
+ _this.reapplyLogThrottle.set(elementKey, now);
1032
+ }
1033
+ }
1034
+ experiments.forEach(function (experimentName) {
1035
+ var appliedChanges = _this.appliedStyleChanges.get(experimentName);
1036
+ if (appliedChanges) {
1037
+ appliedChanges.forEach(function (change) {
1038
+ var e_8, _a;
1039
+ if (change.type === 'style' && element.matches(change.selector)) {
1040
+ var needsReapply = _this.checkStyleOverwritten(element, change.value);
1041
+ if (needsReapply) {
1042
+ _this.reapplyingElements.add(element);
1043
+ _this.domManipulator.applyChange(change, experimentName);
1044
+ var logKey = "".concat(experimentName, "-").concat(change.selector);
1045
+ var now = Date.now();
1046
+ var lastLogged = _this.reapplyLogThrottle.get(logKey) || 0;
1047
+ if (_this.config.debug && now - lastLogged > 5000) {
1048
+ (0, debug_1.logDebug)('Reapplied style after mutation (React/framework conflict detected)', {
1049
+ experimentName: experimentName,
1050
+ selector: change.selector,
1051
+ note: 'This happens when the page framework (React/Vue/etc) fights with DOM changes',
1052
+ });
1053
+ _this.reapplyLogThrottle.set(logKey, now);
1054
+ // Cleanup old throttle entries to prevent memory leak
1055
+ if (_this.reapplyLogThrottle.size > 100) {
1056
+ var oldestAllowed = now - 60000; // 1 minute
1057
+ try {
1058
+ for (var _b = __values(_this.reapplyLogThrottle.entries()), _c = _b.next(); !_c.done; _c = _b.next()) {
1059
+ var _d = __read(_c.value, 2), key = _d[0], time = _d[1];
1060
+ if (time < oldestAllowed) {
1061
+ _this.reapplyLogThrottle.delete(key);
1062
+ }
1063
+ }
1064
+ }
1065
+ catch (e_8_1) { e_8 = { error: e_8_1 }; }
1066
+ finally {
1067
+ try {
1068
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1069
+ }
1070
+ finally { if (e_8) throw e_8.error; }
1071
+ }
1072
+ }
1073
+ }
1074
+ setTimeout(function () {
1075
+ _this.reapplyingElements.delete(element);
1076
+ }, 0);
1077
+ }
1078
+ else if (_this.config.debug) {
1079
+ (0, debug_1.logDebug)('[ABsmartly] Style mutation detected but no reapply needed', {
1080
+ experimentName: experimentName,
1081
+ selector: change.selector,
1082
+ });
1083
+ }
1084
+ }
1085
+ });
1086
+ }
1087
+ });
1088
+ }
1089
+ });
1090
+ });
1091
+ this.persistenceObserver.observe(document.body, {
1092
+ attributes: true,
1093
+ attributeFilter: ['style'],
1094
+ subtree: true,
1095
+ attributeOldValue: true,
1096
+ });
1097
+ if (this.config.debug) {
1098
+ (0, debug_1.logDebug)('[ABsmartly] Style persistence observer setup complete');
1099
+ }
1100
+ };
1101
+ DOMChangesPluginLite.prototype.checkStyleOverwritten = function (element, expectedStyles) {
1102
+ var e_9, _a;
1103
+ try {
1104
+ for (var _b = __values(Object.entries(expectedStyles)), _c = _b.next(); !_c.done; _c = _b.next()) {
1105
+ var _d = __read(_c.value, 2), prop = _d[0], value = _d[1];
1106
+ var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
1107
+ var currentValue = element.style.getPropertyValue(cssProp);
1108
+ var currentPriority = element.style.getPropertyPriority(cssProp);
1109
+ if (currentValue !== value || (value.includes('!important') && !currentPriority)) {
1110
+ return true;
1111
+ }
1112
+ }
1113
+ }
1114
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
1115
+ finally {
1116
+ try {
1117
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1118
+ }
1119
+ finally { if (e_9) throw e_9.error; }
1120
+ }
1121
+ return false;
1122
+ };
1123
+ DOMChangesPluginLite.VERSION = '1.0.0-lite';
1124
+ return DOMChangesPluginLite;
1125
+ }());
1126
+ exports.DOMChangesPluginLite = DOMChangesPluginLite;
1127
+ //# sourceMappingURL=DOMChangesPluginLite.js.map