@useinsider/guido 3.22.0 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +35 -4
  2. package/dist/components/Guido.vue.js +1 -1
  3. package/dist/components/Guido.vue2.js +118 -108
  4. package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue.js +11 -11
  5. package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue2.js +9 -9
  6. package/dist/composables/useEditorOpenMetrics.js +167 -0
  7. package/dist/composables/useStripo.js +93 -82
  8. package/dist/config/compiler/utils/recommendationCompilerUtils.js +22 -22
  9. package/dist/config/migrator/recommendation/compositionMapper.js +56 -49
  10. package/dist/config/migrator/recommendation/extractors.js +100 -40
  11. package/dist/config/migrator/recommendation/htmlBuilder.js +285 -207
  12. package/dist/config/migrator/recommendation/settingsMapper.js +37 -36
  13. package/dist/config/migrator/recommendation/themeMapper.js +53 -41
  14. package/dist/config/migrator/recommendationMigrator.js +68 -61
  15. package/dist/extensions/Blocks/Items/controls/button/link.js +14 -17
  16. package/dist/extensions/Blocks/Items/controls/cardComposition.js +14 -17
  17. package/dist/extensions/Blocks/Items/controls/image/link.js +14 -17
  18. package/dist/extensions/Blocks/Items/controls/name/trimming.js +9 -10
  19. package/dist/extensions/Blocks/Items/controls/price/currencyLocation.js +24 -25
  20. package/dist/extensions/Blocks/Items/controls/price/currencySymbol.js +12 -13
  21. package/dist/extensions/Blocks/Items/controls/price/formattedPrice.js +29 -30
  22. package/dist/extensions/Blocks/Items/controls/price/hideDiscount.js +15 -16
  23. package/dist/extensions/Blocks/Items/controls/price/priceOrientation.js +25 -26
  24. package/dist/extensions/Blocks/Items/controls/price/singlePrice.js +27 -28
  25. package/dist/extensions/Blocks/Items/controls/settingsControl.js +75 -80
  26. package/dist/extensions/Blocks/Recommendation/block.js +33 -24
  27. package/dist/extensions/Blocks/Recommendation/controls/cardBackground/index.js +3 -3
  28. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +27 -26
  29. package/dist/extensions/Blocks/Recommendation/controls/customAttribute/textTrim.js +13 -13
  30. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +165 -175
  31. package/dist/extensions/Blocks/Recommendation/controls/name/textTrim.js +5 -5
  32. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textAfter.js +8 -8
  33. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textBefore.js +15 -15
  34. package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/textAfter.js +12 -12
  35. package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/textBefore.js +10 -10
  36. package/dist/extensions/Blocks/Recommendation/controls/spacing/index.js +1 -1
  37. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +23 -22
  38. package/dist/extensions/Blocks/Recommendation/templates/list/template.js +19 -18
  39. package/dist/extensions/Blocks/Recommendation/templates/utils.js +82 -91
  40. package/dist/extensions/Blocks/Recommendation/utils/inlinePriceOrder.js +12 -0
  41. package/dist/extensions/Blocks/Recommendation/utils/legacyStrategyMap.js +3 -2
  42. package/dist/extensions/Blocks/common-control.js +62 -55
  43. package/dist/guido.css +1 -1
  44. package/dist/library.js +12 -10
  45. package/dist/package.json.js +6 -4
  46. package/dist/public/prefetchRuntime.js +4 -0
  47. package/dist/src/composables/useEditorOpenMetrics.d.ts +27 -0
  48. package/dist/src/composables/useStripo.d.ts +2 -1
  49. package/dist/src/config/migrator/recommendation/compositionMapper.d.ts +3 -1
  50. package/dist/src/config/migrator/recommendation/extractors.d.ts +35 -6
  51. package/dist/src/config/migrator/recommendation/htmlBuilder.d.ts +3 -1
  52. package/dist/src/config/migrator/recommendation/themeMapper.d.ts +3 -1
  53. package/dist/src/config/migrator/recommendation/types.d.ts +11 -1
  54. package/dist/src/extensions/Blocks/Items/controls/cardComposition.d.ts +0 -1
  55. package/dist/src/extensions/Blocks/Recommendation/block.d.ts +1 -0
  56. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +5 -10
  57. package/dist/src/extensions/Blocks/Recommendation/templates/utils.d.ts +1 -13
  58. package/dist/src/extensions/Blocks/Recommendation/utils/inlinePriceOrder.d.ts +9 -0
  59. package/dist/src/extensions/Blocks/Recommendation/utils/legacyStrategyMap.d.ts +2 -19
  60. package/dist/src/extensions/Blocks/common-control.d.ts +2 -0
  61. package/dist/src/library.d.ts +1 -0
  62. package/dist/src/public/prefetchRuntime.d.ts +1 -0
  63. package/dist/src/stores/unsubscribe.d.ts +10 -0
  64. package/dist/src/utils/runtimePrefetch.d.ts +4 -0
  65. package/dist/src/utils/stripoRuntime.d.ts +3 -0
  66. package/dist/static/stripo-runtime-manifest.json.js +9 -0
  67. package/dist/stores/unsubscribe.js +33 -29
  68. package/dist/utils/runtimePrefetch.js +26 -0
  69. package/dist/utils/stripoRuntime.js +13 -0
  70. package/package.json +7 -2
package/README.md CHANGED
@@ -582,9 +582,9 @@ import '@useinsider/guido/style';
582
582
 
583
583
  ### Subpath entries
584
584
 
