@useinsider/guido 3.18.2 → 3.19.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.
@@ -6,6 +6,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
6
6
  isPreviewModeOpen: boolean;
7
7
  editorVisualMode: string;
8
8
  hasChanges: boolean;
9
+ changeSeq: number;
9
10
  isStripoInitialized: boolean;
10
11
  templateId: string;
11
12
  syncModulesEnabled: boolean;
@@ -19,6 +20,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
19
20
  isPreviewModeOpen: boolean;
20
21
  editorVisualMode: string;
21
22
  hasChanges: boolean;
23
+ changeSeq: number;
22
24
  isStripoInitialized: boolean;
23
25
  templateId: string;
24
26
  syncModulesEnabled: boolean;
@@ -31,6 +33,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
31
33
  isPreviewModeOpen: boolean;
32
34
  editorVisualMode: string;
33
35
  hasChanges: boolean;
36
+ changeSeq: number;
34
37
  isStripoInitialized: boolean;
35
38
  templateId: string;
36
39
  syncModulesEnabled: boolean;
@@ -44,6 +47,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
44
47
  isPreviewModeOpen: boolean;
45
48
  editorVisualMode: string;
46
49
  hasChanges: boolean;
50
+ changeSeq: number;
47
51
  isStripoInitialized: boolean;
48
52
  templateId: string;
49
53
  syncModulesEnabled: boolean;
@@ -56,6 +60,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
56
60
  isPreviewModeOpen: boolean;
57
61
  editorVisualMode: string;
58
62
  hasChanges: boolean;
63
+ changeSeq: number;
59
64
  isStripoInitialized: boolean;
60
65
  templateId: string;
61
66
  syncModulesEnabled: boolean;
@@ -69,6 +74,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
69
74
  isPreviewModeOpen: boolean;
70
75
  editorVisualMode: string;
71
76
  hasChanges: boolean;
77
+ changeSeq: number;
72
78
  isStripoInitialized: boolean;
73
79
  templateId: string;
74
80
  syncModulesEnabled: boolean;
@@ -81,6 +87,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
81
87
  isPreviewModeOpen: boolean;
82
88
  editorVisualMode: string;
83
89
  hasChanges: boolean;
90
+ changeSeq: number;
84
91
  isStripoInitialized: boolean;
85
92
  templateId: string;
86
93
  syncModulesEnabled: boolean;
@@ -94,6 +101,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
94
101
  isPreviewModeOpen: boolean;
95
102
  editorVisualMode: string;
96
103
  hasChanges: boolean;
104
+ changeSeq: number;
97
105
  isStripoInitialized: boolean;
98
106
  templateId: string;
99
107
  syncModulesEnabled: boolean;
@@ -106,6 +114,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
106
114
  isPreviewModeOpen: boolean;
107
115
  editorVisualMode: string;
108
116
  hasChanges: boolean;
117
+ changeSeq: number;
109
118
  isStripoInitialized: boolean;
110
119
  templateId: string;
111
120
  syncModulesEnabled: boolean;
@@ -119,6 +128,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
119
128
  isPreviewModeOpen: boolean;
120
129
  editorVisualMode: string;
121
130
  hasChanges: boolean;
131
+ changeSeq: number;
122
132
  isStripoInitialized: boolean;
123
133
  templateId: string;
124
134
  syncModulesEnabled: boolean;
@@ -131,6 +141,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
131
141
  isPreviewModeOpen: boolean;
132
142
  editorVisualMode: string;
133
143
  hasChanges: boolean;
144
+ changeSeq: number;
134
145
  isStripoInitialized: boolean;
135
146
  templateId: string;
136
147
  syncModulesEnabled: boolean;
@@ -144,6 +155,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
144
155
  isPreviewModeOpen: boolean;
145
156
  editorVisualMode: string;
146
157
  hasChanges: boolean;
158
+ changeSeq: number;
147
159
  isStripoInitialized: boolean;
148
160
  templateId: string;
149
161
  syncModulesEnabled: boolean;
@@ -156,6 +168,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
156
168
  isPreviewModeOpen: boolean;
157
169
  editorVisualMode: string;
158
170
  hasChanges: boolean;
