@useinsider/guido 3.3.1-beta.11641c6 → 3.4.0-beta.0ec3bc7

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 (38) hide show
  1. package/dist/@types/config/schemas.js +1 -1
  2. package/dist/components/Guido.vue.js +1 -1
  3. package/dist/components/Guido.vue2.js +42 -40
  4. package/dist/components/organisms/extensions/recommendation/FilterItem.vue.js +9 -11
  5. package/dist/components/organisms/extensions/recommendation/FilterItem.vue2.js +70 -35
  6. package/dist/components/organisms/header/MiddleSlot.vue.js +7 -7
  7. package/dist/composables/useCortexBlueprintBridge.js +66 -0
  8. package/dist/composables/useEmailTemplateApplier.js +41 -0
  9. package/dist/composables/useGuidoStateBridge.js +48 -0
  10. package/dist/composables/useHtmlValidator.js +41 -36
  11. package/dist/composables/useResponsivePreview.js +1 -1
  12. package/dist/config/compiler/recommendationCompilerRules.js +10 -10
  13. package/dist/config/migrator/radioButtonMigrator.js +30 -29
  14. package/dist/config/migrator/recommendation/htmlBuilder.js +65 -65
  15. package/dist/enums/extensions/recommendationBlock.js +33 -32
  16. package/dist/extensions/Blocks/RadioButton/template.js +6 -6
  17. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +30 -21
  18. package/dist/extensions/Blocks/Recommendation/templates/grid/elementRenderer.js +10 -10
  19. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +3 -3
  20. package/dist/extensions/Blocks/Recommendation/templates/list/elementRenderer.js +5 -5
  21. package/dist/extensions/Blocks/Recommendation/utils/filterUtil.js +26 -13
  22. package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +33 -0
  23. package/dist/guido.css +1 -1
  24. package/dist/node_modules/valibot/dist/index.js +252 -329
  25. package/dist/package.json.js +1 -1
  26. package/dist/services/unsubscribeApi.js +6 -6
  27. package/dist/src/composables/useCortexBlueprintBridge.d.ts +25 -0
  28. package/dist/src/composables/useEmailTemplateApplier.d.ts +21 -0
  29. package/dist/src/composables/useGuidoStateBridge.d.ts +22 -0
  30. package/dist/src/enums/extensions/recommendationBlock.d.ts +1 -0
  31. package/dist/src/extensions/Blocks/RadioButton/template.d.ts +1 -1
  32. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +7 -1
  33. package/dist/src/extensions/Blocks/Recommendation/utils/filterUtil.d.ts +2 -0
  34. package/dist/src/extensions/Blocks/Recommendation/utils/filterUtil.test.d.ts +1 -0
  35. package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +21 -0
  36. package/dist/src/stores/guido-email-editor.d.ts +41 -0
  37. package/dist/stores/guido-email-editor.js +20 -0
  38. package/package.json +5 -4
