@rebuy/rebuy 3.41.0 → 3.43.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 (60) hide show
  1. package/dist/index.cjs +971 -787
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.mjs +971 -787
  4. package/dist/pricing/index.cjs +58 -1
  5. package/dist/pricing/index.d.ts +2 -0
  6. package/dist/pricing/index.mjs +58 -1
  7. package/dist/pricing/postPurchaseDisplayFacts.d.ts +36 -0
  8. package/dist/pricing/postPurchaseDisplayPrice.d.ts +8 -0
  9. package/dist/pricing/postPurchaseReduction.d.ts +17 -0
  10. package/dist/schema/checkout-and-beyond/constants.cjs +4 -0
  11. package/dist/schema/checkout-and-beyond/constants.mjs +4 -0
  12. package/dist/schema/checkout-and-beyond/index.cjs +388 -374
  13. package/dist/schema/checkout-and-beyond/index.mjs +388 -374
  14. package/dist/schema/index.d.ts +2 -0
  15. package/dist/schema/postPurchaseAdmission.d.ts +33 -0
  16. package/dist/schema/postPurchaseDisplayPrice.d.ts +31 -0
  17. package/dist/schema/postPurchaseFollowups.d.ts +47 -0
  18. package/dist/schema/postPurchaseHealth.d.ts +5 -0
  19. package/dist/schema/postPurchasePlanCatalog.d.ts +2 -0
  20. package/dist/schema/postPurchaseProduct.d.ts +2 -0
  21. package/dist/schema/postPurchaseProductCollectionView.d.ts +62 -0
  22. package/dist/schema/postPurchaseProductView.d.ts +65 -0
  23. package/dist/schema/postPurchaseRecovery.d.ts +47 -0
  24. package/dist/schema/postPurchaseSubscriptionProduct.d.ts +2 -0
  25. package/dist/schema/postPurchaseUpgrade.d.ts +117 -0
  26. package/dist/schema/widget-data.cjs +452 -441
  27. package/dist/schema/widget-data.mjs +452 -441
  28. package/dist/schema/widgets/checkout-and-beyond/common.d.ts +14 -0
  29. package/dist/schema/widgets/checkout-and-beyond/image.d.ts +8 -0
  30. package/dist/schema/widgets/checkout-and-beyond/imageThumbnails.d.ts +13 -0
  31. package/dist/schema/widgets/checkout-and-beyond/index.d.ts +1 -0
  32. package/dist/schema/widgets/checkout-and-beyond/variants.d.ts +1 -0
  33. package/dist/server/index.cjs +1721 -1419
  34. package/dist/server/index.mjs +1707 -1405
  35. package/dist/server/postPurchasePlanCatalog.d.ts +4 -1
  36. package/dist/server/preparePostPurchaseAdmissionView.d.ts +53 -0
  37. package/dist/server/preparePostPurchaseCollectionGroup.d.ts +57 -0
  38. package/dist/server/preparePostPurchaseCollectionView.d.ts +53 -0
  39. package/dist/server/preparePostPurchaseGroupAdmissionView.d.ts +53 -0
  40. package/dist/server/preparePostPurchaseGroupDefault.d.ts +53 -0
  41. package/dist/server/preparePostPurchaseGroupView.d.ts +53 -0
  42. package/dist/server/preparePostPurchaseMemberView.d.ts +159 -0
  43. package/dist/server/preparePostPurchaseQuantityAdmissionView.d.ts +53 -0
  44. package/dist/server/preparePostPurchaseQuantityView.d.ts +53 -0
  45. package/dist/server/preparePostPurchaseSubscription.d.ts +1 -0
  46. package/dist/server/selectPostPurchaseChoice.d.ts +1 -0
  47. package/dist/transforms/index.cjs +980 -581
  48. package/dist/transforms/index.mjs +980 -581
  49. package/dist/transforms/postPurchase/convertProductInformation.d.ts +6 -2
  50. package/dist/transforms/postPurchase/productCardControls.d.ts +7 -0
  51. package/dist/transforms/postPurchase/productCardCosts.d.ts +3 -0
  52. package/dist/transforms/postPurchase/productCardPricing.d.ts +3 -0
  53. package/dist/transforms/postPurchase/productCardRows.d.ts +63 -0
  54. package/dist/transforms/postPurchase/productCardSettings.d.ts +103 -0
  55. package/dist/transforms/postPurchase/types.d.ts +2 -2
  56. package/dist/transforms/productCard/earnedText.d.ts +25 -0
  57. package/dist/transforms/productCard/priceText.d.ts +2 -0
  58. package/dist/transforms/productCard/quantitySection.d.ts +28 -0
  59. package/dist/transforms/productCard/subscriptionToggle.d.ts +18 -0
  60. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  // src/schema/widgets/checkout-and-beyond/image.ts
2
2
  import { v7 as uuidv713 } from "uuid";
3
- import { z as z21 } from "zod";
3
+ import { z as z22 } from "zod";
4
4
 
5
5
  // src/schema/widgets/checkout-and-beyond/common.ts
6
6
  var freezeEnum = (values) => Object.freeze(Object.fromEntries(values.map((v) => [v, v])));
@@ -170,6 +170,8 @@ var variableTypes = ["boolean", "number", "text"];
170
170
  var VariableType = freezeEnum(variableTypes);
171
171
  var variantModes = ["multiple", "single"];
172
172
  var VariantMode = freezeEnum(variantModes);
173
+ var variantsModes = [...variantModes, "productGroup"];
174
+ var VariantsMode = freezeEnum(variantsModes);
173
175
  var variantSelectors = ["menu", "radio", "button"];
174
176
  var VariantSelector = freezeEnum(variantSelectors);
175
177
  var verticalAlignments = ["top", "middle", "bottom"];
@@ -286,6 +288,13 @@ var IconSize = freezeEnum(iconSizes);
286
288
  var iconTones = ["auto", "critical", "custom", "info", "neutral", "success", "warning"];
287
289
  var IconTone = freezeEnum(iconTones);
288
290
 
291
+ // src/schema/widgets/checkout-and-beyond/imageThumbnails.ts
292
+ import { z } from "zod";
293
+ var CABImageThumbnails = z.object({
294
+ limit: z.number().int().min(1).default(8),
295
+ perLine: z.number().int().min(1).max(8).default(4)
296
+ });
297
+
289
298
  // src/schema/widgets/checkout-and-beyond/regex.ts
290
299
  var DYNAMIC_TOKEN_REGEX = /^\{\{\s*[A-Za-z]+\s*\}\}$/;
291
300
  var HEX_COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
@@ -293,20 +302,20 @@ var ROOT_RELATIVE_PATH_REGEX = /^\/(?!\/)/;
293
302
  var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
294
303
 
295
304
  // src/schema/widgets/checkout-and-beyond/shared.ts
296
- import { z as z20 } from "zod";
305
+ import { z as z21 } from "zod";
297
306
 
298
307
  // src/schema/widgets/checkout-and-beyond/banner.ts
299
- import { z as z4 } from "zod";
308
+ import { z as z5 } from "zod";
300
309
 
301
310
  // src/schema/widgets/checkout-and-beyond/layout.ts
302
311
  import { v7 as uuidv7 } from "uuid";
303
- import { z as z3 } from "zod";
312
+ import { z as z4 } from "zod";
304
313
 
305
314
  // src/schema/widgets/checkout-and-beyond/variables.ts
306
- import { z as z2 } from "zod";
315
+ import { z as z3 } from "zod";
307
316
 
308
317
  // src/schema/widgets/checkout-and-beyond/rule.ts
