@rebuy/rebuy 3.33.0 → 3.35.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 (35) hide show
  1. package/README.md +1 -1
  2. package/dist/cab/index.cjs +12 -1
  3. package/dist/cab/index.d.ts +1 -0
  4. package/dist/cab/index.mjs +12 -1
  5. package/dist/cab/utf8ByteLength.d.ts +6 -0
  6. package/dist/index.cjs +878 -794
  7. package/dist/index.mjs +879 -795
  8. package/dist/schema/index.d.ts +5 -0
  9. package/dist/schema/postPurchaseGroupCatalog.d.ts +56 -0
  10. package/dist/schema/postPurchaseOfferEligibility.d.ts +32 -0
  11. package/dist/schema/postPurchaseOfferPresentation.d.ts +386 -0
  12. package/dist/schema/postPurchaseProductSource.d.ts +10 -5
  13. package/dist/schema/postPurchaseQuantity.d.ts +13 -0
  14. package/dist/schema/postPurchaseVariantDefault.d.ts +17 -0
  15. package/dist/schema/postPurchaseVariantDefaultContext.d.ts +10 -0
  16. package/dist/server/__fixtures__/postPurchaseGroup.d.ts +75 -0
  17. package/dist/server/classifyPostPurchaseOffer.d.ts +3 -0
  18. package/dist/server/createPostPurchaseOrderAttributes.d.ts +9 -0
  19. package/dist/server/index.cjs +605 -192
  20. package/dist/server/index.d.ts +8 -1
  21. package/dist/server/index.mjs +605 -192
  22. package/dist/server/postPurchaseMemberEligibility.d.ts +7 -0
  23. package/dist/server/postPurchaseOfferCopy.d.ts +3 -0
  24. package/dist/server/postPurchaseProductEligibility.d.ts +3 -7
  25. package/dist/server/postPurchaseSubscriptionEligibility.d.ts +2 -3
  26. package/dist/server/prepareNormalizedSubscription.d.ts +2 -3
  27. package/dist/server/preparePostPurchaseGroupDeclineDisplay.d.ts +12 -0
  28. package/dist/server/preparePostPurchaseOfferPresentation.d.ts +137 -0
  29. package/dist/server/projectPostPurchaseProduct.d.ts +5 -7
  30. package/dist/server/readPostPurchaseGroup.d.ts +101 -0
  31. package/dist/server/readPostPurchaseGroupSelection.d.ts +110 -0
  32. package/dist/server/readPostPurchaseQuantity.d.ts +27 -0
  33. package/dist/server/resolvePostPurchaseMemberDefault.d.ts +8 -0
  34. package/dist/server/selectPostPurchaseChoice.d.ts +2 -3
  35. package/package.json +1 -1
@@ -33,18 +33,25 @@ __export(server_exports, {
33
33
  MonetizeInputSchema: () => MonetizeInputSchema,
34
34
  MonetizeTransactionItemSchema: () => MonetizeTransactionItemSchema,
35
35
  NotFoundError: () => NotFoundError,
36
+ PostPurchaseQuantityUnavailable: () => PostPurchaseQuantityUnavailable,
36
37
  REBUY_ENGINE_HOST: () => REBUY_ENGINE_HOST,
37
38
  REQUEST_BOUNDS: () => REQUEST_BOUNDS,
38
39
  UpstreamError: () => UpstreamError,
39
40
  UserConfigInputSchema: () => UserConfigInputSchema,
40
41
  WidgetSettingsInputSchema: () => WidgetSettingsInputSchema,
41
42
  buildEngineParams: () => buildEngineParams,
43
+ classifyPostPurchaseOffer: () => classifyPostPurchaseOffer,
42
44
  convertWidgetSettings: () => convertWidgetSettings,
45
+ createPostPurchaseOrderAttributes: () => createPostPurchaseOrderAttributes,
43
46
  fetchDataSourceResults: () => fetchDataSourceResults,
44
47
  fetchMonetizeOffers: () => fetchMonetizeOffers,
45
48
  fetchUserConfig: () => fetchUserConfig,
46
49
  postAnalyticsEvents: () => postAnalyticsEvents,
50
+ preparePostPurchaseGroupDeclineDisplay: () => preparePostPurchaseGroupDeclineDisplay,
51
+ preparePostPurchaseOfferPresentation: () => preparePostPurchaseOfferPresentation,
47
52
  preparePostPurchaseSubscription: () => preparePostPurchaseSubscription,
53
+ readPostPurchaseGroupSelection: () => readPostPurchaseGroupSelection,
54
+ readPostPurchaseQuantity: () => readPostPurchaseQuantity,
48
55
  translateAnalyticsEvent: () => translateAnalyticsEvent,
49
56
  validateGifts: () => validateGifts
50
57
  });
@@ -679,7 +686,7 @@ var import_uuid13 = require("uuid");
679
686
  var import_zod27 = require("zod");
680
687
 
681
688
  // src/schema/widgets/checkout-and-beyond/common.ts
682
- var freezeEnum = (values) => Object.freeze(Object.fromEntries(values.map((v) => [v, v])));
689
+ var freezeEnum = (values2) => Object.freeze(Object.fromEntries(values2.map((v) => [v, v])));
683
690
  var bannerColors = ["info", "success", "warning", "critical"];
684
691
  var BannerColor = freezeEnum(bannerColors);
685
692
  var borderRadii = ["none", "small", "base", "large", "fullyRounded"];
@@ -2145,15 +2152,15 @@ var CABImageSectionFields = import_zod27.z.object({
2145
2152
  width: import_zod27.z.number().default(100)
2146
2153
  });
2147
2154
  var iconNameSet = new Set(iconNames);
