@rebuy/rebuy 3.28.0 → 3.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1347,7 +1347,14 @@ var CABReviewsSection = z17.object({
1347
1347
  sectionId: z17.uuid().default(() => uuidv710()),
1348
1348
  sectionType: z17.literal(SectionType.reviews).default(SectionType.reviews),
1349
1349
  size: z17.enum(reviewsSizes).default(ReviewsSize.default),
1350
- strokeColor: z17.string().default("#fadb14"),
1350
+ /**
1351
+ * Star outline color, interpolated into a style by the renderer, so it is hex-constrained like
1352
+ * `CABButtonSection.color`. The legacy source (`PostPurchaseSettings.styles.starStrokeColor`) is a free
1353
+ * string: its converter must validate and fall back to this default rather than let one odd value drop
1354
+ * the whole reviews section.
1355
+ */
1356
+ strokeColor: z17.string().regex(HEX_COLOR_REGEX).default("#fadb14"),
1357
+ /** Star outline width in px; `0` draws no outline. The legacy `styles.strokeWidth` is a STRING ('1') — its converter coerces. */
1351
1358
  strokeWidth: z17.number().nonnegative().default(0)
1352
1359
  });
1353
1360
 
@@ -3527,7 +3534,7 @@ var convertOfferToV2 = ({ id, name, settings }) => {
3527
3534
  var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(transform(convertNumericObjects(deepCamelCase(raw))));
3528
3535
 
3529
3536
  // src/transforms/postPurchase/convertMessagePreview.ts
3530
- import { z as z27 } from "zod";
3537
+ import { z as z30 } from "zod";
3531
3538
 
3532
3539
  // src/server/shared.ts
3533
3540
  var NotFoundError = class extends Error {
@@ -3758,6 +3765,150 @@ var convertCalloutBlock = (raw, report) => {
3758
3765
  return sections.length ? [CABLayoutSection.parse({ alignment: { horizontal }, frame: "callout", sections })] : [];
3759
3766
  };
3760
3767
 
3768
+ // src/transforms/postPurchase/convertImageFrame.ts
3769
+ import { z as z26 } from "zod";
3770
+
3771
+ // src/transforms/postPurchase/sizeImageSource.ts
3772
+ var sizeImageSource = (source, size) => {
3773
+ const extension = source.split(".").pop();
3774
+ for (const previous of ["small", "medium", "large", "original", "master"]) {
3775
+ source = source.replace(`_${previous}.${extension}`, `.${extension}`);
3776
+ }
3777
+ return source.replace(`.${extension}`, `${size === void 0 ? "" : `_${size}`}.${extension}`);
3778
+ };
3779
+
3780
+ // src/transforms/postPurchase/convertImageFrame.ts
3781
+ var Source = z26.url().default("https://cdn.shopify.com/s/files/1/0605/0555/5177/files/placeholder.jpg?v=1657762972");
3782
+ var DEFAULT_IMAGE_SIZE = 20;
3783
+ var convertImageFrame = (raw) => {
3784
+ const parsed = ImageBlock.shape.settings.options[0].safeParse(raw);
3785
+ if (!parsed.success) return null;
3786
+ const settings = parsed.data;
3787
+ const source = sizeImageSource(Source.parse(settings.image || void 0));
3788
+ const withAlt = CABImageSection.safeParse({ altText: settings.alt, source });
3789
+ const image = withAlt.success ? withAlt.data : CABImageSection.parse({ source });
3790
+ const size = settings.imageSize > 0 ? settings.imageSize : DEFAULT_IMAGE_SIZE;
3791
+ return CABLayoutSection.parse({
3792
+ alignment: { horizontal: "center" },
3793
+ direction: "grid",
3794
+ grid: { columns: size <= 1 ? ["100%"] : [size] },
3795
+ sections: [image],
3796
+ width: size <= 1 ? size * 100 : 100
3797
+ });
3798
+ };
3799
+
3800
+ // src/transforms/postPurchase/convertImageBlock.ts
3801
+ var dropMalformedAlt = (raw) => {
3802
+ if (typeof raw !== "object" || raw === null) return raw;
3803
+ const { settings, ...rest } = raw;
3804
+ if (typeof settings !== "object" || settings === null || Array.isArray(settings)) return raw;
3805
+ const { alt, ...restSettings } = settings;
3806
+ if (typeof alt === "string" || alt === void 0) return raw;
3807
+ return { ...rest, settings: restSettings };
3808
+ };
3809
+ var convertImageBlock = (raw, report) => {
3810
+ const block = ImageBlock.safeParse(dropMalformedAlt(raw));
3811
+ const image = block.success ? convertImageFrame(block.data.settings) : null;
3812
+ if (!image) {
3813
+ report?.({ detail: "Unreadable post-purchase image", kind: "section" });
3814
+ return [];
3815
+ }
3816
+ return [
3817
+ CABLayoutSection.parse({
3818
+ alignment: { horizontal: "center" },
3819
+ frame: "offer-content",
3820
+ sections: [image],
3821
+ spacing: "none"
3822
+ })
3823
+ ];
3824
+ };
3825
+
3826
+ // src/transforms/postPurchase/convertImageContentBlock.ts
3827
+ import { z as z28 } from "zod";
3828
+
3829
+ // src/transforms/postPurchase/convertImageContentText.ts
3830
+ var fields2 = ["superTitle", "title", "description"];
3831
+ var convertImageContentText = (settings, report) => {
3832
+ const horizontal = { center: "center", leading: "start", trailing: "end" }[settings.horizontalAlignment];
3833
+ const sections = fields2.flatMap((field) => {
3834
+ const omit = () => {
3835
+ report?.({ detail: `Unreadable post-purchase image-content field: ${field}`, kind: "section" });
3836
+ return [];
3837
+ };
3838
+ const value = ImageContentBlock.shape.settings.shape[field].safeParse(settings[field]);
3839
+ if (!value.success) return omit();
3840
+ const text = value.data;
3841
+ if (text === null || text === "") return [];
3842
+ const content = typeof text === "string" ? {
3843
+ content: [
3844
+ {
3845
+ attrs: { textAlign: horizontal },
3846
+ content: [styledTextRun(text, field !== "description", settings[`${field}Size`])]
3847
+ }
3848
+ ]
3849
+ } : text;
3850
+ const section = CABTextSection.safeParse({ content: { en: content } });
3851
+ return section.success ? [section.data] : omit();
3852
+ });
3853
+ return CABLayoutSection.parse({ alignment: { horizontal }, sections });
3854
+ };
3855
+
3856
+ // src/transforms/postPurchase/imageContentSettings.ts
3857
+ import { z as z27 } from "zod";
3858
+ var ImageContentSettings = ImageContentBlock.shape.settings.pick({
3859
+ descriptionSize: true,
3860
+ horizontalAlignment: true,
3861
+ superTitleSize: true,
3862
+ swapContent: true,
3863
+ titleSize: true
3864
+ }).extend({
3865
+ alt: z27.unknown().optional(),
3866
+ description: z27.unknown().optional(),
3867
+ image: z27.unknown().optional(),
3868
+ imagePlacement: ImageContentBlock.shape.settings.shape.imagePlacement.unwrap().nullable(),
3869
+ imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(z27.number().positive()),
3870
+ superTitle: z27.unknown().optional(),
3871
+ title: z27.unknown().optional()
3872
+ });
3873
+
3874
+ // src/transforms/postPurchase/convertImageContentBlock.ts
3875
+ var Shell2 = z28.object({ settings: ImageContentSettings, type: z28.literal("image_content") });
3876
+ var PROPORTIONAL_BREAK_AT = 500;
3877
+ var convertImageContentBlock = (raw, report) => {
3878
+ const shell = Shell2.safeParse(raw);
3879
+ if (!shell.success) {
3880
+ report?.({ detail: "Unreadable post-purchase image-content block", kind: "section" });
3881
+ return [];
3882
+ }
3883
+ const settings = shell.data.settings;
3884
+ const alt = typeof settings.alt === "string" ? settings.alt : void 0;
3885
+ if (settings.alt !== void 0 && alt === void 0) {
3886
+ report?.({ detail: "Unreadable post-purchase image-content alt text", kind: "section" });
3887
+ }
3888
+ const image = convertImageFrame({ alt, image: settings.image, imageSize: settings.imageSize });
3889
+ if (!image) report?.({ detail: "Unreadable post-purchase image-content image", kind: "section" });
3890
+ const text = convertImageContentText(settings, report);
3891
+ const textFrame = CABLayoutSection.parse({ direction: "grid", grid: { columns: ["100%"] }, sections: [text] });
3892
+ const placement = settings.imagePlacement ?? (settings.swapContent ? "right" : "left");
3893
+ const imageFirst = placement === "left" || placement === "top";
3894
+ const sections = imageFirst ? [image, textFrame] : [textFrame, image];
3895
+ const ordered = sections.filter((section) => section !== null);
3896
+ const inner = placement === "left" || placement === "right" ? CABLayoutSection.parse({
3897
+ sections: ordered,
3898
+ spacing: "loose",
3899
+ wrapping: {
3900
+ breakAt: settings.imageSize <= 1 ? PROPORTIONAL_BREAK_AT : settings.imageSize,
3901
+ maxPerLine: 2
3902
+ }
3903
+ }) : CABLayoutSection.parse({
3904
+ direction: "grid",
3905
+ grid: { columns: ["100%"] },
3906
+ sections: [CABLayoutSection.parse({ sections: ordered })],
3907
+ width: 95
3908
+ });
3909
+ return [CABLayoutSection.parse({ frame: "offer-content", sections: [inner], spacing: "none" })];
3910
+ };
3911
+
3761
3912
  // src/transforms/postPurchase/convertPayButtonBlock.ts
3762
3913
  var convertPayButtonBlock = (raw, report) => {
3763
3914
  const omit = () => {
@@ -3786,6 +3937,60 @@ var convertPayButtonBlock = (raw, report) => {
3786
3937
  ];
3787
3938
  };
3788
3939
 
3940
+ // src/transforms/postPurchase/convertProductInformation.ts
3941
+ var convertProductInformation = (raw, report) => {
3942
+ const block = ProductInformationBlock.safeParse(raw);
3943
+ if (!block.success) {
3944
+ report?.({ detail: "Unreadable post-purchase product information", kind: "section" });
3945
+ return [];
3946
+ }
3947
+ return [
3948
+ CABOffersSection.parse({
3949
+ direction: "grid",
3950
+ sections: [
3951
+ CABLayoutSection.parse({
3952
+ alignment: { horizontal: "center" },
3953
+ sections: [
3954
+ CABLayoutSection.parse({
3955
+ alignment: { horizontal: "center" },
3956
+ direction: "grid",
3957
+ grid: { columns: [250] },
3958
+ sections: [
3959
+ CABImageSection.parse({ altText: "{{productTitle}}", source: "{{productImage}}" })
3960
+ ],
3961
+ width: 90
3962
+ })
3963
+ ]
3964
+ }),
3965
+ CABLayoutSection.parse({
3966
+ sections: [
3967
+ CABTextSection.parse({
3968
+ content: {
3969
+ en: {
3970
+ content: [
3971
+ {
3972
+ content: [
3973
+ {
3974
+ marks: [{ attrs: { fontSize: "heading" }, type: "textStyle" }],
3975
+ text: "{{productTitle}}"
3976
+ }
3977
+ ]
3978
+ }
3979
+ ]
3980
+ }
3981
+ }
3982
+ }),
3983
+ CABReviewsSection.parse({}),
3984
+ CABTextSection.parse({ content: { en: "{{productDescription}}" } })
3985
+ ]
3986
+ })
3987
+ ],
3988
+ spacing: "extraLoose",
3989
+ wrapping: { breakAt: 500, maxPerLine: block.data.hideProductImage ? 1 : 2 }
3990
+ })
3991
+ ];
3992
+ };
3993
+
3789
3994
  // src/transforms/postPurchase/convertSeparatorBlock.ts
3790
3995
  var convertSeparatorBlock = (raw, report) => {
3791
3996
  if (!SeparatorBlock.safeParse(raw).success) {
@@ -3796,34 +4001,36 @@ var convertSeparatorBlock = (raw, report) => {
3796
4001
  };
3797
4002
 
3798
4003
  // src/transforms/postPurchase/convertTextBlock.ts
3799
- import { z as z26 } from "zod";
3800
- var fields2 = ["superTitle", "title", "description"];
4004
+ import { z as z29 } from "zod";
4005
+ var fields3 = ["superTitle", "title", "description"];
3801
4006
  var styles = {
3802
4007
  description: [{ attrs: { color: "base", fontSize: "small" }, type: "textStyle" }],
3803
4008
  superTitle: [{ attrs: { color: "subdued", fontSize: "small" }, type: "textStyle" }],
3804
4009
  title: [{ type: "bold" }, { attrs: { color: "base", fontSize: "large" }, type: "textStyle" }]
3805
4010
  };
3806
4011
  var settingsSchema = TextBlock.shape.settings;
3807
- var Shell2 = z26.object({
4012
+ var Shell3 = z29.object({
3808
4013
  settings: settingsSchema.pick({ horizontalAlignment: true }).extend({
3809
- description: z26.unknown().optional(),
3810
- superTitle: z26.unknown().optional(),
3811
- title: z26.unknown().optional()
4014
+ description: z29.unknown().optional(),
4015
+ superTitle: z29.unknown().optional(),
4016
+ title: z29.unknown().optional()
3812
4017
  }),
3813
- type: z26.literal("text")
4018
+ type: z29.literal("text")
3814
4019
  });
3815
4020
  var convertTextBlock = (raw, report) => {
3816
- const shell = Shell2.safeParse(raw);
4021
+ const shell = Shell3.safeParse(raw);
3817
4022
  if (!shell.success) {
3818
4023
  report?.({ detail: "Unreadable post-purchase text block", kind: "section" });
3819
4024
  return [];
3820
4025
  }
3821
- const values = fields2.map((field) => ({
4026
+ const values = fields3.map((field) => ({
3822
4027
  field,
3823
4028
  result: settingsSchema.shape[field].safeParse(shell.data.settings[field])
3824
4029
  }));
3825
4030
  const horizontal = { center: "center", leading: "start", trailing: "end" }[shell.data.settings.horizontalAlignment];
3826
- const styled = values.every(({ result }) => result.success && typeof result.data === "string");
4031
+ const styled = values.every(
4032
+ ({ result }) => result.success && (result.data === null || typeof result.data === "string")
4033
+ );
3827
4034
  const omit = (field) => {
3828
4035
  report?.({ detail: `Unreadable post-purchase text field: ${field}`, kind: "section" });
3829
4036
  return [];
@@ -3836,20 +4043,18 @@ var convertTextBlock = (raw, report) => {
3836
4043
  const section = CABTextSection.safeParse({ content: { en: content } });
3837
4044
  return section.success ? [section.data] : omit(field);
3838
4045
  });
3839
- return [
3840
- CABLayoutSection.parse({
3841
- alignment: {
3842
- horizontal
3843
- },
3844
- sections
3845
- })
3846
- ];
4046
+ return sections.length ? [CABLayoutSection.parse({ alignment: { horizontal }, sections })] : [];
3847
4047
  };
3848
4048
 
3849
4049
  // src/transforms/postPurchase/convertTimerBlock.ts
3850
4050
  var Presentation = TimerBlock.pick({ styles: true }).extend({
3851
4051
  settings: TimerBlock.shape.settings.pick({ title: true })
3852
4052
  });
4053
+ var withCountdown = (doc, run, textAlign) => {
4054
+ const paragraphs = doc.content.length ? doc.content : [TiptapParagraph.parse({ attrs: { textAlign } })];
4055
+ const last = paragraphs[paragraphs.length - 1];
4056
+ return { ...doc, content: [...paragraphs.slice(0, -1), { ...last, content: [...last.content, run] }] };
4057
+ };
3853
4058
  var convertTimerBlock = (raw, report) => {
3854
4059
  const omit = () => {
3855
4060
  report?.({ detail: "Unreadable post-purchase timer display", kind: "section" });
@@ -3860,17 +4065,15 @@ var convertTimerBlock = (raw, report) => {
3860
4065
  const { title } = parsed.data.settings;
3861
4066
  const styles2 = parsed.data.styles;
3862
4067
  const horizontal = { center: "center", leading: "start", trailing: "end" }[styles2.textAlignment];
4068
+ const countdown = styledTextRun(" {{timeRemaining}}", styles2.timerEmphasized, styles2.timerSize);
3863
4069
  const content = typeof title === "string" ? {
3864
4070
  content: [
3865
4071
  {
3866
4072
  attrs: { textAlign: horizontal },
3867
- content: [
3868
- styledTextRun(title, styles2.titleEmphasized, styles2.titleSize),
3869
- styledTextRun(" {{timeRemaining}}", styles2.timerEmphasized, styles2.timerSize)
3870
- ]
4073
+ content: [styledTextRun(title, styles2.titleEmphasized, styles2.titleSize), countdown]
3871
4074
  }
3872
4075
  ]
3873
- } : title;
4076
+ } : withCountdown(title, countdown, horizontal);
3874
4077
  const text = CABTextSection.safeParse({ content: { en: content } });
3875
4078
  if (!text.success) return omit();
3876
4079
  return [
@@ -3884,14 +4087,17 @@ var convertTimerBlock = (raw, report) => {
3884
4087
  };
3885
4088
 
3886
4089
  // src/transforms/postPurchase/convertMessagePreview.ts
3887
- var MessageWidget = z27.object({
3888
- blocks: z27.array(z27.unknown()).min(1),
3889
- type: z27.literal("shopify_post_purchase_extension")
4090
+ var MessageWidget = z30.object({
4091
+ blocks: z30.array(z30.unknown()).min(1),
4092
+ type: z30.literal(WidgetType.shopify_post_purchase_extension)
3890
4093
  });
3891
- var BlockType2 = z27.object({ type: z27.string() });
4094
+ var BlockType2 = z30.object({ type: z30.string() });
3892
4095
  var converters = {
3893
4096
  callout_banner: convertCalloutBlock,
4097
+ image: convertImageBlock,
4098
+ image_content: convertImageContentBlock,
3894
4099
  pay_button: convertPayButtonBlock,
4100
+ product_information: convertProductInformation,
3895
4101
  separator: convertSeparatorBlock,
3896
4102
  text: convertTextBlock,
3897
4103
  timer: convertTimerBlock
@@ -3905,7 +4111,7 @@ var convertMessagePreview = (id, settings, report) => {
3905
4111
  sections: parsed.data.blocks.flatMap((block) => {
3906
4112
  const type = BlockType2.safeParse(block);
3907
4113
  const kind = type.success ? type.data.type : void 0;
3908
- const convert2 = kind ? converters[kind] : void 0;
4114
+ const convert2 = kind && Object.hasOwn(converters, kind) ? converters[kind] : void 0;
3909
4115
  if (convert2) return convert2(block, report);
3910
4116
  report?.({
3911
4117
  detail: kind ? `Unsupported post-purchase block type: ${kind}` : "Unreadable post-purchase block: missing type",
@@ -0,0 +1,4 @@
1
+ import { CABLayoutSection } from '../../schema/widgets/checkout-and-beyond/layout';
2
+ import { type Reporter } from '../../server/shared';
3
+ /** A standalone image block, framed as the post-purchase offer's own content card. */
4
+ export declare const convertImageBlock: (raw: unknown, report?: Reporter) => CABLayoutSection[];
@@ -0,0 +1,7 @@
1
+ import { CABLayoutSection } from '../../schema/widgets/checkout-and-beyond/layout';
2
+ import { type Reporter } from '../../server/shared';
3
+ /**
4
+ * Image with text, placed left/right/top/bottom of it. Alt text is read from THIS block's own settings
5
+ * only — the plain `image` block's `alt` is never rendered by legacy (plan decision 15).
6
+ */
7
+ export declare const convertImageContentBlock: (raw: unknown, report?: Reporter) => CABLayoutSection[];
@@ -0,0 +1,5 @@
1
+ import { CABLayoutSection } from '../../schema/widgets/checkout-and-beyond/layout';
2
+ import { type Reporter } from '../../server/shared';
3
+ import { type ImageContentSettings } from '../../transforms/postPurchase/imageContentSettings';
4
+ /** Style readable strings independently; documents retain their authored marks and alignment. */
5
+ export declare const convertImageContentText: (settings: ImageContentSettings, report?: Reporter) => CABLayoutSection;
@@ -0,0 +1,9 @@
1
+ import { CABLayoutSection } from '../../schema/widgets/checkout-and-beyond/layout';
2
+ /**
3
+ * Shared legacy image policy, preserving numeric pixel and proportional frame units. A malformed `alt`
4
+ * (e.g. stray HTML) never drops the image itself — legacy never rejected the whole block for it, so this
5
+ * retries without alt text rather than returning `null`. A non-positive `imageSize` (corrupted saved data;
6
+ * the schema only defaults on a missing value, not on `0` or a negative one) falls back to the schema's own
7
+ * default instead of producing a zero/negative-width column.
8
+ */
9
+ export declare const convertImageFrame: (raw: unknown) => CABLayoutSection | null;
@@ -1,8 +1,8 @@
1
1
  import { CABRootSection } from '../../schema/widgets/checkout-and-beyond/root';
2
2
  import { type Reporter } from '../../server/shared';
3
3
  /**
4
- * Converts a saved post-purchase widget's blocks into a CAB preview tree. Only the five converters this
5
- * slice ships handle their block; every other block type — future (image/image_content/product_information)
6
- * or truly unknown — reports and drops only itself, and an unreadable block (no `type`) does the same.
4
+ * Converts a saved post-purchase widget's blocks into a CAB preview tree. Only the eight converters above
5
+ * handle their block; a truly unknown block type reports and drops only itself, and an unreadable block
6
+ * (no `type`) does the same.
7
7
  */
8
8
  export declare const convertMessagePreview: (id: number, settings: unknown, report?: Reporter) => CABRootSection;
@@ -0,0 +1,4 @@
1
+ import { CABOffersSection } from '../../schema/widgets/checkout-and-beyond/offers';
2
+ import type { Reporter } from '../../server/shared';
3
+ /** Structure only: the card provider binds the separately prepared fixed product. */
4
+ export declare const convertProductInformation: (raw: unknown, report?: Reporter) => CABOffersSection[];
@@ -0,0 +1,50 @@
1
+ import { z } from 'zod';
2
+ /** Keep raw fields for local recovery and do not inject the full schema's placement default. */
3
+ export declare const ImageContentSettings: z.ZodObject<{
4
+ superTitleSize: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<{
5
+ small: "small";
6
+ default: "default";
7
+ base: "base";
8
+ large: "large";
9
+ medium: "medium";
10
+ xsmall: "xsmall";
11
+ xlarge: "xlarge";
12
+ }>, z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>]>>;
13
+ titleSize: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<{
14
+ small: "small";
15
+ default: "default";
16
+ base: "base";
17
+ large: "large";
18
+ medium: "medium";
19
+ xsmall: "xsmall";
20
+ xlarge: "xlarge";
21
+ }>, z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>]>>;
22
+ descriptionSize: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<{
23
+ small: "small";
24
+ default: "default";
25
+ base: "base";
26
+ large: "large";
27
+ medium: "medium";
28
+ xsmall: "xsmall";
29
+ xlarge: "xlarge";
30
+ }>, z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>]>>;
31
+ horizontalAlignment: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<{
32
+ center: "center";
33
+ leading: "leading";
34
+ trailing: "trailing";
35
+ }>, z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>]>>;
36
+ swapContent: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
37
+ alt: z.ZodOptional<z.ZodUnknown>;
38
+ description: z.ZodOptional<z.ZodUnknown>;
39
+ image: z.ZodOptional<z.ZodUnknown>;
40
+ imagePlacement: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
41
+ top: "top";
42
+ bottom: "bottom";
43
+ right: "right";
44
+ left: "left";
45
+ }>>>;
46
+ imageSize: z.ZodPipe<z.ZodDefault<z.ZodNumber>, z.ZodNumber>;
47
+ superTitle: z.ZodOptional<z.ZodUnknown>;
48
+ title: z.ZodOptional<z.ZodUnknown>;
49
+ }, z.core.$strip>;
50
+ export type ImageContentSettings = z.infer<typeof ImageContentSettings>;
@@ -0,0 +1,2 @@
1
+ /** Preserve legacy named-size removal independently of each image's fallback and requested size. */
2
+ export declare const sizeImageSource: (source: string, size?: string) => string;
@@ -1,5 +1,11 @@
1
1
  import { WidgetType } from '../../schema/widgets/checkout-and-beyond/constants';
2
- /** A saved post-purchase message-block widget: `type` plus its ordered `blocks`, no `version` discriminator. */
2
+ /**
3
+ * A saved post-purchase widget as `/cab/sections` sees it: `type` plus its ordered `blocks`, no `version`
4
+ * discriminator. This is the shape of EVERY `PostPurchaseSettings` (its `blocks` even default to three
5
+ * blocks), so the guard below claims every saved post-purchase widget by design — the section tree is the
6
+ * widget's presentation, and the non-block settings (`discount`, `products`, `integrations`, …) are read by
7
+ * the post-purchase session/Decision contracts, not converted into sections.
8
+ */
3
9
  export type V1PostPurchaseSettings = {
4
10
  blocks: unknown[];
5
11
  type: typeof WidgetType.shopify_post_purchase_extension;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rebuy/rebuy",
3
- "version": "3.28.0",
3
+ "version": "3.29.0",
4
4
  "description": "Shared zod schemas, legacy-to-CAB widget transforms, and server orchestrators for Rebuy's Shopify consumers (rebuy-api, admin-nextjs, rebuy-shopify-extensions)",
5
5
  "license": "MIT",
6
6
  "author": "Rebuy, Inc.",