585
- Two surfaces also ship as their own entry points. Importing one pulls in only its
586
- own dependencies, so a consumer that needs the store or the tracking-id helpers
587
- never loads the editor:
585
+ Three surfaces also ship as their own entry points. Importing one pulls in only its
586
+ own dependencies, so a consumer that needs the store, the tracking-id helpers or the
587
+ runtime prefetch never loads the editor:
588
588
 
589
589
  ```typescript
590
590
  // Live editor state, published by the editor into the host's shared Pinia instance.
@@ -595,11 +595,42 @@ import type { GuidoEmailEditorState } from '@useinsider/guido/editor-state';
595
595
  // Persistent link ids for the click heatmap.
596
596
  import { assignTrackingIds, TRACK_ID_ATTRIBUTE } from '@useinsider/guido/tracking-ids';
597
597
  import type { TrackingIdResult } from '@useinsider/guido/tracking-ids';
598
+
599
+ // Start downloading the Stripo editor runtime before the editor opens.
600
+ import { prefetchGuidoRuntime } from '@useinsider/guido/prefetch';
598
601
  ```
599
602
 
600
- Both are re-exported from the root barrel as well; the subpath is what keeps the
603
+ All three are re-exported from the root barrel as well; the subpath is what keeps the
601
604
  editor out of the consumer's module graph.
602
605
 