171
+ changeSeq: number;
159
172
  isStripoInitialized: boolean;
160
173
  templateId: string;
161
174
  syncModulesEnabled: boolean;
@@ -169,6 +182,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
169
182
  isPreviewModeOpen: boolean;
170
183
  editorVisualMode: string;
171
184
  hasChanges: boolean;
185
+ changeSeq: number;
172
186
  isStripoInitialized: boolean;
173
187
  templateId: string;
174
188
  syncModulesEnabled: boolean;
@@ -181,6 +195,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
181
195
  isPreviewModeOpen: boolean;
182
196
  editorVisualMode: string;
183
197
  hasChanges: boolean;
198
+ changeSeq: number;
184
199
  isStripoInitialized: boolean;
185
200
  templateId: string;
186
201
  syncModulesEnabled: boolean;
@@ -194,6 +209,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
194
209
  isPreviewModeOpen: boolean;
195
210
  editorVisualMode: string;
196
211
  hasChanges: boolean;
212
+ changeSeq: number;
197
213
  isStripoInitialized: boolean;
198
214
  templateId: string;
199
215
  syncModulesEnabled: boolean;
@@ -206,6 +222,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
206
222
  isPreviewModeOpen: boolean;
207
223
  editorVisualMode: string;
208
224
  hasChanges: boolean;
225
+ changeSeq: number;
209
226
  isStripoInitialized: boolean;
210
227
  templateId: string;
211
228
  syncModulesEnabled: boolean;
@@ -219,6 +236,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
219
236
  isPreviewModeOpen: boolean;
220
237
  editorVisualMode: string;
221
238
  hasChanges: boolean;
239
+ changeSeq: number;
222
240
  isStripoInitialized: boolean;
223
241
  templateId: string;
224
242
  syncModulesEnabled: boolean;
@@ -231,6 +249,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
231
249
  isPreviewModeOpen: boolean;
232
250
  editorVisualMode: string;
233
251
  hasChanges: boolean;
252
+ changeSeq: number;
234
253
  isStripoInitialized: boolean;
235
254
  templateId: string;
236
255
  syncModulesEnabled: boolean;
@@ -244,6 +263,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
244
263
  isPreviewModeOpen: boolean;
245
264
  editorVisualMode: string;
246
265
  hasChanges: boolean;
266
+ changeSeq: number;
247
267
  isStripoInitialized: boolean;
248
268
  templateId: string;
249
269
  syncModulesEnabled: boolean;
@@ -256,6 +276,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
256
276
  isPreviewModeOpen: boolean;
257
277
  editorVisualMode: string;
258
278
  hasChanges: boolean;
279
+ changeSeq: number;
259
280
  isStripoInitialized: boolean;
260
281
  templateId: string;
261
282
  syncModulesEnabled: boolean;
@@ -269,6 +290,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
269
290
  isPreviewModeOpen: boolean;
270
291
  editorVisualMode: string;
271
292
  hasChanges: boolean;
293
+ changeSeq: number;
272
294
  isStripoInitialized: boolean;
273
295
  templateId: string;
274
296
  syncModulesEnabled: boolean;
@@ -281,6 +303,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
281
303
  isPreviewModeOpen: boolean;
282
304
  editorVisualMode: string;
283
305
  hasChanges: boolean;
306
+ changeSeq: number;
284
307
  isStripoInitialized: boolean;
285
308
  templateId: string;
286
309
  syncModulesEnabled: boolean;
@@ -294,6 +317,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
294
317
  isPreviewModeOpen: boolean;
295
318
  editorVisualMode: string;
296
319
  hasChanges: boolean;
320
+ changeSeq: number;
297
321
  isStripoInitialized: boolean;
298
322
  templateId: string;
299
323
  syncModulesEnabled: boolean;
@@ -306,6 +330,7 @@ export declare const useEditorStore: import("pinia").StoreDefinition<"guidoEdito
306
330
  isPreviewModeOpen: boolean;
307
331
  editorVisualMode: string;
308
332
  hasChanges: boolean;
333
+ changeSeq: number;
309
334
  isStripoInitialized: boolean;
310
335
  templateId: string;
