@rebuy/rebuy 3.59.0 → 3.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +17 -1
- package/dist/index.mjs +17 -1
- package/dist/schema/checkout-and-beyond/constants.cjs +2 -0
- package/dist/schema/checkout-and-beyond/constants.mjs +2 -0
- package/dist/schema/checkout-and-beyond/index.cjs +2 -0
- package/dist/schema/checkout-and-beyond/index.mjs +2 -0
- package/dist/schema/offerProduct.d.ts +16 -0
- package/dist/schema/postPurchaseProductSettings.d.ts +1 -0
- package/dist/schema/widgets/checkout-and-beyond/common.d.ts +10 -1
- package/dist/schema/widgets/post-purchase-offer/postPurchaseOffer.d.ts +1 -0
- package/dist/schema/widgets/post-purchase-offer/postPurchaseSettings.d.ts +1 -0
- package/dist/schema/widgets/post-purchase-offer/postPurchaseWidget.d.ts +1 -0
- package/dist/server/index.cjs +1734 -1674
- package/dist/server/index.mjs +1692 -1632
- package/dist/server/normalizePostPurchaseCollection.d.ts +2 -0
- package/dist/server/normalizePostPurchaseProduct.d.ts +4 -0
- package/dist/server/offerProductReviews.d.ts +13 -0
- package/dist/server/postPurchaseReviewData.d.ts +9 -0
- package/dist/server/preparePostPurchaseMemberView.d.ts +4 -0
- package/dist/server/preparePostPurchaseStsMember.d.ts +2 -0
- package/dist/server/projectPostPurchaseProduct.d.ts +1 -0
- package/dist/server/shared.d.ts +2 -2
- package/dist/transforms/index.cjs +3 -0
- package/dist/transforms/index.mjs +3 -0
- package/dist/transforms/postPurchase/productCardSettings.d.ts +1 -0
- package/package.json +1 -1
package/dist/server/index.mjs
CHANGED
|
@@ -310,6 +310,10 @@ var OfferProductVariant = z3.object({
|
|
|
310
310
|
price: z3.string(),
|
|
311
311
|
title: z3.string()
|
|
312
312
|
});
|
|
313
|
+
var OfferProductReviews = z3.object({
|
|
314
|
+
rating: z3.number().positive().max(5),
|
|
315
|
+
reviewCount: z3.number().int().nonnegative()
|
|
316
|
+
});
|
|
313
317
|
var OfferProduct = z3.object({
|
|
314
318
|
description: z3.string().optional(),
|
|
315
319
|
discount: OfferProductDiscount.optional(),
|
|
@@ -325,6 +329,7 @@ var OfferProduct = z3.object({
|
|
|
325
329
|
link: z3.string().optional(),
|
|
326
330
|
metafields: z3.array(z3.object({ key: z3.string(), namespace: z3.string(), value: z3.string() })).optional(),
|
|
327
331
|
options: z3.array(OfferProductOption),
|
|
332
|
+
reviews: OfferProductReviews.nullish().catch(void 0),
|
|
328
333
|
sellingPlanGroups: z3.array(z3.object({ requiresSellingPlan: z3.boolean().optional() })).optional(),
|
|
329
334
|
title: z3.string(),
|
|
330
335
|
/** 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. */
|
|
@@ -333,6 +338,27 @@ var OfferProduct = z3.object({
|
|
|
333
338
|
|
|
334
339
|
// src/server/b2bAvailability.ts
|
|
335
340
|
import { z as z4 } from "zod";
|
|
341
|
+
|
|
342
|
+
// src/server/shared.ts
|
|
343
|
+
var REBUY_ENGINE_HOST = "rebuyengine.com";
|
|
344
|
+
var unwrapData = (body) => body && typeof body === "object" && "data" in body ? body.data : body;
|
|
345
|
+
var isEmptyObject = (x) => x == null || typeof x === "object" && !Array.isArray(x) && Object.keys(x).length === 0;
|
|
346
|
+
var UpstreamError = class extends Error {
|
|
347
|
+
constructor(status, body, message) {
|
|
348
|
+
super(message ?? `Upstream returned ${status}`);
|
|
349
|
+
this.body = body;
|
|
350
|
+
this.name = "UpstreamError";
|
|
351
|
+
this.status = status;
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
var NotFoundError = class extends Error {
|
|
355
|
+
constructor(message) {
|
|
356
|
+
super(message);
|
|
357
|
+
this.name = "NotFoundError";
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// src/server/b2bAvailability.ts
|
|
336
362
|
var B2B_AVAILABILITY_PATH = "/admin/api/v1/shop/b2b-catalog-availability";
|
|
337
363
|
var productGid = (product) => `gid://shopify/Product/${String(product.id)}`;
|
|
338
364
|
var Verdict = z4.record(z4.string(), z4.boolean());
|
|
@@ -340,9 +366,18 @@ var B2bAvailabilityResponse = z4.object({
|
|
|
340
366
|
availability: Verdict.optional(),
|
|
341
367
|
data: z4.object({ availability: Verdict.optional() }).optional()
|
|
342
368
|
}).transform(({ availability, data }) => availability ?? data?.availability ?? null);
|
|
369
|
+
var MAX_REASON_LENGTH = 120;
|
|
370
|
+
var failureReason = (error) => {
|
|
371
|
+
if (!(error instanceof Error)) return "unknown error";
|
|
372
|
+
const cut = error.message.indexOf(": ");
|
|
373
|
+
const label2 = (cut === -1 ? error.message : error.message.slice(0, cut)).slice(0, MAX_REASON_LENGTH);
|
|
374
|
+
if (!(error instanceof UpstreamError)) return label2 || error.name;
|
|
375
|
+
return label2 && label2 !== `Upstream returned ${error.status}` ? `upstream ${error.status}: ${label2}` : `upstream ${error.status}`;
|
|
376
|
+
};
|
|
343
377
|
var filterByB2bAvailability = async (products, input, ctx) => {
|
|
344
378
|
if (!input.companyLocationId || products.length === 0) return products;
|
|
345
379
|
let verdict;
|
|
380
|
+
let reason = "unreadable verdict";
|
|
346
381
|
try {
|
|
347
382
|
const response = await ctx.fetchUpstream(
|
|
348
383
|
B2B_AVAILABILITY_PATH,
|
|
@@ -361,12 +396,13 @@ var filterByB2bAvailability = async (products, input, ctx) => {
|
|
|
361
396
|
);
|
|
362
397
|
const parsed = B2bAvailabilityResponse.safeParse(response);
|
|
363
398
|
verdict = parsed.success ? parsed.data : null;
|
|
364
|
-
} catch {
|
|
399
|
+
} catch (error) {
|
|
365
400
|
verdict = null;
|
|
401
|
+
reason = failureReason(error);
|
|
366
402
|
}
|
|
367
403
|
if (verdict === null) {
|
|
368
404
|
ctx.reportDrift?.({
|
|
369
|
-
detail:
|
|
405
|
+
detail: `b2b availability check failed (${reason}) \u2014 products served unfiltered`,
|
|
370
406
|
kind: "b2bAvailability"
|
|
371
407
|
});
|
|
372
408
|
return products;
|
|
@@ -374,265 +410,48 @@ var filterByB2bAvailability = async (products, input, ctx) => {
|
|
|
374
410
|
return products.filter((product) => verdict[productGid(product)] !== false);
|
|
375
411
|
};
|
|
376
412
|
|
|
377
|
-
// src/server/
|
|
378
|
-
|
|
379
|
-
var unwrapData = (body) => body && typeof body === "object" && "data" in body ? body.data : body;
|
|
380
|
-
var isEmptyObject = (x) => x == null || typeof x === "object" && !Array.isArray(x) && Object.keys(x).length === 0;
|
|
381
|
-
var UpstreamError = class extends Error {
|
|
382
|
-
constructor(status, body, message) {
|
|
383
|
-
super(message ?? `Upstream returned ${status}`);
|
|
384
|
-
this.body = body;
|
|
385
|
-
this.name = "UpstreamError";
|
|
386
|
-
this.status = status;
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
|
-
var NotFoundError = class extends Error {
|
|
390
|
-
constructor(message) {
|
|
391
|
-
super(message);
|
|
392
|
-
this.name = "NotFoundError";
|
|
393
|
-
}
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
// src/server/shopSubtotal.ts
|
|
397
|
-
var shopCurrencyRate = (cart) => {
|
|
398
|
-
const rate = cart.currencyRate ?? 1;
|
|
399
|
-
return Number.isFinite(rate) && rate > 0 ? rate : 1;
|
|
400
|
-
};
|
|
401
|
-
var shopSubtotalCents = (cart) => Math.round((cart.subtotal - (cart.discountTotal ?? 0)) / shopCurrencyRate(cart));
|
|
402
|
-
var toShopCents = (majorPresentment, rate) => Math.round(majorPresentment * 100 / rate);
|
|
413
|
+
// src/server/postPurchaseReviewData.ts
|
|
414
|
+
import { z as z17 } from "zod";
|
|
403
415
|
|
|
404
|
-
// src/schema/
|
|
405
|
-
import { z as
|
|
416
|
+
// src/schema/postPurchaseProductReviews.ts
|
|
417
|
+
import { z as z12 } from "zod";
|
|
406
418
|
|
|
407
|
-
// src/schema/
|
|
408
|
-
|
|
419
|
+
// src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
|
|
420
|
+
import { z as z11 } from "zod";
|
|
409
421
|
|
|
410
|
-
// src/schema/
|
|
422
|
+
// src/schema/widgets/post-purchase-offer/common.ts
|
|
423
|
+
import { replace, toNumber, toString } from "es-toolkit/compat";
|
|
411
424
|
import { z as z5 } from "zod";
|
|
412
|
-
var
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
variantIds: z5.array(z5.coerce.number()).optional()
|
|
418
|
-
});
|
|
419
|
-
var SmartCartTierExclusion = z5.looseObject({
|
|
420
|
-
collectionIds: z5.array(z5.coerce.number()).optional().catch(void 0),
|
|
421
|
-
productIds: z5.array(z5.coerce.number()).optional().catch(void 0),
|
|
422
|
-
tags: z5.array(z5.string()).optional().catch(void 0),
|
|
423
|
-
type: z5.string().optional().catch(void 0)
|
|
424
|
-
});
|
|
425
|
-
var SmartCartTier = z5.looseObject({
|
|
426
|
-
allProducts: z5.array(SmartCartTierProduct).optional(),
|
|
427
|
-
/** Merchant-set tier label (e.g. "Free gift", "$100 reward"), shown on the step row when enabled. */
|
|
428
|
-
customTierLabel: z5.boolean().optional(),
|
|
429
|
-
customTierLabelText: z5.string().optional(),
|
|
430
|
-
decorativeAmountReachedLabel: z5.boolean().optional(),
|
|
431
|
-
decorativeAmountReachedLabelText: z5.string().optional(),
|
|
432
|
-
decorativeAmountRemainingLabel: z5.boolean().optional(),
|
|
433
|
-
decorativeAmountRemainingLabelText: z5.string().optional(),
|
|
434
|
-
/** Order-discount reward: `'fixedAmount'` (shop-currency dollars) or `'percentage'` (whole percent). */
|
|
435
|
-
discountAmountFromTotal: z5.coerce.number().optional(),
|
|
436
|
-
discountAmountReachedLabel: z5.boolean().optional(),
|
|
437
|
-
discountAmountReachedLabelText: z5.string().optional(),
|
|
438
|
-
discountAmountRemainingLabel: z5.boolean().optional(),
|
|
439
|
-
discountAmountRemainingLabelText: z5.string().optional(),
|
|
440
|
-
discountType: z5.string().optional(),
|
|
441
|
-
/**
|
|
442
|
-
* onsite `exclusions` + `exclusions_enabled` (REB-22305): per-tier rules the converter carries onto
|
|
443
|
-
* `CABProgressTier.exclusions`. `.catch(undefined)` for the same blast-radius reason as `productTierImage`:
|
|
444
|
-
* one drifted value must degrade to "no tier exclusions", never drop every progress bar for the shop.
|
|
445
|
-
*
|
|
446
|
-
* `exclusionsEnabled` is a STRICT boolean on purpose, even though failing open here changes the tier's math
|
|
447
|
-
* (a non-boolean reads as disabled) rather than just an icon. onsite reads its sibling tier flags strictly —
|
|
448
|
-
* `shouldFilterOutOfStockVariantsFromTier` is `tier?.filter_oos_variants === true`, and its `progressBar.ts`
|
|
449
|
-
* types every tier flag as `boolean` — so a stored `1` / `"1"` / `"true"` is "disabled" on the onsite bar too.
|
|
450
|
-
* A truthiness preprocess would make CAB exclude where onsite does not: the opposite parity break.
|
|
451
|
-
*/
|
|
452
|
-
exclusions: z5.array(SmartCartTierExclusion).optional().catch(void 0),
|
|
453
|
-
exclusionsEnabled: z5.boolean().optional().catch(void 0),
|
|
454
|
-
filterOosVariants: z5.boolean().optional(),
|
|
455
|
-
id: z5.string().optional(),
|
|
456
|
-
/**
|
|
457
|
-
* A `null`/absent minimum stays `undefined` (NOT coerced to `0`): a threshold-0 tier is always reached
|
|
458
|
-
* and would auto-add its gift to every cart. onsite's `isTierDataValid` drops a non-numeric minimum for
|
|
459
|
-
* exactly this reason; the converter's `renderableTiers` mirrors that (`Number.isFinite`). A literal `0`
|
|
460
|
-
* is kept — onsite keeps it too. DELIBERATE DIVERGENCE from onsite for string minimums: onsite's
|
|
461
|
-
* `isTierDataValid` is a strict `typeof === 'number'`, so it drops `'50'`; the converter instead coerces
|
|
462
|
-
* `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
|
|
463
|
-
*/
|
|
464
|
-
minimum: z5.preprocess((value) => value == null ? void 0 : value, z5.coerce.number().optional()),
|
|
465
|
-
presentmentCurrencies: z5.looseObject({ enabled: z5.boolean().optional() }).optional(),
|
|
466
|
-
productAmountReachedLabel: z5.boolean().optional(),
|
|
467
|
-
productAmountReachedLabelText: z5.string().optional(),
|
|
468
|
-
productAmountRemainingLabel: z5.boolean().optional(),
|
|
469
|
-
productAmountRemainingLabelText: z5.string().optional(),
|
|
470
|
-
products: z5.array(SmartCartTierProduct).optional(),
|
|
471
|
-
/**
|
|
472
|
-
* onsite `product_tier_element_size`: the step-row icon's square size as a px STRING (`'18px'` …
|
|
473
|
-
* `'36px'` — the admin's five-value Size control, default `'18px'`). React stamps it onto the icon
|
|
474
|
-
* SVG's `width`/`height` (`getProgressStepIconSize`), so the milestone renders at the merchant's
|
|
475
|
-
* chosen size; the converter turns it into `CABProgressTier.iconSizePx` for the CAB renderer.
|
|
476
|
-
*
|
|
477
|
-
* `.catch(undefined)` for the same blast-radius reason as `productTierImage` below: this key was
|
|
478
|
-
* previously unknown-and-ignored by the `looseObject`, and `SmartCartConfig` is parsed
|
|
479
|
-
* `.nullish().catch(undefined)` with no intermediate catch, so one drifted value (a bare number, a
|
|
480
|
-
* `'2rem'`) would drop EVERY progress bar for the shop rather than just this setting. Failing open to
|
|
481
|
-
* `undefined` lands on the documented 18px default — strictly safer than that blast radius. The
|
|
482
|
-
* converter parses the number out and clamps it, so a junk-but-string value degrades the same way.
|
|
483
|
-
*/
|
|
484
|
-
productTierElementSize: z5.string().optional().catch(void 0),
|
|
485
|
-
/**
|
|
486
|
-
* onsite `product_tier_image`: on a product (gift) tier, show the gift's product image in the step-row
|
|
487
|
-
* slot instead of the generic bag icon (React `TierProgressIcon` swaps in the image when this is set and
|
|
488
|
-
* an image resolves). Per-tier; the client resolves the image (config carries only product IDs).
|
|
489
|
-
*
|
|
490
|
-
* `.catch(undefined)` is load-bearing. This key was previously unknown-and-ignored by the `looseObject`;
|
|
491
|
-
* declaring it as a real boolean means a stored non-boolean (`1` / `"1"` / `"true"`) would now FAIL the
|
|
492
|
-
* tier — and since `SmartCartConfig` is parsed `.nullish().catch(undefined)` (userConfig/cabShopConfig)
|
|
493
|
-
* with no intermediate catch, one drifted flag would drop EVERY progress bar for the shop, not just the
|
|
494
|
-
* flag. The converter only reads it for truthiness (`gift && tier.productTierImage`), so failing open to
|
|
495
|
-
* `undefined` (bag-icon fallback, the documented default) is strictly safer than that blast radius.
|
|
496
|
-
*/
|
|
497
|
-
productTierImage: z5.boolean().optional().catch(void 0),
|
|
498
|
-
type: z5.string().optional(),
|
|
499
|
-
/**
|
|
500
|
-
* onsite's PER-TIER unit switch (`unlock_condition_type`): `'item_quantity'` makes `minimum` an
|
|
501
|
-
* item count (checked before any money handling — no ×100, no FX, no presentment overrides,
|
|
502
|
-
* mirroring onsite `getTierMinimum`); anything else (or absent) keeps the money semantics.
|
|
503
|
-
*/
|
|
504
|
-
unlockConditionType: z5.string().optional()
|
|
505
|
-
});
|
|
506
|
-
var SmartCartBar = z5.looseObject({
|
|
507
|
-
countryCodes: z5.array(z5.string()).optional(),
|
|
508
|
-
/**
|
|
509
|
-
* onsite `exclude_discount_in_subtotal`: measure progress against the PRE-discount subtotal so an
|
|
510
|
-
* applied code/order discount doesn't lower progress. The client adds cart discount allocations back.
|
|
511
|
-
*/
|
|
512
|
-
excludeDiscountInSubtotal: z5.boolean().optional(),
|
|
513
|
-
/** Products excluded from the progress subtotal; the client subtracts their variants' cart cost. */
|
|
514
|
-
excludedProducts: z5.array(z5.looseObject({ variantIds: z5.array(z5.coerce.number()).optional() })).optional(),
|
|
515
|
-
freeShippingOnSubscription: z5.boolean().optional(),
|
|
516
|
-
geolocationEnabled: z5.boolean().optional(),
|
|
517
|
-
id: z5.string().optional(),
|
|
518
|
-
language: z5.looseObject({
|
|
519
|
-
freeShippingReached: z5.string().optional(),
|
|
520
|
-
freeShippingRemaining: z5.string().optional(),
|
|
521
|
-
giftAreaTitle: z5.string().optional()
|
|
522
|
-
}).optional(),
|
|
523
|
-
name: z5.string().optional(),
|
|
524
|
-
tiers: z5.array(SmartCartTier).optional()
|
|
525
|
-
});
|
|
526
|
-
var SmartCartComponent = z5.looseObject({
|
|
527
|
-
settings: z5.looseObject({ bars: z5.array(SmartCartBar).optional() }).optional(),
|
|
528
|
-
type: z5.string().optional()
|
|
529
|
-
});
|
|
530
|
-
var SmartCartConfig = z5.looseObject({
|
|
531
|
-
components: z5.array(SmartCartComponent).optional()
|
|
532
|
-
});
|
|
425
|
+
var strictNumber = z5.union([
|
|
426
|
+
z5.number(),
|
|
427
|
+
z5.string().transform((value) => toNumber(replace(toString(value), /[^0-9.]/g, "")) || 0),
|
|
428
|
+
z5.unknown().transform(() => 0)
|
|
429
|
+
]);
|
|
533
430
|
|
|
534
|
-
// src/schema/
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
var
|
|
548
|
-
/**
|
|
549
|
-
* Per-element resilient: parse as `unknown[]` (non-array → `[]`), then keep only the experiments that
|
|
550
|
-
* validate. A single drifted experiment drops itself instead of `.catch`-ing the WHOLE array to `[]` and
|
|
551
|
-
* silently disabling every live A/B test fleet-wide.
|
|
552
|
-
*/
|
|
553
|
-
activeExperiments: z6.array(z6.unknown()).catch([]).default([]).transform(
|
|
554
|
-
(experiments) => experiments.flatMap((experiment) => {
|
|
555
|
-
const result = CabActiveExperiment.safeParse(experiment);
|
|
556
|
-
return result.success ? [result.data] : [];
|
|
557
|
-
})
|
|
558
|
-
),
|
|
559
|
-
/**
|
|
560
|
-
* Only the two fields the smart-cart entitlement gate reads (`shortName`/`isActive`). Per-element
|
|
561
|
-
* resilient like `activeExperiments`: a drifted package entry degrades to an inert `''`/false one that
|
|
562
|
-
* matches nothing, so a real active `cart-merchandising` package still gates correctly and a sibling
|
|
563
|
-
* drift never fails the shared config parse. Note the salvage is fail-CLOSED, not fail-open, for an
|
|
564
|
-
* entitled v6 shop: a malformed whole array (⇒ `[]`) or an inerted `cart-merchandising` entry (e.g.
|
|
565
|
-
* `is_active: 1` ⇒ inactive) makes the gate find no active package and drop every bar. That matches
|
|
566
|
-
* React's "no proof of entitlement ⇒ render null", but it silently removes bars — so the server gate
|
|
567
|
-
* ({@link file://../server/widgetSettings.ts} `fetchProgressBarContext`) emits a `shopConfig` drift
|
|
568
|
-
* when it sees the inert-entry sentinel (`shortName === ''`). The whole-array `[]` case leaves no
|
|
569
|
-
* sentinel and is not separately signalable here.
|
|
570
|
-
*/
|
|
571
|
-
activePackages: z6.array(z6.object({ isActive: z6.boolean(), shortName: z6.string() }).catch({ isActive: false, shortName: "" })).catch([]).default([]),
|
|
572
|
-
apiKey: z6.string(),
|
|
573
|
-
/** The shop's billing generation; the smart-cart entitlement gate only fires for `'v6'`. Missing/drift ⇒ `null` (fail open, ungated). */
|
|
574
|
-
billingVersion: z6.string().nullable().catch(null).default(null),
|
|
575
|
-
/**
|
|
576
|
-
* The shop's rotating cache-buster: `onsite_cache_key` internally — a unix timestamp the engine bumps,
|
|
577
|
-
* and the edge copy of this config purges, on every widget/settings/theme edit — but serialized on the
|
|
578
|
-
* wire as `cache_key`, which `deepCamelCase` maps to this field (renaming it `onsiteCacheKey` would
|
|
579
|
-
* sever the mapping silently; the wire-level assertion in `userConfig.test.ts` is what fails loudly).
|
|
580
|
-
* Threaded onto the widgets/settings read as `cache_key` so the engine marks the response
|
|
581
|
-
* immutable-cacheable and the `cached.*` edge serves it fresh-by-URL. The engine sends a numeric
|
|
582
|
-
* string — coerce — but admit only number/string inputs and constrain to a positive integer: a bare
|
|
583
|
-
* coercion folds `null`/`''`/`false` to `0` and `true` to `1` — "valid" numbers that would go upstream
|
|
584
|
-
* as a constant never-rotating buster and pin the edge copy permanently stale. A real key is always a
|
|
585
|
-
* positive int sent as number or string, so everything else lands on `.catch()` and degrades that read
|
|
586
|
-
* to un-busted (origin-served — slower, never stale), never a parse fail.
|
|
587
|
-
*/
|
|
588
|
-
cacheKey: z6.union([z6.number(), z6.string()]).transform((value) => Number(value)).pipe(z6.number().int().positive()).optional().catch(void 0),
|
|
589
|
-
/**
|
|
590
|
-
* The shop's base-currency ISO code (e.g. `'USD'`). CAB derives the shop minor-unit exponent from it
|
|
591
|
-
* (`currencyDecimals`) so a Functions-applied fixed discount — whose amount is in shop minor units —
|
|
592
|
-
* converts to the buyer's currency exactly in a cross-decimal market. `.catch()` like its siblings: a
|
|
593
|
-
* missing/renamed currency degrades to "unknown" (client falls back to buyer decimals), never a parse fail.
|
|
594
|
-
*/
|
|
595
|
-
currency: z6.string().optional().catch(void 0),
|
|
596
|
-
/**
|
|
597
|
-
* The merchant's "Use Markets in Data Sources" toggle. The engine (CI2) never reads it on the serve
|
|
598
|
-
* path, so the proxy honouring it before sending market context is what makes the setting mean
|
|
599
|
-
* anything (REB-21688). Fail-CLOSED, unlike the fail-open siblings: a missing/null/drifted field reads
|
|
600
|
-
* as markets OFF — market context silently dropped (engine serves shop-default market), never sent
|
|
601
|
-
* against the merchant's setting. The OFF-reading salvages stay distinguishable: missing AND null are
|
|
602
|
-
* the engine's normal absent vocabulary (`.nullish()`, like `monetize`/`billingVersion`) and read as
|
|
603
|
-
* the plain default — not drift — while only a drifted SHAPE `.catch`es, to the {@link DRIFTED_MARKETS}
|
|
604
|
-
* identity sentinel, so `fetchUserConfig` can emit a `shopConfig` drift for the one case that means an
|
|
605
|
-
* engine rename/retype; otherwise a markets-enabled merchant degrading to shop-default pricing would
|
|
606
|
-
* be indistinguishable from markets genuinely off. The missing-key case is EXPLICIT via `.default()`
|
|
607
|
-
* (a factory, so parses never share a mutable object) rather than inferred from zod running an
|
|
608
|
-
* optional key's transform on `undefined`; `null` flows past the default through `.nullish()` into the
|
|
609
|
-
* transform. `Readonly` on the output type because the drifted salvage IS frozen — an assignment to
|
|
610
|
-
* `markets.enabled` downstream would throw only for drifted shops in production, so surface direct
|
|
611
|
-
* writes to tsc (a guard for the direct case only: TS doesn't check `readonly` in assignability, so
|
|
612
|
-
* laundering through a mutable-shaped alias still compiles).
|
|
613
|
-
* The inner `enabled` stays strict on purpose: `{ enabled: null }` is a genuine retype and drifting is
|
|
614
|
-
* the correct answer (the editor-path `ShopConfig.markets` would hard-fail the same payload).
|
|
615
|
-
*/
|
|
616
|
-
markets: z6.object({ enabled: z6.boolean() }).nullish().catch(DRIFTED_MARKETS).default(() => ({ enabled: false })).transform((markets) => markets ?? { enabled: false }),
|
|
617
|
-
monetize: z6.object({ publisherKey: z6.string().nullable() }).nullish().catch(void 0),
|
|
618
|
-
shopId: z6.number().optional().catch(void 0),
|
|
619
|
-
/**
|
|
620
|
-
* The merchant's display name ("Gift Basket Store") — the Monetize header copy reads it.
|
|
621
|
-
* `.catch()` like its siblings: a missing/drifted name degrades the header to the
|
|
622
|
-
* myshopify-domain slug (the pre-CAB React fallback), never a parse fail. An empty string is a
|
|
623
|
-
* VALID parse — the slug fallback for `''` (and whitespace/tag-only names) lives in
|
|
624
|
-
* composeOffer's `||` chain, not here.
|
|
625
|
-
*/
|
|
626
|
-
shopName: z6.string().nullish().catch(void 0)
|
|
627
|
-
});
|
|
628
|
-
var CabUserConfig = z6.object({
|
|
629
|
-
shop: CabShopConfig,
|
|
630
|
-
smartCart: SmartCartConfig.nullish().catch(void 0)
|
|
631
|
-
});
|
|
431
|
+
// src/schema/widgets/post-purchase-offer/constants.ts
|
|
432
|
+
import { z as z6 } from "zod";
|
|
433
|
+
var blockTypes = [
|
|
434
|
+
"callout_banner",
|
|
435
|
+
"image",
|
|
436
|
+
"image_content",
|
|
437
|
+
"pay_button",
|
|
438
|
+
"product_information",
|
|
439
|
+
"separator",
|
|
440
|
+
"text",
|
|
441
|
+
"timer"
|
|
442
|
+
];
|
|
443
|
+
var blockType = z6.enum(blockTypes);
|
|
444
|
+
var BlockType = blockType.enum;
|
|
632
445
|
|
|
633
|
-
// src/schema/widgets/
|
|
634
|
-
import {
|
|
635
|
-
import {
|
|
446
|
+
// src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
|
|
447
|
+
import { get as get2, isEqual } from "es-toolkit/compat";
|
|
448
|
+
import { v4 as uuidv4 } from "uuid";
|
|
449
|
+
import { z as z10 } from "zod";
|
|
450
|
+
|
|
451
|
+
// src/schema/widgets/checkout-and-beyond/text.ts
|
|
452
|
+
import { forEach, isString as isString2 } from "es-toolkit/compat";
|
|
453
|
+
import { v7 as uuidv7 } from "uuid";
|
|
454
|
+
import { z as z9 } from "zod";
|
|
636
455
|
|
|
637
456
|
// src/schema/widgets/checkout-and-beyond/common.ts
|
|
638
457
|
var freezeEnum = (values2) => Object.freeze(Object.fromEntries(values2.map((v) => [v, v])));
|
|
@@ -786,6 +605,7 @@ var sectionTypes = [
|
|
|
786
605
|
"variants"
|
|
787
606
|
];
|
|
788
607
|
var SectionType = freezeEnum(sectionTypes);
|
|
608
|
+
var SALVAGED_SECTION_TYPE = "unknown";
|
|
789
609
|
var spacings = ["none", "extraTight", "tight", "base", "loose", "extraLoose"];
|
|
790
610
|
var Spacing = freezeEnum(spacings);
|
|
791
611
|
var textAlignments = ["start", "center", "end"];
|
|
@@ -836,6 +656,1064 @@ var widgetTypes = [
|
|
|
836
656
|
];
|
|
837
657
|
var WidgetType = freezeEnum(widgetTypes);
|
|
838
658
|
|
|
659
|
+
// src/schema/widgets/checkout-and-beyond/regex.ts
|
|
660
|
+
var DYNAMIC_TOKEN_REGEX = /^\{\{\s*[A-Za-z]+\s*\}\}$/;
|
|
661
|
+
var HEX_COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
662
|
+
var ROOT_RELATIVE_PATH_REGEX = /^\/(?!\/)/;
|
|
663
|
+
var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
|
|
664
|
+
|
|
665
|
+
// src/schema/widgets/checkout-and-beyond/utils.ts
|
|
666
|
+
import { isPlainObject as isPlainObject2 } from "es-toolkit";
|
|
667
|
+
import { get, isString } from "es-toolkit/compat";
|
|
668
|
+
|
|
669
|
+
// src/transforms/convertNumericObjects.ts
|
|
670
|
+
import { isPlainObject } from "es-toolkit";
|
|
671
|
+
var ARRAY_INDEX_STRING = /^(?:0|[1-9]\d*)$/;
|
|
672
|
+
var hasOnlyNumericKeys = (input, requireCompleteRun) => {
|
|
673
|
+
const keys = Object.keys(input);
|
|
674
|
+
if (keys.length === 0) return false;
|
|
675
|
+
if (!keys.every((key) => ARRAY_INDEX_STRING.test(key) && Number.isSafeInteger(Number(key)))) return false;
|
|
676
|
+
if (!requireCompleteRun) return true;
|
|
677
|
+
const sorted = keys.map(Number).sort((a, b) => a - b);
|
|
678
|
+
return sorted.every((n, i) => n === i);
|
|
679
|
+
};
|
|
680
|
+
var numericObjectToArray = (input) => Object.entries(input).sort(([a], [b]) => Number(a) - Number(b)).map(([, value]) => value);
|
|
681
|
+
var convert = (input, requireCompleteRun) => {
|
|
682
|
+
if (Array.isArray(input)) return input.map((item) => convert(item, requireCompleteRun));
|
|
683
|
+
if (isPlainObject(input)) {
|
|
684
|
+
if (hasOnlyNumericKeys(input, requireCompleteRun)) {
|
|
685
|
+
return numericObjectToArray(input).map((item) => convert(item, requireCompleteRun));
|
|
686
|
+
}
|
|
687
|
+
const out = {};
|
|
688
|
+
for (const [key, value] of Object.entries(input)) out[key] = convert(value, requireCompleteRun);
|
|
689
|
+
return out;
|
|
690
|
+
}
|
|
691
|
+
return input;
|
|
692
|
+
};
|
|
693
|
+
var convertNumericObjects = (input) => convert(input, true);
|
|
694
|
+
|
|
695
|
+
// src/schema/widgets/checkout-and-beyond/utils.ts
|
|
696
|
+
var isHTML = (html = "") => {
|
|
697
|
+
if (typeof window !== "undefined") {
|
|
698
|
+
const parser = new DOMParser();
|
|
699
|
+
const doc = parser.parseFromString(html, "text/html");
|
|
700
|
+
const hasHTML = (nodeList) => Array.from(nodeList).some((node) => node.nodeType === 1);
|
|
701
|
+
return hasHTML(doc.body.childNodes) || hasHTML(doc.head.childNodes);
|
|
702
|
+
}
|
|
703
|
+
return html.search(HTML_TAGS_REGEX) !== -1;
|
|
704
|
+
};
|
|
705
|
+
var hasHTMLInDoc = (doc) => doc.content.some(({ content = [] }) => content.some(({ text: text2 }) => isHTML(text2)));
|
|
706
|
+
var checkForHTML = (input) => !(isString(input) && isHTML(input) || isPlainObject2(input) && hasHTMLInDoc(input));
|
|
707
|
+
var NO_HTML = { message: "HTML is not supported" };
|
|
708
|
+
var isSectionType = (sectionType) => (section) => get(section, "sectionType") === sectionType;
|
|
709
|
+
var isBannerType = isSectionType(SectionType.banner);
|
|
710
|
+
var isButtonType = isSectionType(SectionType.button);
|
|
711
|
+
var isCarouselType = isSectionType(SectionType.carousel);
|
|
712
|
+
var isCartLineType = isSectionType(SectionType.cartLine);
|
|
713
|
+
var isDataSourceType = isSectionType(
|
|
714
|
+
SectionType.dataSource
|
|
715
|
+
);
|
|
716
|
+
var isDiscountType = isSectionType(SectionType.discount);
|
|
717
|
+
var isImageType = isSectionType(SectionType.image);
|
|
718
|
+
var isLayoutType = isSectionType(SectionType.layout);
|
|
719
|
+
var isMonetizeType = isSectionType(SectionType.monetize);
|
|
720
|
+
var isOffersType = isSectionType(SectionType.offers);
|
|
721
|
+
var isProductType = isSectionType(SectionType.product);
|
|
722
|
+
var isProductsType = isSectionType(SectionType.products);
|
|
723
|
+
var isProgressBarType = isSectionType(
|
|
724
|
+
SectionType.progressBar
|
|
725
|
+
);
|
|
726
|
+
var isQuantityType = isSectionType(SectionType.quantity);
|
|
727
|
+
var isReviewsType = isSectionType(SectionType.reviews);
|
|
728
|
+
var isTextType = isSectionType(SectionType.text);
|
|
729
|
+
var isVariantsType = isSectionType(SectionType.variants);
|
|
730
|
+
|
|
731
|
+
// src/schema/widgets/checkout-and-beyond/variables.ts
|
|
732
|
+
import { z as z8 } from "zod";
|
|
733
|
+
|
|
734
|
+
// src/schema/widgets/checkout-and-beyond/rule.ts
|
|
735
|
+
import { z as z7 } from "zod";
|
|
736
|
+
var ruleTypes = [
|
|
737
|
+
"cart",
|
|
738
|
+
"cart_count",
|
|
739
|
+
"cart_item_count",
|
|
740
|
+
"cart_line_count",
|
|
741
|
+
"cart_subtotal",
|
|
742
|
+
"collection",
|
|
743
|
+
"customer",
|
|
744
|
+
"customer_order_count",
|
|
745
|
+
"customer_tag",
|
|
746
|
+
"customer_total_spent",
|
|
747
|
+
"date",
|
|
748
|
+
"product",
|
|
749
|
+
"product_tag",
|
|
750
|
+
"product_title",
|
|
751
|
+
"product_type",
|
|
752
|
+
"product_vendor"
|
|
753
|
+
];
|
|
754
|
+
var ruleType = z7.enum(ruleTypes);
|
|
755
|
+
var RuleType = ruleType.enum;
|
|
756
|
+
var ruleOperators = [
|
|
757
|
+
"after",
|
|
758
|
+
"anything",
|
|
759
|
+
"before",
|
|
760
|
+
"contains",
|
|
761
|
+
"contains_any",
|
|
762
|
+
"does_not_contain",
|
|
763
|
+
"does_not_contain_any",
|
|
764
|
+
"equals",
|
|
765
|
+
"does_not_equal",
|
|
766
|
+
"greater_than",
|
|
767
|
+
"less_than"
|
|
768
|
+
];
|
|
769
|
+
var ruleOperator = z7.enum(ruleOperators);
|
|
770
|
+
var RuleOperator = ruleOperator.enum;
|
|
771
|
+
var RuleCondition = z7.object({
|
|
772
|
+
operator: z7.enum(ruleOperators).default(RuleOperator.anything),
|
|
773
|
+
products: z7.union([z7.array(z7.unknown()), z7.strictObject({}).transform(() => [])]).default(() => []),
|
|
774
|
+
type: z7.enum(ruleTypes).default(RuleType.cart_subtotal),
|
|
775
|
+
value: z7.coerce.string().default("")
|
|
776
|
+
});
|
|
777
|
+
var RuleLogicBlock = z7.object({
|
|
778
|
+
rules: z7.array(RuleCondition).default(() => [])
|
|
779
|
+
});
|
|
780
|
+
var CABRulesetEntry = z7.object({
|
|
781
|
+
exitIfMatched: z7.boolean().default(true),
|
|
782
|
+
logic: z7.array(RuleLogicBlock).default(() => []),
|
|
783
|
+
output: z7.array(
|
|
784
|
+
z7.object({
|
|
785
|
+
key: z7.string().default("should_show"),
|
|
786
|
+
type: z7.literal("data_json").default("data_json"),
|
|
787
|
+
value: z7.string().default("true")
|
|
788
|
+
})
|
|
789
|
+
).default(() => [{ key: "should_show", type: "data_json", value: "true" }])
|
|
790
|
+
});
|
|
791
|
+
var CABRuleset = z7.union([z7.array(CABRulesetEntry), z7.strictObject({}).transform(() => [])]).default(() => []);
|
|
792
|
+
|
|
793
|
+
// src/schema/widgets/checkout-and-beyond/variables.ts
|
|
794
|
+
var variableEffect = z8.enum(variableEffects);
|
|
795
|
+
var CABVariableSeed = z8.object({
|
|
796
|
+
dataSourceId: z8.number().nullable().default(null),
|
|
797
|
+
ruleset: CABRuleset
|
|
798
|
+
});
|
|
799
|
+
var CABBooleanVariable = z8.object({
|
|
800
|
+
/**
|
|
801
|
+
* Holds until the first seed verdict lands (and forever, for unseeded variables). Omitted, it derives
|
|
802
|
+
* from seededness — `false` with a `seed` (visibility is EARNED), `true` without — via the transform
|
|
803
|
+
* below; a cross-field default has no `.default()` spelling. An explicit value always wins.
|
|
804
|
+
*/
|
|
805
|
+
defaultValue: z8.boolean().optional(),
|
|
806
|
+
name: z8.string().min(1),
|
|
807
|
+
seed: CABVariableSeed.optional(),
|
|
808
|
+
/** Defaulted so every stored declaration (all boolean before `text` existed) parses unchanged. */
|
|
809
|
+
type: z8.literal(VariableType.boolean).default(VariableType.boolean)
|
|
810
|
+
});
|
|
811
|
+
var CABTextVariable = z8.object({
|
|
812
|
+
defaultValue: z8.string(),
|
|
813
|
+
name: z8.string().min(1),
|
|
814
|
+
seed: z8.never().optional(),
|
|
815
|
+
type: z8.literal(VariableType.text)
|
|
816
|
+
});
|
|
817
|
+
var CABNumberVariable = z8.object({
|
|
818
|
+
defaultValue: z8.number(),
|
|
819
|
+
name: z8.string().min(1),
|
|
820
|
+
seed: z8.never().optional(),
|
|
821
|
+
type: z8.literal(VariableType.number)
|
|
822
|
+
});
|
|
823
|
+
var CABVariable = z8.union([CABTextVariable, CABNumberVariable, CABBooleanVariable]).transform(
|
|
824
|
+
(variable) => variable.type === VariableType.boolean ? { ...variable, defaultValue: variable.defaultValue ?? variable.seed === void 0 } : variable
|
|
825
|
+
);
|
|
826
|
+
var CABVariableEffect = z8.object({
|
|
827
|
+
effect: variableEffect.default(VariableEffect.toggle),
|
|
828
|
+
variable: z8.string().min(1)
|
|
829
|
+
});
|
|
830
|
+
var CABVisibility = z8.object({
|
|
831
|
+
variable: z8.string().min(1),
|
|
832
|
+
visibleWhen: z8.boolean().default(true)
|
|
833
|
+
});
|
|
834
|
+
var contentOperator = z8.enum(contentOperators);
|
|
835
|
+
var resultCountOperator = z8.enum(resultCountOperators);
|
|
836
|
+
var resultTagOperator = z8.enum(resultTagOperators);
|
|
837
|
+
var mutatorEvent = z8.enum(mutatorEvents);
|
|
838
|
+
var CABContentTrigger = z8.object({
|
|
839
|
+
operator: contentOperator.default(ContentOperator.is_empty),
|
|
840
|
+
type: z8.literal("content")
|
|
841
|
+
});
|
|
842
|
+
var CABResultCountTrigger = z8.object({
|
|
843
|
+
operator: resultCountOperator.default(ResultCountOperator.equals),
|
|
844
|
+
type: z8.literal("result_count"),
|
|
845
|
+
value: z8.number().default(0)
|
|
846
|
+
});
|
|
847
|
+
var CABResultTagTrigger = z8.object({
|
|
848
|
+
operator: resultTagOperator.default(ResultTagOperator.contains),
|
|
849
|
+
type: z8.literal("result_tag"),
|
|
850
|
+
value: z8.string().min(1)
|
|
851
|
+
});
|
|
852
|
+
var CABEventTrigger = z8.object({
|
|
853
|
+
event: mutatorEvent,
|
|
854
|
+
type: z8.literal("event")
|
|
855
|
+
});
|
|
856
|
+
var CABVariableTrigger = z8.discriminatedUnion("type", [
|
|
857
|
+
CABContentTrigger,
|
|
858
|
+
CABEventTrigger,
|
|
859
|
+
CABResultCountTrigger,
|
|
860
|
+
CABResultTagTrigger
|
|
861
|
+
]);
|
|
862
|
+
var CABVariableMutator = z8.object({
|
|
863
|
+
effect: variableEffect.default(VariableEffect.set_false),
|
|
864
|
+
variable: z8.string().min(1),
|
|
865
|
+
when: CABVariableTrigger
|
|
866
|
+
});
|
|
867
|
+
var CABVariableFields = {
|
|
868
|
+
mutators: z8.array(CABVariableMutator).optional(),
|
|
869
|
+
variables: z8.array(CABVariable).refine((variables) => new Set(variables.map(({ name }) => name)).size === variables.length, {
|
|
870
|
+
message: "variable names must be unique within a section"
|
|
871
|
+
}).optional(),
|
|
872
|
+
visibility: CABVisibility.optional()
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
// src/schema/widgets/checkout-and-beyond/text.ts
|
|
876
|
+
var enumOrOmit = (...vals) => z9.string().transform((val) => vals.includes(val) ? val : void 0).optional();
|
|
877
|
+
var TiptapText = z9.object({
|
|
878
|
+
marks: z9.union([
|
|
879
|
+
z9.array(
|
|
880
|
+
z9.discriminatedUnion("type", [
|
|
881
|
+
z9.object({ type: z9.literal("bold") }),
|
|
882
|
+
z9.object({ type: z9.literal("italic") }),
|
|
883
|
+
z9.object({
|
|
884
|
+
attrs: z9.object({
|
|
885
|
+
class: z9.string().nullable(),
|
|
886
|
+
href: z9.union([
|
|
887
|
+
z9.url(),
|
|
888
|
+
z9.literal("#"),
|
|
889
|
+
z9.string().regex(DYNAMIC_TOKEN_REGEX),
|
|
890
|
+
z9.string().regex(ROOT_RELATIVE_PATH_REGEX)
|
|
891
|
+
]),
|
|
892
|
+
rel: z9.string().default("noopener noreferrer nofollow"),
|
|
893
|
+
target: z9.string().default("_blank")
|
|
894
|
+
}),
|
|
895
|
+
type: z9.literal("link")
|
|
896
|
+
}),
|
|
897
|
+
z9.object({ type: z9.literal("strike") }),
|
|
898
|
+
z9.object({
|
|
899
|
+
attrs: z9.object({
|
|
900
|
+
color: enumOrOmit(...textColorNames).default(TextColorName.base),
|
|
901
|
+
fontSize: enumOrOmit(...textSizeNames).default(TextSizeName.base)
|
|
902
|
+
}),
|
|
903
|
+
type: z9.literal("textStyle")
|
|
904
|
+
})
|
|
905
|
+
])
|
|
906
|
+
),
|
|
907
|
+
z9.strictObject({}).transform(() => [])
|
|
908
|
+
]).optional(),
|
|
909
|
+
text: z9.string().default(""),
|
|
910
|
+
type: z9.literal("text").default("text")
|
|
911
|
+
});
|
|
912
|
+
var TiptapParagraph = z9.object({
|
|
913
|
+
attrs: z9.object({
|
|
914
|
+
textAlign: enumOrOmit(...textAlignments)
|
|
915
|
+
}).default({ textAlign: TextAlignment.start }),
|
|
916
|
+
content: z9.union([z9.array(TiptapText), z9.strictObject({}).transform(() => [])]).default(() => []),
|
|
917
|
+
type: z9.literal("paragraph").default("paragraph")
|
|
918
|
+
});
|
|
919
|
+
var TiptapDocument = z9.object({
|
|
920
|
+
attrs: z9.object({
|
|
921
|
+
blockSpacing: enumOrOmit(...spacings)
|
|
922
|
+
}).default({ blockSpacing: Spacing.base }),
|
|
923
|
+
content: z9.union([z9.array(TiptapParagraph), z9.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
|
|
924
|
+
type: z9.literal("doc").default("doc")
|
|
925
|
+
});
|
|
926
|
+
var CABTextTier = z9.object({
|
|
927
|
+
threshold: z9.number().int().nonnegative(),
|
|
928
|
+
thresholds: z9.record(z9.string(), z9.number().int().nonnegative()).default(() => ({})),
|
|
929
|
+
tierId: z9.string().optional(),
|
|
930
|
+
tierType: z9.enum(progressTierTypes).default(ProgressTierType.shipping)
|
|
931
|
+
});
|
|
932
|
+
var CABTextSection = z9.object({
|
|
933
|
+
...CABVariableFields,
|
|
934
|
+
buttonField: z9.enum(buttonFields).optional(),
|
|
935
|
+
content: z9.record(z9.string(), z9.union([z9.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
|
|
936
|
+
name: z9.string().optional(),
|
|
937
|
+
optionId: z9.number().optional(),
|
|
938
|
+
sectionId: z9.uuid().default(() => uuidv7()),
|
|
939
|
+
sectionType: z9.literal(SectionType.text).default(SectionType.text),
|
|
940
|
+
tier: CABTextTier.optional()
|
|
941
|
+
}).superRefine(({ buttonField, content }, ctx) => {
|
|
942
|
+
if (buttonField === ButtonField.destinationUrl && content) {
|
|
943
|
+
forEach(content, (value, lang) => {
|
|
944
|
+
if (value && isString2(value)) {
|
|
945
|
+
if (DYNAMIC_TOKEN_REGEX.test(value)) return;
|
|
946
|
+
try {
|
|
947
|
+
new URL(value);
|
|
948
|
+
} catch {
|
|
949
|
+
ctx.addIssue({
|
|
950
|
+
code: "custom",
|
|
951
|
+
message: "Invalid URL",
|
|
952
|
+
path: ["content", lang]
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
// src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
|
|
961
|
+
var TextAlignment2 = z10.union([z10.enum(["leading", "center", "trailing"]), z10.unknown().transform(() => "leading")]);
|
|
962
|
+
var TextSize = z10.union([
|
|
963
|
+
z10.enum(["xsmall", "small", "base", "default", "medium", "large", "xlarge"]),
|
|
964
|
+
z10.unknown().transform(() => "medium")
|
|
965
|
+
]);
|
|
966
|
+
var CalloutBannerBlock = z10.object({
|
|
967
|
+
id: z10.string().optional().default(() => uuidv4()),
|
|
968
|
+
name: z10.string().optional(),
|
|
969
|
+
settings: z10.object({
|
|
970
|
+
superTitle: z10.union([z10.string(), TiptapDocument]).default(() => "Limited-time Offer"),
|
|
971
|
+
title: z10.union([z10.string(), TiptapDocument]).default(() => "Add this customer favorite to your order")
|
|
972
|
+
}),
|
|
973
|
+
styles: z10.object({
|
|
974
|
+
superTitleEmphasized: z10.boolean().default(false),
|
|
975
|
+
superTitleSize: TextSize.default("large"),
|
|
976
|
+
textAlignment: TextAlignment2.default("center"),
|
|
977
|
+
titleEmphasized: z10.boolean().default(true),
|
|
978
|
+
titleSize: TextSize.default("large")
|
|
979
|
+
}),
|
|
980
|
+
type: z10.literal(BlockType.callout_banner).default(BlockType.callout_banner)
|
|
981
|
+
});
|
|
982
|
+
var ImageBlock = z10.object({
|
|
983
|
+
id: z10.string().optional().default(() => uuidv4()),
|
|
984
|
+
name: z10.string().optional(),
|
|
985
|
+
settings: z10.union([
|
|
986
|
+
z10.object({
|
|
987
|
+
/** This isn't used in the post-purchase offer widget */
|
|
988
|
+
alt: z10.string().optional().default(""),
|
|
989
|
+
image: z10.union([z10.literal(""), z10.url()]).default(""),
|
|
990
|
+
imageSize: z10.number().default(20),
|
|
991
|
+
imageType: z10.enum(["URL", "UPLOAD"]).default("URL")
|
|
992
|
+
}),
|
|
993
|
+
z10.array(z10.never()).transform(() => ({}))
|
|
994
|
+
]),
|
|
995
|
+
type: z10.literal(BlockType.image).default(BlockType.image)
|
|
996
|
+
});
|
|
997
|
+
var ImageContentBlock = z10.object({
|
|
998
|
+
id: z10.string().optional().default(() => uuidv4()),
|
|
999
|
+
name: z10.string().optional(),
|
|
1000
|
+
settings: z10.object({
|
|
1001
|
+
alt: z10.string().optional().default(""),
|
|
1002
|
+
description: z10.union([z10.string(), TiptapDocument, z10.null()]).default(
|
|
1003
|
+
"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."
|
|
1004
|
+
),
|
|
1005
|
+
descriptionSize: TextSize.default("medium"),
|
|
1006
|
+
horizontalAlignment: TextAlignment2.default("leading"),
|
|
1007
|
+
image: z10.union([z10.literal(""), z10.url()]).default(""),
|
|
1008
|
+
imagePlacement: z10.enum(["bottom", "left", "right", "top"]).optional().default("left"),
|
|
1009
|
+
imageSize: z10.number().default(20),
|
|
1010
|
+
superTitle: z10.union([z10.string(), TiptapDocument]).default("Lorem Ipsum!"),
|
|
1011
|
+
superTitleSize: TextSize.default("medium"),
|
|
1012
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1013
|
+
swapContent: z10.boolean().optional().default(false),
|
|
1014
|
+
title: z10.union([z10.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet"),
|
|
1015
|
+
titleSize: TextSize.default("medium")
|
|
1016
|
+
}),
|
|
1017
|
+
type: z10.literal(BlockType.image_content).default(BlockType.image_content)
|
|
1018
|
+
});
|
|
1019
|
+
var PayButtonBlock = z10.object({
|
|
1020
|
+
id: z10.string().optional().default(() => uuidv4()),
|
|
1021
|
+
name: z10.string().optional(),
|
|
1022
|
+
settings: z10.union([
|
|
1023
|
+
z10.object({
|
|
1024
|
+
label: z10.string().default("Pay Now")
|
|
1025
|
+
}),
|
|
1026
|
+
z10.array(z10.never()).transform(() => ({
|
|
1027
|
+
label: "Pay Now"
|
|
1028
|
+
}))
|
|
1029
|
+
]),
|
|
1030
|
+
styles: z10.union([
|
|
1031
|
+
z10.object({
|
|
1032
|
+
buttonWidth: z10.number().min(10).max(100).default(50)
|
|
1033
|
+
}),
|
|
1034
|
+
z10.array(z10.never()).transform(() => ({
|
|
1035
|
+
buttonWidth: 50
|
|
1036
|
+
}))
|
|
1037
|
+
]),
|
|
1038
|
+
type: z10.literal(BlockType.pay_button).default(BlockType.pay_button)
|
|
1039
|
+
});
|
|
1040
|
+
var ProductInformationBlock = z10.object({
|
|
1041
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1042
|
+
hideProductImage: z10.boolean().optional().default(false),
|
|
1043
|
+
id: z10.string().optional().default(() => uuidv4()),
|
|
1044
|
+
name: z10.string().optional(),
|
|
1045
|
+
type: z10.literal(BlockType.product_information).default(BlockType.product_information)
|
|
1046
|
+
});
|
|
1047
|
+
var SeparatorBlock = z10.object({
|
|
1048
|
+
id: z10.string().optional().default(() => uuidv4()),
|
|
1049
|
+
name: z10.string().optional(),
|
|
1050
|
+
type: z10.literal(BlockType.separator).default(BlockType.separator)
|
|
1051
|
+
});
|
|
1052
|
+
var TextBlock = z10.object({
|
|
1053
|
+
id: z10.string().optional().default(() => uuidv4()),
|
|
1054
|
+
name: z10.string().optional(),
|
|
1055
|
+
settings: z10.object({
|
|
1056
|
+
description: z10.union([z10.string(), TiptapDocument]).optional().default(
|
|
1057
|
+
"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."
|
|
1058
|
+
),
|
|
1059
|
+
/** This isn't used in the post-purchase offer widget */
|
|
1060
|
+
descriptionSize: TextSize.default("medium"),
|
|
1061
|
+
horizontalAlignment: TextAlignment2.default("leading"),
|
|
1062
|
+
superTitle: z10.union([z10.string(), TiptapDocument]).default("Super Title"),
|
|
1063
|
+
/** This isn't used in the post-purchase offer widget */
|
|
1064
|
+
superTitleSize: TextSize.default("medium"),
|
|
1065
|
+
title: z10.union([z10.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet."),
|
|
1066
|
+
/** This isn't used in the post-purchase offer widget */
|
|
1067
|
+
titleSize: TextSize.default("medium")
|
|
1068
|
+
}),
|
|
1069
|
+
type: z10.literal(BlockType.text).default(BlockType.text)
|
|
1070
|
+
});
|
|
1071
|
+
var TimerBlock = z10.object({
|
|
1072
|
+
id: z10.string().optional().default(() => uuidv4()),
|
|
1073
|
+
name: z10.string().optional(),
|
|
1074
|
+
settings: z10.object({
|
|
1075
|
+
durationMinutes: z10.number().min(0).default(10),
|
|
1076
|
+
durationSeconds: z10.union([z10.number().min(0), z10.unknown().transform(() => 0)]).default(0),
|
|
1077
|
+
endOffer: z10.boolean().default(true),
|
|
1078
|
+
title: z10.union([z10.string(), TiptapDocument]).default("Hurry \u2014 your special offer ends in:")
|
|
1079
|
+
}),
|
|
1080
|
+
styles: z10.object({
|
|
1081
|
+
textAlignment: TextAlignment2.default("center"),
|
|
1082
|
+
timerBackgroundColor: z10.enum(["info", "warning", "success", "critical"]).default("warning"),
|
|
1083
|
+
timerEmphasized: z10.union([z10.boolean(), z10.unknown().transform(() => true)]).default(true),
|
|
1084
|
+
timerSize: TextSize.default("medium"),
|
|
1085
|
+
timerWidth: z10.number().min(10).max(100).optional().default(100),
|
|
1086
|
+
titleEmphasized: z10.union([z10.boolean(), z10.unknown().transform(() => true)]).default(false),
|
|
1087
|
+
titleSize: TextSize.default("medium")
|
|
1088
|
+
}),
|
|
1089
|
+
type: z10.literal(BlockType.timer).default(BlockType.timer)
|
|
1090
|
+
});
|
|
1091
|
+
var PostPurchaseBlock = z10.discriminatedUnion("type", [
|
|
1092
|
+
CalloutBannerBlock,
|
|
1093
|
+
ImageBlock,
|
|
1094
|
+
ImageContentBlock,
|
|
1095
|
+
PayButtonBlock,
|
|
1096
|
+
ProductInformationBlock,
|
|
1097
|
+
SeparatorBlock,
|
|
1098
|
+
TextBlock,
|
|
1099
|
+
TimerBlock
|
|
1100
|
+
]);
|
|
1101
|
+
|
|
1102
|
+
// src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
|
|
1103
|
+
var PostPurchaseSettings = z11.object({
|
|
1104
|
+
advance: z11.object({ removePartialOrder: z11.boolean().default(true) }).optional().default(() => ({ removePartialOrder: true })),
|
|
1105
|
+
blocks: z11.union([z11.array(PostPurchaseBlock), z11.unknown().transform(() => [])]).default(() => [
|
|
1106
|
+
PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.timer }),
|
|
1107
|
+
PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.callout_banner }),
|
|
1108
|
+
PostPurchaseBlock.parse({ type: BlockType.product_information })
|
|
1109
|
+
]),
|
|
1110
|
+
columnLayout: z11.boolean().optional(),
|
|
1111
|
+
discount: z11.object({
|
|
1112
|
+
amount: strictNumber.default(30),
|
|
1113
|
+
shouldShowSavingText: z11.boolean().optional().default(true),
|
|
1114
|
+
type: z11.enum(["none", "fixed_amount", "percentage"]).default("none")
|
|
1115
|
+
}),
|
|
1116
|
+
discountedFrom: z11.enum(["price", "compare_at_price"]).optional().default("price"),
|
|
1117
|
+
endpoint: z11.string().optional(),
|
|
1118
|
+
integrations: z11.object({
|
|
1119
|
+
judgeme: z11.boolean().default(false),
|
|
1120
|
+
junip: z11.boolean().optional().default(false),
|
|
1121
|
+
klaviyo: z11.boolean().default(false),
|
|
1122
|
+
loox: z11.boolean().default(false),
|
|
1123
|
+
okendo: z11.boolean().default(false),
|
|
1124
|
+
opinew: z11.boolean().optional().default(false),
|
|
1125
|
+
reviewsio: z11.boolean().optional().default(false),
|
|
1126
|
+
stamped: z11.boolean().default(false),
|
|
1127
|
+
yotpo: z11.boolean().default(false)
|
|
1128
|
+
}),
|
|
1129
|
+
key: z11.string().optional(),
|
|
1130
|
+
language: z11.object({
|
|
1131
|
+
description: z11.union([z11.string(), z11.unknown().transform(() => "")]).default(""),
|
|
1132
|
+
descriptionEnabled: z11.boolean().optional().default(false),
|
|
1133
|
+
descriptionRte: z11.object({
|
|
1134
|
+
content: z11.array(z11.unknown()),
|
|
1135
|
+
type: z11.string()
|
|
1136
|
+
}).optional(),
|
|
1137
|
+
descriptionSpacing: z11.enum(["none", "xtight", "tight", "default", "loose", "xloose"]).optional(),
|
|
1138
|
+
displayCtaPrice: z11.boolean().default(true),
|
|
1139
|
+
global: z11.object({
|
|
1140
|
+
declineAll: z11.string().optional().default("Decline All"),
|
|
1141
|
+
declineThisOffer: z11.string().default("Decline this offer"),
|
|
1142
|
+
free: z11.string().optional().default("Free"),
|
|
1143
|
+
notAvailable: z11.string().optional().default("Not available"),
|
|
1144
|
+
/** Label for the one-time choice beside `subscriptionOption` in the purchase-type selector */
|
|
1145
|
+
oneTimePurchase: z11.string().optional().default("One-time Purchase"),
|
|
1146
|
+
payNow: z11.string().default("Pay Now"),
|
|
1147
|
+
payNowUpgradeToSubscription: z11.string().optional().default("Upgrade to Subscription"),
|
|
1148
|
+
quantity: z11.string().default("Quantity"),
|
|
1149
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1150
|
+
recurringShipping: z11.string().optional().default("Recurring shipping"),
|
|
1151
|
+
recurringSubtotal: z11.string().default("Recurring subtotal"),
|
|
1152
|
+
reviewsPlural: z11.string().optional().default("Reviews"),
|
|
1153
|
+
reviewsSingular: z11.string().optional().default("Review"),
|
|
1154
|
+
save: z11.union([z11.string(), z11.unknown().transform(() => "Save")]).optional().default("Save"),
|
|
1155
|
+
shipping: z11.string().default("Shipping"),
|
|
1156
|
+
subscriptionOption: z11.string().optional().default("Subscribe and Save"),
|
|
1157
|
+
subtotal: z11.string().default("Subtotal"),
|
|
1158
|
+
taxes: z11.string().default("Taxes"),
|
|
1159
|
+
total: z11.string().default("Total")
|
|
1160
|
+
}).optional().default(() => ({
|
|
1161
|
+
declineAll: "Decline All",
|
|
1162
|
+
declineThisOffer: "Decline this offer",
|
|
1163
|
+
free: "Free",
|
|
1164
|
+
notAvailable: "Not available",
|
|
1165
|
+
oneTimePurchase: "One-time Purchase",
|
|
1166
|
+
payNow: "Pay Now",
|
|
1167
|
+
payNowUpgradeToSubscription: "Upgrade to Subscription",
|
|
1168
|
+
quantity: "Quantity",
|
|
1169
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1170
|
+
recurringShipping: "Recurring shipping",
|
|
1171
|
+
recurringSubtotal: "Recurring subtotal",
|
|
1172
|
+
reviewsPlural: "Reviews",
|
|
1173
|
+
reviewsSingular: "Review",
|
|
1174
|
+
save: "Save",
|
|
1175
|
+
shipping: "Shipping",
|
|
1176
|
+
subscriptionOption: "Subscribe and Save",
|
|
1177
|
+
subtotal: "Subtotal",
|
|
1178
|
+
taxes: "Taxes",
|
|
1179
|
+
total: "Total"
|
|
1180
|
+
})),
|
|
1181
|
+
globalTranslation: z11.string().optional().default("english")
|
|
1182
|
+
}),
|
|
1183
|
+
metafields: z11.boolean().default(false),
|
|
1184
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1185
|
+
offer: z11.object({
|
|
1186
|
+
count: z11.number().default(1)
|
|
1187
|
+
}),
|
|
1188
|
+
offersLayout: z11.object({
|
|
1189
|
+
itemsPerPage: z11.number().optional(),
|
|
1190
|
+
type: z11.enum(["list", "grid", "carousel"]).default("list")
|
|
1191
|
+
}).optional().default({
|
|
1192
|
+
type: "list"
|
|
1193
|
+
}),
|
|
1194
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1195
|
+
previewMode: z11.boolean().default(false),
|
|
1196
|
+
productLimit: z11.number().optional().default(1),
|
|
1197
|
+
productOptions: z11.object({
|
|
1198
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1199
|
+
hideOutOfStockVariants: z11.boolean().optional().default(false),
|
|
1200
|
+
matchVariant: z11.boolean().optional().default(true),
|
|
1201
|
+
showDeclineAll: z11.enum(["above", "below", "both", "none"]).optional(),
|
|
1202
|
+
showShipping: z11.boolean().optional().default(true),
|
|
1203
|
+
showSubtotal: z11.boolean().optional().default(true),
|
|
1204
|
+
showTaxes: z11.boolean().optional().default(true),
|
|
1205
|
+
showTotal: z11.boolean().optional().default(true),
|
|
1206
|
+
showVariantSelectors: z11.boolean().optional().default(true),
|
|
1207
|
+
variantSelectorDisplayMode: z11.enum(["separate", "single"]).optional().default("separate")
|
|
1208
|
+
}),
|
|
1209
|
+
productType: z11.union([z11.enum(["one-time", "subscription", "both"]), z11.literal("").transform(() => "one-time")]).default("one-time"),
|
|
1210
|
+
productTypeSelector: z11.enum(["dropdown", "radio"]).optional().default("radio"),
|
|
1211
|
+
quantityInputs: z11.object({
|
|
1212
|
+
defaultQuantity: z11.union([z11.number(), z11.null().transform(() => 1)]).default(1),
|
|
1213
|
+
enabled: z11.boolean().default(true),
|
|
1214
|
+
maxValue: z11.union([z11.number(), z11.null().transform(() => 15)]).default(15),
|
|
1215
|
+
minValue: z11.union([z11.number().min(0), z11.unknown().transform(() => 0)]).default(1)
|
|
1216
|
+
}),
|
|
1217
|
+
shipping: z11.object({
|
|
1218
|
+
amount: strictNumber.default(10),
|
|
1219
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1220
|
+
enabled: z11.boolean().default(true),
|
|
1221
|
+
title: z11.string().optional().default("Shipping Fees"),
|
|
1222
|
+
type: z11.enum(["free", "fixed_amount"]).default("free")
|
|
1223
|
+
}),
|
|
1224
|
+
styles: z11.object({
|
|
1225
|
+
starColor: z11.string().optional().default("#fadb14"),
|
|
1226
|
+
starSize: z11.union([z11.enum(["small", "medium", "large"]), z11.unknown().transform(() => "large")]).optional().default("large"),
|
|
1227
|
+
starStrokeColor: z11.string().optional().default("#fadb14"),
|
|
1228
|
+
strokeWidth: z11.string().optional().default("1")
|
|
1229
|
+
}).optional(),
|
|
1230
|
+
subImages: z11.number().nullish().default(8),
|
|
1231
|
+
subscription: z11.object({
|
|
1232
|
+
discount: z11.object({
|
|
1233
|
+
amount: strictNumber.default(30),
|
|
1234
|
+
shouldShowSavingText: z11.boolean().optional().default(true),
|
|
1235
|
+
type: z11.enum(["none", "fixed_amount", "percentage"]).default("none")
|
|
1236
|
+
}),
|
|
1237
|
+
shipping: z11.object({
|
|
1238
|
+
amount: strictNumber.default(1),
|
|
1239
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1240
|
+
enabled: z11.boolean().default(true),
|
|
1241
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1242
|
+
recurringAmount: strictNumber.default(2),
|
|
1243
|
+
shippingTitle: z11.string().default("Shipping Fees"),
|
|
1244
|
+
type: z11.enum(["free", "fixed_amount"]).default("free")
|
|
1245
|
+
})
|
|
1246
|
+
}).optional().default({
|
|
1247
|
+
discount: {
|
|
1248
|
+
amount: 30,
|
|
1249
|
+
shouldShowSavingText: true,
|
|
1250
|
+
type: "none"
|
|
1251
|
+
},
|
|
1252
|
+
shipping: {
|
|
1253
|
+
amount: 1,
|
|
1254
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1255
|
+
enabled: true,
|
|
1256
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1257
|
+
recurringAmount: 2,
|
|
1258
|
+
shippingTitle: "Shipping Fees",
|
|
1259
|
+
type: "free"
|
|
1260
|
+
}
|
|
1261
|
+
}),
|
|
1262
|
+
subscriptionIsDefault: z11.boolean().optional(),
|
|
1263
|
+
/** This isn't configurable in the admin-nextjs editor */
|
|
1264
|
+
template: z11.string().optional().default(""),
|
|
1265
|
+
type: z11.literal("shopify_post_purchase_extension").default("shopify_post_purchase_extension"),
|
|
1266
|
+
upgradeToSubscription: z11.object({
|
|
1267
|
+
acceptButtonText: z11.string().optional().default("Upgrade"),
|
|
1268
|
+
allow: z11.boolean().optional().default(false),
|
|
1269
|
+
emailRefundNotice: z11.boolean().optional().default(false),
|
|
1270
|
+
errorBannerText: z11.string().optional().default("This subscription cannot be added - limit one per order")
|
|
1271
|
+
}).optional().default(() => ({
|
|
1272
|
+
acceptButtonText: "Upgrade",
|
|
1273
|
+
allow: false,
|
|
1274
|
+
emailRefundNotice: false,
|
|
1275
|
+
errorBannerText: "This subscription cannot be added - limit one per order"
|
|
1276
|
+
}))
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
// src/schema/postPurchaseProductReviews.ts
|
|
1280
|
+
var decimal = z12.union([
|
|
1281
|
+
z12.number(),
|
|
1282
|
+
z12.string().regex(/^\d+(?:\.\d+)?$/).transform(Number)
|
|
1283
|
+
]);
|
|
1284
|
+
var PostPurchaseCommonReviewRating = z12.object({ value: decimal.pipe(z12.number().min(0).max(5)) });
|
|
1285
|
+
var PostPurchaseKlaviyoReviewRating = PostPurchaseCommonReviewRating.extend({
|
|
1286
|
+
// Legacy validates key presence, then displays the raw value on five stars without rescaling.
|
|
1287
|
+
scale_max: z12.unknown().nonoptional(),
|
|
1288
|
+
scale_min: z12.unknown().nonoptional()
|
|
1289
|
+
});
|
|
1290
|
+
var PostPurchaseReviewCount = z12.string().regex(/^\d+(?:\.\d+)?$/).transform(Number).pipe(z12.number().int().nonnegative());
|
|
1291
|
+
var PostPurchaseReviewStyles = PostPurchaseSettings.shape.styles.unwrap().extend({
|
|
1292
|
+
strokeWidth: decimal.pipe(z12.number().nonnegative()).default(1)
|
|
1293
|
+
}).prefault({});
|
|
1294
|
+
var PostPurchaseProductReviews = z12.object({
|
|
1295
|
+
color: z12.string(),
|
|
1296
|
+
rating: z12.number().positive().max(5),
|
|
1297
|
+
reviewCount: z12.number().int().nonnegative(),
|
|
1298
|
+
reviewsPlural: z12.string(),
|
|
1299
|
+
reviewsSingular: z12.string(),
|
|
1300
|
+
size: z12.enum(["small", "medium", "large"]),
|
|
1301
|
+
strokeColor: z12.string(),
|
|
1302
|
+
strokeWidth: z12.number().nonnegative()
|
|
1303
|
+
});
|
|
1304
|
+
|
|
1305
|
+
// src/server/postPurchaseJudgeMeReviews.ts
|
|
1306
|
+
import { z as z14 } from "zod";
|
|
1307
|
+
|
|
1308
|
+
// src/server/postPurchaseReviewFields.ts
|
|
1309
|
+
import { z as z13 } from "zod";
|
|
1310
|
+
var Field = z13.object({ key: z13.string(), namespace: z13.string(), value: z13.unknown().optional() });
|
|
1311
|
+
var reviewFields = (raw) => {
|
|
1312
|
+
const fields4 = z13.array(z13.unknown()).parse(raw).flatMap((field) => {
|
|
1313
|
+
const parsed = Field.safeParse(field);
|
|
1314
|
+
return parsed.success ? [parsed.data] : [];
|
|
1315
|
+
});
|
|
1316
|
+
return (namespace, key) => fields4.find((field) => field.namespace === namespace && field.key === key);
|
|
1317
|
+
};
|
|
1318
|
+
var ReviewFieldError = class extends Error {
|
|
1319
|
+
constructor(field) {
|
|
1320
|
+
super(`Unreadable review field ${field}`);
|
|
1321
|
+
this.field = field;
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
var readReviewField = (field, read) => {
|
|
1325
|
+
try {
|
|
1326
|
+
return read(field.value);
|
|
1327
|
+
} catch {
|
|
1328
|
+
throw new ReviewFieldError(`${field.namespace}.${field.key}`);
|
|
1329
|
+
}
|
|
1330
|
+
};
|
|
1331
|
+
|
|
1332
|
+
// src/server/postPurchaseJudgeMeReviews.ts
|
|
1333
|
+
var readJudgeMeReviews = (find) => {
|
|
1334
|
+
const field = find("judgeme", "badge");
|
|
1335
|
+
if (!field) return null;
|
|
1336
|
+
return readReviewField(field, (value) => {
|
|
1337
|
+
const html = z14.string().parse(value);
|
|
1338
|
+
const rating = html.match(/data-average-rating=['"](\d+(?:\.\d+)?)['"]/);
|
|
1339
|
+
const count = html.match(/data-number-of-reviews=['"](\d+)['"]/);
|
|
1340
|
+
if (!rating || !count) throw new Error("Unreadable Judge.me attributes");
|
|
1341
|
+
return {
|
|
1342
|
+
rating: PostPurchaseCommonReviewRating.parse({ value: rating[1] }).value,
|
|
1343
|
+
reviewCount: PostPurchaseReviewCount.parse(count[1])
|
|
1344
|
+
};
|
|
1345
|
+
});
|
|
1346
|
+
};
|
|
1347
|
+
|
|
1348
|
+
// src/server/postPurchaseOkendoReviews.ts
|
|
1349
|
+
import { z as z15 } from "zod";
|
|
1350
|
+
var Summary = z15.object({
|
|
1351
|
+
reviewAverageValue: PostPurchaseCommonReviewRating.shape.value,
|
|
1352
|
+
reviewCount: z15.union([PostPurchaseProductReviews.shape.reviewCount, PostPurchaseReviewCount])
|
|
1353
|
+
});
|
|
1354
|
+
var readOkendoReviews = (find) => {
|
|
1355
|
+
const field = find("okendo", "summaryData");
|
|
1356
|
+
if (!field) return null;
|
|
1357
|
+
const summary = readReviewField(field, (value) => Summary.parse(JSON.parse(z15.string().parse(value))));
|
|
1358
|
+
return { rating: summary.reviewAverageValue, reviewCount: summary.reviewCount };
|
|
1359
|
+
};
|
|
1360
|
+
|
|
1361
|
+
// src/server/postPurchaseScalarReviews.ts
|
|
1362
|
+
import { z as z16 } from "zod";
|
|
1363
|
+
var readScalarReviews = (find, namespace, ratingKey, countKey) => {
|
|
1364
|
+
const rating = find(namespace, ratingKey);
|
|
1365
|
+
const count = find(namespace, countKey);
|
|
1366
|
+
if (!rating || !count) return null;
|
|
1367
|
+
return {
|
|
1368
|
+
rating: readReviewField(
|
|
1369
|
+
rating,
|
|
1370
|
+
(value) => PostPurchaseCommonReviewRating.parse({ value: z16.string().parse(value) }).value
|
|
1371
|
+
),
|
|
1372
|
+
reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
|
|
1373
|
+
};
|
|
1374
|
+
};
|
|
1375
|
+
|
|
1376
|
+
// src/server/postPurchaseReviewData.ts
|
|
1377
|
+
var readStandardReviews = (find) => {
|
|
1378
|
+
const rating = find("reviews", "rating");
|
|
1379
|
+
const count = find("reviews", "rating_count");
|
|
1380
|
+
if (!rating || !count) return null;
|
|
1381
|
+
return {
|
|
1382
|
+
rating: readReviewField(rating, (raw) => {
|
|
1383
|
+
const value = z17.string().parse(raw);
|
|
1384
|
+
return PostPurchaseCommonReviewRating.parse(/^\d+(?:\.\d+)?$/.test(value) ? { value } : JSON.parse(value)).value;
|
|
1385
|
+
}),
|
|
1386
|
+
reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
|
|
1387
|
+
};
|
|
1388
|
+
};
|
|
1389
|
+
var readPostPurchaseReviewData = (provider, find) => {
|
|
1390
|
+
if (provider === "yotpo") return readScalarReviews(find, "yotpo", "reviews_average", "reviews_count");
|
|
1391
|
+
if (provider === "stamped") return readScalarReviews(find, "stamped", "reviews_average", "reviews_count");
|
|
1392
|
+
if (provider === "judgeme") return readJudgeMeReviews(find);
|
|
1393
|
+
if (provider === "okendo") return readOkendoReviews(find);
|
|
1394
|
+
if (provider === "opinew") return readScalarReviews(find, "opinew_metafields", "reviews_average", "reviews_count");
|
|
1395
|
+
if (provider === "reviewsio")
|
|
1396
|
+
return readScalarReviews(find, "reviewscouk", "rating", "total") ?? readStandardReviews(find);
|
|
1397
|
+
if (provider === "loox") return readScalarReviews(find, "loox", "avg_rating", "num_reviews");
|
|
1398
|
+
if (provider === "junip") return readScalarReviews(find, "junip", "rating_average", "rating_count");
|
|
1399
|
+
const rating = find("reviews", "rating");
|
|
1400
|
+
const count = find("reviews", "rating_count");
|
|
1401
|
+
if (!rating || !count) return null;
|
|
1402
|
+
return {
|
|
1403
|
+
rating: readReviewField(
|
|
1404
|
+
rating,
|
|
1405
|
+
(value) => PostPurchaseKlaviyoReviewRating.parse(JSON.parse(z17.string().parse(value))).value
|
|
1406
|
+
),
|
|
1407
|
+
reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
|
|
1408
|
+
};
|
|
1409
|
+
};
|
|
1410
|
+
|
|
1411
|
+
// src/server/postPurchaseReviewProvider.ts
|
|
1412
|
+
import { z as z18 } from "zod";
|
|
1413
|
+
var IntegrationInput = z18.record(z18.string(), z18.unknown()).prefault({});
|
|
1414
|
+
var precedence = [
|
|
1415
|
+
"klaviyo",
|
|
1416
|
+
"judgeme",
|
|
1417
|
+
"junip",
|
|
1418
|
+
"loox",
|
|
1419
|
+
"okendo",
|
|
1420
|
+
"opinew",
|
|
1421
|
+
"reviewsio",
|
|
1422
|
+
"stamped",
|
|
1423
|
+
"yotpo"
|
|
1424
|
+
];
|
|
1425
|
+
var ReviewsIoFlag = z18.preprocess((value) => {
|
|
1426
|
+
if (typeof value === "string") {
|
|
1427
|
+
const flag = value.toLowerCase();
|
|
1428
|
+
if (flag === "true" || flag === "yes") return true;
|
|
1429
|
+
if (flag === "false" || flag === "no") return false;
|
|
1430
|
+
}
|
|
1431
|
+
return value;
|
|
1432
|
+
}, PostPurchaseSettings.shape.integrations.shape.reviewsio);
|
|
1433
|
+
var selectPostPurchaseReviewProvider = (raw) => {
|
|
1434
|
+
const integrations = IntegrationInput.parse(raw);
|
|
1435
|
+
for (const provider of precedence) {
|
|
1436
|
+
const schema = provider === "reviewsio" ? ReviewsIoFlag : PostPurchaseSettings.shape.integrations.shape[provider];
|
|
1437
|
+
if (schema.parse(integrations[provider])) return provider;
|
|
1438
|
+
}
|
|
1439
|
+
return null;
|
|
1440
|
+
};
|
|
1441
|
+
|
|
1442
|
+
// src/server/offerProductReviews.ts
|
|
1443
|
+
var readOrReport = (read, productId2, report) => {
|
|
1444
|
+
try {
|
|
1445
|
+
return read();
|
|
1446
|
+
} catch (error) {
|
|
1447
|
+
if (!(error instanceof ReviewFieldError)) throw error;
|
|
1448
|
+
report?.({
|
|
1449
|
+
detail: "Unreadable offer product reviews metafield",
|
|
1450
|
+
field: error.field,
|
|
1451
|
+
kind: "reviews",
|
|
1452
|
+
productId: productId2
|
|
1453
|
+
});
|
|
1454
|
+
return null;
|
|
1455
|
+
}
|
|
1456
|
+
};
|
|
1457
|
+
var readReviews = (provider, find, productId2, report) => (provider === "klaviyo" ? null : readOrReport(() => readPostPurchaseReviewData(provider, find), productId2, report)) ?? readOrReport(() => readStandardReviews(find), productId2, report);
|
|
1458
|
+
var projectOfferProductReviews = (integrations, { id: productId2, metafields }, report) => {
|
|
1459
|
+
let provider;
|
|
1460
|
+
try {
|
|
1461
|
+
provider = selectPostPurchaseReviewProvider(integrations);
|
|
1462
|
+
} catch {
|
|
1463
|
+
return void 0;
|
|
1464
|
+
}
|
|
1465
|
+
if (!provider) return void 0;
|
|
1466
|
+
try {
|
|
1467
|
+
if (!Array.isArray(metafields)) return null;
|
|
1468
|
+
const data = readReviews(provider, reviewFields(metafields), productId2, report);
|
|
1469
|
+
return data && data.rating > 0 ? data : null;
|
|
1470
|
+
} catch {
|
|
1471
|
+
report?.({ detail: "Unreadable offer product reviews", kind: "product" });
|
|
1472
|
+
return null;
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
|
|
1476
|
+
// src/server/shopSubtotal.ts
|
|
1477
|
+
var shopCurrencyRate = (cart) => {
|
|
1478
|
+
const rate = cart.currencyRate ?? 1;
|
|
1479
|
+
return Number.isFinite(rate) && rate > 0 ? rate : 1;
|
|
1480
|
+
};
|
|
1481
|
+
var shopSubtotalCents = (cart) => Math.round((cart.subtotal - (cart.discountTotal ?? 0)) / shopCurrencyRate(cart));
|
|
1482
|
+
var toShopCents = (majorPresentment, rate) => Math.round(majorPresentment * 100 / rate);
|
|
1483
|
+
|
|
1484
|
+
// src/schema/cabShopConfig.ts
|
|
1485
|
+
import { z as z20 } from "zod";
|
|
1486
|
+
|
|
1487
|
+
// src/schema/driftedMarkets.ts
|
|
1488
|
+
var DRIFTED_MARKETS = Object.freeze({ enabled: false });
|
|
1489
|
+
|
|
1490
|
+
// src/schema/smartCart.ts
|
|
1491
|
+
import { z as z19 } from "zod";
|
|
1492
|
+
var SmartCartTierProduct = z19.looseObject({
|
|
1493
|
+
handle: z19.string().optional(),
|
|
1494
|
+
id: z19.coerce.number().optional(),
|
|
1495
|
+
productId: z19.coerce.number().optional(),
|
|
1496
|
+
title: z19.string().optional(),
|
|
1497
|
+
variantIds: z19.array(z19.coerce.number()).optional()
|
|
1498
|
+
});
|
|
1499
|
+
var SmartCartTierExclusion = z19.looseObject({
|
|
1500
|
+
collectionIds: z19.array(z19.coerce.number()).optional().catch(void 0),
|
|
1501
|
+
productIds: z19.array(z19.coerce.number()).optional().catch(void 0),
|
|
1502
|
+
tags: z19.array(z19.string()).optional().catch(void 0),
|
|
1503
|
+
type: z19.string().optional().catch(void 0)
|
|
1504
|
+
});
|
|
1505
|
+
var SmartCartTier = z19.looseObject({
|
|
1506
|
+
allProducts: z19.array(SmartCartTierProduct).optional(),
|
|
1507
|
+
/** Merchant-set tier label (e.g. "Free gift", "$100 reward"), shown on the step row when enabled. */
|
|
1508
|
+
customTierLabel: z19.boolean().optional(),
|
|
1509
|
+
customTierLabelText: z19.string().optional(),
|
|
1510
|
+
decorativeAmountReachedLabel: z19.boolean().optional(),
|
|
1511
|
+
decorativeAmountReachedLabelText: z19.string().optional(),
|
|
1512
|
+
decorativeAmountRemainingLabel: z19.boolean().optional(),
|
|
1513
|
+
decorativeAmountRemainingLabelText: z19.string().optional(),
|
|
1514
|
+
/** Order-discount reward: `'fixedAmount'` (shop-currency dollars) or `'percentage'` (whole percent). */
|
|
1515
|
+
discountAmountFromTotal: z19.coerce.number().optional(),
|
|
1516
|
+
discountAmountReachedLabel: z19.boolean().optional(),
|
|
1517
|
+
discountAmountReachedLabelText: z19.string().optional(),
|
|
1518
|
+
discountAmountRemainingLabel: z19.boolean().optional(),
|
|
1519
|
+
discountAmountRemainingLabelText: z19.string().optional(),
|
|
1520
|
+
discountType: z19.string().optional(),
|
|
1521
|
+
/**
|
|
1522
|
+
* onsite `exclusions` + `exclusions_enabled` (REB-22305): per-tier rules the converter carries onto
|
|
1523
|
+
* `CABProgressTier.exclusions`. `.catch(undefined)` for the same blast-radius reason as `productTierImage`:
|
|
1524
|
+
* one drifted value must degrade to "no tier exclusions", never drop every progress bar for the shop.
|
|
1525
|
+
*
|
|
1526
|
+
* `exclusionsEnabled` is a STRICT boolean on purpose, even though failing open here changes the tier's math
|
|
1527
|
+
* (a non-boolean reads as disabled) rather than just an icon. onsite reads its sibling tier flags strictly —
|
|
1528
|
+
* `shouldFilterOutOfStockVariantsFromTier` is `tier?.filter_oos_variants === true`, and its `progressBar.ts`
|
|
1529
|
+
* types every tier flag as `boolean` — so a stored `1` / `"1"` / `"true"` is "disabled" on the onsite bar too.
|
|
1530
|
+
* A truthiness preprocess would make CAB exclude where onsite does not: the opposite parity break.
|
|
1531
|
+
*/
|
|
1532
|
+
exclusions: z19.array(SmartCartTierExclusion).optional().catch(void 0),
|
|
1533
|
+
exclusionsEnabled: z19.boolean().optional().catch(void 0),
|
|
1534
|
+
filterOosVariants: z19.boolean().optional(),
|
|
1535
|
+
id: z19.string().optional(),
|
|
1536
|
+
/**
|
|
1537
|
+
* A `null`/absent minimum stays `undefined` (NOT coerced to `0`): a threshold-0 tier is always reached
|
|
1538
|
+
* and would auto-add its gift to every cart. onsite's `isTierDataValid` drops a non-numeric minimum for
|
|
1539
|
+
* exactly this reason; the converter's `renderableTiers` mirrors that (`Number.isFinite`). A literal `0`
|
|
1540
|
+
* is kept — onsite keeps it too. DELIBERATE DIVERGENCE from onsite for string minimums: onsite's
|
|
1541
|
+
* `isTierDataValid` is a strict `typeof === 'number'`, so it drops `'50'`; the converter instead coerces
|
|
1542
|
+
* `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
|
|
1543
|
+
*/
|
|
1544
|
+
minimum: z19.preprocess((value) => value == null ? void 0 : value, z19.coerce.number().optional()),
|
|
1545
|
+
presentmentCurrencies: z19.looseObject({ enabled: z19.boolean().optional() }).optional(),
|
|
1546
|
+
productAmountReachedLabel: z19.boolean().optional(),
|
|
1547
|
+
productAmountReachedLabelText: z19.string().optional(),
|
|
1548
|
+
productAmountRemainingLabel: z19.boolean().optional(),
|
|
1549
|
+
productAmountRemainingLabelText: z19.string().optional(),
|
|
1550
|
+
products: z19.array(SmartCartTierProduct).optional(),
|
|
1551
|
+
/**
|
|
1552
|
+
* onsite `product_tier_element_size`: the step-row icon's square size as a px STRING (`'18px'` …
|
|
1553
|
+
* `'36px'` — the admin's five-value Size control, default `'18px'`). React stamps it onto the icon
|
|
1554
|
+
* SVG's `width`/`height` (`getProgressStepIconSize`), so the milestone renders at the merchant's
|
|
1555
|
+
* chosen size; the converter turns it into `CABProgressTier.iconSizePx` for the CAB renderer.
|
|
1556
|
+
*
|
|
1557
|
+
* `.catch(undefined)` for the same blast-radius reason as `productTierImage` below: this key was
|
|
1558
|
+
* previously unknown-and-ignored by the `looseObject`, and `SmartCartConfig` is parsed
|
|
1559
|
+
* `.nullish().catch(undefined)` with no intermediate catch, so one drifted value (a bare number, a
|
|
1560
|
+
* `'2rem'`) would drop EVERY progress bar for the shop rather than just this setting. Failing open to
|
|
1561
|
+
* `undefined` lands on the documented 18px default — strictly safer than that blast radius. The
|
|
1562
|
+
* converter parses the number out and clamps it, so a junk-but-string value degrades the same way.
|
|
1563
|
+
*/
|
|
1564
|
+
productTierElementSize: z19.string().optional().catch(void 0),
|
|
1565
|
+
/**
|
|
1566
|
+
* onsite `product_tier_image`: on a product (gift) tier, show the gift's product image in the step-row
|
|
1567
|
+
* slot instead of the generic bag icon (React `TierProgressIcon` swaps in the image when this is set and
|
|
1568
|
+
* an image resolves). Per-tier; the client resolves the image (config carries only product IDs).
|
|
1569
|
+
*
|
|
1570
|
+
* `.catch(undefined)` is load-bearing. This key was previously unknown-and-ignored by the `looseObject`;
|
|
1571
|
+
* declaring it as a real boolean means a stored non-boolean (`1` / `"1"` / `"true"`) would now FAIL the
|
|
1572
|
+
* tier — and since `SmartCartConfig` is parsed `.nullish().catch(undefined)` (userConfig/cabShopConfig)
|
|
1573
|
+
* with no intermediate catch, one drifted flag would drop EVERY progress bar for the shop, not just the
|
|
1574
|
+
* flag. The converter only reads it for truthiness (`gift && tier.productTierImage`), so failing open to
|
|
1575
|
+
* `undefined` (bag-icon fallback, the documented default) is strictly safer than that blast radius.
|
|
1576
|
+
*/
|
|
1577
|
+
productTierImage: z19.boolean().optional().catch(void 0),
|
|
1578
|
+
type: z19.string().optional(),
|
|
1579
|
+
/**
|
|
1580
|
+
* onsite's PER-TIER unit switch (`unlock_condition_type`): `'item_quantity'` makes `minimum` an
|
|
1581
|
+
* item count (checked before any money handling — no ×100, no FX, no presentment overrides,
|
|
1582
|
+
* mirroring onsite `getTierMinimum`); anything else (or absent) keeps the money semantics.
|
|
1583
|
+
*/
|
|
1584
|
+
unlockConditionType: z19.string().optional()
|
|
1585
|
+
});
|
|
1586
|
+
var SmartCartBar = z19.looseObject({
|
|
1587
|
+
countryCodes: z19.array(z19.string()).optional(),
|
|
1588
|
+
/**
|
|
1589
|
+
* onsite `exclude_discount_in_subtotal`: measure progress against the PRE-discount subtotal so an
|
|
1590
|
+
* applied code/order discount doesn't lower progress. The client adds cart discount allocations back.
|
|
1591
|
+
*/
|
|
1592
|
+
excludeDiscountInSubtotal: z19.boolean().optional(),
|
|
1593
|
+
/** Products excluded from the progress subtotal; the client subtracts their variants' cart cost. */
|
|
1594
|
+
excludedProducts: z19.array(z19.looseObject({ variantIds: z19.array(z19.coerce.number()).optional() })).optional(),
|
|
1595
|
+
freeShippingOnSubscription: z19.boolean().optional(),
|
|
1596
|
+
geolocationEnabled: z19.boolean().optional(),
|
|
1597
|
+
id: z19.string().optional(),
|
|
1598
|
+
language: z19.looseObject({
|
|
1599
|
+
freeShippingReached: z19.string().optional(),
|
|
1600
|
+
freeShippingRemaining: z19.string().optional(),
|
|
1601
|
+
giftAreaTitle: z19.string().optional()
|
|
1602
|
+
}).optional(),
|
|
1603
|
+
name: z19.string().optional(),
|
|
1604
|
+
tiers: z19.array(SmartCartTier).optional()
|
|
1605
|
+
});
|
|
1606
|
+
var SmartCartComponent = z19.looseObject({
|
|
1607
|
+
settings: z19.looseObject({ bars: z19.array(SmartCartBar).optional() }).optional(),
|
|
1608
|
+
type: z19.string().optional()
|
|
1609
|
+
});
|
|
1610
|
+
var SmartCartConfig = z19.looseObject({
|
|
1611
|
+
components: z19.array(SmartCartComponent).optional()
|
|
1612
|
+
});
|
|
1613
|
+
|
|
1614
|
+
// src/schema/cabShopConfig.ts
|
|
1615
|
+
var CabActiveExperiment = z20.object({
|
|
1616
|
+
data: z20.array(
|
|
1617
|
+
z20.object({
|
|
1618
|
+
elementId: z20.coerce.number(),
|
|
1619
|
+
id: z20.coerce.number(),
|
|
1620
|
+
traffic: z20.coerce.number()
|
|
1621
|
+
})
|
|
1622
|
+
),
|
|
1623
|
+
id: z20.coerce.number(),
|
|
1624
|
+
placeholderId: z20.coerce.number().nullable(),
|
|
1625
|
+
type: z20.string()
|
|
1626
|
+
});
|
|
1627
|
+
var CabShopConfig = z20.object({
|
|
1628
|
+
/**
|
|
1629
|
+
* Per-element resilient: parse as `unknown[]` (non-array → `[]`), then keep only the experiments that
|
|
1630
|
+
* validate. A single drifted experiment drops itself instead of `.catch`-ing the WHOLE array to `[]` and
|
|
1631
|
+
* silently disabling every live A/B test fleet-wide.
|
|
1632
|
+
*/
|
|
1633
|
+
activeExperiments: z20.array(z20.unknown()).catch([]).default([]).transform(
|
|
1634
|
+
(experiments) => experiments.flatMap((experiment) => {
|
|
1635
|
+
const result = CabActiveExperiment.safeParse(experiment);
|
|
1636
|
+
return result.success ? [result.data] : [];
|
|
1637
|
+
})
|
|
1638
|
+
),
|
|
1639
|
+
/**
|
|
1640
|
+
* Only the two fields the smart-cart entitlement gate reads (`shortName`/`isActive`). Per-element
|
|
1641
|
+
* resilient like `activeExperiments`: a drifted package entry degrades to an inert `''`/false one that
|
|
1642
|
+
* matches nothing, so a real active `cart-merchandising` package still gates correctly and a sibling
|
|
1643
|
+
* drift never fails the shared config parse. Note the salvage is fail-CLOSED, not fail-open, for an
|
|
1644
|
+
* entitled v6 shop: a malformed whole array (⇒ `[]`) or an inerted `cart-merchandising` entry (e.g.
|
|
1645
|
+
* `is_active: 1` ⇒ inactive) makes the gate find no active package and drop every bar. That matches
|
|
1646
|
+
* React's "no proof of entitlement ⇒ render null", but it silently removes bars — so the server gate
|
|
1647
|
+
* ({@link file://../server/widgetSettings.ts} `fetchProgressBarContext`) emits a `shopConfig` drift
|
|
1648
|
+
* when it sees the inert-entry sentinel (`shortName === ''`). The whole-array `[]` case leaves no
|
|
1649
|
+
* sentinel and is not separately signalable here.
|
|
1650
|
+
*/
|
|
1651
|
+
activePackages: z20.array(z20.object({ isActive: z20.boolean(), shortName: z20.string() }).catch({ isActive: false, shortName: "" })).catch([]).default([]),
|
|
1652
|
+
apiKey: z20.string(),
|
|
1653
|
+
/** The shop's billing generation; the smart-cart entitlement gate only fires for `'v6'`. Missing/drift ⇒ `null` (fail open, ungated). */
|
|
1654
|
+
billingVersion: z20.string().nullable().catch(null).default(null),
|
|
1655
|
+
/**
|
|
1656
|
+
* The shop's rotating cache-buster: `onsite_cache_key` internally — a unix timestamp the engine bumps,
|
|
1657
|
+
* and the edge copy of this config purges, on every widget/settings/theme edit — but serialized on the
|
|
1658
|
+
* wire as `cache_key`, which `deepCamelCase` maps to this field (renaming it `onsiteCacheKey` would
|
|
1659
|
+
* sever the mapping silently; the wire-level assertion in `userConfig.test.ts` is what fails loudly).
|
|
1660
|
+
* Threaded onto the widgets/settings read as `cache_key` so the engine marks the response
|
|
1661
|
+
* immutable-cacheable and the `cached.*` edge serves it fresh-by-URL. The engine sends a numeric
|
|
1662
|
+
* string — coerce — but admit only number/string inputs and constrain to a positive integer: a bare
|
|
1663
|
+
* coercion folds `null`/`''`/`false` to `0` and `true` to `1` — "valid" numbers that would go upstream
|
|
1664
|
+
* as a constant never-rotating buster and pin the edge copy permanently stale. A real key is always a
|
|
1665
|
+
* positive int sent as number or string, so everything else lands on `.catch()` and degrades that read
|
|
1666
|
+
* to un-busted (origin-served — slower, never stale), never a parse fail.
|
|
1667
|
+
*/
|
|
1668
|
+
cacheKey: z20.union([z20.number(), z20.string()]).transform((value) => Number(value)).pipe(z20.number().int().positive()).optional().catch(void 0),
|
|
1669
|
+
/**
|
|
1670
|
+
* The shop's base-currency ISO code (e.g. `'USD'`). CAB derives the shop minor-unit exponent from it
|
|
1671
|
+
* (`currencyDecimals`) so a Functions-applied fixed discount — whose amount is in shop minor units —
|
|
1672
|
+
* converts to the buyer's currency exactly in a cross-decimal market. `.catch()` like its siblings: a
|
|
1673
|
+
* missing/renamed currency degrades to "unknown" (client falls back to buyer decimals), never a parse fail.
|
|
1674
|
+
*/
|
|
1675
|
+
currency: z20.string().optional().catch(void 0),
|
|
1676
|
+
/**
|
|
1677
|
+
* The merchant's "Use Markets in Data Sources" toggle. The engine (CI2) never reads it on the serve
|
|
1678
|
+
* path, so the proxy honouring it before sending market context is what makes the setting mean
|
|
1679
|
+
* anything (REB-21688). Fail-CLOSED, unlike the fail-open siblings: a missing/null/drifted field reads
|
|
1680
|
+
* as markets OFF — market context silently dropped (engine serves shop-default market), never sent
|
|
1681
|
+
* against the merchant's setting. The OFF-reading salvages stay distinguishable: missing AND null are
|
|
1682
|
+
* the engine's normal absent vocabulary (`.nullish()`, like `monetize`/`billingVersion`) and read as
|
|
1683
|
+
* the plain default — not drift — while only a drifted SHAPE `.catch`es, to the {@link DRIFTED_MARKETS}
|
|
1684
|
+
* identity sentinel, so `fetchUserConfig` can emit a `shopConfig` drift for the one case that means an
|
|
1685
|
+
* engine rename/retype; otherwise a markets-enabled merchant degrading to shop-default pricing would
|
|
1686
|
+
* be indistinguishable from markets genuinely off. The missing-key case is EXPLICIT via `.default()`
|
|
1687
|
+
* (a factory, so parses never share a mutable object) rather than inferred from zod running an
|
|
1688
|
+
* optional key's transform on `undefined`; `null` flows past the default through `.nullish()` into the
|
|
1689
|
+
* transform. `Readonly` on the output type because the drifted salvage IS frozen — an assignment to
|
|
1690
|
+
* `markets.enabled` downstream would throw only for drifted shops in production, so surface direct
|
|
1691
|
+
* writes to tsc (a guard for the direct case only: TS doesn't check `readonly` in assignability, so
|
|
1692
|
+
* laundering through a mutable-shaped alias still compiles).
|
|
1693
|
+
* The inner `enabled` stays strict on purpose: `{ enabled: null }` is a genuine retype and drifting is
|
|
1694
|
+
* the correct answer (the editor-path `ShopConfig.markets` would hard-fail the same payload).
|
|
1695
|
+
*/
|
|
1696
|
+
markets: z20.object({ enabled: z20.boolean() }).nullish().catch(DRIFTED_MARKETS).default(() => ({ enabled: false })).transform((markets) => markets ?? { enabled: false }),
|
|
1697
|
+
monetize: z20.object({ publisherKey: z20.string().nullable() }).nullish().catch(void 0),
|
|
1698
|
+
shopId: z20.number().optional().catch(void 0),
|
|
1699
|
+
/**
|
|
1700
|
+
* The merchant's display name ("Gift Basket Store") — the Monetize header copy reads it.
|
|
1701
|
+
* `.catch()` like its siblings: a missing/drifted name degrades the header to the
|
|
1702
|
+
* myshopify-domain slug (the pre-CAB React fallback), never a parse fail. An empty string is a
|
|
1703
|
+
* VALID parse — the slug fallback for `''` (and whitespace/tag-only names) lives in
|
|
1704
|
+
* composeOffer's `||` chain, not here.
|
|
1705
|
+
*/
|
|
1706
|
+
shopName: z20.string().nullish().catch(void 0)
|
|
1707
|
+
});
|
|
1708
|
+
var CabUserConfig = z20.object({
|
|
1709
|
+
shop: CabShopConfig,
|
|
1710
|
+
smartCart: SmartCartConfig.nullish().catch(void 0)
|
|
1711
|
+
});
|
|
1712
|
+
|
|
1713
|
+
// src/schema/widgets/checkout-and-beyond/image.ts
|
|
1714
|
+
import { v7 as uuidv713 } from "uuid";
|
|
1715
|
+
import { z as z39 } from "zod";
|
|
1716
|
+
|
|
839
1717
|
// src/schema/widgets/checkout-and-beyond/icons.ts
|
|
840
1718
|
var iconNames = [
|
|
841
1719
|
"alert-circle",
|
|
@@ -921,283 +1799,65 @@ var iconTones = ["auto", "critical", "custom", "info", "neutral", "success", "wa
|
|
|
921
1799
|
var IconTone = freezeEnum(iconTones);
|
|
922
1800
|
|
|
923
1801
|
// src/schema/widgets/checkout-and-beyond/imageThumbnails.ts
|
|
924
|
-
import { z as
|
|
925
|
-
var CABImageThumbnails =
|
|
926
|
-
limit:
|
|
927
|
-
perLine:
|
|
1802
|
+
import { z as z21 } from "zod";
|
|
1803
|
+
var CABImageThumbnails = z21.object({
|
|
1804
|
+
limit: z21.number().int().min(1).default(8),
|
|
1805
|
+
perLine: z21.number().int().min(1).max(8).default(4)
|
|
928
1806
|
});
|
|
929
1807
|
|
|
930
|
-
// src/schema/widgets/checkout-and-beyond/regex.ts
|
|
931
|
-
var DYNAMIC_TOKEN_REGEX = /^\{\{\s*[A-Za-z]+\s*\}\}$/;
|
|
932
|
-
var HEX_COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
933
|
-
var ROOT_RELATIVE_PATH_REGEX = /^\/(?!\/)/;
|
|
934
|
-
var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
|
|
935
|
-
|
|
936
1808
|
// src/schema/widgets/checkout-and-beyond/shared.ts
|
|
937
|
-
import { z as
|
|
1809
|
+
import { z as z38 } from "zod";
|
|
938
1810
|
|
|
939
1811
|
// src/schema/widgets/checkout-and-beyond/banner.ts
|
|
940
|
-
import { z as
|
|
941
|
-
|
|
942
|
-
// src/schema/widgets/checkout-and-beyond/layout.ts
|
|
943
|
-
import { v7 as uuidv7 } from "uuid";
|
|
944
|
-
import { z as z10 } from "zod";
|
|
945
|
-
|
|
946
|
-
// src/schema/widgets/checkout-and-beyond/variables.ts
|
|
947
|
-
import { z as z9 } from "zod";
|
|
948
|
-
|
|
949
|
-
// src/schema/widgets/checkout-and-beyond/rule.ts
|
|
950
|
-
import { z as z8 } from "zod";
|
|
951
|
-
var ruleTypes = [
|
|
952
|
-
"cart",
|
|
953
|
-
"cart_count",
|
|
954
|
-
"cart_item_count",
|
|
955
|
-
"cart_line_count",
|
|
956
|
-
"cart_subtotal",
|
|
957
|
-
"collection",
|
|
958
|
-
"customer",
|
|
959
|
-
"customer_order_count",
|
|
960
|
-
"customer_tag",
|
|
961
|
-
"customer_total_spent",
|
|
962
|
-
"date",
|
|
963
|
-
"product",
|
|
964
|
-
"product_tag",
|
|
965
|
-
"product_title",
|
|
966
|
-
"product_type",
|
|
967
|
-
"product_vendor"
|
|
968
|
-
];
|
|
969
|
-
var ruleType = z8.enum(ruleTypes);
|
|
970
|
-
var RuleType = ruleType.enum;
|
|
971
|
-
var ruleOperators = [
|
|
972
|
-
"after",
|
|
973
|
-
"anything",
|
|
974
|
-
"before",
|
|
975
|
-
"contains",
|
|
976
|
-
"contains_any",
|
|
977
|
-
"does_not_contain",
|
|
978
|
-
"does_not_contain_any",
|
|
979
|
-
"equals",
|
|
980
|
-
"does_not_equal",
|
|
981
|
-
"greater_than",
|
|
982
|
-
"less_than"
|
|
983
|
-
];
|
|
984
|
-
var ruleOperator = z8.enum(ruleOperators);
|
|
985
|
-
var RuleOperator = ruleOperator.enum;
|
|
986
|
-
var RuleCondition = z8.object({
|
|
987
|
-
operator: z8.enum(ruleOperators).default(RuleOperator.anything),
|
|
988
|
-
products: z8.union([z8.array(z8.unknown()), z8.strictObject({}).transform(() => [])]).default(() => []),
|
|
989
|
-
type: z8.enum(ruleTypes).default(RuleType.cart_subtotal),
|
|
990
|
-
value: z8.coerce.string().default("")
|
|
991
|
-
});
|
|
992
|
-
var RuleLogicBlock = z8.object({
|
|
993
|
-
rules: z8.array(RuleCondition).default(() => [])
|
|
994
|
-
});
|
|
995
|
-
var CABRulesetEntry = z8.object({
|
|
996
|
-
exitIfMatched: z8.boolean().default(true),
|
|
997
|
-
logic: z8.array(RuleLogicBlock).default(() => []),
|
|
998
|
-
output: z8.array(
|
|
999
|
-
z8.object({
|
|
1000
|
-
key: z8.string().default("should_show"),
|
|
1001
|
-
type: z8.literal("data_json").default("data_json"),
|
|
1002
|
-
value: z8.string().default("true")
|
|
1003
|
-
})
|
|
1004
|
-
).default(() => [{ key: "should_show", type: "data_json", value: "true" }])
|
|
1005
|
-
});
|
|
1006
|
-
var CABRuleset = z8.union([z8.array(CABRulesetEntry), z8.strictObject({}).transform(() => [])]).default(() => []);
|
|
1007
|
-
|
|
1008
|
-
// src/schema/widgets/checkout-and-beyond/variables.ts
|
|
1009
|
-
var variableEffect = z9.enum(variableEffects);
|
|
1010
|
-
var CABVariableSeed = z9.object({
|
|
1011
|
-
dataSourceId: z9.number().nullable().default(null),
|
|
1012
|
-
ruleset: CABRuleset
|
|
1013
|
-
});
|
|
1014
|
-
var CABBooleanVariable = z9.object({
|
|
1015
|
-
/**
|
|
1016
|
-
* Holds until the first seed verdict lands (and forever, for unseeded variables). Omitted, it derives
|
|
1017
|
-
* from seededness — `false` with a `seed` (visibility is EARNED), `true` without — via the transform
|
|
1018
|
-
* below; a cross-field default has no `.default()` spelling. An explicit value always wins.
|
|
1019
|
-
*/
|
|
1020
|
-
defaultValue: z9.boolean().optional(),
|
|
1021
|
-
name: z9.string().min(1),
|
|
1022
|
-
seed: CABVariableSeed.optional(),
|
|
1023
|
-
/** Defaulted so every stored declaration (all boolean before `text` existed) parses unchanged. */
|
|
1024
|
-
type: z9.literal(VariableType.boolean).default(VariableType.boolean)
|
|
1025
|
-
});
|
|
1026
|
-
var CABTextVariable = z9.object({
|
|
1027
|
-
defaultValue: z9.string(),
|
|
1028
|
-
name: z9.string().min(1),
|
|
1029
|
-
seed: z9.never().optional(),
|
|
1030
|
-
type: z9.literal(VariableType.text)
|
|
1031
|
-
});
|
|
1032
|
-
var CABNumberVariable = z9.object({
|
|
1033
|
-
defaultValue: z9.number(),
|
|
1034
|
-
name: z9.string().min(1),
|
|
1035
|
-
seed: z9.never().optional(),
|
|
1036
|
-
type: z9.literal(VariableType.number)
|
|
1037
|
-
});
|
|
1038
|
-
var CABVariable = z9.union([CABTextVariable, CABNumberVariable, CABBooleanVariable]).transform(
|
|
1039
|
-
(variable) => variable.type === VariableType.boolean ? { ...variable, defaultValue: variable.defaultValue ?? variable.seed === void 0 } : variable
|
|
1040
|
-
);
|
|
1041
|
-
var CABVariableEffect = z9.object({
|
|
1042
|
-
effect: variableEffect.default(VariableEffect.toggle),
|
|
1043
|
-
variable: z9.string().min(1)
|
|
1044
|
-
});
|
|
1045
|
-
var CABVisibility = z9.object({
|
|
1046
|
-
variable: z9.string().min(1),
|
|
1047
|
-
visibleWhen: z9.boolean().default(true)
|
|
1048
|
-
});
|
|
1049
|
-
var contentOperator = z9.enum(contentOperators);
|
|
1050
|
-
var resultCountOperator = z9.enum(resultCountOperators);
|
|
1051
|
-
var resultTagOperator = z9.enum(resultTagOperators);
|
|
1052
|
-
var mutatorEvent = z9.enum(mutatorEvents);
|
|
1053
|
-
var CABContentTrigger = z9.object({
|
|
1054
|
-
operator: contentOperator.default(ContentOperator.is_empty),
|
|
1055
|
-
type: z9.literal("content")
|
|
1056
|
-
});
|
|
1057
|
-
var CABResultCountTrigger = z9.object({
|
|
1058
|
-
operator: resultCountOperator.default(ResultCountOperator.equals),
|
|
1059
|
-
type: z9.literal("result_count"),
|
|
1060
|
-
value: z9.number().default(0)
|
|
1061
|
-
});
|
|
1062
|
-
var CABResultTagTrigger = z9.object({
|
|
1063
|
-
operator: resultTagOperator.default(ResultTagOperator.contains),
|
|
1064
|
-
type: z9.literal("result_tag"),
|
|
1065
|
-
value: z9.string().min(1)
|
|
1066
|
-
});
|
|
1067
|
-
var CABEventTrigger = z9.object({
|
|
1068
|
-
event: mutatorEvent,
|
|
1069
|
-
type: z9.literal("event")
|
|
1070
|
-
});
|
|
1071
|
-
var CABVariableTrigger = z9.discriminatedUnion("type", [
|
|
1072
|
-
CABContentTrigger,
|
|
1073
|
-
CABEventTrigger,
|
|
1074
|
-
CABResultCountTrigger,
|
|
1075
|
-
CABResultTagTrigger
|
|
1076
|
-
]);
|
|
1077
|
-
var CABVariableMutator = z9.object({
|
|
1078
|
-
effect: variableEffect.default(VariableEffect.set_false),
|
|
1079
|
-
variable: z9.string().min(1),
|
|
1080
|
-
when: CABVariableTrigger
|
|
1081
|
-
});
|
|
1082
|
-
var CABVariableFields = {
|
|
1083
|
-
mutators: z9.array(CABVariableMutator).optional(),
|
|
1084
|
-
variables: z9.array(CABVariable).refine((variables) => new Set(variables.map(({ name }) => name)).size === variables.length, {
|
|
1085
|
-
message: "variable names must be unique within a section"
|
|
1086
|
-
}).optional(),
|
|
1087
|
-
visibility: CABVisibility.optional()
|
|
1088
|
-
};
|
|
1812
|
+
import { z as z23 } from "zod";
|
|
1089
1813
|
|
|
1090
1814
|
// src/schema/widgets/checkout-and-beyond/layout.ts
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1815
|
+
import { v7 as uuidv72 } from "uuid";
|
|
1816
|
+
import { z as z22 } from "zod";
|
|
1817
|
+
var GridItem = z22.union([z22.literal("auto"), z22.literal("fill"), z22.string().regex(/^\d+%$/), z22.number()]);
|
|
1818
|
+
var CABLayoutWrapping = z22.object({
|
|
1819
|
+
breakAt: z22.number().positive(),
|
|
1820
|
+
maxPerLine: z22.number().int().positive()
|
|
1095
1821
|
});
|
|
1096
|
-
var CABLayoutSection =
|
|
1822
|
+
var CABLayoutSection = z22.object({
|
|
1097
1823
|
...CABVariableFields,
|
|
1098
|
-
alignment:
|
|
1099
|
-
horizontal:
|
|
1100
|
-
vertical:
|
|
1824
|
+
alignment: z22.object({
|
|
1825
|
+
horizontal: z22.enum(horizontalAlignments).default(HorizontalAlignment.start),
|
|
1826
|
+
vertical: z22.enum(verticalAlignments).default(VerticalAlignment.top)
|
|
1101
1827
|
}).default({
|
|
1102
1828
|
horizontal: HorizontalAlignment.start,
|
|
1103
1829
|
vertical: VerticalAlignment.top
|
|
1104
1830
|
}),
|
|
1105
|
-
border:
|
|
1106
|
-
buttonField:
|
|
1107
|
-
direction:
|
|
1831
|
+
border: z22.lazy(() => CABBorder),
|
|
1832
|
+
buttonField: z22.enum(buttonFields).optional(),
|
|
1833
|
+
direction: z22.enum(directions).default(Direction.rows),
|
|
1108
1834
|
/**
|
|
1109
1835
|
* Platform chrome around the section, not a layout behavior: `callout` is a subdued box with block borders
|
|
1110
1836
|
* (the legacy post-purchase callout banner), `offer-content` the post-purchase offer's own content card.
|
|
1111
1837
|
*/
|
|
1112
|
-
frame:
|
|
1113
|
-
grid:
|
|
1114
|
-
columns:
|
|
1115
|
-
rows:
|
|
1838
|
+
frame: z22.enum(layoutFrames).optional(),
|
|
1839
|
+
grid: z22.object({
|
|
1840
|
+
columns: z22.union([z22.array(GridItem), z22.undefined()]).default(() => ["auto"]),
|
|
1841
|
+
rows: z22.union([z22.array(GridItem), z22.undefined()]).default(() => ["auto"])
|
|
1116
1842
|
}).default({ columns: ["auto"], rows: ["auto"] }).optional(),
|
|
1117
|
-
name:
|
|
1118
|
-
padding:
|
|
1119
|
-
sectionId:
|
|
1120
|
-
sections:
|
|
1121
|
-
sectionType:
|
|
1122
|
-
spacing:
|
|
1843
|
+
name: z22.string().optional(),
|
|
1844
|
+
padding: z22.enum(spacings).default(Spacing.none),
|
|
1845
|
+
sectionId: z22.uuid().default(() => uuidv72()),
|
|
1846
|
+
sections: z22.union([z22.array(z22.lazy(() => CABSection)), z22.strictObject({}).transform(() => [])]).default(() => []),
|
|
1847
|
+
sectionType: z22.literal(SectionType.layout).default(SectionType.layout),
|
|
1848
|
+
spacing: z22.enum(spacings).default(Spacing.base),
|
|
1123
1849
|
/** Fire-and-forget impression pixel POSTed once when the section is shown (e.g. a Monetize offer view). */
|
|
1124
|
-
viewUrl:
|
|
1125
|
-
width:
|
|
1850
|
+
viewUrl: z22.string().optional(),
|
|
1851
|
+
width: z22.number().default(100),
|
|
1126
1852
|
wrapping: CABLayoutWrapping.optional()
|
|
1127
1853
|
});
|
|
1128
1854
|
|
|
1129
|
-
// src/schema/widgets/checkout-and-beyond/utils.ts
|
|
1130
|
-
import { isPlainObject as isPlainObject2 } from "es-toolkit";
|
|
1131
|
-
import { get, isString } from "es-toolkit/compat";
|
|
1132
|
-
|
|
1133
|
-
// src/transforms/convertNumericObjects.ts
|
|
1134
|
-
import { isPlainObject } from "es-toolkit";
|
|
1135
|
-
var ARRAY_INDEX_STRING = /^(?:0|[1-9]\d*)$/;
|
|
1136
|
-
var hasOnlyNumericKeys = (input, requireCompleteRun) => {
|
|
1137
|
-
const keys = Object.keys(input);
|
|
1138
|
-
if (keys.length === 0) return false;
|
|
1139
|
-
if (!keys.every((key) => ARRAY_INDEX_STRING.test(key) && Number.isSafeInteger(Number(key)))) return false;
|
|
1140
|
-
if (!requireCompleteRun) return true;
|
|
1141
|
-
const sorted = keys.map(Number).sort((a, b) => a - b);
|
|
1142
|
-
return sorted.every((n, i) => n === i);
|
|
1143
|
-
};
|
|
1144
|
-
var numericObjectToArray = (input) => Object.entries(input).sort(([a], [b]) => Number(a) - Number(b)).map(([, value]) => value);
|
|
1145
|
-
var convert = (input, requireCompleteRun) => {
|
|
1146
|
-
if (Array.isArray(input)) return input.map((item) => convert(item, requireCompleteRun));
|
|
1147
|
-
if (isPlainObject(input)) {
|
|
1148
|
-
if (hasOnlyNumericKeys(input, requireCompleteRun)) {
|
|
1149
|
-
return numericObjectToArray(input).map((item) => convert(item, requireCompleteRun));
|
|
1150
|
-
}
|
|
1151
|
-
const out = {};
|
|
1152
|
-
for (const [key, value] of Object.entries(input)) out[key] = convert(value, requireCompleteRun);
|
|
1153
|
-
return out;
|
|
1154
|
-
}
|
|
1155
|
-
return input;
|
|
1156
|
-
};
|
|
1157
|
-
var convertNumericObjects = (input) => convert(input, true);
|
|
1158
|
-
|
|
1159
|
-
// src/schema/widgets/checkout-and-beyond/utils.ts
|
|
1160
|
-
var isHTML = (html = "") => {
|
|
1161
|
-
if (typeof window !== "undefined") {
|
|
1162
|
-
const parser = new DOMParser();
|
|
1163
|
-
const doc = parser.parseFromString(html, "text/html");
|
|
1164
|
-
const hasHTML = (nodeList) => Array.from(nodeList).some((node) => node.nodeType === 1);
|
|
1165
|
-
return hasHTML(doc.body.childNodes) || hasHTML(doc.head.childNodes);
|
|
1166
|
-
}
|
|
1167
|
-
return html.search(HTML_TAGS_REGEX) !== -1;
|
|
1168
|
-
};
|
|
1169
|
-
var hasHTMLInDoc = (doc) => doc.content.some(({ content = [] }) => content.some(({ text: text2 }) => isHTML(text2)));
|
|
1170
|
-
var checkForHTML = (input) => !(isString(input) && isHTML(input) || isPlainObject2(input) && hasHTMLInDoc(input));
|
|
1171
|
-
var NO_HTML = { message: "HTML is not supported" };
|
|
1172
|
-
var isSectionType = (sectionType) => (section) => get(section, "sectionType") === sectionType;
|
|
1173
|
-
var isBannerType = isSectionType(SectionType.banner);
|
|
1174
|
-
var isButtonType = isSectionType(SectionType.button);
|
|
1175
|
-
var isCarouselType = isSectionType(SectionType.carousel);
|
|
1176
|
-
var isCartLineType = isSectionType(SectionType.cartLine);
|
|
1177
|
-
var isDataSourceType = isSectionType(
|
|
1178
|
-
SectionType.dataSource
|
|
1179
|
-
);
|
|
1180
|
-
var isDiscountType = isSectionType(SectionType.discount);
|
|
1181
|
-
var isImageType = isSectionType(SectionType.image);
|
|
1182
|
-
var isLayoutType = isSectionType(SectionType.layout);
|
|
1183
|
-
var isMonetizeType = isSectionType(SectionType.monetize);
|
|
1184
|
-
var isOffersType = isSectionType(SectionType.offers);
|
|
1185
|
-
var isProductType = isSectionType(SectionType.product);
|
|
1186
|
-
var isProductsType = isSectionType(SectionType.products);
|
|
1187
|
-
var isProgressBarType = isSectionType(
|
|
1188
|
-
SectionType.progressBar
|
|
1189
|
-
);
|
|
1190
|
-
var isQuantityType = isSectionType(SectionType.quantity);
|
|
1191
|
-
var isReviewsType = isSectionType(SectionType.reviews);
|
|
1192
|
-
var isTextType = isSectionType(SectionType.text);
|
|
1193
|
-
var isVariantsType = isSectionType(SectionType.variants);
|
|
1194
|
-
|
|
1195
1855
|
// src/schema/widgets/checkout-and-beyond/banner.ts
|
|
1196
|
-
var CABBannerSection =
|
|
1856
|
+
var CABBannerSection = z23.lazy(
|
|
1197
1857
|
() => CABLayoutSection.omit({ sectionType: true }).extend({
|
|
1198
|
-
buttonField:
|
|
1199
|
-
color:
|
|
1200
|
-
dismissible:
|
|
1858
|
+
buttonField: z23.enum(buttonFields).optional(),
|
|
1859
|
+
color: z23.enum(bannerColors).default("info"),
|
|
1860
|
+
dismissible: z23.boolean().default(true),
|
|
1201
1861
|
/**
|
|
1202
1862
|
* The `s-banner` heading — localized content (a buyer can see a merchant-composed banner). Absent OR
|
|
1203
1863
|
* blank ⇒ no heading; the renderer emits no heading slot for `''` rather than an empty one.
|
|
@@ -1213,140 +1873,50 @@ var CABBannerSection = z11.lazy(
|
|
|
1213
1873
|
* not a 500. Nothing emits `heading` yet; the first converter that maps merchant banner copy into it
|
|
1214
1874
|
* either strips first or teaches `normalizeTextContent` to strip this field.
|
|
1215
1875
|
*/
|
|
1216
|
-
heading:
|
|
1217
|
-
sectionType:
|
|
1876
|
+
heading: z23.record(z23.string(), z23.string().refine(checkForHTML, NO_HTML)).optional(),
|
|
1877
|
+
sectionType: z23.literal(SectionType.banner).default(SectionType.banner)
|
|
1218
1878
|
})
|
|
1219
1879
|
);
|
|
1220
1880
|
|
|
1221
1881
|
// src/schema/widgets/checkout-and-beyond/button.ts
|
|
1222
1882
|
import { v7 as uuidv73 } from "uuid";
|
|
1223
|
-
import { z as
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
import { forEach, isString as isString2 } from "es-toolkit/compat";
|
|
1227
|
-
import { v7 as uuidv72 } from "uuid";
|
|
1228
|
-
import { z as z12 } from "zod";
|
|
1229
|
-
var enumOrOmit = (...vals) => z12.string().transform((val) => vals.includes(val) ? val : void 0).optional();
|
|
1230
|
-
var TiptapText = z12.object({
|
|
1231
|
-
marks: z12.union([
|
|
1232
|
-
z12.array(
|
|
1233
|
-
z12.discriminatedUnion("type", [
|
|
1234
|
-
z12.object({ type: z12.literal("bold") }),
|
|
1235
|
-
z12.object({ type: z12.literal("italic") }),
|
|
1236
|
-
z12.object({
|
|
1237
|
-
attrs: z12.object({
|
|
1238
|
-
class: z12.string().nullable(),
|
|
1239
|
-
href: z12.union([
|
|
1240
|
-
z12.url(),
|
|
1241
|
-
z12.literal("#"),
|
|
1242
|
-
z12.string().regex(DYNAMIC_TOKEN_REGEX),
|
|
1243
|
-
z12.string().regex(ROOT_RELATIVE_PATH_REGEX)
|
|
1244
|
-
]),
|
|
1245
|
-
rel: z12.string().default("noopener noreferrer nofollow"),
|
|
1246
|
-
target: z12.string().default("_blank")
|
|
1247
|
-
}),
|
|
1248
|
-
type: z12.literal("link")
|
|
1249
|
-
}),
|
|
1250
|
-
z12.object({ type: z12.literal("strike") }),
|
|
1251
|
-
z12.object({
|
|
1252
|
-
attrs: z12.object({
|
|
1253
|
-
color: enumOrOmit(...textColorNames).default(TextColorName.base),
|
|
1254
|
-
fontSize: enumOrOmit(...textSizeNames).default(TextSizeName.base)
|
|
1255
|
-
}),
|
|
1256
|
-
type: z12.literal("textStyle")
|
|
1257
|
-
})
|
|
1258
|
-
])
|
|
1259
|
-
),
|
|
1260
|
-
z12.strictObject({}).transform(() => [])
|
|
1261
|
-
]).optional(),
|
|
1262
|
-
text: z12.string().default(""),
|
|
1263
|
-
type: z12.literal("text").default("text")
|
|
1264
|
-
});
|
|
1265
|
-
var TiptapParagraph = z12.object({
|
|
1266
|
-
attrs: z12.object({
|
|
1267
|
-
textAlign: enumOrOmit(...textAlignments)
|
|
1268
|
-
}).default({ textAlign: TextAlignment.start }),
|
|
1269
|
-
content: z12.union([z12.array(TiptapText), z12.strictObject({}).transform(() => [])]).default(() => []),
|
|
1270
|
-
type: z12.literal("paragraph").default("paragraph")
|
|
1271
|
-
});
|
|
1272
|
-
var TiptapDocument = z12.object({
|
|
1273
|
-
attrs: z12.object({
|
|
1274
|
-
blockSpacing: enumOrOmit(...spacings)
|
|
1275
|
-
}).default({ blockSpacing: Spacing.base }),
|
|
1276
|
-
content: z12.union([z12.array(TiptapParagraph), z12.strictObject({}).transform(() => [])]).default(() => [TiptapParagraph.parse({})]),
|
|
1277
|
-
type: z12.literal("doc").default("doc")
|
|
1278
|
-
});
|
|
1279
|
-
var CABTextTier = z12.object({
|
|
1280
|
-
threshold: z12.number().int().nonnegative(),
|
|
1281
|
-
thresholds: z12.record(z12.string(), z12.number().int().nonnegative()).default(() => ({})),
|
|
1282
|
-
tierId: z12.string().optional(),
|
|
1283
|
-
tierType: z12.enum(progressTierTypes).default(ProgressTierType.shipping)
|
|
1284
|
-
});
|
|
1285
|
-
var CABTextSection = z12.object({
|
|
1286
|
-
...CABVariableFields,
|
|
1287
|
-
buttonField: z12.enum(buttonFields).optional(),
|
|
1288
|
-
content: z12.record(z12.string(), z12.union([z12.string(), TiptapDocument]).refine(checkForHTML, NO_HTML).optional()).default({ en: TiptapDocument.parse({}) }).optional(),
|
|
1289
|
-
name: z12.string().optional(),
|
|
1290
|
-
optionId: z12.number().optional(),
|
|
1291
|
-
sectionId: z12.uuid().default(() => uuidv72()),
|
|
1292
|
-
sectionType: z12.literal(SectionType.text).default(SectionType.text),
|
|
1293
|
-
tier: CABTextTier.optional()
|
|
1294
|
-
}).superRefine(({ buttonField, content }, ctx) => {
|
|
1295
|
-
if (buttonField === ButtonField.destinationUrl && content) {
|
|
1296
|
-
forEach(content, (value, lang) => {
|
|
1297
|
-
if (value && isString2(value)) {
|
|
1298
|
-
if (DYNAMIC_TOKEN_REGEX.test(value)) return;
|
|
1299
|
-
try {
|
|
1300
|
-
new URL(value);
|
|
1301
|
-
} catch {
|
|
1302
|
-
ctx.addIssue({
|
|
1303
|
-
code: "custom",
|
|
1304
|
-
message: "Invalid URL",
|
|
1305
|
-
path: ["content", lang]
|
|
1306
|
-
});
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
});
|
|
1310
|
-
}
|
|
1311
|
-
});
|
|
1312
|
-
|
|
1313
|
-
// src/schema/widgets/checkout-and-beyond/button.ts
|
|
1314
|
-
var CABButtonContent = z13.lazy(
|
|
1315
|
-
() => z13.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
|
|
1883
|
+
import { z as z24 } from "zod";
|
|
1884
|
+
var CABButtonContent = z24.lazy(
|
|
1885
|
+
() => z24.discriminatedUnion("sectionType", [CABImageSection, CABLayoutSection, CABTextSection])
|
|
1316
1886
|
);
|
|
1317
|
-
var CABButtonSection =
|
|
1887
|
+
var CABButtonSection = z24.object({
|
|
1318
1888
|
...CABVariableFields,
|
|
1319
|
-
action:
|
|
1320
|
-
buttonStyle:
|
|
1321
|
-
custom:
|
|
1322
|
-
color:
|
|
1323
|
-
height:
|
|
1324
|
-
width:
|
|
1889
|
+
action: z24.union([z24.literal(""), z24.enum(buttonActions)]).default(""),
|
|
1890
|
+
buttonStyle: z24.enum(buttonStyles).default(ButtonStyle.primary),
|
|
1891
|
+
custom: z24.object({
|
|
1892
|
+
color: z24.string().regex(HEX_COLOR_REGEX).default("#005bd3"),
|
|
1893
|
+
height: z24.number().default(52),
|
|
1894
|
+
width: z24.number().default(300)
|
|
1325
1895
|
}).default({
|
|
1326
1896
|
color: "#005bd3",
|
|
1327
1897
|
height: 52,
|
|
1328
1898
|
width: 300
|
|
1329
1899
|
}),
|
|
1330
|
-
disableDowngrade:
|
|
1900
|
+
disableDowngrade: z24.boolean().default(false),
|
|
1331
1901
|
/**
|
|
1332
1902
|
* What labels a `switchToSubscription` button's frequency options. `planName` shows the selling plan's
|
|
1333
1903
|
* own name (legacy post-purchase, L115) and falls back to the `subscriptionOption` template for a plan
|
|
1334
1904
|
* without one; absent or `template` is the template alone (the checkout card). Optional and additive
|
|
1335
1905
|
* (REB-24846); an unknown value reads as absent.
|
|
1336
1906
|
*/
|
|
1337
|
-
frequencyLabel:
|
|
1338
|
-
name:
|
|
1339
|
-
optionId:
|
|
1340
|
-
popover:
|
|
1341
|
-
alignment:
|
|
1342
|
-
position:
|
|
1907
|
+
frequencyLabel: z24.enum(["planName", "template"]).optional().catch(void 0),
|
|
1908
|
+
name: z24.string().optional(),
|
|
1909
|
+
optionId: z24.number().optional(),
|
|
1910
|
+
popover: z24.object({
|
|
1911
|
+
alignment: z24.enum(textAlignments).default(TextAlignment.center),
|
|
1912
|
+
position: z24.enum(popoverPositions).default(PopoverPosition.blockStart)
|
|
1343
1913
|
}).optional().default(() => ({
|
|
1344
1914
|
alignment: TextAlignment.center,
|
|
1345
1915
|
position: PopoverPosition.blockStart
|
|
1346
1916
|
})),
|
|
1347
|
-
sectionId:
|
|
1348
|
-
sections:
|
|
1349
|
-
sectionType:
|
|
1917
|
+
sectionId: z24.uuid().default(() => uuidv73()),
|
|
1918
|
+
sections: z24.union([z24.array(CABButtonContent), z24.strictObject({}).transform(() => [])]).default(() => []),
|
|
1919
|
+
sectionType: z24.literal(SectionType.button).default(SectionType.button),
|
|
1350
1920
|
/**
|
|
1351
1921
|
* The smart-cart tier this button acts on (`addGift`/`removeGift`): scopes the click to one tier's gift. The
|
|
1352
1922
|
* client resolves the tier's gift (productId) from the progress-bar context by this `tierId` — the button node
|
|
@@ -1361,25 +1931,25 @@ var CABButtonSection = z13.object({
|
|
|
1361
1931
|
* lookup finds no tier and the click resolves to nothing. Safe to bound — the field is new, so there are no
|
|
1362
1932
|
* stored payloads to grandfather, and the producer is client code, not a merchant form.
|
|
1363
1933
|
*/
|
|
1364
|
-
tier:
|
|
1934
|
+
tier: z24.object({ tierId: z24.string().min(1) }).optional(),
|
|
1365
1935
|
/** Fire-and-forget pixel POSTed when the button is clicked (e.g. a Monetize decline). */
|
|
1366
|
-
trackingUrl:
|
|
1936
|
+
trackingUrl: z24.string().optional(),
|
|
1367
1937
|
/**
|
|
1368
1938
|
* Secondary effects applied to in-scope variables on click, alongside (never instead of) the primary
|
|
1369
1939
|
* `action` — an `addToOrder` button can also flip a variable. Applied in array order.
|
|
1370
1940
|
*/
|
|
1371
|
-
variableEffects:
|
|
1941
|
+
variableEffects: z24.array(CABVariableEffect).optional()
|
|
1372
1942
|
});
|
|
1373
1943
|
|
|
1374
1944
|
// src/schema/widgets/checkout-and-beyond/carousel.ts
|
|
1375
|
-
import { z as
|
|
1945
|
+
import { z as z29 } from "zod";
|
|
1376
1946
|
|
|
1377
1947
|
// src/schema/widgets/checkout-and-beyond/offers.ts
|
|
1378
|
-
import { z as
|
|
1948
|
+
import { z as z28 } from "zod";
|
|
1379
1949
|
|
|
1380
1950
|
// src/schema/widgets/checkout-and-beyond/dataSource.ts
|
|
1381
1951
|
import { v7 as uuidv74 } from "uuid";
|
|
1382
|
-
import { z as
|
|
1952
|
+
import { z as z25 } from "zod";
|
|
1383
1953
|
|
|
1384
1954
|
// src/schema/widgets/checkout-and-beyond/constants.ts
|
|
1385
1955
|
import { uniqBy } from "es-toolkit";
|
|
@@ -1433,77 +2003,77 @@ var targetAreas = {
|
|
|
1433
2003
|
};
|
|
1434
2004
|
|
|
1435
2005
|
// src/schema/widgets/checkout-and-beyond/dataSource.ts
|
|
1436
|
-
var CABDiscount =
|
|
1437
|
-
amount:
|
|
1438
|
-
discountedBy:
|
|
1439
|
-
discountedFrom:
|
|
1440
|
-
type:
|
|
1441
|
-
});
|
|
1442
|
-
var CABIntegrations =
|
|
1443
|
-
judgeme:
|
|
1444
|
-
junip:
|
|
1445
|
-
klaviyo:
|
|
1446
|
-
loox:
|
|
1447
|
-
okendo:
|
|
1448
|
-
opinew:
|
|
1449
|
-
reviewsio:
|
|
1450
|
-
stamped:
|
|
1451
|
-
yotpo:
|
|
1452
|
-
});
|
|
1453
|
-
var CABVariantLabels =
|
|
1454
|
-
variantOption:
|
|
1455
|
-
variantOptions:
|
|
1456
|
-
});
|
|
1457
|
-
var CABDataSourceSection =
|
|
1458
|
-
dataSourceId:
|
|
1459
|
-
dataSourcePath:
|
|
2006
|
+
var CABDiscount = z25.object({
|
|
2007
|
+
amount: z25.union([z25.number(), z25.string()]).catch(0),
|
|
2008
|
+
discountedBy: z25.string().optional(),
|
|
2009
|
+
discountedFrom: z25.enum(discountSources).optional().catch(void 0),
|
|
2010
|
+
type: z25.enum(discountTypes).catch("none")
|
|
2011
|
+
});
|
|
2012
|
+
var CABIntegrations = z25.object({
|
|
2013
|
+
judgeme: z25.boolean().default(false),
|
|
2014
|
+
junip: z25.boolean().default(false),
|
|
2015
|
+
klaviyo: z25.boolean().default(false),
|
|
2016
|
+
loox: z25.boolean().default(false),
|
|
2017
|
+
okendo: z25.boolean().default(false),
|
|
2018
|
+
opinew: z25.boolean().default(false),
|
|
2019
|
+
reviewsio: z25.boolean().default(false),
|
|
2020
|
+
stamped: z25.boolean().default(false),
|
|
2021
|
+
yotpo: z25.boolean().default(false)
|
|
2022
|
+
});
|
|
2023
|
+
var CABVariantLabels = z25.object({
|
|
2024
|
+
variantOption: z25.string().optional().catch(void 0),
|
|
2025
|
+
variantOptions: z25.string().optional().catch(void 0)
|
|
2026
|
+
});
|
|
2027
|
+
var CABDataSourceSection = z25.object({
|
|
2028
|
+
dataSourceId: z25.number().nullable().default(null),
|
|
2029
|
+
dataSourcePath: z25.string().default(DEFAULT_ENDPOINTS[0].value),
|
|
1460
2030
|
discount: CABDiscount.optional(),
|
|
1461
2031
|
integrations: CABIntegrations.optional(),
|
|
1462
|
-
limit:
|
|
1463
|
-
matchVariant:
|
|
1464
|
-
matchVariantOutOfStock:
|
|
1465
|
-
name:
|
|
1466
|
-
productType:
|
|
1467
|
-
sectionId:
|
|
1468
|
-
sectionType:
|
|
2032
|
+
limit: z25.number().default(1),
|
|
2033
|
+
matchVariant: z25.boolean().default(false),
|
|
2034
|
+
matchVariantOutOfStock: z25.boolean().default(false),
|
|
2035
|
+
name: z25.string().default(DEFAULT_ENDPOINTS[0].label),
|
|
2036
|
+
productType: z25.enum(productTypes).optional(),
|
|
2037
|
+
sectionId: z25.uuid().default(() => uuidv74()),
|
|
2038
|
+
sectionType: z25.literal(SectionType.dataSource).default(SectionType.dataSource),
|
|
1469
2039
|
/** Default subscribe-vs-one-time for `productType: both` (legacy `subscription_is_default`). */
|
|
1470
|
-
subscriptionIsDefault:
|
|
1471
|
-
treatAsGwp:
|
|
2040
|
+
subscriptionIsDefault: z25.boolean().default(false),
|
|
2041
|
+
treatAsGwp: z25.boolean().default(false),
|
|
1472
2042
|
variantLabels: CABVariantLabels.optional().catch(void 0)
|
|
1473
2043
|
});
|
|
1474
2044
|
|
|
1475
2045
|
// src/schema/widgets/checkout-and-beyond/products.ts
|
|
1476
2046
|
import { v7 as uuidv76 } from "uuid";
|
|
1477
|
-
import { z as
|
|
2047
|
+
import { z as z27 } from "zod";
|
|
1478
2048
|
|
|
1479
2049
|
// src/schema/widgets/checkout-and-beyond/product.ts
|
|
1480
2050
|
import { v7 as uuidv75 } from "uuid";
|
|
1481
|
-
import { z as
|
|
1482
|
-
var CABVariantContent =
|
|
1483
|
-
() =>
|
|
2051
|
+
import { z as z26 } from "zod";
|
|
2052
|
+
var CABVariantContent = z26.lazy(
|
|
2053
|
+
() => z26.discriminatedUnion("sectionType", [CABButtonSection, CABTextSection])
|
|
1484
2054
|
);
|
|
1485
|
-
var CABProductSection =
|
|
2055
|
+
var CABProductSection = z26.object({
|
|
1486
2056
|
...CABVariableFields,
|
|
1487
|
-
name:
|
|
1488
|
-
productId:
|
|
1489
|
-
sectionId:
|
|
1490
|
-
sections:
|
|
1491
|
-
sectionType:
|
|
1492
|
-
selectors:
|
|
1493
|
-
variantMode:
|
|
2057
|
+
name: z26.string().optional(),
|
|
2058
|
+
productId: z26.number().nullable().default(null),
|
|
2059
|
+
sectionId: z26.uuid().default(() => uuidv75()),
|
|
2060
|
+
sections: z26.union([z26.array(CABVariantContent), z26.strictObject({}).transform(() => [])]).default(() => []),
|
|
2061
|
+
sectionType: z26.literal(SectionType.product).default(SectionType.product),
|
|
2062
|
+
selectors: z26.record(z26.string(), z26.enum(variantSelectors).default(VariantSelector.menu)).default(() => ({})),
|
|
2063
|
+
variantMode: z26.enum(variantModes).default(VariantMode.multiple)
|
|
1494
2064
|
});
|
|
1495
2065
|
|
|
1496
2066
|
// src/schema/widgets/checkout-and-beyond/products.ts
|
|
1497
|
-
var CABProductsSection =
|
|
2067
|
+
var CABProductsSection = z27.object({
|
|
1498
2068
|
...CABVariableFields,
|
|
1499
|
-
name:
|
|
1500
|
-
sectionId:
|
|
1501
|
-
sections:
|
|
1502
|
-
sectionType:
|
|
2069
|
+
name: z27.string().optional(),
|
|
2070
|
+
sectionId: z27.uuid().default(() => uuidv76()),
|
|
2071
|
+
sections: z27.union([z27.array(z27.lazy(() => CABProductSection)), z27.strictObject({}).transform(() => [])]).default(() => []),
|
|
2072
|
+
sectionType: z27.literal(SectionType.products).default(SectionType.products)
|
|
1503
2073
|
});
|
|
1504
2074
|
|
|
1505
2075
|
// src/schema/widgets/checkout-and-beyond/offers.ts
|
|
1506
|
-
var CABOffersSection =
|
|
2076
|
+
var CABOffersSection = z28.lazy(
|
|
1507
2077
|
() => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
|
|
1508
2078
|
/**
|
|
1509
2079
|
* A rule between consecutive cards in the vertical list — legacy checkout-offers' `<Divider />`,
|
|
@@ -1511,8 +2081,8 @@ var CABOffersSection = z17.lazy(
|
|
|
1511
2081
|
* run of products). Optional, not defaulted: only the v1 converter sets it (REB-24265); a
|
|
1512
2082
|
* hand-built tree keeps React CAB's dividerless rendering.
|
|
1513
2083
|
*/
|
|
1514
|
-
divider:
|
|
1515
|
-
sections:
|
|
2084
|
+
divider: z28.boolean().optional(),
|
|
2085
|
+
sections: z28.union([z28.array(z28.lazy(() => CABSection)), z28.strictObject({}).transform(() => [])]).default(() => [
|
|
1516
2086
|
CABBannerSection.parse({
|
|
1517
2087
|
buttonField: "undoAddToOrder",
|
|
1518
2088
|
color: "success",
|
|
@@ -1526,77 +2096,77 @@ var CABOffersSection = z17.lazy(
|
|
|
1526
2096
|
CABDataSourceSection.parse({}),
|
|
1527
2097
|
CABProductsSection.parse({})
|
|
1528
2098
|
]),
|
|
1529
|
-
sectionType:
|
|
2099
|
+
sectionType: z28.literal(SectionType.offers).default(SectionType.offers)
|
|
1530
2100
|
})
|
|
1531
2101
|
);
|
|
1532
2102
|
|
|
1533
2103
|
// src/schema/widgets/checkout-and-beyond/carousel.ts
|
|
1534
|
-
var CABCarouselSection =
|
|
2104
|
+
var CABCarouselSection = z29.lazy(
|
|
1535
2105
|
() => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
|
|
1536
|
-
autoAdvanceInterval:
|
|
1537
|
-
itemsAtOnce:
|
|
2106
|
+
autoAdvanceInterval: z29.number().default(0),
|
|
2107
|
+
itemsAtOnce: z29.number().min(1).default(1),
|
|
1538
2108
|
/** Card arrangement for the offers child (`horizontal` = side-by-side) — NOT the carousel's own `direction`. */
|
|
1539
|
-
offersDirection:
|
|
1540
|
-
sections:
|
|
1541
|
-
sectionType:
|
|
2109
|
+
offersDirection: z29.enum(offersDirections).default("vertical"),
|
|
2110
|
+
sections: z29.union([z29.array(z29.lazy(() => CABSection)), z29.strictObject({}).transform(() => [])]).default(() => [CABOffersSection.parse({})]),
|
|
2111
|
+
sectionType: z29.literal(SectionType.carousel).default(SectionType.carousel)
|
|
1542
2112
|
})
|
|
1543
2113
|
);
|
|
1544
2114
|
|
|
1545
2115
|
// src/schema/widgets/checkout-and-beyond/cartLine.ts
|
|
1546
|
-
import { z as
|
|
1547
|
-
var CABCartLineSection =
|
|
2116
|
+
import { z as z30 } from "zod";
|
|
2117
|
+
var CABCartLineSection = z30.lazy(
|
|
1548
2118
|
() => CABLayoutSection.omit({ sections: true, sectionType: true }).extend({
|
|
1549
|
-
sections:
|
|
1550
|
-
sectionType:
|
|
2119
|
+
sections: z30.union([z30.array(z30.lazy(() => CABSection)), z30.strictObject({}).transform(() => [])]).default(() => [CABButtonSection.parse({ action: ButtonAction.switchToSubscription })]),
|
|
2120
|
+
sectionType: z30.literal(SectionType.cartLine).default(SectionType.cartLine)
|
|
1551
2121
|
})
|
|
1552
2122
|
);
|
|
1553
2123
|
|
|
1554
2124
|
// src/schema/widgets/checkout-and-beyond/discount.ts
|
|
1555
2125
|
import { v7 as uuidv77 } from "uuid";
|
|
1556
|
-
import { z as
|
|
1557
|
-
var CABDiscountSection =
|
|
2126
|
+
import { z as z31 } from "zod";
|
|
2127
|
+
var CABDiscountSection = z31.object({
|
|
1558
2128
|
...CABVariableFields,
|
|
1559
|
-
amount:
|
|
1560
|
-
discountedBy:
|
|
1561
|
-
discountedFrom:
|
|
1562
|
-
message:
|
|
1563
|
-
name:
|
|
1564
|
-
quantity:
|
|
1565
|
-
sectionId:
|
|
1566
|
-
sectionType:
|
|
1567
|
-
type:
|
|
2129
|
+
amount: z31.union([z31.number(), z31.string()]).catch(0),
|
|
2130
|
+
discountedBy: z31.string().optional(),
|
|
2131
|
+
discountedFrom: z31.enum(discountSources).optional().catch(void 0),
|
|
2132
|
+
message: z31.string().optional(),
|
|
2133
|
+
name: z31.string().optional(),
|
|
2134
|
+
quantity: z31.number().default(1),
|
|
2135
|
+
sectionId: z31.uuid().default(() => uuidv77()),
|
|
2136
|
+
sectionType: z31.literal(SectionType.discount).default(SectionType.discount),
|
|
2137
|
+
type: z31.enum(discountTypes).catch("none")
|
|
1568
2138
|
});
|
|
1569
2139
|
|
|
1570
2140
|
// src/schema/widgets/checkout-and-beyond/monetize.ts
|
|
1571
2141
|
import { v7 as uuidv78 } from "uuid";
|
|
1572
|
-
import { z as
|
|
1573
|
-
var CABMonetizeAds =
|
|
1574
|
-
requestId:
|
|
2142
|
+
import { z as z32 } from "zod";
|
|
2143
|
+
var CABMonetizeAds = z32.object({
|
|
2144
|
+
requestId: z32.string().optional(),
|
|
1575
2145
|
/** Defaulted here, never in the beacon: absence of information is `ads` itself being absent. */
|
|
1576
|
-
testing:
|
|
2146
|
+
testing: z32.boolean().default(false)
|
|
1577
2147
|
});
|
|
1578
|
-
var CABMonetizeSection =
|
|
2148
|
+
var CABMonetizeSection = z32.object({
|
|
1579
2149
|
...CABVariableFields,
|
|
1580
2150
|
ads: CABMonetizeAds.optional(),
|
|
1581
|
-
name:
|
|
2151
|
+
name: z32.string().optional(),
|
|
1582
2152
|
/**
|
|
1583
2153
|
* Server-hydrated offer cards (inline hydration): when `/cab/sections` was asked with a `monetize`
|
|
1584
2154
|
* context block, the composed cards ride the marker itself — `[]` means "hydrated, no fill" (render
|
|
1585
2155
|
* nothing, skip the fetch); ABSENT means "not hydrated" (the client fetches via `/cab/monetize`).
|
|
1586
2156
|
*/
|
|
1587
|
-
offers:
|
|
2157
|
+
offers: z32.array(z32.lazy(() => CABSection)).optional(),
|
|
1588
2158
|
/** 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. */
|
|
1589
|
-
privacyPolicyUrl:
|
|
1590
|
-
sectionId:
|
|
1591
|
-
sectionType:
|
|
2159
|
+
privacyPolicyUrl: z32.string().optional(),
|
|
2160
|
+
sectionId: z32.uuid().default(() => uuidv78()),
|
|
2161
|
+
sectionType: z32.literal(SectionType.monetize).default(SectionType.monetize),
|
|
1592
2162
|
/** Ads-taxonomy sub-vertical id (the widget's `sub_vertical` setting); paired with `vertical`. */
|
|
1593
|
-
subVertical:
|
|
2163
|
+
subVertical: z32.string().optional(),
|
|
1594
2164
|
/** Ads-taxonomy vertical id (the widget's `vertical` setting) — with `subVertical`, the admin Monetize editor's two configurables. */
|
|
1595
|
-
vertical:
|
|
2165
|
+
vertical: z32.string().optional()
|
|
1596
2166
|
});
|
|
1597
2167
|
|
|
1598
2168
|
// src/schema/widgets/checkout-and-beyond/progressBar.ts
|
|
1599
|
-
import { z as
|
|
2169
|
+
import { z as z33 } from "zod";
|
|
1600
2170
|
|
|
1601
2171
|
// src/schema/widgets/checkout-and-beyond/giftLabels.ts
|
|
1602
2172
|
var GIFT_LABELS = {
|
|
@@ -1715,34 +2285,34 @@ var GIFT_LABELS = {
|
|
|
1715
2285
|
};
|
|
1716
2286
|
|
|
1717
2287
|
// src/schema/widgets/checkout-and-beyond/progressBar.ts
|
|
1718
|
-
var CABProgressTierExclusion =
|
|
1719
|
-
collectionIds:
|
|
1720
|
-
productIds:
|
|
1721
|
-
tags:
|
|
1722
|
-
type:
|
|
2288
|
+
var CABProgressTierExclusion = z33.object({
|
|
2289
|
+
collectionIds: z33.array(z33.number().int().positive()).default(() => []),
|
|
2290
|
+
productIds: z33.array(z33.number().int().positive()).default(() => []),
|
|
2291
|
+
tags: z33.array(z33.string().min(1)).default(() => []),
|
|
2292
|
+
type: z33.enum(progressTierExclusionTypes)
|
|
1723
2293
|
});
|
|
1724
|
-
var CABProgressTier =
|
|
2294
|
+
var CABProgressTier = z33.object({
|
|
1725
2295
|
/**
|
|
1726
2296
|
* Order-discount tiers only (onsite `discount`): the reward the order-discount Function applies at
|
|
1727
2297
|
* cart time, carried so the client can resolve the `{{discountAmount}}` token in this tier's copy.
|
|
1728
2298
|
* `fixedAmount`: shop-currency CENTS (FX-scaled by the client, like {@link CABProgressTier.threshold});
|
|
1729
2299
|
* `percentage`: the whole-percent number rendered raw (`{n}%`). Absent on non-discount tiers.
|
|
1730
2300
|
*/
|
|
1731
|
-
discount:
|
|
2301
|
+
discount: z33.object({ amount: z33.number().nonnegative(), type: z33.enum(["fixedAmount", "percentage"]) }).optional(),
|
|
1732
2302
|
/**
|
|
1733
2303
|
* Per-tier exclusion rules (onsite `exclusions` when `exclusions_enabled`): lines they match don't count
|
|
1734
2304
|
* toward this tier. Empty (the default, and the converter's output for a disabled or ruleless tier) means
|
|
1735
2305
|
* the tier measures the plain bar-level adjusted progress. Consumers read ONLY the list named by the rule's
|
|
1736
2306
|
* `type` — the converter leaves the other two at `[]`, so a populated off-type list never reaches the tree.
|
|
1737
2307
|
*/
|
|
1738
|
-
exclusions:
|
|
2308
|
+
exclusions: z33.array(CABProgressTierExclusion).default(() => []),
|
|
1739
2309
|
/**
|
|
1740
2310
|
* Smart-cart product (gift) tiers only (onsite `filter_oos_variants`): when set, the client drops this
|
|
1741
2311
|
* tier entirely once its gift has NO in-stock eligible variant — the milestone, fill slot and gift
|
|
1742
2312
|
* controls all disappear, mirroring onsite removing the tier from `bar.tiers` before it renders. Absent
|
|
1743
2313
|
* on shipping/discount/decorative tiers and left off by default (the tier renders regardless of stock).
|
|
1744
2314
|
*/
|
|
1745
|
-
filterOosVariants:
|
|
2315
|
+
filterOosVariants: z33.boolean().default(false),
|
|
1746
2316
|
/**
|
|
1747
2317
|
* Smart-cart product (gift) tiers only: the reward unlocked at this tier. The client enriches
|
|
1748
2318
|
* `productId`/`variantIds` to live variants (availability, price) and adds the chosen one to the cart
|
|
@@ -1750,10 +2320,10 @@ var CABProgressTier = z22.object({
|
|
|
1750
2320
|
* tiers and on tiers with no configured product. Cart add/remove is a later stage; carried here so the
|
|
1751
2321
|
* tree is complete.
|
|
1752
2322
|
*/
|
|
1753
|
-
gift:
|
|
1754
|
-
productId:
|
|
1755
|
-
title:
|
|
1756
|
-
variantIds:
|
|
2323
|
+
gift: z33.object({
|
|
2324
|
+
productId: z33.number().int().positive(),
|
|
2325
|
+
title: z33.string().optional(),
|
|
2326
|
+
variantIds: z33.array(z33.number().int().positive()).default(() => [])
|
|
1757
2327
|
}).optional(),
|
|
1758
2328
|
/**
|
|
1759
2329
|
* The step-row icon's square size in PIXELS (onsite `product_tier_element_size`, an admin px string the
|
|
@@ -1773,7 +2343,7 @@ var CABProgressTier = z22.object({
|
|
|
1773
2343
|
* renderer never spells a fallback), which also makes a tree authored before this field render at
|
|
1774
2344
|
* React's size rather than the old hardcoded 20.
|
|
1775
2345
|
*/
|
|
1776
|
-
iconSizePx:
|
|
2346
|
+
iconSizePx: z33.number().int().min(1).max(64).default(18),
|
|
1777
2347
|
/**
|
|
1778
2348
|
* The step-row label at this tier's slot (onsite `getTierLabel`): the merchant custom label, else the
|
|
1779
2349
|
* type default — 'Free Shipping' or '{n}% Discount'. A PRODUCT tier gets NO converter label: its name is
|
|
@@ -1783,35 +2353,35 @@ var CABProgressTier = z22.object({
|
|
|
1783
2353
|
* turns a blank label into an absent key, and a client-authored blank means the same thing — the renderer
|
|
1784
2354
|
* emits no caption slot rather than an empty one). Plain text — a compact icon+label.
|
|
1785
2355
|
*/
|
|
1786
|
-
label:
|
|
2356
|
+
label: z33.record(z33.string(), z33.string()).optional(),
|
|
1787
2357
|
/**
|
|
1788
2358
|
* Smart-cart product (gift) tiers only (onsite `product_tier_image`): show the gift's product image in
|
|
1789
2359
|
* the step-row slot instead of the generic bag icon. The converter can't supply the image URL (config
|
|
1790
2360
|
* carries only product IDs), so the client resolves it (authoritative Shopify featured image, React
|
|
1791
2361
|
* parity) and falls back to the bag icon when the flag is off or no image resolves. Default false.
|
|
1792
2362
|
*/
|
|
1793
|
-
productTierImage:
|
|
2363
|
+
productTierImage: z33.boolean().default(false),
|
|
1794
2364
|
/**
|
|
1795
2365
|
* The tier's goal, measured per `unit`. `currency` (default): SHOP-currency cents — the canonical
|
|
1796
2366
|
* fallback: when the buyer's presentment currency has no entry in `thresholds`, the client
|
|
1797
2367
|
* multiplies this by the live FX rate (converter maps the v1 `unlock_price`, e.g. `75` → `7500`).
|
|
1798
2368
|
* `item`: a raw item count — no cents, no FX, no `thresholds` overrides.
|
|
1799
2369
|
*/
|
|
1800
|
-
threshold:
|
|
2370
|
+
threshold: z33.number().int().nonnegative(),
|
|
1801
2371
|
/**
|
|
1802
2372
|
* Per-presentment-currency goal overrides — lowercased ISO currency code → cents (e.g. `{ cad: 9900 }`).
|
|
1803
2373
|
* When the buyer's currency has an entry, the client uses it verbatim INSTEAD of FX-converting
|
|
1804
2374
|
* `threshold`, so merchants show intentional, clean per-market amounts (Shopify Markets) rather than a
|
|
1805
2375
|
* converted base. Defaults to `{}` — no overrides means always fall back to `threshold`.
|
|
1806
2376
|
*/
|
|
1807
|
-
thresholds:
|
|
2377
|
+
thresholds: z33.record(z33.string(), z33.number().int().nonnegative()).default(() => ({})),
|
|
1808
2378
|
/**
|
|
1809
2379
|
* Smart-cart tier identifier, mirrored onto the gift cart line's `_tier` attribute so the client can
|
|
1810
2380
|
* match an in-cart gift back to its tier (add on reach, remove on downgrade/decline). Absent on the
|
|
1811
2381
|
* shipping bar (single unlabeled tier, no gift).
|
|
1812
2382
|
*/
|
|
1813
|
-
tierId:
|
|
1814
|
-
tierType:
|
|
2383
|
+
tierId: z33.string().optional(),
|
|
2384
|
+
tierType: z33.enum(progressTierTypes).default(ProgressTierType.shipping),
|
|
1815
2385
|
/**
|
|
1816
2386
|
* What this tier's progress is measured in — PER TIER (onsite's `unlock_condition_type` model, NOT
|
|
1817
2387
|
* the React port's bar-level `tiers[0]` shortcut). `currency` compares money cents against the
|
|
@@ -1822,9 +2392,9 @@ var CABProgressTier = z22.object({
|
|
|
1822
2392
|
* count carries no injected noun (no English `item`/`items` inflection on localized copy); merchant
|
|
1823
2393
|
* template text supplies grammatically-neutral wording around the token.
|
|
1824
2394
|
*/
|
|
1825
|
-
unit:
|
|
2395
|
+
unit: z33.enum(progressTierUnits).default(ProgressTierUnit.currency)
|
|
1826
2396
|
});
|
|
1827
|
-
var CABProgressBarSection =
|
|
2397
|
+
var CABProgressBarSection = z33.lazy(
|
|
1828
2398
|
() => CABLayoutSection.omit({ sectionType: true }).extend({
|
|
1829
2399
|
/**
|
|
1830
2400
|
* The onsite bar id (smart-cart TPB bars only). The client mirrors it to the cart's `_barId` attribute
|
|
@@ -1833,35 +2403,35 @@ var CABProgressBarSection = z22.lazy(
|
|
|
1833
2403
|
* checkout reaches the extension without it, so the client writes it or the tier gift's 100% discount
|
|
1834
2404
|
* (and any tier order discount) never applies. Absent on the v1 shipping bar (no gift tiers, no id).
|
|
1835
2405
|
*/
|
|
1836
|
-
barId:
|
|
2406
|
+
barId: z33.string().optional(),
|
|
1837
2407
|
/** Empty = shown everywhere; otherwise uppercase ISO country codes. */
|
|
1838
|
-
countryCodes:
|
|
2408
|
+
countryCodes: z33.array(z33.string().transform((code) => code.trim().toUpperCase())).default(() => []),
|
|
1839
2409
|
/**
|
|
1840
2410
|
* Uppercase ISO codes where a higher-precedence geo bar applies, so this (default, non-geo) bar is
|
|
1841
2411
|
* hidden there — replicates React `getbar`'s geo-match-over-default precedence. Empty = never excluded.
|
|
1842
2412
|
*/
|
|
1843
|
-
excludeCountryCodes:
|
|
2413
|
+
excludeCountryCodes: z33.array(z33.string().transform((code) => code.trim().toUpperCase())).default(() => []),
|
|
1844
2414
|
/**
|
|
1845
2415
|
* Measure progress against the PRE-discount subtotal (onsite `exclude_discount_in_subtotal`, and
|
|
1846
2416
|
* forced on for bars with a discount tier so its own reward can't un-reach the tier). The client
|
|
1847
2417
|
* adds the cart's discount allocations back to the live subtotal.
|
|
1848
2418
|
*/
|
|
1849
|
-
excludeDiscountInSubtotal:
|
|
2419
|
+
excludeDiscountInSubtotal: z33.boolean().default(false),
|
|
1850
2420
|
/** Variant ids the client subtracts from the adjusted subtotal (React `bar.excluded_products`). */
|
|
1851
|
-
excludedVariantIds:
|
|
2421
|
+
excludedVariantIds: z33.array(z33.number().int().positive()).default(() => []),
|
|
1852
2422
|
/**
|
|
1853
2423
|
* When the cart holds a subscription item, treat the bar as reached regardless of subtotal (React
|
|
1854
2424
|
* `free_shipping_on_subscription(s)`). `freeShippingOnAll` is already a zero-threshold tier instead.
|
|
1855
2425
|
*/
|
|
1856
|
-
freeShippingOnSubscription:
|
|
2426
|
+
freeShippingOnSubscription: z33.boolean().default(false),
|
|
1857
2427
|
/** Localized heading over the gift controls (onsite `gift_area_title`, default 'FREE GIFTS'). */
|
|
1858
|
-
giftAreaTitle:
|
|
2428
|
+
giftAreaTitle: z33.record(z33.string(), z33.string()).default(() => ({ en: "FREE GIFTS" })),
|
|
1859
2429
|
/** Localized gift-control labels (add/remove/heading); a tier's gift `title` beats `yourGift`. */
|
|
1860
|
-
giftLabels:
|
|
1861
|
-
addGift:
|
|
1862
|
-
remove:
|
|
1863
|
-
selectOptions:
|
|
1864
|
-
yourGift:
|
|
2430
|
+
giftLabels: z33.object({
|
|
2431
|
+
addGift: z33.record(z33.string(), z33.string()).default(() => ({ ...GIFT_LABELS.addGift })),
|
|
2432
|
+
remove: z33.record(z33.string(), z33.string()).default(() => ({ ...GIFT_LABELS.remove })),
|
|
2433
|
+
selectOptions: z33.record(z33.string(), z33.string()).default(() => ({ ...GIFT_LABELS.selectOptions })),
|
|
2434
|
+
yourGift: z33.record(z33.string(), z33.string()).default(() => ({ ...GIFT_LABELS.yourGift }))
|
|
1865
2435
|
}).default(() => ({
|
|
1866
2436
|
addGift: { ...GIFT_LABELS.addGift },
|
|
1867
2437
|
remove: { ...GIFT_LABELS.remove },
|
|
@@ -1869,38 +2439,38 @@ var CABProgressBarSection = z22.lazy(
|
|
|
1869
2439
|
yourGift: { ...GIFT_LABELS.yourGift }
|
|
1870
2440
|
})),
|
|
1871
2441
|
/** The bar's a11y label; the merchant names it in the editor, else this default (React parity). */
|
|
1872
|
-
name:
|
|
2442
|
+
name: z33.string().default("Order progress"),
|
|
1873
2443
|
/**
|
|
1874
2444
|
* Bar fill color. An explicit (widget-authored) value is used verbatim; when absent the server
|
|
1875
2445
|
* fills it with the live shop theme's `buttonBackground` (React `useRebuyTheme` parity). Still
|
|
1876
2446
|
* absent after that ⇒ the theme fetch failed and the client renders its platform-default bar —
|
|
1877
2447
|
* optional, not defaulted, so "merchant chose no color" stays distinguishable from any real value.
|
|
1878
2448
|
*/
|
|
1879
|
-
progressColor:
|
|
1880
|
-
sectionType:
|
|
2449
|
+
progressColor: z33.string().optional(),
|
|
2450
|
+
sectionType: z33.literal(SectionType.progressBar).default(SectionType.progressBar),
|
|
1881
2451
|
/**
|
|
1882
2452
|
* The bar's milestones in the merchant's CONFIGURED order — the renderer does NOT sort them (022
|
|
1883
2453
|
* O-B2: sorting by resolved threshold reversed configured milestones on out-of-order or mixed-unit
|
|
1884
2454
|
* count-vs-cents bars). Drives the fill (even slot per tier) and, for smart-cart product tiers, the
|
|
1885
2455
|
* gift add/remove. The visual tier display lives in `sections` (composable), NOT here.
|
|
1886
2456
|
*/
|
|
1887
|
-
tiers:
|
|
2457
|
+
tiers: z33.union([z33.array(CABProgressTier), z33.strictObject({}).transform(() => [])]).default(() => [])
|
|
1888
2458
|
})
|
|
1889
2459
|
);
|
|
1890
2460
|
|
|
1891
2461
|
// src/schema/widgets/checkout-and-beyond/quantity.ts
|
|
1892
2462
|
import { v7 as uuidv79 } from "uuid";
|
|
1893
|
-
import { z as
|
|
1894
|
-
var CABQuantitySection =
|
|
2463
|
+
import { z as z34 } from "zod";
|
|
2464
|
+
var CABQuantitySection = z34.object({
|
|
1895
2465
|
...CABVariableFields,
|
|
1896
|
-
errorMessages:
|
|
1897
|
-
|
|
1898
|
-
|
|
2466
|
+
errorMessages: z34.record(
|
|
2467
|
+
z34.string(),
|
|
2468
|
+
z34.object({
|
|
1899
2469
|
/** `{{step}}` is interpolated at render — the off-increment message React never gave a merchant key. */
|
|
1900
|
-
increment:
|
|
1901
|
-
max:
|
|
1902
|
-
min:
|
|
1903
|
-
neg:
|
|
2470
|
+
increment: z34.string().optional(),
|
|
2471
|
+
max: z34.string().optional(),
|
|
2472
|
+
min: z34.string().optional(),
|
|
2473
|
+
neg: z34.string().optional()
|
|
1904
2474
|
})
|
|
1905
2475
|
).default({
|
|
1906
2476
|
en: {
|
|
@@ -1910,18 +2480,18 @@ var CABQuantitySection = z23.object({
|
|
|
1910
2480
|
neg: "Quantity cannot be negative"
|
|
1911
2481
|
}
|
|
1912
2482
|
}),
|
|
1913
|
-
inputType:
|
|
1914
|
-
max:
|
|
1915
|
-
min:
|
|
2483
|
+
inputType: z34.enum(quantityInputs).default(QuantityInput.select),
|
|
2484
|
+
max: z34.number().min(1).max(100).default(10),
|
|
2485
|
+
min: z34.number().min(1).default(1),
|
|
1916
2486
|
/** The a11y label for the quantity control; the merchant names it in the editor, else this default. */
|
|
1917
|
-
name:
|
|
1918
|
-
sectionId:
|
|
1919
|
-
sectionType:
|
|
2487
|
+
name: z34.string().default("Quantity"),
|
|
2488
|
+
sectionId: z34.uuid().default(() => uuidv79()),
|
|
2489
|
+
sectionType: z34.literal(SectionType.quantity).default(SectionType.quantity)
|
|
1920
2490
|
});
|
|
1921
2491
|
|
|
1922
2492
|
// src/schema/widgets/checkout-and-beyond/reviews.ts
|
|
1923
2493
|
import { v7 as uuidv710 } from "uuid";
|
|
1924
|
-
import { z as
|
|
2494
|
+
import { z as z35 } from "zod";
|
|
1925
2495
|
|
|
1926
2496
|
// src/schema/widgets/checkout-and-beyond/reviewLabels.ts
|
|
1927
2497
|
var REVIEW_LABELS = {
|
|
@@ -1984,49 +2554,49 @@ var REVIEW_LABELS = {
|
|
|
1984
2554
|
};
|
|
1985
2555
|
|
|
1986
2556
|
// src/schema/widgets/checkout-and-beyond/reviews.ts
|
|
1987
|
-
var CABReviewsSection =
|
|
2557
|
+
var CABReviewsSection = z35.object({
|
|
1988
2558
|
...CABVariableFields,
|
|
1989
|
-
color:
|
|
2559
|
+
color: z35.string().default("#fadb14"),
|
|
1990
2560
|
/**
|
|
1991
2561
|
* Localized review-count templates (`{{reviewCount}}`), one/other plural forms; the client picks the
|
|
1992
2562
|
* form via `Intl.PluralRules`. Defaults here (schema-first) so every tree localizes without converter
|
|
1993
2563
|
* or merchant work.
|
|
1994
2564
|
*/
|
|
1995
|
-
countLabels:
|
|
1996
|
-
one:
|
|
1997
|
-
other:
|
|
2565
|
+
countLabels: z35.object({
|
|
2566
|
+
one: z35.record(z35.string(), z35.string()).default(() => ({ ...REVIEW_LABELS.one })),
|
|
2567
|
+
other: z35.record(z35.string(), z35.string()).default(() => ({ ...REVIEW_LABELS.other }))
|
|
1998
2568
|
}).default(() => ({ one: { ...REVIEW_LABELS.one }, other: { ...REVIEW_LABELS.other } })),
|
|
1999
|
-
name:
|
|
2000
|
-
sectionId:
|
|
2001
|
-
sectionType:
|
|
2002
|
-
size:
|
|
2569
|
+
name: z35.string().optional(),
|
|
2570
|
+
sectionId: z35.uuid().default(() => uuidv710()),
|
|
2571
|
+
sectionType: z35.literal(SectionType.reviews).default(SectionType.reviews),
|
|
2572
|
+
size: z35.enum(reviewsSizes).default(ReviewsSize.default),
|
|
2003
2573
|
/**
|
|
2004
2574
|
* Star outline color, interpolated into a style by the renderer, so it is hex-constrained like
|
|
2005
2575
|
* `CABButtonSection.color`. The legacy source (`PostPurchaseSettings.styles.starStrokeColor`) is a free
|
|
2006
2576
|
* string: its converter must validate and fall back to this default rather than let one odd value drop
|
|
2007
2577
|
* the whole reviews section.
|
|
2008
2578
|
*/
|
|
2009
|
-
strokeColor:
|
|
2579
|
+
strokeColor: z35.string().regex(HEX_COLOR_REGEX).default("#fadb14"),
|
|
2010
2580
|
/** Star outline width in px; `0` draws no outline. The legacy `styles.strokeWidth` is a STRING ('1') — its converter coerces. */
|
|
2011
|
-
strokeWidth:
|
|
2581
|
+
strokeWidth: z35.number().nonnegative().default(0)
|
|
2012
2582
|
});
|
|
2013
2583
|
|
|
2014
2584
|
// src/schema/widgets/checkout-and-beyond/separator.ts
|
|
2015
2585
|
import { v7 as uuidv711 } from "uuid";
|
|
2016
|
-
import { z as
|
|
2017
|
-
var CABSeparatorSection =
|
|
2586
|
+
import { z as z36 } from "zod";
|
|
2587
|
+
var CABSeparatorSection = z36.object({
|
|
2018
2588
|
...CABVariableFields,
|
|
2019
|
-
sectionId:
|
|
2020
|
-
sectionType:
|
|
2589
|
+
sectionId: z36.uuid().default(() => uuidv711()),
|
|
2590
|
+
sectionType: z36.literal(SectionType.separator).default(SectionType.separator)
|
|
2021
2591
|
});
|
|
2022
2592
|
|
|
2023
2593
|
// src/schema/widgets/checkout-and-beyond/variants.ts
|
|
2024
2594
|
import { isEmpty, pickBy, slice } from "es-toolkit/compat";
|
|
2025
2595
|
import { v7 as uuidv712 } from "uuid";
|
|
2026
|
-
import { z as
|
|
2027
|
-
var CABVariantsSection =
|
|
2596
|
+
import { z as z37 } from "zod";
|
|
2597
|
+
var CABVariantsSection = z37.object({
|
|
2028
2598
|
...CABVariableFields,
|
|
2029
|
-
hideOutOfStockVariants:
|
|
2599
|
+
hideOutOfStockVariants: z37.boolean().default(false),
|
|
2030
2600
|
/**
|
|
2031
2601
|
* The menu's own label per buyer locale (`selectLanguage`), for the whole-variant (`single`) and the
|
|
2032
2602
|
* product-group menus; `multiple` labels each option's menu by its name. Optional and additive
|
|
@@ -2037,30 +2607,30 @@ var CABVariantsSection = z26.object({
|
|
|
2037
2607
|
* `selectLanguage` returning `''` — which a renderer's `??` fallback would show as an empty menu label.
|
|
2038
2608
|
* A label left with no entries reads as absent.
|
|
2039
2609
|
*/
|
|
2040
|
-
label:
|
|
2610
|
+
label: z37.record(z37.string(), z37.string()).transform((label2) => {
|
|
2041
2611
|
const filled = pickBy(label2, (value) => value.trim() !== "");
|
|
2042
2612
|
return isEmpty(filled) ? void 0 : filled;
|
|
2043
2613
|
}).optional().catch(void 0),
|
|
2044
|
-
name:
|
|
2045
|
-
sectionId:
|
|
2046
|
-
sectionType:
|
|
2047
|
-
selector:
|
|
2614
|
+
name: z37.string().optional(),
|
|
2615
|
+
sectionId: z37.uuid().default(() => uuidv712()),
|
|
2616
|
+
sectionType: z37.literal(SectionType.variants).default(SectionType.variants),
|
|
2617
|
+
selector: z37.enum(slice(variantSelectors, 0, 3)).default(VariantSelector.menu),
|
|
2048
2618
|
/** `productGroup` is additive (REB-24817): a renderer without group support must render nothing for it. */
|
|
2049
|
-
variantMode:
|
|
2619
|
+
variantMode: z37.enum(variantsModes).default(VariantsMode.multiple)
|
|
2050
2620
|
});
|
|
2051
2621
|
|
|
2052
2622
|
// src/schema/widgets/checkout-and-beyond/shared.ts
|
|
2053
|
-
var CABBorder =
|
|
2054
|
-
radius:
|
|
2055
|
-
style:
|
|
2056
|
-
width:
|
|
2623
|
+
var CABBorder = z38.object({
|
|
2624
|
+
radius: z38.enum(borderRadii).default(BorderRadius.base),
|
|
2625
|
+
style: z38.enum(borderStyles).default(BorderStyle.none),
|
|
2626
|
+
width: z38.enum(borderWidths).default(BorderWidth.base)
|
|
2057
2627
|
}).default({
|
|
2058
2628
|
radius: BorderRadius.base,
|
|
2059
2629
|
style: BorderStyle.none,
|
|
2060
2630
|
width: BorderWidth.base
|
|
2061
2631
|
});
|
|
2062
|
-
var CABSection =
|
|
2063
|
-
() =>
|
|
2632
|
+
var CABSection = z38.lazy(
|
|
2633
|
+
() => z38.discriminatedUnion("sectionType", [
|
|
2064
2634
|
CABBannerSection,
|
|
2065
2635
|
CABButtonSection,
|
|
2066
2636
|
CABCarouselSection,
|
|
@@ -2083,17 +2653,17 @@ var CABSection = z27.lazy(
|
|
|
2083
2653
|
);
|
|
2084
2654
|
|
|
2085
2655
|
// src/schema/widgets/checkout-and-beyond/image.ts
|
|
2086
|
-
var CABImageSectionFields =
|
|
2656
|
+
var CABImageSectionFields = z39.object({
|
|
2087
2657
|
...CABVariableFields,
|
|
2088
|
-
altText:
|
|
2658
|
+
altText: z39.string().refine(checkForHTML, NO_HTML).default(""),
|
|
2089
2659
|
/**
|
|
2090
2660
|
* Image width÷height (e.g. `46` for the progress-bar fill); `null` renders at natural size. Any POSITIVE
|
|
2091
2661
|
* ratio — never limited to 1, but never `0`/negative either: a renderer dividing by it would get `Infinity`,
|
|
2092
2662
|
* and CSS `aspect-ratio` drops a negative value and silently reverts to natural size.
|
|
2093
2663
|
*/
|
|
2094
|
-
aspectRatio:
|
|
2095
|
-
border:
|
|
2096
|
-
buttonField:
|
|
2664
|
+
aspectRatio: z39.number().positive().nullable().default(null),
|
|
2665
|
+
border: z39.lazy(() => CABBorder),
|
|
2666
|
+
buttonField: z39.enum(buttonFields).optional(),
|
|
2097
2667
|
/**
|
|
2098
2668
|
* `icon` renders `source` as a single `s-icon` by name (the uber-image path covers icons too), reading
|
|
2099
2669
|
* `iconSize`/`iconTone`. The other values are a harmless informational holdover from the previous
|
|
@@ -2112,30 +2682,30 @@ var CABImageSectionFields = z28.object({
|
|
|
2112
2682
|
* behavior degraded gracefully and told us about it. The client-assembled half of the invariant was never
|
|
2113
2683
|
* the risky half.
|
|
2114
2684
|
*/
|
|
2115
|
-
category:
|
|
2685
|
+
category: z39.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
|
|
2116
2686
|
/** `icon`-mode only: the `s-icon` `size`; `null` ⇒ the component default (`base`). Ignored by image treatments. */
|
|
2117
|
-
iconSize:
|
|
2687
|
+
iconSize: z39.enum(iconSizes).nullable().default(null),
|
|
2118
2688
|
/** `icon`-mode only: the `s-icon` `tone`; `null` ⇒ the component default (`auto`). Ignored by image treatments. */
|
|
2119
|
-
iconTone:
|
|
2120
|
-
name:
|
|
2121
|
-
naturalHeight:
|
|
2122
|
-
naturalWidth:
|
|
2689
|
+
iconTone: z39.enum(iconTones).nullable().default(null),
|
|
2690
|
+
name: z39.string().optional(),
|
|
2691
|
+
naturalHeight: z39.number().default(0),
|
|
2692
|
+
naturalWidth: z39.number().default(0),
|
|
2123
2693
|
/**
|
|
2124
2694
|
* `contain` (the component default): dimensionless images render in s-image's 1/1 default frame, and
|
|
2125
2695
|
* `cover` would crop non-square art (payment badges lost their edges — 15993); `contain` letterboxes.
|
|
2126
2696
|
*/
|
|
2127
|
-
objectFit:
|
|
2128
|
-
sectionId:
|
|
2129
|
-
sectionType:
|
|
2697
|
+
objectFit: z39.enum(objectFits).default(ObjectFit.contain),
|
|
2698
|
+
sectionId: z39.uuid().default(() => uuidv713()),
|
|
2699
|
+
sectionType: z39.literal(SectionType.image).default(SectionType.image),
|
|
2130
2700
|
/**
|
|
2131
2701
|
* An image URL or dynamic token, an empty default, or — when `category: 'icon'` — an icon NAME. Icon mode
|
|
2132
2702
|
* takes a name or `''` only, NOT a token: no renderer resolves a token to an icon today, so accepting one
|
|
2133
2703
|
* would promise a capability that doesn't exist. Widen the refine's carve-out to `DYNAMIC_TOKEN_REGEX` when a
|
|
2134
2704
|
* server-chosen tier icon actually needs it.
|
|
2135
2705
|
*/
|
|
2136
|
-
source:
|
|
2706
|
+
source: z39.union([z39.url(), z39.literal(""), z39.string().regex(DYNAMIC_TOKEN_REGEX), z39.enum(iconNames)]).default(""),
|
|
2137
2707
|
thumbnails: CABImageThumbnails.optional(),
|
|
2138
|
-
width:
|
|
2708
|
+
width: z39.number().default(100)
|
|
2139
2709
|
});
|
|
2140
2710
|
var iconNameSet = new Set(iconNames);
|
|
2141
2711
|
var isIconName = (source2) => iconNameSet.has(source2);
|
|
@@ -2286,7 +2856,7 @@ var convertContentBlockTextToV2 = (language3, text2 = literalText, textAlign = "
|
|
|
2286
2856
|
};
|
|
2287
2857
|
|
|
2288
2858
|
// src/schema/widgets/checkout-and-beyond/root.ts
|
|
2289
|
-
import { z as
|
|
2859
|
+
import { z as z40 } from "zod";
|
|
2290
2860
|
|
|
2291
2861
|
// src/schema/widgets/checkout-and-beyond/uiLabels.ts
|
|
2292
2862
|
var UI_LABELS = {
|
|
@@ -2306,8 +2876,8 @@ var UI_LABELS = {
|
|
|
2306
2876
|
};
|
|
2307
2877
|
|
|
2308
2878
|
// src/schema/widgets/checkout-and-beyond/root.ts
|
|
2309
|
-
var localized = (fallback) =>
|
|
2310
|
-
var CABUILabels =
|
|
2879
|
+
var localized = (fallback) => z40.record(z40.string(), z40.string()).default(() => ({ ...fallback })).transform((labels) => Object.keys(labels).length > 0 ? labels : { ...fallback });
|
|
2880
|
+
var CABUILabels = z40.object({
|
|
2311
2881
|
currentPage: localized(UI_LABELS.currentPage),
|
|
2312
2882
|
guest: localized(UI_LABELS.guest),
|
|
2313
2883
|
loadingOptions: localized(UI_LABELS.loadingOptions),
|
|
@@ -2332,37 +2902,37 @@ var CABUILabels = z29.object({
|
|
|
2332
2902
|
subscriptionOptions: { ...UI_LABELS.subscriptionOptions },
|
|
2333
2903
|
updating: { ...UI_LABELS.updating }
|
|
2334
2904
|
}));
|
|
2335
|
-
var TargetArea =
|
|
2336
|
-
fill:
|
|
2337
|
-
flip:
|
|
2338
|
-
icon:
|
|
2339
|
-
label:
|
|
2340
|
-
width:
|
|
2905
|
+
var TargetArea = z40.object({
|
|
2906
|
+
fill: z40.boolean().optional(),
|
|
2907
|
+
flip: z40.enum(["both", "horizontal", "vertical"]).optional(),
|
|
2908
|
+
icon: z40.string(),
|
|
2909
|
+
label: z40.string(),
|
|
2910
|
+
width: z40.string()
|
|
2341
2911
|
}).default(targetAreas[EditorMode.checkoutExtension][1]);
|
|
2342
|
-
var CABTracking =
|
|
2343
|
-
enableAttribution:
|
|
2344
|
-
enableSource:
|
|
2345
|
-
enableWidget:
|
|
2912
|
+
var CABTracking = z40.object({
|
|
2913
|
+
enableAttribution: z40.boolean().nullish().transform((value) => value ?? true),
|
|
2914
|
+
enableSource: z40.boolean().nullish().transform((value) => value ?? true),
|
|
2915
|
+
enableWidget: z40.boolean().nullish().transform((value) => value ?? true)
|
|
2346
2916
|
}).nullish().transform((value) => value ?? { enableAttribution: true, enableSource: true, enableWidget: true });
|
|
2347
|
-
var CABExperiment =
|
|
2348
|
-
elementId:
|
|
2349
|
-
experimentId:
|
|
2350
|
-
experimentType:
|
|
2351
|
-
selectedId:
|
|
2917
|
+
var CABExperiment = z40.object({
|
|
2918
|
+
elementId: z40.number(),
|
|
2919
|
+
experimentId: z40.number(),
|
|
2920
|
+
experimentType: z40.string(),
|
|
2921
|
+
selectedId: z40.number()
|
|
2352
2922
|
});
|
|
2353
2923
|
var CABRootSection = CABLayoutSection.extend({
|
|
2354
|
-
editorMode:
|
|
2924
|
+
editorMode: z40.enum(editorModes).default(EditorMode.checkoutExtension),
|
|
2355
2925
|
experiment: CABExperiment.optional(),
|
|
2356
2926
|
// Same rule as CABTracking above: the v1 converters pass raw legacy `previewMode` through, so a
|
|
2357
2927
|
// `null` must fall back rather than throw the widget; malformed values still throw.
|
|
2358
|
-
previewMode:
|
|
2359
|
-
storeId:
|
|
2928
|
+
previewMode: z40.boolean().nullish().transform((value) => value ?? false),
|
|
2929
|
+
storeId: z40.number().nullable().default(null),
|
|
2360
2930
|
targetArea: TargetArea.nullable(),
|
|
2361
2931
|
tracking: CABTracking,
|
|
2362
|
-
type:
|
|
2932
|
+
type: z40.enum(widgetTypes).default(WidgetType.ui_extension_content_block),
|
|
2363
2933
|
uiLabels: CABUILabels,
|
|
2364
|
-
version:
|
|
2365
|
-
widgetId:
|
|
2934
|
+
version: z40.literal(2).default(2),
|
|
2935
|
+
widgetId: z40.number().nullable().default(null)
|
|
2366
2936
|
});
|
|
2367
2937
|
|
|
2368
2938
|
// src/transforms/v1Location.ts
|
|
@@ -3855,172 +4425,10 @@ var convertOfferToV2 = ({ id, name, settings }) => {
|
|
|
3855
4425
|
var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(transform(convertNumericObjects(deepCamelCase(raw))));
|
|
3856
4426
|
|
|
3857
4427
|
// src/transforms/postPurchase/convertMessagePreview.ts
|
|
3858
|
-
import { z as
|
|
4428
|
+
import { z as z47 } from "zod";
|
|
3859
4429
|
|
|
3860
4430
|
// src/transforms/postPurchase/convertCalloutBlock.ts
|
|
3861
|
-
import { z as
|
|
3862
|
-
|
|
3863
|
-
// src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
|
|
3864
|
-
import { get as get2, isEqual } from "es-toolkit/compat";
|
|
3865
|
-
import { v4 as uuidv4 } from "uuid";
|
|
3866
|
-
import { z as z31 } from "zod";
|
|
3867
|
-
|
|
3868
|
-
// src/schema/widgets/post-purchase-offer/constants.ts
|
|
3869
|
-
import { z as z30 } from "zod";
|
|
3870
|
-
var blockTypes = [
|
|
3871
|
-
"callout_banner",
|
|
3872
|
-
"image",
|
|
3873
|
-
"image_content",
|
|
3874
|
-
"pay_button",
|
|
3875
|
-
"product_information",
|
|
3876
|
-
"separator",
|
|
3877
|
-
"text",
|
|
3878
|
-
"timer"
|
|
3879
|
-
];
|
|
3880
|
-
var blockType = z30.enum(blockTypes);
|
|
3881
|
-
var BlockType = blockType.enum;
|
|
3882
|
-
|
|
3883
|
-
// src/schema/widgets/post-purchase-offer/postPurchaseBlocks.ts
|
|
3884
|
-
var TextAlignment2 = z31.union([z31.enum(["leading", "center", "trailing"]), z31.unknown().transform(() => "leading")]);
|
|
3885
|
-
var TextSize = z31.union([
|
|
3886
|
-
z31.enum(["xsmall", "small", "base", "default", "medium", "large", "xlarge"]),
|
|
3887
|
-
z31.unknown().transform(() => "medium")
|
|
3888
|
-
]);
|
|
3889
|
-
var CalloutBannerBlock = z31.object({
|
|
3890
|
-
id: z31.string().optional().default(() => uuidv4()),
|
|
3891
|
-
name: z31.string().optional(),
|
|
3892
|
-
settings: z31.object({
|
|
3893
|
-
superTitle: z31.union([z31.string(), TiptapDocument]).default(() => "Limited-time Offer"),
|
|
3894
|
-
title: z31.union([z31.string(), TiptapDocument]).default(() => "Add this customer favorite to your order")
|
|
3895
|
-
}),
|
|
3896
|
-
styles: z31.object({
|
|
3897
|
-
superTitleEmphasized: z31.boolean().default(false),
|
|
3898
|
-
superTitleSize: TextSize.default("large"),
|
|
3899
|
-
textAlignment: TextAlignment2.default("center"),
|
|
3900
|
-
titleEmphasized: z31.boolean().default(true),
|
|
3901
|
-
titleSize: TextSize.default("large")
|
|
3902
|
-
}),
|
|
3903
|
-
type: z31.literal(BlockType.callout_banner).default(BlockType.callout_banner)
|
|
3904
|
-
});
|
|
3905
|
-
var ImageBlock = z31.object({
|
|
3906
|
-
id: z31.string().optional().default(() => uuidv4()),
|
|
3907
|
-
name: z31.string().optional(),
|
|
3908
|
-
settings: z31.union([
|
|
3909
|
-
z31.object({
|
|
3910
|
-
/** This isn't used in the post-purchase offer widget */
|
|
3911
|
-
alt: z31.string().optional().default(""),
|
|
3912
|
-
image: z31.union([z31.literal(""), z31.url()]).default(""),
|
|
3913
|
-
imageSize: z31.number().default(20),
|
|
3914
|
-
imageType: z31.enum(["URL", "UPLOAD"]).default("URL")
|
|
3915
|
-
}),
|
|
3916
|
-
z31.array(z31.never()).transform(() => ({}))
|
|
3917
|
-
]),
|
|
3918
|
-
type: z31.literal(BlockType.image).default(BlockType.image)
|
|
3919
|
-
});
|
|
3920
|
-
var ImageContentBlock = z31.object({
|
|
3921
|
-
id: z31.string().optional().default(() => uuidv4()),
|
|
3922
|
-
name: z31.string().optional(),
|
|
3923
|
-
settings: z31.object({
|
|
3924
|
-
alt: z31.string().optional().default(""),
|
|
3925
|
-
description: z31.union([z31.string(), TiptapDocument, z31.null()]).default(
|
|
3926
|
-
"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."
|
|
3927
|
-
),
|
|
3928
|
-
descriptionSize: TextSize.default("medium"),
|
|
3929
|
-
horizontalAlignment: TextAlignment2.default("leading"),
|
|
3930
|
-
image: z31.union([z31.literal(""), z31.url()]).default(""),
|
|
3931
|
-
imagePlacement: z31.enum(["bottom", "left", "right", "top"]).optional().default("left"),
|
|
3932
|
-
imageSize: z31.number().default(20),
|
|
3933
|
-
superTitle: z31.union([z31.string(), TiptapDocument]).default("Lorem Ipsum!"),
|
|
3934
|
-
superTitleSize: TextSize.default("medium"),
|
|
3935
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
3936
|
-
swapContent: z31.boolean().optional().default(false),
|
|
3937
|
-
title: z31.union([z31.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet"),
|
|
3938
|
-
titleSize: TextSize.default("medium")
|
|
3939
|
-
}),
|
|
3940
|
-
type: z31.literal(BlockType.image_content).default(BlockType.image_content)
|
|
3941
|
-
});
|
|
3942
|
-
var PayButtonBlock = z31.object({
|
|
3943
|
-
id: z31.string().optional().default(() => uuidv4()),
|
|
3944
|
-
name: z31.string().optional(),
|
|
3945
|
-
settings: z31.union([
|
|
3946
|
-
z31.object({
|
|
3947
|
-
label: z31.string().default("Pay Now")
|
|
3948
|
-
}),
|
|
3949
|
-
z31.array(z31.never()).transform(() => ({
|
|
3950
|
-
label: "Pay Now"
|
|
3951
|
-
}))
|
|
3952
|
-
]),
|
|
3953
|
-
styles: z31.union([
|
|
3954
|
-
z31.object({
|
|
3955
|
-
buttonWidth: z31.number().min(10).max(100).default(50)
|
|
3956
|
-
}),
|
|
3957
|
-
z31.array(z31.never()).transform(() => ({
|
|
3958
|
-
buttonWidth: 50
|
|
3959
|
-
}))
|
|
3960
|
-
]),
|
|
3961
|
-
type: z31.literal(BlockType.pay_button).default(BlockType.pay_button)
|
|
3962
|
-
});
|
|
3963
|
-
var ProductInformationBlock = z31.object({
|
|
3964
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
3965
|
-
hideProductImage: z31.boolean().optional().default(false),
|
|
3966
|
-
id: z31.string().optional().default(() => uuidv4()),
|
|
3967
|
-
name: z31.string().optional(),
|
|
3968
|
-
type: z31.literal(BlockType.product_information).default(BlockType.product_information)
|
|
3969
|
-
});
|
|
3970
|
-
var SeparatorBlock = z31.object({
|
|
3971
|
-
id: z31.string().optional().default(() => uuidv4()),
|
|
3972
|
-
name: z31.string().optional(),
|
|
3973
|
-
type: z31.literal(BlockType.separator).default(BlockType.separator)
|
|
3974
|
-
});
|
|
3975
|
-
var TextBlock = z31.object({
|
|
3976
|
-
id: z31.string().optional().default(() => uuidv4()),
|
|
3977
|
-
name: z31.string().optional(),
|
|
3978
|
-
settings: z31.object({
|
|
3979
|
-
description: z31.union([z31.string(), TiptapDocument]).optional().default(
|
|
3980
|
-
"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."
|
|
3981
|
-
),
|
|
3982
|
-
/** This isn't used in the post-purchase offer widget */
|
|
3983
|
-
descriptionSize: TextSize.default("medium"),
|
|
3984
|
-
horizontalAlignment: TextAlignment2.default("leading"),
|
|
3985
|
-
superTitle: z31.union([z31.string(), TiptapDocument]).default("Super Title"),
|
|
3986
|
-
/** This isn't used in the post-purchase offer widget */
|
|
3987
|
-
superTitleSize: TextSize.default("medium"),
|
|
3988
|
-
title: z31.union([z31.string(), TiptapDocument]).nullable().default("Lorem ipsum dolor sit amet."),
|
|
3989
|
-
/** This isn't used in the post-purchase offer widget */
|
|
3990
|
-
titleSize: TextSize.default("medium")
|
|
3991
|
-
}),
|
|
3992
|
-
type: z31.literal(BlockType.text).default(BlockType.text)
|
|
3993
|
-
});
|
|
3994
|
-
var TimerBlock = z31.object({
|
|
3995
|
-
id: z31.string().optional().default(() => uuidv4()),
|
|
3996
|
-
name: z31.string().optional(),
|
|
3997
|
-
settings: z31.object({
|
|
3998
|
-
durationMinutes: z31.number().min(0).default(10),
|
|
3999
|
-
durationSeconds: z31.union([z31.number().min(0), z31.unknown().transform(() => 0)]).default(0),
|
|
4000
|
-
endOffer: z31.boolean().default(true),
|
|
4001
|
-
title: z31.union([z31.string(), TiptapDocument]).default("Hurry \u2014 your special offer ends in:")
|
|
4002
|
-
}),
|
|
4003
|
-
styles: z31.object({
|
|
4004
|
-
textAlignment: TextAlignment2.default("center"),
|
|
4005
|
-
timerBackgroundColor: z31.enum(["info", "warning", "success", "critical"]).default("warning"),
|
|
4006
|
-
timerEmphasized: z31.union([z31.boolean(), z31.unknown().transform(() => true)]).default(true),
|
|
4007
|
-
timerSize: TextSize.default("medium"),
|
|
4008
|
-
timerWidth: z31.number().min(10).max(100).optional().default(100),
|
|
4009
|
-
titleEmphasized: z31.union([z31.boolean(), z31.unknown().transform(() => true)]).default(false),
|
|
4010
|
-
titleSize: TextSize.default("medium")
|
|
4011
|
-
}),
|
|
4012
|
-
type: z31.literal(BlockType.timer).default(BlockType.timer)
|
|
4013
|
-
});
|
|
4014
|
-
var PostPurchaseBlock = z31.discriminatedUnion("type", [
|
|
4015
|
-
CalloutBannerBlock,
|
|
4016
|
-
ImageBlock,
|
|
4017
|
-
ImageContentBlock,
|
|
4018
|
-
PayButtonBlock,
|
|
4019
|
-
ProductInformationBlock,
|
|
4020
|
-
SeparatorBlock,
|
|
4021
|
-
TextBlock,
|
|
4022
|
-
TimerBlock
|
|
4023
|
-
]);
|
|
4431
|
+
import { z as z41 } from "zod";
|
|
4024
4432
|
|
|
4025
4433
|
// src/transforms/postPurchase/styledTextRun.ts
|
|
4026
4434
|
var sizes = {
|
|
@@ -4044,7 +4452,7 @@ var styledTextRun = (text2, emphasized, size) => ({
|
|
|
4044
4452
|
// src/transforms/postPurchase/convertCalloutBlock.ts
|
|
4045
4453
|
var fields = ["superTitle", "title"];
|
|
4046
4454
|
var Shell = CalloutBannerBlock.pick({ styles: true }).extend({
|
|
4047
|
-
settings:
|
|
4455
|
+
settings: z41.object({ superTitle: z41.unknown().optional(), title: z41.unknown().optional() })
|
|
4048
4456
|
});
|
|
4049
4457
|
var convertCalloutBlock = (raw, report) => {
|
|
4050
4458
|
const omit = (detail) => {
|
|
@@ -4079,7 +4487,7 @@ var convertCalloutBlock = (raw, report) => {
|
|
|
4079
4487
|
};
|
|
4080
4488
|
|
|
4081
4489
|
// src/transforms/postPurchase/convertImageFrame.ts
|
|
4082
|
-
import { z as
|
|
4490
|
+
import { z as z42 } from "zod";
|
|
4083
4491
|
|
|
4084
4492
|
// src/transforms/postPurchase/sizeImageSource.ts
|
|
4085
4493
|
var sizeImageSource = (source2, size) => {
|
|
@@ -4091,7 +4499,7 @@ var sizeImageSource = (source2, size) => {
|
|
|
4091
4499
|
};
|
|
4092
4500
|
|
|
4093
4501
|
// src/transforms/postPurchase/convertImageFrame.ts
|
|
4094
|
-
var Source =
|
|
4502
|
+
var Source = z42.url().default("https://cdn.shopify.com/s/files/1/0605/0555/5177/files/placeholder.jpg?v=1657762972");
|
|
4095
4503
|
var DEFAULT_IMAGE_SIZE = 20;
|
|
4096
4504
|
var convertImageFrame = (raw) => {
|
|
4097
4505
|
const parsed = ImageBlock.shape.settings.options[0].safeParse(raw);
|
|
@@ -4137,7 +4545,7 @@ var convertImageBlock = (raw, report) => {
|
|
|
4137
4545
|
};
|
|
4138
4546
|
|
|
4139
4547
|
// src/transforms/postPurchase/convertImageContentBlock.ts
|
|
4140
|
-
import { z as
|
|
4548
|
+
import { z as z44 } from "zod";
|
|
4141
4549
|
|
|
4142
4550
|
// src/transforms/postPurchase/convertImageContentText.ts
|
|
4143
4551
|
var fields2 = ["superTitle", "title", "description"];
|
|
@@ -4162,286 +4570,98 @@ var convertImageContentText = (settings, report) => {
|
|
|
4162
4570
|
} : text2;
|
|
4163
4571
|
const section = CABTextSection.safeParse({ content: { en: content } });
|
|
4164
4572
|
return section.success ? [section.data] : omit();
|
|
4165
|
-
});
|
|
4166
|
-
return CABLayoutSection.parse({ alignment: { horizontal }, sections });
|
|
4167
|
-
};
|
|
4168
|
-
|
|
4169
|
-
// src/transforms/postPurchase/imageContentSettings.ts
|
|
4170
|
-
import { z as
|
|
4171
|
-
var ImageContentSettings = ImageContentBlock.shape.settings.pick({
|
|
4172
|
-
descriptionSize: true,
|
|
4173
|
-
horizontalAlignment: true,
|
|
4174
|
-
superTitleSize: true,
|
|
4175
|
-
swapContent: true,
|
|
4176
|
-
titleSize: true
|
|
4177
|
-
}).extend({
|
|
4178
|
-
alt:
|
|
4179
|
-
description:
|
|
4180
|
-
image:
|
|
4181
|
-
imagePlacement: ImageContentBlock.shape.settings.shape.imagePlacement.unwrap().nullable(),
|
|
4182
|
-
imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(
|
|
4183
|
-
superTitle:
|
|
4184
|
-
title:
|
|
4185
|
-
});
|
|
4186
|
-
|
|
4187
|
-
// src/transforms/postPurchase/convertImageContentBlock.ts
|
|
4188
|
-
var Shell2 = z35.object({ settings: ImageContentSettings, type: z35.literal("image_content") });
|
|
4189
|
-
var PROPORTIONAL_BREAK_AT = 500;
|
|
4190
|
-
var convertImageContentBlock = (raw, report) => {
|
|
4191
|
-
const shell = Shell2.safeParse(raw);
|
|
4192
|
-
if (!shell.success) {
|
|
4193
|
-
report?.({ detail: "Unreadable post-purchase image-content block", kind: "section" });
|
|
4194
|
-
return [];
|
|
4195
|
-
}
|
|
4196
|
-
const settings = shell.data.settings;
|
|
4197
|
-
const alt = typeof settings.alt === "string" ? settings.alt : void 0;
|
|
4198
|
-
if (settings.alt !== void 0 && alt === void 0) {
|
|
4199
|
-
report?.({ detail: "Unreadable post-purchase image-content alt text", kind: "section" });
|
|
4200
|
-
}
|
|
4201
|
-
const image = convertImageFrame({ alt, image: settings.image, imageSize: settings.imageSize });
|
|
4202
|
-
if (!image) report?.({ detail: "Unreadable post-purchase image-content image", kind: "section" });
|
|
4203
|
-
const text2 = convertImageContentText(settings, report);
|
|
4204
|
-
const textFrame = CABLayoutSection.parse({ direction: "grid", grid: { columns: ["100%"] }, sections: [text2] });
|
|
4205
|
-
const placement = settings.imagePlacement ?? (settings.swapContent ? "right" : "left");
|
|
4206
|
-
const imageFirst = placement === "left" || placement === "top";
|
|
4207
|
-
const sections = imageFirst ? [image, textFrame] : [textFrame, image];
|
|
4208
|
-
const ordered = sections.filter((section) => section !== null);
|
|
4209
|
-
const inner = placement === "left" || placement === "right" ? CABLayoutSection.parse({
|
|
4210
|
-
sections: ordered,
|
|
4211
|
-
spacing: "loose",
|
|
4212
|
-
wrapping: {
|
|
4213
|
-
breakAt: settings.imageSize <= 1 ? PROPORTIONAL_BREAK_AT : settings.imageSize,
|
|
4214
|
-
maxPerLine: 2
|
|
4215
|
-
}
|
|
4216
|
-
}) : CABLayoutSection.parse({
|
|
4217
|
-
direction: "grid",
|
|
4218
|
-
grid: { columns: ["100%"] },
|
|
4219
|
-
sections: [CABLayoutSection.parse({ sections: ordered })],
|
|
4220
|
-
width: 95
|
|
4221
|
-
});
|
|
4222
|
-
return [CABLayoutSection.parse({ frame: "offer-content", sections: [inner], spacing: "none" })];
|
|
4223
|
-
};
|
|
4224
|
-
|
|
4225
|
-
// src/transforms/postPurchase/productCardPay.ts
|
|
4226
|
-
import { mapValues } from "es-toolkit";
|
|
4227
|
-
var PAY_NOW = { en: "Pay Now" };
|
|
4228
|
-
var DECLINE_THIS_OFFER = { en: "Decline this offer" };
|
|
4229
|
-
var NOT_AVAILABLE_DEFAULTS = ["Not available"];
|
|
4230
|
-
var soldOutSlot = ({ language: language3 }) => labelSlot("soldOut", OFFER_LABELS.soldOut, language3.global.notAvailable, [], NOT_AVAILABLE_DEFAULTS);
|
|
4231
|
-
var productCardPay = (settings) => {
|
|
4232
|
-
const payNow = labelSlot("payNow", PAY_NOW, settings.language.global.payNow);
|
|
4233
|
-
const priced = settings.language.displayCtaPrice ? { ...payNow, content: mapValues(payNow.content, (label2) => `${label2} \xB7 {{total}}`) } : payNow;
|
|
4234
|
-
return [addToOrderButton("primary", [priced, soldOutSlot(settings)])];
|
|
4235
|
-
};
|
|
4236
|
-
var productCardDecline = ({ language: language3 }) => [
|
|
4237
|
-
{
|
|
4238
|
-
action: "declineOffer",
|
|
4239
|
-
buttonStyle: "secondary",
|
|
4240
|
-
sections: [labelSlot("declineOffer", DECLINE_THIS_OFFER, language3.global.declineThisOffer)],
|
|
4241
|
-
sectionType: "button"
|
|
4242
|
-
}
|
|
4243
|
-
];
|
|
4244
|
-
|
|
4245
|
-
// src/transforms/postPurchase/productCardSettings.ts
|
|
4246
|
-
import { mapValues as mapValues2 } from "es-toolkit";
|
|
4247
|
-
import { z as z38 } from "zod";
|
|
4248
|
-
|
|
4249
|
-
// src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
|
|
4250
|
-
import { z as z37 } from "zod";
|
|
4251
|
-
|
|
4252
|
-
// src/schema/widgets/post-purchase-offer/common.ts
|
|
4253
|
-
import { replace, toNumber, toString } from "es-toolkit/compat";
|
|
4254
|
-
import { z as z36 } from "zod";
|
|
4255
|
-
var strictNumber = z36.union([
|
|
4256
|
-
z36.number(),
|
|
4257
|
-
z36.string().transform((value) => toNumber(replace(toString(value), /[^0-9.]/g, "")) || 0),
|
|
4258
|
-
z36.unknown().transform(() => 0)
|
|
4259
|
-
]);
|
|
4260
|
-
|
|
4261
|
-
// src/schema/widgets/post-purchase-offer/postPurchaseSettings.ts
|
|
4262
|
-
var PostPurchaseSettings = z37.object({
|
|
4263
|
-
advance: z37.object({ removePartialOrder: z37.boolean().default(true) }).optional().default(() => ({ removePartialOrder: true })),
|
|
4264
|
-
blocks: z37.union([z37.array(PostPurchaseBlock), z37.unknown().transform(() => [])]).default(() => [
|
|
4265
|
-
PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.timer }),
|
|
4266
|
-
PostPurchaseBlock.parse({ settings: {}, styles: {}, type: BlockType.callout_banner }),
|
|
4267
|
-
PostPurchaseBlock.parse({ type: BlockType.product_information })
|
|
4268
|
-
]),
|
|
4269
|
-
columnLayout: z37.boolean().optional(),
|
|
4270
|
-
discount: z37.object({
|
|
4271
|
-
amount: strictNumber.default(30),
|
|
4272
|
-
shouldShowSavingText: z37.boolean().optional().default(true),
|
|
4273
|
-
type: z37.enum(["none", "fixed_amount", "percentage"]).default("none")
|
|
4274
|
-
}),
|
|
4275
|
-
discountedFrom: z37.enum(["price", "compare_at_price"]).optional().default("price"),
|
|
4276
|
-
endpoint: z37.string().optional(),
|
|
4277
|
-
integrations: z37.object({
|
|
4278
|
-
judgeme: z37.boolean().default(false),
|
|
4279
|
-
junip: z37.boolean().optional().default(false),
|
|
4280
|
-
klaviyo: z37.boolean().default(false),
|
|
4281
|
-
loox: z37.boolean().default(false),
|
|
4282
|
-
okendo: z37.boolean().default(false),
|
|
4283
|
-
opinew: z37.boolean().optional().default(false),
|
|
4284
|
-
reviewsio: z37.boolean().optional().default(false),
|
|
4285
|
-
stamped: z37.boolean().default(false),
|
|
4286
|
-
yotpo: z37.boolean().default(false)
|
|
4287
|
-
}),
|
|
4288
|
-
key: z37.string().optional(),
|
|
4289
|
-
language: z37.object({
|
|
4290
|
-
description: z37.union([z37.string(), z37.unknown().transform(() => "")]).default(""),
|
|
4291
|
-
descriptionEnabled: z37.boolean().optional().default(false),
|
|
4292
|
-
descriptionRte: z37.object({
|
|
4293
|
-
content: z37.array(z37.unknown()),
|
|
4294
|
-
type: z37.string()
|
|
4295
|
-
}).optional(),
|
|
4296
|
-
descriptionSpacing: z37.enum(["none", "xtight", "tight", "default", "loose", "xloose"]).optional(),
|
|
4297
|
-
displayCtaPrice: z37.boolean().default(true),
|
|
4298
|
-
global: z37.object({
|
|
4299
|
-
declineAll: z37.string().optional().default("Decline All"),
|
|
4300
|
-
declineThisOffer: z37.string().default("Decline this offer"),
|
|
4301
|
-
free: z37.string().optional().default("Free"),
|
|
4302
|
-
notAvailable: z37.string().optional().default("Not available"),
|
|
4303
|
-
payNow: z37.string().default("Pay Now"),
|
|
4304
|
-
payNowUpgradeToSubscription: z37.string().optional().default("Upgrade to Subscription"),
|
|
4305
|
-
quantity: z37.string().default("Quantity"),
|
|
4306
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4307
|
-
recurringShipping: z37.string().optional().default("Recurring shipping"),
|
|
4308
|
-
recurringSubtotal: z37.string().default("Recurring subtotal"),
|
|
4309
|
-
reviewsPlural: z37.string().optional().default("Reviews"),
|
|
4310
|
-
reviewsSingular: z37.string().optional().default("Review"),
|
|
4311
|
-
save: z37.union([z37.string(), z37.unknown().transform(() => "Save")]).optional().default("Save"),
|
|
4312
|
-
shipping: z37.string().default("Shipping"),
|
|
4313
|
-
subscriptionOption: z37.string().optional().default("Subscribe and Save"),
|
|
4314
|
-
subtotal: z37.string().default("Subtotal"),
|
|
4315
|
-
taxes: z37.string().default("Taxes"),
|
|
4316
|
-
total: z37.string().default("Total")
|
|
4317
|
-
}).optional().default(() => ({
|
|
4318
|
-
declineAll: "Decline All",
|
|
4319
|
-
declineThisOffer: "Decline this offer",
|
|
4320
|
-
free: "Free",
|
|
4321
|
-
notAvailable: "Not available",
|
|
4322
|
-
payNow: "Pay Now",
|
|
4323
|
-
payNowUpgradeToSubscription: "Upgrade to Subscription",
|
|
4324
|
-
quantity: "Quantity",
|
|
4325
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4326
|
-
recurringShipping: "Recurring shipping",
|
|
4327
|
-
recurringSubtotal: "Recurring subtotal",
|
|
4328
|
-
reviewsPlural: "Reviews",
|
|
4329
|
-
reviewsSingular: "Review",
|
|
4330
|
-
save: "Save",
|
|
4331
|
-
shipping: "Shipping",
|
|
4332
|
-
subscriptionOption: "Subscribe and Save",
|
|
4333
|
-
subtotal: "Subtotal",
|
|
4334
|
-
taxes: "Taxes",
|
|
4335
|
-
total: "Total"
|
|
4336
|
-
})),
|
|
4337
|
-
globalTranslation: z37.string().optional().default("english")
|
|
4338
|
-
}),
|
|
4339
|
-
metafields: z37.boolean().default(false),
|
|
4340
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4341
|
-
offer: z37.object({
|
|
4342
|
-
count: z37.number().default(1)
|
|
4343
|
-
}),
|
|
4344
|
-
offersLayout: z37.object({
|
|
4345
|
-
itemsPerPage: z37.number().optional(),
|
|
4346
|
-
type: z37.enum(["list", "grid", "carousel"]).default("list")
|
|
4347
|
-
}).optional().default({
|
|
4348
|
-
type: "list"
|
|
4349
|
-
}),
|
|
4350
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4351
|
-
previewMode: z37.boolean().default(false),
|
|
4352
|
-
productLimit: z37.number().optional().default(1),
|
|
4353
|
-
productOptions: z37.object({
|
|
4354
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4355
|
-
hideOutOfStockVariants: z37.boolean().optional().default(false),
|
|
4356
|
-
matchVariant: z37.boolean().optional().default(true),
|
|
4357
|
-
showDeclineAll: z37.enum(["above", "below", "both", "none"]).optional(),
|
|
4358
|
-
showShipping: z37.boolean().optional().default(true),
|
|
4359
|
-
showSubtotal: z37.boolean().optional().default(true),
|
|
4360
|
-
showTaxes: z37.boolean().optional().default(true),
|
|
4361
|
-
showTotal: z37.boolean().optional().default(true),
|
|
4362
|
-
showVariantSelectors: z37.boolean().optional().default(true),
|
|
4363
|
-
variantSelectorDisplayMode: z37.enum(["separate", "single"]).optional().default("separate")
|
|
4364
|
-
}),
|
|
4365
|
-
productType: z37.union([z37.enum(["one-time", "subscription", "both"]), z37.literal("").transform(() => "one-time")]).default("one-time"),
|
|
4366
|
-
productTypeSelector: z37.enum(["dropdown", "radio"]).optional().default("radio"),
|
|
4367
|
-
quantityInputs: z37.object({
|
|
4368
|
-
defaultQuantity: z37.union([z37.number(), z37.null().transform(() => 1)]).default(1),
|
|
4369
|
-
enabled: z37.boolean().default(true),
|
|
4370
|
-
maxValue: z37.union([z37.number(), z37.null().transform(() => 15)]).default(15),
|
|
4371
|
-
minValue: z37.union([z37.number().min(0), z37.unknown().transform(() => 0)]).default(1)
|
|
4372
|
-
}),
|
|
4373
|
-
shipping: z37.object({
|
|
4374
|
-
amount: strictNumber.default(10),
|
|
4375
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4376
|
-
enabled: z37.boolean().default(true),
|
|
4377
|
-
title: z37.string().optional().default("Shipping Fees"),
|
|
4378
|
-
type: z37.enum(["free", "fixed_amount"]).default("free")
|
|
4379
|
-
}),
|
|
4380
|
-
styles: z37.object({
|
|
4381
|
-
starColor: z37.string().optional().default("#fadb14"),
|
|
4382
|
-
starSize: z37.union([z37.enum(["small", "medium", "large"]), z37.unknown().transform(() => "large")]).optional().default("large"),
|
|
4383
|
-
starStrokeColor: z37.string().optional().default("#fadb14"),
|
|
4384
|
-
strokeWidth: z37.string().optional().default("1")
|
|
4385
|
-
}).optional(),
|
|
4386
|
-
subImages: z37.number().nullish().default(8),
|
|
4387
|
-
subscription: z37.object({
|
|
4388
|
-
discount: z37.object({
|
|
4389
|
-
amount: strictNumber.default(30),
|
|
4390
|
-
shouldShowSavingText: z37.boolean().optional().default(true),
|
|
4391
|
-
type: z37.enum(["none", "fixed_amount", "percentage"]).default("none")
|
|
4392
|
-
}),
|
|
4393
|
-
shipping: z37.object({
|
|
4394
|
-
amount: strictNumber.default(1),
|
|
4395
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4396
|
-
enabled: z37.boolean().default(true),
|
|
4397
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4398
|
-
recurringAmount: strictNumber.default(2),
|
|
4399
|
-
shippingTitle: z37.string().default("Shipping Fees"),
|
|
4400
|
-
type: z37.enum(["free", "fixed_amount"]).default("free")
|
|
4401
|
-
})
|
|
4402
|
-
}).optional().default({
|
|
4403
|
-
discount: {
|
|
4404
|
-
amount: 30,
|
|
4405
|
-
shouldShowSavingText: true,
|
|
4406
|
-
type: "none"
|
|
4407
|
-
},
|
|
4408
|
-
shipping: {
|
|
4409
|
-
amount: 1,
|
|
4410
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4411
|
-
enabled: true,
|
|
4412
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4413
|
-
recurringAmount: 2,
|
|
4414
|
-
shippingTitle: "Shipping Fees",
|
|
4415
|
-
type: "free"
|
|
4416
|
-
}
|
|
4417
|
-
}),
|
|
4418
|
-
subscriptionIsDefault: z37.boolean().optional(),
|
|
4419
|
-
/** This isn't configurable in the admin-nextjs editor */
|
|
4420
|
-
template: z37.string().optional().default(""),
|
|
4421
|
-
type: z37.literal("shopify_post_purchase_extension").default("shopify_post_purchase_extension"),
|
|
4422
|
-
upgradeToSubscription: z37.object({
|
|
4423
|
-
acceptButtonText: z37.string().optional().default("Upgrade"),
|
|
4424
|
-
allow: z37.boolean().optional().default(false),
|
|
4425
|
-
emailRefundNotice: z37.boolean().optional().default(false),
|
|
4426
|
-
errorBannerText: z37.string().optional().default("This subscription cannot be added - limit one per order")
|
|
4427
|
-
}).optional().default(() => ({
|
|
4428
|
-
acceptButtonText: "Upgrade",
|
|
4429
|
-
allow: false,
|
|
4430
|
-
emailRefundNotice: false,
|
|
4431
|
-
errorBannerText: "This subscription cannot be added - limit one per order"
|
|
4432
|
-
}))
|
|
4573
|
+
});
|
|
4574
|
+
return CABLayoutSection.parse({ alignment: { horizontal }, sections });
|
|
4575
|
+
};
|
|
4576
|
+
|
|
4577
|
+
// src/transforms/postPurchase/imageContentSettings.ts
|
|
4578
|
+
import { z as z43 } from "zod";
|
|
4579
|
+
var ImageContentSettings = ImageContentBlock.shape.settings.pick({
|
|
4580
|
+
descriptionSize: true,
|
|
4581
|
+
horizontalAlignment: true,
|
|
4582
|
+
superTitleSize: true,
|
|
4583
|
+
swapContent: true,
|
|
4584
|
+
titleSize: true
|
|
4585
|
+
}).extend({
|
|
4586
|
+
alt: z43.unknown().optional(),
|
|
4587
|
+
description: z43.unknown().optional(),
|
|
4588
|
+
image: z43.unknown().optional(),
|
|
4589
|
+
imagePlacement: ImageContentBlock.shape.settings.shape.imagePlacement.unwrap().nullable(),
|
|
4590
|
+
imageSize: ImageContentBlock.shape.settings.shape.imageSize.pipe(z43.number().positive()),
|
|
4591
|
+
superTitle: z43.unknown().optional(),
|
|
4592
|
+
title: z43.unknown().optional()
|
|
4433
4593
|
});
|
|
4434
4594
|
|
|
4595
|
+
// src/transforms/postPurchase/convertImageContentBlock.ts
|
|
4596
|
+
var Shell2 = z44.object({ settings: ImageContentSettings, type: z44.literal("image_content") });
|
|
4597
|
+
var PROPORTIONAL_BREAK_AT = 500;
|
|
4598
|
+
var convertImageContentBlock = (raw, report) => {
|
|
4599
|
+
const shell = Shell2.safeParse(raw);
|
|
4600
|
+
if (!shell.success) {
|
|
4601
|
+
report?.({ detail: "Unreadable post-purchase image-content block", kind: "section" });
|
|
4602
|
+
return [];
|
|
4603
|
+
}
|
|
4604
|
+
const settings = shell.data.settings;
|
|
4605
|
+
const alt = typeof settings.alt === "string" ? settings.alt : void 0;
|
|
4606
|
+
if (settings.alt !== void 0 && alt === void 0) {
|
|
4607
|
+
report?.({ detail: "Unreadable post-purchase image-content alt text", kind: "section" });
|
|
4608
|
+
}
|
|
4609
|
+
const image = convertImageFrame({ alt, image: settings.image, imageSize: settings.imageSize });
|
|
4610
|
+
if (!image) report?.({ detail: "Unreadable post-purchase image-content image", kind: "section" });
|
|
4611
|
+
const text2 = convertImageContentText(settings, report);
|
|
4612
|
+
const textFrame = CABLayoutSection.parse({ direction: "grid", grid: { columns: ["100%"] }, sections: [text2] });
|
|
4613
|
+
const placement = settings.imagePlacement ?? (settings.swapContent ? "right" : "left");
|
|
4614
|
+
const imageFirst = placement === "left" || placement === "top";
|
|
4615
|
+
const sections = imageFirst ? [image, textFrame] : [textFrame, image];
|
|
4616
|
+
const ordered = sections.filter((section) => section !== null);
|
|
4617
|
+
const inner = placement === "left" || placement === "right" ? CABLayoutSection.parse({
|
|
4618
|
+
sections: ordered,
|
|
4619
|
+
spacing: "loose",
|
|
4620
|
+
wrapping: {
|
|
4621
|
+
breakAt: settings.imageSize <= 1 ? PROPORTIONAL_BREAK_AT : settings.imageSize,
|
|
4622
|
+
maxPerLine: 2
|
|
4623
|
+
}
|
|
4624
|
+
}) : CABLayoutSection.parse({
|
|
4625
|
+
direction: "grid",
|
|
4626
|
+
grid: { columns: ["100%"] },
|
|
4627
|
+
sections: [CABLayoutSection.parse({ sections: ordered })],
|
|
4628
|
+
width: 95
|
|
4629
|
+
});
|
|
4630
|
+
return [CABLayoutSection.parse({ frame: "offer-content", sections: [inner], spacing: "none" })];
|
|
4631
|
+
};
|
|
4632
|
+
|
|
4633
|
+
// src/transforms/postPurchase/productCardPay.ts
|
|
4634
|
+
import { mapValues } from "es-toolkit";
|
|
4635
|
+
var PAY_NOW = { en: "Pay Now" };
|
|
4636
|
+
var DECLINE_THIS_OFFER = { en: "Decline this offer" };
|
|
4637
|
+
var NOT_AVAILABLE_DEFAULTS = ["Not available"];
|
|
4638
|
+
var soldOutSlot = ({ language: language3 }) => labelSlot("soldOut", OFFER_LABELS.soldOut, language3.global.notAvailable, [], NOT_AVAILABLE_DEFAULTS);
|
|
4639
|
+
var productCardPay = (settings) => {
|
|
4640
|
+
const payNow = labelSlot("payNow", PAY_NOW, settings.language.global.payNow);
|
|
4641
|
+
const priced = settings.language.displayCtaPrice ? { ...payNow, content: mapValues(payNow.content, (label2) => `${label2} \xB7 {{total}}`) } : payNow;
|
|
4642
|
+
return [addToOrderButton("primary", [priced, soldOutSlot(settings)])];
|
|
4643
|
+
};
|
|
4644
|
+
var productCardDecline = ({ language: language3 }) => [
|
|
4645
|
+
{
|
|
4646
|
+
action: "declineOffer",
|
|
4647
|
+
buttonStyle: "secondary",
|
|
4648
|
+
sections: [labelSlot("declineOffer", DECLINE_THIS_OFFER, language3.global.declineThisOffer)],
|
|
4649
|
+
sectionType: "button"
|
|
4650
|
+
}
|
|
4651
|
+
];
|
|
4652
|
+
|
|
4435
4653
|
// src/transforms/postPurchase/productCardSettings.ts
|
|
4654
|
+
import { mapValues as mapValues2 } from "es-toolkit";
|
|
4655
|
+
import { z as z45 } from "zod";
|
|
4436
4656
|
var { shape } = PostPurchaseSettings;
|
|
4437
|
-
var Labels =
|
|
4657
|
+
var Labels = z45.object(
|
|
4438
4658
|
mapValues2(shape.language.shape.global.unwrap().unwrap().shape, (label2) => label2.catch(() => label2.parse(void 0)))
|
|
4439
4659
|
);
|
|
4440
|
-
var Language =
|
|
4660
|
+
var Language = z45.object({
|
|
4441
4661
|
displayCtaPrice: shape.language.shape.displayCtaPrice.catch(true),
|
|
4442
4662
|
global: Labels.catch(() => Labels.parse({}))
|
|
4443
4663
|
});
|
|
4444
|
-
var Fields =
|
|
4664
|
+
var Fields = z45.object({
|
|
4445
4665
|
discount: shape.discount.catch(() => shape.discount.parse({})),
|
|
4446
4666
|
language: Language.catch(() => Language.parse({})),
|
|
4447
4667
|
productOptions: shape.productOptions.catch(() => shape.productOptions.parse({})),
|
|
@@ -4725,7 +4945,7 @@ var convertSeparatorBlock = (raw, report) => {
|
|
|
4725
4945
|
};
|
|
4726
4946
|
|
|
4727
4947
|
// src/transforms/postPurchase/convertTextBlock.ts
|
|
4728
|
-
import { z as
|
|
4948
|
+
import { z as z46 } from "zod";
|
|
4729
4949
|
var fields3 = ["superTitle", "title", "description"];
|
|
4730
4950
|
var styles = {
|
|
4731
4951
|
description: [{ attrs: { color: "base", fontSize: "small" }, type: "textStyle" }],
|
|
@@ -4733,13 +4953,13 @@ var styles = {
|
|
|
4733
4953
|
title: [{ type: "bold" }, { attrs: { color: "base", fontSize: "large" }, type: "textStyle" }]
|
|
4734
4954
|
};
|
|
4735
4955
|
var settingsSchema = TextBlock.shape.settings;
|
|
4736
|
-
var Shell3 =
|
|
4956
|
+
var Shell3 = z46.object({
|
|
4737
4957
|
settings: settingsSchema.pick({ horizontalAlignment: true }).extend({
|
|
4738
|
-
description:
|
|
4739
|
-
superTitle:
|
|
4740
|
-
title:
|
|
4958
|
+
description: z46.unknown().optional(),
|
|
4959
|
+
superTitle: z46.unknown().optional(),
|
|
4960
|
+
title: z46.unknown().optional()
|
|
4741
4961
|
}),
|
|
4742
|
-
type:
|
|
4962
|
+
type: z46.literal("text")
|
|
4743
4963
|
});
|
|
4744
4964
|
var convertTextBlock = (raw, report) => {
|
|
4745
4965
|
const shell = Shell3.safeParse(raw);
|
|
@@ -4811,11 +5031,11 @@ var convertTimerBlock = (raw, report) => {
|
|
|
4811
5031
|
};
|
|
4812
5032
|
|
|
4813
5033
|
// src/transforms/postPurchase/convertMessagePreview.ts
|
|
4814
|
-
var MessageWidget =
|
|
4815
|
-
blocks:
|
|
4816
|
-
type:
|
|
5034
|
+
var MessageWidget = z47.object({
|
|
5035
|
+
blocks: z47.array(z47.unknown()).min(1),
|
|
5036
|
+
type: z47.literal(WidgetType.shopify_post_purchase_extension)
|
|
4817
5037
|
});
|
|
4818
|
-
var BlockType2 =
|
|
5038
|
+
var BlockType2 = z47.object({ type: z47.string() });
|
|
4819
5039
|
var converters = {
|
|
4820
5040
|
callout_banner: convertCalloutBlock,
|
|
4821
5041
|
image: convertImageBlock,
|
|
@@ -5327,6 +5547,12 @@ var reportUnreadableVerdict = (metadata, report) => {
|
|
|
5327
5547
|
if (RuleVerdict.safeParse(metadata).success || isDefinitiveRuleAnswer(metadata)) return;
|
|
5328
5548
|
report?.({ detail: "rule verdict lacks readable custom.shouldShow", kind: "ruleVerdict" });
|
|
5329
5549
|
};
|
|
5550
|
+
var withReviews = (product, integrations, report) => {
|
|
5551
|
+
const { reviews: engineReviews, ...rest } = product;
|
|
5552
|
+
const reviews = projectOfferProductReviews(integrations, product, report);
|
|
5553
|
+
if (reviews !== void 0) return { ...rest, reviews };
|
|
5554
|
+
return engineReviews === void 0 ? product : rest;
|
|
5555
|
+
};
|
|
5330
5556
|
var dedupeById = (products) => uniqBy2(products, (product) => product.id);
|
|
5331
5557
|
var MAX_REQUEST_LINE_BYTES = 32e3;
|
|
5332
5558
|
var requestLineBytes = (path, search) => new TextEncoder().encode(`GET ${path}?${search} HTTP/1.1`).length;
|
|
@@ -5353,7 +5579,9 @@ var fetchDataSourceResults = async (input, ctx) => {
|
|
|
5353
5579
|
if (input.limit === 0) reportUnreadableVerdict(metadata, ctx.reportDrift);
|
|
5354
5580
|
if (input.limit !== 0 && (upstream != null && (typeof upstream !== "object" || Array.isArray(upstream)) || raw.data != null && !Array.isArray(raw.data)))
|
|
5355
5581
|
ctx.reportDrift?.({ detail: "data-source products payload is not an array", kind: "dataSource" });
|
|
5356
|
-
const products = dedupeById(rawProducts.filter((product) => keepValidProduct(product, ctx.reportDrift)))
|
|
5582
|
+
const products = dedupeById(rawProducts.filter((product) => keepValidProduct(product, ctx.reportDrift))).map(
|
|
5583
|
+
(product) => withReviews(product, input.integrations, ctx.reportDrift)
|
|
5584
|
+
);
|
|
5357
5585
|
return {
|
|
5358
5586
|
metadata,
|
|
5359
5587
|
/** B2B sessions filter by the company-location catalog server-side (the client bypasses its market hide). */
|
|
@@ -5363,7 +5591,7 @@ var fetchDataSourceResults = async (input, ctx) => {
|
|
|
5363
5591
|
};
|
|
5364
5592
|
|
|
5365
5593
|
// src/server/adsEngine.ts
|
|
5366
|
-
import { z as
|
|
5594
|
+
import { z as z48 } from "zod";
|
|
5367
5595
|
var SUPPLY_KEY = { production: "AQF5RKLR", staging: "Z56LQ7PS" };
|
|
5368
5596
|
var OFFER_LIMIT = 4;
|
|
5369
5597
|
var SUPPORTED_COUNTRIES = /* @__PURE__ */ new Set(["US", "CA", "GB"]);
|
|
@@ -5376,30 +5604,30 @@ var transactionItems = (input) => (input.transactionItems?.map(({ id, priceCents
|
|
|
5376
5604
|
title,
|
|
5377
5605
|
type
|
|
5378
5606
|
})) ?? input.cart.items.map(({ productId: productId2, quantity: quantity3 }) => ({ id: productId2, quantity: quantity3 }))).slice(0, MAX_TRANSACTION_ITEMS);
|
|
5379
|
-
var AdsEngineOffer =
|
|
5607
|
+
var AdsEngineOffer = z48.object({
|
|
5380
5608
|
/** Pill-style value prop ("Get $45 Cashback"). Carried through the parse; the card does not render it yet (REB-24429 — pill design pending). */
|
|
5381
|
-
callout:
|
|
5382
|
-
click_url:
|
|
5383
|
-
cta:
|
|
5609
|
+
callout: z48.string().catch(""),
|
|
5610
|
+
click_url: z48.string(),
|
|
5611
|
+
cta: z48.string(),
|
|
5384
5612
|
/** `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'). */
|
|
5385
|
-
decline_cta:
|
|
5386
|
-
decline_url:
|
|
5387
|
-
description:
|
|
5613
|
+
decline_cta: z48.string().catch(""),
|
|
5614
|
+
decline_url: z48.string(),
|
|
5615
|
+
description: z48.string(),
|
|
5388
5616
|
/** Short legal disclosure (FDIC / auto-renewal / FTC-affiliation lines). Rendered subdued under the CTAs. */
|
|
5389
|
-
disclaimer:
|
|
5617
|
+
disclaimer: z48.string().catch(""),
|
|
5390
5618
|
/** Long legal text behind the disclosure toggle in the composed card (REB-24429). */
|
|
5391
|
-
extended_disclaimer:
|
|
5392
|
-
headline:
|
|
5393
|
-
id:
|
|
5619
|
+
extended_disclaimer: z48.string().catch(""),
|
|
5620
|
+
headline: z48.string(),
|
|
5621
|
+
id: z48.string(),
|
|
5394
5622
|
/** Advertiser-supplied image alt; the composed card falls back to the stripped headline when empty. */
|
|
5395
|
-
image_alt:
|
|
5396
|
-
image_url:
|
|
5623
|
+
image_alt: z48.string().catch(""),
|
|
5624
|
+
image_url: z48.string().optional(),
|
|
5397
5625
|
/** 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. */
|
|
5398
|
-
privacy_url:
|
|
5399
|
-
view_url:
|
|
5626
|
+
privacy_url: z48.string().optional().catch(void 0),
|
|
5627
|
+
view_url: z48.string()
|
|
5400
5628
|
});
|
|
5401
|
-
var AdsEngineResponse =
|
|
5402
|
-
offers:
|
|
5629
|
+
var AdsEngineResponse = z48.object({
|
|
5630
|
+
offers: z48.array(z48.unknown()).default([]).transform(
|
|
5403
5631
|
(offers) => offers.flatMap((offer) => {
|
|
5404
5632
|
const result = AdsEngineOffer.safeParse(offer);
|
|
5405
5633
|
return result.success ? [result.data] : [];
|
|
@@ -5411,8 +5639,8 @@ var AdsEngineResponse = z41.object({
|
|
|
5411
5639
|
* offers-testing fixture on a test store forces it, REB-24467). Both optional: an older engine or a
|
|
5412
5640
|
* non-JSON body must not fail the parse and drop the offers.
|
|
5413
5641
|
*/
|
|
5414
|
-
request_id:
|
|
5415
|
-
testing:
|
|
5642
|
+
request_id: z48.string().optional().catch(void 0),
|
|
5643
|
+
testing: z48.boolean().optional().catch(void 0)
|
|
5416
5644
|
});
|
|
5417
5645
|
var adsHost = (host) => `offers.${host}`;
|
|
5418
5646
|
var isTestingRequest = (input, isProduction) => !isProduction || !!input.testing || input.customerEmail?.toLowerCase() === TEST_CUSTOMER_EMAIL;
|
|
@@ -5728,7 +5956,6 @@ var fetchMonetizeOffers = async (input, ctx, prefetched) => {
|
|
|
5728
5956
|
|
|
5729
5957
|
// src/server/salvageSections.ts
|
|
5730
5958
|
import { v7 as uuidv714 } from "uuid";
|
|
5731
|
-
var STUB_SECTION_TYPE = "unknown";
|
|
5732
5959
|
var knownSectionTypes = new Set(sectionTypes);
|
|
5733
5960
|
var hasSectionsArray = (raw) => typeof raw === "object" && raw !== null && Array.isArray(raw.sections);
|
|
5734
5961
|
var stubSection = (raw, report) => {
|
|
@@ -5741,7 +5968,7 @@ var stubSection = (raw, report) => {
|
|
|
5741
5968
|
});
|
|
5742
5969
|
return {
|
|
5743
5970
|
sectionId: typeof rawId === "string" && rawId ? rawId : uuidv714(),
|
|
5744
|
-
sectionType: typeof original === "string" && !knownSectionTypes.has(original) ? original :
|
|
5971
|
+
sectionType: typeof original === "string" && !knownSectionTypes.has(original) ? original : SALVAGED_SECTION_TYPE
|
|
5745
5972
|
};
|
|
5746
5973
|
};
|
|
5747
5974
|
var salvageSection = (raw, report) => {
|
|
@@ -5884,13 +6111,13 @@ var convertWidgetSettings = async (input, ctx) => {
|
|
|
5884
6111
|
};
|
|
5885
6112
|
|
|
5886
6113
|
// src/server/giftWidgets.ts
|
|
5887
|
-
import { z as
|
|
5888
|
-
var SettingsNumber =
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
]).pipe(
|
|
5892
|
-
var SgwpMilestoneSchema =
|
|
5893
|
-
selectable_product_quantity: SettingsNumber.pipe(
|
|
6114
|
+
import { z as z49 } from "zod";
|
|
6115
|
+
var SettingsNumber = z49.union([
|
|
6116
|
+
z49.number(),
|
|
6117
|
+
z49.string().trim().regex(/^-?\d+(\.\d+)?$/)
|
|
6118
|
+
]).pipe(z49.coerce.number());
|
|
6119
|
+
var SgwpMilestoneSchema = z49.object({
|
|
6120
|
+
selectable_product_quantity: SettingsNumber.pipe(z49.number().int().nonnegative()),
|
|
5894
6121
|
unlock_price: SettingsNumber
|
|
5895
6122
|
});
|
|
5896
6123
|
var fetchGiftWidgetSettings = async (widgetId, shop, ctx) => unwrapData(await ctx.fetchUpstream("/api/v1/widgets/settings", { id: String(widgetId), shop }, { host: ctx.host }));
|
|
@@ -5901,7 +6128,7 @@ var readDataSourcePath = (settings) => {
|
|
|
5901
6128
|
var readMilestones = (settings, report) => {
|
|
5902
6129
|
const raw = settings && typeof settings === "object" ? settings.milestones : void 0;
|
|
5903
6130
|
if (raw == null) return [];
|
|
5904
|
-
const parsed =
|
|
6131
|
+
const parsed = z49.array(SgwpMilestoneSchema).safeParse(raw);
|
|
5905
6132
|
if (parsed.success) return parsed.data;
|
|
5906
6133
|
report?.({
|
|
5907
6134
|
detail: [
|
|
@@ -6016,16 +6243,16 @@ var validateGifts = async (input, ctx) => {
|
|
|
6016
6243
|
|
|
6017
6244
|
// src/server/normalizePostPurchaseProduct.ts
|
|
6018
6245
|
import { merge } from "es-toolkit/compat";
|
|
6019
|
-
import { z as
|
|
6246
|
+
import { z as z53 } from "zod";
|
|
6020
6247
|
|
|
6021
6248
|
// src/schema/postPurchaseProductSettings.ts
|
|
6022
|
-
import { z as
|
|
6249
|
+
import { z as z51 } from "zod";
|
|
6023
6250
|
|
|
6024
6251
|
// src/schema/postPurchaseProductSource.ts
|
|
6025
|
-
import { z as
|
|
6026
|
-
var PostPurchaseAmount =
|
|
6027
|
-
var PostPurchaseProductId =
|
|
6028
|
-
var PostPurchaseVariantId =
|
|
6252
|
+
import { z as z50 } from "zod";
|
|
6253
|
+
var PostPurchaseAmount = z50.string().regex(/^\d+(?:\.\d+)?$/).refine((value) => Number.isFinite(Number(value)));
|
|
6254
|
+
var PostPurchaseProductId = z50.number().int().positive();
|
|
6255
|
+
var PostPurchaseVariantId = z50.number().int().positive();
|
|
6029
6256
|
var ProductBase = OfferProduct.pick({ description: true, id: true, image: true, title: true }).extend({
|
|
6030
6257
|
description: OfferProduct.shape.description.nullable(),
|
|
6031
6258
|
id: PostPurchaseProductId
|
|
@@ -6033,51 +6260,51 @@ var ProductBase = OfferProduct.pick({ description: true, id: true, image: true,
|
|
|
6033
6260
|
var SourceVariant = OfferProduct.shape.variants.element.pick({ id: true, title: true }).extend({
|
|
6034
6261
|
compareAtPrice: PostPurchaseAmount.nullable(),
|
|
6035
6262
|
id: PostPurchaseVariantId,
|
|
6036
|
-
imageId:
|
|
6037
|
-
inventoryManagement:
|
|
6038
|
-
inventoryPolicy:
|
|
6039
|
-
inventoryQuantity:
|
|
6040
|
-
option1:
|
|
6041
|
-
option2:
|
|
6042
|
-
option3:
|
|
6263
|
+
imageId: z50.number().int().nonnegative().nullish(),
|
|
6264
|
+
inventoryManagement: z50.string().nullable(),
|
|
6265
|
+
inventoryPolicy: z50.string(),
|
|
6266
|
+
inventoryQuantity: z50.number(),
|
|
6267
|
+
option1: z50.unknown().optional(),
|
|
6268
|
+
option2: z50.unknown().optional(),
|
|
6269
|
+
option3: z50.unknown().optional(),
|
|
6043
6270
|
price: PostPurchaseAmount,
|
|
6044
6271
|
productId: PostPurchaseProductId,
|
|
6045
|
-
sellingPlanAllocations:
|
|
6272
|
+
sellingPlanAllocations: z50.unknown().optional()
|
|
6046
6273
|
});
|
|
6047
6274
|
var Product2 = ProductBase.extend({
|
|
6048
|
-
images:
|
|
6049
|
-
|
|
6275
|
+
images: z50.array(
|
|
6276
|
+
z50.object({ alt: z50.string().optional().catch(void 0), id: z50.number().int().positive(), src: z50.string() })
|
|
6050
6277
|
).nullish(),
|
|
6051
|
-
metadata:
|
|
6052
|
-
productQuantity:
|
|
6053
|
-
|
|
6054
|
-
|
|
6278
|
+
metadata: z50.object({
|
|
6279
|
+
productQuantity: z50.union([
|
|
6280
|
+
z50.number().int().positive(),
|
|
6281
|
+
z50.string().regex(/^[1-9]\d*$/).transform(Number)
|
|
6055
6282
|
]).optional()
|
|
6056
6283
|
}).optional(),
|
|
6057
|
-
metafields:
|
|
6058
|
-
options:
|
|
6059
|
-
productGroupVariants:
|
|
6284
|
+
metafields: z50.unknown().optional(),
|
|
6285
|
+
options: z50.unknown().optional(),
|
|
6286
|
+
productGroupVariants: z50.array(z50.unknown()).default([]),
|
|
6060
6287
|
// REB-25048: the v2 data source flags a subscription-only product here and sends no selling plan groups
|
|
6061
|
-
requiresSellingPlan:
|
|
6062
|
-
selectedVariant:
|
|
6063
|
-
sellingPlanGroups:
|
|
6288
|
+
requiresSellingPlan: z50.boolean().nullish(),
|
|
6289
|
+
selectedVariant: z50.unknown().optional(),
|
|
6290
|
+
sellingPlanGroups: z50.array(
|
|
6064
6291
|
OfferProduct.shape.sellingPlanGroups.unwrap().element.extend({
|
|
6065
|
-
discountAmount:
|
|
6066
|
-
discountType:
|
|
6067
|
-
id:
|
|
6068
|
-
requiresSellingPlan:
|
|
6069
|
-
sellingPlans:
|
|
6292
|
+
discountAmount: z50.unknown().optional(),
|
|
6293
|
+
discountType: z50.unknown().optional(),
|
|
6294
|
+
id: z50.unknown().optional(),
|
|
6295
|
+
requiresSellingPlan: z50.boolean().default(false),
|
|
6296
|
+
sellingPlans: z50.unknown().optional()
|
|
6070
6297
|
})
|
|
6071
6298
|
).default([]),
|
|
6072
|
-
variants:
|
|
6299
|
+
variants: z50.array(SourceVariant)
|
|
6073
6300
|
});
|
|
6074
|
-
var PostPurchaseProductSource =
|
|
6075
|
-
data:
|
|
6076
|
-
metadata:
|
|
6301
|
+
var PostPurchaseProductSource = z50.object({
|
|
6302
|
+
data: z50.array(Product2),
|
|
6303
|
+
metadata: z50.object({ widget: z50.record(z50.string(), z50.unknown()).default({}) }).default({ widget: {} })
|
|
6077
6304
|
});
|
|
6078
6305
|
|
|
6079
6306
|
// src/schema/postPurchaseProductSettings.ts
|
|
6080
|
-
var amount =
|
|
6307
|
+
var amount = z51.union([z51.number().nonnegative(), PostPurchaseAmount.transform(Number)]);
|
|
6081
6308
|
var PostPurchaseProductSettings = PostPurchaseSettings.pick({
|
|
6082
6309
|
discountedFrom: true,
|
|
6083
6310
|
language: true,
|
|
@@ -6089,18 +6316,18 @@ var PostPurchaseProductSettings = PostPurchaseSettings.pick({
|
|
|
6089
6316
|
subscriptionIsDefault: true,
|
|
6090
6317
|
upgradeToSubscription: true
|
|
6091
6318
|
}).extend({
|
|
6092
|
-
advance:
|
|
6093
|
-
blocks:
|
|
6319
|
+
advance: z51.unknown().default({}),
|
|
6320
|
+
blocks: z51.array(z51.unknown()).optional(),
|
|
6094
6321
|
discount: PostPurchaseSettings.shape.discount.extend({ amount: amount.default(30) }),
|
|
6095
|
-
integrations:
|
|
6322
|
+
integrations: z51.unknown().default({}),
|
|
6096
6323
|
shipping: PostPurchaseSettings.shape.shipping.extend({ amount: amount.default(10) }),
|
|
6097
|
-
styles:
|
|
6324
|
+
styles: z51.unknown().default({}),
|
|
6098
6325
|
subImages: PostPurchaseSettings.shape.subImages.catch(null),
|
|
6099
|
-
subscription:
|
|
6326
|
+
subscription: z51.unknown().default(PostPurchaseSettings.shape.subscription.parse(void 0))
|
|
6100
6327
|
});
|
|
6101
6328
|
|
|
6102
6329
|
// src/server/readPostPurchaseProductSource.ts
|
|
6103
|
-
import { z as
|
|
6330
|
+
import { z as z52 } from "zod";
|
|
6104
6331
|
|
|
6105
6332
|
// src/server/postPurchaseResponseDrift.ts
|
|
6106
6333
|
var heard = /* @__PURE__ */ new WeakMap();
|
|
@@ -6126,9 +6353,9 @@ var requiresOwnSellingPlan = (product) => product.requiresSellingPlan === true;
|
|
|
6126
6353
|
var requiresUnsuppliedSellingPlan = (product) => requiresOwnSellingPlan(product) && !product.sellingPlanGroups?.length;
|
|
6127
6354
|
|
|
6128
6355
|
// src/server/readPostPurchaseProductSource.ts
|
|
6129
|
-
var Envelope = PostPurchaseProductSource.extend({ data:
|
|
6356
|
+
var Envelope = PostPurchaseProductSource.extend({ data: z52.array(z52.unknown()) });
|
|
6130
6357
|
var Product3 = PostPurchaseProductSource.shape.data.element;
|
|
6131
|
-
var Identified =
|
|
6358
|
+
var Identified = z52.object({ id: PostPurchaseProductId });
|
|
6132
6359
|
var readPostPurchaseProductSource = (response, report) => {
|
|
6133
6360
|
const { data, metadata } = Envelope.parse(deepCamelCase(response));
|
|
6134
6361
|
const drift = [];
|
|
@@ -6163,9 +6390,9 @@ var normalizePostPurchaseSource = (settings, response, report) => {
|
|
|
6163
6390
|
const original = PostPurchaseProductSettings.parse(deepCamelCase(settings));
|
|
6164
6391
|
const { dropped, metadata, products } = readPostPurchaseProductSource(response, report);
|
|
6165
6392
|
const overrides = Object.fromEntries(Object.entries(metadata.widget).filter(([key]) => key in original));
|
|
6166
|
-
const discount =
|
|
6393
|
+
const discount = z53.object({ type: z53.string() }).safeParse(overrides.discount);
|
|
6167
6394
|
if (discount.success && discount.data.type === "fixed") {
|
|
6168
|
-
overrides.discount = { ...
|
|
6395
|
+
overrides.discount = { ...z53.record(z53.string(), z53.unknown()).parse(overrides.discount), type: "fixed_amount" };
|
|
6169
6396
|
}
|
|
6170
6397
|
const effective = PostPurchaseProductSettings.parse(merge({}, original, overrides));
|
|
6171
6398
|
const data = products.map(({ product }) => product);
|
|
@@ -6202,52 +6429,52 @@ var postPurchasePlanDiscountPercentage = (price, adjustment) => {
|
|
|
6202
6429
|
};
|
|
6203
6430
|
|
|
6204
6431
|
// src/schema/postPurchasePlanCatalog.ts
|
|
6205
|
-
import { z as
|
|
6432
|
+
import { z as z56 } from "zod";
|
|
6206
6433
|
|
|
6207
6434
|
// src/schema/postPurchasePlanAdjustment.ts
|
|
6208
|
-
import { z as
|
|
6435
|
+
import { z as z55 } from "zod";
|
|
6209
6436
|
|
|
6210
6437
|
// src/schema/postPurchaseDiscount.ts
|
|
6211
|
-
import { z as
|
|
6212
|
-
var Discount =
|
|
6213
|
-
amount:
|
|
6214
|
-
title:
|
|
6215
|
-
type:
|
|
6438
|
+
import { z as z54 } from "zod";
|
|
6439
|
+
var Discount = z54.object({
|
|
6440
|
+
amount: z54.number().nonnegative(),
|
|
6441
|
+
title: z54.string(),
|
|
6442
|
+
type: z54.enum(["none", "fixed_amount", "percentage"])
|
|
6216
6443
|
});
|
|
6217
6444
|
var validPostPurchaseDiscount = (discount) => discount.type !== "percentage" || discount.amount <= 100;
|
|
6218
6445
|
var PostPurchaseDiscount = Discount.refine(validPostPurchaseDiscount);
|
|
6219
6446
|
|
|
6220
6447
|
// src/schema/postPurchasePlanAdjustment.ts
|
|
6221
|
-
var PostPurchasePlanAdjustment =
|
|
6448
|
+
var PostPurchasePlanAdjustment = z55.object({
|
|
6222
6449
|
amount: PostPurchaseDiscount.shape.amount,
|
|
6223
|
-
type:
|
|
6450
|
+
type: z55.enum(["percentage", "fixed_amount", "price"])
|
|
6224
6451
|
}).refine(({ amount: amount2, type }) => type === "price" || validPostPurchaseDiscount({ amount: amount2, type }));
|
|
6225
6452
|
|
|
6226
6453
|
// src/schema/postPurchasePlanCatalog.ts
|
|
6227
|
-
var PostPurchasePlanOption =
|
|
6454
|
+
var PostPurchasePlanOption = z56.object({
|
|
6228
6455
|
adjustment: PostPurchasePlanAdjustment.optional(),
|
|
6229
6456
|
/** cab-checkout's `discountPercentage`: the plan's own whole-percent saving on the regular price (`{{subscriptionDiscount}}`). */
|
|
6230
|
-
discountPercentage:
|
|
6231
|
-
id:
|
|
6232
|
-
intervalFrequency:
|
|
6233
|
-
intervalLabel:
|
|
6234
|
-
name:
|
|
6457
|
+
discountPercentage: z56.number().int().min(0).max(100).optional(),
|
|
6458
|
+
id: z56.number().int().positive(),
|
|
6459
|
+
intervalFrequency: z56.string().regex(/^[1-9]\d*$/).optional(),
|
|
6460
|
+
intervalLabel: z56.string().min(1),
|
|
6461
|
+
name: z56.string().min(1)
|
|
6235
6462
|
});
|
|
6236
|
-
var PostPurchasePlanCatalog =
|
|
6237
|
-
plans:
|
|
6238
|
-
productId:
|
|
6239
|
-
requiresSellingPlan:
|
|
6240
|
-
variantId:
|
|
6463
|
+
var PostPurchasePlanCatalog = z56.object({
|
|
6464
|
+
plans: z56.array(PostPurchasePlanOption),
|
|
6465
|
+
productId: z56.number().int().positive(),
|
|
6466
|
+
requiresSellingPlan: z56.boolean(),
|
|
6467
|
+
variantId: z56.number().int().positive()
|
|
6241
6468
|
});
|
|
6242
6469
|
|
|
6243
6470
|
// src/server/postPurchaseLegacyPlans.ts
|
|
6244
|
-
import { z as
|
|
6471
|
+
import { z as z58 } from "zod";
|
|
6245
6472
|
|
|
6246
6473
|
// src/server/postPurchasePlanAdjustment.ts
|
|
6247
|
-
import { z as
|
|
6248
|
-
var SourceAdjustment =
|
|
6474
|
+
import { z as z57 } from "zod";
|
|
6475
|
+
var SourceAdjustment = z57.object({
|
|
6249
6476
|
amount: PostPurchaseProductSettings.shape.discount.shape.amount.unwrap(),
|
|
6250
|
-
type:
|
|
6477
|
+
type: z57.enum(["percentage", "fixed_amount", "amount", "price", "none", "fixed"])
|
|
6251
6478
|
});
|
|
6252
6479
|
var readPostPurchasePlanAdjustment = (raw) => {
|
|
6253
6480
|
const source2 = SourceAdjustment.parse(raw);
|
|
@@ -6266,13 +6493,13 @@ var readPostPurchasePlanAdjustment = (raw) => {
|
|
|
6266
6493
|
var Plan = PostPurchasePlanOption.pick({ id: true, name: true }).extend({
|
|
6267
6494
|
orderIntervalFrequency: PostPurchasePlanOption.shape.intervalFrequency.unwrap(),
|
|
6268
6495
|
orderIntervalUnitType: PostPurchasePlanOption.shape.intervalLabel,
|
|
6269
|
-
shopifyVariantId:
|
|
6496
|
+
shopifyVariantId: z58.string().regex(/^[1-9]\d*$/).nullish()
|
|
6270
6497
|
});
|
|
6271
|
-
var Group =
|
|
6272
|
-
discountAmount:
|
|
6273
|
-
discountType:
|
|
6274
|
-
id:
|
|
6275
|
-
sellingPlans:
|
|
6498
|
+
var Group = z58.object({
|
|
6499
|
+
discountAmount: z58.unknown(),
|
|
6500
|
+
discountType: z58.unknown(),
|
|
6501
|
+
id: z58.number().int().positive(),
|
|
6502
|
+
sellingPlans: z58.array(z58.object({ shopifyVariantId: Plan.shape.shopifyVariantId }).passthrough())
|
|
6276
6503
|
});
|
|
6277
6504
|
var readPostPurchaseLegacyPlans = (raw, variantId) => {
|
|
6278
6505
|
const group = Group.pick({ id: true, sellingPlans: true }).parse(raw);
|
|
@@ -6293,22 +6520,22 @@ var readPostPurchaseLegacyPlans = (raw, variantId) => {
|
|
|
6293
6520
|
};
|
|
6294
6521
|
|
|
6295
6522
|
// src/server/postPurchaseModernPlans.ts
|
|
6296
|
-
import { z as
|
|
6297
|
-
var Groups =
|
|
6298
|
-
|
|
6299
|
-
id:
|
|
6300
|
-
sellingPlans:
|
|
6523
|
+
import { z as z59 } from "zod";
|
|
6524
|
+
var Groups = z59.array(
|
|
6525
|
+
z59.object({
|
|
6526
|
+
id: z59.string().min(1),
|
|
6527
|
+
sellingPlans: z59.unknown()
|
|
6301
6528
|
})
|
|
6302
6529
|
);
|
|
6303
|
-
var PostPurchasePlanAllocations =
|
|
6530
|
+
var PostPurchasePlanAllocations = z59.array(z59.object({ sellingPlanGroupId: z59.string().min(1) }));
|
|
6304
6531
|
var Allocations = PostPurchasePlanAllocations.default([]);
|
|
6305
|
-
var Plans =
|
|
6532
|
+
var Plans = z59.array(
|
|
6306
6533
|
PostPurchasePlanOption.pick({ id: true, name: true }).extend({
|
|
6307
|
-
options:
|
|
6308
|
-
priceAdjustments:
|
|
6534
|
+
options: z59.array(z59.object({ value: z59.string().min(1) })).min(1),
|
|
6535
|
+
priceAdjustments: z59.array(z59.unknown())
|
|
6309
6536
|
})
|
|
6310
6537
|
);
|
|
6311
|
-
var FirstAdjustment =
|
|
6538
|
+
var FirstAdjustment = z59.object({
|
|
6312
6539
|
value: PostPurchaseProductSettings.shape.discount.shape.amount.unwrap(),
|
|
6313
6540
|
valueType: PostPurchasePlanAdjustment.shape.type
|
|
6314
6541
|
});
|
|
@@ -6366,72 +6593,45 @@ var projectPostPurchasePlanCatalog = (normalized, report) => {
|
|
|
6366
6593
|
};
|
|
6367
6594
|
|
|
6368
6595
|
// src/schema/postPurchaseSubscriptionProduct.ts
|
|
6369
|
-
import { z as
|
|
6596
|
+
import { z as z64 } from "zod";
|
|
6370
6597
|
|
|
6371
6598
|
// src/schema/postPurchaseProduct.ts
|
|
6372
|
-
import { z as
|
|
6599
|
+
import { z as z63 } from "zod";
|
|
6373
6600
|
|
|
6374
6601
|
// src/schema/postPurchaseProductDisplay.ts
|
|
6375
|
-
import { z as
|
|
6602
|
+
import { z as z61 } from "zod";
|
|
6376
6603
|
|
|
6377
6604
|
// src/schema/postPurchaseProductGallery.ts
|
|
6378
|
-
import { z as
|
|
6379
|
-
var PostPurchaseProductGallery =
|
|
6605
|
+
import { z as z60 } from "zod";
|
|
6606
|
+
var PostPurchaseProductGallery = z60.object({
|
|
6380
6607
|
/**
|
|
6381
6608
|
* Show the thumbnail row: the product had more than one image before `images` was capped at the
|
|
6382
6609
|
* sub-image limit, and that limit allows at least one thumbnail. It stays true when the cap leaves one
|
|
6383
6610
|
* image (legacy checks the count before slicing). Older replies omit it; fall back to `images.length > 1`.
|
|
6384
6611
|
*/
|
|
6385
|
-
hasMultiple:
|
|
6386
|
-
images:
|
|
6387
|
-
|
|
6388
|
-
description:
|
|
6389
|
-
id:
|
|
6390
|
-
source:
|
|
6391
|
-
thumbnail:
|
|
6612
|
+
hasMultiple: z60.boolean().optional(),
|
|
6613
|
+
images: z60.array(
|
|
6614
|
+
z60.object({
|
|
6615
|
+
description: z60.string(),
|
|
6616
|
+
id: z60.number().int().positive(),
|
|
6617
|
+
source: z60.string(),
|
|
6618
|
+
thumbnail: z60.string()
|
|
6392
6619
|
})
|
|
6393
6620
|
),
|
|
6394
|
-
selectedImageId:
|
|
6395
|
-
});
|
|
6396
|
-
|
|
6397
|
-
// src/schema/postPurchaseProductReviews.ts
|
|
6398
|
-
import { z as z54 } from "zod";
|
|
6399
|
-
var decimal = z54.union([
|
|
6400
|
-
z54.number(),
|
|
6401
|
-
z54.string().regex(/^\d+(?:\.\d+)?$/).transform(Number)
|
|
6402
|
-
]);
|
|
6403
|
-
var PostPurchaseCommonReviewRating = z54.object({ value: decimal.pipe(z54.number().min(0).max(5)) });
|
|
6404
|
-
var PostPurchaseKlaviyoReviewRating = PostPurchaseCommonReviewRating.extend({
|
|
6405
|
-
// Legacy validates key presence, then displays the raw value on five stars without rescaling.
|
|
6406
|
-
scale_max: z54.unknown().nonoptional(),
|
|
6407
|
-
scale_min: z54.unknown().nonoptional()
|
|
6408
|
-
});
|
|
6409
|
-
var PostPurchaseReviewCount = z54.string().regex(/^\d+(?:\.\d+)?$/).transform(Number).pipe(z54.number().int().nonnegative());
|
|
6410
|
-
var PostPurchaseReviewStyles = PostPurchaseSettings.shape.styles.unwrap().extend({
|
|
6411
|
-
strokeWidth: decimal.pipe(z54.number().nonnegative()).default(1)
|
|
6412
|
-
}).prefault({});
|
|
6413
|
-
var PostPurchaseProductReviews = z54.object({
|
|
6414
|
-
color: z54.string(),
|
|
6415
|
-
rating: z54.number().positive().max(5),
|
|
6416
|
-
reviewCount: z54.number().int().nonnegative(),
|
|
6417
|
-
reviewsPlural: z54.string(),
|
|
6418
|
-
reviewsSingular: z54.string(),
|
|
6419
|
-
size: z54.enum(["small", "medium", "large"]),
|
|
6420
|
-
strokeColor: z54.string(),
|
|
6421
|
-
strokeWidth: z54.number().nonnegative()
|
|
6621
|
+
selectedImageId: z60.number().int().positive().optional()
|
|
6422
6622
|
});
|
|
6423
6623
|
|
|
6424
6624
|
// src/schema/postPurchaseProductDisplay.ts
|
|
6425
6625
|
var language = PostPurchaseSettings.shape.language;
|
|
6426
|
-
var PostPurchasePrimaryImageSource =
|
|
6626
|
+
var PostPurchasePrimaryImageSource = z61.string().default(
|
|
6427
6627
|
"https://cdn.shopify.com/shopifycloud/shopify/assets/no-image-2048-5e88c1b20e087fb7bbe9a3771824e743c244f437e4f8ba93bbf7b11b53f7824c.gif"
|
|
6428
6628
|
);
|
|
6429
|
-
var PostPurchaseProductDisplay =
|
|
6629
|
+
var PostPurchaseProductDisplay = z61.object({
|
|
6430
6630
|
descriptionDocument: TiptapDocument.optional(),
|
|
6431
6631
|
discountedFrom: PostPurchaseSettings.shape.discountedFrom,
|
|
6432
6632
|
gallery: PostPurchaseProductGallery.optional(),
|
|
6433
6633
|
language: language.pick({ description: true, descriptionEnabled: true }),
|
|
6434
|
-
primaryImage:
|
|
6634
|
+
primaryImage: z61.object({ description: z61.string(), source: z61.string() }),
|
|
6435
6635
|
productOptions: PostPurchaseSettings.shape.productOptions.pick({
|
|
6436
6636
|
showDeclineAll: true,
|
|
6437
6637
|
showShipping: true,
|
|
@@ -6446,16 +6646,16 @@ var PostPurchaseProductDisplay = z55.object({
|
|
|
6446
6646
|
});
|
|
6447
6647
|
|
|
6448
6648
|
// src/schema/postPurchaseSubscription.ts
|
|
6449
|
-
import { z as
|
|
6450
|
-
var PostPurchaseSubscriptionTerms =
|
|
6649
|
+
import { z as z62 } from "zod";
|
|
6650
|
+
var PostPurchaseSubscriptionTerms = z62.object({
|
|
6451
6651
|
adjustment: PostPurchasePlanAdjustment.optional(),
|
|
6452
|
-
initialShippingPrice:
|
|
6453
|
-
intervalLabel:
|
|
6454
|
-
name:
|
|
6455
|
-
recurringShippingPrice:
|
|
6456
|
-
shippingOption:
|
|
6652
|
+
initialShippingPrice: z62.number().nonnegative(),
|
|
6653
|
+
intervalLabel: z62.string().min(1),
|
|
6654
|
+
name: z62.string().min(1),
|
|
6655
|
+
recurringShippingPrice: z62.number().nonnegative(),
|
|
6656
|
+
shippingOption: z62.object({ presentmentTitle: z62.string(), title: z62.string() }),
|
|
6457
6657
|
/** A switch to subscription (STS): the one subscription that charges no initial shipping (L122). */
|
|
6458
|
-
sts:
|
|
6658
|
+
sts: z62.literal(true).optional()
|
|
6459
6659
|
});
|
|
6460
6660
|
|
|
6461
6661
|
// src/schema/postPurchaseProduct.ts
|
|
@@ -6465,52 +6665,52 @@ var PostPurchaseVariant = OfferProduct.shape.variants.element.pick({ id: true, t
|
|
|
6465
6665
|
id: PostPurchaseVariantId,
|
|
6466
6666
|
price: PostPurchaseAmount
|
|
6467
6667
|
});
|
|
6468
|
-
var PreparedPostPurchaseProduct =
|
|
6668
|
+
var PreparedPostPurchaseProduct = z63.object({
|
|
6469
6669
|
display: PostPurchaseProductDisplay,
|
|
6470
|
-
labels:
|
|
6670
|
+
labels: z63.object({
|
|
6471
6671
|
declineAll: global.declineAll,
|
|
6472
|
-
free:
|
|
6672
|
+
free: z63.string(),
|
|
6473
6673
|
notAvailable: global.notAvailable,
|
|
6474
|
-
payNow:
|
|
6475
|
-
quantity:
|
|
6674
|
+
payNow: z63.string(),
|
|
6675
|
+
quantity: z63.string(),
|
|
6476
6676
|
recurringShipping: global.recurringShipping,
|
|
6477
6677
|
recurringSubtotal: global.recurringSubtotal,
|
|
6478
|
-
save:
|
|
6479
|
-
shipping:
|
|
6480
|
-
subtotal:
|
|
6481
|
-
taxes:
|
|
6482
|
-
total:
|
|
6678
|
+
save: z63.string(),
|
|
6679
|
+
shipping: z63.string(),
|
|
6680
|
+
subtotal: z63.string(),
|
|
6681
|
+
taxes: z63.string(),
|
|
6682
|
+
total: z63.string()
|
|
6483
6683
|
}),
|
|
6484
6684
|
product: OfferProduct.pick({ description: true, id: true, image: true, title: true }).extend({
|
|
6485
6685
|
description: OfferProduct.shape.description.nullable(),
|
|
6486
6686
|
id: PostPurchaseProductId,
|
|
6487
6687
|
variant: PostPurchaseVariant
|
|
6488
6688
|
}),
|
|
6489
|
-
selection:
|
|
6689
|
+
selection: z63.object({
|
|
6490
6690
|
productId: PostPurchaseProductId,
|
|
6491
|
-
quantity:
|
|
6492
|
-
sellingPlanId:
|
|
6691
|
+
quantity: z63.number().int().positive(),
|
|
6692
|
+
sellingPlanId: z63.number().int().positive().optional(),
|
|
6493
6693
|
variantId: PostPurchaseVariantId
|
|
6494
6694
|
}),
|
|
6495
|
-
status:
|
|
6496
|
-
terms:
|
|
6695
|
+
status: z63.literal("prepared"),
|
|
6696
|
+
terms: z63.object({
|
|
6497
6697
|
discount: PostPurchaseDiscount,
|
|
6498
|
-
shipping:
|
|
6499
|
-
amount:
|
|
6500
|
-
title:
|
|
6501
|
-
type:
|
|
6698
|
+
shipping: z63.object({
|
|
6699
|
+
amount: z63.number().nonnegative(),
|
|
6700
|
+
title: z63.string(),
|
|
6701
|
+
type: z63.enum(["free", "fixed_amount"])
|
|
6502
6702
|
}),
|
|
6503
6703
|
subscription: PostPurchaseSubscriptionTerms.optional()
|
|
6504
6704
|
})
|
|
6505
6705
|
});
|
|
6506
|
-
var PostPurchasePreparation =
|
|
6706
|
+
var PostPurchasePreparation = z63.discriminatedUnion("status", [
|
|
6507
6707
|
PreparedPostPurchaseProduct,
|
|
6508
|
-
|
|
6708
|
+
z63.object({ reason: z63.string(), status: z63.literal("unsupported") })
|
|
6509
6709
|
]);
|
|
6510
6710
|
|
|
6511
6711
|
// src/schema/postPurchaseSubscriptionProduct.ts
|
|
6512
6712
|
var PreparedPostPurchaseSubscription = PreparedPostPurchaseProduct.extend({
|
|
6513
|
-
selection: PreparedPostPurchaseProduct.shape.selection.extend({ sellingPlanId:
|
|
6713
|
+
selection: PreparedPostPurchaseProduct.shape.selection.extend({ sellingPlanId: z64.number().int().positive() }),
|
|
6514
6714
|
terms: PreparedPostPurchaseProduct.shape.terms.extend({
|
|
6515
6715
|
subscription: PostPurchaseSubscriptionTerms
|
|
6516
6716
|
}).refine(
|
|
@@ -6570,7 +6770,7 @@ var subscriptionUnavailable = (normalized, plan, allowCollection, quantity3) =>
|
|
|
6570
6770
|
};
|
|
6571
6771
|
|
|
6572
6772
|
// src/server/postPurchaseProductDisplay.ts
|
|
6573
|
-
import { z as
|
|
6773
|
+
import { z as z66 } from "zod";
|
|
6574
6774
|
|
|
6575
6775
|
// src/server/postPurchasePrimaryImage.ts
|
|
6576
6776
|
var postPurchasePrimaryImage = (product) => {
|
|
@@ -6596,7 +6796,7 @@ var postPurchaseProductGallery = (product, limit) => {
|
|
|
6596
6796
|
};
|
|
6597
6797
|
|
|
6598
6798
|
// src/transforms/postPurchase/convertDescriptionRte.ts
|
|
6599
|
-
import { z as
|
|
6799
|
+
import { z as z65 } from "zod";
|
|
6600
6800
|
var alignments = { center: "center", left: "start", right: "end" };
|
|
6601
6801
|
var colors = ["critical", "subdued", "success", "warning"];
|
|
6602
6802
|
var sizes2 = ["extraSmall", "small", "medium", "large", "extraLarge"];
|
|
@@ -6608,19 +6808,19 @@ var spacings2 = {
|
|
|
6608
6808
|
xloose: "extraLoose",
|
|
6609
6809
|
xtight: "extraTight"
|
|
6610
6810
|
};
|
|
6611
|
-
var Block =
|
|
6612
|
-
attrs:
|
|
6613
|
-
content:
|
|
6614
|
-
type:
|
|
6615
|
-
});
|
|
6616
|
-
var Run =
|
|
6617
|
-
var Inline =
|
|
6618
|
-
attrs:
|
|
6619
|
-
color:
|
|
6620
|
-
emphasis:
|
|
6621
|
-
size:
|
|
6811
|
+
var Block = z65.object({
|
|
6812
|
+
attrs: z65.object({ alignment: z65.enum(["left", "center", "right"]).optional().catch(void 0) }).catch({}),
|
|
6813
|
+
content: z65.array(z65.unknown()).catch([]),
|
|
6814
|
+
type: z65.literal("ShopifyTextBlock")
|
|
6815
|
+
});
|
|
6816
|
+
var Run = z65.object({ marks: z65.array(z65.unknown()).catch([]), text: z65.string().min(1), type: z65.literal("text") });
|
|
6817
|
+
var Inline = z65.object({
|
|
6818
|
+
attrs: z65.object({
|
|
6819
|
+
color: z65.enum(colors).optional().catch(void 0),
|
|
6820
|
+
emphasis: z65.array(z65.unknown()).catch([]),
|
|
6821
|
+
size: z65.enum(sizes2).optional().catch(void 0)
|
|
6622
6822
|
}),
|
|
6623
|
-
type:
|
|
6823
|
+
type: z65.literal("ShopifyTextInline")
|
|
6624
6824
|
});
|
|
6625
6825
|
var marks = (raw) => {
|
|
6626
6826
|
const found = raw.map((mark) => Inline.safeParse(mark)).find(({ success }) => success)?.data;
|
|
@@ -6653,7 +6853,7 @@ var convertDescriptionRte = (rte, spacing) => TiptapDocument.parse({
|
|
|
6653
6853
|
});
|
|
6654
6854
|
|
|
6655
6855
|
// src/server/postPurchaseProductDisplay.ts
|
|
6656
|
-
var ResponseLanguage =
|
|
6856
|
+
var ResponseLanguage = z66.object({ description: PostPurchaseProductDisplay.shape.responseDescription }).default({ description: "" });
|
|
6657
6857
|
var projectPostPurchaseProductDisplay = (effective, metadata, product) => PostPurchaseProductDisplay.parse({
|
|
6658
6858
|
descriptionDocument: effective.language.descriptionRte && convertDescriptionRte(effective.language.descriptionRte, effective.language.descriptionSpacing),
|
|
6659
6859
|
discountedFrom: effective.discountedFrom,
|
|
@@ -6665,146 +6865,6 @@ var projectPostPurchaseProductDisplay = (effective, metadata, product) => PostPu
|
|
|
6665
6865
|
shouldShowSavingText: effective.discount.shouldShowSavingText
|
|
6666
6866
|
});
|
|
6667
6867
|
|
|
6668
|
-
// src/server/postPurchaseReviewData.ts
|
|
6669
|
-
import { z as z65 } from "zod";
|
|
6670
|
-
|
|
6671
|
-
// src/server/postPurchaseJudgeMeReviews.ts
|
|
6672
|
-
import { z as z62 } from "zod";
|
|
6673
|
-
|
|
6674
|
-
// src/server/postPurchaseReviewFields.ts
|
|
6675
|
-
import { z as z61 } from "zod";
|
|
6676
|
-
var Field = z61.object({ key: z61.string(), namespace: z61.string(), value: z61.unknown().optional() });
|
|
6677
|
-
var reviewFields = (raw) => {
|
|
6678
|
-
const fields4 = z61.array(z61.unknown()).parse(raw).flatMap((field) => {
|
|
6679
|
-
const parsed = Field.safeParse(field);
|
|
6680
|
-
return parsed.success ? [parsed.data] : [];
|
|
6681
|
-
});
|
|
6682
|
-
return (namespace, key) => fields4.find((field) => field.namespace === namespace && field.key === key);
|
|
6683
|
-
};
|
|
6684
|
-
var ReviewFieldError = class extends Error {
|
|
6685
|
-
constructor(field) {
|
|
6686
|
-
super(`Unreadable review field ${field}`);
|
|
6687
|
-
this.field = field;
|
|
6688
|
-
}
|
|
6689
|
-
};
|
|
6690
|
-
var readReviewField = (field, read) => {
|
|
6691
|
-
try {
|
|
6692
|
-
return read(field.value);
|
|
6693
|
-
} catch {
|
|
6694
|
-
throw new ReviewFieldError(`${field.namespace}.${field.key}`);
|
|
6695
|
-
}
|
|
6696
|
-
};
|
|
6697
|
-
|
|
6698
|
-
// src/server/postPurchaseJudgeMeReviews.ts
|
|
6699
|
-
var readJudgeMeReviews = (find) => {
|
|
6700
|
-
const field = find("judgeme", "badge");
|
|
6701
|
-
if (!field) return null;
|
|
6702
|
-
return readReviewField(field, (value) => {
|
|
6703
|
-
const html = z62.string().parse(value);
|
|
6704
|
-
const rating = html.match(/data-average-rating=['"](\d+(?:\.\d+)?)['"]/);
|
|
6705
|
-
const count = html.match(/data-number-of-reviews=['"](\d+)['"]/);
|
|
6706
|
-
if (!rating || !count) throw new Error("Unreadable Judge.me attributes");
|
|
6707
|
-
return {
|
|
6708
|
-
rating: PostPurchaseCommonReviewRating.parse({ value: rating[1] }).value,
|
|
6709
|
-
reviewCount: PostPurchaseReviewCount.parse(count[1])
|
|
6710
|
-
};
|
|
6711
|
-
});
|
|
6712
|
-
};
|
|
6713
|
-
|
|
6714
|
-
// src/server/postPurchaseOkendoReviews.ts
|
|
6715
|
-
import { z as z63 } from "zod";
|
|
6716
|
-
var Summary = z63.object({
|
|
6717
|
-
reviewAverageValue: PostPurchaseCommonReviewRating.shape.value,
|
|
6718
|
-
reviewCount: z63.union([PostPurchaseProductReviews.shape.reviewCount, PostPurchaseReviewCount])
|
|
6719
|
-
});
|
|
6720
|
-
var readOkendoReviews = (find) => {
|
|
6721
|
-
const field = find("okendo", "summaryData");
|
|
6722
|
-
if (!field) return null;
|
|
6723
|
-
const summary = readReviewField(field, (value) => Summary.parse(JSON.parse(z63.string().parse(value))));
|
|
6724
|
-
return { rating: summary.reviewAverageValue, reviewCount: summary.reviewCount };
|
|
6725
|
-
};
|
|
6726
|
-
|
|
6727
|
-
// src/server/postPurchaseScalarReviews.ts
|
|
6728
|
-
import { z as z64 } from "zod";
|
|
6729
|
-
var readScalarReviews = (find, namespace, ratingKey, countKey) => {
|
|
6730
|
-
const rating = find(namespace, ratingKey);
|
|
6731
|
-
const count = find(namespace, countKey);
|
|
6732
|
-
if (!rating || !count) return null;
|
|
6733
|
-
return {
|
|
6734
|
-
rating: readReviewField(
|
|
6735
|
-
rating,
|
|
6736
|
-
(value) => PostPurchaseCommonReviewRating.parse({ value: z64.string().parse(value) }).value
|
|
6737
|
-
),
|
|
6738
|
-
reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
|
|
6739
|
-
};
|
|
6740
|
-
};
|
|
6741
|
-
|
|
6742
|
-
// src/server/postPurchaseReviewData.ts
|
|
6743
|
-
var readStandardReviews = (find) => {
|
|
6744
|
-
const rating = find("reviews", "rating");
|
|
6745
|
-
const count = find("reviews", "rating_count");
|
|
6746
|
-
if (!rating || !count) return null;
|
|
6747
|
-
return {
|
|
6748
|
-
rating: readReviewField(rating, (raw) => {
|
|
6749
|
-
const value = z65.string().parse(raw);
|
|
6750
|
-
return PostPurchaseCommonReviewRating.parse(/^\d+(?:\.\d+)?$/.test(value) ? { value } : JSON.parse(value)).value;
|
|
6751
|
-
}),
|
|
6752
|
-
reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
|
|
6753
|
-
};
|
|
6754
|
-
};
|
|
6755
|
-
var readPostPurchaseReviewData = (provider, find) => {
|
|
6756
|
-
if (provider === "yotpo") return readScalarReviews(find, "yotpo", "reviews_average", "reviews_count");
|
|
6757
|
-
if (provider === "stamped") return readScalarReviews(find, "stamped", "reviews_average", "reviews_count");
|
|
6758
|
-
if (provider === "judgeme") return readJudgeMeReviews(find);
|
|
6759
|
-
if (provider === "okendo") return readOkendoReviews(find);
|
|
6760
|
-
if (provider === "opinew") return readScalarReviews(find, "opinew_metafields", "reviews_average", "reviews_count");
|
|
6761
|
-
if (provider === "reviewsio")
|
|
6762
|
-
return readScalarReviews(find, "reviewscouk", "rating", "total") ?? readStandardReviews(find);
|
|
6763
|
-
if (provider === "loox") return readScalarReviews(find, "loox", "avg_rating", "num_reviews");
|
|
6764
|
-
if (provider === "junip") return readScalarReviews(find, "junip", "rating_average", "rating_count");
|
|
6765
|
-
const rating = find("reviews", "rating");
|
|
6766
|
-
const count = find("reviews", "rating_count");
|
|
6767
|
-
if (!rating || !count) return null;
|
|
6768
|
-
return {
|
|
6769
|
-
rating: readReviewField(
|
|
6770
|
-
rating,
|
|
6771
|
-
(value) => PostPurchaseKlaviyoReviewRating.parse(JSON.parse(z65.string().parse(value))).value
|
|
6772
|
-
),
|
|
6773
|
-
reviewCount: readReviewField(count, (value) => PostPurchaseReviewCount.parse(value))
|
|
6774
|
-
};
|
|
6775
|
-
};
|
|
6776
|
-
|
|
6777
|
-
// src/server/postPurchaseReviewProvider.ts
|
|
6778
|
-
import { z as z66 } from "zod";
|
|
6779
|
-
var IntegrationInput = z66.record(z66.string(), z66.unknown()).prefault({});
|
|
6780
|
-
var precedence = [
|
|
6781
|
-
"klaviyo",
|
|
6782
|
-
"judgeme",
|
|
6783
|
-
"junip",
|
|
6784
|
-
"loox",
|
|
6785
|
-
"okendo",
|
|
6786
|
-
"opinew",
|
|
6787
|
-
"reviewsio",
|
|
6788
|
-
"stamped",
|
|
6789
|
-
"yotpo"
|
|
6790
|
-
];
|
|
6791
|
-
var ReviewsIoFlag = z66.preprocess((value) => {
|
|
6792
|
-
if (typeof value === "string") {
|
|
6793
|
-
const flag = value.toLowerCase();
|
|
6794
|
-
if (flag === "true" || flag === "yes") return true;
|
|
6795
|
-
if (flag === "false" || flag === "no") return false;
|
|
6796
|
-
}
|
|
6797
|
-
return value;
|
|
6798
|
-
}, PostPurchaseSettings.shape.integrations.shape.reviewsio);
|
|
6799
|
-
var selectPostPurchaseReviewProvider = (raw) => {
|
|
6800
|
-
const integrations = IntegrationInput.parse(raw);
|
|
6801
|
-
for (const provider of precedence) {
|
|
6802
|
-
const schema = provider === "reviewsio" ? ReviewsIoFlag : PostPurchaseSettings.shape.integrations.shape[provider];
|
|
6803
|
-
if (schema.parse(integrations[provider])) return provider;
|
|
6804
|
-
}
|
|
6805
|
-
return null;
|
|
6806
|
-
};
|
|
6807
|
-
|
|
6808
6868
|
// src/server/postPurchaseReviews.ts
|
|
6809
6869
|
var projectPostPurchaseReviews = (settings, { id: productId2, metafields }, report) => {
|
|
6810
6870
|
try {
|