@@ -1,4 +1,4 @@
1
- const o = { stripo: { version: "2.62.0" } }, s = {
1
+ const o = { stripo: { version: "2.64.0" } }, s = {
2
2
  guido: o
3
3
  };
4
4
  export {
@@ -1,13 +1,13 @@
1
1
  import { useHttp as t } from "../composables/useHttp.js";
2
- import { useToaster as n } from "../composables/useToaster.js";
2
+ import { useToaster as a } from "../composables/useToaster.js";
3
3
  const u = () => {
4
- const { get: r } = t(), { handleError: s } = n();
4
+ const { get: e } = t(), { handleError: s } = a();
5
5
  return { getUnsubscribePages: async () => {
6
6
  try {
7
- const { data: e = [] } = await r("/unsubscribe-pages/get-all");
8
- return e;
9
- } catch (e) {
10
- return s(e, "Failed to fetch unsubscribe pages"), [];
7
+ const { data: r } = await e("/unsubscribe-pages/get-all");
8
+ return Array.isArray(r) ? r : [];
9
+ } catch (r) {
10
+ return s(r, "Failed to fetch unsubscribe pages"), [];
11
11
  }
12
12
  } };
13
13
  };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Bridges cortex-fe's chat store to Guido's Stripo editor.
3
+ *
4
+ * cortex-fe is a Module Federation MFE that registers `defineStore('chat', …)`
5
+ * on the host's shared (singleton) Pinia. Guido — bundled inside MFE consumers
6
+ * that also share that pinia — reads the same store at runtime via
7
+ * `getActivePinia()._s.get('chat')`. No build-time dep on cortex-fe.
8
+ *
9
+ * The bridge handles two segment shapes:
10
+ *
11
+ * - `blueprint` segments with `blueprintType === 'email_template'` are
12
+ * applied to the Stripo editor (immediate on first sighting, debounced on
13
+ * update, identical-html no-ops).
14
+ * - `error` segments (and message-level `isError` / `isCancelled`) trigger
15
+ * a localized toaster.
16
+ *
17
+ * In dev (`import.meta.env.DEV`) every observed segment + message-level flag
18
+ * change is also `console.debug`-logged with the prefix `[guido:cortex]` so a
19
+ * developer can watch the agent stream in real time. In production this is
20
+ * gated behind `localStorage.guido:debug:ai === '1'`.
21
+ *
22
+ * If cortex-fe isn't loaded the chat store is undefined and the bridge is a
23
+ * no-op (intentional — Guido must still work standalone).
24
+ */
25
+ export declare const useCortexBlueprintBridge: () => void;
@@ -0,0 +1,21 @@
1
+ type ApplyStatus = 'pending' | 'applying' | 'applied' | 'failed';
2
+ /**
3
+ * Applies email_template blueprints from the chat agent to the Stripo editor.
4
+ *
5
+ * - blueprint_create + manual Apply click: immediate.
6
+ * - blueprint_update: debounced 250 ms trailing so rapid mid-stream updates
7
+ * don't thrash updateHtmlAndCss.
8
+ */
9
+ export declare const useEmailTemplateApplier: () => {
10
+ applyStatus: import("vue").Ref<Record<string, ApplyStatus>>;
11
+ applyTemplate: (blueprintId: string, data: {
12
+ html?: string;
13
+ css?: string;
14
+ }) => void;
15
+ applyTemplateDebounced: (blueprintId: string, data: {
16
+ html?: string;
17
+ css?: string;
18
+ }) => void;
19
+ };
20
+ export declare const resetEmailTemplateApplier: () => void;
21
+ export {};
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Outbound bridge — publishes the current editor's html/css to the shared
3
+ * Pinia store `guidoEmailEditor` so cortex-fe can read it at chat-stream
4
+ * submit time and forward it as `clientState.editor`. This is what enables
5
+ * sub-case 1.3 (refine an already-loaded template via the email-agent).
6
+ *
7
+ * The bridge writes on three triggers:
8
+ *
9
+ * 1. Stripo finishes initializing — first snapshot.
10
+ * 2. Editor `hasChanges` flips to true — debounced 500 ms so a streaming
11
+ * Stripo edit doesn't thrash the store.
12
+ * 3. Editor `hasChanges` flips back to false (post-save / autosave) —
13
+ * immediate, since this is the canonical "saved" snapshot.
14
+ *
15
+ * `getTemplateData()` is a Stripo iframe call; it must not run before
16
+ * `isStripoInitialized` is true. The bridge guards against that.
17
+ *
18
+ * If cortex-fe isn't loaded the store still gets written — that's fine;
19
+ * the store has zero overhead and any future reader will find consistent
20
+ * state. The bridge is a one-way pipe with no consumer dependency.
21
+ */
22
+ export declare const useGuidoStateBridge: () => void;
@@ -15,6 +15,7 @@ export declare const PriceAttributes: string[];
15
15
  export declare const currencyLocationMaps: TextValueObject[];
16
16
  export declare const currencyOperators: TextValueObject[];
17
17
  export declare const currencyDecimalCounts: TextValueObject[];
18
+ export declare const OP_ANY_OF = "||";
18
19
  export declare const operatorOptionsForStrings: TextValueObject[];
19
20
  export declare const operatorOptionsForArrayOfStrings: TextValueObject[];
20
21
  export declare const operatorOptionsForNumbers: TextValueObject[];
@@ -1,4 +1,4 @@
1
- declare const migrationTemplate = "\n <td\n align=\"left\"\n esd-extension-block-id=\"radio-button-block\"\n esd-handler-name=\"esd-extension-RadioButtonBlock\"\n class=\"\n radio-button\n radio-button-v2\n esd-block-ra\n esd-radio-button-block\n esd-extension-block\n es-p10t\n es-p10b\n es-p30r\n es-p30l\"\n >\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n <td align=\"left\" width=\"70%\" style=\"vertical-align: top;\">\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n {-{-TITLE-}-}\n </tr>\n <tr>\n {-{-DESCRIPTION-}-}\n </tr>\n </tbody>\n </table>\n </td>\n <td align=\"right\" width=\"30%\" style=\"vertical-align: middle;\">\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n <td width=\"50%\">\n <table width=\"100%\">\n <tr>\n <td width=\"24\">\n <input\n type=\"radio\"\n id=\"radioYes\"\n name=\"unsubscribe\"\n data-cke-editable=\"1\"\n style=\"margin: 0px; vertical-align: middle;\">\n </td>\n {-{-YES-}-}\n </tr>\n </table>\n </td>\n <td width=\"50%\">\n <table width=\"100%\">\n <tr>\n <td width=\"24\">\n <input\n type=\"radio\"\n id=\"radioNo\"\n name=\"unsubscribe\"\n data-cke-editable=\"1\"\n style=\"margin: 0px; vertical-align: middle;\">\n </td>\n {-{-NO-}-}\n </tr>\n </table>\n </td>\n </tr>\n </tbody>\n </table>\n </td>\n </tr>\n </tbody>\n </table>\n </td>\n";
1
+ declare const migrationTemplate = "\n <td\n align=\"left\"\n esd-extension-block-id=\"radio-button-block\"\n esd-handler-name=\"esd-extension-RadioButtonBlock\"\n class=\"\n radio-button-block\n radio-button-v2\n esd-block-ra\n esd-radio-button-block\n esd-extension-block\n es-p10t\n es-p10b\n es-p30r\n es-p30l\"\n >\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n <td align=\"left\" width=\"70%\" style=\"vertical-align: top;\">\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n {-{-TITLE-}-}\n </tr>\n <tr>\n {-{-DESCRIPTION-}-}\n </tr>\n </tbody>\n </table>\n </td>\n <td align=\"right\" width=\"30%\" style=\"vertical-align: middle;\">\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n <td width=\"50%\">\n <table width=\"100%\">\n <tr>\n <td width=\"24\">\n <input\n type=\"radio\"\n id=\"radioYes\"\n name=\"unsubscribe\"\n data-cke-editable=\"1\"\n style=\"margin: 0px; vertical-align: middle;\">\n </td>\n {-{-YES-}-}\n </tr>\n </table>\n </td>\n <td width=\"50%\">\n <table width=\"100%\">\n <tr>\n <td width=\"24\">\n <input\n type=\"radio\"\n id=\"radioNo\"\n name=\"unsubscribe\"\n data-cke-editable=\"1\"\n style=\"margin: 0px; vertical-align: middle;\">\n </td>\n {-{-NO-}-}\n </tr>\n </table>\n </td>\n </tr>\n </tbody>\n </table>\n </td>\n </tr>\n </tbody>\n </table>\n </td>\n";
2
2
  /**
3
3
  * @returns The template for the default checkbox block
4
4
  */
@@ -1,5 +1,5 @@
1
1
  import type { Orientation, Languages, Currency, NumericSeparator, FiltersResponse, Filter, RecommendationProduct } from '@@/Types/recommendation';
2
- interface PerBlockConfigs {
2
+ export interface PerBlockConfigs {
3
3
  cardsInRow: number;
4
4
  currencySettings: {
5
5
  name: string;
@@ -272,6 +272,12 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
272
272
  deleteFilter(filter: Filter): void;
273
273
  addFilter(filter: Filter): void;
274
274
  generateFilterQuery(): string;
275
+ /**
276
+ * Validation-only check invoked at save-CTA time. Defined as an action
277
+ * (not a getter) so reading it does not register reactive tracking on
278
+ * every block's recommendationConfigs across user edits.
279
+ */
280
+ hasInvalidBlock(): boolean;
275
281
  fetchRecommendationProducts(): Promise<void>;
276
282
  _doFetchProducts(): Promise<void>;
277
283
  }>;
@@ -1,4 +1,6 @@
1
1
  import type { Filter } from '@@/Types/recommendation';
2
+ export declare function safeDecodeURIComponent(value: string): string;
3
+ export declare function parseTagList(value: string): string[];
2
4
  /**
3
5
  * Generates the complete query with outer group operators
4
6
  * @param filters Array of Filter objects
@@ -0,0 +1,21 @@
1
+ import type { PerBlockConfigs } from '../store/recommendation';
2
+ import type { Currency, Languages } from '@@/Types/recommendation';
3
+ /**
4
+ * Structural slice of the recommendation extension store that descriptors may read.
5
+ * Add new fields here when a future descriptor needs them.
6
+ */
7
+ export interface ExtensionStoreSlice {
8
+ languages: Languages;
9
+ currencyList: Currency[];
10
+ }
11
+ interface RequiredField {
12
+ key: string;
13
+ getValue: (config: PerBlockConfigs) => string;
14
+ getAvailableOptions?: (store: ExtensionStoreSlice) => string[];
15
+ condition?: (config: PerBlockConfigs) => boolean;
16
+ }
17
+ export declare const REQUIRED_RECOMMENDATION_FIELDS: RequiredField[];
18
+ export declare const RecommendationRequiredFieldsKey = "newsletter.recommendation-fill-required-fields";
19
+ export declare function getInvalidFields(config: PerBlockConfigs, store: ExtensionStoreSlice): string[];
20
+ export declare function isConfigValid(config: PerBlockConfigs, store: ExtensionStoreSlice): boolean;
21
+ export {};
@@ -0,0 +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", {
16
+ /** Current Stripo HTML — stripe tables only, no DOCTYPE/wrapper. */
17
+ html: string;
18
+ /** Current Stripo CSS — es-p* utility classes used by the html. */
19
+ css: string;
20
+ /** Wall-clock ms when html/css were last written by the bridge. */
21
+ lastUpdatedAt: number;
22
+ /** Template id from the editor config, for cortex-fe to scope per-template. */
23
+ templateId: string;
24
+ }, {
25
+ /** True once the bridge has published at least one snapshot. */
26
+ hasSnapshot: (state: {
27
+ html: string;
28
+ css: string;
29
+ lastUpdatedAt: number;
30
+ 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;
41
+ }, {}>;
@@ -0,0 +1,20 @@
1
+ import { defineStore as e } from "pinia";
2
+ const d = e("guidoEmailEditor", {
3
+ state: () => ({
4
+ /** Current Stripo HTML — stripe tables only, no DOCTYPE/wrapper. */
5
+ html: "",
6
+ /** Current Stripo CSS — es-p* utility classes used by the html. */
7
+ css: "",
8
+ /** Wall-clock ms when html/css were last written by the bridge. */
9
+ lastUpdatedAt: 0,
10
+ /** Template id from the editor config, for cortex-fe to scope per-template. */
11
+ templateId: ""
12
+ }),
13
+ getters: {
14
+ /** True once the bridge has published at least one snapshot. */
15
+ hasSnapshot: (t) => t.lastUpdatedAt > 0 && t.html !== ""
16
+ }
17
+ });
18
+ export {
19
+ d as useGuidoEmailEditorStore
20
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.3.1-beta.11641c6",
3
+ "version": "3.4.0-beta.0ec3bc7",
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",
@@ -39,7 +39,7 @@
39
39
  "@vueuse/core": "11.3.0",
40
40
  "lodash-es": "4.17.21",
41
41
  "pinia": "2.3.1",
42
- "valibot": "1.1.0",
42
+ "valibot": "1.2.0",
43
43
  "vite": "6.3.5",
44
44
  "vue": "2.7.14"
45
45
  },
@@ -61,7 +61,6 @@
61
61
  "@typescript-eslint/parser": "7.18.0",
62
62
  "@useinsider/eslint-config": "1.5.3",
63
63
  "@vitejs/plugin-vue2": "2.3.1",
64
- "@vue/eslint-config-typescript": "12.0.0",
65
64
  "eslint": "8.57.1",
66
65
  "eslint-config-airbnb-base": "15.0.0",
67
66
  "eslint-config-airbnb-typescript": "18.0.0",
@@ -82,6 +81,8 @@
82
81
  "vue-tsc": "2.2.10"
83
82
  },
84
83
  "overrides": {
84
+ "axios": "1.8.2",
85
+ "flatted": "3.4.2",
85
86
  "micromatch": "4.0.8",
86
87
  "path-to-regexp": "6.3.0"
87
88
  },
@@ -90,7 +91,7 @@
90
91
  },
91
92
  "guido": {
92
93
  "stripo": {
93
- "version": "2.62.0"
94
+ "version": "2.64.0"
94
95
  }
95
96
  }
96
97
  }