311
336
  syncModulesEnabled: boolean;
@@ -1,41 +1,41 @@
1
- /**
2
- * Outbound contract Guido publishes to the host's shared Pinia singleton so
3
- * cortex-fe can pick up the current editor state and forward it as
4
- * `clientState.editor` on the next chat-stream POST.
5
- *
6
- * State + getters only — `useGuidoStateBridge` writes via `$patch`, no actions
7
- * live here (architecture invariant).
8
- *
9
- * Store id `guidoEmailEditor` is cross-MFE: cortex-fe reads it via
10
- * `pinia._s.get('guidoEmailEditor')` at runtime. The internal Guido editor
11
- * store keeps id `guidoEditor` — these are intentionally separate. The
12
- * internal store carries UI state that cortex-fe should not see; this public
13
- * store carries the contract Guido is willing to share.
14
- */
15
- export declare const useGuidoEmailEditorStore: import("pinia").StoreDefinition<"guidoEmailEditor", {
1
+ /** The published editor snapshot — the shape a consumer reads off the shared store. */
2
+ export interface GuidoEmailEditorState {
16
3
  /** Current Stripo HTML — stripe tables only, no DOCTYPE/wrapper. */
17
4
  html: string;
18
5
  /** Current Stripo CSS — es-p* utility classes used by the html. */
19
6
  css: string;
20
7
  /** Wall-clock ms when html/css were last written by the bridge. */
21
8
  lastUpdatedAt: number;
22
- /** Template id from the editor config, for cortex-fe to scope per-template. */
9
+ /** Template id from the editor config, so a consumer can scope per-template. */
23
10
  templateId: string;
24
- }, {
11
+ }
12
+ /**
13
+ * Outbound contract Guido publishes to the host's shared Pinia singleton so a
14
+ * consumer can read the current editor state: cortex-fe forwards it as
15
+ * `clientState.editor` on the next chat-stream POST, email-fe scans it for the
16
+ * Array of Objects lock.
17
+ *
18
+ * Published as `@useinsider/guido/editor-state` and from the root barrel, so a
19
+ * consumer imports this store instead of re-declaring one under the same id.
20
+ *
21
+ * State + getters only, no actions. `useGuidoStateBridge` is the only intended
22
+ * writer, but that is Guido's own convention rather than something the store
23
+ * enforces: publishing the definition hands a consumer `$patch` as well, exactly
24
+ * as the runtime `pinia._s` probe always did.
25
+ *
26
+ * Store id `guidoEmailEditor` is cross-MFE: cortex-fe reads it via
27
+ * `pinia._s.get('guidoEmailEditor')` at runtime rather than importing it, so the
28
+ * id stays part of the contract. The internal Guido editor store keeps id
29
+ * `guidoEditor` — these are intentionally separate. The internal store carries
30
+ * UI state a consumer should not see; this public store carries the contract
31
+ * Guido is willing to share.
32
+ */
33
+ export declare const useGuidoEmailEditorStore: import("pinia").StoreDefinition<"guidoEmailEditor", GuidoEmailEditorState, {
25
34
  /** True once the bridge has published at least one snapshot. */
26
35
  hasSnapshot: (state: {
27
36
  html: string;
28
37
  css: string;
29
38
  lastUpdatedAt: number;
30
39
  templateId: string;
31
- } & import("pinia").PiniaCustomStateProperties<{
32
- /** Current Stripo HTML — stripe tables only, no DOCTYPE/wrapper. */
33
- html: string;
34
- /** Current Stripo CSS — es-p* utility classes used by the html. */
35
- css: string;
36
- /** Wall-clock ms when html/css were last written by the bridge. */
37
- lastUpdatedAt: number;
38
- /** Template id from the editor config, for cortex-fe to scope per-template. */
39
- templateId: string;
40
- }>) => boolean;
40
+ } & import("pinia").PiniaCustomStateProperties<GuidoEmailEditorState>) => boolean;
41
41
  }, {}>;
