@rebuy/rebuy 3.26.0 → 3.28.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 (51) hide show
  1. package/dist/index.cjs +902 -750
  2. package/dist/index.mjs +901 -749
  3. package/dist/schema/checkout-and-beyond/constants.cjs +5 -0
  4. package/dist/schema/checkout-and-beyond/constants.mjs +5 -0
  5. package/dist/schema/checkout-and-beyond/index.cjs +97 -68
  6. package/dist/schema/checkout-and-beyond/index.mjs +97 -68
  7. package/dist/schema/index.d.ts +6 -0
  8. package/dist/schema/postPurchaseEligibility.d.ts +2 -2
  9. package/dist/schema/postPurchaseExitPolicy.d.ts +20 -0
  10. package/dist/schema/postPurchaseIdentity.d.ts +9 -0
  11. package/dist/schema/postPurchaseOrderDecision.d.ts +10 -0
  12. package/dist/schema/postPurchasePolicy.d.ts +62 -0
  13. package/dist/schema/postPurchaseSelection.d.ts +29 -0
  14. package/dist/schema/postPurchaseSession.d.ts +112 -0
  15. package/dist/schema/postPurchaseSessionClose.d.ts +25 -0
  16. package/dist/schema/postPurchaseShadow.d.ts +56 -1
  17. package/dist/schema/postPurchaseSkipTrace.d.ts +2 -2
  18. package/dist/schema/widget-data.cjs +160 -135
  19. package/dist/schema/widget-data.mjs +160 -135
  20. package/dist/schema/widgetData.d.ts +24 -0
  21. package/dist/schema/widgets/checkout-and-beyond/banner.d.ts +8 -0
  22. package/dist/schema/widgets/checkout-and-beyond/carousel.d.ts +8 -0
  23. package/dist/schema/widgets/checkout-and-beyond/cartLine.d.ts +8 -0
  24. package/dist/schema/widgets/checkout-and-beyond/common.d.ts +13 -1
  25. package/dist/schema/widgets/checkout-and-beyond/index.d.ts +1 -0
  26. package/dist/schema/widgets/checkout-and-beyond/layout.d.ts +17 -1
  27. package/dist/schema/widgets/checkout-and-beyond/offers.d.ts +8 -0
  28. package/dist/schema/widgets/checkout-and-beyond/progressBar.d.ts +8 -0
  29. package/dist/schema/widgets/checkout-and-beyond/reviews.d.ts +2 -0
  30. package/dist/schema/widgets/checkout-and-beyond/root.d.ts +8 -0
  31. package/dist/schema/widgets/checkout-and-beyond/separator.d.ts +192 -0
  32. package/dist/schema/widgets/checkout-and-beyond/shared.d.ts +2 -1
  33. package/dist/schema/widgets/contentBlock.d.ts +8 -0
  34. package/dist/schema/widgets/lineItemEditor.d.ts +8 -0
  35. package/dist/schema/widgets/post-purchase-offer/constants.d.ts +2 -2
  36. package/dist/schema/widgets/rebuyButton.d.ts +8 -0
  37. package/dist/server/index.cjs +601 -188
  38. package/dist/server/index.mjs +601 -188
  39. package/dist/server/requestSchemas.d.ts +1 -1
  40. package/dist/transforms/index.cjs +481 -59
  41. package/dist/transforms/index.d.ts +2 -0
  42. package/dist/transforms/index.mjs +481 -59
  43. package/dist/transforms/postPurchase/convertCalloutBlock.d.ts +8 -0
  44. package/dist/transforms/postPurchase/convertMessagePreview.d.ts +8 -0
  45. package/dist/transforms/postPurchase/convertPayButtonBlock.d.ts +4 -0
  46. package/dist/transforms/postPurchase/convertSeparatorBlock.d.ts +4 -0
  47. package/dist/transforms/postPurchase/convertTextBlock.d.ts +4 -0
  48. package/dist/transforms/postPurchase/convertTimerBlock.d.ts +4 -0
  49. package/dist/transforms/postPurchase/styledTextRun.d.ts +3 -0
  50. package/dist/transforms/postPurchase/types.d.ts +8 -0
  51. package/package.json +1 -1
