@rebuy/rebuy 3.60.5 → 3.62.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 CHANGED
@@ -121,6 +121,7 @@ __export(src_exports, {
121
121
  DiscountSource: () => DiscountSource,
122
122
  DiscountType: () => DiscountType,
123
123
  EditorMode: () => EditorMode,
124
+ EngineSmartCart: () => EngineSmartCart,
124
125
  EventCalculationSchema: () => EventCalculationSchema,
125
126
  ExitPolicySchema: () => ExitPolicySchema,
126
127
  FinishedPurchaseSchema: () => FinishedPurchaseSchema,
@@ -1228,7 +1229,22 @@ var SmartCartTierProduct = import_zod.z.looseObject({
1228
1229
  });
1229
1230
  var SmartCartTierExclusion = import_zod.z.looseObject({
1230
1231
  collectionIds: import_zod.z.array(import_zod.z.coerce.number()).optional().catch(void 0),
1231
- productIds: import_zod.z.array(import_zod.z.coerce.number()).optional().catch(void 0),
1232
+ /**
1233
+ * onsite keeps each excluded product with ITS OWN variants, the same shape the bar-level
1234
+ * `excludedProducts` uses, so a rule can exclude one variant of B without touching A.
1235
+ * Flat parallel id lists cannot express that mapping.
1236
+ *
1237
+ * camelCase like every other key in this file, NOT the `product_id` / `variant_ids` the onsite
1238
+ * payload spells: `parseShielded` runs `deepCamelCase` over the tree BEFORE any schema sees it.
1239
+ * A snake_case key here reads as absent, every entry drops, and the converter discards the whole
1240
+ * rule in silence — the exclusion just never reaches checkout.
1241
+ */
1242
+ products: import_zod.z.array(
1243
+ import_zod.z.looseObject({
1244
+ productId: import_zod.z.coerce.number().optional().catch(void 0),
1245
+ variantIds: import_zod.z.array(import_zod.z.coerce.number()).optional().catch(void 0)
1246
+ })
1247
+ ).optional().catch(void 0),
1232
1248
  tags: import_zod.z.array(import_zod.z.string()).optional().catch(void 0),
1233
1249
  type: import_zod.z.string().optional().catch(void 0)
1234
1250
  });
@@ -1363,6 +1379,7 @@ var SmartCartComponent = import_zod.z.looseObject({
1363
1379
  var SmartCartConfig = import_zod.z.looseObject({
1364
1380
  components: import_zod.z.array(SmartCartComponent).optional()
1365
1381
  });
1382
+ var EngineSmartCart = import_zod.z.preprocess((value) => value === false ? null : value, SmartCartConfig.nullish());
1366
1383
 
1367
1384
  // src/schema/cabShopConfig.ts
1368
1385
  var CabActiveExperiment = import_zod2.z.object({
@@ -1460,7 +1477,7 @@ var CabShopConfig = import_zod2.z.object({
1460
1477
  });
1461
1478
  var CabUserConfig = import_zod2.z.object({
1462
1479
  shop: CabShopConfig,
1463
- smartCart: SmartCartConfig.nullish().catch(DRIFTED_SMART_CART)
1480
+ smartCart: EngineSmartCart.catch(DRIFTED_SMART_CART)
1464
1481
  });
1465
1482
 
1466
1483
  // src/schema/metadata.ts
@@ -4124,7 +4141,17 @@ var GIFT_LABELS = {
4124
4141
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
4125
4142
  var CABProgressTierExclusion = import_zod61.z.object({
4126
4143
  collectionIds: import_zod61.z.array(import_zod61.z.number().int().positive()).default(() => []),
4127
- productIds: import_zod61.z.array(import_zod61.z.number().int().positive()).default(() => []),
4144
+ /**
4145
+ * `products` rules: each excluded product with ITS OWN variants, mirroring the bar-level
4146
+ * excluded products. An empty `variantIds` means "the whole product", which is how the admin
4147
+ * picker stores a whole-product selection, and a populated one means those variants.
4148
+ */
4149
+ products: import_zod61.z.array(
4150
+ import_zod61.z.object({
4151
+ productId: import_zod61.z.number().int().positive(),
4152
+ variantIds: import_zod61.z.array(import_zod61.z.number().int().positive()).default(() => [])
4153
+ })
4154
+ ).default(() => []),
4128
4155
  tags: import_zod61.z.array(import_zod61.z.string().min(1)).default(() => []),
4129
4156
  type: import_zod61.z.enum(progressTierExclusionTypes)
4130
4157
  });
@@ -5238,10 +5265,14 @@ var import_zod93 = require("zod");
5238
5265
  var UserConfig = import_zod93.z.object({
5239
5266
  shop: ShopConfig,
5240
5267
  /**
5241
- * `.catch(undefined)` is the safety bar: smart-cart shape drift can NEVER fail `fetchUserConfig`,
5242
- * which resolves the apiKey for every offers/monetize/analytics/gift request.
5268
+ * Parsed like `CabUserConfig.smartCart`: the engine's `false` reads as `null` ({@link EngineSmartCart}), a
5269
+ * drifted component loses only its own settings (`SmartCartComponent.settings` catches per component), and
5270
+ * `.catch(undefined)` is the last safety bar so a wholly unreadable config can never fail the parse that
5271
+ * resolves the shop's apiKey. It lands on `undefined`, not the `DRIFTED_SMART_CART` sentinel: no drift
5272
+ * reporter reads this schema (the server parses `CabUserConfig`), and that sentinel's identity is not
5273
+ * exported from `./schema`, so a consumer could not tell it apart from an empty config anyway.
5243
5274
  */
5244
- smartCart: SmartCartConfig.nullish().catch(void 0),
5275
+ smartCart: EngineSmartCart.catch(void 0),
5245
5276
  smartFlows: import_zod93.z.array(import_zod93.z.unknown())
5246
5277
  });
5247
5278
 
package/dist/index.mjs CHANGED
@@ -746,7 +746,22 @@ var SmartCartTierProduct = z.looseObject({
746
746
  });
747
747
  var SmartCartTierExclusion = z.looseObject({
748
748
  collectionIds: z.array(z.coerce.number()).optional().catch(void 0),
749
- productIds: z.array(z.coerce.number()).optional().catch(void 0),
749
+ /**
750
+ * onsite keeps each excluded product with ITS OWN variants, the same shape the bar-level
751
+ * `excludedProducts` uses, so a rule can exclude one variant of B without touching A.
752
+ * Flat parallel id lists cannot express that mapping.
753
+ *
754
+ * camelCase like every other key in this file, NOT the `product_id` / `variant_ids` the onsite
755
+ * payload spells: `parseShielded` runs `deepCamelCase` over the tree BEFORE any schema sees it.
756
+ * A snake_case key here reads as absent, every entry drops, and the converter discards the whole
757
+ * rule in silence — the exclusion just never reaches checkout.
758
+ */
759
+ products: z.array(
760
+ z.looseObject({
761
+ productId: z.coerce.number().optional().catch(void 0),
762
+ variantIds: z.array(z.coerce.number()).optional().catch(void 0)
763
+ })
764
+ ).optional().catch(void 0),
750
765
  tags: z.array(z.string()).optional().catch(void 0),
751
766
  type: z.string().optional().catch(void 0)
752
767
  });
@@ -881,6 +896,7 @@ var SmartCartComponent = z.looseObject({
881
896
  var SmartCartConfig = z.looseObject({
882
897
  components: z.array(SmartCartComponent).optional()
883
898
  });
899
+ var EngineSmartCart = z.preprocess((value) => value === false ? null : value, SmartCartConfig.nullish());
884
900
 
885
901
  // src/schema/cabShopConfig.ts
886
902
  var CabActiveExperiment = z2.object({
@@ -978,7 +994,7 @@ var CabShopConfig = z2.object({
978
994
  });
979
995
  var CabUserConfig = z2.object({
980
996
  shop: CabShopConfig,
981
- smartCart: SmartCartConfig.nullish().catch(DRIFTED_SMART_CART)
997
+ smartCart: EngineSmartCart.catch(DRIFTED_SMART_CART)
982
998
  });
983
999
 
984
1000
  // src/schema/metadata.ts
@@ -3642,7 +3658,17 @@ var GIFT_LABELS = {
3642
3658
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
3643
3659
  var CABProgressTierExclusion = z61.object({
3644
3660
  collectionIds: z61.array(z61.number().int().positive()).default(() => []),
3645
- productIds: z61.array(z61.number().int().positive()).default(() => []),
3661
+ /**
3662
+ * `products` rules: each excluded product with ITS OWN variants, mirroring the bar-level
3663
+ * excluded products. An empty `variantIds` means "the whole product", which is how the admin
3664
+ * picker stores a whole-product selection, and a populated one means those variants.
3665
+ */
3666
+ products: z61.array(
3667
+ z61.object({
3668
+ productId: z61.number().int().positive(),
3669
+ variantIds: z61.array(z61.number().int().positive()).default(() => [])
3670
+ })
3671
+ ).default(() => []),
3646
3672
  tags: z61.array(z61.string().min(1)).default(() => []),
3647
3673
  type: z61.enum(progressTierExclusionTypes)
3648
3674
  });
@@ -4756,10 +4782,14 @@ import { z as z93 } from "zod";
4756
4782
  var UserConfig = z93.object({
4757
4783
  shop: ShopConfig,
4758
4784
  /**
4759
- * `.catch(undefined)` is the safety bar: smart-cart shape drift can NEVER fail `fetchUserConfig`,
4760
- * which resolves the apiKey for every offers/monetize/analytics/gift request.
4785
+ * Parsed like `CabUserConfig.smartCart`: the engine's `false` reads as `null` ({@link EngineSmartCart}), a
4786
+ * drifted component loses only its own settings (`SmartCartComponent.settings` catches per component), and
4787
+ * `.catch(undefined)` is the last safety bar so a wholly unreadable config can never fail the parse that
4788
+ * resolves the shop's apiKey. It lands on `undefined`, not the `DRIFTED_SMART_CART` sentinel: no drift
4789
+ * reporter reads this schema (the server parses `CabUserConfig`), and that sentinel's identity is not
4790
+ * exported from `./schema`, so a consumer could not tell it apart from an empty config anyway.
4761
4791
  */
4762
- smartCart: SmartCartConfig.nullish().catch(void 0),
4792
+ smartCart: EngineSmartCart.catch(void 0),
4763
4793
  smartFlows: z93.array(z93.unknown())
4764
4794
  });
4765
4795
 
@@ -6753,6 +6783,7 @@ export {
6753
6783
  DiscountSource,
6754
6784
  DiscountType,
6755
6785
  EditorMode,
6786
+ EngineSmartCart,
6756
6787
  EventCalculationSchema,
6757
6788
  ExitPolicySchema,
6758
6789
  FinishedPurchaseSchema,
@@ -62,8 +62,9 @@ export type CabShopConfig = z.infer<typeof CabShopConfig>;
62
62
  *
63
63
  * The catch lands on the {@link DRIFTED_SMART_CART} identity sentinel (no components ⇒ no bars), not
64
64
  * `undefined`, so the server's progress-bar resolution can tell a drifted config from a shop with no smart
65
- * cart (`null`/absent stay `null`/`undefined`) and emit a `shopConfig` drift (REB-25139: this catch used to
66
- * drop every progress bar for the shop silently).
65
+ * cart (`null`/absent stay `null`/`undefined`, and the engine's `false` reads as `null` via
66
+ * {@link EngineSmartCart}) and emit a `shopConfig` drift (REB-25139: this catch used to drop every progress
67
+ * bar for the shop silently; REB-25187: `false` used to land on the sentinel and report a false drift).
67
68
  */
68
69
  export declare const CabUserConfig: z.ZodObject<{
69
70
  shop: z.ZodObject<{
@@ -98,7 +99,7 @@ export declare const CabUserConfig: z.ZodObject<{
98
99
  shopId: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
99
100
  shopName: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
100
101
  }, z.core.$strip>;
101
- smartCart: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodObject<{
102
+ smartCart: z.ZodCatch<z.ZodPreprocess<z.ZodOptional<z.ZodNullable<z.ZodObject<{
102
103
  components: z.ZodOptional<z.ZodArray<z.ZodObject<{
103
104
  settings: z.ZodCatch<z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
104
105
  bars: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -138,7 +139,10 @@ export declare const CabUserConfig: z.ZodObject<{
138
139
  discountType: z.ZodOptional<z.ZodString>;
139
140
  exclusions: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
140
141
  collectionIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
141
- productIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
142
+ products: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
143
+ productId: z.ZodCatch<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
144
+ variantIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
145
+ }, z.core.$loose>>>>;
142
146
  tags: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodString>>>;
143
147
  type: z.ZodCatch<z.ZodOptional<z.ZodString>>;
144
148
  }, z.core.$loose>>>>;
@@ -169,6 +173,6 @@ export declare const CabUserConfig: z.ZodObject<{
169
173
  }, z.core.$loose>>>>;
170
174
  type: z.ZodOptional<z.ZodString>;
171
175
  }, z.core.$loose>>>;
172
- }, z.core.$loose>>>>;
176
+ }, z.core.$loose>>>>>;
173
177
  }, z.core.$strip>;
174
178
  export type CabUserConfig = z.infer<typeof CabUserConfig>;
@@ -1317,7 +1317,17 @@ var GIFT_LABELS = {
1317
1317
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1318
1318
  var CABProgressTierExclusion = import_zod15.z.object({
1319
1319
  collectionIds: import_zod15.z.array(import_zod15.z.number().int().positive()).default(() => []),
1320
- productIds: import_zod15.z.array(import_zod15.z.number().int().positive()).default(() => []),
1320
+ /**
1321
+ * `products` rules: each excluded product with ITS OWN variants, mirroring the bar-level
1322
+ * excluded products. An empty `variantIds` means "the whole product", which is how the admin
1323
+ * picker stores a whole-product selection, and a populated one means those variants.
1324
+ */
1325
+ products: import_zod15.z.array(
1326
+ import_zod15.z.object({
1327
+ productId: import_zod15.z.number().int().positive(),
1328
+ variantIds: import_zod15.z.array(import_zod15.z.number().int().positive()).default(() => [])
1329
+ })
1330
+ ).default(() => []),
1321
1331
  tags: import_zod15.z.array(import_zod15.z.string().min(1)).default(() => []),
1322
1332
  type: import_zod15.z.enum(progressTierExclusionTypes)
1323
1333
  });
@@ -1102,7 +1102,17 @@ var GIFT_LABELS = {
1102
1102
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1103
1103
  var CABProgressTierExclusion = z15.object({
1104
1104
  collectionIds: z15.array(z15.number().int().positive()).default(() => []),
1105
- productIds: z15.array(z15.number().int().positive()).default(() => []),
1105
+ /**
1106
+ * `products` rules: each excluded product with ITS OWN variants, mirroring the bar-level
1107
+ * excluded products. An empty `variantIds` means "the whole product", which is how the admin
1108
+ * picker stores a whole-product selection, and a populated one means those variants.
1109
+ */
1110
+ products: z15.array(
1111
+ z15.object({
1112
+ productId: z15.number().int().positive(),
1113
+ variantIds: z15.array(z15.number().int().positive()).default(() => [])
1114
+ })
1115
+ ).default(() => []),
1106
1116
  tags: z15.array(z15.string().min(1)).default(() => []),
1107
1117
  type: z15.enum(progressTierExclusionTypes)
1108
1118
  });
@@ -23,7 +23,10 @@ export declare const SmartCartTierProduct: z.ZodObject<{
23
23
  */
24
24
  export declare const SmartCartTierExclusion: z.ZodObject<{
25
25
  collectionIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
26
- productIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
26
+ products: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
27
+ productId: z.ZodCatch<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
28
+ variantIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
29
+ }, z.core.$loose>>>>;
27
30
  tags: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodString>>>;
28
31
  type: z.ZodCatch<z.ZodOptional<z.ZodString>>;
29
32
  }, z.core.$loose>;
@@ -61,7 +64,10 @@ export declare const SmartCartTier: z.ZodObject<{
61
64
  discountType: z.ZodOptional<z.ZodString>;
62
65
  exclusions: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
63
66
  collectionIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
64
- productIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
67
+ products: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
68
+ productId: z.ZodCatch<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
69
+ variantIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
70
+ }, z.core.$loose>>>>;
65
71
  tags: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodString>>>;
66
72
  type: z.ZodCatch<z.ZodOptional<z.ZodString>>;
67
73
  }, z.core.$loose>>>>;
@@ -130,7 +136,10 @@ export declare const SmartCartBar: z.ZodObject<{
130
136
  discountType: z.ZodOptional<z.ZodString>;
131
137
  exclusions: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
132
138
  collectionIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
133
- productIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
139
+ products: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
140
+ productId: z.ZodCatch<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
141
+ variantIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
142
+ }, z.core.$loose>>>>;
134
143
  tags: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodString>>>;
135
144
  type: z.ZodCatch<z.ZodOptional<z.ZodString>>;
136
145
  }, z.core.$loose>>>>;
@@ -198,7 +207,10 @@ export declare const SmartCartComponent: z.ZodObject<{
198
207
  discountType: z.ZodOptional<z.ZodString>;
199
208
  exclusions: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
200
209
  collectionIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
201
- productIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
210
+ products: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
211
+ productId: z.ZodCatch<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
212
+ variantIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
213
+ }, z.core.$loose>>>>;
202
214
  tags: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodString>>>;
203
215
  type: z.ZodCatch<z.ZodOptional<z.ZodString>>;
204
216
  }, z.core.$loose>>>>;
@@ -233,7 +245,7 @@ export declare const SmartCartComponent: z.ZodObject<{
233
245
  * The subset of the shop's smart-cart config the checkout extension reads: the
234
246
  * `tiered_progress_bar` component(s) and their bars/tiers. The rest of the onsite
235
247
  * smart-cart config (buy-more-save-more, custom templates/CSS, callbacks) is out of
236
- * scope — `looseObject` preserves-but-ignores it. Parsed under `UserConfig.smartCart`
248
+ * scope — `looseObject` preserves-but-ignores it. Parsed via {@link EngineSmartCart} under `UserConfig.smartCart`
237
249
  * (`.catch(undefined)`) and `CabUserConfig.smartCart` (`.catch` to a drift sentinel) so a shape
238
250
  * drift here can NEVER break apiKey resolution for offers / monetize / analytics / gift validation.
239
251
  */
@@ -277,7 +289,10 @@ export declare const SmartCartConfig: z.ZodObject<{
277
289
  discountType: z.ZodOptional<z.ZodString>;
278
290
  exclusions: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
279
291
  collectionIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
280
- productIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
292
+ products: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
293
+ productId: z.ZodCatch<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
294
+ variantIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
295
+ }, z.core.$loose>>>>;
281
296
  tags: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodString>>>;
282
297
  type: z.ZodCatch<z.ZodOptional<z.ZodString>>;
283
298
  }, z.core.$loose>>>>;
@@ -309,7 +324,90 @@ export declare const SmartCartConfig: z.ZodObject<{
309
324
  type: z.ZodOptional<z.ZodString>;
310
325
  }, z.core.$loose>>>;
311
326
  }, z.core.$loose>;
327
+ /**
328
+ * The `smartCart` field of `/api/v1/user/config` as the engine actually sends it. A shop with no enabled
329
+ * Smart Cart arrives as `smart_cart: false` (the engine's "none" vocabulary, like `null`/absent), so `false`
330
+ * reads as `null` before the object schema sees it: no smart cart, no bars, and no drift. Only `false` — a
331
+ * `true`, a string or a number is a genuine retype and falls through to the reader's own `.catch`.
332
+ * `UserConfig` and `CabUserConfig` both parse through this, each adding its own config-level `.catch`.
333
+ */
334
+ export declare const EngineSmartCart: z.ZodPreprocess<z.ZodOptional<z.ZodNullable<z.ZodObject<{
335
+ components: z.ZodOptional<z.ZodArray<z.ZodObject<{
336
+ settings: z.ZodCatch<z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
337
+ bars: z.ZodOptional<z.ZodArray<z.ZodObject<{
338
+ countryCodes: z.ZodOptional<z.ZodArray<z.ZodString>>;
339
+ excludeDiscountInSubtotal: z.ZodOptional<z.ZodBoolean>;
340
+ excludedProducts: z.ZodOptional<z.ZodArray<z.ZodObject<{
341
+ variantIds: z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>;
342
+ }, z.core.$loose>>>;
343
+ freeShippingOnSubscription: z.ZodOptional<z.ZodBoolean>;
344
+ geolocationEnabled: z.ZodOptional<z.ZodBoolean>;
345
+ id: z.ZodOptional<z.ZodString>;
346
+ language: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
347
+ freeShippingReached: z.ZodOptional<z.ZodString>;
348
+ freeShippingRemaining: z.ZodOptional<z.ZodString>;
349
+ giftAreaTitle: z.ZodOptional<z.ZodString>;
350
+ }, z.core.$loose>>>;
351
+ name: z.ZodOptional<z.ZodString>;
352
+ tiers: z.ZodOptional<z.ZodArray<z.ZodObject<{
353
+ allProducts: z.ZodOptional<z.ZodArray<z.ZodObject<{
354
+ handle: z.ZodOptional<z.ZodString>;
355
+ id: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
356
+ productId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
357
+ title: z.ZodOptional<z.ZodString>;
358
+ variantIds: z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>;
359
+ }, z.core.$loose>>>;
360
+ customTierLabel: z.ZodOptional<z.ZodBoolean>;
361
+ customTierLabelText: z.ZodOptional<z.ZodString>;
362
+ decorativeAmountReachedLabel: z.ZodOptional<z.ZodBoolean>;
363
+ decorativeAmountReachedLabelText: z.ZodOptional<z.ZodString>;
364
+ decorativeAmountRemainingLabel: z.ZodOptional<z.ZodBoolean>;
365
+ decorativeAmountRemainingLabelText: z.ZodOptional<z.ZodString>;
366
+ discountAmountFromTotal: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
367
+ discountAmountReachedLabel: z.ZodOptional<z.ZodBoolean>;
368
+ discountAmountReachedLabelText: z.ZodOptional<z.ZodString>;
369
+ discountAmountRemainingLabel: z.ZodOptional<z.ZodBoolean>;
370
+ discountAmountRemainingLabelText: z.ZodOptional<z.ZodString>;
371
+ discountType: z.ZodOptional<z.ZodString>;
372
+ exclusions: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
373
+ collectionIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
374
+ products: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
375
+ productId: z.ZodCatch<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
376
+ variantIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
377
+ }, z.core.$loose>>>>;
378
+ tags: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodString>>>;
379
+ type: z.ZodCatch<z.ZodOptional<z.ZodString>>;
380
+ }, z.core.$loose>>>>;
381
+ exclusionsEnabled: z.ZodCatch<z.ZodOptional<z.ZodBoolean>>;
382
+ filterOosVariants: z.ZodOptional<z.ZodBoolean>;
383
+ id: z.ZodOptional<z.ZodString>;
384
+ minimum: z.ZodPreprocess<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
385
+ presentmentCurrencies: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
386
+ enabled: z.ZodOptional<z.ZodBoolean>;
387
+ }, z.core.$loose>>>;
388
+ productAmountReachedLabel: z.ZodOptional<z.ZodBoolean>;
389
+ productAmountReachedLabelText: z.ZodOptional<z.ZodString>;
390
+ productAmountRemainingLabel: z.ZodOptional<z.ZodBoolean>;
391
+ productAmountRemainingLabelText: z.ZodOptional<z.ZodString>;
392
+ products: z.ZodOptional<z.ZodArray<z.ZodObject<{
393
+ handle: z.ZodOptional<z.ZodString>;
394
+ id: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
395
+ productId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
396
+ title: z.ZodOptional<z.ZodString>;
397
+ variantIds: z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>;
398
+ }, z.core.$loose>>>;
399
+ productTierElementSize: z.ZodCatch<z.ZodOptional<z.ZodString>>;
400
+ productTierImage: z.ZodCatch<z.ZodOptional<z.ZodBoolean>>;
401
+ type: z.ZodOptional<z.ZodString>;
402
+ unlockConditionType: z.ZodOptional<z.ZodString>;
403
+ }, z.core.$loose>>>;
404
+ }, z.core.$loose>>>;
405
+ }, z.core.$loose>>>>;
406
+ type: z.ZodOptional<z.ZodString>;
407
+ }, z.core.$loose>>>;
408
+ }, z.core.$loose>>>>;
312
409
  export type SmartCartBar = z.infer<typeof SmartCartBar>;
313
410
  export type SmartCartConfig = z.infer<typeof SmartCartConfig>;
314
411
  export type SmartCartTier = z.infer<typeof SmartCartTier>;
412
+ export type SmartCartTierExclusion = z.infer<typeof SmartCartTierExclusion>;
315
413
  export type SmartCartTierProduct = z.infer<typeof SmartCartTierProduct>;
@@ -127,7 +127,22 @@ var SmartCartTierProduct = import_zod2.z.looseObject({
127
127
  });
128
128
  var SmartCartTierExclusion = import_zod2.z.looseObject({
129
129
  collectionIds: import_zod2.z.array(import_zod2.z.coerce.number()).optional().catch(void 0),
130
- productIds: import_zod2.z.array(import_zod2.z.coerce.number()).optional().catch(void 0),
130
+ /**
131
+ * onsite keeps each excluded product with ITS OWN variants, the same shape the bar-level
132
+ * `excludedProducts` uses, so a rule can exclude one variant of B without touching A.
133
+ * Flat parallel id lists cannot express that mapping.
134
+ *
135
+ * camelCase like every other key in this file, NOT the `product_id` / `variant_ids` the onsite
136
+ * payload spells: `parseShielded` runs `deepCamelCase` over the tree BEFORE any schema sees it.
137
+ * A snake_case key here reads as absent, every entry drops, and the converter discards the whole
138
+ * rule in silence — the exclusion just never reaches checkout.
139
+ */
140
+ products: import_zod2.z.array(
141
+ import_zod2.z.looseObject({
142
+ productId: import_zod2.z.coerce.number().optional().catch(void 0),
143
+ variantIds: import_zod2.z.array(import_zod2.z.coerce.number()).optional().catch(void 0)
144
+ })
145
+ ).optional().catch(void 0),
131
146
  tags: import_zod2.z.array(import_zod2.z.string()).optional().catch(void 0),
132
147
  type: import_zod2.z.string().optional().catch(void 0)
133
148
  });
@@ -262,14 +277,19 @@ var SmartCartComponent = import_zod2.z.looseObject({
262
277
  var SmartCartConfig = import_zod2.z.looseObject({
263
278
  components: import_zod2.z.array(SmartCartComponent).optional()
264
279
  });
280
+ var EngineSmartCart = import_zod2.z.preprocess((value) => value === false ? null : value, SmartCartConfig.nullish());
265
281
 
266
282
  // src/schema/userConfig.ts
267
283
  var UserConfig = import_zod3.z.object({
268
284
  shop: ShopConfig,
269
285
  /**
270
- * `.catch(undefined)` is the safety bar: smart-cart shape drift can NEVER fail `fetchUserConfig`,
271
- * which resolves the apiKey for every offers/monetize/analytics/gift request.
286
+ * Parsed like `CabUserConfig.smartCart`: the engine's `false` reads as `null` ({@link EngineSmartCart}), a
287
+ * drifted component loses only its own settings (`SmartCartComponent.settings` catches per component), and
288
+ * `.catch(undefined)` is the last safety bar so a wholly unreadable config can never fail the parse that
289
+ * resolves the shop's apiKey. It lands on `undefined`, not the `DRIFTED_SMART_CART` sentinel: no drift
290
+ * reporter reads this schema (the server parses `CabUserConfig`), and that sentinel's identity is not
291
+ * exported from `./schema`, so a consumer could not tell it apart from an empty config anyway.
272
292
  */
273
- smartCart: SmartCartConfig.nullish().catch(void 0),
293
+ smartCart: EngineSmartCart.catch(void 0),
274
294
  smartFlows: import_zod3.z.array(import_zod3.z.unknown())
275
295
  });
@@ -103,7 +103,22 @@ var SmartCartTierProduct = z2.looseObject({
103
103
  });
104
104
  var SmartCartTierExclusion = z2.looseObject({
105
105
  collectionIds: z2.array(z2.coerce.number()).optional().catch(void 0),
106
- productIds: z2.array(z2.coerce.number()).optional().catch(void 0),
106
+ /**
107
+ * onsite keeps each excluded product with ITS OWN variants, the same shape the bar-level
108
+ * `excludedProducts` uses, so a rule can exclude one variant of B without touching A.
109
+ * Flat parallel id lists cannot express that mapping.
110
+ *
111
+ * camelCase like every other key in this file, NOT the `product_id` / `variant_ids` the onsite
112
+ * payload spells: `parseShielded` runs `deepCamelCase` over the tree BEFORE any schema sees it.
113
+ * A snake_case key here reads as absent, every entry drops, and the converter discards the whole
114
+ * rule in silence — the exclusion just never reaches checkout.
115
+ */
116
+ products: z2.array(
117
+ z2.looseObject({
118
+ productId: z2.coerce.number().optional().catch(void 0),
119
+ variantIds: z2.array(z2.coerce.number()).optional().catch(void 0)
120
+ })
121
+ ).optional().catch(void 0),
107
122
  tags: z2.array(z2.string()).optional().catch(void 0),
108
123
  type: z2.string().optional().catch(void 0)
109
124
  });
@@ -238,15 +253,20 @@ var SmartCartComponent = z2.looseObject({
238
253
  var SmartCartConfig = z2.looseObject({
239
254
  components: z2.array(SmartCartComponent).optional()
240
255
  });
256
+ var EngineSmartCart = z2.preprocess((value) => value === false ? null : value, SmartCartConfig.nullish());
241
257
 
242
258
  // src/schema/userConfig.ts
243
259
  var UserConfig = z3.object({
244
260
  shop: ShopConfig,
245
261
  /**
246
- * `.catch(undefined)` is the safety bar: smart-cart shape drift can NEVER fail `fetchUserConfig`,
247
- * which resolves the apiKey for every offers/monetize/analytics/gift request.
262
+ * Parsed like `CabUserConfig.smartCart`: the engine's `false` reads as `null` ({@link EngineSmartCart}), a
263
+ * drifted component loses only its own settings (`SmartCartComponent.settings` catches per component), and
264
+ * `.catch(undefined)` is the last safety bar so a wholly unreadable config can never fail the parse that
265
+ * resolves the shop's apiKey. It lands on `undefined`, not the `DRIFTED_SMART_CART` sentinel: no drift
266
+ * reporter reads this schema (the server parses `CabUserConfig`), and that sentinel's identity is not
267
+ * exported from `./schema`, so a consumer could not tell it apart from an empty config anyway.
248
268
  */
249
- smartCart: SmartCartConfig.nullish().catch(void 0),
269
+ smartCart: EngineSmartCart.catch(void 0),
250
270
  smartFlows: z3.array(z3.unknown())
251
271
  });
252
272
  export {
@@ -78,7 +78,7 @@ export declare const UserConfig: z.ZodObject<{
78
78
  storefrontAccessToken: z.ZodNullable<z.ZodString>;
79
79
  useRebuyIcons: z.ZodBoolean;
80
80
  }, z.core.$strip>;
81
- smartCart: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodObject<{
81
+ smartCart: z.ZodCatch<z.ZodPreprocess<z.ZodOptional<z.ZodNullable<z.ZodObject<{
82
82
  components: z.ZodOptional<z.ZodArray<z.ZodObject<{
83
83
  settings: z.ZodCatch<z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
84
84
  bars: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -118,7 +118,10 @@ export declare const UserConfig: z.ZodObject<{
118
118
  discountType: z.ZodOptional<z.ZodString>;
119
119
  exclusions: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
120
120
  collectionIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
121
- productIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
121
+ products: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodObject<{
122
+ productId: z.ZodCatch<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
123
+ variantIds: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>>;
124
+ }, z.core.$loose>>>>;
122
125
  tags: z.ZodCatch<z.ZodOptional<z.ZodArray<z.ZodString>>>;
123
126
  type: z.ZodCatch<z.ZodOptional<z.ZodString>>;
124
127
  }, z.core.$loose>>>>;
@@ -149,7 +152,7 @@ export declare const UserConfig: z.ZodObject<{
149
152
  }, z.core.$loose>>>>;
150
153
  type: z.ZodOptional<z.ZodString>;
151
154
  }, z.core.$loose>>>;
152
- }, z.core.$loose>>>>;
155
+ }, z.core.$loose>>>>>;
153
156
  smartFlows: z.ZodArray<z.ZodUnknown>;
154
157
  }, z.core.$strip>;
155
158
  export type UserConfig = z.infer<typeof UserConfig>;
@@ -1138,7 +1138,17 @@ var GIFT_LABELS = {
1138
1138
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1139
1139
  var CABProgressTierExclusion = import_zod18.z.object({
1140
1140
  collectionIds: import_zod18.z.array(import_zod18.z.number().int().positive()).default(() => []),
1141
- productIds: import_zod18.z.array(import_zod18.z.number().int().positive()).default(() => []),
1141
+ /**
1142
+ * `products` rules: each excluded product with ITS OWN variants, mirroring the bar-level
1143
+ * excluded products. An empty `variantIds` means "the whole product", which is how the admin
1144
+ * picker stores a whole-product selection, and a populated one means those variants.
1145
+ */
1146
+ products: import_zod18.z.array(
1147
+ import_zod18.z.object({
1148
+ productId: import_zod18.z.number().int().positive(),
1149
+ variantIds: import_zod18.z.array(import_zod18.z.number().int().positive()).default(() => [])
1150
+ })
1151
+ ).default(() => []),
1142
1152
  tags: import_zod18.z.array(import_zod18.z.string().min(1)).default(() => []),
1143
1153
  type: import_zod18.z.enum(progressTierExclusionTypes)
1144
1154
  });
@@ -1113,7 +1113,17 @@ var GIFT_LABELS = {
1113
1113
  // src/schema/widgets/checkout-and-beyond/progressBar.ts
1114
1114
  var CABProgressTierExclusion = z18.object({
1115
1115
  collectionIds: z18.array(z18.number().int().positive()).default(() => []),
1116
- productIds: z18.array(z18.number().int().positive()).default(() => []),
1116
+ /**
1117
+ * `products` rules: each excluded product with ITS OWN variants, mirroring the bar-level
1118
+ * excluded products. An empty `variantIds` means "the whole product", which is how the admin
1119
+ * picker stores a whole-product selection, and a populated one means those variants.
1120
+ */
1121
+ products: z18.array(
1122
+ z18.object({
1123
+ productId: z18.number().int().positive(),
1124
+ variantIds: z18.array(z18.number().int().positive()).default(() => [])
1125
+ })
1126
+ ).default(() => []),
1117
1127
  tags: z18.array(z18.string().min(1)).default(() => []),
1118
1128
  type: z18.enum(progressTierExclusionTypes)
1119
1129
  });
@@ -235,8 +235,8 @@ export type ProgressTierUnit = (typeof progressTierUnits)[number];
235
235
  /** What a per-tier exclusion rule matches cart lines by (onsite `CartProgressBarTierExclusionType`). */
236
236
  export declare const progressTierExclusionTypes: readonly ["collections", "products", "tags"];
237
237
  export declare const ProgressTierExclusionType: {
238
- readonly tags: "tags";
239
238
  readonly products: "products";
239
+ readonly tags: "tags";
240
240
  readonly collections: "collections";
241
241
  };
242
242
  export type ProgressTierExclusionType = (typeof progressTierExclusionTypes)[number];