@01.software/sdk 0.27.0 → 0.29.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/README.md +125 -1
- package/dist/analytics/react.cjs.map +1 -1
- package/dist/analytics/react.js.map +1 -1
- package/dist/analytics.cjs.map +1 -1
- package/dist/analytics.js.map +1 -1
- package/dist/{const-C0GlmeJ_.d.cts → const-DAjQYNuM.d.ts} +4 -4
- package/dist/{const-D-xucnw4.d.ts → const-Dsixdi6z.d.cts} +4 -4
- package/dist/index.cjs +626 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -8
- package/dist/index.d.ts +19 -8
- package/dist/index.js +626 -13
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-BPvUmPAq.d.cts → payload-types-Ci-ZA7aM.d.cts} +153 -73
- package/dist/{payload-types-BPvUmPAq.d.ts → payload-types-Ci-ZA7aM.d.ts} +153 -73
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/realtime.js.map +1 -1
- package/dist/{server-n3xK4Nks.d.cts → server-C0C8dtms.d.cts} +331 -12
- package/dist/{server-_zvihptw.d.ts → server-Cv0Q4dPQ.d.ts} +331 -12
- package/dist/server.cjs +68 -4
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +68 -4
- package/dist/server.js.map +1 -1
- package/dist/{types-BLdthWiW.d.ts → types-BWq_WlbB.d.ts} +1 -1
- package/dist/{types-DzWNu9pw.d.cts → types-zKjATmDK.d.cts} +1 -1
- package/dist/ui/canvas/server.cjs.map +1 -1
- package/dist/ui/canvas/server.js.map +1 -1
- package/dist/ui/canvas.cjs.map +1 -1
- package/dist/ui/canvas.js.map +1 -1
- package/dist/ui/form.d.cts +1 -1
- package/dist/ui/form.d.ts +1 -1
- package/dist/ui/video.d.cts +1 -1
- package/dist/ui/video.d.ts +1 -1
- package/dist/webhook.d.cts +3 -3
- package/dist/webhook.d.ts +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1141,6 +1141,7 @@ var INTERNAL_COLLECTIONS = [
|
|
|
1141
1141
|
"analytics-event-schemas",
|
|
1142
1142
|
"subscriptions",
|
|
1143
1143
|
"billing-history",
|
|
1144
|
+
"inventory-reservations",
|
|
1144
1145
|
"order-status-logs",
|
|
1145
1146
|
"api-keys",
|
|
1146
1147
|
"personal-access-tokens",
|
|
@@ -1181,8 +1182,8 @@ var COLLECTIONS = [
|
|
|
1181
1182
|
"carts",
|
|
1182
1183
|
"cart-items",
|
|
1183
1184
|
"discounts",
|
|
1184
|
-
"promotions",
|
|
1185
1185
|
"shipping-policies",
|
|
1186
|
+
"shipping-zones",
|
|
1186
1187
|
"documents",
|
|
1187
1188
|
"document-categories",
|
|
1188
1189
|
"document-types",
|
|
@@ -1851,7 +1852,15 @@ var CommerceClient = class {
|
|
|
1851
1852
|
};
|
|
1852
1853
|
this.product = {
|
|
1853
1854
|
stockCheck: (params) => execute("/api/products/stock-check", params),
|
|
1854
|
-
listingGroups: (params) => execute("/api/products/listing-groups", params)
|
|
1855
|
+
listingGroups: (params) => execute("/api/products/listing-groups", params),
|
|
1856
|
+
detail: async (params) => {
|
|
1857
|
+
try {
|
|
1858
|
+
return await execute("/api/products/detail", params);
|
|
1859
|
+
} catch (err) {
|
|
1860
|
+
if (err instanceof NotFoundError) return null;
|
|
1861
|
+
throw err;
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1855
1864
|
};
|
|
1856
1865
|
this.cart = {
|
|
1857
1866
|
get: cartApi.getCart.bind(cartApi),
|
|
@@ -1894,6 +1903,29 @@ var ProductApi = class extends BaseApi {
|
|
|
1894
1903
|
params
|
|
1895
1904
|
);
|
|
1896
1905
|
}
|
|
1906
|
+
/**
|
|
1907
|
+
* Fetch full product detail by slug or id.
|
|
1908
|
+
* Returns `null` on 404 regardless of reason (`not_found` / `not_published` /
|
|
1909
|
+
* `tenant_mismatch` / `feature_disabled`). For the reason behind a null,
|
|
1910
|
+
* inspect `client.lastRequestId` against backend logs.
|
|
1911
|
+
*/
|
|
1912
|
+
async detail(params) {
|
|
1913
|
+
try {
|
|
1914
|
+
return await this.request("/api/products/detail", params);
|
|
1915
|
+
} catch (err) {
|
|
1916
|
+
if (err instanceof NotFoundError) return null;
|
|
1917
|
+
throw err;
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
/**
|
|
1921
|
+
* Atomically create or update a product together with its options,
|
|
1922
|
+
* option-values, and variants in a single transaction. Mirrors Shopify's
|
|
1923
|
+
* `productSet` shape and is the canonical write path for the MCP
|
|
1924
|
+
* `product-upsert` tool.
|
|
1925
|
+
*/
|
|
1926
|
+
upsert(params) {
|
|
1927
|
+
return this.request("/api/products/upsert", params);
|
|
1928
|
+
}
|
|
1897
1929
|
};
|
|
1898
1930
|
|
|
1899
1931
|
// src/core/api/discount-api.ts
|
|
@@ -1986,7 +2018,9 @@ var ServerCommerceClient = class {
|
|
|
1986
2018
|
const orderApi = new OrderApi(serverOptions);
|
|
1987
2019
|
this.product = {
|
|
1988
2020
|
stockCheck: productApi.stockCheck.bind(productApi),
|
|
1989
|
-
listingGroups: productApi.listingGroups.bind(productApi)
|
|
2021
|
+
listingGroups: productApi.listingGroups.bind(productApi),
|
|
2022
|
+
detail: productApi.detail.bind(productApi),
|
|
2023
|
+
upsert: productApi.upsert.bind(productApi)
|
|
1990
2024
|
};
|
|
1991
2025
|
this.cart = {
|
|
1992
2026
|
get: cartApi.getCart.bind(cartApi),
|
|
@@ -2088,10 +2122,24 @@ var customerKeys = {
|
|
|
2088
2122
|
};
|
|
2089
2123
|
var productKeys = {
|
|
2090
2124
|
listingGroups: (options) => ["products", "listing-groups", "list", options],
|
|
2091
|
-
listingGroupsInfinite: (options) => ["products", "listing-groups", "infinite", options]
|
|
2125
|
+
listingGroupsInfinite: (options) => ["products", "listing-groups", "infinite", options],
|
|
2126
|
+
detail: (params) => ["products", "detail", params],
|
|
2127
|
+
detailAll: () => ["products", "detail"]
|
|
2092
2128
|
};
|
|
2093
2129
|
|
|
2094
2130
|
// src/core/query/collection-hooks.ts
|
|
2131
|
+
var PRODUCT_DETAIL_INVALIDATING_COLLECTIONS = /* @__PURE__ */ new Set([
|
|
2132
|
+
"products",
|
|
2133
|
+
"product-variants",
|
|
2134
|
+
"product-options",
|
|
2135
|
+
"product-option-values",
|
|
2136
|
+
"product-categories",
|
|
2137
|
+
"product-tags",
|
|
2138
|
+
"product-collections",
|
|
2139
|
+
"brands",
|
|
2140
|
+
"brand-logos",
|
|
2141
|
+
"images"
|
|
2142
|
+
]);
|
|
2095
2143
|
var DEFAULT_PAGE_SIZE = 20;
|
|
2096
2144
|
var CollectionHooks = class {
|
|
2097
2145
|
constructor(queryClient, collectionClient) {
|
|
@@ -2249,6 +2297,9 @@ var CollectionHooks = class {
|
|
|
2249
2297
|
this.queryClient.invalidateQueries({
|
|
2250
2298
|
queryKey: collectionKeys(collection).all
|
|
2251
2299
|
});
|
|
2300
|
+
if (PRODUCT_DETAIL_INVALIDATING_COLLECTIONS.has(collection)) {
|
|
2301
|
+
this.queryClient.invalidateQueries({ queryKey: ["products", "detail"] });
|
|
2302
|
+
}
|
|
2252
2303
|
options?.onSuccess?.(data);
|
|
2253
2304
|
},
|
|
2254
2305
|
onError: options?.onError,
|
|
@@ -2269,6 +2320,9 @@ var CollectionHooks = class {
|
|
|
2269
2320
|
this.queryClient.invalidateQueries({
|
|
2270
2321
|
queryKey: collectionKeys(collection).all
|
|
2271
2322
|
});
|
|
2323
|
+
if (PRODUCT_DETAIL_INVALIDATING_COLLECTIONS.has(collection)) {
|
|
2324
|
+
this.queryClient.invalidateQueries({ queryKey: ["products", "detail"] });
|
|
2325
|
+
}
|
|
2272
2326
|
options?.onSuccess?.(data);
|
|
2273
2327
|
},
|
|
2274
2328
|
onError: options?.onError,
|
|
@@ -2285,6 +2339,9 @@ var CollectionHooks = class {
|
|
|
2285
2339
|
this.queryClient.invalidateQueries({
|
|
2286
2340
|
queryKey: collectionKeys(collection).all
|
|
2287
2341
|
});
|
|
2342
|
+
if (PRODUCT_DETAIL_INVALIDATING_COLLECTIONS.has(collection)) {
|
|
2343
|
+
this.queryClient.invalidateQueries({ queryKey: ["products", "detail"] });
|
|
2344
|
+
}
|
|
2288
2345
|
options?.onSuccess?.(data);
|
|
2289
2346
|
},
|
|
2290
2347
|
onError: options?.onError,
|
|
@@ -2440,7 +2497,7 @@ var CustomerHooks = class {
|
|
|
2440
2497
|
|
|
2441
2498
|
// src/core/query/query-hooks.ts
|
|
2442
2499
|
var QueryHooks = class extends CollectionHooks {
|
|
2443
|
-
constructor(queryClient, collectionClient, customerAuth) {
|
|
2500
|
+
constructor(queryClient, collectionClient, customerAuth, commerceClient) {
|
|
2444
2501
|
super(queryClient, collectionClient);
|
|
2445
2502
|
// --- Customer hooks delegation ---
|
|
2446
2503
|
this.useCustomerMe = (...args) => this._customer.useCustomerMe(...args);
|
|
@@ -2457,6 +2514,7 @@ var QueryHooks = class extends CollectionHooks {
|
|
|
2457
2514
|
this.getCustomerData = () => this._customer.getCustomerData();
|
|
2458
2515
|
this.setCustomerData = (data) => this._customer.setCustomerData(data);
|
|
2459
2516
|
this._customer = new CustomerHooks(queryClient, customerAuth);
|
|
2517
|
+
this._commerce = commerceClient;
|
|
2460
2518
|
}
|
|
2461
2519
|
useProductListingGroupsQuery(params, options) {
|
|
2462
2520
|
const queryOptions = params.options;
|
|
@@ -2550,6 +2608,21 @@ var QueryHooks = class extends CollectionHooks {
|
|
|
2550
2608
|
staleTime: options?.staleTime
|
|
2551
2609
|
});
|
|
2552
2610
|
}
|
|
2611
|
+
useProductDetail(params, options) {
|
|
2612
|
+
const discriminator = "slug" in params ? params.slug : params.id;
|
|
2613
|
+
const enabled = options?.enabled !== false && Boolean(discriminator);
|
|
2614
|
+
return useQueryOriginal3({
|
|
2615
|
+
queryKey: productKeys.detail(params),
|
|
2616
|
+
queryFn: () => this._commerce.product.detail(params),
|
|
2617
|
+
enabled
|
|
2618
|
+
});
|
|
2619
|
+
}
|
|
2620
|
+
useProductDetailBySlug(slug, options) {
|
|
2621
|
+
return this.useProductDetail({ slug }, options);
|
|
2622
|
+
}
|
|
2623
|
+
useProductDetailById(id, options) {
|
|
2624
|
+
return this.useProductDetail({ id }, options);
|
|
2625
|
+
}
|
|
2553
2626
|
};
|
|
2554
2627
|
|
|
2555
2628
|
// src/core/client/client.ts
|
|
@@ -2612,7 +2685,8 @@ var Client = class {
|
|
|
2612
2685
|
this.query = new QueryHooks(
|
|
2613
2686
|
this.queryClient,
|
|
2614
2687
|
collectionClient,
|
|
2615
|
-
this.customer.auth
|
|
2688
|
+
this.customer.auth,
|
|
2689
|
+
this.commerce
|
|
2616
2690
|
);
|
|
2617
2691
|
}
|
|
2618
2692
|
getState() {
|
|
@@ -2674,7 +2748,7 @@ var ServerClient = class {
|
|
|
2674
2748
|
onRequestId
|
|
2675
2749
|
);
|
|
2676
2750
|
this.queryClient = getQueryClient();
|
|
2677
|
-
this.query = new QueryHooks(this.queryClient, this.collections);
|
|
2751
|
+
this.query = new QueryHooks(this.queryClient, this.collections, void 0, this.commerce);
|
|
2678
2752
|
}
|
|
2679
2753
|
getState() {
|
|
2680
2754
|
return { ...this.state };
|
|
@@ -2951,6 +3025,13 @@ function createTypedWebhookHandler(collection, handler) {
|
|
|
2951
3025
|
}
|
|
2952
3026
|
|
|
2953
3027
|
// src/utils/ecommerce.ts
|
|
3028
|
+
var ProductSelectionCodecError = class extends Error {
|
|
3029
|
+
constructor(message) {
|
|
3030
|
+
super(message);
|
|
3031
|
+
this.code = "ambiguous_product_selection_query";
|
|
3032
|
+
this.name = "ProductSelectionCodecError";
|
|
3033
|
+
}
|
|
3034
|
+
};
|
|
2954
3035
|
function getRelationID(value) {
|
|
2955
3036
|
if (typeof value === "string") return value;
|
|
2956
3037
|
if (typeof value === "number") return String(value);
|
|
@@ -2997,10 +3078,11 @@ function getFirstAvailableVariantPrimaryImage(variants) {
|
|
|
2997
3078
|
}
|
|
2998
3079
|
return null;
|
|
2999
3080
|
}
|
|
3000
|
-
function normalizeOptionValue(value, fallbackOptionId) {
|
|
3081
|
+
function normalizeOptionValue(value, fallbackOptionId, fallbackOptionSlug) {
|
|
3001
3082
|
return {
|
|
3002
3083
|
id: String(value.id),
|
|
3003
3084
|
optionId: getRelationID(value.option) ?? fallbackOptionId,
|
|
3085
|
+
optionSlug: fallbackOptionSlug,
|
|
3004
3086
|
label: value.value || value.slug || String(value.id),
|
|
3005
3087
|
slug: value.slug ?? null,
|
|
3006
3088
|
swatchColor: value.swatchColor ?? null,
|
|
@@ -3009,20 +3091,26 @@ function normalizeOptionValue(value, fallbackOptionId) {
|
|
|
3009
3091
|
order: value._order ?? value["_product-option-values_values_order"] ?? ""
|
|
3010
3092
|
};
|
|
3011
3093
|
}
|
|
3012
|
-
function normalizeVariantOptionValues(variant, valueToOptionId, optionIds) {
|
|
3094
|
+
function normalizeVariantOptionValues(variant, optionById, valueToOptionId, optionIds) {
|
|
3013
3095
|
const optionValueByOptionId = /* @__PURE__ */ new Map();
|
|
3096
|
+
const optionValueByOptionSlug = /* @__PURE__ */ new Map();
|
|
3014
3097
|
for (const rawValue of Array.isArray(variant.optionValues) ? variant.optionValues : []) {
|
|
3015
3098
|
const valueId = getRelationID(rawValue);
|
|
3016
3099
|
if (!valueId) continue;
|
|
3017
3100
|
const optionId = valueToOptionId.get(valueId) ?? (isProductOptionValueDoc(rawValue) ? getRelationID(rawValue.option) : void 0);
|
|
3018
3101
|
if (!optionId || optionValueByOptionId.has(optionId)) continue;
|
|
3019
3102
|
optionValueByOptionId.set(optionId, valueId);
|
|
3103
|
+
const optionSlug = optionById.get(optionId)?.slug;
|
|
3104
|
+
if (optionSlug && !optionValueByOptionSlug.has(optionSlug)) {
|
|
3105
|
+
optionValueByOptionSlug.set(optionSlug, valueId);
|
|
3106
|
+
}
|
|
3020
3107
|
}
|
|
3021
3108
|
const optionValueIds = optionIds.map((optionId) => optionValueByOptionId.get(optionId)).filter((valueId) => Boolean(valueId));
|
|
3022
3109
|
return {
|
|
3023
3110
|
id: String(variant.id),
|
|
3024
3111
|
optionValueIds,
|
|
3025
3112
|
optionValueByOptionId,
|
|
3113
|
+
optionValueByOptionSlug,
|
|
3026
3114
|
source: variant
|
|
3027
3115
|
};
|
|
3028
3116
|
}
|
|
@@ -3032,17 +3120,20 @@ function buildProductOptionMatrix({
|
|
|
3032
3120
|
}) {
|
|
3033
3121
|
const normalizedOptions = options.map((option) => {
|
|
3034
3122
|
const valuesById = /* @__PURE__ */ new Map();
|
|
3123
|
+
const optionSlug = option.slug ?? String(option.id);
|
|
3035
3124
|
for (const rawValue of option.values?.docs ?? []) {
|
|
3036
3125
|
if (!isProductOptionValueDoc(rawValue)) continue;
|
|
3037
3126
|
const normalizedValue = normalizeOptionValue(
|
|
3038
3127
|
rawValue,
|
|
3039
|
-
String(option.id)
|
|
3128
|
+
String(option.id),
|
|
3129
|
+
optionSlug
|
|
3040
3130
|
);
|
|
3041
3131
|
valuesById.set(normalizedValue.id, normalizedValue);
|
|
3042
3132
|
}
|
|
3043
3133
|
return {
|
|
3044
3134
|
id: String(option.id),
|
|
3045
3135
|
title: option.title ?? String(option.id),
|
|
3136
|
+
slug: optionSlug,
|
|
3046
3137
|
order: option._order ?? option["_product-options_options_order"] ?? "",
|
|
3047
3138
|
values: Array.from(valuesById.values()).sort(
|
|
3048
3139
|
(left, right) => compareOrder(left.order, right.order)
|
|
@@ -3052,24 +3143,113 @@ function buildProductOptionMatrix({
|
|
|
3052
3143
|
const optionById = new Map(
|
|
3053
3144
|
normalizedOptions.map((option) => [option.id, option])
|
|
3054
3145
|
);
|
|
3146
|
+
const optionBySlug = new Map(
|
|
3147
|
+
normalizedOptions.map((option) => [option.slug, option])
|
|
3148
|
+
);
|
|
3055
3149
|
const valueById = /* @__PURE__ */ new Map();
|
|
3056
3150
|
const valueToOptionId = /* @__PURE__ */ new Map();
|
|
3151
|
+
const valueToOptionSlug = /* @__PURE__ */ new Map();
|
|
3057
3152
|
for (const option of normalizedOptions) {
|
|
3058
3153
|
for (const value of option.values) {
|
|
3059
3154
|
valueById.set(value.id, value);
|
|
3060
3155
|
valueToOptionId.set(value.id, option.id);
|
|
3156
|
+
valueToOptionSlug.set(value.id, option.slug);
|
|
3061
3157
|
}
|
|
3062
3158
|
}
|
|
3063
3159
|
const optionIds = normalizedOptions.map((option) => option.id);
|
|
3160
|
+
const optionSlugs = normalizedOptions.map((option) => option.slug);
|
|
3064
3161
|
const normalizedVariants = variants.map(
|
|
3065
|
-
(variant) => normalizeVariantOptionValues(
|
|
3162
|
+
(variant) => normalizeVariantOptionValues(
|
|
3163
|
+
variant,
|
|
3164
|
+
optionById,
|
|
3165
|
+
valueToOptionId,
|
|
3166
|
+
optionIds
|
|
3167
|
+
)
|
|
3168
|
+
);
|
|
3169
|
+
return {
|
|
3170
|
+
options: normalizedOptions,
|
|
3171
|
+
optionIds,
|
|
3172
|
+
optionSlugs,
|
|
3173
|
+
optionById,
|
|
3174
|
+
optionBySlug,
|
|
3175
|
+
valueById,
|
|
3176
|
+
valueToOptionId,
|
|
3177
|
+
valueToOptionSlug,
|
|
3178
|
+
variants: normalizedVariants
|
|
3179
|
+
};
|
|
3180
|
+
}
|
|
3181
|
+
function matrixOrder(index) {
|
|
3182
|
+
return String(index).padStart(6, "0");
|
|
3183
|
+
}
|
|
3184
|
+
function buildProductOptionMatrixFromDetail(detail) {
|
|
3185
|
+
const normalizedOptions = detail.options.map((option, optionIndex) => ({
|
|
3186
|
+
id: String(option.id),
|
|
3187
|
+
title: option.title || String(option.id),
|
|
3188
|
+
slug: option.slug,
|
|
3189
|
+
order: matrixOrder(optionIndex),
|
|
3190
|
+
values: option.values.map((value, valueIndex) => ({
|
|
3191
|
+
id: String(value.id),
|
|
3192
|
+
optionId: String(option.id),
|
|
3193
|
+
optionSlug: option.slug,
|
|
3194
|
+
label: value.value || value.slug || String(value.id),
|
|
3195
|
+
slug: value.slug,
|
|
3196
|
+
swatchColor: value.swatchColor ?? null,
|
|
3197
|
+
thumbnail: value.thumbnail ?? null,
|
|
3198
|
+
images: value.images ?? null,
|
|
3199
|
+
order: matrixOrder(valueIndex)
|
|
3200
|
+
}))
|
|
3201
|
+
}));
|
|
3202
|
+
const optionById = new Map(
|
|
3203
|
+
normalizedOptions.map((option) => [option.id, option])
|
|
3204
|
+
);
|
|
3205
|
+
const optionBySlug = new Map(
|
|
3206
|
+
normalizedOptions.map((option) => [option.slug, option])
|
|
3066
3207
|
);
|
|
3208
|
+
const valueById = /* @__PURE__ */ new Map();
|
|
3209
|
+
const valueToOptionId = /* @__PURE__ */ new Map();
|
|
3210
|
+
const valueToOptionSlug = /* @__PURE__ */ new Map();
|
|
3211
|
+
for (const option of normalizedOptions) {
|
|
3212
|
+
for (const value of option.values) {
|
|
3213
|
+
valueById.set(value.id, value);
|
|
3214
|
+
valueToOptionId.set(value.id, option.id);
|
|
3215
|
+
valueToOptionSlug.set(value.id, option.slug);
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
const optionIds = normalizedOptions.map((option) => option.id);
|
|
3219
|
+
const optionSlugs = normalizedOptions.map((option) => option.slug);
|
|
3220
|
+
const normalizedVariants = detail.variants.map((variant) => {
|
|
3221
|
+
const optionValueByOptionId = /* @__PURE__ */ new Map();
|
|
3222
|
+
const optionValueByOptionSlug = /* @__PURE__ */ new Map();
|
|
3223
|
+
for (const rawValue of variant.optionValues) {
|
|
3224
|
+
const optionId = String(rawValue.optionId);
|
|
3225
|
+
const valueId = String(rawValue.valueId);
|
|
3226
|
+
const optionSlug = rawValue.optionSlug;
|
|
3227
|
+
if (!optionById.has(optionId)) continue;
|
|
3228
|
+
if (valueToOptionId.get(valueId) !== optionId) continue;
|
|
3229
|
+
if (optionValueByOptionId.has(optionId)) continue;
|
|
3230
|
+
optionValueByOptionId.set(optionId, valueId);
|
|
3231
|
+
if (optionSlug && !optionValueByOptionSlug.has(optionSlug)) {
|
|
3232
|
+
optionValueByOptionSlug.set(optionSlug, valueId);
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
const optionValueIds = optionIds.map((optionId) => optionValueByOptionId.get(optionId)).filter((valueId) => Boolean(valueId));
|
|
3236
|
+
return {
|
|
3237
|
+
id: String(variant.id),
|
|
3238
|
+
optionValueIds,
|
|
3239
|
+
optionValueByOptionId,
|
|
3240
|
+
optionValueByOptionSlug,
|
|
3241
|
+
source: variant
|
|
3242
|
+
};
|
|
3243
|
+
});
|
|
3067
3244
|
return {
|
|
3068
3245
|
options: normalizedOptions,
|
|
3069
3246
|
optionIds,
|
|
3247
|
+
optionSlugs,
|
|
3070
3248
|
optionById,
|
|
3249
|
+
optionBySlug,
|
|
3071
3250
|
valueById,
|
|
3072
3251
|
valueToOptionId,
|
|
3252
|
+
valueToOptionSlug,
|
|
3073
3253
|
variants: normalizedVariants
|
|
3074
3254
|
};
|
|
3075
3255
|
}
|
|
@@ -3102,7 +3282,7 @@ function getAvailableOptionValues(matrix, optionId, selectedValueIds) {
|
|
|
3102
3282
|
)
|
|
3103
3283
|
);
|
|
3104
3284
|
const availableValueIds = new Set(
|
|
3105
|
-
matchingVariants.map((variant) => variant.optionValueByOptionId.get(optionId)).filter((valueId) => Boolean(valueId))
|
|
3285
|
+
matchingVariants.filter((variant) => variant.source.isActive !== false).map((variant) => variant.optionValueByOptionId.get(optionId)).filter((valueId) => Boolean(valueId))
|
|
3106
3286
|
);
|
|
3107
3287
|
return option.values.filter((value) => availableValueIds.has(value.id));
|
|
3108
3288
|
}
|
|
@@ -3117,6 +3297,432 @@ function resolveVariantForSelection(matrix, selectedValueIds) {
|
|
|
3117
3297
|
)
|
|
3118
3298
|
);
|
|
3119
3299
|
}
|
|
3300
|
+
function getVariantSelection(matrix, variantId) {
|
|
3301
|
+
if (variantId == null) return void 0;
|
|
3302
|
+
const id = String(variantId);
|
|
3303
|
+
return matrix.variants.find((variant) => variant.id === id);
|
|
3304
|
+
}
|
|
3305
|
+
function hasExplicitSelection(selection) {
|
|
3306
|
+
return Boolean(
|
|
3307
|
+
selection.variantId != null || selection.search || selection.valueIds || Object.keys(selection.byOptionId ?? {}).length > 0 || Object.keys(selection.byOptionSlug ?? {}).length > 0
|
|
3308
|
+
);
|
|
3309
|
+
}
|
|
3310
|
+
function assignSelectedValue(matrix, selectedByOptionId, optionId, valueId) {
|
|
3311
|
+
if (valueId == null) return;
|
|
3312
|
+
const normalizedValueId = String(valueId);
|
|
3313
|
+
if (matrix.valueToOptionId.get(normalizedValueId) !== optionId) return;
|
|
3314
|
+
selectedByOptionId.set(optionId, normalizedValueId);
|
|
3315
|
+
}
|
|
3316
|
+
function assignSelectedValueSlugByOptionId(matrix, selectedByOptionId, optionId, valueSlug) {
|
|
3317
|
+
if (!valueSlug) return;
|
|
3318
|
+
const option = matrix.optionById.get(optionId);
|
|
3319
|
+
if (!option) return;
|
|
3320
|
+
const value = option.values.find((candidate) => candidate.slug === valueSlug);
|
|
3321
|
+
if (!value) return;
|
|
3322
|
+
selectedByOptionId.set(optionId, value.id);
|
|
3323
|
+
}
|
|
3324
|
+
function assignSelectedValueSlugByOptionSlug(matrix, selectedByOptionId, optionSlug, valueSlug) {
|
|
3325
|
+
if (!valueSlug) return;
|
|
3326
|
+
const option = matrix.optionBySlug.get(optionSlug);
|
|
3327
|
+
if (!option) return;
|
|
3328
|
+
const value = option.values.find((candidate) => candidate.slug === valueSlug);
|
|
3329
|
+
if (!value) return;
|
|
3330
|
+
selectedByOptionId.set(option.id, value.id);
|
|
3331
|
+
}
|
|
3332
|
+
function requireValueSlug(value) {
|
|
3333
|
+
if (value.slug) return value.slug;
|
|
3334
|
+
throw new ProductSelectionCodecError(
|
|
3335
|
+
`Option value "${value.id}" does not have a slug and cannot be used in product selection URLs.`
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3338
|
+
function requireOptionSlug(option) {
|
|
3339
|
+
if (option.slug) return option.slug;
|
|
3340
|
+
throw new ProductSelectionCodecError(
|
|
3341
|
+
`Option "${option.id}" does not have a slug and cannot be used in product selection URLs.`
|
|
3342
|
+
);
|
|
3343
|
+
}
|
|
3344
|
+
function toSearchParams(search) {
|
|
3345
|
+
if (!search) return new URLSearchParams();
|
|
3346
|
+
if (search instanceof URLSearchParams) return new URLSearchParams(search);
|
|
3347
|
+
if (search instanceof URL) return new URLSearchParams(search.searchParams);
|
|
3348
|
+
const trimmed = search.trim();
|
|
3349
|
+
if (!trimmed) return new URLSearchParams();
|
|
3350
|
+
try {
|
|
3351
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) {
|
|
3352
|
+
return new URL(trimmed).searchParams;
|
|
3353
|
+
}
|
|
3354
|
+
} catch {
|
|
3355
|
+
return new URLSearchParams();
|
|
3356
|
+
}
|
|
3357
|
+
return new URLSearchParams(
|
|
3358
|
+
trimmed.startsWith("?") ? trimmed.slice(1) : trimmed
|
|
3359
|
+
);
|
|
3360
|
+
}
|
|
3361
|
+
function slugLike(value) {
|
|
3362
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3363
|
+
}
|
|
3364
|
+
function assertNoAmbiguousSelectionParams(matrix, params) {
|
|
3365
|
+
const knownSelectionKeys = /* @__PURE__ */ new Set();
|
|
3366
|
+
for (const option of matrix.options) {
|
|
3367
|
+
knownSelectionKeys.add(slugLike(option.slug));
|
|
3368
|
+
knownSelectionKeys.add(slugLike(option.title));
|
|
3369
|
+
for (const value of option.values) {
|
|
3370
|
+
if (value.slug) knownSelectionKeys.add(slugLike(value.slug));
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
for (const [key, value] of params.entries()) {
|
|
3374
|
+
if (key.startsWith("opt.")) {
|
|
3375
|
+
const optionToken = key.slice(4);
|
|
3376
|
+
if (!optionToken || !matrix.optionBySlug.has(optionToken) && !matrix.optionById.has(optionToken)) {
|
|
3377
|
+
throw new ProductSelectionCodecError(
|
|
3378
|
+
`Unknown product selection query parameter "${key}". Use opt.<optionSlug>=<valueSlug>.`
|
|
3379
|
+
);
|
|
3380
|
+
}
|
|
3381
|
+
if (!value) {
|
|
3382
|
+
throw new ProductSelectionCodecError(
|
|
3383
|
+
`Product selection query parameter "${key}" requires a value slug.`
|
|
3384
|
+
);
|
|
3385
|
+
}
|
|
3386
|
+
continue;
|
|
3387
|
+
}
|
|
3388
|
+
const keyToken = slugLike(key);
|
|
3389
|
+
if (knownSelectionKeys.has(keyToken) || value === "" && knownSelectionKeys.has(keyToken)) {
|
|
3390
|
+
throw new ProductSelectionCodecError(
|
|
3391
|
+
`Ambiguous product selection query parameter "${key}". Use opt.<optionSlug>=<valueSlug>.`
|
|
3392
|
+
);
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
function emitLegacyOptionIdParam(options, event) {
|
|
3397
|
+
try {
|
|
3398
|
+
options?.onLegacyOptionIdParam?.(event);
|
|
3399
|
+
} catch {
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
function assignSearchSelection(matrix, selectedByOptionId, search, options) {
|
|
3403
|
+
if (!search) return;
|
|
3404
|
+
const params = toSearchParams(search);
|
|
3405
|
+
assertNoAmbiguousSelectionParams(matrix, params);
|
|
3406
|
+
for (const [key, valueSlug] of params.entries()) {
|
|
3407
|
+
if (!key.startsWith("opt.")) continue;
|
|
3408
|
+
const optionToken = key.slice(4);
|
|
3409
|
+
const optionBySlug = matrix.optionBySlug.get(optionToken);
|
|
3410
|
+
if (optionBySlug) {
|
|
3411
|
+
assignSelectedValueSlugByOptionSlug(
|
|
3412
|
+
matrix,
|
|
3413
|
+
selectedByOptionId,
|
|
3414
|
+
optionBySlug.slug,
|
|
3415
|
+
valueSlug
|
|
3416
|
+
);
|
|
3417
|
+
continue;
|
|
3418
|
+
}
|
|
3419
|
+
const legacyOption = matrix.optionById.get(optionToken);
|
|
3420
|
+
if (!legacyOption) continue;
|
|
3421
|
+
const before = selectedByOptionId.get(legacyOption.id);
|
|
3422
|
+
assignSelectedValueSlugByOptionId(
|
|
3423
|
+
matrix,
|
|
3424
|
+
selectedByOptionId,
|
|
3425
|
+
legacyOption.id,
|
|
3426
|
+
valueSlug
|
|
3427
|
+
);
|
|
3428
|
+
if (selectedByOptionId.get(legacyOption.id) !== before) {
|
|
3429
|
+
emitLegacyOptionIdParam(options, {
|
|
3430
|
+
optionId: legacyOption.id,
|
|
3431
|
+
optionSlug: legacyOption.slug,
|
|
3432
|
+
valueSlug,
|
|
3433
|
+
searchParam: key
|
|
3434
|
+
});
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
function normalizeProductSelection(detail, selection = {}, options) {
|
|
3439
|
+
const matrix = buildProductOptionMatrixFromDetail(detail);
|
|
3440
|
+
const selectedByOptionId = /* @__PURE__ */ new Map();
|
|
3441
|
+
const variantSelection = getVariantSelection(matrix, selection.variantId);
|
|
3442
|
+
const variantId = variantSelection?.id ?? null;
|
|
3443
|
+
if (variantSelection) {
|
|
3444
|
+
for (const [optionId, valueId] of variantSelection.optionValueByOptionId) {
|
|
3445
|
+
selectedByOptionId.set(optionId, valueId);
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
for (const rawValueId of selection.valueIds ?? []) {
|
|
3449
|
+
const valueId = getRelationID(rawValueId);
|
|
3450
|
+
if (!valueId) continue;
|
|
3451
|
+
const optionId = matrix.valueToOptionId.get(valueId);
|
|
3452
|
+
if (!optionId) continue;
|
|
3453
|
+
selectedByOptionId.set(optionId, valueId);
|
|
3454
|
+
}
|
|
3455
|
+
assignSearchSelection(matrix, selectedByOptionId, selection.search, options);
|
|
3456
|
+
for (const [rawOptionId, rawSelection] of Object.entries(
|
|
3457
|
+
selection.byOptionId ?? {}
|
|
3458
|
+
)) {
|
|
3459
|
+
const optionId = String(rawOptionId);
|
|
3460
|
+
if (!matrix.optionById.has(optionId)) continue;
|
|
3461
|
+
if (rawSelection && typeof rawSelection === "object" && "valueId" in rawSelection && rawSelection.valueId != null) {
|
|
3462
|
+
assignSelectedValue(
|
|
3463
|
+
matrix,
|
|
3464
|
+
selectedByOptionId,
|
|
3465
|
+
optionId,
|
|
3466
|
+
rawSelection.valueId
|
|
3467
|
+
);
|
|
3468
|
+
continue;
|
|
3469
|
+
}
|
|
3470
|
+
if (typeof rawSelection === "string" || typeof rawSelection === "number") {
|
|
3471
|
+
assignSelectedValue(matrix, selectedByOptionId, optionId, rawSelection);
|
|
3472
|
+
continue;
|
|
3473
|
+
}
|
|
3474
|
+
if (rawSelection && typeof rawSelection === "object" && "valueSlug" in rawSelection) {
|
|
3475
|
+
assignSelectedValueSlugByOptionId(
|
|
3476
|
+
matrix,
|
|
3477
|
+
selectedByOptionId,
|
|
3478
|
+
optionId,
|
|
3479
|
+
rawSelection.valueSlug
|
|
3480
|
+
);
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
for (const [rawOptionSlug, rawSelection] of Object.entries(
|
|
3484
|
+
selection.byOptionSlug ?? {}
|
|
3485
|
+
)) {
|
|
3486
|
+
const optionSlug = String(rawOptionSlug);
|
|
3487
|
+
if (!matrix.optionBySlug.has(optionSlug)) continue;
|
|
3488
|
+
if (rawSelection && typeof rawSelection === "object" && "valueId" in rawSelection && rawSelection.valueId != null) {
|
|
3489
|
+
const option = matrix.optionBySlug.get(optionSlug);
|
|
3490
|
+
if (option) {
|
|
3491
|
+
assignSelectedValue(
|
|
3492
|
+
matrix,
|
|
3493
|
+
selectedByOptionId,
|
|
3494
|
+
option.id,
|
|
3495
|
+
rawSelection.valueId
|
|
3496
|
+
);
|
|
3497
|
+
}
|
|
3498
|
+
continue;
|
|
3499
|
+
}
|
|
3500
|
+
if (rawSelection && typeof rawSelection === "object" && "valueSlug" in rawSelection) {
|
|
3501
|
+
assignSelectedValueSlugByOptionSlug(
|
|
3502
|
+
matrix,
|
|
3503
|
+
selectedByOptionId,
|
|
3504
|
+
optionSlug,
|
|
3505
|
+
rawSelection.valueSlug
|
|
3506
|
+
);
|
|
3507
|
+
continue;
|
|
3508
|
+
}
|
|
3509
|
+
if (typeof rawSelection === "string" || typeof rawSelection === "number") {
|
|
3510
|
+
assignSelectedValueSlugByOptionSlug(
|
|
3511
|
+
matrix,
|
|
3512
|
+
selectedByOptionId,
|
|
3513
|
+
optionSlug,
|
|
3514
|
+
String(rawSelection)
|
|
3515
|
+
);
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
const byOptionId = Object.fromEntries(
|
|
3519
|
+
matrix.optionIds.map((optionId) => [optionId, selectedByOptionId.get(optionId)]).filter((entry) => Boolean(entry[1]))
|
|
3520
|
+
);
|
|
3521
|
+
const byOptionSlug = Object.fromEntries(
|
|
3522
|
+
matrix.options.map((option) => {
|
|
3523
|
+
const valueId = selectedByOptionId.get(option.id);
|
|
3524
|
+
const value = valueId ? matrix.valueById.get(valueId) : void 0;
|
|
3525
|
+
return [option.slug, value?.slug ?? void 0];
|
|
3526
|
+
}).filter((entry) => Boolean(entry[1]))
|
|
3527
|
+
);
|
|
3528
|
+
return {
|
|
3529
|
+
byOptionSlug,
|
|
3530
|
+
byOptionId,
|
|
3531
|
+
valueIds: matrix.optionIds.map((optionId) => byOptionId[optionId]).filter((valueId) => Boolean(valueId)),
|
|
3532
|
+
variantId
|
|
3533
|
+
};
|
|
3534
|
+
}
|
|
3535
|
+
function parseProductSelection(detail, search, options) {
|
|
3536
|
+
return normalizeProductSelection(detail, { search }, options);
|
|
3537
|
+
}
|
|
3538
|
+
function stringifyProductSelection(detail, selection = {}, options) {
|
|
3539
|
+
const matrix = buildProductOptionMatrixFromDetail(detail);
|
|
3540
|
+
const normalized = normalizeProductSelection(detail, selection, options);
|
|
3541
|
+
const params = new URLSearchParams();
|
|
3542
|
+
for (const optionId of matrix.optionIds) {
|
|
3543
|
+
const valueId = normalized.byOptionId[optionId];
|
|
3544
|
+
if (!valueId) continue;
|
|
3545
|
+
const option = matrix.optionById.get(optionId);
|
|
3546
|
+
const value = matrix.valueById.get(valueId);
|
|
3547
|
+
if (!option || !value) continue;
|
|
3548
|
+
params.append(`opt.${requireOptionSlug(option)}`, requireValueSlug(value));
|
|
3549
|
+
}
|
|
3550
|
+
return params.toString();
|
|
3551
|
+
}
|
|
3552
|
+
function createProductSelectionCodec(detail, options) {
|
|
3553
|
+
return {
|
|
3554
|
+
parse: (search) => parseProductSelection(detail, search, options),
|
|
3555
|
+
stringify: (selection = {}) => stringifyProductSelection(detail, selection, options)
|
|
3556
|
+
};
|
|
3557
|
+
}
|
|
3558
|
+
function selectedEntries(selection) {
|
|
3559
|
+
return Object.entries(selection.byOptionId);
|
|
3560
|
+
}
|
|
3561
|
+
function getMatchingVariantEntries(matrix, selection) {
|
|
3562
|
+
const entries = selectedEntries(selection);
|
|
3563
|
+
if (entries.length === 0) return matrix.variants;
|
|
3564
|
+
return matrix.variants.filter(
|
|
3565
|
+
(variant) => entries.every(
|
|
3566
|
+
([optionId, valueId]) => variant.optionValueByOptionId.get(optionId) === valueId
|
|
3567
|
+
)
|
|
3568
|
+
);
|
|
3569
|
+
}
|
|
3570
|
+
function activeVariantEntries(variants) {
|
|
3571
|
+
return variants.filter((variant) => variant.source.isActive !== false);
|
|
3572
|
+
}
|
|
3573
|
+
function getExactSelectedVariantEntry(matrix, selection, matchingVariants) {
|
|
3574
|
+
if (matrix.optionIds.length === 0) {
|
|
3575
|
+
return getVariantSelection(matrix, selection.variantId) ?? (matchingVariants.length === 1 ? matchingVariants[0] ?? null : null);
|
|
3576
|
+
}
|
|
3577
|
+
const allOptionsSelected = matrix.optionIds.every(
|
|
3578
|
+
(optionId) => Boolean(selection.byOptionId[optionId])
|
|
3579
|
+
);
|
|
3580
|
+
if (!allOptionsSelected) return null;
|
|
3581
|
+
return matchingVariants.find(
|
|
3582
|
+
(variant) => matrix.optionIds.every(
|
|
3583
|
+
(optionId) => variant.optionValueByOptionId.get(optionId) === selection.byOptionId[optionId]
|
|
3584
|
+
)
|
|
3585
|
+
) ?? null;
|
|
3586
|
+
}
|
|
3587
|
+
function buildSelectionPrice(variants) {
|
|
3588
|
+
const { min, max } = getMinMax(variants.map((variant) => variant.price));
|
|
3589
|
+
const { min: compareAtMin, max: compareAtMax } = getMinMax(
|
|
3590
|
+
variants.map((variant) => variant.compareAtPrice)
|
|
3591
|
+
);
|
|
3592
|
+
return {
|
|
3593
|
+
min,
|
|
3594
|
+
max,
|
|
3595
|
+
compareAtMin,
|
|
3596
|
+
compareAtMax,
|
|
3597
|
+
isRange: min !== null && max !== null ? min !== max : false
|
|
3598
|
+
};
|
|
3599
|
+
}
|
|
3600
|
+
function firstMedia(value) {
|
|
3601
|
+
if (value == null) return null;
|
|
3602
|
+
if (Array.isArray(value)) return firstMedia(value[0]);
|
|
3603
|
+
return value;
|
|
3604
|
+
}
|
|
3605
|
+
function isPresentMedia(value) {
|
|
3606
|
+
return value != null;
|
|
3607
|
+
}
|
|
3608
|
+
function mediaArray(values) {
|
|
3609
|
+
if (!Array.isArray(values)) return [];
|
|
3610
|
+
return values.filter(isPresentMedia);
|
|
3611
|
+
}
|
|
3612
|
+
function buildSelectionMedia(detail, selectedVariant, matchingVariants, selectedValues) {
|
|
3613
|
+
const selectedValueImages = selectedValues.flatMap(
|
|
3614
|
+
(value) => mediaArray(value.images)
|
|
3615
|
+
);
|
|
3616
|
+
const selectedValuePrimary = selectedValues.map((value) => firstMedia(value.thumbnail) ?? firstMedia(value.images)).find((value) => value != null) ?? null;
|
|
3617
|
+
const selectedVariantPrimary = firstMedia(selectedVariant?.thumbnail) ?? firstMedia(selectedVariant?.images);
|
|
3618
|
+
const matchingVariantPrimary = matchingVariants.map(
|
|
3619
|
+
(variant) => firstMedia(variant.thumbnail) ?? firstMedia(variant.images)
|
|
3620
|
+
).find((value) => value != null) ?? null;
|
|
3621
|
+
const detailImages = mediaArray(detail.images);
|
|
3622
|
+
const primaryImage = selectedVariantPrimary ?? selectedValuePrimary ?? firstMedia(detail.listing.primaryImage) ?? matchingVariantPrimary ?? firstMedia(detailImages);
|
|
3623
|
+
const images = mediaArray(selectedVariant?.images).length > 0 ? mediaArray(selectedVariant?.images) : selectedValueImages.length > 0 ? selectedValueImages : detailImages;
|
|
3624
|
+
return {
|
|
3625
|
+
primaryImage,
|
|
3626
|
+
images
|
|
3627
|
+
};
|
|
3628
|
+
}
|
|
3629
|
+
function buildSelectionStock(selectedVariant, matchingVariants) {
|
|
3630
|
+
if (selectedVariant) {
|
|
3631
|
+
const availableStock = selectedVariant.isUnlimited ? null : Math.max(0, selectedVariant.stock - selectedVariant.reservedStock);
|
|
3632
|
+
const isActive = selectedVariant.isActive !== false;
|
|
3633
|
+
return {
|
|
3634
|
+
availableForSale: isActive && (selectedVariant.isUnlimited || (availableStock ?? 0) > 0),
|
|
3635
|
+
isUnlimited: selectedVariant.isUnlimited,
|
|
3636
|
+
stock: selectedVariant.stock,
|
|
3637
|
+
reservedStock: selectedVariant.reservedStock,
|
|
3638
|
+
availableStock
|
|
3639
|
+
};
|
|
3640
|
+
}
|
|
3641
|
+
return {
|
|
3642
|
+
availableForSale: matchingVariants.some(isVariantAvailableForSale),
|
|
3643
|
+
isUnlimited: matchingVariants.some((variant) => variant.isUnlimited),
|
|
3644
|
+
stock: null,
|
|
3645
|
+
reservedStock: null,
|
|
3646
|
+
availableStock: null
|
|
3647
|
+
};
|
|
3648
|
+
}
|
|
3649
|
+
function resolveProductSelection(detail, selection = {}, options) {
|
|
3650
|
+
const matrix = buildProductOptionMatrixFromDetail(detail);
|
|
3651
|
+
const effectiveSelection = hasExplicitSelection(selection) || detail.listing.selectionHintVariant == null ? selection : { ...selection, variantId: detail.listing.selectionHintVariant };
|
|
3652
|
+
const normalizedSelection = normalizeProductSelection(
|
|
3653
|
+
detail,
|
|
3654
|
+
effectiveSelection,
|
|
3655
|
+
options
|
|
3656
|
+
);
|
|
3657
|
+
const matchingVariantEntries = getMatchingVariantEntries(
|
|
3658
|
+
matrix,
|
|
3659
|
+
normalizedSelection
|
|
3660
|
+
);
|
|
3661
|
+
const activeMatchingVariantEntries = activeVariantEntries(
|
|
3662
|
+
matchingVariantEntries
|
|
3663
|
+
);
|
|
3664
|
+
const selectedVariantEntry = getExactSelectedVariantEntry(
|
|
3665
|
+
matrix,
|
|
3666
|
+
normalizedSelection,
|
|
3667
|
+
matchingVariantEntries
|
|
3668
|
+
);
|
|
3669
|
+
const selectedVariant = selectedVariantEntry?.source ?? null;
|
|
3670
|
+
const matchingVariants = activeMatchingVariantEntries.map(
|
|
3671
|
+
(variant) => variant.source
|
|
3672
|
+
);
|
|
3673
|
+
const selectedValues = matrix.optionIds.map((optionId) => normalizedSelection.byOptionId[optionId]).map((valueId) => valueId ? matrix.valueById.get(valueId) : void 0).filter((value) => value !== void 0);
|
|
3674
|
+
const availableValuesByOptionId = Object.fromEntries(
|
|
3675
|
+
matrix.options.map((option) => {
|
|
3676
|
+
const availableValueIds = new Set(
|
|
3677
|
+
getAvailableOptionValues(
|
|
3678
|
+
matrix,
|
|
3679
|
+
option.id,
|
|
3680
|
+
normalizedSelection.valueIds
|
|
3681
|
+
).map((value) => value.id)
|
|
3682
|
+
);
|
|
3683
|
+
return [
|
|
3684
|
+
option.id,
|
|
3685
|
+
option.values.map((value) => ({
|
|
3686
|
+
valueId: value.id,
|
|
3687
|
+
value: value.label,
|
|
3688
|
+
slug: requireValueSlug(value),
|
|
3689
|
+
selected: normalizedSelection.byOptionId[option.id] === value.id,
|
|
3690
|
+
available: availableValueIds.has(value.id),
|
|
3691
|
+
swatchColor: value.swatchColor ?? null,
|
|
3692
|
+
thumbnail: value.thumbnail ?? null,
|
|
3693
|
+
images: value.images ?? null
|
|
3694
|
+
}))
|
|
3695
|
+
];
|
|
3696
|
+
})
|
|
3697
|
+
);
|
|
3698
|
+
const availableValuesByOptionSlug = Object.fromEntries(
|
|
3699
|
+
matrix.options.map((option) => [
|
|
3700
|
+
option.slug,
|
|
3701
|
+
availableValuesByOptionId[option.id] ?? []
|
|
3702
|
+
])
|
|
3703
|
+
);
|
|
3704
|
+
const allOptionsSelected = matrix.optionIds.every(
|
|
3705
|
+
(optionId) => Boolean(normalizedSelection.byOptionId[optionId])
|
|
3706
|
+
);
|
|
3707
|
+
const priceVariants = selectedVariant ? [selectedVariant] : matchingVariants;
|
|
3708
|
+
return {
|
|
3709
|
+
normalizedSelection,
|
|
3710
|
+
selectedVariant,
|
|
3711
|
+
matchingVariants,
|
|
3712
|
+
partialVariants: selectedVariant ? [] : matchingVariants,
|
|
3713
|
+
availableValuesByOptionSlug,
|
|
3714
|
+
availableValuesByOptionId,
|
|
3715
|
+
allOptionsSelected,
|
|
3716
|
+
price: buildSelectionPrice(priceVariants),
|
|
3717
|
+
media: buildSelectionMedia(
|
|
3718
|
+
detail,
|
|
3719
|
+
selectedVariant,
|
|
3720
|
+
matchingVariants,
|
|
3721
|
+
selectedValues
|
|
3722
|
+
),
|
|
3723
|
+
stock: buildSelectionStock(selectedVariant, matchingVariants)
|
|
3724
|
+
};
|
|
3725
|
+
}
|
|
3120
3726
|
function compareVariantOrder(a, b) {
|
|
3121
3727
|
const aOrder = Number(a._order ?? Number.MAX_SAFE_INTEGER);
|
|
3122
3728
|
const bOrder = Number(b._order ?? Number.MAX_SAFE_INTEGER);
|
|
@@ -3524,6 +4130,7 @@ export {
|
|
|
3524
4130
|
OrderApi,
|
|
3525
4131
|
PermissionError,
|
|
3526
4132
|
ProductApi,
|
|
4133
|
+
ProductSelectionCodecError,
|
|
3527
4134
|
QueryHooks,
|
|
3528
4135
|
RateLimitError,
|
|
3529
4136
|
ReadOnlyCollectionClient,
|
|
@@ -3543,6 +4150,7 @@ export {
|
|
|
3543
4150
|
buildProductListingGroupsByOption,
|
|
3544
4151
|
buildProductListingProjection,
|
|
3545
4152
|
buildProductOptionMatrix,
|
|
4153
|
+
buildProductOptionMatrixFromDetail,
|
|
3546
4154
|
collectionKeys,
|
|
3547
4155
|
createAnalytics,
|
|
3548
4156
|
createAuthError,
|
|
@@ -3551,6 +4159,7 @@ export {
|
|
|
3551
4159
|
createCustomerAuthWebhookHandler,
|
|
3552
4160
|
createNotFoundError,
|
|
3553
4161
|
createPermissionError,
|
|
4162
|
+
createProductSelectionCodec,
|
|
3554
4163
|
createRateLimitError,
|
|
3555
4164
|
createServerClient,
|
|
3556
4165
|
createTypedWebhookHandler,
|
|
@@ -3587,9 +4196,13 @@ export {
|
|
|
3587
4196
|
isUsageLimitError,
|
|
3588
4197
|
isValidWebhookEvent,
|
|
3589
4198
|
isValidationError,
|
|
4199
|
+
normalizeProductSelection,
|
|
3590
4200
|
normalizeSelectedValueIds,
|
|
4201
|
+
parseProductSelection,
|
|
3591
4202
|
productKeys,
|
|
4203
|
+
resolveProductSelection,
|
|
3592
4204
|
resolveRelation,
|
|
3593
|
-
resolveVariantForSelection
|
|
4205
|
+
resolveVariantForSelection,
|
|
4206
|
+
stringifyProductSelection
|
|
3594
4207
|
};
|
|
3595
4208
|
//# sourceMappingURL=index.js.map
|