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