@useinsider/guido 3.12.0-beta.66af948 → 3.12.0-beta.6d6e76b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -161,7 +161,6 @@ const config: GuidoConfigInput = {
161
161
  modulesDisabled?: boolean, // Default: false - Disable modules panel
162
162
  liquidSyntax?: boolean, // Default: false - Enable Liquid template syntax
163
163
  autosave?: boolean, // Default: false - Show the Auto Save toggle in the header. See wiki/AUTOSAVE.md.
164
- allowlistEnabled?: boolean, // Default: false - Pre-save domain-allowlist check (opt-in). Guido self-serves the block toaster (role lookup, deep-link, copy from window.trans).
165
164
  },
166
165
 
167
166
  // Optional: Callbacks
@@ -1,11 +1,11 @@
1
1
  import { ModuleFolderDefaults as y } from "../../enums/defaults.js";
2
- import { object as a, number as n, optional as e, string as t, picklist as r, pipe as p, minLength as b, custom as h, boolean as o, array as c, record as k, fallback as C, literal as i, looseObject as g, variant as R, union as f, unknown as s, lazy as T } from "../../node_modules/valibot/dist/index.js";
2
+ import { object as a, number as n, optional as e, string as t, picklist as l, pipe as p, minLength as b, custom as f, boolean as o, array as c, record as k, fallback as C, literal as i, looseObject as g, variant as R, union as h, unknown as s, lazy as T } from "../../node_modules/valibot/dist/index.js";
3
3
  const d = {
4
4
  /** Promotional/marketing emails */
5
5
  PROMOTIONAL: 1,
6
6
  /** Transactional/system emails */
7
7
  TRANSACTIONAL: 2
8
- }, l = {
8
+ }, r = {
9
9
  /** Standard email campaigns */
10
10
  EMAIL: 60,
11
11
  /** Architect journey builder */
@@ -38,16 +38,16 @@ const d = {
38
38
  ),
39
39
  /** Product type identifier */
40
40
  productType: e(
41
- r([
42
- l.EMAIL,
43
- l.ARCHITECT,
44
- l.UNSUBSCRIBE_PAGES
41
+ l([
42
+ r.EMAIL,
43
+ r.ARCHITECT,
44
+ r.UNSUBSCRIBE_PAGES
45
45
  ]),
46
- l.EMAIL
46
+ r.EMAIL
47
47
  ),
48
48
  /** Message type (promotional or transactional) */
49
49
  messageType: e(
50
- r([d.PROMOTIONAL, d.TRANSACTIONAL]),
50
+ l([d.PROMOTIONAL, d.TRANSACTIONAL]),
51
51
  d.PROMOTIONAL
52
52
  ),
53
53
  /** Display name for the current user */
@@ -76,14 +76,14 @@ const d = {
76
76
  children: e(c(S)),
77
77
  // eslint-disable-next-line camelcase -- backend field name
78
78
  select_items: e(c(S))
79
- })), E = k(
79
+ })), P = k(
80
80
  t(),
81
81
  C(c(S), [])
82
- ), P = g({
82
+ ), D = g({
83
83
  /** Block ID (matches the dictionary key and the legacy HTML element id) */
84
84
  id: e(n()),
85
85
  /** Decimal places for price display (legacy data may use string or number) */
86
- decimalCount: e(f([t(), n()])),
86
+ decimalCount: e(h([t(), n()])),
87
87
  /** Pinned product IDs (empty array when filter-driven) */
88
88
  productIds: e(c(s())),
89
89
  /** Whether the block requested live products at send time */
@@ -117,14 +117,14 @@ const d = {
117
117
  /** Block type marker used by some legacy variants */
118
118
  blockType: e(t()),
119
119
  /** Size variant marker (legacy data may use string or number) */
120
- size: e(f([t(), n()])),
120
+ size: e(h([t(), n()])),
121
121
  /** Vertical responsiveness flag (legacy size=1 variants) */
122
122
  verticalResponsiveness: e(o()),
123
123
  /** Legacy "Move to next line" price placement toggle (cardPricePlacement.js) */
124
124
  isPriceMovedToNextLine: e(o()),
125
125
  /** Legacy "Hide if same as discounted" / delete-price-for-zero-sale toggle */
126
126
  isPriceDeletedForZeroSale: e(o())
127
- }), D = a({
127
+ }), E = a({
128
128
  /**
129
129
  * Legacy recommendation block configs keyed by block ID.
130
130
  * Pass this when loading a template authored with the v1
@@ -132,7 +132,7 @@ const d = {
132
132
  * strategy, currency, locale, and layout data.
133
133
  */
134
134
  recommendationConfigs: e(
135
- k(t(), P),
135
+ k(t(), D),
136
136
  {}
137
137
  )
138
138
  }), M = a({
@@ -151,7 +151,7 @@ const d = {
151
151
  * (first) partner's leaf attributes into the label→token map that repairs
152
152
  * label-form placeholders (`{{ Phone Number }}`) in dropped saved modules.
153
153
  */
154
- dynamicContentList: e(E, {}),
154
+ dynamicContentList: e(P, {}),
155
155
  /** Valid custom field attribute names from the partner's categorized fields */
156
156
  customFieldAttributes: e(c(t()), []),
157
157
  /** Selected unsubscribe page IDs */
@@ -159,7 +159,7 @@ const d = {
159
159
  /** Force recreate template in Stripo storage (use true when updating externally modified templates) */
160
160
  forceRecreate: e(o(), !1),
161
161
  /** Migration-only inputs (legacy block configs) */
162
- migration: e(D, {})
162
+ migration: e(E, {})
163
163
  }), N = a({
164
164
  /** Sender display name */
165
165
  senderName: e(t(), ""),
@@ -201,10 +201,8 @@ const d = {
201
201
  /** Enable Liquid template syntax */
202
202
  liquidSyntax: e(o(), !1),
203
203
  /** Enable autosave (3-min interval + tab-hide). User toggles on/off from the header. */
204
- autosave: e(o(), !1),
205
- /** Enable pre-save domain-allowlist validation (opt-in; Guido self-serves the block toaster) */
206
- allowlistEnabled: e(o(), !1)
207
- }), U = r([
204
+ autosave: e(o(), !1)
205
+ }), U = l([
208
206
  "amp-accordion",
209
207
  "amp-carousel",
210
208
  "amp-form-controls",
@@ -218,7 +216,7 @@ const d = {
218
216
  "text-block",
219
217
  "timer-block",
220
218
  "video-block"
221
- ]), B = r([
219
+ ]), B = l([
222
220
  "dynamic-content",
223
221
  "checkbox-block",
224
222
  "radio-button-block",
@@ -271,7 +269,7 @@ const d = {
271
269
  ...m.entries,
272
270
  type: i("custom"),
273
271
  /** Custom processor function */
274
- processor: h(
272
+ processor: f(
275
273
  (u) => typeof u == "function",
276
274
  "processor must be a function"
277
275
  )
@@ -291,7 +289,7 @@ const d = {
291
289
  * Return false to cancel the save operation.
292
290
  */
293
291
  externalValidation: e(
294
- h(
292
+ f(
295
293
  (u) => typeof u == "function",
296
294
  "externalValidation must be a function"
297
295
  )
@@ -326,7 +324,7 @@ export {
326
324
  B as CustomBlockTypeSchema,
327
325
  q as CustomRuleSchema,
328
326
  U as DefaultBlockTypeSchema,
329
- E as DynamicContentListSchema,
327
+ P as DynamicContentListSchema,
330
328
  S as DynamicContentNodeSchema,
331
329
  v as DynamicContentSchema,
332
330
  O as EditorSchema,
@@ -335,14 +333,14 @@ export {
335
333
  F as FeaturesSchema,
336
334
  K as GuidoConfigSchema,
337
335
  A as IdentitySchema,
338
- P as LegacyRecommendationConfigSchema,
336
+ D as LegacyRecommendationConfigSchema,
339
337
  d as MessageType,
340
338
  L as PartnerSchema,
341
- l as ProductType,
339
+ r as ProductType,
342
340
  _ as RegexRuleSchema,
343
341
  j as RemoveRuleSchema,
344
342
  H as ReplaceRuleSchema,
345
- D as TemplateMigrationSchema,
343
+ E as TemplateMigrationSchema,
346
344
  M as TemplateSchema,
347
345
  x as UISchema
348
346
  };
@@ -1,43 +1,57 @@
1
- import { useActionsApi as T } from "./useActionsApi.js";
2
- import { useToaster as f } from "./useToaster.js";
3
- import { useTranslations as y } from "./useTranslations.js";
4
- import { ToasterTypeOptions as n } from "../enums/toaster.js";
5
- import { ref as v } from "vue";
6
- const E = 250, s = v({}), o = {}, j = () => {
7
- const { updateHtmlAndCss: l } = T(), { showToaster: p } = f(), i = y(), u = (e) => {
8
- s.value[e] === void 0 && (s.value = { ...s.value, [e]: "pending" });
9
- }, c = (e, t, r) => {
10
- s.value = { ...s.value, [e]: "applying" };
1
+ import { useActionsApi as d } from "./useActionsApi.js";
2
+ import { useConfig as D } from "./useConfig.js";
3
+ import { useToaster as h } from "./useToaster.js";
4
+ import { useTranslations as E } from "./useTranslations.js";
5
+ import { ToasterTypeOptions as f } from "../enums/toaster.js";
6
+ import { useDynamicContentStore as A } from "../stores/dynamic-content.js";
7
+ import { flattenDynamicContentList as S } from "../utils/genericUtil.js";
8
+ import { extractUsedDynamicContent as O } from "../utils/registerUsedDynamicContent.js";
9
+ import { ref as U } from "vue";
10
+ const w = 250, o = U({}), s = {}, u = /* @__PURE__ */ new Map(), z = () => {
11
+ const { updateHtmlAndCss: c } = d(), { showToaster: m } = h(), y = E(), { template: T } = D(), v = A(), g = (e, t) => {
12
+ const a = y(e);
13
+ return a === e ? t : a;
14
+ }, C = (e) => {
15
+ o.value[e] === void 0 && (o.value = { ...o.value, [e]: "pending" });
16
+ }, l = (e, t, a) => {
17
+ var n;
18
+ o.value = { ...o.value, [e]: "applying" };
11
19
  try {
12
- l(t, r), s.value = { ...s.value, [e]: "applied" }, p({
13
- type: n.Success,
14
- message: i("newsletter.ai-template-applied")
15
- });
16
- } catch (a) {
17
- s.value = { ...s.value, [e]: "failed" }, p({
18
- type: n.Error,
19
- message: a instanceof Error ? a.message : "Failed to apply template"
20
+ c(t, a), o.value = { ...o.value, [e]: "applied" };
21
+ try {
22
+ const r = S((n = T.value) == null ? void 0 : n.dynamicContentList), p = O(t, r);
23
+ p.length > 0 && v.registerDynamicContent(p);
24
+ } catch {
25
+ }
26
+ u.get(e) !== t && (u.set(e, t), m({
27
+ type: f.Success,
28
+ message: g("newsletter.ai-template-applied", "Template applied to the editor")
29
+ }));
30
+ } catch (r) {
31
+ o.value = { ...o.value, [e]: "failed" }, m({
32
+ type: f.Error,
33
+ message: r instanceof Error ? r.message : "Failed to apply template"
20
34
  });
21
35
  }
22
- }, m = (e) => {
23
- const t = o[e];
24
- t && (clearTimeout(t), delete o[e]);
36
+ }, i = (e) => {
37
+ const t = s[e];
38
+ t && (clearTimeout(t), delete s[e]);
25
39
  };
26
- return { applyStatus: s, markPending: u, applyTemplate: (e, t) => {
27
- t.html && (m(e), c(e, t.html, t.css ?? ""));
40
+ return { applyStatus: o, markPending: C, applyTemplate: (e, t) => {
41
+ t.html && (i(e), l(e, t.html, t.css ?? ""));
28
42
  }, applyTemplateDebounced: (e, t) => {
29
43
  if (!t.html)
30
44
  return;
31
- m(e);
32
- const { html: r } = t, a = t.css ?? "";
33
- o[e] = setTimeout(() => {
34
- delete o[e], c(e, r, a);
35
- }, E);
45
+ i(e);
46
+ const { html: a } = t, n = t.css ?? "";
47
+ s[e] = setTimeout(() => {
48
+ delete s[e], l(e, a, n);
49
+ }, w);
36
50
  } };
37
- }, k = () => {
38
- Object.values(o).forEach(clearTimeout), Object.keys(o).forEach((l) => delete o[l]), s.value = {};
51
+ }, G = () => {
52
+ Object.values(s).forEach(clearTimeout), Object.keys(s).forEach((c) => delete s[c]), o.value = {};
39
53
  };
40
54
  export {
41
- k as resetEmailTemplateApplier,
42
- j as useEmailTemplateApplier
55
+ G as resetEmailTemplateApplier,
56
+ z as useEmailTemplateApplier
43
57
  };
@@ -1,51 +1,32 @@
1
- import { useActionsApi as T } from "./useActionsApi.js";
2
- import { useConfig as k } from "./useConfig.js";
3
- import { useSaveStart as B, useSaveComplete as E } from "./useGuidoActions.js";
1
+ import { useActionsApi as H } from "./useActionsApi.js";
2
+ import { useConfig as y } from "./useConfig.js";
3
+ import { useSaveStart as w, useSaveComplete as k } from "./useGuidoActions.js";
4
4
  import { useSyncModuleExtractor as q } from "./useSyncModuleExtractor.js";
5
- import { ToasterTypeOptions as C } from "../enums/toaster.js";
6
- import { useStripoApi as D } from "../services/stripoApi.js";
7
- import { useTemplatePreparation as L } from "../utils/templatePreparation.js";
8
- import { useAllowlist as P } from "./useAllowlist.js";
9
- import { useHtmlValidator as U } from "./useHtmlValidator.js";
10
- import { useToaster as A } from "./useToaster.js";
11
- import { useCouponBlockValidator as M } from "./validators/useCouponBlockValidator.js";
12
- import { useLiquidValidator as h } from "./validators/useLiquidValidator.js";
13
- import { useUnsubscribeBlockValidator as F } from "./validators/useUnsubscribeBlockValidator.js";
14
- const $ = () => {
15
- const n = B(), l = E(), { validateHtml: c } = U(), { validateLiquidSyntax: d } = h(), { validateCouponBlockTags: m } = M(), { validateUnsubscribeBlockUniqueness: u, validateUnsubscribeBlockHasTemplate: p } = F(), { callbacks: e, isFeatureEnabled: a } = k(), { extractSyncModuleData: f } = q(), { setSyncModuleUnsubscriptionPages: v } = D(), { editorSave: S } = T(), { showToaster: b } = A(), { getBlockedDomains: w, resolveToast: V } = P();
16
- return { save: async (y = !1, s = !1) => {
17
- var r;
18
- n();
19
- const { prepareTemplateDetails: H } = L(), t = await H();
20
- if (!m(t.compiledHtml) || !u(t.compiledHtml) || !p(t.compiledHtml))
5
+ import { useStripoApi as C } from "../services/stripoApi.js";
6
+ import { useTemplatePreparation as E } from "../utils/templatePreparation.js";
7
+ import { useHtmlValidator as B } from "./useHtmlValidator.js";
8
+ import { useCouponBlockValidator as L } from "./validators/useCouponBlockValidator.js";
9
+ import { useLiquidValidator as P } from "./validators/useLiquidValidator.js";
10
+ import { useUnsubscribeBlockValidator as U } from "./validators/useUnsubscribeBlockValidator.js";
11
+ const K = () => {
12
+ const o = w(), s = k(), { validateHtml: r } = B(), { validateLiquidSyntax: l } = P(), { validateCouponBlockTags: n } = L(), { validateUnsubscribeBlockUniqueness: d, validateUnsubscribeBlockHasTemplate: c } = U(), { callbacks: i, isFeatureEnabled: u } = y(), { extractSyncModuleData: m } = q(), { setSyncModuleUnsubscriptionPages: p } = C(), { editorSave: v } = H();
13
+ return { save: async (f = !1, S = !1) => {
14
+ var a;
15
+ o();
16
+ const { prepareTemplateDetails: V } = E(), t = await V();
17
+ if (!n(t.compiledHtml) || !d(t.compiledHtml) || !c(t.compiledHtml))
21
18
  return;
22
- if (a("liquidSyntax")) {
23
- if (!await d(t.compiledHtml))
19
+ if (u("liquidSyntax")) {
20
+ if (!await l(t.compiledHtml))
24
21
  return;
25
- } else if (!await c(t.compiledHtml, t.dynamicContentList, !0))
22
+ } else if (!await r(t.compiledHtml, t.dynamicContentList, !0))
26
23
  return;
27
- if ((r = e.value) != null && r.externalValidation && !await e.value.externalValidation(t))
24
+ if ((a = i.value) != null && a.externalValidation && !await i.value.externalValidation(t) || !await v())
28
25
  return;
29
- if (a("allowlistEnabled")) {
30
- const i = await w(t.compiledHtml, t.css);
31
- if (i.length) {
32
- if (!s) {
33
- const o = await V(i);
34
- o != null && o.message && b({
35
- type: C.Warning,
36
- message: o.message,
37
- actionButton: o.actionButton
38
- });
39
- }
40
- return;
41
- }
42
- }
43
- if (!await S())
44
- return;
45
- const { unsubscribePayload: g, stripoModules: x } = f(t.rawHtml);
46
- return await v(g), t.modules = x, y || l({ ...t, silent: s }), t;
26
+ const { unsubscribePayload: b, stripoModules: x } = m(t.rawHtml);
27
+ return await p(b), t.modules = x, f || s({ ...t, silent: S }), t;
47
28
  } };
48
29
  };
49
30
  export {
50
- $ as useSave
31
+ K as useSave
51
32
  };
@@ -7,7 +7,6 @@
7
7
  */
8
8
  import type { DynamicContentNode } from '../generic';
9
9
  import type { SavedTemplateDetails } from '../stripo';
10
- import type { ActionButton } from '../toaster';
11
10
  import * as v from 'valibot';
12
11
  /**
13
12
  * Handler function for external validation before save
@@ -15,16 +14,6 @@ import * as v from 'valibot';
15
14
  * @returns Promise<boolean> - true if valid, false to cancel save
16
15
  */
17
16
  export type ExternalValidationHandler = (data: Omit<SavedTemplateDetails, 'metadata'>) => Promise<boolean>;
18
- /**
19
- * Content for the domain-allowlist block toaster. Guido self-serves this (see
20
- * useAllowlist): it resolves the user role via /get-user-role-and-email, builds the
21
- * settings deep-link, and pulls copy from window.trans. `actionButton.onClick` runs the
22
- * action (e.g. the "Add to allowlist" deep-link).
23
- */
24
- export interface AllowlistToastContent {
25
- message: string;
26
- actionButton?: ActionButton;
27
- }
28
17
  /**
29
18
  * Message type constants for email templates
30
19
  */
@@ -388,8 +377,6 @@ export declare const FeaturesSchema: v.ObjectSchema<{
388
377
  readonly liquidSyntax: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
389
378
  /** Enable autosave (3-min interval + tab-hide). User toggles on/off from the header. */
390
379
  readonly autosave: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
391
- /** Enable pre-save domain-allowlist validation (opt-in; Guido self-serves the block toaster) */
392
- readonly allowlistEnabled: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
393
380
  }, undefined>;
394
381
  /**
395
382
  * Default block types available in Stripo
@@ -777,8 +764,6 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
777
764
  readonly liquidSyntax: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
778
765
  /** Enable autosave (3-min interval + tab-hide). User toggles on/off from the header. */
779
766
  readonly autosave: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
780
- /** Enable pre-save domain-allowlist validation (opt-in; Guido self-serves the block toaster) */
781
- readonly allowlistEnabled: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
782
767
  }, undefined>, {}>;
783
768
  /** Block configuration */
784
769
  readonly blocks: v.OptionalSchema<v.ObjectSchema<{
@@ -96,7 +96,6 @@ export declare const useConfig: () => {
96
96
  modulesDisabled: boolean;
97
97
  liquidSyntax: boolean;
98
98
  autosave: boolean;
99
- allowlistEnabled: boolean;
100
99
  };
101
100
  blocks: {
102
101
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -228,7 +227,6 @@ export declare const useConfig: () => {
228
227
  modulesDisabled: boolean;
229
228
  liquidSyntax: boolean;
230
229
  autosave: boolean;
231
- allowlistEnabled: boolean;
232
230
  } | null>;
233
231
  blocks: import("vue").ComputedRef<{
234
232
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -101,7 +101,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
101
101
  modulesDisabled: boolean;
102
102
  liquidSyntax: boolean;
103
103
  autosave: boolean;
104
- allowlistEnabled: boolean;
105
104
  };
106
105
  blocks: {
107
106
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -239,7 +238,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
239
238
  modulesDisabled: boolean;
240
239
  liquidSyntax: boolean;
241
240
  autosave: boolean;
242
- allowlistEnabled: boolean;
243
241
  };
244
242
  blocks: {
245
243
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -377,7 +375,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
377
375
  modulesDisabled: boolean;
378
376
  liquidSyntax: boolean;
379
377
  autosave: boolean;
380
- allowlistEnabled: boolean;
381
378
  };
382
379
  blocks: {
383
380
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -515,7 +512,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
515
512
  modulesDisabled: boolean;
516
513
  liquidSyntax: boolean;
517
514
  autosave: boolean;
518
- allowlistEnabled: boolean;
519
515
  };
520
516
  blocks: {
521
517
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -653,7 +649,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
653
649
  modulesDisabled: boolean;
654
650
  liquidSyntax: boolean;
655
651
  autosave: boolean;
656
- allowlistEnabled: boolean;
657
652
  };
658
653
  blocks: {
659
654
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -791,7 +786,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
791
786
  modulesDisabled: boolean;
792
787
  liquidSyntax: boolean;
793
788
  autosave: boolean;
794
- allowlistEnabled: boolean;
795
789
  };
796
790
  blocks: {
797
791
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -929,7 +923,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
929
923
  modulesDisabled: boolean;
930
924
  liquidSyntax: boolean;
931
925
  autosave: boolean;
932
- allowlistEnabled: boolean;
933
926
  };
934
927
  blocks: {
935
928
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1067,7 +1060,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1067
1060
  modulesDisabled: boolean;
1068
1061
  liquidSyntax: boolean;
1069
1062
  autosave: boolean;
1070
- allowlistEnabled: boolean;
1071
1063
  };
1072
1064
  blocks: {
1073
1065
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1205,7 +1197,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1205
1197
  modulesDisabled: boolean;
1206
1198
  liquidSyntax: boolean;
1207
1199
  autosave: boolean;
1208
- allowlistEnabled: boolean;
1209
1200
  };
1210
1201
  blocks: {
1211
1202
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1343,7 +1334,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1343
1334
  modulesDisabled: boolean;
1344
1335
  liquidSyntax: boolean;
1345
1336
  autosave: boolean;
1346
- allowlistEnabled: boolean;
1347
1337
  };
1348
1338
  blocks: {
1349
1339
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1481,7 +1471,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1481
1471
  modulesDisabled: boolean;
1482
1472
  liquidSyntax: boolean;
1483
1473
  autosave: boolean;
1484
- allowlistEnabled: boolean;
1485
1474
  };
1486
1475
  blocks: {
1487
1476
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1619,7 +1608,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1619
1608
  modulesDisabled: boolean;
1620
1609
  liquidSyntax: boolean;
1621
1610
  autosave: boolean;
1622
- allowlistEnabled: boolean;
1623
1611
  };
1624
1612
  blocks: {
1625
1613
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1757,7 +1745,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1757
1745
  modulesDisabled: boolean;
1758
1746
  liquidSyntax: boolean;
1759
1747
  autosave: boolean;
1760
- allowlistEnabled: boolean;
1761
1748
  };
1762
1749
  blocks: {
1763
1750
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1895,7 +1882,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1895
1882
  modulesDisabled: boolean;
1896
1883
  liquidSyntax: boolean;
1897
1884
  autosave: boolean;
1898
- allowlistEnabled: boolean;
1899
1885
  };
1900
1886
  blocks: {
1901
1887
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -2033,7 +2019,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
2033
2019
  modulesDisabled: boolean;
2034
2020
  liquidSyntax: boolean;
2035
2021
  autosave: boolean;
2036
- allowlistEnabled: boolean;
2037
2022
  };
2038
2023
  blocks: {
2039
2024
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -2171,7 +2156,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
2171
2156
  modulesDisabled: boolean;
2172
2157
  liquidSyntax: boolean;
2173
2158
  autosave: boolean;
2174
- allowlistEnabled: boolean;
2175
2159
  };
2176
2160
  blocks: {
2177
2161
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -2309,7 +2293,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
2309
2293
  modulesDisabled: boolean;
2310
2294
  liquidSyntax: boolean;
2311
2295
  autosave: boolean;
2312
- allowlistEnabled: boolean;
2313
2296
  };
2314
2297
  blocks: {
2315
2298
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -2447,7 +2430,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
2447
2430
  modulesDisabled: boolean;
2448
2431
  liquidSyntax: boolean;
2449
2432
  autosave: boolean;
2450
- allowlistEnabled: boolean;
2451
2433
  };
2452
2434
  blocks: {
2453
2435
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -36,4 +36,21 @@ export declare const useDynamicContentStore: import("pinia").StoreDefinition<"gu
36
36
  }[];
37
37
  }, {
38
38
  setSelectedDynamicContent(dynamicContent: DynamicContent): void;
39
+ /**
40
+ * Bulk, append-only registration for dynamic content used by an
41
+ * AI-applied template (see useEmailTemplateApplier). Unlike
42
+ * `setSelectedDynamicContent`, this does NOT touch
43
+ * `selectedDynamicContent` (there is no single "active" picker
44
+ * selection here) — it only grows `selectedDynamicContentList`. The
45
+ * getter already removes duplicates, so a re-registration of the same
46
+ * entries (e.g. a re-apply) is harmless.
47
+ *
48
+ * `items` typically come straight from the host's own dynamic-content
49
+ * catalog (flattened `templateConfig.dynamicContentList`) — shallow-copy
50
+ * each one rather than storing the host's own object references, so
51
+ * Pinia/Vue's reactive conversion of this state can't turn a later
52
+ * in-place mutation of a "selected" item into an accidental write-back
53
+ * into the host's catalog.
54
+ */
55
+ registerDynamicContent(items: DynamicContent[]): void;
39
56
  }>;
@@ -0,0 +1,13 @@
1
+ import type { DynamicContent } from '@@/Types/generic';
2
+ export declare const extractUsedDynamicContent: (html: string, flattenedCatalog: DynamicContent[] | undefined | null) => DynamicContent[];
3
+ /**
4
+ * Dev-diagnostic sibling of `extractUsedDynamicContent`: the clean token names
5
+ * used in `html` that had NO catalog match (so were intentionally NOT
6
+ * registered). Wired into useEmailTemplateApplier's dev-gated `console.debug`
7
+ * so a developer can spot a neo↔guido personalization-vocabulary mismatch
8
+ * (see T-C2 report §8: neo may emit Atrium-schema keys the guido catalog
9
+ * doesn't recognize) in one look, without changing what actually gets
10
+ * registered. Same empty/undefined/null-catalog handling as
11
+ * `extractUsedDynamicContent` — never throws.
12
+ */
13
+ export declare const getUnmatchedDynamicContentTokens: (html: string, flattenedCatalog: DynamicContent[] | undefined | null) => string[];
@@ -1,6 +1,6 @@
1
1
  import { removeDuplicatesFromArray as n } from "../utils/arrayUtil.js";
2
2
  import { defineStore as a } from "pinia";
3
- const s = a("guidoDynamicContent", {
3
+ const c = a("guidoDynamicContent", {
4
4
  state: () => ({
5
5
  selectedDynamicContent: { text: "", value: "" },
6
6
  selectedDynamicContentList: []
@@ -8,6 +8,25 @@ const s = a("guidoDynamicContent", {
8
8
  actions: {
9
9
  setSelectedDynamicContent(t) {
10
10
  this.selectedDynamicContent = t, this.selectedDynamicContentList.push(t);
11
+ },
12
+ /**
13
+ * Bulk, append-only registration for dynamic content used by an
14
+ * AI-applied template (see useEmailTemplateApplier). Unlike
15
+ * `setSelectedDynamicContent`, this does NOT touch
16
+ * `selectedDynamicContent` (there is no single "active" picker
17
+ * selection here) — it only grows `selectedDynamicContentList`. The
18
+ * getter already removes duplicates, so a re-registration of the same
19
+ * entries (e.g. a re-apply) is harmless.
20
+ *
21
+ * `items` typically come straight from the host's own dynamic-content
22
+ * catalog (flattened `templateConfig.dynamicContentList`) — shallow-copy
23
+ * each one rather than storing the host's own object references, so
24
+ * Pinia/Vue's reactive conversion of this state can't turn a later
25
+ * in-place mutation of a "selected" item into an accidental write-back
26
+ * into the host's catalog.
27
+ */
28
+ registerDynamicContent(t) {
29
+ this.selectedDynamicContentList.push(...t.map((e) => ({ ...e })));
11
30
  }
12
31
  },
13
32
  getters: {
@@ -20,5 +39,5 @@ const s = a("guidoDynamicContent", {
20
39
  }
21
40
  });
22
41
  export {
23
- s as useDynamicContentStore
42
+ c as useDynamicContentStore
24
43
  };
@@ -0,0 +1,23 @@
1
+ import { DATA_ATTRIBUTE_REGEX as T } from "../enums/html-validator.js";
2
+ const d = /{{([a-zA-Z0-9_.\s]*)}}/gm, h = (n, e) => {
3
+ if (!e || e.length === 0)
4
+ return { matched: [], unmatchedTokens: [] };
5
+ const s = n.replace(T, "$1").match(d);
6
+ if (!s)
7
+ return { matched: [], unmatchedTokens: [] };
8
+ const u = new Map(
9
+ e.map((c) => [c.value.trim().toLowerCase(), c])
10
+ ), a = /* @__PURE__ */ new Set(), o = [], m = [];
11
+ return s.forEach((c) => {
12
+ const t = c.slice(2, -2).trim().toLowerCase();
13
+ if (t === "" || a.has(t))
14
+ return;
15
+ a.add(t);
16
+ const r = u.get(t);
17
+ r ? o.push(r) : m.push(t);
18
+ }), { matched: o, unmatchedTokens: m };
19
+ }, E = (n, e) => h(n, e).matched, k = (n, e) => h(n, e).unmatchedTokens;
20
+ export {
21
+ E as extractUsedDynamicContent,
22
+ k as getUnmatchedDynamicContentTokens
23
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.12.0-beta.66af948",
3
+ "version": "3.12.0-beta.6d6e76b",
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",
@@ -1,50 +0,0 @@
1
- import { useAllowlistApi as A } from "../services/allowlistApi.js";
2
- import { base64EncodeWithSpecialChars as p } from "../utils/base64.js";
3
- import { useTranslations as h } from "./useTranslations.js";
4
- import { useUserRole as D } from "./useUserRole.js";
5
- const f = /(?:https?:\/\/|www\.)[^\s"'<>()]+/gi, E = /&quot;\/\//gi, i = {
6
- MANAGE: "journey-builder.domain-allowlist-warning",
7
- NON_MANAGE: "settings.allow-list-warning-not-admin-architect",
8
- ADD_BUTTON: "settings.allow-list-warning-add-button"
9
- }, w = /* @__PURE__ */ new Set(), O = (n) => `/settings?openAddModal=true&type=domain&values=${p(n)}#security`, M = () => {
10
- const { checkDomain: n } = A(), { getIsManageUser: l } = D(), a = h(), d = (t, s) => {
11
- const c = `${t || ""} ${s || ""}`.replace(E, "https://").match(f) || [], e = /* @__PURE__ */ new Set();
12
- return c.forEach((r) => {
13
- const g = /^https?:\/\//i.test(r) ? r : `https://${r}`;
14
- try {
15
- const { hostname: u } = new URL(g);
16
- u && e.add(u.replace(/^www\./i, "").toLowerCase());
17
- } catch {
18
- }
19
- }), [...e];
20
- }, m = async (t) => {
21
- if (w.has(t))
22
- return !0;
23
- try {
24
- const s = await n(t);
25
- return s && w.add(t), s;
26
- } catch (s) {
27
- return console.error("[GUIDO_ALLOWLIST] isDomainAllowlisted failed", t, s), !0;
28
- }
29
- };
30
- return { getBlockedDomains: async (t, s) => {
31
- try {
32
- const o = d(t, s);
33
- return o.length ? (await Promise.all(
34
- o.map(async (e) => ({ domain: e, allowlisted: await m(e) }))
35
- )).filter((e) => !e.allowlisted).map((e) => e.domain) : [];
36
- } catch (o) {
37
- return console.error("[GUIDO_ALLOWLIST] getBlockedDomains failed", o), [];
38
- }
39
- }, resolveToast: async (t) => await l() ? {
40
- message: a(i.MANAGE),
41
- actionButton: {
42
- text: a(i.ADD_BUTTON),
43
- onClick: () => window.open(O(t.join(",")), "_blank")
44
- }
45
- } : { message: a(i.NON_MANAGE) } };
46
- };
47
- export {
48
- O as buildAllowlistSettingsUrl,
49
- M as useAllowlist
50
- };
@@ -1,12 +0,0 @@
1
- import { RoleEnums as t } from "../enums/roles.js";
2
- import { useAllowlistApi as s } from "../services/allowlistApi.js";
3
- let e = null, l = null;
4
- const c = () => {
5
- const { getUserRole: n } = s();
6
- return { getIsManageUser: async () => e !== null ? e : (l || (l = n().then((r) => (e = r === t.MANAGE_USERS, e)).catch((r) => (console.error("[GUIDO_ALLOWLIST] role fetch failed", r), !1)).finally(() => {
7
- l = null;
8
- })), l) };
9
- };
10
- export {
11
- c as useUserRole
12
- };
@@ -1,4 +0,0 @@
1
- var e = /* @__PURE__ */ ((r) => (r.MANAGE_USERS = "manage-users", r))(e || {});
2
- export {
3
- e as RoleEnums
4
- };
@@ -1,15 +0,0 @@
1
- import { useHttp as n } from "../composables/useHttp.js";
2
- import { base64EncodeWithSpecialChars as c } from "../utils/base64.js";
3
- const i = "/allowlist/check-single-item", r = "/get-user-role-and-email", u = () => {
4
- const { get: t } = n();
5
- return { checkDomain: async (e) => {
6
- const o = encodeURIComponent(c(`https://${e}`)), { data: s } = await t(`${i}?item=${o}&type=domain`);
7
- return s.type === "success";
8
- }, getUserRole: async () => {
9
- const { data: e } = await t(r);
10
- return e == null ? void 0 : e.role;
11
- } };
12
- };
13
- export {
14
- u as useAllowlistApi
15
- };
@@ -1,18 +0,0 @@
1
- import type { AllowlistToastContent } from '@@/Types/config/schemas';
2
- /**
3
- * Builds the "Add to allowlist" InOne Settings deep-link (Security tab, add-domain modal
4
- * prefilled). The route is identical across InOne products, so Guido builds it generically.
5
- * @param value - domain(s) to prefill; base64-encoded into the `values` query param.
6
- */
7
- export declare const buildAllowlistSettingsUrl: (value: string) => string;
8
- /**
9
- * Domain-allowlist feature composable. Extracts every external domain from the compiled
10
- * HTML/CSS and asks the backend (via allowlistApi) whether each is allowlisted, so an
11
- * un-allowlisted link can block the save BEFORE anything is persisted; and builds the
12
- * role-gated block-toaster content Guido renders. Gated by `features.allowlistEnabled` in
13
- * useSave — consumers only flip the flag. SD-143197.
14
- */
15
- export declare const useAllowlist: () => {
16
- getBlockedDomains: (html: string, css: string) => Promise<string[]>;
17
- resolveToast: (blockedDomains: string[]) => Promise<AllowlistToastContent>;
18
- };
@@ -1,9 +0,0 @@
1
- /**
2
- * Resolves whether the current user may manage the partner's domain allowlist, via the shared
3
- * InOne endpoint GET /get-user-role-and-email (allowlistApi.getUserRole). Fail-open: on any
4
- * error the user is treated as non-manage (message-only toaster, no "Add to allowlist" deep-link
5
- * they may not be able to use).
6
- */
7
- export declare const useUserRole: () => {
8
- getIsManageUser: () => Promise<boolean>;
9
- };
@@ -1,9 +0,0 @@
1
- /**
2
- * Insider user-role aliases — the kebab-case wire values returned by
3
- * GET /get-user-role-and-email (the same set honey-badger's RoleEnums defines).
4
- * Only the manage-user role is needed in Guido: it gates the "Add to allowlist"
5
- * action in the domain-allowlist block toaster. SD-143197.
6
- */
7
- export declare enum RoleEnums {
8
- MANAGE_USERS = "manage-users"
9
- }
@@ -1,10 +0,0 @@
1
- /**
2
- * Backend calls behind the domain-allowlist feature. Thin transport layer: it owns the
3
- * endpoints, encoding, and response shape, and lets callers (useAllowlist / useUserRole) apply
4
- * the caching + fail-open policy — mirroring how validators/saveAsTemplate delegates its check
5
- * to templateLibraryApi.
6
- */
7
- export declare const useAllowlistApi: () => {
8
- checkDomain: (domain: string) => Promise<boolean>;
9
- getUserRole: () => Promise<string | undefined>;
10
- };