@01.software/sdk 0.28.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/dist/{const-mdQQtIOz.d.ts → const-DAjQYNuM.d.ts} +1 -1
- package/dist/{const-Cz9Ki_I7.d.cts → const-Dsixdi6z.d.cts} +1 -1
- package/dist/index.cjs +546 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +546 -10
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-BrSYb-sh.d.cts → payload-types-Ci-ZA7aM.d.cts} +8 -3
- package/dist/{payload-types-BrSYb-sh.d.ts → payload-types-Ci-ZA7aM.d.ts} +8 -3
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/{server-D369bCVJ.d.cts → server-C0C8dtms.d.cts} +113 -13
- package/dist/{server-C2Q9R-Lu.d.ts → server-Cv0Q4dPQ.d.ts} +113 -13
- package/dist/server.cjs +1 -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 +1 -4
- package/dist/server.js.map +1 -1
- package/dist/{types-BLUb4cYq.d.ts → types-BWq_WlbB.d.ts} +1 -1
- package/dist/{types-CW4PaIL7.d.cts → types-zKjATmDK.d.cts} +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 +3 -3
package/dist/index.js
CHANGED
|
@@ -1924,10 +1924,7 @@ var ProductApi = class extends BaseApi {
|
|
|
1924
1924
|
* `product-upsert` tool.
|
|
1925
1925
|
*/
|
|
1926
1926
|
upsert(params) {
|
|
1927
|
-
return this.request(
|
|
1928
|
-
"/api/products/upsert",
|
|
1929
|
-
params
|
|
1930
|
-
);
|
|
1927
|
+
return this.request("/api/products/upsert", params);
|
|
1931
1928
|
}
|
|
1932
1929
|
};
|
|
1933
1930
|
|
|
@@ -3028,6 +3025,13 @@ function createTypedWebhookHandler(collection, handler) {
|
|
|
3028
3025
|
}
|
|
3029
3026
|
|
|
3030
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
|
+
};
|
|
3031
3035
|
function getRelationID(value) {
|
|
3032
3036
|
if (typeof value === "string") return value;
|
|
3033
3037
|
if (typeof value === "number") return String(value);
|
|
@@ -3074,10 +3078,11 @@ function getFirstAvailableVariantPrimaryImage(variants) {
|
|
|
3074
3078
|
}
|
|
3075
3079
|
return null;
|
|
3076
3080
|
}
|
|
3077
|
-
function normalizeOptionValue(value, fallbackOptionId) {
|
|
3081
|
+
function normalizeOptionValue(value, fallbackOptionId, fallbackOptionSlug) {
|
|
3078
3082
|
return {
|
|
3079
3083
|
id: String(value.id),
|
|
3080
3084
|
optionId: getRelationID(value.option) ?? fallbackOptionId,
|
|
3085
|
+
optionSlug: fallbackOptionSlug,
|
|
3081
3086
|
label: value.value || value.slug || String(value.id),
|
|
3082
3087
|
slug: value.slug ?? null,
|
|
3083
3088
|
swatchColor: value.swatchColor ?? null,
|
|
@@ -3086,20 +3091,26 @@ function normalizeOptionValue(value, fallbackOptionId) {
|
|
|
3086
3091
|
order: value._order ?? value["_product-option-values_values_order"] ?? ""
|
|
3087
3092
|
};
|
|
3088
3093
|
}
|
|
3089
|
-
function normalizeVariantOptionValues(variant, valueToOptionId, optionIds) {
|
|
3094
|
+
function normalizeVariantOptionValues(variant, optionById, valueToOptionId, optionIds) {
|
|
3090
3095
|
const optionValueByOptionId = /* @__PURE__ */ new Map();
|
|
3096
|
+
const optionValueByOptionSlug = /* @__PURE__ */ new Map();
|
|
3091
3097
|
for (const rawValue of Array.isArray(variant.optionValues) ? variant.optionValues : []) {
|
|
3092
3098
|
const valueId = getRelationID(rawValue);
|
|
3093
3099
|
if (!valueId) continue;
|
|
3094
3100
|
const optionId = valueToOptionId.get(valueId) ?? (isProductOptionValueDoc(rawValue) ? getRelationID(rawValue.option) : void 0);
|
|
3095
3101
|
if (!optionId || optionValueByOptionId.has(optionId)) continue;
|
|
3096
3102
|
optionValueByOptionId.set(optionId, valueId);
|
|
3103
|
+
const optionSlug = optionById.get(optionId)?.slug;
|
|
3104
|
+
if (optionSlug && !optionValueByOptionSlug.has(optionSlug)) {
|
|
3105
|
+
optionValueByOptionSlug.set(optionSlug, valueId);
|
|
3106
|
+
}
|
|
3097
3107
|
}
|
|
3098
3108
|
const optionValueIds = optionIds.map((optionId) => optionValueByOptionId.get(optionId)).filter((valueId) => Boolean(valueId));
|
|
3099
3109
|
return {
|
|
3100
3110
|
id: String(variant.id),
|
|
3101
3111
|
optionValueIds,
|
|
3102
3112
|
optionValueByOptionId,
|
|
3113
|
+
optionValueByOptionSlug,
|
|
3103
3114
|
source: variant
|
|
3104
3115
|
};
|
|
3105
3116
|
}
|
|
@@ -3109,17 +3120,20 @@ function buildProductOptionMatrix({
|
|
|
3109
3120
|
}) {
|
|
3110
3121
|
const normalizedOptions = options.map((option) => {
|
|
3111
3122
|
const valuesById = /* @__PURE__ */ new Map();
|
|
3123
|
+
const optionSlug = option.slug ?? String(option.id);
|
|
3112
3124
|
for (const rawValue of option.values?.docs ?? []) {
|
|
3113
3125
|
if (!isProductOptionValueDoc(rawValue)) continue;
|
|
3114
3126
|
const normalizedValue = normalizeOptionValue(
|
|
3115
3127
|
rawValue,
|
|
3116
|
-
String(option.id)
|
|
3128
|
+
String(option.id),
|
|
3129
|
+
optionSlug
|
|
3117
3130
|
);
|
|
3118
3131
|
valuesById.set(normalizedValue.id, normalizedValue);
|
|
3119
3132
|
}
|
|
3120
3133
|
return {
|
|
3121
3134
|
id: String(option.id),
|
|
3122
3135
|
title: option.title ?? String(option.id),
|
|
3136
|
+
slug: optionSlug,
|
|
3123
3137
|
order: option._order ?? option["_product-options_options_order"] ?? "",
|
|
3124
3138
|
values: Array.from(valuesById.values()).sort(
|
|
3125
3139
|
(left, right) => compareOrder(left.order, right.order)
|
|
@@ -3129,24 +3143,113 @@ function buildProductOptionMatrix({
|
|
|
3129
3143
|
const optionById = new Map(
|
|
3130
3144
|
normalizedOptions.map((option) => [option.id, option])
|
|
3131
3145
|
);
|
|
3146
|
+
const optionBySlug = new Map(
|
|
3147
|
+
normalizedOptions.map((option) => [option.slug, option])
|
|
3148
|
+
);
|
|
3132
3149
|
const valueById = /* @__PURE__ */ new Map();
|
|
3133
3150
|
const valueToOptionId = /* @__PURE__ */ new Map();
|
|
3151
|
+
const valueToOptionSlug = /* @__PURE__ */ new Map();
|
|
3134
3152
|
for (const option of normalizedOptions) {
|
|
3135
3153
|
for (const value of option.values) {
|
|
3136
3154
|
valueById.set(value.id, value);
|
|
3137
3155
|
valueToOptionId.set(value.id, option.id);
|
|
3156
|
+
valueToOptionSlug.set(value.id, option.slug);
|
|
3138
3157
|
}
|
|
3139
3158
|
}
|
|
3140
3159
|
const optionIds = normalizedOptions.map((option) => option.id);
|
|
3160
|
+
const optionSlugs = normalizedOptions.map((option) => option.slug);
|
|
3141
3161
|
const normalizedVariants = variants.map(
|
|
3142
|
-
(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])
|
|
3143
3204
|
);
|
|
3205
|
+
const optionBySlug = new Map(
|
|
3206
|
+
normalizedOptions.map((option) => [option.slug, option])
|
|
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
|
+
});
|
|
3144
3244
|
return {
|
|
3145
3245
|
options: normalizedOptions,
|
|
3146
3246
|
optionIds,
|
|
3247
|
+
optionSlugs,
|
|
3147
3248
|
optionById,
|
|
3249
|
+
optionBySlug,
|
|
3148
3250
|
valueById,
|
|
3149
3251
|
valueToOptionId,
|
|
3252
|
+
valueToOptionSlug,
|
|
3150
3253
|
variants: normalizedVariants
|
|
3151
3254
|
};
|
|
3152
3255
|
}
|
|
@@ -3179,7 +3282,7 @@ function getAvailableOptionValues(matrix, optionId, selectedValueIds) {
|
|
|
3179
3282
|
)
|
|
3180
3283
|
);
|
|
3181
3284
|
const availableValueIds = new Set(
|
|
3182
|
-
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))
|
|
3183
3286
|
);
|
|
3184
3287
|
return option.values.filter((value) => availableValueIds.has(value.id));
|
|
3185
3288
|
}
|
|
@@ -3194,6 +3297,432 @@ function resolveVariantForSelection(matrix, selectedValueIds) {
|
|
|
3194
3297
|
)
|
|
3195
3298
|
);
|
|
3196
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
|
+
}
|
|
3197
3726
|
function compareVariantOrder(a, b) {
|
|
3198
3727
|
const aOrder = Number(a._order ?? Number.MAX_SAFE_INTEGER);
|
|
3199
3728
|
const bOrder = Number(b._order ?? Number.MAX_SAFE_INTEGER);
|
|
@@ -3601,6 +4130,7 @@ export {
|
|
|
3601
4130
|
OrderApi,
|
|
3602
4131
|
PermissionError,
|
|
3603
4132
|
ProductApi,
|
|
4133
|
+
ProductSelectionCodecError,
|
|
3604
4134
|
QueryHooks,
|
|
3605
4135
|
RateLimitError,
|
|
3606
4136
|
ReadOnlyCollectionClient,
|
|
@@ -3620,6 +4150,7 @@ export {
|
|
|
3620
4150
|
buildProductListingGroupsByOption,
|
|
3621
4151
|
buildProductListingProjection,
|
|
3622
4152
|
buildProductOptionMatrix,
|
|
4153
|
+
buildProductOptionMatrixFromDetail,
|
|
3623
4154
|
collectionKeys,
|
|
3624
4155
|
createAnalytics,
|
|
3625
4156
|
createAuthError,
|
|
@@ -3628,6 +4159,7 @@ export {
|
|
|
3628
4159
|
createCustomerAuthWebhookHandler,
|
|
3629
4160
|
createNotFoundError,
|
|
3630
4161
|
createPermissionError,
|
|
4162
|
+
createProductSelectionCodec,
|
|
3631
4163
|
createRateLimitError,
|
|
3632
4164
|
createServerClient,
|
|
3633
4165
|
createTypedWebhookHandler,
|
|
@@ -3664,9 +4196,13 @@ export {
|
|
|
3664
4196
|
isUsageLimitError,
|
|
3665
4197
|
isValidWebhookEvent,
|
|
3666
4198
|
isValidationError,
|
|
4199
|
+
normalizeProductSelection,
|
|
3667
4200
|
normalizeSelectedValueIds,
|
|
4201
|
+
parseProductSelection,
|
|
3668
4202
|
productKeys,
|
|
4203
|
+
resolveProductSelection,
|
|
3669
4204
|
resolveRelation,
|
|
3670
|
-
resolveVariantForSelection
|
|
4205
|
+
resolveVariantForSelection,
|
|
4206
|
+
stringifyProductSelection
|
|
3671
4207
|
};
|
|
3672
4208
|
//# sourceMappingURL=index.js.map
|