@@ -32,6 +32,7 @@ __export(transforms_exports, {
32
32
  convertContentBlockTextToV2: () => convertContentBlockTextToV2,
33
33
  convertContentBlockToV2: () => convertContentBlockToV2,
34
34
  convertLineItemEditorToV2: () => convertLineItemEditorToV2,
35
+ convertMessagePreview: () => convertMessagePreview,
35
36
  convertMonetizeToV2: () => convertMonetizeToV2,
36
37
  convertNumericObjects: () => convertNumericObjects,
37
38
  convertOfferToV2: () => convertOfferToV2,
@@ -49,6 +50,7 @@ __export(transforms_exports, {
49
50
  isMonetizeV1: () => isMonetizeV1,
50
51
  isOfferV1: () => isOfferV1,
51
52
  isPlaceholderV1: () => isPlaceholderV1,
53
+ isPostPurchaseV1: () => isPostPurchaseV1,
52
54
  isProgressBarV1: () => isProgressBarV1,
53
55
  normalizeTextContent: () => normalizeTextContent,
54
56
  normalizeTokens: () => normalizeTokens,
@@ -58,8 +60,8 @@ __export(transforms_exports, {
58
60
  module.exports = __toCommonJS(transforms_exports);
59
61
 
60
62
  // src/schema/widgets/checkout-and-beyond/image.ts
61
- var import_uuid12 = require("uuid");
62
- var import_zod20 = require("zod");
63
+ var import_uuid13 = require("uuid");
64
+ var import_zod21 = require("zod");
63
65
 
64
66
  // src/schema/widgets/checkout-and-beyond/common.ts
65
67
  var freezeEnum = (values) => Object.freeze(Object.fromEntries(values.map((v) => [v, v])));
@@ -168,6 +170,8 @@ var languageKeys = [
168
170
  "zh"
169
171
  ];
170
172
  var LanguageKey = freezeEnum(languageKeys);
173
+ var layoutFrames = ["callout", "offer-content"];
174
+ var LayoutFrame = freezeEnum(layoutFrames);
171
175
  var mutatorEvents = ["item_added", "quantity_changed", "variant_selected"];
172
176
  var MutatorEvent = freezeEnum(mutatorEvents);
173
177
  var objectFits = ["cover", "contain"];
@@ -206,6 +210,7 @@ var sectionTypes = [
206
210
  "progressBar",
207
211
  "quantity",
208
212
  "reviews",
213
+ "separator",
209
214
  "text",
210
215
  "variants"
211
216
  ];
@@ -349,7 +354,7 @@ var ROOT_RELATIVE_PATH_REGEX = /^\/(?!\/)/;
349
354
  var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
350
355
 
351
356
  // src/schema/widgets/checkout-and-beyond/shared.ts
352
- var import_zod19 = require("zod");
357
+ var import_zod20 = require("zod");
353
358
 
354
359
  // src/schema/widgets/checkout-and-beyond/banner.ts
355
360
  var import_zod4 = require("zod");
@@ -504,6 +509,10 @@ var CABVariableFields = {
504
509
 
505
510
  // src/schema/widgets/checkout-and-beyond/layout.ts
506
511
  var GridItem = import_zod3.z.union([import_zod3.z.literal("auto"), import_zod3.z.literal("fill"), import_zod3.z.string().regex(/^\d+%$/), import_zod3.z.number()]);
512
+ var CABLayoutWrapping = import_zod3.z.object({
513
+ breakAt: import_zod3.z.number().positive(),
514
+ maxPerLine: import_zod3.z.number().int().positive()
515
+ });
507
516
  var CABLayoutSection = import_zod3.z.object({
508
517
  ...CABVariableFields,
509
518
  alignment: import_zod3.z.object({
@@ -516,6 +525,11 @@ var CABLayoutSection = import_zod3.z.object({
516
525
  border: import_zod3.z.lazy(() => CABBorder),
517
526
  buttonField: import_zod3.z.enum(buttonFields).optional(),
518
527
  direction: import_zod3.z.enum(directions).default(Direction.rows),
528
+ /**
529
+ * Platform chrome around the section, not a layout behavior: `callout` is a subdued box with block borders
530
+ * (the legacy post-purchase callout banner), `offer-content` the post-purchase offer's own content card.
531
+ */
532
+ frame: import_zod3.z.enum(layoutFrames).optional(),
519
533
  grid: import_zod3.z.object({
520
534
  columns: import_zod3.z.union([import_zod3.z.array(GridItem), import_zod3.z.undefined()]).default(() => ["auto"]),
521
535
  rows: import_zod3.z.union([import_zod3.z.array(GridItem), import_zod3.z.undefined()]).default(() => ["auto"])
@@ -528,7 +542,8 @@ var CABLayoutSection = import_zod3.z.object({
528
542
  spacing: import_zod3.z.enum(spacings).default(Spacing.base),
529
543
  /** Fire-and-forget impression pixel POSTed once when the section is shown (e.g. a Monetize offer view). */
530
544
  viewUrl: import_zod3.z.string().optional(),
531
- width: import_zod3.z.number().default(100)
545
+ width: import_zod3.z.number().default(100),
546
+ wrapping: CABLayoutWrapping.optional()
532
547
  });
533
548
 
534
549
  // src/schema/widgets/checkout-and-beyond/utils.ts
@@ -1392,35 +1407,46 @@ var CABReviewsSection = import_zod17.z.object({
1392
1407
  name: import_zod17.z.string().optional(),
1393
1408
  sectionId: import_zod17.z.uuid().default(() => (0, import_uuid10.v7)()),
1394
1409
  sectionType: import_zod17.z.literal(SectionType.reviews).default(SectionType.reviews),
1395
- size: import_zod17.z.enum(reviewsSizes).default(ReviewsSize.default)
1410
+ size: import_zod17.z.enum(reviewsSizes).default(ReviewsSize.default),
1411
+ strokeColor: import_zod17.z.string().default("#fadb14"),
1412
+ strokeWidth: import_zod17.z.number().nonnegative().default(0)
1396
1413
  });
1397
1414
 
1398
- // src/schema/widgets/checkout-and-beyond/variants.ts
1399
- var import_compat3 = require("es-toolkit/compat");
1415
+ // src/schema/widgets/checkout-and-beyond/separator.ts
1400
1416
  var import_uuid11 = require("uuid");
1401
1417
  var import_zod18 = require("zod");
1402
- var CABVariantsSection = import_zod18.z.object({
1418
+ var CABSeparatorSection = import_zod18.z.object({
1403
1419
  ...CABVariableFields,
1404
- hideOutOfStockVariants: import_zod18.z.boolean().default(false),
1405
- name: import_zod18.z.string().optional(),
1406
1420
  sectionId: import_zod18.z.uuid().default(() => (0, import_uuid11.v7)()),
1407
- sectionType: import_zod18.z.literal(SectionType.variants).default(SectionType.variants),
1408
- selector: import_zod18.z.enum((0, import_compat3.slice)(variantSelectors, 0, 3)).default(VariantSelector.menu),
1409
- variantMode: import_zod18.z.enum(variantModes).default(VariantMode.multiple)
1421
+ sectionType: import_zod18.z.literal(SectionType.separator).default(SectionType.separator)
1422
+ });
1423
+
1424
+ // src/schema/widgets/checkout-and-beyond/variants.ts
1425
+ var import_compat3 = require("es-toolkit/compat");
1426
+ var import_uuid12 = require("uuid");
1427
+ var import_zod19 = require("zod");
1428
+ var CABVariantsSection = import_zod19.z.object({
1429
+ ...CABVariableFields,
1430
+ hideOutOfStockVariants: import_zod19.z.boolean().default(false),
1431
+ name: import_zod19.z.string().optional(),
1432
+ sectionId: import_zod19.z.uuid().default(() => (0, import_uuid12.v7)()),
1433
+ sectionType: import_zod19.z.literal(SectionType.variants).default(SectionType.variants),
1434
+ selector: import_zod19.z.enum((0, import_compat3.slice)(variantSelectors, 0, 3)).default(VariantSelector.menu),
1435
+ variantMode: import_zod19.z.enum(variantModes).default(VariantMode.multiple)
1410
1436
  });
1411
1437
 
1412
1438
  // src/schema/widgets/checkout-and-beyond/shared.ts
1413
- var CABBorder = import_zod19.z.object({
1414
- radius: import_zod19.z.enum(borderRadii).default(BorderRadius.base),
1415
- style: import_zod19.z.enum(borderStyles).default(BorderStyle.none),
1416
- width: import_zod19.z.enum(borderWidths).default(BorderWidth.base)
1439
+ var CABBorder = import_zod20.z.object({
1440
+ radius: import_zod20.z.enum(borderRadii).default(BorderRadius.base),
1441
+ style: import_zod20.z.enum(borderStyles).default(BorderStyle.none),
1442
+ width: import_zod20.z.enum(borderWidths).default(BorderWidth.base)
1417
1443
  }).default({
1418
1444
  radius: BorderRadius.base,
1419
1445
  style: BorderStyle.none,
1420
1446
  width: BorderWidth.base
1421
1447
  });
1422
- var CABSection = import_zod19.z.lazy(
1423
- () => import_zod19.z.discriminatedUnion("sectionType", [
1448
+ var CABSection = import_zod20.z.lazy(
1449
+ () => import_zod20.z.discriminatedUnion("sectionType", [
1424
1450
  CABBannerSection,
1425
1451
  CABButtonSection,
1426
1452
  CABCarouselSection,
@@ -1436,23 +1462,24 @@ var CABSection = import_zod19.z.lazy(
1436
1462
  CABProgressBarSection,
1437
1463
  CABQuantitySection,
1438
1464
  CABReviewsSection,
1465
+ CABSeparatorSection,
1439
1466
  CABTextSection,
1440
1467
  CABVariantsSection
1441
1468
  ])
1442
1469
  );
1443
1470
 
1444
1471
  // src/schema/widgets/checkout-and-beyond/image.ts
1445
- var CABImageSectionFields = import_zod20.z.object({
1472
+ var CABImageSectionFields = import_zod21.z.object({
1446
1473
  ...CABVariableFields,
1447
- altText: import_zod20.z.string().refine(checkForHTML, NO_HTML).default(""),
1474
+ altText: import_zod21.z.string().refine(checkForHTML, NO_HTML).default(""),
1448
1475
  /**
1449
1476
  * Image width÷height (e.g. `46` for the progress-bar fill); `null` renders at natural size. Any POSITIVE
1450
1477
  * ratio — never limited to 1, but never `0`/negative either: a renderer dividing by it would get `Infinity`,
1451
1478
  * and CSS `aspect-ratio` drops a negative value and silently reverts to natural size.
1452
1479
  */
1453
- aspectRatio: import_zod20.z.number().positive().nullable().default(null),
1454
- border: import_zod20.z.lazy(() => CABBorder),
1455
- buttonField: import_zod20.z.enum(buttonFields).optional(),
1480
+ aspectRatio: import_zod21.z.number().positive().nullable().default(null),
1481
+ border: import_zod21.z.lazy(() => CABBorder),
1482
+ buttonField: import_zod21.z.enum(buttonFields).optional(),
1456
1483
  /**
1457
1484
  * `icon` renders `source` as a single `s-icon` by name (the uber-image path covers icons too), reading
1458
1485
  * `iconSize`/`iconTone`. The other values are a harmless informational holdover from the previous
@@ -1471,29 +1498,29 @@ var CABImageSectionFields = import_zod20.z.object({
1471
1498
  * behavior degraded gracefully and told us about it. The client-assembled half of the invariant was never
1472
1499
  * the risky half.
1473
1500
  */
1474
- category: import_zod20.z.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
1501
+ category: import_zod21.z.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
1475
1502
  /** `icon`-mode only: the `s-icon` `size`; `null` ⇒ the component default (`base`). Ignored by image treatments. */
1476
- iconSize: import_zod20.z.enum(iconSizes).nullable().default(null),
1503
+ iconSize: import_zod21.z.enum(iconSizes).nullable().default(null),
1477
1504
  /** `icon`-mode only: the `s-icon` `tone`; `null` ⇒ the component default (`auto`). Ignored by image treatments. */
1478
- iconTone: import_zod20.z.enum(iconTones).nullable().default(null),
1479
- name: import_zod20.z.string().optional(),
1480
- naturalHeight: import_zod20.z.number().default(0),
1481
- naturalWidth: import_zod20.z.number().default(0),
1505
+ iconTone: import_zod21.z.enum(iconTones).nullable().default(null),
1506
+ name: import_zod21.z.string().optional(),
1507
+ naturalHeight: import_zod21.z.number().default(0),
1508
+ naturalWidth: import_zod21.z.number().default(0),
1482
1509
  /**
1483
1510
  * `contain` (the component default): dimensionless images render in s-image's 1/1 default frame, and
1484
1511
  * `cover` would crop non-square art (payment badges lost their edges — 15993); `contain` letterboxes.
1485
1512
  */
1486
- objectFit: import_zod20.z.enum(objectFits).default(ObjectFit.contain),
1487
- sectionId: import_zod20.z.uuid().default(() => (0, import_uuid12.v7)()),
1488
- sectionType: import_zod20.z.literal(SectionType.image).default(SectionType.image),
1513
+ objectFit: import_zod21.z.enum(objectFits).default(ObjectFit.contain),
1514
+ sectionId: import_zod21.z.uuid().default(() => (0, import_uuid13.v7)()),
1515
+ sectionType: import_zod21.z.literal(SectionType.image).default(SectionType.image),
1489
1516
  /**
1490
1517
  * An image URL or dynamic token, an empty default, or — when `category: 'icon'` — an icon NAME. Icon mode
1491
1518
  * takes a name or `''` only, NOT a token: no renderer resolves a token to an icon today, so accepting one
1492
1519
  * would promise a capability that doesn't exist. Widen the refine's carve-out to `DYNAMIC_TOKEN_REGEX` when a
1493
1520
  * server-chosen tier icon actually needs it.
1494
1521
  */
1495
- source: import_zod20.z.union([import_zod20.z.url(), import_zod20.z.literal(""), import_zod20.z.string().regex(DYNAMIC_TOKEN_REGEX), import_zod20.z.enum(iconNames)]).default(""),
1496
- width: import_zod20.z.number().default(100)
1522
+ source: import_zod21.z.union([import_zod21.z.url(), import_zod21.z.literal(""), import_zod21.z.string().regex(DYNAMIC_TOKEN_REGEX), import_zod21.z.enum(iconNames)]).default(""),
1523
+ width: import_zod21.z.number().default(100)
1497
1524
  });
1498
1525
  var iconNameSet = new Set(iconNames);
1499
1526
  var isIconName = (source) => iconNameSet.has(source);
@@ -1644,7 +1671,7 @@ var convertContentBlockTextToV2 = (language, text = literalText, textAlign = "ce
1644
1671
  };
1645
1672
 
1646
1673
  // src/schema/widgets/checkout-and-beyond/root.ts
1647
- var import_zod21 = require("zod");
1674
+ var import_zod22 = require("zod");
1648
1675
 
1649
1676
  // src/schema/widgets/checkout-and-beyond/uiLabels.ts
1650
1677
  var UI_LABELS = {
@@ -1664,8 +1691,8 @@ var UI_LABELS = {
1664
1691
  };
1665
1692
 
1666
1693
  // src/schema/widgets/checkout-and-beyond/root.ts
1667
- var localized = (fallback) => import_zod21.z.record(import_zod21.z.string(), import_zod21.z.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
1668
- var CABUILabels = import_zod21.z.object({
1694
+ var localized = (fallback) => import_zod22.z.record(import_zod22.z.string(), import_zod22.z.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
1695
+ var CABUILabels = import_zod22.z.object({
1669
1696
  currentPage: localized(UI_LABELS.currentPage),
1670
1697
  guest: localized(UI_LABELS.guest),
1671
1698
  loadingOptions: localized(UI_LABELS.loadingOptions),
@@ -1690,37 +1717,37 @@ var CABUILabels = import_zod21.z.object({
1690
1717
  subscriptionOptions: { ...UI_LABELS.subscriptionOptions },
1691
1718
  updating: { ...UI_LABELS.updating }
1692
1719
  }));
1693
- var TargetArea = import_zod21.z.object({
1694
- fill: import_zod21.z.boolean().optional(),
1695
- flip: import_zod21.z.enum(["both", "horizontal", "vertical"]).optional(),
1696
- icon: import_zod21.z.string(),
1697
- label: import_zod21.z.string(),
1698
- width: import_zod21.z.string()
1720
+ var TargetArea = import_zod22.z.object({
1721
+ fill: import_zod22.z.boolean().optional(),
1722
+ flip: import_zod22.z.enum(["both", "horizontal", "vertical"]).optional(),
1723
+ icon: import_zod22.z.string(),
1724
+ label: import_zod22.z.string(),
1725
+ width: import_zod22.z.string()
1699
1726
  }).default(targetAreas[EditorMode.checkoutExtension][1]);
1700
- var CABTracking = import_zod21.z.object({
1701
- enableAttribution: import_zod21.z.boolean().nullish().transform((value) => value ?? true),
1702
- enableSource: import_zod21.z.boolean().nullish().transform((value) => value ?? true),
1703
- enableWidget: import_zod21.z.boolean().nullish().transform((value) => value ?? true)
1727
+ var CABTracking = import_zod22.z.object({
1728
+ enableAttribution: import_zod22.z.boolean().nullish().transform((value) => value ?? true),
1729
+ enableSource: import_zod22.z.boolean().nullish().transform((value) => value ?? true),
1730
+ enableWidget: import_zod22.z.boolean().nullish().transform((value) => value ?? true)
1704
1731
  }).nullish().transform((value) => value ?? { enableAttribution: true, enableSource: true, enableWidget: true });
1705
- var CABExperiment = import_zod21.z.object({
1706
- elementId: import_zod21.z.number(),
1707
- experimentId: import_zod21.z.number(),
1708
- experimentType: import_zod21.z.string(),
1709
- selectedId: import_zod21.z.number()
1732
+ var CABExperiment = import_zod22.z.object({
1733
+ elementId: import_zod22.z.number(),
1734
+ experimentId: import_zod22.z.number(),
1735
+ experimentType: import_zod22.z.string(),
1736
+ selectedId: import_zod22.z.number()
1710
1737
  });
1711
1738
  var CABRootSection = CABLayoutSection.extend({
1712
- editorMode: import_zod21.z.enum(editorModes).default(EditorMode.checkoutExtension),
1739
+ editorMode: import_zod22.z.enum(editorModes).default(EditorMode.checkoutExtension),
1713
1740
  experiment: CABExperiment.optional(),
1714
1741
  // Same rule as CABTracking above: the v1 converters pass raw legacy `previewMode` through, so a
1715
1742
  // `null` must fall back rather than throw the widget; malformed values still throw.
1716
- previewMode: import_zod21.z.boolean().nullish().transform((value) => value ?? false),
1717
- storeId: import_zod21.z.number().nullable().default(null),
1743
+ previewMode: import_zod22.z.boolean().nullish().transform((value) => value ?? false),
1744
+ storeId: import_zod22.z.number().nullable().default(null),
1718
1745
  targetArea: TargetArea.nullable(),
1719
1746
  tracking: CABTracking,
1720
- type: import_zod21.z.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
1747
+ type: import_zod22.z.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
1721
1748
  uiLabels: CABUILabels,
1722
- version: import_zod21.z.literal(2).default(2),
1723
- widgetId: import_zod21.z.number().nullable().default(null)
1749
+ version: import_zod22.z.literal(2).default(2),
1750
+ widgetId: import_zod22.z.number().nullable().default(null)
1724
1751
  });
1725
1752
 
1726
1753
  // src/transforms/v1Location.ts
@@ -3560,6 +3587,401 @@ var convertOfferToV2 = ({ id, name, settings }) => {
3560
3587
  // src/transforms/parseShielded.ts
3561
3588
  var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(transform(convertNumericObjects(deepCamelCase(raw))));
3562
3589
 
3590
+ // src/transforms/postPurchase/convertMessagePreview.ts
3591
+ var import_zod27 = require("zod");
3592
+
3593
+ // src/server/shared.ts
3594
+ var NotFoundError = class extends Error {
3595
+ constructor(message) {
3596
+ super(message);
3597
+ this.name = "NotFoundError";
3598
+ }
3599
+ };
3600
+
3601
+ // src/transforms/postPurchase/convertCalloutBlock.ts
3602
+ var import_zod25 = require("zod");
3603
+
3604
+ // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
3605
+ var import_compat4 = require("es-toolkit/compat");
3606
+ var import_uuid14 = require("uuid");
3607
+ var import_zod24 = require("zod");
3608
+
3609
+ // src/schema/widgets/post-purchase-offer/constants.ts
3610
+ var import_zod23 = require("zod");
3611
+ var blockTypes = [
3612
+ "callout_banner",
3613
+ "image",
3614
+ "image_content",
3615
+ "pay_button",
3616
+ "product_information",
3617
+ "separator",
3618
+ "text",
3619
+ "timer"
3620
+ ];
3621
+ var blockType = import_zod23.z.enum(blockTypes);
3622
+ var BlockType = blockType.enum;
3623
+
3624
+ // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
3625
+ var TextAlignment2 = import_zod24.z.union([import_zod24.z.enum(["leading", "center", "trailing"]), import_zod24.z.unknown().transform(() => "leading")]);
3626
+ var TextSize = import_zod24.z.union([
3627
+ import_zod24.z.enum(["xsmall", "small", "base", "default", "medium", "large", "xlarge"]),
3628
+ import_zod24.z.unknown().transform(() => "medium")
3629
+ ]);
3630
+ var CalloutBannerBlock = import_zod24.z.object({
3631
+ id: import_zod24.z.string().optional().default(() => (0, import_uuid14.v4)()),
3632
+ name: import_zod24.z.string().optional(),
3633
+ settings: import_zod24.z.object({
3634
+ superTitle: import_zod24.z.union([import_zod24.z.string(), TiptapDocument]).default(() => "Limited-time Offer"),
3635
+ title: import_zod24.z.union([import_zod24.z.string(), TiptapDocument]).default(() => "Add this customer favorite to your order")
3636
+ }),
3637
+ styles: import_zod24.z.object({
3638
+ superTitleEmphasized: import_zod24.z.boolean().default(false),
3639
+ superTitleSize: TextSize.default("large"),
3640
+ textAlignment: TextAlignment2.default("center"),
3641
+ titleEmphasized: import_zod24.z.boolean().default(true),
3642
+ titleSize: TextSize.default("large")
3643
+ }),
3644
+ type: import_zod24.z.literal(BlockType.callout_banner).default(BlockType.callout_banner)
3645
+ });
3646
+ var ImageBlock = import_zod24.z.object({
3647
+ id: import_zod24.z.string().optional().default(() => (0, import_uuid14.v4)()),
3648
+ name: import_zod24.z.string().optional(),
3649
+ settings: import_zod24.z.union([
3650
+ import_zod24.z.object({
3651
+ /** This isn't used in the post-purchase offer widget */
3652
+ alt: import_zod24.z.string().optional().default(""),
3653
+ image: import_zod24.z.union([import_zod24.z.literal(""), import_zod24.z.url()]).default(""),
3654
+ imageSize: import_zod24.z.number().default(20),
3655
+ imageType: import_zod24.z.enum(["URL", "UPLOAD"]).default("URL")
3656
+ }),
3657
+ import_zod24.z.array(import_zod24.z.never()).transform(() => ({}))
3658
+ ]),
3659
+ type: import_zod24.z.literal(BlockType.image).default(BlockType.image)
3660
+ });
3661
+ var ImageContentBlock = import_zod24.z.object({
3662
+ id: import_zod24.z.string().optional().default(() => (0, import_uuid14.v4)()),
3663
+ name: import_zod24.z.string().optional(),
3664
+ settings: import_zod24.z.object({
3665
+ alt: import_zod24.z.string().optional().default(""),
3666
+ description: import_zod24.z.union([import_zod24.z.string(), TiptapDocument, import_zod24.z.null()]).default(
3667
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
3668
+ ),
3669
+ descriptionSize: TextSize.default("medium"),
3670
+ horizontalAlignment: TextAlignment2.default("leading"),
3671
+ image: import_zod24.z.union([import_zod24.z.literal(""), import_zod24.z.url()]).default(""),
3672
+ imagePlacement: import_zod24.z.enum(["bottom", "left", "right", "top"]).optional().default("left"),
3673
+ imageSize: import_zod24.z.number().default(20),
3674
+ superTitle: import_zod24.z.union([import_zod24.z.string(), TiptapDocument]).default("Lorem Ipsum!"),
3675
+ superTitleSize: TextSize.default("medium"),
3676
+ /** This isn't configurable in the admin-nextjs editor */
3677
+ swapContent: import_zod24.z.boolean().optional().default(false),
3678
+ title: import_zod24.z.union([import_zod24.z.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet"),
3679
+ titleSize: TextSize.default("medium")
3680
+ }),
3681
+ type: import_zod24.z.literal(BlockType.image_content).default(BlockType.image_content)
3682
+ });
3683
+ var PayButtonBlock = import_zod24.z.object({
3684
+ id: import_zod24.z.string().optional().default(() => (0, import_uuid14.v4)()),
3685
+ name: import_zod24.z.string().optional(),
3686
+ settings: import_zod24.z.union([
3687
+ import_zod24.z.object({
3688
+ label: import_zod24.z.string().default("Pay Now")
3689
+ }),
3690
+ import_zod24.z.array(import_zod24.z.never()).transform(() => ({
3691
+ label: "Pay Now"
3692
+ }))
3693
+ ]),
3694
+ styles: import_zod24.z.union([
3695
+ import_zod24.z.object({
3696
+ buttonWidth: import_zod24.z.number().min(10).max(100).default(50)
3697
+ }),
3698
+ import_zod24.z.array(import_zod24.z.never()).transform(() => ({
3699
+ buttonWidth: 50
3700
+ }))
3701
+ ]),
3702
+ type: import_zod24.z.literal(BlockType.pay_button).default(BlockType.pay_button)
3703
+ });
3704
+ var ProductInformationBlock = import_zod24.z.object({
3705
+ /** This isn't configurable in the admin-nextjs editor */
3706
+ hideProductImage: import_zod24.z.boolean().optional().default(false),
3707
+ id: import_zod24.z.string().optional().default(() => (0, import_uuid14.v4)()),
3708
+ name: import_zod24.z.string().optional(),
3709
+ type: import_zod24.z.literal(BlockType.product_information).default(BlockType.product_information)
3710
+ });
3711
+ var SeparatorBlock = import_zod24.z.object({
3712
+ id: import_zod24.z.string().optional().default(() => (0, import_uuid14.v4)()),
3713
+ name: import_zod24.z.string().optional(),
3714
+ type: import_zod24.z.literal(BlockType.separator).default(BlockType.separator)
3715
+ });
3716
+ var TextBlock = import_zod24.z.object({
3717
+ id: import_zod24.z.string().optional().default(() => (0, import_uuid14.v4)()),
3718
+ name: import_zod24.z.string().optional(),
3719
+ settings: import_zod24.z.object({
3720
+ description: import_zod24.z.union([import_zod24.z.string(), TiptapDocument]).optional().default(
3721
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
3722
+ ),
3723
+ /** This isn't used in the post-purchase offer widget */
3724
+ descriptionSize: TextSize.default("medium"),
3725
+ horizontalAlignment: TextAlignment2.default("leading"),
3726
+ superTitle: import_zod24.z.union([import_zod24.z.string(), TiptapDocument]).default("Super Title"),
3727
+ /** This isn't used in the post-purchase offer widget */
3728
+ superTitleSize: TextSize.default("medium"),
3729
+ title: import_zod24.z.union([import_zod24.z.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet."),
3730
+ /** This isn't used in the post-purchase offer widget */
3731
+ titleSize: TextSize.default("medium")
3732
+ }),
3733
+ type: import_zod24.z.literal(BlockType.text).default(BlockType.text)
3734
+ });
3735
+ var TimerBlock = import_zod24.z.object({
3736
+ id: import_zod24.z.string().optional().default(() => (0, import_uuid14.v4)()),
3737
+ name: import_zod24.z.string().optional(),
3738
+ settings: import_zod24.z.object({
3739
+ durationMinutes: import_zod24.z.number().min(0).default(10),
3740
+ durationSeconds: import_zod24.z.union([import_zod24.z.number().min(0), import_zod24.z.unknown().transform(() => 0)]).default(0),
3741
+ endOffer: import_zod24.z.boolean().default(true),
3742
+ title: import_zod24.z.union([import_zod24.z.string(), TiptapDocument]).default("Hurry \u2014 your special offer ends in:")
3743
+ }),
3744
+ styles: import_zod24.z.object({
3745
+ textAlignment: TextAlignment2.default("center"),
3746
+ timerBackgroundColor: import_zod24.z.enum(["info", "warning", "success", "critical"]).default("warning"),
3747
+ timerEmphasized: import_zod24.z.union([import_zod24.z.boolean(), import_zod24.z.unknown().transform(() => true)]).default(true),
3748
+ timerSize: TextSize.default("medium"),
3749
+ timerWidth: import_zod24.z.number().min(10).max(100).optional().default(100),
3750
+ titleEmphasized: import_zod24.z.union([import_zod24.z.boolean(), import_zod24.z.unknown().transform(() => true)]).default(false),
3751
+ titleSize: TextSize.default("medium")
3752
+ }),
3753
+ type: import_zod24.z.literal(BlockType.timer).default(BlockType.timer)
3754
+ });
3755
+ var PostPurchaseBlock = import_zod24.z.discriminatedUnion("type", [
3756
+ CalloutBannerBlock,
3757
+ ImageBlock,
3758
+ ImageContentBlock,
3759
+ PayButtonBlock,
3760
+ ProductInformationBlock,
3761
+ SeparatorBlock,
3762
+ TextBlock,
3763
+ TimerBlock
3764
+ ]);
3765
+
3766
+ // src/transforms/postPurchase/styledTextRun.ts
3767
+ var sizes = {
3768
+ base: "base",
3769
+ default: "base",
3770
+ large: "large",
3771
+ medium: "medium",
3772
+ small: "small",
3773
+ xlarge: "extraLarge",
3774
+ xsmall: "extraSmall"
3775
+ };
3776
+ var styledTextRun = (text, emphasized, size) => ({
3777
+ marks: [
3778
+ ...emphasized ? [{ type: "bold" }] : [],
3779
+ { attrs: { color: "base", fontSize: sizes[size] }, type: "textStyle" }
3780
+ ],
3781
+ text,
3782
+ type: "text"
3783
+ });
3784
+
3785
+ // src/transforms/postPurchase/convertCalloutBlock.ts
3786
+ var fields = ["superTitle", "title"];
3787
+ var Shell = CalloutBannerBlock.pick({ styles: true }).extend({
3788
+ settings: import_zod25.z.object({ superTitle: import_zod25.z.unknown().optional(), title: import_zod25.z.unknown().optional() })
3789
+ });
3790
+ var convertCalloutBlock = (raw, report) => {
3791
+ const omit = (detail) => {
3792
+ report?.({ detail, kind: "section" });
3793
+ return [];
3794
+ };
3795
+ const shell = Shell.safeParse(raw);
3796
+ if (!shell.success) return omit("Unreadable post-purchase callout");
3797
+ const values = fields.map((field) => ({
3798
+ field,
3799
+ result: CalloutBannerBlock.shape.settings.shape[field].safeParse(shell.data.settings[field])
3800
+ }));
3801
+ const styled = values.every(({ result }) => result.success && typeof result.data === "string");
3802
+ const styles2 = shell.data.styles;
3803
+ const horizontal = styled ? { center: "center", leading: "start", trailing: "end" }[styles2.textAlignment] : "center";
3804
+ const sections = values.flatMap(({ field, result }) => {
3805
+ if (!result.success) return omit(`Unreadable post-purchase callout field: ${field}`);
3806
+ const text = result.data;
3807
+ if (text === "") return [];
3808
+ const content = styled && typeof text === "string" ? {
3809
+ content: [
3810
+ {
3811
+ attrs: { textAlign: horizontal },
3812
+ content: [styledTextRun(text, styles2[`${field}Emphasized`], styles2[`${field}Size`])]
3813
+ }
3814
+ ]
3815
+ } : text;
3816
+ const section = CABTextSection.safeParse({ content: { en: content } });
3817
+ return section.success ? [section.data] : omit(`Unreadable post-purchase callout field: ${field}`);
3818
+ });
3819
+ return sections.length ? [CABLayoutSection.parse({ alignment: { horizontal }, frame: "callout", sections })] : [];
3820
+ };
3821
+
3822
+ // src/transforms/postPurchase/convertPayButtonBlock.ts
3823
+ var convertPayButtonBlock = (raw, report) => {
3824
+ const omit = () => {
3825
+ report?.({ detail: "Unreadable post-purchase Pay block", kind: "section" });
3826
+ return [];
3827
+ };
3828
+ const parsed = PayButtonBlock.safeParse(raw);
3829
+ if (!parsed.success) return omit();
3830
+ const { settings, styles: styles2 } = parsed.data;
3831
+ const label = settings.label ? `${settings.label} \xB7 {{total}}` : "{{total}}";
3832
+ const text = CABTextSection.safeParse({ content: { en: label } });
3833
+ if (!text.success) return omit();
3834
+ return [
3835
+ CABLayoutSection.parse({
3836
+ alignment: { horizontal: "center" },
3837
+ direction: "grid",
3838
+ grid: { columns: ["100%"] },
3839
+ sections: [
3840
+ CABButtonSection.parse({
3841
+ action: "addToOrder",
3842
+ sections: [text.data]
3843
+ })
3844
+ ],
3845
+ width: styles2.buttonWidth
3846
+ })
3847
+ ];
3848
+ };
3849
+
3850
+ // src/transforms/postPurchase/convertSeparatorBlock.ts
3851
+ var convertSeparatorBlock = (raw, report) => {
3852
+ if (!SeparatorBlock.safeParse(raw).success) {
3853
+ report?.({ detail: "Unreadable post-purchase separator", kind: "section" });
3854
+ return [];
3855
+ }
3856
+ return [CABSeparatorSection.parse({})];
3857
+ };
3858
+
3859
+ // src/transforms/postPurchase/convertTextBlock.ts
3860
+ var import_zod26 = require("zod");
3861
+ var fields2 = ["superTitle", "title", "description"];
3862
+ var styles = {
3863
+ description: [{ attrs: { color: "base", fontSize: "small" }, type: "textStyle" }],
3864
+ superTitle: [{ attrs: { color: "subdued", fontSize: "small" }, type: "textStyle" }],
3865
+ title: [{ type: "bold" }, { attrs: { color: "base", fontSize: "large" }, type: "textStyle" }]
3866
+ };
3867
+ var settingsSchema = TextBlock.shape.settings;
3868
+ var Shell2 = import_zod26.z.object({
3869
+ settings: settingsSchema.pick({ horizontalAlignment: true }).extend({
3870
+ description: import_zod26.z.unknown().optional(),
3871
+ superTitle: import_zod26.z.unknown().optional(),
3872
+ title: import_zod26.z.unknown().optional()
3873
+ }),
3874
+ type: import_zod26.z.literal("text")
3875
+ });
3876
+ var convertTextBlock = (raw, report) => {
3877
+ const shell = Shell2.safeParse(raw);
3878
+ if (!shell.success) {
3879
+ report?.({ detail: "Unreadable post-purchase text block", kind: "section" });
3880
+ return [];
3881
+ }
3882
+ const values = fields2.map((field) => ({
3883
+ field,
3884
+ result: settingsSchema.shape[field].safeParse(shell.data.settings[field])
3885
+ }));
3886
+ const horizontal = { center: "center", leading: "start", trailing: "end" }[shell.data.settings.horizontalAlignment];
3887
+ const styled = values.every(({ result }) => result.success && typeof result.data === "string");
3888
+ const omit = (field) => {
3889
+ report?.({ detail: `Unreadable post-purchase text field: ${field}`, kind: "section" });
3890
+ return [];
3891
+ };
3892
+ const sections = values.flatMap(({ field, result }) => {
3893
+ if (!result.success) return omit(field);
3894
+ const text = result.data;
3895
+ if (text === null || text === "") return [];
3896
+ const content = styled ? { content: [{ attrs: { textAlign: horizontal }, content: [{ marks: styles[field], text }] }] } : text;
3897
+ const section = CABTextSection.safeParse({ content: { en: content } });
3898
+ return section.success ? [section.data] : omit(field);
3899
+ });
3900
+ return [
3901
+ CABLayoutSection.parse({
3902
+ alignment: {
3903
+ horizontal
3904
+ },
3905
+ sections
3906
+ })
3907
+ ];
3908
+ };
3909
+
3910
+ // src/transforms/postPurchase/convertTimerBlock.ts
3911
+ var Presentation = TimerBlock.pick({ styles: true }).extend({
3912
+ settings: TimerBlock.shape.settings.pick({ title: true })
3913
+ });
3914
+ var convertTimerBlock = (raw, report) => {
3915
+ const omit = () => {
3916
+ report?.({ detail: "Unreadable post-purchase timer display", kind: "section" });
3917
+ return [];
3918
+ };
3919
+ const parsed = Presentation.safeParse(raw);
3920
+ if (!parsed.success) return omit();
3921
+ const { title } = parsed.data.settings;
3922
+ const styles2 = parsed.data.styles;
3923
+ const horizontal = { center: "center", leading: "start", trailing: "end" }[styles2.textAlignment];
3924
+ const content = typeof title === "string" ? {
3925
+ content: [
3926
+ {
3927
+ attrs: { textAlign: horizontal },
3928
+ content: [
3929
+ styledTextRun(title, styles2.titleEmphasized, styles2.titleSize),
3930
+ styledTextRun(" {{timeRemaining}}", styles2.timerEmphasized, styles2.timerSize)
3931
+ ]
3932
+ }
3933
+ ]
3934
+ } : title;
3935
+ const text = CABTextSection.safeParse({ content: { en: content } });
3936
+ if (!text.success) return omit();
3937
+ return [
3938
+ CABBannerSection.parse({
3939
+ color: styles2.timerBackgroundColor,
3940
+ dismissible: false,
3941
+ sections: [text.data],
3942
+ width: styles2.timerWidth
3943
+ })
3944
+ ];
3945
+ };
3946
+
3947
+ // src/transforms/postPurchase/convertMessagePreview.ts
3948
+ var MessageWidget = import_zod27.z.object({
3949
+ blocks: import_zod27.z.array(import_zod27.z.unknown()).min(1),
3950
+ type: import_zod27.z.literal("shopify_post_purchase_extension")
3951
+ });
3952
+ var BlockType2 = import_zod27.z.object({ type: import_zod27.z.string() });
3953
+ var converters = {
3954
+ callout_banner: convertCalloutBlock,
3955
+ pay_button: convertPayButtonBlock,
3956
+ separator: convertSeparatorBlock,
3957
+ text: convertTextBlock,
3958
+ timer: convertTimerBlock
3959
+ };
3960
+ var convertMessagePreview = (id, settings, report) => {
3961
+ const parsed = MessageWidget.safeParse(settings);
3962
+ if (!parsed.success) throw new NotFoundError("Unsupported post-purchase message preview");
3963
+ return CABRootSection.parse({
3964
+ editorMode: "postPurchaseOffer",
3965
+ previewMode: true,
3966
+ sections: parsed.data.blocks.flatMap((block) => {
3967
+ const type = BlockType2.safeParse(block);
3968
+ const kind = type.success ? type.data.type : void 0;
3969
+ const convert2 = kind ? converters[kind] : void 0;
3970
+ if (convert2) return convert2(block, report);
3971
+ report?.({
3972
+ detail: kind ? `Unsupported post-purchase block type: ${kind}` : "Unreadable post-purchase block: missing type",
3973
+ kind: "section"
3974
+ });
3975
+ return [];
3976
+ }),
3977
+ sectionType: "layout",
3978
+ widgetId: id
3979
+ });
3980
+ };
3981
+
3982
+ // src/transforms/postPurchase/types.ts
3983
+ var isPostPurchaseV1 = (data) => !!data && typeof data === "object" && data.type === WidgetType.shopify_post_purchase_extension && Array.isArray(data.blocks);
3984
+
3563
3985
  // src/transforms/presentmentThresholds.ts
3564
3986
  var presentmentThresholds = (presentment) => {
3565
3987
  if (!presentment?.enabled) return {};