@absmartly/sdk-plugins 1.2.2 → 1.3.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/analytics/AnalyticsPlugin.js +96 -0
- package/es/analytics/AnalyticsPlugin.js.map +1 -0
- package/es/analytics/index.js +2 -0
- package/es/analytics/index.js.map +1 -0
- package/es/analytics/types.js +2 -0
- package/es/analytics/types.js.map +1 -0
- package/es/cookies/CookiePlugin.js +59 -18
- package/es/cookies/CookiePlugin.js.map +1 -1
- package/es/core/DOMChangesPluginLite.js +217 -106
- package/es/core/DOMChangesPluginLite.js.map +1 -1
- package/es/core/DOMManipulatorLite.js +285 -153
- package/es/core/DOMManipulatorLite.js.map +1 -1
- package/es/core/ExposureTracker.js +310 -108
- package/es/core/ExposureTracker.js.map +1 -1
- package/es/core/HTMLInjector.js +11 -1
- package/es/core/HTMLInjector.js.map +1 -1
- package/es/core/PendingChangeManager.js +114 -54
- package/es/core/PendingChangeManager.js.map +1 -1
- package/es/generated/buildInfo.js +1 -1
- package/es/index.js +1 -0
- package/es/index.js.map +1 -1
- package/es/overrides/BrowserCookieAdapter.js +3 -31
- package/es/overrides/BrowserCookieAdapter.js.map +1 -1
- package/es/overrides/OverridesPlugin.js +39 -107
- package/es/overrides/OverridesPlugin.js.map +1 -1
- package/es/overrides/OverridesPluginLite.js +5 -136
- package/es/overrides/OverridesPluginLite.js.map +1 -1
- package/es/parsers/VariantExtractor.js +21 -18
- package/es/parsers/VariantExtractor.js.map +1 -1
- package/es/url-redirect/URLRedirectExtractor.js +8 -2
- package/es/url-redirect/URLRedirectExtractor.js.map +1 -1
- package/es/url-redirect/URLRedirectMatcher.js +130 -0
- package/es/url-redirect/URLRedirectMatcher.js.map +1 -1
- package/es/url-redirect/URLRedirectPlugin.js +14 -5
- package/es/url-redirect/URLRedirectPlugin.js.map +1 -1
- package/es/utils/URLMatcher.js.map +1 -1
- package/es/utils/debug.js +11 -0
- package/es/utils/debug.js.map +1 -1
- package/es/utils/persistence.js +143 -75
- package/es/utils/persistence.js.map +1 -1
- package/es/utils/plugin-registry.js.map +1 -1
- package/es/vitals/WebVitalsPlugin.js +9 -4
- package/es/vitals/WebVitalsPlugin.js.map +1 -1
- package/lib/analytics/AnalyticsPlugin.d.ts +8 -0
- package/lib/analytics/AnalyticsPlugin.js +99 -0
- package/lib/analytics/AnalyticsPlugin.js.map +1 -0
- package/lib/analytics/index.d.ts +2 -0
- package/lib/analytics/index.js +6 -0
- package/lib/analytics/index.js.map +1 -0
- package/lib/analytics/types.d.ts +5 -0
- package/lib/analytics/types.js +3 -0
- package/lib/analytics/types.js.map +1 -0
- package/lib/cookies/CookiePlugin.js +59 -18
- package/lib/cookies/CookiePlugin.js.map +1 -1
- package/lib/core/DOMChangesPluginLite.d.ts +5 -2
- package/lib/core/DOMChangesPluginLite.js +217 -106
- package/lib/core/DOMChangesPluginLite.js.map +1 -1
- package/lib/core/DOMManipulatorLite.d.ts +24 -0
- package/lib/core/DOMManipulatorLite.js +284 -152
- package/lib/core/DOMManipulatorLite.js.map +1 -1
- package/lib/core/ExposureTracker.js +310 -108
- package/lib/core/ExposureTracker.js.map +1 -1
- package/lib/core/HTMLInjector.d.ts +1 -0
- package/lib/core/HTMLInjector.js +11 -1
- package/lib/core/HTMLInjector.js.map +1 -1
- package/lib/core/PendingChangeManager.js +114 -54
- package/lib/core/PendingChangeManager.js.map +1 -1
- package/lib/generated/buildInfo.d.ts +1 -1
- package/lib/generated/buildInfo.js +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/overrides/BrowserCookieAdapter.js +3 -31
- package/lib/overrides/BrowserCookieAdapter.js.map +1 -1
- package/lib/overrides/OverridesPlugin.js +39 -107
- package/lib/overrides/OverridesPlugin.js.map +1 -1
- package/lib/overrides/OverridesPluginLite.d.ts +5 -1
- package/lib/overrides/OverridesPluginLite.js +5 -136
- package/lib/overrides/OverridesPluginLite.js.map +1 -1
- package/lib/parsers/VariantExtractor.js +21 -18
- package/lib/parsers/VariantExtractor.js.map +1 -1
- package/lib/types/index.d.ts +5 -0
- package/lib/url-redirect/URLRedirectExtractor.js +8 -2
- package/lib/url-redirect/URLRedirectExtractor.js.map +1 -1
- package/lib/url-redirect/URLRedirectMatcher.d.ts +3 -0
- package/lib/url-redirect/URLRedirectMatcher.js +130 -0
- package/lib/url-redirect/URLRedirectMatcher.js.map +1 -1
- package/lib/url-redirect/URLRedirectPlugin.js +13 -4
- package/lib/url-redirect/URLRedirectPlugin.js.map +1 -1
- package/lib/url-redirect/types.d.ts +1 -1
- package/lib/utils/URLMatcher.d.ts +1 -7
- package/lib/utils/URLMatcher.js.map +1 -1
- package/lib/utils/debug.d.ts +5 -0
- package/lib/utils/debug.js +12 -0
- package/lib/utils/debug.js.map +1 -1
- package/lib/utils/persistence.js +143 -75
- package/lib/utils/persistence.js.map +1 -1
- package/lib/utils/plugin-registry.d.ts +1 -0
- package/lib/utils/plugin-registry.js.map +1 -1
- package/lib/vitals/WebVitalsPlugin.js +9 -4
- package/lib/vitals/WebVitalsPlugin.js.map +1 -1
- package/package.json +13 -3
- package/types/analytics/AnalyticsPlugin.d.ts +8 -0
- package/types/analytics/index.d.ts +2 -0
- package/types/analytics/types.d.ts +5 -0
- package/types/core/DOMChangesPluginLite.d.ts +5 -2
- package/types/core/DOMManipulatorLite.d.ts +24 -0
- package/types/core/HTMLInjector.d.ts +1 -0
- package/types/generated/buildInfo.d.ts +1 -1
- package/types/index.d.ts +2 -0
- package/types/overrides/OverridesPluginLite.d.ts +5 -1
- package/types/types/index.d.ts +5 -0
- package/types/url-redirect/URLRedirectMatcher.d.ts +3 -0
- package/types/url-redirect/types.d.ts +1 -1
- package/types/utils/URLMatcher.d.ts +1 -7
- package/types/utils/debug.d.ts +5 -0
- package/types/utils/plugin-registry.d.ts +1 -0
|
@@ -53,9 +53,120 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
53
53
|
return _this.applyChange(change, experimentName);
|
|
54
54
|
}, debug);
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Execute a user-authored JavaScript DOM change against an element.
|
|
58
|
+
*
|
|
59
|
+
* Strategy:
|
|
60
|
+
* 1. Primary path uses `new Function(...)`. On pages whose CSP includes
|
|
61
|
+
* `unsafe-eval` this succeeds and keeps the fast debug-friendly path
|
|
62
|
+
* with a `//# sourceURL` tag.
|
|
63
|
+
* 2. When CSP blocks dynamic code evaluation the fallback injects a
|
|
64
|
+
* one-shot `<script>` element that calls an anonymous IIFE with the
|
|
65
|
+
* target element bound through a temporary `window` slot. This path
|
|
66
|
+
* works on pages that allow inline scripts but not eval.
|
|
67
|
+
* 3. If both paths fail, the error is logged unconditionally at
|
|
68
|
+
* `console.error` and surfaced via a `CustomEvent('absmartly:js-error', ...)`
|
|
69
|
+
* on `document` so hosting code (browser extension preview, telemetry,
|
|
70
|
+
* etc.) can distinguish CSP failures from runtime errors.
|
|
71
|
+
*
|
|
72
|
+
* Returns true when the code executed successfully through either path.
|
|
73
|
+
*/
|
|
74
|
+
DOMManipulatorLite.prototype.executeUserJavaScript = function (code, element, experimentName, selector) {
|
|
75
|
+
var sourceTag = "absmartly-experiment-".concat(experimentName || 'unknown', ".js");
|
|
76
|
+
var debugPrelude = "var _debug = (typeof _debug !== 'undefined' ? _debug : { debugLog: console.log.bind(console), debugWarn: console.warn.bind(console), debugError: console.error.bind(console) });\n";
|
|
77
|
+
try {
|
|
78
|
+
var fn = new Function('element', debugPrelude + code + "\n//# sourceURL=".concat(sourceTag));
|
|
79
|
+
fn(element);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch (evalError) {
|
|
83
|
+
var evalMessage = evalError instanceof Error ? evalError.message : String(evalError);
|
|
84
|
+
var cspBlockedEval = evalError instanceof EvalError ||
|
|
85
|
+
/unsafe-eval|Content Security Policy|CSP|refused to evaluate/i.test(evalMessage);
|
|
86
|
+
if (!cspBlockedEval) {
|
|
87
|
+
// Runtime error in user code — don't try the fallback, surface immediately.
|
|
88
|
+
this.reportJsExecutionFailure({
|
|
89
|
+
experimentName: experimentName,
|
|
90
|
+
selector: selector,
|
|
91
|
+
reason: 'runtime',
|
|
92
|
+
error: evalMessage,
|
|
93
|
+
stack: evalError instanceof Error ? evalError.stack : undefined,
|
|
94
|
+
});
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
// Fallback: inline <script> tag that binds the element through a temporary window slot.
|
|
98
|
+
// When CSP blocks inline scripts, appendChild does NOT throw — Chrome silently refuses
|
|
99
|
+
// execution and logs a console violation. We detect that by flipping a sentinel inside
|
|
100
|
+
// the injected script and checking it after append.
|
|
101
|
+
try {
|
|
102
|
+
var slotId = "__absmartly_js_target_".concat(Date.now(), "_").concat(Math.floor(Math.random() * 1e9));
|
|
103
|
+
var sentinelId = "".concat(slotId, "_ran");
|
|
104
|
+
window[slotId] = element;
|
|
105
|
+
window[sentinelId] = false;
|
|
106
|
+
var script = document.createElement('script');
|
|
107
|
+
script.textContent =
|
|
108
|
+
"(function(element){".concat(debugPrelude).concat(code, "\n})(window['").concat(slotId, "']);\n") +
|
|
109
|
+
"window['".concat(sentinelId, "'] = true;\n") +
|
|
110
|
+
"try { delete window['".concat(slotId, "']; } catch(_e) { window['").concat(slotId, "'] = undefined; }\n") +
|
|
111
|
+
"//# sourceURL=".concat(sourceTag);
|
|
112
|
+
var parent_1 = document.head || document.documentElement;
|
|
113
|
+
parent_1.appendChild(script);
|
|
114
|
+
script.remove();
|
|
115
|
+
var ran = window[sentinelId] === true;
|
|
116
|
+
try {
|
|
117
|
+
delete window[sentinelId];
|
|
118
|
+
}
|
|
119
|
+
catch (_a) {
|
|
120
|
+
window[sentinelId] = undefined;
|
|
121
|
+
}
|
|
122
|
+
if (!ran) {
|
|
123
|
+
this.reportJsExecutionFailure({
|
|
124
|
+
experimentName: experimentName,
|
|
125
|
+
selector: selector,
|
|
126
|
+
reason: 'csp',
|
|
127
|
+
error: "CSP blocked dynamic script execution. eval(): ".concat(evalMessage, "; inline <script> did not execute (likely blocked by script-src without 'unsafe-inline')."),
|
|
128
|
+
});
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
catch (scriptError) {
|
|
134
|
+
var scriptMessage = scriptError instanceof Error ? scriptError.message : String(scriptError);
|
|
135
|
+
this.reportJsExecutionFailure({
|
|
136
|
+
experimentName: experimentName,
|
|
137
|
+
selector: selector,
|
|
138
|
+
reason: 'csp',
|
|
139
|
+
error: "CSP blocked dynamic script execution. eval(): ".concat(evalMessage, "; inline <script>: ").concat(scriptMessage),
|
|
140
|
+
stack: scriptError instanceof Error ? scriptError.stack : undefined,
|
|
141
|
+
});
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Report a JavaScript execution failure to listeners, without relying on this.debug.
|
|
148
|
+
* Always logs at `console.error` and dispatches a `CustomEvent` on `document`.
|
|
149
|
+
*/
|
|
150
|
+
DOMManipulatorLite.prototype.reportJsExecutionFailure = function (detail) {
|
|
151
|
+
try {
|
|
152
|
+
(0, debug_1.logProductionWarn)("[ABsmartly] JavaScript DOM change failed (".concat(detail.reason, ") for \"").concat(detail.experimentName, "\" selector \"").concat(detail.selector, "\": ").concat(detail.error), detail.stack ? { stack: detail.stack } : undefined);
|
|
153
|
+
}
|
|
154
|
+
catch (_a) {
|
|
155
|
+
// console unavailable; ignore
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
if (typeof document !== 'undefined' && typeof CustomEvent === 'function') {
|
|
159
|
+
document.dispatchEvent(new CustomEvent('absmartly:js-error', { detail: detail }));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (_b) {
|
|
163
|
+
// environments without CustomEvent support
|
|
164
|
+
}
|
|
165
|
+
};
|
|
56
166
|
DOMManipulatorLite.prototype.applyChange = function (change, experimentName) {
|
|
167
|
+
var e_1, _a, e_2, _b, e_3, _c;
|
|
57
168
|
var _this = this;
|
|
58
|
-
var
|
|
169
|
+
var _d, _e, _f, _g, _h, _j, _k, _l;
|
|
59
170
|
if (!change.enabled && change.enabled !== undefined) {
|
|
60
171
|
(0, debug_1.logDebug)("Skipping disabled change for experiment: ".concat(experimentName), {
|
|
61
172
|
experimentName: experimentName,
|
|
@@ -67,7 +178,7 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
67
178
|
var isReapplying = !!this.plugin.reapplyingElements &&
|
|
68
179
|
Array.from(this.plugin.reapplyingElements).length > 0;
|
|
69
180
|
// Get user's variant for this experiment
|
|
70
|
-
var userVariant = (
|
|
181
|
+
var userVariant = (_e = (_d = this.plugin.config) === null || _d === void 0 ? void 0 : _d.context) === null || _e === void 0 ? void 0 : _e.peek(experimentName);
|
|
71
182
|
if (this.debug) {
|
|
72
183
|
(0, debug_1.logDebug)("[DOM-APPLY] [".concat(experimentName, "] ").concat(isReapplying ? 'RE-APPLYING' : 'APPLYING', " change"), {
|
|
73
184
|
experimentName: experimentName,
|
|
@@ -75,7 +186,7 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
75
186
|
selector: change.selector,
|
|
76
187
|
type: change.type,
|
|
77
188
|
timestamp: Date.now(),
|
|
78
|
-
callStack: (
|
|
189
|
+
callStack: (_f = new Error().stack) === null || _f === void 0 ? void 0 : _f.split('\n').slice(2, 4).join('\n'),
|
|
79
190
|
});
|
|
80
191
|
}
|
|
81
192
|
try {
|
|
@@ -95,10 +206,10 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
95
206
|
return false;
|
|
96
207
|
}
|
|
97
208
|
var elements = document.querySelectorAll(change.selector);
|
|
98
|
-
var
|
|
209
|
+
var appliedElements = [];
|
|
99
210
|
if (elements.length === 0) {
|
|
100
211
|
// Add to pending if waitForElement is explicitly true OR if SPA mode is enabled
|
|
101
|
-
var shouldWaitForElement = change.waitForElement || ((
|
|
212
|
+
var shouldWaitForElement = change.waitForElement || ((_g = this.plugin.config) === null || _g === void 0 ? void 0 : _g.spa);
|
|
102
213
|
if (shouldWaitForElement) {
|
|
103
214
|
if (this.debug) {
|
|
104
215
|
(0, debug_1.logDebug)("[ABsmartly] Element not found, adding to pending: ".concat(change.selector));
|
|
@@ -120,45 +231,65 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
120
231
|
});
|
|
121
232
|
return false;
|
|
122
233
|
}
|
|
123
|
-
|
|
124
|
-
var
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
234
|
+
try {
|
|
235
|
+
for (var elements_1 = __values(elements), elements_1_1 = elements_1.next(); !elements_1_1.done; elements_1_1 = elements_1.next()) {
|
|
236
|
+
var element = elements_1_1.value;
|
|
237
|
+
if (this.debug && change.type === 'style') {
|
|
238
|
+
var oldStyles = {};
|
|
239
|
+
if (change.value && typeof change.value === 'object') {
|
|
240
|
+
try {
|
|
241
|
+
for (var _m = (e_2 = void 0, __values(Object.keys(change.value))), _o = _m.next(); !_o.done; _o = _m.next()) {
|
|
242
|
+
var prop = _o.value;
|
|
243
|
+
var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
244
|
+
oldStyles[cssProp] = element.style.getPropertyValue(cssProp);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
248
|
+
finally {
|
|
249
|
+
try {
|
|
250
|
+
if (_o && !_o.done && (_b = _m.return)) _b.call(_m);
|
|
251
|
+
}
|
|
252
|
+
finally { if (e_2) throw e_2.error; }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
(0, debug_1.logDebug)("[DOM-BEFORE-APPLY] Element styles before change", {
|
|
256
|
+
experimentName: experimentName,
|
|
257
|
+
selector: change.selector,
|
|
258
|
+
element: element.tagName,
|
|
259
|
+
oldStyles: oldStyles,
|
|
260
|
+
newStyles: change.value,
|
|
131
261
|
});
|
|
132
262
|
}
|
|
133
|
-
(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
263
|
+
this.applyChangeToElement(element, change);
|
|
264
|
+
if (this.debug && change.type === 'style') {
|
|
265
|
+
var appliedStyles = {};
|
|
266
|
+
if (change.value && typeof change.value === 'object') {
|
|
267
|
+
try {
|
|
268
|
+
for (var _p = (e_3 = void 0, __values(Object.keys(change.value))), _q = _p.next(); !_q.done; _q = _p.next()) {
|
|
269
|
+
var prop = _q.value;
|
|
270
|
+
var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
271
|
+
appliedStyles[cssProp] = element.style.getPropertyValue(cssProp);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
275
|
+
finally {
|
|
276
|
+
try {
|
|
277
|
+
if (_q && !_q.done && (_c = _p.return)) _c.call(_p);
|
|
278
|
+
}
|
|
279
|
+
finally { if (e_3) throw e_3.error; }
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
(0, debug_1.logDebug)("[DOM-AFTER-APPLY] Element styles after change", {
|
|
283
|
+
experimentName: experimentName,
|
|
284
|
+
selector: change.selector,
|
|
285
|
+
element: element.tagName,
|
|
286
|
+
appliedStyles: appliedStyles,
|
|
148
287
|
});
|
|
149
288
|
}
|
|
150
|
-
(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
appliedStyles: appliedStyles_1,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
if (change.type === 'javascript') {
|
|
158
|
-
if (change.value) {
|
|
159
|
-
var userVariant_1 = (_b = (_a = _this.plugin.config) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b.peek(experimentName);
|
|
160
|
-
try {
|
|
161
|
-
if (_this.debug) {
|
|
289
|
+
if (change.type === 'javascript') {
|
|
290
|
+
if (change.value) {
|
|
291
|
+
var userVariant_1 = (_j = (_h = this.plugin.config) === null || _h === void 0 ? void 0 : _h.context) === null || _j === void 0 ? void 0 : _j.peek(experimentName);
|
|
292
|
+
if (this.debug) {
|
|
162
293
|
(0, debug_1.logDebug)("[JAVASCRIPT] [".concat(experimentName, "] Executing JavaScript change"), {
|
|
163
294
|
experimentName: experimentName,
|
|
164
295
|
userVariant: userVariant_1,
|
|
@@ -168,93 +299,85 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
168
299
|
});
|
|
169
300
|
}
|
|
170
301
|
var codeString = String(change.value);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
experimentName: experimentName,
|
|
184
|
-
userVariant: userVariant_1,
|
|
185
|
-
selector: change.selector,
|
|
186
|
-
element: element.tagName,
|
|
187
|
-
code: codeString,
|
|
188
|
-
});
|
|
302
|
+
var executed = this.executeUserJavaScript(codeString, element, experimentName, change.selector);
|
|
303
|
+
if (executed) {
|
|
304
|
+
appliedElements.push(element);
|
|
305
|
+
if (this.debug) {
|
|
306
|
+
(0, debug_1.logDebug)("[JAVASCRIPT] [".concat(experimentName, "] \u2713 JavaScript executed successfully"), {
|
|
307
|
+
experimentName: experimentName,
|
|
308
|
+
userVariant: userVariant_1,
|
|
309
|
+
selector: change.selector,
|
|
310
|
+
element: element.tagName,
|
|
311
|
+
code: codeString,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
189
314
|
}
|
|
190
315
|
}
|
|
191
|
-
|
|
192
|
-
(0, debug_1.logDebug)("[JAVASCRIPT] [".concat(experimentName, "] \u2717 JavaScript
|
|
316
|
+
else {
|
|
317
|
+
(0, debug_1.logDebug)("[JAVASCRIPT] [".concat(experimentName, "] \u2717 No JavaScript code provided in change.value"), {
|
|
193
318
|
experimentName: experimentName,
|
|
194
|
-
userVariant: userVariant_1,
|
|
195
319
|
selector: change.selector,
|
|
196
|
-
element: element.tagName,
|
|
197
|
-
code: String(change.value),
|
|
198
|
-
error: error instanceof Error ? error.message : String(error),
|
|
199
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
200
320
|
});
|
|
201
321
|
}
|
|
202
322
|
}
|
|
323
|
+
else if (change.type === 'move') {
|
|
324
|
+
var targetSelector = change.targetSelector ||
|
|
325
|
+
(change.value && typeof change.value === 'object'
|
|
326
|
+
? change.value.targetSelector
|
|
327
|
+
: null);
|
|
328
|
+
var position = change.position ||
|
|
329
|
+
(change.value && typeof change.value === 'object'
|
|
330
|
+
? change.value.position
|
|
331
|
+
: null);
|
|
332
|
+
if (targetSelector) {
|
|
333
|
+
var target = document.querySelector(targetSelector);
|
|
334
|
+
if (target) {
|
|
335
|
+
this.moveElement(element, target, position);
|
|
336
|
+
appliedElements.push(element);
|
|
337
|
+
}
|
|
338
|
+
else if (this.debug) {
|
|
339
|
+
(0, debug_1.logDebug)("[ABsmartly] Move target not found: ".concat(targetSelector));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
203
343
|
else {
|
|
204
|
-
|
|
344
|
+
appliedElements.push(element);
|
|
345
|
+
}
|
|
346
|
+
// Watch element for persistence or SPA hydration recovery
|
|
347
|
+
var shouldWatch = (change.type === 'style' && change.persistStyle) ||
|
|
348
|
+
(change.type === 'attribute' && change.persistAttribute) ||
|
|
349
|
+
(change.type === 'javascript' && change.persistScript === true) ||
|
|
350
|
+
((_k = this.plugin.config) === null || _k === void 0 ? void 0 : _k.spa); // SPA mode watches ALL types for hydration recovery
|
|
351
|
+
if (shouldWatch) {
|
|
352
|
+
this.plugin.watchElement(element, experimentName, change);
|
|
353
|
+
}
|
|
354
|
+
else if (this.debug) {
|
|
355
|
+
(0, debug_1.logDebug)("[WATCH-SKIP] NOT watching element - no persist flag and SPA disabled", {
|
|
205
356
|
experimentName: experimentName,
|
|
206
357
|
selector: change.selector,
|
|
358
|
+
element: element.tagName,
|
|
359
|
+
changeType: change.type,
|
|
360
|
+
spaMode: (_l = this.plugin.config) === null || _l === void 0 ? void 0 : _l.spa,
|
|
207
361
|
});
|
|
208
362
|
}
|
|
209
363
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
var position = change.position ||
|
|
216
|
-
(change.value && typeof change.value === 'object'
|
|
217
|
-
? change.value.position
|
|
218
|
-
: null);
|
|
219
|
-
if (targetSelector) {
|
|
220
|
-
var target = document.querySelector(targetSelector);
|
|
221
|
-
if (target) {
|
|
222
|
-
_this.moveElement(element, target, position);
|
|
223
|
-
appliedElements_1.push(element);
|
|
224
|
-
}
|
|
225
|
-
else if (_this.debug) {
|
|
226
|
-
(0, debug_1.logDebug)("[ABsmartly] Move target not found: ".concat(targetSelector));
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
appliedElements_1.push(element);
|
|
232
|
-
}
|
|
233
|
-
// Watch element for React hydration recovery (ALL types) OR style persistence (styles only)
|
|
234
|
-
var shouldWatch = (change.type === 'style' && change.persistStyle) || // Explicit style persistence
|
|
235
|
-
((_c = _this.plugin.config) === null || _c === void 0 ? void 0 : _c.spa); // SPA mode watches ALL types for hydration recovery
|
|
236
|
-
if (shouldWatch) {
|
|
237
|
-
_this.plugin.watchElement(element, experimentName, change);
|
|
238
|
-
}
|
|
239
|
-
else if (change.type === 'style' && _this.debug) {
|
|
240
|
-
(0, debug_1.logDebug)("[WATCH-SKIP] NOT watching element - persistStyle and SPA both disabled", {
|
|
241
|
-
experimentName: experimentName,
|
|
242
|
-
selector: change.selector,
|
|
243
|
-
element: element.tagName,
|
|
244
|
-
persistStyle: change.persistStyle,
|
|
245
|
-
spaMode: (_d = _this.plugin.config) === null || _d === void 0 ? void 0 : _d.spa,
|
|
246
|
-
});
|
|
364
|
+
}
|
|
365
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
366
|
+
finally {
|
|
367
|
+
try {
|
|
368
|
+
if (elements_1_1 && !elements_1_1.done && (_a = elements_1.return)) _a.call(elements_1);
|
|
247
369
|
}
|
|
248
|
-
|
|
249
|
-
|
|
370
|
+
finally { if (e_1) throw e_1.error; }
|
|
371
|
+
}
|
|
372
|
+
if (appliedElements.length > 0) {
|
|
250
373
|
this.trackAppliedChange(experimentName, change);
|
|
251
374
|
if (change.waitForElement) {
|
|
252
375
|
this.pendingManager.removePending(change.selector, experimentName, change.observerRoot);
|
|
253
376
|
}
|
|
254
377
|
// Throttle logs during style persistence reapplies (animations can trigger many times per second)
|
|
255
|
-
var isReapplying_1 =
|
|
378
|
+
var isReapplying_1 = appliedElements.some(function (el) { var _a; return (_a = _this.plugin.reapplyingElements) === null || _a === void 0 ? void 0 : _a.has(el); });
|
|
256
379
|
if (!isReapplying_1) {
|
|
257
|
-
(0, debug_1.logChangeApplication)(experimentName, change.selector, change.type,
|
|
380
|
+
(0, debug_1.logChangeApplication)(experimentName, change.selector, change.type, appliedElements.length, true);
|
|
258
381
|
}
|
|
259
382
|
return true;
|
|
260
383
|
}
|
|
@@ -303,7 +426,7 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
303
426
|
}
|
|
304
427
|
};
|
|
305
428
|
DOMManipulatorLite.prototype.createElement = function (change, _experimentName) {
|
|
306
|
-
var
|
|
429
|
+
var e_4, _a;
|
|
307
430
|
if (!change.element || !change.targetSelector) {
|
|
308
431
|
return null;
|
|
309
432
|
}
|
|
@@ -327,12 +450,12 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
327
450
|
this.moveElement(child, target, change.position);
|
|
328
451
|
}
|
|
329
452
|
}
|
|
330
|
-
catch (
|
|
453
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
331
454
|
finally {
|
|
332
455
|
try {
|
|
333
456
|
if (children_1_1 && !children_1_1.done && (_a = children_1.return)) _a.call(children_1);
|
|
334
457
|
}
|
|
335
|
-
finally { if (
|
|
458
|
+
finally { if (e_4) throw e_4.error; }
|
|
336
459
|
}
|
|
337
460
|
// Return the first element for compatibility
|
|
338
461
|
return children[0];
|
|
@@ -372,7 +495,7 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
372
495
|
}
|
|
373
496
|
};
|
|
374
497
|
DOMManipulatorLite.prototype.applyChangeToElement = function (element, change) {
|
|
375
|
-
var _a, _b;
|
|
498
|
+
var e_5, _a, _b, _c, e_6, _d;
|
|
376
499
|
switch (change.type) {
|
|
377
500
|
case 'text':
|
|
378
501
|
if (change.value !== undefined) {
|
|
@@ -386,33 +509,51 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
386
509
|
break;
|
|
387
510
|
case 'style':
|
|
388
511
|
if (change.value && typeof change.value === 'object') {
|
|
389
|
-
|
|
390
|
-
var
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
512
|
+
try {
|
|
513
|
+
for (var _e = __values(Object.entries(change.value)), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
514
|
+
var _g = __read(_f.value, 2), property = _g[0], value = _g[1];
|
|
515
|
+
var cssProperty = property.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
516
|
+
var priority = change.important === true ? 'important' : '';
|
|
517
|
+
element.style.setProperty(cssProperty, String(value), priority);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
521
|
+
finally {
|
|
522
|
+
try {
|
|
523
|
+
if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
|
|
524
|
+
}
|
|
525
|
+
finally { if (e_5) throw e_5.error; }
|
|
526
|
+
}
|
|
395
527
|
}
|
|
396
528
|
break;
|
|
397
529
|
case 'class':
|
|
398
530
|
if (change.add && Array.isArray(change.add)) {
|
|
399
|
-
(
|
|
531
|
+
(_b = element.classList).add.apply(_b, __spreadArray([], __read(change.add), false));
|
|
400
532
|
}
|
|
401
533
|
if (change.remove && Array.isArray(change.remove)) {
|
|
402
|
-
(
|
|
534
|
+
(_c = element.classList).remove.apply(_c, __spreadArray([], __read(change.remove), false));
|
|
403
535
|
}
|
|
404
536
|
break;
|
|
405
537
|
case 'attribute':
|
|
406
538
|
if (change.value && typeof change.value === 'object') {
|
|
407
|
-
|
|
408
|
-
var
|
|
409
|
-
|
|
410
|
-
|
|
539
|
+
try {
|
|
540
|
+
for (var _h = __values(Object.entries(change.value)), _j = _h.next(); !_j.done; _j = _h.next()) {
|
|
541
|
+
var _k = __read(_j.value, 2), attr = _k[0], value = _k[1];
|
|
542
|
+
if (value === null || value === undefined) {
|
|
543
|
+
element.removeAttribute(attr);
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
element.setAttribute(attr, String(value));
|
|
547
|
+
}
|
|
411
548
|
}
|
|
412
|
-
|
|
413
|
-
|
|
549
|
+
}
|
|
550
|
+
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
551
|
+
finally {
|
|
552
|
+
try {
|
|
553
|
+
if (_j && !_j.done && (_d = _h.return)) _d.call(_h);
|
|
414
554
|
}
|
|
415
|
-
|
|
555
|
+
finally { if (e_6) throw e_6.error; }
|
|
556
|
+
}
|
|
416
557
|
}
|
|
417
558
|
break;
|
|
418
559
|
case 'move':
|
|
@@ -437,36 +578,25 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
437
578
|
try {
|
|
438
579
|
this.applyChangeToElement(element, change);
|
|
439
580
|
if (change.type === 'javascript' && change.value) {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
(0, debug_1.logDebug)("[JAVASCRIPT] [".concat(experimentName, "] Executing JavaScript on specific element"), {
|
|
443
|
-
experimentName: experimentName,
|
|
444
|
-
selector: change.selector,
|
|
445
|
-
element: element.tagName,
|
|
446
|
-
code: String(change.value).substring(0, 100) + '...',
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
var fn = new Function('element', String(change.value));
|
|
450
|
-
fn(element);
|
|
451
|
-
if (this.debug) {
|
|
452
|
-
(0, debug_1.logDebug)("[JAVASCRIPT] [".concat(experimentName, "] \u2713 JavaScript executed successfully"), {
|
|
453
|
-
experimentName: experimentName,
|
|
454
|
-
selector: change.selector,
|
|
455
|
-
element: element.tagName,
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
catch (error) {
|
|
460
|
-
(0, debug_1.logDebug)("[JAVASCRIPT] [".concat(experimentName, "] \u2717 JavaScript execution error on specific element:"), {
|
|
581
|
+
if (this.debug) {
|
|
582
|
+
(0, debug_1.logDebug)("[JAVASCRIPT] [".concat(experimentName, "] Executing JavaScript on specific element"), {
|
|
461
583
|
experimentName: experimentName,
|
|
462
584
|
selector: change.selector,
|
|
463
585
|
element: element.tagName,
|
|
464
|
-
code: String(change.value),
|
|
465
|
-
error: error instanceof Error ? error.message : String(error),
|
|
466
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
586
|
+
code: String(change.value).substring(0, 100) + '...',
|
|
467
587
|
});
|
|
588
|
+
}
|
|
589
|
+
var executed = this.executeUserJavaScript(String(change.value), element, experimentName, change.selector);
|
|
590
|
+
if (!executed) {
|
|
468
591
|
return false;
|
|
469
592
|
}
|
|
593
|
+
if (this.debug) {
|
|
594
|
+
(0, debug_1.logDebug)("[JAVASCRIPT] [".concat(experimentName, "] \u2713 JavaScript executed successfully"), {
|
|
595
|
+
experimentName: experimentName,
|
|
596
|
+
selector: change.selector,
|
|
597
|
+
element: element.tagName,
|
|
598
|
+
});
|
|
599
|
+
}
|
|
470
600
|
}
|
|
471
601
|
else if (change.type === 'move') {
|
|
472
602
|
var targetSelector = change.targetSelector ||
|
|
@@ -487,8 +617,10 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
487
617
|
}
|
|
488
618
|
}
|
|
489
619
|
}
|
|
490
|
-
// Watch element for
|
|
491
|
-
var shouldWatch = (change.type === 'style' && change.persistStyle) ||
|
|
620
|
+
// Watch element for persistence or SPA hydration recovery
|
|
621
|
+
var shouldWatch = (change.type === 'style' && change.persistStyle) ||
|
|
622
|
+
(change.type === 'attribute' && change.persistAttribute) ||
|
|
623
|
+
(change.type === 'javascript' && change.persistScript === true) ||
|
|
492
624
|
((_a = this.plugin.config) === null || _a === void 0 ? void 0 : _a.spa); // SPA mode watches ALL types for hydration recovery
|
|
493
625
|
if (shouldWatch) {
|
|
494
626
|
this.plugin.watchElement(element, experimentName, change);
|