@@ -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>;
@@ -0,0 +1,20 @@
1
+ import type { BaseDynamicContent } from '@@/Types/generic';
2
+ export type DynamicContentFormat = NonNullable<BaseDynamicContent['format']>;
3
+ /** Format key the dynamic-content picker sends for a custom date/time format. */
4
+ export declare const TIME_FORMAT_KEY = "time-format";
5
+ /** Wraps a Liquid filter argument in whichever quote style the value itself does not use. */
6
+ export declare const quoteArgument: (value: string) => string | null;
7
+ /**
8
+ * `{ key: 'time-format', value: '%Y-%m-%d' }` -> `date: "%Y-%m-%d"`.
9
+ *
10
+ * Only a custom date/time strftime pattern has a Liquid equivalent. Anything else returns null so
11
+ * the caller emits a plain tag rather than one that silently lost — or literally printed — its
12
+ * format.
13
+ * @example formatToLiquidFilter({ key: 'time-format', value: '%b %-d, %Y' }) -> date: "%b %-d, %Y"
14
+ */
15
+ export declare const formatToLiquidFilter: (format: DynamicContentFormat) => string | null;
16
+ /**
17
+ * Inverse of `formatToLiquidFilter` — reads the picker format back out of one filter segment, so a
18
+ * reopened tag restores its selection in the host's format dropdown.
19
+ */
20
+ export declare const liquidFilterToFormat: (segment: string) => DynamicContentFormat | null;
@@ -8,6 +8,10 @@ const o = e("guidoEditor", {
8
8
  isPreviewModeOpen: !1,
9
9
  editorVisualMode: "desktop",
10
10
  hasChanges: !1,
11
+ // Bumped on every Stripo document change. `hasChanges` is a latch that stays
12
+ // true until a save, so it cannot signal the second edit onwards; watchers
13
+ // that need every change (the outbound state bridge) watch this instead.
14
+ changeSeq: 0,
11
15
  isStripoInitialized: !1,
12
16
  templateId: "",
13
17
  syncModulesEnabled: !1,
@@ -1,13 +1,9 @@
1
1
  import { defineStore as e } from "pinia";
2
2
  const d = e("guidoEmailEditor", {
3
3
  state: () => ({
4
- /** Current Stripo HTML — stripe tables only, no DOCTYPE/wrapper. */
5
4
  html: "",
6
- /** Current Stripo CSS — es-p* utility classes used by the html. */
7
5
  css: "",
8
- /** Wall-clock ms when html/css were last written by the bridge. */
9
6
  lastUpdatedAt: 0,
10
- /** Template id from the editor config, for cortex-fe to scope per-template. */
11
7
  templateId: ""
12
8
  }),
13
9
  getters: {
@@ -1,69 +1,78 @@
1
- const o = (t) => {
2
- const a = t.value.match(/\{\{([^}]+)\}\}/)[1].split("|").map((l) => l.trim()), [s] = a, r = {
1
+ import { formatToLiquidFilter as b, quoteArgument as y, liquidFilterToFormat as h } from "./liquidDynamicContent.js";
2
+ const g = (t) => {
3
+ if (!t.includes("="))
4
+ return null;
5
+ const [r, e] = t.split("=");
6
+ return { key: r.trim(), value: e.trim() };
7
+ }, c = "default:", f = (t) => {
8
+ if (!t.startsWith(c))
9
+ return t;
10
+ const r = t.slice(c.length).trim(), e = (l) => r.length >= 2 && r.startsWith(l) && r.endsWith(l);
11
+ return e('"') || e("'") ? r.slice(1, -1) : r;
12
+ }, k = (t) => {
13
+ const e = t.value.match(/\{\{([^}]+)\}\}/)[1].split("|").map((a) => a.trim()), [l] = e, s = {
3
14
  text: t.label,
4
- value: s || ""
15
+ value: l || ""
5
16
  };
6
- if (a.length >= 2) {
7
- const [, l, e] = a;
8
- if (l.startsWith("default:")) {
9
- let n = l.slice(8).trim();
10
- n.startsWith('"') && n.endsWith('"') && (n = n.slice(1, -1)), r.fallback = n;
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);
17
+ if (e.length >= 2) {
18
+ const [, a, n] = e;
19
+ if (a.startsWith(c))
20
+ s.fallback = f(a);
21
+ else {
22
+ const o = h(a) ?? g(a);
23
+ o ? s.format = o : n || (s.fallback = a), n && (s.fallback = f(n));
14
24
  }
15
25
  }
16
- return r;
17
- }, f = (t, c = !1) => t.map((a) => {
18
- if (a.format)
19
- return {
20
- label: `${a.text} | ${a.format.key}=${a.format.value}`,
21
- value: `{{${a.value}|${a.format.key}=${a.format.value}}}`
22
- };
23
- if (c) {
24
- if (!a.fallback)
25
- return {
26
- label: a.text,
27
- value: `{{ ${a.value} }}`
28
- };
29
- const r = !Number.isNaN(Number(a.fallback)) && a.fallback.trim() !== "" ? a.fallback : `"${a.fallback}"`;
30
- return {
31
- label: `${a.text} | ${a.fallback}`,
32
- value: `{{ ${a.value} | default: ${r} }}`
33
- };
34
- }
26
+ return s;
27
+ }, p = (t) => {
28
+ const e = !Number.isNaN(Number(t)) && t.trim() !== "" ? t : y(t);
29
+ return e === null ? null : `${c} ${e}`;
30
+ }, v = (t) => {
31
+ const r = t.format ? b(t.format) : null, e = t.fallback ? p(t.fallback) : null, l = [t.value, r, e].filter(Boolean);
35
32
  return {
36
- label: a.fallback ? `${a.text} | ${a.fallback}` : a.text,
37
- value: a.fallback ? `{{${a.value}|${a.fallback}}}` : `{{${a.value}}}`
33
+ label: [t.text, r, e && t.fallback].filter(Boolean).join(" | "),
34
+ value: `{{ ${l.join(" | ")} }}`
38
35
  };
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 ?? []];
43
- if (n.length > 0) {
44
- s(n);
36
+ }, i = (t, r = !1) => t.map((e) => r ? v(e) : e.format ? {
37
+ label: `${e.text} | ${e.format.key}=${e.format.value}`,
38
+ value: `{{${e.value}|${e.format.key}=${e.format.value}}}`
39
+ } : {
40
+ label: e.fallback ? `${e.text} | ${e.fallback}` : e.text,
41
+ value: e.fallback ? `{{${e.value}|${e.fallback}}}` : `{{${e.value}}}`
42
+ }), $ = (t) => {
43
+ const r = [], e = /* @__PURE__ */ new Set(), l = (a) => {
44
+ Array.isArray(a) && a.forEach((n) => {
45
+ const o = [...n.children ?? [], ...n.select_items ?? []];
46
+ if (o.length > 0) {
47
+ l(o);
45
48
  return;
46
49
  }
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 }));
50
+ const u = n.text || n.tag_text;
51
+ u && n.value && !e.has(n.value) && (e.add(n.value), r.push({ text: u, value: n.value }));
49
52
  });
50
- }, [r] = Object.values(t ?? {});
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));
53
+ }, [s] = Object.values(t ?? {});
54
+ return l(s), r;
55
+ }, d = (t, r, e = !1) => {
56
+ const l = new Set(t.map((a) => a.value)), s = r.filter((a) => l.has(a.value) ? !1 : (l.add(a.value), !0));
54
57
  return [
55
- ...f(t, a),
56
- ...f(r, a)
58
+ ...i(t, e),
59
+ ...i(s, e)
57
60
  ];
58
- }, v = () => {
61
+ }, F = () => {
59
62
  var t;
60
63
  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) : "";
64
+ }, T = (t) => typeof t == "string" ? t : typeof t == "number" ? String(t) : "", x = (t) => {
65
+ if (t === null || typeof t != "object" || Array.isArray(t))
66
+ return !1;
67
+ const r = Object.getPrototypeOf(t);
68
+ return r === Object.prototype || r === null;
69
+ };
62
70
  export {
63
- k as asText,
64
- i as buildMergeTagEntries,
65
- f as dynamicContentToMergeTags,
66
- b as flattenDynamicContentList,
67
- v as getCsrfToken,
68
- o as mergeTagToDynamicContent
71
+ T as asText,
72
+ d as buildMergeTagEntries,
73
+ i as dynamicContentToMergeTags,
74
+ $ as flattenDynamicContentList,
75
+ F as getCsrfToken,
76
+ x as isPlainObject,
77
+ k as mergeTagToDynamicContent
69
78
  };
