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