@modainteract/moda-interact-shared 5.6.0 → 5.7.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 (30) hide show
  1. package/dist/{chunk-QVPEX7KY.js → chunk-GCCT2BDE.js} +4 -4
  2. package/dist/chunk-QFUK7FIO.js +16 -0
  3. package/dist/chunk-QFUK7FIO.js.map +1 -0
  4. package/dist/{chunk-S42O2OCG.js → chunk-WF2BDUPZ.js} +428 -320
  5. package/dist/chunk-WF2BDUPZ.js.map +1 -0
  6. package/dist/chunk-WHZAAF2Q.js +25 -0
  7. package/dist/chunk-WHZAAF2Q.js.map +1 -0
  8. package/dist/{chunk-KIHGDO35.js → chunk-WK7QSBHJ.js} +3 -3
  9. package/dist/commerce/index.d.ts +33 -5
  10. package/dist/commerce/index.js +17 -16
  11. package/dist/commerce/index.js.map +1 -1
  12. package/dist/commerce/model/node.d.ts +3 -3
  13. package/dist/commerce/model/node.js +3 -3
  14. package/dist/commerce/outreach/index.d.ts +1094 -0
  15. package/dist/commerce/outreach/index.js +1355 -0
  16. package/dist/commerce/outreach/index.js.map +1 -0
  17. package/dist/commerce/presentation/index.d.ts +103 -6
  18. package/dist/commerce/presentation/index.js +80 -13
  19. package/dist/commerce/presentation/index.js.map +1 -1
  20. package/dist/commerce/runner/index.d.ts +4 -4
  21. package/dist/commerce/runner/index.js +12 -28
  22. package/dist/commerce/runner/index.js.map +1 -1
  23. package/dist/{product-context-D3FuI6ah.d.ts → product-context-Bh74WGOo.d.ts} +1 -1
  24. package/dist/recovery-offer-proof.js +2 -2
  25. package/dist/{response-Cs4zC3d3.d.ts → response-DFDEw4K0.d.ts} +115 -1
  26. package/dist/{types-ByoKuP90.d.ts → types-vIMrj5J4.d.ts} +2 -2
  27. package/package.json +12 -6
  28. package/dist/chunk-S42O2OCG.js.map +0 -1
  29. /package/dist/{chunk-QVPEX7KY.js.map → chunk-GCCT2BDE.js.map} +0 -0
  30. /package/dist/{chunk-KIHGDO35.js.map → chunk-WK7QSBHJ.js.map} +0 -0
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  CommerceFinalResponseSchema,
3
+ CommerceProductAttributesSchema,
4
+ CommerceProductDescriptionSchema,
3
5
  CommerceProductOptionsSchema,
4
6
  CommerceProductSchema,
5
7
  CommerceProductSelectedOptionsSchema
