@rebuy/rebuy 3.41.0 → 3.43.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 (60) hide show
  1. package/dist/index.cjs +971 -787
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.mjs +971 -787
  4. package/dist/pricing/index.cjs +58 -1
  5. package/dist/pricing/index.d.ts +2 -0
  6. package/dist/pricing/index.mjs +58 -1
  7. package/dist/pricing/postPurchaseDisplayFacts.d.ts +36 -0
  8. package/dist/pricing/postPurchaseDisplayPrice.d.ts +8 -0
  9. package/dist/pricing/postPurchaseReduction.d.ts +17 -0
  10. package/dist/schema/checkout-and-beyond/constants.cjs +4 -0
  11. package/dist/schema/checkout-and-beyond/constants.mjs +4 -0
  12. package/dist/schema/checkout-and-beyond/index.cjs +388 -374
  13. package/dist/schema/checkout-and-beyond/index.mjs +388 -374
  14. package/dist/schema/index.d.ts +2 -0
  15. package/dist/schema/postPurchaseAdmission.d.ts +33 -0
  16. package/dist/schema/postPurchaseDisplayPrice.d.ts +31 -0
  17. package/dist/schema/postPurchaseFollowups.d.ts +47 -0
  18. package/dist/schema/postPurchaseHealth.d.ts +5 -0
  19. package/dist/schema/postPurchasePlanCatalog.d.ts +2 -0
  20. package/dist/schema/postPurchaseProduct.d.ts +2 -0
  21. package/dist/schema/postPurchaseProductCollectionView.d.ts +62 -0
  22. package/dist/schema/postPurchaseProductView.d.ts +65 -0
  23. package/dist/schema/postPurchaseRecovery.d.ts +47 -0
  24. package/dist/schema/postPurchaseSubscriptionProduct.d.ts +2 -0
  25. package/dist/schema/postPurchaseUpgrade.d.ts +117 -0
  26. package/dist/schema/widget-data.cjs +452 -441
  27. package/dist/schema/widget-data.mjs +452 -441
  28. package/dist/schema/widgets/checkout-and-beyond/common.d.ts +14 -0
  29. package/dist/schema/widgets/checkout-and-beyond/image.d.ts +8 -0
  30. package/dist/schema/widgets/checkout-and-beyond/imageThumbnails.d.ts +13 -0
  31. package/dist/schema/widgets/checkout-and-beyond/index.d.ts +1 -0
  32. package/dist/schema/widgets/checkout-and-beyond/variants.d.ts +1 -0
  33. package/dist/server/index.cjs +1721 -1419
  34. package/dist/server/index.mjs +1707 -1405
  35. package/dist/server/postPurchasePlanCatalog.d.ts +4 -1
  36. package/dist/server/preparePostPurchaseAdmissionView.d.ts +53 -0
  37. package/dist/server/preparePostPurchaseCollectionGroup.d.ts +57 -0
  38. package/dist/server/preparePostPurchaseCollectionView.d.ts +53 -0
  39. package/dist/server/preparePostPurchaseGroupAdmissionView.d.ts +53 -0
  40. package/dist/server/preparePostPurchaseGroupDefault.d.ts +53 -0
  41. package/dist/server/preparePostPurchaseGroupView.d.ts +53 -0
  42. package/dist/server/preparePostPurchaseMemberView.d.ts +159 -0
  43. package/dist/server/preparePostPurchaseQuantityAdmissionView.d.ts +53 -0
  44. package/dist/server/preparePostPurchaseQuantityView.d.ts +53 -0
  45. package/dist/server/preparePostPurchaseSubscription.d.ts +1 -0
  46. package/dist/server/selectPostPurchaseChoice.d.ts +1 -0
  47. package/dist/transforms/index.cjs +980 -581
  48. package/dist/transforms/index.mjs +980 -581
  49. package/dist/transforms/postPurchase/convertProductInformation.d.ts +6 -2
  50. package/dist/transforms/postPurchase/productCardControls.d.ts +7 -0
  51. package/dist/transforms/postPurchase/productCardCosts.d.ts +3 -0
  52. package/dist/transforms/postPurchase/productCardPricing.d.ts +3 -0
  53. package/dist/transforms/postPurchase/productCardRows.d.ts +63 -0
  54. package/dist/transforms/postPurchase/productCardSettings.d.ts +103 -0
  55. package/dist/transforms/postPurchase/types.d.ts +2 -2
  56. package/dist/transforms/productCard/earnedText.d.ts +25 -0
  57. package/dist/transforms/productCard/priceText.d.ts +2 -0
  58. package/dist/transforms/productCard/quantitySection.d.ts +28 -0
  59. package/dist/transforms/productCard/subscriptionToggle.d.ts +18 -0
  60. package/package.json +1 -1
