@useinsider/guido 3.21.0-beta.7e166b5 → 3.21.0-beta.8a9421f

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.
@@ -1,37 +1,37 @@
1
1
  var A = Object.defineProperty;
2
- var b = (c, l, e) => l in c ? A(c, l, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[l] = e;
3
- var m = (c, l, e) => b(c, typeof l != "symbol" ? l + "" : l, e);
4
- import { useConfig as d } from "../../../composables/useConfig.js";
5
- import { BlockId as E } from "../../../enums/block.js";
6
- import { getMigrationBannerHtml as C } from "../../../utils/migrationBannerHtml.js";
7
- import { Block as S, BlockCompositionType as N, ModificationDescription as p } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
8
- import { CURRENT_CONFIG_VERSION as v, PRE_RRS_CONFIG_VERSION as w } from "./constants/defaultConfig.js";
9
- import { RECOMMENDATION_ID_ATTR as h } from "./constants/selectors.js";
2
+ var D = (m, c, e) => c in m ? A(m, c, { enumerable: !0, configurable: !0, writable: !0, value: e }) : m[c] = e;
3
+ var u = (m, c, e) => D(m, typeof c != "symbol" ? c + "" : c, e);
4
+ import { useConfig as g } from "../../../composables/useConfig.js";
5
+ import { BlockId as b } from "../../../enums/block.js";
6
+ import { getMigrationBannerHtml as E } from "../../../utils/migrationBannerHtml.js";
7
+ import { Block as S, BlockCompositionType as v, ModificationDescription as _ } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
8
+ import { CURRENT_CONFIG_VERSION as N, PRE_RRS_CONFIG_VERSION as w } from "./constants/defaultConfig.js";
9
+ import { RECOMMENDATION_ID_ATTR as f } from "./constants/selectors.js";
10
10
  import { regenerateMobileProductRows as M } from "./controls/main/utils.js";
11
11
  import { ensureMobileCssRulesExist as I, setMobileLayoutOptOut as R, hasMobileLayoutOptOut as O } from "./controls/mobileLayout/cssRules.js";
12
- import { RecommendationConfigService as o } from "./services/configService.js";
13
- import { useRecommendationExtensionStore as f } from "./store/recommendation.js";
12
+ import { RecommendationConfigService as a } from "./services/configService.js";
13
+ import { useRecommendationExtensionStore as p } from "./store/recommendation.js";
14
14
  import { getDefaultTemplate as T } from "./templates/grid/template.js";
15
15
  import { useRecommendationBlockWarning as x } from "./useRecommendationBlockWarning.js";
16
- import { registerNodeConfigWriter as k } from "./utils/nodeConfigWriter.js";
17
- import { refreshArrivedStrategyBlocks as $, refreshDuplicatedStrategyBlocks as H } from "./utils/strategyCommit.js";
18
- const y = E.Recommendation, u = "recommendation-block-v2", B = "hide-price";
19
- let D = !1;
20
- class Z extends S {
16
+ import { registerNodeConfigWriter as k, readBlockNodeConfigs as $ } from "./utils/nodeConfigWriter.js";
17
+ import { refreshArrivedStrategyBlocks as q, resolveSourceConfig as H, refreshDuplicatedStrategyBlocks as F } from "./utils/strategyCommit.js";
18
+ const y = b.Recommendation, d = "recommendation-block-v2", C = "hide-price";
19
+ let B = !1;
20
+ class te extends S {
21
21
  constructor() {
22
22
  super();
23
23
  /**
24
24
  * Stores the ID generated in getTemplate() so onCreated() can reuse it.
25
25
  * This avoids generating a new (different) ID in onCreated().
26
26
  */
27
- m(this, "_pendingBlockId", null);
27
+ u(this, "_pendingBlockId", null);
28
28
  /** Ids already reset under their new name, so the deferred pass skips their stale snapshot. */
29
- m(this, "_resetSourceIds", /* @__PURE__ */ new Set());
29
+ u(this, "_resetSourceIds", /* @__PURE__ */ new Set());
30
30
  /** Ids handed to duplicates the document root does not show yet: a copied module renames all its blocks at once. */
31
- m(this, "_unsettledDuplicateIds", /* @__PURE__ */ new Set());
32
- m(this, "_arrivedNodes", []);
33
- /** Ids whose arrival or duplicate refresh is in flight, so a second refresh of the same block does not race it. */
34
- m(this, "_refreshingIds", /* @__PURE__ */ new Set());
31
+ u(this, "_unsettledDuplicateIds", /* @__PURE__ */ new Set());
32
+ u(this, "_arrivedBlocks", []);
33
+ /** Strategy each in-flight arrival or duplicate refresh is fetching, by block id, so a second one does not race it. */
34
+ u(this, "_refreshClaims", /* @__PURE__ */ new Map());
35
35
  }
36
36
  getId() {
37
37
  return y;
@@ -40,7 +40,7 @@ class Z extends S {
40
40
  return "recommendation-icon";
41
41
  }
42
42
  getBlockCompositionType() {
43
- return N.CONTAINER;
43
+ return v.CONTAINER;
44
44
  }
45
45
  getName() {
46
46
  return this.api.translate("Recommendation Block");
@@ -51,7 +51,7 @@ class Z extends S {
51
51
  );
52
52
  }
53
53
  getSettingsPanelTitleHtml() {
54
- return C(
54
+ return E(
55
55
  y,
56
56
  this.api.translate("Recommendation Block"),
57
57
  this.api.translate("This block is switched from the Old Version to the New Version. We recommend you check the Recommendation block and test your message to ensure it works properly.")
@@ -87,14 +87,13 @@ class Z extends S {
87
87
  onCreated(e) {
88
88
  const t = this._getRecommendationId(e);
89
89
  if (t !== null && t > 0) {
90
- if (this._detectDuplicate(t)) {
90
+ if (this._pendingBlockId = null, this._detectDuplicate(t)) {
91
91
  this._handleDuplicate(e, t), this._scheduleArrivalReset(e);
92
92
  return;
93
93
  }
94
- const g = this._pendingBlockId === null;
95
94
  setTimeout(() => {
96
95
  if (this._getBlockElement(e)) {
97
- if (g && this._detectDuplicate(t)) {
96
+ if (this._detectDuplicate(t)) {
98
97
  this._handleDuplicate(e, t);
99
98
  return;
100
99
  }
@@ -105,34 +104,34 @@ class Z extends S {
105
104
  }
106
105
  const i = this._pendingBlockId ?? this._generateNextId();
107
106
  this._pendingBlockId = null, this._assignRecommendationId(e, i);
108
- const r = d().isFeatureEnabled("reusableRecommendationStrategy"), s = r && !o.hasConfig(e), { config: n, wasFreshDrop: a } = o.initializeConfig(
107
+ const r = g().isFeatureEnabled("reusableRecommendationStrategy"), s = r && !a.hasConfig(e), { config: n, wasFreshDrop: o } = a.initializeConfig(
109
108
  this.api,
110
109
  e,
111
110
  {
112
111
  recommendationId: i,
113
- configVersion: r ? v : w,
114
- ...s ? { partnerName: d().partnerName.value } : {},
112
+ configVersion: r ? N : w,
113
+ ...s ? { partnerName: g().partnerName.value } : {},
115
114
  // An RRS block picks a strategy, not an algorithm, and its algorithm control is
116
115
  // hidden. Keeping the `mostPopular` default would bake a most-popular feed URL
117
116
  // at save for a block the user never configured.
118
117
  ...s ? { strategy: "" } : {}
119
118
  }
120
- ), _ = f();
121
- if (_.setCurrentBlock(i), this._stampHidePrice(e, n.priceHideIfSameAsDiscounted), a) {
119
+ ), l = p();
120
+ if (l.setCurrentBlock(i), this._stampHidePrice(e, n.priceHideIfSameAsDiscounted), o) {
122
121
  I(this.api);
123
- const g = this._getBlockElement(e);
124
- g && (R(this.api, g, !0), M({
122
+ const h = this._getBlockElement(e);
123
+ h && (R(this.api, h, !0), M({
125
124
  currentNode: e,
126
125
  documentModifier: this.api.getDocumentModifier()
127
126
  }));
128
127
  }
129
- _.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 }), this._warnIfMultipleBlocks();
128
+ l.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 }), this._warnIfMultipleBlocks();
130
129
  }
131
130
  /** Refreshes every block of an opened template: Stripo restores a stored document without `onCreated`. */
132
131
  onDocumentInit() {
133
132
  try {
134
133
  const e = this.api.getDocumentRoot();
135
- e && "querySelectorAll" in e && e.querySelectorAll(`.${u}`).forEach((t) => this._queueArrivalRefresh(t));
134
+ e && "querySelectorAll" in e && e.querySelectorAll(`.${d}`).forEach((t) => this._queueArrivalRefresh(t));
136
135
  } catch (e) {
137
136
  console.error("[recommendation] refreshing an opened strategy failed", e);
138
137
  }
@@ -148,17 +147,17 @@ class Z extends S {
148
147
  if (!(!e || !("getNodeConfig" in e))) {
149
148
  if (!this._getRecommendationId(e)) {
150
149
  const t = this._generateNextId();
151
- this._assignRecommendationId(e, t), o.hasConfig(e) && o.updateConfig(
150
+ this._assignRecommendationId(e, t), a.hasConfig(e) && a.updateConfig(
152
151
  this.api,
153
152
  e,
154
153
  { recommendationId: t },
155
154
  "Assign recommendation ID to legacy block"
156
155
  );
157
156
  }
158
- this._healLingeringDuplicate(e), o.needsMigration(e) && this._migrateFromLegacy(e), this._healHidePriceAttr(e);
157
+ this._healLingeringDuplicate(e), a.needsMigration(e) && this._migrateFromLegacy(e), this._healHidePriceAttr(e);
159
158
  try {
160
- D || (I(this.api), D = !0);
161
- const t = o.getConfig(e), i = this._getBlockElement(e);
159
+ B || (I(this.api), B = !0);
160
+ const t = a.getConfig(e), i = this._getBlockElement(e);
162
161
  if (i) {
163
162
  const r = !t.mobileLayoutEnabled;
164
163
  O(i) !== r && R(this.api, i, r);
@@ -175,7 +174,7 @@ class Z extends S {
175
174
  */
176
175
  onDelete(e) {
177
176
  const t = this._getRecommendationId(e);
178
- t && f().removeBlockState(t);
177
+ t && p().removeBlockState(t);
179
178
  }
180
179
  /**
181
180
  * Warns (dark advisory toaster) when the design holds more than one live
@@ -204,10 +203,10 @@ class Z extends S {
204
203
  const t = /* @__PURE__ */ new Set();
205
204
  try {
206
205
  const i = this.api.getDocumentRoot();
207
- i && "querySelectorAll" in i && i.querySelectorAll(`.${u}`).forEach((s) => {
206
+ i && "querySelectorAll" in i && i.querySelectorAll(`.${d}`).forEach((s) => {
208
207
  if ("getAttribute" in s) {
209
- const n = s.getAttribute(h), a = n ? parseInt(n) : 0;
210
- t.add(a), a > e && (e = a);
208
+ const n = s.getAttribute(f), o = n ? parseInt(n) : 0;
209
+ t.add(o), o > e && (e = o);
211
210
  }
212
211
  });
213
212
  } catch {
@@ -224,42 +223,64 @@ class Z extends S {
224
223
  * the renamed one depending on where the module was dropped (SD-149916).
225
224
  */
226
225
  _scheduleArrivalReset(e) {
227
- d().isFeatureEnabled("reusableRecommendationStrategy") && setTimeout(() => {
226
+ g().isFeatureEnabled("reusableRecommendationStrategy") && setTimeout(() => {
228
227
  const t = this._getRecommendationId(e);
229
- t !== null && t > 0 && !this._resetSourceIds.delete(t) && f().resetArrivedBlock(t);
228
+ t !== null && t > 0 && !this._resetSourceIds.delete(t) && p().resetArrivedBlock(t);
230
229
  }, 0);
231
230
  }
232
231
  /**
233
232
  * Re-reads the strategy of a block that arrived with saved cards, without waiting for a click.
234
233
  * Blocks of one opened template or dropped module arrive in one tick and refresh together.
235
234
  */
236
- _queueArrivalRefresh(e) {
237
- d().isFeatureEnabled("reusableRecommendationStrategy") && (this._arrivedNodes.push(e) > 1 || setTimeout(() => {
238
- const t = this._arrivedNodes;
239
- this._arrivedNodes = [];
235
+ _queueArrivalRefresh(e, t) {
236
+ g().isFeatureEnabled("reusableRecommendationStrategy") && (this._arrivedBlocks.push({ node: e, id: t }) > 1 || setTimeout(() => {
237
+ const i = this._arrivedBlocks;
238
+ this._arrivedBlocks = [];
240
239
  try {
241
- this._refreshArrivedBlocks(t);
242
- } catch (i) {
243
- console.error("[recommendation] refreshing an arrived strategy failed", i);
240
+ this._refreshArrivedBlocks(i);
241
+ } catch (r) {
242
+ console.error("[recommendation] refreshing an arrived strategy failed", r);
244
243
  }
245
244
  }, 0));
246
245
  }
247
246
  _refreshArrivedBlocks(e) {
248
- const t = e.flatMap((i) => {
249
- const r = this._getRecommendationId(i), s = this._getBlockElement(i);
250
- return !r || !s || this._refreshingIds.has(r) ? [] : (this._refreshingIds.add(r), [{ id: r, config: o.getConfig(s) }]);
247
+ k(this.api);
248
+ const t = /* @__PURE__ */ new Set(), i = e.flatMap(({ node: r, id: s }) => {
249
+ const n = s ?? this._getRecommendationId(r), o = this._getBlockElement(r);
250
+ if (!n || !o || t.has(n))
251
+ return [];
252
+ const l = a.getConfig(o);
253
+ if (!this._canClaimRefresh(n, l.strategyId))
254
+ return [];
255
+ const h = { strategyId: l.strategyId };
256
+ return t.add(n), this._refreshClaims.set(n, h), [{ id: n, config: l, claim: h }];
251
257
  });
252
- t.length && (k(this.api), $(t).catch((i) => console.error("[recommendation] refreshing an arrived strategy failed", i)).finally(() => t.forEach(({ id: i }) => this._refreshingIds.delete(i))));
258
+ i.length && q(i.map(({ id: r, config: s }) => ({ id: r, config: s }))).catch((r) => console.error("[recommendation] refreshing an arrived strategy failed", r)).finally(() => i.forEach(({ id: r, claim: s }) => this._releaseRefreshClaim(r, s)));
259
+ }
260
+ /**
261
+ * A new document reports each block to onCreated and onDocumentInit, not always in one batch, so a
262
+ * claimed block refreshes again only once the document shows it under another strategy (a restored version).
263
+ */
264
+ _canClaimRefresh(e, t) {
265
+ const i = this._refreshClaims.get(e);
266
+ if (!i)
267
+ return !0;
268
+ if (i.strategyId === t)
269
+ return !1;
270
+ const r = $(e);
271
+ return r.length > 0 && r.every((s) => s.strategyId === t);
272
+ }
273
+ _releaseRefreshClaim(e, t) {
274
+ this._refreshClaims.get(e) === t && this._refreshClaims.delete(e);
253
275
  }
254
276
  /**
255
277
  * Heals a duplicate that slipped past the create-time `_detectDuplicate`
256
278
  * scan (or that was persisted by an older template before SD-142352).
257
279
  * When two blocks share a `recommendation-id`, the first occurrence in DOM
258
280
  * order is treated as the source and any later sibling is reassigned a
259
- * fresh id. The store entry and active-block focus are intentionally not
260
- * touched here: each block's persisted `esd-ext-config` carries its own
261
- * truth and the regular save-time hydration (`hydrateRecommendationStore`)
262
- * will seed the new id from that. Skipping `setCurrentBlock` avoids
281
+ * fresh id and queued for the arrival refresh, which seeds the new id's
282
+ * store entry from its persisted `esd-ext-config`. The source's store
283
+ * entry is not cloned and focus is not moved. Skipping `setCurrentBlock` avoids
263
284
  * yanking the user's current selection mid-edit when the heal fires from
264
285
  * `onDocumentChanged`.
265
286
  */
@@ -271,7 +292,7 @@ class Z extends S {
271
292
  if (!i || !("querySelectorAll" in i))
272
293
  return;
273
294
  const r = i.querySelectorAll(
274
- `.${u}[${h}="${t}"]`
295
+ `.${d}[${f}="${t}"]`
275
296
  );
276
297
  if (r.length <= 1)
277
298
  return;
@@ -279,14 +300,14 @@ class Z extends S {
279
300
  if (!s)
280
301
  return;
281
302
  let n = -1;
282
- for (let a = 0; a < r.length; a++)
283
- if (r[a] === s) {
284
- n = a;
303
+ for (let o = 0; o < r.length; o++)
304
+ if (r[o] === s) {
305
+ n = o;
285
306
  break;
286
307
  }
287
308
  if (n <= 0)
288
309
  return;
289
- this._reassignDuplicateId(e, t);
310
+ this._queueArrivalRefresh(e, this._reassignDuplicateId(e, t));
290
311
  } catch {
291
312
  }
292
313
  }
@@ -296,7 +317,7 @@ class Z extends S {
296
317
  const t = this.api.getDocumentRoot();
297
318
  if (t && "querySelectorAll" in t)
298
319
  return t.querySelectorAll(
299
- `.${u}[${h}="${e}"]`
320
+ `.${d}[${f}="${e}"]`
300
321
  ).length > 1;
301
322
  } catch {
302
323
  }
@@ -304,11 +325,14 @@ class Z extends S {
304
325
  }
305
326
  /** Assigns a fresh id to a duplicated block and syncs DOM, node config and store. */
306
327
  _handleDuplicate(e, t) {
307
- const i = this._reassignDuplicateId(e, t), r = f();
308
- if (r.cloneBlockState(t, i), r.setCurrentBlock(i), d().isFeatureEnabled("reusableRecommendationStrategy")) {
328
+ const i = this._reassignDuplicateId(e, t), r = p();
329
+ if (r.cloneBlockState(t, i), r.setCurrentBlock(i), g().isFeatureEnabled("reusableRecommendationStrategy")) {
309
330
  this._resetSourceIds.add(t), k(this.api);
310
- const s = [t, i].filter((n) => !this._refreshingIds.has(n));
311
- s.forEach((n) => this._refreshingIds.add(n)), H(t, i, o.getConfig(e)).catch((n) => console.error("[recommendation] refreshing a duplicated strategy failed", n)).finally(() => s.forEach((n) => this._refreshingIds.delete(n)));
331
+ const s = a.getConfig(e), n = [
332
+ { id: t, claim: { strategyId: H(t, s).strategyId } },
333
+ { id: i, claim: { strategyId: s.strategyId } }
334
+ ].filter(({ id: o }) => !this._refreshClaims.has(o));
335
+ n.forEach(({ id: o, claim: l }) => this._refreshClaims.set(o, l)), F(t, i, s).catch((o) => console.error("[recommendation] refreshing a duplicated strategy failed", o)).finally(() => n.forEach(({ id: o, claim: l }) => this._releaseRefreshClaim(o, l)));
312
336
  }
313
337
  this._warnIfMultipleBlocks();
314
338
  }
@@ -319,13 +343,13 @@ class Z extends S {
319
343
  *
320
344
  * Used by `_handleDuplicate` at create-time (which additionally clones the
321
345
  * store entry and focuses the new block) and by `_healLingeringDuplicate`
322
- * at document-change time (which intentionally skips store/focus side
323
- * effects so older bug-affected templates can self-repair without
324
- * disturbing the user's current selection).
346
+ * at document-change time (which skips the clone and focus change so older
347
+ * bug-affected templates can self-repair without disturbing the user's
348
+ * current selection, and queues the arrival refresh for the new id).
325
349
  */
326
350
  _reassignDuplicateId(e, t) {
327
351
  const i = this._generateNextId(), r = this._getBlockElement(e);
328
- return this._unsettledDuplicateIds.add(i), this._assignRecommendationId(e, i), r && this._reassignInstanceClass(r, t, i), o.hasConfig(e) && o.updateConfig(
352
+ return this._unsettledDuplicateIds.add(i), this._assignRecommendationId(e, i), r && this._reassignInstanceClass(r, t, i), a.hasConfig(e) && a.updateConfig(
329
353
  this.api,
330
354
  e,
331
355
  { recommendationId: i },
@@ -343,7 +367,7 @@ class Z extends S {
343
367
  if (!("getAttribute" in e))
344
368
  return;
345
369
  const r = `ins-recommendation-v3-block-${t}`, s = `ins-recommendation-v3-block-${i}`, n = this.api.getDocumentModifier();
346
- n.modifyHtml(e).removeClass(r).setClass(s), n.apply(new p(
370
+ n.modifyHtml(e).removeClass(r).setClass(s), n.apply(new _(
347
371
  `Reassign recommendation instance class ${r} -> ${s}`
348
372
  ));
349
373
  }
@@ -358,7 +382,7 @@ class Z extends S {
358
382
  if (!i)
359
383
  return;
360
384
  const r = this.api.getDocumentModifier();
361
- r.modifyHtml(i).setAttribute(h, t.toString()), r.apply(new p(`Assign recommendation ID ${t}`));
385
+ r.modifyHtml(i).setAttribute(f, t.toString()), r.apply(new _(`Assign recommendation ID ${t}`));
362
386
  }
363
387
  /**
364
388
  * Stamps the `hide-price` attribute (read by email-service at send time) on
@@ -366,7 +390,7 @@ class Z extends S {
366
390
  */
367
391
  _stampHidePrice(e, t) {
368
392
  const i = this._getBlockElement(e);
369
- i && this.api.getDocumentModifier().modifyHtml(i).setAttribute(B, String(t)).apply(new p("Stamp hide-price"));
393
+ i && this.api.getDocumentModifier().modifyHtml(i).setAttribute(C, String(t)).apply(new _("Stamp hide-price"));
370
394
  }
371
395
  /**
372
396
  * Stamps `hide-price` from config only when the block lacks the attribute —
@@ -374,9 +398,9 @@ class Z extends S {
374
398
  */
375
399
  _healHidePriceAttr(e) {
376
400
  const t = this._getBlockElement(e);
377
- if (!t || !("getAttribute" in t) || t.getAttribute(B) !== null)
401
+ if (!t || !("getAttribute" in t) || t.getAttribute(C) !== null)
378
402
  return;
379
- const { priceHideIfSameAsDiscounted: i } = o.getConfig(e);
403
+ const { priceHideIfSameAsDiscounted: i } = a.getConfig(e);
380
404
  this._stampHidePrice(e, i);
381
405
  }
382
406
  /**
@@ -386,7 +410,7 @@ class Z extends S {
386
410
  const t = this._getBlockElement(e);
387
411
  if (!t || !("getAttribute" in t))
388
412
  return null;
389
- const i = t.getAttribute(h);
413
+ const i = t.getAttribute(f);
390
414
  if (!i)
391
415
  return null;
392
416
  const r = parseInt(i);
@@ -398,19 +422,19 @@ class Z extends S {
398
422
  _getBlockElement(e) {
399
423
  if ("getAttribute" in e) {
400
424
  const t = e.getAttribute("class");
401
- if (t && t.includes(u))
425
+ if (t && t.includes(d))
402
426
  return e;
403
427
  }
404
- return "querySelector" in e ? e.querySelector(`.${u}`) ?? null : null;
428
+ return "querySelector" in e ? e.querySelector(`.${d}`) ?? null : null;
405
429
  }
406
430
  /**
407
431
  * Migrate configuration from legacy format
408
432
  */
409
433
  _migrateFromLegacy(e) {
410
- o.migrateFromDataAttributes(this.api, e);
434
+ a.migrateFromDataAttributes(this.api, e);
411
435
  }
412
436
  }
413
437
  export {
414
438
  y as BLOCK_ID,
415
- Z as RecommendationBlock
439
+ te as RecommendationBlock
416
440
  };
@@ -1,60 +1,64 @@
1
- import { useRecommendationExtensionStore as c } from "../store/recommendation.js";
1
+ import { useRecommendationExtensionStore as f } from "../store/recommendation.js";
2
2
  import { refreshBlockOutsidePanel as l } from "./blockRefresh.js";
3
- import { toBlockUrlConfig as i } from "./blockUrlConfig.js";
4
- import { commitBlockChangeOutsidePanel as y, readBlockNodeConfigs as d } from "./nodeConfigWriter.js";
5
- function S(o, t) {
6
- const r = JSON.stringify(i(t));
7
- return d(o).find((n) => JSON.stringify(i(n)) !== r) ?? t;
3
+ import { toBlockUrlConfig as c } from "./blockUrlConfig.js";
4
+ import { readBlockNodeConfigs as m, commitBlockChangeOutsidePanel as d } from "./nodeConfigWriter.js";
5
+ function u(n, t) {
6
+ const r = JSON.stringify(c(t));
7
+ return m(n).find((s) => JSON.stringify(c(s)) !== r) ?? t;
8
8
  }
9
- async function m(o, t, r = () => !0) {
10
- const n = c();
11
- await Promise.all(o.map(async (e) => {
12
- if (!await n.refreshStrategyBlock(e))
9
+ async function y(n, t, r = () => !0) {
10
+ const s = f();
11
+ await Promise.all(n.map(async (e) => {
12
+ if (!await s.refreshStrategyBlock(e))
13
13
  return;
14
- const { recommendationConfigs: s, recommendationProducts: a } = n.blockStates[e];
15
- r(e, s.size) && y(
14
+ const { recommendationConfigs: a, recommendationProducts: o } = s.blockStates[e];
15
+ r(e, a.size) && d(
16
16
  e,
17
- { size: s.size },
18
- a,
17
+ { size: a.size },
18
+ o,
19
19
  t
20
20
  );
21
21
  }));
22
22
  }
23
- async function C(o, t, r) {
24
- const n = c(), e = [o, t];
25
- (/* @__PURE__ */ new Map([[o, S(o, r)], [t, r]])).forEach((a, f) => {
23
+ async function w(n, t, r) {
24
+ const s = f(), e = [n, t];
25
+ (/* @__PURE__ */ new Map([[n, u(n, r)], [t, r]])).forEach((o, i) => {
26
26
  var g;
27
- (!!a.strategyId || f === t) && ((g = n.blockStates[f]) == null ? void 0 : g.recommendationConfigs.strategyId) !== a.strategyId && n.seedBlockUrlConfig(f, i(a));
28
- }), n.resetArrivedBlock(t), await m(e, "Refresh duplicated recommendation strategy");
27
+ (!!o.strategyId || i === t) && ((g = s.blockStates[i]) == null ? void 0 : g.recommendationConfigs.strategyId) !== o.strategyId && s.seedBlockUrlConfig(i, c(o));
28
+ }), s.resetArrivedBlock(t), await y(e, "Refresh duplicated recommendation strategy");
29
29
  }
30
- async function k(o) {
31
- const t = c(), r = o.filter(({ config: e }) => !!e.strategyId);
30
+ async function k(n) {
31
+ const t = f(), r = n.filter(({ config: e }) => !!e.strategyId);
32
32
  if (!r.length)
33
33
  return;
34
- r.forEach(({ id: e, config: s }) => t.seedBlockUrlConfig(e, i(s))), t.invalidateStrategies();
35
- const n = new Map(r.map(({ id: e, config: s }) => [e, s.size]));
36
- await m(
34
+ r.forEach(({ id: e, config: a }) => t.seedBlockUrlConfig(e, c(a))), t.invalidateStrategies();
35
+ const s = new Map(r.map(({ id: e, config: a }) => [e, a]));
36
+ await y(
37
37
  r.map(({ id: e }) => e),
38
38
  "Refresh recommendation strategy",
39
- (e, s) => s !== n.get(e)
39
+ (e, a) => {
40
+ const o = s.get(e);
41
+ return a !== (o == null ? void 0 : o.size) && m(e).some((i) => i.strategyId === (o == null ? void 0 : o.strategyId));
42
+ }
40
43
  );
41
44
  }
42
- async function O(o, t) {
43
- if (!c().blockStates[o])
45
+ async function O(n, t) {
46
+ if (!f().blockStates[n])
44
47
  return !1;
45
- const r = await l(o, {
46
- pickUpdates: ({ strategyId: n, strategy: e, size: s, nodeConfigVersion: a }) => ({
47
- strategyId: n,
48
+ const r = await l(n, {
49
+ pickUpdates: ({ strategyId: s, strategy: e, size: a, nodeConfigVersion: o }) => ({
50
+ strategyId: s,
48
51
  strategy: e,
49
- size: s,
50
- configVersion: a
52
+ size: a,
53
+ configVersion: o
51
54
  }),
52
55
  description: t
53
56
  });
54
- return r || console.error("[recommendation] strategy change did not reach a node", { blockId: o }), r;
57
+ return r || console.error("[recommendation] strategy change did not reach a node", { blockId: n }), r;
55
58
  }
56
59
  export {
57
60
  O as commitStrategyChange,
58
61
  k as refreshArrivedStrategyBlocks,
59
- C as refreshDuplicatedStrategyBlocks
62
+ w as refreshDuplicatedStrategyBlocks,
63
+ u as resolveSourceConfig
60
64
  };
package/dist/guido.css CHANGED
@@ -1 +1 @@
1
- @charset "UTF-8";.auth-error-modal[data-v-b4d7ae51]{position:relative;z-index:145}.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-b8f24f34] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.view-options-wrapper[data-v-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-baf7a5dd]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.validation-error-list[data-v-e48cebe9]{gap:16px}.validation-error-row[data-v-e48cebe9]{gap:8px;padding:24px;border:1px solid #E1E1E1;border-radius:8px}.validation-error-row__icon[data-v-e48cebe9]{flex-shrink:0;font-size:24px;line-height:0}.validation-error-row__text[data-v-e48cebe9]{font-size:13px;line-height:16px;color:#292929;word-break:break-word}.guido-editor__wrapper[data-v-c5146fc5]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-c5146fc5]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-c5146fc5]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-91a26acd]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-91a26acd]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-91a26acd]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-91a26acd]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-91a26acd]{object-fit:cover;transform:scale(1)}[data-v-b9a93c6e] .guido__verion-history-view-option-selection-desktop svg,[data-v-b9a93c6e] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-b9a93c6e] .in-segments-wrapper__button_selected,[data-v-b9a93c6e] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-cf946232]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-cf946232]{min-height:504px}.iframe-wrapper[data-v-f255b2bb]{width:258px}.iframe-scaled[data-v-f255b2bb]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-6bcaca8a] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-f16f20f8] .vueperslides__bullets{pointer-events:none!important}[data-v-f16f20f8] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-bb3cca55] .vueperslides__bullets{pointer-events:none!important}[data-v-bb3cca55] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-19d8cb42] .vueperslides__bullets,[data-v-ec2027ff] .vueperslides__bullets,[data-v-b09e80c4] .vueperslides__bullets{pointer-events:none!important}[data-v-b09e80c4] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-9bdef600] .vueperslides__parallax-wrapper{padding-bottom:110px!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd]{width:100%;max-width:none}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-skeleton{width:100%!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-dropdown-box__container{width:413px}.assign-strategy-drawer .spaced-dot-sep{background-image:linear-gradient(90deg,#91949f 20%,#fff0 0);background-position:center bottom;background-repeat:repeat-x;background-size:5px 1px}.assign-strategy-drawer .spaced-dot-sep--top{background-position:center top}.assign-strategy-drawer .spaced-dot-sep--fc-n:first-child{background:none}.legacy-strategy-updated-modal[data-v-da2225a1]{position:relative;z-index:145}
1
+ @charset "UTF-8";.auth-error-modal[data-v-b4d7ae51]{position:relative;z-index:145}.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-b8f24f34] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.view-options-wrapper[data-v-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-baf7a5dd]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.validation-error-list[data-v-e48cebe9]{gap:16px}.validation-error-row[data-v-e48cebe9]{gap:8px;padding:24px;border:1px solid #E1E1E1;border-radius:8px}.validation-error-row__icon[data-v-e48cebe9]{flex-shrink:0;font-size:24px;line-height:0}.validation-error-row__text[data-v-e48cebe9]{font-size:13px;line-height:16px;color:#292929;word-break:break-word}.guido-editor__wrapper[data-v-1a3ddd48]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-1a3ddd48]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-1a3ddd48]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-91a26acd]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-91a26acd]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-91a26acd]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-91a26acd]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-91a26acd]{object-fit:cover;transform:scale(1)}[data-v-b9a93c6e] .guido__verion-history-view-option-selection-desktop svg,[data-v-b9a93c6e] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-b9a93c6e] .in-segments-wrapper__button_selected,[data-v-b9a93c6e] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-cf946232]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-cf946232]{min-height:504px}.iframe-wrapper[data-v-f255b2bb]{width:258px}.iframe-scaled[data-v-f255b2bb]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-6bcaca8a] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-f16f20f8] .vueperslides__bullets{pointer-events:none!important}[data-v-f16f20f8] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-bb3cca55] .vueperslides__bullets{pointer-events:none!important}[data-v-bb3cca55] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-19d8cb42] .vueperslides__bullets,[data-v-ec2027ff] .vueperslides__bullets,[data-v-b09e80c4] .vueperslides__bullets{pointer-events:none!important}[data-v-b09e80c4] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-9bdef600] .vueperslides__parallax-wrapper{padding-bottom:110px!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd]{width:100%;max-width:none}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-skeleton{width:100%!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-dropdown-box__container{width:413px}.assign-strategy-drawer .spaced-dot-sep{background-image:linear-gradient(90deg,#91949f 20%,#fff0 0);background-position:center bottom;background-repeat:repeat-x;background-size:5px 1px}.assign-strategy-drawer .spaced-dot-sep--top{background-position:center top}.assign-strategy-drawer .spaced-dot-sep--fc-n:first-child{background:none}.legacy-strategy-updated-modal[data-v-da2225a1]{position:relative;z-index:145}
package/dist/library.js CHANGED
@@ -1,20 +1,22 @@
1
1
  import { default as a } from "./components/Guido.vue.js";
2
- import { MessageType as t, ProductType as d } from "./@types/config/schemas.js";
2
+ import { MessageType as t, ProductType as f } from "./@types/config/schemas.js";
3
3
  import "./@types/config/defaults.js";
4
- import { getValidationErrors as s, isValidConfig as p, parseConfig as g, parseConfigSafe as m, validateConfig as n } from "./@types/config/validator.js";
5
- import { assignTrackingIds as u, readTrackFloor as x, readTrackSeq as T } from "./utils/linkTrackingIds.js";
4
+ import { getValidationErrors as p, isValidConfig as s, parseConfig as m, parseConfigSafe as g, validateConfig as n } from "./@types/config/validator.js";
5
+ import { assignTrackingIds as l, readTrackFloor as x, readTrackSeq as c } from "./utils/linkTrackingIds.js";
6
6
  import { useGuidoEmailEditorStore as C } from "./stores/guido-email-editor.js";
7
+ import { prefetchGuidoRuntime as E } from "./utils/runtimePrefetch.js";
7
8
  export {
8
9
  a as Guido,
9
10
  t as MessageType,
10
- d as ProductType,
11
- u as assignTrackingIds,
12
- s as getValidationErrors,
13
- p as isValidConfig,
14
- g as parseConfig,
15
- m as parseConfigSafe,
11
+ f as ProductType,
12
+ l as assignTrackingIds,
13
+ p as getValidationErrors,
14
+ s as isValidConfig,
15
+ m as parseConfig,
16
+ g as parseConfigSafe,
17
+ E as prefetchGuidoRuntime,
16
18
  x as readTrackFloor,
17
- T as readTrackSeq,
19
+ c as readTrackSeq,
18
20
  C as useGuidoEmailEditorStore,
19
21
  n as validateConfig
20
22
  };
@@ -1,7 +1,9 @@
1
- const o = { stripo: { version: "2.79.0" } }, s = {
2
- guido: o
1
+ const o = "3.21.0-beta.8a9421f", s = { stripo: { version: "2.79.0" } }, t = {
2
+ version: o,
3
+ guido: s
3
4
  };
4
5
  export {
5
- s as default,
6
- o as guido
6
+ t as default,
7
+ s as guido,
8
+ o as version
7
9
  };
@@ -0,0 +1,4 @@
1
+ import { prefetchGuidoRuntime as r } from "../utils/runtimePrefetch.js";
2
+ export {
3
+ r as prefetchGuidoRuntime
4
+ };
@@ -0,0 +1,27 @@
1
+ export type TimedOpenPhase = 'migration' | 'default_template' | 'timer_clone';
2
+ export type OpenPhase = 'setup' | 'host_ready' | `${TimedOpenPhase}_start` | `${TimedOpenPhase}_end` | 'plugin_start' | 'script_ready' | 'fonts_sync_ready' | 'blocks_config_ready' | 'init_editor' | 'token_start' | 'token_end' | 'ready';
3
+ export type OpenOutcome = 'ready' | 'error' | 'abandoned';
4
+ export interface OpenContext {
5
+ partnerName: string;
6
+ productType: number;
7
+ templateId: string;
8
+ variationId: string;
9
+ }
10
+ export interface OpenTemplate {
11
+ html: string;
12
+ css: string;
13
+ forceRecreate: boolean;
14
+ }
15
+ export interface EditorOpenMetrics {
16
+ mark: (phase: OpenPhase) => void;
17
+ timed: <T>(phase: TimedOpenPhase, task: () => Promise<T>) => Promise<T>;
18
+ setContext: (context: OpenContext) => void;
19
+ setTemplate: (template: OpenTemplate) => void;
20
+ setScriptPreloaded: (preloaded: boolean) => void;
21
+ markReady: () => void;
22
+ markFailed: () => void;
23
+ dispose: () => void;
24
+ }
25
+ export declare const startEditorOpenMetrics: () => EditorOpenMetrics;
26
+ /** Binds to the session open at call time, so a remounted editor never writes into its replacement's session. */
27
+ export declare const useEditorOpenMetrics: () => EditorOpenMetrics;