@@ -0,0 +1,15 @@
1
+ const E = "time-format", r = "date", u = new RegExp(`^${r}\\s*:\\s*(?:"([^"]*)"|'([^']*)')$`), s = /%[-_0^#]?\d*[a-zA-Z%]/, c = new RegExp(s, "g"), l = /\b(?:Y{2,4}|M{2,4}|D{1,4}|d{3,4}|H{2}|h{2}|m{2}|s{2}|S{1,3}|A|a)\b/, T = (t) => t.includes('"') ? t.includes("'") ? null : `'${t}'` : `"${t}"`, i = (t) => s.test(t) && !l.test(t.replace(c, "")), R = (t) => {
2
+ if (t.key !== E || !i(t.value ?? ""))
3
+ return null;
4
+ const n = T(t.value);
5
+ return n === null ? null : `${r}: ${n}`;
6
+ }, _ = (t) => {
7
+ const [, n, o] = t.match(u) ?? [], e = n ?? o;
8
+ return e ? { key: E, value: e } : null;
9
+ };
10
+ export {
11
+ E as TIME_FORMAT_KEY,
12
+ R as formatToLiquidFilter,
13
+ _ as liquidFilterToFormat,
14
+ T as quoteArgument
15
+ };
@@ -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";
5
- import { useRecommendationExtensionStore as T } from "../extensions/Blocks/Recommendation/store/recommendation.js";
4
+ import { DEFAULT_CURRENCY as m, DEFAULT_NODE_CONFIG as n } from "../extensions/Blocks/Recommendation/constants/defaultConfig.js";
5
+ import { useRecommendationExtensionStore as A } from "../extensions/Blocks/Recommendation/store/recommendation.js";
6
6
  import { mapLegacyStrategy as L } from "../extensions/Blocks/Recommendation/utils/legacyStrategyMap.js";
