@useinsider/guido 3.18.1-beta.4fbee43 → 3.18.1-beta.5b53256

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,64 +1,64 @@
1
- import { defineComponent as A, ref as c, computed as b, toRef as h, nextTick as C } from "vue";
2
- import N from "../../wrappers/WpDrawer.vue.js";
3
- import { useTranslations as O } from "../../../composables/useTranslations.js";
1
+ import { defineComponent as _, ref as c, computed as h, watch as C, toRef as N, nextTick as O } from "vue";
2
+ import b from "../../wrappers/WpDrawer.vue.js";
3
+ import { useTranslations as D } from "../../../composables/useTranslations.js";
4
4
  import { useTemplateNameValidator as x } from "../../../composables/validators/saveAsTemplate.js";
5
5
  import { useTemplateLibraryApi as B } from "../../../services/templateLibraryApi.js";
6
- import { useEditorStore as D } from "../../../stores/editor.js";
7
- import { useSaveAsTemplateStore as k } from "../../../stores/save-as-template.js";
8
- import { InMultiSelect as I, InBasicTextInput as M } from "@useinsider/design-system-vue";
9
- import { useDebounceFn as V } from "../../../node_modules/@vueuse/shared/index.js";
10
- const H = /* @__PURE__ */ A({
6
+ import { useEditorStore as k } from "../../../stores/editor.js";
7
+ import { useSaveAsTemplateStore as I } from "../../../stores/save-as-template.js";
8
+ import { InMultiSelect as M, InBasicTextInput as V } from "@useinsider/design-system-vue";
9
+ import { useDebounceFn as E } from "../../../node_modules/@vueuse/shared/index.js";
10
+ const J = /* @__PURE__ */ _({
11
11
  __name: "SaveAsTemplateDrawer",
12
- setup(E) {
13
- const o = O(), n = D(), t = k(), { createTemplate: m } = B(), a = c(!1), r = c(!1), l = c(""), f = b(() => ({
12
+ setup(R) {
13
+ const s = D(), o = k(), t = I(), { createTemplate: m } = B(), a = c(!1), n = c(!1), r = c(""), f = h(() => ({
14
14
  primaryButton: {
15
15
  styling: "solid",
16
16
  type: "primary",
17
- labelText: o(a.value ? "newsletter.saving" : "products.save"),
17
+ labelText: s(a.value ? "newsletter.saving" : "products.save"),
18
18
  loadingStatus: a.value,
19
19
  disabledStatus: t.skeletonStatus
20
20
  },
21
21
  cancelOrBackButton: {
22
22
  styling: "ghost",
23
23
  type: "secondary",
24
- labelText: o("products.cancel"),
24
+ labelText: s("products.cancel"),
25
25
  disabledStatus: a.value
26
26
  }
27
- })), u = () => {
28
- l.value = "", n.isSaveAsTemplateDrawerOpen = !1;
29
- }, i = async () => {
30
- const e = h(t, "templateName"), { success: s, errorMessage: _ } = await x(e).validate();
31
- return l.value = _, s;
32
- }, v = V(async (e) => {
33
- t.templateName = e, await i();
34
- }, 500), g = async (e) => {
35
- r.value = !0, await t.addCategory(e), r.value = !1;
36
- }, y = (e) => {
27
+ })), p = () => {
28
+ r.value = "", o.isSaveAsTemplateDrawerOpen = !1;
29
+ }, l = async () => {
30
+ const e = N(t, "templateName"), { success: i, errorMessage: A } = await x(e).validate();
31
+ return r.value = A, i;
32
+ }, v = E(async (e) => {
33
+ t.templateName = e, await l();
34
+ }, 500), S = async (e) => {
35
+ n.value = !0, await t.addCategory(e), n.value = !1;
36
+ }, T = (e) => {
37
37
  t.selectedCategories = e;
38
- }, S = (e) => {
38
+ }, g = (e) => {
39
39
  e && (t.selectedCategories = e);
40
- }, T = () => {
40
+ }, y = () => {
41
41
  t.selectedCategories = [];
42
42
  }, w = async () => {
43
- if (a.value = !0, !await i()) {
43
+ if (a.value = !0, !await l()) {
44
44
  a.value = !1;
45
45
  return;
46
46
  }
47
- const s = await m();
48
- a.value = !1, s && u();
49
- }, p = () => {
50
- C(() => {
47
+ const i = await m();
48
+ a.value = !1, i && p();
49
+ }, u = () => {
50
+ O(() => {
51
51
  const e = document.querySelector("input#guido__template-name-input");
52
52
  e == null || e.focus();
53
53
  });
54
54
  }, d = async () => {
55
- t.$reset(), await t.fetchCategories(), t.skeletonStatus = !1, p();
55
+ t.$reset(), await t.fetchCategories(), t.skeletonStatus = !1, u();
56
56
  };
57
- return n.$subscribe((e, { isSaveAsTemplateDrawerOpen: s }) => {
58
- s && d();
59
- }), { __sfc: !0, trans: o, editorStore: n, saveAsTemplateStore: t, createTemplate: m, isSaving: a, isAddingOption: r, templateNameError: l, footerButtonGroupOptions: f, closeModal: u, validateTemplateName: i, handleTemplateName: v, handleAddOption: g, handleCategoryChange: y, handleSelectAllOptions: S, handleResetAllOptions: T, saveTemplate: w, focusToInput: p, initializeDrawer: d, WpDrawer: N, InBasicTextInput: M, InMultiSelect: I };
57
+ return C(() => o.isSaveAsTemplateDrawerOpen, (e) => {
58
+ e && d();
59
+ }), { __sfc: !0, trans: s, editorStore: o, saveAsTemplateStore: t, createTemplate: m, isSaving: a, isAddingOption: n, templateNameError: r, footerButtonGroupOptions: f, closeModal: p, validateTemplateName: l, handleTemplateName: v, handleAddOption: S, handleCategoryChange: T, handleSelectAllOptions: g, handleResetAllOptions: y, saveTemplate: w, focusToInput: u, initializeDrawer: d, WpDrawer: b, InBasicTextInput: V, InMultiSelect: M };
60
60
  }
61
61
  });
62
62
  export {
63
- H as default
63
+ J as default
64
64
  };
@@ -1,14 +1,16 @@
1
- import { getCsrfToken as H } from "../utils/genericUtil.js";
2
- import { ref as p, computed as T } from "vue";
3
- const k = (b = {}) => {
4
- const h = p(!1), a = p(null), u = p(null), g = T(() => h.value), y = T(() => a.value !== null), v = {
1
+ import { getCsrfToken as O } from "../utils/genericUtil.js";
2
+ import { ref as m, computed as T } from "vue";
3
+ const X = (b = {}) => {
4
+ const p = m(!1), a = m(null), u = m(null), g = T(() => p.value), y = T(() => a.value !== null), v = {
5
5
  baseURL: "",
6
6
  timeout: 1e4,
7
7
  retry: 0,
8
8
  retryDelay: 1e3,
9
9
  headers: {
10
10
  "Content-Type": "application/json",
11
- "X-CSRF-TOKEN": H()
11
+ "X-CSRF-TOKEN": O(),
12
+ Accept: "application/json",
13
+ "X-Requested-With": "XMLHttpRequest"
12
14
  },
13
15
  ...b
14
16
  }, w = (e, s) => {
@@ -22,22 +24,22 @@ const k = (b = {}) => {
22
24
  }, e);
23
25
  }), x = (e) => new Promise((s) => {
24
26
  setTimeout(s, e);
25
- }), i = async (e, s, t, D = {}) => {
26
- a.value = null, h.value = !0, u.value = new AbortController();
27
- const n = { ...v, ...D }, L = w(s, n.baseURL), c = {
27
+ }), i = async (e, s, t, L = {}) => {
28
+ a.value = null, p.value = !0, u.value = new AbortController();
29
+ const n = { ...v, ...L }, D = w(s, n.baseURL), c = {
28
30
  method: e,
29
31
  headers: { ...n.headers },
30
32
  signal: u.value.signal,
31
33
  ...n
32
34
  };
33
35
  t && ["POST", "PUT", "PATCH"].includes(e) && (t instanceof FormData ? (delete c.headers["Content-Type"], c.body = t) : c.body = JSON.stringify(t));
34
- const E = async (m = 0) => {
36
+ const E = async (h = 0) => {
35
37
  try {
36
- const o = [fetch(L, c)];
38
+ const o = [fetch(D, c)];
37
39
  n.timeout && o.push(P(n.timeout));
38
40
  const r = await Promise.race(o);
39
41
  if (!r.ok) {
40
- const O = `HTTP Error: ${r.status} ${r.statusText}`, d = new Error(O);
42
+ const H = `HTTP Error: ${r.status} ${r.statusText}`, d = new Error(H);
41
43
  throw d.status = r.status, d.statusText = r.statusText, d.response = r, d;
42
44
  }
43
45
  let f;
@@ -50,19 +52,19 @@ const k = (b = {}) => {
50
52
  };
51
53
  } catch (o) {
52
54
  const r = o instanceof Error && o.name === "AbortError";
53
- if (m < (n.retry || 0) && !r)
54
- return await x(n.retryDelay || 1e3), E(m + 1);
55
+ if (h < (n.retry || 0) && !r)
56
+ return await x(n.retryDelay || 1e3), E(h + 1);
55
57
  throw o instanceof Error ? o.name === "AbortError" ? a.value = { message: "Request was cancelled" } : a.value = { message: o.message } : a.value = o, o;
56
58
  }
57
59
  };
58
60
  try {
59
61
  return await E();
60
62
  } finally {
61
- h.value = !1, u.value = null;
63
+ p.value = !1, u.value = null;
62
64
  }
63
- }, C = (e, s) => i("GET", e, void 0, s), $ = (e, s, t) => i("POST", e, s, t), R = (e, s, t) => i("PUT", e, s, t), U = (e, s, t) => i("PATCH", e, s, t), A = (e, s) => i("DELETE", e, void 0, s), W = (e) => {
65
+ }, C = (e, s) => i("GET", e, void 0, s), R = (e, s, t) => i("POST", e, s, t), $ = (e, s, t) => i("PUT", e, s, t), q = (e, s, t) => i("PATCH", e, s, t), A = (e, s) => i("DELETE", e, void 0, s), U = (e) => {
64
66
  u.value && u.value.abort(e);
65
- }, q = () => {
67
+ }, W = () => {
66
68
  a.value = null;
67
69
  };
68
70
  return {
@@ -73,14 +75,14 @@ const k = (b = {}) => {
73
75
  // Methods
74
76
  request: i,
75
77
  get: C,
76
- post: $,
77
- put: R,
78
- patch: U,
78
+ post: R,
79
+ put: $,
80
+ patch: q,
79
81
  delete: A,
80
- cancel: W,
81
- clearError: q
82
+ cancel: U,
83
+ clearError: W
82
84
  };
83
85
  };
84
86
  export {
85
- k as useHttp
87
+ X as useHttp
86
88
  };
@@ -23,14 +23,14 @@ import { PricePlacementControl as E } from "./pricePlacement.js";
23
23
  import { PRICE_PLACEMENT_CONTROL_ID as _t } from "./pricePlacement.js";
24
24
  import { ProductCountControl as k } from "./productCount.js";
25
25
  import { PRODUCT_COUNT_CONTROL_ID as Rt } from "./productCount.js";
26
- import { ProductLayoutControl as F } from "./productLayout.js";
26
+ import { ProductLayoutControl as D } from "./productLayout.js";
27
27
  import { PRODUCT_LAYOUT_CONTROL_ID as Tt } from "./productLayout.js";
28
- import { ShuffleControl as D } from "./shuffle.js";
28
+ import { ShuffleControl as F } from "./shuffle.js";
29
29
  import { SHUFFLE_CONTROL_ID as St } from "./shuffle.js";
30
30
  import { StrategyControl as w } from "./strategy.js";
31
31
  import { STRATEGY_CONTROL_ID as Lt } from "./strategy.js";
32
32
  import { setCurrencyAttributes as A, getBlockElement as v, isPartnerManagedBlock as x, updateProductContentInPlace as B, regenerateProductRowsWithStyles as U } from "./utils.js";
33
- import { adjustProductsToSize as kt, formatProductPrice as Ft, getCardComposition as Dt, getCurrentLayout as wt, getMainContainerTbody as At, regenerateMobileProductRows as vt, updatePricesInPlace as xt, updateSingleProductContent as Bt } from "./utils.js";
33
+ import { adjustProductsToSize as kt, formatProductPrice as Dt, getCardComposition as Ft, getCurrentLayout as wt, getMainContainerTbody as At, regenerateMobileProductRows as vt, updatePricesInPlace as xt, updateSingleProductContent as Bt } from "./utils.js";
34
34
  import { useDebounceFn as f } from "../../../../../node_modules/@vueuse/shared/index.js";
35
35
  const $ = "ui-elements-recommendation-block";
36
36
  class at extends N {
@@ -39,6 +39,8 @@ class at extends N {
39
39
  n(this, "store", R());
40
40
  n(this, "storeUnsubscription", () => {
41
41
  });
42
+ // blockId -> fingerprint of the node config as it looked at the last sync.
43
+ n(this, "syncedConfigs", /* @__PURE__ */ new Map());
42
44
  // A config change waiting to reach the node config. Deferred so it can ride the
43
45
  // re-render's single apply() — one user action must cost one undo press.
44
46
  n(this, "pendingNodeConfigWrite", null);
@@ -118,7 +120,7 @@ class at extends N {
118
120
  return this.rrsEnabled = p().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((e) => {
119
121
  var o;
120
122
  return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
121
- }), this.algorithmControl = new T(), this.localeControl = new L(), this.currencyControl = new P(), this.productCountControl = new k(), this.productLayoutControl = new F(), this.filtersControl = new S(), this.shuffleControl = new D(), this.pricePlacementControl = new E(), this.layoutOrientationControl = new O(), this.strategyControl = this.rrsEnabled ? new w() : null, this._subControls.forEach((e) => {
123
+ }), this.algorithmControl = new T(), this.localeControl = new L(), this.currencyControl = new P(), this.productCountControl = new k(), this.productLayoutControl = new D(), this.filtersControl = new S(), this.shuffleControl = new F(), this.pricePlacementControl = new E(), this.layoutOrientationControl = new O(), this.strategyControl = this.rrsEnabled ? new w() : null, this._subControls.forEach((e) => {
122
124
  e && (e.api = this.api);
123
125
  }), `
124
126
  <div class="recommendation-controls-container">
@@ -198,19 +200,11 @@ class at extends N {
198
200
  * fingerprint diff on this hook is the only way to notice (SD-149105).
199
201
  * An unchanged fingerprint means the move came from us, so runtime store
200
202
  * edits are never clobbered (SD-141049).
201
- *
202
- * The fingerprint is kept on the block's own store state so deleting the
203
- * block drops it with the state it describes. A control-owned memo outlived
204
- * that state and made a re-dropped saved module keep the defaults its wiped
205
- * state was rebuilt with (SD-150347).
206
203
  */
207
204
  _syncNodeConfigIfChanged(t) {
208
205
  this.pendingNodeConfigWrite && this.pendingNodeConfigWrite.blockId !== t && this._flushPendingNodeConfig();
209
- const e = this.store.blockStates[t];
210
- if (!e)
211
- return;
212
- const o = JSON.stringify(c.getConfig(this.currentNode)), r = e.syncedConfigFingerprint;
213
- e.syncedConfigFingerprint = o, r !== o && (this.pendingNodeConfigWrite || this._syncNodeConfigToStore());
206
+ const e = JSON.stringify(c.getConfig(this.currentNode)), o = this.syncedConfigs.get(t);
207
+ this.syncedConfigs.set(t, e), o !== e && (this.pendingNodeConfigWrite || this._syncNodeConfigToStore());
214
208
  }
215
209
  _capturePendingNodeConfigWrite() {
216
210
  const t = this.store.currentRecommendationId;
@@ -436,16 +430,16 @@ export {
436
430
  Tt as PRODUCT_LAYOUT_CONTROL_ID,
437
431
  E as PricePlacementControl,
438
432
  k as ProductCountControl,
439
- F as ProductLayoutControl,
433
+ D as ProductLayoutControl,
440
434
  at as RecommendationBlockControl,
441
435
  St as SHUFFLE_CONTROL_ID,
442
436
  Lt as STRATEGY_CONTROL_ID,
443
- D as ShuffleControl,
437
+ F as ShuffleControl,
444
438
  w as StrategyControl,
445
439
  kt as adjustProductsToSize,
446
- Ft as formatProductPrice,
440
+ Dt as formatProductPrice,
447
441
  v as getBlockElement,
448
- Dt as getCardComposition,
442
+ Ft as getCardComposition,
449
443
  wt as getCurrentLayout,
450
444
  At as getMainContainerTbody,
451
445
  x as isPartnerManagedBlock,
@@ -1,7 +1,7 @@
1
1
  import { getRecommendationFeedSourceMaps as b, getOperatorOptions as G, PriceAttributes as v } from "../../../../enums/extensions/recommendationBlock.js";
2
2
  import { useRecommendationApi as D } from "../../../../services/recommendationApi.js";
3
- import { useConfigStore as F } from "../../../../stores/config.js";
4
- import { defineStore as P } from "pinia";
3
+ import { useConfigStore as P } from "../../../../stores/config.js";
4
+ import { defineStore as F } from "pinia";
5
5
  import "../constants/selectors.js";
6
6
  import { DEFAULT_MOBILE_CARDS_IN_ROW as _, DEFAULT_CARDS_IN_ROW as U } from "../constants/layout.js";
7
7
  import { DEFAULT_NODE_CONFIG as N, EXCLUDED_ALGORITHM_IDS as L } from "../constants/defaultConfig.js";
@@ -12,7 +12,7 @@ import { sanitizeProductIds as A } from "../utils/productIds.js";
12
12
  import { isFilterValid as B } from "../validation/filterSchema.js";
13
13
  import { isConfigValid as M } from "../validation/requiredFields.js";
14
14
  const u = D();
15
- let f = null, g = null, h = null, S = null;
15
+ let f = null, h = null, g = null, S = null;
16
16
  const p = /* @__PURE__ */ new Map();
17
17
  function w() {
18
18
  return {
@@ -56,8 +56,7 @@ function C() {
56
56
  removeStrategyModalStatus: !1,
57
57
  filterGroup: 1,
58
58
  isInitialized: !1,
59
- filterSnapshot: null,
60
- syncedConfigFingerprint: null
59
+ filterSnapshot: null
61
60
  };
62
61
  }
63
62
  const z = () => ({
@@ -72,7 +71,7 @@ const z = () => ({
72
71
  blockStates: {},
73
72
  currentRecommendationId: null,
74
73
  configVersion: 0
75
- }), Y = P("guidoRecommendationExtension", {
74
+ }), Y = F("guidoRecommendationExtension", {
76
75
  state: () => z(),
77
76
  getters: {
78
77
  // ====================================================================
@@ -242,7 +241,7 @@ const z = () => ({
242
241
  const r = (o, c) => o === "." || o === "," || o === " " ? o : c, n = {
243
242
  name: e.currencyCode,
244
243
  value: e.currencyCode,
245
- symbol: e.currencySymbol,
244
+ symbol: e.currencyCode,
246
245
  alignment: e.currencyAlignment === "before" ? "0" : "1",
247
246
  decimalCount: String(e.currencyDecimalCount),
248
247
  decimalSeparator: r(e.currencyDecimalSeparator, ","),
@@ -413,18 +412,18 @@ const z = () => ({
413
412
  },
414
413
  async fetchRecommendationFilters() {
415
414
  if (!Object.keys(this.filterList).length) {
416
- if (g) {
417
- await g;
415
+ if (h) {
416
+ await h;
418
417
  return;
419
418
  }
420
- g = (async () => {
419
+ h = (async () => {
421
420
  const t = await u.fetchRecommendationFilters();
422
421
  this.filterList = t;
423
422
  })();
424
423
  try {
425
- await g;
424
+ await h;
426
425
  } finally {
427
- g = null;
426
+ h = null;
428
427
  }
429
428
  }
430
429
  },
@@ -506,21 +505,21 @@ const z = () => ({
506
505
  // ====================================================================
507
506
  async fetchRecommendationProducts() {
508
507
  if (!(this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])) {
509
- if (h) {
510
- await h;
508
+ if (g) {
509
+ await g;
511
510
  return;
512
511
  }
513
- h = this._doFetchProducts();
512
+ g = this._doFetchProducts();
514
513
  try {
515
- await h;
514
+ await g;
516
515
  } finally {
517
- h = null;
516
+ g = null;
518
517
  }
519
518
  }
520
519
  },
521
520
  async _doFetchProducts() {
522
521
  var d;
523
- const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = F();
522
+ const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = P();
524
523
  if (r.strategyId && n.isFeatureEnabled("reusableRecommendationStrategy")) {
525
524
  await this._doFetchStrategyProducts(t);
526
525
  return;
@@ -4,13 +4,14 @@ import { useToaster as C } from "../composables/useToaster.js";
4
4
  import { useTranslations as h } from "../composables/useTranslations.js";
5
5
  import { useLiquidValidator as S } from "../composables/validators/useLiquidValidator.js";
6
6
  import { EditorType as v } from "../enums/defaults.js";
7
- import { ToasterTypeOptions as N } from "../enums/toaster.js";
8
- import { useRecommendationExtensionStore as x } from "../extensions/Blocks/Recommendation/store/recommendation.js";
9
- import { useSaveAsTemplateStore as E } from "../stores/save-as-template.js";
7
+ import { ToasterTypeOptions as x } from "../enums/toaster.js";
8
+ import { useRecommendationExtensionStore as E } from "../extensions/Blocks/Recommendation/store/recommendation.js";
9
+ import { useSaveAsTemplateStore as N } from "../stores/save-as-template.js";
10
10
  import { base64EncodeWithSpecialChars as r } from "../utils/base64.js";
11
+ import { isPlainObject as P } from "../utils/genericUtil.js";
11
12
  import { useTemplatePreparation as A } from "../utils/templatePreparation.js";
12
- const j = () => {
13
- const { get: n, post: m } = b(), { handleError: o, showToaster: l } = C(), { config: c, isFeatureEnabled: p } = w(), { validateLiquidSyntax: g } = S(), u = h();
13
+ const B = () => {
14
+ const { get: n, post: m } = b(), { handleError: o, showToaster: l } = C(), { config: c, isFeatureEnabled: p } = w(), { validateLiquidSyntax: f } = S(), u = h();
14
15
  return {
15
16
  getCategories: async () => {
16
17
  try {
@@ -40,10 +41,10 @@ const j = () => {
40
41
  createTemplate: async () => {
41
42
  var e, t, d, y;
42
43
  try {
43
- const { prepareTemplateDetails: i } = A(), s = E(), a = await i();
44
- if (p("liquidSyntax") && !await g(a.compiledHtml))
44
+ const { prepareTemplateDetails: i } = A(), s = N(), a = await i();
45
+ if (p("liquidSyntax") && !await f(a.compiledHtml))
45
46
  return !1;
46
- const f = {
47
+ const T = {
47
48
  name: s.getTemplateName,
48
49
  categories: s.getSelectedCategoryIds,
49
50
  productId: ((t = (e = c.value) == null ? void 0 : e.partner) == null ? void 0 : t.productType) || 0,
@@ -54,7 +55,7 @@ const j = () => {
54
55
  unsubscriptionPreferencePageStatus: !1,
55
56
  unsubscriptionPreferencePages: [],
56
57
  recommendationCampaignUrls: r(
57
- x().recommendationCampaignUrls
58
+ E().recommendationCampaignUrls
58
59
  ),
59
60
  recommendationConfigs: r({}),
60
61
  isGuido: !0,
@@ -66,16 +67,18 @@ const j = () => {
66
67
  css: a.css,
67
68
  dynamicContentList: a.dynamicContentList
68
69
  })
69
- }, { data: { type: T } } = await m(
70
+ }, { data: g } = await m(
70
71
  "/newsletter/template-library/create-template",
71
- f
72
+ T
72
73
  );
73
- return T === "alert" ? (l({
74
+ if (!P(g))
75
+ throw new Error("Unexpected create-template response");
76
+ return g.type === "alert" ? (l({
74
77
  message: u(
75
78
  "newsletter.template-library-save-alert",
76
79
  { templateName: s.getTemplateName }
77
80
  ),
78
- type: N.Error
81
+ type: x.Error
79
82
  }), !1) : (l({
80
83
  message: u(
81
84
  "newsletter.template-library-save-success",
@@ -90,5 +93,5 @@ const j = () => {
90
93
  };
91
94
  };
92
95
  export {
93
- j as useTemplateLibraryApi
96
+ B as useTemplateLibraryApi
94
97
  };
@@ -20,6 +20,7 @@ export * from './utils';
20
20
  export declare class RecommendationBlockControl extends CommonControl {
21
21
  private store;
22
22
  private storeUnsubscription;
23
+ private syncedConfigs;
23
24
  private pendingNodeConfigWrite;
24
25
  private pendingConfigFlushTimer;
25
26
  private algorithmControl;
@@ -63,11 +64,6 @@ export declare class RecommendationBlockControl extends CommonControl {
63
64
  * fingerprint diff on this hook is the only way to notice (SD-149105).
64
65
  * An unchanged fingerprint means the move came from us, so runtime store
65
66
  * edits are never clobbered (SD-141049).
66
- *
67
- * The fingerprint is kept on the block's own store state so deleting the
68
- * block drops it with the state it describes. A control-owned memo outlived
69
- * that state and made a re-dropped saved module keep the defaults its wiped
70
- * state was rebuilt with (SD-150347).
71
67
  */
72
68
  private _syncNodeConfigIfChanged;
73
69
  private _capturePendingNodeConfigWrite;
@@ -41,16 +41,6 @@ interface PerBlockState {
41
41
  isInitialized: boolean;
42
42
  /** Snapshot of filters taken when the drawer opens, used to revert on cancel */
43
43
  filterSnapshot: Filter[] | null;
44
- /**
45
- * Fingerprint of the node config as this block's state last adopted it.
46
- *
47
- * Lives here, not on the control, because it is a claim ABOUT this state —
48
- * "the store already holds that node config". Held on the control it
49
- * outlived the state it described: `removeBlockState` tore the state down
50
- * while the fingerprint survived, so re-dropping a saved module under the
51
- * same id skipped the re-sync and kept the defaults (SD-150347).
52
- */
53
- syncedConfigFingerprint: string | null;
54
44
  }
55
45
  /**
56
46
  * Persisted-config subset used by `seedBlockUrlConfig` to reconstruct
@@ -67,8 +57,6 @@ export interface PerBlockUrlConfig {
67
57
  filters: Filter[];
68
58
  shuffleProducts: boolean;
69
59
  currencyCode: string;
70
- /** The displayed symbol, which is not the code — a TRY block shows `₺`. */
71
- currencySymbol: string;
72
60
  currencyAlignment: 'before' | 'after';
73
61
  currencyDecimalCount: number;
74
62
  currencyDecimalSeparator: string;
@@ -30,3 +30,9 @@ export declare const replaceString: (string?: string, values?: Record<string, st
30
30
  * a string nor a number becomes ''.
31
31
  */
32
32
  export declare const asText: (value: unknown) => string;
33
+ /**
34
+ * Narrows an unknown API value to a plain JSON object. Arrays and exotic
35
+ * objects (Blob, Date, FormData) are rejected, so a response body that useHttp
36
+ * parsed as text or blob can never be read as a JSON payload.
37
+ */
38
+ export declare const isPlainObject: <T>(value: T) => value is T & Record<string, unknown>;
@@ -1,69 +1,75 @@
1
- const o = (t) => {
2
- const a = t.value.match(/\{\{([^}]+)\}\}/)[1].split("|").map((l) => l.trim()), [s] = a, r = {
3
- text: t.label,
1
+ const o = (a) => {
2
+ const t = a.value.match(/\{\{([^}]+)\}\}/)[1].split("|").map((e) => e.trim()), [s] = t, r = {
3
+ text: a.label,
4
4
  value: s || ""
5
5
  };
6
- if (a.length >= 2) {
7
- const [, l, e] = a;
8
- if (l.startsWith("default:")) {
9
- let n = l.slice(8).trim();
6
+ if (t.length >= 2) {
7
+ const [, e, l] = t;
8
+ if (e.startsWith("default:")) {
9
+ let n = e.slice(8).trim();
10
10
  n.startsWith('"') && n.endsWith('"') && (n = n.slice(1, -1)), r.fallback = n;
11
11
  } else {
12
- const n = l.includes("=") ? { key: l.split("=")[0].trim(), value: l.split("=")[1].trim() } : null;
13
- n ? r.format = n : e || (r.fallback = l), e && (r.fallback = e);
12
+ const n = e.includes("=") ? { key: e.split("=")[0].trim(), value: e.split("=")[1].trim() } : null;
13
+ n ? r.format = n : l || (r.fallback = e), l && (r.fallback = l);
14
14
  }
15
15
  }
16
16
  return r;
17
- }, f = (t, c = !1) => t.map((a) => {
18
- if (a.format)
17
+ }, u = (a, c = !1) => a.map((t) => {
18
+ if (t.format)
19
19
  return {
20
- label: `${a.text} | ${a.format.key}=${a.format.value}`,
21
- value: `{{${a.value}|${a.format.key}=${a.format.value}}}`
20
+ label: `${t.text} | ${t.format.key}=${t.format.value}`,
21
+ value: `{{${t.value}|${t.format.key}=${t.format.value}}}`
22
22
  };
23
23
  if (c) {
24
- if (!a.fallback)
24
+ if (!t.fallback)
25
25
  return {
26
- label: a.text,
27
- value: `{{ ${a.value} }}`
26
+ label: t.text,
27
+ value: `{{ ${t.value} }}`
28
28
  };
29
- const r = !Number.isNaN(Number(a.fallback)) && a.fallback.trim() !== "" ? a.fallback : `"${a.fallback}"`;
29
+ const r = !Number.isNaN(Number(t.fallback)) && t.fallback.trim() !== "" ? t.fallback : `"${t.fallback}"`;
30
30
  return {
31
- label: `${a.text} | ${a.fallback}`,
32
- value: `{{ ${a.value} | default: ${r} }}`
31
+ label: `${t.text} | ${t.fallback}`,
32
+ value: `{{ ${t.value} | default: ${r} }}`
33
33
  };
34
34
  }
35
35
  return {
36
- label: a.fallback ? `${a.text} | ${a.fallback}` : a.text,
37
- value: a.fallback ? `{{${a.value}|${a.fallback}}}` : `{{${a.value}}}`
36
+ label: t.fallback ? `${t.text} | ${t.fallback}` : t.text,
37
+ value: t.fallback ? `{{${t.value}|${t.fallback}}}` : `{{${t.value}}}`
38
38
  };
39
- }), b = (t) => {
40
- const c = [], a = /* @__PURE__ */ new Set(), s = (l) => {
41
- Array.isArray(l) && l.forEach((e) => {
42
- const n = [...e.children ?? [], ...e.select_items ?? []];
39
+ }), b = (a) => {
40
+ const c = [], t = /* @__PURE__ */ new Set(), s = (e) => {
41
+ Array.isArray(e) && e.forEach((l) => {
42
+ const n = [...l.children ?? [], ...l.select_items ?? []];
43
43
  if (n.length > 0) {
44
44
  s(n);
45
45
  return;
46
46
  }
47
- const u = e.text || e.tag_text;
48
- u && e.value && !a.has(e.value) && (a.add(e.value), c.push({ text: u, value: e.value }));
47
+ const f = l.text || l.tag_text;
48
+ f && l.value && !t.has(l.value) && (t.add(l.value), c.push({ text: f, value: l.value }));
49
49
  });
50
- }, [r] = Object.values(t ?? {});
50
+ }, [r] = Object.values(a ?? {});
51
51
  return s(r), c;
52
- }, i = (t, c, a = !1) => {
53
- const s = new Set(t.map((l) => l.value)), r = c.filter((l) => s.has(l.value) ? !1 : (s.add(l.value), !0));
52
+ }, i = (a, c, t = !1) => {
53
+ const s = new Set(a.map((e) => e.value)), r = c.filter((e) => s.has(e.value) ? !1 : (s.add(e.value), !0));
54
54
  return [
55
- ...f(t, a),
56
- ...f(r, a)
55
+ ...u(a, t),
56
+ ...u(r, t)
57
57
  ];
58
- }, v = () => {
59
- var t;
60
- return ((t = document.head.querySelector('meta[name="csrf-token"]')) == null ? void 0 : t.getAttribute("content")) ?? "";
61
- }, k = (t) => typeof t == "string" ? t : typeof t == "number" ? String(t) : "";
58
+ }, k = () => {
59
+ var a;
60
+ return ((a = document.head.querySelector('meta[name="csrf-token"]')) == null ? void 0 : a.getAttribute("content")) ?? "";
61
+ }, v = (a) => typeof a == "string" ? a : typeof a == "number" ? String(a) : "", y = (a) => {
62
+ if (a === null || typeof a != "object" || Array.isArray(a))
63
+ return !1;
64
+ const c = Object.getPrototypeOf(a);
65
+ return c === Object.prototype || c === null;
66
+ };
62
67
  export {
63
- k as asText,
68
+ v as asText,
64
69
  i as buildMergeTagEntries,
65
- f as dynamicContentToMergeTags,
70
+ u as dynamicContentToMergeTags,
66
71
  b as flattenDynamicContentList,
67
- v as getCsrfToken,
72
+ k as getCsrfToken,
73
+ y as isPlainObject,
68
74
  o as mergeTagToDynamicContent
69
75
  };
@@ -1,30 +1,31 @@
1
1
  import { useActionsApi as k } from "../composables/useActionsApi.js";
2
2
  import { useConfig as U } from "../composables/useConfig.js";
3
3
  import { useHtmlCompiler as x } from "../composables/useHtmlCompiler.js";
4
- import { DEFAULT_CURRENCY as m, DEFAULT_NODE_CONFIG as a } from "../extensions/Blocks/Recommendation/constants/defaultConfig.js";
4
+ import { DEFAULT_CURRENCY as d, DEFAULT_NODE_CONFIG as a } from "../extensions/Blocks/Recommendation/constants/defaultConfig.js";
5
5
  import { useRecommendationExtensionStore as T } from "../extensions/Blocks/Recommendation/store/recommendation.js";
6
6
  import { mapLegacyStrategy as L } from "../extensions/Blocks/Recommendation/utils/legacyStrategyMap.js";
7
7
  import { DATA_ATTRIBUTES as C } from "../extensions/Blocks/Unsubscribe/utils/constants.js";
8
8
  import { parsePageList as R } from "../extensions/Blocks/Unsubscribe/utils/utils.js";
9
9
  import { useDynamicContentStore as N } from "../stores/dynamic-content.js";
10
10
  import { useEditorStore as z } from "../stores/editor.js";
11
- import { useUnsubscribeStore as _ } from "../stores/unsubscribe.js";
11
+ import { useUnsubscribeStore as O } from "../stores/unsubscribe.js";
12
+ import { isPlainObject as _ } from "./genericUtil.js";
12
13
  import { assignTrackingIds as v } from "./linkTrackingIds.js";
13
- function O(l) {
14
- const c = new DOMParser().parseFromString(l, "text/html").querySelectorAll(`[${C.PAGE_LIST}]`), t = [];
15
- return c.forEach((i) => {
16
- const o = i.getAttribute(C.PAGE_LIST);
14
+ function M(m) {
15
+ const i = new DOMParser().parseFromString(m, "text/html").querySelectorAll(`[${C.PAGE_LIST}]`), t = [];
16
+ return i.forEach((s) => {
17
+ const o = s.getAttribute(C.PAGE_LIST);
17
18
  o && t.push(...R(o));
18
19
  }), [...new Set(t)];
19
20
  }
20
- async function M(l) {
21
- const n = new DOMParser().parseFromString(l, "text/html").querySelectorAll(".recommendation-block-v2");
21
+ async function q(m) {
22
+ const n = new DOMParser().parseFromString(m, "text/html").querySelectorAll(".recommendation-block-v2");
22
23
  if (n.length === 0)
23
24
  return;
24
- const c = T();
25
+ const i = T();
25
26
  n.forEach((t) => {
26
- var r, d, g, f, s, y;
27
- const i = t.getAttribute("recommendation-id"), o = i ? Number(i) : NaN;
27
+ var r, l, g, f, c;
28
+ const s = t.getAttribute("recommendation-id"), o = s ? Number(s) : NaN;
28
29
  if (!Number.isFinite(o))
29
30
  return;
30
31
  const p = t.getAttribute("esd-ext-config");
@@ -36,9 +37,9 @@ async function M(l) {
36
37
  } catch {
37
38
  return;
38
39
  }
39
- if (!e || typeof e != "object" || Array.isArray(e))
40
+ if (!_(e))
40
41
  return;
41
- const b = {
42
+ const h = {
42
43
  // Normalize legacy strategy keys (e.g. `mostViewed` → `mostPopular`) so
43
44
  // already-saved blocks that never re-run the migrator don't emit a
44
45
  // strategy-less campaign URL. `||` also catches '' / undefined (SD-144882).
@@ -51,17 +52,16 @@ async function M(l) {
51
52
  productIds: e.productIds ?? [...a.productIds],
52
53
  filters: e.filters ?? [...a.filters],
53
54
  shuffleProducts: e.shuffleProducts ?? a.shuffleProducts,
54
- currencyCode: ((r = e.currency) == null ? void 0 : r.code) ?? m.code,
55
- currencySymbol: ((d = e.currency) == null ? void 0 : d.symbol) ?? m.symbol,
56
- currencyAlignment: ((g = e.currency) == null ? void 0 : g.alignment) ?? m.alignment,
57
- currencyDecimalCount: ((f = e.currency) == null ? void 0 : f.decimalCount) ?? m.decimalCount,
58
- currencyDecimalSeparator: ((s = e.currency) == null ? void 0 : s.decimalSeparator) ?? m.decimalSeparator,
59
- currencyThousandSeparator: ((y = e.currency) == null ? void 0 : y.thousandSeparator) ?? m.thousandSeparator
55
+ currencyCode: ((r = e.currency) == null ? void 0 : r.code) ?? d.code,
56
+ currencyAlignment: ((l = e.currency) == null ? void 0 : l.alignment) ?? d.alignment,
57
+ currencyDecimalCount: ((g = e.currency) == null ? void 0 : g.decimalCount) ?? d.decimalCount,
58
+ currencyDecimalSeparator: ((f = e.currency) == null ? void 0 : f.decimalSeparator) ?? d.decimalSeparator,
59
+ currencyThousandSeparator: ((c = e.currency) == null ? void 0 : c.thousandSeparator) ?? d.thousandSeparator
60
60
  };
61
- c.seedBlockUrlConfig(o, b);
61
+ i.seedBlockUrlConfig(o, h);
62
62
  });
63
63
  try {
64
- await c.fetchRecommendationCreateData();
64
+ await i.fetchRecommendationCreateData();
65
65
  } catch (t) {
66
66
  console.warn(
67
67
  "Recommendation reference data pre-load failed; validator will skip the availability check.",
@@ -69,24 +69,24 @@ async function M(l) {
69
69
  );
70
70
  }
71
71
  }
72
- const Z = () => {
73
- const l = N(), u = z(), n = _(), { getCompiledEmail: c, getTemplateData: t, updateHtmlAndCss: i } = k(), { compileHtml: o, compileAmpHtml: p } = x(), { isFeatureEnabled: e } = U();
72
+ const te = () => {
73
+ const m = N(), u = z(), n = O(), { getCompiledEmail: i, getTemplateData: t, updateHtmlAndCss: s } = k(), { compileHtml: o, compileAmpHtml: p } = x(), { isFeatureEnabled: e } = U();
74
74
  return {
75
75
  prepareTemplateDetails: async () => {
76
- let { html: r, css: d, syncModulesIds: g = [] } = await t();
76
+ let { html: r, css: l, syncModulesIds: g = [] } = await t();
77
77
  if (e("linkTrackingIds"))
78
78
  try {
79
- const { html: h, changed: F, nextSeq: H } = v(r, u.trackIdSessionFloor);
80
- u.trackIdSessionFloor = H, F && (r = h, await i(h, d));
81
- } catch (h) {
82
- console.error("Tracking-id step failed, saving anyway:", h);
79
+ const { html: y, changed: F, nextSeq: H } = v(r, u.trackIdSessionFloor);
80
+ u.trackIdSessionFloor = H, F && (r = y, await s(y, l));
81
+ } catch (y) {
82
+ console.error("Tracking-id step failed, saving anyway:", y);
83
83
  }
84
- const { html: f, ampHtml: s = "", ampErrors: y = [] } = await c({
84
+ const { html: f, ampHtml: c = "", ampErrors: A = [] } = await i({
85
85
  minimize: !0,
86
86
  resetDataSavedFlag: !1
87
87
  });
88
- n.selectedUnsubscribePages.length && await n.fetchTemplates(), await M(r);
89
- const { compiledHtml: I, stats: S, appliedRules: w } = o(f), D = s && p(s).compiledHtml, E = l.getSelectedDynamicContentList, P = T(), A = O(r);
88
+ n.selectedUnsubscribePages.length && await n.fetchTemplates(), await q(r);
89
+ const { compiledHtml: I, stats: S, appliedRules: w } = o(f), D = c && p(c).compiledHtml, P = m.getSelectedDynamicContentList, E = T(), b = M(r);
90
90
  return console.debug("HTML Compilation Stats:", {
91
91
  originalSize: S.originalSize,
92
92
  compiledSize: S.compiledSize,
@@ -94,26 +94,26 @@ const Z = () => {
94
94
  appliedRules: w,
95
95
  executionTime: `${S.executionTime.toFixed(2)}ms`
96
96
  }), {
97
- dynamicContentList: E,
97
+ dynamicContentList: P,
98
98
  compiledHtml: I,
99
99
  rawHtml: r,
100
- css: d,
100
+ css: l,
101
101
  ampHtml: D,
102
- ampErrors: y,
102
+ ampErrors: A,
103
103
  modules: g.map(Number),
104
104
  recommendation: {
105
- campaignUrls: P.recommendationCampaignUrls,
105
+ campaignUrls: E.recommendationCampaignUrls,
106
106
  configs: {}
107
107
  },
108
108
  unsubscribe: {
109
- status: A.length > 0,
110
- config: A
109
+ status: b.length > 0,
110
+ config: b
111
111
  }
112
112
  };
113
113
  }
114
114
  };
115
115
  };
116
116
  export {
117
- O as getHtmlReferencedUnsubscribePages,
118
- Z as useTemplatePreparation
117
+ M as getHtmlReferencedUnsubscribePages,
118
+ te as useTemplatePreparation
119
119
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.18.1-beta.4fbee43",
3
+ "version": "3.18.1-beta.5b53256",
4
4
  "description": "Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.",
5
5
  "main": "./dist/guido.umd.cjs",
6
6
  "module": "./dist/library.js",