@@ -624,7 +624,7 @@ var CabUserConfig = z6.object({
624
624
 
625
625
  // src/schema/widgets/checkout-and-beyond/image.ts
626
626
  import { v7 as uuidv713 } from "uuid";
627
- import { z as z27 } from "zod";
627
+ import { z as z28 } from "zod";
628
628
 
629
629
  // src/schema/widgets/checkout-and-beyond/common.ts
630
630
  var freezeEnum = (values2) => Object.freeze(Object.fromEntries(values2.map((v) => [v, v])));
@@ -794,6 +794,8 @@ var variableTypes = ["boolean", "number", "text"];
794
794
  var VariableType = freezeEnum(variableTypes);
795
795
  var variantModes = ["multiple", "single"];
796
796
  var VariantMode = freezeEnum(variantModes);
797
+ var variantsModes = [...variantModes, "productGroup"];
798
+ var VariantsMode = freezeEnum(variantsModes);
797
799
  var variantSelectors = ["menu", "radio", "button"];
798
800
  var VariantSelector = freezeEnum(variantSelectors);
799
801
  var verticalAlignments = ["top", "middle", "bottom"];
@@ -910,6 +912,13 @@ var IconSize = freezeEnum(iconSizes);
910
912
  var iconTones = ["auto", "critical", "custom", "info", "neutral", "success", "warning"];
911
913
  var IconTone = freezeEnum(iconTones);
912
914
 
915
+ // src/schema/widgets/checkout-and-beyond/imageThumbnails.ts
916
+ import { z as z7 } from "zod";
917
+ var CABImageThumbnails = z7.object({
918
+ limit: z7.number().int().min(1).default(8),
919
+ perLine: z7.number().int().min(1).max(8).default(4)
920
+ });
921
+
913
922
  // src/schema/widgets/checkout-and-beyond/regex.ts
914
923
  var DYNAMIC_TOKEN_REGEX = /^\{\{\s*[A-Za-z]+\s*\}\}$/;
915
924
  var HEX_COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
@@ -917,20 +926,20 @@ var ROOT_RELATIVE_PATH_REGEX = /^\/(?!\/)/;
917
926
  var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
918
927
 
919
928
  // src/schema/widgets/checkout-and-beyond/shared.ts
920
- import { z as z26 } from "zod";
929
+ import { z as z27 } from "zod";
921
930
 
922
931
  // src/schema/widgets/checkout-and-beyond/banner.ts
923
- import { z as z10 } from "zod";
932
+ import { z as z11 } from "zod";
924
933
 
925
934
  // src/schema/widgets/checkout-and-beyond/layout.ts
926
935
  import { v7 as uuidv7 } from "uuid";
927
- import { z as z9 } from "zod";
936
+ import { z as z10 } from "zod";
928
937
 
929
938
  // src/schema/widgets/checkout-and-beyond/variables.ts
930
- import { z as z8 } from "zod";
939
+ import { z as z9 } from "zod";
931
940
 
932
941
  // src/schema/widgets/checkout-and-beyond/rule.ts
933
- import { z as z7 } from "zod";
942
+ import { z as z8 } from "zod";
934
943
  var ruleTypes = [
935
944
  "cart",
936
945
  "cart_count",
@@ -949,7 +958,7 @@ var ruleTypes = [
949
958
  "product_type",
950
959
  "product_vendor"
951
960
  ];
952
- var ruleType = z7.enum(ruleTypes);
961
+ var ruleType = z8.enum(ruleTypes);
953
962
  var RuleType = ruleType.enum;
954
963
  var ruleOperators = [
955
964
  "after",
@@ -964,148 +973,148 @@ var ruleOperators = [
964
973
  "greater_than",
965
974
  "less_than"
966
975
  ];
967
- var ruleOperator = z7.enum(ruleOperators);
976
+ var ruleOperator = z8.enum(ruleOperators);
968
977
  var RuleOperator = ruleOperator.enum;
969
- var RuleCondition = z7.object({
970
- operator: z7.enum(ruleOperators).default(RuleOperator.anything),
971
- products: z7.union([z7.array(z7.unknown()), z7.strictObject({}).transform(() => [])]).default(() => []),
972
- type: z7.enum(ruleTypes).default(RuleType.cart_subtotal),
973
- value: z7.coerce.string().default("")
974
- });
975
- var RuleLogicBlock = z7.object({
976
- rules: z7.array(RuleCondition).default(() => [])
977
- });
978
- var CABRulesetEntry = z7.object({
979
- exitIfMatched: z7.boolean().default(true),
980
- logic: z7.array(RuleLogicBlock).default(() => []),
981
- output: z7.array(
982
- z7.object({
983
- key: z7.string().default("should_show"),
984
- type: z7.literal("data_json").default("data_json"),
985
- value: z7.string().default("true")
978
+ var RuleCondition = z8.object({
979
+ operator: z8.enum(ruleOperators).default(RuleOperator.anything),
980
+ products: z8.union([z8.array(z8.unknown()), z8.strictObject({}).transform(() => [])]).default(() => []),
981
+ type: z8.enum(ruleTypes).default(RuleType.cart_subtotal),
982
+ value: z8.coerce.string().default("")
983
+ });
984
+ var RuleLogicBlock = z8.object({
985
+ rules: z8.array(RuleCondition).default(() => [])
986
+ });
987
+ var CABRulesetEntry = z8.object({
988
+ exitIfMatched: z8.boolean().default(true),
989
+ logic: z8.array(RuleLogicBlock).default(() => []),
990
+ output: z8.array(
991
+ z8.object({
992
+ key: z8.string().default("should_show"),
993
+ type: z8.literal("data_json").default("data_json"),
994
+ value: z8.string().default("true")
986
995
  })
987
996
  ).default(() => [{ key: "should_show", type: "data_json", value: "true" }])
988
997
  });
989
- var CABRuleset = z7.union([z7.array(CABRulesetEntry), z7.strictObject({}).transform(() => [])]).default(() => []);
998
+ var CABRuleset = z8.union([z8.array(CABRulesetEntry), z8.strictObject({}).transform(() => [])]).default(() => []);
990
999
 
991
1000
  // src/schema/widgets/checkout-and-beyond/variables.ts
992
- var variableEffect = z8.enum(variableEffects);
993
- var CABVariableSeed = z8.object({
994
- dataSourceId: z8.number().nullable().default(null),
1001
+ var variableEffect = z9.enum(variableEffects);
1002
+ var CABVariableSeed = z9.object({
1003
+ dataSourceId: z9.number().nullable().default(null),
995
1004
  ruleset: CABRuleset
996
1005
  });
997
- var CABBooleanVariable = z8.object({
1006
+ var CABBooleanVariable = z9.object({
998
1007
  /**
999
1008
  * Holds until the first seed verdict lands (and forever, for unseeded variables). Omitted, it derives
1000
1009
  * from seededness — `false` with a `seed` (visibility is EARNED), `true` without — via the transform
1001
1010
  * below; a cross-field default has no `.default()` spelling. An explicit value always wins.
1002
1011
  */
1003
- defaultValue: z8.boolean().optional(),
1004
- name: z8.string().min(1),
1012
+ defaultValue: z9.boolean().optional(),
1013
+ name: z9.string().min(1),
1005
1014
  seed: CABVariableSeed.optional(),
1006
1015
  /** Defaulted so every stored declaration (all boolean before `text` existed) parses unchanged. */
1007
- type: z8.literal(VariableType.boolean).default(VariableType.boolean)
1016
+ type: z9.literal(VariableType.boolean).default(VariableType.boolean)
1008
1017
  });
1009
- var CABTextVariable = z8.object({
1010
- defaultValue: z8.string(),
1011
- name: z8.string().min(1),
1012
- seed: z8.never().optional(),
1013
- type: z8.literal(VariableType.text)
1018
+ var CABTextVariable = z9.object({
1019
+ defaultValue: z9.string(),
1020
+ name: z9.string().min(1),
1021
+ seed: z9.never().optional(),
1022
+ type: z9.literal(VariableType.text)
1014
1023
  });
1015
- var CABNumberVariable = z8.object({
1016
- defaultValue: z8.number(),
1017
- name: z8.string().min(1),
1018
- seed: z8.never().optional(),
1019
- type: z8.literal(VariableType.number)
1024
+ var CABNumberVariable = z9.object({
1025
+ defaultValue: z9.number(),
1026
+ name: z9.string().min(1),
1027
+ seed: z9.never().optional(),
1028
+ type: z9.literal(VariableType.number)
1020
1029
  });
1021
- var CABVariable = z8.union([CABTextVariable, CABNumberVariable, CABBooleanVariable]).transform(
1030
+ var CABVariable = z9.union([CABTextVariable, CABNumberVariable, CABBooleanVariable]).transform(
1022
1031
  (variable) => variable.type === VariableType.boolean ? { ...variable, defaultValue: variable.defaultValue ?? variable.seed === void 0 } : variable
1023
1032
  );
1024
- var CABVariableEffect = z8.object({
1033
+ var CABVariableEffect = z9.object({
1025
1034
  effect: variableEffect.default(VariableEffect.toggle),
1026
- variable: z8.string().min(1)
1035
+ variable: z9.string().min(1)
1027
1036
  });
1028
- var CABVisibility = z8.object({
1029
- variable: z8.string().min(1),
1030
- visibleWhen: z8.boolean().default(true)
1037
+ var CABVisibility = z9.object({
1038
+ variable: z9.string().min(1),
1039
+ visibleWhen: z9.boolean().default(true)
1031
1040
  });
1032
- var contentOperator = z8.enum(contentOperators);
1033
- var resultCountOperator = z8.enum(resultCountOperators);
1034
- var resultTagOperator = z8.enum(resultTagOperators);
1035
- var mutatorEvent = z8.enum(mutatorEvents);
1036
- var CABContentTrigger = z8.object({
1041
+ var contentOperator = z9.enum(contentOperators);
1042
+ var resultCountOperator = z9.enum(resultCountOperators);
1043
+ var resultTagOperator = z9.enum(resultTagOperators);
1044
+ var mutatorEvent = z9.enum(mutatorEvents);
1045
+ var CABContentTrigger = z9.object({
1037
1046
  operator: contentOperator.default(ContentOperator.is_empty),
1038
- type: z8.literal("content")
1047
+ type: z9.literal("content")
1039
1048
  });
1040
- var CABResultCountTrigger = z8.object({
1049
+ var CABResultCountTrigger = z9.object({
1041
1050
  operator: resultCountOperator.default(ResultCountOperator.equals),
1042
- type: z8.literal("result_count"),
1043
- value: z8.number().default(0)
1051
+ type: z9.literal("result_count"),
1052
+ value: z9.number().default(0)
1044
1053
  });
1045
- var CABResultTagTrigger = z8.object({
1054
+ var CABResultTagTrigger = z9.object({
1046
1055
  operator: resultTagOperator.default(ResultTagOperator.contains),
1047
- type: z8.literal("result_tag"),
1048
- value: z8.string().min(1)
1056
+ type: z9.literal("result_tag"),
1057
+ value: z9.string().min(1)
1049
1058
  });
1050
- var CABEventTrigger = z8.object({
1059
+ var CABEventTrigger = z9.object({
1051
1060
  event: mutatorEvent,
1052
- type: z8.literal("event")
1061
+ type: z9.literal("event")
1053
1062
  });
1054
- var CABVariableTrigger = z8.discriminatedUnion("type", [
1063
+ var CABVariableTrigger = z9.discriminatedUnion("type", [
1055
1064
  CABContentTrigger,
1056
1065
  CABEventTrigger,
1057
1066
  CABResultCountTrigger,
1058
1067
  CABResultTagTrigger
1059
1068
  ]);
1060
- var CABVariableMutator = z8.object({
1069
+ var CABVariableMutator = z9.object({
1061
1070
  effect: variableEffect.default(VariableEffect.set_false),
1062
- variable: z8.string().min(1),
1071
+ variable: z9.string().min(1),
1063
1072
  when: CABVariableTrigger
1064
1073
  });
1065
1074
  var CABVariableFields = {
1066
- mutators: z8.array(CABVariableMutator).optional(),
1067
- variables: z8.array(CABVariable).refine((variables) => new Set(variables.map(({ name }) => name)).size === variables.length, {
1075
+ mutators: z9.array(CABVariableMutator).optional(),
1076
+ variables: z9.array(CABVariable).refine((variables) => new Set(variables.map(({ name }) => name)).size === variables.length, {
1068
1077
  message: "variable names must be unique within a section"
1069
1078
  }).optional(),
1070
1079
  visibility: CABVisibility.optional()
1071
1080
  };
1072
1081
 
1073
1082
  // src/schema/widgets/checkout-and-beyond/layout.ts
1074
- var GridItem = z9.union([z9.literal("auto"), z9.literal("fill"), z9.string().regex(/^\d+%$/), z9.number()]);
1075
- var CABLayoutWrapping = z9.object({
1076
- breakAt: z9.number().positive(),
1077
- maxPerLine: z9.number().int().positive()
1083
+ var GridItem = z10.union([z10.literal("auto"), z10.literal("fill"), z10.string().regex(/^\d+%$/), z10.number()]);
1084
+ var CABLayoutWrapping = z10.object({
1085
+ breakAt: z10.number().positive(),
1086
+ maxPerLine: z10.number().int().positive()
1078
1087
  });
1079
- var CABLayoutSection = z9.object({
1088
+ var CABLayoutSection = z10.object({
1080
1089
  ...CABVariableFields,
1081
- alignment: z9.object({
1082
- horizontal: z9.enum(horizontalAlignments).default(HorizontalAlignment.start),
1083
- vertical: z9.enum(verticalAlignments).default(VerticalAlignment.top)
1090
+ alignment: z10.object({
1091
+ horizontal: z10.enum(horizontalAlignments).default(HorizontalAlignment.start),
1092
+ vertical: z10.enum(verticalAlignments).default(VerticalAlignment.top)
1084
1093
  }).default({
1085
1094
  horizontal: HorizontalAlignment.start,
1086
1095
  vertical: VerticalAlignment.top
1087
1096
  }),
1088
- border: z9.lazy(() => CABBorder),
1089
- buttonField: z9.enum(buttonFields).optional(),
1090
- direction: z9.enum(directions).default(Direction.rows),
1097
+ border: z10.lazy(() => CABBorder),
1098
+ buttonField: z10.enum(buttonFields).optional(),
1099
+ direction: z10.enum(directions).default(Direction.rows),
1091
1100
  /**
1092
1101
  * Platform chrome around the section, not a layout behavior: `callout` is a subdued box with block borders
1093
1102
  * (the legacy post-purchase callout banner), `offer-content` the post-purchase offer's own content card.
1094
1103
  */
1095
- frame: z9.enum(layoutFrames).optional(),
1096
- grid: z9.object({
1097
- columns: z9.union([z9.array(GridItem), z9.undefined()]).default(() => ["auto"]),
1098
- rows: z9.union([z9.array(GridItem), z9.undefined()]).default(() => ["auto"])
1104
+ frame: z10.enum(layoutFrames).optional(),
1105
+ grid: z10.object({
1106
+ columns: z10.union([z10.array(GridItem), z10.undefined()]).default(() => ["auto"]),
1107
+ rows: z10.union([z10.array(GridItem), z10.undefined()]).default(() => ["auto"])
1099
1108
  }).default({ columns: ["auto"], rows: ["auto"] }).optional(),
1100
- name: z9.string().optional(),
1101
- padding: z9.enum(spacings).default(Spacing.none),
1102
- sectionId: z9.uuid().default(() => uuidv7()),
1103
- sections: z9.union([z9.array(z9.lazy(() => CABSection)), z9.strictObject({}).transform(() => [])]).default(() => []),
1104
- sectionType: z9.literal(SectionType.layout).default(SectionType.layout),
1105
- spacing: z9.enum(spacings).default(Spacing.base),
1109
+ name: z10.string().optional(),
1110
+ padding: z10.enum(spacings).default(Spacing.none),
1111
+ sectionId: z10.uuid().default(() => uuidv7()),
1112
+ sections: z10.union([z10.array(z10.lazy(() => CABSection)), z10.strictObject({}).transform(() => [])]).default(() => []),
1113
+ sectionType: z10.literal(SectionType.layout).default(SectionType.layout),
1114
+ spacing: z10.enum(spacings).default(Spacing.base),
1106
1115
  /** Fire-and-forget impression pixel POSTed once when the section is shown (e.g. a Monetize offer view). */
1107
- viewUrl: z9.string().optional(),
1108
- width: z9.number().default(100),
1116
+ viewUrl: z10.string().optional(),
1117
+ width: z10.number().default(100),
1109
1118
  wrapping: CABLayoutWrapping.optional()
1110
1119
  });
1111
1120
 
@@ -1176,11 +1185,11 @@ var isTextType = isSectionType(SectionType.text);
1176
1185
  var isVariantsType = isSectionType(SectionType.variants);
1177
1186
 
1178
1187
  // src/schema/widgets/checkout-and-beyond/banner.ts
1179
- var CABBannerSection = z10.lazy(
1188
+ var CABBannerSection = z11.lazy(
1180
1189
  () => CABLayoutSection.omit({ sectionType: true }).extend({
1181
- buttonField: z10.enum(buttonFields).optional(),
1182
- color: z10.enum(bannerColors).default("info"),
1183
- dismissible: z10.boolean().default(true),
1190
+ buttonField: z11.enum(buttonFields).optional(),
1191
+ color: z11.enum(bannerColors).default("info"),
1192
+ dismissible: z11.boolean().default(true),
1184
1193
  /**
1185
1194
  * The `s-banner` heading — localized content (a buyer can see a merchant-composed banner). Absent OR
1186
1195
  * blank ⇒ no heading; the renderer emits no heading slot for `''` rather than an empty one.
@@ -1196,83 +1205,83 @@ var CABBannerSection = z10.lazy(
1196
1205
  * not a 500. Nothing emits `heading` yet; the first converter that maps merchant banner copy into it
1197
1206
  * either strips first or teaches `normalizeTextContent` to strip this field.
1198
1207
  */
1199
- heading: z10.record(z10.string(), z10.string().refine(checkForHTML, NO_HTML)).optional(),
1200
- sectionType: z10.literal(SectionType.banner).default(SectionType.banner)
1208
+ heading: z11.record(z11.string(), z11.string().refine(checkForHTML, NO_HTML)).optional(),
1209
+ sectionType: z11.literal(SectionType.banner).default(SectionType.banner)
1201
1210
  })
1202
1211
  );
1203
1212
 
1204
1213
  // src/schema/widgets/checkout-and-beyond/button.ts
1205
1214
  import { v7 as uuidv73 } from "uuid";
1206
- import { z as z12 } from "zod";
1215
+ import { z as z13 } from "zod";
1207
1216
 
1208
1217
  // src/schema/widgets/checkout-and-beyond/text.ts
1209
1218
  import { forEach, isString as isString2 } from "es-toolkit/compat";
1210
1219
  import { v7 as uuidv72 } from "uuid";
1211
- import { z as z11 } from "zod";
1212
- var enumOrOmit = (...vals) => z11.string().transform((val) => vals.includes(val) ? val : void 0).optional();
1213
- var TiptapText = z11.object({
1214
- marks: z11.union([
1215
- z11.array(
1216
- z11.discriminatedUnion("type", [
1217
- z11.object({ type: z11.literal("bold") }),
1218
- z11.object({ type: z11.literal("italic") }),
1219
- z11.object({
1220
- attrs: z11.object({
1221
- class: z11.string().nullable(),
1222
- href: z11.union([
1223
- z11.url(),
1224
- z11.literal("#"),
1225
- z11.string().regex(DYNAMIC_TOKEN_REGEX),
1226
- z11.string().regex(ROOT_RELATIVE_PATH_REGEX)
1220
+ import { z as z12 } from "zod";
1221
+ var enumOrOmit = (...vals) => z12.string().transform((val) => vals.includes(val) ? val : void 0).optional();
1222
+ var TiptapText = z12.object({
1223
+ marks: z12.union([
1224
+ z12.array(
1225
+ z12.discriminatedUnion("type", [
1226
+ z12.object({ type: z12.literal("bold") }),
1227
+ z12.object({ type: z12.literal("italic") }),
1228
+ z12.object({
1229
+ attrs: z12.object({
1230
+ class: z12.string().nullable(),
1231
+ href: z12.union([
1232
+ z12.url(),
1233
+ z12.literal("#"),
1234
+ z12.string().regex(DYNAMIC_TOKEN_REGEX),
1235
+ z12.string().regex(ROOT_RELATIVE_PATH_REGEX)
1227
1236
  ]),
1228
- rel: z11.string().default("noopener noreferrer nofollow"),
1229
- target: z11.string().default("_blank")
1237
+ rel: z12.string().default("noopener noreferrer nofollow"),
1238
+ target: z12.string().default("_blank")
1230
1239
  }),
1231
- type: z11.literal("link")
1240
+ type: z12.literal("link")
1232
1241
  }),
1233
- z11.object({ type: z11.literal("strike") }),
1234
- z11.object({
1235
- attrs: z11.object({
1242
+ z12.object({ type: z12.literal("strike") }),
1243
+ z12.object({
1244
+ attrs: z12.object({
1236
1245
  color: enumOrOmit(...textColorNames).default(TextColorName.base),
1237
1246
  fontSize: enumOrOmit(...textSizeNames).default(TextSizeName.base)
1238
1247
  }),
1239
- type: z11.literal("textStyle")
1248
+ type: z12.literal("textStyle")
1240
1249
  })
1241
1250
  ])
1242
1251
  ),
1243
- z11.strictObject({}).transform(() => [])
1252
+ z12.strictObject({}).transform(() => [])
1244
1253
  ]).optional(),
1245
- text: z11.string().default(""),
1246
- type: z11.literal("text").default("text")
1254
+ text: z12.string().default(""),
1255
+ type: z12.literal("text").default("text")
1247
1256
  });
1248
- var TiptapParagraph = z11.object({
1249
- attrs: z11.object({
1257
+ var TiptapParagraph = z12.object({
1258
+ attrs: z12.object({
1250
1259
  textAlign: enumOrOmit(...textAlignments)
1251
1260
  }).default({ textAlign: TextAlignment.start }),
1252
- content: z11.union([z11.array(TiptapText), z11.strictObject({}).transform(() => [])]).default(() => []),
1253
- type: z11.literal("paragraph").default("paragraph")
1261
+ content: z12.union([z12.array(TiptapText), z12.strictObject({}).transform(() => [])]).default(() => []),
1262
+ type: z12.literal("paragraph").default("paragraph")
1254
1263
  });
1255
- var TiptapDocument = z11.object({
1256
- attrs: z11.object({
1264
+ var TiptapDocument = z12.object({
1265
+ attrs: z12.object({
1257
1266
  blockSpacing: enumOrOmit(...spacings)
1258
1267
  }).default({ blockSpacing: Spacing.base }),
1259
- content: z11.union([z11.array(TiptapParagraph), z11.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
1260
- type: z11.literal("doc").default("doc")
1268
+ content: z12.union([z12.array(TiptapParagraph), z12.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
1269
+ type: z12.literal("doc").default("doc")
1261
1270
  });
1262
- var CABTextTier = z11.object({
1263
- threshold: z11.number().int().nonnegative(),
1264
- thresholds: z11.record(z11.string(), z11.number().int().nonnegative()).default(() => ({})),
1265
- tierId: z11.string().optional(),
1266
- tierType: z11.enum(progressTierTypes).default(ProgressTierType.shipping)
1271
+ var CABTextTier = z12.object({
1272
+ threshold: z12.number().int().nonnegative(),
1273
+ thresholds: z12.record(z12.string(), z12.number().int().nonnegative()).default(() => ({})),
1274
+ tierId: z12.string().optional(),
1275
+ tierType: z12.enum(progressTierTypes).default(ProgressTierType.shipping)
1267
1276
  });
1268
- var CABTextSection = z11.object({
1277
+ var CABTextSection = z12.object({
1269
1278
  ...CABVariableFields,
1270
- buttonField: z11.enum(buttonFields).optional(),
1271
- content: z11.record(z11.string(), z11.union([z11.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
1272
- name: z11.string().optional(),
1273
- optionId: z11.number().optional(),
1274
- sectionId: z11.uuid().default(() => uuidv72()),
1275
- sectionType: z11.literal(SectionType.text).default(SectionType.text),
1279
+ buttonField: z12.enum(buttonFields).optional(),
1280
+ content: z12.record(z12.string(), z12.union([z12.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
1281
+ name: z12.string().optional(),
1282
+ optionId: z12.number().optional(),
1283
+ sectionId: z12.uuid().default(() => uuidv72()),
1284
+ sectionType: z12.literal(SectionType.text).default(SectionType.text),
1276
1285
  tier: CABTextTier.optional()
1277
1286
  }).superRefine(({ buttonField, content }, ctx) => {
1278
1287
  if (buttonField === ButtonField.destinationUrl && content) {
@@ -1294,35 +1303,35 @@ var CABTextSection = z11.object({
1294
1303
  });
1295
1304
 
1296
1305
  // src/schema/widgets/checkout-and-beyond/button.ts
1297
- var CABButtonContent = z12.lazy(
1298
- () => z12.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
1306
+ var CABButtonContent = z13.lazy(
1307
+ () => z13.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
1299
1308
  );
1300
- var CABButtonSection = z12.object({
1309
+ var CABButtonSection = z13.object({
1301
1310
  ...CABVariableFields,
1302
- action: z12.union([z12.literal(""), z12.enum(buttonActions)]).default(""),
1303
- buttonStyle: z12.enum(buttonStyles).default(ButtonStyle.primary),
1304
- custom: z12.object({
1305
- color: z12.string().regex(HEX_COLOR_REGEX).default("#005bd3"),
1306
- height: z12.number().default(52),
1307
- width: z12.number().default(300)
1311
+ action: z13.union([z13.literal(""), z13.enum(buttonActions)]).default(""),
1312
+ buttonStyle: z13.enum(buttonStyles).default(ButtonStyle.primary),
1313
+ custom: z13.object({
1314
+ color: z13.string().regex(HEX_COLOR_REGEX).default("#005bd3"),
1315
+ height: z13.number().default(52),
1316
+ width: z13.number().default(300)
1308
1317
  }).default({
1309
1318
  color: "#005bd3",
1310
1319
  height: 52,
1311
1320
  width: 300
1312
1321
  }),
1313
- disableDowngrade: z12.boolean().default(false),
1314
- name: z12.string().optional(),
1315
- optionId: z12.number().optional(),
1316
- popover: z12.object({
1317
- alignment: z12.enum(textAlignments).default(TextAlignment.center),
1318
- position: z12.enum(popoverPositions).default(PopoverPosition.blockStart)
1322
+ disableDowngrade: z13.boolean().default(false),
1323
+ name: z13.string().optional(),
1324
+ optionId: z13.number().optional(),
1325
+ popover: z13.object({
1326
+ alignment: z13.enum(textAlignments).default(TextAlignment.center),
1327
+ position: z13.enum(popoverPositions).default(PopoverPosition.blockStart)
1319
1328
  }).optional().default(() => ({
1320
1329
  alignment: TextAlignment.center,
1321
1330
  position: PopoverPosition.blockStart
1322
1331
  })),
1323
- sectionId: z12.uuid().default(() => uuidv73()),
1324
- sections: z12.union([z12.array(CABButtonContent), z12.strictObject({}).transform(() => [])]).default(() => []),
1325
- sectionType: z12.literal(SectionType.button).default(SectionType.button),
1332
+ sectionId: z13.uuid().default(() => uuidv73()),
1333
+ sections: z13.union([z13.array(CABButtonContent), z13.strictObject({}).transform(() => [])]).default(() => []),
1334
+ sectionType: z13.literal(SectionType.button).default(SectionType.button),
1326
1335
  /**
1327
1336
  * The smart-cart tier this button acts on (`addGift`/`removeGift`): scopes the click to one tier's gift. The
1328
1337
  * client resolves the tier's gift (productId) from the progress-bar context by this `tierId` — the button node
@@ -1337,25 +1346,25 @@ var CABButtonSection = z12.object({
1337
1346
  * lookup finds no tier and the click resolves to nothing. Safe to bound — the field is new, so there are no
1338
1347
  * stored payloads to grandfather, and the producer is client code, not a merchant form.
1339
1348
  */
1340
- tier: z12.object({ tierId: z12.string().min(1) }).optional(),
1349
+ tier: z13.object({ tierId: z13.string().min(1) }).optional(),
1341
1350
  /** Fire-and-forget pixel POSTed when the button is clicked (e.g. a Monetize decline). */
1342
- trackingUrl: z12.string().optional(),
1351
+ trackingUrl: z13.string().optional(),
1343
1352
  /**
1344
1353
  * Secondary effects applied to in-scope variables on click, alongside (never instead of) the primary
1345
1354
  * `action` — an `addToOrder` button can also flip a variable. Applied in array order.
1346
1355
  */
1347
- variableEffects: z12.array(CABVariableEffect).optional()
1356
+ variableEffects: z13.array(CABVariableEffect).optional()
1348
1357
  });
1349
1358
 
1350
1359
  // src/schema/widgets/checkout-and-beyond/carousel.ts
1351
- import { z as z17 } from "zod";
1360
+ import { z as z18 } from "zod";
1352
1361
 
1353
1362
  // src/schema/widgets/checkout-and-beyond/offers.ts
1354
- import { z as z16 } from "zod";
1363
+ import { z as z17 } from "zod";
1355
1364
 
1356
1365
  // src/schema/widgets/checkout-and-beyond/dataSource.ts
1357
1366
  import { v7 as uuidv74 } from "uuid";
1358
- import { z as z13 } from "zod";
1367
+ import { z as z14 } from "zod";
1359
1368
 
1360
1369
  // src/schema/widgets/checkout-and-beyond/constants.ts
1361
1370
  import { uniqBy } from "es-toolkit";
@@ -1409,77 +1418,77 @@ var targetAreas = {
1409
1418
  };
1410
1419
 
1411
1420
  // src/schema/widgets/checkout-and-beyond/dataSource.ts
1412
- var CABDiscount = z13.object({
1413
- amount: z13.union([z13.number(), z13.string()]).catch(0),
1414
- discountedBy: z13.string().optional(),
1415
- discountedFrom: z13.enum(discountSources).optional().catch(void 0),
1416
- type: z13.enum(discountTypes).catch("none")
1417
- });
1418
- var CABIntegrations = z13.object({
1419
- judgeme: z13.boolean().default(false),
1420
- junip: z13.boolean().default(false),
1421
- klaviyo: z13.boolean().default(false),
1422
- loox: z13.boolean().default(false),
1423
- okendo: z13.boolean().default(false),
1424
- opinew: z13.boolean().default(false),
1425
- reviewsio: z13.boolean().default(false),
1426
- stamped: z13.boolean().default(false),
1427
- yotpo: z13.boolean().default(false)
1428
- });
1429
- var CABVariantLabels = z13.object({
1430
- variantOption: z13.string().optional().catch(void 0),
1431
- variantOptions: z13.string().optional().catch(void 0)
1432
- });
1433
- var CABDataSourceSection = z13.object({
1434
- dataSourceId: z13.number().nullable().default(null),
1435
- dataSourcePath: z13.string().default(DEFAULT_ENDPOINTS[0].value),
1421
+ var CABDiscount = z14.object({
1422
+ amount: z14.union([z14.number(), z14.string()]).catch(0),
1423
+ discountedBy: z14.string().optional(),
1424
+ discountedFrom: z14.enum(discountSources).optional().catch(void 0),
1425
+ type: z14.enum(discountTypes).catch("none")
1426
+ });
1427
+ var CABIntegrations = z14.object({
1428
+ judgeme: z14.boolean().default(false),
1429
+ junip: z14.boolean().default(false),
1430
+ klaviyo: z14.boolean().default(false),
1431
+ loox: z14.boolean().default(false),
1432
+ okendo: z14.boolean().default(false),
1433
+ opinew: z14.boolean().default(false),
1434
+ reviewsio: z14.boolean().default(false),
1435
+ stamped: z14.boolean().default(false),
1436
+ yotpo: z14.boolean().default(false)
1437
+ });
1438
+ var CABVariantLabels = z14.object({
1439
+ variantOption: z14.string().optional().catch(void 0),
1440
+ variantOptions: z14.string().optional().catch(void 0)
1441
+ });
1442
+ var CABDataSourceSection = z14.object({
1443
+ dataSourceId: z14.number().nullable().default(null),
1444
+ dataSourcePath: z14.string().default(DEFAULT_ENDPOINTS[0].value),
1436
1445
  discount: CABDiscount.optional(),
1437
1446
  integrations: CABIntegrations.optional(),
1438
- limit: z13.number().default(1),
1439
- matchVariant: z13.boolean().default(false),
1440
- matchVariantOutOfStock: z13.boolean().default(false),
1441
- name: z13.string().default(DEFAULT_ENDPOINTS[0].label),
1442
- productType: z13.enum(productTypes).optional(),
1443
- sectionId: z13.uuid().default(() => uuidv74()),
1444
- sectionType: z13.literal(SectionType.dataSource).default(SectionType.dataSource),
1447
+ limit: z14.number().default(1),
1448
+ matchVariant: z14.boolean().default(false),
1449
+ matchVariantOutOfStock: z14.boolean().default(false),
1450
+ name: z14.string().default(DEFAULT_ENDPOINTS[0].label),
1451
+ productType: z14.enum(productTypes).optional(),
1452
+ sectionId: z14.uuid().default(() => uuidv74()),
1453
+ sectionType: z14.literal(SectionType.dataSource).default(SectionType.dataSource),
1445
1454
  /** Default subscribe-vs-one-time for `productType: both` (legacy `subscription_is_default`). */
1446
- subscriptionIsDefault: z13.boolean().default(false),
1447
- treatAsGwp: z13.boolean().default(false),
1455
+ subscriptionIsDefault: z14.boolean().default(false),
1456
+ treatAsGwp: z14.boolean().default(false),
1448
1457
  variantLabels: CABVariantLabels.optional().catch(void 0)
1449
1458
  });
1450
1459
 
1451
1460
  // src/schema/widgets/checkout-and-beyond/products.ts
1452
1461
  import { v7 as uuidv76 } from "uuid";
1453
- import { z as z15 } from "zod";
1462
+ import { z as z16 } from "zod";
1454
1463
 
1455
1464
  // src/schema/widgets/checkout-and-beyond/product.ts
1456
1465
  import { v7 as uuidv75 } from "uuid";
1457
- import { z as z14 } from "zod";
1458
- var CABVariantContent = z14.lazy(
1459
- () => z14.discriminatedUnion("sectionType", [CABButtonSection, CABTextSection])
1466
+ import { z as z15 } from "zod";
1467
+ var CABVariantContent = z15.lazy(
1468
+ () => z15.discriminatedUnion("sectionType", [CABButtonSection, CABTextSection])
1460
1469
  );
1461
- var CABProductSection = z14.object({
1470
+ var CABProductSection = z15.object({
1462
1471
  ...CABVariableFields,
1463
- name: z14.string().optional(),
1464
- productId: z14.number().nullable().default(null),
1465
- sectionId: z14.uuid().default(() => uuidv75()),
1466
- sections: z14.union([z14.array(CABVariantContent), z14.strictObject({}).transform(() => [])]).default(() => []),
1467
- sectionType: z14.literal(SectionType.product).default(SectionType.product),
1468
- selectors: z14.record(z14.string(), z14.enum(variantSelectors).default(VariantSelector.menu)).default(() => ({})),
1469
- variantMode: z14.enum(variantModes).default(VariantMode.multiple)
1472
+ name: z15.string().optional(),
1473
+ productId: z15.number().nullable().default(null),
1474
+ sectionId: z15.uuid().default(() => uuidv75()),
1475
+ sections: z15.union([z15.array(CABVariantContent), z15.strictObject({}).transform(() => [])]).default(() => []),
1476
+ sectionType: z15.literal(SectionType.product).default(SectionType.product),
1477
+ selectors: z15.record(z15.string(), z15.enum(variantSelectors).default(VariantSelector.menu)).default(() => ({})),
1478
+ variantMode: z15.enum(variantModes).default(VariantMode.multiple)
1470
1479
  });
1471
1480
 
1472
1481
  // src/schema/widgets/checkout-and-beyond/products.ts
1473
- var CABProductsSection = z15.object({
1482
+ var CABProductsSection = z16.object({
1474
1483
  ...CABVariableFields,
1475
- name: z15.string().optional(),
1476
- sectionId: z15.uuid().default(() => uuidv76()),
1477
- sections: z15.union([z15.array(z15.lazy(() => CABProductSection)), z15.strictObject({}).transform(() => [])]).default(() => []),
1478
- sectionType: z15.literal(SectionType.products).default(SectionType.products)
1484
+ name: z16.string().optional(),
1485
+ sectionId: z16.uuid().default(() => uuidv76()),
1486
+ sections: z16.union([z16.array(z16.lazy(() => CABProductSection)), z16.strictObject({}).transform(() => [])]).default(() => []),
1487
+ sectionType: z16.literal(SectionType.products).default(SectionType.products)
1479
1488
  });
1480
1489
 
1481
1490
  // src/schema/widgets/checkout-and-beyond/offers.ts
1482
- var CABOffersSection = z16.lazy(
1491
+ var CABOffersSection = z17.lazy(
1483
1492
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
1484
1493
  /**
1485
1494
  * A rule between consecutive cards in the vertical list — legacy checkout-offers' `<Divider />`,
@@ -1487,8 +1496,8 @@ var CABOffersSection = z16.lazy(
1487
1496
  * run of products). Optional, not defaulted: only the v1 converter sets it (REB-24265); a
1488
1497
  * hand-built tree keeps React CAB's dividerless rendering.
1489
1498
  */
1490
- divider: z16.boolean().optional(),
1491
- sections: z16.union([z16.array(z16.lazy(() => CABSection)), z16.strictObject({}).transform(() => [])]).default(() => [
1499
+ divider: z17.boolean().optional(),
1500
+ sections: z17.union([z17.array(z17.lazy(() => CABSection)), z17.strictObject({}).transform(() => [])]).default(() => [
1492
1501
  CABBannerSection.parse({
1493
1502
  buttonField: "undoAddToOrder",
1494
1503
  color: "success",
@@ -1502,77 +1511,77 @@ var CABOffersSection = z16.lazy(
1502
1511
  CABDataSourceSection.parse({}),
1503
1512
  CABProductsSection.parse({})
1504
1513
  ]),
1505
- sectionType: z16.literal(SectionType.offers).default(SectionType.offers)
1514
+ sectionType: z17.literal(SectionType.offers).default(SectionType.offers)
1506
1515
  })
1507
1516
  );
1508
1517
 
1509
1518
  // src/schema/widgets/checkout-and-beyond/carousel.ts
1510
- var CABCarouselSection = z17.lazy(
1519
+ var CABCarouselSection = z18.lazy(
1511
1520
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
1512
- autoAdvanceInterval: z17.number().default(0),
1513
- itemsAtOnce: z17.number().min(1).default(1),
1521
+ autoAdvanceInterval: z18.number().default(0),
1522
+ itemsAtOnce: z18.number().min(1).default(1),
1514
1523
  /** Card arrangement for the offers child (`horizontal` = side-by-side) — NOT the carousel's own `direction`. */
1515
- offersDirection: z17.enum(offersDirections).default("vertical"),
1516
- sections: z17.union([z17.array(z17.lazy(() => CABSection)), z17.strictObject({}).transform(() => [])]).default(() => [CABOffersSection.parse({})]),
1517
- sectionType: z17.literal(SectionType.carousel).default(SectionType.carousel)
1524
+ offersDirection: z18.enum(offersDirections).default("vertical"),
1525
+ sections: z18.union([z18.array(z18.lazy(() => CABSection)), z18.strictObject({}).transform(() => [])]).default(() => [CABOffersSection.parse({})]),
1526
+ sectionType: z18.literal(SectionType.carousel).default(SectionType.carousel)
1518
1527
  })
1519
1528
  );
1520
1529
 
1521
1530
  // src/schema/widgets/checkout-and-beyond/cartLine.ts
1522
- import { z as z18 } from "zod";
1523
- var CABCartLineSection = z18.lazy(
1531
+ import { z as z19 } from "zod";
1532
+ var CABCartLineSection = z19.lazy(
1524
1533
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
1525
- sections: z18.union([z18.array(z18.lazy(() => CABSection)), z18.strictObject({}).transform(() => [])]).default(() => [CABButtonSection.parse({ action: ButtonAction.switchToSubscription })]),
1526
- sectionType: z18.literal(SectionType.cartLine).default(SectionType.cartLine)
1534
+ sections: z19.union([z19.array(z19.lazy(() => CABSection)), z19.strictObject({}).transform(() => [])]).default(() => [CABButtonSection.parse({ action: ButtonAction.switchToSubscription })]),
1535
+ sectionType: z19.literal(SectionType.cartLine).default(SectionType.cartLine)
1527
1536
  })
1528
1537
  );
1529
1538
 
1530
1539
  // src/schema/widgets/checkout-and-beyond/discount.ts
1531
1540
  import { v7 as uuidv77 } from "uuid";
1532
- import { z as z19 } from "zod";
1533
- var CABDiscountSection = z19.object({
1541
+ import { z as z20 } from "zod";
1542
+ var CABDiscountSection = z20.object({
1534
1543
  ...CABVariableFields,
1535
- amount: z19.union([z19.number(), z19.string()]).catch(0),
1536
- discountedBy: z19.string().optional(),
1537
- discountedFrom: z19.enum(discountSources).optional().catch(void 0),
1538
- message: z19.string().optional(),
1539
- name: z19.string().optional(),
1540
- quantity: z19.number().default(1),
1541
- sectionId: z19.uuid().default(() => uuidv77()),
1542
- sectionType: z19.literal(SectionType.discount).default(SectionType.discount),
1543
- type: z19.enum(discountTypes).catch("none")
1544
+ amount: z20.union([z20.number(), z20.string()]).catch(0),
1545
+ discountedBy: z20.string().optional(),
1546
+ discountedFrom: z20.enum(discountSources).optional().catch(void 0),
1547
+ message: z20.string().optional(),
1548
+ name: z20.string().optional(),
1549
+ quantity: z20.number().default(1),
1550
+ sectionId: z20.uuid().default(() => uuidv77()),
1551
+ sectionType: z20.literal(SectionType.discount).default(SectionType.discount),
1552
+ type: z20.enum(discountTypes).catch("none")
1544
1553
  });
1545
1554
 
1546
1555
  // src/schema/widgets/checkout-and-beyond/monetize.ts
1547
1556
  import { v7 as uuidv78 } from "uuid";
1548
- import { z as z20 } from "zod";
1549
- var CABMonetizeAds = z20.object({
1550
- requestId: z20.string().optional(),
1557
+ import { z as z21 } from "zod";
1558
+ var CABMonetizeAds = z21.object({
1559
+ requestId: z21.string().optional(),
1551
1560
  /** Defaulted here, never in the beacon: absence of information is `ads` itself being absent. */
1552
- testing: z20.boolean().default(false)
1561
+ testing: z21.boolean().default(false)
1553
1562
  });
1554
- var CABMonetizeSection = z20.object({
1563
+ var CABMonetizeSection = z21.object({
1555
1564
  ...CABVariableFields,
1556
1565
  ads: CABMonetizeAds.optional(),
1557
- name: z20.string().optional(),
1566
+ name: z21.string().optional(),
1558
1567
  /**
1559
1568
  * Server-hydrated offer cards (inline hydration): when `/cab/sections` was asked with a `monetize`
1560
1569
  * context block, the composed cards ride the marker itself — `[]` means "hydrated, no fill" (render
1561
1570
  * nothing, skip the fetch); ABSENT means "not hydrated" (the client fetches via `/cab/monetize`).
1562
1571
  */
1563
- offers: z20.array(z20.lazy(() => CABSection)).optional(),
1572
+ offers: z21.array(z21.lazy(() => CABSection)).optional(),
1564
1573
  /** Privacy Policy footer href (the widget's `privacy_policy_url` setting); read server-side for hydration, relayed by the client only on the legacy `/cab/monetize` fallback. */
1565
- privacyPolicyUrl: z20.string().optional(),
1566
- sectionId: z20.uuid().default(() => uuidv78()),
1567
- sectionType: z20.literal(SectionType.monetize).default(SectionType.monetize),
1574
+ privacyPolicyUrl: z21.string().optional(),
1575
+ sectionId: z21.uuid().default(() => uuidv78()),
1576
+ sectionType: z21.literal(SectionType.monetize).default(SectionType.monetize),
1568
1577
  /** Ads-taxonomy sub-vertical id (the widget's `sub_vertical` setting); paired with `vertical`. */
1569
- subVertical: z20.string().optional(),
1578
+ subVertical: z21.string().optional(),
1570
1579
  /** Ads-taxonomy vertical id (the widget's `vertical` setting) — with `subVertical`, the admin Monetize editor's two configurables. */
1571
- vertical: z20.string().optional()
1580
+ vertical: z21.string().optional()
1572
1581
  });
1573
1582
 
1574
1583
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1575
- import { z as z21 } from "zod";
1584
+ import { z as z22 } from "zod";
1576
1585
 
1577
1586
  // src/schema/widgets/checkout-and-beyond/giftLabels.ts
1578
1587
  var GIFT_LABELS = {
@@ -1691,34 +1700,34 @@ var GIFT_LABELS = {
1691
1700
  };
1692
1701
 
1693
1702
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1694
- var CABProgressTierExclusion = z21.object({
1695
- collectionIds: z21.array(z21.number().int().positive()).default(() => []),
1696
- productIds: z21.array(z21.number().int().positive()).default(() => []),
1697
- tags: z21.array(z21.string().min(1)).default(() => []),
1698
- type: z21.enum(progressTierExclusionTypes)
1703
+ var CABProgressTierExclusion = z22.object({
1704
+ collectionIds: z22.array(z22.number().int().positive()).default(() => []),
1705
+ productIds: z22.array(z22.number().int().positive()).default(() => []),
1706
+ tags: z22.array(z22.string().min(1)).default(() => []),
1707
+ type: z22.enum(progressTierExclusionTypes)
1699
1708
  });
1700
- var CABProgressTier = z21.object({
1709
+ var CABProgressTier = z22.object({
1701
1710
  /**
1702
1711
  * Order-discount tiers only (onsite `discount`): the reward the order-discount Function applies at
1703
1712
  * cart time, carried so the client can resolve the `{{discountAmount}}` token in this tier's copy.
1704
1713
  * `fixedAmount`: shop-currency CENTS (FX-scaled by the client, like {@link CABProgressTier.threshold});
1705
1714
  * `percentage`: the whole-percent number rendered raw (`{n}%`). Absent on non-discount tiers.
1706
1715
  */
1707
- discount: z21.object({ amount: z21.number().nonnegative(), type: z21.enum(["fixedAmount", "percentage"]) }).optional(),
1716
+ discount: z22.object({ amount: z22.number().nonnegative(), type: z22.enum(["fixedAmount", "percentage"]) }).optional(),
1708
1717
  /**
1709
1718
  * Per-tier exclusion rules (onsite `exclusions` when `exclusions_enabled`): lines they match don't count
1710
1719
  * toward this tier. Empty (the default, and the converter's output for a disabled or ruleless tier) means
1711
1720
  * the tier measures the plain bar-level adjusted progress. Consumers read ONLY the list named by the rule's
1712
1721
  * `type` — the converter leaves the other two at `[]`, so a populated off-type list never reaches the tree.
1713
1722
  */
1714
- exclusions: z21.array(CABProgressTierExclusion).default(() => []),
1723
+ exclusions: z22.array(CABProgressTierExclusion).default(() => []),
1715
1724
  /**
1716
1725
  * Smart-cart product (gift) tiers only (onsite `filter_oos_variants`): when set, the client drops this
1717
1726
  * tier entirely once its gift has NO in-stock eligible variant — the milestone, fill slot and gift
1718
1727
  * controls all disappear, mirroring onsite removing the tier from `bar.tiers` before it renders. Absent
1719
1728
  * on shipping/discount/decorative tiers and left off by default (the tier renders regardless of stock).
1720
1729
  */
1721
- filterOosVariants: z21.boolean().default(false),
1730
+ filterOosVariants: z22.boolean().default(false),
1722
1731
  /**
1723
1732
  * Smart-cart product (gift) tiers only: the reward unlocked at this tier. The client enriches
1724
1733
  * `productId`/`variantIds` to live variants (availability, price) and adds the chosen one to the cart
@@ -1726,10 +1735,10 @@ var CABProgressTier = z21.object({
1726
1735
  * tiers and on tiers with no configured product. Cart add/remove is a later stage; carried here so the
1727
1736
  * tree is complete.
1728
1737
  */
1729
- gift: z21.object({
1730
- productId: z21.number().int().positive(),
1731
- title: z21.string().optional(),
1732
- variantIds: z21.array(z21.number().int().positive()).default(() => [])
1738
+ gift: z22.object({
1739
+ productId: z22.number().int().positive(),
1740
+ title: z22.string().optional(),
1741
+ variantIds: z22.array(z22.number().int().positive()).default(() => [])
1733
1742
  }).optional(),
1734
1743
  /**
1735
1744
  * The step-row icon's square size in PIXELS (onsite `product_tier_element_size`, an admin px string the
@@ -1749,7 +1758,7 @@ var CABProgressTier = z21.object({
1749
1758
  * renderer never spells a fallback), which also makes a tree authored before this field render at
1750
1759
  * React's size rather than the old hardcoded 20.
1751
1760
  */
1752
- iconSizePx: z21.number().int().min(1).max(64).default(18),
1761
+ iconSizePx: z22.number().int().min(1).max(64).default(18),
1753
1762
  /**
1754
1763
  * The step-row label at this tier's slot (onsite `getTierLabel`): the merchant custom label, else the
1755
1764
  * type default — 'Free Shipping' or '{n}% Discount'. A PRODUCT tier gets NO converter label: its name is
@@ -1759,35 +1768,35 @@ var CABProgressTier = z21.object({
1759
1768
  * turns a blank label into an absent key, and a client-authored blank means the same thing — the renderer
1760
1769
  * emits no caption slot rather than an empty one). Plain text — a compact icon+label.
1761
1770
  */
1762
- label: z21.record(z21.string(), z21.string()).optional(),
1771
+ label: z22.record(z22.string(), z22.string()).optional(),
1763
1772
  /**
1764
1773
  * Smart-cart product (gift) tiers only (onsite `product_tier_image`): show the gift's product image in
1765
1774
  * the step-row slot instead of the generic bag icon. The converter can't supply the image URL (config
1766
1775
  * carries only product IDs), so the client resolves it (authoritative Shopify featured image, React
1767
1776
  * parity) and falls back to the bag icon when the flag is off or no image resolves. Default false.
1768
1777
  */
1769
- productTierImage: z21.boolean().default(false),
1778
+ productTierImage: z22.boolean().default(false),
1770
1779
  /**
1771
1780
  * The tier's goal, measured per `unit`. `currency` (default): SHOP-currency cents — the canonical
1772
1781
  * fallback: when the buyer's presentment currency has no entry in `thresholds`, the client
1773
1782
  * multiplies this by the live FX rate (converter maps the v1 `unlock_price`, e.g. `75` → `7500`).
1774
1783
  * `item`: a raw item count — no cents, no FX, no `thresholds` overrides.
1775
1784
  */
1776
- threshold: z21.number().int().nonnegative(),
1785
+ threshold: z22.number().int().nonnegative(),
1777
1786
  /**
1778
1787
  * Per-presentment-currency goal overrides — lowercased ISO currency code → cents (e.g. `{ cad: 9900 }`).
1779
1788
  * When the buyer's currency has an entry, the client uses it verbatim INSTEAD of FX-converting
1780
1789
  * `threshold`, so merchants show intentional, clean per-market amounts (Shopify Markets) rather than a
1781
1790
  * converted base. Defaults to `{}` — no overrides means always fall back to `threshold`.
1782
1791
  */
1783
- thresholds: z21.record(z21.string(), z21.number().int().nonnegative()).default(() => ({})),
1792
+ thresholds: z22.record(z22.string(), z22.number().int().nonnegative()).default(() => ({})),
1784
1793
  /**
1785
1794
  * Smart-cart tier identifier, mirrored onto the gift cart line's `_tier` attribute so the client can
1786
1795
  * match an in-cart gift back to its tier (add on reach, remove on downgrade/decline). Absent on the
1787
1796
  * shipping bar (single unlabeled tier, no gift).
1788
1797
  */
1789
- tierId: z21.string().optional(),
1790
- tierType: z21.enum(progressTierTypes).default(ProgressTierType.shipping),
1798
+ tierId: z22.string().optional(),
1799
+ tierType: z22.enum(progressTierTypes).default(ProgressTierType.shipping),
1791
1800
  /**
1792
1801
  * What this tier's progress is measured in — PER TIER (onsite's `unlock_condition_type` model, NOT
1793
1802
  * the React port's bar-level `tiers[0]` shortcut). `currency` compares money cents against the
@@ -1798,9 +1807,9 @@ var CABProgressTier = z21.object({
1798
1807
  * count carries no injected noun (no English `item`/`items` inflection on localized copy); merchant
1799
1808
  * template text supplies grammatically-neutral wording around the token.
1800
1809
  */
1801
- unit: z21.enum(progressTierUnits).default(ProgressTierUnit.currency)
1810
+ unit: z22.enum(progressTierUnits).default(ProgressTierUnit.currency)
1802
1811
  });
1803
- var CABProgressBarSection = z21.lazy(
1812
+ var CABProgressBarSection = z22.lazy(
1804
1813
  () => CABLayoutSection.omit({ sectionType: true }).extend({
1805
1814
  /**
1806
1815
  * The onsite bar id (smart-cart TPB bars only). The client mirrors it to the cart's `_barId` attribute
@@ -1809,35 +1818,35 @@ var CABProgressBarSection = z21.lazy(
1809
1818
  * checkout reaches the extension without it, so the client writes it or the tier gift's 100% discount
1810
1819
  * (and any tier order discount) never applies. Absent on the v1 shipping bar (no gift tiers, no id).
1811
1820
  */
1812
- barId: z21.string().optional(),
1821
+ barId: z22.string().optional(),
1813
1822
  /** Empty = shown everywhere; otherwise uppercase ISO country codes. */
1814
- countryCodes: z21.array(z21.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1823
+ countryCodes: z22.array(z22.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1815
1824
  /**
1816
1825
  * Uppercase ISO codes where a higher-precedence geo bar applies, so this (default, non-geo) bar is
1817
1826
  * hidden there — replicates React `getbar`'s geo-match-over-default precedence. Empty = never excluded.
1818
1827
  */
1819
- excludeCountryCodes: z21.array(z21.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1828
+ excludeCountryCodes: z22.array(z22.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1820
1829
  /**
1821
1830
  * Measure progress against the PRE-discount subtotal (onsite `exclude_discount_in_subtotal`, and
1822
1831
  * forced on for bars with a discount tier so its own reward can't un-reach the tier). The client
1823
1832
  * adds the cart's discount allocations back to the live subtotal.
1824
1833
  */
1825
- excludeDiscountInSubtotal: z21.boolean().default(false),
1834
+ excludeDiscountInSubtotal: z22.boolean().default(false),
1826
1835
  /** Variant ids the client subtracts from the adjusted subtotal (React `bar.excluded_products`). */
1827
- excludedVariantIds: z21.array(z21.number().int().positive()).default(() => []),
1836
+ excludedVariantIds: z22.array(z22.number().int().positive()).default(() => []),
1828
1837
  /**
1829
1838
  * When the cart holds a subscription item, treat the bar as reached regardless of subtotal (React
1830
1839
  * `free_shipping_on_subscription(s)`). `freeShippingOnAll` is already a zero-threshold tier instead.
1831
1840
  */
1832
- freeShippingOnSubscription: z21.boolean().default(false),
1841
+ freeShippingOnSubscription: z22.boolean().default(false),
1833
1842
  /** Localized heading over the gift controls (onsite `gift_area_title`, default 'FREE GIFTS'). */
1834
- giftAreaTitle: z21.record(z21.string(), z21.string()).default(() => ({ en: "FREE GIFTS" })),
1843
+ giftAreaTitle: z22.record(z22.string(), z22.string()).default(() => ({ en: "FREE GIFTS" })),
1835
1844
  /** Localized gift-control labels (add/remove/heading); a tier's gift `title` beats `yourGift`. */
1836
- giftLabels: z21.object({
1837
- addGift: z21.record(z21.string(), z21.string()).default(() => ({ ...GIFT_LABELS.addGift })),
1838
- remove: z21.record(z21.string(), z21.string()).default(() => ({ ...GIFT_LABELS.remove })),
1839
- selectOptions: z21.record(z21.string(), z21.string()).default(() => ({ ...GIFT_LABELS.selectOptions })),
1840
- yourGift: z21.record(z21.string(), z21.string()).default(() => ({ ...GIFT_LABELS.yourGift }))
1845
+ giftLabels: z22.object({
1846
+ addGift: z22.record(z22.string(), z22.string()).default(() => ({ ...GIFT_LABELS.addGift })),
1847
+ remove: z22.record(z22.string(), z22.string()).default(() => ({ ...GIFT_LABELS.remove })),
1848
+ selectOptions: z22.record(z22.string(), z22.string()).default(() => ({ ...GIFT_LABELS.selectOptions })),
1849
+ yourGift: z22.record(z22.string(), z22.string()).default(() => ({ ...GIFT_LABELS.yourGift }))
1841
1850
  }).default(() => ({
1842
1851
  addGift: { ...GIFT_LABELS.addGift },
1843
1852
  remove: { ...GIFT_LABELS.remove },
@@ -1845,38 +1854,38 @@ var CABProgressBarSection = z21.lazy(
1845
1854
  yourGift: { ...GIFT_LABELS.yourGift }
1846
1855
  })),
1847
1856
  /** The bar's a11y label; the merchant names it in the editor, else this default (React parity). */
1848
- name: z21.string().default("Order progress"),
1857
+ name: z22.string().default("Order progress"),
1849
1858
  /**
1850
1859
  * Bar fill color. An explicit (widget-authored) value is used verbatim; when absent the server
1851
1860
  * fills it with the live shop theme's `buttonBackground` (React `useRebuyTheme` parity). Still
1852
1861
  * absent after that ⇒ the theme fetch failed and the client renders its platform-default bar —
1853
1862
  * optional, not defaulted, so "merchant chose no color" stays distinguishable from any real value.
1854
1863
  */
1855
- progressColor: z21.string().optional(),
1856
- sectionType: z21.literal(SectionType.progressBar).default(SectionType.progressBar),
1864
+ progressColor: z22.string().optional(),
1865
+ sectionType: z22.literal(SectionType.progressBar).default(SectionType.progressBar),
1857
1866
  /**
1858
1867
  * The bar's milestones in the merchant's CONFIGURED order — the renderer does NOT sort them (022
1859
1868
  * O-B2: sorting by resolved threshold reversed configured milestones on out-of-order or mixed-unit
1860
1869
  * count-vs-cents bars). Drives the fill (even slot per tier) and, for smart-cart product tiers, the
1861
1870
  * gift add/remove. The visual tier display lives in `sections` (composable), NOT here.
1862
1871
  */
1863
- tiers: z21.union([z21.array(CABProgressTier), z21.strictObject({}).transform(() => [])]).default(() => [])
1872
+ tiers: z22.union([z22.array(CABProgressTier), z22.strictObject({}).transform(() => [])]).default(() => [])
1864
1873
  })
1865
1874
  );
1866
1875
 
1867
1876
  // src/schema/widgets/checkout-and-beyond/quantity.ts
1868
1877
  import { v7 as uuidv79 } from "uuid";
1869
- import { z as z22 } from "zod";
1870
- var CABQuantitySection = z22.object({
1878
+ import { z as z23 } from "zod";
1879
+ var CABQuantitySection = z23.object({
1871
1880
  ...CABVariableFields,
1872
- errorMessages: z22.record(
1873
- z22.string(),
1874
- z22.object({
1881
+ errorMessages: z23.record(
1882
+ z23.string(),
1883
+ z23.object({
1875
1884
  /** `{{step}}` is interpolated at render — the off-increment message React never gave a merchant key. */
1876
- increment: z22.string().optional(),
1877
- max: z22.string().optional(),
1878
- min: z22.string().optional(),
1879
- neg: z22.string().optional()
1885
+ increment: z23.string().optional(),
1886
+ max: z23.string().optional(),
1887
+ min: z23.string().optional(),
1888
+ neg: z23.string().optional()
1880
1889
  })
1881
1890
  ).default({
1882
1891
  en: {
@@ -1886,18 +1895,18 @@ var CABQuantitySection = z22.object({
1886
1895
  neg: "Quantity cannot be negative"
1887
1896
  }
1888
1897
  }),
1889
- inputType: z22.enum(quantityInputs).default(QuantityInput.select),
1890
- max: z22.number().min(1).max(100).default(10),
1891
- min: z22.number().min(1).default(1),
1898
+ inputType: z23.enum(quantityInputs).default(QuantityInput.select),
1899
+ max: z23.number().min(1).max(100).default(10),
1900
+ min: z23.number().min(1).default(1),
1892
1901
  /** The a11y label for the quantity control; the merchant names it in the editor, else this default. */
1893
- name: z22.string().default("Quantity"),
1894
- sectionId: z22.uuid().default(() => uuidv79()),
1895
- sectionType: z22.literal(SectionType.quantity).default(SectionType.quantity)
1902
+ name: z23.string().default("Quantity"),
1903
+ sectionId: z23.uuid().default(() => uuidv79()),
1904
+ sectionType: z23.literal(SectionType.quantity).default(SectionType.quantity)
1896
1905
  });
1897
1906
 
1898
1907
  // src/schema/widgets/checkout-and-beyond/reviews.ts
1899
1908
  import { v7 as uuidv710 } from "uuid";
1900
- import { z as z23 } from "zod";
1909
+ import { z as z24 } from "zod";
1901
1910
 
1902
1911
  // src/schema/widgets/checkout-and-beyond/reviewLabels.ts
1903
1912
  var REVIEW_LABELS = {
@@ -1960,68 +1969,69 @@ var REVIEW_LABELS = {
1960
1969
  };
1961
1970
 
1962
1971
  // src/schema/widgets/checkout-and-beyond/reviews.ts
1963
- var CABReviewsSection = z23.object({
1972
+ var CABReviewsSection = z24.object({
1964
1973
  ...CABVariableFields,
1965
- color: z23.string().default("#fadb14"),
1974
+ color: z24.string().default("#fadb14"),
1966
1975
  /**
1967
1976
  * Localized review-count templates (`{{reviewCount}}`), one/other plural forms; the client picks the
1968
1977
  * form via `Intl.PluralRules`. Defaults here (schema-first) so every tree localizes without converter
1969
1978
  * or merchant work.
1970
1979
  */
1971
- countLabels: z23.object({
1972
- one: z23.record(z23.string(), z23.string()).default(() => ({ ...REVIEW_LABELS.one })),
1973
- other: z23.record(z23.string(), z23.string()).default(() => ({ ...REVIEW_LABELS.other }))
1980
+ countLabels: z24.object({
1981
+ one: z24.record(z24.string(), z24.string()).default(() => ({ ...REVIEW_LABELS.one })),
1982
+ other: z24.record(z24.string(), z24.string()).default(() => ({ ...REVIEW_LABELS.other }))
1974
1983
  }).default(() => ({ one: { ...REVIEW_LABELS.one }, other: { ...REVIEW_LABELS.other } })),
1975
- name: z23.string().optional(),
1976
- sectionId: z23.uuid().default(() => uuidv710()),
1977
- sectionType: z23.literal(SectionType.reviews).default(SectionType.reviews),
1978
- size: z23.enum(reviewsSizes).default(ReviewsSize.default),
1984
+ name: z24.string().optional(),
1985
+ sectionId: z24.uuid().default(() => uuidv710()),
1986
+ sectionType: z24.literal(SectionType.reviews).default(SectionType.reviews),
1987
+ size: z24.enum(reviewsSizes).default(ReviewsSize.default),
1979
1988
  /**
1980
1989
  * Star outline color, interpolated into a style by the renderer, so it is hex-constrained like
1981
1990
  * `CABButtonSection.color`. The legacy source (`PostPurchaseSettings.styles.starStrokeColor`) is a free
1982
1991
  * string: its converter must validate and fall back to this default rather than let one odd value drop
1983
1992
  * the whole reviews section.
1984
1993
  */
1985
- strokeColor: z23.string().regex(HEX_COLOR_REGEX).default("#fadb14"),
1994
+ strokeColor: z24.string().regex(HEX_COLOR_REGEX).default("#fadb14"),
1986
1995
  /** Star outline width in px; `0` draws no outline. The legacy `styles.strokeWidth` is a STRING ('1') — its converter coerces. */
1987
- strokeWidth: z23.number().nonnegative().default(0)
1996
+ strokeWidth: z24.number().nonnegative().default(0)
1988
1997
  });
1989
1998
 
1990
1999
  // src/schema/widgets/checkout-and-beyond/separator.ts
1991
2000
  import { v7 as uuidv711 } from "uuid";
1992
- import { z as z24 } from "zod";
1993
- var CABSeparatorSection = z24.object({
2001
+ import { z as z25 } from "zod";
2002
+ var CABSeparatorSection = z25.object({
1994
2003
  ...CABVariableFields,
1995
- sectionId: z24.uuid().default(() => uuidv711()),
1996
- sectionType: z24.literal(SectionType.separator).default(SectionType.separator)
2004
+ sectionId: z25.uuid().default(() => uuidv711()),
2005
+ sectionType: z25.literal(SectionType.separator).default(SectionType.separator)
1997
2006
  });
1998
2007
 
1999
2008
  // src/schema/widgets/checkout-and-beyond/variants.ts
2000
2009
  import { slice } from "es-toolkit/compat";
2001
2010
  import { v7 as uuidv712 } from "uuid";
2002
- import { z as z25 } from "zod";
2003
- var CABVariantsSection = z25.object({
2011
+ import { z as z26 } from "zod";
2012
+ var CABVariantsSection = z26.object({
2004
2013
  ...CABVariableFields,
2005
- hideOutOfStockVariants: z25.boolean().default(false),
2006
- name: z25.string().optional(),
2007
- sectionId: z25.uuid().default(() => uuidv712()),
2008
- sectionType: z25.literal(SectionType.variants).default(SectionType.variants),
2009
- selector: z25.enum(slice(variantSelectors, 0, 3)).default(VariantSelector.menu),
2010
- variantMode: z25.enum(variantModes).default(VariantMode.multiple)
2014
+ hideOutOfStockVariants: z26.boolean().default(false),
2015
+ name: z26.string().optional(),
2016
+ sectionId: z26.uuid().default(() => uuidv712()),
2017
+ sectionType: z26.literal(SectionType.variants).default(SectionType.variants),
2018
+ selector: z26.enum(slice(variantSelectors, 0, 3)).default(VariantSelector.menu),
2019
+ /** `productGroup` is additive (REB-24817): a renderer without group support must render nothing for it. */
2020
+ variantMode: z26.enum(variantsModes).default(VariantsMode.multiple)
2011
2021
  });
2012
2022
 
2013
2023
  // src/schema/widgets/checkout-and-beyond/shared.ts
2014
- var CABBorder = z26.object({
2015
- radius: z26.enum(borderRadii).default(BorderRadius.base),
2016
- style: z26.enum(borderStyles).default(BorderStyle.none),
2017
- width: z26.enum(borderWidths).default(BorderWidth.base)
2024
+ var CABBorder = z27.object({
2025
+ radius: z27.enum(borderRadii).default(BorderRadius.base),
2026
+ style: z27.enum(borderStyles).default(BorderStyle.none),
2027
+ width: z27.enum(borderWidths).default(BorderWidth.base)
2018
2028
  }).default({
2019
2029
  radius: BorderRadius.base,
2020
2030
  style: BorderStyle.none,
2021
2031
  width: BorderWidth.base
2022
2032
  });
2023
- var CABSection = z26.lazy(
2024
- () => z26.discriminatedUnion("sectionType", [
2033
+ var CABSection = z27.lazy(
2034
+ () => z27.discriminatedUnion("sectionType", [
2025
2035
  CABBannerSection,
2026
2036
  CABButtonSection,
2027
2037
  CABCarouselSection,
@@ -2044,17 +2054,17 @@ var CABSection = z26.lazy(
2044
2054
  );
2045
2055
 
2046
2056
  // src/schema/widgets/checkout-and-beyond/image.ts
2047
- var CABImageSectionFields = z27.object({
2057
+ var CABImageSectionFields = z28.object({
2048
2058
  ...CABVariableFields,
2049
- altText: z27.string().refine(checkForHTML, NO_HTML).default(""),
2059
+ altText: z28.string().refine(checkForHTML, NO_HTML).default(""),
2050
2060
  /**
2051
2061
  * Image width÷height (e.g. `46` for the progress-bar fill); `null` renders at natural size. Any POSITIVE
2052
2062
  * ratio — never limited to 1, but never `0`/negative either: a renderer dividing by it would get `Infinity`,
2053
2063
  * and CSS `aspect-ratio` drops a negative value and silently reverts to natural size.
2054
2064
  */
2055
- aspectRatio: z27.number().positive().nullable().default(null),
2056
- border: z27.lazy(() => CABBorder),
2057
- buttonField: z27.enum(buttonFields).optional(),
2065
+ aspectRatio: z28.number().positive().nullable().default(null),
2066
+ border: z28.lazy(() => CABBorder),
2067
+ buttonField: z28.enum(buttonFields).optional(),
2058
2068
  /**
2059
2069
  * `icon` renders `source` as a single `s-icon` by name (the uber-image path covers icons too), reading
2060
2070
  * `iconSize`/`iconTone`. The other values are a harmless informational holdover from the previous
@@ -2073,29 +2083,30 @@ var CABImageSectionFields = z27.object({
2073
2083
  * behavior degraded gracefully and told us about it. The client-assembled half of the invariant was never
2074
2084
  * the risky half.
2075
2085
  */
2076
- category: z27.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
2086
+ category: z28.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
2077
2087
  /** `icon`-mode only: the `s-icon` `size`; `null` ⇒ the component default (`base`). Ignored by image treatments. */
2078
- iconSize: z27.enum(iconSizes).nullable().default(null),
2088
+ iconSize: z28.enum(iconSizes).nullable().default(null),
2079
2089
  /** `icon`-mode only: the `s-icon` `tone`; `null` ⇒ the component default (`auto`). Ignored by image treatments. */
2080
- iconTone: z27.enum(iconTones).nullable().default(null),
2081
- name: z27.string().optional(),
2082
- naturalHeight: z27.number().default(0),
2083
- naturalWidth: z27.number().default(0),
2090
+ iconTone: z28.enum(iconTones).nullable().default(null),
2091
+ name: z28.string().optional(),
2092
+ naturalHeight: z28.number().default(0),
2093
+ naturalWidth: z28.number().default(0),
2084
2094
  /**
2085
2095
  * `contain` (the component default): dimensionless images render in s-image's 1/1 default frame, and
2086
2096
  * `cover` would crop non-square art (payment badges lost their edges — 15993); `contain` letterboxes.
2087
2097
  */
2088
- objectFit: z27.enum(objectFits).default(ObjectFit.contain),
2089
- sectionId: z27.uuid().default(() => uuidv713()),
2090
- sectionType: z27.literal(SectionType.image).default(SectionType.image),
2098
+ objectFit: z28.enum(objectFits).default(ObjectFit.contain),
2099
+ sectionId: z28.uuid().default(() => uuidv713()),
2100
+ sectionType: z28.literal(SectionType.image).default(SectionType.image),
2091
2101
  /**
2092
2102
  * An image URL or dynamic token, an empty default, or — when `category: 'icon'` — an icon NAME. Icon mode
2093
2103
  * takes a name or `''` only, NOT a token: no renderer resolves a token to an icon today, so accepting one
2094
2104
  * would promise a capability that doesn't exist. Widen the refine's carve-out to `DYNAMIC_TOKEN_REGEX` when a
2095
2105
  * server-chosen tier icon actually needs it.
2096
2106
  */
2097
- source: z27.union([z27.url(), z27.literal(""), z27.string().regex(DYNAMIC_TOKEN_REGEX), z27.enum(iconNames)]).default(""),
2098
- width: z27.number().default(100)
2107
+ source: z28.union([z28.url(), z28.literal(""), z28.string().regex(DYNAMIC_TOKEN_REGEX), z28.enum(iconNames)]).default(""),
2108
+ thumbnails: CABImageThumbnails.optional(),
2109
+ width: z28.number().default(100)
2099
2110
  });
2100
2111
  var iconNameSet = new Set(iconNames);
2101
2112
  var isIconName = (source2) => iconNameSet.has(source2);
@@ -2246,7 +2257,7 @@ var convertContentBlockTextToV2 = (language3, text2 = literalText, textAlign = "
2246
2257
  };
2247
2258
 
2248
2259
  // src/schema/widgets/checkout-and-beyond/root.ts
2249
- import { z as z28 } from "zod";
2260
+ import { z as z29 } from "zod";
2250
2261
 
2251
2262
  // src/schema/widgets/checkout-and-beyond/uiLabels.ts
2252
2263
  var UI_LABELS = {
@@ -2266,8 +2277,8 @@ var UI_LABELS = {
2266
2277
  };
2267
2278
 
2268
2279
  // src/schema/widgets/checkout-and-beyond/root.ts
2269
- var localized = (fallback) => z28.record(z28.string(), z28.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
2270
- var CABUILabels = z28.object({
2280
+ var localized = (fallback) => z29.record(z29.string(), z29.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
2281
+ var CABUILabels = z29.object({
2271
2282
  currentPage: localized(UI_LABELS.currentPage),
2272
2283
  guest: localized(UI_LABELS.guest),
2273
2284
  loadingOptions: localized(UI_LABELS.loadingOptions),
@@ -2292,37 +2303,37 @@ var CABUILabels = z28.object({
2292
2303
  subscriptionOptions: { ...UI_LABELS.subscriptionOptions },
2293
2304
  updating: { ...UI_LABELS.updating }
2294
2305
  }));
2295
- var TargetArea = z28.object({
2296
- fill: z28.boolean().optional(),
2297
- flip: z28.enum(["both", "horizontal", "vertical"]).optional(),
2298
- icon: z28.string(),
2299
- label: z28.string(),
2300
- width: z28.string()
2306
+ var TargetArea = z29.object({
2307
+ fill: z29.boolean().optional(),
2308
+ flip: z29.enum(["both", "horizontal", "vertical"]).optional(),
2309
+ icon: z29.string(),
2310
+ label: z29.string(),
2311
+ width: z29.string()
2301
2312
  }).default(targetAreas[EditorMode.checkoutExtension][1]);
2302
- var CABTracking = z28.object({
2303
- enableAttribution: z28.boolean().nullish().transform((value) => value ?? true),
2304
- enableSource: z28.boolean().nullish().transform((value) => value ?? true),
2305
- enableWidget: z28.boolean().nullish().transform((value) => value ?? true)
2313
+ var CABTracking = z29.object({
2314
+ enableAttribution: z29.boolean().nullish().transform((value) => value ?? true),
2315
+ enableSource: z29.boolean().nullish().transform((value) => value ?? true),
2316
+ enableWidget: z29.boolean().nullish().transform((value) => value ?? true)
2306
2317
  }).nullish().transform((value) => value ?? { enableAttribution: true, enableSource: true, enableWidget: true });
2307
- var CABExperiment = z28.object({
2308
- elementId: z28.number(),
2309
- experimentId: z28.number(),
2310
- experimentType: z28.string(),
2311
- selectedId: z28.number()
2318
+ var CABExperiment = z29.object({
2319
+ elementId: z29.number(),
2320
+ experimentId: z29.number(),
2321
+ experimentType: z29.string(),
2322
+ selectedId: z29.number()
2312
2323
  });
2313
2324
  var CABRootSection = CABLayoutSection.extend({
2314
- editorMode: z28.enum(editorModes).default(EditorMode.checkoutExtension),
2325
+ editorMode: z29.enum(editorModes).default(EditorMode.checkoutExtension),
2315
2326
  experiment: CABExperiment.optional(),
2316
2327
  // Same rule as CABTracking above: the v1 converters pass raw legacy `previewMode` through, so a
2317
2328
  // `null` must fall back rather than throw the widget; malformed values still throw.
2318
- previewMode: z28.boolean().nullish().transform((value) => value ?? false),
2319
- storeId: z28.number().nullable().default(null),
2329
+ previewMode: z29.boolean().nullish().transform((value) => value ?? false),
2330
+ storeId: z29.number().nullable().default(null),
2320
2331
  targetArea: TargetArea.nullable(),
2321
2332
  tracking: CABTracking,
2322
- type: z28.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
2333
+ type: z29.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
2323
2334
  uiLabels: CABUILabels,
2324
- version: z28.literal(2).default(2),
2325
- widgetId: z28.number().nullable().default(null)
2335
+ version: z29.literal(2).default(2),
2336
+ widgetId: z29.number().nullable().default(null)
2326
2337
  });
2327
2338
 
2328
2339
  // src/transforms/v1Location.ts
@@ -3160,21 +3171,26 @@ var convertPlaceholderToV2 = ({ id, settings }) => CABRootSection.parse({
3160
3171
  // src/transforms/placeholderV1/types.ts
3161
3172
  var isPlaceholderV1 = (data) => !!data && typeof data === "object" && data.type === WidgetType.placeholder;
3162
3173
 
3163
- // src/transforms/offerV1/offerCard.ts
3164
- var borderToken = (tokens, value) => value !== void 0 && tokens.includes(value) ? value : "base";
3165
- var GRID_CARD_IMAGE_PX = 120;
3166
- var COMPACT_CARD_IMAGE_PX = 64;
3167
- var ADD_LABEL_TOKENS = ["quantity", "price", "total"];
3168
- var SWITCH_LABEL_TOKENS2 = ["subscriptionDiscount", "frequency", "interval"];
3169
- var QUANTITY_ERROR_TOKENS = ["max", "min", "step"];
3170
- var VARIANT_SELECTOR = { button: "button", radio: "radio", select: "menu" };
3171
- var buildStyledText = (token, style, fontSize = style?.textSize ?? "base") => {
3172
- const marks2 = [{ attrs: { color: "base", fontSize }, type: "textStyle" }];
3173
- if (style?.textEmphasis === "bold") marks2.push({ type: "bold" });
3174
- if (style?.textEmphasis === "italic") marks2.push({ type: "italic" });
3175
- return { content: [{ content: [{ marks: marks2, text: token, type: "text" }], type: "paragraph" }], type: "doc" };
3176
- };
3177
- var buildPriceContent = () => ({
3174
+ // src/transforms/productCard/earnedText.ts
3175
+ var contentMutator = (effect, variable, operator) => ({
3176
+ effect,
3177
+ variable,
3178
+ when: { operator, type: "content" }
3179
+ });
3180
+ var earnedFrom = (variable) => [
3181
+ contentMutator("set_false", variable, "is_empty"),
3182
+ contentMutator("set_true", variable, "is_not_empty")
3183
+ ];
3184
+ var shownWhile = (variable) => ({ variable, visibleWhen: true });
3185
+ var earnedText = (variable, content) => ({
3186
+ content: { en: content },
3187
+ mutators: earnedFrom(variable),
3188
+ sectionType: "text",
3189
+ visibility: shownWhile(variable)
3190
+ });
3191
+
3192
+ // src/transforms/productCard/priceText.ts
3193
+ var priceContent = () => ({
3178
3194
  content: [
3179
3195
  {
3180
3196
  content: [
@@ -3200,6 +3216,64 @@ var buildPriceContent = () => ({
3200
3216
  ],
3201
3217
  type: "doc"
3202
3218
  });
3219
+ var priceText = () => ({
3220
+ content: { en: priceContent() },
3221
+ sectionType: "text"
3222
+ });
3223
+
3224
+ // src/transforms/productCard/quantitySection.ts
3225
+ var quantitySection = ({ errorMessages, inputType, maxValue, minValue, name }) => {
3226
+ const max = Math.min(Math.max(maxValue ?? 10, 1), 100);
3227
+ const min = Math.min(Math.max(minValue ?? 1, 1), max);
3228
+ return {
3229
+ ...errorMessages && { errorMessages },
3230
+ ...inputType && { inputType },
3231
+ max,
3232
+ min,
3233
+ ...name && { name },
3234
+ sectionType: "quantity"
3235
+ };
3236
+ };
3237
+
3238
+ // src/transforms/productCard/subscriptionToggle.ts
3239
+ var SWITCH_LABEL_TOKENS2 = ["subscriptionDiscount", "frequency", "interval"];
3240
+ var subscriptionToggle = (productType, labels = {}) => {
3241
+ if (productType !== "both" && productType !== "subscription") return [];
3242
+ const slot = (buttonField, override) => ({
3243
+ buttonField,
3244
+ content: localizedContent(SWITCH_LABELS[buttonField], override, SWITCH_LABEL_TOKENS2),
3245
+ sectionType: "text"
3246
+ });
3247
+ return [
3248
+ {
3249
+ action: "switchToSubscription",
3250
+ buttonStyle: "plain",
3251
+ /** A `subscription` widget offers no one-time purchase; suppress the downgrade so the buyer can't switch to one-time. */
3252
+ ...productType === "subscription" && { disableDowngrade: true },
3253
+ sections: [
3254
+ slot("subscriptionOption", void 0),
3255
+ slot("switchToOneTimePurchase", labels.oneTime),
3256
+ slot("switchToSubscriptionNoDiscount", labels.upgrade),
3257
+ slot("switchToSubscriptionWithDiscount", labels.upgrade)
3258
+ ],
3259
+ sectionType: "button"
3260
+ }
3261
+ ];
3262
+ };
3263
+
3264
+ // src/transforms/offerV1/offerCard.ts
3265
+ var borderToken = (tokens, value) => value !== void 0 && tokens.includes(value) ? value : "base";
3266
+ var GRID_CARD_IMAGE_PX = 120;
3267
+ var COMPACT_CARD_IMAGE_PX = 64;
3268
+ var ADD_LABEL_TOKENS = ["quantity", "price", "total"];
3269
+ var QUANTITY_ERROR_TOKENS = ["max", "min", "step"];
3270
+ var VARIANT_SELECTOR = { button: "button", radio: "radio", select: "menu" };
3271
+ var buildStyledText = (token, style, fontSize = style?.textSize ?? "base") => {
3272
+ const marks2 = [{ attrs: { color: "base", fontSize }, type: "textStyle" }];
3273
+ if (style?.textEmphasis === "bold") marks2.push({ type: "bold" });
3274
+ if (style?.textEmphasis === "italic") marks2.push({ type: "italic" });
3275
+ return { content: [{ content: [{ marks: marks2, text: token, type: "text" }], type: "paragraph" }], type: "doc" };
3276
+ };
3203
3277
  var buildReviews = (settings) => {
3204
3278
  if (!settings.integrations || !Object.values(settings.integrations).some(Boolean)) return [];
3205
3279
  const reviews = settings.displaySettings?.reviews;
@@ -3241,29 +3315,11 @@ var buildTitle = (settings) => ({
3241
3315
  },
3242
3316
  sectionType: "text"
3243
3317
  });
3244
- var buildPrice = () => ({
3245
- content: { en: buildPriceContent() },
3246
- sectionType: "text"
3247
- });
3248
3318
  var HAS_VARIANT_TITLE = "hasVariantTitle";
3249
3319
  var buildVariantTitle = (settings) => {
3250
3320
  const show = settings.productOptions?.showVariantTitle;
3251
3321
  if (!show || show === "hide") return [];
3252
- return [
3253
- {
3254
- content: { en: buildStyledText("{{variantTitle}}", settings.displaySettings?.variant) },
3255
- mutators: [
3256
- { effect: "set_false", variable: HAS_VARIANT_TITLE, when: { operator: "is_empty", type: "content" } },
3257
- {
3258
- effect: "set_true",
3259
- variable: HAS_VARIANT_TITLE,
3260
- when: { operator: "is_not_empty", type: "content" }
3261
- }
3262
- ],
3263
- sectionType: "text",
3264
- visibility: { variable: HAS_VARIANT_TITLE, visibleWhen: true }
3265
- }
3266
- ];
3322
+ return [earnedText(HAS_VARIANT_TITLE, buildStyledText("{{variantTitle}}", settings.displaySettings?.variant))];
3267
3323
  };
3268
3324
  var detailBlock = (sections, horizontal, hasVariantTitleLine) => ({
3269
3325
  alignment: { horizontal: horizontal ? "start" : "center", vertical: "top" },
@@ -3292,18 +3348,7 @@ var buildDescription = (settings) => {
3292
3348
  },
3293
3349
  {
3294
3350
  content: { en: buildStyledText("{{productDescription}}", void 0) },
3295
- mutators: [
3296
- {
3297
- effect: "set_false",
3298
- variable: HAS_DESCRIPTION,
3299
- when: { operator: "is_empty", type: "content" }
3300
- },
3301
- {
3302
- effect: "set_true",
3303
- variable: HAS_DESCRIPTION,
3304
- when: { operator: "is_not_empty", type: "content" }
3305
- }
3306
- ],
3351
+ mutators: earnedFrom(HAS_DESCRIPTION),
3307
3352
  sectionType: "text",
3308
3353
  visibility: { variable: SHOW_DESCRIPTION, visibleWhen: true }
3309
3354
  }
@@ -3319,7 +3364,7 @@ var buildDescription = (settings) => {
3319
3364
  var SHOW_VARIANTS = "showVariants";
3320
3365
  var REVEAL_PENDING = "revealPending";
3321
3366
  var revealsVariants = (settings) => settings.viewOptions?.displayActions !== false && settings.productOptions?.showVariantOptions === "default";
3322
- var contentMutator = (effect, variable, operator) => ({
3367
+ var contentMutator2 = (effect, variable, operator) => ({
3323
3368
  effect,
3324
3369
  variable,
3325
3370
  when: { operator, type: "content" }
@@ -3333,10 +3378,10 @@ var buildVariants = (settings) => {
3333
3378
  hideOutOfStockVariants: !!settings.productOptions?.hideOutOfStockVariants,
3334
3379
  ...revealsVariants(settings) && {
3335
3380
  mutators: [
3336
- contentMutator("set_true", SHOW_VARIANTS, "is_empty"),
3337
- contentMutator("set_false", REVEAL_PENDING, "is_empty"),
3338
- contentMutator("set_true", REVEAL_PENDING, "is_not_empty"),
3339
- contentMutator("set_false", SHOW_VARIANTS, "is_not_empty")
3381
+ contentMutator2("set_true", SHOW_VARIANTS, "is_empty"),
3382
+ contentMutator2("set_false", REVEAL_PENDING, "is_empty"),
3383
+ contentMutator2("set_true", REVEAL_PENDING, "is_not_empty"),
3384
+ contentMutator2("set_false", SHOW_VARIANTS, "is_not_empty")
3340
3385
  ]
3341
3386
  },
3342
3387
  ...selector && { selector: VARIANT_SELECTOR[selector] },
@@ -3350,54 +3395,31 @@ var QUANTITY_INPUT_TYPE = {
3350
3395
  "buttons-manual-input": "number",
3351
3396
  "dropdown-select": "select"
3352
3397
  };
3353
- var buildQuantityErrors = (quantity2) => {
3398
+ var buildQuantityErrors = (quantity3) => {
3354
3399
  const en = {
3355
- ...quantity2.maxError && { max: normalizeTokens(quantity2.maxError, QUANTITY_ERROR_TOKENS) },
3356
- ...quantity2.minError && { min: normalizeTokens(quantity2.minError, QUANTITY_ERROR_TOKENS) },
3357
- ...quantity2.negativeError && { neg: normalizeTokens(quantity2.negativeError, QUANTITY_ERROR_TOKENS) }
3400
+ ...quantity3.maxError && { max: normalizeTokens(quantity3.maxError, QUANTITY_ERROR_TOKENS) },
3401
+ ...quantity3.minError && { min: normalizeTokens(quantity3.minError, QUANTITY_ERROR_TOKENS) },
3402
+ ...quantity3.negativeError && { neg: normalizeTokens(quantity3.negativeError, QUANTITY_ERROR_TOKENS) }
3358
3403
  };
3359
3404
  return Object.keys(en).length ? { errorMessages: { en } } : {};
3360
3405
  };
3361
3406
  var buildQuantity = (settings) => {
3362
- const quantity2 = settings.quantityInputs;
3363
- if (!quantity2?.enabled) return [];
3364
- const inputType = quantity2.type ? QUANTITY_INPUT_TYPE[quantity2.type] : void 0;
3365
- const max = Math.min(Math.max(quantity2.maxValue ?? 10, 1), 100);
3366
- const min = Math.min(Math.max(quantity2.minValue ?? 1, 1), max);
3367
- return [
3368
- {
3369
- ...buildQuantityErrors(quantity2),
3370
- ...inputType && { inputType },
3371
- max,
3372
- min,
3373
- sectionType: "quantity"
3374
- }
3375
- ];
3376
- };
3377
- var buildSubscriptionButton = (settings) => {
3378
- if (settings.productType !== "both" && settings.productType !== "subscription") return [];
3379
- const language3 = settings.language;
3380
- const slot = (buttonField, override) => ({
3381
- buttonField,
3382
- content: localizedContent(SWITCH_LABELS[buttonField], override, SWITCH_LABEL_TOKENS2),
3383
- sectionType: "text"
3384
- });
3407
+ const quantity3 = settings.quantityInputs;
3408
+ if (!quantity3?.enabled) return [];
3409
+ const errors = buildQuantityErrors(quantity3);
3385
3410
  return [
3386
- {
3387
- action: "switchToSubscription",
3388
- buttonStyle: "plain",
3389
- /** A `subscription` widget offers no one-time purchase (legacy's offers checkbox renders only when `isProductTypeBoth`); suppress the downgrade so the buyer can't switch to one-time on a subscription-only offer. */
3390
- ...settings.productType === "subscription" && { disableDowngrade: true },
3391
- sections: [
3392
- slot("subscriptionOption", void 0),
3393
- slot("switchToOneTimePurchase", language3?.cartSwitchToOnetime),
3394
- slot("switchToSubscriptionNoDiscount", language3?.upgradeToSubscription),
3395
- slot("switchToSubscriptionWithDiscount", language3?.upgradeToSubscription)
3396
- ],
3397
- sectionType: "button"
3398
- }
3411
+ quantitySection({
3412
+ ...errors,
3413
+ inputType: quantity3.type ? QUANTITY_INPUT_TYPE[quantity3.type] : void 0,
3414
+ maxValue: quantity3.maxValue,
3415
+ minValue: quantity3.minValue
3416
+ })
3399
3417
  ];
3400
3418
  };
3419
+ var buildSubscriptionButton = (settings) => subscriptionToggle(settings.productType, {
3420
+ oneTime: settings.language?.cartSwitchToOnetime,
3421
+ upgrade: settings.language?.upgradeToSubscription
3422
+ });
3401
3423
  var BUTTON_KINDS2 = ["plain", "primary", "secondary"];
3402
3424
  var buttonKind = (settings) => {
3403
3425
  const kind = settings.button?.kind;
@@ -3443,15 +3465,15 @@ var buildOfferCard = (settings, horizontal) => {
3443
3465
  const image = buildImage(settings);
3444
3466
  const title = buildTitle(settings);
3445
3467
  const variantTitle = buildVariantTitle(settings);
3446
- const price = buildPrice();
3468
+ const price = priceText();
3447
3469
  const description = buildDescription(settings);
3448
3470
  const reviews = buildReviews(settings);
3449
3471
  const variants = buildVariants(settings);
3450
- const quantity2 = buildQuantity(settings);
3472
+ const quantity3 = buildQuantity(settings);
3451
3473
  const subscription2 = buildSubscriptionButton(settings);
3452
3474
  const reveal = buildRevealButton(settings);
3453
3475
  const addButton = buildAddButton(settings);
3454
- const controls = [...description, ...quantity2, ...variants, ...subscription2];
3476
+ const controls = [...description, ...quantity3, ...variants, ...subscription2];
3455
3477
  const info = detailBlock([title, ...variantTitle, ...reviews, price], horizontal, variantTitle.length > 0);
3456
3478
  const card = (sections) => [
3457
3479
  {
@@ -3747,18 +3769,18 @@ var convertOfferToV2 = ({ id, name, settings }) => {
3747
3769
  var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(transform(convertNumericObjects(deepCamelCase(raw))));
3748
3770
 
3749
3771
  // src/transforms/postPurchase/convertMessagePreview.ts
3750
- import { z as z36 } from "zod";
3772
+ import { z as z40 } from "zod";
3751
3773
 
3752
3774
  // src/transforms/postPurchase/convertCalloutBlock.ts
3753
- import { z as z31 } from "zod";
3775
+ import { z as z32 } from "zod";
3754
3776
 
3755
3777
  // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
3756
3778
  import { get as get2, isEqual } from "es-toolkit/compat";
3757
3779
  import { v4 as uuidv4 } from "uuid";
3758
- import { z as z30 } from "zod";
3780
+ import { z as z31 } from "zod";
3759
3781
 
3760
3782
  // src/schema/widgets/post-purchase-offer/constants.ts
3761
- import { z as z29 } from "zod";
3783
+ import { z as z30 } from "zod";
3762
3784
  var blockTypes = [
3763
3785
  "callout_banner",
3764
3786
  "image",
@@ -3769,141 +3791,141 @@ var blockTypes = [
3769
3791
  "text",
3770
3792
  "timer"
3771
3793
  ];
3772
- var blockType = z29.enum(blockTypes);
3794
+ var blockType = z30.enum(blockTypes);
3773
3795
  var BlockType = blockType.enum;
3774
3796
 
3775
3797
  // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
3776
- var TextAlignment2 = z30.union([z30.enum(["leading", "center", "trailing"]), z30.unknown().transform(() => "leading")]);
3777
- var TextSize = z30.union([
3778
- z30.enum(["xsmall", "small", "base", "default", "medium", "large", "xlarge"]),
3779
- z30.unknown().transform(() => "medium")
3798
+ var TextAlignment2 = z31.union([z31.enum(["leading", "center", "trailing"]), z31.unknown().transform(() => "leading")]);
3799
+ var TextSize = z31.union([
3800
+ z31.enum(["xsmall", "small", "base", "default", "medium", "large", "xlarge"]),
3801
+ z31.unknown().transform(() => "medium")
3780
3802
  ]);
3781
- var CalloutBannerBlock = z30.object({
3782
- id: z30.string().optional().default(() => uuidv4()),
3783
- name: z30.string().optional(),
3784
- settings: z30.object({
3785
- superTitle: z30.union([z30.string(), TiptapDocument]).default(() => "Limited-time Offer"),
3786
- title: z30.union([z30.string(), TiptapDocument]).default(() => "Add this customer favorite to your order")
3803
+ var CalloutBannerBlock = z31.object({
3804
+ id: z31.string().optional().default(() => uuidv4()),
3805
+ name: z31.string().optional(),
3806
+ settings: z31.object({
3807
+ superTitle: z31.union([z31.string(), TiptapDocument]).default(() => "Limited-time Offer"),
3808
+ title: z31.union([z31.string(), TiptapDocument]).default(() => "Add this customer favorite to your order")
3787
3809
  }),
3788
- styles: z30.object({
3789
- superTitleEmphasized: z30.boolean().default(false),
3810
+ styles: z31.object({
3811
+ superTitleEmphasized: z31.boolean().default(false),
3790
3812
  superTitleSize: TextSize.default("large"),
3791
3813
  textAlignment: TextAlignment2.default("center"),
3792
- titleEmphasized: z30.boolean().default(true),
3814
+ titleEmphasized: z31.boolean().default(true),
3793
3815
  titleSize: TextSize.default("large")
3794
3816
  }),
3795
- type: z30.literal(BlockType.callout_banner).default(BlockType.callout_banner)
3817
+ type: z31.literal(BlockType.callout_banner).default(BlockType.callout_banner)
3796
3818
  });
3797
- var ImageBlock = z30.object({
3798
- id: z30.string().optional().default(() => uuidv4()),
3799
- name: z30.string().optional(),
3800
- settings: z30.union([
3801
- z30.object({
3819
+ var ImageBlock = z31.object({
3820
+ id: z31.string().optional().default(() => uuidv4()),
3821
+ name: z31.string().optional(),
3822
+ settings: z31.union([
3823
+ z31.object({
3802
3824
  /** This isn't used in the post-purchase offer widget */
3803
- alt: z30.string().optional().default(""),
3804
- image: z30.union([z30.literal(""), z30.url()]).default(""),
3805
- imageSize: z30.number().default(20),
3806
- imageType: z30.enum(["URL", "UPLOAD"]).default("URL")
3825
+ alt: z31.string().optional().default(""),
3826
+ image: z31.union([z31.literal(""), z31.url()]).default(""),
3827
+ imageSize: z31.number().default(20),
3828
+ imageType: z31.enum(["URL", "UPLOAD"]).default("URL")
3807
3829
  }),
3808
- z30.array(z30.never()).transform(() => ({}))
3830
+ z31.array(z31.never()).transform(() => ({}))
3809
3831
  ]),
3810
- type: z30.literal(BlockType.image).default(BlockType.image)
3811
- });
3812
- var ImageContentBlock = z30.object({
3813
- id: z30.string().optional().default(() => uuidv4()),
3814
- name: z30.string().optional(),
3815
- settings: z30.object({
3816
- alt: z30.string().optional().default(""),
3817
- description: z30.union([z30.string(), TiptapDocument, z30.null()]).default(
3832
+ type: z31.literal(BlockType.image).default(BlockType.image)
3833
+ });
3834
+ var ImageContentBlock = z31.object({
3835
+ id: z31.string().optional().default(() => uuidv4()),
3836
+ name: z31.string().optional(),
3837
+ settings: z31.object({
3838
+ alt: z31.string().optional().default(""),
3839
+ description: z31.union([z31.string(), TiptapDocument, z31.null()]).default(
3818
3840
  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
3819
3841
  ),
3820
3842
  descriptionSize: TextSize.default("medium"),
3821
3843
  horizontalAlignment: TextAlignment2.default("leading"),
3822
- image: z30.union([z30.literal(""), z30.url()]).default(""),
3823
- imagePlacement: z30.enum(["bottom", "left", "right", "top"]).optional().default("left"),
3824
- imageSize: z30.number().default(20),
3825
- superTitle: z30.union([z30.string(), TiptapDocument]).default("Lorem Ipsum!"),
3844
+ image: z31.union([z31.literal(""), z31.url()]).default(""),
3845
+ imagePlacement: z31.enum(["bottom", "left", "right", "top"]).optional().default("left"),
3846
+ imageSize: z31.number().default(20),
3847
+ superTitle: z31.union([z31.string(), TiptapDocument]).default("Lorem Ipsum!"),
3826
3848
  superTitleSize: TextSize.default("medium"),
3827
3849
  /** This isn't configurable in the admin-nextjs editor */
3828
- swapContent: z30.boolean().optional().default(false),
3829
- title: z30.union([z30.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet"),
3850
+ swapContent: z31.boolean().optional().default(false),
3851
+ title: z31.union([z31.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet"),
3830
3852
  titleSize: TextSize.default("medium")
3831
3853
  }),
3832
- type: z30.literal(BlockType.image_content).default(BlockType.image_content)
3833
- });
3834
- var PayButtonBlock = z30.object({
3835
- id: z30.string().optional().default(() => uuidv4()),
3836
- name: z30.string().optional(),
3837
- settings: z30.union([
3838
- z30.object({
3839
- label: z30.string().default("Pay Now")
3854
+ type: z31.literal(BlockType.image_content).default(BlockType.image_content)
3855
+ });
3856
+ var PayButtonBlock = z31.object({
3857
+ id: z31.string().optional().default(() => uuidv4()),
3858
+ name: z31.string().optional(),
3859
+ settings: z31.union([
3860
+ z31.object({
3861
+ label: z31.string().default("Pay Now")
3840
3862
  }),
3841
- z30.array(z30.never()).transform(() => ({
3863
+ z31.array(z31.never()).transform(() => ({
3842
3864
  label: "Pay Now"
3843
3865
  }))
3844
3866
  ]),
3845
- styles: z30.union([
3846
- z30.object({
3847
- buttonWidth: z30.number().min(10).max(100).default(50)
3867
+ styles: z31.union([
3868
+ z31.object({
3869
+ buttonWidth: z31.number().min(10).max(100).default(50)
3848
3870
  }),
3849
- z30.array(z30.never()).transform(() => ({
3871
+ z31.array(z31.never()).transform(() => ({
3850
3872
  buttonWidth: 50
3851
3873
  }))
3852
3874
  ]),
3853
- type: z30.literal(BlockType.pay_button).default(BlockType.pay_button)
3875
+ type: z31.literal(BlockType.pay_button).default(BlockType.pay_button)
3854
3876
  });
3855
- var ProductInformationBlock = z30.object({
3877
+ var ProductInformationBlock = z31.object({
3856
3878
  /** This isn't configurable in the admin-nextjs editor */
3857
- hideProductImage: z30.boolean().optional().default(false),
3858
- id: z30.string().optional().default(() => uuidv4()),
3859
- name: z30.string().optional(),
3860
- type: z30.literal(BlockType.product_information).default(BlockType.product_information)
3861
- });
3862
- var SeparatorBlock = z30.object({
3863
- id: z30.string().optional().default(() => uuidv4()),
3864
- name: z30.string().optional(),
3865
- type: z30.literal(BlockType.separator).default(BlockType.separator)
3866
- });
3867
- var TextBlock = z30.object({
3868
- id: z30.string().optional().default(() => uuidv4()),
3869
- name: z30.string().optional(),
3870
- settings: z30.object({
3871
- description: z30.union([z30.string(), TiptapDocument]).optional().default(
3879
+ hideProductImage: z31.boolean().optional().default(false),
3880
+ id: z31.string().optional().default(() => uuidv4()),
3881
+ name: z31.string().optional(),
3882
+ type: z31.literal(BlockType.product_information).default(BlockType.product_information)
3883
+ });
3884
+ var SeparatorBlock = z31.object({
3885
+ id: z31.string().optional().default(() => uuidv4()),
3886
+ name: z31.string().optional(),
3887
+ type: z31.literal(BlockType.separator).default(BlockType.separator)
3888
+ });
3889
+ var TextBlock = z31.object({
3890
+ id: z31.string().optional().default(() => uuidv4()),
3891
+ name: z31.string().optional(),
3892
+ settings: z31.object({
3893
+ description: z31.union([z31.string(), TiptapDocument]).optional().default(
3872
3894
  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
3873
3895
  ),
3874
3896
  /** This isn't used in the post-purchase offer widget */
3875
3897
  descriptionSize: TextSize.default("medium"),
3876
3898
  horizontalAlignment: TextAlignment2.default("leading"),
3877
- superTitle: z30.union([z30.string(), TiptapDocument]).default("Super Title"),
3899
+ superTitle: z31.union([z31.string(), TiptapDocument]).default("Super Title"),
3878
3900
  /** This isn't used in the post-purchase offer widget */
3879
3901
  superTitleSize: TextSize.default("medium"),
3880
- title: z30.union([z30.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet."),
3902
+ title: z31.union([z31.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet."),
3881
3903
  /** This isn't used in the post-purchase offer widget */
3882
3904
  titleSize: TextSize.default("medium")
3883
3905
  }),
3884
- type: z30.literal(BlockType.text).default(BlockType.text)
3885
- });
3886
- var TimerBlock = z30.object({
3887
- id: z30.string().optional().default(() => uuidv4()),
3888
- name: z30.string().optional(),
3889
- settings: z30.object({
3890
- durationMinutes: z30.number().min(0).default(10),
3891
- durationSeconds: z30.union([z30.number().min(0), z30.unknown().transform(() => 0)]).default(0),
3892
- endOffer: z30.boolean().default(true),
3893
- title: z30.union([z30.string(), TiptapDocument]).default("Hurry \u2014 your special offer ends in:")
3906
+ type: z31.literal(BlockType.text).default(BlockType.text)
3907
+ });
3908
+ var TimerBlock = z31.object({
3909
+ id: z31.string().optional().default(() => uuidv4()),
3910
+ name: z31.string().optional(),
3911
+ settings: z31.object({
3912
+ durationMinutes: z31.number().min(0).default(10),
3913
+ durationSeconds: z31.union([z31.number().min(0), z31.unknown().transform(() => 0)]).default(0),
3914
+ endOffer: z31.boolean().default(true),
3915
+ title: z31.union([z31.string(), TiptapDocument]).default("Hurry \u2014 your special offer ends in:")
3894
3916
  }),
3895
- styles: z30.object({
3917
+ styles: z31.object({
3896
3918
  textAlignment: TextAlignment2.default("center"),
3897
- timerBackgroundColor: z30.enum(["info", "warning", "success", "critical"]).default("warning"),
3898
- timerEmphasized: z30.union([z30.boolean(), z30.unknown().transform(() => true)]).default(true),
3919
+ timerBackgroundColor: z31.enum(["info", "warning", "success", "critical"]).default("warning"),
3920
+ timerEmphasized: z31.union([z31.boolean(), z31.unknown().transform(() => true)]).default(true),
3899
3921
  timerSize: TextSize.default("medium"),
3900
- timerWidth: z30.number().min(10).max(100).optional().default(100),
3901
- titleEmphasized: z30.union([z30.boolean(), z30.unknown().transform(() => true)]).default(false),
3922
+ timerWidth: z31.number().min(10).max(100).optional().default(100),
3923
+ titleEmphasized: z31.union([z31.boolean(), z31.unknown().transform(() => true)]).default(false),
3902
3924
  titleSize: TextSize.default("medium")
3903
3925
  }),
3904
- type: z30.literal(BlockType.timer).default(BlockType.timer)
3926
+ type: z31.literal(BlockType.timer).default(BlockType.timer)
3905
3927
  });
3906
- var PostPurchaseBlock = z30.discriminatedUnion("type", [
3928
+ var PostPurchaseBlock = z31.discriminatedUnion("type", [
3907
3929
  CalloutBannerBlock,
3908
3930
  ImageBlock,
3909
3931
  ImageContentBlock,
@@ -3936,7 +3958,7 @@ var styledTextRun = (text2, emphasized, size) => ({
3936
3958
  // src/transforms/postPurchase/convertCalloutBlock.ts
3937
3959
  var fields = ["superTitle", "title"];
3938
3960
  var Shell = CalloutBannerBlock.pick({ styles: true }).extend({
3939
- settings: z31.object({ superTitle: z31.unknown().optional(), title: z31.unknown().optional() })
3961
+ settings: z32.object({ superTitle: z32.unknown().optional(), title: z32.unknown().optional() })
3940
3962
  });
3941
3963
  var convertCalloutBlock = (raw, report) => {
3942
3964
  const omit = (detail) => {
@@ -3971,7 +3993,7 @@ var convertCalloutBlock = (raw, report) => {
3971
3993
  };
3972
3994
 
3973
3995
  // src/transforms/postPurchase/convertImageFrame.ts
3974
- import { z as z32 } from "zod";
3996
+ import { z as z33 } from "zod";
3975
3997
 
3976
3998
  // src/transforms/postPurchase/sizeImageSource.ts
3977
3999
  var sizeImageSource = (source2, size) => {
@@ -3983,7 +4005,7 @@ var sizeImageSource = (source2, size) => {
3983
4005
  };
3984
4006
 
3985
4007
  // src/transforms/postPurchase/convertImageFrame.ts
3986
- var Source = z32.url().default("https://cdn.shopify.com/s/files/1/0605/0555/5177/files/placeholder.jpg?v=1657762972");
4008
+ var Source = z33.url().default("https://cdn.shopify.com/s/files/1/0605/0555/5177/files/placeholder.jpg?v=1657762972");
3987
4009
  var DEFAULT_IMAGE_SIZE = 20;
3988
4010
  var convertImageFrame = (raw) => {
3989
4011
  const parsed = ImageBlock.shape.settings.options[0].safeParse(raw);
@@ -4029,7 +4051,7 @@ var convertImageBlock = (raw, report) => {
4029
4051
  };
4030
4052
 
4031
4053
  // src/transforms/postPurchase/convertImageContentBlock.ts
4032
- import { z as z34 } from "zod";
4054
+ import { z as z35 } from "zod";
4033
4055
 
4034
4056
  // src/transforms/postPurchase/convertImageContentText.ts
4035
4057
  var fields2 = ["superTitle", "title", "description"];
@@ -4059,7 +4081,7 @@ var convertImageContentText = (settings, report) => {
4059
4081
  };
4060
4082
 
4061
4083
  // src/transforms/postPurchase/imageContentSettings.ts
4062
- import { z as z33 } from "zod";
4084
+ import { z as z34 } from "zod";
4063
4085
  var ImageContentSettings = ImageContentBlock.shape.settings.pick({
4064
4086
  descriptionSize: true,
4065
4087
  horizontalAlignment: true,
@@ -4067,17 +4089,17 @@ var ImageContentSettings = ImageContentBlock.shape.settings.pick({
4067
4089
  swapContent: true,
4068
4090
  titleSize: true
4069
4091
  }).extend({
4070
- alt: z33.unknown().optional(),
4071
- description: z33.unknown().optional(),
4072
- image: z33.unknown().optional(),
4092
+ alt: z34.unknown().optional(),
4093
+ description: z34.unknown().optional(),
4094
+ image: z34.unknown().optional(),
4073
4095
  imagePlacement: ImageContentBlock.shape.settings.shape.imagePlacement.unwrap().nullable(),
4074
- imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(z33.number().positive()),
4075
- superTitle: z33.unknown().optional(),
4076
- title: z33.unknown().optional()
4096
+ imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(z34.number().positive()),
4097
+ superTitle: z34.unknown().optional(),
4098
+ title: z34.unknown().optional()
4077
4099
  });
4078
4100
 
4079
4101
  // src/transforms/postPurchase/convertImageContentBlock.ts
4080
- var Shell2 = z34.object({ settings: ImageContentSettings, type: z34.literal("image_content") });
4102
+ var Shell2 = z35.object({ settings: ImageContentSettings, type: z35.literal("image_content") });
4081
4103
  var PROPORTIONAL_BREAK_AT = 500;
4082
4104
  var convertImageContentBlock = (raw, report) => {
4083
4105
  const shell = Shell2.safeParse(raw);
@@ -4142,93 +4164,470 @@ var convertPayButtonBlock = (raw, report) => {
4142
4164
  ];
4143
4165
  };
4144
4166
 
4145
- // src/transforms/postPurchase/convertProductInformation.ts
4146
- var convertProductInformation = (raw, report) => {
4147
- const block = ProductInformationBlock.safeParse(raw);
4148
- if (!block.success) {
4149
- report?.({ detail: "Unreadable post-purchase product information", kind: "section" });
4150
- return [];
4151
- }
4167
+ // src/transforms/postPurchase/productCardControls.ts
4168
+ var groupSelector = { sectionType: "variants", selector: "menu", variantMode: "productGroup" };
4169
+ var variantSelector = ({ productOptions }) => {
4170
+ if (!productOptions.showVariantSelectors) return [];
4171
+ const single = productOptions.variantSelectorDisplayMode === "single";
4152
4172
  return [
4153
- CABOffersSection.parse({
4154
- direction: "grid",
4155
- sections: [
4156
- CABLayoutSection.parse({
4157
- alignment: { horizontal: "center" },
4158
- sections: [
4159
- CABLayoutSection.parse({
4160
- alignment: { horizontal: "center" },
4161
- direction: "grid",
4162
- grid: { columns: [250] },
4163
- sections: [
4164
- CABImageSection.parse({ altText: "{{productTitle}}", source: "{{productImage}}" })
4165
- ],
4166
- width: 90
4167
- })
4168
- ]
4169
- }),
4170
- CABLayoutSection.parse({
4171
- sections: [
4172
- CABTextSection.parse({
4173
- content: {
4174
- en: {
4175
- content: [
4176
- {
4177
- content: [
4178
- {
4179
- marks: [{ attrs: { fontSize: "heading" }, type: "textStyle" }],
4180
- text: "{{productTitle}}"
4181
- }
4182
- ]
4183
- }
4184
- ]
4185
- }
4186
- }
4187
- }),
4188
- CABReviewsSection.parse({}),
4189
- CABTextSection.parse({ content: { en: "{{productDescription}}" } })
4190
- ]
4191
- })
4192
- ],
4193
- spacing: "extraLoose",
4194
- wrapping: { breakAt: 500, maxPerLine: block.data.hideProductImage ? 1 : 2 }
4195
- })
4173
+ {
4174
+ hideOutOfStockVariants: single || productOptions.hideOutOfStockVariants,
4175
+ sectionType: "variants",
4176
+ selector: "menu",
4177
+ variantMode: single ? "single" : "multiple"
4178
+ }
4196
4179
  ];
4197
4180
  };
4181
+ var quantity = ({ language: language3, quantityInputs: quantityInputs2 }) => quantityInputs2.enabled ? [
4182
+ quantitySection({
4183
+ maxValue: quantityInputs2.maxValue,
4184
+ minValue: quantityInputs2.minValue,
4185
+ name: language3.global.quantity.trim()
4186
+ })
4187
+ ] : [];
4188
+ var productCardControls = (settings) => [
4189
+ ...subscriptionToggle(settings.productType),
4190
+ groupSelector,
4191
+ ...variantSelector(settings),
4192
+ ...quantity(settings)
4193
+ ];
4198
4194
 
4199
- // src/transforms/postPurchase/convertSeparatorBlock.ts
4200
- var convertSeparatorBlock = (raw, report) => {
4201
- if (!SeparatorBlock.safeParse(raw).success) {
4202
- report?.({ detail: "Unreadable post-purchase separator", kind: "section" });
4203
- return [];
4204
- }
4205
- return [CABSeparatorSection.parse({})];
4195
+ // src/transforms/postPurchase/productCardRows.ts
4196
+ var styledCopy = (text2, look) => ({
4197
+ content: [{ content: [{ marks: [{ attrs: look, type: "textStyle" }], text: text2, type: "text" }], type: "paragraph" }],
4198
+ type: "doc"
4199
+ });
4200
+ var merchantLabel = (value, fallback) => localizedContent({ en: fallback }, value);
4201
+ var boundText = (variable, content) => ({
4202
+ content,
4203
+ sectionType: "text",
4204
+ visibility: shownWhile(variable)
4205
+ });
4206
+ var earnedRow = ({ after, columns, label: label2, look, spacing, token, variable }) => {
4207
+ const styled2 = (text2) => look ? styledCopy(text2, look) : text2;
4208
+ const value = earnedText(variable, styled2(token));
4209
+ return {
4210
+ direction: "grid",
4211
+ grid: { columns, rows: ["auto"] },
4212
+ sections: [
4213
+ boundText(variable, look ? { en: styled2(String(label2.en)) } : label2),
4214
+ value,
4215
+ ...after === void 0 ? [] : [boundText(variable, { en: styled2(String(after)) })]
4216
+ ],
4217
+ sectionType: "layout",
4218
+ ...spacing && { spacing }
4219
+ };
4206
4220
  };
4221
+ var earnedVariables = (names) => names.map((name) => ({ defaultValue: false, name }));
4207
4222
 
4208
- // src/transforms/postPurchase/convertTextBlock.ts
4209
- import { z as z35 } from "zod";
4210
- var fields3 = ["superTitle", "title", "description"];
4211
- var styles = {
4212
- description: [{ attrs: { color: "base", fontSize: "small" }, type: "textStyle" }],
4213
- superTitle: [{ attrs: { color: "subdued", fontSize: "small" }, type: "textStyle" }],
4214
- title: [{ type: "bold" }, { attrs: { color: "base", fontSize: "large" }, type: "textStyle" }]
4215
- };
4216
- var settingsSchema = TextBlock.shape.settings;
4217
- var Shell3 = z35.object({
4218
- settings: settingsSchema.pick({ horizontalAlignment: true }).extend({
4219
- description: z35.unknown().optional(),
4220
- superTitle: z35.unknown().optional(),
4221
- title: z35.unknown().optional()
4222
- }),
4223
- type: z35.literal("text")
4224
- });
4225
- var convertTextBlock = (raw, report) => {
4226
- const shell = Shell3.safeParse(raw);
4227
- if (!shell.success) {
4228
- report?.({ detail: "Unreadable post-purchase text block", kind: "section" });
4229
- return [];
4230
- }
4231
- const values2 = fields3.map((field) => ({
4223
+ // src/transforms/postPurchase/productCardSettings.ts
4224
+ import { mapValues } from "es-toolkit";
4225
+ import { z as z38 } from "zod";
4226
+
4227
+ // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
4228
+ import { z as z37 } from "zod";
4229
+
4230
+ // src/schema/widgets/post-purchase-offer/common.ts
4231
+ import { replace, toNumber, toString } from "es-toolkit/compat";
4232
+ import { z as z36 } from "zod";
4233
+ var strictNumber = z36.union([
4234
+ z36.number(),
4235
+ z36.string().transform((value) => toNumber(replace(toString(value), /[^0-9.]/g, "")) || 0),
4236
+ z36.unknown().transform(() => 0)
4237
+ ]);
4238
+
4239
+ // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
4240
+ var PostPurchaseSettings = z37.object({
4241
+ advance: z37.object({ removePartialOrder: z37.boolean().default(true) }).optional().default(() => ({ removePartialOrder: true })),
4242
+ blocks: z37.union([z37.array(PostPurchaseBlock), z37.unknown().transform(() => [])]).default(() => [
4243
+ PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.timer }),
4244
+ PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.callout_banner }),
4245
+ PostPurchaseBlock.parse({ type: BlockType.product_information })
4246
+ ]),
4247
+ columnLayout: z37.boolean().optional(),
4248
+ discount: z37.object({
4249
+ amount: strictNumber.default(30),
4250
+ shouldShowSavingText: z37.boolean().optional().default(true),
4251
+ type: z37.enum(["none", "fixed_amount", "percentage"]).default("none")
4252
+ }),
4253
+ discountedFrom: z37.enum(["price", "compare_at_price"]).optional().default("price"),
4254
+ endpoint: z37.string().optional(),
4255
+ integrations: z37.object({
4256
+ judgeme: z37.boolean().default(false),
4257
+ junip: z37.boolean().optional().default(false),
4258
+ klaviyo: z37.boolean().default(false),
4259
+ loox: z37.boolean().default(false),
4260
+ okendo: z37.boolean().default(false),
4261
+ opinew: z37.boolean().optional().default(false),
4262
+ reviewsio: z37.boolean().optional().default(false),
4263
+ stamped: z37.boolean().default(false),
4264
+ yotpo: z37.boolean().default(false)
4265
+ }),
4266
+ key: z37.string().optional(),
4267
+ language: z37.object({
4268
+ description: z37.union([z37.string(), z37.unknown().transform(() => "")]).default(""),
4269
+ descriptionEnabled: z37.boolean().optional().default(false),
4270
+ descriptionRte: z37.object({
4271
+ content: z37.array(z37.unknown()),
4272
+ type: z37.string()
4273
+ }).optional(),
4274
+ descriptionSpacing: z37.enum(["none", "xtight", "tight", "default", "loose", "xloose"]).optional(),
4275
+ displayCtaPrice: z37.boolean().default(true),
4276
+ global: z37.object({
4277
+ declineAll: z37.string().optional().default("Decline All"),
4278
+ declineThisOffer: z37.string().default("Decline this offer"),
4279
+ free: z37.string().optional().default("Free"),
4280
+ notAvailable: z37.string().optional().default("Not available"),
4281
+ payNow: z37.string().default("Pay Now"),
4282
+ payNowUpgradeToSubscription: z37.string().optional().default("Upgrade to Subscription"),
4283
+ quantity: z37.string().default("Quantity"),
4284
+ /** This isn't configurable in the admin-nextjs editor */
4285
+ recurringShipping: z37.string().optional().default("Recurring shipping"),
4286
+ recurringSubtotal: z37.string().default("Recurring subtotal"),
4287
+ reviewsPlural: z37.string().optional().default("Reviews"),
4288
+ reviewsSingular: z37.string().optional().default("Review"),
4289
+ save: z37.union([z37.string(), z37.unknown().transform(() => "Save")]).optional().default("Save"),
4290
+ shipping: z37.string().default("Shipping"),
4291
+ subscriptionOption: z37.string().optional().default("Subscribe and Save"),
4292
+ subtotal: z37.string().default("Subtotal"),
4293
+ taxes: z37.string().default("Taxes"),
4294
+ total: z37.string().default("Total")
4295
+ }).optional().default(() => ({
4296
+ declineAll: "Decline All",
4297
+ declineThisOffer: "Decline this offer",
4298
+ free: "Free",
4299
+ notAvailable: "Not available",
4300
+ payNow: "Pay Now",
4301
+ payNowUpgradeToSubscription: "Upgrade to Subscription",
4302
+ quantity: "Quantity",
4303
+ /** This isn't configurable in the admin-nextjs editor */
4304
+ recurringShipping: "Recurring shipping",
4305
+ recurringSubtotal: "Recurring subtotal",
4306
+ reviewsPlural: "Reviews",
4307
+ reviewsSingular: "Review",
4308
+ save: "Save",
4309
+ shipping: "Shipping",
4310
+ subscriptionOption: "Subscribe and Save",
4311
+ subtotal: "Subtotal",
4312
+ taxes: "Taxes",
4313
+ total: "Total"
4314
+ })),
4315
+ globalTranslation: z37.string().optional().default("english")
4316
+ }),
4317
+ metafields: z37.boolean().default(false),
4318
+ /** This isn't configurable in the admin-nextjs editor */
4319
+ offer: z37.object({
4320
+ count: z37.number().default(1)
4321
+ }),
4322
+ offersLayout: z37.object({
4323
+ itemsPerPage: z37.number().optional(),
4324
+ type: z37.enum(["list", "grid", "carousel"]).default("list")
4325
+ }).optional().default({
4326
+ type: "list"
4327
+ }),
4328
+ /** This isn't configurable in the admin-nextjs editor */
4329
+ previewMode: z37.boolean().default(false),
4330
+ productLimit: z37.number().optional().default(1),
4331
+ productOptions: z37.object({
4332
+ /** This isn't configurable in the admin-nextjs editor */
4333
+ hideOutOfStockVariants: z37.boolean().optional().default(false),
4334
+ matchVariant: z37.boolean().optional().default(true),
4335
+ showDeclineAll: z37.enum(["above", "below", "both", "none"]).optional(),
4336
+ showShipping: z37.boolean().optional().default(true),
4337
+ showSubtotal: z37.boolean().optional().default(true),
4338
+ showTaxes: z37.boolean().optional().default(true),
4339
+ showTotal: z37.boolean().optional().default(true),
4340
+ showVariantSelectors: z37.boolean().optional().default(true),
4341
+ variantSelectorDisplayMode: z37.enum(["separate", "single"]).optional().default("separate")
4342
+ }),
4343
+ productType: z37.union([z37.enum(["one-time", "subscription", "both"]), z37.literal("").transform(() => "one-time")]).default("one-time"),
4344
+ productTypeSelector: z37.enum(["dropdown", "radio"]).optional().default("radio"),
4345
+ quantityInputs: z37.object({
4346
+ defaultQuantity: z37.union([z37.number(), z37.null().transform(() => 1)]).default(1),
4347
+ enabled: z37.boolean().default(true),
4348
+ maxValue: z37.union([z37.number(), z37.null().transform(() => 15)]).default(15),
4349
+ minValue: z37.union([z37.number().min(0), z37.unknown().transform(() => 0)]).default(1)
4350
+ }),
4351
+ shipping: z37.object({
4352
+ amount: strictNumber.default(10),
4353
+ /** This isn't configurable in the admin-nextjs editor */
4354
+ enabled: z37.boolean().default(true),
4355
+ title: z37.string().optional().default("Shipping Fees"),
4356
+ type: z37.enum(["free", "fixed_amount"]).default("free")
4357
+ }),
4358
+ styles: z37.object({
4359
+ starColor: z37.string().optional().default("#fadb14"),
4360
+ starSize: z37.union([z37.enum(["small", "medium", "large"]), z37.unknown().transform(() => "large")]).optional().default("large"),
4361
+ starStrokeColor: z37.string().optional().default("#fadb14"),
4362
+ strokeWidth: z37.string().optional().default("1")
4363
+ }).optional(),
4364
+ subImages: z37.number().nullish().default(8),
4365
+ subscription: z37.object({
4366
+ discount: z37.object({
4367
+ amount: strictNumber.default(30),
4368
+ shouldShowSavingText: z37.boolean().optional().default(true),
4369
+ type: z37.enum(["none", "fixed_amount", "percentage"]).default("none")
4370
+ }),
4371
+ shipping: z37.object({
4372
+ amount: strictNumber.default(1),
4373
+ /** This isn't configurable in the admin-nextjs editor */
4374
+ enabled: z37.boolean().default(true),
4375
+ /** This isn't configurable in the admin-nextjs editor */
4376
+ recurringAmount: strictNumber.default(2),
4377
+ shippingTitle: z37.string().default("Shipping Fees"),
4378
+ type: z37.enum(["free", "fixed_amount"]).default("free")
4379
+ })
4380
+ }).optional().default({
4381
+ discount: {
4382
+ amount: 30,
4383
+ shouldShowSavingText: true,
4384
+ type: "none"
4385
+ },
4386
+ shipping: {
4387
+ amount: 1,
4388
+ /** This isn't configurable in the admin-nextjs editor */
4389
+ enabled: true,
4390
+ /** This isn't configurable in the admin-nextjs editor */
4391
+ recurringAmount: 2,
4392
+ shippingTitle: "Shipping Fees",
4393
+ type: "free"
4394
+ }
4395
+ }),
4396
+ subscriptionIsDefault: z37.boolean().optional(),
4397
+ /** This isn't configurable in the admin-nextjs editor */
4398
+ template: z37.string().optional().default(""),
4399
+ type: z37.literal("shopify_post_purchase_extension").default("shopify_post_purchase_extension"),
4400
+ upgradeToSubscription: z37.object({
4401
+ acceptButtonText: z37.string().optional().default("Upgrade"),
4402
+ allow: z37.boolean().optional().default(false),
4403
+ emailRefundNotice: z37.boolean().optional().default(false),
4404
+ errorBannerText: z37.string().optional().default("This subscription cannot be added - limit one per order")
4405
+ }).optional().default(() => ({
4406
+ acceptButtonText: "Upgrade",
4407
+ allow: false,
4408
+ emailRefundNotice: false,
4409
+ errorBannerText: "This subscription cannot be added - limit one per order"
4410
+ }))
4411
+ });
4412
+
4413
+ // src/transforms/postPurchase/productCardSettings.ts
4414
+ var { shape } = PostPurchaseSettings;
4415
+ var Labels = z38.object(
4416
+ mapValues(shape.language.shape.global.unwrap().unwrap().shape, (label2) => label2.catch(() => label2.parse(void 0)))
4417
+ );
4418
+ var Language = z38.object({ global: Labels.catch(() => Labels.parse({})) });
4419
+ var Fields = z38.object({
4420
+ discount: shape.discount.catch(() => shape.discount.parse({})),
4421
+ language: Language.catch(() => Language.parse({})),
4422
+ productOptions: shape.productOptions.catch(() => shape.productOptions.parse({})),
4423
+ productType: shape.productType.catch("one-time"),
4424
+ quantityInputs: shape.quantityInputs.catch(() => shape.quantityInputs.parse({})),
4425
+ subImages: shape.subImages.catch(null),
4426
+ subscription: shape.subscription.catch(() => shape.subscription.parse(void 0)),
4427
+ upgradeToSubscription: shape.upgradeToSubscription.catch(() => shape.upgradeToSubscription.parse(void 0))
4428
+ });
4429
+ var ProductCardSettings = Fields.catch(() => Fields.parse({}));
4430
+ var sellsSubscription = ({ productType, upgradeToSubscription }) => productType !== "one-time" || upgradeToSubscription.allow;
4431
+
4432
+ // src/transforms/postPurchase/productCardCosts.ts
4433
+ var COST_ROWS = [
4434
+ ["showSubtotal", "subtotal", "Subtotal", "hasSubtotal"],
4435
+ ["showShipping", "shipping", "Shipping", "hasShipping"],
4436
+ ["showTaxes", "taxes", "Taxes", "hasTaxes"],
4437
+ ["showTotal", "total", "Total", "hasTotal"]
4438
+ ];
4439
+ var costRows = ({ language: language3, productOptions }) => {
4440
+ const rows = COST_ROWS.filter(([show]) => productOptions[show]);
4441
+ if (!rows.length) return [];
4442
+ return [
4443
+ {
4444
+ direction: "rows",
4445
+ name: "costs",
4446
+ sections: rows.map(
4447
+ ([, key, fallback, variable]) => earnedRow({
4448
+ columns: ["fill", "auto"],
4449
+ label: merchantLabel(language3.global[key], fallback),
4450
+ token: `{{${key}}}`,
4451
+ variable
4452
+ })
4453
+ ),
4454
+ sectionType: "layout",
4455
+ spacing: "tight",
4456
+ variables: earnedVariables(rows.map(([, , , variable]) => variable))
4457
+ }
4458
+ ];
4459
+ };
4460
+ var HAS_RECURRING_TOTAL = "hasRecurringTotal";
4461
+ var HAS_RECURRING_SHIPPING = "hasRecurringShipping";
4462
+ var small = { color: "subdued", fontSize: "small" };
4463
+ var FOOTNOTES = ["Doesn't include tax, duties, or any applicable discounts.", "Auto-renews, skip or cancel anytime"];
4464
+ var recurringSummary = (settings) => {
4465
+ if (!sellsSubscription(settings)) return [];
4466
+ const { global: global2 } = settings.language;
4467
+ return [
4468
+ {
4469
+ direction: "rows",
4470
+ name: "recurring",
4471
+ sections: [
4472
+ earnedRow({
4473
+ after: "on every Delivery",
4474
+ columns: ["fill", "auto", "auto"],
4475
+ label: merchantLabel(global2.recurringSubtotal, "Recurring subtotal"),
4476
+ spacing: "extraTight",
4477
+ token: "{{recurringTotal}}",
4478
+ variable: HAS_RECURRING_TOTAL
4479
+ }),
4480
+ earnedRow({
4481
+ after: "(included)",
4482
+ columns: ["auto", "auto", "auto"],
4483
+ label: { en: `${merchantLabel(global2.recurringShipping, "Recurring shipping").en}:` },
4484
+ look: small,
4485
+ spacing: "extraTight",
4486
+ token: "{{recurringShipping}}",
4487
+ variable: HAS_RECURRING_SHIPPING
4488
+ }),
4489
+ ...FOOTNOTES.map((text2) => ({
4490
+ content: { en: styledCopy(text2, small) },
4491
+ sectionType: "text",
4492
+ visibility: shownWhile(HAS_RECURRING_TOTAL)
4493
+ }))
4494
+ ],
4495
+ sectionType: "layout",
4496
+ spacing: "tight",
4497
+ variables: earnedVariables([HAS_RECURRING_TOTAL, HAS_RECURRING_SHIPPING])
4498
+ }
4499
+ ];
4500
+ };
4501
+ var productCardCosts = (settings) => [
4502
+ ...costRows(settings),
4503
+ ...recurringSummary(settings)
4504
+ ];
4505
+
4506
+ // src/transforms/postPurchase/productCardPricing.ts
4507
+ import { capitalize } from "es-toolkit/compat";
4508
+ var HAS_SAVING = "hasSaving";
4509
+ var savingLine = (settings) => {
4510
+ const subscriptionSaving = sellsSubscription(settings) && settings.subscription.discount.shouldShowSavingText;
4511
+ if (!settings.discount.shouldShowSavingText && !subscriptionSaving) return [];
4512
+ return [
4513
+ {
4514
+ ...earnedRow({
4515
+ columns: ["auto", "auto"],
4516
+ label: merchantLabel(capitalize(settings.language.global.save), "Save"),
4517
+ look: { color: "success" },
4518
+ spacing: "extraTight",
4519
+ token: "{{variantSaving}}",
4520
+ variable: HAS_SAVING
4521
+ }),
4522
+ name: "saving",
4523
+ variables: earnedVariables([HAS_SAVING])
4524
+ }
4525
+ ];
4526
+ };
4527
+ var productCardPricing = (settings) => [
4528
+ priceText(),
4529
+ ...savingLine(settings)
4530
+ ];
4531
+
4532
+ // src/transforms/postPurchase/convertProductInformation.ts
4533
+ var thumbnails = ({ subImages }) => {
4534
+ const limit = Math.floor(subImages ?? 0);
4535
+ return limit >= 1 ? { thumbnails: { limit } } : {};
4536
+ };
4537
+ var convertProductInformation = (raw, report, widgetSettings) => {
4538
+ const block = ProductInformationBlock.safeParse(raw);
4539
+ if (!block.success) {
4540
+ report?.({ detail: "Unreadable post-purchase product information", kind: "section" });
4541
+ return [];
4542
+ }
4543
+ const settings = ProductCardSettings.parse(widgetSettings ?? {});
4544
+ return [
4545
+ CABOffersSection.parse({
4546
+ direction: "grid",
4547
+ sections: [
4548
+ CABLayoutSection.parse({
4549
+ alignment: { horizontal: "center" },
4550
+ sections: [
4551
+ CABLayoutSection.parse({
4552
+ alignment: { horizontal: "center" },
4553
+ direction: "grid",
4554
+ grid: { columns: [250] },
4555
+ sections: [
4556
+ CABImageSection.parse({
4557
+ altText: "{{productTitle}}",
4558
+ source: "{{productImage}}",
4559
+ ...thumbnails(settings)
4560
+ })
4561
+ ],
4562
+ width: 90
4563
+ })
4564
+ ]
4565
+ }),
4566
+ CABLayoutSection.parse({
4567
+ sections: [
4568
+ CABTextSection.parse({
4569
+ content: {
4570
+ en: {
4571
+ content: [
4572
+ {
4573
+ content: [
4574
+ {
4575
+ marks: [{ attrs: { fontSize: "heading" }, type: "textStyle" }],
4576
+ text: "{{productTitle}}"
4577
+ }
4578
+ ]
4579
+ }
4580
+ ]
4581
+ }
4582
+ }
4583
+ }),
4584
+ ...productCardPricing(settings),
4585
+ CABReviewsSection.parse({}),
4586
+ CABTextSection.parse({ content: { en: "{{productDescription}}" } }),
4587
+ ...productCardControls(settings),
4588
+ ...productCardCosts(settings)
4589
+ ]
4590
+ })
4591
+ ],
4592
+ spacing: "extraLoose",
4593
+ wrapping: { breakAt: 500, maxPerLine: block.data.hideProductImage ? 1 : 2 }
4594
+ })
4595
+ ];
4596
+ };
4597
+
4598
+ // src/transforms/postPurchase/convertSeparatorBlock.ts
4599
+ var convertSeparatorBlock = (raw, report) => {
4600
+ if (!SeparatorBlock.safeParse(raw).success) {
4601
+ report?.({ detail: "Unreadable post-purchase separator", kind: "section" });
4602
+ return [];
4603
+ }
4604
+ return [CABSeparatorSection.parse({})];
4605
+ };
4606
+
4607
+ // src/transforms/postPurchase/convertTextBlock.ts
4608
+ import { z as z39 } from "zod";
4609
+ var fields3 = ["superTitle", "title", "description"];
4610
+ var styles = {
4611
+ description: [{ attrs: { color: "base", fontSize: "small" }, type: "textStyle" }],
4612
+ superTitle: [{ attrs: { color: "subdued", fontSize: "small" }, type: "textStyle" }],
4613
+ title: [{ type: "bold" }, { attrs: { color: "base", fontSize: "large" }, type: "textStyle" }]
4614
+ };
4615
+ var settingsSchema = TextBlock.shape.settings;
4616
+ var Shell3 = z39.object({
4617
+ settings: settingsSchema.pick({ horizontalAlignment: true }).extend({
4618
+ description: z39.unknown().optional(),
4619
+ superTitle: z39.unknown().optional(),
4620
+ title: z39.unknown().optional()
4621
+ }),
4622
+ type: z39.literal("text")
4623
+ });
4624
+ var convertTextBlock = (raw, report) => {
4625
+ const shell = Shell3.safeParse(raw);
4626
+ if (!shell.success) {
4627
+ report?.({ detail: "Unreadable post-purchase text block", kind: "section" });
4628
+ return [];
4629
+ }
4630
+ const values2 = fields3.map((field) => ({
4232
4631
  field,
4233
4632
  result: settingsSchema.shape[field].safeParse(shell.data.settings[field])
4234
4633
  }));
@@ -4292,11 +4691,11 @@ var convertTimerBlock = (raw, report) => {
4292
4691
  };
4293
4692
 
4294
4693
  // src/transforms/postPurchase/convertMessagePreview.ts
4295
- var MessageWidget = z36.object({
4296
- blocks: z36.array(z36.unknown()).min(1),
4297
- type: z36.literal(WidgetType.shopify_post_purchase_extension)
4694
+ var MessageWidget = z40.object({
4695
+ blocks: z40.array(z40.unknown()).min(1),
4696
+ type: z40.literal(WidgetType.shopify_post_purchase_extension)
4298
4697
  });
4299
- var BlockType2 = z36.object({ type: z36.string() });
4698
+ var BlockType2 = z40.object({ type: z40.string() });
4300
4699
  var converters = {
4301
4700
  callout_banner: convertCalloutBlock,
4302
4701
  image: convertImageBlock,
@@ -4317,7 +4716,7 @@ var convertMessagePreview = (id, settings, report) => {
4317
4716
  const type = BlockType2.safeParse(block);
4318
4717
  const kind = type.success ? type.data.type : void 0;
4319
4718
  const convert2 = kind && Object.hasOwn(converters, kind) ? converters[kind] : void 0;
4320
- if (convert2) return convert2(block, report);
4719
+ if (convert2) return convert2(block, report, settings);
4321
4720
  report?.({
4322
4721
  detail: kind ? `Unsupported post-purchase block type: ${kind}` : "Unreadable post-purchase block: missing type",
4323
4722
  kind: "section"
@@ -4756,14 +5155,14 @@ function serialize(obj) {
4756
5155
  var encodeAttributes = (pairs = []) => JSON.stringify(Object.fromEntries(pairs.map(({ key, value }) => [key, value ?? ""])));
4757
5156
  var buildEngineParams = (input, key) => {
4758
5157
  const { cart, customerId, filterInputs, integrations, limit, productType, shop, visitorId } = input;
4759
- const items = cart.items.map(({ productId: productId2, properties, quantity: quantity2, subscriptionId, variantId }) => ({
5158
+ const items = cart.items.map(({ productId: productId2, properties, quantity: quantity3, subscriptionId, variantId }) => ({
4760
5159
  product_id: productId2,
4761
5160
  properties: encodeAttributes(properties),
4762
- quantity: quantity2,
5161
+ quantity: quantity3,
4763
5162
  ...subscriptionId && { subscription_id: subscriptionId },
4764
5163
  variant_id: variantId
4765
5164
  }));
4766
- const itemCount = cart.items.reduce((total, { quantity: quantity2 }) => total + quantity2, 0);
5165
+ const itemCount = cart.items.reduce((total, { quantity: quantity3 }) => total + quantity3, 0);
4767
5166
  const subtotal = shopSubtotalCents(cart);
4768
5167
  return {
4769
5168
  cart: {
@@ -4844,43 +5243,43 @@ var fetchDataSourceResults = async (input, ctx) => {
4844
5243
  };
4845
5244
 
4846
5245
  // src/server/adsEngine.ts
4847
- import { z as z37 } from "zod";
5246
+ import { z as z41 } from "zod";
4848
5247
  var SUPPLY_KEY = { production: "AQF5RKLR", staging: "Z56LQ7PS" };
4849
5248
  var OFFER_LIMIT = 4;
4850
5249
  var SUPPORTED_COUNTRIES = /* @__PURE__ */ new Set(["US", "CA", "GB"]);
4851
5250
  var MAX_TRANSACTION_ITEMS = 50;
4852
5251
  var TEST_CUSTOMER_EMAIL = "test@rebuyengine.com";
4853
- var transactionItems = (input) => (input.transactionItems?.map(({ id, priceCents, quantity: quantity2, title, type }) => ({
5252
+ var transactionItems = (input) => (input.transactionItems?.map(({ id, priceCents, quantity: quantity3, title, type }) => ({
4854
5253
  id,
4855
5254
  price_cents: priceCents,
4856
- quantity: quantity2,
5255
+ quantity: quantity3,
4857
5256
  title,
4858
5257
  type
4859
- })) ?? input.cart.items.map(({ productId: productId2, quantity: quantity2 }) => ({ id: productId2, quantity: quantity2 }))).slice(0, MAX_TRANSACTION_ITEMS);
4860
- var AdsEngineOffer = z37.object({
5258
+ })) ?? input.cart.items.map(({ productId: productId2, quantity: quantity3 }) => ({ id: productId2, quantity: quantity3 }))).slice(0, MAX_TRANSACTION_ITEMS);
5259
+ var AdsEngineOffer = z41.object({
4861
5260
  /** Pill-style value prop ("Get $45 Cashback"). Carried through the parse; the card does not render it yet (REB-24429 — pill design pending). */
4862
- callout: z37.string().catch(""),
4863
- click_url: z37.string(),
4864
- cta: z37.string(),
5261
+ callout: z41.string().catch(""),
5262
+ click_url: z41.string(),
5263
+ cta: z41.string(),
4865
5264
  /** `omitempty` on the ad server — a bid without it must not fail the parse and drop the whole batch (composeOffer falls back to 'No Thanks'). */
4866
- decline_cta: z37.string().catch(""),
4867
- decline_url: z37.string(),
4868
- description: z37.string(),
5265
+ decline_cta: z41.string().catch(""),
5266
+ decline_url: z41.string(),
5267
+ description: z41.string(),
4869
5268
  /** Short legal disclosure (FDIC / auto-renewal / FTC-affiliation lines). Rendered subdued under the CTAs. */
4870
- disclaimer: z37.string().catch(""),
5269
+ disclaimer: z41.string().catch(""),
4871
5270
  /** Long legal text behind the disclosure toggle in the composed card (REB-24429). */
4872
- extended_disclaimer: z37.string().catch(""),
4873
- headline: z37.string(),
4874
- id: z37.string(),
5271
+ extended_disclaimer: z41.string().catch(""),
5272
+ headline: z41.string(),
5273
+ id: z41.string(),
4875
5274
  /** Advertiser-supplied image alt; the composed card falls back to the stripped headline when empty. */
4876
- image_alt: z37.string().catch(""),
4877
- image_url: z37.string().optional(),
5275
+ image_alt: z41.string().catch(""),
5276
+ image_url: z41.string().optional(),
4878
5277
  /** The serving network's own privacy page (Falcon, REB-24744); the card prefers it over the widget setting. A bad value drops only this field, never the offer. */
4879
- privacy_url: z37.string().optional().catch(void 0),
4880
- view_url: z37.string()
5278
+ privacy_url: z41.string().optional().catch(void 0),
5279
+ view_url: z41.string()
4881
5280
  });
4882
- var AdsEngineResponse = z37.object({
4883
- offers: z37.array(z37.unknown()).default([]).transform(
5281
+ var AdsEngineResponse = z41.object({
5282
+ offers: z41.array(z41.unknown()).default([]).transform(
4884
5283
  (offers) => offers.flatMap((offer) => {
4885
5284
  const result = AdsEngineOffer.safeParse(offer);
4886
5285
  return result.success ? [result.data] : [];
@@ -4892,8 +5291,8 @@ var AdsEngineResponse = z37.object({
4892
5291
  * offers-testing fixture on a test store forces it, REB-24467). Both optional: an older engine or a
4893
5292
  * non-JSON body must not fail the parse and drop the offers.
4894
5293
  */
4895
- request_id: z37.string().optional().catch(void 0),
4896
- testing: z37.boolean().optional().catch(void 0)
5294
+ request_id: z41.string().optional().catch(void 0),
5295
+ testing: z41.boolean().optional().catch(void 0)
4897
5296
  });
4898
5297
  var adsHost = (host) => `offers.${host}`;
4899
5298
  var isTestingRequest = (input, isProduction) => !isProduction || !!input.testing || input.customerEmail?.toLowerCase() === TEST_CUSTOMER_EMAIL;
@@ -5345,13 +5744,13 @@ var convertWidgetSettings = async (input, ctx) => {
5345
5744
  };
5346
5745
 
5347
5746
  // src/server/giftWidgets.ts
5348
- import { z as z38 } from "zod";
5349
- var SettingsNumber = z38.union([
5350
- z38.number(),
5351
- z38.string().trim().regex(/^-?\d+(\.\d+)?$/)
5352
- ]).pipe(z38.coerce.number());
5353
- var SgwpMilestoneSchema = z38.object({
5354
- selectable_product_quantity: SettingsNumber.pipe(z38.number().int().nonnegative()),
5747
+ import { z as z42 } from "zod";
5748
+ var SettingsNumber = z42.union([
5749
+ z42.number(),
5750
+ z42.string().trim().regex(/^-?\d+(\.\d+)?$/)
5751
+ ]).pipe(z42.coerce.number());
5752
+ var SgwpMilestoneSchema = z42.object({
5753
+ selectable_product_quantity: SettingsNumber.pipe(z42.number().int().nonnegative()),
5355
5754
  unlock_price: SettingsNumber
5356
5755
  });
5357
5756
  var fetchGiftWidgetSettings = async (widgetId, shop, ctx) => unwrapData(await ctx.fetchUpstream("/api/v1/widgets/settings", { id: String(widgetId), shop }, { host: ctx.host }));
@@ -5362,7 +5761,7 @@ var readDataSourcePath = (settings) => {
5362
5761
  var readMilestones = (settings, report) => {
5363
5762
  const raw = settings && typeof settings === "object" ? settings.milestones : void 0;
5364
5763
  if (raw == null) return [];
5365
- const parsed = z38.array(SgwpMilestoneSchema).safeParse(raw);
5764
+ const parsed = z42.array(SgwpMilestoneSchema).safeParse(raw);
5366
5765
  if (parsed.success) return parsed.data;
5367
5766
  report?.({
5368
5767
  detail: [
@@ -5468,25 +5867,25 @@ var validateGifts = async (input, ctx) => {
5468
5867
  const [remove, adjust] = await Promise.all([validateGwpGifts(input, ctx), validateSelectableGifts(input, ctx)]);
5469
5868
  const removed = new Set(remove);
5470
5869
  const targets = /* @__PURE__ */ new Map();
5471
- for (const { lineId, quantity: quantity2 } of adjust) {
5870
+ for (const { lineId, quantity: quantity3 } of adjust) {
5472
5871
  if (removed.has(lineId)) continue;
5473
- targets.set(lineId, Math.min(quantity2, targets.get(lineId) ?? quantity2));
5872
+ targets.set(lineId, Math.min(quantity3, targets.get(lineId) ?? quantity3));
5474
5873
  }
5475
- return { adjust: [...targets].map(([lineId, quantity2]) => ({ lineId, quantity: quantity2 })), remove: [...removed] };
5874
+ return { adjust: [...targets].map(([lineId, quantity3]) => ({ lineId, quantity: quantity3 })), remove: [...removed] };
5476
5875
  };
5477
5876
 
5478
5877
  // src/server/normalizePostPurchaseProduct.ts
5479
5878
  import { merge } from "es-toolkit/compat";
5480
- import { z as z43 } from "zod";
5879
+ import { z as z45 } from "zod";
5481
5880
 
5482
5881
  // src/schema/postPurchaseProductSettings.ts
5483
- import { z as z42 } from "zod";
5882
+ import { z as z44 } from "zod";
5484
5883
 
5485
5884
  // src/schema/postPurchaseProductSource.ts
5486
- import { z as z39 } from "zod";
5487
- var PostPurchaseAmount = z39.string().regex(/^\d+(?:\.\d+)?$/).refine((value) => Number.isFinite(Number(value)));
5488
- var PostPurchaseProductId = z39.number().int().positive();
5489
- var PostPurchaseVariantId = z39.number().int().positive();
5885
+ import { z as z43 } from "zod";
5886
+ var PostPurchaseAmount = z43.string().regex(/^\d+(?:\.\d+)?$/).refine((value) => Number.isFinite(Number(value)));
5887
+ var PostPurchaseProductId = z43.number().int().positive();
5888
+ var PostPurchaseVariantId = z43.number().int().positive();
5490
5889
  var ProductBase = OfferProduct.pick({ description: true, id: true, image: true, title: true }).extend({
5491
5890
  description: OfferProduct.shape.description.nullable(),
5492
5891
  id: PostPurchaseProductId
@@ -5494,235 +5893,49 @@ var ProductBase = OfferProduct.pick({ description: true, id: true, image: true,
5494
5893
  var SourceVariant = OfferProduct.shape.variants.element.pick({ id: true, title: true }).extend({
5495
5894
  compareAtPrice: PostPurchaseAmount.nullable(),
5496
5895
  id: PostPurchaseVariantId,
5497
- imageId: z39.number().int().nonnegative().nullish(),
5498
- inventoryManagement: z39.string().nullable(),
5499
- inventoryPolicy: z39.string(),
5500
- inventoryQuantity: z39.number(),
5501
- option1: z39.unknown().optional(),
5502
- option2: z39.unknown().optional(),
5503
- option3: z39.unknown().optional(),
5896
+ imageId: z43.number().int().nonnegative().nullish(),
5897
+ inventoryManagement: z43.string().nullable(),
5898
+ inventoryPolicy: z43.string(),
5899
+ inventoryQuantity: z43.number(),
5900
+ option1: z43.unknown().optional(),
5901
+ option2: z43.unknown().optional(),
5902
+ option3: z43.unknown().optional(),
5504
5903
  price: PostPurchaseAmount,
5505
5904
  productId: PostPurchaseProductId,
5506
- sellingPlanAllocations: z39.unknown().optional()
5905
+ sellingPlanAllocations: z43.unknown().optional()
5507
5906
  });
5508
5907
  var Product2 = ProductBase.extend({
5509
- images: z39.array(
5510
- z39.object({ alt: z39.string().optional().catch(void 0), id: z39.number().int().positive(), src: z39.string() })
5908
+ images: z43.array(
5909
+ z43.object({ alt: z43.string().optional().catch(void 0), id: z43.number().int().positive(), src: z43.string() })
5511
5910
  ).nullish(),
5512
- metadata: z39.object({
5513
- productQuantity: z39.union([
5514
- z39.number().int().positive(),
5515
- z39.string().regex(/^[1-9]\d*$/).transform(Number)
5911
+ metadata: z43.object({
5912
+ productQuantity: z43.union([
5913
+ z43.number().int().positive(),
5914
+ z43.string().regex(/^[1-9]\d*$/).transform(Number)
5516
5915
  ]).optional()
5517
5916
  }).optional(),
5518
- metafields: z39.unknown().optional(),
5519
- options: z39.unknown().optional(),
5520
- productGroupVariants: z39.array(z39.unknown()).default([]),
5521
- selectedVariant: z39.unknown().optional(),
5522
- sellingPlanGroups: z39.array(
5917
+ metafields: z43.unknown().optional(),
5918
+ options: z43.unknown().optional(),
5919
+ productGroupVariants: z43.array(z43.unknown()).default([]),
5920
+ selectedVariant: z43.unknown().optional(),
5921
+ sellingPlanGroups: z43.array(
5523
5922
  OfferProduct.shape.sellingPlanGroups.unwrap().element.extend({
5524
- discountAmount: z39.unknown().optional(),
5525
- discountType: z39.unknown().optional(),
5526
- id: z39.unknown().optional(),
5527
- requiresSellingPlan: z39.boolean().default(false),
5528
- sellingPlans: z39.unknown().optional()
5923
+ discountAmount: z43.unknown().optional(),
5924
+ discountType: z43.unknown().optional(),
5925
+ id: z43.unknown().optional(),
5926
+ requiresSellingPlan: z43.boolean().default(false),
5927
+ sellingPlans: z43.unknown().optional()
5529
5928
  })
5530
5929
  ).default([]),
5531
- variants: z39.array(SourceVariant)
5930
+ variants: z43.array(SourceVariant)
5532
5931
  });
5533
- var PostPurchaseProductSource = z39.object({
5534
- data: z39.array(Product2),
5535
- metadata: z39.object({ widget: z39.record(z39.string(), z39.unknown()).default({}) }).default({ widget: {} })
5536
- });
5537
-
5538
- // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
5539
- import { z as z41 } from "zod";
5540
-
5541
- // src/schema/widgets/post-purchase-offer/common.ts
5542
- import { replace, toNumber, toString } from "es-toolkit/compat";
5543
- import { z as z40 } from "zod";
5544
- var strictNumber = z40.union([
5545
- z40.number(),
5546
- z40.string().transform((value) => toNumber(replace(toString(value), /[^0-9.]/g, "")) || 0),
5547
- z40.unknown().transform(() => 0)
5548
- ]);
5549
-
5550
- // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
5551
- var PostPurchaseSettings = z41.object({
5552
- advance: z41.object({ removePartialOrder: z41.boolean().default(true) }).optional().default(() => ({ removePartialOrder: true })),
5553
- blocks: z41.union([z41.array(PostPurchaseBlock), z41.unknown().transform(() => [])]).default(() => [
5554
- PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.timer }),
5555
- PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.callout_banner }),
5556
- PostPurchaseBlock.parse({ type: BlockType.product_information })
5557
- ]),
5558
- columnLayout: z41.boolean().optional(),
5559
- discount: z41.object({
5560
- amount: strictNumber.default(30),
5561
- shouldShowSavingText: z41.boolean().optional().default(true),
5562
- type: z41.enum(["none", "fixed_amount", "percentage"]).default("none")
5563
- }),
5564
- discountedFrom: z41.enum(["price", "compare_at_price"]).optional().default("price"),
5565
- endpoint: z41.string().optional(),
5566
- integrations: z41.object({
5567
- judgeme: z41.boolean().default(false),
5568
- junip: z41.boolean().optional().default(false),
5569
- klaviyo: z41.boolean().default(false),
5570
- loox: z41.boolean().default(false),
5571
- okendo: z41.boolean().default(false),
5572
- opinew: z41.boolean().optional().default(false),
5573
- reviewsio: z41.boolean().optional().default(false),
5574
- stamped: z41.boolean().default(false),
5575
- yotpo: z41.boolean().default(false)
5576
- }),
5577
- key: z41.string().optional(),
5578
- language: z41.object({
5579
- description: z41.union([z41.string(), z41.unknown().transform(() => "")]).default(""),
5580
- descriptionEnabled: z41.boolean().optional().default(false),
5581
- descriptionRte: z41.object({
5582
- content: z41.array(z41.unknown()),
5583
- type: z41.string()
5584
- }).optional(),
5585
- descriptionSpacing: z41.enum(["none", "xtight", "tight", "default", "loose", "xloose"]).optional(),
5586
- displayCtaPrice: z41.boolean().default(true),
5587
- global: z41.object({
5588
- declineAll: z41.string().optional().default("Decline All"),
5589
- declineThisOffer: z41.string().default("Decline this offer"),
5590
- free: z41.string().optional().default("Free"),
5591
- notAvailable: z41.string().optional().default("Not available"),
5592
- payNow: z41.string().default("Pay Now"),
5593
- payNowUpgradeToSubscription: z41.string().optional().default("Upgrade to Subscription"),
5594
- quantity: z41.string().default("Quantity"),
5595
- /** This isn't configurable in the admin-nextjs editor */
5596
- recurringShipping: z41.string().optional().default("Recurring shipping"),
5597
- recurringSubtotal: z41.string().default("Recurring subtotal"),
5598
- reviewsPlural: z41.string().optional().default("Reviews"),
5599
- reviewsSingular: z41.string().optional().default("Review"),
5600
- save: z41.union([z41.string(), z41.unknown().transform(() => "Save")]).optional().default("Save"),
5601
- shipping: z41.string().default("Shipping"),
5602
- subscriptionOption: z41.string().optional().default("Subscribe and Save"),
5603
- subtotal: z41.string().default("Subtotal"),
5604
- taxes: z41.string().default("Taxes"),
5605
- total: z41.string().default("Total")
5606
- }).optional().default(() => ({
5607
- declineAll: "Decline All",
5608
- declineThisOffer: "Decline this offer",
5609
- free: "Free",
5610
- notAvailable: "Not available",
5611
- payNow: "Pay Now",
5612
- payNowUpgradeToSubscription: "Upgrade to Subscription",
5613
- quantity: "Quantity",
5614
- /** This isn't configurable in the admin-nextjs editor */
5615
- recurringShipping: "Recurring shipping",
5616
- recurringSubtotal: "Recurring subtotal",
5617
- reviewsPlural: "Reviews",
5618
- reviewsSingular: "Review",
5619
- save: "Save",
5620
- shipping: "Shipping",
5621
- subscriptionOption: "Subscribe and Save",
5622
- subtotal: "Subtotal",
5623
- taxes: "Taxes",
5624
- total: "Total"
5625
- })),
5626
- globalTranslation: z41.string().optional().default("english")
5627
- }),
5628
- metafields: z41.boolean().default(false),
5629
- /** This isn't configurable in the admin-nextjs editor */
5630
- offer: z41.object({
5631
- count: z41.number().default(1)
5632
- }),
5633
- offersLayout: z41.object({
5634
- itemsPerPage: z41.number().optional(),
5635
- type: z41.enum(["list", "grid", "carousel"]).default("list")
5636
- }).optional().default({
5637
- type: "list"
5638
- }),
5639
- /** This isn't configurable in the admin-nextjs editor */
5640
- previewMode: z41.boolean().default(false),
5641
- productLimit: z41.number().optional().default(1),
5642
- productOptions: z41.object({
5643
- /** This isn't configurable in the admin-nextjs editor */
5644
- hideOutOfStockVariants: z41.boolean().optional().default(false),
5645
- matchVariant: z41.boolean().optional().default(true),
5646
- showDeclineAll: z41.enum(["above", "below", "both", "none"]).optional(),
5647
- showShipping: z41.boolean().optional().default(true),
5648
- showSubtotal: z41.boolean().optional().default(true),
5649
- showTaxes: z41.boolean().optional().default(true),
5650
- showTotal: z41.boolean().optional().default(true),
5651
- showVariantSelectors: z41.boolean().optional().default(true),
5652
- variantSelectorDisplayMode: z41.enum(["separate", "single"]).optional().default("separate")
5653
- }),
5654
- productType: z41.union([z41.enum(["one-time", "subscription", "both"]), z41.literal("").transform(() => "one-time")]).default("one-time"),
5655
- productTypeSelector: z41.enum(["dropdown", "radio"]).optional().default("radio"),
5656
- quantityInputs: z41.object({
5657
- defaultQuantity: z41.union([z41.number(), z41.null().transform(() => 1)]).default(1),
5658
- enabled: z41.boolean().default(true),
5659
- maxValue: z41.union([z41.number(), z41.null().transform(() => 15)]).default(15),
5660
- minValue: z41.union([z41.number().min(0), z41.unknown().transform(() => 0)]).default(1)
5661
- }),
5662
- shipping: z41.object({
5663
- amount: strictNumber.default(10),
5664
- /** This isn't configurable in the admin-nextjs editor */
5665
- enabled: z41.boolean().default(true),
5666
- title: z41.string().optional().default("Shipping Fees"),
5667
- type: z41.enum(["free", "fixed_amount"]).default("free")
5668
- }),
5669
- styles: z41.object({
5670
- starColor: z41.string().optional().default("#fadb14"),
5671
- starSize: z41.union([z41.enum(["small", "medium", "large"]), z41.unknown().transform(() => "large")]).optional().default("large"),
5672
- starStrokeColor: z41.string().optional().default("#fadb14"),
5673
- strokeWidth: z41.string().optional().default("1")
5674
- }).optional(),
5675
- subImages: z41.number().nullish().default(8),
5676
- subscription: z41.object({
5677
- discount: z41.object({
5678
- amount: strictNumber.default(30),
5679
- shouldShowSavingText: z41.boolean().optional().default(true),
5680
- type: z41.enum(["none", "fixed_amount", "percentage"]).default("none")
5681
- }),
5682
- shipping: z41.object({
5683
- amount: strictNumber.default(1),
5684
- /** This isn't configurable in the admin-nextjs editor */
5685
- enabled: z41.boolean().default(true),
5686
- /** This isn't configurable in the admin-nextjs editor */
5687
- recurringAmount: strictNumber.default(2),
5688
- shippingTitle: z41.string().default("Shipping Fees"),
5689
- type: z41.enum(["free", "fixed_amount"]).default("free")
5690
- })
5691
- }).optional().default({
5692
- discount: {
5693
- amount: 30,
5694
- shouldShowSavingText: true,
5695
- type: "none"
5696
- },
5697
- shipping: {
5698
- amount: 1,
5699
- /** This isn't configurable in the admin-nextjs editor */
5700
- enabled: true,
5701
- /** This isn't configurable in the admin-nextjs editor */
5702
- recurringAmount: 2,
5703
- shippingTitle: "Shipping Fees",
5704
- type: "free"
5705
- }
5706
- }),
5707
- subscriptionIsDefault: z41.boolean().optional(),
5708
- /** This isn't configurable in the admin-nextjs editor */
5709
- template: z41.string().optional().default(""),
5710
- type: z41.literal("shopify_post_purchase_extension").default("shopify_post_purchase_extension"),
5711
- upgradeToSubscription: z41.object({
5712
- acceptButtonText: z41.string().optional().default("Upgrade"),
5713
- allow: z41.boolean().optional().default(false),
5714
- emailRefundNotice: z41.boolean().optional().default(false),
5715
- errorBannerText: z41.string().optional().default("This subscription cannot be added - limit one per order")
5716
- }).optional().default(() => ({
5717
- acceptButtonText: "Upgrade",
5718
- allow: false,
5719
- emailRefundNotice: false,
5720
- errorBannerText: "This subscription cannot be added - limit one per order"
5721
- }))
5932
+ var PostPurchaseProductSource = z43.object({
5933
+ data: z43.array(Product2),
5934
+ metadata: z43.object({ widget: z43.record(z43.string(), z43.unknown()).default({}) }).default({ widget: {} })
5722
5935
  });
5723
5936
 
5724
5937
  // src/schema/postPurchaseProductSettings.ts
5725
- var amount = z42.union([z42.number().nonnegative(), PostPurchaseAmount.transform(Number)]);
5938
+ var amount = z44.union([z44.number().nonnegative(), PostPurchaseAmount.transform(Number)]);
5726
5939
  var PostPurchaseProductSettings = PostPurchaseSettings.pick({
5727
5940
  discountedFrom: true,
5728
5941
  language: true,
@@ -5734,14 +5947,14 @@ var PostPurchaseProductSettings = PostPurchaseSettings.pick({
5734
5947
  subscriptionIsDefault: true,
5735
5948
  upgradeToSubscription: true
5736
5949
  }).extend({
5737
- advance: z42.unknown().default({}),
5738
- blocks: z42.array(z42.unknown()).optional(),
5950
+ advance: z44.unknown().default({}),
5951
+ blocks: z44.array(z44.unknown()).optional(),
5739
5952
  discount: PostPurchaseSettings.shape.discount.extend({ amount: amount.default(30) }),
5740
- integrations: z42.unknown().default({}),
5953
+ integrations: z44.unknown().default({}),
5741
5954
  shipping: PostPurchaseSettings.shape.shipping.extend({ amount: amount.default(10) }),
5742
- styles: z42.unknown().default({}),
5955
+ styles: z44.unknown().default({}),
5743
5956
  subImages: PostPurchaseSettings.shape.subImages.catch(null),
5744
- subscription: z42.unknown().default(PostPurchaseSettings.shape.subscription.parse(void 0))
5957
+ subscription: z44.unknown().default(PostPurchaseSettings.shape.subscription.parse(void 0))
5745
5958
  });
5746
5959
 
5747
5960
  // src/server/normalizePostPurchaseProduct.ts
@@ -5749,59 +5962,83 @@ var normalizePostPurchaseProduct = (settings, response) => {
5749
5962
  const original = PostPurchaseProductSettings.parse(deepCamelCase(settings));
5750
5963
  const { data, metadata } = PostPurchaseProductSource.parse(deepCamelCase(response));
5751
5964
  const overrides = Object.fromEntries(Object.entries(metadata.widget).filter(([key]) => key in original));
5752
- const discount = z43.object({ type: z43.string() }).safeParse(overrides.discount);
5965
+ const discount = z45.object({ type: z45.string() }).safeParse(overrides.discount);
5753
5966
  if (discount.success && discount.data.type === "fixed") {
5754
- overrides.discount = { ...z43.record(z43.string(), z43.unknown()).parse(overrides.discount), type: "fixed_amount" };
5967
+ overrides.discount = { ...z45.record(z45.string(), z45.unknown()).parse(overrides.discount), type: "fixed_amount" };
5755
5968
  }
5756
5969
  const effective = PostPurchaseProductSettings.parse(merge({}, original, overrides));
5757
5970
  return { data, effective, metadata, original };
5758
5971
  };
5759
5972
 
5973
+ // src/pricing/amountToCents.ts
5974
+ var round = (value, precision = 0) => {
5975
+ const factor = 10 ** precision;
5976
+ return Math.round(value * factor) / factor;
5977
+ };
5978
+ var amountToCents = (amount2, decimals = 2) => {
5979
+ const value = Number(amount2);
5980
+ return Number.isFinite(value) ? round(round(value, decimals) * 10 ** decimals) : 0;
5981
+ };
5982
+
5983
+ // src/pricing/postPurchaseReduction.ts
5984
+ var reducePostPurchaseMinor = (priceMinor, { amount: amount2, type }, decimals) => {
5985
+ if (type === "price") return amountToCents(amount2, decimals);
5986
+ const reduction = type === "percentage" ? Math.round(priceMinor * (amount2 / 100)) : type === "fixed_amount" ? amountToCents(amount2, decimals) : 0;
5987
+ return Math.max(0, priceMinor - reduction);
5988
+ };
5989
+ var postPurchasePlanDiscountPercentage = (price, adjustment) => {
5990
+ const regularMinor = amountToCents(price);
5991
+ const planMinor = adjustment ? reducePostPurchaseMinor(regularMinor, adjustment, 2) : regularMinor;
5992
+ return regularMinor > 0 && planMinor < regularMinor ? Math.round((1 - planMinor / regularMinor) * 100) : 0;
5993
+ };
5994
+
5760
5995
  // src/schema/postPurchasePlanCatalog.ts
5761
- import { z as z46 } from "zod";
5996
+ import { z as z48 } from "zod";
5762
5997
 
5763
5998
  // src/schema/postPurchasePlanAdjustment.ts
5764
- import { z as z45 } from "zod";
5999
+ import { z as z47 } from "zod";
5765
6000
 
5766
6001
  // src/schema/postPurchaseDiscount.ts
5767
- import { z as z44 } from "zod";
5768
- var Discount = z44.object({
5769
- amount: z44.number().nonnegative(),
5770
- title: z44.string(),
5771
- type: z44.enum(["none", "fixed_amount", "percentage"])
6002
+ import { z as z46 } from "zod";
6003
+ var Discount = z46.object({
6004
+ amount: z46.number().nonnegative(),
6005
+ title: z46.string(),
6006
+ type: z46.enum(["none", "fixed_amount", "percentage"])
5772
6007
  });
5773
6008
  var validPostPurchaseDiscount = (discount) => discount.type !== "percentage" || discount.amount <= 100;
5774
6009
  var PostPurchaseDiscount = Discount.refine(validPostPurchaseDiscount);
5775
6010
 
5776
6011
  // src/schema/postPurchasePlanAdjustment.ts
5777
- var PostPurchasePlanAdjustment = z45.object({
6012
+ var PostPurchasePlanAdjustment = z47.object({
5778
6013
  amount: PostPurchaseDiscount.shape.amount,
5779
- type: z45.enum(["percentage", "fixed_amount", "price"])
6014
+ type: z47.enum(["percentage", "fixed_amount", "price"])
5780
6015
  }).refine(({ amount: amount2, type }) => type === "price" || validPostPurchaseDiscount({ amount: amount2, type }));
5781
6016
 
5782
6017
  // src/schema/postPurchasePlanCatalog.ts
5783
- var PostPurchasePlanOption = z46.object({
6018
+ var PostPurchasePlanOption = z48.object({
5784
6019
  adjustment: PostPurchasePlanAdjustment.optional(),
5785
- id: z46.number().int().positive(),
5786
- intervalFrequency: z46.string().regex(/^[1-9]\d*$/).optional(),
5787
- intervalLabel: z46.string().min(1),
5788
- name: z46.string().min(1)
6020
+ /** cab-checkout's `discountPercentage`: the plan's own whole-percent saving on the regular price (`{{subscriptionDiscount}}`). */
6021
+ discountPercentage: z48.number().int().min(0).max(100).optional(),
6022
+ id: z48.number().int().positive(),
6023
+ intervalFrequency: z48.string().regex(/^[1-9]\d*$/).optional(),
6024
+ intervalLabel: z48.string().min(1),
6025
+ name: z48.string().min(1)
5789
6026
  });
5790
- var PostPurchasePlanCatalog = z46.object({
5791
- plans: z46.array(PostPurchasePlanOption),
5792
- productId: z46.number().int().positive(),
5793
- requiresSellingPlan: z46.boolean(),
5794
- variantId: z46.number().int().positive()
6027
+ var PostPurchasePlanCatalog = z48.object({
6028
+ plans: z48.array(PostPurchasePlanOption),
6029
+ productId: z48.number().int().positive(),
6030
+ requiresSellingPlan: z48.boolean(),
6031
+ variantId: z48.number().int().positive()
5795
6032
  });
5796
6033
 
5797
6034
  // src/server/postPurchaseLegacyPlans.ts
5798
- import { z as z48 } from "zod";
6035
+ import { z as z50 } from "zod";
5799
6036
 
5800
6037
  // src/server/postPurchasePlanAdjustment.ts
5801
- import { z as z47 } from "zod";
5802
- var SourceAdjustment = z47.object({
6038
+ import { z as z49 } from "zod";
6039
+ var SourceAdjustment = z49.object({
5803
6040
  amount: PostPurchaseProductSettings.shape.discount.shape.amount.unwrap(),
5804
- type: z47.enum(["percentage", "fixed_amount", "amount", "price", "none", "fixed"])
6041
+ type: z49.enum(["percentage", "fixed_amount", "amount", "price", "none", "fixed"])
5805
6042
  });
5806
6043
  var readPostPurchasePlanAdjustment = (raw) => {
5807
6044
  const source2 = SourceAdjustment.parse(raw);
@@ -5820,13 +6057,13 @@ var readPostPurchasePlanAdjustment = (raw) => {
5820
6057
  var Plan = PostPurchasePlanOption.pick({ id: true, name: true }).extend({
5821
6058
  orderIntervalFrequency: PostPurchasePlanOption.shape.intervalFrequency.unwrap(),
5822
6059
  orderIntervalUnitType: PostPurchasePlanOption.shape.intervalLabel,
5823
- shopifyVariantId: z48.string().regex(/^[1-9]\d*$/).nullish()
6060
+ shopifyVariantId: z50.string().regex(/^[1-9]\d*$/).nullish()
5824
6061
  });
5825
- var Group = z48.object({
5826
- discountAmount: z48.unknown(),
5827
- discountType: z48.unknown(),
5828
- id: z48.number().int().positive(),
5829
- sellingPlans: z48.array(z48.object({ shopifyVariantId: Plan.shape.shopifyVariantId }).passthrough())
6062
+ var Group = z50.object({
6063
+ discountAmount: z50.unknown(),
6064
+ discountType: z50.unknown(),
6065
+ id: z50.number().int().positive(),
6066
+ sellingPlans: z50.array(z50.object({ shopifyVariantId: Plan.shape.shopifyVariantId }).passthrough())
5830
6067
  });
5831
6068
  var readPostPurchaseLegacyPlans = (raw, variantId) => {
5832
6069
  const group = Group.pick({ id: true, sellingPlans: true }).parse(raw);
@@ -5847,21 +6084,21 @@ var readPostPurchaseLegacyPlans = (raw, variantId) => {
5847
6084
  };
5848
6085
 
5849
6086
  // src/server/postPurchaseModernPlans.ts
5850
- import { z as z49 } from "zod";
5851
- var Groups = z49.array(
5852
- z49.object({
5853
- id: z49.string().min(1),
5854
- sellingPlans: z49.unknown()
6087
+ import { z as z51 } from "zod";
6088
+ var Groups = z51.array(
6089
+ z51.object({
6090
+ id: z51.string().min(1),
6091
+ sellingPlans: z51.unknown()
5855
6092
  })
5856
6093
  );
5857
- var Allocations = z49.array(z49.object({ sellingPlanGroupId: z49.string().min(1) })).default([]);
5858
- var Plans = z49.array(
6094
+ var Allocations = z51.array(z51.object({ sellingPlanGroupId: z51.string().min(1) })).default([]);
6095
+ var Plans = z51.array(
5859
6096
  PostPurchasePlanOption.pick({ id: true, name: true }).extend({
5860
- options: z49.array(z49.object({ value: z49.string().min(1) })).min(1),
5861
- priceAdjustments: z49.array(z49.unknown())
6097
+ options: z51.array(z51.object({ value: z51.string().min(1) })).min(1),
6098
+ priceAdjustments: z51.array(z51.unknown())
5862
6099
  })
5863
6100
  );
5864
- var FirstAdjustment = z49.object({
6101
+ var FirstAdjustment = z51.object({
5865
6102
  value: PostPurchaseProductSettings.shape.discount.shape.amount.unwrap(),
5866
6103
  valueType: PostPurchasePlanAdjustment.shape.type
5867
6104
  });
@@ -5901,7 +6138,10 @@ var projectPostPurchasePlanCatalog = (normalized, report) => {
5901
6138
  unique.set(plan.id, plan);
5902
6139
  }
5903
6140
  return PostPurchasePlanCatalog.parse({
5904
- plans: [...unique.values()],
6141
+ plans: [...unique.values()].map((plan) => ({
6142
+ ...plan,
6143
+ discountPercentage: postPurchasePlanDiscountPercentage(variant2.price, plan.adjustment)
6144
+ })),
5905
6145
  productId: product.id,
5906
6146
  requiresSellingPlan: required[0] ?? false,
5907
6147
  variantId: variant2.id
@@ -5913,66 +6153,66 @@ var projectPostPurchasePlanCatalog = (normalized, report) => {
5913
6153
  };
5914
6154
 
5915
6155
  // src/schema/postPurchaseSubscriptionProduct.ts
5916
- import { z as z55 } from "zod";
6156
+ import { z as z57 } from "zod";
5917
6157
 
5918
6158
  // src/schema/postPurchaseProduct.ts
5919
- import { z as z54 } from "zod";
6159
+ import { z as z56 } from "zod";
5920
6160
 
5921
6161
  // src/schema/postPurchaseProductDisplay.ts
5922
- import { z as z52 } from "zod";
6162
+ import { z as z54 } from "zod";
5923
6163
 
5924
6164
  // src/schema/postPurchaseProductGallery.ts
5925
- import { z as z50 } from "zod";
5926
- var PostPurchaseProductGallery = z50.object({
5927
- images: z50.array(
5928
- z50.object({
5929
- description: z50.string(),
5930
- id: z50.number().int().positive(),
5931
- source: z50.string(),
5932
- thumbnail: z50.string()
6165
+ import { z as z52 } from "zod";
6166
+ var PostPurchaseProductGallery = z52.object({
6167
+ images: z52.array(
6168
+ z52.object({
6169
+ description: z52.string(),
6170
+ id: z52.number().int().positive(),
6171
+ source: z52.string(),
6172
+ thumbnail: z52.string()
5933
6173
  })
5934
6174
  ),
5935
- selectedImageId: z50.number().int().positive().optional()
6175
+ selectedImageId: z52.number().int().positive().optional()
5936
6176
  });
5937
6177
 
5938
6178
  // src/schema/postPurchaseProductReviews.ts
5939
- import { z as z51 } from "zod";
5940
- var decimal = z51.union([
5941
- z51.number(),
5942
- z51.string().regex(/^\d+(?:\.\d+)?$/).transform(Number)
6179
+ import { z as z53 } from "zod";
6180
+ var decimal = z53.union([
6181
+ z53.number(),
6182
+ z53.string().regex(/^\d+(?:\.\d+)?$/).transform(Number)
5943
6183
  ]);
5944
- var PostPurchaseCommonReviewRating = z51.object({ value: decimal.pipe(z51.number().min(0).max(5)) });
6184
+ var PostPurchaseCommonReviewRating = z53.object({ value: decimal.pipe(z53.number().min(0).max(5)) });
5945
6185
  var PostPurchaseKlaviyoReviewRating = PostPurchaseCommonReviewRating.extend({
5946
6186
  // Legacy validates key presence, then displays the raw value on five stars without rescaling.
5947
- scale_max: z51.unknown().nonoptional(),
5948
- scale_min: z51.unknown().nonoptional()
6187
+ scale_max: z53.unknown().nonoptional(),
6188
+ scale_min: z53.unknown().nonoptional()
5949
6189
  });
5950
- var PostPurchaseReviewCount = z51.string().regex(/^\d+(?:\.\d+)?$/).transform(Number).pipe(z51.number().int().nonnegative());
6190
+ var PostPurchaseReviewCount = z53.string().regex(/^\d+(?:\.\d+)?$/).transform(Number).pipe(z53.number().int().nonnegative());
5951
6191
  var PostPurchaseReviewStyles = PostPurchaseSettings.shape.styles.unwrap().extend({
5952
- strokeWidth: decimal.pipe(z51.number().nonnegative()).default(1)
6192
+ strokeWidth: decimal.pipe(z53.number().nonnegative()).default(1)
5953
6193
  }).prefault({});
5954
- var PostPurchaseProductReviews = z51.object({
5955
- color: z51.string(),
5956
- rating: z51.number().positive().max(5),
5957
- reviewCount: z51.number().int().nonnegative(),
5958
- reviewsPlural: z51.string(),
5959
- reviewsSingular: z51.string(),
5960
- size: z51.enum(["small", "medium", "large"]),
5961
- strokeColor: z51.string(),
5962
- strokeWidth: z51.number().nonnegative()
6194
+ var PostPurchaseProductReviews = z53.object({
6195
+ color: z53.string(),
6196
+ rating: z53.number().positive().max(5),
6197
+ reviewCount: z53.number().int().nonnegative(),
6198
+ reviewsPlural: z53.string(),
6199
+ reviewsSingular: z53.string(),
6200
+ size: z53.enum(["small", "medium", "large"]),
6201
+ strokeColor: z53.string(),
6202
+ strokeWidth: z53.number().nonnegative()
5963
6203
  });
5964
6204
 
5965
6205
  // src/schema/postPurchaseProductDisplay.ts
5966
6206
  var language = PostPurchaseSettings.shape.language;
5967
- var PostPurchasePrimaryImageSource = z52.string().default(
6207
+ var PostPurchasePrimaryImageSource = z54.string().default(
5968
6208
  "https://cdn.shopify.com/shopifycloud/shopify/assets/no-image-2048-5e88c1b20e087fb7bbe9a3771824e743c244f437e4f8ba93bbf7b11b53f7824c.gif"
5969
6209
  );
5970
- var PostPurchaseProductDisplay = z52.object({
6210
+ var PostPurchaseProductDisplay = z54.object({
5971
6211
  descriptionDocument: TiptapDocument.optional(),
5972
6212
  discountedFrom: PostPurchaseSettings.shape.discountedFrom,
5973
6213
  gallery: PostPurchaseProductGallery.optional(),
5974
6214
  language: language.pick({ description: true, descriptionEnabled: true }),
5975
- primaryImage: z52.object({ description: z52.string(), source: z52.string() }),
6215
+ primaryImage: z54.object({ description: z54.string(), source: z54.string() }),
5976
6216
  productOptions: PostPurchaseSettings.shape.productOptions.pick({
5977
6217
  showDeclineAll: true,
5978
6218
  showShipping: true,
@@ -5987,14 +6227,14 @@ var PostPurchaseProductDisplay = z52.object({
5987
6227
  });
5988
6228
 
5989
6229
  // src/schema/postPurchaseSubscription.ts
5990
- import { z as z53 } from "zod";
5991
- var PostPurchaseSubscriptionTerms = z53.object({
6230
+ import { z as z55 } from "zod";
6231
+ var PostPurchaseSubscriptionTerms = z55.object({
5992
6232
  adjustment: PostPurchasePlanAdjustment.optional(),
5993
- initialShippingPrice: z53.number().nonnegative(),
5994
- intervalLabel: z53.string().min(1),
5995
- name: z53.string().min(1),
5996
- recurringShippingPrice: z53.number().nonnegative(),
5997
- shippingOption: z53.object({ presentmentTitle: z53.string(), title: z53.string() })
6233
+ initialShippingPrice: z55.number().nonnegative(),
6234
+ intervalLabel: z55.string().min(1),
6235
+ name: z55.string().min(1),
6236
+ recurringShippingPrice: z55.number().nonnegative(),
6237
+ shippingOption: z55.object({ presentmentTitle: z55.string(), title: z55.string() })
5998
6238
  });
5999
6239
 
6000
6240
  // src/schema/postPurchaseProduct.ts
@@ -6004,51 +6244,52 @@ var PostPurchaseVariant = OfferProduct.shape.variants.element.pick({ id: true, t
6004
6244
  id: PostPurchaseVariantId,
6005
6245
  price: PostPurchaseAmount
6006
6246
  });
6007
- var PreparedPostPurchaseProduct = z54.object({
6247
+ var PreparedPostPurchaseProduct = z56.object({
6008
6248
  display: PostPurchaseProductDisplay,
6009
- labels: z54.object({
6249
+ labels: z56.object({
6010
6250
  declineAll: global.declineAll,
6011
- free: z54.string(),
6012
- payNow: z54.string(),
6013
- quantity: z54.string(),
6251
+ free: z56.string(),
6252
+ notAvailable: global.notAvailable,
6253
+ payNow: z56.string(),
6254
+ quantity: z56.string(),
6014
6255
  recurringShipping: global.recurringShipping,
6015
6256
  recurringSubtotal: global.recurringSubtotal,
6016
- save: z54.string(),
6017
- shipping: z54.string(),
6018
- subtotal: z54.string(),
6019
- taxes: z54.string(),
6020
- total: z54.string()
6257
+ save: z56.string(),
6258
+ shipping: z56.string(),
6259
+ subtotal: z56.string(),
6260
+ taxes: z56.string(),
6261
+ total: z56.string()
6021
6262
  }),
6022
6263
  product: OfferProduct.pick({ description: true, id: true, image: true, title: true }).extend({
6023
6264
  description: OfferProduct.shape.description.nullable(),
6024
6265
  id: PostPurchaseProductId,
6025
6266
  variant: PostPurchaseVariant
6026
6267
  }),
6027
- selection: z54.object({
6268
+ selection: z56.object({
6028
6269
  productId: PostPurchaseProductId,
6029
- quantity: z54.number().int().positive(),
6030
- sellingPlanId: z54.number().int().positive().optional(),
6270
+ quantity: z56.number().int().positive(),
6271
+ sellingPlanId: z56.number().int().positive().optional(),
6031
6272
  variantId: PostPurchaseVariantId
6032
6273
  }),
6033
- status: z54.literal("prepared"),
6034
- terms: z54.object({
6274
+ status: z56.literal("prepared"),
6275
+ terms: z56.object({
6035
6276
  discount: PostPurchaseDiscount,
6036
- shipping: z54.object({
6037
- amount: z54.number().nonnegative(),
6038
- title: z54.string(),
6039
- type: z54.enum(["free", "fixed_amount"])
6277
+ shipping: z56.object({
6278
+ amount: z56.number().nonnegative(),
6279
+ title: z56.string(),
6280
+ type: z56.enum(["free", "fixed_amount"])
6040
6281
  }),
6041
6282
  subscription: PostPurchaseSubscriptionTerms.optional()
6042
6283
  })
6043
6284
  });
6044
- var PostPurchasePreparation = z54.discriminatedUnion("status", [
6285
+ var PostPurchasePreparation = z56.discriminatedUnion("status", [
6045
6286
  PreparedPostPurchaseProduct,
6046
- z54.object({ reason: z54.string(), status: z54.literal("unsupported") })
6287
+ z56.object({ reason: z56.string(), status: z56.literal("unsupported") })
6047
6288
  ]);
6048
6289
 
6049
6290
  // src/schema/postPurchaseSubscriptionProduct.ts
6050
6291
  var PreparedPostPurchaseSubscription = PreparedPostPurchaseProduct.extend({
6051
- selection: PreparedPostPurchaseProduct.shape.selection.extend({ sellingPlanId: z55.number().int().positive() }),
6292
+ selection: PreparedPostPurchaseProduct.shape.selection.extend({ sellingPlanId: z57.number().int().positive() }),
6052
6293
  terms: PreparedPostPurchaseProduct.shape.terms.extend({
6053
6294
  subscription: PostPurchaseSubscriptionTerms
6054
6295
  }).refine(
@@ -6071,12 +6312,12 @@ var PostPurchaseSubscriptionSettings = subscription.extend({
6071
6312
  var postPurchaseVariantAvailable = (variant2) => !(variant2.inventoryManagement && variant2.inventoryPolicy === "deny" && variant2.inventoryQuantity <= 0);
6072
6313
 
6073
6314
  // src/server/postPurchaseSubscriptionEligibility.ts
6074
- var subscriptionUnavailable = (normalized, plan, allowCollection, quantity2) => {
6315
+ var subscriptionUnavailable = (normalized, plan, allowCollection, quantity3) => {
6075
6316
  const { data, effective, original } = normalized;
6076
6317
  const unavailable = "An eligible subscription plan with supported shipping and discount is required";
6077
6318
  if (data.length !== 1 || data[0].variants.length !== 1) return unavailable;
6078
6319
  if (effective.productType === "one-time" || [original, effective].some(
6079
- (config) => !allowCollection && config.productLimit !== 1 || config.upgradeToSubscription.allow || !quantity2 && config.quantityInputs.enabled && (config.quantityInputs.minValue !== config.quantityInputs.maxValue || config.quantityInputs.defaultQuantity !== config.quantityInputs.minValue)
6320
+ (config) => !allowCollection && config.productLimit !== 1 || config.upgradeToSubscription.allow || !quantity3 && config.quantityInputs.enabled && (config.quantityInputs.minValue !== config.quantityInputs.maxValue || config.quantityInputs.defaultQuantity !== config.quantityInputs.minValue)
6080
6321
  ))
6081
6322
  return unavailable;
6082
6323
  const product = data[0];
@@ -6090,7 +6331,7 @@ var subscriptionUnavailable = (normalized, plan, allowCollection, quantity2) =>
6090
6331
  };
6091
6332
 
6092
6333
  // src/server/postPurchaseProductDisplay.ts
6093
- import { z as z57 } from "zod";
6334
+ import { z as z59 } from "zod";
6094
6335
 
6095
6336
  // src/server/postPurchasePrimaryImage.ts
6096
6337
  var postPurchasePrimaryImage = (product) => {
@@ -6112,7 +6353,7 @@ var postPurchaseProductGallery = (product, limit) => ({
6112
6353
  });
6113
6354
 
6114
6355
  // src/transforms/postPurchase/convertDescriptionRte.ts
6115
- import { z as z56 } from "zod";
6356
+ import { z as z58 } from "zod";
6116
6357
  var alignments = { center: "center", left: "start", right: "end" };
6117
6358
  var colors = ["critical", "subdued", "success", "warning"];
6118
6359
  var sizes2 = ["extraSmall", "small", "medium", "large", "extraLarge"];
@@ -6124,19 +6365,19 @@ var spacings2 = {
6124
6365
  xloose: "extraLoose",
6125
6366
  xtight: "extraTight"
6126
6367
  };
6127
- var Block = z56.object({
6128
- attrs: z56.object({ alignment: z56.enum(["left", "center", "right"]).optional().catch(void 0) }).catch({}),
6129
- content: z56.array(z56.unknown()).catch([]),
6130
- type: z56.literal("ShopifyTextBlock")
6131
- });
6132
- var Run = z56.object({ marks: z56.array(z56.unknown()).catch([]), text: z56.string().min(1), type: z56.literal("text") });
6133
- var Inline = z56.object({
6134
- attrs: z56.object({
6135
- color: z56.enum(colors).optional().catch(void 0),
6136
- emphasis: z56.array(z56.unknown()).catch([]),
6137
- size: z56.enum(sizes2).optional().catch(void 0)
6368
+ var Block = z58.object({
6369
+ attrs: z58.object({ alignment: z58.enum(["left", "center", "right"]).optional().catch(void 0) }).catch({}),
6370
+ content: z58.array(z58.unknown()).catch([]),
6371
+ type: z58.literal("ShopifyTextBlock")
6372
+ });
6373
+ var Run = z58.object({ marks: z58.array(z58.unknown()).catch([]), text: z58.string().min(1), type: z58.literal("text") });
6374
+ var Inline = z58.object({
6375
+ attrs: z58.object({
6376
+ color: z58.enum(colors).optional().catch(void 0),
6377
+ emphasis: z58.array(z58.unknown()).catch([]),
6378
+ size: z58.enum(sizes2).optional().catch(void 0)
6138
6379
  }),
6139
- type: z56.literal("ShopifyTextInline")
6380
+ type: z58.literal("ShopifyTextInline")
6140
6381
  });
6141
6382
  var marks = (raw) => {
6142
6383
  const found = raw.map((mark) => Inline.safeParse(mark)).find(({ success }) => success)?.data;
@@ -6169,7 +6410,7 @@ var convertDescriptionRte = (rte, spacing) => TiptapDocument.parse({
6169
6410
  });
6170
6411
 
6171
6412
  // src/server/postPurchaseProductDisplay.ts
6172
- var ResponseLanguage = z57.object({ description: PostPurchaseProductDisplay.shape.responseDescription }).default({ description: "" });
6413
+ var ResponseLanguage = z59.object({ description: PostPurchaseProductDisplay.shape.responseDescription }).default({ description: "" });
6173
6414
  var projectPostPurchaseProductDisplay = (effective, metadata, product) => PostPurchaseProductDisplay.parse({
6174
6415
  descriptionDocument: effective.language.descriptionRte && convertDescriptionRte(effective.language.descriptionRte, effective.language.descriptionSpacing),
6175
6416
  discountedFrom: effective.discountedFrom,
@@ -6182,14 +6423,14 @@ var projectPostPurchaseProductDisplay = (effective, metadata, product) => PostPu
6182
6423
  });
6183
6424
 
6184
6425
  // src/server/postPurchaseReviewData.ts
6185
- import { z as z61 } from "zod";
6426
+ import { z as z63 } from "zod";
6186
6427
 
6187
6428
  // src/server/postPurchaseJudgeMeReviews.ts
6188
- import { z as z58 } from "zod";
6429
+ import { z as z60 } from "zod";
6189
6430
  var readJudgeMeReviews = (find) => {
6190
6431
  const field = find("judgeme", "badge");
6191
6432
  if (!field) return null;
6192
- const html = z58.string().parse(field.value);
6433
+ const html = z60.string().parse(field.value);
6193
6434
  const rating = html.match(/data-average-rating=['"](\d+(?:\.\d+)?)['"]/);
6194
6435
  const count = html.match(/data-number-of-reviews=['"](\d+)['"]/);
6195
6436
  if (!rating || !count) throw new Error("Unreadable Judge.me attributes");
@@ -6200,26 +6441,26 @@ var readJudgeMeReviews = (find) => {
6200
6441
  };
6201
6442
 
6202
6443
  // src/server/postPurchaseOkendoReviews.ts
6203
- import { z as z59 } from "zod";
6204
- var Summary = z59.object({
6444
+ import { z as z61 } from "zod";
6445
+ var Summary = z61.object({
6205
6446
  reviewAverageValue: PostPurchaseCommonReviewRating.shape.value,
6206
- reviewCount: z59.union([PostPurchaseProductReviews.shape.reviewCount, PostPurchaseReviewCount])
6447
+ reviewCount: z61.union([PostPurchaseProductReviews.shape.reviewCount, PostPurchaseReviewCount])
6207
6448
  });
6208
6449
  var readOkendoReviews = (find) => {
6209
6450
  const field = find("okendo", "summaryData");
6210
6451
  if (!field) return null;
6211
- const summary = Summary.parse(JSON.parse(z59.string().parse(field.value)));
6452
+ const summary = Summary.parse(JSON.parse(z61.string().parse(field.value)));
6212
6453
  return { rating: summary.reviewAverageValue, reviewCount: summary.reviewCount };
6213
6454
  };
6214
6455
 
6215
6456
  // src/server/postPurchaseScalarReviews.ts
6216
- import { z as z60 } from "zod";
6457
+ import { z as z62 } from "zod";
6217
6458
  var readScalarReviews = (find, namespace, ratingKey, countKey) => {
6218
6459
  const rating = find(namespace, ratingKey);
6219
6460
  const count = find(namespace, countKey);
6220
6461
  if (!rating || !count) return null;
6221
6462
  return {
6222
- rating: PostPurchaseCommonReviewRating.parse({ value: z60.string().parse(rating.value) }).value,
6463
+ rating: PostPurchaseCommonReviewRating.parse({ value: z62.string().parse(rating.value) }).value,
6223
6464
  reviewCount: PostPurchaseReviewCount.parse(count.value)
6224
6465
  };
6225
6466
  };
@@ -6238,16 +6479,16 @@ var readPostPurchaseReviewData = (provider, find) => {
6238
6479
  const count = find("reviews", "rating_count");
6239
6480
  if (!rating || !count) return null;
6240
6481
  return {
6241
- rating: PostPurchaseKlaviyoReviewRating.parse(JSON.parse(z61.string().parse(rating.value))).value,
6482
+ rating: PostPurchaseKlaviyoReviewRating.parse(JSON.parse(z63.string().parse(rating.value))).value,
6242
6483
  reviewCount: PostPurchaseReviewCount.parse(count.value)
6243
6484
  };
6244
6485
  };
6245
6486
 
6246
6487
  // src/server/postPurchaseReviewFields.ts
6247
- import { z as z62 } from "zod";
6248
- var Field = z62.object({ key: z62.string(), namespace: z62.string(), value: z62.unknown().optional() });
6488
+ import { z as z64 } from "zod";
6489
+ var Field = z64.object({ key: z64.string(), namespace: z64.string(), value: z64.unknown().optional() });
6249
6490
  var reviewFields = (raw) => {
6250
- const fields4 = z62.array(z62.unknown()).parse(raw).flatMap((field) => {
6491
+ const fields4 = z64.array(z64.unknown()).parse(raw).flatMap((field) => {
6251
6492
  const parsed = Field.safeParse(field);
6252
6493
  return parsed.success ? [parsed.data] : [];
6253
6494
  });
@@ -6255,8 +6496,8 @@ var reviewFields = (raw) => {
6255
6496
  };
6256
6497
 
6257
6498
  // src/server/postPurchaseReviewProvider.ts
6258
- import { z as z63 } from "zod";
6259
- var IntegrationInput = z63.record(z63.string(), z63.unknown()).prefault({});
6499
+ import { z as z65 } from "zod";
6500
+ var IntegrationInput = z65.record(z65.string(), z65.unknown()).prefault({});
6260
6501
  var precedence = [
6261
6502
  "klaviyo",
6262
6503
  "judgeme",
@@ -6268,7 +6509,7 @@ var precedence = [
6268
6509
  "stamped",
6269
6510
  "yotpo"
6270
6511
  ];
6271
- var ReviewsIoFlag = z63.preprocess((value) => {
6512
+ var ReviewsIoFlag = z65.preprocess((value) => {
6272
6513
  if (typeof value === "string") {
6273
6514
  const flag = value.toLowerCase();
6274
6515
  if (flag === "true" || flag === "yes") return true;
@@ -6328,12 +6569,12 @@ var projectPostPurchaseProduct = ({ data, effective, metadata, original }, repor
6328
6569
  };
6329
6570
 
6330
6571
  // src/server/prepareNormalizedSubscription.ts
6331
- var prepareNormalizedSubscription = (normalized, report, plan, quantity2, allowCollection = false) => {
6572
+ var prepareNormalizedSubscription = (normalized, report, plan, quantity3, allowCollection = false) => {
6332
6573
  if (!plan) return { reason: "Subscription plan is unavailable", status: "unsupported" };
6333
- const reason = subscriptionUnavailable(normalized, plan, allowCollection, quantity2);
6574
+ const reason = subscriptionUnavailable(normalized, plan, allowCollection, quantity3);
6334
6575
  if (reason) return { reason, status: "unsupported" };
6335
6576
  const { effective } = normalized;
6336
- const projected = projectPostPurchaseProduct(normalized, report, quantity2);
6577
+ const projected = projectPostPurchaseProduct(normalized, report, quantity3);
6337
6578
  const { discount, shipping } = PostPurchaseSubscriptionSettings.parse(effective.subscription);
6338
6579
  const shippingPrice = shipping.type === "free" ? 0 : shipping.amount;
6339
6580
  return PreparedPostPurchaseSubscription.parse({
@@ -6371,11 +6612,11 @@ var preparePostPurchaseSubscription = (settings, response, report) => {
6371
6612
  };
6372
6613
 
6373
6614
  // src/server/postPurchaseProductEligibility.ts
6374
- var oneTimeUnavailable = (normalized, allowCollection, quantity2) => {
6615
+ var oneTimeUnavailable = (normalized, allowCollection, quantity3) => {
6375
6616
  const { data, effective, original } = normalized;
6376
6617
  if (data.length !== 1 || data[0].variants.length !== 1) return "Only one fixed product and variant are supported";
6377
6618
  if (effective.productType === "subscription" || [original, effective].some(
6378
- (config) => !allowCollection && config.productLimit !== 1 || config.upgradeToSubscription.allow || !quantity2 && config.quantityInputs.enabled && (config.quantityInputs.minValue !== config.quantityInputs.maxValue || config.quantityInputs.defaultQuantity !== config.quantityInputs.minValue)
6619
+ (config) => !allowCollection && config.productLimit !== 1 || config.upgradeToSubscription.allow || !quantity3 && config.quantityInputs.enabled && (config.quantityInputs.minValue !== config.quantityInputs.maxValue || config.quantityInputs.defaultQuantity !== config.quantityInputs.minValue)
6379
6620
  ))
6380
6621
  return "Only fixed one-time configuration is supported";
6381
6622
  const product = data[0];
@@ -6386,12 +6627,12 @@ var oneTimeUnavailable = (normalized, allowCollection, quantity2) => {
6386
6627
  };
6387
6628
 
6388
6629
  // src/server/preparePostPurchaseProduct.ts
6389
- var prepareNormalizedProduct = (normalized, report, quantity2, allowCollection = false) => {
6390
- const reason = oneTimeUnavailable(normalized, allowCollection, quantity2);
6630
+ var prepareNormalizedProduct = (normalized, report, quantity3, allowCollection = false) => {
6631
+ const reason = oneTimeUnavailable(normalized, allowCollection, quantity3);
6391
6632
  if (reason) return { reason, status: "unsupported" };
6392
6633
  const { effective } = normalized;
6393
6634
  return PreparedPostPurchaseProduct.parse({
6394
- ...projectPostPurchaseProduct(normalized, report, quantity2),
6635
+ ...projectPostPurchaseProduct(normalized, report, quantity3),
6395
6636
  status: "prepared",
6396
6637
  terms: {
6397
6638
  discount: { ...effective.discount, title: effective.language.global.save },
@@ -6402,45 +6643,80 @@ var prepareNormalizedProduct = (normalized, report, quantity2, allowCollection =
6402
6643
  var preparePostPurchaseProduct = (settings, response, report) => prepareNormalizedProduct(normalizePostPurchaseProduct(settings, response), report);
6403
6644
 
6404
6645
  // src/schema/postPurchaseProductView.ts
6405
- import { z as z67 } from "zod";
6646
+ import { z as z72 } from "zod";
6406
6647
 
6407
6648
  // src/schema/postPurchaseChoice.ts
6408
- import { z as z64 } from "zod";
6409
- var PostPurchaseChoice = z64.discriminatedUnion("mode", [
6410
- z64.object({ mode: z64.literal("one-time") }).strict(),
6411
- z64.object({ mode: z64.literal("subscription"), sellingPlanId: PostPurchasePlanOption.shape.id }).strict()
6649
+ import { z as z66 } from "zod";
6650
+ var PostPurchaseChoice = z66.discriminatedUnion("mode", [
6651
+ z66.object({ mode: z66.literal("one-time") }).strict(),
6652
+ z66.object({ mode: z66.literal("subscription"), sellingPlanId: PostPurchasePlanOption.shape.id }).strict()
6412
6653
  ]);
6413
- var PostPurchaseOptions = z64.object({
6654
+ var PostPurchaseOptions = z66.object({
6414
6655
  defaultChoice: PostPurchaseChoice,
6415
- modes: z64.array(z64.enum(["one-time", "subscription"])).min(1).max(2),
6656
+ modes: z66.array(z66.enum(["one-time", "subscription"])).min(1).max(2),
6416
6657
  selector: PostPurchaseSettings.shape.productTypeSelector
6417
6658
  });
6418
6659
 
6660
+ // src/schema/postPurchaseDisplayPrice.ts
6661
+ import { z as z68 } from "zod";
6662
+
6663
+ // src/schema/postPurchaseSubscriptionDisplay.ts
6664
+ import { z as z67 } from "zod";
6665
+ var Minor = z67.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
6666
+ var PostPurchaseSubscriptionDisplay = z67.object({
6667
+ comparisonMinor: Minor,
6668
+ currencyCode: z67.string().regex(/^[A-Z]{3}$/),
6669
+ priceMinor: Minor,
6670
+ savingMinor: Minor,
6671
+ savingPercent: z67.number().int().min(0).max(100)
6672
+ });
6673
+
6674
+ // src/schema/postPurchaseDisplayPrice.ts
6675
+ var { currencyCode: CurrencyCode, priceMinor: Minor2, savingPercent: Percent } = PostPurchaseSubscriptionDisplay.shape;
6676
+ var PostPurchaseDisplayPrice = z68.object({
6677
+ currencyCode: CurrencyCode,
6678
+ savingFormat: z68.enum(["amount", "percent"]),
6679
+ savingMinor: Minor2,
6680
+ savingPercent: Percent,
6681
+ subscriptionUnit: PostPurchaseSubscriptionDisplay.optional(),
6682
+ variantCompareAtPriceMinor: Minor2.nullable(),
6683
+ variantPriceMinor: Minor2
6684
+ }).refine(
6685
+ ({ variantCompareAtPriceMinor: struck, variantPriceMinor: price }) => struck === null || struck > price,
6686
+ "A compare-at price is struck only above the price"
6687
+ ).refine(
6688
+ ({ savingMinor, savingPercent, variantCompareAtPriceMinor: struck, variantPriceMinor: price }) => savingMinor === (struck ?? price) - price && (savingMinor > 0 || savingPercent === 0),
6689
+ "The saving is the struck price minus the price"
6690
+ ).refine(
6691
+ ({ subscriptionUnit: unit, ...facts }) => !unit || unit.currencyCode === facts.currencyCode && unit.priceMinor === facts.variantPriceMinor && unit.savingMinor === facts.savingMinor && unit.savingPercent === facts.savingPercent && unit.savingMinor === Math.max(0, unit.comparisonMinor - unit.priceMinor),
6692
+ "The subscription unit estimate restates the plan facts in the same currency"
6693
+ );
6694
+
6419
6695
  // src/schema/postPurchaseGroupCatalog.ts
6420
- import { z as z66 } from "zod";
6696
+ import { z as z70 } from "zod";
6421
6697
 
6422
6698
  // src/schema/postPurchaseVariantCatalog.ts
6423
- import { z as z65 } from "zod";
6424
- var PostPurchaseVariantSelector = z65.object({ variantId: PostPurchaseVariantId }).strict();
6699
+ import { z as z69 } from "zod";
6700
+ var PostPurchaseVariantSelector = z69.object({ variantId: PostPurchaseVariantId }).strict();
6425
6701
  var PostPurchaseVariantOption = OfferProduct.shape.options.element.extend({
6426
- id: z65.number().int().positive(),
6427
- position: z65.number().int().min(1).max(3)
6702
+ id: z69.number().int().positive(),
6703
+ position: z69.number().int().min(1).max(3)
6428
6704
  });
6429
6705
  var PostPurchaseVariantValues = OfferProduct.shape.variants.element.pick({
6430
6706
  option1: true,
6431
6707
  option2: true,
6432
6708
  option3: true
6433
6709
  });
6434
- var PostPurchaseVariantCatalog = z65.object({
6710
+ var PostPurchaseVariantCatalog = z69.object({
6435
6711
  displayMode: PostPurchaseSettings.shape.productOptions.shape.variantSelectorDisplayMode,
6436
- options: z65.array(PostPurchaseVariantOption),
6712
+ options: z69.array(PostPurchaseVariantOption),
6437
6713
  productId: PostPurchaseProductId,
6438
6714
  showSelectors: PostPurchaseSettings.shape.productOptions.shape.showVariantSelectors,
6439
- variants: z65.array(
6715
+ variants: z69.array(
6440
6716
  PostPurchaseVariantValues.partial().extend({
6441
- available: z65.boolean(),
6717
+ available: z69.boolean(),
6442
6718
  id: PostPurchaseVariantId,
6443
- imageId: z65.number().int().nonnegative().nullish(),
6719
+ imageId: z69.number().int().nonnegative().nullish(),
6444
6720
  title: OfferProduct.shape.variants.element.shape.title
6445
6721
  })
6446
6722
  )
@@ -6454,23 +6730,89 @@ var PostPurchaseGroupDescription = source.pick({ description: true, id: true, im
6454
6730
  image: source.shape.image.default(null),
6455
6731
  options: PostPurchaseVariantCatalog.shape.options.default([])
6456
6732
  });
6457
- var PostPurchaseGroupCatalog = z66.object({
6733
+ var PostPurchaseGroupCatalog = z70.object({
6458
6734
  memberProductId: productId,
6459
- options: z66.array(z66.object({ productId, title: z66.string(), variantCatalog: PostPurchaseVariantCatalog }))
6735
+ options: z70.array(z70.object({ productId, title: z70.string(), variantCatalog: PostPurchaseVariantCatalog }))
6460
6736
  });
6461
- var PostPurchaseGroupSelection = z66.object({
6737
+ var PostPurchaseGroupSelection = z70.object({
6462
6738
  memberProductId: productId,
6463
6739
  productId
6464
6740
  });
6465
6741
 
6742
+ // src/schema/postPurchaseProductCalculation.ts
6743
+ import { z as z71 } from "zod";
6744
+ var MoneyBag = z71.object({
6745
+ presentmentMoney: z71.object({
6746
+ amount: PostPurchaseAmount,
6747
+ currencyCode: z71.string().regex(/^[A-Z]{3}$/)
6748
+ })
6749
+ });
6750
+ var PostPurchaseProductCalculation = z71.object({
6751
+ calculatedPurchase: z71.object({
6752
+ addedShippingLines: z71.array(z71.object({ priceSet: MoneyBag })),
6753
+ addedTaxLines: z71.array(z71.object({ priceSet: MoneyBag })),
6754
+ totalOutstandingSet: MoneyBag,
6755
+ updatedLineItems: z71.array(
6756
+ z71.object({
6757
+ priceSet: z71.unknown().optional(),
6758
+ productId: z71.number().int().positive(),
6759
+ sellingPlanId: z71.unknown().optional(),
6760
+ variantId: z71.number().int().positive()
6761
+ })
6762
+ )
6763
+ }),
6764
+ errors: z71.array(z71.unknown()).length(0),
6765
+ status: z71.literal("processed")
6766
+ });
6767
+ var Minor3 = z71.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
6768
+ var PostPurchaseProductCosts = z71.object({
6769
+ currencyCode: MoneyBag.shape.presentmentMoney.shape.currencyCode,
6770
+ recurringDisplay: z71.object({ shippingMinor: Minor3, subtotalMinor: Minor3, totalMinor: Minor3 }).optional(),
6771
+ shippingMinor: Minor3,
6772
+ subtotalMinor: Minor3,
6773
+ taxesMinor: Minor3,
6774
+ totalMinor: Minor3
6775
+ });
6776
+ var ChangesetDiscount = z71.object({
6777
+ title: z71.string(),
6778
+ value: z71.number().nonnegative(),
6779
+ valueType: z71.enum(["percentage", "fixed_amount"])
6780
+ }).optional();
6781
+ var PostPurchaseProductChangeset = z71.object({
6782
+ changes: z71.array(
6783
+ z71.union([
6784
+ z71.object({
6785
+ discount: ChangesetDiscount,
6786
+ quantity: z71.number().int().positive(),
6787
+ type: z71.literal("add_variant"),
6788
+ variantId: z71.number().int().positive()
6789
+ }),
6790
+ z71.object({ price: z71.number().nonnegative(), title: z71.string(), type: z71.literal("add_shipping_line") }),
6791
+ PostPurchaseSubscriptionTerms.pick({
6792
+ initialShippingPrice: true,
6793
+ recurringShippingPrice: true,
6794
+ shippingOption: true
6795
+ }).extend({
6796
+ discount: ChangesetDiscount,
6797
+ quantity: z71.number().int().positive(),
6798
+ sellingPlanId: z71.number().int().positive(),
6799
+ type: z71.literal("add_subscription"),
6800
+ variantId: z71.number().int().positive()
6801
+ })
6802
+ ])
6803
+ )
6804
+ });
6805
+
6466
6806
  // src/schema/postPurchaseProductView.ts
6467
- var PostPurchaseProductView = z67.union([
6468
- z67.object({
6807
+ var PostPurchaseProductView = z72.union([
6808
+ z72.object({
6809
+ changeset: PostPurchaseProductChangeset.optional(),
6810
+ displayPrice: PostPurchaseDisplayPrice.optional(),
6469
6811
  groupCatalog: PostPurchaseGroupCatalog.optional(),
6470
6812
  initialVariant: PostPurchaseVariantSelector.optional(),
6471
6813
  planCatalog: PostPurchasePlanCatalog.nullable().optional(),
6472
6814
  preparation: PreparedPostPurchaseProduct.extend({
6473
- display: PreparedPostPurchaseProduct.shape.display.extend({ description: z67.string().nullable() }).refine(
6815
+ display: PreparedPostPurchaseProduct.shape.display.extend({ description: z72.string().nullable() }).refine(
6474
6816
  ({ description, descriptionDocument }) => description === null === (descriptionDocument !== void 0),
6475
6817
  "Exactly one of the plain and rich descriptions is shown"
6476
6818
  )
@@ -6479,24 +6821,26 @@ var PostPurchaseProductView = z67.union([
6479
6821
  sections: CABRootSection,
6480
6822
  variantCatalog: PostPurchaseVariantCatalog.optional()
6481
6823
  }),
6482
- z67.object({
6824
+ z72.object({
6483
6825
  groupCatalog: PostPurchaseGroupCatalog.optional(),
6484
6826
  initialVariant: PostPurchaseVariantSelector.optional(),
6827
+ /** The localized unavailable copy, for the choices still offered beneath an unprepared product. */
6828
+ labels: PreparedPostPurchaseProduct.shape.labels.pick({ notAvailable: true }).optional(),
6485
6829
  planCatalog: PostPurchasePlanCatalog.nullable().optional(),
6486
6830
  preparation: PostPurchasePreparation.options[1],
6487
6831
  purchaseOptions: PostPurchaseOptions.optional(),
6488
- sections: z67.null(),
6832
+ sections: z72.null(),
6489
6833
  variantCatalog: PostPurchaseVariantCatalog.optional()
6490
6834
  })
6491
6835
  ]);
6492
6836
 
6493
6837
  // src/server/postPurchaseOfferCopy.ts
6494
- import { z as z68 } from "zod";
6495
- var Copy = z68.object({
6838
+ import { z as z73 } from "zod";
6839
+ var Copy = z73.object({
6496
6840
  superTitle: CalloutBannerBlock.shape.settings.shape.superTitle.unwrap().optional().catch(void 0),
6497
6841
  title: CalloutBannerBlock.shape.settings.shape.title.unwrap().optional().catch(void 0)
6498
6842
  });
6499
- var Callout = z68.object({ settings: z68.record(z68.string(), z68.unknown()), type: z68.literal("callout_banner") });
6843
+ var Callout = z73.object({ settings: z73.record(z73.string(), z73.unknown()), type: z73.literal("callout_banner") });
6500
6844
  var postPurchaseOfferCopy = (blocks, metadata) => {
6501
6845
  const copy = Copy.safeParse(metadata.widget.language);
6502
6846
  if (!blocks || !copy.success) return blocks;
@@ -6517,13 +6861,13 @@ var postPurchaseOfferCopy = (blocks, metadata) => {
6517
6861
  };
6518
6862
 
6519
6863
  // src/server/selectPostPurchaseChoice.ts
6520
- var selectPostPurchaseChoice = (normalized, projected, requested, allowCollection, quantity2) => {
6864
+ var selectPostPurchaseChoice = (normalized, projected, requested, allowCollection, quantity3) => {
6521
6865
  const { data, effective } = normalized;
6522
6866
  const modes = [];
6523
6867
  const catalog = projected && projected.productId === data[0]?.id && projected.variantId === data[0].variants[0]?.id ? projected : null;
6524
6868
  const firstPlan = catalog?.plans[0];
6525
- const oneTimeReason = oneTimeUnavailable(normalized, allowCollection, quantity2);
6526
- const subscriptionReason = subscriptionUnavailable(normalized, firstPlan, allowCollection, quantity2);
6869
+ const oneTimeReason = oneTimeUnavailable(normalized, allowCollection, quantity3);
6870
+ const subscriptionReason = subscriptionUnavailable(normalized, firstPlan, allowCollection, quantity3);
6527
6871
  if (!oneTimeReason) modes.push("one-time");
6528
6872
  if (!subscriptionReason) modes.push("subscription");
6529
6873
  if (oneTimeReason && subscriptionReason)
@@ -6551,22 +6895,26 @@ var resolveDescription = ({ descriptionDocument, ...display }, productDescriptio
6551
6895
  const plain = display.language.descriptionEnabled && productDescription || display.responseDescription || (descriptionDocument ? null : display.language.description);
6552
6896
  return plain === null ? { ...display, description: null, descriptionDocument } : { ...display, description: plain };
6553
6897
  };
6554
- var prepareNormalizedPostPurchaseView = (widgetId, normalized, report, choice, quantity2, allowCollection = false) => {
6898
+ var prepareNormalizedPostPurchaseView = (widgetId, normalized, report, choice, quantity3, allowCollection = false) => {
6555
6899
  const planCatalog = projectPostPurchasePlanCatalog(normalized, report);
6556
- const selected = selectPostPurchaseChoice(normalized, planCatalog, choice, allowCollection, quantity2);
6900
+ const selected = selectPostPurchaseChoice(normalized, planCatalog, choice, allowCollection, quantity3);
6557
6901
  const purchaseOptions = selected.options;
6558
- const preparation = !selected.choice ? { reason: selected.reason, status: "unsupported" } : selected.choice.mode === "subscription" ? prepareNormalizedSubscription(normalized, report, selected.plan, quantity2, allowCollection) : prepareNormalizedProduct(normalized, report, quantity2, allowCollection);
6902
+ const labels = { notAvailable: normalized.effective.language.global.notAvailable };
6903
+ const preparation = !selected.choice ? { reason: selected.reason, status: "unsupported" } : selected.choice.mode === "subscription" ? prepareNormalizedSubscription(normalized, report, selected.plan, quantity3, allowCollection) : prepareNormalizedProduct(normalized, report, quantity3, allowCollection);
6559
6904
  const unsupported = (reason) => ({
6905
+ labels,
6560
6906
  planCatalog,
6561
6907
  preparation: { reason, status: "unsupported" },
6562
6908
  purchaseOptions,
6563
6909
  sections: null
6564
6910
  });
6565
- if (preparation.status === "unsupported") return { planCatalog, preparation, purchaseOptions, sections: null };
6911
+ if (preparation.status === "unsupported")
6912
+ return { labels, planCatalog, preparation, purchaseOptions, sections: null };
6566
6913
  if (!normalized.effective.blocks?.length) return unsupported("One fixed product information block is required");
6567
6914
  const sections = convertMessagePreview(
6568
6915
  widgetId,
6569
6916
  {
6917
+ ...normalized.effective,
6570
6918
  blocks: postPurchaseOfferCopy(normalized.effective.blocks, normalized.metadata),
6571
6919
  type: "shopify_post_purchase_extension"
6572
6920
  },
@@ -6595,154 +6943,102 @@ var preparePostPurchaseAdmissionView = (widgetId, settings, response, report, ch
6595
6943
  };
6596
6944
 
6597
6945
  // src/schema/postPurchaseProductCollectionView.ts
6598
- import { z as z76 } from "zod";
6946
+ import { z as z80 } from "zod";
6599
6947
 
6600
6948
  // src/schema/postPurchaseProgress.ts
6601
- import { z as z75 } from "zod";
6949
+ import { z as z79 } from "zod";
6602
6950
 
6603
6951
  // src/schema/postPurchaseDeclineDelivery.ts
6604
- import { z as z74 } from "zod";
6952
+ import { z as z78 } from "zod";
6605
6953
 
6606
6954
  // src/schema/postPurchaseAcceptedEvent.ts
6607
- import { z as z73 } from "zod";
6955
+ import { z as z77 } from "zod";
6608
6956
 
6609
6957
  // src/schema/postPurchaseAdmission.ts
6610
- import { z as z72 } from "zod";
6958
+ import { z as z76 } from "zod";
6611
6959
 
6612
6960
  // src/schema/postPurchaseIdentity.ts
6613
- import { z as z69 } from "zod";
6961
+ import { z as z74 } from "zod";
6614
6962
  var POST_PURCHASE_ID_MAX = 128;
6615
- var PostPurchaseTimestampSchema = z69.number().int().nonnegative();
6616
- var PostPurchaseOrderIdSchema = z69.string().regex(/^gid:\/\/shopify\/Order\/[1-9]\d*$/);
6617
- var ShopifyDomainSchema = z69.string().max(POST_PURCHASE_ID_MAX).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?\.myshopify\.com$/);
6618
- var DecideRequestSchema = z69.object({
6619
- checkoutToken: z69.string().min(1).max(POST_PURCHASE_ID_MAX),
6963
+ var PostPurchaseTimestampSchema = z74.number().int().nonnegative();
6964
+ var PostPurchaseOrderIdSchema = z74.string().regex(/^gid:\/\/shopify\/Order\/[1-9]\d*$/);
6965
+ var ShopifyDomainSchema = z74.string().max(POST_PURCHASE_ID_MAX).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?\.myshopify\.com$/);
6966
+ var DecideRequestSchema = z74.object({
6967
+ checkoutToken: z74.string().min(1).max(POST_PURCHASE_ID_MAX),
6620
6968
  shop: ShopifyDomainSchema
6621
6969
  });
6622
- var PostPurchaseAppIdSchema = z69.string().min(1).max(POST_PURCHASE_ID_MAX);
6623
- var DecisionEntrySchema = z69.object({
6624
- blockId: z69.number().int().positive(),
6625
- blockIndex: z69.string(),
6626
- blockParentIndex: z69.string(),
6627
- flowId: z69.number().int().positive(),
6628
- sectionId: z69.number().int().positive(),
6629
- widgetId: z69.number().int().positive(),
6630
- widgetTraffic: z69.number().min(0).max(100)
6970
+ var PostPurchaseAppIdSchema = z74.string().min(1).max(POST_PURCHASE_ID_MAX);
6971
+ var DecisionEntrySchema = z74.object({
6972
+ blockId: z74.number().int().positive(),
6973
+ blockIndex: z74.string(),
6974
+ blockParentIndex: z74.string(),
6975
+ flowId: z74.number().int().positive(),
6976
+ sectionId: z74.number().int().positive(),
6977
+ widgetId: z74.number().int().positive(),
6978
+ widgetTraffic: z74.number().min(0).max(100)
6631
6979
  });
6632
6980
 
6633
6981
  // src/schema/postPurchaseMemberIdentity.ts
6634
- import { z as z70 } from "zod";
6635
- var PostPurchaseMemberIdentity = z70.object({
6636
- productId: z70.number().int().positive(),
6637
- productIndex: z70.number().int().nonnegative()
6982
+ import { z as z75 } from "zod";
6983
+ var PostPurchaseMemberIdentity = z75.object({
6984
+ productId: z75.number().int().positive(),
6985
+ productIndex: z75.number().int().nonnegative()
6638
6986
  }).strict();
6639
6987
 
6640
- // src/schema/postPurchaseProductCalculation.ts
6641
- import { z as z71 } from "zod";
6642
- var MoneyBag = z71.object({
6643
- presentmentMoney: z71.object({
6644
- amount: PostPurchaseAmount,
6645
- currencyCode: z71.string().regex(/^[A-Z]{3}$/)
6646
- })
6647
- });
6648
- var PostPurchaseProductCalculation = z71.object({
6649
- calculatedPurchase: z71.object({
6650
- addedShippingLines: z71.array(z71.object({ priceSet: MoneyBag })),
6651
- addedTaxLines: z71.array(z71.object({ priceSet: MoneyBag })),
6652
- totalOutstandingSet: MoneyBag,
6653
- updatedLineItems: z71.array(
6654
- z71.object({
6655
- priceSet: z71.unknown().optional(),
6656
- productId: z71.number().int().positive(),
6657
- sellingPlanId: z71.unknown().optional(),
6658
- variantId: z71.number().int().positive()
6659
- })
6660
- )
6661
- }),
6662
- errors: z71.array(z71.unknown()).length(0),
6663
- status: z71.literal("processed")
6664
- });
6665
- var Minor = z71.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
6666
- var PostPurchaseProductCosts = z71.object({
6667
- currencyCode: MoneyBag.shape.presentmentMoney.shape.currencyCode,
6668
- recurringDisplay: z71.object({ shippingMinor: Minor, subtotalMinor: Minor, totalMinor: Minor }).optional(),
6669
- shippingMinor: Minor,
6670
- subtotalMinor: Minor,
6671
- taxesMinor: Minor,
6672
- totalMinor: Minor
6673
- });
6674
- var ChangesetDiscount = z71.object({
6675
- title: z71.string(),
6676
- value: z71.number().nonnegative(),
6677
- valueType: z71.enum(["percentage", "fixed_amount"])
6678
- }).optional();
6679
- var PostPurchaseProductChangeset = z71.object({
6680
- changes: z71.array(
6681
- z71.union([
6682
- z71.object({
6683
- discount: ChangesetDiscount,
6684
- quantity: z71.number().int().positive(),
6685
- type: z71.literal("add_variant"),
6686
- variantId: z71.number().int().positive()
6687
- }),
6688
- z71.object({ price: z71.number().nonnegative(), title: z71.string(), type: z71.literal("add_shipping_line") }),
6689
- PostPurchaseSubscriptionTerms.pick({
6690
- initialShippingPrice: true,
6691
- recurringShippingPrice: true,
6692
- shippingOption: true
6693
- }).extend({
6694
- discount: ChangesetDiscount,
6695
- quantity: z71.number().int().positive(),
6696
- sellingPlanId: z71.number().int().positive(),
6697
- type: z71.literal("add_subscription"),
6698
- variantId: z71.number().int().positive()
6699
- })
6700
- ])
6701
- )
6702
- });
6703
-
6704
6988
  // src/schema/postPurchaseAdmission.ts
6705
- var PurchaseExpectedSchema = z72.object({
6706
- buyerConsentToSubscriptions: z72.boolean().optional(),
6989
+ var PurchaseAdmissionModeSchema = z76.enum(["purchase", "upgrade"]);
6990
+ var selection = PreparedPostPurchaseProduct.shape.selection;
6991
+ var PurchaseExpectedSchema = z76.object({
6992
+ buyerConsentToSubscriptions: z76.boolean().optional(),
6707
6993
  changeset: PostPurchaseProductChangeset.extend({
6708
6994
  changes: PostPurchaseProductChangeset.shape.changes.min(1).max(2)
6709
6995
  }),
6710
6996
  entry: DecisionEntrySchema,
6711
6997
  member: PostPurchaseMemberIdentity.optional(),
6712
- progressRevision: z72.number().int().nonnegative().optional(),
6713
- selection: PreparedPostPurchaseProduct.shape.selection
6998
+ mode: PurchaseAdmissionModeSchema.optional(),
6999
+ progressRevision: z76.number().int().nonnegative().optional(),
7000
+ selection
6714
7001
  }).refine(
6715
7002
  ({ member, progressRevision }) => !member || progressRevision !== void 0,
6716
7003
  "Captured member requires progress"
6717
- ).refine(({ buyerConsentToSubscriptions: consent, changeset, selection: selection3 }) => {
7004
+ ).refine(
7005
+ ({ mode, selection: { sellingPlanId } }) => mode !== "upgrade" || sellingPlanId !== void 0,
7006
+ "An upgrade selects a subscription"
7007
+ ).refine(({ buyerConsentToSubscriptions: consent, changeset, selection: selection4 }) => {
6718
7008
  const [change, shipping] = changeset.changes;
6719
- if (selection3.sellingPlanId === void 0)
6720
- return consent !== true && change?.type === "add_variant" && change.variantId === selection3.variantId && change.quantity === selection3.quantity && (shipping === void 0 || shipping.type === "add_shipping_line");
6721
- return consent === true && changeset.changes.length === 1 && change.type === "add_subscription" && change.sellingPlanId === selection3.sellingPlanId && change.variantId === selection3.variantId && change.quantity === selection3.quantity;
7009
+ if (selection4.sellingPlanId === void 0)
7010
+ return consent !== true && change?.type === "add_variant" && change.variantId === selection4.variantId && change.quantity === selection4.quantity && (shipping === void 0 || shipping.type === "add_shipping_line");
7011
+ return consent === true && changeset.changes.length === 1 && change.type === "add_subscription" && change.sellingPlanId === selection4.sellingPlanId && change.variantId === selection4.variantId && change.quantity === selection4.quantity;
6722
7012
  }, "Selection, change and buyer consent must agree");
6723
7013
  var PurchaseRequestSchema = DecideRequestSchema.extend({
6724
7014
  expected: PurchaseExpectedSchema,
6725
- requestId: z72.uuid()
7015
+ requestId: z76.uuid()
6726
7016
  }).strict();
6727
- var PurchaseReceiptSchema = z72.object({
7017
+ var PurchaseReceiptSchema = z76.object({
6728
7018
  admittedAt: PostPurchaseTimestampSchema,
6729
- changesetToken: z72.string().min(1),
6730
- operationId: z72.uuid(),
6731
- requiresSubscriptionConsent: z72.boolean(),
6732
- selection: PreparedPostPurchaseProduct.shape.selection
7019
+ changesetToken: z76.string().min(1),
7020
+ mode: PurchaseAdmissionModeSchema.optional(),
7021
+ operationId: z76.uuid(),
7022
+ /** The server-bound one-time line an upgrade refunds; its quantity is the order's, not the selection's. */
7023
+ originalLine: z76.strictObject({ quantity: selection.shape.quantity, variantId: selection.shape.variantId }).optional(),
7024
+ requiresSubscriptionConsent: z76.boolean(),
7025
+ selection
6733
7026
  }).refine(
6734
- ({ requiresSubscriptionConsent, selection: selection3 }) => requiresSubscriptionConsent === (selection3.sellingPlanId !== void 0),
7027
+ ({ requiresSubscriptionConsent, selection: selection4 }) => requiresSubscriptionConsent === (selection4.sellingPlanId !== void 0),
6735
7028
  "Receipt consent must match its selected plan"
7029
+ ).refine(
7030
+ ({ mode, originalLine, selection: { sellingPlanId, variantId } }) => mode === "upgrade" ? sellingPlanId !== void 0 && originalLine?.variantId === variantId : originalLine === void 0,
7031
+ "An upgrade Receipt binds the original line of its subscribed variant, and only an upgrade does"
6736
7032
  );
6737
- var PurchaseResponseSchema = z72.object({ data: PurchaseReceiptSchema, successful: z72.literal(true) });
7033
+ var PurchaseResponseSchema = z76.object({ data: PurchaseReceiptSchema, successful: z76.literal(true) });
6738
7034
 
6739
7035
  // src/schema/postPurchaseAcceptedEvent.ts
6740
7036
  var EventCalculationSchema = PostPurchaseProductCosts.pick({ currencyCode: true, totalMinor: true }).strict();
6741
- var AcceptedEventOutcomeSchema = z73.enum(["acknowledged", "rejected", "skipped", "unknown"]);
6742
- var AttemptProgressSchema = z73.strictObject({
7037
+ var AcceptedEventOutcomeSchema = z77.enum(["acknowledged", "rejected", "skipped", "unknown"]);
7038
+ var AttemptProgressSchema = z77.strictObject({
6743
7039
  attemptedAt: PostPurchaseTimestampSchema,
6744
7040
  reportedCalculation: EventCalculationSchema,
6745
- status: z73.literal("attempted")
7041
+ status: z77.literal("attempted")
6746
7042
  });
6747
7043
  var AcceptedEventAttemptProgressSchema = AttemptProgressSchema.extend({
6748
7044
  operationId: PurchaseReceiptSchema.shape.operationId
@@ -6755,17 +7051,17 @@ var AcceptedEventRequestSchema = DecideRequestSchema.extend({
6755
7051
  operationId: PurchaseReceiptSchema.shape.operationId,
6756
7052
  reportedCalculation: EventCalculationSchema
6757
7053
  }).strict();
6758
- var AcceptedEventResponseSchema = z73.object({
6759
- data: z73.union([AcceptedEventAttemptProgressSchema, AcceptedEventResultProgressSchema]),
6760
- successful: z73.literal(true)
7054
+ var AcceptedEventResponseSchema = z77.object({
7055
+ data: z77.union([AcceptedEventAttemptProgressSchema, AcceptedEventResultProgressSchema]),
7056
+ successful: z77.literal(true)
6761
7057
  });
6762
7058
 
6763
7059
  // src/schema/postPurchaseDeclineDelivery.ts
6764
- var AttemptSchema = z74.strictObject({
7060
+ var AttemptSchema = z78.strictObject({
6765
7061
  attemptedAt: PostPurchaseTimestampSchema,
6766
- status: z74.enum(["attempted", "unavailable"])
7062
+ status: z78.enum(["attempted", "unavailable"])
6767
7063
  });
6768
- var DeclineDeliveryProgressSchema = z74.union([
7064
+ var DeclineDeliveryProgressSchema = z78.union([
6769
7065
  AttemptSchema,
6770
7066
  AttemptSchema.extend({
6771
7067
  finishedAt: PostPurchaseTimestampSchema,
@@ -6774,36 +7070,36 @@ var DeclineDeliveryProgressSchema = z74.union([
6774
7070
  ]);
6775
7071
 
6776
7072
  // src/schema/postPurchaseProgress.ts
6777
- var PostPurchaseProgressSchema = z75.object({
7073
+ var PostPurchaseProgressSchema = z79.object({
6778
7074
  closedAt: PostPurchaseTimestampSchema.nullable(),
6779
7075
  deadline: PostPurchaseTimestampSchema,
6780
7076
  entry: DecisionEntrySchema,
6781
- entryRevision: z75.number().int().nonnegative(),
6782
- members: z75.array(
7077
+ entryRevision: z79.number().int().nonnegative(),
7078
+ members: z79.array(
6783
7079
  PostPurchaseMemberIdentity.extend({
6784
7080
  declineDelivery: DeclineDeliveryProgressSchema.optional(),
6785
- status: z75.enum(["unhandled", "accepted", "declined"])
7081
+ status: z79.enum(["unhandled", "accepted", "declined"])
6786
7082
  }).strict()
6787
7083
  ),
6788
- revision: z75.number().int().nonnegative()
7084
+ revision: z79.number().int().nonnegative()
6789
7085
  }).strict();
6790
7086
 
6791
7087
  // src/schema/postPurchaseProductCollectionView.ts
6792
- var PostPurchaseProductCollectionView = z76.object({
6793
- members: z76.array(
6794
- z76.object({
7088
+ var PostPurchaseProductCollectionView = z80.object({
7089
+ members: z80.array(
7090
+ z80.object({
6795
7091
  productId: PostPurchaseProductId,
6796
- productIndex: z76.number().int().nonnegative(),
7092
+ productIndex: z80.number().int().nonnegative(),
6797
7093
  view: PostPurchaseProductView
6798
7094
  })
6799
7095
  )
6800
7096
  });
6801
- var PostPurchaseCollectionChoice = z76.object({
7097
+ var PostPurchaseCollectionChoice = z80.object({
6802
7098
  choice: PostPurchaseChoice.optional(),
6803
7099
  productId: PostPurchaseProductId,
6804
7100
  variantId: PostPurchaseVariantSelector.shape.variantId.optional()
6805
7101
  }).strict();
6806
- var PostPurchaseExcludedProductIds = z76.array(PostPurchaseProductId).default([]);
7102
+ var PostPurchaseExcludedProductIds = z80.array(PostPurchaseProductId).default([]);
6807
7103
  var PostPurchaseMemberSelector = PostPurchaseProgressSchema.shape.members.element.pick({ productId: true }).extend({ progressRevision: PostPurchaseProgressSchema.shape.revision });
6808
7104
  var PostPurchaseMemberPointer = PostPurchaseProgressSchema.shape.members.element.omit({ status: true }).extend({
6809
7105
  entryRevision: PostPurchaseProgressSchema.shape.entryRevision,
@@ -6811,10 +7107,10 @@ var PostPurchaseMemberPointer = PostPurchaseProgressSchema.shape.members.element
6811
7107
  });
6812
7108
 
6813
7109
  // src/server/normalizePostPurchaseCollection.ts
6814
- import { z as z77 } from "zod";
7110
+ import { z as z81 } from "zod";
6815
7111
  var normalizePostPurchaseCollection = (settings, response, excludedProductIds) => {
6816
7112
  const normalized = normalizePostPurchaseProduct(settings, response);
6817
- const limit = z77.number().int().positive();
7113
+ const limit = z81.number().int().positive();
6818
7114
  limit.parse(normalized.original.productLimit);
6819
7115
  const prefix = normalized.data.slice(0, limit.parse(normalized.effective.productLimit));
6820
7116
  if (new Set(prefix.map(({ id }) => id)).size !== prefix.length)
@@ -6858,13 +7154,13 @@ var projectPostPurchaseVariantCatalog = (product, settings) => {
6858
7154
  };
6859
7155
 
6860
7156
  // src/schema/postPurchaseQuantity.ts
6861
- import { z as z78 } from "zod";
6862
- var quantity = PreparedPostPurchaseProduct.shape.selection.shape.quantity;
6863
- var PostPurchaseQuantityChoice = PostPurchaseCollectionChoice.extend({ quantity: quantity.optional() });
7157
+ import { z as z82 } from "zod";
7158
+ var quantity2 = PreparedPostPurchaseProduct.shape.selection.shape.quantity;
7159
+ var PostPurchaseQuantityChoice = PostPurchaseCollectionChoice.extend({ quantity: quantity2.optional() });
6864
7160
  var PostPurchaseQuantityPolicy = PostPurchaseSettings.shape.quantityInputs.omit({ defaultQuantity: true }).extend({
6865
- initialQuantity: quantity,
6866
- maxValue: quantity,
6867
- minValue: z78.literal(0).transform(() => 1).or(quantity)
7161
+ initialQuantity: quantity2,
7162
+ maxValue: quantity2,
7163
+ minValue: z82.literal(0).transform(() => 1).or(quantity2)
6868
7164
  }).refine(({ maxValue, minValue }) => minValue <= maxValue, "Quantity bounds are reversed");
6869
7165
 
6870
7166
  // src/server/readPostPurchaseQuantity.ts
@@ -6874,7 +7170,7 @@ var readPostPurchaseQuantity = ({
6874
7170
  data,
6875
7171
  effective,
6876
7172
  original
6877
- }, selection3) => {
7173
+ }, selection4) => {
6878
7174
  const positive = PreparedPostPurchaseProduct.shape.selection.shape.quantity;
6879
7175
  for (const config of [original, effective]) {
6880
7176
  if (!config.quantityInputs.enabled) continue;
@@ -6887,47 +7183,47 @@ var readPostPurchaseQuantity = ({
6887
7183
  const policy = PostPurchaseQuantityPolicy.parse(
6888
7184
  effective.quantityInputs.enabled ? { ...effective.quantityInputs, initialQuantity } : { enabled: false, initialQuantity, maxValue: initialQuantity, minValue: initialQuantity }
6889
7185
  );
6890
- const requested = "quantity" in selection3 ? selection3.quantity : selection3.expectedQuantity === initialQuantity ? void 0 : selection3.expectedQuantity;
6891
- const quantity2 = positive.parse(requested ?? initialQuantity);
6892
- if (requested !== void 0 && (policy.enabled ? quantity2 < policy.minValue || quantity2 > policy.maxValue : quantity2 !== initialQuantity))
7186
+ const requested = "quantity" in selection4 ? selection4.quantity : selection4.expectedQuantity === initialQuantity ? void 0 : selection4.expectedQuantity;
7187
+ const quantity3 = positive.parse(requested ?? initialQuantity);
7188
+ if (requested !== void 0 && (policy.enabled ? quantity3 < policy.minValue || quantity3 > policy.maxValue : quantity3 !== initialQuantity))
6893
7189
  throw new PostPurchaseQuantityUnavailable("Requested quantity is unavailable");
6894
- return { policy, quantity: quantity2 };
7190
+ return { policy, quantity: quantity3 };
6895
7191
  };
6896
7192
 
6897
7193
  // src/schema/postPurchaseVariantDefault.ts
6898
- import { z as z79 } from "zod";
7194
+ import { z as z83 } from "zod";
6899
7195
  var values = PostPurchaseVariantValues.partial().extend({
6900
7196
  option1: PostPurchaseVariantValues.shape.option1.nullish()
6901
7197
  });
6902
7198
  var variant = values.extend({
6903
7199
  id: PostPurchaseVariantId,
6904
- inventoryManagement: z79.string().nullable(),
6905
- inventoryPolicy: z79.string(),
6906
- inventoryQuantity: z79.number()
7200
+ inventoryManagement: z83.string().nullable(),
7201
+ inventoryPolicy: z83.string(),
7202
+ inventoryQuantity: z83.number()
6907
7203
  });
6908
- var options = z79.array(PostPurchaseVariantOption.pick({ name: true, values: true }));
6909
- var PostPurchaseVariantDefaultProduct = z79.object({
7204
+ var options = z83.array(PostPurchaseVariantOption.pick({ name: true, values: true }));
7205
+ var PostPurchaseVariantDefaultProduct = z83.object({
6910
7206
  id: PostPurchaseProductId,
6911
7207
  options,
6912
7208
  selectedVariant: variant.optional(),
6913
- variants: z79.array(variant)
7209
+ variants: z83.array(variant)
6914
7210
  });
6915
7211
  var PostPurchaseVariantDefaultSettings = PostPurchaseSettings.shape.productOptions.pick({
6916
7212
  hideOutOfStockVariants: true,
6917
7213
  matchVariant: true
6918
7214
  });
6919
- var PostPurchaseOrderAttributes = z79.record(z79.string(), z79.array(z79.string())).default({});
6920
- var PostPurchaseOriginalVariants = z79.array(
6921
- z79.object({ productId: PostPurchaseProductId, variantId: PostPurchaseVariantId })
7215
+ var PostPurchaseOrderAttributes = z83.record(z83.string(), z83.array(z83.string())).default({});
7216
+ var PostPurchaseOriginalVariants = z83.array(
7217
+ z83.object({ productId: PostPurchaseProductId, variantId: PostPurchaseVariantId })
6922
7218
  );
6923
- var PostPurchaseAttributeProducts = z79.array(
6924
- z79.object({ id: PostPurchaseProductId, options, variants: z79.array(values.extend({ id: PostPurchaseVariantId })) })
7219
+ var PostPurchaseAttributeProducts = z83.array(
7220
+ z83.object({ id: PostPurchaseProductId, options, variants: z83.array(values.extend({ id: PostPurchaseVariantId })) })
6925
7221
  );
6926
7222
 
6927
7223
  // src/schema/postPurchaseVariantDefaultContext.ts
6928
- import { z as z80 } from "zod";
6929
- var PostPurchaseVariantDefaultContext = z80.object({
6930
- enrichedLineItems: z80.unknown().optional(),
7224
+ import { z as z84 } from "zod";
7225
+ var PostPurchaseVariantDefaultContext = z84.object({
7226
+ enrichedLineItems: z84.unknown().optional(),
6931
7227
  originalVariants: PostPurchaseOriginalVariants
6932
7228
  });
6933
7229
 
@@ -7013,13 +7309,13 @@ var prepareMember = (widgetId, settings, response, requested, report, excludedPr
7013
7309
  variants: found.product.variants.filter(({ id }) => id === variantId)
7014
7310
  };
7015
7311
  const selectedInput = { ...normalized, data: [product] };
7016
- const quantity2 = requestedQuantity ? readPostPurchaseQuantity(selectedInput, requestedQuantity) : void 0;
7017
- const view = prepareNormalizedPostPurchaseView(widgetId, selectedInput, report, selected.choice, quantity2, true);
7312
+ const quantity3 = requestedQuantity ? readPostPurchaseQuantity(selectedInput, requestedQuantity) : void 0;
7313
+ const view = prepareNormalizedPostPurchaseView(widgetId, selectedInput, report, selected.choice, quantity3, true);
7018
7314
  if (selected.variantId !== void 0 || found.product.variants.length > 1)
7019
7315
  view.variantCatalog = projectPostPurchaseVariantCatalog(found.product, normalized.effective);
7020
7316
  if (defaults && selected.variantId === void 0 && variantId && view.variantCatalog?.variants.some(({ id }) => id === variantId))
7021
7317
  view.initialVariant = { variantId };
7022
- return { member: { productId: found.product.id, productIndex: found.productIndex, view }, normalized, quantity: quantity2 };
7318
+ return { member: { productId: found.product.id, productIndex: found.productIndex, view }, normalized, quantity: quantity3 };
7023
7319
  };
7024
7320
  var preparePostPurchaseMemberView = (widgetId, settings, response, requested, report, excludedProductIds) => prepareMember(widgetId, settings, response, requested, report, excludedProductIds)?.member ?? null;
7025
7321
  var preparePostPurchaseMemberAdmissionView = (widgetId, settings, response, requested, report, excludedProductIds) => {
@@ -7031,24 +7327,24 @@ var preparePostPurchaseMemberAdmissionView = (widgetId, settings, response, requ
7031
7327
 
7032
7328
  // src/server/preparePostPurchaseQuantityView.ts
7033
7329
  var preparePostPurchaseQuantityView = (widgetId, settings, response, requested, report, excludedProductIds, defaults) => {
7034
- const { quantity: quantity2, ...selection3 } = PostPurchaseQuantityChoice.parse(requested);
7330
+ const { quantity: quantity3, ...selection4 } = PostPurchaseQuantityChoice.parse(requested);
7035
7331
  const prepared = prepareMember(
7036
7332
  widgetId,
7037
7333
  settings,
7038
7334
  response,
7039
- selection3,
7335
+ selection4,
7040
7336
  report,
7041
7337
  excludedProductIds,
7042
- { quantity: quantity2 },
7338
+ { quantity: quantity3 },
7043
7339
  defaults
7044
7340
  );
7045
7341
  return prepared ? { ...prepared.member, quantityPolicy: prepared.quantity.policy } : null;
7046
7342
  };
7047
7343
 
7048
7344
  // src/server/preparePostPurchaseQuantityAdmissionView.ts
7049
- var selection = PostPurchaseQuantityChoice.required({ quantity: true });
7345
+ var selection2 = PostPurchaseQuantityChoice.required({ quantity: true });
7050
7346
  var preparePostPurchaseQuantityAdmissionView = (widgetId, settings, response, expected, report, excludedProductIds, defaults) => {
7051
- const { quantity: expectedQuantity, ...requested } = selection.parse(expected);
7347
+ const { quantity: expectedQuantity, ...requested } = selection2.parse(expected);
7052
7348
  const prepared = prepareMember(
7053
7349
  widgetId,
7054
7350
  settings,
@@ -7101,12 +7397,12 @@ var readPostPurchaseGroup = (product, settings, excludedProductIds) => {
7101
7397
 
7102
7398
  // src/server/readPostPurchaseGroupSelection.ts
7103
7399
  var readPostPurchaseGroupSelection = (settings, response, requested, excludedProductIds) => {
7104
- const selection3 = PostPurchaseGroupSelection.parse(requested);
7400
+ const selection4 = PostPurchaseGroupSelection.parse(requested);
7105
7401
  const { members, normalized } = normalizePostPurchaseCollection(settings, response);
7106
- const member = members.find(({ product }) => product.id === selection3.memberProductId);
7402
+ const member = members.find(({ product }) => product.id === selection4.memberProductId);
7107
7403
  if (!member || !member.product.productGroupVariants.length) return null;
7108
7404
  const group = readPostPurchaseGroup(member.product, normalized.effective, excludedProductIds);
7109
- const entry = group.entries.find(({ product }) => product.id === selection3.productId);
7405
+ const entry = group.entries.find(({ product }) => product.id === selection4.productId);
7110
7406
  if (!entry) return null;
7111
7407
  return {
7112
7408
  groupCatalog: group.catalog,
@@ -7120,16 +7416,16 @@ var readPostPurchaseGroupSelection = (settings, response, requested, excludedPro
7120
7416
 
7121
7417
  // src/server/preparePostPurchaseGroupView.ts
7122
7418
  var preparePostPurchaseGroupView = (widgetId, settings, response, requested, report, excludedProductIds) => {
7123
- const { memberProductId, ...selection3 } = PostPurchaseGroupChoice.parse(requested);
7419
+ const { memberProductId, ...selection4 } = PostPurchaseGroupChoice.parse(requested);
7124
7420
  const group = readPostPurchaseGroupSelection(settings, response, requested, excludedProductIds);
7125
7421
  if (!group) return null;
7126
- const variantId = selection3.variantId ?? group.variantCatalog.variants.find(({ available }) => available)?.id;
7422
+ const variantId = selection4.variantId ?? group.variantCatalog.variants.find(({ available }) => available)?.id;
7127
7423
  if (variantId === void 0) return null;
7128
7424
  const prepared = preparePostPurchaseQuantityView(
7129
7425
  widgetId,
7130
7426
  settings,
7131
7427
  group.response,
7132
- { ...selection3, variantId },
7428
+ { ...selection4, variantId },
7133
7429
  report
7134
7430
  );
7135
7431
  return prepared && {
@@ -7143,16 +7439,16 @@ var preparePostPurchaseGroupView = (widgetId, settings, response, requested, rep
7143
7439
 
7144
7440
  // src/server/preparePostPurchaseGroupAdmissionView.ts
7145
7441
  var preparePostPurchaseGroupAdmissionView = (widgetId, settings, response, requested, report, excludedProductIds) => {
7146
- const { memberProductId, ...selection3 } = PostPurchaseGroupChoice.required({ quantity: true }).parse(requested);
7442
+ const { memberProductId, ...selection4 } = PostPurchaseGroupChoice.required({ quantity: true }).parse(requested);
7147
7443
  const group = readPostPurchaseGroupSelection(settings, response, requested, excludedProductIds);
7148
7444
  if (!group) return null;
7149
- const variantId = selection3.variantId ?? group.variantCatalog.variants.find(({ available }) => available)?.id;
7445
+ const variantId = selection4.variantId ?? group.variantCatalog.variants.find(({ available }) => available)?.id;
7150
7446
  if (variantId === void 0) return null;
7151
7447
  const prepared = preparePostPurchaseQuantityAdmissionView(
7152
7448
  widgetId,
7153
7449
  settings,
7154
7450
  group.response,
7155
- { ...selection3, variantId },
7451
+ { ...selection4, variantId },
7156
7452
  report
7157
7453
  );
7158
7454
  return prepared && {
@@ -7215,6 +7511,7 @@ var preparePostPurchaseCollectionGroup = (widgetId, settings, response, member,
7215
7511
  reportingProduct: { id: member.product.id, title: member.product.title },
7216
7512
  view: prepared ? { ...prepared.view, groupCatalog: prepared.groupCatalog } : {
7217
7513
  groupCatalog: group.catalog,
7514
+ labels: { notAvailable: normalized.effective.language.global.notAvailable },
7218
7515
  preparation: { reason: "Post-purchase group default is unavailable", status: "unsupported" },
7219
7516
  sections: null
7220
7517
  }
@@ -7270,22 +7567,22 @@ var preparePostPurchaseCollectionView = (widgetId, settings, response, report, r
7270
7567
  };
7271
7568
 
7272
7569
  // src/schema/postPurchaseOfferEligibility.ts
7273
- import { z as z81 } from "zod";
7274
- var selection2 = PreparedPostPurchaseProduct.shape.selection;
7275
- var PostPurchaseOfferSkipReason = z81.enum(["empty", "no-eligible-subscription"]);
7276
- var PostPurchaseOfferEligibilityContext = z81.object({
7570
+ import { z as z85 } from "zod";
7571
+ var selection3 = PreparedPostPurchaseProduct.shape.selection;
7572
+ var PostPurchaseOfferSkipReason = z85.enum(["empty", "no-eligible-subscription"]);
7573
+ var PostPurchaseOfferEligibilityContext = z85.object({
7277
7574
  excludedProductIds: PostPurchaseExcludedProductIds,
7278
- originalLineItems: z81.array(selection2.pick({ productId: true, sellingPlanId: true, variantId: true }))
7575
+ originalLineItems: z85.array(selection3.pick({ productId: true, sellingPlanId: true, variantId: true }))
7279
7576
  });
7280
- var PostPurchaseOfferEligibility = z81.discriminatedUnion("status", [
7281
- z81.object({
7282
- members: z81.array(
7283
- z81.object({ productId: selection2.shape.productId, productIndex: z81.number().int().nonnegative() })
7577
+ var PostPurchaseOfferEligibility = z85.discriminatedUnion("status", [
7578
+ z85.object({
7579
+ members: z85.array(
7580
+ z85.object({ productId: selection3.shape.productId, productIndex: z85.number().int().nonnegative() })
7284
7581
  ),
7285
- status: z81.literal("retain")
7582
+ status: z85.literal("retain")
7286
7583
  }),
7287
- z81.object({ reason: PostPurchaseOfferSkipReason, status: z81.literal("skip") }),
7288
- z81.object({ reason: z81.literal("eligible-upgrade").optional(), status: z81.literal("unavailable") })
7584
+ z85.object({ reason: PostPurchaseOfferSkipReason, status: z85.literal("skip") }),
7585
+ z85.object({ reason: z85.literal("eligible-upgrade").optional(), status: z85.literal("unavailable") })
7289
7586
  ]);
7290
7587
 
7291
7588
  // src/server/postPurchaseMemberEligibility.ts
@@ -7364,10 +7661,10 @@ var classifyPostPurchaseOffer = (settings, response, context) => {
7364
7661
  };
7365
7662
 
7366
7663
  // src/server/preparePostPurchaseDeclineDisplay.ts
7367
- import { z as z83 } from "zod";
7664
+ import { z as z87 } from "zod";
7368
7665
 
7369
7666
  // src/schema/postPurchaseDecline.ts
7370
- import { z as z82 } from "zod";
7667
+ import { z as z86 } from "zod";
7371
7668
  var OfferDeclineRequestSchema = DecideRequestSchema.extend({
7372
7669
  entryRevision: PostPurchaseProgressSchema.shape.entryRevision,
7373
7670
  productId: PostPurchaseProgressSchema.shape.members.element.shape.productId,
@@ -7379,23 +7676,23 @@ var OfferDeclineRequestSchema = DecideRequestSchema.extend({
7379
7676
  "Selected merchandise requires a variant"
7380
7677
  );
7381
7678
  var RecordedOfferDeclineSchema = PostPurchaseProgressSchema.shape.members.element.omit({ declineDelivery: true, status: true }).extend({ entry: DecisionEntrySchema.strict(), entryRevision: PostPurchaseProgressSchema.shape.entryRevision }).strict();
7382
- var OfferDeclineResponseSchema = z82.object({
7383
- data: z82.object({ decline: RecordedOfferDeclineSchema, progress: PostPurchaseProgressSchema }),
7384
- successful: z82.literal(true)
7679
+ var OfferDeclineResponseSchema = z86.object({
7680
+ data: z86.object({ decline: RecordedOfferDeclineSchema, progress: PostPurchaseProgressSchema }),
7681
+ successful: z86.literal(true)
7385
7682
  });
7386
7683
 
7387
7684
  // src/server/preparePostPurchaseDeclineDisplay.ts
7388
- var Selection = z83.object({
7685
+ var Selection = z87.object({
7389
7686
  productId: OfferDeclineRequestSchema.shape.productId,
7390
7687
  variant: OfferDeclineRequestSchema.shape.variant.unwrap()
7391
7688
  });
7392
7689
  var preparePostPurchaseDeclineDisplay = (settings, response, requested) => {
7393
- const selection3 = Selection.parse(requested);
7690
+ const selection4 = Selection.parse(requested);
7394
7691
  const { members, normalized } = normalizePostPurchaseCollection(settings, response);
7395
- const found = members.find(({ product }) => product.id === selection3.productId);
7692
+ const found = members.find(({ product }) => product.id === selection4.productId);
7396
7693
  if (!found) return null;
7397
7694
  const catalog = projectPostPurchaseVariantCatalog(found.product, normalized.effective);
7398
- const variant2 = catalog.variants.find(({ id }) => id === selection3.variant.variantId);
7695
+ const variant2 = catalog.variants.find(({ id }) => id === selection4.variant.variantId);
7399
7696
  return variant2 ? { productTitle: found.product.title, variantId: variant2.id, variantTitle: variant2.title } : null;
7400
7697
  };
7401
7698
 
@@ -7415,40 +7712,45 @@ var preparePostPurchaseGroupDeclineDisplay = (settings, response, requested, exc
7415
7712
 
7416
7713
  // src/server/preparePostPurchaseOfferPresentation.ts
7417
7714
  import { merge as merge2 } from "es-toolkit/compat";
7418
- import { z as z85 } from "zod";
7715
+ import { z as z89 } from "zod";
7419
7716
 
7420
7717
  // src/schema/postPurchaseOfferPresentation.ts
7421
- import { z as z84 } from "zod";
7718
+ import { z as z88 } from "zod";
7422
7719
  var language2 = PostPurchaseSettings.shape.language.shape.global.unwrap().unwrap();
7423
- var PostPurchaseOfferPresentation = z84.strictObject({
7720
+ var PostPurchaseOfferPresentation = z88.strictObject({
7424
7721
  labels: language2.pick({ declineAll: true, declineThisOffer: true }),
7425
7722
  layout: PostPurchaseSettings.shape.offersLayout,
7426
7723
  sections: CABRootSection.nullable(),
7427
7724
  showDeclineAll: PostPurchaseSettings.shape.productOptions.shape.showDeclineAll
7428
7725
  });
7429
7726
  var OfferPresentationRequestSchema = DecideRequestSchema.strict();
7430
- var OfferPresentationResponseSchema = z84.object({
7431
- data: z84.strictObject({
7727
+ var OfferPresentationResponseSchema = z88.object({
7728
+ data: z88.strictObject({
7432
7729
  presentation: PostPurchaseOfferPresentation.nullable(),
7433
7730
  progress: PostPurchaseProgressSchema.nullable(),
7434
7731
  serverNow: PostPurchaseTimestampSchema
7435
7732
  }),
7436
- successful: z84.literal(true)
7733
+ successful: z88.literal(true)
7437
7734
  });
7438
7735
 
7439
7736
  // src/server/preparePostPurchaseOfferPresentation.ts
7440
7737
  var FrameSettings = PostPurchaseSettings.pick({ language: true, offersLayout: true, productOptions: true }).extend({
7441
- blocks: z85.array(z85.unknown()).optional()
7738
+ blocks: z89.array(z89.unknown()).optional()
7442
7739
  });
7443
7740
  var preparePostPurchaseOfferPresentation = (widgetId, settings, response, report) => {
7444
7741
  const { metadata } = PostPurchaseProductSource.pick({ metadata: true }).parse(deepCamelCase(response));
7445
7742
  const original = FrameSettings.parse(deepCamelCase(settings));
7743
+ const merged = merge2({}, deepCamelCase(settings), metadata.widget);
7446
7744
  const effective = FrameSettings.parse(merge2({}, original, metadata.widget));
7447
7745
  let sections = null;
7448
7746
  try {
7449
7747
  sections = convertMessagePreview(
7450
7748
  widgetId,
7451
- { blocks: postPurchaseOfferCopy(effective.blocks, metadata), type: "shopify_post_purchase_extension" },
7749
+ {
7750
+ ...merged,
7751
+ blocks: postPurchaseOfferCopy(effective.blocks, metadata),
7752
+ type: "shopify_post_purchase_extension"
7753
+ },
7452
7754
  report
7453
7755
  );
7454
7756
  } catch (error) {
@@ -7598,7 +7900,7 @@ var postAnalyticsEvents = async (input, ctx) => {
7598
7900
  };
7599
7901
 
7600
7902
  // src/server/requestSchemas.ts
7601
- import { z as z86 } from "zod";
7903
+ import { z as z90 } from "zod";
7602
7904
  var REQUEST_BOUNDS = {
7603
7905
  /** Cart-level attributes per cart. */
7604
7906
  CART_ATTRIBUTES_MAX: 100,
@@ -7629,42 +7931,42 @@ var REQUEST_BOUNDS = {
7629
7931
  /** Rich ads transaction lines — the engine's ads contract. */
7630
7932
  TRANSACTION_ITEMS_MAX: 50
7631
7933
  };
7632
- var KeyValue = z86.object({
7633
- key: z86.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
7634
- value: z86.string().max(REQUEST_BOUNDS.STRING_VALUE_MAX).optional()
7934
+ var KeyValue = z90.object({
7935
+ key: z90.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
7936
+ value: z90.string().max(REQUEST_BOUNDS.STRING_VALUE_MAX).optional()
7635
7937
  });
7636
- var CartLineInputSchema = z86.object({
7637
- productId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7638
- properties: z86.array(KeyValue).max(REQUEST_BOUNDS.LINE_PROPERTIES_MAX).optional(),
7639
- quantity: z86.number(),
7640
- subscriptionId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7641
- variantId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX)
7938
+ var CartLineInputSchema = z90.object({
7939
+ productId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7940
+ properties: z90.array(KeyValue).max(REQUEST_BOUNDS.LINE_PROPERTIES_MAX).optional(),
7941
+ quantity: z90.number(),
7942
+ subscriptionId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7943
+ variantId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX)
7642
7944
  });
7643
- var CartInputSchema = z86.object({
7644
- attributes: z86.array(KeyValue).max(REQUEST_BOUNDS.CART_ATTRIBUTES_MAX).optional(),
7945
+ var CartInputSchema = z90.object({
7946
+ attributes: z90.array(KeyValue).max(REQUEST_BOUNDS.CART_ATTRIBUTES_MAX).optional(),
7645
7947
  /**
7646
7948
  * Presentment-per-shop-currency FX rate (buyer price ÷ shop price, e.g. `1.35` for a USD shop
7647
7949
  * selling in CAD). Money rule thresholds are authored in SHOP currency, so the engine subtotal is
7648
7950
  * divided by this before evaluation. Omit (or send 1) when the cart is already in the shop's currency.
7649
7951
  */
7650
- currencyRate: z86.number().optional(),
7952
+ currencyRate: z90.number().optional(),
7651
7953
  /** Applied discount codes; the engine evaluates `discount_code` rules against them (sent as `[{code}]`). */
7652
- discountCodes: z86.array(z86.string().max(REQUEST_BOUNDS.STRING_KEY_MAX)).max(REQUEST_BOUNDS.DISCOUNT_CODES_MAX).optional(),
7954
+ discountCodes: z90.array(z90.string().max(REQUEST_BOUNDS.STRING_KEY_MAX)).max(REQUEST_BOUNDS.DISCOUNT_CODES_MAX).optional(),
7653
7955
  /** Presentment cents of cart-level discount allocations, subtracted from `subtotal` for the engine. */
7654
- discountTotal: z86.number().optional(),
7655
- items: z86.array(CartLineInputSchema).max(REQUEST_BOUNDS.CART_ITEMS_MAX),
7956
+ discountTotal: z90.number().optional(),
7957
+ items: z90.array(CartLineInputSchema).max(REQUEST_BOUNDS.CART_ITEMS_MAX),
7656
7958
  /** Presentment subtotal in cents. */
7657
- subtotal: z86.number()
7959
+ subtotal: z90.number()
7658
7960
  });
7659
- var UserConfigInputSchema = z86.object({ shop: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX) });
7660
- var DataSourceInputSchema = z86.object({
7961
+ var UserConfigInputSchema = z90.object({ shop: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX) });
7962
+ var DataSourceInputSchema = z90.object({
7661
7963
  cart: CartInputSchema,
7662
7964
  /**
7663
7965
  * Numeric Shopify company-location id when the buyer is a B2B session (`buyerIdentity.purchasingCompany`).
7664
7966
  * Present ⇒ the orchestrator filters results by the location's catalog via admin-api (REB-23713); the
7665
7967
  * client's country-context market check is bypassed for B2B (it false-negatives B2B-catalog products).
7666
7968
  */
7667
- companyLocationId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7969
+ companyLocationId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7668
7970
  /**
7669
7971
  * Buyer's market country (ISO 3166-1 alpha-2) — forwarded to the engine as the `country_code` PARAM
7670
7972
  * when the shop's markets toggle is on (REB-21688; the sink was the `X-Country-Code` header under
@@ -7673,16 +7975,16 @@ var DataSourceInputSchema = z86.object({
7673
7975
  * uppercase (the wire value is forwarded verbatim as the param) so a case-sensitive engine lookup
7674
7976
  * can't silently miss a lowercase code — `adsEngine.ts` uppercases for the same reason.
7675
7977
  */
7676
- country: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z]{2}$/, "must be an ISO 3166-1 alpha-2 country code (e.g. CA)").transform((value) => value.toUpperCase()).optional(),
7677
- customerId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7678
- dataSourcePath: z86.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
7978
+ country: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z]{2}$/, "must be an ISO 3166-1 alpha-2 country code (e.g. CA)").transform((value) => value.toUpperCase()).optional(),
7979
+ customerId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7980
+ dataSourcePath: z90.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
7679
7981
  /**
7680
7982
  * Engine `filter_inputs` override: `'no'` keeps in-cart (input) products in the results/rule
7681
7983
  * outputs — gift validation sends it so a gift's own product can appear in its answer. Omitted = the
7682
7984
  * engine's default filtering.
7683
7985
  */
7684
- filterInputs: z86.enum(["no", "yes"]).optional(),
7685
- integrations: z86.record(z86.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z86.boolean()).refine((record) => Object.keys(record).length <= REQUEST_BOUNDS.INTEGRATION_KEYS_MAX, {
7986
+ filterInputs: z90.enum(["no", "yes"]).optional(),
7987
+ integrations: z90.record(z90.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z90.boolean()).refine((record) => Object.keys(record).length <= REQUEST_BOUNDS.INTEGRATION_KEYS_MAX, {
7686
7988
  message: `Too many integration keys (max ${REQUEST_BOUNDS.INTEGRATION_KEYS_MAX})`
7687
7989
  }).optional(),
7688
7990
  /**
@@ -7695,31 +7997,31 @@ var DataSourceInputSchema = z86.object({
7695
7997
  * request header) fails the regex. Callers should send the buyer's resolved locale (e.g. Shopify
7696
7998
  * checkout's `localization.language.isoCode`), not the request header verbatim.
7697
7999
  */
7698
- language: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z0-9-]+$/, "must be a single BCP-47 tag (e.g. fr-CA), not a q-value list").optional(),
7699
- limit: z86.number().max(REQUEST_BOUNDS.LIMIT_MAX),
7700
- productType: z86.enum(["both", "one-time", "subscription"]).optional(),
7701
- shop: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7702
- visitorId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
7703
- });
7704
- var GiftInputSchema = z86.object({
7705
- cost: z86.number(),
7706
- discounted: z86.boolean(),
8000
+ language: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z0-9-]+$/, "must be a single BCP-47 tag (e.g. fr-CA), not a q-value list").optional(),
8001
+ limit: z90.number().max(REQUEST_BOUNDS.LIMIT_MAX),
8002
+ productType: z90.enum(["both", "one-time", "subscription"]).optional(),
8003
+ shop: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
8004
+ visitorId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
8005
+ });
8006
+ var GiftInputSchema = z90.object({
8007
+ cost: z90.number(),
8008
+ discounted: z90.boolean(),
7707
8009
  /**
7708
8010
  * Which gift attribution the line carries (REB-24363). Defaults to `gwp` because a client that predates
7709
8011
  * the field only ever sent GWP lines — without the default an older extension's request would 422.
7710
8012
  */
7711
- kind: z86.enum(GIFT_KINDS).default("gwp"),
7712
- lineId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7713
- productId: z86.number(),
8013
+ kind: z90.enum(GIFT_KINDS).default("gwp"),
8014
+ lineId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
8015
+ productId: z90.number(),
7714
8016
  /**
7715
8017
  * The line's unit count (REB-24363) — the selectable-GWP verdict trims surplus units against milestone
7716
8018
  * capacity. The second deliberate default: a client predating the field sent only GWP lines, whose
7717
8019
  * verdict is whole-line, so a missing quantity reads as one unit rather than 422ing the older request.
7718
8020
  */
7719
- quantity: z86.number().int().min(1).default(1),
7720
- widgetId: z86.number()
8021
+ quantity: z90.number().int().min(1).default(1),
8022
+ widgetId: z90.number()
7721
8023
  });
7722
- var GiftValidationInputSchema = z86.object({
8024
+ var GiftValidationInputSchema = z90.object({
7723
8025
  cart: CartInputSchema,
7724
8026
  /**
7725
8027
  * Buyer's market country — threaded into the per-widget data-source evaluations, which forward it to
@@ -7728,25 +8030,25 @@ var GiftValidationInputSchema = z86.object({
7728
8030
  * turns markets off); regex-bound and uppercase-normalized for the same reasons as
7729
8031
  * `DataSourceInputSchema`'s `country`.
7730
8032
  */
7731
- country: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z]{2}$/, "must be an ISO 3166-1 alpha-2 country code (e.g. CA)").transform((value) => value.toUpperCase()).optional(),
7732
- customerId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7733
- gifts: z86.array(GiftInputSchema).max(REQUEST_BOUNDS.GIFTS_MAX),
8033
+ country: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z]{2}$/, "must be an ISO 3166-1 alpha-2 country code (e.g. CA)").transform((value) => value.toUpperCase()).optional(),
8034
+ customerId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8035
+ gifts: z90.array(GiftInputSchema).max(REQUEST_BOUNDS.GIFTS_MAX),
7734
8036
  /**
7735
8037
  * Buyer's checkout language — threaded into the per-widget data-source evaluations, which normalize
7736
8038
  * and forward it as the engine `locale` param under the same markets-toggle gate (REB-21688). MUST be
7737
8039
  * a single BCP-47 tag, for the same reason as `DataSourceInputSchema`'s `language` above.
7738
8040
  */
7739
- language: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z0-9-]+$/, "must be a single BCP-47 tag (e.g. fr-CA), not a q-value list").optional(),
7740
- shop: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7741
- visitorId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
8041
+ language: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z0-9-]+$/, "must be a single BCP-47 tag (e.g. fr-CA), not a q-value list").optional(),
8042
+ shop: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
8043
+ visitorId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
7742
8044
  });
7743
- var GiftAdjustmentSchema = z86.object({
7744
- lineId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7745
- quantity: z86.number().int().nonnegative()
8045
+ var GiftAdjustmentSchema = z90.object({
8046
+ lineId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
8047
+ quantity: z90.number().int().nonnegative()
7746
8048
  });
7747
- var GiftValidationResponseSchema = z86.object({
7748
- adjust: z86.array(GiftAdjustmentSchema).max(REQUEST_BOUNDS.GIFTS_MAX).default([]),
7749
- remove: z86.array(z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX)).max(REQUEST_BOUNDS.GIFTS_MAX).refine(
8049
+ var GiftValidationResponseSchema = z90.object({
8050
+ adjust: z90.array(GiftAdjustmentSchema).max(REQUEST_BOUNDS.GIFTS_MAX).default([]),
8051
+ remove: z90.array(z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX)).max(REQUEST_BOUNDS.GIFTS_MAX).refine(
7750
8052
  (remove) => new Set(remove).size === remove.length,
7751
8053
  "a line id may appear at most once in `remove`"
7752
8054
  )
@@ -7757,47 +8059,47 @@ var GiftValidationResponseSchema = z86.object({
7757
8059
  ({ adjust }) => new Set(adjust.map(({ lineId }) => lineId)).size === adjust.length,
7758
8060
  "a line id may appear at most once in `adjust`"
7759
8061
  );
7760
- var MonetizeTransactionItemSchema = z86.object({
7761
- id: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7762
- priceCents: z86.number(),
7763
- quantity: z86.number(),
7764
- title: z86.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX),
7765
- type: z86.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX)
7766
- });
7767
- var MonetizeInputSchema = z86.object({
8062
+ var MonetizeTransactionItemSchema = z90.object({
8063
+ id: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
8064
+ priceCents: z90.number(),
8065
+ quantity: z90.number(),
8066
+ title: z90.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX),
8067
+ type: z90.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX)
8068
+ });
8069
+ var MonetizeInputSchema = z90.object({
7768
8070
  cart: CartInputSchema,
7769
8071
  /** Client-minted render-beacon correlation id; forwarded to the ads engine as `client_request_id`. */
7770
- clientRequestId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7771
- country: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7772
- currency: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8072
+ clientRequestId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8073
+ country: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8074
+ currency: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7773
8075
  /** Ads-targeting identity/geo/locale fields (React parity); folded into the engine query verbatim. */
7774
- customerEmail: z86.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
7775
- customerFirstName: z86.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
7776
- customerId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7777
- customerLastName: z86.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
7778
- language: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8076
+ customerEmail: z90.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
8077
+ customerFirstName: z90.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
8078
+ customerId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8079
+ customerLastName: z90.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
8080
+ language: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7779
8081
  /** Buyer-facing order name (e.g. `#1001`) for the server-composed "Order … Confirmed" chrome line. */
7780
- orderName: z86.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
8082
+ orderName: z90.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
7781
8083
  /** Ads surface label, forwarded verbatim; `customer_account` is measured/floored as its own surface (the account-area order list). */
7782
- placement: z86.enum(["customer_account", "order_status", "thank_you_page"]),
8084
+ placement: z90.enum(["customer_account", "order_status", "thank_you_page"]),
7783
8085
  /** Privacy Policy footer href — the Monetize widget's `privacy_policy_url` setting (React parity). */
7784
- privacyPolicyUrl: z86.string().max(REQUEST_BOUNDS.STRING_URL_MAX).optional(),
8086
+ privacyPolicyUrl: z90.string().max(REQUEST_BOUNDS.STRING_URL_MAX).optional(),
7785
8087
  /** 30-min rolling session id (React parity); used for the ads `session_id`, else the visitor id. */
7786
- sessionId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7787
- shop: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
8088
+ sessionId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8089
+ shop: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7788
8090
  /** Editor/QA indicator; OR-ed into the ads-engine `testing` flag so it stays out of billing/reporting. */
7789
- testing: z86.boolean().optional(),
7790
- timezone: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8091
+ testing: z90.boolean().optional(),
8092
+ timezone: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7791
8093
  /** Decorated (numeric) order id → the ads `transaction_id`. */
7792
- transactionId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8094
+ transactionId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7793
8095
  /** Rich per-line ads items; capped at the engine's ads contract. Preferred over `cart.items`. */
7794
- transactionItems: z86.array(MonetizeTransactionItemSchema).max(REQUEST_BOUNDS.TRANSACTION_ITEMS_MAX).optional(),
8096
+ transactionItems: z90.array(MonetizeTransactionItemSchema).max(REQUEST_BOUNDS.TRANSACTION_ITEMS_MAX).optional(),
7795
8097
  /** Order total in presentment cents (React prefers total over subtotal); else `cart.subtotal`. */
7796
- transactionTotal: z86.number().optional(),
7797
- visitorId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7798
- zipCode: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
8098
+ transactionTotal: z90.number().optional(),
8099
+ visitorId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8100
+ zipCode: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
7799
8101
  });
7800
- var WidgetSettingsInputSchema = z86.object({
8102
+ var WidgetSettingsInputSchema = z90.object({
7801
8103
  /**
7802
8104
  * Same domain as `CabShopConfig.cacheKey`, for the same reason: this side WINS the orchestrator's
7803
8105
  * `input.cacheKey ?? config.shop.cacheKey` (and an explicit value skips the config read entirely), so
@@ -7805,9 +8107,9 @@ var WidgetSettingsInputSchema = z86.object({
7805
8107
  * and pin the edge copy permanently stale. `.catch(undefined)` because a bogus buster should degrade
7806
8108
  * the read to un-busted, never 400 a widget render.
7807
8109
  */
7808
- cacheKey: z86.number().int().positive().optional().catch(void 0),
7809
- id: z86.number(),
7810
- key: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8110
+ cacheKey: z90.number().int().positive().optional().catch(void 0),
8111
+ id: z90.number(),
8112
+ key: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7811
8113
  /**
7812
8114
  * Monetize context for inline hydration: when present AND the widget converts to a Monetize marker,
7813
8115
  * the server fetches/composes the offer cards inside this same request (no second `/cab/monetize`
@@ -7816,36 +8118,36 @@ var WidgetSettingsInputSchema = z86.object({
7816
8118
  * `privacyPolicyUrl` comes from the widget settings server-side (more authoritative than a relay).
7817
8119
  */
7818
8120
  monetize: MonetizeInputSchema.omit({ privacyPolicyUrl: true, shop: true }).optional(),
7819
- shop: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
8121
+ shop: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7820
8122
  /** Stable per-buyer id; when present, enables sticky server-side A/B variant selection. */
7821
- visitorId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
8123
+ visitorId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
7822
8124
  });
7823
- var AnalyticsEventInputSchema = z86.object({
7824
- name: z86.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
7825
- properties: z86.record(z86.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z86.unknown()).optional(),
7826
- sentAt: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
8125
+ var AnalyticsEventInputSchema = z90.object({
8126
+ name: z90.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
8127
+ properties: z90.record(z90.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z90.unknown()).optional(),
8128
+ sentAt: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
7827
8129
  });
7828
- var AnalyticsSegmentsInputSchema = z86.object({
7829
- device: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
7830
- source: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
7831
- visitor: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0)
8130
+ var AnalyticsSegmentsInputSchema = z90.object({
8131
+ device: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
8132
+ source: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
8133
+ visitor: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0)
7832
8134
  });
7833
- var AnalyticsInputSchema = z86.object({
8135
+ var AnalyticsInputSchema = z90.object({
7834
8136
  /** Rebuy cart token (the `r_cart_token` cart attribute), when available — primary aggregation key. */
7835
- cartToken: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8137
+ cartToken: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7836
8138
  /** Shopify checkout token, when available — drives cart/checkout aggregation downstream. */
7837
- checkoutToken: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
7838
- events: z86.array(AnalyticsEventInputSchema).max(REQUEST_BOUNDS.EVENTS_MAX),
8139
+ checkoutToken: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
8140
+ events: z90.array(AnalyticsEventInputSchema).max(REQUEST_BOUNDS.EVENTS_MAX),
7839
8141
  /**
7840
8142
  * Request-scoped like the tokens: one visitor's segments apply to every event in the batch. The container
7841
8143
  * degrades too (`null` is a realistic wire artifact of `attributes ? {…} : null`), so the degrade rule is
7842
8144
  * total: nothing about `segments` can cost the envelope.
7843
8145
  */
7844
8146
  segments: AnalyticsSegmentsInputSchema.optional().catch(void 0),
7845
- shop: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7846
- visitorId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
8147
+ shop: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
8148
+ visitorId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
7847
8149
  /** The widget id (smartBlockId) the events belong to. */
7848
- widgetId: z86.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
8150
+ widgetId: z90.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
7849
8151
  });
7850
8152
  export {
7851
8153
  AnalyticsEventInputSchema,