6
- } from "../../chunk-S42O2OCG.js";
7
- import "../../chunk-QVPEX7KY.js";
8
- import "../../chunk-AUS3WQIW.js";
8
+ } from "../../chunk-WF2BDUPZ.js";
9
+ import "../../chunk-GCCT2BDE.js";
9
10
  import {
10
11
  MODA_SUPPORTED_LANGUAGE_TAGS,
11
12
  ModaSupportedLanguageTagSchema,
@@ -14,12 +15,72 @@ import {
14
15
  resolveModaConfigurationLocale,
15
16
  validateIcuCatalogue
16
17
  } from "../../chunk-4KSODB2R.js";
18
+ import "../../chunk-AUS3WQIW.js";
19
+
20
+ // src/commerce/presentation/facts.ts
21
+ import { z } from "zod";
22
+
23
+ // src/commerce/presentation/fact-messages.ts
24
+ var labels = {
25
+ "zh-Hans": ["\u5546\u54C1\u8BE6\u60C5\u4E0D\u53EF\u7528\u3002", "\u5546\u54C1\u4FE1\u606F\u4E0D\u5B8C\u6574\u3002", "\u6240\u9009\u9009\u9879"],
26
+ "zh-Hant": ["\u5546\u54C1\u8A73\u60C5\u7121\u6CD5\u53D6\u5F97\u3002", "\u5546\u54C1\u8CC7\u8A0A\u4E0D\u5B8C\u6574\u3002", "\u6240\u9078\u9078\u9805"],
27
+ cs: ["Podrobnosti produktu nejsou dostupn\xE9.", "Informace o produktu jsou ne\xFApln\xE9.", "Vybran\xE9 mo\u017Enosti"],
28
+ da: ["Produktoplysninger er ikke tilg\xE6ngelige.", "Produktoplysningerne er ufuldst\xE6ndige.", "Valgte muligheder"],
29
+ nl: ["Productdetails zijn niet beschikbaar.", "De productinformatie is onvolledig.", "Geselecteerde opties"],
30
+ en: ["Product details are unavailable.", "Product information is incomplete.", "Selected options"],
31
+ fi: ["Tuotetietoja ei ole saatavilla.", "Tuotetiedot ovat puutteelliset.", "Valitut vaihtoehdot"],
32
+ fr: ["Les d\xE9tails du produit sont indisponibles.", "Les informations du produit sont incompl\xE8tes.", "Options s\xE9lectionn\xE9es"],
33
+ de: ["Produktdetails sind nicht verf\xFCgbar.", "Die Produktinformationen sind unvollst\xE4ndig.", "Ausgew\xE4hlte Optionen"],
34
+ it: ["I dettagli del prodotto non sono disponibili.", "Le informazioni sul prodotto sono incomplete.", "Opzioni selezionate"],
35
+ ja: ["\u5546\u54C1\u8A73\u7D30\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002", "\u5546\u54C1\u60C5\u5831\u306F\u5B8C\u5168\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002", "\u9078\u629E\u3057\u305F\u30AA\u30D7\u30B7\u30E7\u30F3"],
36
+ ko: ["\uC81C\uD488 \uC138\uBD80 \uC815\uBCF4\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "\uC81C\uD488 \uC815\uBCF4\uAC00 \uC644\uC804\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "\uC120\uD0DD\uD55C \uC635\uC158"],
37
+ nb: ["Produktdetaljer er ikke tilgjengelige.", "Produktinformasjonen er ufullstendig.", "Valgte alternativer"],
38
+ pl: ["Szczeg\xF3\u0142y produktu s\u0105 niedost\u0119pne.", "Informacje o produkcie s\u0105 niepe\u0142ne.", "Wybrane opcje"],
39
+ "pt-BR": ["Os detalhes do produto est\xE3o indispon\xEDveis.", "As informa\xE7\xF5es do produto est\xE3o incompletas.", "Op\xE7\xF5es selecionadas"],
40
+ "pt-PT": ["Os detalhes do produto est\xE3o indispon\xEDveis.", "As informa\xE7\xF5es do produto est\xE3o incompletas.", "Op\xE7\xF5es selecionadas"],
41
+ es: ["Los detalles del producto no est\xE1n disponibles.", "La informaci\xF3n del producto est\xE1 incompleta.", "Opciones seleccionadas"],
42
+ sv: ["Produktinformation \xE4r inte tillg\xE4nglig.", "Produktinformationen \xE4r ofullst\xE4ndig.", "Valda alternativ"],
43
+ th: ["\u0E44\u0E21\u0E48\u0E21\u0E35\u0E23\u0E32\u0E22\u0E25\u0E30\u0E40\u0E2D\u0E35\u0E22\u0E14\u0E2A\u0E34\u0E19\u0E04\u0E49\u0E32", "\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E2A\u0E34\u0E19\u0E04\u0E49\u0E32\u0E44\u0E21\u0E48\u0E04\u0E23\u0E1A\u0E16\u0E49\u0E27\u0E19", "\u0E15\u0E31\u0E27\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E17\u0E35\u0E48\u0E40\u0E25\u0E37\u0E2D\u0E01"],
44
+ tr: ["\xDCr\xFCn ayr\u0131nt\u0131lar\u0131 mevcut de\u011Fil.", "\xDCr\xFCn bilgileri eksik.", "Se\xE7ilen se\xE7enekler"]
45
+ };
46
+ var productFactMessages = Object.freeze(labels);
47
+
48
+ // src/commerce/presentation/facts.ts
49
+ var CommerceProductFactSchema = z.strictObject({ productId: z.string().min(1).max(128), variantId: z.string().min(1).max(128).nullable(), title: z.string().min(1).max(512), description: CommerceProductDescriptionSchema, attributes: CommerceProductAttributesSchema, options: CommerceProductOptionsSchema, selectedOptions: CommerceProductSelectedOptionsSchema });
50
+ function verifyCommerceProductFacts(selection, currentProducts) {
51
+ const parsed = z.array(z.strictObject({ productId: z.string().min(1).max(128), variantId: z.string().min(1).max(128).nullable() })).max(3).safeParse(selection);
52
+ if (!parsed.success || new Set(selection.map((s) => JSON.stringify([s.productId, s.variantId]))).size !== selection.length) return { kind: "limitation", reason: "INVALID_SELECTION" };
53
+ const facts = [];
54
+ for (const selected of parsed.data) {
55
+ const matches = currentProducts.filter((p) => p && typeof p === "object" && p.productId === selected.productId && p.variantId === selected.variantId);
56
+ if (matches.length !== 1) return { kind: "limitation", reason: "PRODUCT_NOT_FOUND" };
57
+ const product2 = CommerceProductSchema.safeParse(matches[0]);
58
+ if (!product2.success) return { kind: "limitation", reason: "PRODUCT_INVALID" };
59
+ facts.push({ productId: product2.data.productId, variantId: product2.data.variantId, title: product2.data.title, description: product2.data.description ?? { status: "PARTIAL", text: "" }, attributes: product2.data.attributes ?? { status: "PARTIAL", items: [] }, options: product2.data.options ?? { status: "PARTIAL", items: [] }, selectedOptions: product2.data.selectedOptions ?? [] });
60
+ }
61
+ return { kind: "verified", productFacts: facts };
62
+ }
63
+ function renderCommerceProductFacts(facts, locale) {
64
+ const [unavailable, incomplete, selected] = productFactMessages[locale];
65
+ if (!facts.length) return unavailable;
66
+ return facts.map((f) => {
67
+ const lines = [];
68
+ if (f.description.text) lines.push(f.description.text);
69
+ const selectedLines = [...new Set(f.selectedOptions.map((o) => `${o.name}: ${o.value}`))];
70
+ const factLines = [...f.attributes.items.map((a) => `${a.name}: ${a.values.length ? a.values.join(", ") : unavailable}`), ...f.options.items.filter((o) => !f.attributes.items.some((a) => a.name === o.name && JSON.stringify(a.values) === JSON.stringify(o.values))).map((o) => `${o.name}: ${o.values.length ? o.values.join(", ") : unavailable}`)];
71
+ lines.push(...new Set(factLines.filter((line) => !selectedLines.includes(line))));
72
+ if (selectedLines.length) lines.push(`${selected}:`, ...selectedLines);
73
+ if (!f.description.text && !f.attributes.items.some((a) => a.values.length) && !f.options.items.some((o) => o.values.length) && !selectedLines.length) lines.push(unavailable);
74
+ if ([f.description.status, f.attributes.status, f.options.status].includes("PARTIAL")) lines.push(incomplete);
75
+ return [f.title, ...lines].join("\n");
76
+ }).join("\n\n");
77
+ }
17
78
 
18
79
  // src/commerce/presentation/schemas.ts
19
- import { z as z2 } from "zod";
80
+ import { z as z3 } from "zod";
20
81
 
21
82
  // src/commerce/presentation/option-messages.ts
22
- var labels = {
83
+ var labels2 = {
23
84
  "zh-Hans": ["\u9009\u9879\u8BE6\u60C5\u4E0D\u53EF\u7528\u3002", "\u9009\u9879\u5217\u8868\u4E0D\u5B8C\u6574\u3002", "\u6240\u9009\u9009\u9879"],
24
85
  "zh-Hant": ["\u9078\u9805\u8A73\u60C5\u7121\u6CD5\u53D6\u5F97\u3002", "\u9078\u9805\u6E05\u55AE\u4E0D\u5B8C\u6574\u3002", "\u6240\u9078\u9078\u9805"],
25
86
  cs: ["Podrobnosti mo\u017Enost\xED nejsou dostupn\xE9.", "Seznam mo\u017Enost\xED nen\xED \xFApln\xFD.", "Vybran\xE9 mo\u017Enosti"],
@@ -41,7 +102,7 @@ var labels = {
41
102
  th: ["\u0E44\u0E21\u0E48\u0E21\u0E35\u0E23\u0E32\u0E22\u0E25\u0E30\u0E40\u0E2D\u0E35\u0E22\u0E14\u0E15\u0E31\u0E27\u0E40\u0E25\u0E37\u0E2D\u0E01", "\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E15\u0E31\u0E27\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E21\u0E48\u0E04\u0E23\u0E1A\u0E16\u0E49\u0E27\u0E19", "\u0E15\u0E31\u0E27\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E17\u0E35\u0E48\u0E40\u0E25\u0E37\u0E2D\u0E01"],
42
103
  tr: ["Se\xE7enek ayr\u0131nt\u0131lar\u0131 mevcut de\u011Fil.", "Se\xE7enek listesi eksik.", "Se\xE7ilen se\xE7enekler"]
43
104
  };
44
- var productOptionMessages = Object.freeze(labels);
105
+ var productOptionMessages = Object.freeze(labels2);
45
106
 
46
107
  // src/commerce/presentation/messages.ts
47
108
  var recommendationMessageKeys = [
@@ -102,10 +163,10 @@ function recommendationMessage(locale, key, values) {
102
163
  }
103
164
 
104
165
  // src/commerce/presentation/options.ts
105
- import { z } from "zod";
106
- var CommerceOptionFactSchema = z.strictObject({ productId: z.string().min(1).max(128), variantId: z.string().min(1).max(128).nullable(), title: z.string().min(1).max(512), options: CommerceProductOptionsSchema, selectedOptions: CommerceProductSelectedOptionsSchema });
166
+ import { z as z2 } from "zod";
167
+ var CommerceOptionFactSchema = z2.strictObject({ productId: z2.string().min(1).max(128), variantId: z2.string().min(1).max(128).nullable(), title: z2.string().min(1).max(512), options: CommerceProductOptionsSchema, selectedOptions: CommerceProductSelectedOptionsSchema });
107
168
  function verifyCommerceOptionFacts(selection, currentProducts) {
108
- const parsed = z.array(z.strictObject({ productId: z.string().min(1).max(128), variantId: z.string().min(1).max(128).nullable() })).max(3).safeParse(selection);
169
+ const parsed = z2.array(z2.strictObject({ productId: z2.string().min(1).max(128), variantId: z2.string().min(1).max(128).nullable() })).max(3).safeParse(selection);
109
170
  if (!parsed.success || new Set(selection.map((s) => JSON.stringify([s.productId, s.variantId]))).size !== selection.length) return { kind: "limitation", reason: "INVALID_SELECTION" };
110
171
  const facts = [];
111
172
  for (const selected of parsed.data) {
@@ -124,7 +185,7 @@ function renderProductOptionFacts(facts, locale) {
124
185
  }
125
186
 
126
187
  // src/commerce/presentation/schemas.ts
127
- var safeUrl = z2.string().max(2048).refine((value) => {
188
+ var safeUrl = z3.string().max(2048).refine((value) => {
128
189
  try {
129
190
  const u = new URL(value);
130
191
  return !/[\x00-\x1f\x7f]/.test(value) && !u.hostname.startsWith("[") && !/^[0-9.]+$/.test(u.hostname) && u.hostname !== "localhost" && !u.hostname.endsWith(".localhost") && u.protocol === "https:" && !u.username && !u.password && !u.port && !u.hash;
@@ -132,8 +193,9 @@ var safeUrl = z2.string().max(2048).refine((value) => {
132
193
  return false;
133
194
  }
134
195
  });
135
- var product = z2.strictObject({ title: z2.string().min(1).max(512), url: safeUrl, quantity: z2.number().int().min(1).max(Number.MAX_SAFE_INTEGER), scope: z2.enum(["PRODUCT_ONLY", "ADD_TO_BASKET", "REPLACE_BASKET_LINE"]), currentPrice: z2.string().max(128).nullable(), currency: z2.string().regex(/^[A-Z]{3}$/).nullable(), regularPrice: z2.string().max(128).nullable().optional(), offerTerms: z2.array(z2.strictObject({ kind: z2.enum(["percent", "amount", "free-shipping"]), value: z2.string().max(128).optional(), currency: z2.string().regex(/^[A-Z]{3}$/).optional(), code: z2.string().max(128).nullable().optional(), automatic: z2.boolean().optional() })).max(32).optional() });
136
- var CommerceVerifiedPresentationSchema = z2.strictObject({ schemaVersion: z2.literal(1), brandName: z2.string().min(1).max(512).nullable(), locale: ModaSupportedLanguageTagSchema, disposition: z2.enum(["STANDARD", "OUT_OF_SCOPE_REDIRECT", "SHIPPING_INFORMATION_UNVERIFIED", "PRODUCT_OPTIONS"]), storeUrl: safeUrl.refine((value) => !new URL(value).search), products: z2.array(product).max(3), optionFacts: z2.array(CommerceOptionFactSchema).max(3), requiresShipping: z2.boolean().nullable(), policyUrl: safeUrl.refine((value) => !new URL(value).search).nullable(), includeNoVerifiedOffer: z2.boolean() }).superRefine((v, c) => {
196
+ var product = z3.strictObject({ title: z3.string().min(1).max(512), url: safeUrl, quantity: z3.number().int().min(1).max(Number.MAX_SAFE_INTEGER), scope: z3.enum(["PRODUCT_ONLY", "ADD_TO_BASKET", "REPLACE_BASKET_LINE"]), currentPrice: z3.string().max(128).nullable(), currency: z3.string().regex(/^[A-Z]{3}$/).nullable(), regularPrice: z3.string().max(128).nullable().optional(), offerTerms: z3.array(z3.strictObject({ kind: z3.enum(["percent", "amount", "free-shipping"]), value: z3.string().max(128).optional(), currency: z3.string().regex(/^[A-Z]{3}$/).optional(), code: z3.string().max(128).nullable().optional(), automatic: z3.boolean().optional() })).max(32).optional() });
197
+ var CommerceVerifiedPresentationSchema = z3.strictObject({ schemaVersion: z3.literal(1), brandName: z3.string().min(1).max(512).nullable(), locale: ModaSupportedLanguageTagSchema, disposition: z3.enum(["STANDARD", "OUT_OF_SCOPE_REDIRECT", "SHIPPING_INFORMATION_UNVERIFIED", "PRODUCT_OPTIONS", "PRODUCT_DETAILS"]), storeUrl: safeUrl.refine((value) => !new URL(value).search), products: z3.array(product).max(3), productFacts: z3.array(CommerceProductFactSchema).max(3).default([]), optionFacts: z3.array(CommerceOptionFactSchema).max(3), requiresShipping: z3.boolean().nullable(), policyUrl: safeUrl.refine((value) => !new URL(value).search).nullable(), includeNoVerifiedOffer: z3.boolean() }).superRefine((v, c) => {
198
+ if (v.disposition === "PRODUCT_DETAILS" && (!v.productFacts.length || v.optionFacts.length || v.products.length)) c.addIssue({ code: "custom", message: "Invalid product details combination" });
137
199
  try {
138
200
  const origin = new URL(v.storeUrl).origin;
139
201
  if (v.products.some((p) => new URL(p.url).origin !== origin) || v.policyUrl && new URL(v.policyUrl).origin !== origin) c.addIssue({ code: "custom", message: "Presentation URL is outside current shop" });
@@ -517,6 +579,7 @@ function languageChoices(input, onInvalid) {
517
579
  // src/commerce/presentation/compose.ts
518
580
  function candidatesFor(envelope, p) {
519
581
  if (envelope.answerKind === "REFER_TO_STORE") return buildReplyCandidates({ fullBody: normalizeCommerceReplyText(envelope.replyText), minimalBody: normalizeCommerceReplyText(envelope.replyText) });
582
+ if (p.disposition === "PRODUCT_DETAILS") return buildReplyCandidates({ fullBody: renderCommerceProductFacts(p.productFacts, p.locale), firstProductBody: p.productFacts.length > 1 ? renderCommerceProductFacts(p.productFacts.slice(0, 1), p.locale) : null, minimalBody: renderCommerceProductFacts([], p.locale) });
520
583
  if (p.disposition === "PRODUCT_OPTIONS") return buildReplyCandidates({ fullBody: renderProductOptionFacts(p.optionFacts, p.locale), firstProductBody: p.optionFacts.length > 1 ? renderProductOptionFacts(p.optionFacts.slice(0, 1), p.locale) : null, minimalBody: renderProductOptionFacts([], p.locale) });
521
584
  if (p.products.length || p.disposition !== "STANDARD" || p.requiresShipping !== null || p.policyUrl) {
522
585
  const shared = { locale: p.locale, disposition: p.disposition, storeUrl: p.storeUrl, policyUrl: p.policyUrl, requiresShipping: p.requiresShipping };
@@ -563,6 +626,7 @@ function composeCommerceWhatsAppPreview(input) {
563
626
  }
564
627
  export {
565
628
  CommerceOptionFactSchema,
629
+ CommerceProductFactSchema,
566
630
  CommerceVerifiedPresentationSchema,
567
631
  MAX_WHATSAPP_TEXT_LENGTH,
568
632
  buildReplyCandidates,
@@ -577,11 +641,13 @@ export {
577
641
  languageChoices,
578
642
  minorUnitsToDecimal,
579
643
  normalizeCommerceReplyText,
644
+ productFactMessages,
580
645
  productOptionMessages,
581
646
  readPreparedWrapper,
582
647
  recommendationMessage,
583
648
  recommendationMessageKeys,
584
649
  recommendationMessages,
650
+ renderCommerceProductFacts,
585
651
  renderPreparedWrapper,
586
652
  renderProductOptionFacts,
587
653
  renderRecommendationReply,
@@ -589,6 +655,7 @@ export {
589
655
  stableJson,
590
656
  sumPurchaseSubtotal,
591
657
  validDefinition,
592
- verifyCommerceOptionFacts
658
+ verifyCommerceOptionFacts,
659
+ verifyCommerceProductFacts
593
660
  };
594
661
  //# sourceMappingURL=index.js.map