@rebuy/rebuy 3.28.0 → 3.29.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.
@@ -1971,7 +1971,14 @@ var CABReviewsSection = z23.object({
1971
1971
  sectionId: z23.uuid().default(() => uuidv710()),
1972
1972
  sectionType: z23.literal(SectionType.reviews).default(SectionType.reviews),
1973
1973
  size: z23.enum(reviewsSizes).default(ReviewsSize.default),
1974
- strokeColor: z23.string().default("#fadb14"),
1974
+ /**
1975
+ * Star outline color, interpolated into a style by the renderer, so it is hex-constrained like
1976
+ * `CABButtonSection.color`. The legacy source (`PostPurchaseSettings.styles.starStrokeColor`) is a free
1977
+ * string: its converter must validate and fall back to this default rather than let one odd value drop
1978
+ * the whole reviews section.
1979
+ */
1980
+ strokeColor: z23.string().regex(HEX_COLOR_REGEX).default("#fadb14"),
1981
+ /** Star outline width in px; `0` draws no outline. The legacy `styles.strokeWidth` is a STRING ('1') — its converter coerces. */
1975
1982
  strokeWidth: z23.number().nonnegative().default(0)
1976
1983
  });
1977
1984
 
@@ -3720,7 +3727,7 @@ var convertOfferToV2 = ({ id, name, settings }) => {
3720
3727
  var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(transform(convertNumericObjects(deepCamelCase(raw))));
3721
3728
 
3722
3729
  // src/transforms/postPurchase/convertMessagePreview.ts
3723
- import { z as z33 } from "zod";
3730
+ import { z as z36 } from "zod";
3724
3731
 
3725
3732
  // src/transforms/postPurchase/convertCalloutBlock.ts
3726
3733
  import { z as z31 } from "zod";
@@ -3943,6 +3950,150 @@ var convertCalloutBlock = (raw, report) => {
3943
3950
  return sections.length ? [CABLayoutSection.parse({ alignment: { horizontal }, frame: "callout", sections })] : [];
3944
3951
  };
3945
3952
 
3953
+ // src/transforms/postPurchase/convertImageFrame.ts
3954
+ import { z as z32 } from "zod";
3955
+
3956
+ // src/transforms/postPurchase/sizeImageSource.ts
3957
+ var sizeImageSource = (source, size) => {
3958
+ const extension = source.split(".").pop();
3959
+ for (const previous of ["small", "medium", "large", "original", "master"]) {
3960
+ source = source.replace(`_${previous}.${extension}`, `.${extension}`);
3961
+ }
3962
+ return source.replace(`.${extension}`, `${size === void 0 ? "" : `_${size}`}.${extension}`);
3963
+ };
3964
+
3965
+ // src/transforms/postPurchase/convertImageFrame.ts
3966
+ var Source = z32.url().default("https://cdn.shopify.com/s/files/1/0605/0555/5177/files/placeholder.jpg?v=1657762972");
3967
+ var DEFAULT_IMAGE_SIZE = 20;
3968
+ var convertImageFrame = (raw) => {
3969
+ const parsed = ImageBlock.shape.settings.options[0].safeParse(raw);
3970
+ if (!parsed.success) return null;
3971
+ const settings = parsed.data;
3972
+ const source = sizeImageSource(Source.parse(settings.image || void 0));
3973
+ const withAlt = CABImageSection.safeParse({ altText: settings.alt, source });
3974
+ const image = withAlt.success ? withAlt.data : CABImageSection.parse({ source });
3975
+ const size = settings.imageSize > 0 ? settings.imageSize : DEFAULT_IMAGE_SIZE;
3976
+ return CABLayoutSection.parse({
3977
+ alignment: { horizontal: "center" },
3978
+ direction: "grid",
3979
+ grid: { columns: size <= 1 ? ["100%"] : [size] },
3980
+ sections: [image],
3981
+ width: size <= 1 ? size * 100 : 100
3982
+ });
3983
+ };
3984
+
3985
+ // src/transforms/postPurchase/convertImageBlock.ts
3986
+ var dropMalformedAlt = (raw) => {
3987
+ if (typeof raw !== "object" || raw === null) return raw;
3988
+ const { settings, ...rest } = raw;
3989
+ if (typeof settings !== "object" || settings === null || Array.isArray(settings)) return raw;
3990
+ const { alt, ...restSettings } = settings;
3991
+ if (typeof alt === "string" || alt === void 0) return raw;
3992
+ return { ...rest, settings: restSettings };
3993
+ };
3994
+ var convertImageBlock = (raw, report) => {
3995
+ const block = ImageBlock.safeParse(dropMalformedAlt(raw));
3996
+ const image = block.success ? convertImageFrame(block.data.settings) : null;
3997
+ if (!image) {
3998
+ report?.({ detail: "Unreadable post-purchase image", kind: "section" });
3999
+ return [];
4000
+ }
4001
+ return [
4002
+ CABLayoutSection.parse({
4003
+ alignment: { horizontal: "center" },
4004
+ frame: "offer-content",
4005
+ sections: [image],
4006
+ spacing: "none"
4007
+ })
4008
+ ];
4009
+ };
4010
+
4011
+ // src/transforms/postPurchase/convertImageContentBlock.ts
4012
+ import { z as z34 } from "zod";
4013
+
4014
+ // src/transforms/postPurchase/convertImageContentText.ts
4015
+ var fields2 = ["superTitle", "title", "description"];
4016
+ var convertImageContentText = (settings, report) => {
4017
+ const horizontal = { center: "center", leading: "start", trailing: "end" }[settings.horizontalAlignment];
4018
+ const sections = fields2.flatMap((field) => {
4019
+ const omit = () => {
4020
+ report?.({ detail: `Unreadable post-purchase image-content field: ${field}`, kind: "section" });
4021
+ return [];
4022
+ };
4023
+ const value = ImageContentBlock.shape.settings.shape[field].safeParse(settings[field]);
4024
+ if (!value.success) return omit();
4025
+ const text2 = value.data;
4026
+ if (text2 === null || text2 === "") return [];
4027
+ const content = typeof text2 === "string" ? {
4028
+ content: [
4029
+ {
4030
+ attrs: { textAlign: horizontal },
4031
+ content: [styledTextRun(text2, field !== "description", settings[`${field}Size`])]
4032
+ }
4033
+ ]
4034
+ } : text2;
4035
+ const section = CABTextSection.safeParse({ content: { en: content } });
4036
+ return section.success ? [section.data] : omit();
4037
+ });
4038
+ return CABLayoutSection.parse({ alignment: { horizontal }, sections });
4039
+ };
4040
+
4041
+ // src/transforms/postPurchase/imageContentSettings.ts
4042
+ import { z as z33 } from "zod";
4043
+ var ImageContentSettings = ImageContentBlock.shape.settings.pick({
4044
+ descriptionSize: true,
4045
+ horizontalAlignment: true,
4046
+ superTitleSize: true,
4047
+ swapContent: true,
4048
+ titleSize: true
4049
+ }).extend({
4050
+ alt: z33.unknown().optional(),
4051
+ description: z33.unknown().optional(),
4052
+ image: z33.unknown().optional(),
4053
+ imagePlacement: ImageContentBlock.shape.settings.shape.imagePlacement.unwrap().nullable(),
4054
+ imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(z33.number().positive()),
4055
+ superTitle: z33.unknown().optional(),
4056
+ title: z33.unknown().optional()
4057
+ });
4058
+
4059
+ // src/transforms/postPurchase/convertImageContentBlock.ts
4060
+ var Shell2 = z34.object({ settings: ImageContentSettings, type: z34.literal("image_content") });
4061
+ var PROPORTIONAL_BREAK_AT = 500;
4062
+ var convertImageContentBlock = (raw, report) => {
4063
+ const shell = Shell2.safeParse(raw);
4064
+ if (!shell.success) {
4065
+ report?.({ detail: "Unreadable post-purchase image-content block", kind: "section" });
4066
+ return [];
4067
+ }
4068
+ const settings = shell.data.settings;
4069
+ const alt = typeof settings.alt === "string" ? settings.alt : void 0;
4070
+ if (settings.alt !== void 0 && alt === void 0) {
4071
+ report?.({ detail: "Unreadable post-purchase image-content alt text", kind: "section" });
4072
+ }
4073
+ const image = convertImageFrame({ alt, image: settings.image, imageSize: settings.imageSize });
4074
+ if (!image) report?.({ detail: "Unreadable post-purchase image-content image", kind: "section" });
4075
+ const text2 = convertImageContentText(settings, report);
4076
+ const textFrame = CABLayoutSection.parse({ direction: "grid", grid: { columns: ["100%"] }, sections: [text2] });
4077
+ const placement = settings.imagePlacement ?? (settings.swapContent ? "right" : "left");
4078
+ const imageFirst = placement === "left" || placement === "top";
4079
+ const sections = imageFirst ? [image, textFrame] : [textFrame, image];
4080
+ const ordered = sections.filter((section) => section !== null);
4081
+ const inner = placement === "left" || placement === "right" ? CABLayoutSection.parse({
4082
+ sections: ordered,
4083
+ spacing: "loose",
4084
+ wrapping: {
4085
+ breakAt: settings.imageSize <= 1 ? PROPORTIONAL_BREAK_AT : settings.imageSize,
4086
+ maxPerLine: 2
4087
+ }
4088
+ }) : CABLayoutSection.parse({
4089
+ direction: "grid",
4090
+ grid: { columns: ["100%"] },
4091
+ sections: [CABLayoutSection.parse({ sections: ordered })],
4092
+ width: 95
4093
+ });
4094
+ return [CABLayoutSection.parse({ frame: "offer-content", sections: [inner], spacing: "none" })];
4095
+ };
4096
+
3946
4097
  // src/transforms/postPurchase/convertPayButtonBlock.ts
3947
4098
  var convertPayButtonBlock = (raw, report) => {
3948
4099
  const omit = () => {
@@ -3971,6 +4122,60 @@ var convertPayButtonBlock = (raw, report) => {
3971
4122
  ];
3972
4123
  };
3973
4124
 
4125
+ // src/transforms/postPurchase/convertProductInformation.ts
4126
+ var convertProductInformation = (raw, report) => {
4127
+ const block = ProductInformationBlock.safeParse(raw);
4128
+ if (!block.success) {
4129
+ report?.({ detail: "Unreadable post-purchase product information", kind: "section" });
4130
+ return [];
4131
+ }
4132
+ return [
4133
+ CABOffersSection.parse({
4134
+ direction: "grid",
4135
+ sections: [
4136
+ CABLayoutSection.parse({
4137
+ alignment: { horizontal: "center" },
4138
+ sections: [
4139
+ CABLayoutSection.parse({
4140
+ alignment: { horizontal: "center" },
4141
+ direction: "grid",
4142
+ grid: { columns: [250] },
4143
+ sections: [
4144
+ CABImageSection.parse({ altText: "{{productTitle}}", source: "{{productImage}}" })
4145
+ ],
4146
+ width: 90
4147
+ })
4148
+ ]
4149
+ }),
4150
+ CABLayoutSection.parse({
4151
+ sections: [
4152
+ CABTextSection.parse({
4153
+ content: {
4154
+ en: {
4155
+ content: [
4156
+ {
4157
+ content: [
4158
+ {
4159
+ marks: [{ attrs: { fontSize: "heading" }, type: "textStyle" }],
4160
+ text: "{{productTitle}}"
4161
+ }
4162
+ ]
4163
+ }
4164
+ ]
4165
+ }
4166
+ }
4167
+ }),
4168
+ CABReviewsSection.parse({}),
4169
+ CABTextSection.parse({ content: { en: "{{productDescription}}" } })
4170
+ ]
4171
+ })
4172
+ ],
4173
+ spacing: "extraLoose",
4174
+ wrapping: { breakAt: 500, maxPerLine: block.data.hideProductImage ? 1 : 2 }
4175
+ })
4176
+ ];
4177
+ };
4178
+
3974
4179
  // src/transforms/postPurchase/convertSeparatorBlock.ts
3975
4180
  var convertSeparatorBlock = (raw, report) => {
3976
4181
  if (!SeparatorBlock.safeParse(raw).success) {
@@ -3981,34 +4186,36 @@ var convertSeparatorBlock = (raw, report) => {
3981
4186
  };
3982
4187
 
3983
4188
  // src/transforms/postPurchase/convertTextBlock.ts
3984
- import { z as z32 } from "zod";
3985
- var fields2 = ["superTitle", "title", "description"];
4189
+ import { z as z35 } from "zod";
4190
+ var fields3 = ["superTitle", "title", "description"];
3986
4191
  var styles = {
3987
4192
  description: [{ attrs: { color: "base", fontSize: "small" }, type: "textStyle" }],
3988
4193
  superTitle: [{ attrs: { color: "subdued", fontSize: "small" }, type: "textStyle" }],
3989
4194
  title: [{ type: "bold" }, { attrs: { color: "base", fontSize: "large" }, type: "textStyle" }]
3990
4195
  };
3991
4196
  var settingsSchema = TextBlock.shape.settings;
3992
- var Shell2 = z32.object({
4197
+ var Shell3 = z35.object({
3993
4198
  settings: settingsSchema.pick({ horizontalAlignment: true }).extend({
3994
- description: z32.unknown().optional(),
3995
- superTitle: z32.unknown().optional(),
3996
- title: z32.unknown().optional()
4199
+ description: z35.unknown().optional(),
4200
+ superTitle: z35.unknown().optional(),
4201
+ title: z35.unknown().optional()
3997
4202
  }),
3998
- type: z32.literal("text")
4203
+ type: z35.literal("text")
3999
4204
  });
4000
4205
  var convertTextBlock = (raw, report) => {
4001
- const shell = Shell2.safeParse(raw);
4206
+ const shell = Shell3.safeParse(raw);
4002
4207
  if (!shell.success) {
4003
4208
  report?.({ detail: "Unreadable post-purchase text block", kind: "section" });
4004
4209
  return [];
4005
4210
  }
4006
- const values = fields2.map((field) => ({
4211
+ const values = fields3.map((field) => ({
4007
4212
  field,
4008
4213
  result: settingsSchema.shape[field].safeParse(shell.data.settings[field])
4009
4214
  }));
4010
4215
  const horizontal = { center: "center", leading: "start", trailing: "end" }[shell.data.settings.horizontalAlignment];
4011
- const styled2 = values.every(({ result }) => result.success && typeof result.data === "string");
4216
+ const styled2 = values.every(
4217
+ ({ result }) => result.success && (result.data === null || typeof result.data === "string")
4218
+ );
4012
4219
  const omit = (field) => {
4013
4220
  report?.({ detail: `Unreadable post-purchase text field: ${field}`, kind: "section" });
4014
4221
  return [];
@@ -4021,20 +4228,18 @@ var convertTextBlock = (raw, report) => {
4021
4228
  const section = CABTextSection.safeParse({ content: { en: content } });
4022
4229
  return section.success ? [section.data] : omit(field);
4023
4230
  });
4024
- return [
4025
- CABLayoutSection.parse({
4026
- alignment: {
4027
- horizontal
4028
- },
4029
- sections
4030
- })
4031
- ];
4231
+ return sections.length ? [CABLayoutSection.parse({ alignment: { horizontal }, sections })] : [];
4032
4232
  };
4033
4233
 
4034
4234
  // src/transforms/postPurchase/convertTimerBlock.ts
4035
4235
  var Presentation = TimerBlock.pick({ styles: true }).extend({
4036
4236
  settings: TimerBlock.shape.settings.pick({ title: true })
4037
4237
  });
4238
+ var withCountdown = (doc, run, textAlign) => {
4239
+ const paragraphs = doc.content.length ? doc.content : [TiptapParagraph.parse({ attrs: { textAlign } })];
4240
+ const last = paragraphs[paragraphs.length - 1];
4241
+ return { ...doc, content: [...paragraphs.slice(0, -1), { ...last, content: [...last.content, run] }] };
4242
+ };
4038
4243
  var convertTimerBlock = (raw, report) => {
4039
4244
  const omit = () => {
4040
4245
  report?.({ detail: "Unreadable post-purchase timer display", kind: "section" });
@@ -4045,17 +4250,15 @@ var convertTimerBlock = (raw, report) => {
4045
4250
  const { title } = parsed.data.settings;
4046
4251
  const styles2 = parsed.data.styles;
4047
4252
  const horizontal = { center: "center", leading: "start", trailing: "end" }[styles2.textAlignment];
4253
+ const countdown = styledTextRun(" {{timeRemaining}}", styles2.timerEmphasized, styles2.timerSize);
4048
4254
  const content = typeof title === "string" ? {
4049
4255
  content: [
4050
4256
  {
4051
4257
  attrs: { textAlign: horizontal },
4052
- content: [
4053
- styledTextRun(title, styles2.titleEmphasized, styles2.titleSize),
4054
- styledTextRun(" {{timeRemaining}}", styles2.timerEmphasized, styles2.timerSize)
4055
- ]
4258
+ content: [styledTextRun(title, styles2.titleEmphasized, styles2.titleSize), countdown]
4056
4259
  }
4057
4260
  ]
4058
- } : title;
4261
+ } : withCountdown(title, countdown, horizontal);
4059
4262
  const text2 = CABTextSection.safeParse({ content: { en: content } });
4060
4263
  if (!text2.success) return omit();
4061
4264
  return [
@@ -4069,14 +4272,17 @@ var convertTimerBlock = (raw, report) => {
4069
4272
  };
4070
4273
 
4071
4274
  // src/transforms/postPurchase/convertMessagePreview.ts
4072
- var MessageWidget = z33.object({
4073
- blocks: z33.array(z33.unknown()).min(1),
4074
- type: z33.literal("shopify_post_purchase_extension")
4275
+ var MessageWidget = z36.object({
4276
+ blocks: z36.array(z36.unknown()).min(1),
4277
+ type: z36.literal(WidgetType.shopify_post_purchase_extension)
4075
4278
  });
4076
- var BlockType2 = z33.object({ type: z33.string() });
4279
+ var BlockType2 = z36.object({ type: z36.string() });
4077
4280
  var converters = {
4078
4281
  callout_banner: convertCalloutBlock,
4282
+ image: convertImageBlock,
4283
+ image_content: convertImageContentBlock,
4079
4284
  pay_button: convertPayButtonBlock,
4285
+ product_information: convertProductInformation,
4080
4286
  separator: convertSeparatorBlock,
4081
4287
  text: convertTextBlock,
4082
4288
  timer: convertTimerBlock
@@ -4090,7 +4296,7 @@ var convertMessagePreview = (id, settings, report) => {
4090
4296
  sections: parsed.data.blocks.flatMap((block) => {
4091
4297
  const type = BlockType2.safeParse(block);
4092
4298
  const kind = type.success ? type.data.type : void 0;
4093
- const convert2 = kind ? converters[kind] : void 0;
4299
+ const convert2 = kind && Object.hasOwn(converters, kind) ? converters[kind] : void 0;
4094
4300
  if (convert2) return convert2(block, report);
4095
4301
  report?.({
4096
4302
  detail: kind ? `Unsupported post-purchase block type: ${kind}` : "Unreadable post-purchase block: missing type",
@@ -4618,7 +4824,7 @@ var fetchDataSourceResults = async (input, ctx) => {
4618
4824
  };
4619
4825
 
4620
4826
  // src/server/adsEngine.ts
4621
- import { z as z34 } from "zod";
4827
+ import { z as z37 } from "zod";
4622
4828
  var SUPPLY_KEY = { production: "AQF5RKLR", staging: "Z56LQ7PS" };
4623
4829
  var OFFER_LIMIT = 4;
4624
4830
  var SUPPORTED_COUNTRIES = /* @__PURE__ */ new Set(["US", "CA"]);
@@ -4631,28 +4837,28 @@ var transactionItems = (input) => (input.transactionItems?.map(({ id, priceCents
4631
4837
  title,
4632
4838
  type
4633
4839
  })) ?? input.cart.items.map(({ productId, quantity }) => ({ id: productId, quantity }))).slice(0, MAX_TRANSACTION_ITEMS);
4634
- var AdsEngineOffer = z34.object({
4840
+ var AdsEngineOffer = z37.object({
4635
4841
  /** Pill-style value prop ("Get $45 Cashback"). Carried through the parse; the card does not render it yet (REB-24429 — pill design pending). */
4636
- callout: z34.string().catch(""),
4637
- click_url: z34.string(),
4638
- cta: z34.string(),
4842
+ callout: z37.string().catch(""),
4843
+ click_url: z37.string(),
4844
+ cta: z37.string(),
4639
4845
  /** `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'). */
4640
- decline_cta: z34.string().catch(""),
4641
- decline_url: z34.string(),
4642
- description: z34.string(),
4846
+ decline_cta: z37.string().catch(""),
4847
+ decline_url: z37.string(),
4848
+ description: z37.string(),
4643
4849
  /** Short legal disclosure (FDIC / auto-renewal / FTC-affiliation lines). Rendered subdued under the CTAs. */
4644
- disclaimer: z34.string().catch(""),
4850
+ disclaimer: z37.string().catch(""),
4645
4851
  /** Long legal text behind the disclosure toggle in the composed card (REB-24429). */
4646
- extended_disclaimer: z34.string().catch(""),
4647
- headline: z34.string(),
4648
- id: z34.string(),
4852
+ extended_disclaimer: z37.string().catch(""),
4853
+ headline: z37.string(),
4854
+ id: z37.string(),
4649
4855
  /** Advertiser-supplied image alt; the composed card falls back to the stripped headline when empty. */
4650
- image_alt: z34.string().catch(""),
4651
- image_url: z34.string().optional(),
4652
- view_url: z34.string()
4856
+ image_alt: z37.string().catch(""),
4857
+ image_url: z37.string().optional(),
4858
+ view_url: z37.string()
4653
4859
  });
4654
- var AdsEngineResponse = z34.object({
4655
- offers: z34.array(z34.unknown()).default([]).transform(
4860
+ var AdsEngineResponse = z37.object({
4861
+ offers: z37.array(z37.unknown()).default([]).transform(
4656
4862
  (offers) => offers.flatMap((offer) => {
4657
4863
  const result = AdsEngineOffer.safeParse(offer);
4658
4864
  return result.success ? [result.data] : [];
@@ -4664,8 +4870,8 @@ var AdsEngineResponse = z34.object({
4664
4870
  * offers-testing fixture on a test store forces it, REB-24467). Both optional: an older engine or a
4665
4871
  * non-JSON body must not fail the parse and drop the offers.
4666
4872
  */
4667
- request_id: z34.string().optional().catch(void 0),
4668
- testing: z34.boolean().optional().catch(void 0)
4873
+ request_id: z37.string().optional().catch(void 0),
4874
+ testing: z37.boolean().optional().catch(void 0)
4669
4875
  });
4670
4876
  var adsHost = (host) => `offers.${host}`;
4671
4877
  var isTestingRequest = (input, isProduction) => !isProduction || !!input.testing || input.customerEmail?.toLowerCase() === TEST_CUSTOMER_EMAIL;
@@ -5095,13 +5301,13 @@ var convertWidgetSettings = async (input, ctx) => {
5095
5301
  };
5096
5302
 
5097
5303
  // src/server/giftWidgets.ts
5098
- import { z as z35 } from "zod";
5099
- var SettingsNumber = z35.union([
5100
- z35.number(),
5101
- z35.string().trim().regex(/^-?\d+(\.\d+)?$/)
5102
- ]).pipe(z35.coerce.number());
5103
- var SgwpMilestoneSchema = z35.object({
5104
- selectable_product_quantity: SettingsNumber.pipe(z35.number().int().nonnegative()),
5304
+ import { z as z38 } from "zod";
5305
+ var SettingsNumber = z38.union([
5306
+ z38.number(),
5307
+ z38.string().trim().regex(/^-?\d+(\.\d+)?$/)
5308
+ ]).pipe(z38.coerce.number());
5309
+ var SgwpMilestoneSchema = z38.object({
5310
+ selectable_product_quantity: SettingsNumber.pipe(z38.number().int().nonnegative()),
5105
5311
  unlock_price: SettingsNumber
5106
5312
  });
5107
5313
  var fetchGiftWidgetSettings = async (widgetId, shop, ctx) => unwrapData(await ctx.fetchUpstream("/api/v1/widgets/settings", { id: String(widgetId), shop }, { host: ctx.host }));
@@ -5112,7 +5318,7 @@ var readDataSourcePath = (settings) => {
5112
5318
  var readMilestones = (settings, report) => {
5113
5319
  const raw = settings && typeof settings === "object" ? settings.milestones : void 0;
5114
5320
  if (raw == null) return [];
5115
- const parsed = z35.array(SgwpMilestoneSchema).safeParse(raw);
5321
+ const parsed = z38.array(SgwpMilestoneSchema).safeParse(raw);
5116
5322
  if (parsed.success) return parsed.data;
5117
5323
  report?.({
5118
5324
  detail: [
@@ -5361,7 +5567,7 @@ var postAnalyticsEvents = async (input, ctx) => {
5361
5567
  };
5362
5568
 
5363
5569
  // src/server/requestSchemas.ts
5364
- import { z as z36 } from "zod";
5570
+ import { z as z39 } from "zod";
5365
5571
  var REQUEST_BOUNDS = {
5366
5572
  /** Cart-level attributes per cart. */
5367
5573
  CART_ATTRIBUTES_MAX: 100,
@@ -5392,42 +5598,42 @@ var REQUEST_BOUNDS = {
5392
5598
  /** Rich ads transaction lines — the engine's ads contract. */
5393
5599
  TRANSACTION_ITEMS_MAX: 50
5394
5600
  };
5395
- var KeyValue = z36.object({
5396
- key: z36.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
5397
- value: z36.string().max(REQUEST_BOUNDS.STRING_VALUE_MAX).optional()
5601
+ var KeyValue = z39.object({
5602
+ key: z39.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
5603
+ value: z39.string().max(REQUEST_BOUNDS.STRING_VALUE_MAX).optional()
5398
5604
  });
5399
- var CartLineInputSchema = z36.object({
5400
- productId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5401
- properties: z36.array(KeyValue).max(REQUEST_BOUNDS.LINE_PROPERTIES_MAX).optional(),
5402
- quantity: z36.number(),
5403
- subscriptionId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5404
- variantId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX)
5605
+ var CartLineInputSchema = z39.object({
5606
+ productId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5607
+ properties: z39.array(KeyValue).max(REQUEST_BOUNDS.LINE_PROPERTIES_MAX).optional(),
5608
+ quantity: z39.number(),
5609
+ subscriptionId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5610
+ variantId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX)
5405
5611
  });
5406
- var CartInputSchema = z36.object({
5407
- attributes: z36.array(KeyValue).max(REQUEST_BOUNDS.CART_ATTRIBUTES_MAX).optional(),
5612
+ var CartInputSchema = z39.object({
5613
+ attributes: z39.array(KeyValue).max(REQUEST_BOUNDS.CART_ATTRIBUTES_MAX).optional(),
5408
5614
  /**
5409
5615
  * Presentment-per-shop-currency FX rate (buyer price ÷ shop price, e.g. `1.35` for a USD shop
5410
5616
  * selling in CAD). Money rule thresholds are authored in SHOP currency, so the engine subtotal is
5411
5617
  * divided by this before evaluation. Omit (or send 1) when the cart is already in the shop's currency.
5412
5618
  */
5413
- currencyRate: z36.number().optional(),
5619
+ currencyRate: z39.number().optional(),
5414
5620
  /** Applied discount codes; the engine evaluates `discount_code` rules against them (sent as `[{code}]`). */
5415
- discountCodes: z36.array(z36.string().max(REQUEST_BOUNDS.STRING_KEY_MAX)).max(REQUEST_BOUNDS.DISCOUNT_CODES_MAX).optional(),
5621
+ discountCodes: z39.array(z39.string().max(REQUEST_BOUNDS.STRING_KEY_MAX)).max(REQUEST_BOUNDS.DISCOUNT_CODES_MAX).optional(),
5416
5622
  /** Presentment cents of cart-level discount allocations, subtracted from `subtotal` for the engine. */
5417
- discountTotal: z36.number().optional(),
5418
- items: z36.array(CartLineInputSchema).max(REQUEST_BOUNDS.CART_ITEMS_MAX),
5623
+ discountTotal: z39.number().optional(),
5624
+ items: z39.array(CartLineInputSchema).max(REQUEST_BOUNDS.CART_ITEMS_MAX),
5419
5625
  /** Presentment subtotal in cents. */
5420
- subtotal: z36.number()
5626
+ subtotal: z39.number()
5421
5627
  });
5422
- var UserConfigInputSchema = z36.object({ shop: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX) });
5423
- var DataSourceInputSchema = z36.object({
5628
+ var UserConfigInputSchema = z39.object({ shop: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX) });
5629
+ var DataSourceInputSchema = z39.object({
5424
5630
  cart: CartInputSchema,
5425
5631
  /**
5426
5632
  * Numeric Shopify company-location id when the buyer is a B2B session (`buyerIdentity.purchasingCompany`).
5427
5633
  * Present ⇒ the orchestrator filters results by the location's catalog via admin-api (REB-23713); the
5428
5634
  * client's country-context market check is bypassed for B2B (it false-negatives B2B-catalog products).
5429
5635
  */
5430
- companyLocationId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5636
+ companyLocationId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5431
5637
  /**
5432
5638
  * Buyer's market country (ISO 3166-1 alpha-2) — forwarded to the engine as the `country_code` PARAM
5433
5639
  * when the shop's markets toggle is on (REB-21688; the sink was the `X-Country-Code` header under
@@ -5436,16 +5642,16 @@ var DataSourceInputSchema = z36.object({
5436
5642
  * uppercase (the wire value is forwarded verbatim as the param) so a case-sensitive engine lookup
5437
5643
  * can't silently miss a lowercase code — `adsEngine.ts` uppercases for the same reason.
5438
5644
  */
5439
- country: z36.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(),
5440
- customerId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5441
- dataSourcePath: z36.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
5645
+ country: z39.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(),
5646
+ customerId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5647
+ dataSourcePath: z39.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
5442
5648
  /**
5443
5649
  * Engine `filter_inputs` override: `'no'` keeps in-cart (input) products in the results/rule
5444
5650
  * outputs — gift validation sends it so a gift's own product can appear in its answer. Omitted = the
5445
5651
  * engine's default filtering.
5446
5652
  */
5447
- filterInputs: z36.enum(["no", "yes"]).optional(),
5448
- integrations: z36.record(z36.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z36.boolean()).refine((record) => Object.keys(record).length <= REQUEST_BOUNDS.INTEGRATION_KEYS_MAX, {
5653
+ filterInputs: z39.enum(["no", "yes"]).optional(),
5654
+ integrations: z39.record(z39.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z39.boolean()).refine((record) => Object.keys(record).length <= REQUEST_BOUNDS.INTEGRATION_KEYS_MAX, {
5449
5655
  message: `Too many integration keys (max ${REQUEST_BOUNDS.INTEGRATION_KEYS_MAX})`
5450
5656
  }).optional(),
5451
5657
  /**
@@ -5458,31 +5664,31 @@ var DataSourceInputSchema = z36.object({
5458
5664
  * request header) fails the regex. Callers should send the buyer's resolved locale (e.g. Shopify
5459
5665
  * checkout's `localization.language.isoCode`), not the request header verbatim.
5460
5666
  */
5461
- language: z36.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(),
5462
- limit: z36.number().max(REQUEST_BOUNDS.LIMIT_MAX),
5463
- productType: z36.enum(["both", "one-time", "subscription"]).optional(),
5464
- shop: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5465
- visitorId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5667
+ language: z39.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(),
5668
+ limit: z39.number().max(REQUEST_BOUNDS.LIMIT_MAX),
5669
+ productType: z39.enum(["both", "one-time", "subscription"]).optional(),
5670
+ shop: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5671
+ visitorId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5466
5672
  });
5467
- var GiftInputSchema = z36.object({
5468
- cost: z36.number(),
5469
- discounted: z36.boolean(),
5673
+ var GiftInputSchema = z39.object({
5674
+ cost: z39.number(),
5675
+ discounted: z39.boolean(),
5470
5676
  /**
5471
5677
  * Which gift attribution the line carries (REB-24363). Defaults to `gwp` because a client that predates
5472
5678
  * the field only ever sent GWP lines — without the default an older extension's request would 422.
5473
5679
  */
5474
- kind: z36.enum(GIFT_KINDS).default("gwp"),
5475
- lineId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5476
- productId: z36.number(),
5680
+ kind: z39.enum(GIFT_KINDS).default("gwp"),
5681
+ lineId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5682
+ productId: z39.number(),
5477
5683
  /**
5478
5684
  * The line's unit count (REB-24363) — the selectable-GWP verdict trims surplus units against milestone
5479
5685
  * capacity. The second deliberate default: a client predating the field sent only GWP lines, whose
5480
5686
  * verdict is whole-line, so a missing quantity reads as one unit rather than 422ing the older request.
5481
5687
  */
5482
- quantity: z36.number().int().min(1).default(1),
5483
- widgetId: z36.number()
5688
+ quantity: z39.number().int().min(1).default(1),
5689
+ widgetId: z39.number()
5484
5690
  });
5485
- var GiftValidationInputSchema = z36.object({
5691
+ var GiftValidationInputSchema = z39.object({
5486
5692
  cart: CartInputSchema,
5487
5693
  /**
5488
5694
  * Buyer's market country — threaded into the per-widget data-source evaluations, which forward it to
@@ -5491,25 +5697,25 @@ var GiftValidationInputSchema = z36.object({
5491
5697
  * turns markets off); regex-bound and uppercase-normalized for the same reasons as
5492
5698
  * `DataSourceInputSchema`'s `country`.
5493
5699
  */
5494
- country: z36.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(),
5495
- customerId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5496
- gifts: z36.array(GiftInputSchema).max(REQUEST_BOUNDS.GIFTS_MAX),
5700
+ country: z39.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(),
5701
+ customerId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5702
+ gifts: z39.array(GiftInputSchema).max(REQUEST_BOUNDS.GIFTS_MAX),
5497
5703
  /**
5498
5704
  * Buyer's checkout language — threaded into the per-widget data-source evaluations, which normalize
5499
5705
  * and forward it as the engine `locale` param under the same markets-toggle gate (REB-21688). MUST be
5500
5706
  * a single BCP-47 tag, for the same reason as `DataSourceInputSchema`'s `language` above.
5501
5707
  */
5502
- language: z36.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(),
5503
- shop: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5504
- visitorId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5708
+ language: z39.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(),
5709
+ shop: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5710
+ visitorId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5505
5711
  });
5506
- var GiftAdjustmentSchema = z36.object({
5507
- lineId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5508
- quantity: z36.number().int().nonnegative()
5712
+ var GiftAdjustmentSchema = z39.object({
5713
+ lineId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5714
+ quantity: z39.number().int().nonnegative()
5509
5715
  });
5510
- var GiftValidationResponseSchema = z36.object({
5511
- adjust: z36.array(GiftAdjustmentSchema).max(REQUEST_BOUNDS.GIFTS_MAX).default([]),
5512
- remove: z36.array(z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX)).max(REQUEST_BOUNDS.GIFTS_MAX).refine(
5716
+ var GiftValidationResponseSchema = z39.object({
5717
+ adjust: z39.array(GiftAdjustmentSchema).max(REQUEST_BOUNDS.GIFTS_MAX).default([]),
5718
+ remove: z39.array(z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX)).max(REQUEST_BOUNDS.GIFTS_MAX).refine(
5513
5719
  (remove) => new Set(remove).size === remove.length,
5514
5720
  "a line id may appear at most once in `remove`"
5515
5721
  )
@@ -5520,47 +5726,47 @@ var GiftValidationResponseSchema = z36.object({
5520
5726
  ({ adjust }) => new Set(adjust.map(({ lineId }) => lineId)).size === adjust.length,
5521
5727
  "a line id may appear at most once in `adjust`"
5522
5728
  );
5523
- var MonetizeTransactionItemSchema = z36.object({
5524
- id: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5525
- priceCents: z36.number(),
5526
- quantity: z36.number(),
5527
- title: z36.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX),
5528
- type: z36.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX)
5729
+ var MonetizeTransactionItemSchema = z39.object({
5730
+ id: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5731
+ priceCents: z39.number(),
5732
+ quantity: z39.number(),
5733
+ title: z39.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX),
5734
+ type: z39.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX)
5529
5735
  });
5530
- var MonetizeInputSchema = z36.object({
5736
+ var MonetizeInputSchema = z39.object({
5531
5737
  cart: CartInputSchema,
5532
5738
  /** Client-minted render-beacon correlation id; forwarded to the ads engine as `client_request_id`. */
5533
- clientRequestId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5534
- country: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5535
- currency: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5739
+ clientRequestId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5740
+ country: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5741
+ currency: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5536
5742
  /** Ads-targeting identity/geo/locale fields (React parity); folded into the engine query verbatim. */
5537
- customerEmail: z36.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
5538
- customerFirstName: z36.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
5539
- customerId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5540
- customerLastName: z36.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
5541
- language: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5743
+ customerEmail: z39.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
5744
+ customerFirstName: z39.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
5745
+ customerId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5746
+ customerLastName: z39.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
5747
+ language: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5542
5748
  /** Buyer-facing order name (e.g. `#1001`) for the server-composed "Order … Confirmed" chrome line. */
5543
- orderName: z36.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
5749
+ orderName: z39.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
5544
5750
  /** Ads surface label, forwarded verbatim; `customer_account` is measured/floored as its own surface (the account-area order list). */
5545
- placement: z36.enum(["customer_account", "order_status", "thank_you_page"]),
5751
+ placement: z39.enum(["customer_account", "order_status", "thank_you_page"]),
5546
5752
  /** Privacy Policy footer href — the Monetize widget's `privacy_policy_url` setting (React parity). */
5547
- privacyPolicyUrl: z36.string().max(REQUEST_BOUNDS.STRING_URL_MAX).optional(),
5753
+ privacyPolicyUrl: z39.string().max(REQUEST_BOUNDS.STRING_URL_MAX).optional(),
5548
5754
  /** 30-min rolling session id (React parity); used for the ads `session_id`, else the visitor id. */
5549
- sessionId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5550
- shop: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5755
+ sessionId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5756
+ shop: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5551
5757
  /** Editor/QA indicator; OR-ed into the ads-engine `testing` flag so it stays out of billing/reporting. */
5552
- testing: z36.boolean().optional(),
5553
- timezone: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5758
+ testing: z39.boolean().optional(),
5759
+ timezone: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5554
5760
  /** Decorated (numeric) order id → the ads `transaction_id`. */
5555
- transactionId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5761
+ transactionId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5556
5762
  /** Rich per-line ads items; capped at the engine's ads contract. Preferred over `cart.items`. */
5557
- transactionItems: z36.array(MonetizeTransactionItemSchema).max(REQUEST_BOUNDS.TRANSACTION_ITEMS_MAX).optional(),
5763
+ transactionItems: z39.array(MonetizeTransactionItemSchema).max(REQUEST_BOUNDS.TRANSACTION_ITEMS_MAX).optional(),
5558
5764
  /** Order total in presentment cents (React prefers total over subtotal); else `cart.subtotal`. */
5559
- transactionTotal: z36.number().optional(),
5560
- visitorId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5561
- zipCode: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5765
+ transactionTotal: z39.number().optional(),
5766
+ visitorId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5767
+ zipCode: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5562
5768
  });
5563
- var WidgetSettingsInputSchema = z36.object({
5769
+ var WidgetSettingsInputSchema = z39.object({
5564
5770
  /**
5565
5771
  * Same domain as `CabShopConfig.cacheKey`, for the same reason: this side WINS the orchestrator's
5566
5772
  * `input.cacheKey ?? config.shop.cacheKey` (and an explicit value skips the config read entirely), so
@@ -5568,9 +5774,9 @@ var WidgetSettingsInputSchema = z36.object({
5568
5774
  * and pin the edge copy permanently stale. `.catch(undefined)` because a bogus buster should degrade
5569
5775
  * the read to un-busted, never 400 a widget render.
5570
5776
  */
5571
- cacheKey: z36.number().int().positive().optional().catch(void 0),
5572
- id: z36.number(),
5573
- key: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5777
+ cacheKey: z39.number().int().positive().optional().catch(void 0),
5778
+ id: z39.number(),
5779
+ key: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5574
5780
  /**
5575
5781
  * Monetize context for inline hydration: when present AND the widget converts to a Monetize marker,
5576
5782
  * the server fetches/composes the offer cards inside this same request (no second `/cab/monetize`
@@ -5579,36 +5785,36 @@ var WidgetSettingsInputSchema = z36.object({
5579
5785
  * `privacyPolicyUrl` comes from the widget settings server-side (more authoritative than a relay).
5580
5786
  */
5581
5787
  monetize: MonetizeInputSchema.omit({ privacyPolicyUrl: true, shop: true }).optional(),
5582
- shop: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5788
+ shop: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5583
5789
  /** Stable per-buyer id; when present, enables sticky server-side A/B variant selection. */
5584
- visitorId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5790
+ visitorId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5585
5791
  });
5586
- var AnalyticsEventInputSchema = z36.object({
5587
- name: z36.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
5588
- properties: z36.record(z36.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z36.unknown()).optional(),
5589
- sentAt: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5792
+ var AnalyticsEventInputSchema = z39.object({
5793
+ name: z39.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
5794
+ properties: z39.record(z39.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z39.unknown()).optional(),
5795
+ sentAt: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5590
5796
  });
5591
- var AnalyticsSegmentsInputSchema = z36.object({
5592
- device: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
5593
- source: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
5594
- visitor: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0)
5797
+ var AnalyticsSegmentsInputSchema = z39.object({
5798
+ device: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
5799
+ source: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
5800
+ visitor: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0)
5595
5801
  });
5596
- var AnalyticsInputSchema = z36.object({
5802
+ var AnalyticsInputSchema = z39.object({
5597
5803
  /** Rebuy cart token (the `r_cart_token` cart attribute), when available — primary aggregation key. */
5598
- cartToken: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5804
+ cartToken: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5599
5805
  /** Shopify checkout token, when available — drives cart/checkout aggregation downstream. */
5600
- checkoutToken: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5601
- events: z36.array(AnalyticsEventInputSchema).max(REQUEST_BOUNDS.EVENTS_MAX),
5806
+ checkoutToken: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
5807
+ events: z39.array(AnalyticsEventInputSchema).max(REQUEST_BOUNDS.EVENTS_MAX),
5602
5808
  /**
5603
5809
  * Request-scoped like the tokens: one visitor's segments apply to every event in the batch. The container
5604
5810
  * degrades too (`null` is a realistic wire artifact of `attributes ? {…} : null`), so the degrade rule is
5605
5811
  * total: nothing about `segments` can cost the envelope.
5606
5812
  */
5607
5813
  segments: AnalyticsSegmentsInputSchema.optional().catch(void 0),
5608
- shop: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5609
- visitorId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5814
+ shop: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5815
+ visitorId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
5610
5816
  /** The widget id (smartBlockId) the events belong to. */
5611
- widgetId: z36.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5817
+ widgetId: z39.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
5612
5818
  });
5613
5819
  export {
5614
5820
  AnalyticsEventInputSchema,