@rebuy/rebuy 3.59.0 → 3.60.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.
@@ -383,6 +383,10 @@ var OfferProductVariant = import_zod3.z.object({
383
383
  price: import_zod3.z.string(),
384
384
  title: import_zod3.z.string()
385
385
  });
386
+ var OfferProductReviews = import_zod3.z.object({
387
+ rating: import_zod3.z.number().positive().max(5),
388
+ reviewCount: import_zod3.z.number().int().nonnegative()
389
+ });
386
390
  var OfferProduct = import_zod3.z.object({
387
391
  description: import_zod3.z.string().optional(),
388
392
  discount: OfferProductDiscount.optional(),
@@ -398,6 +402,7 @@ var OfferProduct = import_zod3.z.object({
398
402
  link: import_zod3.z.string().optional(),
399
403
  metafields: import_zod3.z.array(import_zod3.z.object({ key: import_zod3.z.string(), namespace: import_zod3.z.string(), value: import_zod3.z.string() })).optional(),
400
404
  options: import_zod3.z.array(OfferProductOption),
405
+ reviews: OfferProductReviews.nullish().catch(void 0),
401
406
  sellingPlanGroups: import_zod3.z.array(import_zod3.z.object({ requiresSellingPlan: import_zod3.z.boolean().optional() })).optional(),
402
407
  title: import_zod3.z.string(),
403
408
  /** At least one variant — a zero-variant product renders an offer card with no addable merchandise (no Add CTA). `keepValidProduct` drops it with a `variants` drift signal rather than shipping a dead card. */
@@ -406,6 +411,27 @@ var OfferProduct = import_zod3.z.object({
406
411
 
407
412
  // src/server/b2bAvailability.ts
408
413
  var import_zod4 = require("zod");
414
+
415
+ // src/server/shared.ts
416
+ var REBUY_ENGINE_HOST = "rebuyengine.com";
417
+ var unwrapData = (body) => body && typeof body === "object" && "data" in body ? body.data : body;
418
+ var isEmptyObject = (x) => x == null || typeof x === "object" && !Array.isArray(x) && Object.keys(x).length === 0;
419
+ var UpstreamError = class extends Error {
420
+ constructor(status, body, message) {
421
+ super(message ?? `Upstream returned ${status}`);
422
+ this.body = body;
423
+ this.name = "UpstreamError";
424
+ this.status = status;
425
+ }
426
+ };
427
+ var NotFoundError = class extends Error {
428
+ constructor(message) {
429
+ super(message);
430
+ this.name = "NotFoundError";
431
+ }
432
+ };
433
+
434
+ // src/server/b2bAvailability.ts
409
435
  var B2B_AVAILABILITY_PATH = "/admin/api/v1/shop/b2b-catalog-availability";
410
436
  var productGid = (product) => `gid://shopify/Product/${String(product.id)}`;
411
437
  var Verdict = import_zod4.z.record(import_zod4.z.string(), import_zod4.z.boolean());
@@ -413,9 +439,18 @@ var B2bAvailabilityResponse = import_zod4.z.object({
413
439
  availability: Verdict.optional(),
414
440
  data: import_zod4.z.object({ availability: Verdict.optional() }).optional()
415
441
  }).transform(({ availability, data }) => availability ?? data?.availability ?? null);
442
+ var MAX_REASON_LENGTH = 120;
443
+ var failureReason = (error) => {
444
+ if (!(error instanceof Error)) return "unknown error";
445
+ const cut = error.message.indexOf(": ");
446
+ const label2 = (cut === -1 ? error.message : error.message.slice(0, cut)).slice(0, MAX_REASON_LENGTH);
447
+ if (!(error instanceof UpstreamError)) return label2 || error.name;
448
+ return label2 && label2 !== `Upstream returned ${error.status}` ? `upstream ${error.status}: ${label2}` : `upstream ${error.status}`;
449
+ };
416
450
  var filterByB2bAvailability = async (products, input, ctx) => {
417
451
  if (!input.companyLocationId || products.length === 0) return products;
418
452
  let verdict;
453
+ let reason = "unreadable verdict";
419
454
  try {
420
455
  const response = await ctx.fetchUpstream(
421
456
  B2B_AVAILABILITY_PATH,
@@ -434,12 +469,13 @@ var filterByB2bAvailability = async (products, input, ctx) => {
434
469
  );
435
470
  const parsed = B2bAvailabilityResponse.safeParse(response);
436
471
  verdict = parsed.success ? parsed.data : null;
437
- } catch {
472
+ } catch (error) {
438
473
  verdict = null;
474
+ reason = failureReason(error);
439
475
  }
440
476
  if (verdict === null) {
441
477
  ctx.reportDrift?.({
442
- detail: "b2b availability check failed \u2014 products served unfiltered",
478
+ detail: `b2b availability check failed (${reason}) \u2014 products served unfiltered`,
443
479
  kind: "b2bAvailability"
444
480
  });
445
481
  return products;
@@ -447,265 +483,48 @@ var filterByB2bAvailability = async (products, input, ctx) => {
447
483
  return products.filter((product) => verdict[productGid(product)] !== false);
448
484
  };
449
485
 
450
- // src/server/shared.ts
451
- var REBUY_ENGINE_HOST = "rebuyengine.com";
452
- var unwrapData = (body) => body && typeof body === "object" && "data" in body ? body.data : body;
453
- var isEmptyObject = (x) => x == null || typeof x === "object" && !Array.isArray(x) && Object.keys(x).length === 0;
454
- var UpstreamError = class extends Error {
455
- constructor(status, body, message) {
456
- super(message ?? `Upstream returned ${status}`);
457
- this.body = body;
458
- this.name = "UpstreamError";
459
- this.status = status;
460
- }
461
- };
462
- var NotFoundError = class extends Error {
463
- constructor(message) {
464
- super(message);
465
- this.name = "NotFoundError";
466
- }
467
- };
468
-
469
- // src/server/shopSubtotal.ts
470
- var shopCurrencyRate = (cart) => {
471
- const rate = cart.currencyRate ?? 1;
472
- return Number.isFinite(rate) && rate > 0 ? rate : 1;
473
- };
474
- var shopSubtotalCents = (cart) => Math.round((cart.subtotal - (cart.discountTotal ?? 0)) / shopCurrencyRate(cart));
475
- var toShopCents = (majorPresentment, rate) => Math.round(majorPresentment * 100 / rate);
486
+ // src/server/postPurchaseReviewData.ts
487
+ var import_zod17 = require("zod");
476
488
 
477
- // src/schema/cabShopConfig.ts
478
- var import_zod6 = require("zod");
489
+ // src/schema/postPurchaseProductReviews.ts
490
+ var import_zod12 = require("zod");
479
491
 
480
- // src/schema/driftedMarkets.ts
481
- var DRIFTED_MARKETS = Object.freeze({ enabled: false });
492
+ // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
493
+ var import_zod11 = require("zod");
482
494
 
483
- // src/schema/smartCart.ts
495
+ // src/schema/widgets/post-purchase-offer/common.ts
496
+ var import_compat = require("es-toolkit/compat");
484
497
  var import_zod5 = require("zod");
485
- var SmartCartTierProduct = import_zod5.z.looseObject({
486
- handle: import_zod5.z.string().optional(),
487
- id: import_zod5.z.coerce.number().optional(),
488
- productId: import_zod5.z.coerce.number().optional(),
489
- title: import_zod5.z.string().optional(),
490
- variantIds: import_zod5.z.array(import_zod5.z.coerce.number()).optional()
491
- });
492
- var SmartCartTierExclusion = import_zod5.z.looseObject({
493
- collectionIds: import_zod5.z.array(import_zod5.z.coerce.number()).optional().catch(void 0),
494
- productIds: import_zod5.z.array(import_zod5.z.coerce.number()).optional().catch(void 0),
495
- tags: import_zod5.z.array(import_zod5.z.string()).optional().catch(void 0),
496
- type: import_zod5.z.string().optional().catch(void 0)
497
- });
498
- var SmartCartTier = import_zod5.z.looseObject({
499
- allProducts: import_zod5.z.array(SmartCartTierProduct).optional(),
500
- /** Merchant-set tier label (e.g. "Free gift", "$100 reward"), shown on the step row when enabled. */
501
- customTierLabel: import_zod5.z.boolean().optional(),
502
- customTierLabelText: import_zod5.z.string().optional(),
503
- decorativeAmountReachedLabel: import_zod5.z.boolean().optional(),
504
- decorativeAmountReachedLabelText: import_zod5.z.string().optional(),
505
- decorativeAmountRemainingLabel: import_zod5.z.boolean().optional(),
506
- decorativeAmountRemainingLabelText: import_zod5.z.string().optional(),
507
- /** Order-discount reward: `'fixedAmount'` (shop-currency dollars) or `'percentage'` (whole percent). */
508
- discountAmountFromTotal: import_zod5.z.coerce.number().optional(),
509
- discountAmountReachedLabel: import_zod5.z.boolean().optional(),
510
- discountAmountReachedLabelText: import_zod5.z.string().optional(),
511
- discountAmountRemainingLabel: import_zod5.z.boolean().optional(),
512
- discountAmountRemainingLabelText: import_zod5.z.string().optional(),
513
- discountType: import_zod5.z.string().optional(),
514
- /**
515
- * onsite `exclusions` + `exclusions_enabled` (REB-22305): per-tier rules the converter carries onto
516
- * `CABProgressTier.exclusions`. `.catch(undefined)` for the same blast-radius reason as `productTierImage`:
517
- * one drifted value must degrade to "no tier exclusions", never drop every progress bar for the shop.
518
- *
519
- * `exclusionsEnabled` is a STRICT boolean on purpose, even though failing open here changes the tier's math
520
- * (a non-boolean reads as disabled) rather than just an icon. onsite reads its sibling tier flags strictly —
521
- * `shouldFilterOutOfStockVariantsFromTier` is `tier?.filter_oos_variants === true`, and its `progressBar.ts`
522
- * types every tier flag as `boolean` — so a stored `1` / `"1"` / `"true"` is "disabled" on the onsite bar too.
523
- * A truthiness preprocess would make CAB exclude where onsite does not: the opposite parity break.
524
- */
525
- exclusions: import_zod5.z.array(SmartCartTierExclusion).optional().catch(void 0),
526
- exclusionsEnabled: import_zod5.z.boolean().optional().catch(void 0),
527
- filterOosVariants: import_zod5.z.boolean().optional(),
528
- id: import_zod5.z.string().optional(),
529
- /**
530
- * A `null`/absent minimum stays `undefined` (NOT coerced to `0`): a threshold-0 tier is always reached
531
- * and would auto-add its gift to every cart. onsite's `isTierDataValid` drops a non-numeric minimum for
532
- * exactly this reason; the converter's `renderableTiers` mirrors that (`Number.isFinite`). A literal `0`
533
- * is kept — onsite keeps it too. DELIBERATE DIVERGENCE from onsite for string minimums: onsite's
534
- * `isTierDataValid` is a strict `typeof === 'number'`, so it drops `'50'`; the converter instead coerces
535
- * `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
536
- */
537
- minimum: import_zod5.z.preprocess((value) => value == null ? void 0 : value, import_zod5.z.coerce.number().optional()),
538
- presentmentCurrencies: import_zod5.z.looseObject({ enabled: import_zod5.z.boolean().optional() }).optional(),
539
- productAmountReachedLabel: import_zod5.z.boolean().optional(),
540
- productAmountReachedLabelText: import_zod5.z.string().optional(),
541
- productAmountRemainingLabel: import_zod5.z.boolean().optional(),
542
- productAmountRemainingLabelText: import_zod5.z.string().optional(),
543
- products: import_zod5.z.array(SmartCartTierProduct).optional(),
544
- /**
545
- * onsite `product_tier_element_size`: the step-row icon's square size as a px STRING (`'18px'` …
546
- * `'36px'` — the admin's five-value Size control, default `'18px'`). React stamps it onto the icon
547
- * SVG's `width`/`height` (`getProgressStepIconSize`), so the milestone renders at the merchant's
548
- * chosen size; the converter turns it into `CABProgressTier.iconSizePx` for the CAB renderer.
549
- *
550
- * `.catch(undefined)` for the same blast-radius reason as `productTierImage` below: this key was
551
- * previously unknown-and-ignored by the `looseObject`, and `SmartCartConfig` is parsed
552
- * `.nullish().catch(undefined)` with no intermediate catch, so one drifted value (a bare number, a
553
- * `'2rem'`) would drop EVERY progress bar for the shop rather than just this setting. Failing open to
554
- * `undefined` lands on the documented 18px default — strictly safer than that blast radius. The
555
- * converter parses the number out and clamps it, so a junk-but-string value degrades the same way.
556
- */
557
- productTierElementSize: import_zod5.z.string().optional().catch(void 0),
558
- /**
559
- * onsite `product_tier_image`: on a product (gift) tier, show the gift's product image in the step-row
560
- * slot instead of the generic bag icon (React `TierProgressIcon` swaps in the image when this is set and
561
- * an image resolves). Per-tier; the client resolves the image (config carries only product IDs).
562
- *
563
- * `.catch(undefined)` is load-bearing. This key was previously unknown-and-ignored by the `looseObject`;
564
- * declaring it as a real boolean means a stored non-boolean (`1` / `"1"` / `"true"`) would now FAIL the
565
- * tier — and since `SmartCartConfig` is parsed `.nullish().catch(undefined)` (userConfig/cabShopConfig)
566
- * with no intermediate catch, one drifted flag would drop EVERY progress bar for the shop, not just the
567
- * flag. The converter only reads it for truthiness (`gift && tier.productTierImage`), so failing open to
568
- * `undefined` (bag-icon fallback, the documented default) is strictly safer than that blast radius.
569
- */
570
- productTierImage: import_zod5.z.boolean().optional().catch(void 0),
571
- type: import_zod5.z.string().optional(),
572
- /**
573
- * onsite's PER-TIER unit switch (`unlock_condition_type`): `'item_quantity'` makes `minimum` an
574
- * item count (checked before any money handling — no ×100, no FX, no presentment overrides,
575
- * mirroring onsite `getTierMinimum`); anything else (or absent) keeps the money semantics.
576
- */
577
- unlockConditionType: import_zod5.z.string().optional()
578
- });
579
- var SmartCartBar = import_zod5.z.looseObject({
580
- countryCodes: import_zod5.z.array(import_zod5.z.string()).optional(),
581
- /**
582
- * onsite `exclude_discount_in_subtotal`: measure progress against the PRE-discount subtotal so an
583
- * applied code/order discount doesn't lower progress. The client adds cart discount allocations back.
584
- */
585
- excludeDiscountInSubtotal: import_zod5.z.boolean().optional(),
586
- /** Products excluded from the progress subtotal; the client subtracts their variants' cart cost. */
587
- excludedProducts: import_zod5.z.array(import_zod5.z.looseObject({ variantIds: import_zod5.z.array(import_zod5.z.coerce.number()).optional() })).optional(),
588
- freeShippingOnSubscription: import_zod5.z.boolean().optional(),
589
- geolocationEnabled: import_zod5.z.boolean().optional(),
590
- id: import_zod5.z.string().optional(),
591
- language: import_zod5.z.looseObject({
592
- freeShippingReached: import_zod5.z.string().optional(),
593
- freeShippingRemaining: import_zod5.z.string().optional(),
594
- giftAreaTitle: import_zod5.z.string().optional()
595
- }).optional(),
596
- name: import_zod5.z.string().optional(),
597
- tiers: import_zod5.z.array(SmartCartTier).optional()
598
- });
599
- var SmartCartComponent = import_zod5.z.looseObject({
600
- settings: import_zod5.z.looseObject({ bars: import_zod5.z.array(SmartCartBar).optional() }).optional(),
601
- type: import_zod5.z.string().optional()
602
- });
603
- var SmartCartConfig = import_zod5.z.looseObject({
604
- components: import_zod5.z.array(SmartCartComponent).optional()
605
- });
498
+ var strictNumber = import_zod5.z.union([
499
+ import_zod5.z.number(),
500
+ import_zod5.z.string().transform((value) => (0, import_compat.toNumber)((0, import_compat.replace)((0, import_compat.toString)(value), /[^0-9.]/g, "")) || 0),
501
+ import_zod5.z.unknown().transform(() => 0)
502
+ ]);
606
503
 
607
- // src/schema/cabShopConfig.ts
608
- var CabActiveExperiment = import_zod6.z.object({
609
- data: import_zod6.z.array(
610
- import_zod6.z.object({
611
- elementId: import_zod6.z.coerce.number(),
612
- id: import_zod6.z.coerce.number(),
613
- traffic: import_zod6.z.coerce.number()
614
- })
615
- ),
616
- id: import_zod6.z.coerce.number(),
617
- placeholderId: import_zod6.z.coerce.number().nullable(),
618
- type: import_zod6.z.string()
619
- });
620
- var CabShopConfig = import_zod6.z.object({
621
- /**
622
- * Per-element resilient: parse as `unknown[]` (non-array → `[]`), then keep only the experiments that
623
- * validate. A single drifted experiment drops itself instead of `.catch`-ing the WHOLE array to `[]` and
624
- * silently disabling every live A/B test fleet-wide.
625
- */
626
- activeExperiments: import_zod6.z.array(import_zod6.z.unknown()).catch([]).default([]).transform(
627
- (experiments) => experiments.flatMap((experiment) => {
628
- const result = CabActiveExperiment.safeParse(experiment);
629
- return result.success ? [result.data] : [];
630
- })
631
- ),
632
- /**
633
- * Only the two fields the smart-cart entitlement gate reads (`shortName`/`isActive`). Per-element
634
- * resilient like `activeExperiments`: a drifted package entry degrades to an inert `''`/false one that
635
- * matches nothing, so a real active `cart-merchandising` package still gates correctly and a sibling
636
- * drift never fails the shared config parse. Note the salvage is fail-CLOSED, not fail-open, for an
637
- * entitled v6 shop: a malformed whole array (⇒ `[]`) or an inerted `cart-merchandising` entry (e.g.
638
- * `is_active: 1` ⇒ inactive) makes the gate find no active package and drop every bar. That matches
639
- * React's "no proof of entitlement ⇒ render null", but it silently removes bars — so the server gate
640
- * ({@link file://../server/widgetSettings.ts} `fetchProgressBarContext`) emits a `shopConfig` drift
641
- * when it sees the inert-entry sentinel (`shortName === ''`). The whole-array `[]` case leaves no
642
- * sentinel and is not separately signalable here.
643
- */
644
- activePackages: import_zod6.z.array(import_zod6.z.object({ isActive: import_zod6.z.boolean(), shortName: import_zod6.z.string() }).catch({ isActive: false, shortName: "" })).catch([]).default([]),
645
- apiKey: import_zod6.z.string(),
646
- /** The shop's billing generation; the smart-cart entitlement gate only fires for `'v6'`. Missing/drift ⇒ `null` (fail open, ungated). */
647
- billingVersion: import_zod6.z.string().nullable().catch(null).default(null),
648
- /**
649
- * The shop's rotating cache-buster: `onsite_cache_key` internally — a unix timestamp the engine bumps,
650
- * and the edge copy of this config purges, on every widget/settings/theme edit — but serialized on the
651
- * wire as `cache_key`, which `deepCamelCase` maps to this field (renaming it `onsiteCacheKey` would
652
- * sever the mapping silently; the wire-level assertion in `userConfig.test.ts` is what fails loudly).
653
- * Threaded onto the widgets/settings read as `cache_key` so the engine marks the response
654
- * immutable-cacheable and the `cached.*` edge serves it fresh-by-URL. The engine sends a numeric
655
- * string — coerce — but admit only number/string inputs and constrain to a positive integer: a bare
656
- * coercion folds `null`/`''`/`false` to `0` and `true` to `1` — "valid" numbers that would go upstream
657
- * as a constant never-rotating buster and pin the edge copy permanently stale. A real key is always a
658
- * positive int sent as number or string, so everything else lands on `.catch()` and degrades that read
659
- * to un-busted (origin-served — slower, never stale), never a parse fail.
660
- */
661
- cacheKey: import_zod6.z.union([import_zod6.z.number(), import_zod6.z.string()]).transform((value) => Number(value)).pipe(import_zod6.z.number().int().positive()).optional().catch(void 0),
662
- /**
663
- * The shop's base-currency ISO code (e.g. `'USD'`). CAB derives the shop minor-unit exponent from it
664
- * (`currencyDecimals`) so a Functions-applied fixed discount — whose amount is in shop minor units —
665
- * converts to the buyer's currency exactly in a cross-decimal market. `.catch()` like its siblings: a
666
- * missing/renamed currency degrades to "unknown" (client falls back to buyer decimals), never a parse fail.
667
- */
668
- currency: import_zod6.z.string().optional().catch(void 0),
669
- /**
670
- * The merchant's "Use Markets in Data Sources" toggle. The engine (CI2) never reads it on the serve
671
- * path, so the proxy honouring it before sending market context is what makes the setting mean
672
- * anything (REB-21688). Fail-CLOSED, unlike the fail-open siblings: a missing/null/drifted field reads
673
- * as markets OFF — market context silently dropped (engine serves shop-default market), never sent
674
- * against the merchant's setting. The OFF-reading salvages stay distinguishable: missing AND null are
675
- * the engine's normal absent vocabulary (`.nullish()`, like `monetize`/`billingVersion`) and read as
676
- * the plain default — not drift — while only a drifted SHAPE `.catch`es, to the {@link DRIFTED_MARKETS}
677
- * identity sentinel, so `fetchUserConfig` can emit a `shopConfig` drift for the one case that means an
678
- * engine rename/retype; otherwise a markets-enabled merchant degrading to shop-default pricing would
679
- * be indistinguishable from markets genuinely off. The missing-key case is EXPLICIT via `.default()`
680
- * (a factory, so parses never share a mutable object) rather than inferred from zod running an
681
- * optional key's transform on `undefined`; `null` flows past the default through `.nullish()` into the
682
- * transform. `Readonly` on the output type because the drifted salvage IS frozen — an assignment to
683
- * `markets.enabled` downstream would throw only for drifted shops in production, so surface direct
684
- * writes to tsc (a guard for the direct case only: TS doesn't check `readonly` in assignability, so
685
- * laundering through a mutable-shaped alias still compiles).
686
- * The inner `enabled` stays strict on purpose: `{ enabled: null }` is a genuine retype and drifting is
687
- * the correct answer (the editor-path `ShopConfig.markets` would hard-fail the same payload).
688
- */
689
- markets: import_zod6.z.object({ enabled: import_zod6.z.boolean() }).nullish().catch(DRIFTED_MARKETS).default(() => ({ enabled: false })).transform((markets) => markets ?? { enabled: false }),
690
- monetize: import_zod6.z.object({ publisherKey: import_zod6.z.string().nullable() }).nullish().catch(void 0),
691
- shopId: import_zod6.z.number().optional().catch(void 0),
692
- /**
693
- * The merchant's display name ("Gift Basket Store") — the Monetize header copy reads it.
694
- * `.catch()` like its siblings: a missing/drifted name degrades the header to the
695
- * myshopify-domain slug (the pre-CAB React fallback), never a parse fail. An empty string is a
696
- * VALID parse — the slug fallback for `''` (and whitespace/tag-only names) lives in
697
- * composeOffer's `||` chain, not here.
698
- */
699
- shopName: import_zod6.z.string().nullish().catch(void 0)
700
- });
701
- var CabUserConfig = import_zod6.z.object({
702
- shop: CabShopConfig,
703
- smartCart: SmartCartConfig.nullish().catch(void 0)
704
- });
504
+ // src/schema/widgets/post-purchase-offer/constants.ts
505
+ var import_zod6 = require("zod");
506
+ var blockTypes = [
507
+ "callout_banner",
508
+ "image",
509
+ "image_content",
510
+ "pay_button",
511
+ "product_information",
512
+ "separator",
513
+ "text",
514
+ "timer"
515
+ ];
516
+ var blockType = import_zod6.z.enum(blockTypes);
517
+ var BlockType = blockType.enum;
705
518
 
706
- // src/schema/widgets/checkout-and-beyond/image.ts
707
- var import_uuid13 = require("uuid");
708
- var import_zod28 = require("zod");
519
+ // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
520
+ var import_compat4 = require("es-toolkit/compat");
521
+ var import_uuid2 = require("uuid");
522
+ var import_zod10 = require("zod");
523
+
524
+ // src/schema/widgets/checkout-and-beyond/text.ts
525
+ var import_compat3 = require("es-toolkit/compat");
526
+ var import_uuid = require("uuid");
527
+ var import_zod9 = require("zod");
709
528
 
710
529
  // src/schema/widgets/checkout-and-beyond/common.ts
711
530
  var freezeEnum = (values2) => Object.freeze(Object.fromEntries(values2.map((v) => [v, v])));
@@ -859,6 +678,7 @@ var sectionTypes = [
859
678
  "variants"
860
679
  ];
861
680
  var SectionType = freezeEnum(sectionTypes);
681
+ var SALVAGED_SECTION_TYPE = "unknown";
862
682
  var spacings = ["none", "extraTight", "tight", "base", "loose", "extraLoose"];
863
683
  var Spacing = freezeEnum(spacings);
864
684
  var textAlignments = ["start", "center", "end"];
@@ -909,34 +729,1092 @@ var widgetTypes = [
909
729
  ];
910
730
  var WidgetType = freezeEnum(widgetTypes);
911
731
 
912
- // src/schema/widgets/checkout-and-beyond/icons.ts
913
- var iconNames = [
914
- "alert-circle",
915
- "alert-triangle",
916
- "alert-triangle-filled",
917
- "arrow-down",
918
- "arrow-left",
919
- "arrow-right",
920
- "arrow-up",
921
- "arrow-up-right",
922
- "bag",
923
- "bullet",
924
- "calendar",
925
- "camera",
926
- "caret-down",
927
- "cart",
928
- "cash-dollar",
929
- "categories",
930
- "check",
931
- "check-circle",
932
- "check-circle-filled",
933
- "chevron-down",
934
- "chevron-left",
935
- "chevron-right",
936
- "chevron-up",
937
- "circle",
938
- "clipboard",
939
- "clock",
732
+ // src/schema/widgets/checkout-and-beyond/regex.ts
733
+ var DYNAMIC_TOKEN_REGEX = /^\{\{\s*[A-Za-z]+\s*\}\}$/;
734
+ var HEX_COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
735
+ var ROOT_RELATIVE_PATH_REGEX = /^\/(?!\/)/;
736
+ var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
737
+
738
+ // src/schema/widgets/checkout-and-beyond/utils.ts
739
+ var import_es_toolkit2 = require("es-toolkit");
740
+ var import_compat2 = require("es-toolkit/compat");
741
+
742
+ // src/transforms/convertNumericObjects.ts
743
+ var import_es_toolkit = require("es-toolkit");
744
+ var ARRAY_INDEX_STRING = /^(?:0|[1-9]\d*)$/;
745
+ var hasOnlyNumericKeys = (input, requireCompleteRun) => {
746
+ const keys = Object.keys(input);
747
+ if (keys.length === 0) return false;
748
+ if (!keys.every((key) => ARRAY_INDEX_STRING.test(key) && Number.isSafeInteger(Number(key)))) return false;
749
+ if (!requireCompleteRun) return true;
750
+ const sorted = keys.map(Number).sort((a, b) => a - b);
751
+ return sorted.every((n, i) => n === i);
752
+ };
753
+ var numericObjectToArray = (input) => Object.entries(input).sort(([a], [b]) => Number(a) - Number(b)).map(([, value]) => value);
754
+ var convert = (input, requireCompleteRun) => {
755
+ if (Array.isArray(input)) return input.map((item) => convert(item, requireCompleteRun));
756
+ if ((0, import_es_toolkit.isPlainObject)(input)) {
757
+ if (hasOnlyNumericKeys(input, requireCompleteRun)) {
758
+ return numericObjectToArray(input).map((item) => convert(item, requireCompleteRun));
759
+ }
760
+ const out = {};
761
+ for (const [key, value] of Object.entries(input)) out[key] = convert(value, requireCompleteRun);
762
+ return out;
763
+ }
764
+ return input;
765
+ };
766
+ var convertNumericObjects = (input) => convert(input, true);
767
+
768
+ // src/schema/widgets/checkout-and-beyond/utils.ts
769
+ var isHTML = (html = "") => {
770
+ if (typeof window !== "undefined") {
771
+ const parser = new DOMParser();
772
+ const doc = parser.parseFromString(html, "text/html");
773
+ const hasHTML = (nodeList) => Array.from(nodeList).some((node) => node.nodeType === 1);
774
+ return hasHTML(doc.body.childNodes) || hasHTML(doc.head.childNodes);
775
+ }
776
+ return html.search(HTML_TAGS_REGEX) !== -1;
777
+ };
778
+ var hasHTMLInDoc = (doc) => doc.content.some(({ content = [] }) => content.some(({ text: text2 }) => isHTML(text2)));
779
+ var checkForHTML = (input) => !((0, import_compat2.isString)(input) && isHTML(input) || (0, import_es_toolkit2.isPlainObject)(input) && hasHTMLInDoc(input));
780
+ var NO_HTML = { message: "HTML is not supported" };
781
+ var isSectionType = (sectionType) => (section) => (0, import_compat2.get)(section, "sectionType") === sectionType;
782
+ var isBannerType = isSectionType(SectionType.banner);
783
+ var isButtonType = isSectionType(SectionType.button);
784
+ var isCarouselType = isSectionType(SectionType.carousel);
785
+ var isCartLineType = isSectionType(SectionType.cartLine);
786
+ var isDataSourceType = isSectionType(
787
+ SectionType.dataSource
788
+ );
789
+ var isDiscountType = isSectionType(SectionType.discount);
790
+ var isImageType = isSectionType(SectionType.image);
791
+ var isLayoutType = isSectionType(SectionType.layout);
792
+ var isMonetizeType = isSectionType(SectionType.monetize);
793
+ var isOffersType = isSectionType(SectionType.offers);
794
+ var isProductType = isSectionType(SectionType.product);
795
+ var isProductsType = isSectionType(SectionType.products);
796
+ var isProgressBarType = isSectionType(
797
+ SectionType.progressBar
798
+ );
799
+ var isQuantityType = isSectionType(SectionType.quantity);
800
+ var isReviewsType = isSectionType(SectionType.reviews);
801
+ var isTextType = isSectionType(SectionType.text);
802
+ var isVariantsType = isSectionType(SectionType.variants);
803
+
804
+ // src/schema/widgets/checkout-and-beyond/variables.ts
805
+ var import_zod8 = require("zod");
806
+
807
+ // src/schema/widgets/checkout-and-beyond/rule.ts
808
+ var import_zod7 = require("zod");
809
+ var ruleTypes = [
810
+ "cart",
811
+ "cart_count",
812
+ "cart_item_count",
813
+ "cart_line_count",
814
+ "cart_subtotal",
815
+ "collection",
816
+ "customer",
817
+ "customer_order_count",
818
+ "customer_tag",
819
+ "customer_total_spent",
820
+ "date",
821
+ "product",
822
+ "product_tag",
823
+ "product_title",
824
+ "product_type",
825
+ "product_vendor"
826
+ ];
827
+ var ruleType = import_zod7.z.enum(ruleTypes);
828
+ var RuleType = ruleType.enum;
829
+ var ruleOperators = [
830
+ "after",
831
+ "anything",
832
+ "before",
833
+ "contains",
834
+ "contains_any",
835
+ "does_not_contain",
836
+ "does_not_contain_any",
837
+ "equals",
838
+ "does_not_equal",
839
+ "greater_than",
840
+ "less_than"
841
+ ];
842
+ var ruleOperator = import_zod7.z.enum(ruleOperators);
843
+ var RuleOperator = ruleOperator.enum;
844
+ var RuleCondition = import_zod7.z.object({
845
+ operator: import_zod7.z.enum(ruleOperators).default(RuleOperator.anything),
846
+ products: import_zod7.z.union([import_zod7.z.array(import_zod7.z.unknown()), import_zod7.z.strictObject({}).transform(() => [])]).default(() => []),
847
+ type: import_zod7.z.enum(ruleTypes).default(RuleType.cart_subtotal),
848
+ value: import_zod7.z.coerce.string().default("")
849
+ });
850
+ var RuleLogicBlock = import_zod7.z.object({
851
+ rules: import_zod7.z.array(RuleCondition).default(() => [])
852
+ });
853
+ var CABRulesetEntry = import_zod7.z.object({
854
+ exitIfMatched: import_zod7.z.boolean().default(true),
855
+ logic: import_zod7.z.array(RuleLogicBlock).default(() => []),
856
+ output: import_zod7.z.array(
857
+ import_zod7.z.object({
858
+ key: import_zod7.z.string().default("should_show"),
859
+ type: import_zod7.z.literal("data_json").default("data_json"),
860
+ value: import_zod7.z.string().default("true")
861
+ })
862
+ ).default(() => [{ key: "should_show", type: "data_json", value: "true" }])
863
+ });
864
+ var CABRuleset = import_zod7.z.union([import_zod7.z.array(CABRulesetEntry), import_zod7.z.strictObject({}).transform(() => [])]).default(() => []);
865
+
866
+ // src/schema/widgets/checkout-and-beyond/variables.ts
867
+ var variableEffect = import_zod8.z.enum(variableEffects);
868
+ var CABVariableSeed = import_zod8.z.object({
869
+ dataSourceId: import_zod8.z.number().nullable().default(null),
870
+ ruleset: CABRuleset
871
+ });
872
+ var CABBooleanVariable = import_zod8.z.object({
873
+ /**
874
+ * Holds until the first seed verdict lands (and forever, for unseeded variables). Omitted, it derives
875
+ * from seededness — `false` with a `seed` (visibility is EARNED), `true` without — via the transform
876
+ * below; a cross-field default has no `.default()` spelling. An explicit value always wins.
877
+ */
878
+ defaultValue: import_zod8.z.boolean().optional(),
879
+ name: import_zod8.z.string().min(1),
880
+ seed: CABVariableSeed.optional(),
881
+ /** Defaulted so every stored declaration (all boolean before `text` existed) parses unchanged. */
882
+ type: import_zod8.z.literal(VariableType.boolean).default(VariableType.boolean)
883
+ });
884
+ var CABTextVariable = import_zod8.z.object({
885
+ defaultValue: import_zod8.z.string(),
886
+ name: import_zod8.z.string().min(1),
887
+ seed: import_zod8.z.never().optional(),
888
+ type: import_zod8.z.literal(VariableType.text)
889
+ });
890
+ var CABNumberVariable = import_zod8.z.object({
891
+ defaultValue: import_zod8.z.number(),
892
+ name: import_zod8.z.string().min(1),
893
+ seed: import_zod8.z.never().optional(),
894
+ type: import_zod8.z.literal(VariableType.number)
895
+ });
896
+ var CABVariable = import_zod8.z.union([CABTextVariable, CABNumberVariable, CABBooleanVariable]).transform(
897
+ (variable) => variable.type === VariableType.boolean ? { ...variable, defaultValue: variable.defaultValue ?? variable.seed === void 0 } : variable
898
+ );
899
+ var CABVariableEffect = import_zod8.z.object({
900
+ effect: variableEffect.default(VariableEffect.toggle),
901
+ variable: import_zod8.z.string().min(1)
902
+ });
903
+ var CABVisibility = import_zod8.z.object({
904
+ variable: import_zod8.z.string().min(1),
905
+ visibleWhen: import_zod8.z.boolean().default(true)
906
+ });
907
+ var contentOperator = import_zod8.z.enum(contentOperators);
908
+ var resultCountOperator = import_zod8.z.enum(resultCountOperators);
909
+ var resultTagOperator = import_zod8.z.enum(resultTagOperators);
910
+ var mutatorEvent = import_zod8.z.enum(mutatorEvents);
911
+ var CABContentTrigger = import_zod8.z.object({
912
+ operator: contentOperator.default(ContentOperator.is_empty),
913
+ type: import_zod8.z.literal("content")
914
+ });
915
+ var CABResultCountTrigger = import_zod8.z.object({
916
+ operator: resultCountOperator.default(ResultCountOperator.equals),
917
+ type: import_zod8.z.literal("result_count"),
918
+ value: import_zod8.z.number().default(0)
919
+ });
920
+ var CABResultTagTrigger = import_zod8.z.object({
921
+ operator: resultTagOperator.default(ResultTagOperator.contains),
922
+ type: import_zod8.z.literal("result_tag"),
923
+ value: import_zod8.z.string().min(1)
924
+ });
925
+ var CABEventTrigger = import_zod8.z.object({
926
+ event: mutatorEvent,
927
+ type: import_zod8.z.literal("event")
928
+ });
929
+ var CABVariableTrigger = import_zod8.z.discriminatedUnion("type", [
930
+ CABContentTrigger,
931
+ CABEventTrigger,
932
+ CABResultCountTrigger,
933
+ CABResultTagTrigger
934
+ ]);
935
+ var CABVariableMutator = import_zod8.z.object({
936
+ effect: variableEffect.default(VariableEffect.set_false),
937
+ variable: import_zod8.z.string().min(1),
938
+ when: CABVariableTrigger
939
+ });
940
+ var CABVariableFields = {
941
+ mutators: import_zod8.z.array(CABVariableMutator).optional(),
942
+ variables: import_zod8.z.array(CABVariable).refine((variables) => new Set(variables.map(({ name }) => name)).size === variables.length, {
943
+ message: "variable names must be unique within a section"
944
+ }).optional(),
945
+ visibility: CABVisibility.optional()
946
+ };
947
+
948
+ // src/schema/widgets/checkout-and-beyond/text.ts
949
+ var enumOrOmit = (...vals) => import_zod9.z.string().transform((val) => vals.includes(val) ? val : void 0).optional();
950
+ var TiptapText = import_zod9.z.object({
951
+ marks: import_zod9.z.union([
952
+ import_zod9.z.array(
953
+ import_zod9.z.discriminatedUnion("type", [
954
+ import_zod9.z.object({ type: import_zod9.z.literal("bold") }),
955
+ import_zod9.z.object({ type: import_zod9.z.literal("italic") }),
956
+ import_zod9.z.object({
957
+ attrs: import_zod9.z.object({
958
+ class: import_zod9.z.string().nullable(),
959
+ href: import_zod9.z.union([
960
+ import_zod9.z.url(),
961
+ import_zod9.z.literal("#"),
962
+ import_zod9.z.string().regex(DYNAMIC_TOKEN_REGEX),
963
+ import_zod9.z.string().regex(ROOT_RELATIVE_PATH_REGEX)
964
+ ]),
965
+ rel: import_zod9.z.string().default("noopener noreferrer nofollow"),
966
+ target: import_zod9.z.string().default("_blank")
967
+ }),
968
+ type: import_zod9.z.literal("link")
969
+ }),
970
+ import_zod9.z.object({ type: import_zod9.z.literal("strike") }),
971
+ import_zod9.z.object({
972
+ attrs: import_zod9.z.object({
973
+ color: enumOrOmit(...textColorNames).default(TextColorName.base),
974
+ fontSize: enumOrOmit(...textSizeNames).default(TextSizeName.base)
975
+ }),
976
+ type: import_zod9.z.literal("textStyle")
977
+ })
978
+ ])
979
+ ),
980
+ import_zod9.z.strictObject({}).transform(() => [])
981
+ ]).optional(),
982
+ text: import_zod9.z.string().default(""),
983
+ type: import_zod9.z.literal("text").default("text")
984
+ });
985
+ var TiptapParagraph = import_zod9.z.object({
986
+ attrs: import_zod9.z.object({
987
+ textAlign: enumOrOmit(...textAlignments)
988
+ }).default({ textAlign: TextAlignment.start }),
989
+ content: import_zod9.z.union([import_zod9.z.array(TiptapText), import_zod9.z.strictObject({}).transform(() => [])]).default(() => []),
990
+ type: import_zod9.z.literal("paragraph").default("paragraph")
991
+ });
992
+ var TiptapDocument = import_zod9.z.object({
993
+ attrs: import_zod9.z.object({
994
+ blockSpacing: enumOrOmit(...spacings)
995
+ }).default({ blockSpacing: Spacing.base }),
996
+ content: import_zod9.z.union([import_zod9.z.array(TiptapParagraph), import_zod9.z.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
997
+ type: import_zod9.z.literal("doc").default("doc")
998
+ });
999
+ var CABTextTier = import_zod9.z.object({
1000
+ threshold: import_zod9.z.number().int().nonnegative(),
1001
+ thresholds: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.number().int().nonnegative()).default(() => ({})),
1002
+ tierId: import_zod9.z.string().optional(),
1003
+ tierType: import_zod9.z.enum(progressTierTypes).default(ProgressTierType.shipping)
1004
+ });
1005
+ var CABTextSection = import_zod9.z.object({
1006
+ ...CABVariableFields,
1007
+ buttonField: import_zod9.z.enum(buttonFields).optional(),
1008
+ content: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.union([import_zod9.z.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
1009
+ name: import_zod9.z.string().optional(),
1010
+ optionId: import_zod9.z.number().optional(),
1011
+ sectionId: import_zod9.z.uuid().default(() => (0, import_uuid.v7)()),
1012
+ sectionType: import_zod9.z.literal(SectionType.text).default(SectionType.text),
1013
+ tier: CABTextTier.optional()
1014
+ }).superRefine(({ buttonField, content }, ctx) => {
1015
+ if (buttonField === ButtonField.destinationUrl && content) {
1016
+ (0, import_compat3.forEach)(content, (value, lang) => {
1017
+ if (value && (0, import_compat3.isString)(value)) {
1018
+ if (DYNAMIC_TOKEN_REGEX.test(value)) return;
1019
+ try {
1020
+ new URL(value);
1021
+ } catch {
1022
+ ctx.addIssue({
1023
+ code: "custom",
1024
+ message: "Invalid URL",
1025
+ path: ["content", lang]
1026
+ });
1027
+ }
1028
+ }
1029
+ });
1030
+ }
1031
+ });
1032
+
1033
+ // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
1034
+ var TextAlignment2 = import_zod10.z.union([import_zod10.z.enum(["leading", "center", "trailing"]), import_zod10.z.unknown().transform(() => "leading")]);
1035
+ var TextSize = import_zod10.z.union([
1036
+ import_zod10.z.enum(["xsmall", "small", "base", "default", "medium", "large", "xlarge"]),
1037
+ import_zod10.z.unknown().transform(() => "medium")
1038
+ ]);
1039
+ var CalloutBannerBlock = import_zod10.z.object({
1040
+ id: import_zod10.z.string().optional().default(() => (0, import_uuid2.v4)()),
1041
+ name: import_zod10.z.string().optional(),
1042
+ settings: import_zod10.z.object({
1043
+ superTitle: import_zod10.z.union([import_zod10.z.string(), TiptapDocument]).default(() => "Limited-time Offer"),
1044
+ title: import_zod10.z.union([import_zod10.z.string(), TiptapDocument]).default(() => "Add this customer favorite to your order")
1045
+ }),
1046
+ styles: import_zod10.z.object({
1047
+ superTitleEmphasized: import_zod10.z.boolean().default(false),
1048
+ superTitleSize: TextSize.default("large"),
1049
+ textAlignment: TextAlignment2.default("center"),
1050
+ titleEmphasized: import_zod10.z.boolean().default(true),
1051
+ titleSize: TextSize.default("large")
1052
+ }),
1053
+ type: import_zod10.z.literal(BlockType.callout_banner).default(BlockType.callout_banner)
1054
+ });
1055
+ var ImageBlock = import_zod10.z.object({
1056
+ id: import_zod10.z.string().optional().default(() => (0, import_uuid2.v4)()),
1057
+ name: import_zod10.z.string().optional(),
1058
+ settings: import_zod10.z.union([
1059
+ import_zod10.z.object({
1060
+ /** This isn't used in the post-purchase offer widget */
1061
+ alt: import_zod10.z.string().optional().default(""),
1062
+ image: import_zod10.z.union([import_zod10.z.literal(""), import_zod10.z.url()]).default(""),
1063
+ imageSize: import_zod10.z.number().default(20),
1064
+ imageType: import_zod10.z.enum(["URL", "UPLOAD"]).default("URL")
1065
+ }),
1066
+ import_zod10.z.array(import_zod10.z.never()).transform(() => ({}))
1067
+ ]),
1068
+ type: import_zod10.z.literal(BlockType.image).default(BlockType.image)
1069
+ });
1070
+ var ImageContentBlock = import_zod10.z.object({
1071
+ id: import_zod10.z.string().optional().default(() => (0, import_uuid2.v4)()),
1072
+ name: import_zod10.z.string().optional(),
1073
+ settings: import_zod10.z.object({
1074
+ alt: import_zod10.z.string().optional().default(""),
1075
+ description: import_zod10.z.union([import_zod10.z.string(), TiptapDocument, import_zod10.z.null()]).default(
1076
+ "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."
1077
+ ),
1078
+ descriptionSize: TextSize.default("medium"),
1079
+ horizontalAlignment: TextAlignment2.default("leading"),
1080
+ image: import_zod10.z.union([import_zod10.z.literal(""), import_zod10.z.url()]).default(""),
1081
+ imagePlacement: import_zod10.z.enum(["bottom", "left", "right", "top"]).optional().default("left"),
1082
+ imageSize: import_zod10.z.number().default(20),
1083
+ superTitle: import_zod10.z.union([import_zod10.z.string(), TiptapDocument]).default("Lorem Ipsum!"),
1084
+ superTitleSize: TextSize.default("medium"),
1085
+ /** This isn't configurable in the admin-nextjs editor */
1086
+ swapContent: import_zod10.z.boolean().optional().default(false),
1087
+ title: import_zod10.z.union([import_zod10.z.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet"),
1088
+ titleSize: TextSize.default("medium")
1089
+ }),
1090
+ type: import_zod10.z.literal(BlockType.image_content).default(BlockType.image_content)
1091
+ });
1092
+ var PayButtonBlock = import_zod10.z.object({
1093
+ id: import_zod10.z.string().optional().default(() => (0, import_uuid2.v4)()),
1094
+ name: import_zod10.z.string().optional(),
1095
+ settings: import_zod10.z.union([
1096
+ import_zod10.z.object({
1097
+ label: import_zod10.z.string().default("Pay Now")
1098
+ }),
1099
+ import_zod10.z.array(import_zod10.z.never()).transform(() => ({
1100
+ label: "Pay Now"
1101
+ }))
1102
+ ]),
1103
+ styles: import_zod10.z.union([
1104
+ import_zod10.z.object({
1105
+ buttonWidth: import_zod10.z.number().min(10).max(100).default(50)
1106
+ }),
1107
+ import_zod10.z.array(import_zod10.z.never()).transform(() => ({
1108
+ buttonWidth: 50
1109
+ }))
1110
+ ]),
1111
+ type: import_zod10.z.literal(BlockType.pay_button).default(BlockType.pay_button)
1112
+ });
1113
+ var ProductInformationBlock = import_zod10.z.object({
1114
+ /** This isn't configurable in the admin-nextjs editor */
1115
+ hideProductImage: import_zod10.z.boolean().optional().default(false),
1116
+ id: import_zod10.z.string().optional().default(() => (0, import_uuid2.v4)()),
1117
+ name: import_zod10.z.string().optional(),
1118
+ type: import_zod10.z.literal(BlockType.product_information).default(BlockType.product_information)
1119
+ });
1120
+ var SeparatorBlock = import_zod10.z.object({
1121
+ id: import_zod10.z.string().optional().default(() => (0, import_uuid2.v4)()),
1122
+ name: import_zod10.z.string().optional(),
1123
+ type: import_zod10.z.literal(BlockType.separator).default(BlockType.separator)
1124
+ });
1125
+ var TextBlock = import_zod10.z.object({
1126
+ id: import_zod10.z.string().optional().default(() => (0, import_uuid2.v4)()),
1127
+ name: import_zod10.z.string().optional(),
1128
+ settings: import_zod10.z.object({
1129
+ description: import_zod10.z.union([import_zod10.z.string(), TiptapDocument]).optional().default(
1130
+ "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."
1131
+ ),
1132
+ /** This isn't used in the post-purchase offer widget */
1133
+ descriptionSize: TextSize.default("medium"),
1134
+ horizontalAlignment: TextAlignment2.default("leading"),
1135
+ superTitle: import_zod10.z.union([import_zod10.z.string(), TiptapDocument]).default("Super Title"),
1136
+ /** This isn't used in the post-purchase offer widget */
1137
+ superTitleSize: TextSize.default("medium"),
1138
+ title: import_zod10.z.union([import_zod10.z.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet."),
1139
+ /** This isn't used in the post-purchase offer widget */
1140
+ titleSize: TextSize.default("medium")
1141
+ }),
1142
+ type: import_zod10.z.literal(BlockType.text).default(BlockType.text)
1143
+ });
1144
+ var TimerBlock = import_zod10.z.object({
1145
+ id: import_zod10.z.string().optional().default(() => (0, import_uuid2.v4)()),
1146
+ name: import_zod10.z.string().optional(),
1147
+ settings: import_zod10.z.object({
1148
+ durationMinutes: import_zod10.z.number().min(0).default(10),
1149
+ durationSeconds: import_zod10.z.union([import_zod10.z.number().min(0), import_zod10.z.unknown().transform(() => 0)]).default(0),
1150
+ endOffer: import_zod10.z.boolean().default(true),
1151
+ title: import_zod10.z.union([import_zod10.z.string(), TiptapDocument]).default("Hurry \u2014 your special offer ends in:")
1152
+ }),
1153
+ styles: import_zod10.z.object({
1154
+ textAlignment: TextAlignment2.default("center"),
1155
+ timerBackgroundColor: import_zod10.z.enum(["info", "warning", "success", "critical"]).default("warning"),
1156
+ timerEmphasized: import_zod10.z.union([import_zod10.z.boolean(), import_zod10.z.unknown().transform(() => true)]).default(true),
1157
+ timerSize: TextSize.default("medium"),
1158
+ timerWidth: import_zod10.z.number().min(10).max(100).optional().default(100),
1159
+ titleEmphasized: import_zod10.z.union([import_zod10.z.boolean(), import_zod10.z.unknown().transform(() => true)]).default(false),
1160
+ titleSize: TextSize.default("medium")
1161
+ }),
1162
+ type: import_zod10.z.literal(BlockType.timer).default(BlockType.timer)
1163
+ });
1164
+ var PostPurchaseBlock = import_zod10.z.discriminatedUnion("type", [
1165
+ CalloutBannerBlock,
1166
+ ImageBlock,
1167
+ ImageContentBlock,
1168
+ PayButtonBlock,
1169
+ ProductInformationBlock,
1170
+ SeparatorBlock,
1171
+ TextBlock,
1172
+ TimerBlock
1173
+ ]);
1174
+
1175
+ // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
1176
+ var PostPurchaseSettings = import_zod11.z.object({
1177
+ advance: import_zod11.z.object({ removePartialOrder: import_zod11.z.boolean().default(true) }).optional().default(() => ({ removePartialOrder: true })),
1178
+ blocks: import_zod11.z.union([import_zod11.z.array(PostPurchaseBlock), import_zod11.z.unknown().transform(() => [])]).default(() => [
1179
+ PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.timer }),
1180
+ PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.callout_banner }),
1181
+ PostPurchaseBlock.parse({ type: BlockType.product_information })
1182
+ ]),
1183
+ columnLayout: import_zod11.z.boolean().optional(),
1184
+ discount: import_zod11.z.object({
1185
+ amount: strictNumber.default(30),
1186
+ shouldShowSavingText: import_zod11.z.boolean().optional().default(true),
1187
+ type: import_zod11.z.enum(["none", "fixed_amount", "percentage"]).default("none")
1188
+ }),
1189
+ discountedFrom: import_zod11.z.enum(["price", "compare_at_price"]).optional().default("price"),
1190
+ endpoint: import_zod11.z.string().optional(),
1191
+ integrations: import_zod11.z.object({
1192
+ judgeme: import_zod11.z.boolean().default(false),
1193
+ junip: import_zod11.z.boolean().optional().default(false),
1194
+ klaviyo: import_zod11.z.boolean().default(false),
1195
+ loox: import_zod11.z.boolean().default(false),
1196
+ okendo: import_zod11.z.boolean().default(false),
1197
+ opinew: import_zod11.z.boolean().optional().default(false),
1198
+ reviewsio: import_zod11.z.boolean().optional().default(false),
1199
+ stamped: import_zod11.z.boolean().default(false),
1200
+ yotpo: import_zod11.z.boolean().default(false)
1201
+ }),
1202
+ key: import_zod11.z.string().optional(),
1203
+ language: import_zod11.z.object({
1204
+ description: import_zod11.z.union([import_zod11.z.string(), import_zod11.z.unknown().transform(() => "")]).default(""),
1205
+ descriptionEnabled: import_zod11.z.boolean().optional().default(false),
1206
+ descriptionRte: import_zod11.z.object({
1207
+ content: import_zod11.z.array(import_zod11.z.unknown()),
1208
+ type: import_zod11.z.string()
1209
+ }).optional(),
1210
+ descriptionSpacing: import_zod11.z.enum(["none", "xtight", "tight", "default", "loose", "xloose"]).optional(),
1211
+ displayCtaPrice: import_zod11.z.boolean().default(true),
1212
+ global: import_zod11.z.object({
1213
+ declineAll: import_zod11.z.string().optional().default("Decline All"),
1214
+ declineThisOffer: import_zod11.z.string().default("Decline this offer"),
1215
+ free: import_zod11.z.string().optional().default("Free"),
1216
+ notAvailable: import_zod11.z.string().optional().default("Not available"),
1217
+ /** Label for the one-time choice beside `subscriptionOption` in the purchase-type selector */
1218
+ oneTimePurchase: import_zod11.z.string().optional().default("One-time Purchase"),
1219
+ payNow: import_zod11.z.string().default("Pay Now"),
1220
+ payNowUpgradeToSubscription: import_zod11.z.string().optional().default("Upgrade to Subscription"),
1221
+ quantity: import_zod11.z.string().default("Quantity"),
1222
+ /** This isn't configurable in the admin-nextjs editor */
1223
+ recurringShipping: import_zod11.z.string().optional().default("Recurring shipping"),
1224
+ recurringSubtotal: import_zod11.z.string().default("Recurring subtotal"),
1225
+ reviewsPlural: import_zod11.z.string().optional().default("Reviews"),
1226
+ reviewsSingular: import_zod11.z.string().optional().default("Review"),
1227
+ save: import_zod11.z.union([import_zod11.z.string(), import_zod11.z.unknown().transform(() => "Save")]).optional().default("Save"),
1228
+ shipping: import_zod11.z.string().default("Shipping"),
1229
+ subscriptionOption: import_zod11.z.string().optional().default("Subscribe and Save"),
1230
+ subtotal: import_zod11.z.string().default("Subtotal"),
1231
+ taxes: import_zod11.z.string().default("Taxes"),
1232
+ total: import_zod11.z.string().default("Total")
1233
+ }).optional().default(() => ({
1234
+ declineAll: "Decline All",
1235
+ declineThisOffer: "Decline this offer",
1236
+ free: "Free",
1237
+ notAvailable: "Not available",
1238
+ oneTimePurchase: "One-time Purchase",
1239
+ payNow: "Pay Now",
1240
+ payNowUpgradeToSubscription: "Upgrade to Subscription",
1241
+ quantity: "Quantity",
1242
+ /** This isn't configurable in the admin-nextjs editor */
1243
+ recurringShipping: "Recurring shipping",
1244
+ recurringSubtotal: "Recurring subtotal",
1245
+ reviewsPlural: "Reviews",
1246
+ reviewsSingular: "Review",
1247
+ save: "Save",
1248
+ shipping: "Shipping",
1249
+ subscriptionOption: "Subscribe and Save",
1250
+ subtotal: "Subtotal",
1251
+ taxes: "Taxes",
1252
+ total: "Total"
1253
+ })),
1254
+ globalTranslation: import_zod11.z.string().optional().default("english")
1255
+ }),
1256
+ metafields: import_zod11.z.boolean().default(false),
1257
+ /** This isn't configurable in the admin-nextjs editor */
1258
+ offer: import_zod11.z.object({
1259
+ count: import_zod11.z.number().default(1)
1260
+ }),
1261
+ offersLayout: import_zod11.z.object({
1262
+ itemsPerPage: import_zod11.z.number().optional(),
1263
+ type: import_zod11.z.enum(["list", "grid", "carousel"]).default("list")
1264
+ }).optional().default({
1265
+ type: "list"
1266
+ }),
1267
+ /** This isn't configurable in the admin-nextjs editor */
1268
+ previewMode: import_zod11.z.boolean().default(false),
1269
+ productLimit: import_zod11.z.number().optional().default(1),
1270
+ productOptions: import_zod11.z.object({
1271
+ /** This isn't configurable in the admin-nextjs editor */
1272
+ hideOutOfStockVariants: import_zod11.z.boolean().optional().default(false),
1273
+ matchVariant: import_zod11.z.boolean().optional().default(true),
1274
+ showDeclineAll: import_zod11.z.enum(["above", "below", "both", "none"]).optional(),
1275
+ showShipping: import_zod11.z.boolean().optional().default(true),
1276
+ showSubtotal: import_zod11.z.boolean().optional().default(true),
1277
+ showTaxes: import_zod11.z.boolean().optional().default(true),
1278
+ showTotal: import_zod11.z.boolean().optional().default(true),
1279
+ showVariantSelectors: import_zod11.z.boolean().optional().default(true),
1280
+ variantSelectorDisplayMode: import_zod11.z.enum(["separate", "single"]).optional().default("separate")
1281
+ }),
1282
+ productType: import_zod11.z.union([import_zod11.z.enum(["one-time", "subscription", "both"]), import_zod11.z.literal("").transform(() => "one-time")]).default("one-time"),
1283
+ productTypeSelector: import_zod11.z.enum(["dropdown", "radio"]).optional().default("radio"),
1284
+ quantityInputs: import_zod11.z.object({
1285
+ defaultQuantity: import_zod11.z.union([import_zod11.z.number(), import_zod11.z.null().transform(() => 1)]).default(1),
1286
+ enabled: import_zod11.z.boolean().default(true),
1287
+ maxValue: import_zod11.z.union([import_zod11.z.number(), import_zod11.z.null().transform(() => 15)]).default(15),
1288
+ minValue: import_zod11.z.union([import_zod11.z.number().min(0), import_zod11.z.unknown().transform(() => 0)]).default(1)
1289
+ }),
1290
+ shipping: import_zod11.z.object({
1291
+ amount: strictNumber.default(10),
1292
+ /** This isn't configurable in the admin-nextjs editor */
1293
+ enabled: import_zod11.z.boolean().default(true),
1294
+ title: import_zod11.z.string().optional().default("Shipping Fees"),
1295
+ type: import_zod11.z.enum(["free", "fixed_amount"]).default("free")
1296
+ }),
1297
+ styles: import_zod11.z.object({
1298
+ starColor: import_zod11.z.string().optional().default("#fadb14"),
1299
+ starSize: import_zod11.z.union([import_zod11.z.enum(["small", "medium", "large"]), import_zod11.z.unknown().transform(() => "large")]).optional().default("large"),
1300
+ starStrokeColor: import_zod11.z.string().optional().default("#fadb14"),
1301
+ strokeWidth: import_zod11.z.string().optional().default("1")
1302
+ }).optional(),
1303
+ subImages: import_zod11.z.number().nullish().default(8),
1304
+ subscription: import_zod11.z.object({
1305
+ discount: import_zod11.z.object({
1306
+ amount: strictNumber.default(30),
1307
+ shouldShowSavingText: import_zod11.z.boolean().optional().default(true),
1308
+ type: import_zod11.z.enum(["none", "fixed_amount", "percentage"]).default("none")
1309
+ }),
1310
+ shipping: import_zod11.z.object({
1311
+ amount: strictNumber.default(1),
1312
+ /** This isn't configurable in the admin-nextjs editor */
1313
+ enabled: import_zod11.z.boolean().default(true),
1314
+ /** This isn't configurable in the admin-nextjs editor */
1315
+ recurringAmount: strictNumber.default(2),
1316
+ shippingTitle: import_zod11.z.string().default("Shipping Fees"),
1317
+ type: import_zod11.z.enum(["free", "fixed_amount"]).default("free")
1318
+ })
1319
+ }).optional().default({
1320
+ discount: {
1321
+ amount: 30,
1322
+ shouldShowSavingText: true,
1323
+ type: "none"
1324
+ },
1325
+ shipping: {
1326
+ amount: 1,
1327
+ /** This isn't configurable in the admin-nextjs editor */
1328
+ enabled: true,
1329
+ /** This isn't configurable in the admin-nextjs editor */
1330
+ recurringAmount: 2,
1331
+ shippingTitle: "Shipping Fees",
1332
+ type: "free"
1333
+ }
1334
+ }),
1335
+ subscriptionIsDefault: import_zod11.z.boolean().optional(),
1336
+ /** This isn't configurable in the admin-nextjs editor */
1337
+ template: import_zod11.z.string().optional().default(""),
1338
+ type: import_zod11.z.literal("shopify_post_purchase_extension").default("shopify_post_purchase_extension"),
1339
+ upgradeToSubscription: import_zod11.z.object({
1340
+ acceptButtonText: import_zod11.z.string().optional().default("Upgrade"),
1341
+ allow: import_zod11.z.boolean().optional().default(false),
1342
+ emailRefundNotice: import_zod11.z.boolean().optional().default(false),
1343
+ errorBannerText: import_zod11.z.string().optional().default("This subscription cannot be added - limit one per order")
1344
+ }).optional().default(() => ({
1345
+ acceptButtonText: "Upgrade",
1346
+ allow: false,
1347
+ emailRefundNotice: false,
1348
+ errorBannerText: "This subscription cannot be added - limit one per order"
1349
+ }))
1350
+ });
1351
+
1352
+ // src/schema/postPurchaseProductReviews.ts
1353
+ var decimal = import_zod12.z.union([
1354
+ import_zod12.z.number(),
1355
+ import_zod12.z.string().regex(/^\d+(?:\.\d+)?$/).transform(Number)
1356
+ ]);
1357
+ var PostPurchaseCommonReviewRating = import_zod12.z.object({ value: decimal.pipe(import_zod12.z.number().min(0).max(5)) });
1358
+ var PostPurchaseKlaviyoReviewRating = PostPurchaseCommonReviewRating.extend({
1359
+ // Legacy validates key presence, then displays the raw value on five stars without rescaling.
1360
+ scale_max: import_zod12.z.unknown().nonoptional(),
1361
+ scale_min: import_zod12.z.unknown().nonoptional()
1362
+ });
1363
+ var PostPurchaseReviewCount = import_zod12.z.string().regex(/^\d+(?:\.\d+)?$/).transform(Number).pipe(import_zod12.z.number().int().nonnegative());
1364
+ var PostPurchaseReviewStyles = PostPurchaseSettings.shape.styles.unwrap().extend({
1365
+ strokeWidth: decimal.pipe(import_zod12.z.number().nonnegative()).default(1)
1366
+ }).prefault({});
1367
+ var PostPurchaseProductReviews = import_zod12.z.object({
1368
+ color: import_zod12.z.string(),
1369
+ rating: import_zod12.z.number().positive().max(5),
1370
+ reviewCount: import_zod12.z.number().int().nonnegative(),
1371
+ reviewsPlural: import_zod12.z.string(),
1372
+ reviewsSingular: import_zod12.z.string(),
1373
+ size: import_zod12.z.enum(["small", "medium", "large"]),
1374
+ strokeColor: import_zod12.z.string(),
1375
+ strokeWidth: import_zod12.z.number().nonnegative()
1376
+ });
1377
+
1378
+ // src/server/postPurchaseJudgeMeReviews.ts
1379
+ var import_zod14 = require("zod");
1380
+
1381
+ // src/server/postPurchaseReviewFields.ts
1382
+ var import_zod13 = require("zod");
1383
+ var Field = import_zod13.z.object({ key: import_zod13.z.string(), namespace: import_zod13.z.string(), value: import_zod13.z.unknown().optional() });
1384
+ var reviewFields = (raw) => {
1385
+ const fields4 = import_zod13.z.array(import_zod13.z.unknown()).parse(raw).flatMap((field) => {
1386
+ const parsed = Field.safeParse(field);
1387
+ return parsed.success ? [parsed.data] : [];
1388
+ });
1389
+ return (namespace, key) => fields4.find((field) => field.namespace === namespace && field.key === key);
1390
+ };
1391
+ var ReviewFieldError = class extends Error {
1392
+ constructor(field) {
1393
+ super(`Unreadable review field ${field}`);
1394
+ this.field = field;
1395
+ }
1396
+ };
1397
+ var readReviewField = (field, read) => {
1398
+ try {
1399
+ return read(field.value);
1400
+ } catch {
1401
+ throw new ReviewFieldError(`${field.namespace}.${field.key}`);
1402
+ }
1403
+ };
1404
+
1405
+ // src/server/postPurchaseJudgeMeReviews.ts
1406
+ var readJudgeMeReviews = (find) => {
1407
+ const field = find("judgeme", "badge");
1408
+ if (!field) return null;
1409
+ return readReviewField(field, (value) => {
1410
+ const html = import_zod14.z.string().parse(value);
1411
+ const rating = html.match(/data-average-rating=['"](\d+(?:\.\d+)?)['"]/);
1412
+ const count = html.match(/data-number-of-reviews=['"](\d+)['"]/);
1413
+ if (!rating || !count) throw new Error("Unreadable Judge.me attributes");
1414
+ return {
1415
+ rating: PostPurchaseCommonReviewRating.parse({ value: rating[1] }).value,
1416
+ reviewCount: PostPurchaseReviewCount.parse(count[1])
1417
+ };
1418
+ });
1419
+ };
1420
+
1421
+ // src/server/postPurchaseOkendoReviews.ts
1422
+ var import_zod15 = require("zod");
1423
+ var Summary = import_zod15.z.object({
1424
+ reviewAverageValue: PostPurchaseCommonReviewRating.shape.value,
1425
+ reviewCount: import_zod15.z.union([PostPurchaseProductReviews.shape.reviewCount, PostPurchaseReviewCount])
1426
+ });
1427
+ var readOkendoReviews = (find) => {
1428
+ const field = find("okendo", "summaryData");
1429
+ if (!field) return null;
1430
+ const summary = readReviewField(field, (value) => Summary.parse(JSON.parse(import_zod15.z.string().parse(value))));
1431
+ return { rating: summary.reviewAverageValue, reviewCount: summary.reviewCount };
1432
+ };
1433
+
1434
+ // src/server/postPurchaseScalarReviews.ts
1435
+ var import_zod16 = require("zod");
1436
+ var readScalarReviews = (find, namespace, ratingKey, countKey) => {
1437
+ const rating = find(namespace, ratingKey);
1438
+ const count = find(namespace, countKey);
1439
+ if (!rating || !count) return null;
1440
+ return {
1441
+ rating: readReviewField(
1442
+ rating,
1443
+ (value) => PostPurchaseCommonReviewRating.parse({ value: import_zod16.z.string().parse(value) }).value
1444
+ ),
1445
+ reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
1446
+ };
1447
+ };
1448
+
1449
+ // src/server/postPurchaseReviewData.ts
1450
+ var readStandardReviews = (find) => {
1451
+ const rating = find("reviews", "rating");
1452
+ const count = find("reviews", "rating_count");
1453
+ if (!rating || !count) return null;
1454
+ return {
1455
+ rating: readReviewField(rating, (raw) => {
1456
+ const value = import_zod17.z.string().parse(raw);
1457
+ return PostPurchaseCommonReviewRating.parse(/^\d+(?:\.\d+)?$/.test(value) ? { value } : JSON.parse(value)).value;
1458
+ }),
1459
+ reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
1460
+ };
1461
+ };
1462
+ var readPostPurchaseReviewData = (provider, find) => {
1463
+ if (provider === "yotpo") return readScalarReviews(find, "yotpo", "reviews_average", "reviews_count");
1464
+ if (provider === "stamped") return readScalarReviews(find, "stamped", "reviews_average", "reviews_count");
1465
+ if (provider === "judgeme") return readJudgeMeReviews(find);
1466
+ if (provider === "okendo") return readOkendoReviews(find);
1467
+ if (provider === "opinew") return readScalarReviews(find, "opinew_metafields", "reviews_average", "reviews_count");
1468
+ if (provider === "reviewsio")
1469
+ return readScalarReviews(find, "reviewscouk", "rating", "total") ?? readStandardReviews(find);
1470
+ if (provider === "loox") return readScalarReviews(find, "loox", "avg_rating", "num_reviews");
1471
+ if (provider === "junip") return readScalarReviews(find, "junip", "rating_average", "rating_count");
1472
+ const rating = find("reviews", "rating");
1473
+ const count = find("reviews", "rating_count");
1474
+ if (!rating || !count) return null;
1475
+ return {
1476
+ rating: readReviewField(
1477
+ rating,
1478
+ (value) => PostPurchaseKlaviyoReviewRating.parse(JSON.parse(import_zod17.z.string().parse(value))).value
1479
+ ),
1480
+ reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
1481
+ };
1482
+ };
1483
+
1484
+ // src/server/postPurchaseReviewProvider.ts
1485
+ var import_zod18 = require("zod");
1486
+ var IntegrationInput = import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).prefault({});
1487
+ var precedence = [
1488
+ "klaviyo",
1489
+ "judgeme",
1490
+ "junip",
1491
+ "loox",
1492
+ "okendo",
1493
+ "opinew",
1494
+ "reviewsio",
1495
+ "stamped",
1496
+ "yotpo"
1497
+ ];
1498
+ var ReviewsIoFlag = import_zod18.z.preprocess((value) => {
1499
+ if (typeof value === "string") {
1500
+ const flag = value.toLowerCase();
1501
+ if (flag === "true" || flag === "yes") return true;
1502
+ if (flag === "false" || flag === "no") return false;
1503
+ }
1504
+ return value;
1505
+ }, PostPurchaseSettings.shape.integrations.shape.reviewsio);
1506
+ var selectPostPurchaseReviewProvider = (raw) => {
1507
+ const integrations = IntegrationInput.parse(raw);
1508
+ for (const provider of precedence) {
1509
+ const schema = provider === "reviewsio" ? ReviewsIoFlag : PostPurchaseSettings.shape.integrations.shape[provider];
1510
+ if (schema.parse(integrations[provider])) return provider;
1511
+ }
1512
+ return null;
1513
+ };
1514
+
1515
+ // src/server/offerProductReviews.ts
1516
+ var readOrReport = (read, productId2, report) => {
1517
+ try {
1518
+ return read();
1519
+ } catch (error) {
1520
+ if (!(error instanceof ReviewFieldError)) throw error;
1521
+ report?.({
1522
+ detail: "Unreadable offer product reviews metafield",
1523
+ field: error.field,
1524
+ kind: "reviews",
1525
+ productId: productId2
1526
+ });
1527
+ return null;
1528
+ }
1529
+ };
1530
+ var readReviews = (provider, find, productId2, report) => (provider === "klaviyo" ? null : readOrReport(() => readPostPurchaseReviewData(provider, find), productId2, report)) ?? readOrReport(() => readStandardReviews(find), productId2, report);
1531
+ var projectOfferProductReviews = (integrations, { id: productId2, metafields }, report) => {
1532
+ let provider;
1533
+ try {
1534
+ provider = selectPostPurchaseReviewProvider(integrations);
1535
+ } catch {
1536
+ return void 0;
1537
+ }
1538
+ if (!provider) return void 0;
1539
+ try {
1540
+ if (!Array.isArray(metafields)) return null;
1541
+ const data = readReviews(provider, reviewFields(metafields), productId2, report);
1542
+ return data && data.rating > 0 ? data : null;
1543
+ } catch {
1544
+ report?.({ detail: "Unreadable offer product reviews", kind: "product" });
1545
+ return null;
1546
+ }
1547
+ };
1548
+
1549
+ // src/server/shopSubtotal.ts
1550
+ var shopCurrencyRate = (cart) => {
1551
+ const rate = cart.currencyRate ?? 1;
1552
+ return Number.isFinite(rate) && rate > 0 ? rate : 1;
1553
+ };
1554
+ var shopSubtotalCents = (cart) => Math.round((cart.subtotal - (cart.discountTotal ?? 0)) / shopCurrencyRate(cart));
1555
+ var toShopCents = (majorPresentment, rate) => Math.round(majorPresentment * 100 / rate);
1556
+
1557
+ // src/schema/cabShopConfig.ts
1558
+ var import_zod20 = require("zod");
1559
+
1560
+ // src/schema/driftedMarkets.ts
1561
+ var DRIFTED_MARKETS = Object.freeze({ enabled: false });
1562
+
1563
+ // src/schema/smartCart.ts
1564
+ var import_zod19 = require("zod");
1565
+ var SmartCartTierProduct = import_zod19.z.looseObject({
1566
+ handle: import_zod19.z.string().optional(),
1567
+ id: import_zod19.z.coerce.number().optional(),
1568
+ productId: import_zod19.z.coerce.number().optional(),
1569
+ title: import_zod19.z.string().optional(),
1570
+ variantIds: import_zod19.z.array(import_zod19.z.coerce.number()).optional()
1571
+ });
1572
+ var SmartCartTierExclusion = import_zod19.z.looseObject({
1573
+ collectionIds: import_zod19.z.array(import_zod19.z.coerce.number()).optional().catch(void 0),
1574
+ productIds: import_zod19.z.array(import_zod19.z.coerce.number()).optional().catch(void 0),
1575
+ tags: import_zod19.z.array(import_zod19.z.string()).optional().catch(void 0),
1576
+ type: import_zod19.z.string().optional().catch(void 0)
1577
+ });
1578
+ var SmartCartTier = import_zod19.z.looseObject({
1579
+ allProducts: import_zod19.z.array(SmartCartTierProduct).optional(),
1580
+ /** Merchant-set tier label (e.g. "Free gift", "$100 reward"), shown on the step row when enabled. */
1581
+ customTierLabel: import_zod19.z.boolean().optional(),
1582
+ customTierLabelText: import_zod19.z.string().optional(),
1583
+ decorativeAmountReachedLabel: import_zod19.z.boolean().optional(),
1584
+ decorativeAmountReachedLabelText: import_zod19.z.string().optional(),
1585
+ decorativeAmountRemainingLabel: import_zod19.z.boolean().optional(),
1586
+ decorativeAmountRemainingLabelText: import_zod19.z.string().optional(),
1587
+ /** Order-discount reward: `'fixedAmount'` (shop-currency dollars) or `'percentage'` (whole percent). */
1588
+ discountAmountFromTotal: import_zod19.z.coerce.number().optional(),
1589
+ discountAmountReachedLabel: import_zod19.z.boolean().optional(),
1590
+ discountAmountReachedLabelText: import_zod19.z.string().optional(),
1591
+ discountAmountRemainingLabel: import_zod19.z.boolean().optional(),
1592
+ discountAmountRemainingLabelText: import_zod19.z.string().optional(),
1593
+ discountType: import_zod19.z.string().optional(),
1594
+ /**
1595
+ * onsite `exclusions` + `exclusions_enabled` (REB-22305): per-tier rules the converter carries onto
1596
+ * `CABProgressTier.exclusions`. `.catch(undefined)` for the same blast-radius reason as `productTierImage`:
1597
+ * one drifted value must degrade to "no tier exclusions", never drop every progress bar for the shop.
1598
+ *
1599
+ * `exclusionsEnabled` is a STRICT boolean on purpose, even though failing open here changes the tier's math
1600
+ * (a non-boolean reads as disabled) rather than just an icon. onsite reads its sibling tier flags strictly —
1601
+ * `shouldFilterOutOfStockVariantsFromTier` is `tier?.filter_oos_variants === true`, and its `progressBar.ts`
1602
+ * types every tier flag as `boolean` — so a stored `1` / `"1"` / `"true"` is "disabled" on the onsite bar too.
1603
+ * A truthiness preprocess would make CAB exclude where onsite does not: the opposite parity break.
1604
+ */
1605
+ exclusions: import_zod19.z.array(SmartCartTierExclusion).optional().catch(void 0),
1606
+ exclusionsEnabled: import_zod19.z.boolean().optional().catch(void 0),
1607
+ filterOosVariants: import_zod19.z.boolean().optional(),
1608
+ id: import_zod19.z.string().optional(),
1609
+ /**
1610
+ * A `null`/absent minimum stays `undefined` (NOT coerced to `0`): a threshold-0 tier is always reached
1611
+ * and would auto-add its gift to every cart. onsite's `isTierDataValid` drops a non-numeric minimum for
1612
+ * exactly this reason; the converter's `renderableTiers` mirrors that (`Number.isFinite`). A literal `0`
1613
+ * is kept — onsite keeps it too. DELIBERATE DIVERGENCE from onsite for string minimums: onsite's
1614
+ * `isTierDataValid` is a strict `typeof === 'number'`, so it drops `'50'`; the converter instead coerces
1615
+ * `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
1616
+ */
1617
+ minimum: import_zod19.z.preprocess((value) => value == null ? void 0 : value, import_zod19.z.coerce.number().optional()),
1618
+ presentmentCurrencies: import_zod19.z.looseObject({ enabled: import_zod19.z.boolean().optional() }).optional(),
1619
+ productAmountReachedLabel: import_zod19.z.boolean().optional(),
1620
+ productAmountReachedLabelText: import_zod19.z.string().optional(),
1621
+ productAmountRemainingLabel: import_zod19.z.boolean().optional(),
1622
+ productAmountRemainingLabelText: import_zod19.z.string().optional(),
1623
+ products: import_zod19.z.array(SmartCartTierProduct).optional(),
1624
+ /**
1625
+ * onsite `product_tier_element_size`: the step-row icon's square size as a px STRING (`'18px'` …
1626
+ * `'36px'` — the admin's five-value Size control, default `'18px'`). React stamps it onto the icon
1627
+ * SVG's `width`/`height` (`getProgressStepIconSize`), so the milestone renders at the merchant's
1628
+ * chosen size; the converter turns it into `CABProgressTier.iconSizePx` for the CAB renderer.
1629
+ *
1630
+ * `.catch(undefined)` for the same blast-radius reason as `productTierImage` below: this key was
1631
+ * previously unknown-and-ignored by the `looseObject`, and `SmartCartConfig` is parsed
1632
+ * `.nullish().catch(undefined)` with no intermediate catch, so one drifted value (a bare number, a
1633
+ * `'2rem'`) would drop EVERY progress bar for the shop rather than just this setting. Failing open to
1634
+ * `undefined` lands on the documented 18px default — strictly safer than that blast radius. The
1635
+ * converter parses the number out and clamps it, so a junk-but-string value degrades the same way.
1636
+ */
1637
+ productTierElementSize: import_zod19.z.string().optional().catch(void 0),
1638
+ /**
1639
+ * onsite `product_tier_image`: on a product (gift) tier, show the gift's product image in the step-row
1640
+ * slot instead of the generic bag icon (React `TierProgressIcon` swaps in the image when this is set and
1641
+ * an image resolves). Per-tier; the client resolves the image (config carries only product IDs).
1642
+ *
1643
+ * `.catch(undefined)` is load-bearing. This key was previously unknown-and-ignored by the `looseObject`;
1644
+ * declaring it as a real boolean means a stored non-boolean (`1` / `"1"` / `"true"`) would now FAIL the
1645
+ * tier — and since `SmartCartConfig` is parsed `.nullish().catch(undefined)` (userConfig/cabShopConfig)
1646
+ * with no intermediate catch, one drifted flag would drop EVERY progress bar for the shop, not just the
1647
+ * flag. The converter only reads it for truthiness (`gift && tier.productTierImage`), so failing open to
1648
+ * `undefined` (bag-icon fallback, the documented default) is strictly safer than that blast radius.
1649
+ */
1650
+ productTierImage: import_zod19.z.boolean().optional().catch(void 0),
1651
+ type: import_zod19.z.string().optional(),
1652
+ /**
1653
+ * onsite's PER-TIER unit switch (`unlock_condition_type`): `'item_quantity'` makes `minimum` an
1654
+ * item count (checked before any money handling — no ×100, no FX, no presentment overrides,
1655
+ * mirroring onsite `getTierMinimum`); anything else (or absent) keeps the money semantics.
1656
+ */
1657
+ unlockConditionType: import_zod19.z.string().optional()
1658
+ });
1659
+ var SmartCartBar = import_zod19.z.looseObject({
1660
+ countryCodes: import_zod19.z.array(import_zod19.z.string()).optional(),
1661
+ /**
1662
+ * onsite `exclude_discount_in_subtotal`: measure progress against the PRE-discount subtotal so an
1663
+ * applied code/order discount doesn't lower progress. The client adds cart discount allocations back.
1664
+ */
1665
+ excludeDiscountInSubtotal: import_zod19.z.boolean().optional(),
1666
+ /** Products excluded from the progress subtotal; the client subtracts their variants' cart cost. */
1667
+ excludedProducts: import_zod19.z.array(import_zod19.z.looseObject({ variantIds: import_zod19.z.array(import_zod19.z.coerce.number()).optional() })).optional(),
1668
+ freeShippingOnSubscription: import_zod19.z.boolean().optional(),
1669
+ geolocationEnabled: import_zod19.z.boolean().optional(),
1670
+ id: import_zod19.z.string().optional(),
1671
+ language: import_zod19.z.looseObject({
1672
+ freeShippingReached: import_zod19.z.string().optional(),
1673
+ freeShippingRemaining: import_zod19.z.string().optional(),
1674
+ giftAreaTitle: import_zod19.z.string().optional()
1675
+ }).optional(),
1676
+ name: import_zod19.z.string().optional(),
1677
+ tiers: import_zod19.z.array(SmartCartTier).optional()
1678
+ });
1679
+ var SmartCartComponent = import_zod19.z.looseObject({
1680
+ settings: import_zod19.z.looseObject({ bars: import_zod19.z.array(SmartCartBar).optional() }).optional(),
1681
+ type: import_zod19.z.string().optional()
1682
+ });
1683
+ var SmartCartConfig = import_zod19.z.looseObject({
1684
+ components: import_zod19.z.array(SmartCartComponent).optional()
1685
+ });
1686
+
1687
+ // src/schema/cabShopConfig.ts
1688
+ var CabActiveExperiment = import_zod20.z.object({
1689
+ data: import_zod20.z.array(
1690
+ import_zod20.z.object({
1691
+ elementId: import_zod20.z.coerce.number(),
1692
+ id: import_zod20.z.coerce.number(),
1693
+ traffic: import_zod20.z.coerce.number()
1694
+ })
1695
+ ),
1696
+ id: import_zod20.z.coerce.number(),
1697
+ placeholderId: import_zod20.z.coerce.number().nullable(),
1698
+ type: import_zod20.z.string()
1699
+ });
1700
+ var CabShopConfig = import_zod20.z.object({
1701
+ /**
1702
+ * Per-element resilient: parse as `unknown[]` (non-array → `[]`), then keep only the experiments that
1703
+ * validate. A single drifted experiment drops itself instead of `.catch`-ing the WHOLE array to `[]` and
1704
+ * silently disabling every live A/B test fleet-wide.
1705
+ */
1706
+ activeExperiments: import_zod20.z.array(import_zod20.z.unknown()).catch([]).default([]).transform(
1707
+ (experiments) => experiments.flatMap((experiment) => {
1708
+ const result = CabActiveExperiment.safeParse(experiment);
1709
+ return result.success ? [result.data] : [];
1710
+ })
1711
+ ),
1712
+ /**
1713
+ * Only the two fields the smart-cart entitlement gate reads (`shortName`/`isActive`). Per-element
1714
+ * resilient like `activeExperiments`: a drifted package entry degrades to an inert `''`/false one that
1715
+ * matches nothing, so a real active `cart-merchandising` package still gates correctly and a sibling
1716
+ * drift never fails the shared config parse. Note the salvage is fail-CLOSED, not fail-open, for an
1717
+ * entitled v6 shop: a malformed whole array (⇒ `[]`) or an inerted `cart-merchandising` entry (e.g.
1718
+ * `is_active: 1` ⇒ inactive) makes the gate find no active package and drop every bar. That matches
1719
+ * React's "no proof of entitlement ⇒ render null", but it silently removes bars — so the server gate
1720
+ * ({@link file://../server/widgetSettings.ts} `fetchProgressBarContext`) emits a `shopConfig` drift
1721
+ * when it sees the inert-entry sentinel (`shortName === ''`). The whole-array `[]` case leaves no
1722
+ * sentinel and is not separately signalable here.
1723
+ */
1724
+ activePackages: import_zod20.z.array(import_zod20.z.object({ isActive: import_zod20.z.boolean(), shortName: import_zod20.z.string() }).catch({ isActive: false, shortName: "" })).catch([]).default([]),
1725
+ apiKey: import_zod20.z.string(),
1726
+ /** The shop's billing generation; the smart-cart entitlement gate only fires for `'v6'`. Missing/drift ⇒ `null` (fail open, ungated). */
1727
+ billingVersion: import_zod20.z.string().nullable().catch(null).default(null),
1728
+ /**
1729
+ * The shop's rotating cache-buster: `onsite_cache_key` internally — a unix timestamp the engine bumps,
1730
+ * and the edge copy of this config purges, on every widget/settings/theme edit — but serialized on the
1731
+ * wire as `cache_key`, which `deepCamelCase` maps to this field (renaming it `onsiteCacheKey` would
1732
+ * sever the mapping silently; the wire-level assertion in `userConfig.test.ts` is what fails loudly).
1733
+ * Threaded onto the widgets/settings read as `cache_key` so the engine marks the response
1734
+ * immutable-cacheable and the `cached.*` edge serves it fresh-by-URL. The engine sends a numeric
1735
+ * string — coerce — but admit only number/string inputs and constrain to a positive integer: a bare
1736
+ * coercion folds `null`/`''`/`false` to `0` and `true` to `1` — "valid" numbers that would go upstream
1737
+ * as a constant never-rotating buster and pin the edge copy permanently stale. A real key is always a
1738
+ * positive int sent as number or string, so everything else lands on `.catch()` and degrades that read
1739
+ * to un-busted (origin-served — slower, never stale), never a parse fail.
1740
+ */
1741
+ cacheKey: import_zod20.z.union([import_zod20.z.number(), import_zod20.z.string()]).transform((value) => Number(value)).pipe(import_zod20.z.number().int().positive()).optional().catch(void 0),
1742
+ /**
1743
+ * The shop's base-currency ISO code (e.g. `'USD'`). CAB derives the shop minor-unit exponent from it
1744
+ * (`currencyDecimals`) so a Functions-applied fixed discount — whose amount is in shop minor units —
1745
+ * converts to the buyer's currency exactly in a cross-decimal market. `.catch()` like its siblings: a
1746
+ * missing/renamed currency degrades to "unknown" (client falls back to buyer decimals), never a parse fail.
1747
+ */
1748
+ currency: import_zod20.z.string().optional().catch(void 0),
1749
+ /**
1750
+ * The merchant's "Use Markets in Data Sources" toggle. The engine (CI2) never reads it on the serve
1751
+ * path, so the proxy honouring it before sending market context is what makes the setting mean
1752
+ * anything (REB-21688). Fail-CLOSED, unlike the fail-open siblings: a missing/null/drifted field reads
1753
+ * as markets OFF — market context silently dropped (engine serves shop-default market), never sent
1754
+ * against the merchant's setting. The OFF-reading salvages stay distinguishable: missing AND null are
1755
+ * the engine's normal absent vocabulary (`.nullish()`, like `monetize`/`billingVersion`) and read as
1756
+ * the plain default — not drift — while only a drifted SHAPE `.catch`es, to the {@link DRIFTED_MARKETS}
1757
+ * identity sentinel, so `fetchUserConfig` can emit a `shopConfig` drift for the one case that means an
1758
+ * engine rename/retype; otherwise a markets-enabled merchant degrading to shop-default pricing would
1759
+ * be indistinguishable from markets genuinely off. The missing-key case is EXPLICIT via `.default()`
1760
+ * (a factory, so parses never share a mutable object) rather than inferred from zod running an
1761
+ * optional key's transform on `undefined`; `null` flows past the default through `.nullish()` into the
1762
+ * transform. `Readonly` on the output type because the drifted salvage IS frozen — an assignment to
1763
+ * `markets.enabled` downstream would throw only for drifted shops in production, so surface direct
1764
+ * writes to tsc (a guard for the direct case only: TS doesn't check `readonly` in assignability, so
1765
+ * laundering through a mutable-shaped alias still compiles).
1766
+ * The inner `enabled` stays strict on purpose: `{ enabled: null }` is a genuine retype and drifting is
1767
+ * the correct answer (the editor-path `ShopConfig.markets` would hard-fail the same payload).
1768
+ */
1769
+ markets: import_zod20.z.object({ enabled: import_zod20.z.boolean() }).nullish().catch(DRIFTED_MARKETS).default(() => ({ enabled: false })).transform((markets) => markets ?? { enabled: false }),
1770
+ monetize: import_zod20.z.object({ publisherKey: import_zod20.z.string().nullable() }).nullish().catch(void 0),
1771
+ shopId: import_zod20.z.number().optional().catch(void 0),
1772
+ /**
1773
+ * The merchant's display name ("Gift Basket Store") — the Monetize header copy reads it.
1774
+ * `.catch()` like its siblings: a missing/drifted name degrades the header to the
1775
+ * myshopify-domain slug (the pre-CAB React fallback), never a parse fail. An empty string is a
1776
+ * VALID parse — the slug fallback for `''` (and whitespace/tag-only names) lives in
1777
+ * composeOffer's `||` chain, not here.
1778
+ */
1779
+ shopName: import_zod20.z.string().nullish().catch(void 0)
1780
+ });
1781
+ var CabUserConfig = import_zod20.z.object({
1782
+ shop: CabShopConfig,
1783
+ smartCart: SmartCartConfig.nullish().catch(void 0)
1784
+ });
1785
+
1786
+ // src/schema/widgets/checkout-and-beyond/image.ts
1787
+ var import_uuid14 = require("uuid");
1788
+ var import_zod39 = require("zod");
1789
+
1790
+ // src/schema/widgets/checkout-and-beyond/icons.ts
1791
+ var iconNames = [
1792
+ "alert-circle",
1793
+ "alert-triangle",
1794
+ "alert-triangle-filled",
1795
+ "arrow-down",
1796
+ "arrow-left",
1797
+ "arrow-right",
1798
+ "arrow-up",
1799
+ "arrow-up-right",
1800
+ "bag",
1801
+ "bullet",
1802
+ "calendar",
1803
+ "camera",
1804
+ "caret-down",
1805
+ "cart",
1806
+ "cash-dollar",
1807
+ "categories",
1808
+ "check",
1809
+ "check-circle",
1810
+ "check-circle-filled",
1811
+ "chevron-down",
1812
+ "chevron-left",
1813
+ "chevron-right",
1814
+ "chevron-up",
1815
+ "circle",
1816
+ "clipboard",
1817
+ "clock",
940
1818
  "credit-card",
941
1819
  "delete",
942
1820
  "delivered",
@@ -994,283 +1872,65 @@ var iconTones = ["auto", "critical", "custom", "info", "neutral", "success", "wa
994
1872
  var IconTone = freezeEnum(iconTones);
995
1873
 
996
1874
  // src/schema/widgets/checkout-and-beyond/imageThumbnails.ts
997
- var import_zod7 = require("zod");
998
- var CABImageThumbnails = import_zod7.z.object({
999
- limit: import_zod7.z.number().int().min(1).default(8),
1000
- perLine: import_zod7.z.number().int().min(1).max(8).default(4)
1001
- });
1002
-
1003
- // src/schema/widgets/checkout-and-beyond/regex.ts
1004
- var DYNAMIC_TOKEN_REGEX = /^\{\{\s*[A-Za-z]+\s*\}\}$/;
1005
- var HEX_COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
1006
- var ROOT_RELATIVE_PATH_REGEX = /^\/(?!\/)/;
1007
- var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
1875
+ var import_zod21 = require("zod");
1876
+ var CABImageThumbnails = import_zod21.z.object({
1877
+ limit: import_zod21.z.number().int().min(1).default(8),
1878
+ perLine: import_zod21.z.number().int().min(1).max(8).default(4)
1879
+ });
1008
1880
 
1009
1881
  // src/schema/widgets/checkout-and-beyond/shared.ts
1010
- var import_zod27 = require("zod");
1882
+ var import_zod38 = require("zod");
1011
1883
 
1012
1884
  // src/schema/widgets/checkout-and-beyond/banner.ts
1013
- var import_zod11 = require("zod");
1014
-
1015
- // src/schema/widgets/checkout-and-beyond/layout.ts
1016
- var import_uuid = require("uuid");
1017
- var import_zod10 = require("zod");
1018
-
1019
- // src/schema/widgets/checkout-and-beyond/variables.ts
1020
- var import_zod9 = require("zod");
1021
-
1022
- // src/schema/widgets/checkout-and-beyond/rule.ts
1023
- var import_zod8 = require("zod");
1024
- var ruleTypes = [
1025
- "cart",
1026
- "cart_count",
1027
- "cart_item_count",
1028
- "cart_line_count",
1029
- "cart_subtotal",
1030
- "collection",
1031
- "customer",
1032
- "customer_order_count",
1033
- "customer_tag",
1034
- "customer_total_spent",
1035
- "date",
1036
- "product",
1037
- "product_tag",
1038
- "product_title",
1039
- "product_type",
1040
- "product_vendor"
1041
- ];
1042
- var ruleType = import_zod8.z.enum(ruleTypes);
1043
- var RuleType = ruleType.enum;
1044
- var ruleOperators = [
1045
- "after",
1046
- "anything",
1047
- "before",
1048
- "contains",
1049
- "contains_any",
1050
- "does_not_contain",
1051
- "does_not_contain_any",
1052
- "equals",
1053
- "does_not_equal",
1054
- "greater_than",
1055
- "less_than"
1056
- ];
1057
- var ruleOperator = import_zod8.z.enum(ruleOperators);
1058
- var RuleOperator = ruleOperator.enum;
1059
- var RuleCondition = import_zod8.z.object({
1060
- operator: import_zod8.z.enum(ruleOperators).default(RuleOperator.anything),
1061
- products: import_zod8.z.union([import_zod8.z.array(import_zod8.z.unknown()), import_zod8.z.strictObject({}).transform(() => [])]).default(() => []),
1062
- type: import_zod8.z.enum(ruleTypes).default(RuleType.cart_subtotal),
1063
- value: import_zod8.z.coerce.string().default("")
1064
- });
1065
- var RuleLogicBlock = import_zod8.z.object({
1066
- rules: import_zod8.z.array(RuleCondition).default(() => [])
1067
- });
1068
- var CABRulesetEntry = import_zod8.z.object({
1069
- exitIfMatched: import_zod8.z.boolean().default(true),
1070
- logic: import_zod8.z.array(RuleLogicBlock).default(() => []),
1071
- output: import_zod8.z.array(
1072
- import_zod8.z.object({
1073
- key: import_zod8.z.string().default("should_show"),
1074
- type: import_zod8.z.literal("data_json").default("data_json"),
1075
- value: import_zod8.z.string().default("true")
1076
- })
1077
- ).default(() => [{ key: "should_show", type: "data_json", value: "true" }])
1078
- });
1079
- var CABRuleset = import_zod8.z.union([import_zod8.z.array(CABRulesetEntry), import_zod8.z.strictObject({}).transform(() => [])]).default(() => []);
1080
-
1081
- // src/schema/widgets/checkout-and-beyond/variables.ts
1082
- var variableEffect = import_zod9.z.enum(variableEffects);
1083
- var CABVariableSeed = import_zod9.z.object({
1084
- dataSourceId: import_zod9.z.number().nullable().default(null),
1085
- ruleset: CABRuleset
1086
- });
1087
- var CABBooleanVariable = import_zod9.z.object({
1088
- /**
1089
- * Holds until the first seed verdict lands (and forever, for unseeded variables). Omitted, it derives
1090
- * from seededness — `false` with a `seed` (visibility is EARNED), `true` without — via the transform
1091
- * below; a cross-field default has no `.default()` spelling. An explicit value always wins.
1092
- */
1093
- defaultValue: import_zod9.z.boolean().optional(),
1094
- name: import_zod9.z.string().min(1),
1095
- seed: CABVariableSeed.optional(),
1096
- /** Defaulted so every stored declaration (all boolean before `text` existed) parses unchanged. */
1097
- type: import_zod9.z.literal(VariableType.boolean).default(VariableType.boolean)
1098
- });
1099
- var CABTextVariable = import_zod9.z.object({
1100
- defaultValue: import_zod9.z.string(),
1101
- name: import_zod9.z.string().min(1),
1102
- seed: import_zod9.z.never().optional(),
1103
- type: import_zod9.z.literal(VariableType.text)
1104
- });
1105
- var CABNumberVariable = import_zod9.z.object({
1106
- defaultValue: import_zod9.z.number(),
1107
- name: import_zod9.z.string().min(1),
1108
- seed: import_zod9.z.never().optional(),
1109
- type: import_zod9.z.literal(VariableType.number)
1110
- });
1111
- var CABVariable = import_zod9.z.union([CABTextVariable, CABNumberVariable, CABBooleanVariable]).transform(
1112
- (variable) => variable.type === VariableType.boolean ? { ...variable, defaultValue: variable.defaultValue ?? variable.seed === void 0 } : variable
1113
- );
1114
- var CABVariableEffect = import_zod9.z.object({
1115
- effect: variableEffect.default(VariableEffect.toggle),
1116
- variable: import_zod9.z.string().min(1)
1117
- });
1118
- var CABVisibility = import_zod9.z.object({
1119
- variable: import_zod9.z.string().min(1),
1120
- visibleWhen: import_zod9.z.boolean().default(true)
1121
- });
1122
- var contentOperator = import_zod9.z.enum(contentOperators);
1123
- var resultCountOperator = import_zod9.z.enum(resultCountOperators);
1124
- var resultTagOperator = import_zod9.z.enum(resultTagOperators);
1125
- var mutatorEvent = import_zod9.z.enum(mutatorEvents);
1126
- var CABContentTrigger = import_zod9.z.object({
1127
- operator: contentOperator.default(ContentOperator.is_empty),
1128
- type: import_zod9.z.literal("content")
1129
- });
1130
- var CABResultCountTrigger = import_zod9.z.object({
1131
- operator: resultCountOperator.default(ResultCountOperator.equals),
1132
- type: import_zod9.z.literal("result_count"),
1133
- value: import_zod9.z.number().default(0)
1134
- });
1135
- var CABResultTagTrigger = import_zod9.z.object({
1136
- operator: resultTagOperator.default(ResultTagOperator.contains),
1137
- type: import_zod9.z.literal("result_tag"),
1138
- value: import_zod9.z.string().min(1)
1139
- });
1140
- var CABEventTrigger = import_zod9.z.object({
1141
- event: mutatorEvent,
1142
- type: import_zod9.z.literal("event")
1143
- });
1144
- var CABVariableTrigger = import_zod9.z.discriminatedUnion("type", [
1145
- CABContentTrigger,
1146
- CABEventTrigger,
1147
- CABResultCountTrigger,
1148
- CABResultTagTrigger
1149
- ]);
1150
- var CABVariableMutator = import_zod9.z.object({
1151
- effect: variableEffect.default(VariableEffect.set_false),
1152
- variable: import_zod9.z.string().min(1),
1153
- when: CABVariableTrigger
1154
- });
1155
- var CABVariableFields = {
1156
- mutators: import_zod9.z.array(CABVariableMutator).optional(),
1157
- variables: import_zod9.z.array(CABVariable).refine((variables) => new Set(variables.map(({ name }) => name)).size === variables.length, {
1158
- message: "variable names must be unique within a section"
1159
- }).optional(),
1160
- visibility: CABVisibility.optional()
1161
- };
1885
+ var import_zod23 = require("zod");
1162
1886
 
1163
1887
  // src/schema/widgets/checkout-and-beyond/layout.ts
1164
- var GridItem = import_zod10.z.union([import_zod10.z.literal("auto"), import_zod10.z.literal("fill"), import_zod10.z.string().regex(/^\d+%$/), import_zod10.z.number()]);
1165
- var CABLayoutWrapping = import_zod10.z.object({
1166
- breakAt: import_zod10.z.number().positive(),
1167
- maxPerLine: import_zod10.z.number().int().positive()
1888
+ var import_uuid3 = require("uuid");
1889
+ var import_zod22 = require("zod");
1890
+ var GridItem = import_zod22.z.union([import_zod22.z.literal("auto"), import_zod22.z.literal("fill"), import_zod22.z.string().regex(/^\d+%$/), import_zod22.z.number()]);
1891
+ var CABLayoutWrapping = import_zod22.z.object({
1892
+ breakAt: import_zod22.z.number().positive(),
1893
+ maxPerLine: import_zod22.z.number().int().positive()
1168
1894
  });
1169
- var CABLayoutSection = import_zod10.z.object({
1895
+ var CABLayoutSection = import_zod22.z.object({
1170
1896
  ...CABVariableFields,
1171
- alignment: import_zod10.z.object({
1172
- horizontal: import_zod10.z.enum(horizontalAlignments).default(HorizontalAlignment.start),
1173
- vertical: import_zod10.z.enum(verticalAlignments).default(VerticalAlignment.top)
1897
+ alignment: import_zod22.z.object({
1898
+ horizontal: import_zod22.z.enum(horizontalAlignments).default(HorizontalAlignment.start),
1899
+ vertical: import_zod22.z.enum(verticalAlignments).default(VerticalAlignment.top)
1174
1900
  }).default({
1175
1901
  horizontal: HorizontalAlignment.start,
1176
1902
  vertical: VerticalAlignment.top
1177
1903
  }),
1178
- border: import_zod10.z.lazy(() => CABBorder),
1179
- buttonField: import_zod10.z.enum(buttonFields).optional(),
1180
- direction: import_zod10.z.enum(directions).default(Direction.rows),
1904
+ border: import_zod22.z.lazy(() => CABBorder),
1905
+ buttonField: import_zod22.z.enum(buttonFields).optional(),
1906
+ direction: import_zod22.z.enum(directions).default(Direction.rows),
1181
1907
  /**
1182
1908
  * Platform chrome around the section, not a layout behavior: `callout` is a subdued box with block borders
1183
1909
  * (the legacy post-purchase callout banner), `offer-content` the post-purchase offer's own content card.
1184
1910
  */
1185
- frame: import_zod10.z.enum(layoutFrames).optional(),
1186
- grid: import_zod10.z.object({
1187
- columns: import_zod10.z.union([import_zod10.z.array(GridItem), import_zod10.z.undefined()]).default(() => ["auto"]),
1188
- rows: import_zod10.z.union([import_zod10.z.array(GridItem), import_zod10.z.undefined()]).default(() => ["auto"])
1911
+ frame: import_zod22.z.enum(layoutFrames).optional(),
1912
+ grid: import_zod22.z.object({
1913
+ columns: import_zod22.z.union([import_zod22.z.array(GridItem), import_zod22.z.undefined()]).default(() => ["auto"]),
1914
+ rows: import_zod22.z.union([import_zod22.z.array(GridItem), import_zod22.z.undefined()]).default(() => ["auto"])
1189
1915
  }).default({ columns: ["auto"], rows: ["auto"] }).optional(),
1190
- name: import_zod10.z.string().optional(),
1191
- padding: import_zod10.z.enum(spacings).default(Spacing.none),
1192
- sectionId: import_zod10.z.uuid().default(() => (0, import_uuid.v7)()),
1193
- sections: import_zod10.z.union([import_zod10.z.array(import_zod10.z.lazy(() => CABSection)), import_zod10.z.strictObject({}).transform(() => [])]).default(() => []),
1194
- sectionType: import_zod10.z.literal(SectionType.layout).default(SectionType.layout),
1195
- spacing: import_zod10.z.enum(spacings).default(Spacing.base),
1916
+ name: import_zod22.z.string().optional(),
1917
+ padding: import_zod22.z.enum(spacings).default(Spacing.none),
1918
+ sectionId: import_zod22.z.uuid().default(() => (0, import_uuid3.v7)()),
1919
+ sections: import_zod22.z.union([import_zod22.z.array(import_zod22.z.lazy(() => CABSection)), import_zod22.z.strictObject({}).transform(() => [])]).default(() => []),
1920
+ sectionType: import_zod22.z.literal(SectionType.layout).default(SectionType.layout),
1921
+ spacing: import_zod22.z.enum(spacings).default(Spacing.base),
1196
1922
  /** Fire-and-forget impression pixel POSTed once when the section is shown (e.g. a Monetize offer view). */
1197
- viewUrl: import_zod10.z.string().optional(),
1198
- width: import_zod10.z.number().default(100),
1923
+ viewUrl: import_zod22.z.string().optional(),
1924
+ width: import_zod22.z.number().default(100),
1199
1925
  wrapping: CABLayoutWrapping.optional()
1200
1926
  });
1201
1927
 
1202
- // src/schema/widgets/checkout-and-beyond/utils.ts
1203
- var import_es_toolkit2 = require("es-toolkit");
1204
- var import_compat = require("es-toolkit/compat");
1205
-
1206
- // src/transforms/convertNumericObjects.ts
1207
- var import_es_toolkit = require("es-toolkit");
1208
- var ARRAY_INDEX_STRING = /^(?:0|[1-9]\d*)$/;
1209
- var hasOnlyNumericKeys = (input, requireCompleteRun) => {
1210
- const keys = Object.keys(input);
1211
- if (keys.length === 0) return false;
1212
- if (!keys.every((key) => ARRAY_INDEX_STRING.test(key) && Number.isSafeInteger(Number(key)))) return false;
1213
- if (!requireCompleteRun) return true;
1214
- const sorted = keys.map(Number).sort((a, b) => a - b);
1215
- return sorted.every((n, i) => n === i);
1216
- };
1217
- var numericObjectToArray = (input) => Object.entries(input).sort(([a], [b]) => Number(a) - Number(b)).map(([, value]) => value);
1218
- var convert = (input, requireCompleteRun) => {
1219
- if (Array.isArray(input)) return input.map((item) => convert(item, requireCompleteRun));
1220
- if ((0, import_es_toolkit.isPlainObject)(input)) {
1221
- if (hasOnlyNumericKeys(input, requireCompleteRun)) {
1222
- return numericObjectToArray(input).map((item) => convert(item, requireCompleteRun));
1223
- }
1224
- const out = {};
1225
- for (const [key, value] of Object.entries(input)) out[key] = convert(value, requireCompleteRun);
1226
- return out;
1227
- }
1228
- return input;
1229
- };
1230
- var convertNumericObjects = (input) => convert(input, true);
1231
-
1232
- // src/schema/widgets/checkout-and-beyond/utils.ts
1233
- var isHTML = (html = "") => {
1234
- if (typeof window !== "undefined") {
1235
- const parser = new DOMParser();
1236
- const doc = parser.parseFromString(html, "text/html");
1237
- const hasHTML = (nodeList) => Array.from(nodeList).some((node) => node.nodeType === 1);
1238
- return hasHTML(doc.body.childNodes) || hasHTML(doc.head.childNodes);
1239
- }
1240
- return html.search(HTML_TAGS_REGEX) !== -1;
1241
- };
1242
- var hasHTMLInDoc = (doc) => doc.content.some(({ content = [] }) => content.some(({ text: text2 }) => isHTML(text2)));
1243
- var checkForHTML = (input) => !((0, import_compat.isString)(input) && isHTML(input) || (0, import_es_toolkit2.isPlainObject)(input) && hasHTMLInDoc(input));
1244
- var NO_HTML = { message: "HTML is not supported" };
1245
- var isSectionType = (sectionType) => (section) => (0, import_compat.get)(section, "sectionType") === sectionType;
1246
- var isBannerType = isSectionType(SectionType.banner);
1247
- var isButtonType = isSectionType(SectionType.button);
1248
- var isCarouselType = isSectionType(SectionType.carousel);
1249
- var isCartLineType = isSectionType(SectionType.cartLine);
1250
- var isDataSourceType = isSectionType(
1251
- SectionType.dataSource
1252
- );
1253
- var isDiscountType = isSectionType(SectionType.discount);
1254
- var isImageType = isSectionType(SectionType.image);
1255
- var isLayoutType = isSectionType(SectionType.layout);
1256
- var isMonetizeType = isSectionType(SectionType.monetize);
1257
- var isOffersType = isSectionType(SectionType.offers);
1258
- var isProductType = isSectionType(SectionType.product);
1259
- var isProductsType = isSectionType(SectionType.products);
1260
- var isProgressBarType = isSectionType(
1261
- SectionType.progressBar
1262
- );
1263
- var isQuantityType = isSectionType(SectionType.quantity);
1264
- var isReviewsType = isSectionType(SectionType.reviews);
1265
- var isTextType = isSectionType(SectionType.text);
1266
- var isVariantsType = isSectionType(SectionType.variants);
1267
-
1268
1928
  // src/schema/widgets/checkout-and-beyond/banner.ts
1269
- var CABBannerSection = import_zod11.z.lazy(
1929
+ var CABBannerSection = import_zod23.z.lazy(
1270
1930
  () => CABLayoutSection.omit({ sectionType: true }).extend({
1271
- buttonField: import_zod11.z.enum(buttonFields).optional(),
1272
- color: import_zod11.z.enum(bannerColors).default("info"),
1273
- dismissible: import_zod11.z.boolean().default(true),
1931
+ buttonField: import_zod23.z.enum(buttonFields).optional(),
1932
+ color: import_zod23.z.enum(bannerColors).default("info"),
1933
+ dismissible: import_zod23.z.boolean().default(true),
1274
1934
  /**
1275
1935
  * The `s-banner` heading — localized content (a buyer can see a merchant-composed banner). Absent OR
1276
1936
  * blank ⇒ no heading; the renderer emits no heading slot for `''` rather than an empty one.
@@ -1286,140 +1946,50 @@ var CABBannerSection = import_zod11.z.lazy(
1286
1946
  * not a 500. Nothing emits `heading` yet; the first converter that maps merchant banner copy into it
1287
1947
  * either strips first or teaches `normalizeTextContent` to strip this field.
1288
1948
  */
1289
- heading: import_zod11.z.record(import_zod11.z.string(), import_zod11.z.string().refine(checkForHTML, NO_HTML)).optional(),
1290
- sectionType: import_zod11.z.literal(SectionType.banner).default(SectionType.banner)
1949
+ heading: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string().refine(checkForHTML, NO_HTML)).optional(),
1950
+ sectionType: import_zod23.z.literal(SectionType.banner).default(SectionType.banner)
1291
1951
  })
1292
1952
  );
1293
1953
 
1294
1954
  // src/schema/widgets/checkout-and-beyond/button.ts
1295
- var import_uuid3 = require("uuid");
1296
- var import_zod13 = require("zod");
1297
-
1298
- // src/schema/widgets/checkout-and-beyond/text.ts
1299
- var import_compat2 = require("es-toolkit/compat");
1300
- var import_uuid2 = require("uuid");
1301
- var import_zod12 = require("zod");
1302
- var enumOrOmit = (...vals) => import_zod12.z.string().transform((val) => vals.includes(val) ? val : void 0).optional();
1303
- var TiptapText = import_zod12.z.object({
1304
- marks: import_zod12.z.union([
1305
- import_zod12.z.array(
1306
- import_zod12.z.discriminatedUnion("type", [
1307
- import_zod12.z.object({ type: import_zod12.z.literal("bold") }),
1308
- import_zod12.z.object({ type: import_zod12.z.literal("italic") }),
1309
- import_zod12.z.object({
1310
- attrs: import_zod12.z.object({
1311
- class: import_zod12.z.string().nullable(),
1312
- href: import_zod12.z.union([
1313
- import_zod12.z.url(),
1314
- import_zod12.z.literal("#"),
1315
- import_zod12.z.string().regex(DYNAMIC_TOKEN_REGEX),
1316
- import_zod12.z.string().regex(ROOT_RELATIVE_PATH_REGEX)
1317
- ]),
1318
- rel: import_zod12.z.string().default("noopener noreferrer nofollow"),
1319
- target: import_zod12.z.string().default("_blank")
1320
- }),
1321
- type: import_zod12.z.literal("link")
1322
- }),
1323
- import_zod12.z.object({ type: import_zod12.z.literal("strike") }),
1324
- import_zod12.z.object({
1325
- attrs: import_zod12.z.object({
1326
- color: enumOrOmit(...textColorNames).default(TextColorName.base),
1327
- fontSize: enumOrOmit(...textSizeNames).default(TextSizeName.base)
1328
- }),
1329
- type: import_zod12.z.literal("textStyle")
1330
- })
1331
- ])
1332
- ),
1333
- import_zod12.z.strictObject({}).transform(() => [])
1334
- ]).optional(),
1335
- text: import_zod12.z.string().default(""),
1336
- type: import_zod12.z.literal("text").default("text")
1337
- });
1338
- var TiptapParagraph = import_zod12.z.object({
1339
- attrs: import_zod12.z.object({
1340
- textAlign: enumOrOmit(...textAlignments)
1341
- }).default({ textAlign: TextAlignment.start }),
1342
- content: import_zod12.z.union([import_zod12.z.array(TiptapText), import_zod12.z.strictObject({}).transform(() => [])]).default(() => []),
1343
- type: import_zod12.z.literal("paragraph").default("paragraph")
1344
- });
1345
- var TiptapDocument = import_zod12.z.object({
1346
- attrs: import_zod12.z.object({
1347
- blockSpacing: enumOrOmit(...spacings)
1348
- }).default({ blockSpacing: Spacing.base }),
1349
- content: import_zod12.z.union([import_zod12.z.array(TiptapParagraph), import_zod12.z.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
1350
- type: import_zod12.z.literal("doc").default("doc")
1351
- });
1352
- var CABTextTier = import_zod12.z.object({
1353
- threshold: import_zod12.z.number().int().nonnegative(),
1354
- thresholds: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.number().int().nonnegative()).default(() => ({})),
1355
- tierId: import_zod12.z.string().optional(),
1356
- tierType: import_zod12.z.enum(progressTierTypes).default(ProgressTierType.shipping)
1357
- });
1358
- var CABTextSection = import_zod12.z.object({
1359
- ...CABVariableFields,
1360
- buttonField: import_zod12.z.enum(buttonFields).optional(),
1361
- content: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.union([import_zod12.z.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
1362
- name: import_zod12.z.string().optional(),
1363
- optionId: import_zod12.z.number().optional(),
1364
- sectionId: import_zod12.z.uuid().default(() => (0, import_uuid2.v7)()),
1365
- sectionType: import_zod12.z.literal(SectionType.text).default(SectionType.text),
1366
- tier: CABTextTier.optional()
1367
- }).superRefine(({ buttonField, content }, ctx) => {
1368
- if (buttonField === ButtonField.destinationUrl && content) {
1369
- (0, import_compat2.forEach)(content, (value, lang) => {
1370
- if (value && (0, import_compat2.isString)(value)) {
1371
- if (DYNAMIC_TOKEN_REGEX.test(value)) return;
1372
- try {
1373
- new URL(value);
1374
- } catch {
1375
- ctx.addIssue({
1376
- code: "custom",
1377
- message: "Invalid URL",
1378
- path: ["content", lang]
1379
- });
1380
- }
1381
- }
1382
- });
1383
- }
1384
- });
1385
-
1386
- // src/schema/widgets/checkout-and-beyond/button.ts
1387
- var CABButtonContent = import_zod13.z.lazy(
1388
- () => import_zod13.z.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
1955
+ var import_uuid4 = require("uuid");
1956
+ var import_zod24 = require("zod");
1957
+ var CABButtonContent = import_zod24.z.lazy(
1958
+ () => import_zod24.z.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
1389
1959
  );
1390
- var CABButtonSection = import_zod13.z.object({
1960
+ var CABButtonSection = import_zod24.z.object({
1391
1961
  ...CABVariableFields,
1392
- action: import_zod13.z.union([import_zod13.z.literal(""), import_zod13.z.enum(buttonActions)]).default(""),
1393
- buttonStyle: import_zod13.z.enum(buttonStyles).default(ButtonStyle.primary),
1394
- custom: import_zod13.z.object({
1395
- color: import_zod13.z.string().regex(HEX_COLOR_REGEX).default("#005bd3"),
1396
- height: import_zod13.z.number().default(52),
1397
- width: import_zod13.z.number().default(300)
1962
+ action: import_zod24.z.union([import_zod24.z.literal(""), import_zod24.z.enum(buttonActions)]).default(""),
1963
+ buttonStyle: import_zod24.z.enum(buttonStyles).default(ButtonStyle.primary),
1964
+ custom: import_zod24.z.object({
1965
+ color: import_zod24.z.string().regex(HEX_COLOR_REGEX).default("#005bd3"),
1966
+ height: import_zod24.z.number().default(52),
1967
+ width: import_zod24.z.number().default(300)
1398
1968
  }).default({
1399
1969
  color: "#005bd3",
1400
1970
  height: 52,
1401
1971
  width: 300
1402
1972
  }),
1403
- disableDowngrade: import_zod13.z.boolean().default(false),
1973
+ disableDowngrade: import_zod24.z.boolean().default(false),
1404
1974
  /**
1405
1975
  * What labels a `switchToSubscription` button's frequency options. `planName` shows the selling plan's
1406
1976
  * own name (legacy post-purchase, L115) and falls back to the `subscriptionOption` template for a plan
1407
1977
  * without one; absent or `template` is the template alone (the checkout card). Optional and additive
1408
1978
  * (REB-24846); an unknown value reads as absent.
1409
1979
  */
1410
- frequencyLabel: import_zod13.z.enum(["planName", "template"]).optional().catch(void 0),
1411
- name: import_zod13.z.string().optional(),
1412
- optionId: import_zod13.z.number().optional(),
1413
- popover: import_zod13.z.object({
1414
- alignment: import_zod13.z.enum(textAlignments).default(TextAlignment.center),
1415
- position: import_zod13.z.enum(popoverPositions).default(PopoverPosition.blockStart)
1980
+ frequencyLabel: import_zod24.z.enum(["planName", "template"]).optional().catch(void 0),
1981
+ name: import_zod24.z.string().optional(),
1982
+ optionId: import_zod24.z.number().optional(),
1983
+ popover: import_zod24.z.object({
1984
+ alignment: import_zod24.z.enum(textAlignments).default(TextAlignment.center),
1985
+ position: import_zod24.z.enum(popoverPositions).default(PopoverPosition.blockStart)
1416
1986
  }).optional().default(() => ({
1417
1987
  alignment: TextAlignment.center,
1418
1988
  position: PopoverPosition.blockStart
1419
1989
  })),
1420
- sectionId: import_zod13.z.uuid().default(() => (0, import_uuid3.v7)()),
1421
- sections: import_zod13.z.union([import_zod13.z.array(CABButtonContent), import_zod13.z.strictObject({}).transform(() => [])]).default(() => []),
1422
- sectionType: import_zod13.z.literal(SectionType.button).default(SectionType.button),
1990
+ sectionId: import_zod24.z.uuid().default(() => (0, import_uuid4.v7)()),
1991
+ sections: import_zod24.z.union([import_zod24.z.array(CABButtonContent), import_zod24.z.strictObject({}).transform(() => [])]).default(() => []),
1992
+ sectionType: import_zod24.z.literal(SectionType.button).default(SectionType.button),
1423
1993
  /**
1424
1994
  * The smart-cart tier this button acts on (`addGift`/`removeGift`): scopes the click to one tier's gift. The
1425
1995
  * client resolves the tier's gift (productId) from the progress-bar context by this `tierId` — the button node
@@ -1434,25 +2004,25 @@ var CABButtonSection = import_zod13.z.object({
1434
2004
  * lookup finds no tier and the click resolves to nothing. Safe to bound — the field is new, so there are no
1435
2005
  * stored payloads to grandfather, and the producer is client code, not a merchant form.
1436
2006
  */
1437
- tier: import_zod13.z.object({ tierId: import_zod13.z.string().min(1) }).optional(),
2007
+ tier: import_zod24.z.object({ tierId: import_zod24.z.string().min(1) }).optional(),
1438
2008
  /** Fire-and-forget pixel POSTed when the button is clicked (e.g. a Monetize decline). */
1439
- trackingUrl: import_zod13.z.string().optional(),
2009
+ trackingUrl: import_zod24.z.string().optional(),
1440
2010
  /**
1441
2011
  * Secondary effects applied to in-scope variables on click, alongside (never instead of) the primary
1442
2012
  * `action` — an `addToOrder` button can also flip a variable. Applied in array order.
1443
2013
  */
1444
- variableEffects: import_zod13.z.array(CABVariableEffect).optional()
2014
+ variableEffects: import_zod24.z.array(CABVariableEffect).optional()
1445
2015
  });
1446
2016
 
1447
2017
  // src/schema/widgets/checkout-and-beyond/carousel.ts
1448
- var import_zod18 = require("zod");
2018
+ var import_zod29 = require("zod");
1449
2019
 
1450
2020
  // src/schema/widgets/checkout-and-beyond/offers.ts
1451
- var import_zod17 = require("zod");
2021
+ var import_zod28 = require("zod");
1452
2022
 
1453
2023
  // src/schema/widgets/checkout-and-beyond/dataSource.ts
1454
- var import_uuid4 = require("uuid");
1455
- var import_zod14 = require("zod");
2024
+ var import_uuid5 = require("uuid");
2025
+ var import_zod25 = require("zod");
1456
2026
 
1457
2027
  // src/schema/widgets/checkout-and-beyond/constants.ts
1458
2028
  var import_es_toolkit3 = require("es-toolkit");
@@ -1506,77 +2076,77 @@ var targetAreas = {
1506
2076
  };
1507
2077
 
1508
2078
  // src/schema/widgets/checkout-and-beyond/dataSource.ts
1509
- var CABDiscount = import_zod14.z.object({
1510
- amount: import_zod14.z.union([import_zod14.z.number(), import_zod14.z.string()]).catch(0),
1511
- discountedBy: import_zod14.z.string().optional(),
1512
- discountedFrom: import_zod14.z.enum(discountSources).optional().catch(void 0),
1513
- type: import_zod14.z.enum(discountTypes).catch("none")
1514
- });
1515
- var CABIntegrations = import_zod14.z.object({
1516
- judgeme: import_zod14.z.boolean().default(false),
1517
- junip: import_zod14.z.boolean().default(false),
1518
- klaviyo: import_zod14.z.boolean().default(false),
1519
- loox: import_zod14.z.boolean().default(false),
1520
- okendo: import_zod14.z.boolean().default(false),
1521
- opinew: import_zod14.z.boolean().default(false),
1522
- reviewsio: import_zod14.z.boolean().default(false),
1523
- stamped: import_zod14.z.boolean().default(false),
1524
- yotpo: import_zod14.z.boolean().default(false)
1525
- });
1526
- var CABVariantLabels = import_zod14.z.object({
1527
- variantOption: import_zod14.z.string().optional().catch(void 0),
1528
- variantOptions: import_zod14.z.string().optional().catch(void 0)
1529
- });
1530
- var CABDataSourceSection = import_zod14.z.object({
1531
- dataSourceId: import_zod14.z.number().nullable().default(null),
1532
- dataSourcePath: import_zod14.z.string().default(DEFAULT_ENDPOINTS[0].value),
2079
+ var CABDiscount = import_zod25.z.object({
2080
+ amount: import_zod25.z.union([import_zod25.z.number(), import_zod25.z.string()]).catch(0),
2081
+ discountedBy: import_zod25.z.string().optional(),
2082
+ discountedFrom: import_zod25.z.enum(discountSources).optional().catch(void 0),
2083
+ type: import_zod25.z.enum(discountTypes).catch("none")
2084
+ });
2085
+ var CABIntegrations = import_zod25.z.object({
2086
+ judgeme: import_zod25.z.boolean().default(false),
2087
+ junip: import_zod25.z.boolean().default(false),
2088
+ klaviyo: import_zod25.z.boolean().default(false),
2089
+ loox: import_zod25.z.boolean().default(false),
2090
+ okendo: import_zod25.z.boolean().default(false),
2091
+ opinew: import_zod25.z.boolean().default(false),
2092
+ reviewsio: import_zod25.z.boolean().default(false),
2093
+ stamped: import_zod25.z.boolean().default(false),
2094
+ yotpo: import_zod25.z.boolean().default(false)
2095
+ });
2096
+ var CABVariantLabels = import_zod25.z.object({
2097
+ variantOption: import_zod25.z.string().optional().catch(void 0),
2098
+ variantOptions: import_zod25.z.string().optional().catch(void 0)
2099
+ });
2100
+ var CABDataSourceSection = import_zod25.z.object({
2101
+ dataSourceId: import_zod25.z.number().nullable().default(null),
2102
+ dataSourcePath: import_zod25.z.string().default(DEFAULT_ENDPOINTS[0].value),
1533
2103
  discount: CABDiscount.optional(),
1534
2104
  integrations: CABIntegrations.optional(),
1535
- limit: import_zod14.z.number().default(1),
1536
- matchVariant: import_zod14.z.boolean().default(false),
1537
- matchVariantOutOfStock: import_zod14.z.boolean().default(false),
1538
- name: import_zod14.z.string().default(DEFAULT_ENDPOINTS[0].label),
1539
- productType: import_zod14.z.enum(productTypes).optional(),
1540
- sectionId: import_zod14.z.uuid().default(() => (0, import_uuid4.v7)()),
1541
- sectionType: import_zod14.z.literal(SectionType.dataSource).default(SectionType.dataSource),
2105
+ limit: import_zod25.z.number().default(1),
2106
+ matchVariant: import_zod25.z.boolean().default(false),
2107
+ matchVariantOutOfStock: import_zod25.z.boolean().default(false),
2108
+ name: import_zod25.z.string().default(DEFAULT_ENDPOINTS[0].label),
2109
+ productType: import_zod25.z.enum(productTypes).optional(),
2110
+ sectionId: import_zod25.z.uuid().default(() => (0, import_uuid5.v7)()),
2111
+ sectionType: import_zod25.z.literal(SectionType.dataSource).default(SectionType.dataSource),
1542
2112
  /** Default subscribe-vs-one-time for `productType: both` (legacy `subscription_is_default`). */
1543
- subscriptionIsDefault: import_zod14.z.boolean().default(false),
1544
- treatAsGwp: import_zod14.z.boolean().default(false),
2113
+ subscriptionIsDefault: import_zod25.z.boolean().default(false),
2114
+ treatAsGwp: import_zod25.z.boolean().default(false),
1545
2115
  variantLabels: CABVariantLabels.optional().catch(void 0)
1546
2116
  });
1547
2117
 
1548
2118
  // src/schema/widgets/checkout-and-beyond/products.ts
1549
- var import_uuid6 = require("uuid");
1550
- var import_zod16 = require("zod");
2119
+ var import_uuid7 = require("uuid");
2120
+ var import_zod27 = require("zod");
1551
2121
 
1552
2122
  // src/schema/widgets/checkout-and-beyond/product.ts
1553
- var import_uuid5 = require("uuid");
1554
- var import_zod15 = require("zod");
1555
- var CABVariantContent = import_zod15.z.lazy(
1556
- () => import_zod15.z.discriminatedUnion("sectionType", [CABButtonSection, CABTextSection])
2123
+ var import_uuid6 = require("uuid");
2124
+ var import_zod26 = require("zod");
2125
+ var CABVariantContent = import_zod26.z.lazy(
2126
+ () => import_zod26.z.discriminatedUnion("sectionType", [CABButtonSection, CABTextSection])
1557
2127
  );
1558
- var CABProductSection = import_zod15.z.object({
2128
+ var CABProductSection = import_zod26.z.object({
1559
2129
  ...CABVariableFields,
1560
- name: import_zod15.z.string().optional(),
1561
- productId: import_zod15.z.number().nullable().default(null),
1562
- sectionId: import_zod15.z.uuid().default(() => (0, import_uuid5.v7)()),
1563
- sections: import_zod15.z.union([import_zod15.z.array(CABVariantContent), import_zod15.z.strictObject({}).transform(() => [])]).default(() => []),
1564
- sectionType: import_zod15.z.literal(SectionType.product).default(SectionType.product),
1565
- selectors: import_zod15.z.record(import_zod15.z.string(), import_zod15.z.enum(variantSelectors).default(VariantSelector.menu)).default(() => ({})),
1566
- variantMode: import_zod15.z.enum(variantModes).default(VariantMode.multiple)
2130
+ name: import_zod26.z.string().optional(),
2131
+ productId: import_zod26.z.number().nullable().default(null),
2132
+ sectionId: import_zod26.z.uuid().default(() => (0, import_uuid6.v7)()),
2133
+ sections: import_zod26.z.union([import_zod26.z.array(CABVariantContent), import_zod26.z.strictObject({}).transform(() => [])]).default(() => []),
2134
+ sectionType: import_zod26.z.literal(SectionType.product).default(SectionType.product),
2135
+ selectors: import_zod26.z.record(import_zod26.z.string(), import_zod26.z.enum(variantSelectors).default(VariantSelector.menu)).default(() => ({})),
2136
+ variantMode: import_zod26.z.enum(variantModes).default(VariantMode.multiple)
1567
2137
  });
1568
2138
 
1569
2139
  // src/schema/widgets/checkout-and-beyond/products.ts
1570
- var CABProductsSection = import_zod16.z.object({
2140
+ var CABProductsSection = import_zod27.z.object({
1571
2141
  ...CABVariableFields,
1572
- name: import_zod16.z.string().optional(),
1573
- sectionId: import_zod16.z.uuid().default(() => (0, import_uuid6.v7)()),
1574
- sections: import_zod16.z.union([import_zod16.z.array(import_zod16.z.lazy(() => CABProductSection)), import_zod16.z.strictObject({}).transform(() => [])]).default(() => []),
1575
- sectionType: import_zod16.z.literal(SectionType.products).default(SectionType.products)
2142
+ name: import_zod27.z.string().optional(),
2143
+ sectionId: import_zod27.z.uuid().default(() => (0, import_uuid7.v7)()),
2144
+ sections: import_zod27.z.union([import_zod27.z.array(import_zod27.z.lazy(() => CABProductSection)), import_zod27.z.strictObject({}).transform(() => [])]).default(() => []),
2145
+ sectionType: import_zod27.z.literal(SectionType.products).default(SectionType.products)
1576
2146
  });
1577
2147
 
1578
2148
  // src/schema/widgets/checkout-and-beyond/offers.ts
1579
- var CABOffersSection = import_zod17.z.lazy(
2149
+ var CABOffersSection = import_zod28.z.lazy(
1580
2150
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
1581
2151
  /**
1582
2152
  * A rule between consecutive cards in the vertical list — legacy checkout-offers' `<Divider />`,
@@ -1584,8 +2154,8 @@ var CABOffersSection = import_zod17.z.lazy(
1584
2154
  * run of products). Optional, not defaulted: only the v1 converter sets it (REB-24265); a
1585
2155
  * hand-built tree keeps React CAB's dividerless rendering.
1586
2156
  */
1587
- divider: import_zod17.z.boolean().optional(),
1588
- sections: import_zod17.z.union([import_zod17.z.array(import_zod17.z.lazy(() => CABSection)), import_zod17.z.strictObject({}).transform(() => [])]).default(() => [
2157
+ divider: import_zod28.z.boolean().optional(),
2158
+ sections: import_zod28.z.union([import_zod28.z.array(import_zod28.z.lazy(() => CABSection)), import_zod28.z.strictObject({}).transform(() => [])]).default(() => [
1589
2159
  CABBannerSection.parse({
1590
2160
  buttonField: "undoAddToOrder",
1591
2161
  color: "success",
@@ -1599,77 +2169,77 @@ var CABOffersSection = import_zod17.z.lazy(
1599
2169
  CABDataSourceSection.parse({}),
1600
2170
  CABProductsSection.parse({})
1601
2171
  ]),
1602
- sectionType: import_zod17.z.literal(SectionType.offers).default(SectionType.offers)
2172
+ sectionType: import_zod28.z.literal(SectionType.offers).default(SectionType.offers)
1603
2173
  })
1604
2174
  );
1605
2175
 
1606
2176
  // src/schema/widgets/checkout-and-beyond/carousel.ts
1607
- var CABCarouselSection = import_zod18.z.lazy(
2177
+ var CABCarouselSection = import_zod29.z.lazy(
1608
2178
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
1609
- autoAdvanceInterval: import_zod18.z.number().default(0),
1610
- itemsAtOnce: import_zod18.z.number().min(1).default(1),
2179
+ autoAdvanceInterval: import_zod29.z.number().default(0),
2180
+ itemsAtOnce: import_zod29.z.number().min(1).default(1),
1611
2181
  /** Card arrangement for the offers child (`horizontal` = side-by-side) — NOT the carousel's own `direction`. */
1612
- offersDirection: import_zod18.z.enum(offersDirections).default("vertical"),
1613
- sections: import_zod18.z.union([import_zod18.z.array(import_zod18.z.lazy(() => CABSection)), import_zod18.z.strictObject({}).transform(() => [])]).default(() => [CABOffersSection.parse({})]),
1614
- sectionType: import_zod18.z.literal(SectionType.carousel).default(SectionType.carousel)
2182
+ offersDirection: import_zod29.z.enum(offersDirections).default("vertical"),
2183
+ sections: import_zod29.z.union([import_zod29.z.array(import_zod29.z.lazy(() => CABSection)), import_zod29.z.strictObject({}).transform(() => [])]).default(() => [CABOffersSection.parse({})]),
2184
+ sectionType: import_zod29.z.literal(SectionType.carousel).default(SectionType.carousel)
1615
2185
  })
1616
2186
  );
1617
2187
 
1618
2188
  // src/schema/widgets/checkout-and-beyond/cartLine.ts
1619
- var import_zod19 = require("zod");
1620
- var CABCartLineSection = import_zod19.z.lazy(
2189
+ var import_zod30 = require("zod");
2190
+ var CABCartLineSection = import_zod30.z.lazy(
1621
2191
  () => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
1622
- sections: import_zod19.z.union([import_zod19.z.array(import_zod19.z.lazy(() => CABSection)), import_zod19.z.strictObject({}).transform(() => [])]).default(() => [CABButtonSection.parse({ action: ButtonAction.switchToSubscription })]),
1623
- sectionType: import_zod19.z.literal(SectionType.cartLine).default(SectionType.cartLine)
2192
+ sections: import_zod30.z.union([import_zod30.z.array(import_zod30.z.lazy(() => CABSection)), import_zod30.z.strictObject({}).transform(() => [])]).default(() => [CABButtonSection.parse({ action: ButtonAction.switchToSubscription })]),
2193
+ sectionType: import_zod30.z.literal(SectionType.cartLine).default(SectionType.cartLine)
1624
2194
  })
1625
2195
  );
1626
2196
 
1627
2197
  // src/schema/widgets/checkout-and-beyond/discount.ts
1628
- var import_uuid7 = require("uuid");
1629
- var import_zod20 = require("zod");
1630
- var CABDiscountSection = import_zod20.z.object({
2198
+ var import_uuid8 = require("uuid");
2199
+ var import_zod31 = require("zod");
2200
+ var CABDiscountSection = import_zod31.z.object({
1631
2201
  ...CABVariableFields,
1632
- amount: import_zod20.z.union([import_zod20.z.number(), import_zod20.z.string()]).catch(0),
1633
- discountedBy: import_zod20.z.string().optional(),
1634
- discountedFrom: import_zod20.z.enum(discountSources).optional().catch(void 0),
1635
- message: import_zod20.z.string().optional(),
1636
- name: import_zod20.z.string().optional(),
1637
- quantity: import_zod20.z.number().default(1),
1638
- sectionId: import_zod20.z.uuid().default(() => (0, import_uuid7.v7)()),
1639
- sectionType: import_zod20.z.literal(SectionType.discount).default(SectionType.discount),
1640
- type: import_zod20.z.enum(discountTypes).catch("none")
2202
+ amount: import_zod31.z.union([import_zod31.z.number(), import_zod31.z.string()]).catch(0),
2203
+ discountedBy: import_zod31.z.string().optional(),
2204
+ discountedFrom: import_zod31.z.enum(discountSources).optional().catch(void 0),
2205
+ message: import_zod31.z.string().optional(),
2206
+ name: import_zod31.z.string().optional(),
2207
+ quantity: import_zod31.z.number().default(1),
2208
+ sectionId: import_zod31.z.uuid().default(() => (0, import_uuid8.v7)()),
2209
+ sectionType: import_zod31.z.literal(SectionType.discount).default(SectionType.discount),
2210
+ type: import_zod31.z.enum(discountTypes).catch("none")
1641
2211
  });
1642
2212
 
1643
2213
  // src/schema/widgets/checkout-and-beyond/monetize.ts
1644
- var import_uuid8 = require("uuid");
1645
- var import_zod21 = require("zod");
1646
- var CABMonetizeAds = import_zod21.z.object({
1647
- requestId: import_zod21.z.string().optional(),
2214
+ var import_uuid9 = require("uuid");
2215
+ var import_zod32 = require("zod");
2216
+ var CABMonetizeAds = import_zod32.z.object({
2217
+ requestId: import_zod32.z.string().optional(),
1648
2218
  /** Defaulted here, never in the beacon: absence of information is `ads` itself being absent. */
1649
- testing: import_zod21.z.boolean().default(false)
2219
+ testing: import_zod32.z.boolean().default(false)
1650
2220
  });
1651
- var CABMonetizeSection = import_zod21.z.object({
2221
+ var CABMonetizeSection = import_zod32.z.object({
1652
2222
  ...CABVariableFields,
1653
2223
  ads: CABMonetizeAds.optional(),
1654
- name: import_zod21.z.string().optional(),
2224
+ name: import_zod32.z.string().optional(),
1655
2225
  /**
1656
2226
  * Server-hydrated offer cards (inline hydration): when `/cab/sections` was asked with a `monetize`
1657
2227
  * context block, the composed cards ride the marker itself — `[]` means "hydrated, no fill" (render
1658
2228
  * nothing, skip the fetch); ABSENT means "not hydrated" (the client fetches via `/cab/monetize`).
1659
2229
  */
1660
- offers: import_zod21.z.array(import_zod21.z.lazy(() => CABSection)).optional(),
2230
+ offers: import_zod32.z.array(import_zod32.z.lazy(() => CABSection)).optional(),
1661
2231
  /** 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. */
1662
- privacyPolicyUrl: import_zod21.z.string().optional(),
1663
- sectionId: import_zod21.z.uuid().default(() => (0, import_uuid8.v7)()),
1664
- sectionType: import_zod21.z.literal(SectionType.monetize).default(SectionType.monetize),
2232
+ privacyPolicyUrl: import_zod32.z.string().optional(),
2233
+ sectionId: import_zod32.z.uuid().default(() => (0, import_uuid9.v7)()),
2234
+ sectionType: import_zod32.z.literal(SectionType.monetize).default(SectionType.monetize),
1665
2235
  /** Ads-taxonomy sub-vertical id (the widget's `sub_vertical` setting); paired with `vertical`. */
1666
- subVertical: import_zod21.z.string().optional(),
2236
+ subVertical: import_zod32.z.string().optional(),
1667
2237
  /** Ads-taxonomy vertical id (the widget's `vertical` setting) — with `subVertical`, the admin Monetize editor's two configurables. */
1668
- vertical: import_zod21.z.string().optional()
2238
+ vertical: import_zod32.z.string().optional()
1669
2239
  });
1670
2240
 
1671
2241
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1672
- var import_zod22 = require("zod");
2242
+ var import_zod33 = require("zod");
1673
2243
 
1674
2244
  // src/schema/widgets/checkout-and-beyond/giftLabels.ts
1675
2245
  var GIFT_LABELS = {
@@ -1788,34 +2358,34 @@ var GIFT_LABELS = {
1788
2358
  };
1789
2359
 
1790
2360
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1791
- var CABProgressTierExclusion = import_zod22.z.object({
1792
- collectionIds: import_zod22.z.array(import_zod22.z.number().int().positive()).default(() => []),
1793
- productIds: import_zod22.z.array(import_zod22.z.number().int().positive()).default(() => []),
1794
- tags: import_zod22.z.array(import_zod22.z.string().min(1)).default(() => []),
1795
- type: import_zod22.z.enum(progressTierExclusionTypes)
2361
+ var CABProgressTierExclusion = import_zod33.z.object({
2362
+ collectionIds: import_zod33.z.array(import_zod33.z.number().int().positive()).default(() => []),
2363
+ productIds: import_zod33.z.array(import_zod33.z.number().int().positive()).default(() => []),
2364
+ tags: import_zod33.z.array(import_zod33.z.string().min(1)).default(() => []),
2365
+ type: import_zod33.z.enum(progressTierExclusionTypes)
1796
2366
  });
1797
- var CABProgressTier = import_zod22.z.object({
2367
+ var CABProgressTier = import_zod33.z.object({
1798
2368
  /**
1799
2369
  * Order-discount tiers only (onsite `discount`): the reward the order-discount Function applies at
1800
2370
  * cart time, carried so the client can resolve the `{{discountAmount}}` token in this tier's copy.
1801
2371
  * `fixedAmount`: shop-currency CENTS (FX-scaled by the client, like {@link CABProgressTier.threshold});
1802
2372
  * `percentage`: the whole-percent number rendered raw (`{n}%`). Absent on non-discount tiers.
1803
2373
  */
1804
- discount: import_zod22.z.object({ amount: import_zod22.z.number().nonnegative(), type: import_zod22.z.enum(["fixedAmount", "percentage"]) }).optional(),
2374
+ discount: import_zod33.z.object({ amount: import_zod33.z.number().nonnegative(), type: import_zod33.z.enum(["fixedAmount", "percentage"]) }).optional(),
1805
2375
  /**
1806
2376
  * Per-tier exclusion rules (onsite `exclusions` when `exclusions_enabled`): lines they match don't count
1807
2377
  * toward this tier. Empty (the default, and the converter's output for a disabled or ruleless tier) means
1808
2378
  * the tier measures the plain bar-level adjusted progress. Consumers read ONLY the list named by the rule's
1809
2379
  * `type` — the converter leaves the other two at `[]`, so a populated off-type list never reaches the tree.
1810
2380
  */
1811
- exclusions: import_zod22.z.array(CABProgressTierExclusion).default(() => []),
2381
+ exclusions: import_zod33.z.array(CABProgressTierExclusion).default(() => []),
1812
2382
  /**
1813
2383
  * Smart-cart product (gift) tiers only (onsite `filter_oos_variants`): when set, the client drops this
1814
2384
  * tier entirely once its gift has NO in-stock eligible variant — the milestone, fill slot and gift
1815
2385
  * controls all disappear, mirroring onsite removing the tier from `bar.tiers` before it renders. Absent
1816
2386
  * on shipping/discount/decorative tiers and left off by default (the tier renders regardless of stock).
1817
2387
  */
1818
- filterOosVariants: import_zod22.z.boolean().default(false),
2388
+ filterOosVariants: import_zod33.z.boolean().default(false),
1819
2389
  /**
1820
2390
  * Smart-cart product (gift) tiers only: the reward unlocked at this tier. The client enriches
1821
2391
  * `productId`/`variantIds` to live variants (availability, price) and adds the chosen one to the cart
@@ -1823,10 +2393,10 @@ var CABProgressTier = import_zod22.z.object({
1823
2393
  * tiers and on tiers with no configured product. Cart add/remove is a later stage; carried here so the
1824
2394
  * tree is complete.
1825
2395
  */
1826
- gift: import_zod22.z.object({
1827
- productId: import_zod22.z.number().int().positive(),
1828
- title: import_zod22.z.string().optional(),
1829
- variantIds: import_zod22.z.array(import_zod22.z.number().int().positive()).default(() => [])
2396
+ gift: import_zod33.z.object({
2397
+ productId: import_zod33.z.number().int().positive(),
2398
+ title: import_zod33.z.string().optional(),
2399
+ variantIds: import_zod33.z.array(import_zod33.z.number().int().positive()).default(() => [])
1830
2400
  }).optional(),
1831
2401
  /**
1832
2402
  * The step-row icon's square size in PIXELS (onsite `product_tier_element_size`, an admin px string the
@@ -1846,7 +2416,7 @@ var CABProgressTier = import_zod22.z.object({
1846
2416
  * renderer never spells a fallback), which also makes a tree authored before this field render at
1847
2417
  * React's size rather than the old hardcoded 20.
1848
2418
  */
1849
- iconSizePx: import_zod22.z.number().int().min(1).max(64).default(18),
2419
+ iconSizePx: import_zod33.z.number().int().min(1).max(64).default(18),
1850
2420
  /**
1851
2421
  * The step-row label at this tier's slot (onsite `getTierLabel`): the merchant custom label, else the
1852
2422
  * type default — 'Free Shipping' or '{n}% Discount'. A PRODUCT tier gets NO converter label: its name is
@@ -1856,35 +2426,35 @@ var CABProgressTier = import_zod22.z.object({
1856
2426
  * turns a blank label into an absent key, and a client-authored blank means the same thing — the renderer
1857
2427
  * emits no caption slot rather than an empty one). Plain text — a compact icon+label.
1858
2428
  */
1859
- label: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.string()).optional(),
2429
+ label: import_zod33.z.record(import_zod33.z.string(), import_zod33.z.string()).optional(),
1860
2430
  /**
1861
2431
  * Smart-cart product (gift) tiers only (onsite `product_tier_image`): show the gift's product image in
1862
2432
  * the step-row slot instead of the generic bag icon. The converter can't supply the image URL (config
1863
2433
  * carries only product IDs), so the client resolves it (authoritative Shopify featured image, React
1864
2434
  * parity) and falls back to the bag icon when the flag is off or no image resolves. Default false.
1865
2435
  */
1866
- productTierImage: import_zod22.z.boolean().default(false),
2436
+ productTierImage: import_zod33.z.boolean().default(false),
1867
2437
  /**
1868
2438
  * The tier's goal, measured per `unit`. `currency` (default): SHOP-currency cents — the canonical
1869
2439
  * fallback: when the buyer's presentment currency has no entry in `thresholds`, the client
1870
2440
  * multiplies this by the live FX rate (converter maps the v1 `unlock_price`, e.g. `75` → `7500`).
1871
2441
  * `item`: a raw item count — no cents, no FX, no `thresholds` overrides.
1872
2442
  */
1873
- threshold: import_zod22.z.number().int().nonnegative(),
2443
+ threshold: import_zod33.z.number().int().nonnegative(),
1874
2444
  /**
1875
2445
  * Per-presentment-currency goal overrides — lowercased ISO currency code → cents (e.g. `{ cad: 9900 }`).
1876
2446
  * When the buyer's currency has an entry, the client uses it verbatim INSTEAD of FX-converting
1877
2447
  * `threshold`, so merchants show intentional, clean per-market amounts (Shopify Markets) rather than a
1878
2448
  * converted base. Defaults to `{}` — no overrides means always fall back to `threshold`.
1879
2449
  */
1880
- thresholds: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.number().int().nonnegative()).default(() => ({})),
2450
+ thresholds: import_zod33.z.record(import_zod33.z.string(), import_zod33.z.number().int().nonnegative()).default(() => ({})),
1881
2451
  /**
1882
2452
  * Smart-cart tier identifier, mirrored onto the gift cart line's `_tier` attribute so the client can
1883
2453
  * match an in-cart gift back to its tier (add on reach, remove on downgrade/decline). Absent on the
1884
2454
  * shipping bar (single unlabeled tier, no gift).
1885
2455
  */
1886
- tierId: import_zod22.z.string().optional(),
1887
- tierType: import_zod22.z.enum(progressTierTypes).default(ProgressTierType.shipping),
2456
+ tierId: import_zod33.z.string().optional(),
2457
+ tierType: import_zod33.z.enum(progressTierTypes).default(ProgressTierType.shipping),
1888
2458
  /**
1889
2459
  * What this tier's progress is measured in — PER TIER (onsite's `unlock_condition_type` model, NOT
1890
2460
  * the React port's bar-level `tiers[0]` shortcut). `currency` compares money cents against the
@@ -1895,9 +2465,9 @@ var CABProgressTier = import_zod22.z.object({
1895
2465
  * count carries no injected noun (no English `item`/`items` inflection on localized copy); merchant
1896
2466
  * template text supplies grammatically-neutral wording around the token.
1897
2467
  */
1898
- unit: import_zod22.z.enum(progressTierUnits).default(ProgressTierUnit.currency)
2468
+ unit: import_zod33.z.enum(progressTierUnits).default(ProgressTierUnit.currency)
1899
2469
  });
1900
- var CABProgressBarSection = import_zod22.z.lazy(
2470
+ var CABProgressBarSection = import_zod33.z.lazy(
1901
2471
  () => CABLayoutSection.omit({ sectionType: true }).extend({
1902
2472
  /**
1903
2473
  * The onsite bar id (smart-cart TPB bars only). The client mirrors it to the cart's `_barId` attribute
@@ -1906,35 +2476,35 @@ var CABProgressBarSection = import_zod22.z.lazy(
1906
2476
  * checkout reaches the extension without it, so the client writes it or the tier gift's 100% discount
1907
2477
  * (and any tier order discount) never applies. Absent on the v1 shipping bar (no gift tiers, no id).
1908
2478
  */
1909
- barId: import_zod22.z.string().optional(),
2479
+ barId: import_zod33.z.string().optional(),
1910
2480
  /** Empty = shown everywhere; otherwise uppercase ISO country codes. */
1911
- countryCodes: import_zod22.z.array(import_zod22.z.string().transform((code) => code.trim().toUpperCase())).default(() => []),
2481
+ countryCodes: import_zod33.z.array(import_zod33.z.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1912
2482
  /**
1913
2483
  * Uppercase ISO codes where a higher-precedence geo bar applies, so this (default, non-geo) bar is
1914
2484
  * hidden there — replicates React `getbar`'s geo-match-over-default precedence. Empty = never excluded.
1915
2485
  */
1916
- excludeCountryCodes: import_zod22.z.array(import_zod22.z.string().transform((code) => code.trim().toUpperCase())).default(() => []),
2486
+ excludeCountryCodes: import_zod33.z.array(import_zod33.z.string().transform((code) => code.trim().toUpperCase())).default(() => []),
1917
2487
  /**
1918
2488
  * Measure progress against the PRE-discount subtotal (onsite `exclude_discount_in_subtotal`, and
1919
2489
  * forced on for bars with a discount tier so its own reward can't un-reach the tier). The client
1920
2490
  * adds the cart's discount allocations back to the live subtotal.
1921
2491
  */
1922
- excludeDiscountInSubtotal: import_zod22.z.boolean().default(false),
2492
+ excludeDiscountInSubtotal: import_zod33.z.boolean().default(false),
1923
2493
  /** Variant ids the client subtracts from the adjusted subtotal (React `bar.excluded_products`). */
1924
- excludedVariantIds: import_zod22.z.array(import_zod22.z.number().int().positive()).default(() => []),
2494
+ excludedVariantIds: import_zod33.z.array(import_zod33.z.number().int().positive()).default(() => []),
1925
2495
  /**
1926
2496
  * When the cart holds a subscription item, treat the bar as reached regardless of subtotal (React
1927
2497
  * `free_shipping_on_subscription(s)`). `freeShippingOnAll` is already a zero-threshold tier instead.
1928
2498
  */
1929
- freeShippingOnSubscription: import_zod22.z.boolean().default(false),
2499
+ freeShippingOnSubscription: import_zod33.z.boolean().default(false),
1930
2500
  /** Localized heading over the gift controls (onsite `gift_area_title`, default 'FREE GIFTS'). */
1931
- giftAreaTitle: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.string()).default(() => ({ en: "FREE GIFTS" })),
2501
+ giftAreaTitle: import_zod33.z.record(import_zod33.z.string(), import_zod33.z.string()).default(() => ({ en: "FREE GIFTS" })),
1932
2502
  /** Localized gift-control labels (add/remove/heading); a tier's gift `title` beats `yourGift`. */
1933
- giftLabels: import_zod22.z.object({
1934
- addGift: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.string()).default(() => ({ ...GIFT_LABELS.addGift })),
1935
- remove: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.string()).default(() => ({ ...GIFT_LABELS.remove })),
1936
- selectOptions: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.string()).default(() => ({ ...GIFT_LABELS.selectOptions })),
1937
- yourGift: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.string()).default(() => ({ ...GIFT_LABELS.yourGift }))
2503
+ giftLabels: import_zod33.z.object({
2504
+ addGift: import_zod33.z.record(import_zod33.z.string(), import_zod33.z.string()).default(() => ({ ...GIFT_LABELS.addGift })),
2505
+ remove: import_zod33.z.record(import_zod33.z.string(), import_zod33.z.string()).default(() => ({ ...GIFT_LABELS.remove })),
2506
+ selectOptions: import_zod33.z.record(import_zod33.z.string(), import_zod33.z.string()).default(() => ({ ...GIFT_LABELS.selectOptions })),
2507
+ yourGift: import_zod33.z.record(import_zod33.z.string(), import_zod33.z.string()).default(() => ({ ...GIFT_LABELS.yourGift }))
1938
2508
  }).default(() => ({
1939
2509
  addGift: { ...GIFT_LABELS.addGift },
1940
2510
  remove: { ...GIFT_LABELS.remove },
@@ -1942,38 +2512,38 @@ var CABProgressBarSection = import_zod22.z.lazy(
1942
2512
  yourGift: { ...GIFT_LABELS.yourGift }
1943
2513
  })),
1944
2514
  /** The bar's a11y label; the merchant names it in the editor, else this default (React parity). */
1945
- name: import_zod22.z.string().default("Order progress"),
2515
+ name: import_zod33.z.string().default("Order progress"),
1946
2516
  /**
1947
2517
  * Bar fill color. An explicit (widget-authored) value is used verbatim; when absent the server
1948
2518
  * fills it with the live shop theme's `buttonBackground` (React `useRebuyTheme` parity). Still
1949
2519
  * absent after that ⇒ the theme fetch failed and the client renders its platform-default bar —
1950
2520
  * optional, not defaulted, so "merchant chose no color" stays distinguishable from any real value.
1951
2521
  */
1952
- progressColor: import_zod22.z.string().optional(),
1953
- sectionType: import_zod22.z.literal(SectionType.progressBar).default(SectionType.progressBar),
2522
+ progressColor: import_zod33.z.string().optional(),
2523
+ sectionType: import_zod33.z.literal(SectionType.progressBar).default(SectionType.progressBar),
1954
2524
  /**
1955
2525
  * The bar's milestones in the merchant's CONFIGURED order — the renderer does NOT sort them (022
1956
2526
  * O-B2: sorting by resolved threshold reversed configured milestones on out-of-order or mixed-unit
1957
2527
  * count-vs-cents bars). Drives the fill (even slot per tier) and, for smart-cart product tiers, the
1958
2528
  * gift add/remove. The visual tier display lives in `sections` (composable), NOT here.
1959
2529
  */
1960
- tiers: import_zod22.z.union([import_zod22.z.array(CABProgressTier), import_zod22.z.strictObject({}).transform(() => [])]).default(() => [])
2530
+ tiers: import_zod33.z.union([import_zod33.z.array(CABProgressTier), import_zod33.z.strictObject({}).transform(() => [])]).default(() => [])
1961
2531
  })
1962
2532
  );
1963
2533
 
1964
2534
  // src/schema/widgets/checkout-and-beyond/quantity.ts
1965
- var import_uuid9 = require("uuid");
1966
- var import_zod23 = require("zod");
1967
- var CABQuantitySection = import_zod23.z.object({
2535
+ var import_uuid10 = require("uuid");
2536
+ var import_zod34 = require("zod");
2537
+ var CABQuantitySection = import_zod34.z.object({
1968
2538
  ...CABVariableFields,
1969
- errorMessages: import_zod23.z.record(
1970
- import_zod23.z.string(),
1971
- import_zod23.z.object({
2539
+ errorMessages: import_zod34.z.record(
2540
+ import_zod34.z.string(),
2541
+ import_zod34.z.object({
1972
2542
  /** `{{step}}` is interpolated at render — the off-increment message React never gave a merchant key. */
1973
- increment: import_zod23.z.string().optional(),
1974
- max: import_zod23.z.string().optional(),
1975
- min: import_zod23.z.string().optional(),
1976
- neg: import_zod23.z.string().optional()
2543
+ increment: import_zod34.z.string().optional(),
2544
+ max: import_zod34.z.string().optional(),
2545
+ min: import_zod34.z.string().optional(),
2546
+ neg: import_zod34.z.string().optional()
1977
2547
  })
1978
2548
  ).default({
1979
2549
  en: {
@@ -1983,18 +2553,18 @@ var CABQuantitySection = import_zod23.z.object({
1983
2553
  neg: "Quantity cannot be negative"
1984
2554
  }
1985
2555
  }),
1986
- inputType: import_zod23.z.enum(quantityInputs).default(QuantityInput.select),
1987
- max: import_zod23.z.number().min(1).max(100).default(10),
1988
- min: import_zod23.z.number().min(1).default(1),
2556
+ inputType: import_zod34.z.enum(quantityInputs).default(QuantityInput.select),
2557
+ max: import_zod34.z.number().min(1).max(100).default(10),
2558
+ min: import_zod34.z.number().min(1).default(1),
1989
2559
  /** The a11y label for the quantity control; the merchant names it in the editor, else this default. */
1990
- name: import_zod23.z.string().default("Quantity"),
1991
- sectionId: import_zod23.z.uuid().default(() => (0, import_uuid9.v7)()),
1992
- sectionType: import_zod23.z.literal(SectionType.quantity).default(SectionType.quantity)
2560
+ name: import_zod34.z.string().default("Quantity"),
2561
+ sectionId: import_zod34.z.uuid().default(() => (0, import_uuid10.v7)()),
2562
+ sectionType: import_zod34.z.literal(SectionType.quantity).default(SectionType.quantity)
1993
2563
  });
1994
2564
 
1995
2565
  // src/schema/widgets/checkout-and-beyond/reviews.ts
1996
- var import_uuid10 = require("uuid");
1997
- var import_zod24 = require("zod");
2566
+ var import_uuid11 = require("uuid");
2567
+ var import_zod35 = require("zod");
1998
2568
 
1999
2569
  // src/schema/widgets/checkout-and-beyond/reviewLabels.ts
2000
2570
  var REVIEW_LABELS = {
@@ -2057,49 +2627,49 @@ var REVIEW_LABELS = {
2057
2627
  };
2058
2628
 
2059
2629
  // src/schema/widgets/checkout-and-beyond/reviews.ts
2060
- var CABReviewsSection = import_zod24.z.object({
2630
+ var CABReviewsSection = import_zod35.z.object({
2061
2631
  ...CABVariableFields,
2062
- color: import_zod24.z.string().default("#fadb14"),
2632
+ color: import_zod35.z.string().default("#fadb14"),
2063
2633
  /**
2064
2634
  * Localized review-count templates (`{{reviewCount}}`), one/other plural forms; the client picks the
2065
2635
  * form via `Intl.PluralRules`. Defaults here (schema-first) so every tree localizes without converter
2066
2636
  * or merchant work.
2067
2637
  */
2068
- countLabels: import_zod24.z.object({
2069
- one: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).default(() => ({ ...REVIEW_LABELS.one })),
2070
- other: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).default(() => ({ ...REVIEW_LABELS.other }))
2638
+ countLabels: import_zod35.z.object({
2639
+ one: import_zod35.z.record(import_zod35.z.string(), import_zod35.z.string()).default(() => ({ ...REVIEW_LABELS.one })),
2640
+ other: import_zod35.z.record(import_zod35.z.string(), import_zod35.z.string()).default(() => ({ ...REVIEW_LABELS.other }))
2071
2641
  }).default(() => ({ one: { ...REVIEW_LABELS.one }, other: { ...REVIEW_LABELS.other } })),
2072
- name: import_zod24.z.string().optional(),
2073
- sectionId: import_zod24.z.uuid().default(() => (0, import_uuid10.v7)()),
2074
- sectionType: import_zod24.z.literal(SectionType.reviews).default(SectionType.reviews),
2075
- size: import_zod24.z.enum(reviewsSizes).default(ReviewsSize.default),
2642
+ name: import_zod35.z.string().optional(),
2643
+ sectionId: import_zod35.z.uuid().default(() => (0, import_uuid11.v7)()),
2644
+ sectionType: import_zod35.z.literal(SectionType.reviews).default(SectionType.reviews),
2645
+ size: import_zod35.z.enum(reviewsSizes).default(ReviewsSize.default),
2076
2646
  /**
2077
2647
  * Star outline color, interpolated into a style by the renderer, so it is hex-constrained like
2078
2648
  * `CABButtonSection.color`. The legacy source (`PostPurchaseSettings.styles.starStrokeColor`) is a free
2079
2649
  * string: its converter must validate and fall back to this default rather than let one odd value drop
2080
2650
  * the whole reviews section.
2081
2651
  */
2082
- strokeColor: import_zod24.z.string().regex(HEX_COLOR_REGEX).default("#fadb14"),
2652
+ strokeColor: import_zod35.z.string().regex(HEX_COLOR_REGEX).default("#fadb14"),
2083
2653
  /** Star outline width in px; `0` draws no outline. The legacy `styles.strokeWidth` is a STRING ('1') — its converter coerces. */
2084
- strokeWidth: import_zod24.z.number().nonnegative().default(0)
2654
+ strokeWidth: import_zod35.z.number().nonnegative().default(0)
2085
2655
  });
2086
2656
 
2087
2657
  // src/schema/widgets/checkout-and-beyond/separator.ts
2088
- var import_uuid11 = require("uuid");
2089
- var import_zod25 = require("zod");
2090
- var CABSeparatorSection = import_zod25.z.object({
2658
+ var import_uuid12 = require("uuid");
2659
+ var import_zod36 = require("zod");
2660
+ var CABSeparatorSection = import_zod36.z.object({
2091
2661
  ...CABVariableFields,
2092
- sectionId: import_zod25.z.uuid().default(() => (0, import_uuid11.v7)()),
2093
- sectionType: import_zod25.z.literal(SectionType.separator).default(SectionType.separator)
2662
+ sectionId: import_zod36.z.uuid().default(() => (0, import_uuid12.v7)()),
2663
+ sectionType: import_zod36.z.literal(SectionType.separator).default(SectionType.separator)
2094
2664
  });
2095
2665
 
2096
2666
  // src/schema/widgets/checkout-and-beyond/variants.ts
2097
- var import_compat3 = require("es-toolkit/compat");
2098
- var import_uuid12 = require("uuid");
2099
- var import_zod26 = require("zod");
2100
- var CABVariantsSection = import_zod26.z.object({
2667
+ var import_compat5 = require("es-toolkit/compat");
2668
+ var import_uuid13 = require("uuid");
2669
+ var import_zod37 = require("zod");
2670
+ var CABVariantsSection = import_zod37.z.object({
2101
2671
  ...CABVariableFields,
2102
- hideOutOfStockVariants: import_zod26.z.boolean().default(false),
2672
+ hideOutOfStockVariants: import_zod37.z.boolean().default(false),
2103
2673
  /**
2104
2674
  * The menu's own label per buyer locale (`selectLanguage`), for the whole-variant (`single`) and the
2105
2675
  * product-group menus; `multiple` labels each option's menu by its name. Optional and additive
@@ -2110,30 +2680,30 @@ var CABVariantsSection = import_zod26.z.object({
2110
2680
  * `selectLanguage` returning `''` — which a renderer's `??` fallback would show as an empty menu label.
2111
2681
  * A label left with no entries reads as absent.
2112
2682
  */
2113
- label: import_zod26.z.record(import_zod26.z.string(), import_zod26.z.string()).transform((label2) => {
2114
- const filled = (0, import_compat3.pickBy)(label2, (value) => value.trim() !== "");
2115
- return (0, import_compat3.isEmpty)(filled) ? void 0 : filled;
2683
+ label: import_zod37.z.record(import_zod37.z.string(), import_zod37.z.string()).transform((label2) => {
2684
+ const filled = (0, import_compat5.pickBy)(label2, (value) => value.trim() !== "");
2685
+ return (0, import_compat5.isEmpty)(filled) ? void 0 : filled;
2116
2686
  }).optional().catch(void 0),
2117
- name: import_zod26.z.string().optional(),
2118
- sectionId: import_zod26.z.uuid().default(() => (0, import_uuid12.v7)()),
2119
- sectionType: import_zod26.z.literal(SectionType.variants).default(SectionType.variants),
2120
- selector: import_zod26.z.enum((0, import_compat3.slice)(variantSelectors, 0, 3)).default(VariantSelector.menu),
2687
+ name: import_zod37.z.string().optional(),
2688
+ sectionId: import_zod37.z.uuid().default(() => (0, import_uuid13.v7)()),
2689
+ sectionType: import_zod37.z.literal(SectionType.variants).default(SectionType.variants),
2690
+ selector: import_zod37.z.enum((0, import_compat5.slice)(variantSelectors, 0, 3)).default(VariantSelector.menu),
2121
2691
  /** `productGroup` is additive (REB-24817): a renderer without group support must render nothing for it. */
2122
- variantMode: import_zod26.z.enum(variantsModes).default(VariantsMode.multiple)
2692
+ variantMode: import_zod37.z.enum(variantsModes).default(VariantsMode.multiple)
2123
2693
  });
2124
2694
 
2125
2695
  // src/schema/widgets/checkout-and-beyond/shared.ts
2126
- var CABBorder = import_zod27.z.object({
2127
- radius: import_zod27.z.enum(borderRadii).default(BorderRadius.base),
2128
- style: import_zod27.z.enum(borderStyles).default(BorderStyle.none),
2129
- width: import_zod27.z.enum(borderWidths).default(BorderWidth.base)
2696
+ var CABBorder = import_zod38.z.object({
2697
+ radius: import_zod38.z.enum(borderRadii).default(BorderRadius.base),
2698
+ style: import_zod38.z.enum(borderStyles).default(BorderStyle.none),
2699
+ width: import_zod38.z.enum(borderWidths).default(BorderWidth.base)
2130
2700
  }).default({
2131
2701
  radius: BorderRadius.base,
2132
2702
  style: BorderStyle.none,
2133
2703
  width: BorderWidth.base
2134
2704
  });
2135
- var CABSection = import_zod27.z.lazy(
2136
- () => import_zod27.z.discriminatedUnion("sectionType", [
2705
+ var CABSection = import_zod38.z.lazy(
2706
+ () => import_zod38.z.discriminatedUnion("sectionType", [
2137
2707
  CABBannerSection,
2138
2708
  CABButtonSection,
2139
2709
  CABCarouselSection,
@@ -2156,17 +2726,17 @@ var CABSection = import_zod27.z.lazy(
2156
2726
  );
2157
2727
 
2158
2728
  // src/schema/widgets/checkout-and-beyond/image.ts
2159
- var CABImageSectionFields = import_zod28.z.object({
2729
+ var CABImageSectionFields = import_zod39.z.object({
2160
2730
  ...CABVariableFields,
2161
- altText: import_zod28.z.string().refine(checkForHTML, NO_HTML).default(""),
2731
+ altText: import_zod39.z.string().refine(checkForHTML, NO_HTML).default(""),
2162
2732
  /**
2163
2733
  * Image width÷height (e.g. `46` for the progress-bar fill); `null` renders at natural size. Any POSITIVE
2164
2734
  * ratio — never limited to 1, but never `0`/negative either: a renderer dividing by it would get `Infinity`,
2165
2735
  * and CSS `aspect-ratio` drops a negative value and silently reverts to natural size.
2166
2736
  */
2167
- aspectRatio: import_zod28.z.number().positive().nullable().default(null),
2168
- border: import_zod28.z.lazy(() => CABBorder),
2169
- buttonField: import_zod28.z.enum(buttonFields).optional(),
2737
+ aspectRatio: import_zod39.z.number().positive().nullable().default(null),
2738
+ border: import_zod39.z.lazy(() => CABBorder),
2739
+ buttonField: import_zod39.z.enum(buttonFields).optional(),
2170
2740
  /**
2171
2741
  * `icon` renders `source` as a single `s-icon` by name (the uber-image path covers icons too), reading
2172
2742
  * `iconSize`/`iconTone`. The other values are a harmless informational holdover from the previous
@@ -2185,30 +2755,30 @@ var CABImageSectionFields = import_zod28.z.object({
2185
2755
  * behavior degraded gracefully and told us about it. The client-assembled half of the invariant was never
2186
2756
  * the risky half.
2187
2757
  */
2188
- category: import_zod28.z.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
2758
+ category: import_zod39.z.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
2189
2759
  /** `icon`-mode only: the `s-icon` `size`; `null` ⇒ the component default (`base`). Ignored by image treatments. */
2190
- iconSize: import_zod28.z.enum(iconSizes).nullable().default(null),
2760
+ iconSize: import_zod39.z.enum(iconSizes).nullable().default(null),
2191
2761
  /** `icon`-mode only: the `s-icon` `tone`; `null` ⇒ the component default (`auto`). Ignored by image treatments. */
2192
- iconTone: import_zod28.z.enum(iconTones).nullable().default(null),
2193
- name: import_zod28.z.string().optional(),
2194
- naturalHeight: import_zod28.z.number().default(0),
2195
- naturalWidth: import_zod28.z.number().default(0),
2762
+ iconTone: import_zod39.z.enum(iconTones).nullable().default(null),
2763
+ name: import_zod39.z.string().optional(),
2764
+ naturalHeight: import_zod39.z.number().default(0),
2765
+ naturalWidth: import_zod39.z.number().default(0),
2196
2766
  /**
2197
2767
  * `contain` (the component default): dimensionless images render in s-image's 1/1 default frame, and
2198
2768
  * `cover` would crop non-square art (payment badges lost their edges — 15993); `contain` letterboxes.
2199
2769
  */
2200
- objectFit: import_zod28.z.enum(objectFits).default(ObjectFit.contain),
2201
- sectionId: import_zod28.z.uuid().default(() => (0, import_uuid13.v7)()),
2202
- sectionType: import_zod28.z.literal(SectionType.image).default(SectionType.image),
2770
+ objectFit: import_zod39.z.enum(objectFits).default(ObjectFit.contain),
2771
+ sectionId: import_zod39.z.uuid().default(() => (0, import_uuid14.v7)()),
2772
+ sectionType: import_zod39.z.literal(SectionType.image).default(SectionType.image),
2203
2773
  /**
2204
2774
  * An image URL or dynamic token, an empty default, or — when `category: 'icon'` — an icon NAME. Icon mode
2205
2775
  * takes a name or `''` only, NOT a token: no renderer resolves a token to an icon today, so accepting one
2206
2776
  * would promise a capability that doesn't exist. Widen the refine's carve-out to `DYNAMIC_TOKEN_REGEX` when a
2207
2777
  * server-chosen tier icon actually needs it.
2208
2778
  */
2209
- source: import_zod28.z.union([import_zod28.z.url(), import_zod28.z.literal(""), import_zod28.z.string().regex(DYNAMIC_TOKEN_REGEX), import_zod28.z.enum(iconNames)]).default(""),
2779
+ source: import_zod39.z.union([import_zod39.z.url(), import_zod39.z.literal(""), import_zod39.z.string().regex(DYNAMIC_TOKEN_REGEX), import_zod39.z.enum(iconNames)]).default(""),
2210
2780
  thumbnails: CABImageThumbnails.optional(),
2211
- width: import_zod28.z.number().default(100)
2781
+ width: import_zod39.z.number().default(100)
2212
2782
  });
2213
2783
  var iconNameSet = new Set(iconNames);
2214
2784
  var isIconName = (source2) => iconNameSet.has(source2);
@@ -2359,7 +2929,7 @@ var convertContentBlockTextToV2 = (language3, text2 = literalText, textAlign = "
2359
2929
  };
2360
2930
 
2361
2931
  // src/schema/widgets/checkout-and-beyond/root.ts
2362
- var import_zod29 = require("zod");
2932
+ var import_zod40 = require("zod");
2363
2933
 
2364
2934
  // src/schema/widgets/checkout-and-beyond/uiLabels.ts
2365
2935
  var UI_LABELS = {
@@ -2379,8 +2949,8 @@ var UI_LABELS = {
2379
2949
  };
2380
2950
 
2381
2951
  // src/schema/widgets/checkout-and-beyond/root.ts
2382
- var localized = (fallback) => import_zod29.z.record(import_zod29.z.string(), import_zod29.z.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
2383
- var CABUILabels = import_zod29.z.object({
2952
+ var localized = (fallback) => import_zod40.z.record(import_zod40.z.string(), import_zod40.z.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
2953
+ var CABUILabels = import_zod40.z.object({
2384
2954
  currentPage: localized(UI_LABELS.currentPage),
2385
2955
  guest: localized(UI_LABELS.guest),
2386
2956
  loadingOptions: localized(UI_LABELS.loadingOptions),
@@ -2405,37 +2975,37 @@ var CABUILabels = import_zod29.z.object({
2405
2975
  subscriptionOptions: { ...UI_LABELS.subscriptionOptions },
2406
2976
  updating: { ...UI_LABELS.updating }
2407
2977
  }));
2408
- var TargetArea = import_zod29.z.object({
2409
- fill: import_zod29.z.boolean().optional(),
2410
- flip: import_zod29.z.enum(["both", "horizontal", "vertical"]).optional(),
2411
- icon: import_zod29.z.string(),
2412
- label: import_zod29.z.string(),
2413
- width: import_zod29.z.string()
2978
+ var TargetArea = import_zod40.z.object({
2979
+ fill: import_zod40.z.boolean().optional(),
2980
+ flip: import_zod40.z.enum(["both", "horizontal", "vertical"]).optional(),
2981
+ icon: import_zod40.z.string(),
2982
+ label: import_zod40.z.string(),
2983
+ width: import_zod40.z.string()
2414
2984
  }).default(targetAreas[EditorMode.checkoutExtension][1]);
2415
- var CABTracking = import_zod29.z.object({
2416
- enableAttribution: import_zod29.z.boolean().nullish().transform((value) => value ?? true),
2417
- enableSource: import_zod29.z.boolean().nullish().transform((value) => value ?? true),
2418
- enableWidget: import_zod29.z.boolean().nullish().transform((value) => value ?? true)
2985
+ var CABTracking = import_zod40.z.object({
2986
+ enableAttribution: import_zod40.z.boolean().nullish().transform((value) => value ?? true),
2987
+ enableSource: import_zod40.z.boolean().nullish().transform((value) => value ?? true),
2988
+ enableWidget: import_zod40.z.boolean().nullish().transform((value) => value ?? true)
2419
2989
  }).nullish().transform((value) => value ?? { enableAttribution: true, enableSource: true, enableWidget: true });
2420
- var CABExperiment = import_zod29.z.object({
2421
- elementId: import_zod29.z.number(),
2422
- experimentId: import_zod29.z.number(),
2423
- experimentType: import_zod29.z.string(),
2424
- selectedId: import_zod29.z.number()
2990
+ var CABExperiment = import_zod40.z.object({
2991
+ elementId: import_zod40.z.number(),
2992
+ experimentId: import_zod40.z.number(),
2993
+ experimentType: import_zod40.z.string(),
2994
+ selectedId: import_zod40.z.number()
2425
2995
  });
2426
2996
  var CABRootSection = CABLayoutSection.extend({
2427
- editorMode: import_zod29.z.enum(editorModes).default(EditorMode.checkoutExtension),
2997
+ editorMode: import_zod40.z.enum(editorModes).default(EditorMode.checkoutExtension),
2428
2998
  experiment: CABExperiment.optional(),
2429
2999
  // Same rule as CABTracking above: the v1 converters pass raw legacy `previewMode` through, so a
2430
3000
  // `null` must fall back rather than throw the widget; malformed values still throw.
2431
- previewMode: import_zod29.z.boolean().nullish().transform((value) => value ?? false),
2432
- storeId: import_zod29.z.number().nullable().default(null),
3001
+ previewMode: import_zod40.z.boolean().nullish().transform((value) => value ?? false),
3002
+ storeId: import_zod40.z.number().nullable().default(null),
2433
3003
  targetArea: TargetArea.nullable(),
2434
3004
  tracking: CABTracking,
2435
- type: import_zod29.z.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
3005
+ type: import_zod40.z.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
2436
3006
  uiLabels: CABUILabels,
2437
- version: import_zod29.z.literal(2).default(2),
2438
- widgetId: import_zod29.z.number().nullable().default(null)
3007
+ version: import_zod40.z.literal(2).default(2),
3008
+ widgetId: import_zod40.z.number().nullable().default(null)
2439
3009
  });
2440
3010
 
2441
3011
  // src/transforms/v1Location.ts
@@ -3928,172 +4498,10 @@ var convertOfferToV2 = ({ id, name, settings }) => {
3928
4498
  var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(transform(convertNumericObjects(deepCamelCase(raw))));
3929
4499
 
3930
4500
  // src/transforms/postPurchase/convertMessagePreview.ts
3931
- var import_zod40 = require("zod");
4501
+ var import_zod47 = require("zod");
3932
4502
 
3933
4503
  // src/transforms/postPurchase/convertCalloutBlock.ts
3934
- var import_zod32 = require("zod");
3935
-
3936
- // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
3937
- var import_compat4 = require("es-toolkit/compat");
3938
- var import_uuid14 = require("uuid");
3939
- var import_zod31 = require("zod");
3940
-
3941
- // src/schema/widgets/post-purchase-offer/constants.ts
3942
- var import_zod30 = require("zod");
3943
- var blockTypes = [
3944
- "callout_banner",
3945
- "image",
3946
- "image_content",
3947
- "pay_button",
3948
- "product_information",
3949
- "separator",
3950
- "text",
3951
- "timer"
3952
- ];
3953
- var blockType = import_zod30.z.enum(blockTypes);
3954
- var BlockType = blockType.enum;
3955
-
3956
- // src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
3957
- var TextAlignment2 = import_zod31.z.union([import_zod31.z.enum(["leading", "center", "trailing"]), import_zod31.z.unknown().transform(() => "leading")]);
3958
- var TextSize = import_zod31.z.union([
3959
- import_zod31.z.enum(["xsmall", "small", "base", "default", "medium", "large", "xlarge"]),
3960
- import_zod31.z.unknown().transform(() => "medium")
3961
- ]);
3962
- var CalloutBannerBlock = import_zod31.z.object({
3963
- id: import_zod31.z.string().optional().default(() => (0, import_uuid14.v4)()),
3964
- name: import_zod31.z.string().optional(),
3965
- settings: import_zod31.z.object({
3966
- superTitle: import_zod31.z.union([import_zod31.z.string(), TiptapDocument]).default(() => "Limited-time Offer"),
3967
- title: import_zod31.z.union([import_zod31.z.string(), TiptapDocument]).default(() => "Add this customer favorite to your order")
3968
- }),
3969
- styles: import_zod31.z.object({
3970
- superTitleEmphasized: import_zod31.z.boolean().default(false),
3971
- superTitleSize: TextSize.default("large"),
3972
- textAlignment: TextAlignment2.default("center"),
3973
- titleEmphasized: import_zod31.z.boolean().default(true),
3974
- titleSize: TextSize.default("large")
3975
- }),
3976
- type: import_zod31.z.literal(BlockType.callout_banner).default(BlockType.callout_banner)
3977
- });
3978
- var ImageBlock = import_zod31.z.object({
3979
- id: import_zod31.z.string().optional().default(() => (0, import_uuid14.v4)()),
3980
- name: import_zod31.z.string().optional(),
3981
- settings: import_zod31.z.union([
3982
- import_zod31.z.object({
3983
- /** This isn't used in the post-purchase offer widget */
3984
- alt: import_zod31.z.string().optional().default(""),
3985
- image: import_zod31.z.union([import_zod31.z.literal(""), import_zod31.z.url()]).default(""),
3986
- imageSize: import_zod31.z.number().default(20),
3987
- imageType: import_zod31.z.enum(["URL", "UPLOAD"]).default("URL")
3988
- }),
3989
- import_zod31.z.array(import_zod31.z.never()).transform(() => ({}))
3990
- ]),
3991
- type: import_zod31.z.literal(BlockType.image).default(BlockType.image)
3992
- });
3993
- var ImageContentBlock = import_zod31.z.object({
3994
- id: import_zod31.z.string().optional().default(() => (0, import_uuid14.v4)()),
3995
- name: import_zod31.z.string().optional(),
3996
- settings: import_zod31.z.object({
3997
- alt: import_zod31.z.string().optional().default(""),
3998
- description: import_zod31.z.union([import_zod31.z.string(), TiptapDocument, import_zod31.z.null()]).default(
3999
- "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."
4000
- ),
4001
- descriptionSize: TextSize.default("medium"),
4002
- horizontalAlignment: TextAlignment2.default("leading"),
4003
- image: import_zod31.z.union([import_zod31.z.literal(""), import_zod31.z.url()]).default(""),
4004
- imagePlacement: import_zod31.z.enum(["bottom", "left", "right", "top"]).optional().default("left"),
4005
- imageSize: import_zod31.z.number().default(20),
4006
- superTitle: import_zod31.z.union([import_zod31.z.string(), TiptapDocument]).default("Lorem Ipsum!"),
4007
- superTitleSize: TextSize.default("medium"),
4008
- /** This isn't configurable in the admin-nextjs editor */
4009
- swapContent: import_zod31.z.boolean().optional().default(false),
4010
- title: import_zod31.z.union([import_zod31.z.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet"),
4011
- titleSize: TextSize.default("medium")
4012
- }),
4013
- type: import_zod31.z.literal(BlockType.image_content).default(BlockType.image_content)
4014
- });
4015
- var PayButtonBlock = import_zod31.z.object({
4016
- id: import_zod31.z.string().optional().default(() => (0, import_uuid14.v4)()),
4017
- name: import_zod31.z.string().optional(),
4018
- settings: import_zod31.z.union([
4019
- import_zod31.z.object({
4020
- label: import_zod31.z.string().default("Pay Now")
4021
- }),
4022
- import_zod31.z.array(import_zod31.z.never()).transform(() => ({
4023
- label: "Pay Now"
4024
- }))
4025
- ]),
4026
- styles: import_zod31.z.union([
4027
- import_zod31.z.object({
4028
- buttonWidth: import_zod31.z.number().min(10).max(100).default(50)
4029
- }),
4030
- import_zod31.z.array(import_zod31.z.never()).transform(() => ({
4031
- buttonWidth: 50
4032
- }))
4033
- ]),
4034
- type: import_zod31.z.literal(BlockType.pay_button).default(BlockType.pay_button)
4035
- });
4036
- var ProductInformationBlock = import_zod31.z.object({
4037
- /** This isn't configurable in the admin-nextjs editor */
4038
- hideProductImage: import_zod31.z.boolean().optional().default(false),
4039
- id: import_zod31.z.string().optional().default(() => (0, import_uuid14.v4)()),
4040
- name: import_zod31.z.string().optional(),
4041
- type: import_zod31.z.literal(BlockType.product_information).default(BlockType.product_information)
4042
- });
4043
- var SeparatorBlock = import_zod31.z.object({
4044
- id: import_zod31.z.string().optional().default(() => (0, import_uuid14.v4)()),
4045
- name: import_zod31.z.string().optional(),
4046
- type: import_zod31.z.literal(BlockType.separator).default(BlockType.separator)
4047
- });
4048
- var TextBlock = import_zod31.z.object({
4049
- id: import_zod31.z.string().optional().default(() => (0, import_uuid14.v4)()),
4050
- name: import_zod31.z.string().optional(),
4051
- settings: import_zod31.z.object({
4052
- description: import_zod31.z.union([import_zod31.z.string(), TiptapDocument]).optional().default(
4053
- "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."
4054
- ),
4055
- /** This isn't used in the post-purchase offer widget */
4056
- descriptionSize: TextSize.default("medium"),
4057
- horizontalAlignment: TextAlignment2.default("leading"),
4058
- superTitle: import_zod31.z.union([import_zod31.z.string(), TiptapDocument]).default("Super Title"),
4059
- /** This isn't used in the post-purchase offer widget */
4060
- superTitleSize: TextSize.default("medium"),
4061
- title: import_zod31.z.union([import_zod31.z.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet."),
4062
- /** This isn't used in the post-purchase offer widget */
4063
- titleSize: TextSize.default("medium")
4064
- }),
4065
- type: import_zod31.z.literal(BlockType.text).default(BlockType.text)
4066
- });
4067
- var TimerBlock = import_zod31.z.object({
4068
- id: import_zod31.z.string().optional().default(() => (0, import_uuid14.v4)()),
4069
- name: import_zod31.z.string().optional(),
4070
- settings: import_zod31.z.object({
4071
- durationMinutes: import_zod31.z.number().min(0).default(10),
4072
- durationSeconds: import_zod31.z.union([import_zod31.z.number().min(0), import_zod31.z.unknown().transform(() => 0)]).default(0),
4073
- endOffer: import_zod31.z.boolean().default(true),
4074
- title: import_zod31.z.union([import_zod31.z.string(), TiptapDocument]).default("Hurry \u2014 your special offer ends in:")
4075
- }),
4076
- styles: import_zod31.z.object({
4077
- textAlignment: TextAlignment2.default("center"),
4078
- timerBackgroundColor: import_zod31.z.enum(["info", "warning", "success", "critical"]).default("warning"),
4079
- timerEmphasized: import_zod31.z.union([import_zod31.z.boolean(), import_zod31.z.unknown().transform(() => true)]).default(true),
4080
- timerSize: TextSize.default("medium"),
4081
- timerWidth: import_zod31.z.number().min(10).max(100).optional().default(100),
4082
- titleEmphasized: import_zod31.z.union([import_zod31.z.boolean(), import_zod31.z.unknown().transform(() => true)]).default(false),
4083
- titleSize: TextSize.default("medium")
4084
- }),
4085
- type: import_zod31.z.literal(BlockType.timer).default(BlockType.timer)
4086
- });
4087
- var PostPurchaseBlock = import_zod31.z.discriminatedUnion("type", [
4088
- CalloutBannerBlock,
4089
- ImageBlock,
4090
- ImageContentBlock,
4091
- PayButtonBlock,
4092
- ProductInformationBlock,
4093
- SeparatorBlock,
4094
- TextBlock,
4095
- TimerBlock
4096
- ]);
4504
+ var import_zod41 = require("zod");
4097
4505
 
4098
4506
  // src/transforms/postPurchase/styledTextRun.ts
4099
4507
  var sizes = {
@@ -4117,7 +4525,7 @@ var styledTextRun = (text2, emphasized, size) => ({
4117
4525
  // src/transforms/postPurchase/convertCalloutBlock.ts
4118
4526
  var fields = ["superTitle", "title"];
4119
4527
  var Shell = CalloutBannerBlock.pick({ styles: true }).extend({
4120
- settings: import_zod32.z.object({ superTitle: import_zod32.z.unknown().optional(), title: import_zod32.z.unknown().optional() })
4528
+ settings: import_zod41.z.object({ superTitle: import_zod41.z.unknown().optional(), title: import_zod41.z.unknown().optional() })
4121
4529
  });
4122
4530
  var convertCalloutBlock = (raw, report) => {
4123
4531
  const omit = (detail) => {
@@ -4152,7 +4560,7 @@ var convertCalloutBlock = (raw, report) => {
4152
4560
  };
4153
4561
 
4154
4562
  // src/transforms/postPurchase/convertImageFrame.ts
4155
- var import_zod33 = require("zod");
4563
+ var import_zod42 = require("zod");
4156
4564
 
4157
4565
  // src/transforms/postPurchase/sizeImageSource.ts
4158
4566
  var sizeImageSource = (source2, size) => {
@@ -4164,7 +4572,7 @@ var sizeImageSource = (source2, size) => {
4164
4572
  };
4165
4573
 
4166
4574
  // src/transforms/postPurchase/convertImageFrame.ts
4167
- var Source = import_zod33.z.url().default("https://cdn.shopify.com/s/files/1/0605/0555/5177/files/placeholder.jpg?v=1657762972");
4575
+ var Source = import_zod42.z.url().default("https://cdn.shopify.com/s/files/1/0605/0555/5177/files/placeholder.jpg?v=1657762972");
4168
4576
  var DEFAULT_IMAGE_SIZE = 20;
4169
4577
  var convertImageFrame = (raw) => {
4170
4578
  const parsed = ImageBlock.shape.settings.options[0].safeParse(raw);
@@ -4210,7 +4618,7 @@ var convertImageBlock = (raw, report) => {
4210
4618
  };
4211
4619
 
4212
4620
  // src/transforms/postPurchase/convertImageContentBlock.ts
4213
- var import_zod35 = require("zod");
4621
+ var import_zod44 = require("zod");
4214
4622
 
4215
4623
  // src/transforms/postPurchase/convertImageContentText.ts
4216
4624
  var fields2 = ["superTitle", "title", "description"];
@@ -4235,286 +4643,98 @@ var convertImageContentText = (settings, report) => {
4235
4643
  } : text2;
4236
4644
  const section = CABTextSection.safeParse({ content: { en: content } });
4237
4645
  return section.success ? [section.data] : omit();
4238
- });
4239
- return CABLayoutSection.parse({ alignment: { horizontal }, sections });
4240
- };
4241
-
4242
- // src/transforms/postPurchase/imageContentSettings.ts
4243
- var import_zod34 = require("zod");
4244
- var ImageContentSettings = ImageContentBlock.shape.settings.pick({
4245
- descriptionSize: true,
4246
- horizontalAlignment: true,
4247
- superTitleSize: true,
4248
- swapContent: true,
4249
- titleSize: true
4250
- }).extend({
4251
- alt: import_zod34.z.unknown().optional(),
4252
- description: import_zod34.z.unknown().optional(),
4253
- image: import_zod34.z.unknown().optional(),
4254
- imagePlacement: ImageContentBlock.shape.settings.shape.imagePlacement.unwrap().nullable(),
4255
- imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(import_zod34.z.number().positive()),
4256
- superTitle: import_zod34.z.unknown().optional(),
4257
- title: import_zod34.z.unknown().optional()
4258
- });
4259
-
4260
- // src/transforms/postPurchase/convertImageContentBlock.ts
4261
- var Shell2 = import_zod35.z.object({ settings: ImageContentSettings, type: import_zod35.z.literal("image_content") });
4262
- var PROPORTIONAL_BREAK_AT = 500;
4263
- var convertImageContentBlock = (raw, report) => {
4264
- const shell = Shell2.safeParse(raw);
4265
- if (!shell.success) {
4266
- report?.({ detail: "Unreadable post-purchase image-content block", kind: "section" });
4267
- return [];
4268
- }
4269
- const settings = shell.data.settings;
4270
- const alt = typeof settings.alt === "string" ? settings.alt : void 0;
4271
- if (settings.alt !== void 0 && alt === void 0) {
4272
- report?.({ detail: "Unreadable post-purchase image-content alt text", kind: "section" });
4273
- }
4274
- const image = convertImageFrame({ alt, image: settings.image, imageSize: settings.imageSize });
4275
- if (!image) report?.({ detail: "Unreadable post-purchase image-content image", kind: "section" });
4276
- const text2 = convertImageContentText(settings, report);
4277
- const textFrame = CABLayoutSection.parse({ direction: "grid", grid: { columns: ["100%"] }, sections: [text2] });
4278
- const placement = settings.imagePlacement ?? (settings.swapContent ? "right" : "left");
4279
- const imageFirst = placement === "left" || placement === "top";
4280
- const sections = imageFirst ? [image, textFrame] : [textFrame, image];
4281
- const ordered = sections.filter((section) => section !== null);
4282
- const inner = placement === "left" || placement === "right" ? CABLayoutSection.parse({
4283
- sections: ordered,
4284
- spacing: "loose",
4285
- wrapping: {
4286
- breakAt: settings.imageSize <= 1 ? PROPORTIONAL_BREAK_AT : settings.imageSize,
4287
- maxPerLine: 2
4288
- }
4289
- }) : CABLayoutSection.parse({
4290
- direction: "grid",
4291
- grid: { columns: ["100%"] },
4292
- sections: [CABLayoutSection.parse({ sections: ordered })],
4293
- width: 95
4294
- });
4295
- return [CABLayoutSection.parse({ frame: "offer-content", sections: [inner], spacing: "none" })];
4296
- };
4297
-
4298
- // src/transforms/postPurchase/productCardPay.ts
4299
- var import_es_toolkit6 = require("es-toolkit");
4300
- var PAY_NOW = { en: "Pay Now" };
4301
- var DECLINE_THIS_OFFER = { en: "Decline this offer" };
4302
- var NOT_AVAILABLE_DEFAULTS = ["Not available"];
4303
- var soldOutSlot = ({ language: language3 }) => labelSlot("soldOut", OFFER_LABELS.soldOut, language3.global.notAvailable, [], NOT_AVAILABLE_DEFAULTS);
4304
- var productCardPay = (settings) => {
4305
- const payNow = labelSlot("payNow", PAY_NOW, settings.language.global.payNow);
4306
- const priced = settings.language.displayCtaPrice ? { ...payNow, content: (0, import_es_toolkit6.mapValues)(payNow.content, (label2) => `${label2} \xB7 {{total}}`) } : payNow;
4307
- return [addToOrderButton("primary", [priced, soldOutSlot(settings)])];
4308
- };
4309
- var productCardDecline = ({ language: language3 }) => [
4310
- {
4311
- action: "declineOffer",
4312
- buttonStyle: "secondary",
4313
- sections: [labelSlot("declineOffer", DECLINE_THIS_OFFER, language3.global.declineThisOffer)],
4314
- sectionType: "button"
4315
- }
4316
- ];
4317
-
4318
- // src/transforms/postPurchase/productCardSettings.ts
4319
- var import_es_toolkit7 = require("es-toolkit");
4320
- var import_zod38 = require("zod");
4321
-
4322
- // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
4323
- var import_zod37 = require("zod");
4324
-
4325
- // src/schema/widgets/post-purchase-offer/common.ts
4326
- var import_compat5 = require("es-toolkit/compat");
4327
- var import_zod36 = require("zod");
4328
- var strictNumber = import_zod36.z.union([
4329
- import_zod36.z.number(),
4330
- import_zod36.z.string().transform((value) => (0, import_compat5.toNumber)((0, import_compat5.replace)((0, import_compat5.toString)(value), /[^0-9.]/g, "")) || 0),
4331
- import_zod36.z.unknown().transform(() => 0)
4332
- ]);
4333
-
4334
- // src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
4335
- var PostPurchaseSettings = import_zod37.z.object({
4336
- advance: import_zod37.z.object({ removePartialOrder: import_zod37.z.boolean().default(true) }).optional().default(() => ({ removePartialOrder: true })),
4337
- blocks: import_zod37.z.union([import_zod37.z.array(PostPurchaseBlock), import_zod37.z.unknown().transform(() => [])]).default(() => [
4338
- PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.timer }),
4339
- PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.callout_banner }),
4340
- PostPurchaseBlock.parse({ type: BlockType.product_information })
4341
- ]),
4342
- columnLayout: import_zod37.z.boolean().optional(),
4343
- discount: import_zod37.z.object({
4344
- amount: strictNumber.default(30),
4345
- shouldShowSavingText: import_zod37.z.boolean().optional().default(true),
4346
- type: import_zod37.z.enum(["none", "fixed_amount", "percentage"]).default("none")
4347
- }),
4348
- discountedFrom: import_zod37.z.enum(["price", "compare_at_price"]).optional().default("price"),
4349
- endpoint: import_zod37.z.string().optional(),
4350
- integrations: import_zod37.z.object({
4351
- judgeme: import_zod37.z.boolean().default(false),
4352
- junip: import_zod37.z.boolean().optional().default(false),
4353
- klaviyo: import_zod37.z.boolean().default(false),
4354
- loox: import_zod37.z.boolean().default(false),
4355
- okendo: import_zod37.z.boolean().default(false),
4356
- opinew: import_zod37.z.boolean().optional().default(false),
4357
- reviewsio: import_zod37.z.boolean().optional().default(false),
4358
- stamped: import_zod37.z.boolean().default(false),
4359
- yotpo: import_zod37.z.boolean().default(false)
4360
- }),
4361
- key: import_zod37.z.string().optional(),
4362
- language: import_zod37.z.object({
4363
- description: import_zod37.z.union([import_zod37.z.string(), import_zod37.z.unknown().transform(() => "")]).default(""),
4364
- descriptionEnabled: import_zod37.z.boolean().optional().default(false),
4365
- descriptionRte: import_zod37.z.object({
4366
- content: import_zod37.z.array(import_zod37.z.unknown()),
4367
- type: import_zod37.z.string()
4368
- }).optional(),
4369
- descriptionSpacing: import_zod37.z.enum(["none", "xtight", "tight", "default", "loose", "xloose"]).optional(),
4370
- displayCtaPrice: import_zod37.z.boolean().default(true),
4371
- global: import_zod37.z.object({
4372
- declineAll: import_zod37.z.string().optional().default("Decline All"),
4373
- declineThisOffer: import_zod37.z.string().default("Decline this offer"),
4374
- free: import_zod37.z.string().optional().default("Free"),
4375
- notAvailable: import_zod37.z.string().optional().default("Not available"),
4376
- payNow: import_zod37.z.string().default("Pay Now"),
4377
- payNowUpgradeToSubscription: import_zod37.z.string().optional().default("Upgrade to Subscription"),
4378
- quantity: import_zod37.z.string().default("Quantity"),
4379
- /** This isn't configurable in the admin-nextjs editor */
4380
- recurringShipping: import_zod37.z.string().optional().default("Recurring shipping"),
4381
- recurringSubtotal: import_zod37.z.string().default("Recurring subtotal"),
4382
- reviewsPlural: import_zod37.z.string().optional().default("Reviews"),
4383
- reviewsSingular: import_zod37.z.string().optional().default("Review"),
4384
- save: import_zod37.z.union([import_zod37.z.string(), import_zod37.z.unknown().transform(() => "Save")]).optional().default("Save"),
4385
- shipping: import_zod37.z.string().default("Shipping"),
4386
- subscriptionOption: import_zod37.z.string().optional().default("Subscribe and Save"),
4387
- subtotal: import_zod37.z.string().default("Subtotal"),
4388
- taxes: import_zod37.z.string().default("Taxes"),
4389
- total: import_zod37.z.string().default("Total")
4390
- }).optional().default(() => ({
4391
- declineAll: "Decline All",
4392
- declineThisOffer: "Decline this offer",
4393
- free: "Free",
4394
- notAvailable: "Not available",
4395
- payNow: "Pay Now",
4396
- payNowUpgradeToSubscription: "Upgrade to Subscription",
4397
- quantity: "Quantity",
4398
- /** This isn't configurable in the admin-nextjs editor */
4399
- recurringShipping: "Recurring shipping",
4400
- recurringSubtotal: "Recurring subtotal",
4401
- reviewsPlural: "Reviews",
4402
- reviewsSingular: "Review",
4403
- save: "Save",
4404
- shipping: "Shipping",
4405
- subscriptionOption: "Subscribe and Save",
4406
- subtotal: "Subtotal",
4407
- taxes: "Taxes",
4408
- total: "Total"
4409
- })),
4410
- globalTranslation: import_zod37.z.string().optional().default("english")
4411
- }),
4412
- metafields: import_zod37.z.boolean().default(false),
4413
- /** This isn't configurable in the admin-nextjs editor */
4414
- offer: import_zod37.z.object({
4415
- count: import_zod37.z.number().default(1)
4416
- }),
4417
- offersLayout: import_zod37.z.object({
4418
- itemsPerPage: import_zod37.z.number().optional(),
4419
- type: import_zod37.z.enum(["list", "grid", "carousel"]).default("list")
4420
- }).optional().default({
4421
- type: "list"
4422
- }),
4423
- /** This isn't configurable in the admin-nextjs editor */
4424
- previewMode: import_zod37.z.boolean().default(false),
4425
- productLimit: import_zod37.z.number().optional().default(1),
4426
- productOptions: import_zod37.z.object({
4427
- /** This isn't configurable in the admin-nextjs editor */
4428
- hideOutOfStockVariants: import_zod37.z.boolean().optional().default(false),
4429
- matchVariant: import_zod37.z.boolean().optional().default(true),
4430
- showDeclineAll: import_zod37.z.enum(["above", "below", "both", "none"]).optional(),
4431
- showShipping: import_zod37.z.boolean().optional().default(true),
4432
- showSubtotal: import_zod37.z.boolean().optional().default(true),
4433
- showTaxes: import_zod37.z.boolean().optional().default(true),
4434
- showTotal: import_zod37.z.boolean().optional().default(true),
4435
- showVariantSelectors: import_zod37.z.boolean().optional().default(true),
4436
- variantSelectorDisplayMode: import_zod37.z.enum(["separate", "single"]).optional().default("separate")
4437
- }),
4438
- productType: import_zod37.z.union([import_zod37.z.enum(["one-time", "subscription", "both"]), import_zod37.z.literal("").transform(() => "one-time")]).default("one-time"),
4439
- productTypeSelector: import_zod37.z.enum(["dropdown", "radio"]).optional().default("radio"),
4440
- quantityInputs: import_zod37.z.object({
4441
- defaultQuantity: import_zod37.z.union([import_zod37.z.number(), import_zod37.z.null().transform(() => 1)]).default(1),
4442
- enabled: import_zod37.z.boolean().default(true),
4443
- maxValue: import_zod37.z.union([import_zod37.z.number(), import_zod37.z.null().transform(() => 15)]).default(15),
4444
- minValue: import_zod37.z.union([import_zod37.z.number().min(0), import_zod37.z.unknown().transform(() => 0)]).default(1)
4445
- }),
4446
- shipping: import_zod37.z.object({
4447
- amount: strictNumber.default(10),
4448
- /** This isn't configurable in the admin-nextjs editor */
4449
- enabled: import_zod37.z.boolean().default(true),
4450
- title: import_zod37.z.string().optional().default("Shipping Fees"),
4451
- type: import_zod37.z.enum(["free", "fixed_amount"]).default("free")
4452
- }),
4453
- styles: import_zod37.z.object({
4454
- starColor: import_zod37.z.string().optional().default("#fadb14"),
4455
- starSize: import_zod37.z.union([import_zod37.z.enum(["small", "medium", "large"]), import_zod37.z.unknown().transform(() => "large")]).optional().default("large"),
4456
- starStrokeColor: import_zod37.z.string().optional().default("#fadb14"),
4457
- strokeWidth: import_zod37.z.string().optional().default("1")
4458
- }).optional(),
4459
- subImages: import_zod37.z.number().nullish().default(8),
4460
- subscription: import_zod37.z.object({
4461
- discount: import_zod37.z.object({
4462
- amount: strictNumber.default(30),
4463
- shouldShowSavingText: import_zod37.z.boolean().optional().default(true),
4464
- type: import_zod37.z.enum(["none", "fixed_amount", "percentage"]).default("none")
4465
- }),
4466
- shipping: import_zod37.z.object({
4467
- amount: strictNumber.default(1),
4468
- /** This isn't configurable in the admin-nextjs editor */
4469
- enabled: import_zod37.z.boolean().default(true),
4470
- /** This isn't configurable in the admin-nextjs editor */
4471
- recurringAmount: strictNumber.default(2),
4472
- shippingTitle: import_zod37.z.string().default("Shipping Fees"),
4473
- type: import_zod37.z.enum(["free", "fixed_amount"]).default("free")
4474
- })
4475
- }).optional().default({
4476
- discount: {
4477
- amount: 30,
4478
- shouldShowSavingText: true,
4479
- type: "none"
4480
- },
4481
- shipping: {
4482
- amount: 1,
4483
- /** This isn't configurable in the admin-nextjs editor */
4484
- enabled: true,
4485
- /** This isn't configurable in the admin-nextjs editor */
4486
- recurringAmount: 2,
4487
- shippingTitle: "Shipping Fees",
4488
- type: "free"
4489
- }
4490
- }),
4491
- subscriptionIsDefault: import_zod37.z.boolean().optional(),
4492
- /** This isn't configurable in the admin-nextjs editor */
4493
- template: import_zod37.z.string().optional().default(""),
4494
- type: import_zod37.z.literal("shopify_post_purchase_extension").default("shopify_post_purchase_extension"),
4495
- upgradeToSubscription: import_zod37.z.object({
4496
- acceptButtonText: import_zod37.z.string().optional().default("Upgrade"),
4497
- allow: import_zod37.z.boolean().optional().default(false),
4498
- emailRefundNotice: import_zod37.z.boolean().optional().default(false),
4499
- errorBannerText: import_zod37.z.string().optional().default("This subscription cannot be added - limit one per order")
4500
- }).optional().default(() => ({
4501
- acceptButtonText: "Upgrade",
4502
- allow: false,
4503
- emailRefundNotice: false,
4504
- errorBannerText: "This subscription cannot be added - limit one per order"
4505
- }))
4646
+ });
4647
+ return CABLayoutSection.parse({ alignment: { horizontal }, sections });
4648
+ };
4649
+
4650
+ // src/transforms/postPurchase/imageContentSettings.ts
4651
+ var import_zod43 = require("zod");
4652
+ var ImageContentSettings = ImageContentBlock.shape.settings.pick({
4653
+ descriptionSize: true,
4654
+ horizontalAlignment: true,
4655
+ superTitleSize: true,
4656
+ swapContent: true,
4657
+ titleSize: true
4658
+ }).extend({
4659
+ alt: import_zod43.z.unknown().optional(),
4660
+ description: import_zod43.z.unknown().optional(),
4661
+ image: import_zod43.z.unknown().optional(),
4662
+ imagePlacement: ImageContentBlock.shape.settings.shape.imagePlacement.unwrap().nullable(),
4663
+ imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(import_zod43.z.number().positive()),
4664
+ superTitle: import_zod43.z.unknown().optional(),
4665
+ title: import_zod43.z.unknown().optional()
4506
4666
  });
4507
4667
 
4668
+ // src/transforms/postPurchase/convertImageContentBlock.ts
4669
+ var Shell2 = import_zod44.z.object({ settings: ImageContentSettings, type: import_zod44.z.literal("image_content") });
4670
+ var PROPORTIONAL_BREAK_AT = 500;
4671
+ var convertImageContentBlock = (raw, report) => {
4672
+ const shell = Shell2.safeParse(raw);
4673
+ if (!shell.success) {
4674
+ report?.({ detail: "Unreadable post-purchase image-content block", kind: "section" });
4675
+ return [];
4676
+ }
4677
+ const settings = shell.data.settings;
4678
+ const alt = typeof settings.alt === "string" ? settings.alt : void 0;
4679
+ if (settings.alt !== void 0 && alt === void 0) {
4680
+ report?.({ detail: "Unreadable post-purchase image-content alt text", kind: "section" });
4681
+ }
4682
+ const image = convertImageFrame({ alt, image: settings.image, imageSize: settings.imageSize });
4683
+ if (!image) report?.({ detail: "Unreadable post-purchase image-content image", kind: "section" });
4684
+ const text2 = convertImageContentText(settings, report);
4685
+ const textFrame = CABLayoutSection.parse({ direction: "grid", grid: { columns: ["100%"] }, sections: [text2] });
4686
+ const placement = settings.imagePlacement ?? (settings.swapContent ? "right" : "left");
4687
+ const imageFirst = placement === "left" || placement === "top";
4688
+ const sections = imageFirst ? [image, textFrame] : [textFrame, image];
4689
+ const ordered = sections.filter((section) => section !== null);
4690
+ const inner = placement === "left" || placement === "right" ? CABLayoutSection.parse({
4691
+ sections: ordered,
4692
+ spacing: "loose",
4693
+ wrapping: {
4694
+ breakAt: settings.imageSize <= 1 ? PROPORTIONAL_BREAK_AT : settings.imageSize,
4695
+ maxPerLine: 2
4696
+ }
4697
+ }) : CABLayoutSection.parse({
4698
+ direction: "grid",
4699
+ grid: { columns: ["100%"] },
4700
+ sections: [CABLayoutSection.parse({ sections: ordered })],
4701
+ width: 95
4702
+ });
4703
+ return [CABLayoutSection.parse({ frame: "offer-content", sections: [inner], spacing: "none" })];
4704
+ };
4705
+
4706
+ // src/transforms/postPurchase/productCardPay.ts
4707
+ var import_es_toolkit6 = require("es-toolkit");
4708
+ var PAY_NOW = { en: "Pay Now" };
4709
+ var DECLINE_THIS_OFFER = { en: "Decline this offer" };
4710
+ var NOT_AVAILABLE_DEFAULTS = ["Not available"];
4711
+ var soldOutSlot = ({ language: language3 }) => labelSlot("soldOut", OFFER_LABELS.soldOut, language3.global.notAvailable, [], NOT_AVAILABLE_DEFAULTS);
4712
+ var productCardPay = (settings) => {
4713
+ const payNow = labelSlot("payNow", PAY_NOW, settings.language.global.payNow);
4714
+ const priced = settings.language.displayCtaPrice ? { ...payNow, content: (0, import_es_toolkit6.mapValues)(payNow.content, (label2) => `${label2} \xB7 {{total}}`) } : payNow;
4715
+ return [addToOrderButton("primary", [priced, soldOutSlot(settings)])];
4716
+ };
4717
+ var productCardDecline = ({ language: language3 }) => [
4718
+ {
4719
+ action: "declineOffer",
4720
+ buttonStyle: "secondary",
4721
+ sections: [labelSlot("declineOffer", DECLINE_THIS_OFFER, language3.global.declineThisOffer)],
4722
+ sectionType: "button"
4723
+ }
4724
+ ];
4725
+
4508
4726
  // src/transforms/postPurchase/productCardSettings.ts
4727
+ var import_es_toolkit7 = require("es-toolkit");
4728
+ var import_zod45 = require("zod");
4509
4729
  var { shape } = PostPurchaseSettings;
4510
- var Labels = import_zod38.z.object(
4730
+ var Labels = import_zod45.z.object(
4511
4731
  (0, import_es_toolkit7.mapValues)(shape.language.shape.global.unwrap().unwrap().shape, (label2) => label2.catch(() => label2.parse(void 0)))
4512
4732
  );
4513
- var Language = import_zod38.z.object({
4733
+ var Language = import_zod45.z.object({
4514
4734
  displayCtaPrice: shape.language.shape.displayCtaPrice.catch(true),
4515
4735
  global: Labels.catch(() => Labels.parse({}))
4516
4736
  });
4517
- var Fields = import_zod38.z.object({
4737
+ var Fields = import_zod45.z.object({
4518
4738
  discount: shape.discount.catch(() => shape.discount.parse({})),
4519
4739
  language: Language.catch(() => Language.parse({})),
4520
4740
  productOptions: shape.productOptions.catch(() => shape.productOptions.parse({})),
@@ -4798,7 +5018,7 @@ var convertSeparatorBlock = (raw, report) => {
4798
5018
  };
4799
5019
 
4800
5020
  // src/transforms/postPurchase/convertTextBlock.ts
4801
- var import_zod39 = require("zod");
5021
+ var import_zod46 = require("zod");
4802
5022
  var fields3 = ["superTitle", "title", "description"];
4803
5023
  var styles = {
4804
5024
  description: [{ attrs: { color: "base", fontSize: "small" }, type: "textStyle" }],
@@ -4806,13 +5026,13 @@ var styles = {
4806
5026
  title: [{ type: "bold" }, { attrs: { color: "base", fontSize: "large" }, type: "textStyle" }]
4807
5027
  };
4808
5028
  var settingsSchema = TextBlock.shape.settings;
4809
- var Shell3 = import_zod39.z.object({
5029
+ var Shell3 = import_zod46.z.object({
4810
5030
  settings: settingsSchema.pick({ horizontalAlignment: true }).extend({
4811
- description: import_zod39.z.unknown().optional(),
4812
- superTitle: import_zod39.z.unknown().optional(),
4813
- title: import_zod39.z.unknown().optional()
5031
+ description: import_zod46.z.unknown().optional(),
5032
+ superTitle: import_zod46.z.unknown().optional(),
5033
+ title: import_zod46.z.unknown().optional()
4814
5034
  }),
4815
- type: import_zod39.z.literal("text")
5035
+ type: import_zod46.z.literal("text")
4816
5036
  });
4817
5037
  var convertTextBlock = (raw, report) => {
4818
5038
  const shell = Shell3.safeParse(raw);
@@ -4884,11 +5104,11 @@ var convertTimerBlock = (raw, report) => {
4884
5104
  };
4885
5105
 
4886
5106
  // src/transforms/postPurchase/convertMessagePreview.ts
4887
- var MessageWidget = import_zod40.z.object({
4888
- blocks: import_zod40.z.array(import_zod40.z.unknown()).min(1),
4889
- type: import_zod40.z.literal(WidgetType.shopify_post_purchase_extension)
5107
+ var MessageWidget = import_zod47.z.object({
5108
+ blocks: import_zod47.z.array(import_zod47.z.unknown()).min(1),
5109
+ type: import_zod47.z.literal(WidgetType.shopify_post_purchase_extension)
4890
5110
  });
4891
- var BlockType2 = import_zod40.z.object({ type: import_zod40.z.string() });
5111
+ var BlockType2 = import_zod47.z.object({ type: import_zod47.z.string() });
4892
5112
  var converters = {
4893
5113
  callout_banner: convertCalloutBlock,
4894
5114
  image: convertImageBlock,
@@ -5400,6 +5620,12 @@ var reportUnreadableVerdict = (metadata, report) => {
5400
5620
  if (RuleVerdict.safeParse(metadata).success || isDefinitiveRuleAnswer(metadata)) return;
5401
5621
  report?.({ detail: "rule verdict lacks readable custom.shouldShow", kind: "ruleVerdict" });
5402
5622
  };
5623
+ var withReviews = (product, integrations, report) => {
5624
+ const { reviews: engineReviews, ...rest } = product;
5625
+ const reviews = projectOfferProductReviews(integrations, product, report);
5626
+ if (reviews !== void 0) return { ...rest, reviews };
5627
+ return engineReviews === void 0 ? product : rest;
5628
+ };
5403
5629
  var dedupeById = (products) => (0, import_es_toolkit8.uniqBy)(products, (product) => product.id);
5404
5630
  var MAX_REQUEST_LINE_BYTES = 32e3;
5405
5631
  var requestLineBytes = (path, search) => new TextEncoder().encode(`GET ${path}?${search} HTTP/1.1`).length;
@@ -5426,7 +5652,9 @@ var fetchDataSourceResults = async (input, ctx) => {
5426
5652
  if (input.limit === 0) reportUnreadableVerdict(metadata, ctx.reportDrift);
5427
5653
  if (input.limit !== 0 && (upstream != null && (typeof upstream !== "object" || Array.isArray(upstream)) || raw.data != null && !Array.isArray(raw.data)))
5428
5654
  ctx.reportDrift?.({ detail: "data-source products payload is not an array", kind: "dataSource" });
5429
- const products = dedupeById(rawProducts.filter((product) => keepValidProduct(product, ctx.reportDrift)));
5655
+ const products = dedupeById(rawProducts.filter((product) => keepValidProduct(product, ctx.reportDrift))).map(
5656
+ (product) => withReviews(product, input.integrations, ctx.reportDrift)
5657
+ );
5430
5658
  return {
5431
5659
  metadata,
5432
5660
  /** B2B sessions filter by the company-location catalog server-side (the client bypasses its market hide). */
@@ -5436,7 +5664,7 @@ var fetchDataSourceResults = async (input, ctx) => {
5436
5664
  };
5437
5665
 
5438
5666
  // src/server/adsEngine.ts
5439
- var import_zod41 = require("zod");
5667
+ var import_zod48 = require("zod");
5440
5668
  var SUPPLY_KEY = { production: "AQF5RKLR", staging: "Z56LQ7PS" };
5441
5669
  var OFFER_LIMIT = 4;
5442
5670
  var SUPPORTED_COUNTRIES = /* @__PURE__ */ new Set(["US", "CA", "GB"]);
@@ -5449,30 +5677,30 @@ var transactionItems = (input) => (input.transactionItems?.map(({ id, priceCents
5449
5677
  title,
5450
5678
  type
5451
5679
  })) ?? input.cart.items.map(({ productId: productId2, quantity: quantity3 }) => ({ id: productId2, quantity: quantity3 }))).slice(0, MAX_TRANSACTION_ITEMS);
5452
- var AdsEngineOffer = import_zod41.z.object({
5680
+ var AdsEngineOffer = import_zod48.z.object({
5453
5681
  /** Pill-style value prop ("Get $45 Cashback"). Carried through the parse; the card does not render it yet (REB-24429 — pill design pending). */
5454
- callout: import_zod41.z.string().catch(""),
5455
- click_url: import_zod41.z.string(),
5456
- cta: import_zod41.z.string(),
5682
+ callout: import_zod48.z.string().catch(""),
5683
+ click_url: import_zod48.z.string(),
5684
+ cta: import_zod48.z.string(),
5457
5685
  /** `omitempty` on the ad server — a bid without it must not fail the parse and drop the whole batch (composeOffer falls back to 'No Thanks'). */
5458
- decline_cta: import_zod41.z.string().catch(""),
5459
- decline_url: import_zod41.z.string(),
5460
- description: import_zod41.z.string(),
5686
+ decline_cta: import_zod48.z.string().catch(""),
5687
+ decline_url: import_zod48.z.string(),
5688
+ description: import_zod48.z.string(),
5461
5689
  /** Short legal disclosure (FDIC / auto-renewal / FTC-affiliation lines). Rendered subdued under the CTAs. */
5462
- disclaimer: import_zod41.z.string().catch(""),
5690
+ disclaimer: import_zod48.z.string().catch(""),
5463
5691
  /** Long legal text behind the disclosure toggle in the composed card (REB-24429). */
5464
- extended_disclaimer: import_zod41.z.string().catch(""),
5465
- headline: import_zod41.z.string(),
5466
- id: import_zod41.z.string(),
5692
+ extended_disclaimer: import_zod48.z.string().catch(""),
5693
+ headline: import_zod48.z.string(),
5694
+ id: import_zod48.z.string(),
5467
5695
  /** Advertiser-supplied image alt; the composed card falls back to the stripped headline when empty. */
5468
- image_alt: import_zod41.z.string().catch(""),
5469
- image_url: import_zod41.z.string().optional(),
5696
+ image_alt: import_zod48.z.string().catch(""),
5697
+ image_url: import_zod48.z.string().optional(),
5470
5698
  /** The serving network's own privacy page (Falcon, REB-24744); the card prefers it over the widget setting. A bad value drops only this field, never the offer. */
5471
- privacy_url: import_zod41.z.string().optional().catch(void 0),
5472
- view_url: import_zod41.z.string()
5699
+ privacy_url: import_zod48.z.string().optional().catch(void 0),
5700
+ view_url: import_zod48.z.string()
5473
5701
  });
5474
- var AdsEngineResponse = import_zod41.z.object({
5475
- offers: import_zod41.z.array(import_zod41.z.unknown()).default([]).transform(
5702
+ var AdsEngineResponse = import_zod48.z.object({
5703
+ offers: import_zod48.z.array(import_zod48.z.unknown()).default([]).transform(
5476
5704
  (offers) => offers.flatMap((offer) => {
5477
5705
  const result = AdsEngineOffer.safeParse(offer);
5478
5706
  return result.success ? [result.data] : [];
@@ -5484,8 +5712,8 @@ var AdsEngineResponse = import_zod41.z.object({
5484
5712
  * offers-testing fixture on a test store forces it, REB-24467). Both optional: an older engine or a
5485
5713
  * non-JSON body must not fail the parse and drop the offers.
5486
5714
  */
5487
- request_id: import_zod41.z.string().optional().catch(void 0),
5488
- testing: import_zod41.z.boolean().optional().catch(void 0)
5715
+ request_id: import_zod48.z.string().optional().catch(void 0),
5716
+ testing: import_zod48.z.boolean().optional().catch(void 0)
5489
5717
  });
5490
5718
  var adsHost = (host) => `offers.${host}`;
5491
5719
  var isTestingRequest = (input, isProduction) => !isProduction || !!input.testing || input.customerEmail?.toLowerCase() === TEST_CUSTOMER_EMAIL;
@@ -5801,7 +6029,6 @@ var fetchMonetizeOffers = async (input, ctx, prefetched) => {
5801
6029
 
5802
6030
  // src/server/salvageSections.ts
5803
6031
  var import_uuid16 = require("uuid");
5804
- var STUB_SECTION_TYPE = "unknown";
5805
6032
  var knownSectionTypes = new Set(sectionTypes);
5806
6033
  var hasSectionsArray = (raw) => typeof raw === "object" && raw !== null && Array.isArray(raw.sections);
5807
6034
  var stubSection = (raw, report) => {
@@ -5814,7 +6041,7 @@ var stubSection = (raw, report) => {
5814
6041
  });
5815
6042
  return {
5816
6043
  sectionId: typeof rawId === "string" && rawId ? rawId : (0, import_uuid16.v7)(),
5817
- sectionType: typeof original === "string" && !knownSectionTypes.has(original) ? original : STUB_SECTION_TYPE
6044
+ sectionType: typeof original === "string" && !knownSectionTypes.has(original) ? original : SALVAGED_SECTION_TYPE
5818
6045
  };
5819
6046
  };
5820
6047
  var salvageSection = (raw, report) => {
@@ -5957,13 +6184,13 @@ var convertWidgetSettings = async (input, ctx) => {
5957
6184
  };
5958
6185
 
5959
6186
  // src/server/giftWidgets.ts
5960
- var import_zod42 = require("zod");
5961
- var SettingsNumber = import_zod42.z.union([
5962
- import_zod42.z.number(),
5963
- import_zod42.z.string().trim().regex(/^-?\d+(\.\d+)?$/)
5964
- ]).pipe(import_zod42.z.coerce.number());
5965
- var SgwpMilestoneSchema = import_zod42.z.object({
5966
- selectable_product_quantity: SettingsNumber.pipe(import_zod42.z.number().int().nonnegative()),
6187
+ var import_zod49 = require("zod");
6188
+ var SettingsNumber = import_zod49.z.union([
6189
+ import_zod49.z.number(),
6190
+ import_zod49.z.string().trim().regex(/^-?\d+(\.\d+)?$/)
6191
+ ]).pipe(import_zod49.z.coerce.number());
6192
+ var SgwpMilestoneSchema = import_zod49.z.object({
6193
+ selectable_product_quantity: SettingsNumber.pipe(import_zod49.z.number().int().nonnegative()),
5967
6194
  unlock_price: SettingsNumber
5968
6195
  });
5969
6196
  var fetchGiftWidgetSettings = async (widgetId, shop, ctx) => unwrapData(await ctx.fetchUpstream("/api/v1/widgets/settings", { id: String(widgetId), shop }, { host: ctx.host }));
@@ -5974,7 +6201,7 @@ var readDataSourcePath = (settings) => {
5974
6201
  var readMilestones = (settings, report) => {
5975
6202
  const raw = settings && typeof settings === "object" ? settings.milestones : void 0;
5976
6203
  if (raw == null) return [];
5977
- const parsed = import_zod42.z.array(SgwpMilestoneSchema).safeParse(raw);
6204
+ const parsed = import_zod49.z.array(SgwpMilestoneSchema).safeParse(raw);
5978
6205
  if (parsed.success) return parsed.data;
5979
6206
  report?.({
5980
6207
  detail: [
@@ -6089,16 +6316,16 @@ var validateGifts = async (input, ctx) => {
6089
6316
 
6090
6317
  // src/server/normalizePostPurchaseProduct.ts
6091
6318
  var import_compat7 = require("es-toolkit/compat");
6092
- var import_zod46 = require("zod");
6319
+ var import_zod53 = require("zod");
6093
6320
 
6094
6321
  // src/schema/postPurchaseProductSettings.ts
6095
- var import_zod44 = require("zod");
6322
+ var import_zod51 = require("zod");
6096
6323
 
6097
6324
  // src/schema/postPurchaseProductSource.ts
6098
- var import_zod43 = require("zod");
6099
- var PostPurchaseAmount = import_zod43.z.string().regex(/^\d+(?:\.\d+)?$/).refine((value) => Number.isFinite(Number(value)));
6100
- var PostPurchaseProductId = import_zod43.z.number().int().positive();
6101
- var PostPurchaseVariantId = import_zod43.z.number().int().positive();
6325
+ var import_zod50 = require("zod");
6326
+ var PostPurchaseAmount = import_zod50.z.string().regex(/^\d+(?:\.\d+)?$/).refine((value) => Number.isFinite(Number(value)));
6327
+ var PostPurchaseProductId = import_zod50.z.number().int().positive();
6328
+ var PostPurchaseVariantId = import_zod50.z.number().int().positive();
6102
6329
  var ProductBase = OfferProduct.pick({ description: true, id: true, image: true, title: true }).extend({
6103
6330
  description: OfferProduct.shape.description.nullable(),
6104
6331
  id: PostPurchaseProductId
@@ -6106,51 +6333,51 @@ var ProductBase = OfferProduct.pick({ description: true, id: true, image: true,
6106
6333
  var SourceVariant = OfferProduct.shape.variants.element.pick({ id: true, title: true }).extend({
6107
6334
  compareAtPrice: PostPurchaseAmount.nullable(),
6108
6335
  id: PostPurchaseVariantId,
6109
- imageId: import_zod43.z.number().int().nonnegative().nullish(),
6110
- inventoryManagement: import_zod43.z.string().nullable(),
6111
- inventoryPolicy: import_zod43.z.string(),
6112
- inventoryQuantity: import_zod43.z.number(),
6113
- option1: import_zod43.z.unknown().optional(),
6114
- option2: import_zod43.z.unknown().optional(),
6115
- option3: import_zod43.z.unknown().optional(),
6336
+ imageId: import_zod50.z.number().int().nonnegative().nullish(),
6337
+ inventoryManagement: import_zod50.z.string().nullable(),
6338
+ inventoryPolicy: import_zod50.z.string(),
6339
+ inventoryQuantity: import_zod50.z.number(),
6340
+ option1: import_zod50.z.unknown().optional(),
6341
+ option2: import_zod50.z.unknown().optional(),
6342
+ option3: import_zod50.z.unknown().optional(),
6116
6343
  price: PostPurchaseAmount,
6117
6344
  productId: PostPurchaseProductId,
6118
- sellingPlanAllocations: import_zod43.z.unknown().optional()
6345
+ sellingPlanAllocations: import_zod50.z.unknown().optional()
6119
6346
  });
6120
6347
  var Product2 = ProductBase.extend({
6121
- images: import_zod43.z.array(
6122
- import_zod43.z.object({ alt: import_zod43.z.string().optional().catch(void 0), id: import_zod43.z.number().int().positive(), src: import_zod43.z.string() })
6348
+ images: import_zod50.z.array(
6349
+ import_zod50.z.object({ alt: import_zod50.z.string().optional().catch(void 0), id: import_zod50.z.number().int().positive(), src: import_zod50.z.string() })
6123
6350
  ).nullish(),
6124
- metadata: import_zod43.z.object({
6125
- productQuantity: import_zod43.z.union([
6126
- import_zod43.z.number().int().positive(),
6127
- import_zod43.z.string().regex(/^[1-9]\d*$/).transform(Number)
6351
+ metadata: import_zod50.z.object({
6352
+ productQuantity: import_zod50.z.union([
6353
+ import_zod50.z.number().int().positive(),
6354
+ import_zod50.z.string().regex(/^[1-9]\d*$/).transform(Number)
6128
6355
  ]).optional()
6129
6356
  }).optional(),
6130
- metafields: import_zod43.z.unknown().optional(),
6131
- options: import_zod43.z.unknown().optional(),
6132
- productGroupVariants: import_zod43.z.array(import_zod43.z.unknown()).default([]),
6357
+ metafields: import_zod50.z.unknown().optional(),
6358
+ options: import_zod50.z.unknown().optional(),
6359
+ productGroupVariants: import_zod50.z.array(import_zod50.z.unknown()).default([]),
6133
6360
  // REB-25048: the v2 data source flags a subscription-only product here and sends no selling plan groups
6134
- requiresSellingPlan: import_zod43.z.boolean().nullish(),
6135
- selectedVariant: import_zod43.z.unknown().optional(),
6136
- sellingPlanGroups: import_zod43.z.array(
6361
+ requiresSellingPlan: import_zod50.z.boolean().nullish(),
6362
+ selectedVariant: import_zod50.z.unknown().optional(),
6363
+ sellingPlanGroups: import_zod50.z.array(
6137
6364
  OfferProduct.shape.sellingPlanGroups.unwrap().element.extend({
6138
- discountAmount: import_zod43.z.unknown().optional(),
6139
- discountType: import_zod43.z.unknown().optional(),
6140
- id: import_zod43.z.unknown().optional(),
6141
- requiresSellingPlan: import_zod43.z.boolean().default(false),
6142
- sellingPlans: import_zod43.z.unknown().optional()
6365
+ discountAmount: import_zod50.z.unknown().optional(),
6366
+ discountType: import_zod50.z.unknown().optional(),
6367
+ id: import_zod50.z.unknown().optional(),
6368
+ requiresSellingPlan: import_zod50.z.boolean().default(false),
6369
+ sellingPlans: import_zod50.z.unknown().optional()
6143
6370
  })
6144
6371
  ).default([]),
6145
- variants: import_zod43.z.array(SourceVariant)
6372
+ variants: import_zod50.z.array(SourceVariant)
6146
6373
  });
6147
- var PostPurchaseProductSource = import_zod43.z.object({
6148
- data: import_zod43.z.array(Product2),
6149
- metadata: import_zod43.z.object({ widget: import_zod43.z.record(import_zod43.z.string(), import_zod43.z.unknown()).default({}) }).default({ widget: {} })
6374
+ var PostPurchaseProductSource = import_zod50.z.object({
6375
+ data: import_zod50.z.array(Product2),
6376
+ metadata: import_zod50.z.object({ widget: import_zod50.z.record(import_zod50.z.string(), import_zod50.z.unknown()).default({}) }).default({ widget: {} })
6150
6377
  });
6151
6378
 
6152
6379
  // src/schema/postPurchaseProductSettings.ts
6153
- var amount = import_zod44.z.union([import_zod44.z.number().nonnegative(), PostPurchaseAmount.transform(Number)]);
6380
+ var amount = import_zod51.z.union([import_zod51.z.number().nonnegative(), PostPurchaseAmount.transform(Number)]);
6154
6381
  var PostPurchaseProductSettings = PostPurchaseSettings.pick({
6155
6382
  discountedFrom: true,
6156
6383
  language: true,
@@ -6162,18 +6389,18 @@ var PostPurchaseProductSettings = PostPurchaseSettings.pick({
6162
6389
  subscriptionIsDefault: true,
6163
6390
  upgradeToSubscription: true
6164
6391
  }).extend({
6165
- advance: import_zod44.z.unknown().default({}),
6166
- blocks: import_zod44.z.array(import_zod44.z.unknown()).optional(),
6392
+ advance: import_zod51.z.unknown().default({}),
6393
+ blocks: import_zod51.z.array(import_zod51.z.unknown()).optional(),
6167
6394
  discount: PostPurchaseSettings.shape.discount.extend({ amount: amount.default(30) }),
6168
- integrations: import_zod44.z.unknown().default({}),
6395
+ integrations: import_zod51.z.unknown().default({}),
6169
6396
  shipping: PostPurchaseSettings.shape.shipping.extend({ amount: amount.default(10) }),
6170
- styles: import_zod44.z.unknown().default({}),
6397
+ styles: import_zod51.z.unknown().default({}),
6171
6398
  subImages: PostPurchaseSettings.shape.subImages.catch(null),
6172
- subscription: import_zod44.z.unknown().default(PostPurchaseSettings.shape.subscription.parse(void 0))
6399
+ subscription: import_zod51.z.unknown().default(PostPurchaseSettings.shape.subscription.parse(void 0))
6173
6400
  });
6174
6401
 
6175
6402
  // src/server/readPostPurchaseProductSource.ts
6176
- var import_zod45 = require("zod");
6403
+ var import_zod52 = require("zod");
6177
6404
 
6178
6405
  // src/server/postPurchaseResponseDrift.ts
6179
6406
  var heard = /* @__PURE__ */ new WeakMap();
@@ -6199,9 +6426,9 @@ var requiresOwnSellingPlan = (product) => product.requiresSellingPlan === true;
6199
6426
  var requiresUnsuppliedSellingPlan = (product) => requiresOwnSellingPlan(product) && !product.sellingPlanGroups?.length;
6200
6427
 
6201
6428
  // src/server/readPostPurchaseProductSource.ts
6202
- var Envelope = PostPurchaseProductSource.extend({ data: import_zod45.z.array(import_zod45.z.unknown()) });
6429
+ var Envelope = PostPurchaseProductSource.extend({ data: import_zod52.z.array(import_zod52.z.unknown()) });
6203
6430
  var Product3 = PostPurchaseProductSource.shape.data.element;
6204
- var Identified = import_zod45.z.object({ id: PostPurchaseProductId });
6431
+ var Identified = import_zod52.z.object({ id: PostPurchaseProductId });
6205
6432
  var readPostPurchaseProductSource = (response, report) => {
6206
6433
  const { data, metadata } = Envelope.parse(deepCamelCase(response));
6207
6434
  const drift = [];
@@ -6236,9 +6463,9 @@ var normalizePostPurchaseSource = (settings, response, report) => {
6236
6463
  const original = PostPurchaseProductSettings.parse(deepCamelCase(settings));
6237
6464
  const { dropped, metadata, products } = readPostPurchaseProductSource(response, report);
6238
6465
  const overrides = Object.fromEntries(Object.entries(metadata.widget).filter(([key]) => key in original));
6239
- const discount = import_zod46.z.object({ type: import_zod46.z.string() }).safeParse(overrides.discount);
6466
+ const discount = import_zod53.z.object({ type: import_zod53.z.string() }).safeParse(overrides.discount);
6240
6467
  if (discount.success && discount.data.type === "fixed") {
6241
- overrides.discount = { ...import_zod46.z.record(import_zod46.z.string(), import_zod46.z.unknown()).parse(overrides.discount), type: "fixed_amount" };
6468
+ overrides.discount = { ...import_zod53.z.record(import_zod53.z.string(), import_zod53.z.unknown()).parse(overrides.discount), type: "fixed_amount" };
6242
6469
  }
6243
6470
  const effective = PostPurchaseProductSettings.parse((0, import_compat7.merge)({}, original, overrides));
6244
6471
  const data = products.map(({ product }) => product);
@@ -6275,52 +6502,52 @@ var postPurchasePlanDiscountPercentage = (price, adjustment) => {
6275
6502
  };
6276
6503
 
6277
6504
  // src/schema/postPurchasePlanCatalog.ts
6278
- var import_zod49 = require("zod");
6505
+ var import_zod56 = require("zod");
6279
6506
 
6280
6507
  // src/schema/postPurchasePlanAdjustment.ts
6281
- var import_zod48 = require("zod");
6508
+ var import_zod55 = require("zod");
6282
6509
 
6283
6510
  // src/schema/postPurchaseDiscount.ts
6284
- var import_zod47 = require("zod");
6285
- var Discount = import_zod47.z.object({
6286
- amount: import_zod47.z.number().nonnegative(),
6287
- title: import_zod47.z.string(),
6288
- type: import_zod47.z.enum(["none", "fixed_amount", "percentage"])
6511
+ var import_zod54 = require("zod");
6512
+ var Discount = import_zod54.z.object({
6513
+ amount: import_zod54.z.number().nonnegative(),
6514
+ title: import_zod54.z.string(),
6515
+ type: import_zod54.z.enum(["none", "fixed_amount", "percentage"])
6289
6516
  });
6290
6517
  var validPostPurchaseDiscount = (discount) => discount.type !== "percentage" || discount.amount <= 100;
6291
6518
  var PostPurchaseDiscount = Discount.refine(validPostPurchaseDiscount);
6292
6519
 
6293
6520
  // src/schema/postPurchasePlanAdjustment.ts
6294
- var PostPurchasePlanAdjustment = import_zod48.z.object({
6521
+ var PostPurchasePlanAdjustment = import_zod55.z.object({
6295
6522
  amount: PostPurchaseDiscount.shape.amount,
6296
- type: import_zod48.z.enum(["percentage", "fixed_amount", "price"])
6523
+ type: import_zod55.z.enum(["percentage", "fixed_amount", "price"])
6297
6524
  }).refine(({ amount: amount2, type }) => type === "price" || validPostPurchaseDiscount({ amount: amount2, type }));
6298
6525
 
6299
6526
  // src/schema/postPurchasePlanCatalog.ts
6300
- var PostPurchasePlanOption = import_zod49.z.object({
6527
+ var PostPurchasePlanOption = import_zod56.z.object({
6301
6528
  adjustment: PostPurchasePlanAdjustment.optional(),
6302
6529
  /** cab-checkout's `discountPercentage`: the plan's own whole-percent saving on the regular price (`{{subscriptionDiscount}}`). */
6303
- discountPercentage: import_zod49.z.number().int().min(0).max(100).optional(),
6304
- id: import_zod49.z.number().int().positive(),
6305
- intervalFrequency: import_zod49.z.string().regex(/^[1-9]\d*$/).optional(),
6306
- intervalLabel: import_zod49.z.string().min(1),
6307
- name: import_zod49.z.string().min(1)
6530
+ discountPercentage: import_zod56.z.number().int().min(0).max(100).optional(),
6531
+ id: import_zod56.z.number().int().positive(),
6532
+ intervalFrequency: import_zod56.z.string().regex(/^[1-9]\d*$/).optional(),
6533
+ intervalLabel: import_zod56.z.string().min(1),
6534
+ name: import_zod56.z.string().min(1)
6308
6535
  });
6309
- var PostPurchasePlanCatalog = import_zod49.z.object({
6310
- plans: import_zod49.z.array(PostPurchasePlanOption),
6311
- productId: import_zod49.z.number().int().positive(),
6312
- requiresSellingPlan: import_zod49.z.boolean(),
6313
- variantId: import_zod49.z.number().int().positive()
6536
+ var PostPurchasePlanCatalog = import_zod56.z.object({
6537
+ plans: import_zod56.z.array(PostPurchasePlanOption),
6538
+ productId: import_zod56.z.number().int().positive(),
6539
+ requiresSellingPlan: import_zod56.z.boolean(),
6540
+ variantId: import_zod56.z.number().int().positive()
6314
6541
  });
6315
6542
 
6316
6543
  // src/server/postPurchaseLegacyPlans.ts
6317
- var import_zod51 = require("zod");
6544
+ var import_zod58 = require("zod");
6318
6545
 
6319
6546
  // src/server/postPurchasePlanAdjustment.ts
6320
- var import_zod50 = require("zod");
6321
- var SourceAdjustment = import_zod50.z.object({
6547
+ var import_zod57 = require("zod");
6548
+ var SourceAdjustment = import_zod57.z.object({
6322
6549
  amount: PostPurchaseProductSettings.shape.discount.shape.amount.unwrap(),
6323
- type: import_zod50.z.enum(["percentage", "fixed_amount", "amount", "price", "none", "fixed"])
6550
+ type: import_zod57.z.enum(["percentage", "fixed_amount", "amount", "price", "none", "fixed"])
6324
6551
  });
6325
6552
  var readPostPurchasePlanAdjustment = (raw) => {
6326
6553
  const source2 = SourceAdjustment.parse(raw);
@@ -6339,13 +6566,13 @@ var readPostPurchasePlanAdjustment = (raw) => {
6339
6566
  var Plan = PostPurchasePlanOption.pick({ id: true, name: true }).extend({
6340
6567
  orderIntervalFrequency: PostPurchasePlanOption.shape.intervalFrequency.unwrap(),
6341
6568
  orderIntervalUnitType: PostPurchasePlanOption.shape.intervalLabel,
6342
- shopifyVariantId: import_zod51.z.string().regex(/^[1-9]\d*$/).nullish()
6569
+ shopifyVariantId: import_zod58.z.string().regex(/^[1-9]\d*$/).nullish()
6343
6570
  });
6344
- var Group = import_zod51.z.object({
6345
- discountAmount: import_zod51.z.unknown(),
6346
- discountType: import_zod51.z.unknown(),
6347
- id: import_zod51.z.number().int().positive(),
6348
- sellingPlans: import_zod51.z.array(import_zod51.z.object({ shopifyVariantId: Plan.shape.shopifyVariantId }).passthrough())
6571
+ var Group = import_zod58.z.object({
6572
+ discountAmount: import_zod58.z.unknown(),
6573
+ discountType: import_zod58.z.unknown(),
6574
+ id: import_zod58.z.number().int().positive(),
6575
+ sellingPlans: import_zod58.z.array(import_zod58.z.object({ shopifyVariantId: Plan.shape.shopifyVariantId }).passthrough())
6349
6576
  });
6350
6577
  var readPostPurchaseLegacyPlans = (raw, variantId) => {
6351
6578
  const group = Group.pick({ id: true, sellingPlans: true }).parse(raw);
@@ -6366,22 +6593,22 @@ var readPostPurchaseLegacyPlans = (raw, variantId) => {
6366
6593
  };
6367
6594
 
6368
6595
  // src/server/postPurchaseModernPlans.ts
6369
- var import_zod52 = require("zod");
6370
- var Groups = import_zod52.z.array(
6371
- import_zod52.z.object({
6372
- id: import_zod52.z.string().min(1),
6373
- sellingPlans: import_zod52.z.unknown()
6596
+ var import_zod59 = require("zod");
6597
+ var Groups = import_zod59.z.array(
6598
+ import_zod59.z.object({
6599
+ id: import_zod59.z.string().min(1),
6600
+ sellingPlans: import_zod59.z.unknown()
6374
6601
  })
6375
6602
  );
6376
- var PostPurchasePlanAllocations = import_zod52.z.array(import_zod52.z.object({ sellingPlanGroupId: import_zod52.z.string().min(1) }));
6603
+ var PostPurchasePlanAllocations = import_zod59.z.array(import_zod59.z.object({ sellingPlanGroupId: import_zod59.z.string().min(1) }));
6377
6604
  var Allocations = PostPurchasePlanAllocations.default([]);
6378
- var Plans = import_zod52.z.array(
6605
+ var Plans = import_zod59.z.array(
6379
6606
  PostPurchasePlanOption.pick({ id: true, name: true }).extend({
6380
- options: import_zod52.z.array(import_zod52.z.object({ value: import_zod52.z.string().min(1) })).min(1),
6381
- priceAdjustments: import_zod52.z.array(import_zod52.z.unknown())
6607
+ options: import_zod59.z.array(import_zod59.z.object({ value: import_zod59.z.string().min(1) })).min(1),
6608
+ priceAdjustments: import_zod59.z.array(import_zod59.z.unknown())
6382
6609
  })
6383
6610
  );
6384
- var FirstAdjustment = import_zod52.z.object({
6611
+ var FirstAdjustment = import_zod59.z.object({
6385
6612
  value: PostPurchaseProductSettings.shape.discount.shape.amount.unwrap(),
6386
6613
  valueType: PostPurchasePlanAdjustment.shape.type
6387
6614
  });
@@ -6439,72 +6666,45 @@ var projectPostPurchasePlanCatalog = (normalized, report) => {
6439
6666
  };
6440
6667
 
6441
6668
  // src/schema/postPurchaseSubscriptionProduct.ts
6442
- var import_zod58 = require("zod");
6669
+ var import_zod64 = require("zod");
6443
6670
 
6444
6671
  // src/schema/postPurchaseProduct.ts
6445
- var import_zod57 = require("zod");
6672
+ var import_zod63 = require("zod");
6446
6673
 
6447
6674
  // src/schema/postPurchaseProductDisplay.ts
6448
- var import_zod55 = require("zod");
6675
+ var import_zod61 = require("zod");
6449
6676
 
6450
6677
  // src/schema/postPurchaseProductGallery.ts
6451
- var import_zod53 = require("zod");
6452
- var PostPurchaseProductGallery = import_zod53.z.object({
6678
+ var import_zod60 = require("zod");
6679
+ var PostPurchaseProductGallery = import_zod60.z.object({
6453
6680
  /**
6454
6681
  * Show the thumbnail row: the product had more than one image before `images` was capped at the
6455
6682
  * sub-image limit, and that limit allows at least one thumbnail. It stays true when the cap leaves one
6456
6683
  * image (legacy checks the count before slicing). Older replies omit it; fall back to `images.length > 1`.
6457
6684
  */
6458
- hasMultiple: import_zod53.z.boolean().optional(),
6459
- images: import_zod53.z.array(
6460
- import_zod53.z.object({
6461
- description: import_zod53.z.string(),
6462
- id: import_zod53.z.number().int().positive(),
6463
- source: import_zod53.z.string(),
6464
- thumbnail: import_zod53.z.string()
6685
+ hasMultiple: import_zod60.z.boolean().optional(),
6686
+ images: import_zod60.z.array(
6687
+ import_zod60.z.object({
6688
+ description: import_zod60.z.string(),
6689
+ id: import_zod60.z.number().int().positive(),
6690
+ source: import_zod60.z.string(),
6691
+ thumbnail: import_zod60.z.string()
6465
6692
  })
6466
6693
  ),
6467
- selectedImageId: import_zod53.z.number().int().positive().optional()
6468
- });
6469
-
6470
- // src/schema/postPurchaseProductReviews.ts
6471
- var import_zod54 = require("zod");
6472
- var decimal = import_zod54.z.union([
6473
- import_zod54.z.number(),
6474
- import_zod54.z.string().regex(/^\d+(?:\.\d+)?$/).transform(Number)
6475
- ]);
6476
- var PostPurchaseCommonReviewRating = import_zod54.z.object({ value: decimal.pipe(import_zod54.z.number().min(0).max(5)) });
6477
- var PostPurchaseKlaviyoReviewRating = PostPurchaseCommonReviewRating.extend({
6478
- // Legacy validates key presence, then displays the raw value on five stars without rescaling.
6479
- scale_max: import_zod54.z.unknown().nonoptional(),
6480
- scale_min: import_zod54.z.unknown().nonoptional()
6481
- });
6482
- var PostPurchaseReviewCount = import_zod54.z.string().regex(/^\d+(?:\.\d+)?$/).transform(Number).pipe(import_zod54.z.number().int().nonnegative());
6483
- var PostPurchaseReviewStyles = PostPurchaseSettings.shape.styles.unwrap().extend({
6484
- strokeWidth: decimal.pipe(import_zod54.z.number().nonnegative()).default(1)
6485
- }).prefault({});
6486
- var PostPurchaseProductReviews = import_zod54.z.object({
6487
- color: import_zod54.z.string(),
6488
- rating: import_zod54.z.number().positive().max(5),
6489
- reviewCount: import_zod54.z.number().int().nonnegative(),
6490
- reviewsPlural: import_zod54.z.string(),
6491
- reviewsSingular: import_zod54.z.string(),
6492
- size: import_zod54.z.enum(["small", "medium", "large"]),
6493
- strokeColor: import_zod54.z.string(),
6494
- strokeWidth: import_zod54.z.number().nonnegative()
6694
+ selectedImageId: import_zod60.z.number().int().positive().optional()
6495
6695
  });
6496
6696
 
6497
6697
  // src/schema/postPurchaseProductDisplay.ts
6498
6698
  var language = PostPurchaseSettings.shape.language;
6499
- var PostPurchasePrimaryImageSource = import_zod55.z.string().default(
6699
+ var PostPurchasePrimaryImageSource = import_zod61.z.string().default(
6500
6700
  "https://cdn.shopify.com/shopifycloud/shopify/assets/no-image-2048-5e88c1b20e087fb7bbe9a3771824e743c244f437e4f8ba93bbf7b11b53f7824c.gif"
6501
6701
  );
6502
- var PostPurchaseProductDisplay = import_zod55.z.object({
6702
+ var PostPurchaseProductDisplay = import_zod61.z.object({
6503
6703
  descriptionDocument: TiptapDocument.optional(),
6504
6704
  discountedFrom: PostPurchaseSettings.shape.discountedFrom,
6505
6705
  gallery: PostPurchaseProductGallery.optional(),
6506
6706
  language: language.pick({ description: true, descriptionEnabled: true }),
6507
- primaryImage: import_zod55.z.object({ description: import_zod55.z.string(), source: import_zod55.z.string() }),
6707
+ primaryImage: import_zod61.z.object({ description: import_zod61.z.string(), source: import_zod61.z.string() }),
6508
6708
  productOptions: PostPurchaseSettings.shape.productOptions.pick({
6509
6709
  showDeclineAll: true,
6510
6710
  showShipping: true,
@@ -6519,16 +6719,16 @@ var PostPurchaseProductDisplay = import_zod55.z.object({
6519
6719
  });
6520
6720
 
6521
6721
  // src/schema/postPurchaseSubscription.ts
6522
- var import_zod56 = require("zod");
6523
- var PostPurchaseSubscriptionTerms = import_zod56.z.object({
6722
+ var import_zod62 = require("zod");
6723
+ var PostPurchaseSubscriptionTerms = import_zod62.z.object({
6524
6724
  adjustment: PostPurchasePlanAdjustment.optional(),
6525
- initialShippingPrice: import_zod56.z.number().nonnegative(),
6526
- intervalLabel: import_zod56.z.string().min(1),
6527
- name: import_zod56.z.string().min(1),
6528
- recurringShippingPrice: import_zod56.z.number().nonnegative(),
6529
- shippingOption: import_zod56.z.object({ presentmentTitle: import_zod56.z.string(), title: import_zod56.z.string() }),
6725
+ initialShippingPrice: import_zod62.z.number().nonnegative(),
6726
+ intervalLabel: import_zod62.z.string().min(1),
6727
+ name: import_zod62.z.string().min(1),
6728
+ recurringShippingPrice: import_zod62.z.number().nonnegative(),
6729
+ shippingOption: import_zod62.z.object({ presentmentTitle: import_zod62.z.string(), title: import_zod62.z.string() }),
6530
6730
  /** A switch to subscription (STS): the one subscription that charges no initial shipping (L122). */
6531
- sts: import_zod56.z.literal(true).optional()
6731
+ sts: import_zod62.z.literal(true).optional()
6532
6732
  });
6533
6733
 
6534
6734
  // src/schema/postPurchaseProduct.ts
@@ -6538,52 +6738,52 @@ var PostPurchaseVariant = OfferProduct.shape.variants.element.pick({ id: true, t
6538
6738
  id: PostPurchaseVariantId,
6539
6739
  price: PostPurchaseAmount
6540
6740
  });
6541
- var PreparedPostPurchaseProduct = import_zod57.z.object({
6741
+ var PreparedPostPurchaseProduct = import_zod63.z.object({
6542
6742
  display: PostPurchaseProductDisplay,
6543
- labels: import_zod57.z.object({
6743
+ labels: import_zod63.z.object({
6544
6744
  declineAll: global.declineAll,
6545
- free: import_zod57.z.string(),
6745
+ free: import_zod63.z.string(),
6546
6746
  notAvailable: global.notAvailable,
6547
- payNow: import_zod57.z.string(),
6548
- quantity: import_zod57.z.string(),
6747
+ payNow: import_zod63.z.string(),
6748
+ quantity: import_zod63.z.string(),
6549
6749
  recurringShipping: global.recurringShipping,
6550
6750
  recurringSubtotal: global.recurringSubtotal,
6551
- save: import_zod57.z.string(),
6552
- shipping: import_zod57.z.string(),
6553
- subtotal: import_zod57.z.string(),
6554
- taxes: import_zod57.z.string(),
6555
- total: import_zod57.z.string()
6751
+ save: import_zod63.z.string(),
6752
+ shipping: import_zod63.z.string(),
6753
+ subtotal: import_zod63.z.string(),
6754
+ taxes: import_zod63.z.string(),
6755
+ total: import_zod63.z.string()
6556
6756
  }),
6557
6757
  product: OfferProduct.pick({ description: true, id: true, image: true, title: true }).extend({
6558
6758
  description: OfferProduct.shape.description.nullable(),
6559
6759
  id: PostPurchaseProductId,
6560
6760
  variant: PostPurchaseVariant
6561
6761
  }),
6562
- selection: import_zod57.z.object({
6762
+ selection: import_zod63.z.object({
6563
6763
  productId: PostPurchaseProductId,
6564
- quantity: import_zod57.z.number().int().positive(),
6565
- sellingPlanId: import_zod57.z.number().int().positive().optional(),
6764
+ quantity: import_zod63.z.number().int().positive(),
6765
+ sellingPlanId: import_zod63.z.number().int().positive().optional(),
6566
6766
  variantId: PostPurchaseVariantId
6567
6767
  }),
6568
- status: import_zod57.z.literal("prepared"),
6569
- terms: import_zod57.z.object({
6768
+ status: import_zod63.z.literal("prepared"),
6769
+ terms: import_zod63.z.object({
6570
6770
  discount: PostPurchaseDiscount,
6571
- shipping: import_zod57.z.object({
6572
- amount: import_zod57.z.number().nonnegative(),
6573
- title: import_zod57.z.string(),
6574
- type: import_zod57.z.enum(["free", "fixed_amount"])
6771
+ shipping: import_zod63.z.object({
6772
+ amount: import_zod63.z.number().nonnegative(),
6773
+ title: import_zod63.z.string(),
6774
+ type: import_zod63.z.enum(["free", "fixed_amount"])
6575
6775
  }),
6576
6776
  subscription: PostPurchaseSubscriptionTerms.optional()
6577
6777
  })
6578
6778
  });
6579
- var PostPurchasePreparation = import_zod57.z.discriminatedUnion("status", [
6779
+ var PostPurchasePreparation = import_zod63.z.discriminatedUnion("status", [
6580
6780
  PreparedPostPurchaseProduct,
6581
- import_zod57.z.object({ reason: import_zod57.z.string(), status: import_zod57.z.literal("unsupported") })
6781
+ import_zod63.z.object({ reason: import_zod63.z.string(), status: import_zod63.z.literal("unsupported") })
6582
6782
  ]);
6583
6783
 
6584
6784
  // src/schema/postPurchaseSubscriptionProduct.ts
6585
6785
  var PreparedPostPurchaseSubscription = PreparedPostPurchaseProduct.extend({
6586
- selection: PreparedPostPurchaseProduct.shape.selection.extend({ sellingPlanId: import_zod58.z.number().int().positive() }),
6786
+ selection: PreparedPostPurchaseProduct.shape.selection.extend({ sellingPlanId: import_zod64.z.number().int().positive() }),
6587
6787
  terms: PreparedPostPurchaseProduct.shape.terms.extend({
6588
6788
  subscription: PostPurchaseSubscriptionTerms
6589
6789
  }).refine(
@@ -6643,7 +6843,7 @@ var subscriptionUnavailable = (normalized, plan, allowCollection, quantity3) =>
6643
6843
  };
6644
6844
 
6645
6845
  // src/server/postPurchaseProductDisplay.ts
6646
- var import_zod60 = require("zod");
6846
+ var import_zod66 = require("zod");
6647
6847
 
6648
6848
  // src/server/postPurchasePrimaryImage.ts
6649
6849
  var postPurchasePrimaryImage = (product) => {
@@ -6669,7 +6869,7 @@ var postPurchaseProductGallery = (product, limit) => {
6669
6869
  };
6670
6870
 
6671
6871
  // src/transforms/postPurchase/convertDescriptionRte.ts
6672
- var import_zod59 = require("zod");
6872
+ var import_zod65 = require("zod");
6673
6873
  var alignments = { center: "center", left: "start", right: "end" };
6674
6874
  var colors = ["critical", "subdued", "success", "warning"];
6675
6875
  var sizes2 = ["extraSmall", "small", "medium", "large", "extraLarge"];
@@ -6681,19 +6881,19 @@ var spacings2 = {
6681
6881
  xloose: "extraLoose",
6682
6882
  xtight: "extraTight"
6683
6883
  };
6684
- var Block = import_zod59.z.object({
6685
- attrs: import_zod59.z.object({ alignment: import_zod59.z.enum(["left", "center", "right"]).optional().catch(void 0) }).catch({}),
6686
- content: import_zod59.z.array(import_zod59.z.unknown()).catch([]),
6687
- type: import_zod59.z.literal("ShopifyTextBlock")
6688
- });
6689
- var Run = import_zod59.z.object({ marks: import_zod59.z.array(import_zod59.z.unknown()).catch([]), text: import_zod59.z.string().min(1), type: import_zod59.z.literal("text") });
6690
- var Inline = import_zod59.z.object({
6691
- attrs: import_zod59.z.object({
6692
- color: import_zod59.z.enum(colors).optional().catch(void 0),
6693
- emphasis: import_zod59.z.array(import_zod59.z.unknown()).catch([]),
6694
- size: import_zod59.z.enum(sizes2).optional().catch(void 0)
6884
+ var Block = import_zod65.z.object({
6885
+ attrs: import_zod65.z.object({ alignment: import_zod65.z.enum(["left", "center", "right"]).optional().catch(void 0) }).catch({}),
6886
+ content: import_zod65.z.array(import_zod65.z.unknown()).catch([]),
6887
+ type: import_zod65.z.literal("ShopifyTextBlock")
6888
+ });
6889
+ var Run = import_zod65.z.object({ marks: import_zod65.z.array(import_zod65.z.unknown()).catch([]), text: import_zod65.z.string().min(1), type: import_zod65.z.literal("text") });
6890
+ var Inline = import_zod65.z.object({
6891
+ attrs: import_zod65.z.object({
6892
+ color: import_zod65.z.enum(colors).optional().catch(void 0),
6893
+ emphasis: import_zod65.z.array(import_zod65.z.unknown()).catch([]),
6894
+ size: import_zod65.z.enum(sizes2).optional().catch(void 0)
6695
6895
  }),
6696
- type: import_zod59.z.literal("ShopifyTextInline")
6896
+ type: import_zod65.z.literal("ShopifyTextInline")
6697
6897
  });
6698
6898
  var marks = (raw) => {
6699
6899
  const found = raw.map((mark) => Inline.safeParse(mark)).find(({ success }) => success)?.data;
@@ -6726,7 +6926,7 @@ var convertDescriptionRte = (rte, spacing) => TiptapDocument.parse({
6726
6926
  });
6727
6927
 
6728
6928
  // src/server/postPurchaseProductDisplay.ts
6729
- var ResponseLanguage = import_zod60.z.object({ description: PostPurchaseProductDisplay.shape.responseDescription }).default({ description: "" });
6929
+ var ResponseLanguage = import_zod66.z.object({ description: PostPurchaseProductDisplay.shape.responseDescription }).default({ description: "" });
6730
6930
  var projectPostPurchaseProductDisplay = (effective, metadata, product) => PostPurchaseProductDisplay.parse({
6731
6931
  descriptionDocument: effective.language.descriptionRte && convertDescriptionRte(effective.language.descriptionRte, effective.language.descriptionSpacing),
6732
6932
  discountedFrom: effective.discountedFrom,
@@ -6738,146 +6938,6 @@ var projectPostPurchaseProductDisplay = (effective, metadata, product) => PostPu
6738
6938
  shouldShowSavingText: effective.discount.shouldShowSavingText
6739
6939
  });
6740
6940
 
6741
- // src/server/postPurchaseReviewData.ts
6742
- var import_zod65 = require("zod");
6743
-
6744
- // src/server/postPurchaseJudgeMeReviews.ts
6745
- var import_zod62 = require("zod");
6746
-
6747
- // src/server/postPurchaseReviewFields.ts
6748
- var import_zod61 = require("zod");
6749
- var Field = import_zod61.z.object({ key: import_zod61.z.string(), namespace: import_zod61.z.string(), value: import_zod61.z.unknown().optional() });
6750
- var reviewFields = (raw) => {
6751
- const fields4 = import_zod61.z.array(import_zod61.z.unknown()).parse(raw).flatMap((field) => {
6752
- const parsed = Field.safeParse(field);
6753
- return parsed.success ? [parsed.data] : [];
6754
- });
6755
- return (namespace, key) => fields4.find((field) => field.namespace === namespace && field.key === key);
6756
- };
6757
- var ReviewFieldError = class extends Error {
6758
- constructor(field) {
6759
- super(`Unreadable review field ${field}`);
6760
- this.field = field;
6761
- }
6762
- };
6763
- var readReviewField = (field, read) => {
6764
- try {
6765
- return read(field.value);
6766
- } catch {
6767
- throw new ReviewFieldError(`${field.namespace}.${field.key}`);
6768
- }
6769
- };
6770
-
6771
- // src/server/postPurchaseJudgeMeReviews.ts
6772
- var readJudgeMeReviews = (find) => {
6773
- const field = find("judgeme", "badge");
6774
- if (!field) return null;
6775
- return readReviewField(field, (value) => {
6776
- const html = import_zod62.z.string().parse(value);
6777
- const rating = html.match(/data-average-rating=['"](\d+(?:\.\d+)?)['"]/);
6778
- const count = html.match(/data-number-of-reviews=['"](\d+)['"]/);
6779
- if (!rating || !count) throw new Error("Unreadable Judge.me attributes");
6780
- return {
6781
- rating: PostPurchaseCommonReviewRating.parse({ value: rating[1] }).value,
6782
- reviewCount: PostPurchaseReviewCount.parse(count[1])
6783
- };
6784
- });
6785
- };
6786
-
6787
- // src/server/postPurchaseOkendoReviews.ts
6788
- var import_zod63 = require("zod");
6789
- var Summary = import_zod63.z.object({
6790
- reviewAverageValue: PostPurchaseCommonReviewRating.shape.value,
6791
- reviewCount: import_zod63.z.union([PostPurchaseProductReviews.shape.reviewCount, PostPurchaseReviewCount])
6792
- });
6793
- var readOkendoReviews = (find) => {
6794
- const field = find("okendo", "summaryData");
6795
- if (!field) return null;
6796
- const summary = readReviewField(field, (value) => Summary.parse(JSON.parse(import_zod63.z.string().parse(value))));
6797
- return { rating: summary.reviewAverageValue, reviewCount: summary.reviewCount };
6798
- };
6799
-
6800
- // src/server/postPurchaseScalarReviews.ts
6801
- var import_zod64 = require("zod");
6802
- var readScalarReviews = (find, namespace, ratingKey, countKey) => {
6803
- const rating = find(namespace, ratingKey);
6804
- const count = find(namespace, countKey);
6805
- if (!rating || !count) return null;
6806
- return {
6807
- rating: readReviewField(
6808
- rating,
6809
- (value) => PostPurchaseCommonReviewRating.parse({ value: import_zod64.z.string().parse(value) }).value
6810
- ),
6811
- reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
6812
- };
6813
- };
6814
-
6815
- // src/server/postPurchaseReviewData.ts
6816
- var readStandardReviews = (find) => {
6817
- const rating = find("reviews", "rating");
6818
- const count = find("reviews", "rating_count");
6819
- if (!rating || !count) return null;
6820
- return {
6821
- rating: readReviewField(rating, (raw) => {
6822
- const value = import_zod65.z.string().parse(raw);
6823
- return PostPurchaseCommonReviewRating.parse(/^\d+(?:\.\d+)?$/.test(value) ? { value } : JSON.parse(value)).value;
6824
- }),
6825
- reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
6826
- };
6827
- };
6828
- var readPostPurchaseReviewData = (provider, find) => {
6829
- if (provider === "yotpo") return readScalarReviews(find, "yotpo", "reviews_average", "reviews_count");
6830
- if (provider === "stamped") return readScalarReviews(find, "stamped", "reviews_average", "reviews_count");
6831
- if (provider === "judgeme") return readJudgeMeReviews(find);
6832
- if (provider === "okendo") return readOkendoReviews(find);
6833
- if (provider === "opinew") return readScalarReviews(find, "opinew_metafields", "reviews_average", "reviews_count");
6834
- if (provider === "reviewsio")
6835
- return readScalarReviews(find, "reviewscouk", "rating", "total") ?? readStandardReviews(find);
6836
- if (provider === "loox") return readScalarReviews(find, "loox", "avg_rating", "num_reviews");
6837
- if (provider === "junip") return readScalarReviews(find, "junip", "rating_average", "rating_count");
6838
- const rating = find("reviews", "rating");
6839
- const count = find("reviews", "rating_count");
6840
- if (!rating || !count) return null;
6841
- return {
6842
- rating: readReviewField(
6843
- rating,
6844
- (value) => PostPurchaseKlaviyoReviewRating.parse(JSON.parse(import_zod65.z.string().parse(value))).value
6845
- ),
6846
- reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
6847
- };
6848
- };
6849
-
6850
- // src/server/postPurchaseReviewProvider.ts
6851
- var import_zod66 = require("zod");
6852
- var IntegrationInput = import_zod66.z.record(import_zod66.z.string(), import_zod66.z.unknown()).prefault({});
6853
- var precedence = [
6854
- "klaviyo",
6855
- "judgeme",
6856
- "junip",
6857
- "loox",
6858
- "okendo",
6859
- "opinew",
6860
- "reviewsio",
6861
- "stamped",
6862
- "yotpo"
6863
- ];
6864
- var ReviewsIoFlag = import_zod66.z.preprocess((value) => {
6865
- if (typeof value === "string") {
6866
- const flag = value.toLowerCase();
6867
- if (flag === "true" || flag === "yes") return true;
6868
- if (flag === "false" || flag === "no") return false;
6869
- }
6870
- return value;
6871
- }, PostPurchaseSettings.shape.integrations.shape.reviewsio);
6872
- var selectPostPurchaseReviewProvider = (raw) => {
6873
- const integrations = IntegrationInput.parse(raw);
6874
- for (const provider of precedence) {
6875
- const schema = provider === "reviewsio" ? ReviewsIoFlag : PostPurchaseSettings.shape.integrations.shape[provider];
6876
- if (schema.parse(integrations[provider])) return provider;
6877
- }
6878
- return null;
6879
- };
6880
-
6881
6941
  // src/server/postPurchaseReviews.ts
6882
6942
  var projectPostPurchaseReviews = (settings, { id: productId2, metafields }, report) => {
6883
6943
  try {