@rebuy/rebuy 3.43.1 → 3.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/index.cjs +72 -13
  2. package/dist/index.mjs +72 -13
  3. package/dist/pricing/postPurchaseDisplayPrice.d.ts +2 -0
  4. package/dist/schema/postPurchaseDisplayPrice.d.ts +4 -3
  5. package/dist/schema/postPurchaseProductCollectionView.d.ts +365 -3
  6. package/dist/schema/postPurchaseProductView.d.ts +367 -4
  7. package/dist/schema/postPurchaseTransition.d.ts +80 -3
  8. package/dist/server/index.cjs +119 -40
  9. package/dist/server/index.d.ts +1 -0
  10. package/dist/server/index.mjs +119 -40
  11. package/dist/server/postPurchaseCardSections.d.ts +12 -0
  12. package/dist/server/postPurchaseProductEligibility.d.ts +1 -1
  13. package/dist/server/postPurchaseSubscriptionEligibility.d.ts +1 -1
  14. package/dist/server/postPurchaseUnavailableChoice.d.ts +12 -0
  15. package/dist/server/preparePostPurchaseAdmissionView.d.ts +125 -2
  16. package/dist/server/preparePostPurchaseCollectionGroup.d.ts +130 -4
  17. package/dist/server/preparePostPurchaseCollectionView.d.ts +125 -2
  18. package/dist/server/preparePostPurchaseGroupAdmissionView.d.ts +125 -2
  19. package/dist/server/preparePostPurchaseGroupDefault.d.ts +125 -2
  20. package/dist/server/preparePostPurchaseGroupView.d.ts +125 -2
  21. package/dist/server/preparePostPurchaseMemberView.d.ts +375 -6
  22. package/dist/server/preparePostPurchaseQuantityAdmissionView.d.ts +125 -2
  23. package/dist/server/preparePostPurchaseQuantityView.d.ts +125 -2
  24. package/dist/server/preparePostPurchaseView.d.ts +4 -1
  25. package/dist/transforms/index.cjs +57 -7
  26. package/dist/transforms/index.mjs +57 -7
  27. package/dist/transforms/legacyLabelDefaults.d.ts +15 -0
  28. package/dist/transforms/localizedContent.d.ts +23 -6
  29. package/dist/transforms/postPurchase/productCardRows.d.ts +3 -1
  30. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -185,6 +185,7 @@ __export(src_exports, {
185
185
  PostPurchaseCommonReviewRating: () => PostPurchaseCommonReviewRating,
186
186
  PostPurchaseDiscount: () => PostPurchaseDiscount,
187
187
  PostPurchaseDisplayPrice: () => PostPurchaseDisplayPrice,
188
+ PostPurchaseEndReasonSchema: () => PostPurchaseEndReasonSchema,
188
189
  PostPurchaseExcludedProductIds: () => PostPurchaseExcludedProductIds,
189
190
  PostPurchaseGroupCatalog: () => PostPurchaseGroupCatalog,
190
191
  PostPurchaseGroupChoice: () => PostPurchaseGroupChoice,
@@ -3139,7 +3140,7 @@ var PostPurchaseSubscriptionDisplay = import_zod35.z.object({
3139
3140
  var { currencyCode: CurrencyCode, priceMinor: Minor3, savingPercent: Percent } = PostPurchaseSubscriptionDisplay.shape;
3140
3141
  var PostPurchaseDisplayPrice = import_zod36.z.object({
3141
3142
  currencyCode: CurrencyCode,
3142
- savingFormat: import_zod36.z.enum(["amount", "percent"]),
3143
+ savingFormat: import_zod36.z.enum(["amount", "percent"]).nullable(),
3143
3144
  savingMinor: Minor3,
3144
3145
  savingPercent: Percent,
3145
3146
  subscriptionUnit: PostPurchaseSubscriptionDisplay.optional(),
@@ -4483,7 +4484,8 @@ var PostPurchaseProductView = import_zod67.z.union([
4483
4484
  planCatalog: PostPurchasePlanCatalog.nullable().optional(),
4484
4485
  preparation: PostPurchasePreparation.options[1],
4485
4486
  purchaseOptions: PostPurchaseOptions.optional(),
4486
- sections: import_zod67.z.null(),
4487
+ /** A choice-level unavailable product keeps its card (values resolve blank); configuration failures send null. */
4488
+ sections: CABRootSection.nullable(),
4487
4489
  variantCatalog: PostPurchaseVariantCatalog.optional()
4488
4490
  })
4489
4491
  ]);
@@ -4906,12 +4908,19 @@ var OfferTransitionRequestSchema = DecideRequestSchema.extend({
4906
4908
  entryRevision: PostPurchaseProgressSchema.shape.entryRevision,
4907
4909
  progressRevision: PostPurchaseProgressSchema.shape.revision
4908
4910
  }).strict();
4911
+ var PostPurchaseEndReasonSchema = import_zod88.z.enum(["no-child", "no-products", "accept-cap"]);
4912
+ var TransitionBaseSchema = import_zod88.z.object({
4913
+ attemptedSkips: PostPurchaseSkipTraceSchema.optional(),
4914
+ progress: PostPurchaseProgressSchema
4915
+ });
4909
4916
  var OfferTransitionResponseSchema = import_zod88.z.object({
4910
- data: import_zod88.z.object({
4911
- attemptedSkips: PostPurchaseSkipTraceSchema.optional(),
4912
- progress: PostPurchaseProgressSchema,
4913
- status: import_zod88.z.enum(["advanced", "no-child", "unavailable"])
4914
- }),
4917
+ data: import_zod88.z.discriminatedUnion("status", [
4918
+ TransitionBaseSchema.extend({ status: import_zod88.z.enum(["advanced", "unavailable"]) }),
4919
+ TransitionBaseSchema.extend({
4920
+ endReason: PostPurchaseEndReasonSchema.optional(),
4921
+ status: import_zod88.z.literal("no-child")
4922
+ })
4923
+ ]),
4915
4924
  successful: import_zod88.z.literal(true)
4916
4925
  });
4917
4926
 
@@ -5640,10 +5649,37 @@ var LOCATION_TO_EDITOR_MODE = {
5640
5649
  "thank-you": "thankYouPage"
5641
5650
  };
5642
5651
 
5652
+ // src/transforms/legacyLabelDefaults.ts
5653
+ var LEGACY_LABEL_DEFAULTS = {
5654
+ /** The banner's RTE default, compared by its plain text. */
5655
+ addedToCartMessage: ["{{quantity}} {{product_title}} successfully added to cart!"],
5656
+ /** Offers template; the Recommended template stores the bare `Add`. */
5657
+ addToCart: ["Add {{quantity}} \u2022 {{total}}", "Add"],
5658
+ /** Line-item editor template, then the base template's `cartSwitchToOnetime` (the offer card's one-time label). */
5659
+ switchToOneTimePurchase: ["Downgrade to One-time", "One-time purchase"],
5660
+ /** Line-item editor template; the offers template's one upsell label fills both upsell slots. */
5661
+ switchToSubscriptionNoDiscount: [
5662
+ "Upgrade to Subscription",
5663
+ "Upgrade to Subscription and Save {{subscription_discount}}%"
5664
+ ],
5665
+ /** Line-item editor template, then the offers template. */
5666
+ switchToSubscriptionWithDiscount: [
5667
+ "Upgrade to Subscription & Save {{subscription_discount}}%",
5668
+ "Upgrade to Subscription and Save {{subscription_discount}}%"
5669
+ ]
5670
+ };
5671
+
5643
5672
  // src/transforms/localizedContent.ts
5644
- var localizedContent = (defaults, override, knownTokens = []) => {
5673
+ var comparable = (label) => label.replace(/\s+/g, " ").trim().toLowerCase();
5674
+ var isDefaultLabel = (label, defaults, knownTokens = [], legacyDefaults = []) => {
5675
+ const candidates = [defaults.en, ...legacyDefaults];
5676
+ const target = comparable(normalizeTokens(label, knownTokens));
5677
+ return candidates.some((candidate) => comparable(normalizeTokens(candidate, knownTokens)) === target);
5678
+ };
5679
+ var localizedContent = (defaults, override, knownTokens = [], legacyDefaults = []) => {
5645
5680
  const trimmed = normalizeTokens(stripContentBlockHtml(override ?? "").trim(), knownTokens);
5646
- return trimmed ? { ...defaults, en: trimmed } : defaults;
5681
+ if (!trimmed) return defaults;
5682
+ return isDefaultLabel(trimmed, defaults, knownTokens, legacyDefaults) ? { ...defaults, en: trimmed } : { en: trimmed };
5647
5683
  };
5648
5684
 
5649
5685
  // src/transforms/offerV1/offerTemplateSeed.ts
@@ -6084,6 +6120,14 @@ var buildOfferTemplate = ({ location: location2, name } = {}) => CABRootSection.
6084
6120
  type: SHOPIFY_CHECKOUT_EXTENSION
6085
6121
  });
6086
6122
 
6123
+ // src/cab/listOf.ts
6124
+ var listOf = (value) => Array.isArray(value) ? value.filter((item) => !!item) : [];
6125
+
6126
+ // src/cab/tiptapPlain.ts
6127
+ var tiptapPlainText = (doc) => listOf(doc?.content).map(
6128
+ (paragraph) => listOf(paragraph.content).map((node) => node.text ?? "").join("")
6129
+ ).join(" ").trim();
6130
+
6087
6131
  // src/transforms/productCard/earnedText.ts
6088
6132
  var contentMutator = (effect, variable, operator) => ({
6089
6133
  effect,
@@ -6154,7 +6198,12 @@ var subscriptionToggle = (productType, labels = {}) => {
6154
6198
  if (productType !== "both" && productType !== "subscription") return [];
6155
6199
  const slot = (buttonField, override) => ({
6156
6200
  buttonField,
6157
- content: localizedContent(SWITCH_LABELS[buttonField], override, SWITCH_LABEL_TOKENS),
6201
+ content: localizedContent(
6202
+ SWITCH_LABELS[buttonField],
6203
+ override,
6204
+ SWITCH_LABEL_TOKENS,
6205
+ LEGACY_LABEL_DEFAULTS[buttonField]
6206
+ ),
6158
6207
  sectionType: "text"
6159
6208
  });
6160
6209
  return [
@@ -6356,7 +6405,12 @@ var buildRevealButton = (settings) => revealsVariants(settings) ? [
6356
6405
  var buildAddButton = (settings) => {
6357
6406
  const slot = (buttonField, override) => ({
6358
6407
  buttonField,
6359
- content: localizedContent(OFFER_LABELS[buttonField], override, ADD_LABEL_TOKENS),
6408
+ content: localizedContent(
6409
+ OFFER_LABELS[buttonField],
6410
+ override,
6411
+ ADD_LABEL_TOKENS,
6412
+ LEGACY_LABEL_DEFAULTS[buttonField]
6413
+ ),
6360
6414
  sectionType: "text"
6361
6415
  });
6362
6416
  return {
@@ -6537,9 +6591,13 @@ var buildDiscountSection = (discount) => {
6537
6591
  }
6538
6592
  ];
6539
6593
  };
6594
+ var BANNER_MESSAGE_TOKENS = ["quantity", "productTitle"];
6540
6595
  var bannerMessageContent = (message) => {
6541
- const sanitized = typeof message === "string" ? stripContentBlockHtml(message) : message;
6542
- return sanitized ? { ...OFFER_LABELS.addedToCartMessage, en: sanitized } : OFFER_LABELS.addedToCartMessage;
6596
+ const { addedToCartMessage } = OFFER_LABELS;
6597
+ const legacyDefaults = LEGACY_LABEL_DEFAULTS.addedToCartMessage;
6598
+ if (typeof message === "string" || !message)
6599
+ return localizedContent(addedToCartMessage, message, BANNER_MESSAGE_TOKENS, legacyDefaults);
6600
+ return isDefaultLabel(tiptapPlainText(message), addedToCartMessage, BANNER_MESSAGE_TOKENS, legacyDefaults) ? { ...addedToCartMessage, en: message } : { en: message };
6543
6601
  };
6544
6602
  var coerceIntegrations = (integrations) => Object.fromEntries(
6545
6603
  Object.entries(integrations).map(([key, value]) => {
@@ -6871,6 +6929,7 @@ var postPurchaseDisplayPrice = (prepared, currencyCode) => {
6871
6929
  });
6872
6930
  return PostPurchaseDisplayPrice.parse({
6873
6931
  ...facts,
6932
+ ...!prepared.display.shouldShowSavingText && { savingFormat: null },
6874
6933
  ...subscription && { subscriptionUnit: postPurchaseSubscriptionDisplay(subscription, currencyCode) }
6875
6934
  });
6876
6935
  };
package/dist/index.mjs CHANGED
@@ -2670,7 +2670,7 @@ var PostPurchaseSubscriptionDisplay = z35.object({
2670
2670
  var { currencyCode: CurrencyCode, priceMinor: Minor3, savingPercent: Percent } = PostPurchaseSubscriptionDisplay.shape;
2671
2671
  var PostPurchaseDisplayPrice = z36.object({
2672
2672
  currencyCode: CurrencyCode,
2673
- savingFormat: z36.enum(["amount", "percent"]),
2673
+ savingFormat: z36.enum(["amount", "percent"]).nullable(),
2674
2674
  savingMinor: Minor3,
2675
2675
  savingPercent: Percent,
2676
2676
  subscriptionUnit: PostPurchaseSubscriptionDisplay.optional(),
@@ -4014,7 +4014,8 @@ var PostPurchaseProductView = z67.union([
4014
4014
  planCatalog: PostPurchasePlanCatalog.nullable().optional(),
4015
4015
  preparation: PostPurchasePreparation.options[1],
4016
4016
  purchaseOptions: PostPurchaseOptions.optional(),
4017
- sections: z67.null(),
4017
+ /** A choice-level unavailable product keeps its card (values resolve blank); configuration failures send null. */
4018
+ sections: CABRootSection.nullable(),
4018
4019
  variantCatalog: PostPurchaseVariantCatalog.optional()
4019
4020
  })
4020
4021
  ]);
@@ -4437,12 +4438,19 @@ var OfferTransitionRequestSchema = DecideRequestSchema.extend({
4437
4438
  entryRevision: PostPurchaseProgressSchema.shape.entryRevision,
4438
4439
  progressRevision: PostPurchaseProgressSchema.shape.revision
4439
4440
  }).strict();
4441
+ var PostPurchaseEndReasonSchema = z88.enum(["no-child", "no-products", "accept-cap"]);
4442
+ var TransitionBaseSchema = z88.object({
4443
+ attemptedSkips: PostPurchaseSkipTraceSchema.optional(),
4444
+ progress: PostPurchaseProgressSchema
4445
+ });
4440
4446
  var OfferTransitionResponseSchema = z88.object({
4441
- data: z88.object({
4442
- attemptedSkips: PostPurchaseSkipTraceSchema.optional(),
4443
- progress: PostPurchaseProgressSchema,
4444
- status: z88.enum(["advanced", "no-child", "unavailable"])
4445
- }),
4447
+ data: z88.discriminatedUnion("status", [
4448
+ TransitionBaseSchema.extend({ status: z88.enum(["advanced", "unavailable"]) }),
4449
+ TransitionBaseSchema.extend({
4450
+ endReason: PostPurchaseEndReasonSchema.optional(),
4451
+ status: z88.literal("no-child")
4452
+ })
4453
+ ]),
4446
4454
  successful: z88.literal(true)
4447
4455
  });
4448
4456
 
@@ -5171,10 +5179,37 @@ var LOCATION_TO_EDITOR_MODE = {
5171
5179
  "thank-you": "thankYouPage"
5172
5180
  };
5173
5181
 
5182
+ // src/transforms/legacyLabelDefaults.ts
5183
+ var LEGACY_LABEL_DEFAULTS = {
5184
+ /** The banner's RTE default, compared by its plain text. */
5185
+ addedToCartMessage: ["{{quantity}} {{product_title}} successfully added to cart!"],
5186
+ /** Offers template; the Recommended template stores the bare `Add`. */
5187
+ addToCart: ["Add {{quantity}} \u2022 {{total}}", "Add"],
5188
+ /** Line-item editor template, then the base template's `cartSwitchToOnetime` (the offer card's one-time label). */
5189
+ switchToOneTimePurchase: ["Downgrade to One-time", "One-time purchase"],
5190
+ /** Line-item editor template; the offers template's one upsell label fills both upsell slots. */
5191
+ switchToSubscriptionNoDiscount: [
5192
+ "Upgrade to Subscription",
5193
+ "Upgrade to Subscription and Save {{subscription_discount}}%"
5194
+ ],
5195
+ /** Line-item editor template, then the offers template. */
5196
+ switchToSubscriptionWithDiscount: [
5197
+ "Upgrade to Subscription & Save {{subscription_discount}}%",
5198
+ "Upgrade to Subscription and Save {{subscription_discount}}%"
5199
+ ]
5200
+ };
5201
+
5174
5202
  // src/transforms/localizedContent.ts
5175
- var localizedContent = (defaults, override, knownTokens = []) => {
5203
+ var comparable = (label) => label.replace(/\s+/g, " ").trim().toLowerCase();
5204
+ var isDefaultLabel = (label, defaults, knownTokens = [], legacyDefaults = []) => {
5205
+ const candidates = [defaults.en, ...legacyDefaults];
5206
+ const target = comparable(normalizeTokens(label, knownTokens));
5207
+ return candidates.some((candidate) => comparable(normalizeTokens(candidate, knownTokens)) === target);
5208
+ };
5209
+ var localizedContent = (defaults, override, knownTokens = [], legacyDefaults = []) => {
5176
5210
  const trimmed = normalizeTokens(stripContentBlockHtml(override ?? "").trim(), knownTokens);
5177
- return trimmed ? { ...defaults, en: trimmed } : defaults;
5211
+ if (!trimmed) return defaults;
5212
+ return isDefaultLabel(trimmed, defaults, knownTokens, legacyDefaults) ? { ...defaults, en: trimmed } : { en: trimmed };
5178
5213
  };
5179
5214
 
5180
5215
  // src/transforms/offerV1/offerTemplateSeed.ts
@@ -5615,6 +5650,14 @@ var buildOfferTemplate = ({ location: location2, name } = {}) => CABRootSection.
5615
5650
  type: SHOPIFY_CHECKOUT_EXTENSION
5616
5651
  });
5617
5652
 
5653
+ // src/cab/listOf.ts
5654
+ var listOf = (value) => Array.isArray(value) ? value.filter((item) => !!item) : [];
5655
+
5656
+ // src/cab/tiptapPlain.ts
5657
+ var tiptapPlainText = (doc) => listOf(doc?.content).map(
5658
+ (paragraph) => listOf(paragraph.content).map((node) => node.text ?? "").join("")
5659
+ ).join(" ").trim();
5660
+
5618
5661
  // src/transforms/productCard/earnedText.ts
5619
5662
  var contentMutator = (effect, variable, operator) => ({
5620
5663
  effect,
@@ -5685,7 +5728,12 @@ var subscriptionToggle = (productType, labels = {}) => {
5685
5728
  if (productType !== "both" && productType !== "subscription") return [];
5686
5729
  const slot = (buttonField, override) => ({
5687
5730
  buttonField,
5688
- content: localizedContent(SWITCH_LABELS[buttonField], override, SWITCH_LABEL_TOKENS),
5731
+ content: localizedContent(
5732
+ SWITCH_LABELS[buttonField],
5733
+ override,
5734
+ SWITCH_LABEL_TOKENS,
5735
+ LEGACY_LABEL_DEFAULTS[buttonField]
5736
+ ),
5689
5737
  sectionType: "text"
5690
5738
  });
5691
5739
  return [
@@ -5887,7 +5935,12 @@ var buildRevealButton = (settings) => revealsVariants(settings) ? [
5887
5935
  var buildAddButton = (settings) => {
5888
5936
  const slot = (buttonField, override) => ({
5889
5937
  buttonField,
5890
- content: localizedContent(OFFER_LABELS[buttonField], override, ADD_LABEL_TOKENS),
5938
+ content: localizedContent(
5939
+ OFFER_LABELS[buttonField],
5940
+ override,
5941
+ ADD_LABEL_TOKENS,
5942
+ LEGACY_LABEL_DEFAULTS[buttonField]
5943
+ ),
5891
5944
  sectionType: "text"
5892
5945
  });
5893
5946
  return {
@@ -6068,9 +6121,13 @@ var buildDiscountSection = (discount) => {
6068
6121
  }
6069
6122
  ];
6070
6123
  };
6124
+ var BANNER_MESSAGE_TOKENS = ["quantity", "productTitle"];
6071
6125
  var bannerMessageContent = (message) => {
6072
- const sanitized = typeof message === "string" ? stripContentBlockHtml(message) : message;
6073
- return sanitized ? { ...OFFER_LABELS.addedToCartMessage, en: sanitized } : OFFER_LABELS.addedToCartMessage;
6126
+ const { addedToCartMessage } = OFFER_LABELS;
6127
+ const legacyDefaults = LEGACY_LABEL_DEFAULTS.addedToCartMessage;
6128
+ if (typeof message === "string" || !message)
6129
+ return localizedContent(addedToCartMessage, message, BANNER_MESSAGE_TOKENS, legacyDefaults);
6130
+ return isDefaultLabel(tiptapPlainText(message), addedToCartMessage, BANNER_MESSAGE_TOKENS, legacyDefaults) ? { ...addedToCartMessage, en: message } : { en: message };
6074
6131
  };
6075
6132
  var coerceIntegrations = (integrations) => Object.fromEntries(
6076
6133
  Object.entries(integrations).map(([key, value]) => {
@@ -6402,6 +6459,7 @@ var postPurchaseDisplayPrice = (prepared, currencyCode) => {
6402
6459
  });
6403
6460
  return PostPurchaseDisplayPrice.parse({
6404
6461
  ...facts,
6462
+ ...!prepared.display.shouldShowSavingText && { savingFormat: null },
6405
6463
  ...subscription && { subscriptionUnit: postPurchaseSubscriptionDisplay(subscription, currencyCode) }
6406
6464
  });
6407
6465
  };
@@ -6571,6 +6629,7 @@ export {
6571
6629
  PostPurchaseCommonReviewRating,
6572
6630
  PostPurchaseDiscount,
6573
6631
  PostPurchaseDisplayPrice,
6632
+ PostPurchaseEndReasonSchema,
6574
6633
  PostPurchaseExcludedProductIds,
6575
6634
  PostPurchaseGroupCatalog,
6576
6635
  PostPurchaseGroupChoice,
@@ -4,5 +4,7 @@ import type { PreparedPostPurchaseProduct } from '../schema/postPurchaseProduct'
4
4
  /**
5
5
  * The prepared view's `displayPrice` for the choice this preparation binds — one-time or a plan — derived from the
6
6
  * same preparation the changeset is, in the buyer's presentment currency. A plan choice also carries the unit estimate.
7
+ * The chosen mode's `shouldShowSavingText` off hides the saving text by value (`savingFormat: null`), never by a
8
+ * client setting check.
7
9
  */
8
10
  export declare const postPurchaseDisplayPrice: (prepared: z.infer<typeof PreparedPostPurchaseProduct>, currencyCode: string) => PostPurchaseDisplayPrice;
@@ -4,7 +4,8 @@ import { z } from 'zod';
4
4
  * only formats minor units into cab-checkout's tokens: `variantPriceMinor` → `{{variantPrice}}` (× quantity →
5
5
  * `{{variantTotalPrice}}`), `variantCompareAtPriceMinor` → `{{variantCompareAtPrice}}` (null: nothing struck,
6
6
  * the exemplar's ''). The saving is the struck price minus the price; `savingFormat` is which of
7
- * `savingMinor` / `savingPercent` the saving text shows (L140: currency for a fixed amount). A plan choice also
7
+ * `savingMinor` / `savingPercent` the saving text shows (L140: currency for a fixed amount), or `null` when the
8
+ * chosen mode's `shouldShowSavingText` is off: no saving text, while the strike and amounts stay. A plan choice also
8
9
  * carries `postPurchaseSubscriptionDisplay`'s unit estimate, which must restate these facts: with the saving tied
9
10
  * to its own comparison, its comparison is the struck price when one is struck and at most the price when none is
10
11
  * (a plan `price` above the regular price compares below it, so equality to the price would be too strict). A
@@ -12,10 +13,10 @@ import { z } from 'zod';
12
13
  */
13
14
  export declare const PostPurchaseDisplayPrice: z.ZodObject<{
14
15
  currencyCode: z.ZodString;
15
- savingFormat: z.ZodEnum<{
16
+ savingFormat: z.ZodNullable<z.ZodEnum<{
16
17
  amount: "amount";
17
18
  percent: "percent";
18
- }>;
19
+ }>>;
19
20
  savingMinor: z.ZodNumber;
20
21
  savingPercent: z.ZodNumber;
21
22
  subscriptionUnit: z.ZodOptional<z.ZodObject<{