2148
- var isIconName = (source) => iconNameSet.has(source);
2149
- var CABImageSection = CABImageSectionFields.superRefine(({ category, source }, ctx) => {
2150
- if (category === "icon" && source !== "" && !isIconName(source))
2155
+ var isIconName = (source2) => iconNameSet.has(source2);
2156
+ var CABImageSection = CABImageSectionFields.superRefine(({ category, source: source2 }, ctx) => {
2157
+ if (category === "icon" && source2 !== "" && !isIconName(source2))
2151
2158
  ctx.addIssue({
2152
2159
  code: "custom",
2153
2160
  message: "icon-mode source must be an icon name",
2154
2161
  path: ["source"]
2155
2162
  });
2156
- if (category !== "icon" && isIconName(source))
2163
+ if (category !== "icon" && isIconName(source2))
2157
2164
  ctx.addIssue({
2158
2165
  code: "custom",
2159
2166
  message: "source must be a URL or dynamic token unless category is `icon`",
@@ -2265,10 +2272,10 @@ var HEADER_PARAGRAPH_STYLES = {
2265
2272
  superTitle: { color: "base", fontSize: "extraLarge", marks: [{ type: "bold" }] },
2266
2273
  title: { color: "base", fontSize: "medium", marks: [{ type: "bold" }] }
2267
2274
  };
2268
- var convertContentBlockTextToV2 = (language2, text2 = literalText, textAlign = "center") => {
2269
- const description = language2?.description;
2270
- const superTitle = language2?.superTitle;
2271
- const title = language2?.title;
2275
+ var convertContentBlockTextToV2 = (language3, text2 = literalText, textAlign = "center") => {
2276
+ const description = language3?.description;
2277
+ const superTitle = language3?.superTitle;
2278
+ const title = language3?.title;
2272
2279
  return TiptapDocument.parse({
2273
2280
  attrs: { blockSpacing: "tight" },
2274
2281
  content: [
@@ -2380,7 +2387,7 @@ var LOCATION_TO_EDITOR_MODE = {
2380
2387
  };
2381
2388
 
2382
2389
  // src/transforms/contentBlockV1/convertContentBlockToV2.ts
2383
- var hasText = (language2) => !!language2 && !!(language2.description || language2.superTitle || language2.title);
2390
+ var hasText = (language3) => !!language3 && !!(language3.description || language3.superTitle || language3.title);
2384
2391
  var convertContentBlockToV2 = ({ id, settings }) => {
2385
2392
  const imageBlocks = settings.imageBlocks ?? [];
2386
2393
  return CABRootSection.parse({
@@ -2653,15 +2660,15 @@ var stripHtmlComments = (html = "") => html.replace(HTML_COMMENT_RE2, "");
2653
2660
  var maybeFlushParagraph = (state) => {
2654
2661
  if (state.currentRuns.length > 0) flushParagraph(state);
2655
2662
  };
2656
- var htmlToTiptap = (html, options = {}) => {
2663
+ var htmlToTiptap = (html, options2 = {}) => {
2657
2664
  const state = {
2658
2665
  currentRuns: [],
2659
- defaultTextStyleMark: buildDefaultTextStyleMark(options.defaultTextStyle),
2666
+ defaultTextStyleMark: buildDefaultTextStyleMark(options2.defaultTextStyle),
2660
2667
  listStack: [],
2661
2668
  paragraphs: [],
2662
2669
  stack: []
2663
2670
  };
2664
- const blockSpacing = options.blockSpacing ?? "base";
2671
+ const blockSpacing = options2.blockSpacing ?? "base";
2665
2672
  if (typeof html !== "string" || !html) return makeDoc([makeParagraph([])], blockSpacing);
2666
2673
  const htmlWithoutComments = stripHtmlComments(html);
2667
2674
  let lastIndex = 0;
@@ -2906,9 +2913,9 @@ var isMonetizeV1 = isWidgetV1(WidgetType.ui_extension_ad);
2906
2913
  var HTML_TAG_RE2 = /<[a-zA-Z]/;
2907
2914
  var containsHtml = (text2) => HTML_TAG_RE2.test(text2);
2908
2915
  var isObject = (x) => x !== null && typeof x === "object" && !Array.isArray(x);
2909
- var normalizeTextValue = (value, options = {}) => {
2916
+ var normalizeTextValue = (value, options2 = {}) => {
2910
2917
  const tokenized = normalizeTokens(value);
2911
- return containsHtml(tokenized) || options.defaultTextStyle ? htmlToTiptap(tokenized, options) : decodeTextEntities(tokenized);
2918
+ return containsHtml(tokenized) || options2.defaultTextStyle ? htmlToTiptap(tokenized, options2) : decodeTextEntities(tokenized);
2912
2919
  };
2913
2920
  var normalizeLangValue = (value) => typeof value === "string" ? normalizeTextValue(value) : value;
2914
2921
  var normalizeTextContent = (node) => {
@@ -2941,15 +2948,15 @@ var resolveExperiment = (experiments, placeholderId, visitorId) => {
2941
2948
  if (!experiment || experiment.data.length === 0) return void 0;
2942
2949
  const roll = rollPercent(`${visitorId}:${experiment.id}`);
2943
2950
  let cumulative = 0;
2944
- const variant = experiment.data.find((candidate) => {
2951
+ const variant2 = experiment.data.find((candidate) => {
2945
2952
  cumulative += candidate.traffic;
2946
2953
  return roll < cumulative;
2947
2954
  }) ?? experiment.data[0];
2948
2955
  return {
2949
- elementId: variant.elementId,
2956
+ elementId: variant2.elementId,
2950
2957
  experimentId: experiment.id,
2951
2958
  experimentType: experiment.type,
2952
- selectedId: variant.id
2959
+ selectedId: variant2.id
2953
2960
  };
2954
2961
  };
2955
2962
 
@@ -3397,23 +3404,23 @@ var QUANTITY_INPUT_TYPE = {
3397
3404
  "buttons-manual-input": "number",
3398
3405
  "dropdown-select": "select"
3399
3406
  };
3400
- var buildQuantityErrors = (quantity) => {
3407
+ var buildQuantityErrors = (quantity2) => {
3401
3408
  const en = {
3402
- ...quantity.maxError && { max: normalizeTokens(quantity.maxError, QUANTITY_ERROR_TOKENS) },
3403
- ...quantity.minError && { min: normalizeTokens(quantity.minError, QUANTITY_ERROR_TOKENS) },
3404
- ...quantity.negativeError && { neg: normalizeTokens(quantity.negativeError, QUANTITY_ERROR_TOKENS) }
3409
+ ...quantity2.maxError && { max: normalizeTokens(quantity2.maxError, QUANTITY_ERROR_TOKENS) },
3410
+ ...quantity2.minError && { min: normalizeTokens(quantity2.minError, QUANTITY_ERROR_TOKENS) },
3411
+ ...quantity2.negativeError && { neg: normalizeTokens(quantity2.negativeError, QUANTITY_ERROR_TOKENS) }
3405
3412
  };
3406
3413
  return Object.keys(en).length ? { errorMessages: { en } } : {};
3407
3414
  };
3408
3415
  var buildQuantity = (settings) => {
3409
- const quantity = settings.quantityInputs;
3410
- if (!quantity?.enabled) return [];
3411
- const inputType = quantity.type ? QUANTITY_INPUT_TYPE[quantity.type] : void 0;
3412
- const max = Math.min(Math.max(quantity.maxValue ?? 10, 1), 100);
3413
- const min = Math.min(Math.max(quantity.minValue ?? 1, 1), max);
3416
+ const quantity2 = settings.quantityInputs;
3417
+ if (!quantity2?.enabled) return [];
3418
+ const inputType = quantity2.type ? QUANTITY_INPUT_TYPE[quantity2.type] : void 0;
3419
+ const max = Math.min(Math.max(quantity2.maxValue ?? 10, 1), 100);
3420
+ const min = Math.min(Math.max(quantity2.minValue ?? 1, 1), max);
3414
3421
  return [
3415
3422
  {
3416
- ...buildQuantityErrors(quantity),
3423
+ ...buildQuantityErrors(quantity2),
3417
3424
  ...inputType && { inputType },
3418
3425
  max,
3419
3426
  min,
@@ -3423,7 +3430,7 @@ var buildQuantity = (settings) => {
3423
3430
  };
3424
3431
  var buildSubscriptionButton = (settings) => {
3425
3432
  if (settings.productType !== "both" && settings.productType !== "subscription") return [];
3426
- const language2 = settings.language;
3433
+ const language3 = settings.language;
3427
3434
  const slot = (buttonField, override) => ({
3428
3435
  buttonField,
3429
3436
  content: localizedContent(SWITCH_LABELS[buttonField], override, SWITCH_LABEL_TOKENS2),
@@ -3437,9 +3444,9 @@ var buildSubscriptionButton = (settings) => {
3437
3444
  ...settings.productType === "subscription" && { disableDowngrade: true },
3438
3445
  sections: [
3439
3446
  slot("subscriptionOption", void 0),
3440
- slot("switchToOneTimePurchase", language2?.cartSwitchToOnetime),
3441
- slot("switchToSubscriptionNoDiscount", language2?.upgradeToSubscription),
3442
- slot("switchToSubscriptionWithDiscount", language2?.upgradeToSubscription)
3447
+ slot("switchToOneTimePurchase", language3?.cartSwitchToOnetime),
3448
+ slot("switchToSubscriptionNoDiscount", language3?.upgradeToSubscription),
3449
+ slot("switchToSubscriptionWithDiscount", language3?.upgradeToSubscription)
3443
3450
  ],
3444
3451
  sectionType: "button"
3445
3452
  }
@@ -3494,11 +3501,11 @@ var buildOfferCard = (settings, horizontal) => {
3494
3501
  const description = buildDescription(settings);
3495
3502
  const reviews = buildReviews(settings);
3496
3503
  const variants = buildVariants(settings);
3497
- const quantity = buildQuantity(settings);
3504
+ const quantity2 = buildQuantity(settings);
3498
3505
  const subscription2 = buildSubscriptionButton(settings);
3499
3506
  const reveal = buildRevealButton(settings);
3500
3507
  const addButton = buildAddButton(settings);
3501
- const controls = [...description, ...quantity, ...variants, ...subscription2];
3508
+ const controls = [...description, ...quantity2, ...variants, ...subscription2];
3502
3509
  const info = detailBlock([title, ...variantTitle, ...reviews, price], horizontal, variantTitle.length > 0);
3503
3510
  const card = (sections) => [
3504
3511
  {
@@ -3552,9 +3559,9 @@ var buildCarouselNav = () => ({
3552
3559
  sectionType: "layout"
3553
3560
  });
3554
3561
  var HEADER_FIELDS = ["superTitle", "title", "description"];
3555
- var sanitizedHeader = (language2) => Object.fromEntries(
3562
+ var sanitizedHeader = (language3) => Object.fromEntries(
3556
3563
  HEADER_FIELDS.flatMap((field) => {
3557
- const value = language2?.[field];
3564
+ const value = language3?.[field];
3558
3565
  const sanitized = value ? stripContentBlockHtml(normalizeTokens(value)) : "";
3559
3566
  return sanitized ? [[field, sanitized]] : [];
3560
3567
  })
@@ -3651,7 +3658,7 @@ var coerceIntegrations = (integrations) => Object.fromEntries(
3651
3658
  return [key, value];
3652
3659
  })
3653
3660
  );
3654
- var buildBanner = (language2) => language2?.successBannerEnabled ? [
3661
+ var buildBanner = (language3) => language3?.successBannerEnabled ? [
3655
3662
  {
3656
3663
  /**
3657
3664
  * The banner-level tag is the extraction/routing key on BOTH renderers (React CAB's
@@ -3664,7 +3671,7 @@ var buildBanner = (language2) => language2?.successBannerEnabled ? [
3664
3671
  dismissible: true,
3665
3672
  sections: [
3666
3673
  {
3667
- content: bannerMessageContent(language2.successBannerMessageRte),
3674
+ content: bannerMessageContent(language3.successBannerMessageRte),
3668
3675
  sectionType: "text"
3669
3676
  },
3670
3677
  {
@@ -3981,14 +3988,14 @@ var convertCalloutBlock = (raw, report) => {
3981
3988
  };
3982
3989
  const shell = Shell.safeParse(raw);
3983
3990
  if (!shell.success) return omit("Unreadable post-purchase callout");
3984
- const values = fields.map((field) => ({
3991
+ const values2 = fields.map((field) => ({
3985
3992
  field,
3986
3993
  result: CalloutBannerBlock.shape.settings.shape[field].safeParse(shell.data.settings[field])
3987
3994
  }));
3988
- const styled2 = values.every(({ result }) => result.success && typeof result.data === "string");
3995
+ const styled2 = values2.every(({ result }) => result.success && typeof result.data === "string");
3989
3996
  const styles2 = shell.data.styles;
3990
3997
  const horizontal = styled2 ? { center: "center", leading: "start", trailing: "end" }[styles2.textAlignment] : "center";
3991
- const sections = values.flatMap(({ field, result }) => {
3998
+ const sections = values2.flatMap(({ field, result }) => {
3992
3999
  if (!result.success) return omit(`Unreadable post-purchase callout field: ${field}`);
3993
4000
  const text2 = result.data;
3994
4001
  if (text2 === "") return [];
@@ -4010,12 +4017,12 @@ var convertCalloutBlock = (raw, report) => {
4010
4017
  var import_zod32 = require("zod");
4011
4018
 
4012
4019
  // src/transforms/postPurchase/sizeImageSource.ts
4013
- var sizeImageSource = (source, size) => {
4014
- const extension = source.split(".").pop();
4020
+ var sizeImageSource = (source2, size) => {
4021
+ const extension = source2.split(".").pop();
4015
4022
  for (const previous of ["small", "medium", "large", "original", "master"]) {
4016
- source = source.replace(`_${previous}.${extension}`, `.${extension}`);
4023
+ source2 = source2.replace(`_${previous}.${extension}`, `.${extension}`);
4017
4024
  }
4018
- return source.replace(`.${extension}`, `${size === void 0 ? "" : `_${size}`}.${extension}`);
4025
+ return source2.replace(`.${extension}`, `${size === void 0 ? "" : `_${size}`}.${extension}`);
4019
4026
  };
4020
4027
 
4021
4028
  // src/transforms/postPurchase/convertImageFrame.ts
@@ -4025,9 +4032,9 @@ var convertImageFrame = (raw) => {
4025
4032
  const parsed = ImageBlock.shape.settings.options[0].safeParse(raw);
4026
4033
  if (!parsed.success) return null;
4027
4034
  const settings = parsed.data;
4028
- const source = sizeImageSource(Source.parse(settings.image || void 0));
4029
- const withAlt = CABImageSection.safeParse({ altText: settings.alt, source });
4030
- const image = withAlt.success ? withAlt.data : CABImageSection.parse({ source });
4035
+ const source2 = sizeImageSource(Source.parse(settings.image || void 0));
4036
+ const withAlt = CABImageSection.safeParse({ altText: settings.alt, source: source2 });
4037
+ const image = withAlt.success ? withAlt.data : CABImageSection.parse({ source: source2 });
4031
4038
  const size = settings.imageSize > 0 ? settings.imageSize : DEFAULT_IMAGE_SIZE;
4032
4039
  return CABLayoutSection.parse({
4033
4040
  alignment: { horizontal: "center" },
@@ -4264,19 +4271,19 @@ var convertTextBlock = (raw, report) => {
4264
4271
  report?.({ detail: "Unreadable post-purchase text block", kind: "section" });
4265
4272
  return [];
4266
4273
  }
4267
- const values = fields3.map((field) => ({
4274
+ const values2 = fields3.map((field) => ({
4268
4275
  field,
4269
4276
  result: settingsSchema.shape[field].safeParse(shell.data.settings[field])
4270
4277
  }));
4271
4278
  const horizontal = { center: "center", leading: "start", trailing: "end" }[shell.data.settings.horizontalAlignment];
4272
- const styled2 = values.every(
4279
+ const styled2 = values2.every(
4273
4280
  ({ result }) => result.success && (result.data === null || typeof result.data === "string")
4274
4281
  );
4275
4282
  const omit = (field) => {
4276
4283
  report?.({ detail: `Unreadable post-purchase text field: ${field}`, kind: "section" });
4277
4284
  return [];
4278
4285
  };
4279
- const sections = values.flatMap(({ field, result }) => {
4286
+ const sections = values2.flatMap(({ field, result }) => {
4280
4287
  if (!result.success) return omit(field);
4281
4288
  const text2 = result.data;
4282
4289
  if (text2 === null || text2 === "") return [];
@@ -4510,10 +4517,10 @@ var giftOf = (tier) => {
4510
4517
  if (tier.type !== "product") return void 0;
4511
4518
  const product = tier.products?.[0] ?? tier.allProducts?.[0];
4512
4519
  if (!product) return void 0;
4513
- const productId = product.productId ?? product.id;
4514
- if (productId === void 0) return void 0;
4520
+ const productId2 = product.productId ?? product.id;
4521
+ if (productId2 === void 0) return void 0;
4515
4522
  return {
4516
- productId,
4523
+ productId: productId2,
4517
4524
  title: product.title,
4518
4525
  variantIds: positiveIds(product.variantIds)
4519
4526
  };
@@ -4792,14 +4799,14 @@ function serialize(obj) {
4792
4799
  var encodeAttributes = (pairs = []) => JSON.stringify(Object.fromEntries(pairs.map(({ key, value }) => [key, value ?? ""])));
4793
4800
  var buildEngineParams = (input, key) => {
4794
4801
  const { cart, customerId, filterInputs, integrations, limit, productType, shop, visitorId } = input;
4795
- const items = cart.items.map(({ productId, properties, quantity, subscriptionId, variantId }) => ({
4796
- product_id: productId,
4802
+ const items = cart.items.map(({ productId: productId2, properties, quantity: quantity2, subscriptionId, variantId }) => ({
4803
+ product_id: productId2,
4797
4804
  properties: encodeAttributes(properties),
4798
- quantity,
4805
+ quantity: quantity2,
4799
4806
  ...subscriptionId && { subscription_id: subscriptionId },
4800
4807
  variant_id: variantId
4801
4808
  }));
4802
- const itemCount = cart.items.reduce((total, { quantity }) => total + quantity, 0);
4809
+ const itemCount = cart.items.reduce((total, { quantity: quantity2 }) => total + quantity2, 0);
4803
4810
  const subtotal = shopSubtotalCents(cart);
4804
4811
  return {
4805
4812
  cart: {
@@ -4886,13 +4893,13 @@ var OFFER_LIMIT = 4;
4886
4893
  var SUPPORTED_COUNTRIES = /* @__PURE__ */ new Set(["US", "CA", "GB"]);
4887
4894
  var MAX_TRANSACTION_ITEMS = 50;
4888
4895
  var TEST_CUSTOMER_EMAIL = "test@rebuyengine.com";
4889
- var transactionItems = (input) => (input.transactionItems?.map(({ id, priceCents, quantity, title, type }) => ({
4896
+ var transactionItems = (input) => (input.transactionItems?.map(({ id, priceCents, quantity: quantity2, title, type }) => ({
4890
4897
  id,
4891
4898
  price_cents: priceCents,
4892
- quantity,
4899
+ quantity: quantity2,
4893
4900
  title,
4894
4901
  type
4895
- })) ?? input.cart.items.map(({ productId, quantity }) => ({ id: productId, quantity }))).slice(0, MAX_TRANSACTION_ITEMS);
4902
+ })) ?? input.cart.items.map(({ productId: productId2, quantity: quantity2 }) => ({ id: productId2, quantity: quantity2 }))).slice(0, MAX_TRANSACTION_ITEMS);
4896
4903
  var AdsEngineOffer = import_zod37.z.object({
4897
4904
  /** Pill-style value prop ("Get $45 Cashback"). Carried through the parse; the card does not render it yet (REB-24429 — pill design pending). */
4898
4905
  callout: import_zod37.z.string().catch(""),
@@ -5010,9 +5017,9 @@ var label = (text2) => ({
5010
5017
  });
5011
5018
  var text = (content) => ({ content: { en: content }, sectionType: SectionType.text });
5012
5019
  var AS_DOC = { defaultTextStyle: {} };
5013
- var safeTextValue = (raw, options) => {
5014
- const converted = normalizeTextValue(raw, options);
5015
- return checkForHTML(converted) ? converted : normalizeTextValue(htmlToPlainText(raw), options);
5020
+ var safeTextValue = (raw, options2) => {
5021
+ const converted = normalizeTextValue(raw, options2);
5022
+ return checkForHTML(converted) ? converted : normalizeTextValue(htmlToPlainText(raw), options2);
5016
5023
  };
5017
5024
  var headlineText = (raw) => {
5018
5025
  const doc = safeTextValue(raw, AS_DOC);
@@ -5496,11 +5503,11 @@ var validateGifts = async (input, ctx) => {
5496
5503
  const [remove, adjust] = await Promise.all([validateGwpGifts(input, ctx), validateSelectableGifts(input, ctx)]);
5497
5504
  const removed = new Set(remove);
5498
5505
  const targets = /* @__PURE__ */ new Map();
5499
- for (const { lineId, quantity } of adjust) {
5506
+ for (const { lineId, quantity: quantity2 } of adjust) {
5500
5507
  if (removed.has(lineId)) continue;
5501
- targets.set(lineId, Math.min(quantity, targets.get(lineId) ?? quantity));
5508
+ targets.set(lineId, Math.min(quantity2, targets.get(lineId) ?? quantity2));
5502
5509
  }
5503
- return { adjust: [...targets].map(([lineId, quantity]) => ({ lineId, quantity })), remove: [...removed] };
5510
+ return { adjust: [...targets].map(([lineId, quantity2]) => ({ lineId, quantity: quantity2 })), remove: [...removed] };
5504
5511
  };
5505
5512
 
5506
5513
  // src/server/normalizePostPurchaseProduct.ts
@@ -5832,14 +5839,14 @@ var SourceAdjustment = import_zod47.z.object({
5832
5839
  type: import_zod47.z.enum(["percentage", "fixed_amount", "amount", "price", "none", "fixed"])
5833
5840
  });
5834
5841
  var readPostPurchasePlanAdjustment = (raw) => {
5835
- const source = SourceAdjustment.parse(raw);
5836
- if (source.type === "none" || source.type === "fixed") {
5837
- if (source.amount !== 0) throw new Error("Unsupported plan adjustment");
5842
+ const source2 = SourceAdjustment.parse(raw);
5843
+ if (source2.type === "none" || source2.type === "fixed") {
5844
+ if (source2.amount !== 0) throw new Error("Unsupported plan adjustment");
5838
5845
  return void 0;
5839
5846
  }
5840
5847
  const adjustment = PostPurchasePlanAdjustment.parse({
5841
- amount: source.amount,
5842
- type: source.type === "amount" ? "fixed_amount" : source.type
5848
+ amount: source2.amount,
5849
+ type: source2.type === "amount" ? "fixed_amount" : source2.type
5843
5850
  });
5844
5851
  return adjustment.amount === 0 && adjustment.type !== "price" ? void 0 : adjustment;
5845
5852
  };
@@ -5916,12 +5923,12 @@ var projectPostPurchasePlanCatalog = (normalized, report) => {
5916
5923
  const { data } = normalized;
5917
5924
  if (data.length !== 1 || data[0].variants.length !== 1) throw new Error("Ambiguous product");
5918
5925
  const product = data[0];
5919
- const variant = product.variants[0];
5920
- if (variant.productId !== product.id) throw new Error("Foreign variant");
5926
+ const variant2 = product.variants[0];
5927
+ if (variant2.productId !== product.id) throw new Error("Foreign variant");
5921
5928
  const groups = product.sellingPlanGroups;
5922
5929
  const required = groups.map((group) => group.requiresSellingPlan);
5923
5930
  if (required.some((flag) => flag !== required[0])) throw new Error("Conflicting requirement");
5924
- const plans = typeof groups[0]?.id === "number" ? readPostPurchaseLegacyPlans(groups[0], variant.id) : readPostPurchaseModernPlans(groups, variant.sellingPlanAllocations);
5931
+ const plans = typeof groups[0]?.id === "number" ? readPostPurchaseLegacyPlans(groups[0], variant2.id) : readPostPurchaseModernPlans(groups, variant2.sellingPlanAllocations);
5925
5932
  const unique = /* @__PURE__ */ new Map();
5926
5933
  for (const plan of plans) {
5927
5934
  const previous = unique.get(plan.id);
@@ -5932,7 +5939,7 @@ var projectPostPurchasePlanCatalog = (normalized, report) => {
5932
5939
  plans: [...unique.values()],
5933
5940
  productId: product.id,
5934
5941
  requiresSellingPlan: required[0] ?? false,
5935
- variantId: variant.id
5942
+ variantId: variant2.id
5936
5943
  });
5937
5944
  } catch {
5938
5945
  report?.({ detail: "Unreadable post-purchase plan catalog", kind: "product" });
@@ -6072,20 +6079,20 @@ var PostPurchaseSubscriptionSettings = subscription.extend({
6072
6079
  });
6073
6080
 
6074
6081
  // src/server/postPurchaseVariantAvailable.ts
6075
- var postPurchaseVariantAvailable = (variant) => !(variant.inventoryManagement && variant.inventoryPolicy === "deny" && variant.inventoryQuantity <= 0);
6082
+ var postPurchaseVariantAvailable = (variant2) => !(variant2.inventoryManagement && variant2.inventoryPolicy === "deny" && variant2.inventoryQuantity <= 0);
6076
6083
 
6077
6084
  // src/server/postPurchaseSubscriptionEligibility.ts
6078
- var subscriptionUnavailable = (normalized, plan, allowCollection, quantity) => {
6085
+ var subscriptionUnavailable = (normalized, plan, allowCollection, quantity2) => {
6079
6086
  const { data, effective, original } = normalized;
6080
6087
  const unavailable = "An eligible subscription plan with supported shipping and discount is required";
6081
6088
  if (data.length !== 1 || data[0].variants.length !== 1) return unavailable;
6082
6089
  if (effective.productType === "one-time" || [original, effective].some(
6083
- (config) => !allowCollection && config.productLimit !== 1 || config.upgradeToSubscription.allow || !quantity && config.quantityInputs.enabled && (config.quantityInputs.minValue !== config.quantityInputs.maxValue || config.quantityInputs.defaultQuantity !== config.quantityInputs.minValue)
6090
+ (config) => !allowCollection && config.productLimit !== 1 || config.upgradeToSubscription.allow || !quantity2 && config.quantityInputs.enabled && (config.quantityInputs.minValue !== config.quantityInputs.maxValue || config.quantityInputs.defaultQuantity !== config.quantityInputs.minValue)
6084
6091
  ))
6085
6092
  return unavailable;
6086
6093
  const product = data[0];
6087
- const variant = product.variants[0];
6088
- if (product.productGroupVariants.length || !postPurchaseVariantAvailable(variant) || variant.productId !== product.id)
6094
+ const variant2 = product.variants[0];
6095
+ if (product.productGroupVariants.length || !postPurchaseVariantAvailable(variant2) || variant2.productId !== product.id)
6089
6096
  return unavailable;
6090
6097
  const terms = [original, effective].map(
6091
6098
  (config) => PostPurchaseSubscriptionSettings.safeParse(config.subscription)
@@ -6100,8 +6107,8 @@ var import_zod55 = require("zod");
6100
6107
  var postPurchasePrimaryImage = (product) => {
6101
6108
  const variantImageId = product.variants[0].imageId;
6102
6109
  const selectedImage = variantImageId ? product.images?.find((image) => image.id === variantImageId) : void 0;
6103
- const source = PostPurchasePrimaryImageSource.parse((selectedImage ?? product.image)?.src || void 0);
6104
- return { description: product.title, source: sizeImageSource(source, "800x800") };
6110
+ const source2 = PostPurchasePrimaryImageSource.parse((selectedImage ?? product.image)?.src || void 0);
6111
+ return { description: product.title, source: sizeImageSource(source2, "800x800") };
6105
6112
  };
6106
6113
 
6107
6114
  // src/server/postPurchaseProductGallery.ts
@@ -6130,26 +6137,26 @@ var projectPostPurchaseProductDisplay = (effective, metadata, product) => PostPu
6130
6137
  // src/server/projectPostPurchaseProduct.ts
6131
6138
  var projectPostPurchaseProduct = ({ data, effective, metadata, original }, selectedQuantity) => {
6132
6139
  const product = data[0];
6133
- const variant = product.variants[0];
6140
+ const variant2 = product.variants[0];
6134
6141
  return {
6135
6142
  display: projectPostPurchaseProductDisplay(effective, metadata, product),
6136
6143
  labels: effective.language.global,
6137
- product: { ...product, variant },
6144
+ product: { ...product, variant: variant2 },
6138
6145
  selection: {
6139
6146
  productId: product.id,
6140
6147
  quantity: selectedQuantity?.quantity ?? product.metadata?.productQuantity ?? (original.quantityInputs.enabled ? original.quantityInputs.defaultQuantity : 1),
6141
- variantId: variant.id
6148
+ variantId: variant2.id
6142
6149
  }
6143
6150
  };
6144
6151
  };
6145
6152
 
6146
6153
  // src/server/prepareNormalizedSubscription.ts
6147
- var prepareNormalizedSubscription = (normalized, report, plan, quantity, allowCollection = false) => {
6154
+ var prepareNormalizedSubscription = (normalized, report, plan, quantity2, allowCollection = false) => {
6148
6155
  if (!plan) return { reason: "Subscription plan is unavailable", status: "unsupported" };
6149
- const reason = subscriptionUnavailable(normalized, plan, allowCollection, quantity);
6156
+ const reason = subscriptionUnavailable(normalized, plan, allowCollection, quantity2);
6150
6157
  if (reason) return { reason, status: "unsupported" };
6151
6158
  const { effective } = normalized;
6152
- const projected = projectPostPurchaseProduct(normalized, quantity);
6159
+ const projected = projectPostPurchaseProduct(normalized, quantity2);
6153
6160
  const { discount, shipping } = PostPurchaseSubscriptionSettings.parse(effective.subscription);
6154
6161
  const shippingPrice = shipping.type === "free" ? 0 : shipping.amount;
6155
6162
  return PreparedPostPurchaseSubscription.parse({
@@ -6186,6 +6193,412 @@ var preparePostPurchaseSubscription = (settings, response, report) => {
6186
6193
  );
6187
6194
  };
6188
6195
 
6196
+ // src/schema/postPurchaseOfferEligibility.ts
6197
+ var import_zod57 = require("zod");
6198
+
6199
+ // src/schema/postPurchaseProductCollectionView.ts
6200
+ var import_zod56 = require("zod");
6201
+ var PostPurchaseExcludedProductIds = import_zod56.z.array(PostPurchaseProductId).default([]);
6202
+
6203
+ // src/schema/postPurchaseOfferEligibility.ts
6204
+ var selection = PreparedPostPurchaseProduct.shape.selection;
6205
+ var PostPurchaseOfferSkipReason = import_zod57.z.enum(["empty", "no-eligible-subscription"]);
6206
+ var PostPurchaseOfferEligibilityContext = import_zod57.z.object({
6207
+ excludedProductIds: PostPurchaseExcludedProductIds,
6208
+ originalLineItems: import_zod57.z.array(selection.pick({ productId: true, sellingPlanId: true, variantId: true }))
6209
+ });
6210
+ var PostPurchaseOfferEligibility = import_zod57.z.discriminatedUnion("status", [
6211
+ import_zod57.z.object({
6212
+ members: import_zod57.z.array(
6213
+ import_zod57.z.object({ productId: selection.shape.productId, productIndex: import_zod57.z.number().int().nonnegative() })
6214
+ ),
6215
+ status: import_zod57.z.literal("retain")
6216
+ }),
6217
+ import_zod57.z.object({ reason: PostPurchaseOfferSkipReason, status: import_zod57.z.literal("skip") }),
6218
+ import_zod57.z.object({ reason: import_zod57.z.literal("eligible-upgrade").optional(), status: import_zod57.z.literal("unavailable") })
6219
+ ]);
6220
+
6221
+ // src/server/normalizePostPurchaseCollection.ts
6222
+ var import_zod58 = require("zod");
6223
+ var normalizePostPurchaseCollection = (settings, response, excludedProductIds) => {
6224
+ const normalized = normalizePostPurchaseProduct(settings, response);
6225
+ const limit = import_zod58.z.number().int().positive();
6226
+ limit.parse(normalized.original.productLimit);
6227
+ const prefix = normalized.data.slice(0, limit.parse(normalized.effective.productLimit));
6228
+ if (new Set(prefix.map(({ id }) => id)).size !== prefix.length)
6229
+ throw new Error("Ambiguous post-purchase collection");
6230
+ const excluded = new Set(PostPurchaseExcludedProductIds.parse(excludedProductIds));
6231
+ const members = prefix.map((product, productIndex) => ({ product, productIndex })).filter(({ product }) => !excluded.has(product.id));
6232
+ return { members, normalized };
6233
+ };
6234
+
6235
+ // src/schema/postPurchaseVariantCatalog.ts
6236
+ var import_zod59 = require("zod");
6237
+ var PostPurchaseVariantSelector = import_zod59.z.object({ variantId: PostPurchaseVariantId }).strict();
6238
+ var PostPurchaseVariantOption = OfferProduct.shape.options.element.extend({
6239
+ id: import_zod59.z.number().int().positive(),
6240
+ position: import_zod59.z.number().int().min(1).max(3)
6241
+ });
6242
+ var PostPurchaseVariantValues = OfferProduct.shape.variants.element.pick({
6243
+ option1: true,
6244
+ option2: true,
6245
+ option3: true
6246
+ });
6247
+ var PostPurchaseVariantCatalog = import_zod59.z.object({
6248
+ displayMode: PostPurchaseSettings.shape.productOptions.shape.variantSelectorDisplayMode,
6249
+ options: import_zod59.z.array(PostPurchaseVariantOption),
6250
+ productId: PostPurchaseProductId,
6251
+ showSelectors: PostPurchaseSettings.shape.productOptions.shape.showVariantSelectors,
6252
+ variants: import_zod59.z.array(
6253
+ PostPurchaseVariantValues.partial().extend({
6254
+ available: import_zod59.z.boolean(),
6255
+ id: PostPurchaseVariantId,
6256
+ imageId: import_zod59.z.number().int().nonnegative().nullish(),
6257
+ title: OfferProduct.shape.variants.element.shape.title
6258
+ })
6259
+ )
6260
+ });
6261
+
6262
+ // src/server/postPurchaseVariantCatalog.ts
6263
+ var projectPostPurchaseVariantCatalog = (product, settings) => {
6264
+ const options2 = PostPurchaseVariantCatalog.shape.options.parse(product.options === void 0 ? [] : product.options).sort((a, b) => a.position - b.position);
6265
+ const variants = product.variants.map((variant2) => ({
6266
+ ...variant2,
6267
+ ...PostPurchaseVariantValues.partial().parse(variant2)
6268
+ }));
6269
+ const tuples = variants.map(({ option1, option2, option3 }) => [option1, option2, option3]);
6270
+ if (new Set(product.variants.map(({ id }) => id)).size !== product.variants.length || product.variants.some(({ productId: productId2 }) => productId2 !== product.id) || new Set(options2.map(({ id }) => id)).size !== options2.length || options2.some(
6271
+ ({ position, values: values2 }, index) => position !== index + 1 || new Set(values2).size !== values2.length
6272
+ ) || product.variants.length > 1 && new Set(tuples.map((tuple) => JSON.stringify(tuple))).size !== tuples.length)
6273
+ throw new Error("Ambiguous post-purchase variant catalog");
6274
+ for (const tuple of tuples) {
6275
+ if (options2.some(({ position, values: values2 }) => !values2.some((value) => value === tuple[position - 1])) || tuple.some((value, index) => value != null && !options2[index]))
6276
+ throw new Error("Variant option tuple does not match the catalog");
6277
+ }
6278
+ return PostPurchaseVariantCatalog.parse({
6279
+ displayMode: settings.productOptions.variantSelectorDisplayMode,
6280
+ options: options2,
6281
+ productId: product.id,
6282
+ showSelectors: settings.productOptions.showVariantSelectors,
6283
+ variants: variants.map(({ id, imageId, option1, option2, option3, title, ...inventory }) => ({
6284
+ available: postPurchaseVariantAvailable(inventory),
6285
+ id,
6286
+ imageId,
6287
+ option1,
6288
+ option2,
6289
+ option3,
6290
+ title
6291
+ }))
6292
+ });
6293
+ };
6294
+
6295
+ // src/schema/postPurchaseGroupCatalog.ts
6296
+ var import_zod60 = require("zod");
6297
+ var productId = PreparedPostPurchaseProduct.shape.selection.shape.productId;
6298
+ var source = PostPurchaseProductSource.shape.data.element;
6299
+ var PostPurchaseGroupDescription = source.pick({ description: true, id: true, image: true, images: true, title: true }).extend({
6300
+ description: source.shape.description.default(null),
6301
+ image: source.shape.image.default(null),
6302
+ options: PostPurchaseVariantCatalog.shape.options.default([])
6303
+ });
6304
+ var PostPurchaseGroupCatalog = import_zod60.z.object({
6305
+ memberProductId: productId,
6306
+ options: import_zod60.z.array(import_zod60.z.object({ productId, title: import_zod60.z.string(), variantCatalog: PostPurchaseVariantCatalog }))
6307
+ });
6308
+ var PostPurchaseGroupSelection = import_zod60.z.object({
6309
+ memberProductId: productId,
6310
+ productId
6311
+ });
6312
+
6313
+ // src/server/readPostPurchaseGroup.ts
6314
+ var readPostPurchaseGroup = (product, settings, excludedProductIds) => {
6315
+ const descriptions = PostPurchaseGroupDescription.nullable().array().parse(product.productGroupVariants).filter((value) => value !== null);
6316
+ const ids = new Set(descriptions.map((value) => value.id));
6317
+ if (ids.size !== descriptions.length || new Set(product.variants.map(({ id }) => id)).size !== product.variants.length || product.variants.some(({ productId: productId2 }) => !ids.has(productId2)))
6318
+ throw new Error("Ambiguous post-purchase group ownership");
6319
+ const excluded = new Set(PostPurchaseExcludedProductIds.parse(excludedProductIds));
6320
+ const entries = descriptions.map((description) => {
6321
+ const value = {
6322
+ ...product,
6323
+ ...description,
6324
+ images: description.images,
6325
+ productGroupVariants: [],
6326
+ variants: product.variants.filter(({ productId: productId2 }) => productId2 === description.id)
6327
+ };
6328
+ return { product: value, variantCatalog: projectPostPurchaseVariantCatalog(value, settings) };
6329
+ }).filter(({ product: value }) => !excluded.has(value.id));
6330
+ return {
6331
+ catalog: PostPurchaseGroupCatalog.parse({
6332
+ memberProductId: product.id,
6333
+ options: entries.map(({ product: value, variantCatalog }) => ({
6334
+ productId: value.id,
6335
+ title: value.title,
6336
+ variantCatalog
6337
+ }))
6338
+ }),
6339
+ entries
6340
+ };
6341
+ };
6342
+
6343
+ // src/server/postPurchaseMemberEligibility.ts
6344
+ var PostPurchaseInventoryUnavailable = class extends Error {
6345
+ };
6346
+ var postPurchaseMemberEligibility = (normalized, product, excluded) => {
6347
+ if (product.productGroupVariants.length) {
6348
+ const group = readPostPurchaseGroup(product, normalized.effective, excluded);
6349
+ return group.entries.map(({ product: option }) => postPurchaseMemberEligibility(normalized, option)).some(Boolean);
6350
+ }
6351
+ if (!product.variants.length) throw new Error("Unsupported catalog");
6352
+ const variants = projectPostPurchaseVariantCatalog(product, normalized.effective).variants;
6353
+ const catalogs = product.variants.map((variant2) => {
6354
+ const catalog = projectPostPurchasePlanCatalog({
6355
+ ...normalized,
6356
+ data: [{ ...product, variants: [variant2] }]
6357
+ });
6358
+ if (!catalog) throw new Error("Unreadable subscription catalog");
6359
+ if (normalized.effective.productType === "one-time" && catalog.requiresSellingPlan)
6360
+ throw new Error("Unsupported purchase mode");
6361
+ return catalog;
6362
+ });
6363
+ if (!variants.some((variant2) => variant2.available))
6364
+ throw new PostPurchaseInventoryUnavailable("Unavailable inventory");
6365
+ return catalogs.some(
6366
+ (catalog, index) => variants[index].available && (normalized.effective.productType !== "subscription" && !catalog.requiresSellingPlan || normalized.effective.productType !== "one-time" && catalog.plans.length > 0)
6367
+ );
6368
+ };
6369
+
6370
+ // src/server/classifyPostPurchaseOffer.ts
6371
+ var classifyPostPurchaseOffer = (settings, response, context) => {
6372
+ try {
6373
+ const trusted = PostPurchaseOfferEligibilityContext.parse(context);
6374
+ const { members, normalized } = normalizePostPurchaseCollection(settings, response);
6375
+ const configurations = [normalized.original, normalized.effective];
6376
+ const upgrades = configurations.some((config) => config.upgradeToSubscription.allow);
6377
+ const oneTime = new Set(
6378
+ trusted.originalLineItems.filter((line) => line.sellingPlanId === void 0).map((line) => line.variantId)
6379
+ );
6380
+ if (upgrades && members.some(
6381
+ ({ product }) => product.sellingPlanGroups?.length && product.variants.some((variant2) => oneTime.has(variant2.id))
6382
+ ))
6383
+ return { reason: "eligible-upgrade", status: "unavailable" };
6384
+ if (normalized.effective.productType !== "one-time") {
6385
+ configurations.forEach((config) => PostPurchaseSubscriptionSettings.parse(config.subscription));
6386
+ }
6387
+ const classified = members.map((member) => {
6388
+ try {
6389
+ return {
6390
+ ...member,
6391
+ eligible: postPurchaseMemberEligibility(normalized, member.product, trusted.excludedProductIds)
6392
+ };
6393
+ } catch (error) {
6394
+ if (error instanceof PostPurchaseInventoryUnavailable && !member.product.productGroupVariants.length && trusted.excludedProductIds.includes(member.product.id))
6395
+ return { ...member, eligible: false };
6396
+ throw error;
6397
+ }
6398
+ });
6399
+ if (!members.length) return { reason: "empty", status: "skip" };
6400
+ if (upgrades) return { reason: "no-eligible-subscription", status: "skip" };
6401
+ const candidates = classified.filter(
6402
+ ({ product }) => product.productGroupVariants.length ? readPostPurchaseGroup(product, normalized.effective, trusted.excludedProductIds).entries.length > 0 : !trusted.excludedProductIds.includes(product.id)
6403
+ );
6404
+ if (!candidates.length) return { reason: "empty", status: "skip" };
6405
+ const retained = candidates.filter(({ eligible }) => eligible);
6406
+ return retained.length ? {
6407
+ members: retained.map(({ product, productIndex }) => ({
6408
+ productId: product.id,
6409
+ productIndex
6410
+ })),
6411
+ status: "retain"
6412
+ } : { reason: "no-eligible-subscription", status: "skip" };
6413
+ } catch {
6414
+ return { status: "unavailable" };
6415
+ }
6416
+ };
6417
+
6418
+ // src/schema/postPurchaseVariantDefault.ts
6419
+ var import_zod61 = require("zod");
6420
+ var values = PostPurchaseVariantValues.partial().extend({
6421
+ option1: PostPurchaseVariantValues.shape.option1.nullish()
6422
+ });
6423
+ var variant = values.extend({
6424
+ id: PostPurchaseVariantId,
6425
+ inventoryManagement: import_zod61.z.string().nullable(),
6426
+ inventoryPolicy: import_zod61.z.string(),
6427
+ inventoryQuantity: import_zod61.z.number()
6428
+ });
6429
+ var options = import_zod61.z.array(PostPurchaseVariantOption.pick({ name: true, values: true }));
6430
+ var PostPurchaseVariantDefaultProduct = import_zod61.z.object({
6431
+ id: PostPurchaseProductId,
6432
+ options,
6433
+ selectedVariant: variant.optional(),
6434
+ variants: import_zod61.z.array(variant)
6435
+ });
6436
+ var PostPurchaseVariantDefaultSettings = PostPurchaseSettings.shape.productOptions.pick({
6437
+ hideOutOfStockVariants: true,
6438
+ matchVariant: true
6439
+ });
6440
+ var PostPurchaseOrderAttributes = import_zod61.z.record(import_zod61.z.string(), import_zod61.z.array(import_zod61.z.string())).default({});
6441
+ var PostPurchaseOriginalVariants = import_zod61.z.array(
6442
+ import_zod61.z.object({ productId: PostPurchaseProductId, variantId: PostPurchaseVariantId })
6443
+ );
6444
+ var PostPurchaseAttributeProducts = import_zod61.z.array(
6445
+ import_zod61.z.object({ id: PostPurchaseProductId, options, variants: import_zod61.z.array(values.extend({ id: PostPurchaseVariantId })) })
6446
+ );
6447
+
6448
+ // src/server/createPostPurchaseOrderAttributes.ts
6449
+ var createPostPurchaseOrderAttributes = (original, enriched) => {
6450
+ const products = PostPurchaseAttributeProducts.parse(enriched);
6451
+ const attributes = {};
6452
+ for (const item of PostPurchaseOriginalVariants.parse(original)) {
6453
+ const product = products.find(({ id }) => id === item.productId);
6454
+ const variant2 = product?.variants.find(({ id }) => id === item.variantId);
6455
+ if (!variant2 || !product) continue;
6456
+ ["option1", "option2", "option3"].forEach((key, index) => {
6457
+ const value = variant2[key];
6458
+ const option = product.options[index];
6459
+ if (!value || !option) return;
6460
+ const values2 = attributes[option.name] ?? [];
6461
+ if (!values2.includes(value)) attributes[option.name] = [...values2, value];
6462
+ });
6463
+ }
6464
+ return attributes;
6465
+ };
6466
+
6467
+ // src/server/readPostPurchaseGroupSelection.ts
6468
+ var readPostPurchaseGroupSelection = (settings, response, requested, excludedProductIds) => {
6469
+ const selection2 = PostPurchaseGroupSelection.parse(requested);
6470
+ const { members, normalized } = normalizePostPurchaseCollection(settings, response);
6471
+ const member = members.find(({ product }) => product.id === selection2.memberProductId);
6472
+ if (!member || !member.product.productGroupVariants.length) return null;
6473
+ const group = readPostPurchaseGroup(member.product, normalized.effective, excludedProductIds);
6474
+ const entry = group.entries.find(({ product }) => product.id === selection2.productId);
6475
+ if (!entry) return null;
6476
+ return {
6477
+ groupCatalog: group.catalog,
6478
+ memberProductId: member.product.id,
6479
+ productIndex: member.productIndex,
6480
+ reportingProduct: { id: member.product.id, title: member.product.title },
6481
+ response: { data: [entry.product], metadata: normalized.metadata },
6482
+ variantCatalog: entry.variantCatalog
6483
+ };
6484
+ };
6485
+
6486
+ // src/server/preparePostPurchaseGroupDeclineDisplay.ts
6487
+ var preparePostPurchaseGroupDeclineDisplay = (settings, response, requested, excludedProductIds) => {
6488
+ const group = readPostPurchaseGroupSelection(settings, response, requested, excludedProductIds);
6489
+ const variant2 = group?.variantCatalog.variants.find(({ id }) => id === requested.variantId);
6490
+ return group && variant2 ? {
6491
+ display: {
6492
+ productTitle: group.reportingProduct.title,
6493
+ variantId: variant2.id,
6494
+ variantTitle: variant2.title
6495
+ },
6496
+ productIndex: group.productIndex
6497
+ } : null;
6498
+ };
6499
+
6500
+ // src/server/preparePostPurchaseOfferPresentation.ts
6501
+ var import_compat7 = require("es-toolkit/compat");
6502
+ var import_zod64 = require("zod");
6503
+
6504
+ // src/schema/postPurchaseOfferPresentation.ts
6505
+ var import_zod62 = require("zod");
6506
+ var language2 = PostPurchaseSettings.shape.language.shape.global.unwrap().unwrap();
6507
+ var PostPurchaseOfferPresentation = import_zod62.z.strictObject({
6508
+ labels: language2.pick({ declineAll: true, declineThisOffer: true }),
6509
+ layout: PostPurchaseSettings.shape.offersLayout,
6510
+ sections: CABRootSection.nullable(),
6511
+ showDeclineAll: PostPurchaseSettings.shape.productOptions.shape.showDeclineAll
6512
+ });
6513
+
6514
+ // src/server/postPurchaseOfferCopy.ts
6515
+ var import_zod63 = require("zod");
6516
+ var Copy = import_zod63.z.object({
6517
+ superTitle: CalloutBannerBlock.shape.settings.shape.superTitle.unwrap().optional().catch(void 0),
6518
+ title: CalloutBannerBlock.shape.settings.shape.title.unwrap().optional().catch(void 0)
6519
+ });
6520
+ var Callout = import_zod63.z.object({ settings: import_zod63.z.record(import_zod63.z.string(), import_zod63.z.unknown()), type: import_zod63.z.literal("callout_banner") });
6521
+ var postPurchaseOfferCopy = (blocks, metadata) => {
6522
+ const copy = Copy.safeParse(metadata.widget.language);
6523
+ if (!blocks || !copy.success) return blocks;
6524
+ const first = blocks.findIndex((block) => Callout.pick({ type: true }).safeParse(block).success);
6525
+ return blocks.map((block, index) => {
6526
+ if (index !== first) return block;
6527
+ const callout = Callout.passthrough().safeParse(block);
6528
+ if (!callout.success) return block;
6529
+ return {
6530
+ ...callout.data,
6531
+ settings: {
6532
+ ...callout.data.settings,
6533
+ ...copy.data.title && { title: copy.data.title },
6534
+ ...copy.data.superTitle && { superTitle: copy.data.superTitle }
6535
+ }
6536
+ };
6537
+ });
6538
+ };
6539
+
6540
+ // src/server/preparePostPurchaseOfferPresentation.ts
6541
+ var FrameSettings = PostPurchaseSettings.pick({ language: true, offersLayout: true, productOptions: true }).extend({
6542
+ blocks: import_zod64.z.array(import_zod64.z.unknown()).optional()
6543
+ });
6544
+ var preparePostPurchaseOfferPresentation = (widgetId, settings, response, report) => {
6545
+ const { metadata } = PostPurchaseProductSource.pick({ metadata: true }).parse(deepCamelCase(response));
6546
+ const original = FrameSettings.parse(deepCamelCase(settings));
6547
+ const effective = FrameSettings.parse((0, import_compat7.merge)({}, original, metadata.widget));
6548
+ let sections = null;
6549
+ try {
6550
+ sections = convertMessagePreview(
6551
+ widgetId,
6552
+ { blocks: postPurchaseOfferCopy(effective.blocks, metadata), type: "shopify_post_purchase_extension" },
6553
+ report
6554
+ );
6555
+ } catch (error) {
6556
+ if (!(error instanceof NotFoundError)) throw error;
6557
+ }
6558
+ return PostPurchaseOfferPresentation.parse({
6559
+ labels: effective.language.global,
6560
+ layout: effective.offersLayout,
6561
+ sections,
6562
+ showDeclineAll: effective.productOptions.showDeclineAll
6563
+ });
6564
+ };
6565
+
6566
+ // src/schema/postPurchaseQuantity.ts
6567
+ var import_zod65 = require("zod");
6568
+ var quantity = PreparedPostPurchaseProduct.shape.selection.shape.quantity;
6569
+ var PostPurchaseQuantityPolicy = PostPurchaseSettings.shape.quantityInputs.omit({ defaultQuantity: true }).extend({
6570
+ initialQuantity: quantity,
6571
+ maxValue: quantity,
6572
+ minValue: import_zod65.z.literal(0).transform(() => 1).or(quantity)
6573
+ }).refine(({ maxValue, minValue }) => minValue <= maxValue, "Quantity bounds are reversed");
6574
+
6575
+ // src/server/readPostPurchaseQuantity.ts
6576
+ var PostPurchaseQuantityUnavailable = class extends Error {
6577
+ };
6578
+ var readPostPurchaseQuantity = ({
6579
+ data,
6580
+ effective,
6581
+ original
6582
+ }, selection2) => {
6583
+ const positive = PreparedPostPurchaseProduct.shape.selection.shape.quantity;
6584
+ for (const config of [original, effective]) {
6585
+ if (!config.quantityInputs.enabled) continue;
6586
+ const initialQuantity2 = positive.parse(config.quantityInputs.defaultQuantity);
6587
+ const policy2 = PostPurchaseQuantityPolicy.parse({ ...config.quantityInputs, initialQuantity: initialQuantity2 });
6588
+ if (initialQuantity2 < policy2.minValue || initialQuantity2 > policy2.maxValue)
6589
+ throw new Error("Configured quantity default is outside its bounds");
6590
+ }
6591
+ const initialQuantity = data[0]?.metadata?.productQuantity ?? (original.quantityInputs.enabled ? original.quantityInputs.defaultQuantity : 1);
6592
+ const policy = PostPurchaseQuantityPolicy.parse(
6593
+ effective.quantityInputs.enabled ? { ...effective.quantityInputs, initialQuantity } : { enabled: false, initialQuantity, maxValue: initialQuantity, minValue: initialQuantity }
6594
+ );
6595
+ const requested = "quantity" in selection2 ? selection2.quantity : selection2.expectedQuantity === initialQuantity ? void 0 : selection2.expectedQuantity;
6596
+ const quantity2 = positive.parse(requested ?? initialQuantity);
6597
+ if (requested !== void 0 && (policy.enabled ? quantity2 < policy.minValue || quantity2 > policy.maxValue : quantity2 !== initialQuantity))
6598
+ throw new PostPurchaseQuantityUnavailable("Requested quantity is unavailable");
6599
+ return { policy, quantity: quantity2 };
6600
+ };
6601
+
6189
6602
  // src/server/analytics.ts
6190
6603
  var import_es_toolkit7 = require("es-toolkit");
6191
6604
 
@@ -6230,8 +6643,8 @@ var TAXONOMY = {
6230
6643
  "added-to-cart": {
6231
6644
  /** React credits the add to the A/B-selected variant (`defined_noun_id: selectedId`). */
6232
6645
  buildDefinedNounId: ({ selectedId }) => selectedId != null ? String(selectedId) : void 0,
6233
- buildMeta: ({ productId, variantId }) => ({
6234
- ...productId != null && { [`product_id:${productId}`]: true },
6646
+ buildMeta: ({ productId: productId2, variantId }) => ({
6647
+ ...productId2 != null && { [`product_id:${productId2}`]: true },
6235
6648
  ...variantId != null && { [`variant_id:${variantId}`]: true }
6236
6649
  }),
6237
6650
  buildTags: experimentTags,
@@ -6322,7 +6735,7 @@ var postAnalyticsEvents = async (input, ctx) => {
6322
6735
  };
6323
6736
 
6324
6737
  // src/server/requestSchemas.ts
6325
- var import_zod56 = require("zod");
6738
+ var import_zod66 = require("zod");
6326
6739
  var REQUEST_BOUNDS = {
6327
6740
  /** Cart-level attributes per cart. */
6328
6741
  CART_ATTRIBUTES_MAX: 100,
@@ -6353,42 +6766,42 @@ var REQUEST_BOUNDS = {
6353
6766
  /** Rich ads transaction lines — the engine's ads contract. */
6354
6767
  TRANSACTION_ITEMS_MAX: 50
6355
6768
  };
6356
- var KeyValue = import_zod56.z.object({
6357
- key: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
6358
- value: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_VALUE_MAX).optional()
6769
+ var KeyValue = import_zod66.z.object({
6770
+ key: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
6771
+ value: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_VALUE_MAX).optional()
6359
6772
  });
6360
- var CartLineInputSchema = import_zod56.z.object({
6361
- productId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6362
- properties: import_zod56.z.array(KeyValue).max(REQUEST_BOUNDS.LINE_PROPERTIES_MAX).optional(),
6363
- quantity: import_zod56.z.number(),
6364
- subscriptionId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6365
- variantId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX)
6773
+ var CartLineInputSchema = import_zod66.z.object({
6774
+ productId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6775
+ properties: import_zod66.z.array(KeyValue).max(REQUEST_BOUNDS.LINE_PROPERTIES_MAX).optional(),
6776
+ quantity: import_zod66.z.number(),
6777
+ subscriptionId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6778
+ variantId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX)
6366
6779
  });
6367
- var CartInputSchema = import_zod56.z.object({
6368
- attributes: import_zod56.z.array(KeyValue).max(REQUEST_BOUNDS.CART_ATTRIBUTES_MAX).optional(),
6780
+ var CartInputSchema = import_zod66.z.object({
6781
+ attributes: import_zod66.z.array(KeyValue).max(REQUEST_BOUNDS.CART_ATTRIBUTES_MAX).optional(),
6369
6782
  /**
6370
6783
  * Presentment-per-shop-currency FX rate (buyer price ÷ shop price, e.g. `1.35` for a USD shop
6371
6784
  * selling in CAD). Money rule thresholds are authored in SHOP currency, so the engine subtotal is
6372
6785
  * divided by this before evaluation. Omit (or send 1) when the cart is already in the shop's currency.
6373
6786
  */
6374
- currencyRate: import_zod56.z.number().optional(),
6787
+ currencyRate: import_zod66.z.number().optional(),
6375
6788
  /** Applied discount codes; the engine evaluates `discount_code` rules against them (sent as `[{code}]`). */
6376
- discountCodes: import_zod56.z.array(import_zod56.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX)).max(REQUEST_BOUNDS.DISCOUNT_CODES_MAX).optional(),
6789
+ discountCodes: import_zod66.z.array(import_zod66.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX)).max(REQUEST_BOUNDS.DISCOUNT_CODES_MAX).optional(),
6377
6790
  /** Presentment cents of cart-level discount allocations, subtracted from `subtotal` for the engine. */
6378
- discountTotal: import_zod56.z.number().optional(),
6379
- items: import_zod56.z.array(CartLineInputSchema).max(REQUEST_BOUNDS.CART_ITEMS_MAX),
6791
+ discountTotal: import_zod66.z.number().optional(),
6792
+ items: import_zod66.z.array(CartLineInputSchema).max(REQUEST_BOUNDS.CART_ITEMS_MAX),
6380
6793
  /** Presentment subtotal in cents. */
6381
- subtotal: import_zod56.z.number()
6794
+ subtotal: import_zod66.z.number()
6382
6795
  });
6383
- var UserConfigInputSchema = import_zod56.z.object({ shop: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX) });
6384
- var DataSourceInputSchema = import_zod56.z.object({
6796
+ var UserConfigInputSchema = import_zod66.z.object({ shop: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX) });
6797
+ var DataSourceInputSchema = import_zod66.z.object({
6385
6798
  cart: CartInputSchema,
6386
6799
  /**
6387
6800
  * Numeric Shopify company-location id when the buyer is a B2B session (`buyerIdentity.purchasingCompany`).
6388
6801
  * Present ⇒ the orchestrator filters results by the location's catalog via admin-api (REB-23713); the
6389
6802
  * client's country-context market check is bypassed for B2B (it false-negatives B2B-catalog products).
6390
6803
  */
6391
- companyLocationId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6804
+ companyLocationId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6392
6805
  /**
6393
6806
  * Buyer's market country (ISO 3166-1 alpha-2) — forwarded to the engine as the `country_code` PARAM
6394
6807
  * when the shop's markets toggle is on (REB-21688; the sink was the `X-Country-Code` header under
@@ -6397,16 +6810,16 @@ var DataSourceInputSchema = import_zod56.z.object({
6397
6810
  * uppercase (the wire value is forwarded verbatim as the param) so a case-sensitive engine lookup
6398
6811
  * can't silently miss a lowercase code — `adsEngine.ts` uppercases for the same reason.
6399
6812
  */
6400
- country: import_zod56.z.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(),
6401
- customerId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6402
- dataSourcePath: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
6813
+ country: import_zod66.z.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(),
6814
+ customerId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6815
+ dataSourcePath: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
6403
6816
  /**
6404
6817
  * Engine `filter_inputs` override: `'no'` keeps in-cart (input) products in the results/rule
6405
6818
  * outputs — gift validation sends it so a gift's own product can appear in its answer. Omitted = the
6406
6819
  * engine's default filtering.
6407
6820
  */
6408
- filterInputs: import_zod56.z.enum(["no", "yes"]).optional(),
6409
- integrations: import_zod56.z.record(import_zod56.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), import_zod56.z.boolean()).refine((record) => Object.keys(record).length <= REQUEST_BOUNDS.INTEGRATION_KEYS_MAX, {
6821
+ filterInputs: import_zod66.z.enum(["no", "yes"]).optional(),
6822
+ integrations: import_zod66.z.record(import_zod66.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), import_zod66.z.boolean()).refine((record) => Object.keys(record).length <= REQUEST_BOUNDS.INTEGRATION_KEYS_MAX, {
6410
6823
  message: `Too many integration keys (max ${REQUEST_BOUNDS.INTEGRATION_KEYS_MAX})`
6411
6824
  }).optional(),
6412
6825
  /**
@@ -6419,31 +6832,31 @@ var DataSourceInputSchema = import_zod56.z.object({
6419
6832
  * request header) fails the regex. Callers should send the buyer's resolved locale (e.g. Shopify
6420
6833
  * checkout's `localization.language.isoCode`), not the request header verbatim.
6421
6834
  */
6422
- language: import_zod56.z.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(),
6423
- limit: import_zod56.z.number().max(REQUEST_BOUNDS.LIMIT_MAX),
6424
- productType: import_zod56.z.enum(["both", "one-time", "subscription"]).optional(),
6425
- shop: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6426
- visitorId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6427
- });
6428
- var GiftInputSchema = import_zod56.z.object({
6429
- cost: import_zod56.z.number(),
6430
- discounted: import_zod56.z.boolean(),
6835
+ language: import_zod66.z.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(),
6836
+ limit: import_zod66.z.number().max(REQUEST_BOUNDS.LIMIT_MAX),
6837
+ productType: import_zod66.z.enum(["both", "one-time", "subscription"]).optional(),
6838
+ shop: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6839
+ visitorId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6840
+ });
6841
+ var GiftInputSchema = import_zod66.z.object({
6842
+ cost: import_zod66.z.number(),
6843
+ discounted: import_zod66.z.boolean(),
6431
6844
  /**
6432
6845
  * Which gift attribution the line carries (REB-24363). Defaults to `gwp` because a client that predates
6433
6846
  * the field only ever sent GWP lines — without the default an older extension's request would 422.
6434
6847
  */
6435
- kind: import_zod56.z.enum(GIFT_KINDS).default("gwp"),
6436
- lineId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6437
- productId: import_zod56.z.number(),
6848
+ kind: import_zod66.z.enum(GIFT_KINDS).default("gwp"),
6849
+ lineId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6850
+ productId: import_zod66.z.number(),
6438
6851
  /**
6439
6852
  * The line's unit count (REB-24363) — the selectable-GWP verdict trims surplus units against milestone
6440
6853
  * capacity. The second deliberate default: a client predating the field sent only GWP lines, whose
6441
6854
  * verdict is whole-line, so a missing quantity reads as one unit rather than 422ing the older request.
6442
6855
  */
6443
- quantity: import_zod56.z.number().int().min(1).default(1),
6444
- widgetId: import_zod56.z.number()
6856
+ quantity: import_zod66.z.number().int().min(1).default(1),
6857
+ widgetId: import_zod66.z.number()
6445
6858
  });
6446
- var GiftValidationInputSchema = import_zod56.z.object({
6859
+ var GiftValidationInputSchema = import_zod66.z.object({
6447
6860
  cart: CartInputSchema,
6448
6861
  /**
6449
6862
  * Buyer's market country — threaded into the per-widget data-source evaluations, which forward it to
@@ -6452,25 +6865,25 @@ var GiftValidationInputSchema = import_zod56.z.object({
6452
6865
  * turns markets off); regex-bound and uppercase-normalized for the same reasons as
6453
6866
  * `DataSourceInputSchema`'s `country`.
6454
6867
  */
6455
- country: import_zod56.z.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(),
6456
- customerId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6457
- gifts: import_zod56.z.array(GiftInputSchema).max(REQUEST_BOUNDS.GIFTS_MAX),
6868
+ country: import_zod66.z.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(),
6869
+ customerId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6870
+ gifts: import_zod66.z.array(GiftInputSchema).max(REQUEST_BOUNDS.GIFTS_MAX),
6458
6871
  /**
6459
6872
  * Buyer's checkout language — threaded into the per-widget data-source evaluations, which normalize
6460
6873
  * and forward it as the engine `locale` param under the same markets-toggle gate (REB-21688). MUST be
6461
6874
  * a single BCP-47 tag, for the same reason as `DataSourceInputSchema`'s `language` above.
6462
6875
  */
6463
- language: import_zod56.z.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(),
6464
- shop: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6465
- visitorId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6876
+ language: import_zod66.z.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(),
6877
+ shop: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6878
+ visitorId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6466
6879
  });
6467
- var GiftAdjustmentSchema = import_zod56.z.object({
6468
- lineId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6469
- quantity: import_zod56.z.number().int().nonnegative()
6880
+ var GiftAdjustmentSchema = import_zod66.z.object({
6881
+ lineId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6882
+ quantity: import_zod66.z.number().int().nonnegative()
6470
6883
  });
6471
- var GiftValidationResponseSchema = import_zod56.z.object({
6472
- adjust: import_zod56.z.array(GiftAdjustmentSchema).max(REQUEST_BOUNDS.GIFTS_MAX).default([]),
6473
- remove: import_zod56.z.array(import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX)).max(REQUEST_BOUNDS.GIFTS_MAX).refine(
6884
+ var GiftValidationResponseSchema = import_zod66.z.object({
6885
+ adjust: import_zod66.z.array(GiftAdjustmentSchema).max(REQUEST_BOUNDS.GIFTS_MAX).default([]),
6886
+ remove: import_zod66.z.array(import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX)).max(REQUEST_BOUNDS.GIFTS_MAX).refine(
6474
6887
  (remove) => new Set(remove).size === remove.length,
6475
6888
  "a line id may appear at most once in `remove`"
6476
6889
  )
@@ -6481,47 +6894,47 @@ var GiftValidationResponseSchema = import_zod56.z.object({
6481
6894
  ({ adjust }) => new Set(adjust.map(({ lineId }) => lineId)).size === adjust.length,
6482
6895
  "a line id may appear at most once in `adjust`"
6483
6896
  );
6484
- var MonetizeTransactionItemSchema = import_zod56.z.object({
6485
- id: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6486
- priceCents: import_zod56.z.number(),
6487
- quantity: import_zod56.z.number(),
6488
- title: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX),
6489
- type: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX)
6490
- });
6491
- var MonetizeInputSchema = import_zod56.z.object({
6897
+ var MonetizeTransactionItemSchema = import_zod66.z.object({
6898
+ id: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6899
+ priceCents: import_zod66.z.number(),
6900
+ quantity: import_zod66.z.number(),
6901
+ title: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX),
6902
+ type: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX)
6903
+ });
6904
+ var MonetizeInputSchema = import_zod66.z.object({
6492
6905
  cart: CartInputSchema,
6493
6906
  /** Client-minted render-beacon correlation id; forwarded to the ads engine as `client_request_id`. */
6494
- clientRequestId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6495
- country: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6496
- currency: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6907
+ clientRequestId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6908
+ country: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6909
+ currency: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6497
6910
  /** Ads-targeting identity/geo/locale fields (React parity); folded into the engine query verbatim. */
6498
- customerEmail: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
6499
- customerFirstName: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
6500
- customerId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6501
- customerLastName: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
6502
- language: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6911
+ customerEmail: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
6912
+ customerFirstName: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
6913
+ customerId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6914
+ customerLastName: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
6915
+ language: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6503
6916
  /** Buyer-facing order name (e.g. `#1001`) for the server-composed "Order … Confirmed" chrome line. */
6504
- orderName: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
6917
+ orderName: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
6505
6918
  /** Ads surface label, forwarded verbatim; `customer_account` is measured/floored as its own surface (the account-area order list). */
6506
- placement: import_zod56.z.enum(["customer_account", "order_status", "thank_you_page"]),
6919
+ placement: import_zod66.z.enum(["customer_account", "order_status", "thank_you_page"]),
6507
6920
  /** Privacy Policy footer href — the Monetize widget's `privacy_policy_url` setting (React parity). */
6508
- privacyPolicyUrl: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_URL_MAX).optional(),
6921
+ privacyPolicyUrl: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_URL_MAX).optional(),
6509
6922
  /** 30-min rolling session id (React parity); used for the ads `session_id`, else the visitor id. */
6510
- sessionId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6511
- shop: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6923
+ sessionId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6924
+ shop: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6512
6925
  /** Editor/QA indicator; OR-ed into the ads-engine `testing` flag so it stays out of billing/reporting. */
6513
- testing: import_zod56.z.boolean().optional(),
6514
- timezone: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6926
+ testing: import_zod66.z.boolean().optional(),
6927
+ timezone: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6515
6928
  /** Decorated (numeric) order id → the ads `transaction_id`. */
6516
- transactionId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6929
+ transactionId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6517
6930
  /** Rich per-line ads items; capped at the engine's ads contract. Preferred over `cart.items`. */
6518
- transactionItems: import_zod56.z.array(MonetizeTransactionItemSchema).max(REQUEST_BOUNDS.TRANSACTION_ITEMS_MAX).optional(),
6931
+ transactionItems: import_zod66.z.array(MonetizeTransactionItemSchema).max(REQUEST_BOUNDS.TRANSACTION_ITEMS_MAX).optional(),
6519
6932
  /** Order total in presentment cents (React prefers total over subtotal); else `cart.subtotal`. */
6520
- transactionTotal: import_zod56.z.number().optional(),
6521
- visitorId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6522
- zipCode: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6933
+ transactionTotal: import_zod66.z.number().optional(),
6934
+ visitorId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6935
+ zipCode: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6523
6936
  });
6524
- var WidgetSettingsInputSchema = import_zod56.z.object({
6937
+ var WidgetSettingsInputSchema = import_zod66.z.object({
6525
6938
  /**
6526
6939
  * Same domain as `CabShopConfig.cacheKey`, for the same reason: this side WINS the orchestrator's
6527
6940
  * `input.cacheKey ?? config.shop.cacheKey` (and an explicit value skips the config read entirely), so
@@ -6529,9 +6942,9 @@ var WidgetSettingsInputSchema = import_zod56.z.object({
6529
6942
  * and pin the edge copy permanently stale. `.catch(undefined)` because a bogus buster should degrade
6530
6943
  * the read to un-busted, never 400 a widget render.
6531
6944
  */
6532
- cacheKey: import_zod56.z.number().int().positive().optional().catch(void 0),
6533
- id: import_zod56.z.number(),
6534
- key: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6945
+ cacheKey: import_zod66.z.number().int().positive().optional().catch(void 0),
6946
+ id: import_zod66.z.number(),
6947
+ key: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6535
6948
  /**
6536
6949
  * Monetize context for inline hydration: when present AND the widget converts to a Monetize marker,
6537
6950
  * the server fetches/composes the offer cards inside this same request (no second `/cab/monetize`
@@ -6540,34 +6953,34 @@ var WidgetSettingsInputSchema = import_zod56.z.object({
6540
6953
  * `privacyPolicyUrl` comes from the widget settings server-side (more authoritative than a relay).
6541
6954
  */
6542
6955
  monetize: MonetizeInputSchema.omit({ privacyPolicyUrl: true, shop: true }).optional(),
6543
- shop: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6956
+ shop: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6544
6957
  /** Stable per-buyer id; when present, enables sticky server-side A/B variant selection. */
6545
- visitorId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6958
+ visitorId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6546
6959
  });
6547
- var AnalyticsEventInputSchema = import_zod56.z.object({
6548
- name: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
6549
- properties: import_zod56.z.record(import_zod56.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), import_zod56.z.unknown()).optional(),
6550
- sentAt: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6960
+ var AnalyticsEventInputSchema = import_zod66.z.object({
6961
+ name: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
6962
+ properties: import_zod66.z.record(import_zod66.z.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), import_zod66.z.unknown()).optional(),
6963
+ sentAt: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6551
6964
  });
6552
- var AnalyticsSegmentsInputSchema = import_zod56.z.object({
6553
- device: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
6554
- source: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
6555
- visitor: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0)
6965
+ var AnalyticsSegmentsInputSchema = import_zod66.z.object({
6966
+ device: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
6967
+ source: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0),
6968
+ visitor: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional().catch(void 0)
6556
6969
  });
6557
- var AnalyticsInputSchema = import_zod56.z.object({
6970
+ var AnalyticsInputSchema = import_zod66.z.object({
6558
6971
  /** Rebuy cart token (the `r_cart_token` cart attribute), when available — primary aggregation key. */
6559
- cartToken: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6972
+ cartToken: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6560
6973
  /** Shopify checkout token, when available — drives cart/checkout aggregation downstream. */
6561
- checkoutToken: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6562
- events: import_zod56.z.array(AnalyticsEventInputSchema).max(REQUEST_BOUNDS.EVENTS_MAX),
6974
+ checkoutToken: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
6975
+ events: import_zod66.z.array(AnalyticsEventInputSchema).max(REQUEST_BOUNDS.EVENTS_MAX),
6563
6976
  /**
6564
6977
  * Request-scoped like the tokens: one visitor's segments apply to every event in the batch. The container
6565
6978
  * degrades too (`null` is a realistic wire artifact of `attributes ? {…} : null`), so the degrade rule is
6566
6979
  * total: nothing about `segments` can cost the envelope.
6567
6980
  */
6568
6981
  segments: AnalyticsSegmentsInputSchema.optional().catch(void 0),
6569
- shop: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6570
- visitorId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6982
+ shop: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6983
+ visitorId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
6571
6984
  /** The widget id (smartBlockId) the events belong to. */
6572
- widgetId: import_zod56.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6985
+ widgetId: import_zod66.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
6573
6986
  });