606
+ ### Runtime prefetch
607
+
608
+ ```typescript
609
+ import { prefetchGuidoRuntime } from '@useinsider/guido/prefetch';
610
+
611
+ prefetchGuidoRuntime(); // e.g. when the user lands on the page that opens the editor
612
+ ```
613
+
614
+ Call it as early as the host knows an editor is likely to open. It appends one
615
+ `<link rel="prefetch" data-guido-prefetch>` per file of the pinned Stripo runtime
616
+ (`src/static/stripo-runtime-manifest.json`) from
617
+ `https://email-static.useinsider.com/guido/<stripo version>/`, so the files are in the
618
+ HTTP cache when `<Guido>` mounts. It only downloads: no Stripo code runs and the
619
+ editor's startup order does not change.
620
+
621
+ - Returns `void` and never throws.
622
+ - Idempotent: later calls add nothing.
623
+ - Adds nothing when the runtime is already loading or loaded (`#UiEditorScript` exists
624
+ or `window.UIEditor` is defined), when the browser does not support `rel="prefetch"`
625
+ (Safari by default), when `navigator.connection.saveData` is on, or when
626
+ `navigator.connection.effectiveType` is `slow-2g` or `2g`.
627
+ - The `guido_editor_open` metric reports it as `runtime_prefetch`: `none` (not called
628
+ before Guido's setup), `pending` (some files still downloading) or `done`.
629
+
630
+ After bumping `guido.stripo.version`, regenerate the file list with
631
+ `npm run stripo:manifest`; a unit test fails while the manifest's version differs from
632
+ the pinned one.
633
+
603
634
  ---
604
635
 
605
636
  ## Constants
@@ -12,7 +12,7 @@ var t = function() {
12
12
  s,
13
13
  !1,
14
14
  null,
15
- "c5146fc5"
15
+ "f2154cb6"
16
16
  );
17
17
  const v = n.exports;
18
18
  export {
@@ -1,179 +1,189 @@
1
- import { defineComponent as ie, defineAsyncComponent as m, ref as W, computed as p, watch as G, onMounted as ce, onUnmounted as de } from "vue";
2
- import { useCortexBlueprintBridge as me } from "../composables/useCortexBlueprintBridge.js";
3
- import { useEditorLock as le } from "../composables/useEditorLock.js";
4
- import { provideGuidoActions as ue } from "../composables/useGuidoActions.js";
5
- import { useGuidoStateBridge as pe } from "../composables/useGuidoStateBridge.js";
6
- import { usePartner as fe } from "../composables/usePartner.js";
7
- import { useSaveValidationRollout as ye } from "../composables/useSaveValidationRollout.js";
8
- import { useStripo as ge } from "../composables/useStripo.js";
9
- import { useTimerClone as Se } from "../composables/useTimerClone.js";
10
- import { migrate as V } from "../config/migrator/index.js";
11
- import { ModuleFolderDefaults as $ } from "../enums/defaults.js";
12
- import { RIBBON_SELECTOR as ve } from "../enums/onboarding.js";
13
- import { useRecommendationExtensionStore as z, disposeStrategyPageReturnListeners as be } from "../extensions/Blocks/Recommendation/store/recommendation.js";
14
- import { disposeUnsubscribeListeners as he } from "../extensions/Blocks/Unsubscribe/block.js";
15
- import Ee from "./organisms/AutoSaveController.vue.js";
16
- import we from "./organisms/base/AuthErrorModal.vue.js";
17
- import De from "./organisms/base/Toaster.vue.js";
18
- import Ce from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
19
- import ke from "./organisms/header/HeaderWrapper.vue.js";
20
- import Re from "./organisms/LoadingWrapper.vue.js";
21
- import Fe from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
22
- import Le from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
23
- import Me from "./organisms/validation/ValidationErrorDrawer.vue.js";
24
- import { useStripoApi as Te } from "../services/stripoApi.js";
25
- import { useConfigStore as Ie } from "../stores/config.js";
26
- import { useDynamicContentStore as Ue } from "../stores/dynamic-content.js";
27
- import { useEditorStore as E } from "../stores/editor.js";
28
- import { usePreviewStore as Ae } from "../stores/preview.js";
29
- import { useSaveValidationStore as Be } from "../stores/save-validation.js";
30
- import { useTemplateStore as Ne } from "../stores/template.js";
31
- import { useUnsubscribeStore as Pe } from "../stores/unsubscribe.js";
32
- import { readTrackFloor as H } from "../utils/linkTrackingIds.js";
33
- const yt = /* @__PURE__ */ ie({
1
+ import { defineComponent as de, defineAsyncComponent as l, ref as W, computed as f, watch as G, onMounted as me, onUnmounted as le } from "vue";
2
+ import { useCortexBlueprintBridge as ue } from "../composables/useCortexBlueprintBridge.js";
3
+ import { useEditorLock as pe } from "../composables/useEditorLock.js";
4
+ import { startEditorOpenMetrics as fe } from "../composables/useEditorOpenMetrics.js";
5
+ import { provideGuidoActions as ye } from "../composables/useGuidoActions.js";
6
+ import { useGuidoStateBridge as ge } from "../composables/useGuidoStateBridge.js";
7
+ import { usePartner as ve } from "../composables/usePartner.js";
8
+ import { useSaveValidationRollout as Se } from "../composables/useSaveValidationRollout.js";
9
+ import { useStripo as be } from "../composables/useStripo.js";
10
+ import { useTimerClone as he } from "../composables/useTimerClone.js";
11
+ import { migrate as Ee } from "../config/migrator/index.js";
12
+ import { ModuleFolderDefaults as H } from "../enums/defaults.js";
13
+ import { RIBBON_SELECTOR as we } from "../enums/onboarding.js";
14
+ import { useRecommendationExtensionStore as V, disposeStrategyPageReturnListeners as ke } from "../extensions/Blocks/Recommendation/store/recommendation.js";
15
+ import { disposeUnsubscribeListeners as Ce } from "../extensions/Blocks/Unsubscribe/block.js";
16
+ import De from "./organisms/AutoSaveController.vue.js";
17
+ import Ie from "./organisms/base/AuthErrorModal.vue.js";
18
+ import Fe from "./organisms/base/Toaster.vue.js";
19
+ import Me from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
20
+ import Re from "./organisms/header/HeaderWrapper.vue.js";
21
+ import Te from "./organisms/LoadingWrapper.vue.js";
22
+ import Le from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
23
+ import Ue from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
24
+ import Ne from "./organisms/validation/ValidationErrorDrawer.vue.js";
25
+ import { useStripoApi as _e } from "../services/stripoApi.js";
26
+ import { useConfigStore as Ae } from "../stores/config.js";
27
+ import { useDynamicContentStore as Be } from "../stores/dynamic-content.js";
28
+ import { useEditorStore as w } from "../stores/editor.js";
29
+ import { usePreviewStore as Oe } from "../stores/preview.js";
30
+ import { useSaveValidationStore as Pe } from "../stores/save-validation.js";
31
+ import { useTemplateStore as xe } from "../stores/template.js";
32
+ import { useUnsubscribeStore as We } from "../stores/unsubscribe.js";
33
+ import { readTrackFloor as $ } from "../utils/linkTrackingIds.js";
34
+ const ht = /* @__PURE__ */ de({
34
35
  __name: "Guido",
35
36
  props: {
36
37
  config: null,
37
38
  ready: { type: Boolean, default: !0 }
38
39
  },
39
40
  emits: ["dynamic-content:open", "back", "save:start", "save:complete", "on-change", "ready", "onboarding:finished", "test-email:click"],
40
- setup(q, { expose: K, emit: r }) {
41
- const s = q, j = m(
41
+ setup(z, { expose: q, emit: a }) {
42
+ const s = z, n = fe(), K = l(
42
43
  () => import("./organisms/email-preview/PreviewContainer.vue.js")
43
- ), J = m(
44
+ ), j = l(
44
45
  () => import("./organisms/onboarding/OnboardingWrapper.vue.js")
45
- ), Q = m(
46
+ ), J = l(
46
47
  () => import("./organisms/extensions/recommendation/AssignStrategyDrawer.vue.js")
47
- ), X = m(
48
+ ), Q = l(
48
49
  () => import("./organisms/extensions/recommendation/RemoveStrategyModal.vue.js")
49
- ), Y = m(
50
+ ), X = l(
50
51
  () => import("./organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js")
51
- ), w = W(), f = W(), y = Ue(), D = Pe(), o = Ie();
52
+ ), k = W(), y = W(), g = Be(), C = We(), o = Ae();
52
53
  s.ready && o.init(s.config);
53
- const c = E(), Z = Ae(), l = p(() => c.hasChanges), { isTestPartner: ee } = fe(), { isEnabled: te, loadRollout: C } = ye(), k = () => {
54
+ const d = w(), Y = Oe(), u = f(() => d.hasChanges), { isTestPartner: Z } = ve(), { isEnabled: ee, loadRollout: D } = Se(), I = () => {
54
55
  var t;
55
- return (t = w.value) == null ? void 0 : t.handleSave(!0);
56
- }, R = (t) => {
57
- c.loadingStatus = t;
56
+ return (t = k.value) == null ? void 0 : t.handleSave(!0);
57
+ }, F = (t) => {
58
+ d.loadingStatus = t;
58
59
  };
59
- me(), pe();
60
- const g = () => {
60
+ ue(), ge();
61
+ const v = () => {
61
62
  var t, e;
62
63
  return {
63
64
  emailId: o.templateId,
64
65
  userId: o.userId,
65
66
  username: o.username,
66
67
  partnerName: o.partnerName,
67
- savedModulesFolderName: ((t = o.editor) == null ? void 0 : t.savedModulesFolderName) || $.SAVED_MODULES,
68
- defaultModulesFolderName: ((e = o.editor) == null ? void 0 : e.defaultModulesFolderName) || $.DEFAULT_MODULES
68
+ savedModulesFolderName: ((t = o.editor) == null ? void 0 : t.savedModulesFolderName) || H.SAVED_MODULES,
69
+ defaultModulesFolderName: ((e = o.editor) == null ? void 0 : e.defaultModulesFolderName) || H.DEFAULT_MODULES
69
70
  };
70
- }, { initPlugin: F, preloadRuntime: L } = ge(), { runExclusive: M, beginMount: T, isCurrentMount: S } = le();
71
- let u = 0;
72
- const { getDefaultTemplate: I } = Te(), { cloneTimersOnSave: U, hasTimerBlocks: A } = Se(), oe = p(() => {
71
+ }, { initPlugin: M, preloadRuntime: R } = be(n), { runExclusive: T, beginMount: L, isCurrentMount: S } = pe();
72
+ let p = 0;
73
+ const { getDefaultTemplate: U } = _e(), { cloneTimersOnSave: N, hasTimerBlocks: _ } = he(), te = f(() => {
73
74
  var t;
74
75
  return !((t = o.ui) != null && t.showHeader);
75
- }), ne = p(() => o.isFeatureEnabled("reusableRecommendationStrategy")), re = p(
76
- () => !!z().recommendationConfigs.strategyId
76
+ }), oe = f(() => o.isFeatureEnabled("reusableRecommendationStrategy")), re = f(
77
+ () => !!V().recommendationConfigs.strategyId
77
78
  );
78
- ue({
79
+ ye({
79
80
  onBack: () => {
80
- console.debug("guido:back"), r("back");
81
+ console.debug("guido:back"), a("back");
81
82
  },
82
83
  onSaveStart: () => {
83
- console.debug("guido:save:start"), r("save:start");
84
+ console.debug("guido:save:start"), a("save:start");
84
85
  },
85
86
  onSaveComplete: (t) => {
86
- const e = { ...t, metadata: g() };
87
- console.debug("guido:save:complete", e), r("save:complete", e);
87
+ const e = { ...t, metadata: v() };
88
+ console.debug("guido:save:complete", e), a("save:complete", e);
88
89
  },
89
90
  onTestEmailClick: () => {
90
- console.debug("guido:test-email:click"), r("test-email:click");
91
+ console.debug("guido:test-email:click"), a("test-email:click");
91
92
  }
92
93
  });
93
- const B = (t) => {
94
- console.debug("dynamic-content:close", t), y.setSelectedDynamicContent(t), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: t }));
95
- }, N = () => {
94
+ const A = (t) => {
95
+ console.debug("dynamic-content:close", t), g.setSelectedDynamicContent(t), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: t }));
96
+ }, B = () => {
96
97
  console.debug("dynamic-content:close", "Without Data"), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: { text: "", value: "" } }));
97
98
  };
98
- G(() => l.value, () => {
99
- r("on-change", l.value);
99
+ G(() => u.value, () => {
100
+ a("on-change", u.value);
100
101
  });
101
- const v = (t) => {
102
- const e = t, { attribute: a, position: d } = e.detail;
103
- console.debug("dynamic-content:open", e.detail), r("dynamic-content:open", a, d);
102
+ const b = (t) => {
103
+ const e = t, { attribute: i, position: m } = e.detail;
104
+ console.debug("dynamic-content:open", e.detail), a("dynamic-content:open", i, m);
104
105
  };
105
- let i = null;
106
- const b = () => {
106
+ let c = null;
107
+ const h = () => {
107
108
  var e;
108
- const t = document.querySelector(ve);
109
- (e = f.value) == null || e.style.setProperty("--ribbon-offset", `${(t == null ? void 0 : t.offsetHeight) ?? 0}px`);
110
- }, h = async () => {
109
+ const t = document.querySelector(we);
110
+ (e = y.value) == null || e.style.setProperty("--ribbon-offset", `${(t == null ? void 0 : t.offsetHeight) ?? 0}px`);
111
+ }, E = async () => {
111
112
  var t;
113
+ n.mark("host_ready");
112
114
  try {
113
- o.initialized || o.init(s.config), c.templateId = o.templateId;
114
- const e = o.template, a = (e == null ? void 0 : e.html) || "", d = (e == null ? void 0 : e.css) || "", P = (e == null ? void 0 : e.preselectedDynamicContent) || [];
115
- D.selectedUnsubscribePages = (e == null ? void 0 : e.selectedUnsubscribePages) || [];
116
- const _ = ((t = e == null ? void 0 : e.migration) == null ? void 0 : t.recommendationConfigs) ?? {}, O = o.isFeatureEnabled("linkTrackingIds"), x = {
115
+ o.initialized || o.init(s.config), d.templateId = o.templateId, n.setContext({
116
+ partnerName: o.partnerName,
117
+ productType: o.productType,
118
+ templateId: o.templateId,
119
+ variationId: o.variationId
120
+ });
121
+ const e = o.template, i = (e == null ? void 0 : e.html) || "", m = (e == null ? void 0 : e.css) || "", O = (e == null ? void 0 : e.preselectedDynamicContent) || [];
122
+ C.selectedUnsubscribePages = (e == null ? void 0 : e.selectedUnsubscribePages) || [];
123
+ const ne = ((t = e == null ? void 0 : e.migration) == null ? void 0 : t.recommendationConfigs) ?? {}, P = o.isFeatureEnabled("linkTrackingIds"), ae = {
117
124
  partnerName: o.partnerName,
118
125
  campaignUrls: e == null ? void 0 : e.recommendationCampaignUrls,
119
126
  rrsEnabled: o.isFeatureEnabled("reusableRecommendationStrategy")
127
+ }, x = (ce) => n.timed(
128
+ "migration",
129
+ () => Ee(ce, ne, ae)
130
+ );
131
+ let r = {
132
+ html: i && await x(i),
133
+ css: m
120
134
  };
121
- let n = {
122
- html: a && await V(a, _, x),
123
- css: d
124
- };
125
- n.html || (n = await I(), n.html = await V(n.html, _, x));
126
- const ae = O ? H(n.html, (e == null ? void 0 : e.trackIdCounter) || 0) : 0;
127
- A(n.html) && (n.html = await U(n.html)), O && (c.trackIdSessionFloor = Math.max(ae, H(n.html)));
135
+ r.html || (r = await n.timed("default_template", () => U()), r.html = await x(r.html));
136
+ const ie = P ? $(r.html, (e == null ? void 0 : e.trackIdCounter) || 0) : 0;
137
+ _(r.html) && (r.html = await n.timed("timer_clone", () => N(r.html))), P && (d.trackIdSessionFloor = Math.max(ie, $(r.html)));
128
138
  const se = {
129
- preselectedDynamicContentList: P,
139
+ preselectedDynamicContentList: O,
130
140
  onReady: () => {
131
- console.debug("guido:ready"), r("ready");
141
+ console.debug("guido:ready"), a("ready");
132
142
  }
133
143
  };
134
- u = T(), await F(n, g(), se), y.selectedDynamicContentList = P;
144
+ p = L(), await M(r, v(), se), g.selectedDynamicContentList = O;
135
145
  } catch (e) {
136
- console.error("Failed to initialize Stripo editor:", e);
146
+ console.error("Failed to initialize Stripo editor:", e), n.markFailed();
137
147
  }
138
148
  };
139
- return ce(async () => {
149
+ return me(async () => {
140
150
  var e;
141
- console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), z().$reset(), E().$reset(), Ne().$reset(), Be().$reset(), C(), b();
142
- const t = (e = f.value) == null ? void 0 : e.parentElement;
143
- if (t && (i = new ResizeObserver(b), i.observe(t)), L(), s.ready)
144
- await h();
151
+ console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), V().$reset(), w().$reset(), xe().$reset(), Pe().$reset(), D(), h();
152
+ const t = (e = y.value) == null ? void 0 : e.parentElement;
153
+ if (t && (c = new ResizeObserver(h), c.observe(t)), R(), s.ready)
154
+ await E();
145
155
  else {
146
- const a = G(() => s.ready, (d) => {
147
- d && (a(), h());
156
+ const i = G(() => s.ready, (m) => {
157
+ m && (i(), E());
148
158
  });
149
159
  }
150
- document.addEventListener("dynamic-content:open", v);
151
- }), de(() => {
152
- if (he(), be(), i == null || i.disconnect(), document.removeEventListener("dynamic-content:open", v), S(u))
160
+ document.addEventListener("dynamic-content:open", b);
161
+ }), le(() => {
162
+ if (Ce(), ke(), n.dispose(), c == null || c.disconnect(), document.removeEventListener("dynamic-content:open", b), S(p))
153
163
  try {
154
- E().isStripoInitialized = !1;
164
+ w().isStripoInitialized = !1;
155
165
  } catch (t) {
156
166
  console.debug("Failed to close the editor readiness gate on unmount", t);
157
167
  }
158
- M(async () => {
159
- if (S(u))
168
+ T(async () => {
169
+ if (S(p))
160
170
  try {
161
171
  window.UIEditor.removeEditor();
162
172
  } catch {
163
173
  console.debug("Failed to remove Stripo editor: No editor found");
164
174
  }
165
175
  }), o.reset();
166
- }), K({
176
+ }), q({
167
177
  dynamicContent: {
168
- insert: B,
169
- close: N
178
+ insert: A,
179
+ close: B
170
180
  },
171
- hasChanges: l,
172
- saveSilent: k,
173
- setLoading: R
174
- }), { __sfc: !0, PreviewContainer: j, OnboardingWrapper: J, AssignStrategyDrawer: Q, RemoveStrategyModal: X, LegacyStrategyUpdatedModal: Y, headerWrapperRef: w, wrapperRef: f, dynamicContentStore: y, unsubscribeStore: D, props: s, configStore: o, editorStore: c, previewStore: Z, hasChanges: l, isTestPartner: ee, isSaveValidationEnabled: te, loadRollout: C, saveSilent: k, setLoading: R, emit: r, buildMetadata: g, initPlugin: F, preloadRuntime: L, runExclusive: M, beginMount: T, isCurrentMount: S, mountGeneration: u, getDefaultTemplate: I, cloneTimersOnSave: U, hasTimerBlocks: A, noHeader: oe, isRrsEnabled: ne, hasAssignedStrategy: re, insertDynamicContent: B, closeDynamicContent: N, handleDynamicContentOpen: v, ribbonObserver: i, updateRibbonOffset: b, startEditor: h, AutoSaveController: Ee, AuthErrorModal: we, Toaster: De, FilterSelectionDrawer: Ce, HeaderWrapper: ke, LoadingWrapper: Re, SaveAsTemplateDrawer: Fe, UnsubscribeWrapper: Le, ValidationErrorDrawer: Me };
181
+ hasChanges: u,
182
+ saveSilent: I,
183
+ setLoading: F
184
+ }), { __sfc: !0, openMetrics: n, PreviewContainer: K, OnboardingWrapper: j, AssignStrategyDrawer: J, RemoveStrategyModal: Q, LegacyStrategyUpdatedModal: X, headerWrapperRef: k, wrapperRef: y, dynamicContentStore: g, unsubscribeStore: C, props: s, configStore: o, editorStore: d, previewStore: Y, hasChanges: u, isTestPartner: Z, isSaveValidationEnabled: ee, loadRollout: D, saveSilent: I, setLoading: F, emit: a, buildMetadata: v, initPlugin: M, preloadRuntime: R, runExclusive: T, beginMount: L, isCurrentMount: S, mountGeneration: p, getDefaultTemplate: U, cloneTimersOnSave: N, hasTimerBlocks: _, noHeader: te, isRrsEnabled: oe, hasAssignedStrategy: re, insertDynamicContent: A, closeDynamicContent: B, handleDynamicContentOpen: b, ribbonObserver: c, updateRibbonOffset: h, startEditor: E, AutoSaveController: De, AuthErrorModal: Ie, Toaster: Fe, FilterSelectionDrawer: Me, HeaderWrapper: Re, LoadingWrapper: Te, SaveAsTemplateDrawer: Le, UnsubscribeWrapper: Ue, ValidationErrorDrawer: Ne };
175
185
  }
176
186
  });
177
187
  export {
178
- yt as default
188
+ ht as default
179
189
  };
@@ -1,22 +1,22 @@
1
1
  import a from "./UnsubscribePageSelection.vue2.js";
2
2
  /* empty css */
3
3
  import n from "../../../_virtual/_plugin-vue2_normalizer.js";
4
- var o = function() {
5
- var r = this, e = r._self._c, t = r._self._setupProxy;
6
- return e(t.WpDrawer, { attrs: { id: "unsubscribe-modal", "description-status": "", size: "large", "footer-button-group-options": t.footerButtonGroupOptions, status: t.unsubscribeStore.pageSelectionDrawerStatus, "title-text": t.trans("newsletter.select-a-template") }, on: { cancelOrBackButtonEvent: t.handleBack, onCloseEvent: t.handleClose, primaryButtonEvent: t.handleSave }, scopedSlots: r._u([{ key: "headerBottomSlot", fn: function() {
7
- return [e(t.UnsubscribeBreadcrumb, { staticClass: "px-5 py-3" })];
8
- }, proxy: !0 }]) }, [e("div", { staticClass: "d-g templates-wrapper" }, r._l(t.unsubscribeStore.getTemplatesByActiveType, function(s) {
9
- return e("div", { key: s.id, staticClass: "template-wrapper", on: { click: function(u) {
10
- return t.selectTemplate(s.id);
11
- } } }, [e(t.InContainer, { staticClass: "template-container o-h", class: { selected: t.unsubscribeStore.getSelectedTemplateByActiveType === s.id }, attrs: { border: t.getBorderClass(s.id) } }, [e("div", { staticClass: "w-1 h-1 d-f j-c-c a-i-c" }, [e("img", { staticClass: "w-1 h-1 thumbnail o-h", attrs: { alt: s.name, src: s.thumbnail } })])]), e("div", { staticClass: "mt-1 f-s-1" }, [r._v(" " + r._s(s.name) + " ")])], 1);
4
+ var i = function() {
5
+ var r = this, t = r._self._c, e = r._self._setupProxy;
6
+ return t(e.WpDrawer, { attrs: { id: "unsubscribe-modal", "description-status": "", size: "large", "footer-button-group-options": e.footerButtonGroupOptions, status: e.unsubscribeStore.pageSelectionDrawerStatus, "title-text": e.trans("newsletter.select-a-template") }, on: { cancelOrBackButtonEvent: e.handleBack, onCloseEvent: e.handleClose, primaryButtonEvent: e.handleSave }, scopedSlots: r._u([{ key: "headerBottomSlot", fn: function() {
7
+ return [t(e.UnsubscribeBreadcrumb, { staticClass: "px-5 py-3" })];
8
+ }, proxy: !0 }]) }, [t("div", { staticClass: "d-g templates-wrapper" }, r._l(e.unsubscribeStore.getTemplatesByActiveType, function(s) {
9
+ return t("div", { key: s.id, staticClass: "template-wrapper", on: { click: function(u) {
10
+ return e.selectTemplate(s.id);
11
+ } } }, [t(e.InContainer, { staticClass: "template-container o-h p-r", class: { selected: e.unsubscribeStore.getSelectedTemplateByActiveType === s.id }, attrs: { border: e.getBorderClass(s.id) } }, [t("div", { staticClass: "w-1 h-1 d-f j-c-c a-i-c" }, [t("img", { staticClass: "w-1 h-1 thumbnail o-h", attrs: { alt: s.name, src: s.thumbnail } })]), s.isDefault ? t(e.InChips, { staticClass: "p-a t-3 r-3", attrs: { id: "guido__unsubscribe-default-chip", type: "neutral", value: "default", "close-button": !1, interactive: !1, text: e.trans("unsubscription-preference.default") } }) : r._e()], 1), t("div", { staticClass: "mt-1 f-s-1" }, [r._v(" " + r._s(s.name) + " ")])], 1);
12
12
  }), 0)]);
13
- }, i = [], c = /* @__PURE__ */ n(
13
+ }, o = [], c = /* @__PURE__ */ n(
14
14
  a,
15
- o,
16
15
  i,
16
+ o,
17
17
  !1,
18
18
  null,
19
- "91a26acd"
19
+ "eaf8e461"
20
20
  );
21
21
  const _ = c.exports;
22
22
  export {
@@ -1,16 +1,16 @@
1
1
  import { defineComponent as y, ref as T, computed as a, watch as v } from "vue";
2
2
  import w from "../../wrappers/WpDrawer.vue.js";
3
- import { useToaster as B } from "../../../composables/useToaster.js";
4
- import { useTranslations as C } from "../../../composables/useTranslations.js";
3
+ import { useToaster as C } from "../../../composables/useToaster.js";
4
+ import { useTranslations as B } from "../../../composables/useTranslations.js";
5
5
  import { ToasterTypeOptions as h } from "../../../enums/toaster.js";
6
6
  import { useEditorStore as P } from "../../../stores/editor.js";
7
7
  import { useUnsubscribeStore as U } from "../../../stores/unsubscribe.js";
8
- import { InContainer as _ } from "@useinsider/design-system-vue";
9
- import I from "./UnsubscribeBreadcrumb.vue.js";
10
- const N = /* @__PURE__ */ y({
8
+ import { InContainer as I, InChips as _ } from "@useinsider/design-system-vue";
9
+ import x from "./UnsubscribeBreadcrumb.vue.js";
10
+ const W = /* @__PURE__ */ y({
11
11
  __name: "UnsubscribePageSelection",
12
- setup(x) {
13
- const s = C(), e = U(), r = P(), { showToaster: c } = B(), o = T(!1), i = a(() => e.isActiveTypeLastInCollection ? o.value ? s("unsubscription-preference.applying-changes") : s("statistics.apply") : s("products.select-and-continue")), l = a(() => e.pageSelectionUpdateStatus && e.isActiveTypeFirstInCollection ? s("products.cancel") : s("newsletter.back")), p = a(() => ({
12
+ setup(A) {
13
+ const s = B(), e = U(), r = P(), { showToaster: c } = C(), o = T(!1), i = a(() => e.isActiveTypeLastInCollection ? o.value ? s("unsubscription-preference.applying-changes") : s("statistics.apply") : s("products.select-and-continue")), l = a(() => e.pageSelectionUpdateStatus && e.isActiveTypeFirstInCollection ? s("products.cancel") : s("newsletter.back")), p = a(() => ({
14
14
  primaryButton: {
15
15
  styling: "solid",
16
16
  type: "primary",
@@ -63,9 +63,9 @@ const N = /* @__PURE__ */ y({
63
63
  };
64
64
  return v(() => e.pageSelectionDrawerStatus, (t) => {
65
65
  t && e.pageSelectionUpdateStatus && e.fetchTemplates();
66
- }), { __sfc: !0, trans: s, unsubscribeStore: e, editorStore: r, showToaster: c, isApplying: o, getPrimaryButtonText: i, getCancelOrBackButtonText: l, footerButtonGroupOptions: p, getBorderClass: d, closeModal: n, handleClose: m, handleBack: b, handleSave: f, selectTemplate: g, WpDrawer: w, InContainer: _, UnsubscribeBreadcrumb: I };
66
+ }), { __sfc: !0, trans: s, unsubscribeStore: e, editorStore: r, showToaster: c, isApplying: o, getPrimaryButtonText: i, getCancelOrBackButtonText: l, footerButtonGroupOptions: p, getBorderClass: d, closeModal: n, handleClose: m, handleBack: b, handleSave: f, selectTemplate: g, WpDrawer: w, InChips: _, InContainer: I, UnsubscribeBreadcrumb: x };
67
67
  }
68
68
  });
69
69
  export {
70
- N as default
70
+ W as default
71
71
  };
@@ -0,0 +1,167 @@
1
+ import { SYNC_MODULE_CLASS as w } from "./useSyncModuleExtractor.js";
2
+ import { readRuntimePrefetchState as S } from "../utils/runtimePrefetch.js";
3
+ import { getStripoVersion as R } from "../utils/stripoRuntime.js";
4
+ import M from "../package.json.js";
5
+ const A = [
6
+ "setup",
7
+ "host_ready",
8
+ "migration_start",
9
+ "migration_end",
10
+ "default_template_start",
11
+ "default_template_end",
12
+ "timer_clone_start",
13
+ "timer_clone_end",
14
+ "plugin_start",
15
+ "script_ready",
16
+ "fonts_sync_ready",
17
+ "blocks_config_ready",
18
+ "init_editor",
19
+ "token_start",
20
+ "token_end",
21
+ "ready"
22
+ ], m = "guido:open:", h = "total", p = [
23
+ ["host_wait", "setup", "host_ready"],
24
+ ["migration", "migration_start", "migration_end"],
25
+ ["default_template", "default_template_start", "default_template_end"],
26
+ ["timer_clone", "timer_clone_start", "timer_clone_end"],
27
+ ["script", "plugin_start", "script_ready"],
28
+ ["fonts_sync", "script_ready", "fonts_sync_ready"],
29
+ ["blocks_config", "fonts_sync_ready", "blocks_config_ready"],
30
+ ["editor_config", "blocks_config_ready", "init_editor"],
31
+ ["stripo_load", "init_editor", "ready"],
32
+ ["token", "token_start", "token_end"]
33
+ ], b = (e) => new RegExp(`(?:^|[\\s"'])(?:${e})(?=[\\s"'])`, "g"), N = /<img\b/gi, $ = b(w), L = /\srecommendation-id=/g, C = b("items-block-v2|esd-(?:cart|browsed|purchased)-items-block"), I = "esd-timer-id", f = {
34
+ html_bytes: null,
35
+ css_bytes: null,
36
+ image_count: null,
37
+ synced_module_count: null,
38
+ recommendation_block_count: null,
39
+ items_block_count: null,
40
+ has_timers: null,
41
+ force_recreate: null
42
+ };
43
+ let l = null;
44
+ const i = (e) => {
45
+ try {
46
+ e();
47
+ } catch (t) {
48
+ console.debug("guido:open: metrics step failed", t);
49
+ }
50
+ }, k = () => window.DD_RUM, g = (e, t) => e === void 0 || t === void 0 ? null : Math.round(t - e), _ = (e, t) => {
51
+ var r;
52
+ return ((r = e.match(t)) == null ? void 0 : r.length) ?? 0;
53
+ }, y = (e) => new TextEncoder().encode(e).length, O = (e) => {
54
+ if (!e)
55
+ return f;
56
+ try {
57
+ const { html: t, css: r, forceRecreate: o } = e;
58
+ return {
59
+ html_bytes: y(t),
60
+ css_bytes: y(r),
61
+ image_count: _(t, N),
62
+ synced_module_count: _(t, $),
63
+ recommendation_block_count: _(t, L),
64
+ items_block_count: _(t, C),
65
+ has_timers: t.includes(I),
66
+ force_recreate: o
67
+ };
68
+ } catch (t) {
69
+ return console.debug("guido:open: template weight failed", t), f;
70
+ }
71
+ }, E = () => {
72
+ i(() => {
73
+ A.forEach((e) => performance.clearMarks(`${m}${e}`)), [...p.map(([e]) => e), h].forEach((e) => performance.clearMeasures(`${m}${e}`));
74
+ });
75
+ }, c = (e, t) => {
76
+ if (e.finished || e.marks[t] !== void 0)
77
+ return;
78
+ const r = performance.now();
79
+ e.marks[t] = r, e === l && i(() => performance.mark(`${m}${t}`, { startTime: r }));
80
+ }, s = (e) => {
81
+ e.finished = !0, document.removeEventListener("visibilitychange", e.onVisibilityChange), window.removeEventListener("pagehide", e.onPageHide);
82
+ }, B = (e, t) => {
83
+ const { marks: r } = e, o = p.map(([n, a, d]) => [n, r[a], r[d]]);
84
+ o.push([h, r.setup, t]), o.forEach(([n, a, d]) => {
85
+ a !== void 0 && d !== void 0 && i(() => performance.measure(`${m}${n}`, { start: a, end: d }));
86
+ });
87
+ }, D = (e, t, r) => {
88
+ const { marks: o, context: n } = e, a = Object.fromEntries(
89
+ p.map(([d, v, P]) => [`${d}_ms`, g(o[v], o[P])])
90
+ );
91
+ return {
92
+ outcome: t,
93
+ open_ms: g(o.setup, r),
94
+ ...a,
95
+ script_preloaded: e.scriptPreloaded,
96
+ runtime_prefetch: e.runtimePrefetch,
97
+ ...O(e.template),
98
+ partner_name: (n == null ? void 0 : n.partnerName) ?? null,
99
+ product_type: (n == null ? void 0 : n.productType) ?? null,
100
+ template_id: (n == null ? void 0 : n.templateId) ?? null,
101
+ variation_id: (n == null ? void 0 : n.variationId) ?? null,
102
+ guido_version: M.version,
103
+ stripo_version: R(),
104
+ was_backgrounded: e.wasBackgrounded
105
+ };
106
+ }, u = (e, t) => {
107
+ i(() => {
108
+ const r = e.marks.ready ?? performance.now(), o = D(e, t, r);
109
+ e.template = null, e === l && B(e, r), console.debug("guido:open", o), i(() => {
110
+ var n, a;
111
+ return (a = (n = k()) == null ? void 0 : n.addAction) == null ? void 0 : a.call(n, "guido_editor_open", o);
112
+ });
113
+ });
114
+ }, T = (e) => {
115
+ e.finished || (s(e), u(e, "abandoned"));
116
+ }, H = () => {
117
+ const e = {
118
+ marks: {},
119
+ context: null,
120
+ template: null,
121
+ scriptPreloaded: null,
122
+ runtimePrefetch: null,
123
+ wasBackgrounded: document.visibilityState === "hidden",
124
+ finished: !1,
125
+ onVisibilityChange: () => {
126
+ document.visibilityState === "hidden" && (e.wasBackgrounded = !0);
127
+ },
128
+ onPageHide: () => T(e)
129
+ };
130
+ return e;
131
+ }, Y = (e) => ({
132
+ mark: (t) => c(e, t),
133
+ timed: async (t, r) => {
134
+ c(e, `${t}_start`);
135
+ const o = await r();
136
+ return c(e, `${t}_end`), o;
137
+ },
138
+ setContext: (t) => {
139
+ e.context = t;
140
+ },
141
+ setTemplate: (t) => {
142
+ e.template = t;
143
+ },
144
+ setScriptPreloaded: (t) => {
145
+ e.scriptPreloaded = t;
146
+ },
147
+ markReady: () => {
148
+ e.finished || (c(e, "ready"), s(e), i(() => {
149
+ var t, r;
150
+ return (r = (t = k()) == null ? void 0 : t.addTiming) == null ? void 0 : r.call(t, "guido_editor_ready");
151
+ }), setTimeout(() => u(e, "ready"), 0));
152
+ },
153
+ markFailed: () => {
154
+ e.finished || (s(e), u(e, "error"));
155
+ },
156
+ dispose: () => {
157
+ T(e), e === l && (E(), l = null);
158
+ }
159
+ }), K = () => {
160
+ const e = H();
161
+ return E(), l = e, i(() => {
162
+ e.runtimePrefetch = S();
163
+ }), document.addEventListener("visibilitychange", e.onVisibilityChange), window.addEventListener("pagehide", e.onPageHide), c(e, "setup"), Y(e);
164
+ };
165
+ export {
166
+ K as startEditorOpenMetrics
167
+ };