@accelerated-agency/visual-editor 0.4.2 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +23 -3
- package/dist/vite.cjs +278 -58
- package/dist/vite.js +278 -58
- package/package.json +3 -2
package/dist/vite.js
CHANGED
|
@@ -78,17 +78,26 @@ function hasTrackingMarker(input, markers) {
|
|
|
78
78
|
}
|
|
79
79
|
return false;
|
|
80
80
|
}
|
|
81
|
+
function patchKnownUnsafeEditorPatterns(scriptTag) {
|
|
82
|
+
let out = String(scriptTag || "");
|
|
83
|
+
out = out.replace(
|
|
84
|
+
/dragRegion\.addEventListener\((['"])pointerdown\1,\s*onPointerDown\);?/g,
|
|
85
|
+
"if (typeof dragRegion !== 'undefined' && dragRegion) dragRegion.addEventListener($1pointerdown$1, onPointerDown);"
|
|
86
|
+
);
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
81
89
|
function stripTrackingScriptsFromScrapedHtml(html, markers) {
|
|
82
90
|
let removedCount = 0;
|
|
83
91
|
let out = html;
|
|
84
92
|
out = out.replace(/<script\b[\s\S]*?<\/script>/gi, (tag) => {
|
|
93
|
+
var patchedTag = patchKnownUnsafeEditorPatterns(tag);
|
|
85
94
|
const srcMatch = tag.match(/\bsrc\s*=\s*(["'])(.*?)\1/i);
|
|
86
95
|
const src = srcMatch?.[2] || "";
|
|
87
96
|
if (hasTrackingMarker(src, markers) || hasTrackingMarker(tag, markers)) {
|
|
88
97
|
removedCount += 1;
|
|
89
98
|
return "";
|
|
90
99
|
}
|
|
91
|
-
return
|
|
100
|
+
return patchedTag;
|
|
92
101
|
});
|
|
93
102
|
out = out.replace(/<noscript\b[\s\S]*?<\/noscript>/gi, (tag) => {
|
|
94
103
|
if (!hasTrackingMarker(tag, markers)) return tag;
|
|
@@ -852,7 +861,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
852
861
|
<button class="tb-dk-btn" title="More options"><i class="bi bi-three-dots"></i></button>
|
|
853
862
|
</div>
|
|
854
863
|
<button class="tb-dk-btn" id="btn-undo" title="Undo (\u2318Z)"><i class="bi bi-arrow-counterclockwise"></i></button>
|
|
855
|
-
<button class="tb-dk-btn" id="btn-redo" title="Redo (\u2318\u21E7Z)"><i class="bi bi-arrow-clockwise"></i></button>
|
|
864
|
+
<button class="tb-dk-btn" id="btn-redo" title="Redo (\u2318\u21E7Z)" style="display:none"><i class="bi bi-arrow-clockwise"></i></button>
|
|
856
865
|
</div>
|
|
857
866
|
|
|
858
867
|
<div id="iframe-loading-toolbar" class="tb-page-loading" aria-live="polite" aria-atomic="true">
|
|
@@ -923,8 +932,8 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
923
932
|
<!-- Elements -->
|
|
924
933
|
<div class="lp-sec lp-sec-no-border">
|
|
925
934
|
<div class="lp-sec-hd">
|
|
926
|
-
<span class="lp-sec-hd-left">Elements <i class="bi bi-info-circle lp-info-icon" title="Page elements"></i></span>
|
|
927
|
-
<button class="lp-add-btn" title="Add element">+ Add</button>
|
|
935
|
+
<span class="lp-sec-hd-left">Elements <i style="display:none" class="bi bi-info-circle lp-info-icon" title="Page elements"></i></span>
|
|
936
|
+
<button class="lp-add-btn" id="btn-add-element" title="Add element">+ Add</button>
|
|
928
937
|
</div>
|
|
929
938
|
|
|
930
939
|
<!-- Search (hidden, kept for JS) -->
|
|
@@ -994,14 +1003,16 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
994
1003
|
|
|
995
1004
|
<!-- Right panel -->
|
|
996
1005
|
<div id="right-panel">
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
<div class="
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
<div
|
|
1004
|
-
|
|
1006
|
+
<div id="section-components-panel" style="display:none">
|
|
1007
|
+
<!-- Left-tab controls moved here -->
|
|
1008
|
+
<div class="section-components-tabs">
|
|
1009
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('components')">Components</div>
|
|
1010
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('sections')">Sections</div>
|
|
1011
|
+
</div>
|
|
1012
|
+
<div class="lp-body">
|
|
1013
|
+
<div id="tab-components" class="tab-pane"></div>
|
|
1014
|
+
<div id="tab-sections" class="tab-pane"></div>
|
|
1015
|
+
</div>
|
|
1005
1016
|
</div>
|
|
1006
1017
|
<!-- Element badge (hidden until selection) -->
|
|
1007
1018
|
<div id="el-info" style="display:none">
|
|
@@ -1132,6 +1143,8 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1132
1143
|
</div>
|
|
1133
1144
|
|
|
1134
1145
|
<!-- CDN scripts -->
|
|
1146
|
+
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
|
|
1147
|
+
<script src="https://cdn.jsdelivr.net/npm/jquery-ui-dist@1.13.3/jquery-ui.min.js"></script>
|
|
1135
1148
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
1136
1149
|
<script>
|
|
1137
1150
|
window.__veLoadFallback = function(el, candidates){
|
|
@@ -1159,10 +1172,6 @@ window.__veLoadFallback = function(el, candidates){
|
|
|
1159
1172
|
onerror="window.__veLoadFallback(this,'https://cdn.jsdelivr.net/npm/vvvebjs@latest/libs/builder/inputs.js||https://unpkg.com/vvvebjs@latest/libs/builder/inputs.js')"
|
|
1160
1173
|
></script>
|
|
1161
1174
|
<!-- components.js removed (frequently missing on npm CDN); safety stubs below prevent bootstrap/widgets loader errors -->
|
|
1162
|
-
// <script
|
|
1163
|
-
// src="https://cdn.jsdelivr.net/npm/vvvebjs@latest/libs/builder/components-widgets.js"
|
|
1164
|
-
// onerror="window.__veLoadFallback(this,'https://cdn.jsdelivr.net/npm/vvvebjs@latest/libs/builder/components-widgets.js||https://unpkg.com/vvvebjs@latest/libs/builder/components-widgets.js')"
|
|
1165
|
-
// ></script>
|
|
1166
1175
|
<script>
|
|
1167
1176
|
/* Safety stub: if components.js didn't define these, create empty arrays so
|
|
1168
1177
|
components-bootstrap5.js doesn't throw ReferenceError on load. */
|
|
@@ -1191,7 +1200,7 @@ if (window.Vvveb && window.Vvveb.Components) {
|
|
|
1191
1200
|
</script>
|
|
1192
1201
|
<script
|
|
1193
1202
|
src="https://cdn.jsdelivr.net/npm/vvvebjs@latest/libs/builder/components-bootstrap4.js"
|
|
1194
|
-
onerror="window.__veLoadFallback(this,'https://cdn.jsdelivr.net/npm/vvvebjs@latest/libs/builder/components-bootstrap4.js||https://unpkg.com/vvvebjs@latest/libs/builder/components-bootstrap4.js')"
|
|
1203
|
+
onerror="window.__veLoadFallback(this,'https://cdn.jsdelivr.net/npm/vvvebjs@latest/libs/builder/components-bootstrap5.js||https://cdn.jsdelivr.net/npm/vvvebjs@latest/libs/builder/components-bootstrap4.js||https://unpkg.com/vvvebjs@latest/libs/builder/components-bootstrap5.js||https://unpkg.com/vvvebjs@latest/libs/builder/components-bootstrap4.js')"
|
|
1195
1204
|
></script>
|
|
1196
1205
|
<script
|
|
1197
1206
|
src="https://cdn.jsdelivr.net/npm/vvvebjs@latest/libs/builder/components-widgets.js"
|
|
@@ -1660,6 +1669,19 @@ function switchSectionComponentsTab(tab) {
|
|
|
1660
1669
|
renderSidebar(inp ? inp.value : '');
|
|
1661
1670
|
}
|
|
1662
1671
|
|
|
1672
|
+
function toggleSectionComponentsPanel(forceVisible) {
|
|
1673
|
+
var panel = document.getElementById('section-components-panel');
|
|
1674
|
+
if (!panel) return;
|
|
1675
|
+
var shouldShow =
|
|
1676
|
+
typeof forceVisible === 'boolean'
|
|
1677
|
+
? forceVisible
|
|
1678
|
+
: panel.style.display === 'none';
|
|
1679
|
+
panel.style.display = shouldShow ? '' : 'none';
|
|
1680
|
+
if (shouldShow) {
|
|
1681
|
+
switchSectionComponentsTab(currentSectionComponentsTab || 'components');
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1663
1685
|
// \u2500\u2500 Accordion toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1664
1686
|
function toggleAcc(name) {
|
|
1665
1687
|
var sec = document.getElementById('acc-' + name);
|
|
@@ -1869,6 +1891,24 @@ function syncDesignInput(change) {
|
|
|
1869
1891
|
function removeStateChange(idx) {
|
|
1870
1892
|
var change = stateChanges[idx];
|
|
1871
1893
|
if (!change) return;
|
|
1894
|
+
if (change.isStructuralLive) {
|
|
1895
|
+
removeSessionStructuralRowByTimestamp(
|
|
1896
|
+
change.structuralVarId || activeVarId,
|
|
1897
|
+
change.vveTs,
|
|
1898
|
+
);
|
|
1899
|
+
stateChanges.splice(idx, 1);
|
|
1900
|
+
commitStateChangesForActiveVariation();
|
|
1901
|
+
renderStatesTab();
|
|
1902
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
1903
|
+
try {
|
|
1904
|
+
delete varHtmlCache[activeVarId];
|
|
1905
|
+
} catch(_) {}
|
|
1906
|
+
appliedStructuralChangesetKeys = {};
|
|
1907
|
+
recomputeEditorDirty();
|
|
1908
|
+
scheduleDomTreeRefresh();
|
|
1909
|
+
softReloadEditorIframe();
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1872
1912
|
revertChangeOnDom(change);
|
|
1873
1913
|
syncDesignInput(change);
|
|
1874
1914
|
stateChanges.splice(idx, 1);
|
|
@@ -2225,6 +2265,14 @@ function getLatestHistoryUndoTarget() {
|
|
|
2225
2265
|
return list.length ? list[0] : null;
|
|
2226
2266
|
}
|
|
2227
2267
|
|
|
2268
|
+
function getLatestLiveUndoTarget() {
|
|
2269
|
+
var list = getUnifiedHistoryItems();
|
|
2270
|
+
for (var i = 0; i < list.length; i++) {
|
|
2271
|
+
if (list[i] && list[i].source === 'live') return list[i];
|
|
2272
|
+
}
|
|
2273
|
+
return null;
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2228
2276
|
function changesetListHasStructural(arr) {
|
|
2229
2277
|
if (!arr || !arr.length) return false;
|
|
2230
2278
|
for (var i = 0; i < arr.length; i++) {
|
|
@@ -2323,8 +2371,15 @@ function removeHistoryChangeset(idx, evt) {
|
|
|
2323
2371
|
function clearAllHistoryChangesets() {
|
|
2324
2372
|
var v = getActiveVariationForHistory();
|
|
2325
2373
|
if (!v) return;
|
|
2326
|
-
|
|
2374
|
+
var hasSavedChangesets = parseVariationChangesets(v).length > 0;
|
|
2375
|
+
var hasSessionStructural =
|
|
2376
|
+
!!(activeVarId && sessionStructuralChainRowsByVarId[activeVarId] && sessionStructuralChainRowsByVarId[activeVarId].length);
|
|
2377
|
+
if (!hasSavedChangesets && !hasSessionStructural) return;
|
|
2378
|
+
|
|
2327
2379
|
persistActiveVariationChangesets([]);
|
|
2380
|
+
if (activeVarId) {
|
|
2381
|
+
sessionStructuralChainRowsByVarId[activeVarId] = [];
|
|
2382
|
+
}
|
|
2328
2383
|
appliedChangesetSnapshots = {};
|
|
2329
2384
|
appliedStructuralChangesetKeys = {};
|
|
2330
2385
|
try {
|
|
@@ -2337,6 +2392,10 @@ function clearAllHistoryChangesets() {
|
|
|
2337
2392
|
}
|
|
2338
2393
|
|
|
2339
2394
|
function clearAllUnifiedHistory() {
|
|
2395
|
+
if (activeVarId) {
|
|
2396
|
+
// Ensure structural unsaved rows are also removed by "Clear all changes".
|
|
2397
|
+
sessionStructuralChainRowsByVarId[activeVarId] = [];
|
|
2398
|
+
}
|
|
2340
2399
|
clearAllStates();
|
|
2341
2400
|
clearAllHistoryChangesets();
|
|
2342
2401
|
if (currentMainTab === 'history') renderHistoryTab();
|
|
@@ -2348,15 +2407,32 @@ var VVE_LOCAL_STORAGE_PREFIX = 'vve:';
|
|
|
2348
2407
|
|
|
2349
2408
|
function clearVisualEditorLocalStorage() {
|
|
2350
2409
|
try {
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2410
|
+
var stores = [];
|
|
2411
|
+
try { stores.push(localStorage); } catch(_) {}
|
|
2412
|
+
try { stores.push(sessionStorage); } catch(_) {}
|
|
2413
|
+
for (var si = 0; si < stores.length; si++) {
|
|
2414
|
+
var store = stores[si];
|
|
2415
|
+
if (!store) continue;
|
|
2416
|
+
for (var i = store.length - 1; i >= 0; i--) {
|
|
2417
|
+
var k = store.key(i);
|
|
2418
|
+
if (k && k.indexOf(VVE_LOCAL_STORAGE_PREFIX) === 0) {
|
|
2419
|
+
store.removeItem(k);
|
|
2420
|
+
}
|
|
2355
2421
|
}
|
|
2356
2422
|
}
|
|
2357
2423
|
} catch(_) {}
|
|
2358
2424
|
}
|
|
2359
2425
|
|
|
2426
|
+
function clearPersistedActiveVariationForData(data) {
|
|
2427
|
+
try {
|
|
2428
|
+
var sk = activeVariationStorageKeyFromPayload(data);
|
|
2429
|
+
if (sk && sk !== VVE_LOCAL_STORAGE_PREFIX + 'activeVar::') {
|
|
2430
|
+
try { localStorage.removeItem(sk); } catch(_) {}
|
|
2431
|
+
try { sessionStorage.removeItem(sk); } catch(_) {}
|
|
2432
|
+
}
|
|
2433
|
+
} catch(_) {}
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2360
2436
|
function activeVariationStorageKeyFromPayload(data) {
|
|
2361
2437
|
return (
|
|
2362
2438
|
VVE_LOCAL_STORAGE_PREFIX +
|
|
@@ -2395,14 +2471,18 @@ function writePersistedActiveVariationId(varId) {
|
|
|
2395
2471
|
* @param allowPrevMemory when true, keep in-session activeVarId if still valid (skip-reload path).
|
|
2396
2472
|
*/
|
|
2397
2473
|
function pickActiveVariationIdForLoad(data, variationsArr, prevMemoryId, allowPrevMemory) {
|
|
2398
|
-
var
|
|
2399
|
-
var fallback = (
|
|
2474
|
+
var firstNonBaseline = variationsArr.find(function(v) { return !v.baseline; });
|
|
2475
|
+
var fallback = (firstNonBaseline || variationsArr[0] || {})._id || null;
|
|
2400
2476
|
if (!variationsArr.length) return null;
|
|
2401
2477
|
if (allowPrevMemory && prevMemoryId && variationsArr.some(function(v) { return v._id === prevMemoryId; })) {
|
|
2402
2478
|
return prevMemoryId;
|
|
2403
2479
|
}
|
|
2404
2480
|
var stored = readPersistedActiveVariationId(data);
|
|
2405
2481
|
if (stored && variationsArr.some(function(v) { return v._id === stored; })) {
|
|
2482
|
+
var storedVar = variationsArr.find(function(v) { return v._id === stored; });
|
|
2483
|
+
if (storedVar && storedVar.baseline && firstNonBaseline && firstNonBaseline._id) {
|
|
2484
|
+
return firstNonBaseline._id;
|
|
2485
|
+
}
|
|
2406
2486
|
return stored;
|
|
2407
2487
|
}
|
|
2408
2488
|
return fallback;
|
|
@@ -2424,12 +2504,24 @@ function handleLoadExperiment(data) {
|
|
|
2424
2504
|
var extraTrackingMarkers = Array.isArray(data && data.trackingMarkers)
|
|
2425
2505
|
? data.trackingMarkers.filter(function(m){return typeof m === 'string' && m.trim().length > 0;})
|
|
2426
2506
|
: [];
|
|
2507
|
+
var conversionProxyBaseUrl = (typeof (data && data.conversionProxyBaseUrl) === 'string'
|
|
2508
|
+
? data.conversionProxyBaseUrl
|
|
2509
|
+
: '').trim().replace(/\\/+$/, '');
|
|
2510
|
+
var proxyPath = '/api/conversion-proxy';
|
|
2511
|
+
// Keep iframe navigation same-origin for DOM access (selection/editing).
|
|
2512
|
+
// If conversionProxyBaseUrl is provided, middleware delegates upstream fetches
|
|
2513
|
+
// server-side while browser URLs stay local.
|
|
2514
|
+
var proxyRoot = proxyPath;
|
|
2427
2515
|
var trackingMarkersParam = extraTrackingMarkers.length
|
|
2428
2516
|
? '&trackingMarkers=' + encodeURIComponent(JSON.stringify(extraTrackingMarkers))
|
|
2429
2517
|
: '';
|
|
2430
|
-
var
|
|
2518
|
+
var conversionProxyBaseUrlParam = conversionProxyBaseUrl
|
|
2519
|
+
? '&conversionProxyBaseUrl=' + encodeURIComponent(conversionProxyBaseUrl)
|
|
2520
|
+
: '';
|
|
2521
|
+
var proxyUrl = proxyRoot + '?password=' + encodeURIComponent(data.editorPassword || '') +
|
|
2431
2522
|
'&url=' + encodeURIComponent(pageUrl) +
|
|
2432
2523
|
'&strictObserverFreeze=' + encodeURIComponent(data && data.strictObserverFreeze ? '1' : '0') +
|
|
2524
|
+
conversionProxyBaseUrlParam +
|
|
2433
2525
|
trackingMarkersParam;
|
|
2434
2526
|
|
|
2435
2527
|
// Parent often re-posts load-experiment when React re-renders (new object identity) or
|
|
@@ -2614,7 +2706,13 @@ function granularAnySelectorMatches(doc, cs) {
|
|
|
2614
2706
|
|
|
2615
2707
|
/** Bust bfcache / same-URL no-op reloads so the iframe actually re-parses (loading \u2192 interactive). */
|
|
2616
2708
|
function appendIframeReloadBust(url) {
|
|
2617
|
-
|
|
2709
|
+
try {
|
|
2710
|
+
var u = new URL(String(url || ''), window.location.href);
|
|
2711
|
+
u.searchParams.set('_vve_reload', String(Date.now()));
|
|
2712
|
+
return u.toString();
|
|
2713
|
+
} catch(_) {
|
|
2714
|
+
return url;
|
|
2715
|
+
}
|
|
2618
2716
|
}
|
|
2619
2717
|
|
|
2620
2718
|
// True when the iframe contentDocument belongs to the current iframe.src navigation.
|
|
@@ -2992,6 +3090,44 @@ function appendSessionStructuralChainRow(varId, row) {
|
|
|
2992
3090
|
sessionStructuralChainRowsByVarId[varId].push(row);
|
|
2993
3091
|
}
|
|
2994
3092
|
|
|
3093
|
+
function markStructuralRowApplied(row) {
|
|
3094
|
+
try {
|
|
3095
|
+
var k = structuralChangesetDedupKey(row);
|
|
3096
|
+
if (k) appliedStructuralChangesetKeys[k] = true;
|
|
3097
|
+
} catch(_) {}
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
function logStructuralStateChange(row, label, value, targetEl) {
|
|
3101
|
+
if (!row || !row.selector) return;
|
|
3102
|
+
stateChanges.push({
|
|
3103
|
+
selector: row.selector,
|
|
3104
|
+
inputId: 'vve-struct',
|
|
3105
|
+
label: label || 'Structure change',
|
|
3106
|
+
cssProp: null,
|
|
3107
|
+
value: value != null ? String(value) : String(row.type || ''),
|
|
3108
|
+
targetEl: targetEl || null,
|
|
3109
|
+
originalValue: '',
|
|
3110
|
+
vveTs: row.vveTs || nextHistoryTimestamp(),
|
|
3111
|
+
isStructuralLive: true,
|
|
3112
|
+
structuralVarId: activeVarId || null,
|
|
3113
|
+
structuralType: row.type || '',
|
|
3114
|
+
});
|
|
3115
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
3116
|
+
commitStateChangesForActiveVariation();
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3119
|
+
function removeSessionStructuralRowByTimestamp(varId, ts) {
|
|
3120
|
+
if (!varId || !ts) return;
|
|
3121
|
+
var arr = sessionStructuralChainRowsByVarId[varId];
|
|
3122
|
+
if (!arr || !arr.length) return;
|
|
3123
|
+
for (var i = arr.length - 1; i >= 0; i--) {
|
|
3124
|
+
if (arr[i] && arr[i].vveTs === ts) {
|
|
3125
|
+
arr.splice(i, 1);
|
|
3126
|
+
return;
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
|
|
2995
3131
|
/** One States-tab row -> Conversion.io chain-set shape (matches applyChangesetEntry). */
|
|
2996
3132
|
function stateChangeToChainSet(c) {
|
|
2997
3133
|
if (!c || !c.selector) return null;
|
|
@@ -3686,12 +3822,15 @@ function duplicateSelectedEl() {
|
|
|
3686
3822
|
clone.setAttribute('data-vve-instance', generateVveInstanceId());
|
|
3687
3823
|
} catch(_) {}
|
|
3688
3824
|
if (activeVarId) {
|
|
3689
|
-
|
|
3825
|
+
var dupRow = {
|
|
3690
3826
|
selector: anchorSel,
|
|
3691
3827
|
type: 'insert',
|
|
3692
3828
|
action: 'after',
|
|
3693
3829
|
html: clone.outerHTML,
|
|
3694
|
-
}
|
|
3830
|
+
};
|
|
3831
|
+
appendSessionStructuralChainRow(activeVarId, dupRow);
|
|
3832
|
+
markStructuralRowApplied(dupRow);
|
|
3833
|
+
logStructuralStateChange(dupRow, 'Duplicated via toolbar', 'Duplicate inserted', selectedEl);
|
|
3695
3834
|
}
|
|
3696
3835
|
selectedEl.parentNode.insertBefore(clone, selectedEl.nextSibling);
|
|
3697
3836
|
saveCurrentVariationHtml();
|
|
@@ -3707,23 +3846,27 @@ function toggleHideSelectedEl() {
|
|
|
3707
3846
|
selectedEl.style.visibility = '';
|
|
3708
3847
|
selectedEl.removeAttribute('data-vve-hidden');
|
|
3709
3848
|
if (activeVarId) {
|
|
3710
|
-
|
|
3849
|
+
var showRow = {
|
|
3711
3850
|
selector: hidSel,
|
|
3712
3851
|
type: 'style',
|
|
3713
3852
|
property: 'visibility',
|
|
3714
3853
|
value: '',
|
|
3715
|
-
}
|
|
3854
|
+
};
|
|
3855
|
+
appendSessionStructuralChainRow(activeVarId, showRow);
|
|
3856
|
+
logStructuralStateChange(showRow, 'Shown via toolbar', 'Visibility restored', selectedEl);
|
|
3716
3857
|
}
|
|
3717
3858
|
} else {
|
|
3718
3859
|
selectedEl.style.visibility = 'hidden';
|
|
3719
3860
|
selectedEl.setAttribute('data-vve-hidden', '1');
|
|
3720
3861
|
if (activeVarId) {
|
|
3721
|
-
|
|
3862
|
+
var hideRow = {
|
|
3722
3863
|
selector: hidSel,
|
|
3723
3864
|
type: 'style',
|
|
3724
3865
|
property: 'visibility',
|
|
3725
3866
|
value: 'hidden',
|
|
3726
|
-
}
|
|
3867
|
+
};
|
|
3868
|
+
appendSessionStructuralChainRow(activeVarId, hideRow);
|
|
3869
|
+
logStructuralStateChange(hideRow, 'Hidden via toolbar', 'Visibility set to hidden', selectedEl);
|
|
3727
3870
|
}
|
|
3728
3871
|
}
|
|
3729
3872
|
saveCurrentVariationHtml();
|
|
@@ -3734,7 +3877,11 @@ function deleteSelectedEl() {
|
|
|
3734
3877
|
if (!selectedEl || !selectedEl.parentNode) return;
|
|
3735
3878
|
var delSel = buildSelector(selectedEl);
|
|
3736
3879
|
selectedEl.remove();
|
|
3737
|
-
if (activeVarId)
|
|
3880
|
+
if (activeVarId) {
|
|
3881
|
+
var delRow = { selector: delSel, type: 'remove' };
|
|
3882
|
+
appendSessionStructuralChainRow(activeVarId, delRow);
|
|
3883
|
+
logStructuralStateChange(delRow, 'Deleted via toolbar', 'Element removed', null);
|
|
3884
|
+
}
|
|
3738
3885
|
saveCurrentVariationHtml();
|
|
3739
3886
|
recomputeEditorDirty();
|
|
3740
3887
|
deselectElement();
|
|
@@ -4635,19 +4782,25 @@ function recordReorderAfterDrag(movedEl) {
|
|
|
4635
4782
|
var prev = movedEl.previousElementSibling;
|
|
4636
4783
|
var next = movedEl.nextElementSibling;
|
|
4637
4784
|
if (prev) {
|
|
4638
|
-
|
|
4785
|
+
var reorderAfterRow = {
|
|
4639
4786
|
selector: buildSelector(movedEl),
|
|
4640
4787
|
type: 'reorder',
|
|
4641
4788
|
targetSelector: buildSelector(prev),
|
|
4642
4789
|
action: 'after',
|
|
4643
|
-
}
|
|
4790
|
+
};
|
|
4791
|
+
appendSessionStructuralChainRow(activeVarId, reorderAfterRow);
|
|
4792
|
+
markStructuralRowApplied(reorderAfterRow);
|
|
4793
|
+
logStructuralStateChange(reorderAfterRow, 'Reordered via drag', 'Moved after sibling', movedEl);
|
|
4644
4794
|
} else if (next) {
|
|
4645
|
-
|
|
4795
|
+
var reorderBeforeRow = {
|
|
4646
4796
|
selector: buildSelector(movedEl),
|
|
4647
4797
|
type: 'reorder',
|
|
4648
4798
|
targetSelector: buildSelector(next),
|
|
4649
4799
|
action: 'before',
|
|
4650
|
-
}
|
|
4800
|
+
};
|
|
4801
|
+
appendSessionStructuralChainRow(activeVarId, reorderBeforeRow);
|
|
4802
|
+
markStructuralRowApplied(reorderBeforeRow);
|
|
4803
|
+
logStructuralStateChange(reorderBeforeRow, 'Reordered via drag', 'Moved before sibling', movedEl);
|
|
4651
4804
|
}
|
|
4652
4805
|
}
|
|
4653
4806
|
|
|
@@ -4928,12 +5081,15 @@ function insertHtml(html) {
|
|
|
4928
5081
|
}
|
|
4929
5082
|
if (firstEl) selectElement(firstEl);
|
|
4930
5083
|
if (activeVarId) {
|
|
4931
|
-
|
|
5084
|
+
var insertRow = {
|
|
4932
5085
|
selector: anchorSel,
|
|
4933
5086
|
type: 'insert',
|
|
4934
5087
|
action: 'after',
|
|
4935
5088
|
html: htmlStr,
|
|
4936
|
-
}
|
|
5089
|
+
};
|
|
5090
|
+
appendSessionStructuralChainRow(activeVarId, insertRow);
|
|
5091
|
+
markStructuralRowApplied(insertRow);
|
|
5092
|
+
logStructuralStateChange(insertRow, 'Added component/section', 'Inserted new element', firstEl || selectedEl);
|
|
4937
5093
|
}
|
|
4938
5094
|
saveCurrentVariationHtml();
|
|
4939
5095
|
recomputeEditorDirty();
|
|
@@ -5023,6 +5179,14 @@ document.getElementById('comp-search').addEventListener('input', function() {
|
|
|
5023
5179
|
renderSidebar(this.value);
|
|
5024
5180
|
}
|
|
5025
5181
|
});
|
|
5182
|
+
var btnAddElement = document.getElementById('btn-add-element');
|
|
5183
|
+
if (btnAddElement) {
|
|
5184
|
+
btnAddElement.addEventListener('click', function(e) {
|
|
5185
|
+
e.preventDefault();
|
|
5186
|
+
e.stopPropagation();
|
|
5187
|
+
toggleSectionComponentsPanel();
|
|
5188
|
+
});
|
|
5189
|
+
}
|
|
5026
5190
|
|
|
5027
5191
|
// \u2500\u2500 Save / Close \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5028
5192
|
document.getElementById('btn-save').addEventListener('click', handleSave);
|
|
@@ -5063,11 +5227,21 @@ function handleSave() {
|
|
|
5063
5227
|
}
|
|
5064
5228
|
|
|
5065
5229
|
function handleClose() {
|
|
5230
|
+
clearPersistedActiveVariationForData(experimentData);
|
|
5066
5231
|
clearVisualEditorLocalStorage();
|
|
5067
5232
|
// Unsaved-changes UX lives in the parent (PlatformVisualEditorV2); avoid double confirm here.
|
|
5068
5233
|
send('close-editor', {});
|
|
5069
5234
|
}
|
|
5070
5235
|
|
|
5236
|
+
// Defensive cleanup: if parent closes/unmounts the editor shell without
|
|
5237
|
+
// invoking handleClose(), clear persisted VVE keys on unload as well.
|
|
5238
|
+
window.addEventListener('pagehide', function() {
|
|
5239
|
+
clearVisualEditorLocalStorage();
|
|
5240
|
+
});
|
|
5241
|
+
window.addEventListener('beforeunload', function() {
|
|
5242
|
+
clearVisualEditorLocalStorage();
|
|
5243
|
+
});
|
|
5244
|
+
|
|
5071
5245
|
// \u2500\u2500 Keyboard shortcuts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5072
5246
|
function isNativeEditableTarget(target) {
|
|
5073
5247
|
if (!target || target.nodeType !== 1) return false;
|
|
@@ -5089,10 +5263,7 @@ document.addEventListener('keydown', function(e) {
|
|
|
5089
5263
|
e.preventDefault();
|
|
5090
5264
|
runEditorUndo();
|
|
5091
5265
|
}
|
|
5092
|
-
|
|
5093
|
-
e.preventDefault();
|
|
5094
|
-
runEditorRedo();
|
|
5095
|
-
}
|
|
5266
|
+
// Redo is intentionally hidden/disabled in this editor flow.
|
|
5096
5267
|
if (meta && e.key === 's') { e.preventDefault(); handleSave(); }
|
|
5097
5268
|
if (e.key === 'Escape') {
|
|
5098
5269
|
var openTips = document.querySelectorAll('.ve-pl-tip.is-tip-open');
|
|
@@ -5112,11 +5283,17 @@ document.addEventListener('keydown', function(e) {
|
|
|
5112
5283
|
}
|
|
5113
5284
|
});
|
|
5114
5285
|
function runEditorUndo() {
|
|
5115
|
-
|
|
5116
|
-
if (
|
|
5117
|
-
|
|
5286
|
+
// Undo only unsaved in-session edits; do not remove persisted history rows.
|
|
5287
|
+
if (!isDirty) return;
|
|
5288
|
+
|
|
5289
|
+
// 1) Prefer live unsaved change stack (stateChanges shown in History tab).
|
|
5290
|
+
var liveTarget = getLatestLiveUndoTarget();
|
|
5291
|
+
if (liveTarget) {
|
|
5292
|
+
removeHistoryItem('live', liveTarget.idx);
|
|
5118
5293
|
return;
|
|
5119
5294
|
}
|
|
5295
|
+
|
|
5296
|
+
// 2) Fallback to Vvveb internal undo stack (e.g. structural drag/drop ops).
|
|
5120
5297
|
if (!(typeof Vvveb !== 'undefined' && Vvveb.Undo)) return;
|
|
5121
5298
|
Vvveb.Undo.undo();
|
|
5122
5299
|
saveCurrentVariationHtml();
|
|
@@ -5139,11 +5316,10 @@ document.getElementById('btn-undo').addEventListener('click', function(e) {
|
|
|
5139
5316
|
e.stopPropagation();
|
|
5140
5317
|
runEditorUndo();
|
|
5141
5318
|
});
|
|
5142
|
-
document.getElementById('btn-redo')
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
});
|
|
5319
|
+
var btnRedo = document.getElementById('btn-redo');
|
|
5320
|
+
if (btnRedo) {
|
|
5321
|
+
btnRedo.style.display = 'none';
|
|
5322
|
+
}
|
|
5147
5323
|
|
|
5148
5324
|
function layoutLoadingTooltip(host) {
|
|
5149
5325
|
var tip = host.querySelector('.ve-pl-tooltip');
|
|
@@ -5515,6 +5691,8 @@ function createVisualEditorMiddleware(options) {
|
|
|
5515
5691
|
const url = new URL(req.url || "", "http://localhost");
|
|
5516
5692
|
const targetUrl = url.searchParams.get("url");
|
|
5517
5693
|
const password = url.searchParams.get("password") || "";
|
|
5694
|
+
const conversionProxyBaseUrlForRequest = (url.searchParams.get("conversionProxyBaseUrl") || "").trim().replace(/\/+$/, "");
|
|
5695
|
+
const proxyRootForRequest = "/api/conversion-proxy";
|
|
5518
5696
|
const extraTrackingMarkersForRequest = parseTrackingMarkersParam(
|
|
5519
5697
|
url.searchParams.get("trackingMarkers")
|
|
5520
5698
|
);
|
|
@@ -5567,7 +5745,34 @@ function createVisualEditorMiddleware(options) {
|
|
|
5567
5745
|
return false;
|
|
5568
5746
|
}
|
|
5569
5747
|
};
|
|
5748
|
+
const workerRawFetch = (input, init = {}) => {
|
|
5749
|
+
const workerUrl = new URL("/api/conversion-proxy", conversionProxyBaseUrlForRequest);
|
|
5750
|
+
workerUrl.searchParams.set("url", input);
|
|
5751
|
+
workerUrl.searchParams.set("raw", "1");
|
|
5752
|
+
const method2 = (init?.method || "GET").toUpperCase();
|
|
5753
|
+
const nextHeaders = {};
|
|
5754
|
+
const h = init?.headers;
|
|
5755
|
+
if (h && typeof h.forEach === "function") {
|
|
5756
|
+
h.forEach((v, k) => {
|
|
5757
|
+
if (!v) return;
|
|
5758
|
+
nextHeaders[k] = String(v);
|
|
5759
|
+
});
|
|
5760
|
+
} else {
|
|
5761
|
+
Object.entries(h || {}).forEach(([k, v]) => {
|
|
5762
|
+
if (!v) return;
|
|
5763
|
+
nextHeaders[k] = Array.isArray(v) ? v.join(",") : String(v);
|
|
5764
|
+
});
|
|
5765
|
+
}
|
|
5766
|
+
return fetch(workerUrl.toString(), {
|
|
5767
|
+
...init,
|
|
5768
|
+
method: method2,
|
|
5769
|
+
headers: nextHeaders
|
|
5770
|
+
});
|
|
5771
|
+
};
|
|
5570
5772
|
const upstreamFetch = async (input, init = {}) => {
|
|
5773
|
+
if (conversionProxyBaseUrlForRequest) {
|
|
5774
|
+
return workerRawFetch(input, init);
|
|
5775
|
+
}
|
|
5571
5776
|
const primary = await scraperFetch(input, init);
|
|
5572
5777
|
if (!await shouldFallbackFromScraper(primary)) {
|
|
5573
5778
|
return primary;
|
|
@@ -5598,7 +5803,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
5598
5803
|
)}`,
|
|
5599
5804
|
redirect: "manual"
|
|
5600
5805
|
});
|
|
5601
|
-
const setCookies = passResp.headers.getSetCookie?.() || [];
|
|
5806
|
+
const setCookies = passResp.headers.getSetCookie?.() || (passResp.headers.get("set-cookie") ? [String(passResp.headers.get("set-cookie"))] : []);
|
|
5602
5807
|
cookieHeader = setCookies.map((c) => c.split(";")[0]).join("; ");
|
|
5603
5808
|
}
|
|
5604
5809
|
const fetchHeaders = { ...headers };
|
|
@@ -5696,7 +5901,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
5696
5901
|
html = stripTrackingScriptsFromScrapedHtml(html, trackingMarkersForRequest);
|
|
5697
5902
|
html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
|
|
5698
5903
|
const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5699
|
-
const proxyBase =
|
|
5904
|
+
const proxyBase = `${proxyRootForRequest}?password=${encodeURIComponent(password)}&url=`;
|
|
5700
5905
|
html = html.replace(
|
|
5701
5906
|
new RegExp(`(href|action)="${escapedOrigin}(/[^"]*)"`, "g"),
|
|
5702
5907
|
(match, attr, urlPath) => {
|
|
@@ -5709,7 +5914,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
5709
5914
|
);
|
|
5710
5915
|
html = html.replace(
|
|
5711
5916
|
/data-link="\/(?!\/)([^"]*)"/g,
|
|
5712
|
-
(_match, pathPart) => `data-link="
|
|
5917
|
+
(_match, pathPart) => `data-link="${proxyRootForRequest}?password=${encodeURIComponent(password)}&url=${encodeURIComponent(
|
|
5713
5918
|
`${origin}/${pathPart}`
|
|
5714
5919
|
)}"`
|
|
5715
5920
|
);
|
|
@@ -5733,6 +5938,7 @@ ${iframeAlwaysShowCssGuardScript}
|
|
|
5733
5938
|
var TARGET_ORIGIN=${JSON.stringify(origin)};
|
|
5734
5939
|
var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
|
|
5735
5940
|
var PROXY_PASSWORD=${JSON.stringify(password)};
|
|
5941
|
+
var PROXY_BASE_URL="";
|
|
5736
5942
|
var STRICT_OBSERVER_FREEZE=${JSON.stringify(strictObserverFreezeForRequest)};
|
|
5737
5943
|
var PARENT_URL_CHANNEL="vvveb-proxy-url";
|
|
5738
5944
|
window.__CONVERSION_EDITOR_ACTIVE__=true;
|
|
@@ -5783,7 +5989,7 @@ function shouldBlockEditorTracking(rawUrl){
|
|
|
5783
5989
|
var looksLikeHeartbeatPayload=hasViewportPing&&hasSessionIds;
|
|
5784
5990
|
var isCrossOriginCollector=host!==TARGET_HOSTNAME&&hasMarker(host,TRACKING_HOST_MARKERS)&&hasMarker(path,TRACKING_PATH_MARKERS);
|
|
5785
5991
|
var isSnowplowStylePath=path==="/i"||path.indexOf("/com.snowplowanalytics.snowplow/")!==-1||path.indexOf("/tp2")!==-1;
|
|
5786
|
-
var isTaboolaUnip=host==="trc-events.taboola.com"
|
|
5992
|
+
var isTaboolaUnip=host==="trc-events.taboola.com"&&/\\/log\\/\\d+\\/unip(?:\\/|$)/.test(path);
|
|
5787
5993
|
var isCollectApiPath=path==="/api/collect"||path.indexOf("/api/collect/")===0;
|
|
5788
5994
|
var isNbCollectorPath=path==="/nb-collector"||path.indexOf("/nb-collector/")===0;
|
|
5789
5995
|
return isCrossOriginCollector||(looksLikeHeartbeatPayload&&isSnowplowStylePath)||isCollectApiPath||isTaboolaUnip||isNbCollectorPath;
|
|
@@ -5853,7 +6059,7 @@ try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
|
|
|
5853
6059
|
try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
|
|
5854
6060
|
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
5855
6061
|
function toAbsolute(raw){if(isSkippable(raw))return raw;try{var base=raw.startsWith("/")||raw.startsWith("//")?TARGET_ORIGIN:TARGET_PAGE_URL;return new URL(raw,base).toString();}catch(_){return raw;}}
|
|
5856
|
-
function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;
|
|
6062
|
+
function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;var root="/api/conversion-proxy";return root+"?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
|
|
5857
6063
|
var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
|
|
5858
6064
|
var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
|
|
5859
6065
|
function safeNavigate(raw,mode){var abs=toAbsolute(raw);var prox=toProxy(raw);if(!prox){try{console.warn("[conversion-proxy] redirect blocked",{mode:mode,requested:raw,resolved:abs,origin:TARGET_ORIGIN});}catch(_){}return false;}try{console.info("[conversion-proxy] redirect intercepted",{mode:mode,requested:raw,resolved:abs,proxied:prox});if(mode==="replace"&&nativeReplace){nativeReplace(prox);return true;}if(nativeAssign){nativeAssign(prox);return true;}window.location.href=prox;return true;}catch(err){try{console.warn("[conversion-proxy] redirect interception failed",{mode:mode,requested:raw,resolved:abs,proxied:prox,error:err&&err.message?err.message:String(err)});}catch(_){}return false;}}
|
|
@@ -5922,8 +6128,22 @@ if(window.fetch){
|
|
|
5922
6128
|
try{
|
|
5923
6129
|
var u=afterUrl?resolveUrl(afterUrl):null;
|
|
5924
6130
|
var sameOrigin=!!(u&&u.origin===TARGET_ORIGIN);
|
|
5925
|
-
var
|
|
5926
|
-
|
|
6131
|
+
var reqMethod=(init&&init.method?String(init.method):(input&&input.method?String(input.method):"GET")).toUpperCase();
|
|
6132
|
+
var isSafeMethod=reqMethod==="GET"||reqMethod==="HEAD";
|
|
6133
|
+
var path=(u&&u.pathname?u.pathname:"").toLowerCase();
|
|
6134
|
+
var qs=(u&&u.search?u.search:"").toLowerCase();
|
|
6135
|
+
var likelyBackgroundEndpoint=!!(u&&(
|
|
6136
|
+
/(^|\\/)apps?(\\/|$)|(^|\\/)a(\\/|$)/.test(path)||
|
|
6137
|
+
path==="/cart"||
|
|
6138
|
+
path==="/cart.js"||
|
|
6139
|
+
path.indexOf("/cart/")===0||
|
|
6140
|
+
path.indexOf("/recommendations/")===0||
|
|
6141
|
+
path.indexOf("/search/suggest")===0||
|
|
6142
|
+
qs.indexOf("sections=")!==-1||
|
|
6143
|
+
qs.indexOf("section_id=")!==-1
|
|
6144
|
+
));
|
|
6145
|
+
var likelyThirdPartyBg=!sameOrigin||likelyBackgroundEndpoint;
|
|
6146
|
+
if(window.__CONVERSION_EDITOR_ACTIVE__&&isSafeMethod&&likelyThirdPartyBg){
|
|
5927
6147
|
console.warn("[conversion-proxy] suppressed fetch failure",{url:afterUrl,error:err&&err.message?err.message:String(err)});
|
|
5928
6148
|
return new Response("{}",{status:200,headers:{"Content-Type":"application/json; charset=utf-8"}});
|
|
5929
6149
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@accelerated-agency/visual-editor",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Conversion visual editor as a reusable React package",
|
|
6
6
|
"type": "module",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"clean": "rm -rf dist",
|
|
27
27
|
"build": "tsup",
|
|
28
28
|
"local:build": "tsup && yarn --cwd ../codebase-server clean && yarn --cwd ../codebase-server dev",
|
|
29
|
-
"watch": "tsup --watch"
|
|
29
|
+
"watch": "tsup --watch",
|
|
30
|
+
"deploy:worker": "wrangler deploy"
|
|
30
31
|
},
|
|
31
32
|
"peerDependencies": {
|
|
32
33
|
"react": ">=18",
|