@modainteract/moda-interact-shared 5.9.0 → 5.11.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.
- package/dist/{chunk-SW2AFMT7.js → chunk-GADJQUWU.js} +24 -3
- package/dist/chunk-GADJQUWU.js.map +1 -0
- package/dist/{chunk-WHZAAF2Q.js → chunk-POCE2AES.js} +2 -2
- package/dist/{chunk-WHZAAF2Q.js.map → chunk-POCE2AES.js.map} +1 -1
- package/dist/{chunk-2XZVIWQZ.js → chunk-X3TXXIAX.js} +25 -6
- package/dist/chunk-X3TXXIAX.js.map +1 -0
- package/dist/commerce/index.d.ts +5 -5
- package/dist/commerce/index.js +8 -2
- package/dist/commerce/index.js.map +1 -1
- package/dist/commerce/model/node.d.ts +3 -3
- package/dist/commerce/model/node.js +1 -1
- package/dist/commerce/outreach/index.d.ts +718 -5
- package/dist/commerce/outreach/index.js +242 -203
- package/dist/commerce/outreach/index.js.map +1 -1
- package/dist/commerce/presentation/index.d.ts +30 -2
- package/dist/commerce/presentation/index.js +33 -6
- package/dist/commerce/presentation/index.js.map +1 -1
- package/dist/commerce/runner/index.d.ts +4 -4
- package/dist/commerce/runner/index.js +4 -4
- package/dist/commerce/runner/index.js.map +1 -1
- package/dist/{product-context-qfk6k9uk.d.ts → product-context-D1Xfe1FX.d.ts} +18 -2
- package/dist/{response-DD6HXT8s.d.ts → response-gHpvLkzy.d.ts} +96 -8
- package/dist/{types-BXeYmpeg.d.ts → types-CxiCD8Pw.d.ts} +2 -2
- package/package.json +1 -1
- package/dist/chunk-2XZVIWQZ.js.map +0 -1
- package/dist/chunk-SW2AFMT7.js.map +0 -1
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
PLATFORM_INSTRUCTIONS,
|
|
6
6
|
RUNTIME_DATA_AUTHORITY_INSTRUCTION
|
|
7
|
-
} from "../../chunk-
|
|
7
|
+
} from "../../chunk-POCE2AES.js";
|
|
8
8
|
import {
|
|
9
9
|
CommerceModelInvocationFailure
|
|
10
10
|
} from "../../chunk-WONND3OK.js";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
CommerceProductSchema,
|
|
13
13
|
CommerceToolInputs,
|
|
14
14
|
CommerceToolOutputs
|
|
15
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-GADJQUWU.js";
|
|
16
16
|
import {
|
|
17
17
|
CurrencySchema,
|
|
18
18
|
DateSchema,
|
|
@@ -115,6 +115,12 @@ var InitialOutreachRenderResultSchema = z2.discriminatedUnion("kind", [
|
|
|
115
115
|
z2.strictObject({ kind: z2.literal("ready"), purpose: z2.enum(["INITIAL_NO_OFFER", "INITIAL_CODE_OFFER", "INITIAL_AUTOMATIC_OFFER"]), templateProvenance: z2.strictObject({ variantId: hostId, registrationId: hostId, definitionId: hostId, providerTemplateId: hostId, providerTemplateName: text, providerLanguageCode: text, submittedContentHash: HashSchema, bindingFingerprint: HashSchema }), parameters: z2.array(PreparedComponentSchema).max(4), headerPreview: ReadyMediaSchema.nullable(), renderedText: z2.string().max(8192) }),
|
|
116
116
|
z2.strictObject({ kind: z2.literal("refused"), reasonCode: RenderReasonSchema })
|
|
117
117
|
]);
|
|
118
|
+
var StudioOutreachTemplateSchema = z2.strictObject({ templateId: hostId, localeId: hostId, languageTag: z2.string().min(1).max(512), components: z2.array(ComponentSchema).min(1).max(4), bindings: FrozenBindingsSchema });
|
|
119
|
+
var StudioInitialOutreachRenderInputSchema = InitialOutreachRenderInputSchema.omit({ preparedProjection: true }).extend({ template: StudioOutreachTemplateSchema });
|
|
120
|
+
var StudioInitialOutreachRenderResultSchema = z2.discriminatedUnion("kind", [
|
|
121
|
+
z2.strictObject({ kind: z2.literal("ready"), renderedText: z2.string().max(8192), parameters: z2.array(PreparedComponentSchema).max(4), headerPreview: ReadyMediaSchema.nullable(), templateId: hostId, localeId: hostId, templateValidation: z2.literal("NOT_EVALUATED") }),
|
|
122
|
+
z2.strictObject({ kind: z2.literal("refused"), reasonCode: RenderReasonSchema })
|
|
123
|
+
]);
|
|
118
124
|
|
|
119
125
|
// src/commerce/outreach/evaluate.ts
|
|
120
126
|
import { z as z3 } from "zod";
|
|
@@ -788,6 +794,188 @@ async function evaluateInitialOutreach(raw, ports) {
|
|
|
788
794
|
}
|
|
789
795
|
var evaluateInitialOutreachPreview = evaluateInitialOutreach;
|
|
790
796
|
|
|
797
|
+
// src/commerce/outreach/recovery-template-items-summary.ts
|
|
798
|
+
var MAX_LINE_ITEMS = 100;
|
|
799
|
+
var MAX_DISPLAYED_ITEMS = 3;
|
|
800
|
+
var MAX_TITLE_LENGTH = 160;
|
|
801
|
+
var MAX_SUMMARY_LENGTH = 400;
|
|
802
|
+
function safeText(value, limit) {
|
|
803
|
+
if (typeof value !== "string")
|
|
804
|
+
return null;
|
|
805
|
+
const text2 = value.normalize("NFC").trim().replace(/\s+/gu, " ");
|
|
806
|
+
if (!text2 || text2.length > limit || /[\p{Cc}\p{Cf}{}]/u.test(text2) || text2.includes("{{") || text2.includes("}}"))
|
|
807
|
+
return null;
|
|
808
|
+
try {
|
|
809
|
+
encodeURIComponent(text2);
|
|
810
|
+
} catch {
|
|
811
|
+
return null;
|
|
812
|
+
}
|
|
813
|
+
return text2;
|
|
814
|
+
}
|
|
815
|
+
function parseItem(value) {
|
|
816
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
817
|
+
return null;
|
|
818
|
+
const item = value;
|
|
819
|
+
const title = safeText(item.title, MAX_TITLE_LENGTH);
|
|
820
|
+
const quantity = item.quantity;
|
|
821
|
+
if (!title || typeof quantity !== "number" || !Number.isSafeInteger(quantity) || quantity < 1 || quantity > 99999)
|
|
822
|
+
return null;
|
|
823
|
+
const variant = safeText(item.variantTitle, MAX_TITLE_LENGTH);
|
|
824
|
+
const displayTitle = variant && variant.toLowerCase() !== "default title" && variant !== title ? `${title} (${variant})` : title;
|
|
825
|
+
return { title: displayTitle, quantity };
|
|
826
|
+
}
|
|
827
|
+
function formatCheckoutItemsSummary(lineItems, languageTag) {
|
|
828
|
+
if (!Array.isArray(lineItems) || lineItems.length === 0 || lineItems.length > MAX_LINE_ITEMS)
|
|
829
|
+
return null;
|
|
830
|
+
let locale;
|
|
831
|
+
try {
|
|
832
|
+
locale = Intl.getCanonicalLocales(languageTag)[0] ?? "en";
|
|
833
|
+
} catch {
|
|
834
|
+
return null;
|
|
835
|
+
}
|
|
836
|
+
const items = lineItems.map(parseItem).filter((item) => item !== null);
|
|
837
|
+
if (!items.length)
|
|
838
|
+
return null;
|
|
839
|
+
const numbers = new Intl.NumberFormat(locale, { maximumFractionDigits: 0 });
|
|
840
|
+
const list = new Intl.ListFormat(locale, { style: "long", type: "conjunction" });
|
|
841
|
+
const visible = items.slice(0, MAX_DISPLAYED_ITEMS).map(({ title, quantity }) => `${numbers.format(quantity)} \xD7 ${title}`);
|
|
842
|
+
if (items.length > MAX_DISPLAYED_ITEMS) {
|
|
843
|
+
visible.push(`+${numbers.format(items.length - MAX_DISPLAYED_ITEMS)}`);
|
|
844
|
+
}
|
|
845
|
+
const summary = list.format(visible);
|
|
846
|
+
if (summary.length <= MAX_SUMMARY_LENGTH)
|
|
847
|
+
return summary;
|
|
848
|
+
return `${Array.from(summary).slice(0, MAX_SUMMARY_LENGTH - 1).join("").trimEnd()}\u2026`;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// src/commerce/outreach/variables.ts
|
|
852
|
+
function isSemanticKey(v) {
|
|
853
|
+
return SemanticKeySchema.safeParse(v).success;
|
|
854
|
+
}
|
|
855
|
+
var BindingUnavailable = class extends Error {
|
|
856
|
+
constructor(reason) {
|
|
857
|
+
super(reason);
|
|
858
|
+
this.reason = reason;
|
|
859
|
+
}
|
|
860
|
+
reason;
|
|
861
|
+
};
|
|
862
|
+
function boundedText(v, limit) {
|
|
863
|
+
if (typeof v !== "string" || !v.trim() || v.length > limit || /[\x00-\x1f\x7f\u2028\u2029]/u.test(v) || v.includes("{{") || v.includes("}}"))
|
|
864
|
+
throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
865
|
+
try {
|
|
866
|
+
encodeURIComponent(v);
|
|
867
|
+
} catch {
|
|
868
|
+
throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
869
|
+
}
|
|
870
|
+
return v.trim();
|
|
871
|
+
}
|
|
872
|
+
var PreparedVariableResolver = class {
|
|
873
|
+
constructor(input, languageTag, sendable) {
|
|
874
|
+
this.input = input;
|
|
875
|
+
this.languageTag = languageTag;
|
|
876
|
+
this.sendable = sendable;
|
|
877
|
+
}
|
|
878
|
+
input;
|
|
879
|
+
languageTag;
|
|
880
|
+
sendable;
|
|
881
|
+
encodeCheckoutButtonSuffix(_prefix) {
|
|
882
|
+
return encodeURIComponent(this.input.variables.checkoutUrl);
|
|
883
|
+
}
|
|
884
|
+
encodePromotionButtonSuffix(_prefix) {
|
|
885
|
+
throw new BindingUnavailable("PROMOTION_PRODUCT_URL_UNAVAILABLE");
|
|
886
|
+
}
|
|
887
|
+
checkStaticButtonUrl(value) {
|
|
888
|
+
const u = new URL(value), checkout = new URL(this.input.variables.checkoutUrl);
|
|
889
|
+
if (u.protocol !== "https:" || u.username || u.password || u.hash || u.hostname !== checkout.hostname)
|
|
890
|
+
throw new BindingUnavailable("CHECKOUT_UNTRUSTED");
|
|
891
|
+
}
|
|
892
|
+
imageHeader(role) {
|
|
893
|
+
const m = this.input.headerMedia;
|
|
894
|
+
if (!m || m.shopId !== this.input.evaluation.shopId || m.role !== role)
|
|
895
|
+
throw new BindingUnavailable("MEDIA_NOT_READY");
|
|
896
|
+
return m.httpsUrl;
|
|
897
|
+
}
|
|
898
|
+
brandMedia(role) {
|
|
899
|
+
const media = this.input.preparedBrandMedia?.[role];
|
|
900
|
+
if (!media) throw new BindingUnavailable("MEDIA_NOT_READY");
|
|
901
|
+
boundedText(media.httpsUrl, 2048);
|
|
902
|
+
return media.httpsUrl;
|
|
903
|
+
}
|
|
904
|
+
resolve(key) {
|
|
905
|
+
const i = this.input, d = this.sendable;
|
|
906
|
+
switch (key) {
|
|
907
|
+
case "customer.firstName":
|
|
908
|
+
return boundedText(i.variables.customerFirstName, 200);
|
|
909
|
+
case "shop.name":
|
|
910
|
+
return boundedText(i.variables.shopName, 200);
|
|
911
|
+
case "shop.categoryName":
|
|
912
|
+
return boundedText(i.variables.shopCategory, 200);
|
|
913
|
+
case "checkout.url":
|
|
914
|
+
return i.variables.checkoutUrl;
|
|
915
|
+
case "checkout.itemsSummary": {
|
|
916
|
+
const items = i.evaluation.lines.map((l) => ({ title: l.currentProduct.title, quantity: l.quantity, variantTitle: l.currentProduct.selectedOptions?.map((o) => o.value).join(" / ") || null }));
|
|
917
|
+
if (items.some((l) => l.quantity > 99999 || /[\p{Cc}\p{Cf}{}]/u.test(l.title) || l.title.length > 160 || l.variantTitle !== null && (/[\p{Cc}\p{Cf}{}]/u.test(l.variantTitle) || l.variantTitle.length > 160)))
|
|
918
|
+
throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
919
|
+
return boundedText(formatCheckoutItemsSummary(items, this.languageTag), 500);
|
|
920
|
+
}
|
|
921
|
+
case "offer.code":
|
|
922
|
+
if (d.presentation === "CODE_OFFER" && d.members.length === 1 && d.members[0]?.method === "CODE")
|
|
923
|
+
return boundedText(d.members[0].code, 100);
|
|
924
|
+
break;
|
|
925
|
+
case "offer.codes":
|
|
926
|
+
if (d.presentation === "CODE_OFFER" && d.members.every((m) => m.method === "CODE"))
|
|
927
|
+
return d.members.map((m) => boundedText(m.code, 100)).join(", ");
|
|
928
|
+
break;
|
|
929
|
+
case "offer.description":
|
|
930
|
+
if (d.presentation !== "NO_OFFER")
|
|
931
|
+
return boundedText(d.members.map((m) => m.description).join(", "), 200);
|
|
932
|
+
break;
|
|
933
|
+
case "shopBrand.brandName":
|
|
934
|
+
return boundedText(i.preparedBrand?.brandName, 200);
|
|
935
|
+
case "shopBrand.logoAltText":
|
|
936
|
+
return boundedText(i.preparedBrand?.logoAltText, 200);
|
|
937
|
+
case "shopBrand.squareLogoAltText":
|
|
938
|
+
return boundedText(i.preparedBrand?.squareLogoAltText, 200);
|
|
939
|
+
case "shopBrand.logoWidth":
|
|
940
|
+
case "shopBrand.logoHeight": {
|
|
941
|
+
const value = key === "shopBrand.logoWidth" ? i.preparedBrand?.logoWidth : i.preparedBrand?.logoHeight;
|
|
942
|
+
if (value === null || value === void 0) throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
943
|
+
return boundedText(String(value), 200);
|
|
944
|
+
}
|
|
945
|
+
case "shopBrand.logoUrl":
|
|
946
|
+
return this.brandMedia("logo");
|
|
947
|
+
case "shopBrand.squareLogoUrl":
|
|
948
|
+
return this.brandMedia("squareLogo");
|
|
949
|
+
case "shopBrand.coverImageUrl":
|
|
950
|
+
return this.brandMedia("coverImage");
|
|
951
|
+
}
|
|
952
|
+
throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
// src/commerce/outreach/component-render.ts
|
|
957
|
+
function renderStoredComponentText(components, parameters) {
|
|
958
|
+
function substitute(text3, type) {
|
|
959
|
+
const values = parameters.find((p) => p.type === type)?.parameters ?? [];
|
|
960
|
+
return text3.replace(/\{\{([1-9][0-9]*)\}\}/g, (_, position) => {
|
|
961
|
+
const value = values[Number(position) - 1];
|
|
962
|
+
if (!value || value.type !== "text") throw new BindingUnavailable("BINDINGS_INVALID");
|
|
963
|
+
return value.text;
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
const body = components.find((c) => c.type === "BODY");
|
|
967
|
+
if (!body || body.type !== "BODY") throw new BindingUnavailable("BINDINGS_INVALID");
|
|
968
|
+
if (substitute(body.text, "body").length > 4096) throw new BindingUnavailable("MESSAGE_TOO_LARGE");
|
|
969
|
+
const text2 = components.flatMap((c) => {
|
|
970
|
+
if (c.type === "BODY") return [substitute(c.text, "body")];
|
|
971
|
+
if (c.type === "FOOTER") return [c.text];
|
|
972
|
+
if (c.type === "HEADER" && c.format === "TEXT") return [substitute(c.text, "header")];
|
|
973
|
+
return [];
|
|
974
|
+
}).join("\n");
|
|
975
|
+
if (text2.length > 8192) throw new BindingUnavailable("MESSAGE_TOO_LARGE");
|
|
976
|
+
return text2;
|
|
977
|
+
}
|
|
978
|
+
|
|
791
979
|
// src/commerce/outreach/initial-checkout-items-policy.ts
|
|
792
980
|
function decideInitialCheckoutItemsBinding(input) {
|
|
793
981
|
if (input.stage === "FOLLOW_UP")
|
|
@@ -955,167 +1143,6 @@ function selectRecoveryAssignment(input) {
|
|
|
955
1143
|
|
|
956
1144
|
// src/commerce/outreach/bindings.ts
|
|
957
1145
|
import { createHash as createHash2 } from "crypto";
|
|
958
|
-
|
|
959
|
-
// src/commerce/outreach/recovery-template-items-summary.ts
|
|
960
|
-
var MAX_LINE_ITEMS = 100;
|
|
961
|
-
var MAX_DISPLAYED_ITEMS = 3;
|
|
962
|
-
var MAX_TITLE_LENGTH = 160;
|
|
963
|
-
var MAX_SUMMARY_LENGTH = 400;
|
|
964
|
-
function safeText(value, limit) {
|
|
965
|
-
if (typeof value !== "string")
|
|
966
|
-
return null;
|
|
967
|
-
const text2 = value.normalize("NFC").trim().replace(/\s+/gu, " ");
|
|
968
|
-
if (!text2 || text2.length > limit || /[\p{Cc}\p{Cf}{}]/u.test(text2) || text2.includes("{{") || text2.includes("}}"))
|
|
969
|
-
return null;
|
|
970
|
-
try {
|
|
971
|
-
encodeURIComponent(text2);
|
|
972
|
-
} catch {
|
|
973
|
-
return null;
|
|
974
|
-
}
|
|
975
|
-
return text2;
|
|
976
|
-
}
|
|
977
|
-
function parseItem(value) {
|
|
978
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
979
|
-
return null;
|
|
980
|
-
const item = value;
|
|
981
|
-
const title = safeText(item.title, MAX_TITLE_LENGTH);
|
|
982
|
-
const quantity = item.quantity;
|
|
983
|
-
if (!title || typeof quantity !== "number" || !Number.isSafeInteger(quantity) || quantity < 1 || quantity > 99999)
|
|
984
|
-
return null;
|
|
985
|
-
const variant = safeText(item.variantTitle, MAX_TITLE_LENGTH);
|
|
986
|
-
const displayTitle = variant && variant.toLowerCase() !== "default title" && variant !== title ? `${title} (${variant})` : title;
|
|
987
|
-
return { title: displayTitle, quantity };
|
|
988
|
-
}
|
|
989
|
-
function formatCheckoutItemsSummary(lineItems, languageTag) {
|
|
990
|
-
if (!Array.isArray(lineItems) || lineItems.length === 0 || lineItems.length > MAX_LINE_ITEMS)
|
|
991
|
-
return null;
|
|
992
|
-
let locale;
|
|
993
|
-
try {
|
|
994
|
-
locale = Intl.getCanonicalLocales(languageTag)[0] ?? "en";
|
|
995
|
-
} catch {
|
|
996
|
-
return null;
|
|
997
|
-
}
|
|
998
|
-
const items = lineItems.map(parseItem).filter((item) => item !== null);
|
|
999
|
-
if (!items.length)
|
|
1000
|
-
return null;
|
|
1001
|
-
const numbers = new Intl.NumberFormat(locale, { maximumFractionDigits: 0 });
|
|
1002
|
-
const list = new Intl.ListFormat(locale, { style: "long", type: "conjunction" });
|
|
1003
|
-
const visible = items.slice(0, MAX_DISPLAYED_ITEMS).map(({ title, quantity }) => `${numbers.format(quantity)} \xD7 ${title}`);
|
|
1004
|
-
if (items.length > MAX_DISPLAYED_ITEMS) {
|
|
1005
|
-
visible.push(`+${numbers.format(items.length - MAX_DISPLAYED_ITEMS)}`);
|
|
1006
|
-
}
|
|
1007
|
-
const summary = list.format(visible);
|
|
1008
|
-
if (summary.length <= MAX_SUMMARY_LENGTH)
|
|
1009
|
-
return summary;
|
|
1010
|
-
return `${Array.from(summary).slice(0, MAX_SUMMARY_LENGTH - 1).join("").trimEnd()}\u2026`;
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
// src/commerce/outreach/variables.ts
|
|
1014
|
-
function isSemanticKey(v) {
|
|
1015
|
-
return SemanticKeySchema.safeParse(v).success;
|
|
1016
|
-
}
|
|
1017
|
-
var BindingUnavailable = class extends Error {
|
|
1018
|
-
constructor(reason) {
|
|
1019
|
-
super(reason);
|
|
1020
|
-
this.reason = reason;
|
|
1021
|
-
}
|
|
1022
|
-
reason;
|
|
1023
|
-
};
|
|
1024
|
-
function boundedText(v, limit) {
|
|
1025
|
-
if (typeof v !== "string" || !v.trim() || v.length > limit || /[\x00-\x1f\x7f\u2028\u2029]/u.test(v) || v.includes("{{") || v.includes("}}"))
|
|
1026
|
-
throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
1027
|
-
try {
|
|
1028
|
-
encodeURIComponent(v);
|
|
1029
|
-
} catch {
|
|
1030
|
-
throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
1031
|
-
}
|
|
1032
|
-
return v.trim();
|
|
1033
|
-
}
|
|
1034
|
-
var PreparedVariableResolver = class {
|
|
1035
|
-
constructor(input, languageTag, sendable) {
|
|
1036
|
-
this.input = input;
|
|
1037
|
-
this.languageTag = languageTag;
|
|
1038
|
-
this.sendable = sendable;
|
|
1039
|
-
}
|
|
1040
|
-
input;
|
|
1041
|
-
languageTag;
|
|
1042
|
-
sendable;
|
|
1043
|
-
encodeCheckoutButtonSuffix(_prefix) {
|
|
1044
|
-
return encodeURIComponent(this.input.variables.checkoutUrl);
|
|
1045
|
-
}
|
|
1046
|
-
encodePromotionButtonSuffix(_prefix) {
|
|
1047
|
-
throw new BindingUnavailable("PROMOTION_PRODUCT_URL_UNAVAILABLE");
|
|
1048
|
-
}
|
|
1049
|
-
checkStaticButtonUrl(value) {
|
|
1050
|
-
const u = new URL(value), checkout = new URL(this.input.variables.checkoutUrl);
|
|
1051
|
-
if (u.protocol !== "https:" || u.username || u.password || u.hash || u.hostname !== checkout.hostname)
|
|
1052
|
-
throw new BindingUnavailable("CHECKOUT_UNTRUSTED");
|
|
1053
|
-
}
|
|
1054
|
-
imageHeader(role) {
|
|
1055
|
-
const m = this.input.headerMedia;
|
|
1056
|
-
if (!m || m.shopId !== this.input.evaluation.shopId || m.role !== role)
|
|
1057
|
-
throw new BindingUnavailable("MEDIA_NOT_READY");
|
|
1058
|
-
return m.httpsUrl;
|
|
1059
|
-
}
|
|
1060
|
-
brandMedia(role) {
|
|
1061
|
-
const media = this.input.preparedBrandMedia?.[role];
|
|
1062
|
-
if (!media) throw new BindingUnavailable("MEDIA_NOT_READY");
|
|
1063
|
-
boundedText(media.httpsUrl, 2048);
|
|
1064
|
-
return media.httpsUrl;
|
|
1065
|
-
}
|
|
1066
|
-
resolve(key) {
|
|
1067
|
-
const i = this.input, d = this.sendable;
|
|
1068
|
-
switch (key) {
|
|
1069
|
-
case "customer.firstName":
|
|
1070
|
-
return boundedText(i.variables.customerFirstName, 200);
|
|
1071
|
-
case "shop.name":
|
|
1072
|
-
return boundedText(i.variables.shopName, 200);
|
|
1073
|
-
case "shop.categoryName":
|
|
1074
|
-
return boundedText(i.variables.shopCategory, 200);
|
|
1075
|
-
case "checkout.url":
|
|
1076
|
-
return i.variables.checkoutUrl;
|
|
1077
|
-
case "checkout.itemsSummary": {
|
|
1078
|
-
const items = i.evaluation.lines.map((l) => ({ title: l.currentProduct.title, quantity: l.quantity, variantTitle: l.currentProduct.selectedOptions?.map((o) => o.value).join(" / ") || null }));
|
|
1079
|
-
if (items.some((l) => l.quantity > 99999 || /[\p{Cc}\p{Cf}{}]/u.test(l.title) || l.title.length > 160 || l.variantTitle !== null && (/[\p{Cc}\p{Cf}{}]/u.test(l.variantTitle) || l.variantTitle.length > 160)))
|
|
1080
|
-
throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
1081
|
-
return boundedText(formatCheckoutItemsSummary(items, this.languageTag), 500);
|
|
1082
|
-
}
|
|
1083
|
-
case "offer.code":
|
|
1084
|
-
if (d.presentation === "CODE_OFFER" && d.members.length === 1 && d.members[0]?.method === "CODE")
|
|
1085
|
-
return boundedText(d.members[0].code, 100);
|
|
1086
|
-
break;
|
|
1087
|
-
case "offer.codes":
|
|
1088
|
-
if (d.presentation === "CODE_OFFER" && d.members.every((m) => m.method === "CODE"))
|
|
1089
|
-
return d.members.map((m) => boundedText(m.code, 100)).join(", ");
|
|
1090
|
-
break;
|
|
1091
|
-
case "offer.description":
|
|
1092
|
-
if (d.presentation !== "NO_OFFER")
|
|
1093
|
-
return boundedText(d.members.map((m) => m.description).join(", "), 200);
|
|
1094
|
-
break;
|
|
1095
|
-
case "shopBrand.brandName":
|
|
1096
|
-
return boundedText(i.preparedBrand?.brandName, 200);
|
|
1097
|
-
case "shopBrand.logoAltText":
|
|
1098
|
-
return boundedText(i.preparedBrand?.logoAltText, 200);
|
|
1099
|
-
case "shopBrand.squareLogoAltText":
|
|
1100
|
-
return boundedText(i.preparedBrand?.squareLogoAltText, 200);
|
|
1101
|
-
case "shopBrand.logoWidth":
|
|
1102
|
-
case "shopBrand.logoHeight": {
|
|
1103
|
-
const value = key === "shopBrand.logoWidth" ? i.preparedBrand?.logoWidth : i.preparedBrand?.logoHeight;
|
|
1104
|
-
if (value === null || value === void 0) throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
1105
|
-
return boundedText(String(value), 200);
|
|
1106
|
-
}
|
|
1107
|
-
case "shopBrand.logoUrl":
|
|
1108
|
-
return this.brandMedia("logo");
|
|
1109
|
-
case "shopBrand.squareLogoUrl":
|
|
1110
|
-
return this.brandMedia("squareLogo");
|
|
1111
|
-
case "shopBrand.coverImageUrl":
|
|
1112
|
-
return this.brandMedia("coverImage");
|
|
1113
|
-
}
|
|
1114
|
-
throw new BindingUnavailable("BINDING_VALUE_UNAVAILABLE");
|
|
1115
|
-
}
|
|
1116
|
-
};
|
|
1117
|
-
|
|
1118
|
-
// src/commerce/outreach/bindings.ts
|
|
1119
1146
|
var MEDIA_ROLES = ["LOGO", "SQUARE_LOGO", "COVER_IMAGE", "CHECKOUT_PRODUCT"];
|
|
1120
1147
|
var obj = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1121
1148
|
function invalid() {
|
|
@@ -1226,6 +1253,12 @@ function prepareFrozenComponents(input) {
|
|
|
1226
1253
|
}
|
|
1227
1254
|
if (registration.category !== "MARKETING")
|
|
1228
1255
|
return invalid();
|
|
1256
|
+
return { ...prepareStoredComponents({ components: approved, bindings: frozen, variables }), bindingFingerprint: fingerprint };
|
|
1257
|
+
}
|
|
1258
|
+
function prepareStoredComponents(input) {
|
|
1259
|
+
const approved = strictComponents(input.components);
|
|
1260
|
+
const frozen = parseFrozenBindings(input.bindings);
|
|
1261
|
+
const variables = input.variables;
|
|
1229
1262
|
const result2 = [];
|
|
1230
1263
|
let matchedHeader = false;
|
|
1231
1264
|
let matchedBody = false;
|
|
@@ -1289,7 +1322,7 @@ function prepareFrozenComponents(input) {
|
|
|
1289
1322
|
}
|
|
1290
1323
|
if (!matchedBody || frozen.header.length > 0 && !matchedHeader || frozen.buttons.length > 0 && !matchedButtons)
|
|
1291
1324
|
return invalid();
|
|
1292
|
-
return { components: result2
|
|
1325
|
+
return { components: result2 };
|
|
1293
1326
|
}
|
|
1294
1327
|
|
|
1295
1328
|
// src/commerce/outreach/sendable-offer.ts
|
|
@@ -1322,16 +1355,8 @@ function renderInitialOutreachPreview(raw) {
|
|
|
1322
1355
|
if (!parsed.success)
|
|
1323
1356
|
return { kind: "refused", reasonCode: "INVALID_REQUEST" };
|
|
1324
1357
|
const input = parsed.data;
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
for (const [key, role] of [["logo", "LOGO"], ["squareLogo", "SQUARE_LOGO"], ["coverImage", "COVER_IMAGE"]]) {
|
|
1328
|
-
const media = input.preparedBrandMedia?.[key];
|
|
1329
|
-
if (media) {
|
|
1330
|
-
const url = new URL(media.httpsUrl);
|
|
1331
|
-
if (media.shopId !== input.evaluation.shopId || media.role !== role || url.hash || media.httpsUrl.includes("#") || !url.hostname.includes("."))
|
|
1332
|
-
return { kind: "refused", reasonCode: "MEDIA_NOT_READY" };
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1358
|
+
const assetError = validatePreparedAssets(input);
|
|
1359
|
+
if (assetError) return { kind: "refused", reasonCode: assetError };
|
|
1335
1360
|
let projection = input.preparedProjection;
|
|
1336
1361
|
if (!projection)
|
|
1337
1362
|
return { kind: "refused", reasonCode: "NO_APPROVED_ASSIGNMENT" };
|
|
@@ -1353,40 +1378,48 @@ function renderInitialOutreachPreview(raw) {
|
|
|
1353
1378
|
const registration = v.metaRegistration;
|
|
1354
1379
|
try {
|
|
1355
1380
|
const prepared = prepareFrozenComponents({ registration, variables: new PreparedVariableResolver(input, projection.canonicalLanguageTag, sendable) });
|
|
1356
|
-
const
|
|
1357
|
-
if (!body || !("text" in body))
|
|
1358
|
-
throw new BindingUnavailable("BINDINGS_INVALID");
|
|
1359
|
-
const params = prepared.components.find((c) => c.type === "body")?.parameters ?? [];
|
|
1360
|
-
const renderedText = body.text.replace(/\{\{([1-9][0-9]*)\}\}/g, (_, n) => {
|
|
1361
|
-
const value = params[Number(n) - 1];
|
|
1362
|
-
if (!value || value.type !== "text")
|
|
1363
|
-
throw new BindingUnavailable("BINDINGS_INVALID");
|
|
1364
|
-
return value.text;
|
|
1365
|
-
});
|
|
1366
|
-
if (renderedText.length > 4096)
|
|
1367
|
-
return { kind: "refused", reasonCode: "MESSAGE_TOO_LARGE" };
|
|
1368
|
-
const fullText = registration.componentsSnapshot.flatMap((component) => {
|
|
1369
|
-
if (component.type === "BODY")
|
|
1370
|
-
return [renderedText];
|
|
1371
|
-
if (component.type === "FOOTER")
|
|
1372
|
-
return [component.text];
|
|
1373
|
-
if (component.type === "HEADER" && component.format === "TEXT") {
|
|
1374
|
-
const headerParams = prepared.components.find((c) => c.type === "header")?.parameters ?? [];
|
|
1375
|
-
return [component.text.replace(/\{\{([1-9][0-9]*)\}\}/g, (_, n) => {
|
|
1376
|
-
const p = headerParams[Number(n) - 1];
|
|
1377
|
-
if (!p || p.type !== "text")
|
|
1378
|
-
throw new BindingUnavailable("BINDINGS_INVALID");
|
|
1379
|
-
return p.text;
|
|
1380
|
-
})];
|
|
1381
|
-
}
|
|
1382
|
-
return [];
|
|
1383
|
-
}).join("\n");
|
|
1381
|
+
const fullText = renderStoredComponentText(registration.componentsSnapshot, prepared.components);
|
|
1384
1382
|
return InitialOutreachRenderResultSchema.parse({ kind: "ready", purpose, templateProvenance: { variantId: v.id, registrationId: registration.id, definitionId: registration.locale.definition.id, providerTemplateId: registration.providerTemplateId, providerTemplateName: registration.providerTemplateName, providerLanguageCode: registration.providerLanguageCode, submittedContentHash: registration.submittedContentHash, bindingFingerprint: prepared.bindingFingerprint }, parameters: prepared.components, headerPreview: image ? input.headerMedia : null, renderedText: fullText });
|
|
1385
1383
|
} catch (e) {
|
|
1386
1384
|
return { kind: "refused", reasonCode: e instanceof BindingUnavailable ? e.reason : "BINDINGS_INVALID" };
|
|
1387
1385
|
}
|
|
1388
1386
|
}
|
|
1387
|
+
function validatePreparedAssets(input) {
|
|
1388
|
+
if (input.preparedBrand && input.preparedBrand.shopId !== input.evaluation.shopId)
|
|
1389
|
+
return "IDENTITY_MISMATCH";
|
|
1390
|
+
for (const [key, role] of [["logo", "LOGO"], ["squareLogo", "SQUARE_LOGO"], ["coverImage", "COVER_IMAGE"]]) {
|
|
1391
|
+
const media = input.preparedBrandMedia?.[key];
|
|
1392
|
+
if (media) {
|
|
1393
|
+
const url = new URL(media.httpsUrl);
|
|
1394
|
+
if (media.shopId !== input.evaluation.shopId || media.role !== role || url.hash || media.httpsUrl.includes("#") || !url.hostname.includes("."))
|
|
1395
|
+
return "MEDIA_NOT_READY";
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
return null;
|
|
1399
|
+
}
|
|
1400
|
+
function renderStudioInitialOutreachPreview(raw) {
|
|
1401
|
+
let parsed;
|
|
1402
|
+
try {
|
|
1403
|
+
parsed = StudioInitialOutreachRenderInputSchema.safeParse(raw);
|
|
1404
|
+
} catch {
|
|
1405
|
+
return { kind: "refused", reasonCode: "INVALID_REQUEST" };
|
|
1406
|
+
}
|
|
1407
|
+
if (!parsed.success) return { kind: "refused", reasonCode: "INVALID_REQUEST" };
|
|
1408
|
+
const input = parsed.data;
|
|
1409
|
+
const assetError = validatePreparedAssets(input);
|
|
1410
|
+
if (assetError) return { kind: "refused", reasonCode: assetError };
|
|
1411
|
+
try {
|
|
1412
|
+
const sendable = selectSendableOutreachOffer(input.evaluation.offerDecision);
|
|
1413
|
+
const prepared = prepareStoredComponents({ components: input.template.components, bindings: input.template.bindings, variables: new PreparedVariableResolver(input, input.template.languageTag, sendable) });
|
|
1414
|
+
const image = input.template.components.some((c) => c.type === "HEADER" && c.format === "IMAGE");
|
|
1415
|
+
return StudioInitialOutreachRenderResultSchema.parse({ kind: "ready", renderedText: renderStoredComponentText(input.template.components, prepared.components), parameters: prepared.components, headerPreview: image ? input.headerMedia : null, templateId: input.template.templateId, localeId: input.template.localeId, templateValidation: "NOT_EVALUATED" });
|
|
1416
|
+
} catch (error) {
|
|
1417
|
+
return { kind: "refused", reasonCode: error instanceof BindingUnavailable ? error.reason : "BINDINGS_INVALID" };
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1389
1420
|
export {
|
|
1421
|
+
ComponentSchema,
|
|
1422
|
+
FrozenBindingsSchema,
|
|
1390
1423
|
InitialOutreachEvaluationInputSchema,
|
|
1391
1424
|
InitialOutreachEvaluationResultSchema,
|
|
1392
1425
|
InitialOutreachRenderInputSchema,
|
|
@@ -1394,10 +1427,16 @@ export {
|
|
|
1394
1427
|
PreparedOutreachBrandMediaItemSchema,
|
|
1395
1428
|
PreparedOutreachBrandMediaSchema,
|
|
1396
1429
|
PreparedOutreachBrandSchema,
|
|
1430
|
+
StudioInitialOutreachRenderInputSchema,
|
|
1431
|
+
StudioInitialOutreachRenderResultSchema,
|
|
1432
|
+
StudioOutreachTemplateSchema,
|
|
1397
1433
|
evaluateInitialOutreach,
|
|
1398
1434
|
evaluateInitialOutreachPreview,
|
|
1399
1435
|
fingerprintInitialOutreachBasket,
|
|
1436
|
+
purposeFor,
|
|
1400
1437
|
renderInitialOutreachPreview,
|
|
1401
|
-
|
|
1438
|
+
renderStudioInitialOutreachPreview,
|
|
1439
|
+
selectRecoveryAssignment,
|
|
1440
|
+
selectSendableOutreachOffer
|
|
1402
1441
|
};
|
|
1403
1442
|
//# sourceMappingURL=index.js.map
|