@rebuy/rebuy 3.60.1 → 3.60.3
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/cab/hasOwnKey.d.ts +8 -0
- package/dist/cab/index.cjs +7 -4
- package/dist/cab/index.mjs +7 -4
- package/dist/cab/selectLanguage.d.ts +1 -1
- package/dist/index.cjs +36 -8
- package/dist/index.mjs +36 -8
- package/dist/schema/cabShopConfig.d.ts +11 -6
- package/dist/schema/driftedSmartCart.d.ts +15 -0
- package/dist/schema/smartCart.d.ts +20 -20
- package/dist/schema/user-config.cjs +37 -7
- package/dist/schema/user-config.mjs +37 -7
- package/dist/schema/userConfig.d.ts +6 -6
- package/dist/server/index.cjs +57 -9
- package/dist/server/index.mjs +57 -9
- package/dist/transforms/index.cjs +4 -1
- package/dist/transforms/index.mjs +4 -1
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether `key` is an OWN key of `object`, never an inherited `Object.prototype` one (`constructor`,
|
|
3
|
+
* `toString`, `__proto__`) — what `Object.hasOwn` answers, without needing it. `Object.hasOwn` is ES2022:
|
|
4
|
+
* Safari/iOS before 15.4 and Chromium before 93 lack it, those buyers still load every renderer that bundles
|
|
5
|
+
* `./cab`, and esbuild's `es2020` target rewrites syntax only, so the call shipped as-is and threw on the first
|
|
6
|
+
* section render (REB-24990). Read off `Object.prototype` so an own `hasOwnProperty` key cannot shadow it.
|
|
7
|
+
*/
|
|
8
|
+
export declare const hasOwnKey: (object: object, key: PropertyKey) => boolean;
|
package/dist/cab/index.cjs
CHANGED
|
@@ -45,6 +45,9 @@ var asLayout = (section) => ({
|
|
|
45
45
|
visibility: void 0
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
+
// src/cab/hasOwnKey.ts
|
|
49
|
+
var hasOwnKey = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
50
|
+
|
|
48
51
|
// src/schema/widgets/checkout-and-beyond/regex.ts
|
|
49
52
|
var DYNAMIC_TOKEN_REGEX = /^\{\{\s*[A-Za-z]+\s*\}\}$/;
|
|
50
53
|
var DYNAMIC_TOKEN_ANYWHERE_REGEX = /\{\{\s*[A-Za-z0-9_]+\s*\}\}/;
|
|
@@ -54,9 +57,9 @@ var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
|
|
|
54
57
|
var TOKEN_REGEX = /{{1,2}\s*([^{}\s]+)\s*}{1,2}/g;
|
|
55
58
|
var toCamelCase = (key) => key.replace(/_([a-z0-9])/g, (_, char) => char.toUpperCase());
|
|
56
59
|
var resolveKey = (key, variables) => {
|
|
57
|
-
if (
|
|
60
|
+
if (hasOwnKey(variables, key)) return key;
|
|
58
61
|
const camel = toCamelCase(key);
|
|
59
|
-
if (
|
|
62
|
+
if (hasOwnKey(variables, camel)) return camel;
|
|
60
63
|
const lower = camel.toLowerCase();
|
|
61
64
|
return Object.keys(variables).find((name) => name.toLowerCase() === lower);
|
|
62
65
|
};
|
|
@@ -70,8 +73,8 @@ var interpolateAndSanitize = (input, variables) => (input ?? "").replace(TOKEN_R
|
|
|
70
73
|
var FALLBACK_LANGUAGE = "en";
|
|
71
74
|
var selectLanguage = (content, language) => {
|
|
72
75
|
if (!content) return void 0;
|
|
73
|
-
if (language &&
|
|
74
|
-
if (
|
|
76
|
+
if (language && hasOwnKey(content, language)) return content[language];
|
|
77
|
+
if (hasOwnKey(content, FALLBACK_LANGUAGE)) return content[FALLBACK_LANGUAGE];
|
|
75
78
|
return Object.values(content)[0];
|
|
76
79
|
};
|
|
77
80
|
|
package/dist/cab/index.mjs
CHANGED
|
@@ -7,6 +7,9 @@ var asLayout = (section) => ({
|
|
|
7
7
|
visibility: void 0
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
+
// src/cab/hasOwnKey.ts
|
|
11
|
+
var hasOwnKey = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
12
|
+
|
|
10
13
|
// src/schema/widgets/checkout-and-beyond/regex.ts
|
|
11
14
|
var DYNAMIC_TOKEN_REGEX = /^\{\{\s*[A-Za-z]+\s*\}\}$/;
|
|
12
15
|
var DYNAMIC_TOKEN_ANYWHERE_REGEX = /\{\{\s*[A-Za-z0-9_]+\s*\}\}/;
|
|
@@ -16,9 +19,9 @@ var HTML_TAGS_REGEX = /<\/?[a-zA-Z][^>]*>/g;
|
|
|
16
19
|
var TOKEN_REGEX = /{{1,2}\s*([^{}\s]+)\s*}{1,2}/g;
|
|
17
20
|
var toCamelCase = (key) => key.replace(/_([a-z0-9])/g, (_, char) => char.toUpperCase());
|
|
18
21
|
var resolveKey = (key, variables) => {
|
|
19
|
-
if (
|
|
22
|
+
if (hasOwnKey(variables, key)) return key;
|
|
20
23
|
const camel = toCamelCase(key);
|
|
21
|
-
if (
|
|
24
|
+
if (hasOwnKey(variables, camel)) return camel;
|
|
22
25
|
const lower = camel.toLowerCase();
|
|
23
26
|
return Object.keys(variables).find((name) => name.toLowerCase() === lower);
|
|
24
27
|
};
|
|
@@ -32,8 +35,8 @@ var interpolateAndSanitize = (input, variables) => (input ?? "").replace(TOKEN_R
|
|
|
32
35
|
var FALLBACK_LANGUAGE = "en";
|
|
33
36
|
var selectLanguage = (content, language) => {
|
|
34
37
|
if (!content) return void 0;
|
|
35
|
-
if (language &&
|
|
36
|
-
if (
|
|
38
|
+
if (language && hasOwnKey(content, language)) return content[language];
|
|
39
|
+
if (hasOwnKey(content, FALLBACK_LANGUAGE)) return content[FALLBACK_LANGUAGE];
|
|
37
40
|
return Object.values(content)[0];
|
|
38
41
|
};
|
|
39
42
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Fallback chain: requested language, then 'en', then first available value.
|
|
3
3
|
*
|
|
4
|
-
* `
|
|
4
|
+
* Own keys only (`hasOwnKey`), never `in` — `in` would resolve an inherited `Object.prototype` key (`constructor`,
|
|
5
5
|
* `toString`) as if it were a translation. Far less reachable than in `interpolateAndSanitize`, since a
|
|
6
6
|
* language code is not merchant-authored, but the two must agree on what counts as present.
|
|
7
7
|
*/
|
package/dist/index.cjs
CHANGED
|
@@ -1212,8 +1212,13 @@ var import_zod2 = require("zod");
|
|
|
1212
1212
|
// src/schema/driftedMarkets.ts
|
|
1213
1213
|
var DRIFTED_MARKETS = Object.freeze({ enabled: false });
|
|
1214
1214
|
|
|
1215
|
+
// src/schema/driftedSmartCart.ts
|
|
1216
|
+
var DRIFTED_SMART_CART_SETTINGS = Object.freeze({});
|
|
1217
|
+
var DRIFTED_SMART_CART = Object.freeze({});
|
|
1218
|
+
|
|
1215
1219
|
// src/schema/smartCart.ts
|
|
1216
1220
|
var import_zod = require("zod");
|
|
1221
|
+
var phpEmptyMapAsAbsent = (value) => Array.isArray(value) && value.length === 0 ? void 0 : value;
|
|
1217
1222
|
var SmartCartTierProduct = import_zod.z.looseObject({
|
|
1218
1223
|
handle: import_zod.z.string().optional(),
|
|
1219
1224
|
id: import_zod.z.coerce.number().optional(),
|
|
@@ -1267,7 +1272,11 @@ var SmartCartTier = import_zod.z.looseObject({
|
|
|
1267
1272
|
* `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
|
|
1268
1273
|
*/
|
|
1269
1274
|
minimum: import_zod.z.preprocess((value) => value == null ? void 0 : value, import_zod.z.coerce.number().optional()),
|
|
1270
|
-
|
|
1275
|
+
/** An empty map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed tier. */
|
|
1276
|
+
presentmentCurrencies: import_zod.z.preprocess(
|
|
1277
|
+
phpEmptyMapAsAbsent,
|
|
1278
|
+
import_zod.z.looseObject({ enabled: import_zod.z.boolean().optional() }).optional()
|
|
1279
|
+
),
|
|
1271
1280
|
productAmountReachedLabel: import_zod.z.boolean().optional(),
|
|
1272
1281
|
productAmountReachedLabelText: import_zod.z.string().optional(),
|
|
1273
1282
|
productAmountRemainingLabel: import_zod.z.boolean().optional(),
|
|
@@ -1320,16 +1329,35 @@ var SmartCartBar = import_zod.z.looseObject({
|
|
|
1320
1329
|
freeShippingOnSubscription: import_zod.z.boolean().optional(),
|
|
1321
1330
|
geolocationEnabled: import_zod.z.boolean().optional(),
|
|
1322
1331
|
id: import_zod.z.string().optional(),
|
|
1323
|
-
language
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1332
|
+
/** An empty `language` map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed bar. */
|
|
1333
|
+
language: import_zod.z.preprocess(
|
|
1334
|
+
phpEmptyMapAsAbsent,
|
|
1335
|
+
import_zod.z.looseObject({
|
|
1336
|
+
freeShippingReached: import_zod.z.string().optional(),
|
|
1337
|
+
freeShippingRemaining: import_zod.z.string().optional(),
|
|
1338
|
+
giftAreaTitle: import_zod.z.string().optional()
|
|
1339
|
+
}).optional()
|
|
1340
|
+
),
|
|
1328
1341
|
name: import_zod.z.string().optional(),
|
|
1329
1342
|
tiers: import_zod.z.array(SmartCartTier).optional()
|
|
1330
1343
|
});
|
|
1331
1344
|
var SmartCartComponent = import_zod.z.looseObject({
|
|
1332
|
-
|
|
1345
|
+
/**
|
|
1346
|
+
* Every component in the layout is parsed, not just the progress bar, so this field is the blast-radius
|
|
1347
|
+
* boundary (REB-25139): before it caught, b.box's `cart_items` component arriving as `settings: []` failed
|
|
1348
|
+
* the component, the `components` array and the whole config — and `CabUserConfig`'s config-level catch
|
|
1349
|
+
* then silently dropped every progress bar for the shop. Now:
|
|
1350
|
+
*
|
|
1351
|
+
* - PHP's empty-map `[]` reads as absent ({@link phpEmptyMapAsAbsent}) — normal engine vocabulary, no drift.
|
|
1352
|
+
* - Any other unreadable settings (a string, a non-empty array, a bar that fails its schema) `.catch` to the
|
|
1353
|
+
* {@link DRIFTED_SMART_CART_SETTINGS} identity sentinel: that component loses its settings (no bars),
|
|
1354
|
+
* its siblings — and the progress bar, when it is a sibling — still parse, and the server's progress-bar
|
|
1355
|
+
* resolution emits a `shopConfig` drift on seeing the sentinel.
|
|
1356
|
+
*
|
|
1357
|
+
* Bars are not salvaged per element: the only reader takes the first progress-bar component's bars as a
|
|
1358
|
+
* set (one per geo segment), and a drifted bar now costs that component's bars WITH a drift, not the cart.
|
|
1359
|
+
*/
|
|
1360
|
+
settings: import_zod.z.preprocess(phpEmptyMapAsAbsent, import_zod.z.looseObject({ bars: import_zod.z.array(SmartCartBar).optional() }).optional()).catch(DRIFTED_SMART_CART_SETTINGS),
|
|
1333
1361
|
type: import_zod.z.string().optional()
|
|
1334
1362
|
});
|
|
1335
1363
|
var SmartCartConfig = import_zod.z.looseObject({
|
|
@@ -1432,7 +1460,7 @@ var CabShopConfig = import_zod2.z.object({
|
|
|
1432
1460
|
});
|
|
1433
1461
|
var CabUserConfig = import_zod2.z.object({
|
|
1434
1462
|
shop: CabShopConfig,
|
|
1435
|
-
smartCart: SmartCartConfig.nullish().catch(
|
|
1463
|
+
smartCart: SmartCartConfig.nullish().catch(DRIFTED_SMART_CART)
|
|
1436
1464
|
});
|
|
1437
1465
|
|
|
1438
1466
|
// src/schema/metadata.ts
|
package/dist/index.mjs
CHANGED
|
@@ -730,8 +730,13 @@ import { z as z2 } from "zod";
|
|
|
730
730
|
// src/schema/driftedMarkets.ts
|
|
731
731
|
var DRIFTED_MARKETS = Object.freeze({ enabled: false });
|
|
732
732
|
|
|
733
|
+
// src/schema/driftedSmartCart.ts
|
|
734
|
+
var DRIFTED_SMART_CART_SETTINGS = Object.freeze({});
|
|
735
|
+
var DRIFTED_SMART_CART = Object.freeze({});
|
|
736
|
+
|
|
733
737
|
// src/schema/smartCart.ts
|
|
734
738
|
import { z } from "zod";
|
|
739
|
+
var phpEmptyMapAsAbsent = (value) => Array.isArray(value) && value.length === 0 ? void 0 : value;
|
|
735
740
|
var SmartCartTierProduct = z.looseObject({
|
|
736
741
|
handle: z.string().optional(),
|
|
737
742
|
id: z.coerce.number().optional(),
|
|
@@ -785,7 +790,11 @@ var SmartCartTier = z.looseObject({
|
|
|
785
790
|
* `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
|
|
786
791
|
*/
|
|
787
792
|
minimum: z.preprocess((value) => value == null ? void 0 : value, z.coerce.number().optional()),
|
|
788
|
-
|
|
793
|
+
/** An empty map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed tier. */
|
|
794
|
+
presentmentCurrencies: z.preprocess(
|
|
795
|
+
phpEmptyMapAsAbsent,
|
|
796
|
+
z.looseObject({ enabled: z.boolean().optional() }).optional()
|
|
797
|
+
),
|
|
789
798
|
productAmountReachedLabel: z.boolean().optional(),
|
|
790
799
|
productAmountReachedLabelText: z.string().optional(),
|
|
791
800
|
productAmountRemainingLabel: z.boolean().optional(),
|
|
@@ -838,16 +847,35 @@ var SmartCartBar = z.looseObject({
|
|
|
838
847
|
freeShippingOnSubscription: z.boolean().optional(),
|
|
839
848
|
geolocationEnabled: z.boolean().optional(),
|
|
840
849
|
id: z.string().optional(),
|
|
841
|
-
language
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
850
|
+
/** An empty `language` map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed bar. */
|
|
851
|
+
language: z.preprocess(
|
|
852
|
+
phpEmptyMapAsAbsent,
|
|
853
|
+
z.looseObject({
|
|
854
|
+
freeShippingReached: z.string().optional(),
|
|
855
|
+
freeShippingRemaining: z.string().optional(),
|
|
856
|
+
giftAreaTitle: z.string().optional()
|
|
857
|
+
}).optional()
|
|
858
|
+
),
|
|
846
859
|
name: z.string().optional(),
|
|
847
860
|
tiers: z.array(SmartCartTier).optional()
|
|
848
861
|
});
|
|
849
862
|
var SmartCartComponent = z.looseObject({
|
|
850
|
-
|
|
863
|
+
/**
|
|
864
|
+
* Every component in the layout is parsed, not just the progress bar, so this field is the blast-radius
|
|
865
|
+
* boundary (REB-25139): before it caught, b.box's `cart_items` component arriving as `settings: []` failed
|
|
866
|
+
* the component, the `components` array and the whole config — and `CabUserConfig`'s config-level catch
|
|
867
|
+
* then silently dropped every progress bar for the shop. Now:
|
|
868
|
+
*
|
|
869
|
+
* - PHP's empty-map `[]` reads as absent ({@link phpEmptyMapAsAbsent}) — normal engine vocabulary, no drift.
|
|
870
|
+
* - Any other unreadable settings (a string, a non-empty array, a bar that fails its schema) `.catch` to the
|
|
871
|
+
* {@link DRIFTED_SMART_CART_SETTINGS} identity sentinel: that component loses its settings (no bars),
|
|
872
|
+
* its siblings — and the progress bar, when it is a sibling — still parse, and the server's progress-bar
|
|
873
|
+
* resolution emits a `shopConfig` drift on seeing the sentinel.
|
|
874
|
+
*
|
|
875
|
+
* Bars are not salvaged per element: the only reader takes the first progress-bar component's bars as a
|
|
876
|
+
* set (one per geo segment), and a drifted bar now costs that component's bars WITH a drift, not the cart.
|
|
877
|
+
*/
|
|
878
|
+
settings: z.preprocess(phpEmptyMapAsAbsent, z.looseObject({ bars: z.array(SmartCartBar).optional() }).optional()).catch(DRIFTED_SMART_CART_SETTINGS),
|
|
851
879
|
type: z.string().optional()
|
|
852
880
|
});
|
|
853
881
|
var SmartCartConfig = z.looseObject({
|
|
@@ -950,7 +978,7 @@ var CabShopConfig = z2.object({
|
|
|
950
978
|
});
|
|
951
979
|
var CabUserConfig = z2.object({
|
|
952
980
|
shop: CabShopConfig,
|
|
953
|
-
smartCart: SmartCartConfig.nullish().catch(
|
|
981
|
+
smartCart: SmartCartConfig.nullish().catch(DRIFTED_SMART_CART)
|
|
954
982
|
});
|
|
955
983
|
|
|
956
984
|
// src/schema/metadata.ts
|
|
@@ -59,6 +59,11 @@ export type CabShopConfig = z.infer<typeof CabShopConfig>;
|
|
|
59
59
|
* The lean `/api/v1/user/config` projection `fetchUserConfig` parses. `smartFlows` (schema-required on
|
|
60
60
|
* the full `UserConfig` but read by no CAB path) is dropped; `smartCart` keeps its `.catch()`
|
|
61
61
|
* safety bar so a smart-cart shape drift can never fail apiKey resolution.
|
|
62
|
+
*
|
|
63
|
+
* The catch lands on the {@link DRIFTED_SMART_CART} identity sentinel (no components ⇒ no bars), not
|
|
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).
|
|
62
67
|
*/
|
|
63
68
|
export declare const CabUserConfig: z.ZodObject<{
|
|
64
69
|
shop: z.ZodObject<{
|
|
@@ -95,7 +100,7 @@ export declare const CabUserConfig: z.ZodObject<{
|
|
|
95
100
|
}, z.core.$strip>;
|
|
96
101
|
smartCart: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
97
102
|
components: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
98
|
-
settings: z.ZodOptional<z.ZodObject<{
|
|
103
|
+
settings: z.ZodCatch<z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
99
104
|
bars: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
100
105
|
countryCodes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
101
106
|
excludeDiscountInSubtotal: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -105,11 +110,11 @@ export declare const CabUserConfig: z.ZodObject<{
|
|
|
105
110
|
freeShippingOnSubscription: z.ZodOptional<z.ZodBoolean>;
|
|
106
111
|
geolocationEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
107
112
|
id: z.ZodOptional<z.ZodString>;
|
|
108
|
-
language: z.ZodOptional<z.ZodObject<{
|
|
113
|
+
language: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
109
114
|
freeShippingReached: z.ZodOptional<z.ZodString>;
|
|
110
115
|
freeShippingRemaining: z.ZodOptional<z.ZodString>;
|
|
111
116
|
giftAreaTitle: z.ZodOptional<z.ZodString>;
|
|
112
|
-
}, z.core.$loose
|
|
117
|
+
}, z.core.$loose>>>;
|
|
113
118
|
name: z.ZodOptional<z.ZodString>;
|
|
114
119
|
tiers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
115
120
|
allProducts: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -141,9 +146,9 @@ export declare const CabUserConfig: z.ZodObject<{
|
|
|
141
146
|
filterOosVariants: z.ZodOptional<z.ZodBoolean>;
|
|
142
147
|
id: z.ZodOptional<z.ZodString>;
|
|
143
148
|
minimum: z.ZodPreprocess<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
144
|
-
presentmentCurrencies: z.ZodOptional<z.ZodObject<{
|
|
149
|
+
presentmentCurrencies: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
145
150
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
146
|
-
}, z.core.$loose
|
|
151
|
+
}, z.core.$loose>>>;
|
|
147
152
|
productAmountReachedLabel: z.ZodOptional<z.ZodBoolean>;
|
|
148
153
|
productAmountReachedLabelText: z.ZodOptional<z.ZodString>;
|
|
149
154
|
productAmountRemainingLabel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -161,7 +166,7 @@ export declare const CabUserConfig: z.ZodObject<{
|
|
|
161
166
|
unlockConditionType: z.ZodOptional<z.ZodString>;
|
|
162
167
|
}, z.core.$loose>>>;
|
|
163
168
|
}, z.core.$loose>>>;
|
|
164
|
-
}, z.core.$loose
|
|
169
|
+
}, z.core.$loose>>>>;
|
|
165
170
|
type: z.ZodOptional<z.ZodString>;
|
|
166
171
|
}, z.core.$loose>>>;
|
|
167
172
|
}, z.core.$loose>>>>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity sentinels for the smart-cart salvages (REB-25139), on the {@link file://./driftedMarkets.ts} pattern:
|
|
3
|
+
* the schema's `.catch` returns one of THESE frozen objects, and the server's progress-bar resolution detects the
|
|
4
|
+
* drift by reference and emits a `shopConfig` drift. Both read as "no bars" to every consumer — `settings: {}`
|
|
5
|
+
* carries no `bars`, a config `{}` carries no `components` — so a consumer that never checks identity degrades
|
|
6
|
+
* exactly as it would on a missing field.
|
|
7
|
+
*
|
|
8
|
+
* Deliberately NOT re-exported from `src/schema/index.ts` for the same reason as `DRIFTED_MARKETS`: identity only
|
|
9
|
+
* holds within one bundle, and the comparison lives in `./server` (`server/widgetSettings.ts`), where the
|
|
10
|
+
* `CabUserConfig` parse that produced the value also runs.
|
|
11
|
+
*/
|
|
12
|
+
/** A smart-cart component whose `settings` failed to parse: dropped to no settings, its siblings kept. */
|
|
13
|
+
export declare const DRIFTED_SMART_CART_SETTINGS: Readonly<{}>;
|
|
14
|
+
/** A smart-cart config that failed to parse as a whole (e.g. a non-array `components`): no components. */
|
|
15
|
+
export declare const DRIFTED_SMART_CART: Readonly<{}>;
|
|
@@ -69,9 +69,9 @@ export declare const SmartCartTier: z.ZodObject<{
|
|
|
69
69
|
filterOosVariants: z.ZodOptional<z.ZodBoolean>;
|
|
70
70
|
id: z.ZodOptional<z.ZodString>;
|
|
71
71
|
minimum: z.ZodPreprocess<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
72
|
-
presentmentCurrencies: z.ZodOptional<z.ZodObject<{
|
|
72
|
+
presentmentCurrencies: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
73
73
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
74
|
-
}, z.core.$loose
|
|
74
|
+
}, z.core.$loose>>>;
|
|
75
75
|
productAmountReachedLabel: z.ZodOptional<z.ZodBoolean>;
|
|
76
76
|
productAmountReachedLabelText: z.ZodOptional<z.ZodString>;
|
|
77
77
|
productAmountRemainingLabel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -102,11 +102,11 @@ export declare const SmartCartBar: z.ZodObject<{
|
|
|
102
102
|
freeShippingOnSubscription: z.ZodOptional<z.ZodBoolean>;
|
|
103
103
|
geolocationEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
104
104
|
id: z.ZodOptional<z.ZodString>;
|
|
105
|
-
language: z.ZodOptional<z.ZodObject<{
|
|
105
|
+
language: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
106
106
|
freeShippingReached: z.ZodOptional<z.ZodString>;
|
|
107
107
|
freeShippingRemaining: z.ZodOptional<z.ZodString>;
|
|
108
108
|
giftAreaTitle: z.ZodOptional<z.ZodString>;
|
|
109
|
-
}, z.core.$loose
|
|
109
|
+
}, z.core.$loose>>>;
|
|
110
110
|
name: z.ZodOptional<z.ZodString>;
|
|
111
111
|
tiers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
112
112
|
allProducts: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -138,9 +138,9 @@ export declare const SmartCartBar: z.ZodObject<{
|
|
|
138
138
|
filterOosVariants: z.ZodOptional<z.ZodBoolean>;
|
|
139
139
|
id: z.ZodOptional<z.ZodString>;
|
|
140
140
|
minimum: z.ZodPreprocess<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
141
|
-
presentmentCurrencies: z.ZodOptional<z.ZodObject<{
|
|
141
|
+
presentmentCurrencies: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
142
142
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
143
|
-
}, z.core.$loose
|
|
143
|
+
}, z.core.$loose>>>;
|
|
144
144
|
productAmountReachedLabel: z.ZodOptional<z.ZodBoolean>;
|
|
145
145
|
productAmountReachedLabelText: z.ZodOptional<z.ZodString>;
|
|
146
146
|
productAmountRemainingLabel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -160,7 +160,7 @@ export declare const SmartCartBar: z.ZodObject<{
|
|
|
160
160
|
}, z.core.$loose>;
|
|
161
161
|
/** A smart-cart layout component; only `type === 'tiered_progress_bar'` carries the bars we render. */
|
|
162
162
|
export declare const SmartCartComponent: z.ZodObject<{
|
|
163
|
-
settings: z.ZodOptional<z.ZodObject<{
|
|
163
|
+
settings: z.ZodCatch<z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
164
164
|
bars: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
165
165
|
countryCodes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
166
166
|
excludeDiscountInSubtotal: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -170,11 +170,11 @@ export declare const SmartCartComponent: z.ZodObject<{
|
|
|
170
170
|
freeShippingOnSubscription: z.ZodOptional<z.ZodBoolean>;
|
|
171
171
|
geolocationEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
172
172
|
id: z.ZodOptional<z.ZodString>;
|
|
173
|
-
language: z.ZodOptional<z.ZodObject<{
|
|
173
|
+
language: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
174
174
|
freeShippingReached: z.ZodOptional<z.ZodString>;
|
|
175
175
|
freeShippingRemaining: z.ZodOptional<z.ZodString>;
|
|
176
176
|
giftAreaTitle: z.ZodOptional<z.ZodString>;
|
|
177
|
-
}, z.core.$loose
|
|
177
|
+
}, z.core.$loose>>>;
|
|
178
178
|
name: z.ZodOptional<z.ZodString>;
|
|
179
179
|
tiers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
180
180
|
allProducts: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -206,9 +206,9 @@ export declare const SmartCartComponent: z.ZodObject<{
|
|
|
206
206
|
filterOosVariants: z.ZodOptional<z.ZodBoolean>;
|
|
207
207
|
id: z.ZodOptional<z.ZodString>;
|
|
208
208
|
minimum: z.ZodPreprocess<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
209
|
-
presentmentCurrencies: z.ZodOptional<z.ZodObject<{
|
|
209
|
+
presentmentCurrencies: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
210
210
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
211
|
-
}, z.core.$loose
|
|
211
|
+
}, z.core.$loose>>>;
|
|
212
212
|
productAmountReachedLabel: z.ZodOptional<z.ZodBoolean>;
|
|
213
213
|
productAmountReachedLabelText: z.ZodOptional<z.ZodString>;
|
|
214
214
|
productAmountRemainingLabel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -226,7 +226,7 @@ export declare const SmartCartComponent: z.ZodObject<{
|
|
|
226
226
|
unlockConditionType: z.ZodOptional<z.ZodString>;
|
|
227
227
|
}, z.core.$loose>>>;
|
|
228
228
|
}, z.core.$loose>>>;
|
|
229
|
-
}, z.core.$loose
|
|
229
|
+
}, z.core.$loose>>>>;
|
|
230
230
|
type: z.ZodOptional<z.ZodString>;
|
|
231
231
|
}, z.core.$loose>;
|
|
232
232
|
/**
|
|
@@ -234,12 +234,12 @@ export declare const SmartCartComponent: z.ZodObject<{
|
|
|
234
234
|
* `tiered_progress_bar` component(s) and their bars/tiers. The rest of the onsite
|
|
235
235
|
* smart-cart config (buy-more-save-more, custom templates/CSS, callbacks) is out of
|
|
236
236
|
* scope — `looseObject` preserves-but-ignores it. Parsed under `UserConfig.smartCart`
|
|
237
|
-
*
|
|
238
|
-
* offers / monetize / analytics / gift validation.
|
|
237
|
+
* (`.catch(undefined)`) and `CabUserConfig.smartCart` (`.catch` to a drift sentinel) so a shape
|
|
238
|
+
* drift here can NEVER break apiKey resolution for offers / monetize / analytics / gift validation.
|
|
239
239
|
*/
|
|
240
240
|
export declare const SmartCartConfig: z.ZodObject<{
|
|
241
241
|
components: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
242
|
-
settings: z.ZodOptional<z.ZodObject<{
|
|
242
|
+
settings: z.ZodCatch<z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
243
243
|
bars: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
244
244
|
countryCodes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
245
245
|
excludeDiscountInSubtotal: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -249,11 +249,11 @@ export declare const SmartCartConfig: z.ZodObject<{
|
|
|
249
249
|
freeShippingOnSubscription: z.ZodOptional<z.ZodBoolean>;
|
|
250
250
|
geolocationEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
251
251
|
id: z.ZodOptional<z.ZodString>;
|
|
252
|
-
language: z.ZodOptional<z.ZodObject<{
|
|
252
|
+
language: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
253
253
|
freeShippingReached: z.ZodOptional<z.ZodString>;
|
|
254
254
|
freeShippingRemaining: z.ZodOptional<z.ZodString>;
|
|
255
255
|
giftAreaTitle: z.ZodOptional<z.ZodString>;
|
|
256
|
-
}, z.core.$loose
|
|
256
|
+
}, z.core.$loose>>>;
|
|
257
257
|
name: z.ZodOptional<z.ZodString>;
|
|
258
258
|
tiers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
259
259
|
allProducts: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -285,9 +285,9 @@ export declare const SmartCartConfig: z.ZodObject<{
|
|
|
285
285
|
filterOosVariants: z.ZodOptional<z.ZodBoolean>;
|
|
286
286
|
id: z.ZodOptional<z.ZodString>;
|
|
287
287
|
minimum: z.ZodPreprocess<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
288
|
-
presentmentCurrencies: z.ZodOptional<z.ZodObject<{
|
|
288
|
+
presentmentCurrencies: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
289
289
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
290
|
-
}, z.core.$loose
|
|
290
|
+
}, z.core.$loose>>>;
|
|
291
291
|
productAmountReachedLabel: z.ZodOptional<z.ZodBoolean>;
|
|
292
292
|
productAmountReachedLabelText: z.ZodOptional<z.ZodString>;
|
|
293
293
|
productAmountRemainingLabel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -305,7 +305,7 @@ export declare const SmartCartConfig: z.ZodObject<{
|
|
|
305
305
|
unlockConditionType: z.ZodOptional<z.ZodString>;
|
|
306
306
|
}, z.core.$loose>>>;
|
|
307
307
|
}, z.core.$loose>>>;
|
|
308
|
-
}, z.core.$loose
|
|
308
|
+
}, z.core.$loose>>>>;
|
|
309
309
|
type: z.ZodOptional<z.ZodString>;
|
|
310
310
|
}, z.core.$loose>>>;
|
|
311
311
|
}, z.core.$loose>;
|
|
@@ -111,6 +111,13 @@ var ShopConfig = import_zod.z.object({
|
|
|
111
111
|
|
|
112
112
|
// src/schema/smartCart.ts
|
|
113
113
|
var import_zod2 = require("zod");
|
|
114
|
+
|
|
115
|
+
// src/schema/driftedSmartCart.ts
|
|
116
|
+
var DRIFTED_SMART_CART_SETTINGS = Object.freeze({});
|
|
117
|
+
var DRIFTED_SMART_CART = Object.freeze({});
|
|
118
|
+
|
|
119
|
+
// src/schema/smartCart.ts
|
|
120
|
+
var phpEmptyMapAsAbsent = (value) => Array.isArray(value) && value.length === 0 ? void 0 : value;
|
|
114
121
|
var SmartCartTierProduct = import_zod2.z.looseObject({
|
|
115
122
|
handle: import_zod2.z.string().optional(),
|
|
116
123
|
id: import_zod2.z.coerce.number().optional(),
|
|
@@ -164,7 +171,11 @@ var SmartCartTier = import_zod2.z.looseObject({
|
|
|
164
171
|
* `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
|
|
165
172
|
*/
|
|
166
173
|
minimum: import_zod2.z.preprocess((value) => value == null ? void 0 : value, import_zod2.z.coerce.number().optional()),
|
|
167
|
-
|
|
174
|
+
/** An empty map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed tier. */
|
|
175
|
+
presentmentCurrencies: import_zod2.z.preprocess(
|
|
176
|
+
phpEmptyMapAsAbsent,
|
|
177
|
+
import_zod2.z.looseObject({ enabled: import_zod2.z.boolean().optional() }).optional()
|
|
178
|
+
),
|
|
168
179
|
productAmountReachedLabel: import_zod2.z.boolean().optional(),
|
|
169
180
|
productAmountReachedLabelText: import_zod2.z.string().optional(),
|
|
170
181
|
productAmountRemainingLabel: import_zod2.z.boolean().optional(),
|
|
@@ -217,16 +228,35 @@ var SmartCartBar = import_zod2.z.looseObject({
|
|
|
217
228
|
freeShippingOnSubscription: import_zod2.z.boolean().optional(),
|
|
218
229
|
geolocationEnabled: import_zod2.z.boolean().optional(),
|
|
219
230
|
id: import_zod2.z.string().optional(),
|
|
220
|
-
language
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
231
|
+
/** An empty `language` map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed bar. */
|
|
232
|
+
language: import_zod2.z.preprocess(
|
|
233
|
+
phpEmptyMapAsAbsent,
|
|
234
|
+
import_zod2.z.looseObject({
|
|
235
|
+
freeShippingReached: import_zod2.z.string().optional(),
|
|
236
|
+
freeShippingRemaining: import_zod2.z.string().optional(),
|
|
237
|
+
giftAreaTitle: import_zod2.z.string().optional()
|
|
238
|
+
}).optional()
|
|
239
|
+
),
|
|
225
240
|
name: import_zod2.z.string().optional(),
|
|
226
241
|
tiers: import_zod2.z.array(SmartCartTier).optional()
|
|
227
242
|
});
|
|
228
243
|
var SmartCartComponent = import_zod2.z.looseObject({
|
|
229
|
-
|
|
244
|
+
/**
|
|
245
|
+
* Every component in the layout is parsed, not just the progress bar, so this field is the blast-radius
|
|
246
|
+
* boundary (REB-25139): before it caught, b.box's `cart_items` component arriving as `settings: []` failed
|
|
247
|
+
* the component, the `components` array and the whole config — and `CabUserConfig`'s config-level catch
|
|
248
|
+
* then silently dropped every progress bar for the shop. Now:
|
|
249
|
+
*
|
|
250
|
+
* - PHP's empty-map `[]` reads as absent ({@link phpEmptyMapAsAbsent}) — normal engine vocabulary, no drift.
|
|
251
|
+
* - Any other unreadable settings (a string, a non-empty array, a bar that fails its schema) `.catch` to the
|
|
252
|
+
* {@link DRIFTED_SMART_CART_SETTINGS} identity sentinel: that component loses its settings (no bars),
|
|
253
|
+
* its siblings — and the progress bar, when it is a sibling — still parse, and the server's progress-bar
|
|
254
|
+
* resolution emits a `shopConfig` drift on seeing the sentinel.
|
|
255
|
+
*
|
|
256
|
+
* Bars are not salvaged per element: the only reader takes the first progress-bar component's bars as a
|
|
257
|
+
* set (one per geo segment), and a drifted bar now costs that component's bars WITH a drift, not the cart.
|
|
258
|
+
*/
|
|
259
|
+
settings: import_zod2.z.preprocess(phpEmptyMapAsAbsent, import_zod2.z.looseObject({ bars: import_zod2.z.array(SmartCartBar).optional() }).optional()).catch(DRIFTED_SMART_CART_SETTINGS),
|
|
230
260
|
type: import_zod2.z.string().optional()
|
|
231
261
|
});
|
|
232
262
|
var SmartCartConfig = import_zod2.z.looseObject({
|
|
@@ -87,6 +87,13 @@ var ShopConfig = z.object({
|
|
|
87
87
|
|
|
88
88
|
// src/schema/smartCart.ts
|
|
89
89
|
import { z as z2 } from "zod";
|
|
90
|
+
|
|
91
|
+
// src/schema/driftedSmartCart.ts
|
|
92
|
+
var DRIFTED_SMART_CART_SETTINGS = Object.freeze({});
|
|
93
|
+
var DRIFTED_SMART_CART = Object.freeze({});
|
|
94
|
+
|
|
95
|
+
// src/schema/smartCart.ts
|
|
96
|
+
var phpEmptyMapAsAbsent = (value) => Array.isArray(value) && value.length === 0 ? void 0 : value;
|
|
90
97
|
var SmartCartTierProduct = z2.looseObject({
|
|
91
98
|
handle: z2.string().optional(),
|
|
92
99
|
id: z2.coerce.number().optional(),
|
|
@@ -140,7 +147,11 @@ var SmartCartTier = z2.looseObject({
|
|
|
140
147
|
* `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
|
|
141
148
|
*/
|
|
142
149
|
minimum: z2.preprocess((value) => value == null ? void 0 : value, z2.coerce.number().optional()),
|
|
143
|
-
|
|
150
|
+
/** An empty map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed tier. */
|
|
151
|
+
presentmentCurrencies: z2.preprocess(
|
|
152
|
+
phpEmptyMapAsAbsent,
|
|
153
|
+
z2.looseObject({ enabled: z2.boolean().optional() }).optional()
|
|
154
|
+
),
|
|
144
155
|
productAmountReachedLabel: z2.boolean().optional(),
|
|
145
156
|
productAmountReachedLabelText: z2.string().optional(),
|
|
146
157
|
productAmountRemainingLabel: z2.boolean().optional(),
|
|
@@ -193,16 +204,35 @@ var SmartCartBar = z2.looseObject({
|
|
|
193
204
|
freeShippingOnSubscription: z2.boolean().optional(),
|
|
194
205
|
geolocationEnabled: z2.boolean().optional(),
|
|
195
206
|
id: z2.string().optional(),
|
|
196
|
-
language
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
/** An empty `language` map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed bar. */
|
|
208
|
+
language: z2.preprocess(
|
|
209
|
+
phpEmptyMapAsAbsent,
|
|
210
|
+
z2.looseObject({
|
|
211
|
+
freeShippingReached: z2.string().optional(),
|
|
212
|
+
freeShippingRemaining: z2.string().optional(),
|
|
213
|
+
giftAreaTitle: z2.string().optional()
|
|
214
|
+
}).optional()
|
|
215
|
+
),
|
|
201
216
|
name: z2.string().optional(),
|
|
202
217
|
tiers: z2.array(SmartCartTier).optional()
|
|
203
218
|
});
|
|
204
219
|
var SmartCartComponent = z2.looseObject({
|
|
205
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Every component in the layout is parsed, not just the progress bar, so this field is the blast-radius
|
|
222
|
+
* boundary (REB-25139): before it caught, b.box's `cart_items` component arriving as `settings: []` failed
|
|
223
|
+
* the component, the `components` array and the whole config — and `CabUserConfig`'s config-level catch
|
|
224
|
+
* then silently dropped every progress bar for the shop. Now:
|
|
225
|
+
*
|
|
226
|
+
* - PHP's empty-map `[]` reads as absent ({@link phpEmptyMapAsAbsent}) — normal engine vocabulary, no drift.
|
|
227
|
+
* - Any other unreadable settings (a string, a non-empty array, a bar that fails its schema) `.catch` to the
|
|
228
|
+
* {@link DRIFTED_SMART_CART_SETTINGS} identity sentinel: that component loses its settings (no bars),
|
|
229
|
+
* its siblings — and the progress bar, when it is a sibling — still parse, and the server's progress-bar
|
|
230
|
+
* resolution emits a `shopConfig` drift on seeing the sentinel.
|
|
231
|
+
*
|
|
232
|
+
* Bars are not salvaged per element: the only reader takes the first progress-bar component's bars as a
|
|
233
|
+
* set (one per geo segment), and a drifted bar now costs that component's bars WITH a drift, not the cart.
|
|
234
|
+
*/
|
|
235
|
+
settings: z2.preprocess(phpEmptyMapAsAbsent, z2.looseObject({ bars: z2.array(SmartCartBar).optional() }).optional()).catch(DRIFTED_SMART_CART_SETTINGS),
|
|
206
236
|
type: z2.string().optional()
|
|
207
237
|
});
|
|
208
238
|
var SmartCartConfig = z2.looseObject({
|
|
@@ -80,7 +80,7 @@ export declare const UserConfig: z.ZodObject<{
|
|
|
80
80
|
}, z.core.$strip>;
|
|
81
81
|
smartCart: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
82
82
|
components: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
83
|
-
settings: z.ZodOptional<z.ZodObject<{
|
|
83
|
+
settings: z.ZodCatch<z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
84
84
|
bars: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
85
85
|
countryCodes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
86
86
|
excludeDiscountInSubtotal: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -90,11 +90,11 @@ export declare const UserConfig: z.ZodObject<{
|
|
|
90
90
|
freeShippingOnSubscription: z.ZodOptional<z.ZodBoolean>;
|
|
91
91
|
geolocationEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
92
92
|
id: z.ZodOptional<z.ZodString>;
|
|
93
|
-
language: z.ZodOptional<z.ZodObject<{
|
|
93
|
+
language: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
94
94
|
freeShippingReached: z.ZodOptional<z.ZodString>;
|
|
95
95
|
freeShippingRemaining: z.ZodOptional<z.ZodString>;
|
|
96
96
|
giftAreaTitle: z.ZodOptional<z.ZodString>;
|
|
97
|
-
}, z.core.$loose
|
|
97
|
+
}, z.core.$loose>>>;
|
|
98
98
|
name: z.ZodOptional<z.ZodString>;
|
|
99
99
|
tiers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
100
100
|
allProducts: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -126,9 +126,9 @@ export declare const UserConfig: z.ZodObject<{
|
|
|
126
126
|
filterOosVariants: z.ZodOptional<z.ZodBoolean>;
|
|
127
127
|
id: z.ZodOptional<z.ZodString>;
|
|
128
128
|
minimum: z.ZodPreprocess<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
129
|
-
presentmentCurrencies: z.ZodOptional<z.ZodObject<{
|
|
129
|
+
presentmentCurrencies: z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
130
130
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
131
|
-
}, z.core.$loose
|
|
131
|
+
}, z.core.$loose>>>;
|
|
132
132
|
productAmountReachedLabel: z.ZodOptional<z.ZodBoolean>;
|
|
133
133
|
productAmountReachedLabelText: z.ZodOptional<z.ZodString>;
|
|
134
134
|
productAmountRemainingLabel: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -146,7 +146,7 @@ export declare const UserConfig: z.ZodObject<{
|
|
|
146
146
|
unlockConditionType: z.ZodOptional<z.ZodString>;
|
|
147
147
|
}, z.core.$loose>>>;
|
|
148
148
|
}, z.core.$loose>>>;
|
|
149
|
-
}, z.core.$loose
|
|
149
|
+
}, z.core.$loose>>>>;
|
|
150
150
|
type: z.ZodOptional<z.ZodString>;
|
|
151
151
|
}, z.core.$loose>>>;
|
|
152
152
|
}, z.core.$loose>>>>;
|
package/dist/server/index.cjs
CHANGED
|
@@ -1560,8 +1560,13 @@ var import_zod20 = require("zod");
|
|
|
1560
1560
|
// src/schema/driftedMarkets.ts
|
|
1561
1561
|
var DRIFTED_MARKETS = Object.freeze({ enabled: false });
|
|
1562
1562
|
|
|
1563
|
+
// src/schema/driftedSmartCart.ts
|
|
1564
|
+
var DRIFTED_SMART_CART_SETTINGS = Object.freeze({});
|
|
1565
|
+
var DRIFTED_SMART_CART = Object.freeze({});
|
|
1566
|
+
|
|
1563
1567
|
// src/schema/smartCart.ts
|
|
1564
1568
|
var import_zod19 = require("zod");
|
|
1569
|
+
var phpEmptyMapAsAbsent = (value) => Array.isArray(value) && value.length === 0 ? void 0 : value;
|
|
1565
1570
|
var SmartCartTierProduct = import_zod19.z.looseObject({
|
|
1566
1571
|
handle: import_zod19.z.string().optional(),
|
|
1567
1572
|
id: import_zod19.z.coerce.number().optional(),
|
|
@@ -1615,7 +1620,11 @@ var SmartCartTier = import_zod19.z.looseObject({
|
|
|
1615
1620
|
* `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
|
|
1616
1621
|
*/
|
|
1617
1622
|
minimum: import_zod19.z.preprocess((value) => value == null ? void 0 : value, import_zod19.z.coerce.number().optional()),
|
|
1618
|
-
|
|
1623
|
+
/** An empty map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed tier. */
|
|
1624
|
+
presentmentCurrencies: import_zod19.z.preprocess(
|
|
1625
|
+
phpEmptyMapAsAbsent,
|
|
1626
|
+
import_zod19.z.looseObject({ enabled: import_zod19.z.boolean().optional() }).optional()
|
|
1627
|
+
),
|
|
1619
1628
|
productAmountReachedLabel: import_zod19.z.boolean().optional(),
|
|
1620
1629
|
productAmountReachedLabelText: import_zod19.z.string().optional(),
|
|
1621
1630
|
productAmountRemainingLabel: import_zod19.z.boolean().optional(),
|
|
@@ -1668,16 +1677,35 @@ var SmartCartBar = import_zod19.z.looseObject({
|
|
|
1668
1677
|
freeShippingOnSubscription: import_zod19.z.boolean().optional(),
|
|
1669
1678
|
geolocationEnabled: import_zod19.z.boolean().optional(),
|
|
1670
1679
|
id: import_zod19.z.string().optional(),
|
|
1671
|
-
language
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1680
|
+
/** An empty `language` map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed bar. */
|
|
1681
|
+
language: import_zod19.z.preprocess(
|
|
1682
|
+
phpEmptyMapAsAbsent,
|
|
1683
|
+
import_zod19.z.looseObject({
|
|
1684
|
+
freeShippingReached: import_zod19.z.string().optional(),
|
|
1685
|
+
freeShippingRemaining: import_zod19.z.string().optional(),
|
|
1686
|
+
giftAreaTitle: import_zod19.z.string().optional()
|
|
1687
|
+
}).optional()
|
|
1688
|
+
),
|
|
1676
1689
|
name: import_zod19.z.string().optional(),
|
|
1677
1690
|
tiers: import_zod19.z.array(SmartCartTier).optional()
|
|
1678
1691
|
});
|
|
1679
1692
|
var SmartCartComponent = import_zod19.z.looseObject({
|
|
1680
|
-
|
|
1693
|
+
/**
|
|
1694
|
+
* Every component in the layout is parsed, not just the progress bar, so this field is the blast-radius
|
|
1695
|
+
* boundary (REB-25139): before it caught, b.box's `cart_items` component arriving as `settings: []` failed
|
|
1696
|
+
* the component, the `components` array and the whole config — and `CabUserConfig`'s config-level catch
|
|
1697
|
+
* then silently dropped every progress bar for the shop. Now:
|
|
1698
|
+
*
|
|
1699
|
+
* - PHP's empty-map `[]` reads as absent ({@link phpEmptyMapAsAbsent}) — normal engine vocabulary, no drift.
|
|
1700
|
+
* - Any other unreadable settings (a string, a non-empty array, a bar that fails its schema) `.catch` to the
|
|
1701
|
+
* {@link DRIFTED_SMART_CART_SETTINGS} identity sentinel: that component loses its settings (no bars),
|
|
1702
|
+
* its siblings — and the progress bar, when it is a sibling — still parse, and the server's progress-bar
|
|
1703
|
+
* resolution emits a `shopConfig` drift on seeing the sentinel.
|
|
1704
|
+
*
|
|
1705
|
+
* Bars are not salvaged per element: the only reader takes the first progress-bar component's bars as a
|
|
1706
|
+
* set (one per geo segment), and a drifted bar now costs that component's bars WITH a drift, not the cart.
|
|
1707
|
+
*/
|
|
1708
|
+
settings: import_zod19.z.preprocess(phpEmptyMapAsAbsent, import_zod19.z.looseObject({ bars: import_zod19.z.array(SmartCartBar).optional() }).optional()).catch(DRIFTED_SMART_CART_SETTINGS),
|
|
1681
1709
|
type: import_zod19.z.string().optional()
|
|
1682
1710
|
});
|
|
1683
1711
|
var SmartCartConfig = import_zod19.z.looseObject({
|
|
@@ -1780,7 +1808,7 @@ var CabShopConfig = import_zod20.z.object({
|
|
|
1780
1808
|
});
|
|
1781
1809
|
var CabUserConfig = import_zod20.z.object({
|
|
1782
1810
|
shop: CabShopConfig,
|
|
1783
|
-
smartCart: SmartCartConfig.nullish().catch(
|
|
1811
|
+
smartCart: SmartCartConfig.nullish().catch(DRIFTED_SMART_CART)
|
|
1784
1812
|
});
|
|
1785
1813
|
|
|
1786
1814
|
// src/schema/widgets/checkout-and-beyond/image.ts
|
|
@@ -4500,6 +4528,9 @@ var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(
|
|
|
4500
4528
|
// src/transforms/postPurchase/convertMessagePreview.ts
|
|
4501
4529
|
var import_zod47 = require("zod");
|
|
4502
4530
|
|
|
4531
|
+
// src/cab/hasOwnKey.ts
|
|
4532
|
+
var hasOwnKey = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
4533
|
+
|
|
4503
4534
|
// src/transforms/postPurchase/convertCalloutBlock.ts
|
|
4504
4535
|
var import_zod41 = require("zod");
|
|
4505
4536
|
|
|
@@ -5128,7 +5159,7 @@ var convertMessagePreview = (id, settings, report) => {
|
|
|
5128
5159
|
sections: parsed.data.blocks.flatMap((block) => {
|
|
5129
5160
|
const type = BlockType2.safeParse(block);
|
|
5130
5161
|
const kind = type.success ? type.data.type : void 0;
|
|
5131
|
-
const convert2 = kind &&
|
|
5162
|
+
const convert2 = kind && hasOwnKey(converters, kind) ? converters[kind] : void 0;
|
|
5132
5163
|
if (convert2) return convert2(block, report, settings);
|
|
5133
5164
|
report?.({
|
|
5134
5165
|
detail: kind ? `Unsupported post-purchase block type: ${kind}` : "Unreadable post-purchase block: missing type",
|
|
@@ -6092,9 +6123,26 @@ var dispatchWidgetTransform = (id, normalized, report) => {
|
|
|
6092
6123
|
if (isOfferV1(normalized)) return convertOfferToV2({ id, name: normalized.name, settings: normalized });
|
|
6093
6124
|
return normalized;
|
|
6094
6125
|
};
|
|
6126
|
+
var reportSmartCartDrift = (shop, smartCart, ctx) => {
|
|
6127
|
+
if (smartCart === DRIFTED_SMART_CART) {
|
|
6128
|
+
ctx.reportDrift?.({
|
|
6129
|
+
detail: `smart cart config unreadable (drifted shape) \u2014 every progress bar dropped for ${shop}`,
|
|
6130
|
+
kind: "shopConfig"
|
|
6131
|
+
});
|
|
6132
|
+
return;
|
|
6133
|
+
}
|
|
6134
|
+
const drifted = (smartCart?.components ?? []).filter((entry) => entry.settings === DRIFTED_SMART_CART_SETTINGS);
|
|
6135
|
+
if (drifted.length) {
|
|
6136
|
+
ctx.reportDrift?.({
|
|
6137
|
+
detail: `smart cart component settings unreadable (drifted shape) \u2014 dropped for ${drifted.map((entry) => entry.type ?? "untyped").join(", ")} on ${shop}`,
|
|
6138
|
+
kind: "shopConfig"
|
|
6139
|
+
});
|
|
6140
|
+
}
|
|
6141
|
+
};
|
|
6095
6142
|
var fetchProgressBarContext = async (shop, ctx, prefetched) => {
|
|
6096
6143
|
const config = prefetched === void 0 ? await fetchUserConfig({ shop }, ctx).catch(() => void 0) : prefetched;
|
|
6097
6144
|
if (!config) return {};
|
|
6145
|
+
reportSmartCartDrift(shop, config.smartCart, ctx);
|
|
6098
6146
|
if (config.shop.billingVersion === "v6" && config.shop.activePackages.some((pkg) => pkg.shortName === "")) {
|
|
6099
6147
|
ctx.reportDrift?.({
|
|
6100
6148
|
detail: "shop config active package entry inerted (drifted shape) \u2014 smart-cart entitlement may misgate",
|
package/dist/server/index.mjs
CHANGED
|
@@ -1487,8 +1487,13 @@ import { z as z20 } from "zod";
|
|
|
1487
1487
|
// src/schema/driftedMarkets.ts
|
|
1488
1488
|
var DRIFTED_MARKETS = Object.freeze({ enabled: false });
|
|
1489
1489
|
|
|
1490
|
+
// src/schema/driftedSmartCart.ts
|
|
1491
|
+
var DRIFTED_SMART_CART_SETTINGS = Object.freeze({});
|
|
1492
|
+
var DRIFTED_SMART_CART = Object.freeze({});
|
|
1493
|
+
|
|
1490
1494
|
// src/schema/smartCart.ts
|
|
1491
1495
|
import { z as z19 } from "zod";
|
|
1496
|
+
var phpEmptyMapAsAbsent = (value) => Array.isArray(value) && value.length === 0 ? void 0 : value;
|
|
1492
1497
|
var SmartCartTierProduct = z19.looseObject({
|
|
1493
1498
|
handle: z19.string().optional(),
|
|
1494
1499
|
id: z19.coerce.number().optional(),
|
|
@@ -1542,7 +1547,11 @@ var SmartCartTier = z19.looseObject({
|
|
|
1542
1547
|
* `'50' → 50` and keeps the tier (a numeric-string minimum is a valid threshold, not a data defect).
|
|
1543
1548
|
*/
|
|
1544
1549
|
minimum: z19.preprocess((value) => value == null ? void 0 : value, z19.coerce.number().optional()),
|
|
1545
|
-
|
|
1550
|
+
/** An empty map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed tier. */
|
|
1551
|
+
presentmentCurrencies: z19.preprocess(
|
|
1552
|
+
phpEmptyMapAsAbsent,
|
|
1553
|
+
z19.looseObject({ enabled: z19.boolean().optional() }).optional()
|
|
1554
|
+
),
|
|
1546
1555
|
productAmountReachedLabel: z19.boolean().optional(),
|
|
1547
1556
|
productAmountReachedLabelText: z19.string().optional(),
|
|
1548
1557
|
productAmountRemainingLabel: z19.boolean().optional(),
|
|
@@ -1595,16 +1604,35 @@ var SmartCartBar = z19.looseObject({
|
|
|
1595
1604
|
freeShippingOnSubscription: z19.boolean().optional(),
|
|
1596
1605
|
geolocationEnabled: z19.boolean().optional(),
|
|
1597
1606
|
id: z19.string().optional(),
|
|
1598
|
-
language
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1607
|
+
/** An empty `language` map arrives as PHP's `[]` (see {@link phpEmptyMapAsAbsent}) — absent, not a failed bar. */
|
|
1608
|
+
language: z19.preprocess(
|
|
1609
|
+
phpEmptyMapAsAbsent,
|
|
1610
|
+
z19.looseObject({
|
|
1611
|
+
freeShippingReached: z19.string().optional(),
|
|
1612
|
+
freeShippingRemaining: z19.string().optional(),
|
|
1613
|
+
giftAreaTitle: z19.string().optional()
|
|
1614
|
+
}).optional()
|
|
1615
|
+
),
|
|
1603
1616
|
name: z19.string().optional(),
|
|
1604
1617
|
tiers: z19.array(SmartCartTier).optional()
|
|
1605
1618
|
});
|
|
1606
1619
|
var SmartCartComponent = z19.looseObject({
|
|
1607
|
-
|
|
1620
|
+
/**
|
|
1621
|
+
* Every component in the layout is parsed, not just the progress bar, so this field is the blast-radius
|
|
1622
|
+
* boundary (REB-25139): before it caught, b.box's `cart_items` component arriving as `settings: []` failed
|
|
1623
|
+
* the component, the `components` array and the whole config — and `CabUserConfig`'s config-level catch
|
|
1624
|
+
* then silently dropped every progress bar for the shop. Now:
|
|
1625
|
+
*
|
|
1626
|
+
* - PHP's empty-map `[]` reads as absent ({@link phpEmptyMapAsAbsent}) — normal engine vocabulary, no drift.
|
|
1627
|
+
* - Any other unreadable settings (a string, a non-empty array, a bar that fails its schema) `.catch` to the
|
|
1628
|
+
* {@link DRIFTED_SMART_CART_SETTINGS} identity sentinel: that component loses its settings (no bars),
|
|
1629
|
+
* its siblings — and the progress bar, when it is a sibling — still parse, and the server's progress-bar
|
|
1630
|
+
* resolution emits a `shopConfig` drift on seeing the sentinel.
|
|
1631
|
+
*
|
|
1632
|
+
* Bars are not salvaged per element: the only reader takes the first progress-bar component's bars as a
|
|
1633
|
+
* set (one per geo segment), and a drifted bar now costs that component's bars WITH a drift, not the cart.
|
|
1634
|
+
*/
|
|
1635
|
+
settings: z19.preprocess(phpEmptyMapAsAbsent, z19.looseObject({ bars: z19.array(SmartCartBar).optional() }).optional()).catch(DRIFTED_SMART_CART_SETTINGS),
|
|
1608
1636
|
type: z19.string().optional()
|
|
1609
1637
|
});
|
|
1610
1638
|
var SmartCartConfig = z19.looseObject({
|
|
@@ -1707,7 +1735,7 @@ var CabShopConfig = z20.object({
|
|
|
1707
1735
|
});
|
|
1708
1736
|
var CabUserConfig = z20.object({
|
|
1709
1737
|
shop: CabShopConfig,
|
|
1710
|
-
smartCart: SmartCartConfig.nullish().catch(
|
|
1738
|
+
smartCart: SmartCartConfig.nullish().catch(DRIFTED_SMART_CART)
|
|
1711
1739
|
});
|
|
1712
1740
|
|
|
1713
1741
|
// src/schema/widgets/checkout-and-beyond/image.ts
|
|
@@ -4427,6 +4455,9 @@ var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(
|
|
|
4427
4455
|
// src/transforms/postPurchase/convertMessagePreview.ts
|
|
4428
4456
|
import { z as z47 } from "zod";
|
|
4429
4457
|
|
|
4458
|
+
// src/cab/hasOwnKey.ts
|
|
4459
|
+
var hasOwnKey = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
4460
|
+
|
|
4430
4461
|
// src/transforms/postPurchase/convertCalloutBlock.ts
|
|
4431
4462
|
import { z as z41 } from "zod";
|
|
4432
4463
|
|
|
@@ -5055,7 +5086,7 @@ var convertMessagePreview = (id, settings, report) => {
|
|
|
5055
5086
|
sections: parsed.data.blocks.flatMap((block) => {
|
|
5056
5087
|
const type = BlockType2.safeParse(block);
|
|
5057
5088
|
const kind = type.success ? type.data.type : void 0;
|
|
5058
|
-
const convert2 = kind &&
|
|
5089
|
+
const convert2 = kind && hasOwnKey(converters, kind) ? converters[kind] : void 0;
|
|
5059
5090
|
if (convert2) return convert2(block, report, settings);
|
|
5060
5091
|
report?.({
|
|
5061
5092
|
detail: kind ? `Unsupported post-purchase block type: ${kind}` : "Unreadable post-purchase block: missing type",
|
|
@@ -6019,9 +6050,26 @@ var dispatchWidgetTransform = (id, normalized, report) => {
|
|
|
6019
6050
|
if (isOfferV1(normalized)) return convertOfferToV2({ id, name: normalized.name, settings: normalized });
|
|
6020
6051
|
return normalized;
|
|
6021
6052
|
};
|
|
6053
|
+
var reportSmartCartDrift = (shop, smartCart, ctx) => {
|
|
6054
|
+
if (smartCart === DRIFTED_SMART_CART) {
|
|
6055
|
+
ctx.reportDrift?.({
|
|
6056
|
+
detail: `smart cart config unreadable (drifted shape) \u2014 every progress bar dropped for ${shop}`,
|
|
6057
|
+
kind: "shopConfig"
|
|
6058
|
+
});
|
|
6059
|
+
return;
|
|
6060
|
+
}
|
|
6061
|
+
const drifted = (smartCart?.components ?? []).filter((entry) => entry.settings === DRIFTED_SMART_CART_SETTINGS);
|
|
6062
|
+
if (drifted.length) {
|
|
6063
|
+
ctx.reportDrift?.({
|
|
6064
|
+
detail: `smart cart component settings unreadable (drifted shape) \u2014 dropped for ${drifted.map((entry) => entry.type ?? "untyped").join(", ")} on ${shop}`,
|
|
6065
|
+
kind: "shopConfig"
|
|
6066
|
+
});
|
|
6067
|
+
}
|
|
6068
|
+
};
|
|
6022
6069
|
var fetchProgressBarContext = async (shop, ctx, prefetched) => {
|
|
6023
6070
|
const config = prefetched === void 0 ? await fetchUserConfig({ shop }, ctx).catch(() => void 0) : prefetched;
|
|
6024
6071
|
if (!config) return {};
|
|
6072
|
+
reportSmartCartDrift(shop, config.smartCart, ctx);
|
|
6025
6073
|
if (config.shop.billingVersion === "v6" && config.shop.activePackages.some((pkg) => pkg.shortName === "")) {
|
|
6026
6074
|
ctx.reportDrift?.({
|
|
6027
6075
|
detail: "shop config active package entry inerted (drifted shape) \u2014 smart-cart entitlement may misgate",
|
|
@@ -3717,6 +3717,9 @@ var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(
|
|
|
3717
3717
|
// src/transforms/postPurchase/convertMessagePreview.ts
|
|
3718
3718
|
var import_zod34 = require("zod");
|
|
3719
3719
|
|
|
3720
|
+
// src/cab/hasOwnKey.ts
|
|
3721
|
+
var hasOwnKey = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
3722
|
+
|
|
3720
3723
|
// src/server/shared.ts
|
|
3721
3724
|
var NotFoundError = class extends Error {
|
|
3722
3725
|
constructor(message) {
|
|
@@ -4706,7 +4709,7 @@ var convertMessagePreview = (id, settings, report) => {
|
|
|
4706
4709
|
sections: parsed.data.blocks.flatMap((block) => {
|
|
4707
4710
|
const type = BlockType2.safeParse(block);
|
|
4708
4711
|
const kind = type.success ? type.data.type : void 0;
|
|
4709
|
-
const convert2 = kind &&
|
|
4712
|
+
const convert2 = kind && hasOwnKey(converters, kind) ? converters[kind] : void 0;
|
|
4710
4713
|
if (convert2) return convert2(block, report, settings);
|
|
4711
4714
|
report?.({
|
|
4712
4715
|
detail: kind ? `Unsupported post-purchase block type: ${kind}` : "Unreadable post-purchase block: missing type",
|
|
@@ -3656,6 +3656,9 @@ var parseShielded = (schema, raw, transform = (input) => input) => schema.parse(
|
|
|
3656
3656
|
// src/transforms/postPurchase/convertMessagePreview.ts
|
|
3657
3657
|
import { z as z34 } from "zod";
|
|
3658
3658
|
|
|
3659
|
+
// src/cab/hasOwnKey.ts
|
|
3660
|
+
var hasOwnKey = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
3661
|
+
|
|
3659
3662
|
// src/server/shared.ts
|
|
3660
3663
|
var NotFoundError = class extends Error {
|
|
3661
3664
|
constructor(message) {
|
|
@@ -4645,7 +4648,7 @@ var convertMessagePreview = (id, settings, report) => {
|
|
|
4645
4648
|
sections: parsed.data.blocks.flatMap((block) => {
|
|
4646
4649
|
const type = BlockType2.safeParse(block);
|
|
4647
4650
|
const kind = type.success ? type.data.type : void 0;
|
|
4648
|
-
const convert2 = kind &&
|
|
4651
|
+
const convert2 = kind && hasOwnKey(converters, kind) ? converters[kind] : void 0;
|
|
4649
4652
|
if (convert2) return convert2(block, report, settings);
|
|
4650
4653
|
report?.({
|
|
4651
4654
|
detail: kind ? `Unsupported post-purchase block type: ${kind}` : "Unreadable post-purchase block: missing type",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebuy/rebuy",
|
|
3
|
-
"version": "3.60.
|
|
3
|
+
"version": "3.60.3",
|
|
4
4
|
"description": "Shared zod schemas, legacy-to-CAB widget transforms, and server orchestrators for Rebuy's Shopify consumers (rebuy-api, admin-nextjs, rebuy-shopify-extensions)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Rebuy, Inc.",
|