309
- import { z } from "zod";
318
+ import { z as z2 } from "zod";
310
319
  var ruleTypes = [
311
320
  "cart",
312
321
  "cart_count",
@@ -325,7 +334,7 @@ var ruleTypes = [
325
334
  "product_type",
326
335
  "product_vendor"
327
336
  ];
328
- var ruleType = z.enum(ruleTypes);
337
+ var ruleType = z2.enum(ruleTypes);
329
338
  var RuleType = ruleType.enum;
330
339
  var ruleOperators = [
331
340
  "after",
@@ -340,148 +349,148 @@ var ruleOperators = [
340
349
  "greater_than",
341
350
  "less_than"
342
351
  ];
343
- var ruleOperator = z.enum(ruleOperators);
352
+ var ruleOperator = z2.enum(ruleOperators);
344
353
  var RuleOperator = ruleOperator.enum;
345
- var RuleCondition = z.object({
346
- operator: z.enum(ruleOperators).default(RuleOperator.anything),
347
- products: z.union([z.array(z.unknown()), z.strictObject({}).transform(() => [])]).default(() => []),
348
- type: z.enum(ruleTypes).default(RuleType.cart_subtotal),
349
- value: z.coerce.string().default("")
354
+ var RuleCondition = z2.object({
355
+ operator: z2.enum(ruleOperators).default(RuleOperator.anything),
356
+ products: z2.union([z2.array(z2.unknown()), z2.strictObject({}).transform(() => [])]).default(() => []),
357
+ type: z2.enum(ruleTypes).default(RuleType.cart_subtotal),
358
+ value: z2.coerce.string().default("")
350
359
  });
351
- var RuleLogicBlock = z.object({
352
- rules: z.array(RuleCondition).default(() => [])
360
+ var RuleLogicBlock = z2.object({
361
+ rules: z2.array(RuleCondition).default(() => [])
353
362
  });
354
- var CABRulesetEntry = z.object({
355
- exitIfMatched: z.boolean().default(true),
356
- logic: z.array(RuleLogicBlock).default(() => []),
357
- output: z.array(
358
- z.object({
359
- key: z.string().default("should_show"),
360
- type: z.literal("data_json").default("data_json"),
361
- value: z.string().default("true")
363
+ var CABRulesetEntry = z2.object({
364
+ exitIfMatched: z2.boolean().default(true),
365
+ logic: z2.array(RuleLogicBlock).default(() => []),
366
+ output: z2.array(
367
+ z2.object({
368
+ key: z2.string().default("should_show"),
369
+ type: z2.literal("data_json").default("data_json"),
370
+ value: z2.string().default("true")
362
371
  })
363
372
  ).default(() => [{ key: "should_show", type: "data_json", value: "true" }])
364
373
  });
365
- var CABRuleset = z.union([z.array(CABRulesetEntry), z.strictObject({}).transform(() => [])]).default(() => []);
374
+ var CABRuleset = z2.union([z2.array(CABRulesetEntry), z2.strictObject({}).transform(() => [])]).default(() => []);
366
375
 
367
376
  // src/schema/widgets/checkout-and-beyond/variables.ts
368
- var variableEffect = z2.enum(variableEffects);
369
- var CABVariableSeed = z2.object({
370
- dataSourceId: z2.number().nullable().default(null),
377
+ var variableEffect = z3.enum(variableEffects);
378
+ var CABVariableSeed = z3.object({
379
+ dataSourceId: z3.number().nullable().default(null),
371
380
  ruleset: CABRuleset
372
381
  });
373
- var CABBooleanVariable = z2.object({
382
+ var CABBooleanVariable = z3.object({
374
383
  /**
375
384
  * Holds until the first seed verdict lands (and forever, for unseeded variables). Omitted, it derives
376
385
  * from seededness — `false` with a `seed` (visibility is EARNED), `true` without — via the transform
377
386
  * below; a cross-field default has no `.default()` spelling. An explicit value always wins.
378
387
  */
379
- defaultValue: z2.boolean().optional(),
380
- name: z2.string().min(1),
388
+ defaultValue: z3.boolean().optional(),
389
+ name: z3.string().min(1),
381
390
  seed: CABVariableSeed.optional(),
382
391
  /** Defaulted so every stored declaration (all boolean before `text` existed) parses unchanged. */
383
- type: z2.literal(VariableType.boolean).default(VariableType.boolean)
392
+ type: z3.literal(VariableType.boolean).default(VariableType.boolean)
384
393
  });
385
- var CABTextVariable = z2.object({
386
- defaultValue: z2.string(),
387
- name: z2.string().min(1),
388
- seed: z2.never().optional(),
389
- type: z2.literal(VariableType.text)
394
+ var CABTextVariable = z3.object({
395
+ defaultValue: z3.string(),
396
+ name: z3.string().min(1),
397
+ seed: z3.never().optional(),
398
+ type: z3.literal(VariableType.text)
390
399
  });
391
- var CABNumberVariable = z2.object({
392
- defaultValue: z2.number(),
393
- name: z2.string().min(1),
394
- seed: z2.never().optional(),
395
- type: z2.literal(VariableType.number)
400
+ var CABNumberVariable = z3.object({
401
+ defaultValue: z3.number(),
402
+ name: z3.string().min(1),
403
+ seed: z3.never().optional(),
404
+ type: z3.literal(VariableType.number)
396
405
  });
397
- var CABVariable = z2.union([CABTextVariable, CABNumberVariable, CABBooleanVariable]).transform(
406
+ var CABVariable = z3.union([CABTextVariable, CABNumberVariable, CABBooleanVariable]).transform(
398
407
  (variable) => variable.type === VariableType.boolean ? { ...variable, defaultValue: variable.defaultValue ?? variable.seed === void 0 } : variable
399
408
  );
400
- var CABVariableEffect = z2.object({
409
+ var CABVariableEffect = z3.object({
401
410
  effect: variableEffect.default(VariableEffect.toggle),
402
- variable: z2.string().min(1)
411
+ variable: z3.string().min(1)
403
412
  });
404
- var CABVisibility = z2.object({
405
- variable: z2.string().min(1),
406
- visibleWhen: z2.boolean().default(true)
413
+ var CABVisibility = z3.object({
414
+ variable: z3.string().min(1),
415
+ visibleWhen: z3.boolean().default(true)
407
416
  });
408
- var contentOperator = z2.enum(contentOperators);
409
- var resultCountOperator = z2.enum(resultCountOperators);
410
- var resultTagOperator = z2.enum(resultTagOperators);
411
- var mutatorEvent = z2.enum(mutatorEvents);
412
- var CABContentTrigger = z2.object({
417
+ var contentOperator = z3.enum(contentOperators);
418
+ var resultCountOperator = z3.enum(resultCountOperators);
419
+ var resultTagOperator = z3.enum(resultTagOperators);
420
+ var mutatorEvent = z3.enum(mutatorEvents);
421
+ var CABContentTrigger = z3.object({
413
422
  operator: contentOperator.default(ContentOperator.is_empty),
414
- type: z2.literal("content")
423
+ type: z3.literal("content")
415
424
  });
416
- var CABResultCountTrigger = z2.object({
425
+ var CABResultCountTrigger = z3.object({
417
426
  operator: resultCountOperator.default(ResultCountOperator.equals),
418
- type: z2.literal("result_count"),
419
- value: z2.number().default(0)
427
+ type: z3.literal("result_count"),
428
+ value: z3.number().default(0)
420
429
  });
421
- var CABResultTagTrigger = z2.object({
430
+ var CABResultTagTrigger = z3.object({
422
431
  operator: resultTagOperator.default(ResultTagOperator.contains),
423
- type: z2.literal("result_tag"),
424
- value: z2.string().min(1)
432
+ type: z3.literal("result_tag"),
433
+ value: z3.string().min(1)
425
434
  });
426
- var CABEventTrigger = z2.object({
435
+ var CABEventTrigger = z3.object({
427
436
  event: mutatorEvent,
428
- type: z2.literal("event")
437
+ type: z3.literal("event")
429
438
  });
430
- var CABVariableTrigger = z2.discriminatedUnion("type", [
439
+ var CABVariableTrigger = z3.discriminatedUnion("type", [
431
440
  CABContentTrigger,
432
441
  CABEventTrigger,
433
442
  CABResultCountTrigger,
434
443
  CABResultTagTrigger
435
444
  ]);
436
- var CABVariableMutator = z2.object({
445
+ var CABVariableMutator = z3.object({
437
446
  effect: variableEffect.default(VariableEffect.set_false),
438
- variable: z2.string().min(1),
447
+ variable: z3.string().min(1),
439
448
  when: CABVariableTrigger
440
449
  });
441
450
  var CABVariableFields = {
442
- mutators: z2.array(CABVariableMutator).optional(),
443
- variables: z2.array(CABVariable).refine((variables) => new Set(variables.map(({ name }) => name)).size === variables.length, {
451
+ mutators: z3.array(CABVariableMutator).optional(),
452
+ variables: z3.array(CABVariable).refine((variables) => new Set(variables.map(({ name }) => name)).size === variables.length, {
444
453
  message: "variable names must be unique within a section"
445
454
  }).optional(),
446
455
  visibility: CABVisibility.optional()
447
456
  };
448
457
 
449
458
  // src/schema/widgets/checkout-and-beyond/layout.ts
450
- var GridItem = z3.union([z3.literal("auto"), z3.literal("fill"), z3.string().regex(/^\d+%$/), z3.number()]);
451
- var CABLayoutWrapping = z3.object({
452
- breakAt: z3.number().positive(),
453
- maxPerLine: z3.number().int().positive()
459
+ var GridItem = z4.union([z4.literal("auto"), z4.literal("fill"), z4.string().regex(/^\d+%$/), z4.number()]);
460
+ var CABLayoutWrapping = z4.object({
461
+ breakAt: z4.number().positive(),
462
+ maxPerLine: z4.number().int().positive()
454
463
  });
455
- var CABLayoutSection = z3.object({
464
+ var CABLayoutSection = z4.object({
456
465
  ...CABVariableFields,
457
- alignment: z3.object({
458
- horizontal: z3.enum(horizontalAlignments).default(HorizontalAlignment.start),
459
- vertical: z3.enum(verticalAlignments).default(VerticalAlignment.top)
466
+ alignment: z4.object({
467
+ horizontal: z4.enum(horizontalAlignments).default(HorizontalAlignment.start),
468
+ vertical: z4.enum(verticalAlignments).default(VerticalAlignment.top)
460
469
  }).default({
461
470
  horizontal: HorizontalAlignment.start,
462
471
  vertical: VerticalAlignment.top
463
472
  }),
464
- border: z3.lazy(() => CABBorder),
465
- buttonField: z3.enum(buttonFields).optional(),
466
- direction: z3.enum(directions).default(Direction.rows),
473
+ border: z4.lazy(() => CABBorder),
474
+ buttonField: z4.enum(buttonFields).optional(),
475
+ direction: z4.enum(directions).default(Direction.rows),
467
476
  /**
468
477
  * Platform chrome around the section, not a layout behavior: `callout` is a subdued box with block borders
469
478
  * (the legacy post-purchase callout banner), `offer-content` the post-purchase offer's own content card.
470
479
  */
471
- frame: z3.enum(layoutFrames).optional(),
472
- grid: z3.object({
473
- columns: z3.union([z3.array(GridItem), z3.undefined()]).default(() => ["auto"]),
474
- rows: z3.union([z3.array(GridItem), z3.undefined()]).default(() => ["auto"])
480
+ frame: z4.enum(layoutFrames).optional(),
481
+ grid: z4.object({
482
+ columns: z4.union([z4.array(GridItem), z4.undefined()]).default(() => ["auto"]),
483
+ rows: z4.union([z4.array(GridItem), z4.undefined()]).default(() => ["auto"])
475
484
  }).default({ columns: ["auto"], rows: ["auto"] }).optional(),
476
- name: z3.string().optional(),
477
- padding: z3.enum(spacings).default(Spacing.none),
478
- sectionId: z3.uuid().default(() => uuidv7()),
479
- sections: z3.union([z3.array(z3.lazy(() => CABSection)), z3.strictObject({}).transform(() => [])]).default(() => []),
480
- sectionType: z3.literal(SectionType.layout).default(SectionType.layout),
481
- spacing: z3.enum(spacings).default(Spacing.base),
485
+ name: z4.string().optional(),
486
+ padding: z4.enum(spacings).default(Spacing.none),
487
+ sectionId: z4.uuid().default(() => uuidv7()),
488
+ sections: z4.union([z4.array(z4.lazy(() => CABSection)), z4.strictObject({}).transform(() => [])]).default(() => []),
489
+ sectionType: z4.literal(SectionType.layout).default(SectionType.layout),
490
+ spacing: z4.enum(spacings).default(Spacing.base),
482
491
  /** Fire-and-forget impression pixel POSTed once when the section is shown (e.g. a Monetize offer view). */
483
- viewUrl: z3.string().optional(),
484
- width: z3.number().default(100),
492
+ viewUrl: z4.string().optional(),
493
+ width: z4.number().default(100),
485
494
  wrapping: CABLayoutWrapping.optional()
486
495
  });
487
496
 
@@ -552,11 +561,11 @@ var isTextType = isSectionType(SectionType.text);
552
561
  var isVariantsType = isSectionType(SectionType.variants);
553
562
 
554
563
  // src/schema/widgets/checkout-and-beyond/banner.ts
555
- var CABBannerSection = z4.lazy(
564
+ var CABBannerSection = z5.lazy(
556
565
  () => CABLayoutSection.omit({ sectionType: true }).extend({
557
- buttonField: z4.enum(buttonFields).optional(),
558
- color: z4.enum(bannerColors).default("info"),
559
- dismissible: z4.boolean().default(true),
566
+ buttonField: z5.enum(buttonFields).optional(),
567
+ color: z5.enum(bannerColors).default("info"),
568
+ dismissible: z5.boolean().default(true),
560
569
  /**
561
570
  * The `s-banner` heading — localized content (a buyer can see a merchant-composed banner). Absent OR
562
571
  * blank ⇒ no heading; the renderer emits no heading slot for `''` rather than an empty one.
@@ -572,83 +581,83 @@ var CABBannerSection = z4.lazy(
572
581
  * not a 500. Nothing emits `heading` yet; the first converter that maps merchant banner copy into it
573
582
  * either strips first or teaches `normalizeTextContent` to strip this field.
574
583
  */
575
- heading: z4.record(z4.string(), z4.string().refine(checkForHTML, NO_HTML)).optional(),
576
- sectionType: z4.literal(SectionType.banner).default(SectionType.banner)
584
+ heading: z5.record(z5.string(), z5.string().refine(checkForHTML, NO_HTML)).optional(),
585
+ sectionType: z5.literal(SectionType.banner).default(SectionType.banner)
577
586
  })
578
587
  );
579
588
 
580
589
  // src/schema/widgets/checkout-and-beyond/button.ts
581
590
  import { v7 as uuidv73 } from "uuid";
582
- import { z as z6 } from "zod";
591
+ import { z as z7 } from "zod";
583
592
 
584
593
  // src/schema/widgets/checkout-and-beyond/text.ts
585
594
  import { forEach, isString as isString2 } from "es-toolkit/compat";
586
595
  import { v7 as uuidv72 } from "uuid";
587
- import { z as z5 } from "zod";
588
- var enumOrOmit = (...vals) => z5.string().transform((val) => vals.includes(val) ? val : void 0).optional();
589
- var TiptapText = z5.object({
590
- marks: z5.union([
591
- z5.array(
592
- z5.discriminatedUnion("type", [
593
- z5.object({ type: z5.literal("bold") }),
594
- z5.object({ type: z5.literal("italic") }),
595
- z5.object({
596
- attrs: z5.object({
597
- class: z5.string().nullable(),
598
- href: z5.union([
599
- z5.url(),
600
- z5.literal("#"),
601
- z5.string().regex(DYNAMIC_TOKEN_REGEX),
602
- z5.string().regex(ROOT_RELATIVE_PATH_REGEX)
596
+ import { z as z6 } from "zod";
597
+ var enumOrOmit = (...vals) => z6.string().transform((val) => vals.includes(val) ? val : void 0).optional();
598
+ var TiptapText = z6.object({
599
+ marks: z6.union([
600
+ z6.array(
601
+ z6.discriminatedUnion("type", [
602
+ z6.object({ type: z6.literal("bold") }),
603
+ z6.object({ type: z6.literal("italic") }),
604
+ z6.object({
605
+ attrs: z6.object({
606
+ class: z6.string().nullable(),
607
+ href: z6.union([
608
+ z6.url(),
609
+ z6.literal("#"),
610
+ z6.string().regex(DYNAMIC_TOKEN_REGEX),
611
+ z6.string().regex(ROOT_RELATIVE_PATH_REGEX)
603
612
  ]),
604
- rel: z5.string().default("noopener noreferrer nofollow"),
605
- target: z5.string().default("_blank")
613
+ rel: z6.string().default("noopener noreferrer nofollow"),
614
+ target: z6.string().default("_blank")
606
615
  }),
607
- type: z5.literal("link")
616
+ type: z6.literal("link")
608
617
  }),
609
- z5.object({ type: z5.literal("strike") }),
610
- z5.object({
611
- attrs: z5.object({
618
+ z6.object({ type: z6.literal("strike") }),
619
+ z6.object({
620
+ attrs: z6.object({
612
621
  color: enumOrOmit(...textColorNames).default(TextColorName.base),
613
622
  fontSize: enumOrOmit(...textSizeNames).default(TextSizeName.base)
614
623
  }),
615
- type: z5.literal("textStyle")
624
+ type: z6.literal("textStyle")
616
625
  })
617
626
  ])
618
627
  ),
619
- z5.strictObject({}).transform(() => [])
628
+ z6.strictObject({}).transform(() => [])
620
629
  ]).optional(),
621
- text: z5.string().default(""),
622
- type: z5.literal("text").default("text")
630
+ text: z6.string().default(""),
631
+ type: z6.literal("text").default("text")
623
632
  });
624
- var TiptapParagraph = z5.object({
625
- attrs: z5.object({
633
+ var TiptapParagraph = z6.object({
634
+ attrs: z6.object({
626
635
  textAlign: enumOrOmit(...textAlignments)
627
636
  }).default({ textAlign: TextAlignment.start }),
628
- content: z5.union([z5.array(TiptapText), z5.strictObject({}).transform(() => [])]).default(() => []),
629
- type: z5.literal("paragraph").default("paragraph")
637
+ content: z6.union([z6.array(TiptapText), z6.strictObject({}).transform(() => [])]).default(() => []),
638
+ type: z6.literal("paragraph").default("paragraph")
630
639
  });
631
- var TiptapDocument = z5.object({
632
- attrs: z5.object({
640
+ var TiptapDocument = z6.object({
641
+ attrs: z6.object({
633
642
  blockSpacing: enumOrOmit(...spacings)
634
643
  }).default({ blockSpacing: Spacing.base }),
635
- content: z5.union([z5.array(TiptapParagraph), z5.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
636
- type: z5.literal("doc").default("doc")
644
+ content: z6.union([z6.array(TiptapParagraph), z6.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
645
+ type: z6.literal("doc").default("doc")
637
646
  });
638
- var CABTextTier = z5.object({
639
- threshold: z5.number().int().nonnegative(),
640
- thresholds: z5.record(z5.string(), z5.number().int().nonnegative()).default(() => ({})),
641
- tierId: z5.string().optional(),
642
- tierType: z5.enum(progressTierTypes).default(ProgressTierType.shipping)
647
+ var CABTextTier = z6.object({
648
+ threshold: z6.number().int().nonnegative(),
649
+ thresholds: z6.record(z6.string(), z6.number().int().nonnegative()).default(() => ({})),
650
+ tierId: z6.string().optional(),
651
+ tierType: z6.enum(progressTierTypes).default(ProgressTierType.shipping)
643
652
  });
644
- var CABTextSection = z5.object({
653
+ var CABTextSection = z6.object({
645
654
  ...CABVariableFields,
646
- buttonField: z5.enum(buttonFields).optional(),
647
- content: z5.record(z5.string(), z5.union([z5.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
648
- name: z5.string().optional(),
649
- optionId: z5.number().optional(),
650
- sectionId: z5.uuid().default(() => uuidv72()),
651
- sectionType: z5.literal(SectionType.text).default(SectionType.text),
655
+ buttonField: z6.enum(buttonFields).optional(),
656
+ content: z6.record(z6.string(), z6.union([z6.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
657
+ name: z6.string().optional(),
658
+ optionId: z6.number().optional(),
659
+ sectionId: z6.uuid().default(() => uuidv72()),
660
+ sectionType: z6.literal(SectionType.text).default(SectionType.text),
652
661
  tier: CABTextTier.optional()
653
662
  }).superRefine(({ buttonField, content }, ctx) => {
654
663
  if (buttonField === ButtonField.destinationUrl && content) {
@@ -670,35 +679,35 @@ var CABTextSection = z5.object({
670
679
  });
671
680
 
672
681
  // src/schema/widgets/checkout-and-beyond/button.ts
673
- var CABButtonContent = z6.lazy(
674
- () => z6.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
682
+ var CABButtonContent = z7.lazy(
683
+ () => z7.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
675
684
  );
676
- var CABButtonSection = z6.object({
685
+ var CABButtonSection = z7.object({
677
686
  ...CABVariableFields,
678
- action: z6.union([z6.literal(""), z6.enum(buttonActions)]).default(""),
679
- buttonStyle: z6.enum(buttonStyles).default(ButtonStyle.primary),
680
- custom: z6.object({
681
- color: z6.string().regex(HEX_COLOR_REGEX).default("#005bd3"),
682
- height: z6.number().default(52),
683
- width: z6.number().default(300)
687
+ action: z7.union([z7.literal(""), z7.enum(buttonActions)]).default(""),
688
+ buttonStyle: z7.enum(buttonStyles).default(ButtonStyle.primary),
689
+ custom: z7.object({
690
+ color: z7.string().regex(HEX_COLOR_REGEX).default("#005bd3"),
691
+ height: z7.number().default(52),
692
+ width: z7.number().default(300)
684
693
  }).default({
685
694
  color: "#005bd3",
686
695
  height: 52,
687
696
  width: 300
688
697
  }),
689
- disableDowngrade: z6.boolean().default(false),
690
- name: z6.string().optional(),
691
- optionId: z6.number().optional(),
692
- popover: z6.object({
693
- alignment: z6.enum(textAlignments).default(TextAlignment.center),
694
- position: z6.enum(popoverPositions).default(PopoverPosition.blockStart)
698
+ disableDowngrade: z7.boolean().default(false),
699
+ name: z7.string().optional(),
700
+ optionId: z7.number().optional(),
701
+ popover: z7.object({
702
+ alignment: z7.enum(textAlignments).default(TextAlignment.center),
703
+ position: z7.enum(popoverPositions).default(PopoverPosition.blockStart)
695
704
  }).optional().default(() => ({
696
705
  alignment: TextAlignment.center,
697
706
  position: PopoverPosition.blockStart
698
707
  })),
699
- sectionId: z6.uuid().default(() => uuidv73()),
700
- sections: z6.union([z6.array(CABButtonContent), z6.strictObject({}).transform(() => [])]).default(() => []),
701
- sectionType: z6.literal(SectionType.button).default(SectionType.button),
708
+ sectionId: z7.uuid().default(() => uuidv73()),
709
+ sections: z7.union([z7.array(CABButtonContent), z7.strictObject({}).transform(() => [])]).default(() => []),
710
+ sectionType: z7.literal(SectionType.button).default(SectionType.button),
702
711
  /**
703
712
  * The smart-cart tier this button acts on (`addGift`/`removeGift`): scopes the click to one tier's gift. The
704
713
  * client resolves the tier's gift (productId) from the progress-bar context by this `tierId` — the button node
@@ -713,25 +722,25 @@ var CABButtonSection = z6.object({
713
722
  * lookup finds no tier and the click resolves to nothing. Safe to bound — the field is new, so there are no
714
723
  * stored payloads to grandfather, and the producer is client code, not a merchant form.
715
724
  */
716
- tier: z6.object({ tierId: z6.string().min(1) }).optional(),
725
+ tier: z7.object({ tierId: z7.string().min(1) }).optional(),
717
726
  /** Fire-and-forget pixel POSTed when the button is clicked (e.g. a Monetize decline). */
718
- trackingUrl: z6.string().optional(),
727
+ trackingUrl: z7.string().optional(),
719
728
  /**
720
729
  * Secondary effects applied to in-scope variables on click, alongside (never instead of) the primary
721
730
  * `action` — an `addToOrder` button can also flip a variable. Applied in array order.
722
731
  */
723
- variableEffects: z6.array(CABVariableEffect).optional()
732
+ variableEffects: z7.array(CABVariableEffect).optional()
724
733
  });
725
734
 
726
735
  // src/schema/widgets/checkout-and-beyond/carousel.ts
727
- import { z as z11 } from "zod";
736
+ import { z as z12 } from "zod";
728
737
 
729
738
  // src/schema/widgets/checkout-and-beyond/offers.ts
730
- import { z as z10 } from "zod";
739
+ import { z as z11 } from "zod";
731
740
 
732
741
  // src/schema/widgets/checkout-and-beyond/dataSource.ts
733
742
  import { v7 as uuidv74 } from "uuid";
734
- import { z as z7 } from "zod";
743
+ import { z as z8 } from "zod";
735
744
 
736
745
  // src/schema/widgets/checkout-and-beyond/constants.ts
737
746
  import { uniqBy } from "es-toolkit";
@@ -785,77 +794,77 @@ var targetAreas = {
785
794
  };
786
795
 
787
796
  // src/schema/widgets/checkout-and-beyond/dataSource.ts
788
- var CABDiscount = z7.object({
789
- amount: z7.union([z7.number(), z7.string()]).catch(0),
790
- discountedBy: z7.string().optional(),
791
- discountedFrom: z7.enum(discountSources).optional().catch(void 0),
792
- type: z7.enum(discountTypes).catch("none")
797
+ var CABDiscount = z8.object({
798
+ amount: z8.union([z8.number(), z8.string()]).catch(0),
799
+ discountedBy: z8.string().optional(),
800
+ discountedFrom: z8.enum(discountSources).optional().catch(void 0),
801
+ type: z8.enum(discountTypes).catch("none")
793
802
  });
794
- var CABIntegrations = z7.object({
795
- judgeme: z7.boolean().default(false),
796
- junip: z7.boolean().default(false),
797
- klaviyo: z7.boolean().default(false),
798
- loox: z7.boolean().default(false),
799
- okendo: z7.boolean().default(false),
800
- opinew: z7.boolean().default(false),
801
- reviewsio: z7.boolean().default(false),
802
- stamped: z7.boolean().default(false),
803
- yotpo: z7.boolean().default(false)
803
+ var CABIntegrations = z8.object({
804
+ judgeme: z8.boolean().default(false),
805
+ junip: z8.boolean().default(false),
806
+ klaviyo: z8.boolean().default(false),
807
+ loox: z8.boolean().default(false),
808
+ okendo: z8.boolean().default(false),
809
+ opinew: z8.boolean().default(false),
810
+ reviewsio: z8.boolean().default(false),
811
+ stamped: z8.boolean().default(false),
812
+ yotpo: z8.boolean().default(false)
804
813
  });
805
- var CABVariantLabels = z7.object({
806
- variantOption: z7.string().optional().catch(void 0),
807
- variantOptions: z7.string().optional().catch(void 0)
814
+ var CABVariantLabels = z8.object({
815
+ variantOption: z8.string().optional().catch(void 0),
816
+ variantOptions: z8.string().optional().catch(void 0)
808
817
  });
809
- var CABDataSourceSection = z7.object({
810
- dataSourceId: z7.number().nullable().default(null),
811
- dataSourcePath: z7.string().default(DEFAULT_ENDPOINTS[0].value),
818
+ var CABDataSourceSection = z8.object({
819
+ dataSourceId: z8.number().nullable().default(null),
820
+ dataSourcePath: z8.string().default(DEFAULT_ENDPOINTS[0].value),
812
821
  discount: CABDiscount.optional(),
813
822
  integrations: CABIntegrations.optional(),
814
- limit: z7.number().default(1),
815
- matchVariant: z7.boolean().default(false),
816
- matchVariantOutOfStock: z7.boolean().default(false),
817
- name: z7.string().default(DEFAULT_ENDPOINTS[0].label),
818
- productType: z7.enum(productTypes).optional(),
819
- sectionId: z7.uuid().default(() => uuidv74()),
820
- sectionType: z7.literal(SectionType.dataSource).default(SectionType.dataSource),
823
+ limit: z8.number().default(1),
824
+ matchVariant: z8.boolean().default(false),
825
+ matchVariantOutOfStock: z8.boolean().default(false),
826
+ name: z8.string().default(DEFAULT_ENDPOINTS[0].label),
827
+ productType: z8.enum(productTypes).optional(),
828
+ sectionId: z8.uuid().default(() => uuidv74()),
829
+ sectionType: z8.literal(SectionType.dataSource).default(SectionType.dataSource),
821
830
  /** Default subscribe-vs-one-time for `productType: both` (legacy `subscription_is_default`). */
822
- subscriptionIsDefault: z7.boolean().default(false),
823
- treatAsGwp: z7.boolean().default(false),
831
+ subscriptionIsDefault: z8.boolean().default(false),
832
+ treatAsGwp: z8.boolean().default(false),
824
833
  variantLabels: CABVariantLabels.optional().catch(void 0)
825
834
  });
826
835
 
827
836
  // src/schema/widgets/checkout-and-beyond/products.ts
828
837
  import { v7 as uuidv76 } from "uuid";
829
- import { z as z9 } from "zod";
838
+ import { z as z10 } from "zod";
830
839
 
831
840
  // src/schema/widgets/checkout-and-beyond/product.ts
832
841
  import { v7 as uuidv75 } from "uuid";
833
- import { z as z8 } from "zod";
834
- var CABVariantContent = z8.lazy(
835
- () => z8.discriminatedUnion("sectionType", [CABButtonSection, CABTextSection])
842
+ import { z as z9 } from "zod";
843
+ var CABVariantContent = z9.lazy(
844
+ () => z9.discriminatedUnion("sectionType", [CABButtonSection, CABTextSection])
836
845
  );
837
- var CABProductSection = z8.object({
846
+ var CABProductSection = z9.object({
838
847
  ...CABVariableFields,
839
- name: z8.string().optional(),
840
- productId: z8.number().nullable().default(null),
841
- sectionId: z8.uuid().default(() => uuidv75()),
842
- sections: z8.union([z8.array(CABVariantContent), z8.strictObject({}).transform(() => [])]).default(() => []),
843
- sectionType: z8.literal(SectionType.product).default(SectionType.product),
844
- selectors: z8.record(z8.string(), z8.enum(variantSelectors).default(VariantSelector.menu)).default(() => ({})),
845
- variantMode: z8.enum(variantModes).default(VariantMode.multiple)
848
+ name: z9.string().optional(),
849
+ productId: z9.number().nullable().default(null),
850
+ sectionId: z9.uuid().default(() => uuidv75()),
851
+ sections: z9.union([z9.array(CABVariantContent), z9.strictObject({}).transform(() => [])]).default(() => []),
852
+ sectionType: z9.literal(SectionType.product).default(SectionType.product),
853
+ selectors: z9.record(z9.string(), z9.enum(variantSelectors).default(VariantSelector.menu)).default(() => ({})),
854
+ variantMode: z9.enum(variantModes).default(VariantMode.multiple)
846
855
  });
847
856
 
848
857
  // src/schema/widgets/checkout-and-beyond/products.ts
849
- var CABProductsSection = z9.object({
858
+ var CABProductsSection = z10.object({
850
859
  ...CABVariableFields,
851
- name: z9.string().optional(),
852
- sectionId: z9.uuid().default(() => uuidv76()),
853
- sections: z9.union([z9.array(z9.lazy(() => CABProductSection)), z9.strictObject({}).transform(() => [])]).default(() => []),
854
- sectionType: z9.literal(SectionType.products).default(SectionType.products)
860
+ name: z10.string().optional(),
861
+ sectionId: z10.uuid().default(() => uuidv76()),
862
+ sections: z10.union([z10.array(z10.lazy(() => CABProductSection)), z10.strictObject({}).transform(() => [])]).default(() => []),
863
+ sectionType: z10.literal(SectionType.products).default(SectionType.products)
855
864
  });
856
865
 
857
866
  // src/schema/widgets/checkout-and-beyond/offers.ts
858
- var CABOffersSection = z10.lazy(
867
+ var CABOffersSection = z11.lazy(
859
868
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
860
869
  /**
861
870
  * A rule between consecutive cards in the vertical list — legacy checkout-offers' `<Divider />`,
@@ -863,8 +872,8 @@ var CABOffersSection = z10.lazy(
863
872
  * run of products). Optional, not defaulted: only the v1 converter sets it (REB-24265); a
864
873
  * hand-built tree keeps React CAB's dividerless rendering.
865
874
  */
866
- divider: z10.boolean().optional(),
867
- sections: z10.union([z10.array(z10.lazy(() => CABSection)), z10.strictObject({}).transform(() => [])]).default(() => [
875
+ divider: z11.boolean().optional(),
876
+ sections: z11.union([z11.array(z11.lazy(() => CABSection)), z11.strictObject({}).transform(() => [])]).default(() => [
868
877
  CABBannerSection.parse({
869
878
  buttonField: "undoAddToOrder",
870
879
  color: "success",
@@ -878,77 +887,77 @@ var CABOffersSection = z10.lazy(
878
887
  CABDataSourceSection.parse({}),
879
888
  CABProductsSection.parse({})
880
889
  ]),
881
- sectionType: z10.literal(SectionType.offers).default(SectionType.offers)
890
+ sectionType: z11.literal(SectionType.offers).default(SectionType.offers)
882
891
  })
883
892
  );
884
893
 
885
894
  // src/schema/widgets/checkout-and-beyond/carousel.ts
886
- var CABCarouselSection = z11.lazy(
895
+ var CABCarouselSection = z12.lazy(
887
896
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
888
- autoAdvanceInterval: z11.number().default(0),
889
- itemsAtOnce: z11.number().min(1).default(1),
897
+ autoAdvanceInterval: z12.number().default(0),
898
+ itemsAtOnce: z12.number().min(1).default(1),
890
899
  /** Card arrangement for the offers child (`horizontal` = side-by-side) — NOT the carousel's own `direction`. */
891
- offersDirection: z11.enum(offersDirections).default("vertical"),
892
- sections: z11.union([z11.array(z11.lazy(() => CABSection)), z11.strictObject({}).transform(() => [])]).default(() => [CABOffersSection.parse({})]),
893
- sectionType: z11.literal(SectionType.carousel).default(SectionType.carousel)
900
+ offersDirection: z12.enum(offersDirections).default("vertical"),
901
+ sections: z12.union([z12.array(z12.lazy(() => CABSection)), z12.strictObject({}).transform(() => [])]).default(() => [CABOffersSection.parse({})]),
902
+ sectionType: z12.literal(SectionType.carousel).default(SectionType.carousel)
894
903
  })
895
904
  );
896
905
 
897
906
  // src/schema/widgets/checkout-and-beyond/cartLine.ts
898
- import { z as z12 } from "zod";
899
- var CABCartLineSection = z12.lazy(
907
+ import { z as z13 } from "zod";
908
+ var CABCartLineSection = z13.lazy(
900
909
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
901
- sections: z12.union([z12.array(z12.lazy(() => CABSection)), z12.strictObject({}).transform(() => [])]).default(() => [CABButtonSection.parse({ action: ButtonAction.switchToSubscription })]),
902
- sectionType: z12.literal(SectionType.cartLine).default(SectionType.cartLine)
910
+ sections: z13.union([z13.array(z13.lazy(() => CABSection)), z13.strictObject({}).transform(() => [])]).default(() => [CABButtonSection.parse({ action: ButtonAction.switchToSubscription })]),
911
+ sectionType: z13.literal(SectionType.cartLine).default(SectionType.cartLine)
903
912
  })
904
913
  );
905
914
 
906
915
  // src/schema/widgets/checkout-and-beyond/discount.ts
907
916
  import { v7 as uuidv77 } from "uuid";
908
- import { z as z13 } from "zod";
909
- var CABDiscountSection = z13.object({
917
+ import { z as z14 } from "zod";
918
+ var CABDiscountSection = z14.object({
910
919
  ...CABVariableFields,
911
- amount: z13.union([z13.number(), z13.string()]).catch(0),
912
- discountedBy: z13.string().optional(),
913
- discountedFrom: z13.enum(discountSources).optional().catch(void 0),
914
- message: z13.string().optional(),
915
- name: z13.string().optional(),
916
- quantity: z13.number().default(1),
917
- sectionId: z13.uuid().default(() => uuidv77()),
918
- sectionType: z13.literal(SectionType.discount).default(SectionType.discount),
919
- type: z13.enum(discountTypes).catch("none")
920
+ amount: z14.union([z14.number(), z14.string()]).catch(0),
921
+ discountedBy: z14.string().optional(),
922
+ discountedFrom: z14.enum(discountSources).optional().catch(void 0),
923
+ message: z14.string().optional(),
924
+ name: z14.string().optional(),
925
+ quantity: z14.number().default(1),
926
+ sectionId: z14.uuid().default(() => uuidv77()),
927
+ sectionType: z14.literal(SectionType.discount).default(SectionType.discount),
928
+ type: z14.enum(discountTypes).catch("none")
920
929
  });
921
930
 
922
931
  // src/schema/widgets/checkout-and-beyond/monetize.ts
923
932
  import { v7 as uuidv78 } from "uuid";
924
- import { z as z14 } from "zod";
925
- var CABMonetizeAds = z14.object({
926
- requestId: z14.string().optional(),
933
+ import { z as z15 } from "zod";
934
+ var CABMonetizeAds = z15.object({
935
+ requestId: z15.string().optional(),
927
936
  /** Defaulted here, never in the beacon: absence of information is `ads` itself being absent. */
928
- testing: z14.boolean().default(false)
937
+ testing: z15.boolean().default(false)
929
938
  });
930
- var CABMonetizeSection = z14.object({
939
+ var CABMonetizeSection = z15.object({
931
940
  ...CABVariableFields,
932
941
  ads: CABMonetizeAds.optional(),
933
- name: z14.string().optional(),
942
+ name: z15.string().optional(),
934
943
  /**
935
944
  * Server-hydrated offer cards (inline hydration): when `/cab/sections` was asked with a `monetize`
936
945
  * context block, the composed cards ride the marker itself — `[]` means "hydrated, no fill" (render
937
946
  * nothing, skip the fetch); ABSENT means "not hydrated" (the client fetches via `/cab/monetize`).
938
947
  */
939
- offers: z14.array(z14.lazy(() => CABSection)).optional(),
948
+ offers: z15.array(z15.lazy(() => CABSection)).optional(),
940
949
  /** Privacy Policy footer href (the widget's `privacy_policy_url` setting); read server-side for hydration, relayed by the client only on the legacy `/cab/monetize` fallback. */
941
- privacyPolicyUrl: z14.string().optional(),
942
- sectionId: z14.uuid().default(() => uuidv78()),
943
- sectionType: z14.literal(SectionType.monetize).default(SectionType.monetize),
950
+ privacyPolicyUrl: z15.string().optional(),
951
+ sectionId: z15.uuid().default(() => uuidv78()),
952
+ sectionType: z15.literal(SectionType.monetize).default(SectionType.monetize),
944
953
  /** Ads-taxonomy sub-vertical id (the widget's `sub_vertical` setting); paired with `vertical`. */
945
- subVertical: z14.string().optional(),
954
+ subVertical: z15.string().optional(),
946
955
  /** Ads-taxonomy vertical id (the widget's `vertical` setting) — with `subVertical`, the admin Monetize editor's two configurables. */
947
- vertical: z14.string().optional()
956
+ vertical: z15.string().optional()
948
957
  });
949
958
 
950
959
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
951
- import { z as z15 } from "zod";
960
+ import { z as z16 } from "zod";
952
961
 
953
962
  // src/schema/widgets/checkout-and-beyond/giftLabels.ts
954
963
  var GIFT_LABELS = {
@@ -1067,34 +1076,34 @@ var GIFT_LABELS = {
1067
1076
  };
1068
1077
 
1069
1078
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1070
- var CABProgressTierExclusion = z15.object({
1071
- collectionIds: z15.array(z15.number().int().positive()).default(() => []),
1072
- productIds: z15.array(z15.number().int().positive()).default(() => []),
1073
- tags: z15.array(z15.string().min(1)).default(() => []),
1074
- type: z15.enum(progressTierExclusionTypes)
1079
+ var CABProgressTierExclusion = z16.object({
1080
+ collectionIds: z16.array(z16.number().int().positive()).default(() => []),
1081
+ productIds: z16.array(z16.number().int().positive()).default(() => []),
1082
+ tags: z16.array(z16.string().min(1)).default(() => []),
1083
+ type: z16.enum(progressTierExclusionTypes)
1075
1084
  });
1076
- var CABProgressTier = z15.object({
1085
+ var CABProgressTier = z16.object({
1077
1086
  /**
1078
1087
  * Order-discount tiers only (onsite `discount`): the reward the order-discount Function applies at
1079
1088
  * cart time, carried so the client can resolve the `{{discountAmount}}` token in this tier's copy.
1080
1089
  * `fixedAmount`: shop-currency CENTS (FX-scaled by the client, like {@link CABProgressTier.threshold});
1081
1090
  * `percentage`: the whole-percent number rendered raw (`{n}%`). Absent on non-discount tiers.
1082
1091
  */
1083
- discount: z15.object({ amount: z15.number().nonnegative(), type: z15.enum(["fixedAmount", "percentage"]) }).optional(),
1092
+ discount: z16.object({ amount: z16.number().nonnegative(), type: z16.enum(["fixedAmount", "percentage"]) }).optional(),
1084
1093
  /**
1085
1094
  * Per-tier exclusion rules (onsite `exclusions` when `exclusions_enabled`): lines they match don't count
1086
1095
  * toward this tier. Empty (the default, and the converter's output for a disabled or ruleless tier) means
1087
1096
  * the tier measures the plain bar-level adjusted progress. Consumers read ONLY the list named by the rule's
1088
1097
  * `type` — the converter leaves the other two at `[]`, so a populated off-type list never reaches the tree.
1089
1098
  */
1090
- exclusions: z15.array(CABProgressTierExclusion).default(() => []),
1099
+ exclusions: z16.array(CABProgressTierExclusion).default(() => []),
1091
1100
  /**
1092
1101
  * Smart-cart product (gift) tiers only (onsite `filter_oos_variants`): when set, the client drops this
1093
1102
  * tier entirely once its gift has NO in-stock eligible variant — the milestone, fill slot and gift
1094
1103
  * controls all disappear, mirroring onsite removing the tier from `bar.tiers` before it renders. Absent
1095
1104
  * on shipping/discount/decorative tiers and left off by default (the tier renders regardless of stock).
1096
1105
  */
1097
- filterOosVariants: z15.boolean().default(false),
1106
+ filterOosVariants: z16.boolean().default(false),
1098
1107
  /**
1099
1108
  * Smart-cart product (gift) tiers only: the reward unlocked at this tier. The client enriches
1100
1109
  * `productId`/`variantIds` to live variants (availability, price) and adds the chosen one to the cart
@@ -1102,10 +1111,10 @@ var CABProgressTier = z15.object({
1102
1111
  * tiers and on tiers with no configured product. Cart add/remove is a later stage; carried here so the
1103
1112
  * tree is complete.
1104
1113
  */
1105
- gift: z15.object({
1106
- productId: z15.number().int().positive(),
1107
- title: z15.string().optional(),
1108
- variantIds: z15.array(z15.number().int().positive()).default(() => [])
1114
+ gift: z16.object({
1115
+ productId: z16.number().int().positive(),
1116
+ title: z16.string().optional(),
1117
+ variantIds: z16.array(z16.number().int().positive()).default(() => [])
1109
1118
  }).optional(),
1110
1119
  /**
1111
1120
  * The step-row icon's square size in PIXELS (onsite `product_tier_element_size`, an admin px string the
@@ -1125,7 +1134,7 @@ var CABProgressTier = z15.object({
1125
1134
  * renderer never spells a fallback), which also makes a tree authored before this field render at
1126
1135
  * React's size rather than the old hardcoded 20.
1127
1136
  */
1128
- iconSizePx: z15.number().int().min(1).max(64).default(18),
1137
+ iconSizePx: z16.number().int().min(1).max(64).default(18),
1129
1138
  /**
1130
1139
  * The step-row label at this tier's slot (onsite `getTierLabel`): the merchant custom label, else the
1131
1140
  * type default — 'Free Shipping' or '{n}% Discount'. A PRODUCT tier gets NO converter label: its name is
@@ -1135,35 +1144,35 @@ var CABProgressTier = z15.object({
1135
1144
  * turns a blank label into an absent key, and a client-authored blank means the same thing — the renderer
1136
1145
  * emits no caption slot rather than an empty one). Plain text — a compact icon+label.
1137
1146
  */
1138
- label: z15.record(z15.string(), z15.string()).optional(),
1147
+ label: z16.record(z16.string(), z16.string()).optional(),
1139
1148
  /**
1140
1149
  * Smart-cart product (gift) tiers only (onsite `product_tier_image`): show the gift's product image in
1141
1150
  * the step-row slot instead of the generic bag icon. The converter can't supply the image URL (config
1142
1151
  * carries only product IDs), so the client resolves it (authoritative Shopify featured image, React
1143
1152
  * parity) and falls back to the bag icon when the flag is off or no image resolves. Default false.
1144
1153
  */
1145
- productTierImage: z15.boolean().default(false),
1154
+ productTierImage: z16.boolean().default(false),
1146
1155
  /**
1147
1156
  * The tier's goal, measured per `unit`. `currency` (default): SHOP-currency cents — the canonical
1148
1157
  * fallback: when the buyer's presentment currency has no entry in `thresholds`, the client
1149
1158
  * multiplies this by the live FX rate (converter maps the v1 `unlock_price`, e.g. `75` → `7500`).
1150
1159
  * `item`: a raw item count — no cents, no FX, no `thresholds` overrides.
1151
1160
  */
1152
- threshold: z15.number().int().nonnegative(),
1161
+ threshold: z16.number().int().nonnegative(),
1153
1162
  /**
1154
1163
  * Per-presentment-currency goal overrides — lowercased ISO currency code → cents (e.g. `{ cad: 9900 }`).
1155
1164
  * When the buyer's currency has an entry, the client uses it verbatim INSTEAD of FX-converting
1156
1165
  * `threshold`, so merchants show intentional, clean per-market amounts (Shopify Markets) rather than a
1157
1166
  * converted base. Defaults to `{}` — no overrides means always fall back to `threshold`.
1158
1167
  */
1159
- thresholds: z15.record(z15.string(), z15.number().int().nonnegative()).default(() => ({})),
1168
+ thresholds: z16.record(z16.string(), z16.number().int().nonnegative()).default(() => ({})),
1160
1169
  /**
1161
1170
  * Smart-cart tier identifier, mirrored onto the gift cart line's `_tier` attribute so the client can
1162
1171
  * match an in-cart gift back to its tier (add on reach, remove on downgrade/decline). Absent on the
1163
1172
  * shipping bar (single unlabeled tier, no gift).
1164
1173
  */
1165
- tierId: z15.string().optional(),
1166
- tierType: z15.enum(progressTierTypes).default(ProgressTierType.shipping),
1174
+ tierId: z16.string().optional(),
1175
+ tierType: z16.enum(progressTierTypes).default(ProgressTierType.shipping),
1167
1176
  /**
1168
1177
  * What this tier's progress is measured in — PER TIER (onsite's `unlock_condition_type` model, NOT
1169
1178
  * the React port's bar-level `tiers[0]` shortcut). `currency` compares money cents against the
@@ -1174,9 +1183,9 @@ var CABProgressTier = z15.object({
1174
1183
  * count carries no injected noun (no English `item`/`items` inflection on localized copy); merchant
1175
1184
  * template text supplies grammatically-neutral wording around the token.
1176
1185
  */
1177
- unit: z15.enum(progressTierUnits).default(ProgressTierUnit.currency)
1186
+ unit: z16.enum(progressTierUnits).default(ProgressTierUnit.currency)
1178
1187
  });
1179
- var CABProgressBarSection = z15.lazy(
1188
+ var CABProgressBarSection = z16.lazy(
1180
1189
  () => CABLayoutSection.omit({ sectionType: true }).extend({
1181
1190
  /**
1182
1191
  * The onsite bar id (smart-cart TPB bars only). The client mirrors it to the cart's `_barId` attribute
@@ -1185,35 +1194,35 @@ var CABProgressBarSection = z15.lazy(
1185
1194
  * checkout reaches the extension without it, so the client writes it or the tier gift's 100% discount
1186
1195
  * (and any tier order discount) never applies. Absent on the v1 shipping bar (no gift tiers, no id).
1187
1196
  */
1188
- barId: z15.string().optional(),
1197
+ barId: z16.string().optional(),
1189
1198
  /** Empty = shown everywhere; otherwise uppercase ISO country codes. */
1190
- countryCodes: z15.array(z15.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1199
+ countryCodes: z16.array(z16.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1191
1200
  /**
1192
1201
  * Uppercase ISO codes where a higher-precedence geo bar applies, so this (default, non-geo) bar is
1193
1202
  * hidden there — replicates React `getbar`'s geo-match-over-default precedence. Empty = never excluded.
1194
1203
  */
1195
- excludeCountryCodes: z15.array(z15.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1204
+ excludeCountryCodes: z16.array(z16.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1196
1205
  /**
1197
1206
  * Measure progress against the PRE-discount subtotal (onsite `exclude_discount_in_subtotal`, and
1198
1207
  * forced on for bars with a discount tier so its own reward can't un-reach the tier). The client
1199
1208
  * adds the cart's discount allocations back to the live subtotal.
1200
1209
  */
1201
- excludeDiscountInSubtotal: z15.boolean().default(false),
1210
+ excludeDiscountInSubtotal: z16.boolean().default(false),
1202
1211
  /** Variant ids the client subtracts from the adjusted subtotal (React `bar.excluded_products`). */
1203
- excludedVariantIds: z15.array(z15.number().int().positive()).default(() => []),
1212
+ excludedVariantIds: z16.array(z16.number().int().positive()).default(() => []),
1204
1213
  /**
1205
1214
  * When the cart holds a subscription item, treat the bar as reached regardless of subtotal (React
1206
1215
  * `free_shipping_on_subscription(s)`). `freeShippingOnAll` is already a zero-threshold tier instead.
1207
1216
  */
1208
- freeShippingOnSubscription: z15.boolean().default(false),
1217
+ freeShippingOnSubscription: z16.boolean().default(false),
1209
1218
  /** Localized heading over the gift controls (onsite `gift_area_title`, default 'FREE GIFTS'). */
1210
- giftAreaTitle: z15.record(z15.string(), z15.string()).default(() => ({ en: "FREE GIFTS" })),
1219
+ giftAreaTitle: z16.record(z16.string(), z16.string()).default(() => ({ en: "FREE GIFTS" })),
1211
1220
  /** Localized gift-control labels (add/remove/heading); a tier's gift `title` beats `yourGift`. */
1212
- giftLabels: z15.object({
1213
- addGift: z15.record(z15.string(), z15.string()).default(() => ({ ...GIFT_LABELS.addGift })),
1214
- remove: z15.record(z15.string(), z15.string()).default(() => ({ ...GIFT_LABELS.remove })),
1215
- selectOptions: z15.record(z15.string(), z15.string()).default(() => ({ ...GIFT_LABELS.selectOptions })),
1216
- yourGift: z15.record(z15.string(), z15.string()).default(() => ({ ...GIFT_LABELS.yourGift }))
1221
+ giftLabels: z16.object({
1222
+ addGift: z16.record(z16.string(), z16.string()).default(() => ({ ...GIFT_LABELS.addGift })),
1223
+ remove: z16.record(z16.string(), z16.string()).default(() => ({ ...GIFT_LABELS.remove })),
1224
+ selectOptions: z16.record(z16.string(), z16.string()).default(() => ({ ...GIFT_LABELS.selectOptions })),
1225
+ yourGift: z16.record(z16.string(), z16.string()).default(() => ({ ...GIFT_LABELS.yourGift }))
1217
1226
  }).default(() => ({
1218
1227
  addGift: { ...GIFT_LABELS.addGift },
1219
1228
  remove: { ...GIFT_LABELS.remove },
@@ -1221,38 +1230,38 @@ var CABProgressBarSection = z15.lazy(
1221
1230
  yourGift: { ...GIFT_LABELS.yourGift }
1222
1231
  })),
1223
1232
  /** The bar's a11y label; the merchant names it in the editor, else this default (React parity). */
1224
- name: z15.string().default("Order progress"),
1233
+ name: z16.string().default("Order progress"),
1225
1234
  /**
1226
1235
  * Bar fill color. An explicit (widget-authored) value is used verbatim; when absent the server
1227
1236
  * fills it with the live shop theme's `buttonBackground` (React `useRebuyTheme` parity). Still
1228
1237
  * absent after that ⇒ the theme fetch failed and the client renders its platform-default bar —
1229
1238
  * optional, not defaulted, so "merchant chose no color" stays distinguishable from any real value.
1230
1239
  */
1231
- progressColor: z15.string().optional(),
1232
- sectionType: z15.literal(SectionType.progressBar).default(SectionType.progressBar),
1240
+ progressColor: z16.string().optional(),
1241
+ sectionType: z16.literal(SectionType.progressBar).default(SectionType.progressBar),
1233
1242
  /**
1234
1243
  * The bar's milestones in the merchant's CONFIGURED order — the renderer does NOT sort them (022
1235
1244
  * O-B2: sorting by resolved threshold reversed configured milestones on out-of-order or mixed-unit
1236
1245
  * count-vs-cents bars). Drives the fill (even slot per tier) and, for smart-cart product tiers, the
1237
1246
  * gift add/remove. The visual tier display lives in `sections` (composable), NOT here.
1238
1247
  */
1239
- tiers: z15.union([z15.array(CABProgressTier), z15.strictObject({}).transform(() => [])]).default(() => [])
1248
+ tiers: z16.union([z16.array(CABProgressTier), z16.strictObject({}).transform(() => [])]).default(() => [])
1240
1249
  })
1241
1250
  );
1242
1251
 
1243
1252
  // src/schema/widgets/checkout-and-beyond/quantity.ts
1244
1253
  import { v7 as uuidv79 } from "uuid";
1245
- import { z as z16 } from "zod";
1246
- var CABQuantitySection = z16.object({
1254
+ import { z as z17 } from "zod";
1255
+ var CABQuantitySection = z17.object({
1247
1256
  ...CABVariableFields,
1248
- errorMessages: z16.record(
1249
- z16.string(),
1250
- z16.object({
1257
+ errorMessages: z17.record(
1258
+ z17.string(),
1259
+ z17.object({
1251
1260
  /** `{{step}}` is interpolated at render — the off-increment message React never gave a merchant key. */
1252
- increment: z16.string().optional(),
1253
- max: z16.string().optional(),
1254
- min: z16.string().optional(),
1255
- neg: z16.string().optional()
1261
+ increment: z17.string().optional(),
1262
+ max: z17.string().optional(),
1263
+ min: z17.string().optional(),
1264
+ neg: z17.string().optional()
1256
1265
  })
1257
1266
  ).default({
1258
1267
  en: {
@@ -1262,18 +1271,18 @@ var CABQuantitySection = z16.object({
1262
1271
  neg: "Quantity cannot be negative"
1263
1272
  }
1264
1273
  }),
1265
- inputType: z16.enum(quantityInputs).default(QuantityInput.select),
1266
- max: z16.number().min(1).max(100).default(10),
1267
- min: z16.number().min(1).default(1),
1274
+ inputType: z17.enum(quantityInputs).default(QuantityInput.select),
1275
+ max: z17.number().min(1).max(100).default(10),
1276
+ min: z17.number().min(1).default(1),
1268
1277
  /** The a11y label for the quantity control; the merchant names it in the editor, else this default. */
1269
- name: z16.string().default("Quantity"),
1270
- sectionId: z16.uuid().default(() => uuidv79()),
1271
- sectionType: z16.literal(SectionType.quantity).default(SectionType.quantity)
1278
+ name: z17.string().default("Quantity"),
1279
+ sectionId: z17.uuid().default(() => uuidv79()),
1280
+ sectionType: z17.literal(SectionType.quantity).default(SectionType.quantity)
1272
1281
  });
1273
1282
 
1274
1283
  // src/schema/widgets/checkout-and-beyond/reviews.ts
1275
1284
  import { v7 as uuidv710 } from "uuid";
1276
- import { z as z17 } from "zod";
1285
+ import { z as z18 } from "zod";
1277
1286
 
1278
1287
  // src/schema/widgets/checkout-and-beyond/reviewLabels.ts
1279
1288
  var REVIEW_LABELS = {
@@ -1336,68 +1345,69 @@ var REVIEW_LABELS = {
1336
1345
  };
1337
1346
 
1338
1347
  // src/schema/widgets/checkout-and-beyond/reviews.ts
1339
- var CABReviewsSection = z17.object({
1348
+ var CABReviewsSection = z18.object({
1340
1349
  ...CABVariableFields,
1341
- color: z17.string().default("#fadb14"),
1350
+ color: z18.string().default("#fadb14"),
1342
1351
  /**
1343
1352
  * Localized review-count templates (`{{reviewCount}}`), one/other plural forms; the client picks the
1344
1353
  * form via `Intl.PluralRules`. Defaults here (schema-first) so every tree localizes without converter
1345
1354
  * or merchant work.
1346
1355
  */
1347
- countLabels: z17.object({
1348
- one: z17.record(z17.string(), z17.string()).default(() => ({ ...REVIEW_LABELS.one })),
1349
- other: z17.record(z17.string(), z17.string()).default(() => ({ ...REVIEW_LABELS.other }))
1356
+ countLabels: z18.object({
1357
+ one: z18.record(z18.string(), z18.string()).default(() => ({ ...REVIEW_LABELS.one })),
1358
+ other: z18.record(z18.string(), z18.string()).default(() => ({ ...REVIEW_LABELS.other }))
1350
1359
  }).default(() => ({ one: { ...REVIEW_LABELS.one }, other: { ...REVIEW_LABELS.other } })),
1351
- name: z17.string().optional(),
1352
- sectionId: z17.uuid().default(() => uuidv710()),
1353
- sectionType: z17.literal(SectionType.reviews).default(SectionType.reviews),
1354
- size: z17.enum(reviewsSizes).default(ReviewsSize.default),
1360
+ name: z18.string().optional(),
1361
+ sectionId: z18.uuid().default(() => uuidv710()),
1362
+ sectionType: z18.literal(SectionType.reviews).default(SectionType.reviews),
1363
+ size: z18.enum(reviewsSizes).default(ReviewsSize.default),
1355
1364
  /**
1356
1365
  * Star outline color, interpolated into a style by the renderer, so it is hex-constrained like
1357
1366
  * `CABButtonSection.color`. The legacy source (`PostPurchaseSettings.styles.starStrokeColor`) is a free
1358
1367
  * string: its converter must validate and fall back to this default rather than let one odd value drop
1359
1368
  * the whole reviews section.
1360
1369
  */
1361
- strokeColor: z17.string().regex(HEX_COLOR_REGEX).default("#fadb14"),
1370
+ strokeColor: z18.string().regex(HEX_COLOR_REGEX).default("#fadb14"),
1362
1371
  /** Star outline width in px; `0` draws no outline. The legacy `styles.strokeWidth` is a STRING ('1') — its converter coerces. */
1363
- strokeWidth: z17.number().nonnegative().default(0)
1372
+ strokeWidth: z18.number().nonnegative().default(0)
1364
1373
  });
1365
1374
 
1366
1375
  // src/schema/widgets/checkout-and-beyond/separator.ts
1367
1376
  import { v7 as uuidv711 } from "uuid";
1368
- import { z as z18 } from "zod";
1369
- var CABSeparatorSection = z18.object({
1377
+ import { z as z19 } from "zod";
1378
+ var CABSeparatorSection = z19.object({
1370
1379
  ...CABVariableFields,
1371
- sectionId: z18.uuid().default(() => uuidv711()),
1372
- sectionType: z18.literal(SectionType.separator).default(SectionType.separator)
1380
+ sectionId: z19.uuid().default(() => uuidv711()),
1381
+ sectionType: z19.literal(SectionType.separator).default(SectionType.separator)
1373
1382
  });
1374
1383
 
1375
1384
  // src/schema/widgets/checkout-and-beyond/variants.ts
1376
1385
  import { slice } from "es-toolkit/compat";
1377
1386
  import { v7 as uuidv712 } from "uuid";
1378
- import { z as z19 } from "zod";
1379
- var CABVariantsSection = z19.object({
1387
+ import { z as z20 } from "zod";
1388
+ var CABVariantsSection = z20.object({
1380
1389
  ...CABVariableFields,
1381
- hideOutOfStockVariants: z19.boolean().default(false),
1382
- name: z19.string().optional(),
1383
- sectionId: z19.uuid().default(() => uuidv712()),
1384
- sectionType: z19.literal(SectionType.variants).default(SectionType.variants),
1385
- selector: z19.enum(slice(variantSelectors, 0, 3)).default(VariantSelector.menu),
1386
- variantMode: z19.enum(variantModes).default(VariantMode.multiple)
1390
+ hideOutOfStockVariants: z20.boolean().default(false),
1391
+ name: z20.string().optional(),
1392
+ sectionId: z20.uuid().default(() => uuidv712()),
1393
+ sectionType: z20.literal(SectionType.variants).default(SectionType.variants),
1394
+ selector: z20.enum(slice(variantSelectors, 0, 3)).default(VariantSelector.menu),
1395
+ /** `productGroup` is additive (REB-24817): a renderer without group support must render nothing for it. */
1396
+ variantMode: z20.enum(variantsModes).default(VariantsMode.multiple)
1387
1397
  });
1388
1398
 
1389
1399
  // src/schema/widgets/checkout-and-beyond/shared.ts
1390
- var CABBorder = z20.object({
1391
- radius: z20.enum(borderRadii).default(BorderRadius.base),
1392
- style: z20.enum(borderStyles).default(BorderStyle.none),
1393
- width: z20.enum(borderWidths).default(BorderWidth.base)
1400
+ var CABBorder = z21.object({
1401
+ radius: z21.enum(borderRadii).default(BorderRadius.base),
1402
+ style: z21.enum(borderStyles).default(BorderStyle.none),
1403
+ width: z21.enum(borderWidths).default(BorderWidth.base)
1394
1404
  }).default({
1395
1405
  radius: BorderRadius.base,
1396
1406
  style: BorderStyle.none,
1397
1407
  width: BorderWidth.base
1398
1408
  });
1399
- var CABSection = z20.lazy(
1400
- () => z20.discriminatedUnion("sectionType", [
1409
+ var CABSection = z21.lazy(
1410
+ () => z21.discriminatedUnion("sectionType", [
1401
1411
  CABBannerSection,
1402
1412
  CABButtonSection,
1403
1413
  CABCarouselSection,
@@ -1420,17 +1430,17 @@ var CABSection = z20.lazy(
1420
1430
  );
1421
1431
 
1422
1432
  // src/schema/widgets/checkout-and-beyond/image.ts
1423
- var CABImageSectionFields = z21.object({
1433
+ var CABImageSectionFields = z22.object({
1424
1434
  ...CABVariableFields,
1425
- altText: z21.string().refine(checkForHTML, NO_HTML).default(""),
1435
+ altText: z22.string().refine(checkForHTML, NO_HTML).default(""),
1426
1436
  /**
1427
1437
  * Image width÷height (e.g. `46` for the progress-bar fill); `null` renders at natural size. Any POSITIVE
1428
1438
  * ratio — never limited to 1, but never `0`/negative either: a renderer dividing by it would get `Infinity`,
1429
1439
  * and CSS `aspect-ratio` drops a negative value and silently reverts to natural size.
1430
1440
  */
1431
- aspectRatio: z21.number().positive().nullable().default(null),
1432
- border: z21.lazy(() => CABBorder),
1433
- buttonField: z21.enum(buttonFields).optional(),
1441
+ aspectRatio: z22.number().positive().nullable().default(null),
1442
+ border: z22.lazy(() => CABBorder),
1443
+ buttonField: z22.enum(buttonFields).optional(),
1434
1444
  /**
1435
1445
  * `icon` renders `source` as a single `s-icon` by name (the uber-image path covers icons too), reading
1436
1446
  * `iconSize`/`iconTone`. The other values are a harmless informational holdover from the previous
@@ -1449,29 +1459,30 @@ var CABImageSectionFields = z21.object({
1449
1459
  * behavior degraded gracefully and told us about it. The client-assembled half of the invariant was never
1450
1460
  * the risky half.
1451
1461
  */
1452
- category: z21.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
1462
+ category: z22.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
1453
1463
  /** `icon`-mode only: the `s-icon` `size`; `null` ⇒ the component default (`base`). Ignored by image treatments. */
1454
- iconSize: z21.enum(iconSizes).nullable().default(null),
1464
+ iconSize: z22.enum(iconSizes).nullable().default(null),
1455
1465
  /** `icon`-mode only: the `s-icon` `tone`; `null` ⇒ the component default (`auto`). Ignored by image treatments. */
1456
- iconTone: z21.enum(iconTones).nullable().default(null),
1457
- name: z21.string().optional(),
1458
- naturalHeight: z21.number().default(0),
1459
- naturalWidth: z21.number().default(0),
1466
+ iconTone: z22.enum(iconTones).nullable().default(null),
1467
+ name: z22.string().optional(),
1468
+ naturalHeight: z22.number().default(0),
1469
+ naturalWidth: z22.number().default(0),
1460
1470
  /**
1461
1471
  * `contain` (the component default): dimensionless images render in s-image's 1/1 default frame, and
1462
1472
  * `cover` would crop non-square art (payment badges lost their edges — 15993); `contain` letterboxes.
1463
1473
  */
1464
- objectFit: z21.enum(objectFits).default(ObjectFit.contain),
1465
- sectionId: z21.uuid().default(() => uuidv713()),
1466
- sectionType: z21.literal(SectionType.image).default(SectionType.image),
1474
+ objectFit: z22.enum(objectFits).default(ObjectFit.contain),
1475
+ sectionId: z22.uuid().default(() => uuidv713()),
1476
+ sectionType: z22.literal(SectionType.image).default(SectionType.image),
1467
1477
  /**
1468
1478
  * An image URL or dynamic token, an empty default, or — when `category: 'icon'` — an icon NAME. Icon mode
1469
1479
  * takes a name or `''` only, NOT a token: no renderer resolves a token to an icon today, so accepting one
1470
1480
  * would promise a capability that doesn't exist. Widen the refine's carve-out to `DYNAMIC_TOKEN_REGEX` when a
1471
1481
  * server-chosen tier icon actually needs it.
1472
1482
  */
1473
- source: z21.union([z21.url(), z21.literal(""), z21.string().regex(DYNAMIC_TOKEN_REGEX), z21.enum(iconNames)]).default(""),
1474
- width: z21.number().default(100)
1483
+ source: z22.union([z22.url(), z22.literal(""), z22.string().regex(DYNAMIC_TOKEN_REGEX), z22.enum(iconNames)]).default(""),
1484
+ thumbnails: CABImageThumbnails.optional(),
1485
+ width: z22.number().default(100)
1475
1486
  });
1476
1487
  var iconNameSet = new Set(iconNames);
1477
1488
  var isIconName = (source) => iconNameSet.has(source);
@@ -1622,7 +1633,7 @@ var convertContentBlockTextToV2 = (language, text = literalText, textAlign = "ce
1622
1633
  };
1623
1634
 
1624
1635
  // src/schema/widgets/checkout-and-beyond/root.ts
1625
- import { z as z22 } from "zod";
1636
+ import { z as z23 } from "zod";
1626
1637
 
1627
1638
  // src/schema/widgets/checkout-and-beyond/uiLabels.ts
1628
1639
  var UI_LABELS = {
@@ -1642,8 +1653,8 @@ var UI_LABELS = {
1642
1653
  };
1643
1654
 
1644
1655
  // src/schema/widgets/checkout-and-beyond/root.ts
1645
- var localized = (fallback) => z22.record(z22.string(), z22.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
1646
- var CABUILabels = z22.object({
1656
+ var localized = (fallback) => z23.record(z23.string(), z23.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
1657
+ var CABUILabels = z23.object({
1647
1658
  currentPage: localized(UI_LABELS.currentPage),
1648
1659
  guest: localized(UI_LABELS.guest),
1649
1660
  loadingOptions: localized(UI_LABELS.loadingOptions),
@@ -1668,37 +1679,37 @@ var CABUILabels = z22.object({
1668
1679
  subscriptionOptions: { ...UI_LABELS.subscriptionOptions },
1669
1680
  updating: { ...UI_LABELS.updating }
1670
1681
  }));
1671
- var TargetArea = z22.object({
1672
- fill: z22.boolean().optional(),
1673
- flip: z22.enum(["both", "horizontal", "vertical"]).optional(),
1674
- icon: z22.string(),
1675
- label: z22.string(),
1676
- width: z22.string()
1682
+ var TargetArea = z23.object({
1683
+ fill: z23.boolean().optional(),
1684
+ flip: z23.enum(["both", "horizontal", "vertical"]).optional(),
1685
+ icon: z23.string(),
1686
+ label: z23.string(),
1687
+ width: z23.string()
1677
1688
  }).default(targetAreas[EditorMode.checkoutExtension][1]);
1678
- var CABTracking = z22.object({
1679
- enableAttribution: z22.boolean().nullish().transform((value) => value ?? true),
1680
- enableSource: z22.boolean().nullish().transform((value) => value ?? true),
1681
- enableWidget: z22.boolean().nullish().transform((value) => value ?? true)
1689
+ var CABTracking = z23.object({
1690
+ enableAttribution: z23.boolean().nullish().transform((value) => value ?? true),
1691
+ enableSource: z23.boolean().nullish().transform((value) => value ?? true),
1692
+ enableWidget: z23.boolean().nullish().transform((value) => value ?? true)
1682
1693
  }).nullish().transform((value) => value ?? { enableAttribution: true, enableSource: true, enableWidget: true });
1683
- var CABExperiment = z22.object({
1684
- elementId: z22.number(),
1685
- experimentId: z22.number(),
1686
- experimentType: z22.string(),
1687
- selectedId: z22.number()
1694
+ var CABExperiment = z23.object({
1695
+ elementId: z23.number(),
1696
+ experimentId: z23.number(),
1697
+ experimentType: z23.string(),
1698
+ selectedId: z23.number()
1688
1699
  });
1689
1700
  var CABRootSection = CABLayoutSection.extend({
1690
- editorMode: z22.enum(editorModes).default(EditorMode.checkoutExtension),
1701
+ editorMode: z23.enum(editorModes).default(EditorMode.checkoutExtension),
1691
1702
  experiment: CABExperiment.optional(),
1692
1703
  // Same rule as CABTracking above: the v1 converters pass raw legacy `previewMode` through, so a
1693
1704
  // `null` must fall back rather than throw the widget; malformed values still throw.
1694
- previewMode: z22.boolean().nullish().transform((value) => value ?? false),
1695
- storeId: z22.number().nullable().default(null),
1705
+ previewMode: z23.boolean().nullish().transform((value) => value ?? false),
1706
+ storeId: z23.number().nullable().default(null),
1696
1707
  targetArea: TargetArea.nullable(),
1697
1708
  tracking: CABTracking,
1698
- type: z22.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
1709
+ type: z23.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
1699
1710
  uiLabels: CABUILabels,
1700
- version: z22.literal(2).default(2),
1701
- widgetId: z22.number().nullable().default(null)
1711
+ version: z23.literal(2).default(2),
1712
+ widgetId: z23.number().nullable().default(null)
1702
1713
  });
1703
1714
 
1704
1715
  // src/transforms/v1Location.ts
@@ -2967,21 +2978,26 @@ var convertPlaceholderToV2 = ({ id, settings }) => CABRootSection.parse({
2967
2978
  // src/transforms/placeholderV1/types.ts
2968
2979
  var isPlaceholderV1 = (data) => !!data && typeof data === "object" && data.type === WidgetType.placeholder;
2969
2980
 
2970
- // src/transforms/offerV1/offerCard.ts
2971
- var borderToken = (tokens, value) => value !== void 0 && tokens.includes(value) ? value : "base";
2972
- var GRID_CARD_IMAGE_PX = 120;
2973
- var COMPACT_CARD_IMAGE_PX = 64;
2974
- var ADD_LABEL_TOKENS = ["quantity", "price", "total"];
2975
- var SWITCH_LABEL_TOKENS2 = ["subscriptionDiscount", "frequency", "interval"];
2976
- var QUANTITY_ERROR_TOKENS = ["max", "min", "step"];
2977
- var VARIANT_SELECTOR = { button: "button", radio: "radio", select: "menu" };
2978
- var buildStyledText = (token, style, fontSize = style?.textSize ?? "base") => {
2979
- const marks = [{ attrs: { color: "base", fontSize }, type: "textStyle" }];
2980
- if (style?.textEmphasis === "bold") marks.push({ type: "bold" });
2981
- if (style?.textEmphasis === "italic") marks.push({ type: "italic" });
2982
- return { content: [{ content: [{ marks, text: token, type: "text" }], type: "paragraph" }], type: "doc" };
2983
- };
2984
- var buildPriceContent = () => ({
2981
+ // src/transforms/productCard/earnedText.ts
2982
+ var contentMutator = (effect, variable, operator) => ({
2983
+ effect,
2984
+ variable,
2985
+ when: { operator, type: "content" }
2986
+ });
2987
+ var earnedFrom = (variable) => [
2988
+ contentMutator("set_false", variable, "is_empty"),
2989
+ contentMutator("set_true", variable, "is_not_empty")
2990
+ ];
2991
+ var shownWhile = (variable) => ({ variable, visibleWhen: true });
2992
+ var earnedText = (variable, content) => ({
2993
+ content: { en: content },
2994
+ mutators: earnedFrom(variable),
2995
+ sectionType: "text",
2996
+ visibility: shownWhile(variable)
2997
+ });
2998
+
2999
+ // src/transforms/productCard/priceText.ts
3000
+ var priceContent = () => ({
2985
3001
  content: [
2986
3002
  {
2987
3003
  content: [
@@ -3007,6 +3023,64 @@ var buildPriceContent = () => ({
3007
3023
  ],
3008
3024
  type: "doc"
3009
3025
  });
3026
+ var priceText = () => ({
3027
+ content: { en: priceContent() },
3028
+ sectionType: "text"
3029
+ });
3030
+
3031
+ // src/transforms/productCard/quantitySection.ts
3032
+ var quantitySection = ({ errorMessages, inputType, maxValue, minValue, name }) => {
3033
+ const max = Math.min(Math.max(maxValue ?? 10, 1), 100);
3034
+ const min = Math.min(Math.max(minValue ?? 1, 1), max);
3035
+ return {
3036
+ ...errorMessages && { errorMessages },
3037
+ ...inputType && { inputType },
3038
+ max,
3039
+ min,
3040
+ ...name && { name },
3041
+ sectionType: "quantity"
3042
+ };
3043
+ };
3044
+
3045
+ // src/transforms/productCard/subscriptionToggle.ts
3046
+ var SWITCH_LABEL_TOKENS2 = ["subscriptionDiscount", "frequency", "interval"];
3047
+ var subscriptionToggle = (productType, labels = {}) => {
3048
+ if (productType !== "both" && productType !== "subscription") return [];
3049
+ const slot = (buttonField, override) => ({
3050
+ buttonField,
3051
+ content: localizedContent(SWITCH_LABELS[buttonField], override, SWITCH_LABEL_TOKENS2),
3052
+ sectionType: "text"
3053
+ });
3054
+ return [
3055
+ {
3056
+ action: "switchToSubscription",
3057
+ buttonStyle: "plain",
3058
+ /** A `subscription` widget offers no one-time purchase; suppress the downgrade so the buyer can't switch to one-time. */
3059
+ ...productType === "subscription" && { disableDowngrade: true },
3060
+ sections: [
3061
+ slot("subscriptionOption", void 0),
3062
+ slot("switchToOneTimePurchase", labels.oneTime),
3063
+ slot("switchToSubscriptionNoDiscount", labels.upgrade),
3064
+ slot("switchToSubscriptionWithDiscount", labels.upgrade)
3065
+ ],
3066
+ sectionType: "button"
3067
+ }
3068
+ ];
3069
+ };
3070
+
3071
+ // src/transforms/offerV1/offerCard.ts
3072
+ var borderToken = (tokens, value) => value !== void 0 && tokens.includes(value) ? value : "base";
3073
+ var GRID_CARD_IMAGE_PX = 120;
3074
+ var COMPACT_CARD_IMAGE_PX = 64;
3075
+ var ADD_LABEL_TOKENS = ["quantity", "price", "total"];
3076
+ var QUANTITY_ERROR_TOKENS = ["max", "min", "step"];
3077
+ var VARIANT_SELECTOR = { button: "button", radio: "radio", select: "menu" };
3078
+ var buildStyledText = (token, style, fontSize = style?.textSize ?? "base") => {
3079
+ const marks = [{ attrs: { color: "base", fontSize }, type: "textStyle" }];
3080
+ if (style?.textEmphasis === "bold") marks.push({ type: "bold" });
3081
+ if (style?.textEmphasis === "italic") marks.push({ type: "italic" });
3082
+ return { content: [{ content: [{ marks, text: token, type: "text" }], type: "paragraph" }], type: "doc" };
3083
+ };
3010
3084
  var buildReviews = (settings) => {
3011
3085
  if (!settings.integrations || !Object.values(settings.integrations).some(Boolean)) return [];
3012
3086
  const reviews = settings.displaySettings?.reviews;
@@ -3048,29 +3122,11 @@ var buildTitle = (settings) => ({
3048
3122
  },
3049
3123
  sectionType: "text"
3050
3124
  });
3051
- var buildPrice = () => ({
3052
- content: { en: buildPriceContent() },
3053
- sectionType: "text"
3054
- });
3055
3125
  var HAS_VARIANT_TITLE = "hasVariantTitle";
3056
3126
  var buildVariantTitle = (settings) => {
3057
3127
  const show = settings.productOptions?.showVariantTitle;
3058
3128
  if (!show || show === "hide") return [];
3059
- return [
3060
- {
3061
- content: { en: buildStyledText("{{variantTitle}}", settings.displaySettings?.variant) },
3062
- mutators: [
3063
- { effect: "set_false", variable: HAS_VARIANT_TITLE, when: { operator: "is_empty", type: "content" } },
3064
- {
3065
- effect: "set_true",
3066
- variable: HAS_VARIANT_TITLE,
3067
- when: { operator: "is_not_empty", type: "content" }
3068
- }
3069
- ],
3070
- sectionType: "text",
3071
- visibility: { variable: HAS_VARIANT_TITLE, visibleWhen: true }
3072
- }
3073
- ];
3129
+ return [earnedText(HAS_VARIANT_TITLE, buildStyledText("{{variantTitle}}", settings.displaySettings?.variant))];
3074
3130
  };
3075
3131
  var detailBlock = (sections, horizontal, hasVariantTitleLine) => ({
3076
3132
  alignment: { horizontal: horizontal ? "start" : "center", vertical: "top" },
@@ -3099,18 +3155,7 @@ var buildDescription = (settings) => {
3099
3155
  },
3100
3156
  {
3101
3157
  content: { en: buildStyledText("{{productDescription}}", void 0) },
3102
- mutators: [
3103
- {
3104
- effect: "set_false",
3105
- variable: HAS_DESCRIPTION,
3106
- when: { operator: "is_empty", type: "content" }
3107
- },
3108
- {
3109
- effect: "set_true",
3110
- variable: HAS_DESCRIPTION,
3111
- when: { operator: "is_not_empty", type: "content" }
3112
- }
3113
- ],
3158
+ mutators: earnedFrom(HAS_DESCRIPTION),
3114
3159
  sectionType: "text",
3115
3160
  visibility: { variable: SHOW_DESCRIPTION, visibleWhen: true }
3116
3161
  }
@@ -3126,7 +3171,7 @@ var buildDescription = (settings) => {
3126
3171
  var SHOW_VARIANTS = "showVariants";
3127
3172
  var REVEAL_PENDING = "revealPending";
3128
3173
  var revealsVariants = (settings) => settings.viewOptions?.displayActions !== false && settings.productOptions?.showVariantOptions === "default";
3129
- var contentMutator = (effect, variable, operator) => ({
3174
+ var contentMutator2 = (effect, variable, operator) => ({
3130
3175
  effect,
3131
3176
  variable,
3132
3177
  when: { operator, type: "content" }
@@ -3140,10 +3185,10 @@ var buildVariants = (settings) => {
3140
3185
  hideOutOfStockVariants: !!settings.productOptions?.hideOutOfStockVariants,
3141
3186
  ...revealsVariants(settings) && {
3142
3187
  mutators: [
3143
- contentMutator("set_true", SHOW_VARIANTS, "is_empty"),
3144
- contentMutator("set_false", REVEAL_PENDING, "is_empty"),
3145
- contentMutator("set_true", REVEAL_PENDING, "is_not_empty"),
3146
- contentMutator("set_false", SHOW_VARIANTS, "is_not_empty")
3188
+ contentMutator2("set_true", SHOW_VARIANTS, "is_empty"),
3189
+ contentMutator2("set_false", REVEAL_PENDING, "is_empty"),
3190
+ contentMutator2("set_true", REVEAL_PENDING, "is_not_empty"),
3191
+ contentMutator2("set_false", SHOW_VARIANTS, "is_not_empty")
3147
3192
  ]
3148
3193
  },
3149
3194
  ...selector && { selector: VARIANT_SELECTOR[selector] },
@@ -3157,54 +3202,31 @@ var QUANTITY_INPUT_TYPE = {
3157
3202
  "buttons-manual-input": "number",
3158
3203
  "dropdown-select": "select"
3159
3204
  };
3160
- var buildQuantityErrors = (quantity) => {
3205
+ var buildQuantityErrors = (quantity2) => {
3161
3206
  const en = {
3162
- ...quantity.maxError && { max: normalizeTokens(quantity.maxError, QUANTITY_ERROR_TOKENS) },
3163
- ...quantity.minError && { min: normalizeTokens(quantity.minError, QUANTITY_ERROR_TOKENS) },
3164
- ...quantity.negativeError && { neg: normalizeTokens(quantity.negativeError, QUANTITY_ERROR_TOKENS) }
3207
+ ...quantity2.maxError && { max: normalizeTokens(quantity2.maxError, QUANTITY_ERROR_TOKENS) },
3208
+ ...quantity2.minError && { min: normalizeTokens(quantity2.minError, QUANTITY_ERROR_TOKENS) },
3209
+ ...quantity2.negativeError && { neg: normalizeTokens(quantity2.negativeError, QUANTITY_ERROR_TOKENS) }
3165
3210
  };
3166
3211
  return Object.keys(en).length ? { errorMessages: { en } } : {};
3167
3212
  };
3168
3213
  var buildQuantity = (settings) => {
3169
- const quantity = settings.quantityInputs;
3170
- if (!quantity?.enabled) return [];
3171
- const inputType = quantity.type ? QUANTITY_INPUT_TYPE[quantity.type] : void 0;
3172
- const max = Math.min(Math.max(quantity.maxValue ?? 10, 1), 100);
3173
- const min = Math.min(Math.max(quantity.minValue ?? 1, 1), max);
3174
- return [
3175
- {
3176
- ...buildQuantityErrors(quantity),
3177
- ...inputType && { inputType },
3178
- max,
3179
- min,
3180
- sectionType: "quantity"
3181
- }
3182
- ];
3183
- };
3184
- var buildSubscriptionButton = (settings) => {
3185
- if (settings.productType !== "both" && settings.productType !== "subscription") return [];
3186
- const language = settings.language;
3187
- const slot = (buttonField, override) => ({
3188
- buttonField,
3189
- content: localizedContent(SWITCH_LABELS[buttonField], override, SWITCH_LABEL_TOKENS2),
3190
- sectionType: "text"
3191
- });
3214
+ const quantity2 = settings.quantityInputs;
3215
+ if (!quantity2?.enabled) return [];
3216
+ const errors = buildQuantityErrors(quantity2);
3192
3217
  return [
3193
- {
3194
- action: "switchToSubscription",
3195
- buttonStyle: "plain",
3196
- /** A `subscription` widget offers no one-time purchase (legacy's offers checkbox renders only when `isProductTypeBoth`); suppress the downgrade so the buyer can't switch to one-time on a subscription-only offer. */
3197
- ...settings.productType === "subscription" && { disableDowngrade: true },
3198
- sections: [
3199
- slot("subscriptionOption", void 0),
3200
- slot("switchToOneTimePurchase", language?.cartSwitchToOnetime),
3201
- slot("switchToSubscriptionNoDiscount", language?.upgradeToSubscription),
3202
- slot("switchToSubscriptionWithDiscount", language?.upgradeToSubscription)
3203
- ],
3204
- sectionType: "button"
3205
- }
3218
+ quantitySection({
3219
+ ...errors,
3220
+ inputType: quantity2.type ? QUANTITY_INPUT_TYPE[quantity2.type] : void 0,
3221
+ maxValue: quantity2.maxValue,
3222
+ minValue: quantity2.minValue
3223
+ })
3206
3224
  ];
3207
3225
  };
3226
+ var buildSubscriptionButton = (settings) => subscriptionToggle(settings.productType, {
3227
+ oneTime: settings.language?.cartSwitchToOnetime,
3228
+ upgrade: settings.language?.upgradeToSubscription
3229
+ });
3208
3230
  var BUTTON_KINDS2 = ["plain", "primary", "secondary"];
3209
3231
  var buttonKind = (settings) => {
3210
3232
  const kind = settings.button?.kind;
@@ -3250,15 +3272,15 @@ var buildOfferCard = (settings, horizontal) => {
3250
3272
  const image = buildImage(settings);
3251
3273
  const title = buildTitle(settings);
3252
3274
  const variantTitle = buildVariantTitle(settings);
3253
- const price = buildPrice();
3275
+ const price = priceText();
3254
3276
  const description = buildDescription(settings);
3255
3277
  const reviews = buildReviews(settings);
3256
3278
  const variants = buildVariants(settings);
3257
- const quantity = buildQuantity(settings);
3279
+ const quantity2 = buildQuantity(settings);
3258
3280
  const subscription = buildSubscriptionButton(settings);
3259
3281
  const reveal = buildRevealButton(settings);
3260
3282
  const addButton = buildAddButton(settings);
3261
- const controls = [...description, ...quantity, ...variants, ...subscription];
3283
+ const controls = [...description, ...quantity2, ...variants, ...subscription];
3262
3284
  const info = detailBlock([title, ...variantTitle, ...reviews, price], horizontal, variantTitle.length > 0);
3263
3285
  const card = (sections) => [
3264
3286
  {
@@ -3554,7 +3576,7 @@ var convertOfferToV2 = ({ id, name, settings }) => {
3554
3576
  var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(transform(convertNumericObjects(deepCamelCase(raw))));
3555
3577
 
3556
3578
  // src/transforms/postPurchase/convertMessagePreview.ts
3557
- import { z as z30 } from "zod";
3579
+ import { z as z34 } from "zod";
3558
3580
 
3559
3581
  // src/server/shared.ts
3560
3582
  var NotFoundError = class extends Error {
@@ -3565,15 +3587,15 @@ var NotFoundError = class extends Error {
3565
3587
  };
3566
3588
 
3567
3589
  // src/transforms/postPurchase/convertCalloutBlock.ts
3568
- import { z as z25 } from "zod";
3590
+ import { z as z26 } from "zod";
3569
3591
 
3570
3592
  // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
3571
3593
  import { get as get2, isEqual } from "es-toolkit/compat";
3572
3594
  import { v4 as uuidv4 } from "uuid";
3573
- import { z as z24 } from "zod";
3595
+ import { z as z25 } from "zod";
3574
3596
 
3575
3597
  // src/schema/widgets/post-purchase-offer/constants.ts
3576
- import { z as z23 } from "zod";
3598
+ import { z as z24 } from "zod";
3577
3599
  var blockTypes = [
3578
3600
  "callout_banner",
3579
3601
  "image",
@@ -3584,141 +3606,141 @@ var blockTypes = [
3584
3606
  "text",
3585
3607
  "timer"
3586
3608
  ];
3587
- var blockType = z23.enum(blockTypes);
3609
+ var blockType = z24.enum(blockTypes);
3588
3610
  var BlockType = blockType.enum;
3589
3611
 
3590
3612
  // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
3591
- var TextAlignment2 = z24.union([z24.enum(["leading", "center", "trailing"]), z24.unknown().transform(() => "leading")]);
3592
- var TextSize = z24.union([
3593
- z24.enum(["xsmall", "small", "base", "default", "medium", "large", "xlarge"]),
3594
- z24.unknown().transform(() => "medium")
3613
+ var TextAlignment2 = z25.union([z25.enum(["leading", "center", "trailing"]), z25.unknown().transform(() => "leading")]);
3614
+ var TextSize = z25.union([
3615
+ z25.enum(["xsmall", "small", "base", "default", "medium", "large", "xlarge"]),
3616
+ z25.unknown().transform(() => "medium")
3595
3617
  ]);
3596
- var CalloutBannerBlock = z24.object({
3597
- id: z24.string().optional().default(() => uuidv4()),
3598
- name: z24.string().optional(),
3599
- settings: z24.object({
3600
- superTitle: z24.union([z24.string(), TiptapDocument]).default(() => "Limited-time Offer"),
3601
- title: z24.union([z24.string(), TiptapDocument]).default(() => "Add this customer favorite to your order")
3618
+ var CalloutBannerBlock = z25.object({
3619
+ id: z25.string().optional().default(() => uuidv4()),
3620
+ name: z25.string().optional(),
3621
+ settings: z25.object({
3622
+ superTitle: z25.union([z25.string(), TiptapDocument]).default(() => "Limited-time Offer"),
3623
+ title: z25.union([z25.string(), TiptapDocument]).default(() => "Add this customer favorite to your order")
3602
3624
  }),
3603
- styles: z24.object({
3604
- superTitleEmphasized: z24.boolean().default(false),
3625
+ styles: z25.object({
3626
+ superTitleEmphasized: z25.boolean().default(false),
3605
3627
  superTitleSize: TextSize.default("large"),
3606
3628
  textAlignment: TextAlignment2.default("center"),
3607
- titleEmphasized: z24.boolean().default(true),
3629
+ titleEmphasized: z25.boolean().default(true),
3608
3630
  titleSize: TextSize.default("large")
3609
3631
  }),
3610
- type: z24.literal(BlockType.callout_banner).default(BlockType.callout_banner)
3632
+ type: z25.literal(BlockType.callout_banner).default(BlockType.callout_banner)
3611
3633
  });
3612
- var ImageBlock = z24.object({
3613
- id: z24.string().optional().default(() => uuidv4()),
3614
- name: z24.string().optional(),
3615
- settings: z24.union([
3616
- z24.object({
3634
+ var ImageBlock = z25.object({
3635
+ id: z25.string().optional().default(() => uuidv4()),
3636
+ name: z25.string().optional(),
3637
+ settings: z25.union([
3638
+ z25.object({
3617
3639
  /** This isn't used in the post-purchase offer widget */
3618
- alt: z24.string().optional().default(""),
3619
- image: z24.union([z24.literal(""), z24.url()]).default(""),
3620
- imageSize: z24.number().default(20),
3621
- imageType: z24.enum(["URL", "UPLOAD"]).default("URL")
3640
+ alt: z25.string().optional().default(""),
3641
+ image: z25.union([z25.literal(""), z25.url()]).default(""),
3642
+ imageSize: z25.number().default(20),
3643
+ imageType: z25.enum(["URL", "UPLOAD"]).default("URL")
3622
3644
  }),
3623
- z24.array(z24.never()).transform(() => ({}))
3645
+ z25.array(z25.never()).transform(() => ({}))
3624
3646
  ]),
3625
- type: z24.literal(BlockType.image).default(BlockType.image)
3647
+ type: z25.literal(BlockType.image).default(BlockType.image)
3626
3648
  });
3627
- var ImageContentBlock = z24.object({
3628
- id: z24.string().optional().default(() => uuidv4()),
3629
- name: z24.string().optional(),
3630
- settings: z24.object({
3631
- alt: z24.string().optional().default(""),
3632
- description: z24.union([z24.string(), TiptapDocument, z24.null()]).default(
3649
+ var ImageContentBlock = z25.object({
3650
+ id: z25.string().optional().default(() => uuidv4()),
3651
+ name: z25.string().optional(),
3652
+ settings: z25.object({
3653
+ alt: z25.string().optional().default(""),
3654
+ description: z25.union([z25.string(), TiptapDocument, z25.null()]).default(
3633
3655
  "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."
3634
3656
  ),
3635
3657
  descriptionSize: TextSize.default("medium"),
3636
3658
  horizontalAlignment: TextAlignment2.default("leading"),
3637
- image: z24.union([z24.literal(""), z24.url()]).default(""),
3638
- imagePlacement: z24.enum(["bottom", "left", "right", "top"]).optional().default("left"),
3639
- imageSize: z24.number().default(20),
3640
- superTitle: z24.union([z24.string(), TiptapDocument]).default("Lorem Ipsum!"),
3659
+ image: z25.union([z25.literal(""), z25.url()]).default(""),
3660
+ imagePlacement: z25.enum(["bottom", "left", "right", "top"]).optional().default("left"),
3661
+ imageSize: z25.number().default(20),
3662
+ superTitle: z25.union([z25.string(), TiptapDocument]).default("Lorem Ipsum!"),
3641
3663
  superTitleSize: TextSize.default("medium"),
3642
3664
  /** This isn't configurable in the admin-nextjs editor */
3643
- swapContent: z24.boolean().optional().default(false),
3644
- title: z24.union([z24.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet"),
3665
+ swapContent: z25.boolean().optional().default(false),
3666
+ title: z25.union([z25.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet"),
3645
3667
  titleSize: TextSize.default("medium")
3646
3668
  }),
3647
- type: z24.literal(BlockType.image_content).default(BlockType.image_content)
3669
+ type: z25.literal(BlockType.image_content).default(BlockType.image_content)
3648
3670
  });
3649
- var PayButtonBlock = z24.object({
3650
- id: z24.string().optional().default(() => uuidv4()),
3651
- name: z24.string().optional(),
3652
- settings: z24.union([
3653
- z24.object({
3654
- label: z24.string().default("Pay Now")
3671
+ var PayButtonBlock = z25.object({
3672
+ id: z25.string().optional().default(() => uuidv4()),
3673
+ name: z25.string().optional(),
3674
+ settings: z25.union([
3675
+ z25.object({
3676
+ label: z25.string().default("Pay Now")
3655
3677
  }),
3656
- z24.array(z24.never()).transform(() => ({
3678
+ z25.array(z25.never()).transform(() => ({
3657
3679
  label: "Pay Now"
3658
3680
  }))
3659
3681
  ]),
3660
- styles: z24.union([
3661
- z24.object({
3662
- buttonWidth: z24.number().min(10).max(100).default(50)
3682
+ styles: z25.union([
3683
+ z25.object({
3684
+ buttonWidth: z25.number().min(10).max(100).default(50)
3663
3685
  }),
3664
- z24.array(z24.never()).transform(() => ({
3686
+ z25.array(z25.never()).transform(() => ({
3665
3687
  buttonWidth: 50
3666
3688
  }))
3667
3689
  ]),
3668
- type: z24.literal(BlockType.pay_button).default(BlockType.pay_button)
3690
+ type: z25.literal(BlockType.pay_button).default(BlockType.pay_button)
3669
3691
  });
3670
- var ProductInformationBlock = z24.object({
3692
+ var ProductInformationBlock = z25.object({
3671
3693
  /** This isn't configurable in the admin-nextjs editor */
3672
- hideProductImage: z24.boolean().optional().default(false),
3673
- id: z24.string().optional().default(() => uuidv4()),
3674
- name: z24.string().optional(),
3675
- type: z24.literal(BlockType.product_information).default(BlockType.product_information)
3694
+ hideProductImage: z25.boolean().optional().default(false),
3695
+ id: z25.string().optional().default(() => uuidv4()),
3696
+ name: z25.string().optional(),
3697
+ type: z25.literal(BlockType.product_information).default(BlockType.product_information)
3676
3698
  });
3677
- var SeparatorBlock = z24.object({
3678
- id: z24.string().optional().default(() => uuidv4()),
3679
- name: z24.string().optional(),
3680
- type: z24.literal(BlockType.separator).default(BlockType.separator)
3699
+ var SeparatorBlock = z25.object({
3700
+ id: z25.string().optional().default(() => uuidv4()),
3701
+ name: z25.string().optional(),
3702
+ type: z25.literal(BlockType.separator).default(BlockType.separator)
3681
3703
  });
3682
- var TextBlock = z24.object({
3683
- id: z24.string().optional().default(() => uuidv4()),
3684
- name: z24.string().optional(),
3685
- settings: z24.object({
3686
- description: z24.union([z24.string(), TiptapDocument]).optional().default(
3704
+ var TextBlock = z25.object({
3705
+ id: z25.string().optional().default(() => uuidv4()),
3706
+ name: z25.string().optional(),
3707
+ settings: z25.object({
3708
+ description: z25.union([z25.string(), TiptapDocument]).optional().default(
3687
3709
  "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."
3688
3710
  ),
3689
3711
  /** This isn't used in the post-purchase offer widget */
3690
3712
  descriptionSize: TextSize.default("medium"),
3691
3713
  horizontalAlignment: TextAlignment2.default("leading"),
3692
- superTitle: z24.union([z24.string(), TiptapDocument]).default("Super Title"),
3714
+ superTitle: z25.union([z25.string(), TiptapDocument]).default("Super Title"),
3693
3715
  /** This isn't used in the post-purchase offer widget */
3694
3716
  superTitleSize: TextSize.default("medium"),
3695
- title: z24.union([z24.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet."),
3717
+ title: z25.union([z25.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet."),
3696
3718
  /** This isn't used in the post-purchase offer widget */
3697
3719
  titleSize: TextSize.default("medium")
3698
3720
  }),
3699
- type: z24.literal(BlockType.text).default(BlockType.text)
3721
+ type: z25.literal(BlockType.text).default(BlockType.text)
3700
3722
  });
3701
- var TimerBlock = z24.object({
3702
- id: z24.string().optional().default(() => uuidv4()),
3703
- name: z24.string().optional(),
3704
- settings: z24.object({
3705
- durationMinutes: z24.number().min(0).default(10),
3706
- durationSeconds: z24.union([z24.number().min(0), z24.unknown().transform(() => 0)]).default(0),
3707
- endOffer: z24.boolean().default(true),
3708
- title: z24.union([z24.string(), TiptapDocument]).default("Hurry \u2014 your special offer ends in:")
3723
+ var TimerBlock = z25.object({
3724
+ id: z25.string().optional().default(() => uuidv4()),
3725
+ name: z25.string().optional(),
3726
+ settings: z25.object({
3727
+ durationMinutes: z25.number().min(0).default(10),
3728
+ durationSeconds: z25.union([z25.number().min(0), z25.unknown().transform(() => 0)]).default(0),
3729
+ endOffer: z25.boolean().default(true),
3730
+ title: z25.union([z25.string(), TiptapDocument]).default("Hurry \u2014 your special offer ends in:")
3709
3731
  }),
3710
- styles: z24.object({
3732
+ styles: z25.object({
3711
3733
  textAlignment: TextAlignment2.default("center"),
3712
- timerBackgroundColor: z24.enum(["info", "warning", "success", "critical"]).default("warning"),
3713
- timerEmphasized: z24.union([z24.boolean(), z24.unknown().transform(() => true)]).default(true),
3734
+ timerBackgroundColor: z25.enum(["info", "warning", "success", "critical"]).default("warning"),
3735
+ timerEmphasized: z25.union([z25.boolean(), z25.unknown().transform(() => true)]).default(true),
3714
3736
  timerSize: TextSize.default("medium"),
3715
- timerWidth: z24.number().min(10).max(100).optional().default(100),
3716
- titleEmphasized: z24.union([z24.boolean(), z24.unknown().transform(() => true)]).default(false),
3737
+ timerWidth: z25.number().min(10).max(100).optional().default(100),
3738
+ titleEmphasized: z25.union([z25.boolean(), z25.unknown().transform(() => true)]).default(false),
3717
3739
  titleSize: TextSize.default("medium")
3718
3740
  }),
3719
- type: z24.literal(BlockType.timer).default(BlockType.timer)
3741
+ type: z25.literal(BlockType.timer).default(BlockType.timer)
3720
3742
  });
3721
- var PostPurchaseBlock = z24.discriminatedUnion("type", [
3743
+ var PostPurchaseBlock = z25.discriminatedUnion("type", [
3722
3744
  CalloutBannerBlock,
3723
3745
  ImageBlock,
3724
3746
  ImageContentBlock,
@@ -3751,7 +3773,7 @@ var styledTextRun = (text, emphasized, size) => ({
3751
3773
  // src/transforms/postPurchase/convertCalloutBlock.ts
3752
3774
  var fields = ["superTitle", "title"];
3753
3775
  var Shell = CalloutBannerBlock.pick({ styles: true }).extend({
3754
- settings: z25.object({ superTitle: z25.unknown().optional(), title: z25.unknown().optional() })
3776
+ settings: z26.object({ superTitle: z26.unknown().optional(), title: z26.unknown().optional() })
3755
3777
  });
3756
3778
  var convertCalloutBlock = (raw, report) => {
3757
3779
  const omit = (detail) => {
@@ -3786,7 +3808,7 @@ var convertCalloutBlock = (raw, report) => {
3786
3808
  };
3787
3809
 
3788
3810
  // src/transforms/postPurchase/convertImageFrame.ts
3789
- import { z as z26 } from "zod";
3811
+ import { z as z27 } from "zod";
3790
3812
 
3791
3813
  // src/transforms/postPurchase/sizeImageSource.ts
3792
3814
  var sizeImageSource = (source, size) => {
@@ -3798,7 +3820,7 @@ var sizeImageSource = (source, size) => {
3798
3820
  };
3799
3821
 
3800
3822
  // src/transforms/postPurchase/convertImageFrame.ts
3801
- var Source = z26.url().default("https://cdn.shopify.com/s/files/1/0605/0555/5177/files/placeholder.jpg?v=1657762972");
3823
+ var Source = z27.url().default("https://cdn.shopify.com/s/files/1/0605/0555/5177/files/placeholder.jpg?v=1657762972");
3802
3824
  var DEFAULT_IMAGE_SIZE = 20;
3803
3825
  var convertImageFrame = (raw) => {
3804
3826
  const parsed = ImageBlock.shape.settings.options[0].safeParse(raw);
@@ -3844,7 +3866,7 @@ var convertImageBlock = (raw, report) => {
3844
3866
  };
3845
3867
 
3846
3868
  // src/transforms/postPurchase/convertImageContentBlock.ts
3847
- import { z as z28 } from "zod";
3869
+ import { z as z29 } from "zod";
3848
3870
 
3849
3871
  // src/transforms/postPurchase/convertImageContentText.ts
3850
3872
  var fields2 = ["superTitle", "title", "description"];
@@ -3874,7 +3896,7 @@ var convertImageContentText = (settings, report) => {
3874
3896
  };
3875
3897
 
3876
3898
  // src/transforms/postPurchase/imageContentSettings.ts
3877
- import { z as z27 } from "zod";
3899
+ import { z as z28 } from "zod";
3878
3900
  var ImageContentSettings = ImageContentBlock.shape.settings.pick({
3879
3901
  descriptionSize: true,
3880
3902
  horizontalAlignment: true,
@@ -3882,17 +3904,17 @@ var ImageContentSettings = ImageContentBlock.shape.settings.pick({
3882
3904
  swapContent: true,
3883
3905
  titleSize: true
3884
3906
  }).extend({
3885
- alt: z27.unknown().optional(),
3886
- description: z27.unknown().optional(),
3887
- image: z27.unknown().optional(),
3907
+ alt: z28.unknown().optional(),
3908
+ description: z28.unknown().optional(),
3909
+ image: z28.unknown().optional(),
3888
3910
  imagePlacement: ImageContentBlock.shape.settings.shape.imagePlacement.unwrap().nullable(),
3889
- imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(z27.number().positive()),
3890
- superTitle: z27.unknown().optional(),
3891
- title: z27.unknown().optional()
3911
+ imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(z28.number().positive()),
3912
+ superTitle: z28.unknown().optional(),
3913
+ title: z28.unknown().optional()
3892
3914
  });
3893
3915
 
3894
3916
  // src/transforms/postPurchase/convertImageContentBlock.ts
3895
- var Shell2 = z28.object({ settings: ImageContentSettings, type: z28.literal("image_content") });
3917
+ var Shell2 = z29.object({ settings: ImageContentSettings, type: z29.literal("image_content") });
3896
3918
  var PROPORTIONAL_BREAK_AT = 500;
3897
3919
  var convertImageContentBlock = (raw, report) => {
3898
3920
  const shell = Shell2.safeParse(raw);
@@ -3957,13 +3979,383 @@ var convertPayButtonBlock = (raw, report) => {
3957
3979
  ];
3958
3980
  };
3959
3981
 
3982
+ // src/transforms/postPurchase/productCardControls.ts
3983
+ var groupSelector = { sectionType: "variants", selector: "menu", variantMode: "productGroup" };
3984
+ var variantSelector = ({ productOptions }) => {
3985
+ if (!productOptions.showVariantSelectors) return [];
3986
+ const single = productOptions.variantSelectorDisplayMode === "single";
3987
+ return [
3988
+ {
3989
+ hideOutOfStockVariants: single || productOptions.hideOutOfStockVariants,
3990
+ sectionType: "variants",
3991
+ selector: "menu",
3992
+ variantMode: single ? "single" : "multiple"
3993
+ }
3994
+ ];
3995
+ };
3996
+ var quantity = ({ language, quantityInputs: quantityInputs2 }) => quantityInputs2.enabled ? [
3997
+ quantitySection({
3998
+ maxValue: quantityInputs2.maxValue,
3999
+ minValue: quantityInputs2.minValue,
4000
+ name: language.global.quantity.trim()
4001
+ })
4002
+ ] : [];
4003
+ var productCardControls = (settings) => [
4004
+ ...subscriptionToggle(settings.productType),
4005
+ groupSelector,
4006
+ ...variantSelector(settings),
4007
+ ...quantity(settings)
4008
+ ];
4009
+
4010
+ // src/transforms/postPurchase/productCardRows.ts
4011
+ var styledCopy = (text, look) => ({
4012
+ content: [{ content: [{ marks: [{ attrs: look, type: "textStyle" }], text, type: "text" }], type: "paragraph" }],
4013
+ type: "doc"
4014
+ });
4015
+ var merchantLabel = (value, fallback) => localizedContent({ en: fallback }, value);
4016
+ var boundText = (variable, content) => ({
4017
+ content,
4018
+ sectionType: "text",
4019
+ visibility: shownWhile(variable)
4020
+ });
4021
+ var earnedRow = ({ after, columns, label, look, spacing, token, variable }) => {
4022
+ const styled = (text) => look ? styledCopy(text, look) : text;
4023
+ const value = earnedText(variable, styled(token));
4024
+ return {
4025
+ direction: "grid",
4026
+ grid: { columns, rows: ["auto"] },
4027
+ sections: [
4028
+ boundText(variable, look ? { en: styled(String(label.en)) } : label),
4029
+ value,
4030
+ ...after === void 0 ? [] : [boundText(variable, { en: styled(String(after)) })]
4031
+ ],
4032
+ sectionType: "layout",
4033
+ ...spacing && { spacing }
4034
+ };
4035
+ };
4036
+ var earnedVariables = (names) => names.map((name) => ({ defaultValue: false, name }));
4037
+
4038
+ // src/transforms/postPurchase/productCardSettings.ts
4039
+ import { mapValues } from "es-toolkit";
4040
+ import { z as z32 } from "zod";
4041
+
4042
+ // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
4043
+ import { z as z31 } from "zod";
4044
+
4045
+ // src/schema/widgets/post-purchase-offer/common.ts
4046
+ import { replace, toNumber, toString } from "es-toolkit/compat";
4047
+ import { z as z30 } from "zod";
4048
+ var strictNumber = z30.union([
4049
+ z30.number(),
4050
+ z30.string().transform((value) => toNumber(replace(toString(value), /[^0-9.]/g, "")) || 0),
4051
+ z30.unknown().transform(() => 0)
4052
+ ]);
4053
+
4054
+ // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
4055
+ var PostPurchaseSettings = z31.object({
4056
+ advance: z31.object({ removePartialOrder: z31.boolean().default(true) }).optional().default(() => ({ removePartialOrder: true })),
4057
+ blocks: z31.union([z31.array(PostPurchaseBlock), z31.unknown().transform(() => [])]).default(() => [
4058
+ PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.timer }),
4059
+ PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.callout_banner }),
4060
+ PostPurchaseBlock.parse({ type: BlockType.product_information })
4061
+ ]),
4062
+ columnLayout: z31.boolean().optional(),
4063
+ discount: z31.object({
4064
+ amount: strictNumber.default(30),
4065
+ shouldShowSavingText: z31.boolean().optional().default(true),
4066
+ type: z31.enum(["none", "fixed_amount", "percentage"]).default("none")
4067
+ }),
4068
+ discountedFrom: z31.enum(["price", "compare_at_price"]).optional().default("price"),
4069
+ endpoint: z31.string().optional(),
4070
+ integrations: z31.object({
4071
+ judgeme: z31.boolean().default(false),
4072
+ junip: z31.boolean().optional().default(false),
4073
+ klaviyo: z31.boolean().default(false),
4074
+ loox: z31.boolean().default(false),
4075
+ okendo: z31.boolean().default(false),
4076
+ opinew: z31.boolean().optional().default(false),
4077
+ reviewsio: z31.boolean().optional().default(false),
4078
+ stamped: z31.boolean().default(false),
4079
+ yotpo: z31.boolean().default(false)
4080
+ }),
4081
+ key: z31.string().optional(),
4082
+ language: z31.object({
4083
+ description: z31.union([z31.string(), z31.unknown().transform(() => "")]).default(""),
4084
+ descriptionEnabled: z31.boolean().optional().default(false),
4085
+ descriptionRte: z31.object({
4086
+ content: z31.array(z31.unknown()),
4087
+ type: z31.string()
4088
+ }).optional(),
4089
+ descriptionSpacing: z31.enum(["none", "xtight", "tight", "default", "loose", "xloose"]).optional(),
4090
+ displayCtaPrice: z31.boolean().default(true),
4091
+ global: z31.object({
4092
+ declineAll: z31.string().optional().default("Decline All"),
4093
+ declineThisOffer: z31.string().default("Decline this offer"),
4094
+ free: z31.string().optional().default("Free"),
4095
+ notAvailable: z31.string().optional().default("Not available"),
4096
+ payNow: z31.string().default("Pay Now"),
4097
+ payNowUpgradeToSubscription: z31.string().optional().default("Upgrade to Subscription"),
4098
+ quantity: z31.string().default("Quantity"),
4099
+ /** This isn't configurable in the admin-nextjs editor */
4100
+ recurringShipping: z31.string().optional().default("Recurring shipping"),
4101
+ recurringSubtotal: z31.string().default("Recurring subtotal"),
4102
+ reviewsPlural: z31.string().optional().default("Reviews"),
4103
+ reviewsSingular: z31.string().optional().default("Review"),
4104
+ save: z31.union([z31.string(), z31.unknown().transform(() => "Save")]).optional().default("Save"),
4105
+ shipping: z31.string().default("Shipping"),
4106
+ subscriptionOption: z31.string().optional().default("Subscribe and Save"),
4107
+ subtotal: z31.string().default("Subtotal"),
4108
+ taxes: z31.string().default("Taxes"),
4109
+ total: z31.string().default("Total")
4110
+ }).optional().default(() => ({
4111
+ declineAll: "Decline All",
4112
+ declineThisOffer: "Decline this offer",
4113
+ free: "Free",
4114
+ notAvailable: "Not available",
4115
+ payNow: "Pay Now",
4116
+ payNowUpgradeToSubscription: "Upgrade to Subscription",
4117
+ quantity: "Quantity",
4118
+ /** This isn't configurable in the admin-nextjs editor */
4119
+ recurringShipping: "Recurring shipping",
4120
+ recurringSubtotal: "Recurring subtotal",
4121
+ reviewsPlural: "Reviews",
4122
+ reviewsSingular: "Review",
4123
+ save: "Save",
4124
+ shipping: "Shipping",
4125
+ subscriptionOption: "Subscribe and Save",
4126
+ subtotal: "Subtotal",
4127
+ taxes: "Taxes",
4128
+ total: "Total"
4129
+ })),
4130
+ globalTranslation: z31.string().optional().default("english")
4131
+ }),
4132
+ metafields: z31.boolean().default(false),
4133
+ /** This isn't configurable in the admin-nextjs editor */
4134
+ offer: z31.object({
4135
+ count: z31.number().default(1)
4136
+ }),
4137
+ offersLayout: z31.object({
4138
+ itemsPerPage: z31.number().optional(),
4139
+ type: z31.enum(["list", "grid", "carousel"]).default("list")
4140
+ }).optional().default({
4141
+ type: "list"
4142
+ }),
4143
+ /** This isn't configurable in the admin-nextjs editor */
4144
+ previewMode: z31.boolean().default(false),
4145
+ productLimit: z31.number().optional().default(1),
4146
+ productOptions: z31.object({
4147
+ /** This isn't configurable in the admin-nextjs editor */
4148
+ hideOutOfStockVariants: z31.boolean().optional().default(false),
4149
+ matchVariant: z31.boolean().optional().default(true),
4150
+ showDeclineAll: z31.enum(["above", "below", "both", "none"]).optional(),
4151
+ showShipping: z31.boolean().optional().default(true),
4152
+ showSubtotal: z31.boolean().optional().default(true),
4153
+ showTaxes: z31.boolean().optional().default(true),
4154
+ showTotal: z31.boolean().optional().default(true),
4155
+ showVariantSelectors: z31.boolean().optional().default(true),
4156
+ variantSelectorDisplayMode: z31.enum(["separate", "single"]).optional().default("separate")
4157
+ }),
4158
+ productType: z31.union([z31.enum(["one-time", "subscription", "both"]), z31.literal("").transform(() => "one-time")]).default("one-time"),
4159
+ productTypeSelector: z31.enum(["dropdown", "radio"]).optional().default("radio"),
4160
+ quantityInputs: z31.object({
4161
+ defaultQuantity: z31.union([z31.number(), z31.null().transform(() => 1)]).default(1),
4162
+ enabled: z31.boolean().default(true),
4163
+ maxValue: z31.union([z31.number(), z31.null().transform(() => 15)]).default(15),
4164
+ minValue: z31.union([z31.number().min(0), z31.unknown().transform(() => 0)]).default(1)
4165
+ }),
4166
+ shipping: z31.object({
4167
+ amount: strictNumber.default(10),
4168
+ /** This isn't configurable in the admin-nextjs editor */
4169
+ enabled: z31.boolean().default(true),
4170
+ title: z31.string().optional().default("Shipping Fees"),
4171
+ type: z31.enum(["free", "fixed_amount"]).default("free")
4172
+ }),
4173
+ styles: z31.object({
4174
+ starColor: z31.string().optional().default("#fadb14"),
4175
+ starSize: z31.union([z31.enum(["small", "medium", "large"]), z31.unknown().transform(() => "large")]).optional().default("large"),
4176
+ starStrokeColor: z31.string().optional().default("#fadb14"),
4177
+ strokeWidth: z31.string().optional().default("1")
4178
+ }).optional(),
4179
+ subImages: z31.number().nullish().default(8),
4180
+ subscription: z31.object({
4181
+ discount: z31.object({
4182
+ amount: strictNumber.default(30),
4183
+ shouldShowSavingText: z31.boolean().optional().default(true),
4184
+ type: z31.enum(["none", "fixed_amount", "percentage"]).default("none")
4185
+ }),
4186
+ shipping: z31.object({
4187
+ amount: strictNumber.default(1),
4188
+ /** This isn't configurable in the admin-nextjs editor */
4189
+ enabled: z31.boolean().default(true),
4190
+ /** This isn't configurable in the admin-nextjs editor */
4191
+ recurringAmount: strictNumber.default(2),
4192
+ shippingTitle: z31.string().default("Shipping Fees"),
4193
+ type: z31.enum(["free", "fixed_amount"]).default("free")
4194
+ })
4195
+ }).optional().default({
4196
+ discount: {
4197
+ amount: 30,
4198
+ shouldShowSavingText: true,
4199
+ type: "none"
4200
+ },
4201
+ shipping: {
4202
+ amount: 1,
4203
+ /** This isn't configurable in the admin-nextjs editor */
4204
+ enabled: true,
4205
+ /** This isn't configurable in the admin-nextjs editor */
4206
+ recurringAmount: 2,
4207
+ shippingTitle: "Shipping Fees",
4208
+ type: "free"
4209
+ }
4210
+ }),
4211
+ subscriptionIsDefault: z31.boolean().optional(),
4212
+ /** This isn't configurable in the admin-nextjs editor */
4213
+ template: z31.string().optional().default(""),
4214
+ type: z31.literal("shopify_post_purchase_extension").default("shopify_post_purchase_extension"),
4215
+ upgradeToSubscription: z31.object({
4216
+ acceptButtonText: z31.string().optional().default("Upgrade"),
4217
+ allow: z31.boolean().optional().default(false),
4218
+ emailRefundNotice: z31.boolean().optional().default(false),
4219
+ errorBannerText: z31.string().optional().default("This subscription cannot be added - limit one per order")
4220
+ }).optional().default(() => ({
4221
+ acceptButtonText: "Upgrade",
4222
+ allow: false,
4223
+ emailRefundNotice: false,
4224
+ errorBannerText: "This subscription cannot be added - limit one per order"
4225
+ }))
4226
+ });
4227
+
4228
+ // src/transforms/postPurchase/productCardSettings.ts
4229
+ var { shape } = PostPurchaseSettings;
4230
+ var Labels = z32.object(
4231
+ mapValues(shape.language.shape.global.unwrap().unwrap().shape, (label) => label.catch(() => label.parse(void 0)))
4232
+ );
4233
+ var Language = z32.object({ global: Labels.catch(() => Labels.parse({})) });
4234
+ var Fields = z32.object({
4235
+ discount: shape.discount.catch(() => shape.discount.parse({})),
4236
+ language: Language.catch(() => Language.parse({})),
4237
+ productOptions: shape.productOptions.catch(() => shape.productOptions.parse({})),
4238
+ productType: shape.productType.catch("one-time"),
4239
+ quantityInputs: shape.quantityInputs.catch(() => shape.quantityInputs.parse({})),
4240
+ subImages: shape.subImages.catch(null),
4241
+ subscription: shape.subscription.catch(() => shape.subscription.parse(void 0)),
4242
+ upgradeToSubscription: shape.upgradeToSubscription.catch(() => shape.upgradeToSubscription.parse(void 0))
4243
+ });
4244
+ var ProductCardSettings = Fields.catch(() => Fields.parse({}));
4245
+ var sellsSubscription = ({ productType, upgradeToSubscription }) => productType !== "one-time" || upgradeToSubscription.allow;
4246
+
4247
+ // src/transforms/postPurchase/productCardCosts.ts
4248
+ var COST_ROWS = [
4249
+ ["showSubtotal", "subtotal", "Subtotal", "hasSubtotal"],
4250
+ ["showShipping", "shipping", "Shipping", "hasShipping"],
4251
+ ["showTaxes", "taxes", "Taxes", "hasTaxes"],
4252
+ ["showTotal", "total", "Total", "hasTotal"]
4253
+ ];
4254
+ var costRows = ({ language, productOptions }) => {
4255
+ const rows = COST_ROWS.filter(([show]) => productOptions[show]);
4256
+ if (!rows.length) return [];
4257
+ return [
4258
+ {
4259
+ direction: "rows",
4260
+ name: "costs",
4261
+ sections: rows.map(
4262
+ ([, key, fallback, variable]) => earnedRow({
4263
+ columns: ["fill", "auto"],
4264
+ label: merchantLabel(language.global[key], fallback),
4265
+ token: `{{${key}}}`,
4266
+ variable
4267
+ })
4268
+ ),
4269
+ sectionType: "layout",
4270
+ spacing: "tight",
4271
+ variables: earnedVariables(rows.map(([, , , variable]) => variable))
4272
+ }
4273
+ ];
4274
+ };
4275
+ var HAS_RECURRING_TOTAL = "hasRecurringTotal";
4276
+ var HAS_RECURRING_SHIPPING = "hasRecurringShipping";
4277
+ var small = { color: "subdued", fontSize: "small" };
4278
+ var FOOTNOTES = ["Doesn't include tax, duties, or any applicable discounts.", "Auto-renews, skip or cancel anytime"];
4279
+ var recurringSummary = (settings) => {
4280
+ if (!sellsSubscription(settings)) return [];
4281
+ const { global } = settings.language;
4282
+ return [
4283
+ {
4284
+ direction: "rows",
4285
+ name: "recurring",
4286
+ sections: [
4287
+ earnedRow({
4288
+ after: "on every Delivery",
4289
+ columns: ["fill", "auto", "auto"],
4290
+ label: merchantLabel(global.recurringSubtotal, "Recurring subtotal"),
4291
+ spacing: "extraTight",
4292
+ token: "{{recurringTotal}}",
4293
+ variable: HAS_RECURRING_TOTAL
4294
+ }),
4295
+ earnedRow({
4296
+ after: "(included)",
4297
+ columns: ["auto", "auto", "auto"],
4298
+ label: { en: `${merchantLabel(global.recurringShipping, "Recurring shipping").en}:` },
4299
+ look: small,
4300
+ spacing: "extraTight",
4301
+ token: "{{recurringShipping}}",
4302
+ variable: HAS_RECURRING_SHIPPING
4303
+ }),
4304
+ ...FOOTNOTES.map((text) => ({
4305
+ content: { en: styledCopy(text, small) },
4306
+ sectionType: "text",
4307
+ visibility: shownWhile(HAS_RECURRING_TOTAL)
4308
+ }))
4309
+ ],
4310
+ sectionType: "layout",
4311
+ spacing: "tight",
4312
+ variables: earnedVariables([HAS_RECURRING_TOTAL, HAS_RECURRING_SHIPPING])
4313
+ }
4314
+ ];
4315
+ };
4316
+ var productCardCosts = (settings) => [
4317
+ ...costRows(settings),
4318
+ ...recurringSummary(settings)
4319
+ ];
4320
+
4321
+ // src/transforms/postPurchase/productCardPricing.ts
4322
+ import { capitalize } from "es-toolkit/compat";
4323
+ var HAS_SAVING = "hasSaving";
4324
+ var savingLine = (settings) => {
4325
+ const subscriptionSaving = sellsSubscription(settings) && settings.subscription.discount.shouldShowSavingText;
4326
+ if (!settings.discount.shouldShowSavingText && !subscriptionSaving) return [];
4327
+ return [
4328
+ {
4329
+ ...earnedRow({
4330
+ columns: ["auto", "auto"],
4331
+ label: merchantLabel(capitalize(settings.language.global.save), "Save"),
4332
+ look: { color: "success" },
4333
+ spacing: "extraTight",
4334
+ token: "{{variantSaving}}",
4335
+ variable: HAS_SAVING
4336
+ }),
4337
+ name: "saving",
4338
+ variables: earnedVariables([HAS_SAVING])
4339
+ }
4340
+ ];
4341
+ };
4342
+ var productCardPricing = (settings) => [
4343
+ priceText(),
4344
+ ...savingLine(settings)
4345
+ ];
4346
+
3960
4347
  // src/transforms/postPurchase/convertProductInformation.ts
3961
- var convertProductInformation = (raw, report) => {
4348
+ var thumbnails = ({ subImages }) => {
4349
+ const limit = Math.floor(subImages ?? 0);
4350
+ return limit >= 1 ? { thumbnails: { limit } } : {};
4351
+ };
4352
+ var convertProductInformation = (raw, report, widgetSettings) => {
3962
4353
  const block = ProductInformationBlock.safeParse(raw);
3963
4354
  if (!block.success) {
3964
4355
  report?.({ detail: "Unreadable post-purchase product information", kind: "section" });
3965
4356
  return [];
3966
4357
  }
4358
+ const settings = ProductCardSettings.parse(widgetSettings ?? {});
3967
4359
  return [
3968
4360
  CABOffersSection.parse({
3969
4361
  direction: "grid",
@@ -3976,7 +4368,11 @@ var convertProductInformation = (raw, report) => {
3976
4368
  direction: "grid",
3977
4369
  grid: { columns: [250] },
3978
4370
  sections: [
3979
- CABImageSection.parse({ altText: "{{productTitle}}", source: "{{productImage}}" })
4371
+ CABImageSection.parse({
4372
+ altText: "{{productTitle}}",
4373
+ source: "{{productImage}}",
4374
+ ...thumbnails(settings)
4375
+ })
3980
4376
  ],
3981
4377
  width: 90
3982
4378
  })
@@ -4000,8 +4396,11 @@ var convertProductInformation = (raw, report) => {
4000
4396
  }
4001
4397
  }
4002
4398
  }),
4399
+ ...productCardPricing(settings),
4003
4400
  CABReviewsSection.parse({}),
4004
- CABTextSection.parse({ content: { en: "{{productDescription}}" } })
4401
+ CABTextSection.parse({ content: { en: "{{productDescription}}" } }),
4402
+ ...productCardControls(settings),
4403
+ ...productCardCosts(settings)
4005
4404
  ]
4006
4405
  })
4007
4406
  ],
@@ -4021,7 +4420,7 @@ var convertSeparatorBlock = (raw, report) => {
4021
4420
  };
4022
4421
 
4023
4422
  // src/transforms/postPurchase/convertTextBlock.ts
4024
- import { z as z29 } from "zod";
4423
+ import { z as z33 } from "zod";
4025
4424
  var fields3 = ["superTitle", "title", "description"];
4026
4425
  var styles = {
4027
4426
  description: [{ attrs: { color: "base", fontSize: "small" }, type: "textStyle" }],
@@ -4029,13 +4428,13 @@ var styles = {
4029
4428
  title: [{ type: "bold" }, { attrs: { color: "base", fontSize: "large" }, type: "textStyle" }]
4030
4429
  };
4031
4430
  var settingsSchema = TextBlock.shape.settings;
4032
- var Shell3 = z29.object({
4431
+ var Shell3 = z33.object({
4033
4432
  settings: settingsSchema.pick({ horizontalAlignment: true }).extend({
4034
- description: z29.unknown().optional(),
4035
- superTitle: z29.unknown().optional(),
4036
- title: z29.unknown().optional()
4433
+ description: z33.unknown().optional(),
4434
+ superTitle: z33.unknown().optional(),
4435
+ title: z33.unknown().optional()
4037
4436
  }),
4038
- type: z29.literal("text")
4437
+ type: z33.literal("text")
4039
4438
  });
4040
4439
  var convertTextBlock = (raw, report) => {
4041
4440
  const shell = Shell3.safeParse(raw);
@@ -4107,11 +4506,11 @@ var convertTimerBlock = (raw, report) => {
4107
4506
  };
4108
4507
 
4109
4508
  // src/transforms/postPurchase/convertMessagePreview.ts
4110
- var MessageWidget = z30.object({
4111
- blocks: z30.array(z30.unknown()).min(1),
4112
- type: z30.literal(WidgetType.shopify_post_purchase_extension)
4509
+ var MessageWidget = z34.object({
4510
+ blocks: z34.array(z34.unknown()).min(1),
4511
+ type: z34.literal(WidgetType.shopify_post_purchase_extension)
4113
4512
  });
4114
- var BlockType2 = z30.object({ type: z30.string() });
4513
+ var BlockType2 = z34.object({ type: z34.string() });
4115
4514
  var converters = {
4116
4515
  callout_banner: convertCalloutBlock,
4117
4516
  image: convertImageBlock,
@@ -4132,7 +4531,7 @@ var convertMessagePreview = (id, settings, report) => {
4132
4531
  const type = BlockType2.safeParse(block);
4133
4532
  const kind = type.success ? type.data.type : void 0;
4134
4533
  const convert2 = kind && Object.hasOwn(converters, kind) ? converters[kind] : void 0;
4135
- if (convert2) return convert2(block, report);
4534
+ if (convert2) return convert2(block, report, settings);
4136
4535
  report?.({
4137
4536
  detail: kind ? `Unsupported post-purchase block type: ${kind}` : "Unreadable post-purchase block: missing type",
4138
4537
  kind: "section"