@rebuy/rebuy 3.5.0 → 3.6.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 (40) hide show
  1. package/dist/index.cjs +740 -647
  2. package/dist/index.mjs +740 -647
  3. package/dist/schema/checkout-and-beyond/constants.cjs +16 -0
  4. package/dist/schema/checkout-and-beyond/constants.mjs +16 -0
  5. package/dist/schema/checkout-and-beyond/index.cjs +454 -362
  6. package/dist/schema/checkout-and-beyond/index.mjs +454 -362
  7. package/dist/schema/widget-data.cjs +508 -435
  8. package/dist/schema/widget-data.mjs +508 -435
  9. package/dist/schema/widgetData.d.ts +438 -147
  10. package/dist/schema/widgets/checkout-and-beyond/banner.d.ts +145 -48
  11. package/dist/schema/widgets/checkout-and-beyond/button.d.ts +154 -49
  12. package/dist/schema/widgets/checkout-and-beyond/carousel.d.ts +145 -48
  13. package/dist/schema/widgets/checkout-and-beyond/cartLine.d.ts +145 -48
  14. package/dist/schema/widgets/checkout-and-beyond/common.d.ts +29 -0
  15. package/dist/schema/widgets/checkout-and-beyond/discount.d.ts +146 -0
  16. package/dist/schema/widgets/checkout-and-beyond/icons.d.ts +1 -1
  17. package/dist/schema/widgets/checkout-and-beyond/image.d.ts +294 -100
  18. package/dist/schema/widgets/checkout-and-beyond/index.d.ts +1 -0
  19. package/dist/schema/widgets/checkout-and-beyond/layout.d.ts +148 -52
  20. package/dist/schema/widgets/checkout-and-beyond/monetize.d.ts +146 -49
  21. package/dist/schema/widgets/checkout-and-beyond/offers.d.ts +145 -48
  22. package/dist/schema/widgets/checkout-and-beyond/product.d.ts +146 -0
  23. package/dist/schema/widgets/checkout-and-beyond/products.d.ts +292 -0
  24. package/dist/schema/widgets/checkout-and-beyond/progressBar.d.ts +145 -48
  25. package/dist/schema/widgets/checkout-and-beyond/quantity.d.ts +146 -49
  26. package/dist/schema/widgets/checkout-and-beyond/reviews.d.ts +146 -49
  27. package/dist/schema/widgets/checkout-and-beyond/root.d.ts +146 -49
  28. package/dist/schema/widgets/checkout-and-beyond/rule.d.ts +140 -68
  29. package/dist/schema/widgets/checkout-and-beyond/text.d.ts +146 -49
  30. package/dist/schema/widgets/checkout-and-beyond/variables.d.ts +470 -0
  31. package/dist/schema/widgets/checkout-and-beyond/variants.d.ts +146 -49
  32. package/dist/schema/widgets/contentBlock.d.ts +146 -49
  33. package/dist/schema/widgets/lineItemEditor.d.ts +146 -49
  34. package/dist/schema/widgets/rebuyButton.d.ts +146 -49
  35. package/dist/server/index.cjs +492 -416
  36. package/dist/server/index.mjs +492 -416
  37. package/dist/transforms/index.cjs +393 -317
  38. package/dist/transforms/index.mjs +393 -317
  39. package/dist/transforms/monetizeV1/convertMonetizeToV2.d.ts +2 -2
  40. package/package.json +1 -1