7
- import { DATA_ATTRIBUTES as C } from "../extensions/Blocks/Unsubscribe/utils/constants.js";
7
+ import { DATA_ATTRIBUTES as T } 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(l) {
15
+ const i = new DOMParser().parseFromString(l, "text/html").querySelectorAll(`[${T.PAGE_LIST}]`), t = [];
16
+ return i.forEach((c) => {
17
+ const o = c.getAttribute(T.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");
22
- if (n.length === 0)
21
+ async function q(l) {
22
+ const a = new DOMParser().parseFromString(l, "text/html").querySelectorAll(".recommendation-block-v2");
23
+ if (a.length === 0)
23
24
  return;
24
- const c = T();
25
- n.forEach((t) => {
25
+ const i = A();
26
+ a.forEach((t) => {
26
27
  var r, d, g, f, s, y;
27
- const i = t.getAttribute("recommendation-id"), o = i ? Number(i) : NaN;
28
+ const c = t.getAttribute("recommendation-id"), o = c ? Number(c) : NaN;
28
29
  if (!Number.isFinite(o))
29
30
  return;
30
31
  const p = t.getAttribute("esd-ext-config");
@@ -36,21 +37,21 @@ 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
42
  const b = {
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).
45
- strategy: L(e.strategy) || a.strategy,
46
- strategyId: e.strategyId ?? a.strategyId,
47
- language: e.language ?? a.language,
48
- size: e.size ?? a.size,
46
+ strategy: L(e.strategy) || n.strategy,
47
+ strategyId: e.strategyId ?? n.strategyId,
48
+ language: e.language ?? n.language,
49
+ size: e.size ?? n.size,
49
50
  // Spread the default arrays so each block gets a fresh reference
50
51
  // instead of sharing the singleton in DEFAULT_NODE_CONFIG.
51
- productIds: e.productIds ?? [...a.productIds],
52
- filters: e.filters ?? [...a.filters],
53
- shuffleProducts: e.shuffleProducts ?? a.shuffleProducts,
52
+ productIds: e.productIds ?? [...n.productIds],
53
+ filters: e.filters ?? [...n.filters],
54
+ shuffleProducts: e.shuffleProducts ?? n.shuffleProducts,
54
55
  currencyCode: ((r = e.currency) == null ? void 0 : r.code) ?? m.code,
55
56
  currencySymbol: ((d = e.currency) == null ? void 0 : d.symbol) ?? m.symbol,
56
57
  currencyAlignment: ((g = e.currency) == null ? void 0 : g.alignment) ?? m.alignment,
@@ -58,10 +59,10 @@ async function M(l) {
58
59
  currencyDecimalSeparator: ((s = e.currency) == null ? void 0 : s.decimalSeparator) ?? m.decimalSeparator,
59
60
  currencyThousandSeparator: ((y = e.currency) == null ? void 0 : y.thousandSeparator) ?? m.thousandSeparator
60
61
  };
61
- c.seedBlockUrlConfig(o, b);
62
+ i.seedBlockUrlConfig(o, b);
62
63
  });
63
64
  try {
64
- await c.fetchRecommendationCreateData();
65
+ await i.fetchRecommendationCreateData();
65
66
  } catch (t) {
66
67
  console.warn(
67
68
  "Recommendation reference data pre-load failed; validator will skip the availability check.",
@@ -69,24 +70,24 @@ async function M(l) {
69
70
  );
70
71
  }
71
72
  }
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();
73
+ const te = () => {
74
+ const l = N(), u = z(), a = O(), { getCompiledEmail: i, getTemplateData: t, updateHtmlAndCss: c } = k(), { compileHtml: o, compileAmpHtml: p } = x(), { isFeatureEnabled: e } = U();
74
75
  return {
75
76
  prepareTemplateDetails: async () => {
76
77
  let { html: r, css: d, syncModulesIds: g = [] } = await t();
77
78
  if (e("linkTrackingIds"))
78
79
  try {
79
80
  const { html: h, changed: F, nextSeq: H } = v(r, u.trackIdSessionFloor);
80
- u.trackIdSessionFloor = H, F && (r = h, await i(h, d));
81
+ u.trackIdSessionFloor = H, F && (r = h, await c(h, d));
81
82
  } catch (h) {
82
83
  console.error("Tracking-id step failed, saving anyway:", h);
83
84
  }
84
- const { html: f, ampHtml: s = "", ampErrors: y = [] } = await c({
85
+ const { html: f, ampHtml: s = "", ampErrors: y = [] } = await i({
85
86
  minimize: !0,
86
87
  resetDataSavedFlag: !1
87
88
  });
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);
89
+ a.selectedUnsubscribePages.length && await a.fetchTemplates(), await q(r);
90
+ const { compiledHtml: I, stats: S, appliedRules: w } = o(f), D = s && p(s).compiledHtml, P = l.getSelectedDynamicContentList, E = A(), C = M(r);
90
91
  return console.debug("HTML Compilation Stats:", {
91
92
  originalSize: S.originalSize,
92
93
  compiledSize: S.compiledSize,
@@ -94,7 +95,7 @@ const Z = () => {
94
95
  appliedRules: w,
95
96
  executionTime: `${S.executionTime.toFixed(2)}ms`
96
97
  }), {
97
- dynamicContentList: E,
98
+ dynamicContentList: P,
98
99
  compiledHtml: I,
99
100
  rawHtml: r,
100
101
  css: d,
@@ -102,18 +103,18 @@ const Z = () => {
102
103
  ampErrors: y,
103
104
  modules: g.map(Number),
104
105
  recommendation: {
105
- campaignUrls: P.recommendationCampaignUrls,
106
+ campaignUrls: E.recommendationCampaignUrls,
106
107
  configs: {}
107
108
  },
108
109
  unsubscribe: {
109
- status: A.length > 0,
110
- config: A
110
+ status: C.length > 0,
111
+ config: C
111
112
  }
112
113
  };
113
114
  }
114
115
  };
115
116
  };
116
117
  export {
117
- O as getHtmlReferencedUnsubscribePages,
118
- Z as useTemplatePreparation
118
+ M as getHtmlReferencedUnsubscribePages,
119
+ te as useTemplatePreparation
119
120
  };