@@ -536,7 +536,7 @@ var CabUserConfig = z6.object({
536
536
 
537
537
  // src/schema/widgets/checkout-and-beyond/image.ts
538
538
  import { v7 as uuidv712 } from "uuid";
539
- import { z as z25 } from "zod";
539
+ import { z as z26 } from "zod";
540
540
 
541
541
  // src/schema/widgets/checkout-and-beyond/common.ts
542
542
  var freezeEnum = (values) => Object.freeze(Object.fromEntries(values.map((v) => [v, v])));
@@ -643,6 +643,8 @@ var languageKeys = [
643
643
  "zh"
644
644
  ];
645
645
  var LanguageKey = freezeEnum(languageKeys);
646
+ var mutatorEvents = ["item_added", "quantity_changed", "variant_selected"];
647
+ var MutatorEvent = freezeEnum(mutatorEvents);
646
648
  var objectFits = ["cover", "contain"];
647
649
  var ObjectFit = freezeEnum(objectFits);
648
650
  var popoverPositions = ["inlineStart", "inlineEnd", "blockStart", "blockEnd"];
@@ -655,6 +657,10 @@ var progressTierUnits = ["currency", "item"];
655
657
  var ProgressTierUnit = freezeEnum(progressTierUnits);
656
658
  var quantityInputs = ["select", "number"];
657
659
  var QuantityInput = freezeEnum(quantityInputs);
660
+ var resultCountOperators = ["equals", "greater_than", "less_than"];
661
+ var ResultCountOperator = freezeEnum(resultCountOperators);
662
+ var resultTagOperators = ["contains", "does_not_contain"];
663
+ var ResultTagOperator = freezeEnum(resultTagOperators);
658
664
  var reviewsSizes = ["small", "default", "large"];
659
665
  var ReviewsSize = freezeEnum(reviewsSizes);
660
666
  var sectionTypes = [
@@ -687,6 +693,8 @@ var inlineTextSizeNames = ["extraSmall", "small", "base", "medium", "large", "ex
687
693
  var InlineTextSizeName = freezeEnum(inlineTextSizeNames);
688
694
  var textSizeNames = [...inlineTextSizeNames, "heading"];
689
695
  var TextSizeName = freezeEnum(textSizeNames);
696
+ var variableEffects = ["set_false", "set_true", "toggle"];
697
+ var VariableEffect = freezeEnum(variableEffects);
690
698
  var variantModes = ["multiple", "single"];
691
699
  var VariantMode = freezeEnum(variantModes);
692
700
  var variantSelectors = ["menu", "radio", "button"];
@@ -784,6 +792,19 @@ var HEX_COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
784
792
  var ROOT_RELATIVE_PATH_REGEX = /^\/(?!\/)/;
785
793
  var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
786
794
 
795
+ // src/schema/widgets/checkout-and-beyond/shared.ts
796
+ import { z as z25 } from "zod";
797
+
798
+ // src/schema/widgets/checkout-and-beyond/banner.ts
799
+ import { z as z10 } from "zod";
800
+
801
+ // src/schema/widgets/checkout-and-beyond/layout.ts
802
+ import { v7 as uuidv7 } from "uuid";
803
+ import { z as z9 } from "zod";
804
+
805
+ // src/schema/widgets/checkout-and-beyond/variables.ts
806
+ import { z as z8 } from "zod";
807
+
787
808
  // src/schema/widgets/checkout-and-beyond/rule.ts
788
809
  import { z as z7 } from "zod";
789
810
  var ruleTypes = [
@@ -830,62 +851,108 @@ var RuleCondition = z7.object({
830
851
  var RuleLogicBlock = z7.object({
831
852
  rules: z7.array(RuleCondition).default(() => [])
832
853
  });
833
- var CABRule = z7.object({
834
- dataSourceId: z7.number().nullable().default(null),
835
- enabled: z7.boolean().default(false),
836
- ruleset: z7.union([
837
- z7.array(
838
- z7.object({
839
- exitIfMatched: z7.boolean().default(true),
840
- logic: z7.array(RuleLogicBlock).default(() => []),
841
- output: z7.array(
842
- z7.object({
843
- key: z7.string().default("should_show"),
844
- type: z7.literal("data_json").default("data_json"),
845
- value: z7.string().default("true")
846
- })
847
- ).default(() => [{ key: "should_show", type: "data_json", value: "true" }])
848
- })
849
- ),
850
- z7.strictObject({}).transform(() => [])
851
- ]).default(() => [])
854
+ var CABRulesetEntry = z7.object({
855
+ exitIfMatched: z7.boolean().default(true),
856
+ logic: z7.array(RuleLogicBlock).default(() => []),
857
+ output: z7.array(
858
+ z7.object({
859
+ key: z7.string().default("should_show"),
860
+ type: z7.literal("data_json").default("data_json"),
861
+ value: z7.string().default("true")
862
+ })
863
+ ).default(() => [{ key: "should_show", type: "data_json", value: "true" }])
852
864
  });
865
+ var CABRuleset = z7.union([z7.array(CABRulesetEntry), z7.strictObject({}).transform(() => [])]).default(() => []);
853
866
 
854
- // src/schema/widgets/checkout-and-beyond/shared.ts
855
- import { z as z24 } from "zod";
856
-
857
- // src/schema/widgets/checkout-and-beyond/banner.ts
858
- import { z as z9 } from "zod";
867
+ // src/schema/widgets/checkout-and-beyond/variables.ts
868
+ var variableEffect = z8.enum(variableEffects);
869
+ var CABVariableSeed = z8.object({
870
+ dataSourceId: z8.number().nullable().default(null),
871
+ ruleset: CABRuleset
872
+ });
873
+ var CABVariable = z8.object({
874
+ /**
875
+ * Holds until the first seed verdict lands (and forever, for unseeded variables). Omitted, it derives
876
+ * from seededness — `false` with a `seed` (visibility is EARNED), `true` without — via the transform
877
+ * below; a cross-field default has no `.default()` spelling. An explicit value always wins.
878
+ */
879
+ defaultValue: z8.boolean().optional(),
880
+ name: z8.string().min(1),
881
+ seed: CABVariableSeed.optional()
882
+ }).transform(({ defaultValue, ...variable }) => ({
883
+ defaultValue: defaultValue ?? variable.seed === void 0,
884
+ ...variable
885
+ }));
886
+ var CABVariableEffect = z8.object({
887
+ effect: variableEffect.default(VariableEffect.toggle),
888
+ variable: z8.string().min(1)
889
+ });
890
+ var CABVisibility = z8.object({
891
+ variable: z8.string().min(1),
892
+ visibleWhen: z8.boolean().default(true)
893
+ });
894
+ var resultCountOperator = z8.enum(resultCountOperators);
895
+ var resultTagOperator = z8.enum(resultTagOperators);
896
+ var mutatorEvent = z8.enum(mutatorEvents);
897
+ var CABResultCountTrigger = z8.object({
898
+ operator: resultCountOperator.default(ResultCountOperator.equals),
899
+ type: z8.literal("result_count"),
900
+ value: z8.number().default(0)
901
+ });
902
+ var CABResultTagTrigger = z8.object({
903
+ operator: resultTagOperator.default(ResultTagOperator.contains),
904
+ type: z8.literal("result_tag"),
905
+ value: z8.string().min(1)
906
+ });
907
+ var CABEventTrigger = z8.object({
908
+ event: mutatorEvent,
909
+ type: z8.literal("event")
910
+ });
911
+ var CABVariableTrigger = z8.discriminatedUnion("type", [
912
+ CABEventTrigger,
913
+ CABResultCountTrigger,
914
+ CABResultTagTrigger
915
+ ]);
916
+ var CABVariableMutator = z8.object({
917
+ effect: variableEffect.default(VariableEffect.set_false),
918
+ variable: z8.string().min(1),
919
+ when: CABVariableTrigger
920
+ });
921
+ var CABVariableFields = {
922
+ mutators: z8.array(CABVariableMutator).optional(),
923
+ variables: z8.array(CABVariable).refine((variables) => new Set(variables.map(({ name }) => name)).size === variables.length, {
924
+ message: "variable names must be unique within a section"
925
+ }).optional(),
926
+ visibility: CABVisibility.optional()
927
+ };
859
928
 
860
929
  // src/schema/widgets/checkout-and-beyond/layout.ts
861
- import { v7 as uuidv7 } from "uuid";
862
- import { z as z8 } from "zod";
863
- var GridItem = z8.union([z8.literal("auto"), z8.literal("fill"), z8.string().regex(/^\d+%$/), z8.number()]);
864
- var CABLayoutSection = z8.object({
865
- alignment: z8.object({
866
- horizontal: z8.enum(horizontalAlignments).default(HorizontalAlignment.start),
867
- vertical: z8.enum(verticalAlignments).default(VerticalAlignment.top)
930
+ var GridItem = z9.union([z9.literal("auto"), z9.literal("fill"), z9.string().regex(/^\d+%$/), z9.number()]);
931
+ var CABLayoutSection = z9.object({
932
+ ...CABVariableFields,
933
+ alignment: z9.object({
934
+ horizontal: z9.enum(horizontalAlignments).default(HorizontalAlignment.start),
935
+ vertical: z9.enum(verticalAlignments).default(VerticalAlignment.top)
868
936
  }).default({
869
937
  horizontal: HorizontalAlignment.start,
870
938
  vertical: VerticalAlignment.top
871
939
  }),
872
- border: z8.lazy(() => CABBorder),
873
- buttonField: z8.enum(buttonFields).optional(),
874
- direction: z8.enum(directions).default(Direction.rows),
875
- grid: z8.object({
876
- columns: z8.union([z8.array(GridItem), z8.undefined()]).default(() => ["auto"]),
877
- rows: z8.union([z8.array(GridItem), z8.undefined()]).default(() => ["auto"])
940
+ border: z9.lazy(() => CABBorder),
941
+ buttonField: z9.enum(buttonFields).optional(),
942
+ direction: z9.enum(directions).default(Direction.rows),
943
+ grid: z9.object({
944
+ columns: z9.union([z9.array(GridItem), z9.undefined()]).default(() => ["auto"]),
945
+ rows: z9.union([z9.array(GridItem), z9.undefined()]).default(() => ["auto"])
878
946
  }).default({ columns: ["auto"], rows: ["auto"] }).optional(),
879
- name: z8.string().optional(),
880
- padding: z8.enum(spacings).default(Spacing.none),
881
- rule: CABRule.optional(),
882
- sectionId: z8.uuid().default(() => uuidv7()),
883
- sections: z8.union([z8.array(z8.lazy(() => CABSection)), z8.strictObject({}).transform(() => [])]).default(() => []),
884
- sectionType: z8.literal(SectionType.layout).default(SectionType.layout),
885
- spacing: z8.enum(spacings).default(Spacing.base),
947
+ name: z9.string().optional(),
948
+ padding: z9.enum(spacings).default(Spacing.none),
949
+ sectionId: z9.uuid().default(() => uuidv7()),
950
+ sections: z9.union([z9.array(z9.lazy(() => CABSection)), z9.strictObject({}).transform(() => [])]).default(() => []),
951
+ sectionType: z9.literal(SectionType.layout).default(SectionType.layout),
952
+ spacing: z9.enum(spacings).default(Spacing.base),
886
953
  /** Fire-and-forget impression pixel POSTed once when the section is shown (e.g. a Monetize offer view). */
887
- viewUrl: z8.string().optional(),
888
- width: z8.number().default(100)
954
+ viewUrl: z9.string().optional(),
955
+ width: z9.number().default(100)
889
956
  });
890
957
 
891
958
  // src/schema/widgets/checkout-and-beyond/utils.ts
@@ -955,11 +1022,11 @@ var isTextType = isSectionType(SectionType.text);
955
1022
  var isVariantsType = isSectionType(SectionType.variants);
956
1023
 
957
1024
  // src/schema/widgets/checkout-and-beyond/banner.ts
958
- var CABBannerSection = z9.lazy(
1025
+ var CABBannerSection = z10.lazy(
959
1026
  () => CABLayoutSection.omit({ sectionType: true }).extend({
960
- buttonField: z9.enum(buttonFields).optional(),
961
- color: z9.enum(bannerColors).default("info"),
962
- dismissible: z9.boolean().default(true),
1027
+ buttonField: z10.enum(buttonFields).optional(),
1028
+ color: z10.enum(bannerColors).default("info"),
1029
+ dismissible: z10.boolean().default(true),
963
1030
  /**
964
1031
  * The `s-banner` heading — localized content (a buyer can see a merchant-composed banner). Absent OR
965
1032
  * blank ⇒ no heading; the renderer emits no heading slot for `''` rather than an empty one.
@@ -975,83 +1042,83 @@ var CABBannerSection = z9.lazy(
975
1042
  * not a 500. Nothing emits `heading` yet; the first converter that maps merchant banner copy into it
976
1043
  * either strips first or teaches `normalizeTextContent` to strip this field.
977
1044
  */
978
- heading: z9.record(z9.string(), z9.string().refine(checkForHTML, NO_HTML)).optional(),
979
- sectionType: z9.literal(SectionType.banner).default(SectionType.banner)
1045
+ heading: z10.record(z10.string(), z10.string().refine(checkForHTML, NO_HTML)).optional(),
1046
+ sectionType: z10.literal(SectionType.banner).default(SectionType.banner)
980
1047
  })
981
1048
  );
982
1049
 
983
1050
  // src/schema/widgets/checkout-and-beyond/button.ts
984
1051
  import { v7 as uuidv73 } from "uuid";
985
- import { z as z11 } from "zod";
1052
+ import { z as z12 } from "zod";
986
1053
 
987
1054
  // src/schema/widgets/checkout-and-beyond/text.ts
988
1055
  import { forEach, isString as isString2 } from "es-toolkit/compat";
989
1056
  import { v7 as uuidv72 } from "uuid";
990
- import { z as z10 } from "zod";
991
- var enumOrOmit = (...vals) => z10.string().transform((val) => vals.includes(val) ? val : void 0).optional();
992
- var TiptapText = z10.object({
993
- marks: z10.union([
994
- z10.array(
995
- z10.discriminatedUnion("type", [
996
- z10.object({ type: z10.literal("bold") }),
997
- z10.object({ type: z10.literal("italic") }),
998
- z10.object({
999
- attrs: z10.object({
1000
- class: z10.string().nullable(),
1001
- href: z10.union([
1002
- z10.url(),
1003
- z10.literal("#"),
1004
- z10.string().regex(DYNAMIC_TOKEN_REGEX),
1005
- z10.string().regex(ROOT_RELATIVE_PATH_REGEX)
1057
+ import { z as z11 } from "zod";
1058
+ var enumOrOmit = (...vals) => z11.string().transform((val) => vals.includes(val) ? val : void 0).optional();
1059
+ var TiptapText = z11.object({
1060
+ marks: z11.union([
1061
+ z11.array(
1062
+ z11.discriminatedUnion("type", [
1063
+ z11.object({ type: z11.literal("bold") }),
1064
+ z11.object({ type: z11.literal("italic") }),
1065
+ z11.object({
1066
+ attrs: z11.object({
1067
+ class: z11.string().nullable(),
1068
+ href: z11.union([
1069
+ z11.url(),
1070
+ z11.literal("#"),
1071
+ z11.string().regex(DYNAMIC_TOKEN_REGEX),
1072
+ z11.string().regex(ROOT_RELATIVE_PATH_REGEX)
1006
1073
  ]),
1007
- rel: z10.string().default("noopener noreferrer nofollow"),
1008
- target: z10.string().default("_blank")
1074
+ rel: z11.string().default("noopener noreferrer nofollow"),
1075
+ target: z11.string().default("_blank")
1009
1076
  }),
1010
- type: z10.literal("link")
1077
+ type: z11.literal("link")
1011
1078
  }),
1012
- z10.object({ type: z10.literal("strike") }),
1013
- z10.object({
1014
- attrs: z10.object({
1079
+ z11.object({ type: z11.literal("strike") }),
1080
+ z11.object({
1081
+ attrs: z11.object({
1015
1082
  color: enumOrOmit(...textColorNames).default(TextColorName.base),
1016
1083
  fontSize: enumOrOmit(...textSizeNames).default(TextSizeName.base)
1017
1084
  }),
1018
- type: z10.literal("textStyle")
1085
+ type: z11.literal("textStyle")
1019
1086
  })
1020
1087
  ])
1021
1088
  ),
1022
- z10.strictObject({}).transform(() => [])
1089
+ z11.strictObject({}).transform(() => [])
1023
1090
  ]).optional(),
1024
- text: z10.string().default(""),
1025
- type: z10.literal("text").default("text")
1091
+ text: z11.string().default(""),
1092
+ type: z11.literal("text").default("text")
1026
1093
  });
1027
- var TiptapParagraph = z10.object({
1028
- attrs: z10.object({
1094
+ var TiptapParagraph = z11.object({
1095
+ attrs: z11.object({
1029
1096
  textAlign: enumOrOmit(...textAlignments)
1030
1097
  }).default({ textAlign: TextAlignment.start }),
1031
- content: z10.union([z10.array(TiptapText), z10.strictObject({}).transform(() => [])]).default(() => []),
1032
- type: z10.literal("paragraph").default("paragraph")
1098
+ content: z11.union([z11.array(TiptapText), z11.strictObject({}).transform(() => [])]).default(() => []),
1099
+ type: z11.literal("paragraph").default("paragraph")
1033
1100
  });
1034
- var TiptapDocument = z10.object({
1035
- attrs: z10.object({
1101
+ var TiptapDocument = z11.object({
1102
+ attrs: z11.object({
1036
1103
  blockSpacing: enumOrOmit(...spacings)
1037
1104
  }).default({ blockSpacing: Spacing.base }),
1038
- content: z10.union([z10.array(TiptapParagraph), z10.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
1039
- type: z10.literal("doc").default("doc")
1105
+ content: z11.union([z11.array(TiptapParagraph), z11.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
1106
+ type: z11.literal("doc").default("doc")
1040
1107
  });
1041
- var CABTextTier = z10.object({
1042
- threshold: z10.number().int().nonnegative(),
1043
- thresholds: z10.record(z10.string(), z10.number().int().nonnegative()).default(() => ({})),
1044
- tierId: z10.string().optional(),
1045
- tierType: z10.enum(progressTierTypes).default(ProgressTierType.shipping)
1108
+ var CABTextTier = z11.object({
1109
+ threshold: z11.number().int().nonnegative(),
1110
+ thresholds: z11.record(z11.string(), z11.number().int().nonnegative()).default(() => ({})),
1111
+ tierId: z11.string().optional(),
1112
+ tierType: z11.enum(progressTierTypes).default(ProgressTierType.shipping)
1046
1113
  });
1047
- var CABTextSection = z10.object({
1048
- buttonField: z10.enum(buttonFields).optional(),
1049
- content: z10.record(z10.string(), z10.union([z10.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
1050
- name: z10.string().optional(),
1051
- optionId: z10.number().optional(),
1052
- rule: CABRule.optional(),
1053
- sectionId: z10.uuid().default(() => uuidv72()),
1054
- sectionType: z10.literal(SectionType.text).default(SectionType.text),
1114
+ var CABTextSection = z11.object({
1115
+ ...CABVariableFields,
1116
+ buttonField: z11.enum(buttonFields).optional(),
1117
+ content: z11.record(z11.string(), z11.union([z11.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
1118
+ name: z11.string().optional(),
1119
+ optionId: z11.number().optional(),
1120
+ sectionId: z11.uuid().default(() => uuidv72()),
1121
+ sectionType: z11.literal(SectionType.text).default(SectionType.text),
1055
1122
  tier: CABTextTier.optional()
1056
1123
  }).superRefine(({ buttonField, content }, ctx) => {
1057
1124
  if (buttonField === ButtonField.destinationUrl && content) {
@@ -1073,35 +1140,35 @@ var CABTextSection = z10.object({
1073
1140
  });
1074
1141
 
1075
1142
  // src/schema/widgets/checkout-and-beyond/button.ts
1076
- var CABButtonContent = z11.lazy(
1077
- () => z11.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
1143
+ var CABButtonContent = z12.lazy(
1144
+ () => z12.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
1078
1145
  );
1079
- var CABButtonSection = z11.object({
1080
- action: z11.union([z11.literal(""), z11.enum(buttonActions)]).default(""),
1081
- buttonStyle: z11.enum(buttonStyles).default(ButtonStyle.primary),
1082
- custom: z11.object({
1083
- color: z11.string().regex(HEX_COLOR_REGEX).default("#005bd3"),
1084
- height: z11.number().default(52),
1085
- width: z11.number().default(300)
1146
+ var CABButtonSection = z12.object({
1147
+ ...CABVariableFields,
1148
+ action: z12.union([z12.literal(""), z12.enum(buttonActions)]).default(""),
1149
+ buttonStyle: z12.enum(buttonStyles).default(ButtonStyle.primary),
1150
+ custom: z12.object({
1151
+ color: z12.string().regex(HEX_COLOR_REGEX).default("#005bd3"),
1152
+ height: z12.number().default(52),
1153
+ width: z12.number().default(300)
1086
1154
  }).default({
1087
1155
  color: "#005bd3",
1088
1156
  height: 52,
1089
1157
  width: 300
1090
1158
  }),
1091
- disableDowngrade: z11.boolean().default(false),
1092
- name: z11.string().optional(),
1093
- optionId: z11.number().optional(),
1094
- popover: z11.object({
1095
- alignment: z11.enum(textAlignments).default(TextAlignment.center),
1096
- position: z11.enum(popoverPositions).default(PopoverPosition.blockStart)
1159
+ disableDowngrade: z12.boolean().default(false),
1160
+ name: z12.string().optional(),
1161
+ optionId: z12.number().optional(),
1162
+ popover: z12.object({
1163
+ alignment: z12.enum(textAlignments).default(TextAlignment.center),
1164
+ position: z12.enum(popoverPositions).default(PopoverPosition.blockStart)
1097
1165
  }).optional().default(() => ({
1098
1166
  alignment: TextAlignment.center,
1099
1167
  position: PopoverPosition.blockStart
1100
1168
  })),
1101
- rule: CABRule.optional(),
1102
- sectionId: z11.uuid().default(() => uuidv73()),
1103
- sections: z11.union([z11.array(CABButtonContent), z11.strictObject({}).transform(() => [])]).default(() => []),
1104
- sectionType: z11.literal(SectionType.button).default(SectionType.button),
1169
+ sectionId: z12.uuid().default(() => uuidv73()),
1170
+ sections: z12.union([z12.array(CABButtonContent), z12.strictObject({}).transform(() => [])]).default(() => []),
1171
+ sectionType: z12.literal(SectionType.button).default(SectionType.button),
1105
1172
  /**
1106
1173
  * The smart-cart tier this button acts on (`addGift`/`removeGift`): scopes the click to one tier's gift. The
1107
1174
  * client resolves the tier's gift (productId) from the progress-bar context by this `tierId` — the button node
@@ -1116,20 +1183,25 @@ var CABButtonSection = z11.object({
1116
1183
  * lookup finds no tier and the click resolves to nothing. Safe to bound — the field is new, so there are no
1117
1184
  * stored payloads to grandfather, and the producer is client code, not a merchant form.
1118
1185
  */
1119
- tier: z11.object({ tierId: z11.string().min(1) }).optional(),
1186
+ tier: z12.object({ tierId: z12.string().min(1) }).optional(),
1120
1187
  /** Fire-and-forget pixel POSTed when the button is clicked (e.g. a Monetize decline). */
1121
- trackingUrl: z11.string().optional()
1188
+ trackingUrl: z12.string().optional(),
1189
+ /**
1190
+ * Secondary effects applied to in-scope variables on click, alongside (never instead of) the primary
1191
+ * `action` — an `addToOrder` button can also flip a variable. Applied in array order.
1192
+ */
1193
+ variableEffects: z12.array(CABVariableEffect).optional()
1122
1194
  });
1123
1195
 
1124
1196
  // src/schema/widgets/checkout-and-beyond/carousel.ts
1125
- import { z as z16 } from "zod";
1197
+ import { z as z17 } from "zod";
1126
1198
 
1127
1199
  // src/schema/widgets/checkout-and-beyond/offers.ts
1128
- import { z as z15 } from "zod";
1200
+ import { z as z16 } from "zod";
1129
1201
 
1130
1202
  // src/schema/widgets/checkout-and-beyond/dataSource.ts
1131
1203
  import { v7 as uuidv74 } from "uuid";
1132
- import { z as z12 } from "zod";
1204
+ import { z as z13 } from "zod";
1133
1205
 
1134
1206
  // src/schema/widgets/checkout-and-beyond/constants.ts
1135
1207
  import { uniqBy } from "es-toolkit";
@@ -1208,72 +1280,74 @@ var widgetTypes = [
1208
1280
  var WidgetType = freezeEnum(widgetTypes);
1209
1281
 
1210
1282
  // src/schema/widgets/checkout-and-beyond/dataSource.ts
1211
- var CABDiscount = z12.object({
1212
- amount: z12.union([z12.number(), z12.string()]).catch(0),
1213
- discountedBy: z12.string().optional(),
1214
- discountedFrom: z12.enum(discountSources).optional().catch(void 0),
1215
- type: z12.enum(discountTypes).catch("none")
1283
+ var CABDiscount = z13.object({
1284
+ amount: z13.union([z13.number(), z13.string()]).catch(0),
1285
+ discountedBy: z13.string().optional(),
1286
+ discountedFrom: z13.enum(discountSources).optional().catch(void 0),
1287
+ type: z13.enum(discountTypes).catch("none")
1216
1288
  });
1217
- var CABIntegrations = z12.object({
1218
- judgeme: z12.boolean().default(false),
1219
- junip: z12.boolean().default(false),
1220
- klaviyo: z12.boolean().default(false),
1221
- loox: z12.boolean().default(false),
1222
- okendo: z12.boolean().default(false),
1223
- opinew: z12.boolean().default(false),
1224
- reviewsio: z12.boolean().default(false),
1225
- stamped: z12.boolean().default(false),
1226
- yotpo: z12.boolean().default(false)
1289
+ var CABIntegrations = z13.object({
1290
+ judgeme: z13.boolean().default(false),
1291
+ junip: z13.boolean().default(false),
1292
+ klaviyo: z13.boolean().default(false),
1293
+ loox: z13.boolean().default(false),
1294
+ okendo: z13.boolean().default(false),
1295
+ opinew: z13.boolean().default(false),
1296
+ reviewsio: z13.boolean().default(false),
1297
+ stamped: z13.boolean().default(false),
1298
+ yotpo: z13.boolean().default(false)
1227
1299
  });
1228
- var CABDataSourceSection = z12.object({
1229
- dataSourceId: z12.number().nullable().default(null),
1230
- dataSourcePath: z12.string().default(DEFAULT_ENDPOINTS[0].value),
1300
+ var CABDataSourceSection = z13.object({
1301
+ dataSourceId: z13.number().nullable().default(null),
1302
+ dataSourcePath: z13.string().default(DEFAULT_ENDPOINTS[0].value),
1231
1303
  discount: CABDiscount.optional(),
1232
1304
  integrations: CABIntegrations.optional(),
1233
- limit: z12.number().default(1),
1234
- matchVariant: z12.boolean().default(false),
1235
- matchVariantOutOfStock: z12.boolean().default(false),
1236
- name: z12.string().default(DEFAULT_ENDPOINTS[0].label),
1237
- productType: z12.enum(productTypes).optional(),
1238
- sectionId: z12.uuid().default(() => uuidv74()),
1239
- sectionType: z12.literal(SectionType.dataSource).default(SectionType.dataSource),
1305
+ limit: z13.number().default(1),
1306
+ matchVariant: z13.boolean().default(false),
1307
+ matchVariantOutOfStock: z13.boolean().default(false),
1308
+ name: z13.string().default(DEFAULT_ENDPOINTS[0].label),
1309
+ productType: z13.enum(productTypes).optional(),
1310
+ sectionId: z13.uuid().default(() => uuidv74()),
1311
+ sectionType: z13.literal(SectionType.dataSource).default(SectionType.dataSource),
1240
1312
  /** Default subscribe-vs-one-time for `productType: both` (legacy `subscription_is_default`). */
1241
- subscriptionIsDefault: z12.boolean().default(false),
1242
- treatAsGwp: z12.boolean().default(false)
1313
+ subscriptionIsDefault: z13.boolean().default(false),
1314
+ treatAsGwp: z13.boolean().default(false)
1243
1315
  });
1244
1316
 
1245
1317
  // src/schema/widgets/checkout-and-beyond/products.ts
1246
1318
  import { v7 as uuidv76 } from "uuid";
1247
- import { z as z14 } from "zod";
1319
+ import { z as z15 } from "zod";
1248
1320
 
1249
1321
  // src/schema/widgets/checkout-and-beyond/product.ts
1250
1322
  import { v7 as uuidv75 } from "uuid";
1251
- import { z as z13 } from "zod";
1252
- var CABVariantContent = z13.lazy(
1253
- () => z13.discriminatedUnion("sectionType", [CABButtonSection, CABTextSection])
1323
+ import { z as z14 } from "zod";
1324
+ var CABVariantContent = z14.lazy(
1325
+ () => z14.discriminatedUnion("sectionType", [CABButtonSection, CABTextSection])
1254
1326
  );
1255
- var CABProductSection = z13.object({
1256
- name: z13.string().optional(),
1257
- productId: z13.number().nullable().default(null),
1258
- sectionId: z13.uuid().default(() => uuidv75()),
1259
- sections: z13.union([z13.array(CABVariantContent), z13.strictObject({}).transform(() => [])]).default(() => []),
1260
- sectionType: z13.literal(SectionType.product).default(SectionType.product),
1261
- selectors: z13.record(z13.string(), z13.enum(variantSelectors).default(VariantSelector.menu)).default(() => ({})),
1262
- variantMode: z13.enum(variantModes).default(VariantMode.multiple)
1327
+ var CABProductSection = z14.object({
1328
+ ...CABVariableFields,
1329
+ name: z14.string().optional(),
1330
+ productId: z14.number().nullable().default(null),
1331
+ sectionId: z14.uuid().default(() => uuidv75()),
1332
+ sections: z14.union([z14.array(CABVariantContent), z14.strictObject({}).transform(() => [])]).default(() => []),
1333
+ sectionType: z14.literal(SectionType.product).default(SectionType.product),
1334
+ selectors: z14.record(z14.string(), z14.enum(variantSelectors).default(VariantSelector.menu)).default(() => ({})),
1335
+ variantMode: z14.enum(variantModes).default(VariantMode.multiple)
1263
1336
  });
1264
1337
 
1265
1338
  // src/schema/widgets/checkout-and-beyond/products.ts
1266
- var CABProductsSection = z14.object({
1267
- name: z14.string().optional(),
1268
- sectionId: z14.uuid().default(() => uuidv76()),
1269
- sections: z14.union([z14.array(z14.lazy(() => CABProductSection)), z14.strictObject({}).transform(() => [])]).default(() => []),
1270
- sectionType: z14.literal(SectionType.products).default(SectionType.products)
1339
+ var CABProductsSection = z15.object({
1340
+ ...CABVariableFields,
1341
+ name: z15.string().optional(),
1342
+ sectionId: z15.uuid().default(() => uuidv76()),
1343
+ sections: z15.union([z15.array(z15.lazy(() => CABProductSection)), z15.strictObject({}).transform(() => [])]).default(() => []),
1344
+ sectionType: z15.literal(SectionType.products).default(SectionType.products)
1271
1345
  });
1272
1346
 
1273
1347
  // src/schema/widgets/checkout-and-beyond/offers.ts
1274
- var CABOffersSection = z15.lazy(
1348
+ var CABOffersSection = z16.lazy(
1275
1349
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
1276
- sections: z15.union([z15.array(z15.lazy(() => CABSection)), z15.strictObject({}).transform(() => [])]).default(() => [
1350
+ sections: z16.union([z16.array(z16.lazy(() => CABSection)), z16.strictObject({}).transform(() => [])]).default(() => [
1277
1351
  CABBannerSection.parse({
1278
1352
  buttonField: "undoAddToOrder",
1279
1353
  color: "success",
@@ -1287,64 +1361,65 @@ var CABOffersSection = z15.lazy(
1287
1361
  CABDataSourceSection.parse({}),
1288
1362
  CABProductsSection.parse({})
1289
1363
  ]),
1290
- sectionType: z15.literal(SectionType.offers).default(SectionType.offers)
1364
+ sectionType: z16.literal(SectionType.offers).default(SectionType.offers)
1291
1365
  })
1292
1366
  );
1293
1367
 
1294
1368
  // src/schema/widgets/checkout-and-beyond/carousel.ts
1295
- var CABCarouselSection = z16.lazy(
1369
+ var CABCarouselSection = z17.lazy(
1296
1370
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
1297
- autoAdvanceInterval: z16.number().default(0),
1298
- itemsAtOnce: z16.number().min(1).default(1),
1371
+ autoAdvanceInterval: z17.number().default(0),
1372
+ itemsAtOnce: z17.number().min(1).default(1),
1299
1373
  /** Card arrangement for the offers child (`horizontal` = side-by-side) — NOT the carousel's own `direction`. */
1300
- offersDirection: z16.enum(offersDirections).default("vertical"),
1301
- sections: z16.union([z16.array(z16.lazy(() => CABSection)), z16.strictObject({}).transform(() => [])]).default(() => [CABOffersSection.parse({})]),
1302
- sectionType: z16.literal(SectionType.carousel).default(SectionType.carousel)
1374
+ offersDirection: z17.enum(offersDirections).default("vertical"),
1375
+ sections: z17.union([z17.array(z17.lazy(() => CABSection)), z17.strictObject({}).transform(() => [])]).default(() => [CABOffersSection.parse({})]),
1376
+ sectionType: z17.literal(SectionType.carousel).default(SectionType.carousel)
1303
1377
  })
1304
1378
  );
1305
1379
 
1306
1380
  // src/schema/widgets/checkout-and-beyond/cartLine.ts
1307
- import { z as z17 } from "zod";
1308
- var CABCartLineSection = z17.lazy(
1381
+ import { z as z18 } from "zod";
1382
+ var CABCartLineSection = z18.lazy(
1309
1383
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
1310
- sections: z17.union([z17.array(z17.lazy(() => CABSection)), z17.strictObject({}).transform(() => [])]).default(() => [CABButtonSection.parse({ action: ButtonAction.switchToSubscription })]),
1311
- sectionType: z17.literal(SectionType.cartLine).default(SectionType.cartLine)
1384
+ sections: z18.union([z18.array(z18.lazy(() => CABSection)), z18.strictObject({}).transform(() => [])]).default(() => [CABButtonSection.parse({ action: ButtonAction.switchToSubscription })]),
1385
+ sectionType: z18.literal(SectionType.cartLine).default(SectionType.cartLine)
1312
1386
  })
1313
1387
  );
1314
1388
 
1315
1389
  // src/schema/widgets/checkout-and-beyond/discount.ts
1316
1390
  import { v7 as uuidv77 } from "uuid";
1317
- import { z as z18 } from "zod";
1318
- var CABDiscountSection = z18.object({
1319
- amount: z18.union([z18.number(), z18.string()]).catch(0),
1320
- discountedBy: z18.string().optional(),
1321
- discountedFrom: z18.enum(discountSources).optional().catch(void 0),
1322
- message: z18.string().optional(),
1323
- name: z18.string().optional(),
1324
- quantity: z18.number().default(1),
1325
- sectionId: z18.uuid().default(() => uuidv77()),
1326
- sectionType: z18.literal(SectionType.discount).default(SectionType.discount),
1327
- type: z18.enum(discountTypes).catch("none")
1391
+ import { z as z19 } from "zod";
1392
+ var CABDiscountSection = z19.object({
1393
+ ...CABVariableFields,
1394
+ amount: z19.union([z19.number(), z19.string()]).catch(0),
1395
+ discountedBy: z19.string().optional(),
1396
+ discountedFrom: z19.enum(discountSources).optional().catch(void 0),
1397
+ message: z19.string().optional(),
1398
+ name: z19.string().optional(),
1399
+ quantity: z19.number().default(1),
1400
+ sectionId: z19.uuid().default(() => uuidv77()),
1401
+ sectionType: z19.literal(SectionType.discount).default(SectionType.discount),
1402
+ type: z19.enum(discountTypes).catch("none")
1328
1403
  });
1329
1404
 
1330
1405
  // src/schema/widgets/checkout-and-beyond/monetize.ts
1331
1406
  import { v7 as uuidv78 } from "uuid";
1332
- import { z as z19 } from "zod";
1333
- var CABMonetizeSection = z19.object({
1334
- name: z19.string().optional(),
1407
+ import { z as z20 } from "zod";
1408
+ var CABMonetizeSection = z20.object({
1409
+ ...CABVariableFields,
1410
+ name: z20.string().optional(),
1335
1411
  /** Privacy Policy footer href (the widget's `privacy_policy_url` setting); the client relays it to `/cab/monetize`. */
1336
- privacyPolicyUrl: z19.string().optional(),
1337
- rule: CABRule.optional(),
1338
- sectionId: z19.uuid().default(() => uuidv78()),
1339
- sectionType: z19.literal(SectionType.monetize).default(SectionType.monetize),
1412
+ privacyPolicyUrl: z20.string().optional(),
1413
+ sectionId: z20.uuid().default(() => uuidv78()),
1414
+ sectionType: z20.literal(SectionType.monetize).default(SectionType.monetize),
1340
1415
  /** Ads-taxonomy sub-vertical id (the widget's `sub_vertical` setting); paired with `vertical`. */
1341
- subVertical: z19.string().optional(),
1416
+ subVertical: z20.string().optional(),
1342
1417
  /** Ads-taxonomy vertical id (the widget's `vertical` setting) — with `subVertical`, the admin Monetize editor's two configurables. */
1343
- vertical: z19.string().optional()
1418
+ vertical: z20.string().optional()
1344
1419
  });
1345
1420
 
1346
1421
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1347
- import { z as z20 } from "zod";
1422
+ import { z as z21 } from "zod";
1348
1423
 
1349
1424
  // src/schema/widgets/checkout-and-beyond/giftLabels.ts
1350
1425
  var GIFT_LABELS = {
@@ -1463,21 +1538,21 @@ var GIFT_LABELS = {
1463
1538
  };
1464
1539
 
1465
1540
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1466
- var CABProgressTier = z20.object({
1541
+ var CABProgressTier = z21.object({
1467
1542
  /**
1468
1543
  * Order-discount tiers only (onsite `discount`): the reward the order-discount Function applies at
1469
1544
  * cart time, carried so the client can resolve the `{{discountAmount}}` token in this tier's copy.
1470
1545
  * `fixedAmount`: shop-currency CENTS (FX-scaled by the client, like {@link CABProgressTier.threshold});
1471
1546
  * `percentage`: the whole-percent number rendered raw (`{n}%`). Absent on non-discount tiers.
1472
1547
  */
1473
- discount: z20.object({ amount: z20.number().nonnegative(), type: z20.enum(["fixedAmount", "percentage"]) }).optional(),
1548
+ discount: z21.object({ amount: z21.number().nonnegative(), type: z21.enum(["fixedAmount", "percentage"]) }).optional(),
1474
1549
  /**
1475
1550
  * Smart-cart product (gift) tiers only (onsite `filter_oos_variants`): when set, the client drops this
1476
1551
  * tier entirely once its gift has NO in-stock eligible variant — the milestone, fill slot and gift
1477
1552
  * controls all disappear, mirroring onsite removing the tier from `bar.tiers` before it renders. Absent
1478
1553
  * on shipping/discount/decorative tiers and left off by default (the tier renders regardless of stock).
1479
1554
  */
1480
- filterOosVariants: z20.boolean().default(false),
1555
+ filterOosVariants: z21.boolean().default(false),
1481
1556
  /**
1482
1557
  * Smart-cart product (gift) tiers only: the reward unlocked at this tier. The client enriches
1483
1558
  * `productId`/`variantIds` to live variants (availability, price) and adds the chosen one to the cart
@@ -1485,10 +1560,10 @@ var CABProgressTier = z20.object({
1485
1560
  * tiers and on tiers with no configured product. Cart add/remove is a later stage; carried here so the
1486
1561
  * tree is complete.
1487
1562
  */
1488
- gift: z20.object({
1489
- productId: z20.number().int().positive(),
1490
- title: z20.string().optional(),
1491
- variantIds: z20.array(z20.number().int().positive()).default(() => [])
1563
+ gift: z21.object({
1564
+ productId: z21.number().int().positive(),
1565
+ title: z21.string().optional(),
1566
+ variantIds: z21.array(z21.number().int().positive()).default(() => [])
1492
1567
  }).optional(),
1493
1568
  /**
1494
1569
  * The step-row label at this tier's slot (onsite `getTierLabel`): the merchant custom label, else the
@@ -1499,35 +1574,35 @@ var CABProgressTier = z20.object({
1499
1574
  * turns a blank label into an absent key, and a client-authored blank means the same thing — the renderer
1500
1575
  * emits no caption slot rather than an empty one). Plain text — a compact icon+label.
1501
1576
  */
1502
- label: z20.record(z20.string(), z20.string()).optional(),
1577
+ label: z21.record(z21.string(), z21.string()).optional(),
1503
1578
  /**
1504
1579
  * Smart-cart product (gift) tiers only (onsite `product_tier_image`): show the gift's product image in
1505
1580
  * the step-row slot instead of the generic bag icon. The converter can't supply the image URL (config
1506
1581
  * carries only product IDs), so the client resolves it (authoritative Shopify featured image, React
1507
1582
  * parity) and falls back to the bag icon when the flag is off or no image resolves. Default false.
1508
1583
  */
1509
- productTierImage: z20.boolean().default(false),
1584
+ productTierImage: z21.boolean().default(false),
1510
1585
  /**
1511
1586
  * The tier's goal, measured per `unit`. `currency` (default): SHOP-currency cents — the canonical
1512
1587
  * fallback: when the buyer's presentment currency has no entry in `thresholds`, the client
1513
1588
  * multiplies this by the live FX rate (converter maps the v1 `unlock_price`, e.g. `75` → `7500`).
1514
1589
  * `item`: a raw item count — no cents, no FX, no `thresholds` overrides.
1515
1590
  */
1516
- threshold: z20.number().int().nonnegative(),
1591
+ threshold: z21.number().int().nonnegative(),
1517
1592
  /**
1518
1593
  * Per-presentment-currency goal overrides — lowercased ISO currency code → cents (e.g. `{ cad: 9900 }`).
1519
1594
  * When the buyer's currency has an entry, the client uses it verbatim INSTEAD of FX-converting
1520
1595
  * `threshold`, so merchants show intentional, clean per-market amounts (Shopify Markets) rather than a
1521
1596
  * converted base. Defaults to `{}` — no overrides means always fall back to `threshold`.
1522
1597
  */
1523
- thresholds: z20.record(z20.string(), z20.number().int().nonnegative()).default(() => ({})),
1598
+ thresholds: z21.record(z21.string(), z21.number().int().nonnegative()).default(() => ({})),
1524
1599
  /**
1525
1600
  * Smart-cart tier identifier, mirrored onto the gift cart line's `_tier` attribute so the client can
1526
1601
  * match an in-cart gift back to its tier (add on reach, remove on downgrade/decline). Absent on the
1527
1602
  * shipping bar (single unlabeled tier, no gift).
1528
1603
  */
1529
- tierId: z20.string().optional(),
1530
- tierType: z20.enum(progressTierTypes).default(ProgressTierType.shipping),
1604
+ tierId: z21.string().optional(),
1605
+ tierType: z21.enum(progressTierTypes).default(ProgressTierType.shipping),
1531
1606
  /**
1532
1607
  * What this tier's progress is measured in — PER TIER (onsite's `unlock_condition_type` model, NOT
1533
1608
  * the React port's bar-level `tiers[0]` shortcut). `currency` compares money cents against the
@@ -1538,9 +1613,9 @@ var CABProgressTier = z20.object({
1538
1613
  * count carries no injected noun (no English `item`/`items` inflection on localized copy); merchant
1539
1614
  * template text supplies grammatically-neutral wording around the token.
1540
1615
  */
1541
- unit: z20.enum(progressTierUnits).default(ProgressTierUnit.currency)
1616
+ unit: z21.enum(progressTierUnits).default(ProgressTierUnit.currency)
1542
1617
  });
1543
- var CABProgressBarSection = z20.lazy(
1618
+ var CABProgressBarSection = z21.lazy(
1544
1619
  () => CABLayoutSection.omit({ sectionType: true }).extend({
1545
1620
  /**
1546
1621
  * The onsite bar id (smart-cart TPB bars only). The client mirrors it to the cart's `_barId` attribute
@@ -1549,35 +1624,35 @@ var CABProgressBarSection = z20.lazy(
1549
1624
  * checkout reaches the extension without it, so the client writes it or the tier gift's 100% discount
1550
1625
  * (and any tier order discount) never applies. Absent on the v1 shipping bar (no gift tiers, no id).
1551
1626
  */
1552
- barId: z20.string().optional(),
1627
+ barId: z21.string().optional(),
1553
1628
  /** Empty = shown everywhere; otherwise uppercase ISO country codes. */
1554
- countryCodes: z20.array(z20.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1629
+ countryCodes: z21.array(z21.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1555
1630
  /**
1556
1631
  * Uppercase ISO codes where a higher-precedence geo bar applies, so this (default, non-geo) bar is
1557
1632
  * hidden there — replicates React `getbar`'s geo-match-over-default precedence. Empty = never excluded.
1558
1633
  */
1559
- excludeCountryCodes: z20.array(z20.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1634
+ excludeCountryCodes: z21.array(z21.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1560
1635
  /**
1561
1636
  * Measure progress against the PRE-discount subtotal (onsite `exclude_discount_in_subtotal`, and
1562
1637
  * forced on for bars with a discount tier so its own reward can't un-reach the tier). The client
1563
1638
  * adds the cart's discount allocations back to the live subtotal.
1564
1639
  */
1565
- excludeDiscountInSubtotal: z20.boolean().default(false),
1640
+ excludeDiscountInSubtotal: z21.boolean().default(false),
1566
1641
  /** Variant ids the client subtracts from the adjusted subtotal (React `bar.excluded_products`). */
1567
- excludedVariantIds: z20.array(z20.number().int().positive()).default(() => []),
1642
+ excludedVariantIds: z21.array(z21.number().int().positive()).default(() => []),
1568
1643
  /**
1569
1644
  * When the cart holds a subscription item, treat the bar as reached regardless of subtotal (React
1570
1645
  * `free_shipping_on_subscription(s)`). `freeShippingOnAll` is already a zero-threshold tier instead.
1571
1646
  */
1572
- freeShippingOnSubscription: z20.boolean().default(false),
1647
+ freeShippingOnSubscription: z21.boolean().default(false),
1573
1648
  /** Localized heading over the gift controls (onsite `gift_area_title`, default 'FREE GIFTS'). */
1574
- giftAreaTitle: z20.record(z20.string(), z20.string()).default(() => ({ en: "FREE GIFTS" })),
1649
+ giftAreaTitle: z21.record(z21.string(), z21.string()).default(() => ({ en: "FREE GIFTS" })),
1575
1650
  /** Localized gift-control labels (add/remove/heading); a tier's gift `title` beats `yourGift`. */
1576
- giftLabels: z20.object({
1577
- addGift: z20.record(z20.string(), z20.string()).default(() => ({ ...GIFT_LABELS.addGift })),
1578
- remove: z20.record(z20.string(), z20.string()).default(() => ({ ...GIFT_LABELS.remove })),
1579
- selectOptions: z20.record(z20.string(), z20.string()).default(() => ({ ...GIFT_LABELS.selectOptions })),
1580
- yourGift: z20.record(z20.string(), z20.string()).default(() => ({ ...GIFT_LABELS.yourGift }))
1651
+ giftLabels: z21.object({
1652
+ addGift: z21.record(z21.string(), z21.string()).default(() => ({ ...GIFT_LABELS.addGift })),
1653
+ remove: z21.record(z21.string(), z21.string()).default(() => ({ ...GIFT_LABELS.remove })),
1654
+ selectOptions: z21.record(z21.string(), z21.string()).default(() => ({ ...GIFT_LABELS.selectOptions })),
1655
+ yourGift: z21.record(z21.string(), z21.string()).default(() => ({ ...GIFT_LABELS.yourGift }))
1581
1656
  }).default(() => ({
1582
1657
  addGift: { ...GIFT_LABELS.addGift },
1583
1658
  remove: { ...GIFT_LABELS.remove },
@@ -1585,37 +1660,38 @@ var CABProgressBarSection = z20.lazy(
1585
1660
  yourGift: { ...GIFT_LABELS.yourGift }
1586
1661
  })),
1587
1662
  /** The bar's a11y label; the merchant names it in the editor, else this default (React parity). */
1588
- name: z20.string().default("Order progress"),
1663
+ name: z21.string().default("Order progress"),
1589
1664
  /**
1590
1665
  * Bar fill color. An explicit (widget-authored) value is used verbatim; when absent the server
1591
1666
  * fills it with the live shop theme's `buttonBackground` (React `useRebuyTheme` parity). Still
1592
1667
  * absent after that ⇒ the theme fetch failed and the client renders its platform-default bar —
1593
1668
  * optional, not defaulted, so "merchant chose no color" stays distinguishable from any real value.
1594
1669
  */
1595
- progressColor: z20.string().optional(),
1596
- sectionType: z20.literal(SectionType.progressBar).default(SectionType.progressBar),
1670
+ progressColor: z21.string().optional(),
1671
+ sectionType: z21.literal(SectionType.progressBar).default(SectionType.progressBar),
1597
1672
  /**
1598
1673
  * The bar's milestones in the merchant's CONFIGURED order — the renderer does NOT sort them (022
1599
1674
  * O-B2: sorting by resolved threshold reversed configured milestones on out-of-order or mixed-unit
1600
1675
  * count-vs-cents bars). Drives the fill (even slot per tier) and, for smart-cart product tiers, the
1601
1676
  * gift add/remove. The visual tier display lives in `sections` (composable), NOT here.
1602
1677
  */
1603
- tiers: z20.union([z20.array(CABProgressTier), z20.strictObject({}).transform(() => [])]).default(() => [])
1678
+ tiers: z21.union([z21.array(CABProgressTier), z21.strictObject({}).transform(() => [])]).default(() => [])
1604
1679
  })
1605
1680
  );
1606
1681
 
1607
1682
  // src/schema/widgets/checkout-and-beyond/quantity.ts
1608
1683
  import { v7 as uuidv79 } from "uuid";
1609
- import { z as z21 } from "zod";
1610
- var CABQuantitySection = z21.object({
1611
- errorMessages: z21.record(
1612
- z21.string(),
1613
- z21.object({
1684
+ import { z as z22 } from "zod";
1685
+ var CABQuantitySection = z22.object({
1686
+ ...CABVariableFields,
1687
+ errorMessages: z22.record(
1688
+ z22.string(),
1689
+ z22.object({
1614
1690
  /** `{{step}}` is interpolated at render — the off-increment message React never gave a merchant key. */
1615
- increment: z21.string().optional(),
1616
- max: z21.string().optional(),
1617
- min: z21.string().optional(),
1618
- neg: z21.string().optional()
1691
+ increment: z22.string().optional(),
1692
+ max: z22.string().optional(),
1693
+ min: z22.string().optional(),
1694
+ neg: z22.string().optional()
1619
1695
  })
1620
1696
  ).default({
1621
1697
  en: {
@@ -1625,19 +1701,18 @@ var CABQuantitySection = z21.object({
1625
1701
  neg: "Quantity cannot be negative"
1626
1702
  }
1627
1703
  }),
1628
- inputType: z21.enum(quantityInputs).default(QuantityInput.select),
1629
- max: z21.number().min(1).max(100).default(10),
1630
- min: z21.number().min(1).default(1),
1704
+ inputType: z22.enum(quantityInputs).default(QuantityInput.select),
1705
+ max: z22.number().min(1).max(100).default(10),
1706
+ min: z22.number().min(1).default(1),
1631
1707
  /** The a11y label for the quantity control; the merchant names it in the editor, else this default. */
1632
- name: z21.string().default("Quantity"),
1633
- rule: CABRule.optional(),
1634
- sectionId: z21.uuid().default(() => uuidv79()),
1635
- sectionType: z21.literal(SectionType.quantity).default(SectionType.quantity)
1708
+ name: z22.string().default("Quantity"),
1709
+ sectionId: z22.uuid().default(() => uuidv79()),
1710
+ sectionType: z22.literal(SectionType.quantity).default(SectionType.quantity)
1636
1711
  });
1637
1712
 
1638
1713
  // src/schema/widgets/checkout-and-beyond/reviews.ts
1639
1714
  import { v7 as uuidv710 } from "uuid";
1640
- import { z as z22 } from "zod";
1715
+ import { z as z23 } from "zod";
1641
1716
 
1642
1717
  // src/schema/widgets/checkout-and-beyond/reviewLabels.ts
1643
1718
  var REVIEW_LABELS = {
@@ -1700,50 +1775,50 @@ var REVIEW_LABELS = {
1700
1775
  };
1701
1776
 
1702
1777
  // src/schema/widgets/checkout-and-beyond/reviews.ts
1703
- var CABReviewsSection = z22.object({
1704
- color: z22.string().default("#fadb14"),
1778
+ var CABReviewsSection = z23.object({
1779
+ ...CABVariableFields,
1780
+ color: z23.string().default("#fadb14"),
1705
1781
  /**
1706
1782
  * Localized review-count templates (`{{reviewCount}}`), one/other plural forms; the client picks the
1707
1783
  * form via `Intl.PluralRules`. Defaults here (schema-first) so every tree localizes without converter
1708
1784
  * or merchant work.
1709
1785
  */
1710
- countLabels: z22.object({
1711
- one: z22.record(z22.string(), z22.string()).default(() => ({ ...REVIEW_LABELS.one })),
1712
- other: z22.record(z22.string(), z22.string()).default(() => ({ ...REVIEW_LABELS.other }))
1786
+ countLabels: z23.object({
1787
+ one: z23.record(z23.string(), z23.string()).default(() => ({ ...REVIEW_LABELS.one })),
1788
+ other: z23.record(z23.string(), z23.string()).default(() => ({ ...REVIEW_LABELS.other }))
1713
1789
  }).default(() => ({ one: { ...REVIEW_LABELS.one }, other: { ...REVIEW_LABELS.other } })),
1714
- name: z22.string().optional(),
1715
- rule: CABRule.optional(),
1716
- sectionId: z22.uuid().default(() => uuidv710()),
1717
- sectionType: z22.literal(SectionType.reviews).default(SectionType.reviews),
1718
- size: z22.enum(reviewsSizes).default(ReviewsSize.default)
1790
+ name: z23.string().optional(),
1791
+ sectionId: z23.uuid().default(() => uuidv710()),
1792
+ sectionType: z23.literal(SectionType.reviews).default(SectionType.reviews),
1793
+ size: z23.enum(reviewsSizes).default(ReviewsSize.default)
1719
1794
  });
1720
1795
 
1721
1796
  // src/schema/widgets/checkout-and-beyond/variants.ts
1722
1797
  import { slice } from "es-toolkit/compat";
1723
1798
  import { v7 as uuidv711 } from "uuid";
1724
- import { z as z23 } from "zod";
1725
- var CABVariantsSection = z23.object({
1726
- hideOutOfStockVariants: z23.boolean().default(false),
1727
- name: z23.string().optional(),
1728
- rule: CABRule.optional(),
1729
- sectionId: z23.uuid().default(() => uuidv711()),
1730
- sectionType: z23.literal(SectionType.variants).default(SectionType.variants),
1731
- selector: z23.enum(slice(variantSelectors, 0, 3)).default(VariantSelector.menu),
1732
- variantMode: z23.enum(variantModes).default(VariantMode.multiple)
1799
+ import { z as z24 } from "zod";
1800
+ var CABVariantsSection = z24.object({
1801
+ ...CABVariableFields,
1802
+ hideOutOfStockVariants: z24.boolean().default(false),
1803
+ name: z24.string().optional(),
1804
+ sectionId: z24.uuid().default(() => uuidv711()),
1805
+ sectionType: z24.literal(SectionType.variants).default(SectionType.variants),
1806
+ selector: z24.enum(slice(variantSelectors, 0, 3)).default(VariantSelector.menu),
1807
+ variantMode: z24.enum(variantModes).default(VariantMode.multiple)
1733
1808
  });
1734
1809
 
1735
1810
  // src/schema/widgets/checkout-and-beyond/shared.ts
1736
- var CABBorder = z24.object({
1737
- radius: z24.enum(borderRadii).default(BorderRadius.base),
1738
- style: z24.enum(borderStyles).default(BorderStyle.none),
1739
- width: z24.enum(borderWidths).default(BorderWidth.base)
1811
+ var CABBorder = z25.object({
1812
+ radius: z25.enum(borderRadii).default(BorderRadius.base),
1813
+ style: z25.enum(borderStyles).default(BorderStyle.none),
1814
+ width: z25.enum(borderWidths).default(BorderWidth.base)
1740
1815
  }).default({
1741
1816
  radius: BorderRadius.base,
1742
1817
  style: BorderStyle.none,
1743
1818
  width: BorderWidth.base
1744
1819
  });
1745
- var CABSection = z24.lazy(
1746
- () => z24.discriminatedUnion("sectionType", [
1820
+ var CABSection = z25.lazy(
1821
+ () => z25.discriminatedUnion("sectionType", [
1747
1822
  CABBannerSection,
1748
1823
  CABButtonSection,
1749
1824
  CABCarouselSection,
@@ -1765,16 +1840,17 @@ var CABSection = z24.lazy(
1765
1840
  );
1766
1841
 
1767
1842
  // src/schema/widgets/checkout-and-beyond/image.ts
1768
- var CABImageSectionFields = z25.object({
1769
- altText: z25.string().refine(checkForHTML, NO_HTML).default(""),
1843
+ var CABImageSectionFields = z26.object({
1844
+ ...CABVariableFields,
1845
+ altText: z26.string().refine(checkForHTML, NO_HTML).default(""),
1770
1846
  /**
1771
1847
  * Image width÷height (e.g. `46` for the progress-bar fill); `null` renders at natural size. Any POSITIVE
1772
1848
  * ratio — never limited to 1, but never `0`/negative either: a renderer dividing by it would get `Infinity`,
1773
1849
  * and CSS `aspect-ratio` drops a negative value and silently reverts to natural size.
1774
1850
  */
1775
- aspectRatio: z25.number().positive().nullable().default(null),
1776
- border: z25.lazy(() => CABBorder),
1777
- buttonField: z25.enum(buttonFields).optional(),
1851
+ aspectRatio: z26.number().positive().nullable().default(null),
1852
+ border: z26.lazy(() => CABBorder),
1853
+ buttonField: z26.enum(buttonFields).optional(),
1778
1854
  /**
1779
1855
  * `icon` renders `source` as a single `s-icon` by name (the uber-image path covers icons too), reading
1780
1856
  * `iconSize`/`iconTone`. The other values are a harmless informational holdover from the previous
@@ -1793,30 +1869,29 @@ var CABImageSectionFields = z25.object({
1793
1869
  * behavior degraded gracefully and told us about it. The client-assembled half of the invariant was never
1794
1870
  * the risky half.
1795
1871
  */
1796
- category: z25.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
1872
+ category: z26.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
1797
1873
  /** `icon`-mode only: the `s-icon` `size`; `null` ⇒ the component default (`base`). Ignored by image treatments. */
1798
- iconSize: z25.enum(iconSizes).nullable().default(null),
1874
+ iconSize: z26.enum(iconSizes).nullable().default(null),
1799
1875
  /** `icon`-mode only: the `s-icon` `tone`; `null` ⇒ the component default (`auto`). Ignored by image treatments. */
1800
- iconTone: z25.enum(iconTones).nullable().default(null),
1801
- name: z25.string().optional(),
1802
- naturalHeight: z25.number().default(0),
1803
- naturalWidth: z25.number().default(0),
1876
+ iconTone: z26.enum(iconTones).nullable().default(null),
1877
+ name: z26.string().optional(),
1878
+ naturalHeight: z26.number().default(0),
1879
+ naturalWidth: z26.number().default(0),
1804
1880
  /**
1805
1881
  * `contain` (the component default): dimensionless images render in s-image's 1/1 default frame, and
1806
1882
  * `cover` would crop non-square art (payment badges lost their edges — 15993); `contain` letterboxes.
1807
1883
  */
1808
- objectFit: z25.enum(objectFits).default(ObjectFit.contain),
1809
- rule: CABRule.optional(),
1810
- sectionId: z25.uuid().default(() => uuidv712()),
1811
- sectionType: z25.literal(SectionType.image).default(SectionType.image),
1884
+ objectFit: z26.enum(objectFits).default(ObjectFit.contain),
1885
+ sectionId: z26.uuid().default(() => uuidv712()),
1886
+ sectionType: z26.literal(SectionType.image).default(SectionType.image),
1812
1887
  /**
1813
1888
  * An image URL or dynamic token, an empty default, or — when `category: 'icon'` — an icon NAME. Icon mode
1814
1889
  * takes a name or `''` only, NOT a token: no renderer resolves a token to an icon today, so accepting one
1815
1890
  * would promise a capability that doesn't exist. Widen the refine's carve-out to `DYNAMIC_TOKEN_REGEX` when a
1816
1891
  * server-chosen tier icon actually needs it.
1817
1892
  */
1818
- source: z25.union([z25.url(), z25.literal(""), z25.string().regex(DYNAMIC_TOKEN_REGEX), z25.enum(iconNames)]).default(""),
1819
- width: z25.number().default(100)
1893
+ source: z26.union([z26.url(), z26.literal(""), z26.string().regex(DYNAMIC_TOKEN_REGEX), z26.enum(iconNames)]).default(""),
1894
+ width: z26.number().default(100)
1820
1895
  });
1821
1896
  var iconNameSet = new Set(iconNames);
1822
1897
  var isIconName = (source) => iconNameSet.has(source);
@@ -1966,7 +2041,7 @@ var convertContentBlockTextToV2 = (language) => {
1966
2041
  };
1967
2042
 
1968
2043
  // src/schema/widgets/checkout-and-beyond/root.ts
1969
- import { z as z26 } from "zod";
2044
+ import { z as z27 } from "zod";
1970
2045
 
1971
2046
  // src/schema/widgets/checkout-and-beyond/uiLabels.ts
1972
2047
  var UI_LABELS = {
@@ -1982,8 +2057,8 @@ var UI_LABELS = {
1982
2057
  };
1983
2058
 
1984
2059
  // src/schema/widgets/checkout-and-beyond/root.ts
1985
- var localized = (fallback) => z26.record(z26.string(), z26.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
1986
- var CABUILabels = z26.object({
2060
+ var localized = (fallback) => z27.record(z27.string(), z27.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
2061
+ var CABUILabels = z27.object({
1987
2062
  currentPage: localized(UI_LABELS.currentPage),
1988
2063
  loadingOptions: localized(UI_LABELS.loadingOptions),
1989
2064
  nextPage: localized(UI_LABELS.nextPage),
@@ -2004,37 +2079,37 @@ var CABUILabels = z26.object({
2004
2079
  subscriptionOptions: { ...UI_LABELS.subscriptionOptions },
2005
2080
  updating: { ...UI_LABELS.updating }
2006
2081
  }));
2007
- var TargetArea = z26.object({
2008
- fill: z26.boolean().optional(),
2009
- flip: z26.enum(["both", "horizontal", "vertical"]).optional(),
2010
- icon: z26.string(),
2011
- label: z26.string(),
2012
- width: z26.string()
2082
+ var TargetArea = z27.object({
2083
+ fill: z27.boolean().optional(),
2084
+ flip: z27.enum(["both", "horizontal", "vertical"]).optional(),
2085
+ icon: z27.string(),
2086
+ label: z27.string(),
2087
+ width: z27.string()
2013
2088
  }).default(targetAreas[EditorMode.checkoutExtension][1]);
2014
- var CABTracking = z26.object({
2015
- enableAttribution: z26.boolean().nullish().transform((value) => value ?? true),
2016
- enableSource: z26.boolean().nullish().transform((value) => value ?? true),
2017
- enableWidget: z26.boolean().nullish().transform((value) => value ?? true)
2089
+ var CABTracking = z27.object({
2090
+ enableAttribution: z27.boolean().nullish().transform((value) => value ?? true),
2091
+ enableSource: z27.boolean().nullish().transform((value) => value ?? true),
2092
+ enableWidget: z27.boolean().nullish().transform((value) => value ?? true)
2018
2093
  }).nullish().transform((value) => value ?? { enableAttribution: true, enableSource: true, enableWidget: true });
2019
- var CABExperiment = z26.object({
2020
- elementId: z26.number(),
2021
- experimentId: z26.number(),
2022
- experimentType: z26.string(),
2023
- selectedId: z26.number()
2094
+ var CABExperiment = z27.object({
2095
+ elementId: z27.number(),
2096
+ experimentId: z27.number(),
2097
+ experimentType: z27.string(),
2098
+ selectedId: z27.number()
2024
2099
  });
2025
2100
  var CABRootSection = CABLayoutSection.extend({
2026
- editorMode: z26.enum(editorModes).default(EditorMode.checkoutExtension),
2101
+ editorMode: z27.enum(editorModes).default(EditorMode.checkoutExtension),
2027
2102
  experiment: CABExperiment.optional(),
2028
2103
  // Same rule as CABTracking above: the v1 converters pass raw legacy `previewMode` through, so a
2029
2104
  // `null` must fall back rather than throw the widget; malformed values still throw.
2030
- previewMode: z26.boolean().nullish().transform((value) => value ?? false),
2031
- storeId: z26.number().nullable().default(null),
2105
+ previewMode: z27.boolean().nullish().transform((value) => value ?? false),
2106
+ storeId: z27.number().nullable().default(null),
2032
2107
  targetArea: TargetArea.nullable(),
2033
2108
  tracking: CABTracking,
2034
- type: z26.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
2109
+ type: z27.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
2035
2110
  uiLabels: CABUILabels,
2036
- version: z26.literal(2).default(2),
2037
- widgetId: z26.number().nullable().default(null)
2111
+ version: z27.literal(2).default(2),
2112
+ widgetId: z27.number().nullable().default(null)
2038
2113
  });
2039
2114
 
2040
2115
  // src/transforms/v1Location.ts
@@ -3188,6 +3263,7 @@ var convertOfferToV2 = ({ id, name, settings }) => {
3188
3263
  sectionType: "carousel"
3189
3264
  };
3190
3265
  return CABRootSection.parse({
3266
+ alignment: { horizontal: "center", vertical: "top" },
3191
3267
  direction: "rows",
3192
3268
  editorMode: LOCATION_TO_EDITOR_MODE[settings.location ?? "checkout"],
3193
3269
  // The widget name is required by the admin save schema; carry the legacy widget's name through.
@@ -3876,7 +3952,7 @@ var validateGifts = async (input, ctx) => {
3876
3952
  };
3877
3953
 
3878
3954
  // src/server/adsEngine.ts
3879
- import { z as z27 } from "zod";
3955
+ import { z as z28 } from "zod";
3880
3956
  var SUPPLY_KEY = { production: "AQF5RKLR", staging: "Z56LQ7PS" };
3881
3957
  var OFFER_LIMIT = 4;
3882
3958
  var SUPPORTED_COUNTRIES = /* @__PURE__ */ new Set(["US", "CA"]);
@@ -3889,20 +3965,20 @@ var transactionItems = (input) => (input.transactionItems?.map(({ id, priceCents
3889
3965
  title,
3890
3966
  type
3891
3967
  })) ?? input.cart.items.map(({ productId, quantity }) => ({ id: productId, quantity }))).slice(0, MAX_TRANSACTION_ITEMS);
3892
- var AdsEngineOffer = z27.object({
3893
- click_url: z27.string(),
3894
- cta: z27.string(),
3968
+ var AdsEngineOffer = z28.object({
3969
+ click_url: z28.string(),
3970
+ cta: z28.string(),
3895
3971
  /** `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'). */
3896
- decline_cta: z27.string().catch(""),
3897
- decline_url: z27.string(),
3898
- description: z27.string(),
3899
- headline: z27.string(),
3900
- id: z27.string(),
3901
- image_url: z27.string().optional(),
3902
- view_url: z27.string()
3972
+ decline_cta: z28.string().catch(""),
3973
+ decline_url: z28.string(),
3974
+ description: z28.string(),
3975
+ headline: z28.string(),
3976
+ id: z28.string(),
3977
+ image_url: z28.string().optional(),
3978
+ view_url: z28.string()
3903
3979
  });
3904
- var AdsEngineResponse = z27.object({
3905
- offers: z27.array(z27.unknown()).default([]).transform(
3980
+ var AdsEngineResponse = z28.object({
3981
+ offers: z28.array(z28.unknown()).default([]).transform(
3906
3982
  (offers) => offers.flatMap((offer) => {
3907
3983
  const result = AdsEngineOffer.safeParse(offer);
3908
3984
  return result.success ? [result.data] : [];
@@ -4217,7 +4293,7 @@ var postAnalyticsEvents = async (input, ctx) => {
4217
4293
  };
4218
4294
 
4219
4295
  // src/server/requestSchemas.ts
4220
- import { z as z28 } from "zod";
4296
+ import { z as z29 } from "zod";
4221
4297
  var REQUEST_BOUNDS = {
4222
4298
  /** Cart-level attributes per cart. */
4223
4299
  CART_ATTRIBUTES_MAX: 100,
@@ -4248,50 +4324,50 @@ var REQUEST_BOUNDS = {
4248
4324
  /** Rich ads transaction lines — the engine's ads contract. */
4249
4325
  TRANSACTION_ITEMS_MAX: 50
4250
4326
  };
4251
- var KeyValue = z28.object({
4252
- key: z28.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
4253
- value: z28.string().max(REQUEST_BOUNDS.STRING_VALUE_MAX).optional()
4327
+ var KeyValue = z29.object({
4328
+ key: z29.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
4329
+ value: z29.string().max(REQUEST_BOUNDS.STRING_VALUE_MAX).optional()
4254
4330
  });
4255
- var CartLineInputSchema = z28.object({
4256
- productId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4257
- properties: z28.array(KeyValue).max(REQUEST_BOUNDS.LINE_PROPERTIES_MAX).optional(),
4258
- quantity: z28.number(),
4259
- subscriptionId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4260
- variantId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX)
4331
+ var CartLineInputSchema = z29.object({
4332
+ productId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4333
+ properties: z29.array(KeyValue).max(REQUEST_BOUNDS.LINE_PROPERTIES_MAX).optional(),
4334
+ quantity: z29.number(),
4335
+ subscriptionId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4336
+ variantId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX)
4261
4337
  });
4262
- var CartInputSchema = z28.object({
4263
- attributes: z28.array(KeyValue).max(REQUEST_BOUNDS.CART_ATTRIBUTES_MAX).optional(),
4338
+ var CartInputSchema = z29.object({
4339
+ attributes: z29.array(KeyValue).max(REQUEST_BOUNDS.CART_ATTRIBUTES_MAX).optional(),
4264
4340
  /**
4265
4341
  * Presentment-per-shop-currency FX rate (buyer price ÷ shop price, e.g. `1.35` for a USD shop
4266
4342
  * selling in CAD). Money rule thresholds are authored in SHOP currency, so the engine subtotal is
4267
4343
  * divided by this before evaluation. Omit (or send 1) when the cart is already in the shop's currency.
4268
4344
  */
4269
- currencyRate: z28.number().optional(),
4345
+ currencyRate: z29.number().optional(),
4270
4346
  /** Applied discount codes; the engine evaluates `discount_code` rules against them (sent as `[{code}]`). */
4271
- discountCodes: z28.array(z28.string().max(REQUEST_BOUNDS.STRING_KEY_MAX)).max(REQUEST_BOUNDS.DISCOUNT_CODES_MAX).optional(),
4347
+ discountCodes: z29.array(z29.string().max(REQUEST_BOUNDS.STRING_KEY_MAX)).max(REQUEST_BOUNDS.DISCOUNT_CODES_MAX).optional(),
4272
4348
  /** Presentment cents of cart-level discount allocations, subtracted from `subtotal` for the engine. */
4273
- discountTotal: z28.number().optional(),
4274
- items: z28.array(CartLineInputSchema).max(REQUEST_BOUNDS.CART_ITEMS_MAX),
4349
+ discountTotal: z29.number().optional(),
4350
+ items: z29.array(CartLineInputSchema).max(REQUEST_BOUNDS.CART_ITEMS_MAX),
4275
4351
  /** Presentment subtotal in cents. */
4276
- subtotal: z28.number()
4352
+ subtotal: z29.number()
4277
4353
  });
4278
- var WidgetSettingsInputSchema = z28.object({
4279
- cacheKey: z28.number().optional(),
4280
- id: z28.number(),
4281
- key: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4282
- shop: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4354
+ var WidgetSettingsInputSchema = z29.object({
4355
+ cacheKey: z29.number().optional(),
4356
+ id: z29.number(),
4357
+ key: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4358
+ shop: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4283
4359
  /** Stable per-buyer id; when present, enables sticky server-side A/B variant selection. */
4284
- visitorId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4360
+ visitorId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4285
4361
  });
4286
- var UserConfigInputSchema = z28.object({ shop: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX) });
4287
- var DataSourceInputSchema = z28.object({
4362
+ var UserConfigInputSchema = z29.object({ shop: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX) });
4363
+ var DataSourceInputSchema = z29.object({
4288
4364
  cart: CartInputSchema,
4289
4365
  /**
4290
4366
  * Numeric Shopify company-location id when the buyer is a B2B session (`buyerIdentity.purchasingCompany`).
4291
4367
  * Present ⇒ the orchestrator filters results by the location's catalog via admin-api (REB-23713); the
4292
4368
  * client's country-context market check is bypassed for B2B (it false-negatives B2B-catalog products).
4293
4369
  */
4294
- companyLocationId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4370
+ companyLocationId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4295
4371
  /**
4296
4372
  * Buyer's market country (ISO 3166-1 alpha-2) — forwarded to the engine as the `country_code` PARAM
4297
4373
  * when the shop's markets toggle is on (REB-21688; the sink was the `X-Country-Code` header under
@@ -4300,16 +4376,16 @@ var DataSourceInputSchema = z28.object({
4300
4376
  * uppercase (the wire value is forwarded verbatim as the param) so a case-sensitive engine lookup
4301
4377
  * can't silently miss a lowercase code — `adsEngine.ts` uppercases for the same reason.
4302
4378
  */
4303
- country: z28.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(),
4304
- customerId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4305
- dataSourcePath: z28.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
4379
+ country: z29.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(),
4380
+ customerId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4381
+ dataSourcePath: z29.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
4306
4382
  /**
4307
4383
  * Engine `filter_inputs` override: `'no'` keeps in-cart (input) products in the results/rule
4308
4384
  * outputs — gift validation sends it so a gift's own product can appear in its answer. Omitted = the
4309
4385
  * engine's default filtering.
4310
4386
  */
4311
- filterInputs: z28.enum(["no", "yes"]).optional(),
4312
- integrations: z28.record(z28.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z28.boolean()).refine((record) => Object.keys(record).length <= REQUEST_BOUNDS.INTEGRATION_KEYS_MAX, {
4387
+ filterInputs: z29.enum(["no", "yes"]).optional(),
4388
+ integrations: z29.record(z29.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z29.boolean()).refine((record) => Object.keys(record).length <= REQUEST_BOUNDS.INTEGRATION_KEYS_MAX, {
4313
4389
  message: `Too many integration keys (max ${REQUEST_BOUNDS.INTEGRATION_KEYS_MAX})`
4314
4390
  }).optional(),
4315
4391
  /**
@@ -4322,20 +4398,20 @@ var DataSourceInputSchema = z28.object({
4322
4398
  * request header) fails the regex. Callers should send the buyer's resolved locale (e.g. Shopify
4323
4399
  * checkout's `localization.language.isoCode`), not the request header verbatim.
4324
4400
  */
4325
- language: z28.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(),
4326
- limit: z28.number().max(REQUEST_BOUNDS.LIMIT_MAX),
4327
- productType: z28.enum(["both", "one-time", "subscription"]).optional(),
4328
- shop: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4329
- visitorId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4401
+ language: z29.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(),
4402
+ limit: z29.number().max(REQUEST_BOUNDS.LIMIT_MAX),
4403
+ productType: z29.enum(["both", "one-time", "subscription"]).optional(),
4404
+ shop: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4405
+ visitorId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4330
4406
  });
4331
- var GiftInputSchema = z28.object({
4332
- cost: z28.number(),
4333
- discounted: z28.boolean(),
4334
- lineId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4335
- productId: z28.number(),
4336
- widgetId: z28.number()
4407
+ var GiftInputSchema = z29.object({
4408
+ cost: z29.number(),
4409
+ discounted: z29.boolean(),
4410
+ lineId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4411
+ productId: z29.number(),
4412
+ widgetId: z29.number()
4337
4413
  });
4338
- var GiftValidationInputSchema = z28.object({
4414
+ var GiftValidationInputSchema = z29.object({
4339
4415
  cart: CartInputSchema,
4340
4416
  /**
4341
4417
  * Buyer's market country — threaded into the per-widget data-source evaluations, which forward it to
@@ -4344,71 +4420,71 @@ var GiftValidationInputSchema = z28.object({
4344
4420
  * turns markets off); regex-bound and uppercase-normalized for the same reasons as
4345
4421
  * `DataSourceInputSchema`'s `country`.
4346
4422
  */
4347
- country: z28.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(),
4348
- customerId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4349
- gifts: z28.array(GiftInputSchema).max(REQUEST_BOUNDS.GIFTS_MAX),
4423
+ country: z29.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(),
4424
+ customerId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4425
+ gifts: z29.array(GiftInputSchema).max(REQUEST_BOUNDS.GIFTS_MAX),
4350
4426
  /**
4351
4427
  * Buyer's checkout language — threaded into the per-widget data-source evaluations, which normalize
4352
4428
  * and forward it as the engine `locale` param under the same markets-toggle gate (REB-21688). MUST be
4353
4429
  * a single BCP-47 tag, for the same reason as `DataSourceInputSchema`'s `language` above.
4354
4430
  */
4355
- language: z28.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(),
4356
- shop: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4357
- visitorId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4431
+ language: z29.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(),
4432
+ shop: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4433
+ visitorId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4358
4434
  });
4359
- var MonetizeTransactionItemSchema = z28.object({
4360
- id: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4361
- priceCents: z28.number(),
4362
- quantity: z28.number(),
4363
- title: z28.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX),
4364
- type: z28.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX)
4435
+ var MonetizeTransactionItemSchema = z29.object({
4436
+ id: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4437
+ priceCents: z29.number(),
4438
+ quantity: z29.number(),
4439
+ title: z29.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX),
4440
+ type: z29.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX)
4365
4441
  });
4366
- var MonetizeInputSchema = z28.object({
4442
+ var MonetizeInputSchema = z29.object({
4367
4443
  cart: CartInputSchema,
4368
- country: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4369
- currency: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4444
+ country: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4445
+ currency: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4370
4446
  /** Ads-targeting identity/geo/locale fields (React parity); folded into the engine query verbatim. */
4371
- customerEmail: z28.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
4372
- customerFirstName: z28.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
4373
- customerId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4374
- customerLastName: z28.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
4375
- language: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4447
+ customerEmail: z29.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
4448
+ customerFirstName: z29.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
4449
+ customerId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4450
+ customerLastName: z29.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
4451
+ language: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4376
4452
  /** Buyer-facing order name (e.g. `#1001`) for the server-composed "Order … Confirmed" chrome line. */
4377
- orderName: z28.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
4453
+ orderName: z29.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
4378
4454
  /** Ads surface label, forwarded verbatim; `customer_account` is measured/floored as its own surface (the account-area order list). */
4379
- placement: z28.enum(["customer_account", "order_status", "thank_you_page"]),
4455
+ placement: z29.enum(["customer_account", "order_status", "thank_you_page"]),
4380
4456
  /** Privacy Policy footer href — the Monetize widget's `privacy_policy_url` setting (React parity). */
4381
- privacyPolicyUrl: z28.string().max(REQUEST_BOUNDS.STRING_URL_MAX).optional(),
4457
+ privacyPolicyUrl: z29.string().max(REQUEST_BOUNDS.STRING_URL_MAX).optional(),
4382
4458
  /** 30-min rolling session id (React parity); used for the ads `session_id`, else the visitor id. */
4383
- sessionId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4384
- shop: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4459
+ sessionId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4460
+ shop: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4385
4461
  /** Editor/QA indicator; OR-ed into the ads-engine `testing` flag so it stays out of billing/reporting. */
4386
- testing: z28.boolean().optional(),
4387
- timezone: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4462
+ testing: z29.boolean().optional(),
4463
+ timezone: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4388
4464
  /** Decorated (numeric) order id → the ads `transaction_id`. */
4389
- transactionId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4465
+ transactionId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4390
4466
  /** Rich per-line ads items; capped at the engine's ads contract. Preferred over `cart.items`. */
4391
- transactionItems: z28.array(MonetizeTransactionItemSchema).max(REQUEST_BOUNDS.TRANSACTION_ITEMS_MAX).optional(),
4467
+ transactionItems: z29.array(MonetizeTransactionItemSchema).max(REQUEST_BOUNDS.TRANSACTION_ITEMS_MAX).optional(),
4392
4468
  /** Order total in presentment cents (React prefers total over subtotal); else `cart.subtotal`. */
4393
- transactionTotal: z28.number().optional(),
4394
- visitorId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4395
- zipCode: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4469
+ transactionTotal: z29.number().optional(),
4470
+ visitorId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4471
+ zipCode: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4396
4472
  });
4397
- var AnalyticsEventInputSchema = z28.object({
4398
- name: z28.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
4399
- properties: z28.record(z28.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z28.unknown()).optional(),
4400
- sentAt: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4473
+ var AnalyticsEventInputSchema = z29.object({
4474
+ name: z29.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
4475
+ properties: z29.record(z29.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z29.unknown()).optional(),
4476
+ sentAt: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4401
4477
  });
4402
- var AnalyticsInputSchema = z28.object({
4478
+ var AnalyticsInputSchema = z29.object({
4403
4479
  /** Rebuy cart token (the `r_cart_token` cart attribute), when available — primary aggregation key. */
4404
- cartToken: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4480
+ cartToken: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4405
4481
  /** Shopify checkout token, when available — drives cart/checkout aggregation downstream. */
4406
- checkoutToken: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4407
- events: z28.array(AnalyticsEventInputSchema).max(REQUEST_BOUNDS.EVENTS_MAX),
4408
- shop: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4409
- visitorId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4482
+ checkoutToken: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
4483
+ events: z29.array(AnalyticsEventInputSchema).max(REQUEST_BOUNDS.EVENTS_MAX),
4484
+ shop: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4485
+ visitorId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
4410
4486
  /** The widget id (smartBlockId) the events belong to. */
4411
- widgetId: z28.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4487
+ widgetId: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
4412
4488
  });
4413
4489
  export {
4414
4490
  AnalyticsEventInputSchema,