@01.software/sdk 0.33.0 → 0.35.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 +214 -22
- 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/client.cjs +342 -27
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +7 -6
- package/dist/client.d.ts +7 -6
- package/dist/client.js +342 -27
- package/dist/client.js.map +1 -1
- package/dist/{collection-client-De6eKW1J.d.cts → collection-client-CR2B8c1v.d.cts} +7 -3
- package/dist/{collection-client-B6SlhzIP.d.ts → collection-client-DkREjhQ9.d.ts} +7 -3
- package/dist/{const-sPR2IkCe.d.cts → const-BTvdrXtY.d.cts} +4 -4
- package/dist/{const-DwmSDeWq.d.ts → const-CdqCauHQ.d.ts} +4 -4
- package/dist/errors.cjs +300 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/{index-BGEhoDUs.d.cts → errors.d.cts} +13 -1
- package/dist/{index-BGEhoDUs.d.ts → errors.d.ts} +13 -1
- package/dist/errors.js +277 -0
- package/dist/errors.js.map +1 -0
- package/dist/index-CjA3U6X3.d.cts +186 -0
- package/dist/index-DK8_NXkh.d.ts +186 -0
- package/dist/index.cjs +1402 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -10
- package/dist/index.d.ts +75 -10
- package/dist/index.js +1402 -177
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-dkeQyrDC.d.cts → payload-types-C7tb7Xbs.d.cts} +208 -52
- package/dist/{payload-types-dkeQyrDC.d.ts → payload-types-C7tb7Xbs.d.ts} +208 -52
- package/dist/query.cjs +195 -36
- package/dist/query.cjs.map +1 -1
- package/dist/query.d.cts +45 -18
- package/dist/query.d.ts +45 -18
- package/dist/query.js +195 -36
- package/dist/query.js.map +1 -1
- 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-CrsPyqEc.d.cts → server-nXOezi4b.d.cts} +22 -6
- package/dist/{server-CrsPyqEc.d.ts → server-nXOezi4b.d.ts} +22 -6
- package/dist/server.cjs +440 -33
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +11 -179
- package/dist/server.d.ts +11 -179
- package/dist/server.js +440 -33
- package/dist/server.js.map +1 -1
- package/dist/{types-Cel_4L9t.d.ts → types-1ylMrCuW.d.ts} +1 -1
- package/dist/{types-B3YT092I.d.cts → types-Bx558PU6.d.cts} +1 -1
- package/dist/{types-BHh0YLmq.d.ts → types-Byo_Rty4.d.ts} +705 -69
- package/dist/{types-BZKxss8Y.d.cts → types-DDhtZI6E.d.cts} +705 -69
- package/dist/ui/canvas/server.cjs +231 -38
- package/dist/ui/canvas/server.cjs.map +1 -1
- package/dist/ui/canvas/server.d.cts +1 -1
- package/dist/ui/canvas/server.d.ts +1 -1
- package/dist/ui/canvas/server.js +221 -38
- package/dist/ui/canvas/server.js.map +1 -1
- package/dist/ui/canvas.cjs +320 -257
- package/dist/ui/canvas.cjs.map +1 -1
- package/dist/ui/canvas.d.cts +5 -19
- package/dist/ui/canvas.d.ts +5 -19
- package/dist/ui/canvas.js +323 -260
- 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.cjs +2 -1
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.d.cts +20 -179
- package/dist/webhook.d.ts +20 -179
- package/dist/webhook.js +2 -1
- package/dist/webhook.js.map +1 -1
- package/package.json +12 -3
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(src_exports, {
|
|
|
36
36
|
CustomerAuth: () => CustomerAuth,
|
|
37
37
|
CustomerNamespace: () => CustomerNamespace,
|
|
38
38
|
DiscountApi: () => DiscountApi,
|
|
39
|
+
EventsClient: () => EventsClient,
|
|
39
40
|
GoneError: () => GoneError,
|
|
40
41
|
IMAGE_SIZES: () => IMAGE_SIZES,
|
|
41
42
|
INTERNAL_COLLECTIONS: () => INTERNAL_COLLECTIONS,
|
|
@@ -43,6 +44,8 @@ __export(src_exports, {
|
|
|
43
44
|
NotFoundError: () => NotFoundError,
|
|
44
45
|
ORDER_CHANGED_EVENT_TYPE: () => ORDER_CHANGED_EVENT_TYPE,
|
|
45
46
|
OrderApi: () => OrderApi,
|
|
47
|
+
PRODUCT_UPSERT_READONLY_FIELD_REASON: () => PRODUCT_UPSERT_READONLY_FIELD_REASON,
|
|
48
|
+
PRODUCT_UPSERT_UNKNOWN_FIELD_REASON: () => PRODUCT_UPSERT_UNKNOWN_FIELD_REASON,
|
|
46
49
|
PermissionError: () => PermissionError,
|
|
47
50
|
ProductApi: () => ProductApi,
|
|
48
51
|
ProductSelectionCodecError: () => ProductSelectionCodecError,
|
|
@@ -102,6 +105,7 @@ __export(src_exports, {
|
|
|
102
105
|
isNotFoundError: () => isNotFoundError,
|
|
103
106
|
isOrderChangedWebhookEvent: () => isOrderChangedWebhookEvent,
|
|
104
107
|
isPermissionError: () => isPermissionError,
|
|
108
|
+
isProductUpsertFieldValidationErrorBody: () => isProductUpsertFieldValidationErrorBody,
|
|
105
109
|
isRateLimitError: () => isRateLimitError,
|
|
106
110
|
isSDKError: () => isSDKError,
|
|
107
111
|
isServiceUnavailableError: () => isServiceUnavailableError,
|
|
@@ -111,14 +115,22 @@ __export(src_exports, {
|
|
|
111
115
|
isValidationError: () => isValidationError,
|
|
112
116
|
isWebhookCollection: () => isWebhookCollection,
|
|
113
117
|
isWebhookOperation: () => isWebhookOperation,
|
|
118
|
+
mergeProductDetailWithStock: () => mergeProductDetailWithStock,
|
|
114
119
|
normalizeProductSelection: () => normalizeProductSelection,
|
|
115
120
|
normalizeProductSelectionFromMatrix: () => normalizeProductSelectionFromMatrix,
|
|
116
121
|
normalizeSelectedValueIds: () => normalizeSelectedValueIds,
|
|
117
122
|
parseProductSelection: () => parseProductSelection,
|
|
123
|
+
resolveListingPrimaryImagePointer: () => resolveListingPrimaryImagePointer,
|
|
124
|
+
resolveProductDisplayMedia: () => resolveProductDisplayMedia,
|
|
125
|
+
resolveProductGallery: () => resolveProductGallery,
|
|
126
|
+
resolveProductMedia: () => resolveProductMedia,
|
|
118
127
|
resolveProductSelection: () => resolveProductSelection,
|
|
119
128
|
resolveProductSelectionFromMatrix: () => resolveProductSelectionFromMatrix,
|
|
129
|
+
resolveProductSelectionMedia: () => resolveProductSelectionMedia,
|
|
120
130
|
resolveRelation: () => resolveRelation,
|
|
121
131
|
resolveVariantForSelection: () => resolveVariantForSelection,
|
|
132
|
+
selectNext: () => selectNext,
|
|
133
|
+
selectedSwatchMediaItemId: () => selectedSwatchMediaItemId,
|
|
122
134
|
stringifyProductSelection: () => stringifyProductSelection
|
|
123
135
|
});
|
|
124
136
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -126,7 +138,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
126
138
|
// src/core/collection/http-client.ts
|
|
127
139
|
var import_qs_esm = require("qs-esm");
|
|
128
140
|
|
|
129
|
-
// src/core/
|
|
141
|
+
// src/core/errors.ts
|
|
130
142
|
var SDKError = class extends Error {
|
|
131
143
|
constructor(code, message, status, details, userMessage, suggestion, requestId) {
|
|
132
144
|
super(message);
|
|
@@ -378,9 +390,12 @@ function resolveApiUrl(apiUrl) {
|
|
|
378
390
|
|
|
379
391
|
// src/core/internal/utils/http.ts
|
|
380
392
|
var DEFAULT_TIMEOUT = 3e4;
|
|
393
|
+
var STOREFRONT_BROWSER_TIMEOUT = 15e3;
|
|
381
394
|
var DEFAULT_RETRYABLE_STATUSES = [408, 429, 500, 502, 503, 504];
|
|
382
395
|
var NON_RETRYABLE_STATUSES = [400, 401, 403, 404, 409, 422];
|
|
383
396
|
var SAFE_METHODS = ["GET", "HEAD", "OPTIONS"];
|
|
397
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
398
|
+
var STOREFRONT_BROWSER_MAX_RETRIES = 1;
|
|
384
399
|
function debugLog(debug, type, message, data) {
|
|
385
400
|
if (!debug) return;
|
|
386
401
|
const shouldLog = debug === true || type === "request" && debug.logRequests || type === "response" && debug.logResponses || type === "error" && debug.logErrors;
|
|
@@ -573,15 +588,18 @@ async function httpFetch(url, options) {
|
|
|
573
588
|
publishableKey,
|
|
574
589
|
secretKey,
|
|
575
590
|
customerToken,
|
|
576
|
-
timeout = DEFAULT_TIMEOUT,
|
|
591
|
+
timeout: timeoutOption = DEFAULT_TIMEOUT,
|
|
577
592
|
debug,
|
|
578
593
|
retry,
|
|
579
594
|
onUnauthorized,
|
|
580
595
|
...requestInit
|
|
581
596
|
} = options || {};
|
|
582
597
|
const baseUrl = resolveApiUrl(apiUrl);
|
|
598
|
+
const method = (requestInit.method || "GET").toUpperCase();
|
|
599
|
+
const isPublishableKeyBrowserGet = typeof window !== "undefined" && !secretKey && !customerToken && Boolean(publishableKey) && SAFE_METHODS.includes(method);
|
|
600
|
+
const timeout = timeoutOption === DEFAULT_TIMEOUT && isPublishableKeyBrowserGet ? STOREFRONT_BROWSER_TIMEOUT : timeoutOption;
|
|
583
601
|
const retryConfig = {
|
|
584
|
-
maxRetries: retry?.maxRetries ??
|
|
602
|
+
maxRetries: retry?.maxRetries ?? (isPublishableKeyBrowserGet ? STOREFRONT_BROWSER_MAX_RETRIES : DEFAULT_MAX_RETRIES),
|
|
585
603
|
retryableStatuses: retry?.retryableStatuses ?? DEFAULT_RETRYABLE_STATUSES,
|
|
586
604
|
retryDelay: retry?.retryDelay ?? ((attempt) => Math.min(1e3 * 2 ** attempt, 1e4))
|
|
587
605
|
};
|
|
@@ -689,8 +707,8 @@ async function httpFetch(url, options) {
|
|
|
689
707
|
),
|
|
690
708
|
requestId
|
|
691
709
|
);
|
|
692
|
-
const
|
|
693
|
-
if (attempt < retryConfig.maxRetries && SAFE_METHODS.includes(
|
|
710
|
+
const method2 = (requestInit.method || "GET").toUpperCase();
|
|
711
|
+
if (attempt < retryConfig.maxRetries && SAFE_METHODS.includes(method2) && retryConfig.retryableStatuses.includes(response.status)) {
|
|
694
712
|
lastError = error;
|
|
695
713
|
const retryDelay = retryConfig.retryDelay(attempt);
|
|
696
714
|
debugLog(debug, "error", `Retrying in ${retryDelay}ms...`, error);
|
|
@@ -702,8 +720,8 @@ async function httpFetch(url, options) {
|
|
|
702
720
|
return response;
|
|
703
721
|
} catch (error) {
|
|
704
722
|
debugLog(debug, "error", url, error);
|
|
705
|
-
const
|
|
706
|
-
const isSafe = SAFE_METHODS.includes(
|
|
723
|
+
const method2 = (requestInit.method || "GET").toUpperCase();
|
|
724
|
+
const isSafe = SAFE_METHODS.includes(method2);
|
|
707
725
|
if (error instanceof Error && error.name === "AbortError") {
|
|
708
726
|
const timeoutError = createTimeoutError(
|
|
709
727
|
`Request timed out after ${timeout}ms.`,
|
|
@@ -762,6 +780,35 @@ async function httpFetch(url, options) {
|
|
|
762
780
|
throw lastError ?? new NetworkError("Request failed after retries");
|
|
763
781
|
}
|
|
764
782
|
|
|
783
|
+
// src/core/internal/utils/query-string.ts
|
|
784
|
+
function productDetailQuery(params) {
|
|
785
|
+
const search = new URLSearchParams();
|
|
786
|
+
if ("slug" in params) {
|
|
787
|
+
search.set("slug", params.slug);
|
|
788
|
+
} else {
|
|
789
|
+
search.set("id", params.id);
|
|
790
|
+
}
|
|
791
|
+
return `/api/products/detail?${search}`;
|
|
792
|
+
}
|
|
793
|
+
function productDetailCatalogQuery(params) {
|
|
794
|
+
const search = new URLSearchParams();
|
|
795
|
+
if ("slug" in params) {
|
|
796
|
+
search.set("slug", params.slug);
|
|
797
|
+
} else {
|
|
798
|
+
search.set("id", params.id);
|
|
799
|
+
}
|
|
800
|
+
return `/api/products/detail/catalog?${search}`;
|
|
801
|
+
}
|
|
802
|
+
function listingGroupsQuery(params) {
|
|
803
|
+
return `/api/products/listing-groups?ids=${params.productIds.map(encodeURIComponent).join(",")}`;
|
|
804
|
+
}
|
|
805
|
+
function listingGroupsCatalogQuery(params) {
|
|
806
|
+
return `/api/products/listing-groups/catalog?ids=${params.productIds.map(encodeURIComponent).join(",")}`;
|
|
807
|
+
}
|
|
808
|
+
function stockSnapshotQuery(params) {
|
|
809
|
+
return `/api/products/stock?variantIds=${params.variantIds.map(encodeURIComponent).join(",")}`;
|
|
810
|
+
}
|
|
811
|
+
|
|
765
812
|
// src/core/collection/http-client.ts
|
|
766
813
|
var HttpClient = class {
|
|
767
814
|
constructor(publishableKey, secretKey, getCustomerToken, onUnauthorized, onRequestId, apiUrl) {
|
|
@@ -1080,6 +1127,8 @@ async function parseApiResponse(response, endpoint) {
|
|
|
1080
1127
|
}
|
|
1081
1128
|
|
|
1082
1129
|
// src/core/community/community-client.ts
|
|
1130
|
+
var DEFAULT_POST_LIST_SORT = "-lastActivityAt";
|
|
1131
|
+
var DEFAULT_COMMENT_LIST_SORT = "-createdAt";
|
|
1083
1132
|
var CommunityClient = class {
|
|
1084
1133
|
constructor(options) {
|
|
1085
1134
|
this.publishableKey = requirePublishableKeyForSecret(
|
|
@@ -1098,6 +1147,40 @@ var CommunityClient = class {
|
|
|
1098
1147
|
const entries = Object.entries(params).filter((e) => e[1] !== void 0).map(([k, v]) => [k, String(v)]);
|
|
1099
1148
|
return entries.length ? `?${new URLSearchParams(entries).toString()}` : "";
|
|
1100
1149
|
}
|
|
1150
|
+
buildPostsListQuery(params) {
|
|
1151
|
+
const urlParams = new URLSearchParams();
|
|
1152
|
+
const sort = params?.sort ?? DEFAULT_POST_LIST_SORT;
|
|
1153
|
+
urlParams.set("sort", sort);
|
|
1154
|
+
if (params?.limit !== void 0) urlParams.set("limit", String(params.limit));
|
|
1155
|
+
if (params?.page !== void 0) urlParams.set("page", String(params.page));
|
|
1156
|
+
if (params?.categoryId !== void 0) {
|
|
1157
|
+
urlParams.set("where[categories][in]", params.categoryId);
|
|
1158
|
+
}
|
|
1159
|
+
if (params?.tagId !== void 0) {
|
|
1160
|
+
urlParams.set("where[tags][in]", params.tagId);
|
|
1161
|
+
}
|
|
1162
|
+
return `/api/posts?${urlParams.toString()}`;
|
|
1163
|
+
}
|
|
1164
|
+
buildCommentsListQuery(params) {
|
|
1165
|
+
const urlParams = new URLSearchParams();
|
|
1166
|
+
const sort = params.sort ?? DEFAULT_COMMENT_LIST_SORT;
|
|
1167
|
+
urlParams.set("sort", sort);
|
|
1168
|
+
if (params.postId !== void 0) {
|
|
1169
|
+
urlParams.set("where[post][equals]", params.postId);
|
|
1170
|
+
}
|
|
1171
|
+
if (params.parentId !== void 0) {
|
|
1172
|
+
urlParams.set("where[parent][equals]", params.parentId);
|
|
1173
|
+
}
|
|
1174
|
+
if (params.rootComment !== void 0) {
|
|
1175
|
+
urlParams.set("where[rootComment][equals]", params.rootComment);
|
|
1176
|
+
}
|
|
1177
|
+
if (params.topLevelOnly) {
|
|
1178
|
+
urlParams.set("where[parent][exists]", "false");
|
|
1179
|
+
}
|
|
1180
|
+
if (params.limit !== void 0) urlParams.set("limit", String(params.limit));
|
|
1181
|
+
if (params.page !== void 0) urlParams.set("page", String(params.page));
|
|
1182
|
+
return `/api/comments?${urlParams.toString()}`;
|
|
1183
|
+
}
|
|
1101
1184
|
async execute(endpoint, method, body) {
|
|
1102
1185
|
const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
|
|
1103
1186
|
try {
|
|
@@ -1121,6 +1204,28 @@ var CommunityClient = class {
|
|
|
1121
1204
|
createPost(params) {
|
|
1122
1205
|
return this.execute("/api/posts", "POST", params);
|
|
1123
1206
|
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Public post feed. Server applies the same visibility contract as
|
|
1209
|
+
* `communityPostRead` (published + visible + moderation-safe).
|
|
1210
|
+
*/
|
|
1211
|
+
listPosts(params) {
|
|
1212
|
+
return this.execute(
|
|
1213
|
+
this.buildPostsListQuery(params),
|
|
1214
|
+
"GET"
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
listPostCategories(params) {
|
|
1218
|
+
return this.execute(
|
|
1219
|
+
`/api/post-categories${this.buildQuery(params)}`,
|
|
1220
|
+
"GET"
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
listPostTags(params) {
|
|
1224
|
+
return this.execute(
|
|
1225
|
+
`/api/post-tags${this.buildQuery(params)}`,
|
|
1226
|
+
"GET"
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1124
1229
|
getMyPosts(params) {
|
|
1125
1230
|
return this.execute(
|
|
1126
1231
|
`/api/posts/my${this.buildQuery(params)}`,
|
|
@@ -1156,16 +1261,37 @@ var CommunityClient = class {
|
|
|
1156
1261
|
}
|
|
1157
1262
|
return this.execute("/api/comments", "POST", body);
|
|
1158
1263
|
}
|
|
1264
|
+
/**
|
|
1265
|
+
* List comments for a post.
|
|
1266
|
+
*
|
|
1267
|
+
* - Default: all visible comments on the post (any depth).
|
|
1268
|
+
* - `topLevelOnly: true`: only root comments (`parent` unset).
|
|
1269
|
+
* - `rootComment`: comments belonging to a thread rooted at that comment.
|
|
1270
|
+
*/
|
|
1159
1271
|
listComments(params) {
|
|
1160
|
-
const { postId, page, limit, rootComment } = params;
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1272
|
+
const { postId, page, limit, rootComment, topLevelOnly, sort } = params;
|
|
1273
|
+
return this.execute(
|
|
1274
|
+
this.buildCommentsListQuery({
|
|
1275
|
+
postId,
|
|
1276
|
+
page,
|
|
1277
|
+
limit,
|
|
1278
|
+
rootComment,
|
|
1279
|
+
topLevelOnly,
|
|
1280
|
+
sort
|
|
1281
|
+
}),
|
|
1282
|
+
"GET"
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
/** Direct replies to a comment (`where[parent][equals]`). */
|
|
1286
|
+
listReplies(params) {
|
|
1287
|
+
const { commentId, page, limit, sort } = params;
|
|
1167
1288
|
return this.execute(
|
|
1168
|
-
|
|
1289
|
+
this.buildCommentsListQuery({
|
|
1290
|
+
parentId: commentId,
|
|
1291
|
+
page,
|
|
1292
|
+
limit,
|
|
1293
|
+
sort
|
|
1294
|
+
}),
|
|
1169
1295
|
"GET"
|
|
1170
1296
|
);
|
|
1171
1297
|
}
|
|
@@ -1193,10 +1319,18 @@ var CommunityClient = class {
|
|
|
1193
1319
|
}
|
|
1194
1320
|
// Reactions
|
|
1195
1321
|
addReaction(params) {
|
|
1196
|
-
const { postId, type } = params;
|
|
1322
|
+
const { postId, typeSlug, type } = params;
|
|
1323
|
+
const reactionType = typeSlug ?? type;
|
|
1324
|
+
if (!reactionType) {
|
|
1325
|
+
throw new SDKError(
|
|
1326
|
+
"validation_failed",
|
|
1327
|
+
"addReaction requires typeSlug (or deprecated type)",
|
|
1328
|
+
400
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1197
1331
|
return this.execute("/api/reactions", "POST", {
|
|
1198
1332
|
post: postId,
|
|
1199
|
-
type
|
|
1333
|
+
type: reactionType
|
|
1200
1334
|
});
|
|
1201
1335
|
}
|
|
1202
1336
|
removeReaction(params) {
|
|
@@ -1207,10 +1341,18 @@ var CommunityClient = class {
|
|
|
1207
1341
|
);
|
|
1208
1342
|
}
|
|
1209
1343
|
addCommentReaction(params) {
|
|
1210
|
-
const { commentId, type } = params;
|
|
1344
|
+
const { commentId, typeSlug, type } = params;
|
|
1345
|
+
const reactionType = typeSlug ?? type;
|
|
1346
|
+
if (!reactionType) {
|
|
1347
|
+
throw new SDKError(
|
|
1348
|
+
"validation_failed",
|
|
1349
|
+
"addCommentReaction requires typeSlug (or deprecated type)",
|
|
1350
|
+
400
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1211
1353
|
return this.execute("/api/reactions", "POST", {
|
|
1212
1354
|
comment: commentId,
|
|
1213
|
-
type
|
|
1355
|
+
type: reactionType
|
|
1214
1356
|
});
|
|
1215
1357
|
}
|
|
1216
1358
|
removeCommentReaction(params) {
|
|
@@ -1226,6 +1368,12 @@ var CommunityClient = class {
|
|
|
1226
1368
|
"GET"
|
|
1227
1369
|
);
|
|
1228
1370
|
}
|
|
1371
|
+
getCommentReactionSummary(params) {
|
|
1372
|
+
return this.execute(
|
|
1373
|
+
`/api/comments/${params.commentId}/reactions`,
|
|
1374
|
+
"GET"
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1229
1377
|
getReactionTypes() {
|
|
1230
1378
|
return this.execute(
|
|
1231
1379
|
"/api/reaction-types?limit=100",
|
|
@@ -1250,6 +1398,25 @@ var CommunityClient = class {
|
|
|
1250
1398
|
"GET"
|
|
1251
1399
|
);
|
|
1252
1400
|
}
|
|
1401
|
+
// Profiles
|
|
1402
|
+
listProfileLists(params) {
|
|
1403
|
+
return this.execute(
|
|
1404
|
+
`/api/customer-profile-lists${this.buildQuery(params)}`,
|
|
1405
|
+
"GET"
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
async getProfileList(params) {
|
|
1409
|
+
const query = "slug" in params ? `?where[slug][equals]=${encodeURIComponent(params.slug)}&limit=1` : `?where[id][equals]=${encodeURIComponent(params.id)}&limit=1`;
|
|
1410
|
+
const res = await this.execute(`/api/customer-profile-lists${query}`, "GET");
|
|
1411
|
+
return res.docs[0] ?? null;
|
|
1412
|
+
}
|
|
1413
|
+
updatePublicProfile(body) {
|
|
1414
|
+
return this.execute(
|
|
1415
|
+
"/api/customers/me/profile",
|
|
1416
|
+
"PATCH",
|
|
1417
|
+
body
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1253
1420
|
};
|
|
1254
1421
|
|
|
1255
1422
|
// src/core/customer/customer-auth.ts
|
|
@@ -1594,6 +1761,45 @@ function productDetailResultFromError(error) {
|
|
|
1594
1761
|
if (!reason) return void 0;
|
|
1595
1762
|
return { found: false, reason };
|
|
1596
1763
|
}
|
|
1764
|
+
function rejectLegacyOptionValueSwatchColor(value) {
|
|
1765
|
+
if (Object.prototype.hasOwnProperty.call(
|
|
1766
|
+
value,
|
|
1767
|
+
"swatchColor"
|
|
1768
|
+
)) {
|
|
1769
|
+
throw new TypeError(
|
|
1770
|
+
'Product upsert option values no longer accept legacy flat "swatchColor"; use nested "swatch" instead.'
|
|
1771
|
+
);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
function normalizeProductUpsertOptionValue(value) {
|
|
1775
|
+
rejectLegacyOptionValueSwatchColor(value);
|
|
1776
|
+
return value;
|
|
1777
|
+
}
|
|
1778
|
+
function normalizeProductUpsertParams(params) {
|
|
1779
|
+
const options = params.options ?? [];
|
|
1780
|
+
const variants = params.variants ?? [];
|
|
1781
|
+
if (!options.length) {
|
|
1782
|
+
return { ...params, options, variants };
|
|
1783
|
+
}
|
|
1784
|
+
return {
|
|
1785
|
+
...params,
|
|
1786
|
+
options: options.map((option) => ({
|
|
1787
|
+
...option,
|
|
1788
|
+
values: option.values.map(
|
|
1789
|
+
(value) => normalizeProductUpsertOptionValue(value)
|
|
1790
|
+
)
|
|
1791
|
+
})),
|
|
1792
|
+
variants
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
var PRODUCT_UPSERT_UNKNOWN_FIELD_REASON = "unknown_field";
|
|
1796
|
+
var PRODUCT_UPSERT_READONLY_FIELD_REASON = "product_field_readonly";
|
|
1797
|
+
function isProductUpsertFieldValidationErrorBody(value) {
|
|
1798
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1799
|
+
const body = value;
|
|
1800
|
+
const reason = body.reason;
|
|
1801
|
+
return typeof body.error === "string" && typeof body.field === "string" && (reason === PRODUCT_UPSERT_UNKNOWN_FIELD_REASON || reason === PRODUCT_UPSERT_READONLY_FIELD_REASON);
|
|
1802
|
+
}
|
|
1597
1803
|
var ProductApi = class extends BaseApi {
|
|
1598
1804
|
constructor(options) {
|
|
1599
1805
|
super("ProductApi", options);
|
|
@@ -1606,10 +1812,25 @@ var ProductApi = class extends BaseApi {
|
|
|
1606
1812
|
stockCheck(params) {
|
|
1607
1813
|
return this.request("/api/products/stock-check", params);
|
|
1608
1814
|
}
|
|
1815
|
+
stockSnapshot(params) {
|
|
1816
|
+
return this.request(
|
|
1817
|
+
stockSnapshotQuery(params),
|
|
1818
|
+
void 0,
|
|
1819
|
+
{ method: "GET" }
|
|
1820
|
+
);
|
|
1821
|
+
}
|
|
1609
1822
|
listingGroups(params) {
|
|
1610
1823
|
return this.request(
|
|
1611
|
-
|
|
1612
|
-
|
|
1824
|
+
listingGroupsQuery(params),
|
|
1825
|
+
void 0,
|
|
1826
|
+
{ method: "GET" }
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1829
|
+
listingGroupsCatalog(params) {
|
|
1830
|
+
return this.request(
|
|
1831
|
+
listingGroupsCatalogQuery(params),
|
|
1832
|
+
void 0,
|
|
1833
|
+
{ method: "GET" }
|
|
1613
1834
|
);
|
|
1614
1835
|
}
|
|
1615
1836
|
/**
|
|
@@ -1625,8 +1846,9 @@ var ProductApi = class extends BaseApi {
|
|
|
1625
1846
|
async detail(params) {
|
|
1626
1847
|
try {
|
|
1627
1848
|
const product = await this.request(
|
|
1628
|
-
|
|
1629
|
-
|
|
1849
|
+
productDetailQuery(params),
|
|
1850
|
+
void 0,
|
|
1851
|
+
{ method: "GET" }
|
|
1630
1852
|
);
|
|
1631
1853
|
return { found: true, product };
|
|
1632
1854
|
} catch (err) {
|
|
@@ -1635,6 +1857,20 @@ var ProductApi = class extends BaseApi {
|
|
|
1635
1857
|
throw err;
|
|
1636
1858
|
}
|
|
1637
1859
|
}
|
|
1860
|
+
async detailCatalog(params) {
|
|
1861
|
+
try {
|
|
1862
|
+
const product = await this.request(
|
|
1863
|
+
productDetailCatalogQuery(params),
|
|
1864
|
+
void 0,
|
|
1865
|
+
{ method: "GET" }
|
|
1866
|
+
);
|
|
1867
|
+
return { found: true, product };
|
|
1868
|
+
} catch (err) {
|
|
1869
|
+
const notFoundResult = productDetailResultFromError(err);
|
|
1870
|
+
if (notFoundResult?.found === false) return notFoundResult;
|
|
1871
|
+
throw err;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1638
1874
|
/**
|
|
1639
1875
|
* Atomically create or update a product together with its options,
|
|
1640
1876
|
* option-values, and variants in a single transaction. Mirrors Shopify's
|
|
@@ -1642,7 +1878,104 @@ var ProductApi = class extends BaseApi {
|
|
|
1642
1878
|
* `product-upsert` tool.
|
|
1643
1879
|
*/
|
|
1644
1880
|
upsert(params) {
|
|
1645
|
-
return this.request(
|
|
1881
|
+
return this.request(
|
|
1882
|
+
"/api/products/upsert",
|
|
1883
|
+
normalizeProductUpsertParams(params)
|
|
1884
|
+
);
|
|
1885
|
+
}
|
|
1886
|
+
};
|
|
1887
|
+
|
|
1888
|
+
// src/core/api/order-api.ts
|
|
1889
|
+
function idempotencyRequestOptions(idempotencyKey) {
|
|
1890
|
+
return idempotencyKey ? { headers: { "X-Idempotency-Key": idempotencyKey } } : void 0;
|
|
1891
|
+
}
|
|
1892
|
+
function splitIdempotencyKey(params) {
|
|
1893
|
+
const { idempotencyKey, ...body } = params;
|
|
1894
|
+
return { body, idempotencyKey };
|
|
1895
|
+
}
|
|
1896
|
+
var OrderApi = class extends BaseApi {
|
|
1897
|
+
constructor(options) {
|
|
1898
|
+
super("OrderApi", options);
|
|
1899
|
+
}
|
|
1900
|
+
createOrder(params) {
|
|
1901
|
+
const { body, idempotencyKey } = splitIdempotencyKey(params);
|
|
1902
|
+
return this.request(
|
|
1903
|
+
"/api/orders/create",
|
|
1904
|
+
body,
|
|
1905
|
+
idempotencyRequestOptions(idempotencyKey)
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
updateOrder(params) {
|
|
1909
|
+
return this.request("/api/orders/update", params);
|
|
1910
|
+
}
|
|
1911
|
+
updateTransaction(params) {
|
|
1912
|
+
return this.request("/api/transactions/update", params);
|
|
1913
|
+
}
|
|
1914
|
+
confirmPayment(params) {
|
|
1915
|
+
const { body, idempotencyKey } = splitIdempotencyKey(params);
|
|
1916
|
+
const headerKey = idempotencyKey ?? params.providerEventId;
|
|
1917
|
+
return this.request(
|
|
1918
|
+
"/api/orders/confirm-payment",
|
|
1919
|
+
body,
|
|
1920
|
+
idempotencyRequestOptions(headerKey)
|
|
1921
|
+
);
|
|
1922
|
+
}
|
|
1923
|
+
cancelOrder(params) {
|
|
1924
|
+
const { idempotencyKey } = params;
|
|
1925
|
+
const body = {
|
|
1926
|
+
orderNumber: params.orderNumber,
|
|
1927
|
+
reasonCode: params.reasonCode,
|
|
1928
|
+
reasonDetail: params.reasonDetail
|
|
1929
|
+
};
|
|
1930
|
+
return this.request(
|
|
1931
|
+
"/api/orders/cancel",
|
|
1932
|
+
body,
|
|
1933
|
+
idempotencyKey ? { headers: { "X-Idempotency-Key": idempotencyKey } } : void 0
|
|
1934
|
+
);
|
|
1935
|
+
}
|
|
1936
|
+
checkout(params) {
|
|
1937
|
+
const { body, idempotencyKey } = splitIdempotencyKey(params);
|
|
1938
|
+
return this.request(
|
|
1939
|
+
"/api/orders/checkout",
|
|
1940
|
+
body,
|
|
1941
|
+
idempotencyRequestOptions(idempotencyKey)
|
|
1942
|
+
);
|
|
1943
|
+
}
|
|
1944
|
+
createFulfillment(params) {
|
|
1945
|
+
const { body, idempotencyKey } = splitIdempotencyKey(params);
|
|
1946
|
+
return this.request(
|
|
1947
|
+
"/api/orders/create-fulfillment",
|
|
1948
|
+
body,
|
|
1949
|
+
idempotencyRequestOptions(idempotencyKey)
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
updateFulfillment(params) {
|
|
1953
|
+
return this.request("/api/orders/update-fulfillment", params);
|
|
1954
|
+
}
|
|
1955
|
+
bulkImportFulfillments(params) {
|
|
1956
|
+
return this.request(
|
|
1957
|
+
"/api/fulfillments/bulk-import",
|
|
1958
|
+
params
|
|
1959
|
+
);
|
|
1960
|
+
}
|
|
1961
|
+
returnWithRefund(params) {
|
|
1962
|
+
const { body, idempotencyKey } = splitIdempotencyKey(params);
|
|
1963
|
+
return this.request(
|
|
1964
|
+
"/api/returns/return-refund",
|
|
1965
|
+
body,
|
|
1966
|
+
idempotencyRequestOptions(idempotencyKey)
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
createReturn(params) {
|
|
1970
|
+
const { body, idempotencyKey } = splitIdempotencyKey(params);
|
|
1971
|
+
return this.request(
|
|
1972
|
+
"/api/returns/create",
|
|
1973
|
+
body,
|
|
1974
|
+
idempotencyRequestOptions(idempotencyKey)
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
updateReturn(params) {
|
|
1978
|
+
return this.request("/api/returns/update", params);
|
|
1646
1979
|
}
|
|
1647
1980
|
};
|
|
1648
1981
|
|
|
@@ -1656,7 +1989,7 @@ var CommerceClient = class {
|
|
|
1656
1989
|
onUnauthorized: options.onUnauthorized,
|
|
1657
1990
|
onRequestId: options.onRequestId
|
|
1658
1991
|
});
|
|
1659
|
-
const execute = async (endpoint, body) => {
|
|
1992
|
+
const execute = async (endpoint, body, requestOptions) => {
|
|
1660
1993
|
const token = options.customerToken();
|
|
1661
1994
|
try {
|
|
1662
1995
|
const response = await httpFetch(endpoint, {
|
|
@@ -1665,7 +1998,26 @@ var CommerceClient = class {
|
|
|
1665
1998
|
publishableKey: options.publishableKey,
|
|
1666
1999
|
customerToken: token ?? void 0,
|
|
1667
2000
|
...token && options.onUnauthorized && { onUnauthorized: options.onUnauthorized },
|
|
1668
|
-
body: JSON.stringify(body)
|
|
2001
|
+
body: JSON.stringify(body),
|
|
2002
|
+
...requestOptions?.headers && { headers: requestOptions.headers }
|
|
2003
|
+
});
|
|
2004
|
+
options.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
2005
|
+
return parseApiResponse(response, endpoint);
|
|
2006
|
+
} catch (err) {
|
|
2007
|
+
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
2008
|
+
options.onRequestId?.(id);
|
|
2009
|
+
throw err;
|
|
2010
|
+
}
|
|
2011
|
+
};
|
|
2012
|
+
const executeGet = async (endpoint) => {
|
|
2013
|
+
const token = options.customerToken();
|
|
2014
|
+
try {
|
|
2015
|
+
const response = await httpFetch(endpoint, {
|
|
2016
|
+
method: "GET",
|
|
2017
|
+
apiUrl: options.apiUrl,
|
|
2018
|
+
publishableKey: options.publishableKey,
|
|
2019
|
+
customerToken: token ?? void 0,
|
|
2020
|
+
...token && options.onUnauthorized && { onUnauthorized: options.onUnauthorized }
|
|
1669
2021
|
});
|
|
1670
2022
|
options.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
1671
2023
|
return parseApiResponse(response, endpoint);
|
|
@@ -1677,19 +2029,30 @@ var CommerceClient = class {
|
|
|
1677
2029
|
};
|
|
1678
2030
|
this.product = {
|
|
1679
2031
|
stockCheck: (params) => execute("/api/products/stock-check", params),
|
|
1680
|
-
|
|
2032
|
+
stockSnapshot: (params) => executeGet(stockSnapshotQuery(params)),
|
|
2033
|
+
listingGroups: (params) => executeGet(listingGroupsQuery(params)),
|
|
2034
|
+
listingGroupsCatalog: (params) => executeGet(listingGroupsCatalogQuery(params)),
|
|
1681
2035
|
detail: async (params) => {
|
|
1682
2036
|
try {
|
|
1683
|
-
const product = await
|
|
1684
|
-
"/api/products/detail",
|
|
1685
|
-
params
|
|
1686
|
-
);
|
|
2037
|
+
const product = await executeGet(productDetailQuery(params));
|
|
1687
2038
|
return { found: true, product };
|
|
1688
2039
|
} catch (err) {
|
|
1689
2040
|
const notFoundResult = productDetailResultFromError(err);
|
|
1690
2041
|
if (notFoundResult) return notFoundResult;
|
|
1691
2042
|
throw err;
|
|
1692
2043
|
}
|
|
2044
|
+
},
|
|
2045
|
+
detailCatalog: async (params) => {
|
|
2046
|
+
try {
|
|
2047
|
+
const product = await executeGet(
|
|
2048
|
+
productDetailCatalogQuery(params)
|
|
2049
|
+
);
|
|
2050
|
+
return { found: true, product };
|
|
2051
|
+
} catch (err) {
|
|
2052
|
+
const notFoundResult = productDetailResultFromError(err);
|
|
2053
|
+
if (notFoundResult?.found === false) return notFoundResult;
|
|
2054
|
+
throw err;
|
|
2055
|
+
}
|
|
1693
2056
|
}
|
|
1694
2057
|
};
|
|
1695
2058
|
this.cart = {
|
|
@@ -1702,7 +2065,14 @@ var CommerceClient = class {
|
|
|
1702
2065
|
clear: cartApi.clearCart.bind(cartApi)
|
|
1703
2066
|
};
|
|
1704
2067
|
this.orders = {
|
|
1705
|
-
checkout: (params) =>
|
|
2068
|
+
checkout: (params) => {
|
|
2069
|
+
const { body, idempotencyKey } = splitIdempotencyKey(params);
|
|
2070
|
+
return execute(
|
|
2071
|
+
"/api/orders/checkout",
|
|
2072
|
+
body,
|
|
2073
|
+
idempotencyRequestOptions(idempotencyKey)
|
|
2074
|
+
);
|
|
2075
|
+
},
|
|
1706
2076
|
listMine: (params) => options.customerAuth.getMyOrders(params)
|
|
1707
2077
|
};
|
|
1708
2078
|
this.discounts = {
|
|
@@ -1714,6 +2084,113 @@ var CommerceClient = class {
|
|
|
1714
2084
|
}
|
|
1715
2085
|
};
|
|
1716
2086
|
|
|
2087
|
+
// src/core/events/events-client.ts
|
|
2088
|
+
var EventsClient = class {
|
|
2089
|
+
constructor(options) {
|
|
2090
|
+
const secretKey = options.secretKey;
|
|
2091
|
+
this.publishableKey = requirePublishableKeyForSecret(
|
|
2092
|
+
"EventsClient",
|
|
2093
|
+
options.publishableKey,
|
|
2094
|
+
secretKey
|
|
2095
|
+
);
|
|
2096
|
+
this.apiUrl = options.apiUrl;
|
|
2097
|
+
this.customerToken = options.customerToken;
|
|
2098
|
+
this.onUnauthorized = options.onUnauthorized;
|
|
2099
|
+
this.onRequestId = options.onRequestId;
|
|
2100
|
+
}
|
|
2101
|
+
getRange(params) {
|
|
2102
|
+
return this.execute(
|
|
2103
|
+
buildRangeEndpoint(params),
|
|
2104
|
+
"GET",
|
|
2105
|
+
void 0,
|
|
2106
|
+
{ useCustomerAuth: false }
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
register(params) {
|
|
2110
|
+
return this.execute(
|
|
2111
|
+
"/api/event-registrations/register",
|
|
2112
|
+
"POST",
|
|
2113
|
+
buildRegistrationRequestBody(params),
|
|
2114
|
+
{ useCustomerAuth: true }
|
|
2115
|
+
);
|
|
2116
|
+
}
|
|
2117
|
+
getGuestRegistration(token) {
|
|
2118
|
+
return this.execute(
|
|
2119
|
+
"/api/event-registrations/guest/lookup",
|
|
2120
|
+
"POST",
|
|
2121
|
+
{ token },
|
|
2122
|
+
{ useCustomerAuth: false }
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
2125
|
+
cancelGuestRegistration(token, params = {}) {
|
|
2126
|
+
return this.execute(
|
|
2127
|
+
"/api/event-registrations/guest/cancel",
|
|
2128
|
+
"POST",
|
|
2129
|
+
buildGuestCancelRequestBody(token, params),
|
|
2130
|
+
{ useCustomerAuth: false }
|
|
2131
|
+
);
|
|
2132
|
+
}
|
|
2133
|
+
async execute(endpoint, method, body, options = {}) {
|
|
2134
|
+
const useCustomerAuth = options.useCustomerAuth === true;
|
|
2135
|
+
const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
|
|
2136
|
+
try {
|
|
2137
|
+
const response = await httpFetch(endpoint, {
|
|
2138
|
+
method,
|
|
2139
|
+
apiUrl: this.apiUrl,
|
|
2140
|
+
publishableKey: this.publishableKey,
|
|
2141
|
+
...useCustomerAuth && token ? { customerToken: token } : {},
|
|
2142
|
+
...useCustomerAuth && token && this.onUnauthorized && { onUnauthorized: this.onUnauthorized },
|
|
2143
|
+
...body !== void 0 && { body: JSON.stringify(body) }
|
|
2144
|
+
});
|
|
2145
|
+
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
2146
|
+
return parseApiResponse(response, endpoint);
|
|
2147
|
+
} catch (err) {
|
|
2148
|
+
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
2149
|
+
this.onRequestId?.(id);
|
|
2150
|
+
throw err;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
function buildRegistrationRequestBody(params) {
|
|
2155
|
+
return {
|
|
2156
|
+
event: params.event,
|
|
2157
|
+
occurrence: params.occurrence,
|
|
2158
|
+
...params.quantity !== void 0 && { quantity: params.quantity },
|
|
2159
|
+
...params.attendee !== void 0 && { attendee: params.attendee },
|
|
2160
|
+
...params.answers !== void 0 && { answers: params.answers }
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
function buildGuestCancelRequestBody(token, params) {
|
|
2164
|
+
return {
|
|
2165
|
+
token,
|
|
2166
|
+
...params.reason !== void 0 && { reason: params.reason }
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
function buildRangeEndpoint(params) {
|
|
2170
|
+
const urlParams = new URLSearchParams();
|
|
2171
|
+
urlParams.set("start", formatDateParam(params.start));
|
|
2172
|
+
urlParams.set("end", formatDateParam(params.end));
|
|
2173
|
+
if (params.limit !== void 0) urlParams.set("limit", String(params.limit));
|
|
2174
|
+
if (params.page !== void 0) urlParams.set("page", String(params.page));
|
|
2175
|
+
appendValues(urlParams, "calendar", params.calendar);
|
|
2176
|
+
appendValues(urlParams, "calendarSlug", params.calendarSlug);
|
|
2177
|
+
appendValues(urlParams, "category", params.category);
|
|
2178
|
+
appendValues(urlParams, "categorySlug", params.categorySlug);
|
|
2179
|
+
appendValues(urlParams, "tag", params.tag);
|
|
2180
|
+
appendValues(urlParams, "tagSlug", params.tagSlug);
|
|
2181
|
+
return `/api/event-occurrences/range?${urlParams.toString()}`;
|
|
2182
|
+
}
|
|
2183
|
+
function formatDateParam(value) {
|
|
2184
|
+
return value instanceof Date ? value.toISOString() : value;
|
|
2185
|
+
}
|
|
2186
|
+
function appendValues(params, key, value) {
|
|
2187
|
+
if (value === void 0) return;
|
|
2188
|
+
const values = Array.isArray(value) ? value : [value];
|
|
2189
|
+
for (const entry of values) {
|
|
2190
|
+
if (entry) params.append(key, entry);
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
|
|
1717
2194
|
// src/core/client/client.ts
|
|
1718
2195
|
var Client = class {
|
|
1719
2196
|
constructor(options) {
|
|
@@ -1759,6 +2236,13 @@ var Client = class {
|
|
|
1759
2236
|
onUnauthorized,
|
|
1760
2237
|
onRequestId
|
|
1761
2238
|
});
|
|
2239
|
+
this.events = new EventsClient({
|
|
2240
|
+
publishableKey: this.config.publishableKey,
|
|
2241
|
+
apiUrl: this.config.apiUrl,
|
|
2242
|
+
customerToken: () => this.customer.auth.getToken(),
|
|
2243
|
+
onUnauthorized,
|
|
2244
|
+
onRequestId
|
|
2245
|
+
});
|
|
1762
2246
|
this.collections = new ReadOnlyCollectionClient(
|
|
1763
2247
|
this.config.publishableKey,
|
|
1764
2248
|
void 0,
|
|
@@ -1779,56 +2263,6 @@ function createClient(options) {
|
|
|
1779
2263
|
return new Client(options);
|
|
1780
2264
|
}
|
|
1781
2265
|
|
|
1782
|
-
// src/core/api/order-api.ts
|
|
1783
|
-
var OrderApi = class extends BaseApi {
|
|
1784
|
-
constructor(options) {
|
|
1785
|
-
super("OrderApi", options);
|
|
1786
|
-
}
|
|
1787
|
-
createOrder(params) {
|
|
1788
|
-
return this.request("/api/orders/create", params);
|
|
1789
|
-
}
|
|
1790
|
-
updateOrder(params) {
|
|
1791
|
-
return this.request("/api/orders/update", params);
|
|
1792
|
-
}
|
|
1793
|
-
updateTransaction(params) {
|
|
1794
|
-
return this.request("/api/transactions/update", params);
|
|
1795
|
-
}
|
|
1796
|
-
confirmPayment(params) {
|
|
1797
|
-
return this.request(
|
|
1798
|
-
"/api/orders/confirm-payment",
|
|
1799
|
-
params,
|
|
1800
|
-
params.providerEventId ? { headers: { "X-Idempotency-Key": params.providerEventId } } : void 0
|
|
1801
|
-
);
|
|
1802
|
-
}
|
|
1803
|
-
checkout(params) {
|
|
1804
|
-
return this.request("/api/orders/checkout", params);
|
|
1805
|
-
}
|
|
1806
|
-
createFulfillment(params) {
|
|
1807
|
-
return this.request("/api/orders/create-fulfillment", params);
|
|
1808
|
-
}
|
|
1809
|
-
updateFulfillment(params) {
|
|
1810
|
-
return this.request("/api/orders/update-fulfillment", params);
|
|
1811
|
-
}
|
|
1812
|
-
bulkImportFulfillments(params) {
|
|
1813
|
-
return this.request(
|
|
1814
|
-
"/api/fulfillments/bulk-import",
|
|
1815
|
-
params
|
|
1816
|
-
);
|
|
1817
|
-
}
|
|
1818
|
-
returnWithRefund(params) {
|
|
1819
|
-
return this.request(
|
|
1820
|
-
"/api/returns/return-refund",
|
|
1821
|
-
params
|
|
1822
|
-
);
|
|
1823
|
-
}
|
|
1824
|
-
createReturn(params) {
|
|
1825
|
-
return this.request("/api/returns/create", params);
|
|
1826
|
-
}
|
|
1827
|
-
updateReturn(params) {
|
|
1828
|
-
return this.request("/api/returns/update", params);
|
|
1829
|
-
}
|
|
1830
|
-
};
|
|
1831
|
-
|
|
1832
2266
|
// src/core/api/discount-api.ts
|
|
1833
2267
|
var DiscountApi = class extends BaseApi {
|
|
1834
2268
|
constructor(options) {
|
|
@@ -1849,6 +2283,44 @@ var ShippingApi = class extends BaseApi {
|
|
|
1849
2283
|
}
|
|
1850
2284
|
};
|
|
1851
2285
|
|
|
2286
|
+
// src/core/commerce/merge-catalog-stock.ts
|
|
2287
|
+
function mergeProductDetailWithStock(catalog, snapshot) {
|
|
2288
|
+
const snapshotByVariantId = new Map(
|
|
2289
|
+
snapshot.snapshots.map((item) => [item.variantId, item])
|
|
2290
|
+
);
|
|
2291
|
+
let missingSnapshotCount = 0;
|
|
2292
|
+
const variants = catalog.variants.map((variant) => {
|
|
2293
|
+
const snap = snapshotByVariantId.get(String(variant.id));
|
|
2294
|
+
if (!snap) {
|
|
2295
|
+
missingSnapshotCount += 1;
|
|
2296
|
+
return { ...variant, stock: 0, reservedStock: 0 };
|
|
2297
|
+
}
|
|
2298
|
+
return {
|
|
2299
|
+
...variant,
|
|
2300
|
+
stock: snap.isUnlimited ? 0 : snap.availableStock,
|
|
2301
|
+
reservedStock: 0
|
|
2302
|
+
};
|
|
2303
|
+
});
|
|
2304
|
+
const trackedVariants = variants.filter((variant) => !variant.isUnlimited);
|
|
2305
|
+
const totalInventory = trackedVariants.length === 0 ? null : trackedVariants.reduce(
|
|
2306
|
+
(sum, variant) => sum + Math.max(0, (variant.stock ?? 0) - (variant.reservedStock ?? 0)),
|
|
2307
|
+
0
|
|
2308
|
+
);
|
|
2309
|
+
const { liveStockRequired: _liveStockRequired, ...listingBase } = catalog.listing;
|
|
2310
|
+
const availableForSale = snapshot.snapshots.some(
|
|
2311
|
+
(item) => item.status === "available" && item.availableForSale
|
|
2312
|
+
);
|
|
2313
|
+
return {
|
|
2314
|
+
stockMergeStatus: missingSnapshotCount === 0 ? "complete" : "partial",
|
|
2315
|
+
product: {
|
|
2316
|
+
...catalog,
|
|
2317
|
+
product: { ...catalog.product, totalInventory },
|
|
2318
|
+
variants,
|
|
2319
|
+
listing: { ...listingBase, availableForSale }
|
|
2320
|
+
}
|
|
2321
|
+
};
|
|
2322
|
+
}
|
|
2323
|
+
|
|
1852
2324
|
// src/core/webhook/index.ts
|
|
1853
2325
|
var ORDER_CHANGED_EVENT_TYPE = "collection.orderChanged";
|
|
1854
2326
|
var COMMERCE_NOTIFICATION_EVENT_TYPE = "commerce.notification";
|
|
@@ -1860,6 +2332,7 @@ function isValidWebhookEvent(data) {
|
|
|
1860
2332
|
var COMMERCE_NOTIFICATION_OPERATION = "notification";
|
|
1861
2333
|
var COMMERCE_NOTIFICATION_EVENTS = [
|
|
1862
2334
|
"orderPaid",
|
|
2335
|
+
"orderCanceled",
|
|
1863
2336
|
"fulfillmentShipped",
|
|
1864
2337
|
"orderDelivered",
|
|
1865
2338
|
"returnRequested",
|
|
@@ -1945,7 +2418,7 @@ function isCommerceNotificationWebhookEvent(event) {
|
|
|
1945
2418
|
if (!matchesOptionalId(change.sourceId, sourceId)) return false;
|
|
1946
2419
|
}
|
|
1947
2420
|
const changeSourceId = isWebhookCommerceNotificationChange(change) ? change.sourceId : void 0;
|
|
1948
|
-
if (notification.event === "orderPaid" || notification.event === "orderDelivered") {
|
|
2421
|
+
if (notification.event === "orderPaid" || notification.event === "orderCanceled" || notification.event === "orderDelivered") {
|
|
1949
2422
|
return sourceCollection === "orders" && typeof notification.orderId === "string" && notification.orderId.length > 0 && matchesOptionalId(data.orderId, sourceId) && matchesOptionalId(notification.orderId, sourceId) && matchesOptionalId(data.orderId, notification.orderId) && matchesOptionalId(changeSourceId, data.orderId ?? notification.orderId);
|
|
1950
2423
|
}
|
|
1951
2424
|
if (notification.event === "fulfillmentShipped") {
|
|
@@ -2200,6 +2673,7 @@ var COLLECTIONS = [
|
|
|
2200
2673
|
"reaction-types",
|
|
2201
2674
|
"bookmarks",
|
|
2202
2675
|
"post-categories",
|
|
2676
|
+
"post-tags",
|
|
2203
2677
|
"customer-profile-lists",
|
|
2204
2678
|
// Events
|
|
2205
2679
|
"event-calendars",
|
|
@@ -2348,22 +2822,252 @@ var RealtimeConnection = class {
|
|
|
2348
2822
|
}
|
|
2349
2823
|
}
|
|
2350
2824
|
}
|
|
2351
|
-
scheduleReconnect() {
|
|
2352
|
-
if (this.reconnectTimer) return;
|
|
2353
|
-
const delay2 = Math.min(
|
|
2354
|
-
INITIAL_RECONNECT_DELAY * Math.pow(RECONNECT_BACKOFF_FACTOR, this.reconnectAttempt),
|
|
2355
|
-
MAX_RECONNECT_DELAY
|
|
2356
|
-
);
|
|
2357
|
-
this.reconnectAttempt++;
|
|
2358
|
-
this.reconnectTimer = setTimeout(() => {
|
|
2359
|
-
this.reconnectTimer = null;
|
|
2360
|
-
this.abortController = new AbortController();
|
|
2361
|
-
this.startStream(this.abortController.signal);
|
|
2362
|
-
}, delay2);
|
|
2825
|
+
scheduleReconnect() {
|
|
2826
|
+
if (this.reconnectTimer) return;
|
|
2827
|
+
const delay2 = Math.min(
|
|
2828
|
+
INITIAL_RECONNECT_DELAY * Math.pow(RECONNECT_BACKOFF_FACTOR, this.reconnectAttempt),
|
|
2829
|
+
MAX_RECONNECT_DELAY
|
|
2830
|
+
);
|
|
2831
|
+
this.reconnectAttempt++;
|
|
2832
|
+
this.reconnectTimer = setTimeout(() => {
|
|
2833
|
+
this.reconnectTimer = null;
|
|
2834
|
+
this.abortController = new AbortController();
|
|
2835
|
+
this.startStream(this.abortController.signal);
|
|
2836
|
+
}, delay2);
|
|
2837
|
+
}
|
|
2838
|
+
};
|
|
2839
|
+
|
|
2840
|
+
// src/utils/product-selection-media.ts
|
|
2841
|
+
function selectedSwatchMediaItemId(swatch) {
|
|
2842
|
+
if (!swatch || swatch.type !== "media") return null;
|
|
2843
|
+
const id = swatch.mediaItemId;
|
|
2844
|
+
if (id == null || id === "") return null;
|
|
2845
|
+
return String(id);
|
|
2846
|
+
}
|
|
2847
|
+
function getMediaId(value) {
|
|
2848
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
2849
|
+
return String(value);
|
|
2850
|
+
}
|
|
2851
|
+
if (typeof value === "object" && value !== null && "id" in value) {
|
|
2852
|
+
const id = value.id;
|
|
2853
|
+
if (typeof id === "string" || typeof id === "number") return String(id);
|
|
2854
|
+
}
|
|
2855
|
+
return null;
|
|
2856
|
+
}
|
|
2857
|
+
function toPointerId(value) {
|
|
2858
|
+
return getMediaId(value);
|
|
2859
|
+
}
|
|
2860
|
+
function mediaArray(value) {
|
|
2861
|
+
if (!Array.isArray(value)) return [];
|
|
2862
|
+
return value.filter((entry) => entry != null);
|
|
2863
|
+
}
|
|
2864
|
+
function uniqueWithPrimaryFirst(primary, items) {
|
|
2865
|
+
const unique = /* @__PURE__ */ new Map();
|
|
2866
|
+
for (const item of items) {
|
|
2867
|
+
const id = getMediaId(item);
|
|
2868
|
+
const key = id ?? `inline:${unique.size}`;
|
|
2869
|
+
if (!unique.has(key)) unique.set(key, item);
|
|
2870
|
+
}
|
|
2871
|
+
if (primary) {
|
|
2872
|
+
const primaryId = getMediaId(primary);
|
|
2873
|
+
const prefixed = /* @__PURE__ */ new Map();
|
|
2874
|
+
const primaryKey = primaryId ?? "inline:primary";
|
|
2875
|
+
prefixed.set(primaryKey, primary);
|
|
2876
|
+
for (const [key, value] of unique.entries()) {
|
|
2877
|
+
if (!prefixed.has(key)) prefixed.set(key, value);
|
|
2878
|
+
}
|
|
2879
|
+
return Array.from(prefixed.values());
|
|
2880
|
+
}
|
|
2881
|
+
return Array.from(unique.values());
|
|
2882
|
+
}
|
|
2883
|
+
function buildPoolById(pool) {
|
|
2884
|
+
const poolById = /* @__PURE__ */ new Map();
|
|
2885
|
+
for (const item of pool) {
|
|
2886
|
+
const id = getMediaId(item);
|
|
2887
|
+
if (id) poolById.set(id, item);
|
|
2888
|
+
}
|
|
2889
|
+
return poolById;
|
|
2890
|
+
}
|
|
2891
|
+
function resolveVariantImageItems(variant, poolById) {
|
|
2892
|
+
if (!variant || !Array.isArray(variant.images)) return [];
|
|
2893
|
+
const resolved = [];
|
|
2894
|
+
for (const entry of variant.images) {
|
|
2895
|
+
if (entry == null) continue;
|
|
2896
|
+
if (typeof entry === "string" || typeof entry === "number") {
|
|
2897
|
+
const pooled = poolById.get(String(entry));
|
|
2898
|
+
if (pooled) resolved.push(pooled);
|
|
2899
|
+
continue;
|
|
2900
|
+
}
|
|
2901
|
+
const mediaId2 = getMediaId(entry);
|
|
2902
|
+
if (mediaId2) {
|
|
2903
|
+
const pooled = poolById.get(mediaId2);
|
|
2904
|
+
if (pooled) {
|
|
2905
|
+
resolved.push(pooled);
|
|
2906
|
+
}
|
|
2907
|
+
continue;
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
return resolved;
|
|
2911
|
+
}
|
|
2912
|
+
function resolveOptionSwatchPrimary(selectedOptionValues, poolById) {
|
|
2913
|
+
if (!selectedOptionValues?.length) return null;
|
|
2914
|
+
for (const optionValue of selectedOptionValues) {
|
|
2915
|
+
const swatch = optionValue?.swatch;
|
|
2916
|
+
const swatchPointer = selectedSwatchMediaItemId(swatch);
|
|
2917
|
+
if (swatchPointer) {
|
|
2918
|
+
const pooled = poolById.get(swatchPointer);
|
|
2919
|
+
if (pooled) return pooled;
|
|
2920
|
+
}
|
|
2921
|
+
const inline = swatch?.inlineMedia;
|
|
2922
|
+
if (inline != null && typeof inline === "object") {
|
|
2923
|
+
return inline;
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
return null;
|
|
2927
|
+
}
|
|
2928
|
+
function resolveProductSelectionMedia(input) {
|
|
2929
|
+
const pool = mediaArray(input.productMediaPool);
|
|
2930
|
+
const poolById = buildPoolById(pool);
|
|
2931
|
+
const selectedVariantImages = resolveVariantImageItems(
|
|
2932
|
+
input.selectedVariant,
|
|
2933
|
+
poolById
|
|
2934
|
+
);
|
|
2935
|
+
if (selectedVariantImages.length > 0) {
|
|
2936
|
+
const primaryImage = selectedVariantImages[0] ?? null;
|
|
2937
|
+
return {
|
|
2938
|
+
primaryImage,
|
|
2939
|
+
images: uniqueWithPrimaryFirst(primaryImage, selectedVariantImages),
|
|
2940
|
+
source: "variant_media_selected"
|
|
2941
|
+
};
|
|
2942
|
+
}
|
|
2943
|
+
if (input.selectedVariant == null && (input.matchingVariants?.length ?? 0) > 0) {
|
|
2944
|
+
const mergedMatchingImages = [];
|
|
2945
|
+
for (const matchingVariant of input.matchingVariants ?? []) {
|
|
2946
|
+
mergedMatchingImages.push(
|
|
2947
|
+
...resolveVariantImageItems(matchingVariant, poolById)
|
|
2948
|
+
);
|
|
2949
|
+
}
|
|
2950
|
+
if (mergedMatchingImages.length > 0) {
|
|
2951
|
+
const primaryImage = mergedMatchingImages[0] ?? null;
|
|
2952
|
+
return {
|
|
2953
|
+
primaryImage,
|
|
2954
|
+
images: uniqueWithPrimaryFirst(primaryImage, mergedMatchingImages),
|
|
2955
|
+
source: "variant_media_matching"
|
|
2956
|
+
};
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
const optionSwatchPrimary = resolveOptionSwatchPrimary(
|
|
2960
|
+
input.selectedOptionValues,
|
|
2961
|
+
poolById
|
|
2962
|
+
);
|
|
2963
|
+
if (optionSwatchPrimary) {
|
|
2964
|
+
return {
|
|
2965
|
+
primaryImage: optionSwatchPrimary,
|
|
2966
|
+
images: [optionSwatchPrimary],
|
|
2967
|
+
source: "option_swatch"
|
|
2968
|
+
};
|
|
2363
2969
|
}
|
|
2364
|
-
|
|
2970
|
+
return {
|
|
2971
|
+
primaryImage: null,
|
|
2972
|
+
images: [],
|
|
2973
|
+
source: "none"
|
|
2974
|
+
};
|
|
2975
|
+
}
|
|
2976
|
+
function resolveProductDisplayMedia(input) {
|
|
2977
|
+
const pool = mediaArray(input.productMediaPool);
|
|
2978
|
+
const poolById = buildPoolById(pool);
|
|
2979
|
+
const listingPointer = toPointerId(input.listingPrimaryImage);
|
|
2980
|
+
if (listingPointer) {
|
|
2981
|
+
const listingPrimary = poolById.get(listingPointer);
|
|
2982
|
+
if (listingPrimary) {
|
|
2983
|
+
return {
|
|
2984
|
+
primaryImage: listingPrimary,
|
|
2985
|
+
images: uniqueWithPrimaryFirst(listingPrimary, pool),
|
|
2986
|
+
source: "listing_primary"
|
|
2987
|
+
};
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
const productPrimaryPointer = getMediaId(input.productPrimaryMediaItemId);
|
|
2991
|
+
if (productPrimaryPointer) {
|
|
2992
|
+
const productPrimary = poolById.get(productPrimaryPointer);
|
|
2993
|
+
if (productPrimary) {
|
|
2994
|
+
return {
|
|
2995
|
+
primaryImage: productPrimary,
|
|
2996
|
+
images: uniqueWithPrimaryFirst(productPrimary, pool),
|
|
2997
|
+
source: "product_primary"
|
|
2998
|
+
};
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
if (pool.length > 0) {
|
|
3002
|
+
const productPoolPrimary = pool[0] ?? null;
|
|
3003
|
+
if (productPoolPrimary) {
|
|
3004
|
+
return {
|
|
3005
|
+
primaryImage: productPoolPrimary,
|
|
3006
|
+
images: uniqueWithPrimaryFirst(productPoolPrimary, pool),
|
|
3007
|
+
source: "product_pool"
|
|
3008
|
+
};
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
return {
|
|
3012
|
+
primaryImage: null,
|
|
3013
|
+
images: [],
|
|
3014
|
+
source: "none"
|
|
3015
|
+
};
|
|
3016
|
+
}
|
|
3017
|
+
function resolveListingPrimaryImagePointer(input) {
|
|
3018
|
+
const pool = mediaArray(input.productMediaPool);
|
|
3019
|
+
const resolvedPointer = getMediaId(input.resolvedPrimary);
|
|
3020
|
+
if (resolvedPointer && input.resolvedSource !== "product_pool" && input.resolvedSource !== "none") {
|
|
3021
|
+
return resolvedPointer;
|
|
3022
|
+
}
|
|
3023
|
+
const poolById = buildPoolById(pool);
|
|
3024
|
+
const listingPointer = getMediaId(input.listingPrimaryImage);
|
|
3025
|
+
if (listingPointer && poolById.has(listingPointer)) {
|
|
3026
|
+
return listingPointer;
|
|
3027
|
+
}
|
|
3028
|
+
const primaryPointer = toPointerId(input.productPrimaryMediaItemId);
|
|
3029
|
+
if (primaryPointer && poolById.has(primaryPointer)) return primaryPointer;
|
|
3030
|
+
const thumbnailPointer = getMediaId(input.productThumbnail);
|
|
3031
|
+
if (thumbnailPointer && poolById.has(thumbnailPointer)) {
|
|
3032
|
+
return thumbnailPointer;
|
|
3033
|
+
}
|
|
3034
|
+
if (pool.length > 0) {
|
|
3035
|
+
const firstPoolId = getMediaId(pool[0]);
|
|
3036
|
+
if (firstPoolId) return firstPoolId;
|
|
3037
|
+
}
|
|
3038
|
+
return null;
|
|
3039
|
+
}
|
|
2365
3040
|
|
|
2366
3041
|
// src/utils/ecommerce.ts
|
|
3042
|
+
function normalizeMatrixSwatch(swatch) {
|
|
3043
|
+
if (!swatch) return null;
|
|
3044
|
+
const rawMedia = swatch.mediaItemId;
|
|
3045
|
+
const inlineMedia = rawMedia != null && typeof rawMedia === "object" && "url" in rawMedia && typeof rawMedia.url === "string" ? rawMedia : null;
|
|
3046
|
+
return {
|
|
3047
|
+
type: swatch.type ?? null,
|
|
3048
|
+
color: swatch.color ?? null,
|
|
3049
|
+
mediaItemId: extractEntityId(rawMedia),
|
|
3050
|
+
inlineMedia
|
|
3051
|
+
};
|
|
3052
|
+
}
|
|
3053
|
+
var DEFAULT_PRODUCT_SELECTION_URL_EMIT = "slug-compat";
|
|
3054
|
+
function resolveProductSelectionUrlEmit(emit) {
|
|
3055
|
+
return emit ?? DEFAULT_PRODUCT_SELECTION_URL_EMIT;
|
|
3056
|
+
}
|
|
3057
|
+
function appendSlugCompatSelectionParam(params, matrix, optionId, valueId) {
|
|
3058
|
+
const option = matrix.optionById.get(optionId);
|
|
3059
|
+
const value = matrix.valueById.get(valueId);
|
|
3060
|
+
if (!option?.slug || !value?.slug) return false;
|
|
3061
|
+
const slugMatches = option.values.filter(
|
|
3062
|
+
(candidate) => candidate.slug === value.slug
|
|
3063
|
+
);
|
|
3064
|
+
if (slugMatches.length !== 1) return false;
|
|
3065
|
+
params.append(`opt.${option.slug}`, value.slug);
|
|
3066
|
+
return true;
|
|
3067
|
+
}
|
|
3068
|
+
function appendCanonicalSelectionParam(params, optionId, valueId) {
|
|
3069
|
+
params.append(`opt.${optionId}`, valueId);
|
|
3070
|
+
}
|
|
2367
3071
|
var ProductSelectionCodecError = class extends Error {
|
|
2368
3072
|
constructor(message) {
|
|
2369
3073
|
super(message);
|
|
@@ -2408,6 +3112,18 @@ function getVariantPrimaryImage(variant) {
|
|
|
2408
3112
|
if (!variant) return null;
|
|
2409
3113
|
return extractEntityId(variant.thumbnail) ?? getFirstMediaId(variant.images);
|
|
2410
3114
|
}
|
|
3115
|
+
function resolveGenericListingPrimaryImage(product, resolvedPrimary, resolvedSource) {
|
|
3116
|
+
return resolveListingPrimaryImagePointer({
|
|
3117
|
+
productMediaPool: product?.images ?? [],
|
|
3118
|
+
productPrimaryMediaItemId: getRelationID(
|
|
3119
|
+
product?.primaryMediaItemId ?? null
|
|
3120
|
+
),
|
|
3121
|
+
productThumbnail: product?.thumbnail ?? null,
|
|
3122
|
+
listingPrimaryImage: product?.listing?.primaryImage ?? null,
|
|
3123
|
+
resolvedPrimary,
|
|
3124
|
+
resolvedSource
|
|
3125
|
+
});
|
|
3126
|
+
}
|
|
2411
3127
|
function getFirstAvailableVariantPrimaryImage(variants) {
|
|
2412
3128
|
const orderedVariants = [...variants].sort(compareVariantOrder);
|
|
2413
3129
|
for (const variant of orderedVariants) {
|
|
@@ -2417,6 +3133,27 @@ function getFirstAvailableVariantPrimaryImage(variants) {
|
|
|
2417
3133
|
}
|
|
2418
3134
|
return null;
|
|
2419
3135
|
}
|
|
3136
|
+
function normalizeProductOptionValueSwatch(swatch) {
|
|
3137
|
+
if (swatch == null) return null;
|
|
3138
|
+
if (typeof swatch !== "object") return null;
|
|
3139
|
+
const raw = swatch;
|
|
3140
|
+
const mediaItemId = extractEntityId(raw.mediaItemId);
|
|
3141
|
+
const color = typeof raw.color === "string" ? raw.color.trim() : "";
|
|
3142
|
+
const hasColor = color.length > 0;
|
|
3143
|
+
if (raw.type === "media" || mediaItemId && raw.type !== "color") {
|
|
3144
|
+
if (!mediaItemId || hasColor) return null;
|
|
3145
|
+
return {
|
|
3146
|
+
type: "media",
|
|
3147
|
+
mediaItemId,
|
|
3148
|
+
color: null
|
|
3149
|
+
};
|
|
3150
|
+
}
|
|
3151
|
+
if (raw.type === "color" || hasColor) {
|
|
3152
|
+
if (mediaItemId || !hasColor) return null;
|
|
3153
|
+
return { type: "color", color, mediaItemId: null };
|
|
3154
|
+
}
|
|
3155
|
+
return null;
|
|
3156
|
+
}
|
|
2420
3157
|
function normalizeOptionValue(value, fallbackOptionId, fallbackOptionSlug) {
|
|
2421
3158
|
return {
|
|
2422
3159
|
id: String(value.id),
|
|
@@ -2424,9 +3161,7 @@ function normalizeOptionValue(value, fallbackOptionId, fallbackOptionSlug) {
|
|
|
2424
3161
|
optionSlug: fallbackOptionSlug,
|
|
2425
3162
|
label: value.value || value.slug || String(value.id),
|
|
2426
3163
|
slug: value.slug ?? null,
|
|
2427
|
-
|
|
2428
|
-
thumbnail: value.thumbnail ?? null,
|
|
2429
|
-
images: value.images ?? null,
|
|
3164
|
+
swatch: normalizeProductOptionValueSwatch(value.swatch),
|
|
2430
3165
|
order: value._order ?? value["_product-option-values_values_order"] ?? ""
|
|
2431
3166
|
};
|
|
2432
3167
|
}
|
|
@@ -2532,9 +3267,7 @@ function buildProductOptionMatrixFromDetail(detail) {
|
|
|
2532
3267
|
optionSlug: option.slug,
|
|
2533
3268
|
label: value.value || value.slug || String(value.id),
|
|
2534
3269
|
slug: value.slug,
|
|
2535
|
-
|
|
2536
|
-
thumbnail: value.thumbnail ?? null,
|
|
2537
|
-
images: value.images ?? null,
|
|
3270
|
+
swatch: normalizeProductOptionValueSwatch(value.swatch),
|
|
2538
3271
|
order: matrixOrder(valueIndex)
|
|
2539
3272
|
}))
|
|
2540
3273
|
}));
|
|
@@ -2970,13 +3703,19 @@ function stringifyProductSelection(detail, selection = {}, options) {
|
|
|
2970
3703
|
return params.toString();
|
|
2971
3704
|
}
|
|
2972
3705
|
}
|
|
3706
|
+
const emit = resolveProductSelectionUrlEmit(options?.emit);
|
|
2973
3707
|
for (const optionId of matrix.optionIds) {
|
|
2974
3708
|
const valueId = normalized.byOptionId[optionId];
|
|
2975
3709
|
if (!valueId) continue;
|
|
2976
3710
|
if (!matrix.optionById.has(optionId) || !matrix.valueById.has(valueId)) {
|
|
2977
3711
|
continue;
|
|
2978
3712
|
}
|
|
2979
|
-
|
|
3713
|
+
if (emit === "slug-compat") {
|
|
3714
|
+
if (appendSlugCompatSelectionParam(params, matrix, optionId, valueId)) {
|
|
3715
|
+
continue;
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
appendCanonicalSelectionParam(params, optionId, valueId);
|
|
2980
3719
|
}
|
|
2981
3720
|
return params.toString();
|
|
2982
3721
|
}
|
|
@@ -3015,6 +3754,100 @@ function getExactSelectedVariantEntry(matrix, selection, matchingVariants) {
|
|
|
3015
3754
|
)
|
|
3016
3755
|
) ?? null;
|
|
3017
3756
|
}
|
|
3757
|
+
function normalizedSelectionFromByOptionId(matrix, selectedByOptionId, variantId) {
|
|
3758
|
+
const byOptionId = Object.fromEntries(
|
|
3759
|
+
matrix.optionIds.map((optionId) => [optionId, selectedByOptionId.get(optionId)]).filter((entry) => Boolean(entry[1]))
|
|
3760
|
+
);
|
|
3761
|
+
const byOptionSlug = Object.fromEntries(
|
|
3762
|
+
matrix.options.map((option) => {
|
|
3763
|
+
const valueId = selectedByOptionId.get(option.id);
|
|
3764
|
+
const value = valueId ? matrix.valueById.get(valueId) : void 0;
|
|
3765
|
+
return [option.slug, value?.slug ?? void 0];
|
|
3766
|
+
}).filter((entry) => Boolean(entry[1]))
|
|
3767
|
+
);
|
|
3768
|
+
return {
|
|
3769
|
+
byOptionSlug,
|
|
3770
|
+
byOptionId,
|
|
3771
|
+
valueIds: matrix.optionIds.map((optionId) => byOptionId[optionId]).filter((valueId) => Boolean(valueId)),
|
|
3772
|
+
variantId
|
|
3773
|
+
};
|
|
3774
|
+
}
|
|
3775
|
+
function buildFilledNormalizedSelection(matrix, normalizedSelection, listing) {
|
|
3776
|
+
const selectedByOptionId = new Map(
|
|
3777
|
+
Object.entries(normalizedSelection.byOptionId)
|
|
3778
|
+
);
|
|
3779
|
+
if (matrix.optionIds.every((optionId) => selectedByOptionId.has(optionId))) {
|
|
3780
|
+
const variantId = normalizedSelection.variantId ?? resolveVariantIdForCompleteSelection(matrix, selectedByOptionId);
|
|
3781
|
+
if (variantId === normalizedSelection.variantId) {
|
|
3782
|
+
return normalizedSelection;
|
|
3783
|
+
}
|
|
3784
|
+
return normalizedSelectionFromByOptionId(
|
|
3785
|
+
matrix,
|
|
3786
|
+
selectedByOptionId,
|
|
3787
|
+
variantId
|
|
3788
|
+
);
|
|
3789
|
+
}
|
|
3790
|
+
for (const option of matrix.options) {
|
|
3791
|
+
if (selectedByOptionId.has(option.id)) continue;
|
|
3792
|
+
if (option.values.length === 1) {
|
|
3793
|
+
selectedByOptionId.set(option.id, option.values[0].id);
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
if (matrix.optionIds.every((optionId) => selectedByOptionId.has(optionId))) {
|
|
3797
|
+
const variantId = normalizedSelection.variantId ?? resolveVariantIdForCompleteSelection(matrix, selectedByOptionId);
|
|
3798
|
+
return normalizedSelectionFromByOptionId(
|
|
3799
|
+
matrix,
|
|
3800
|
+
selectedByOptionId,
|
|
3801
|
+
variantId
|
|
3802
|
+
);
|
|
3803
|
+
}
|
|
3804
|
+
const partialNormalized = normalizedSelectionFromByOptionId(
|
|
3805
|
+
matrix,
|
|
3806
|
+
selectedByOptionId,
|
|
3807
|
+
normalizedSelection.variantId
|
|
3808
|
+
);
|
|
3809
|
+
const matchingVariantEntries = getMatchingVariantEntries(
|
|
3810
|
+
matrix,
|
|
3811
|
+
partialNormalized
|
|
3812
|
+
);
|
|
3813
|
+
const orderedMatches = [...matchingVariantEntries].sort(
|
|
3814
|
+
(left, right) => compareVariantOrder(left.source, right.source)
|
|
3815
|
+
);
|
|
3816
|
+
const hintVariantId = listing.selectionHintVariant != null ? String(listing.selectionHintVariant) : null;
|
|
3817
|
+
const hintedEntry = hintVariantId != null ? orderedMatches.find((entry) => entry.id === hintVariantId) : void 0;
|
|
3818
|
+
const availableEntry = orderedMatches.find(
|
|
3819
|
+
(entry) => isVariantAvailableForSale(entry.source)
|
|
3820
|
+
);
|
|
3821
|
+
const chosenEntry = hintedEntry ?? availableEntry ?? orderedMatches[0];
|
|
3822
|
+
if (!chosenEntry) {
|
|
3823
|
+
return normalizedSelection;
|
|
3824
|
+
}
|
|
3825
|
+
for (const optionId of matrix.optionIds) {
|
|
3826
|
+
if (selectedByOptionId.has(optionId)) continue;
|
|
3827
|
+
const valueId = chosenEntry.optionValueByOptionId.get(optionId);
|
|
3828
|
+
if (valueId) selectedByOptionId.set(optionId, valueId);
|
|
3829
|
+
}
|
|
3830
|
+
const filledVariantId = matrix.optionIds.every(
|
|
3831
|
+
(optionId) => selectedByOptionId.has(optionId)
|
|
3832
|
+
) ? resolveVariantIdForCompleteSelection(matrix, selectedByOptionId) ?? chosenEntry.id : normalizedSelection.variantId;
|
|
3833
|
+
return normalizedSelectionFromByOptionId(
|
|
3834
|
+
matrix,
|
|
3835
|
+
selectedByOptionId,
|
|
3836
|
+
filledVariantId
|
|
3837
|
+
);
|
|
3838
|
+
}
|
|
3839
|
+
function resolveVariantIdForCompleteSelection(matrix, selectedByOptionId) {
|
|
3840
|
+
if (!matrix.optionIds.every((optionId) => selectedByOptionId.has(optionId))) {
|
|
3841
|
+
return null;
|
|
3842
|
+
}
|
|
3843
|
+
const normalized = normalizedSelectionFromByOptionId(
|
|
3844
|
+
matrix,
|
|
3845
|
+
selectedByOptionId,
|
|
3846
|
+
null
|
|
3847
|
+
);
|
|
3848
|
+
const matchingVariantEntries = getMatchingVariantEntries(matrix, normalized);
|
|
3849
|
+
return getExactSelectedVariantEntry(matrix, normalized, matchingVariantEntries)?.id ?? null;
|
|
3850
|
+
}
|
|
3018
3851
|
function buildSelectionPrice(variants) {
|
|
3019
3852
|
const { min, max } = getMinMax(variants.map((variant) => variant.price));
|
|
3020
3853
|
const { min: compareAtMin, max: compareAtMax } = getMinMax(
|
|
@@ -3028,38 +3861,51 @@ function buildSelectionPrice(variants) {
|
|
|
3028
3861
|
isRange: min !== null && max !== null ? min !== max : false
|
|
3029
3862
|
};
|
|
3030
3863
|
}
|
|
3031
|
-
function firstMedia(value) {
|
|
3032
|
-
if (value == null) return null;
|
|
3033
|
-
if (Array.isArray(value)) return firstMedia(value[0]);
|
|
3034
|
-
return value;
|
|
3035
|
-
}
|
|
3036
3864
|
function isPresentMedia(value) {
|
|
3037
3865
|
return value != null;
|
|
3038
3866
|
}
|
|
3039
|
-
function
|
|
3867
|
+
function mediaArray2(values) {
|
|
3040
3868
|
if (!Array.isArray(values)) return [];
|
|
3041
3869
|
return values.filter(isPresentMedia);
|
|
3042
3870
|
}
|
|
3043
3871
|
function buildSelectionMedia(detail, selectedVariant, matchingVariants, selectedValues) {
|
|
3044
|
-
const
|
|
3045
|
-
const
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3872
|
+
const productPool = mediaArray2(detail.images);
|
|
3873
|
+
const resolvedMedia = resolveProductSelectionMedia({
|
|
3874
|
+
productMediaPool: productPool,
|
|
3875
|
+
productPrimaryMediaItemId: getRelationID(detail.primaryMediaItemId),
|
|
3876
|
+
selectedVariant: selectedVariant ? {
|
|
3877
|
+
id: selectedVariant.id,
|
|
3878
|
+
images: selectedVariant.images
|
|
3879
|
+
} : null,
|
|
3880
|
+
matchingVariants: matchingVariants.map((variant) => ({
|
|
3881
|
+
id: variant.id,
|
|
3882
|
+
images: variant.images
|
|
3883
|
+
})),
|
|
3884
|
+
selectedOptionValues: selectedValues.map((value) => ({
|
|
3885
|
+
id: value.id,
|
|
3886
|
+
swatch: normalizeMatrixSwatch(value.swatch)
|
|
3887
|
+
}))
|
|
3888
|
+
});
|
|
3889
|
+
if (resolvedMedia.source !== "none") {
|
|
3890
|
+
return {
|
|
3891
|
+
primaryImage: resolvedMedia.primaryImage,
|
|
3892
|
+
images: resolvedMedia.images,
|
|
3893
|
+
source: resolvedMedia.source
|
|
3894
|
+
};
|
|
3895
|
+
}
|
|
3896
|
+
const displayMedia = resolveProductDisplayMedia({
|
|
3897
|
+
productMediaPool: productPool,
|
|
3898
|
+
productPrimaryMediaItemId: getRelationID(detail.primaryMediaItemId),
|
|
3899
|
+
listingPrimaryImage: detail.listing.primaryImage ?? null
|
|
3900
|
+
});
|
|
3901
|
+
if (displayMedia.source !== "none") {
|
|
3902
|
+
return {
|
|
3903
|
+
primaryImage: displayMedia.primaryImage,
|
|
3904
|
+
images: displayMedia.images,
|
|
3905
|
+
source: displayMedia.source
|
|
3906
|
+
};
|
|
3907
|
+
}
|
|
3908
|
+
return { primaryImage: null, images: [], source: "none" };
|
|
3063
3909
|
}
|
|
3064
3910
|
function buildSelectionStock(selectedVariant, matchingVariants) {
|
|
3065
3911
|
if (selectedVariant) {
|
|
@@ -3082,7 +3928,9 @@ function buildSelectionStock(selectedVariant, matchingVariants) {
|
|
|
3082
3928
|
};
|
|
3083
3929
|
}
|
|
3084
3930
|
function buildAvailableValueStock(variants) {
|
|
3085
|
-
const activeVariants = variants.filter(
|
|
3931
|
+
const activeVariants = variants.filter(
|
|
3932
|
+
(variant) => variant.isActive !== false
|
|
3933
|
+
);
|
|
3086
3934
|
const isUnlimited = activeVariants.some((variant) => variant.isUnlimited);
|
|
3087
3935
|
const availableStock = isUnlimited ? null : activeVariants.reduce(
|
|
3088
3936
|
(sum, variant) => sum + Math.max(0, variant.stock - variant.reservedStock),
|
|
@@ -3094,6 +3942,19 @@ function buildAvailableValueStock(variants) {
|
|
|
3094
3942
|
availableStock
|
|
3095
3943
|
};
|
|
3096
3944
|
}
|
|
3945
|
+
function buildProductSelectionAvailableValue(matrixValue, _productImages, selected, available, stock) {
|
|
3946
|
+
return {
|
|
3947
|
+
valueId: matrixValue.id,
|
|
3948
|
+
value: matrixValue.label,
|
|
3949
|
+
label: matrixValue.label,
|
|
3950
|
+
slug: matrixValue.slug ?? "",
|
|
3951
|
+
selected,
|
|
3952
|
+
available,
|
|
3953
|
+
exists: available,
|
|
3954
|
+
...stock,
|
|
3955
|
+
swatch: matrixValue.swatch ?? null
|
|
3956
|
+
};
|
|
3957
|
+
}
|
|
3097
3958
|
function getCandidateVariantsForValue(matrix, optionId, valueId, selectedValueIds) {
|
|
3098
3959
|
const selectedByOption = getSelectedValueByOptionId(matrix, selectedValueIds);
|
|
3099
3960
|
selectedByOption.set(optionId, valueId);
|
|
@@ -3106,17 +3967,25 @@ function getCandidateVariantsForValue(matrix, optionId, valueId, selectedValueId
|
|
|
3106
3967
|
function getResolutionContext(context) {
|
|
3107
3968
|
return {
|
|
3108
3969
|
images: context?.images ?? context?.detail?.images ?? [],
|
|
3109
|
-
listing: context?.listing ?? context?.detail?.listing ?? {}
|
|
3970
|
+
listing: context?.listing ?? context?.detail?.listing ?? {},
|
|
3971
|
+
primaryMediaItemId: context?.primaryMediaItemId ?? context?.detail?.primaryMediaItemId ?? null
|
|
3110
3972
|
};
|
|
3111
3973
|
}
|
|
3112
3974
|
function resolveProductSelectionFromMatrix(matrix, selection = {}, options, context) {
|
|
3113
|
-
const { images, listing } = getResolutionContext(context);
|
|
3975
|
+
const { images, listing, primaryMediaItemId } = getResolutionContext(context);
|
|
3114
3976
|
const effectiveSelection = hasExplicitSelection(selection) || listing.selectionHintVariant == null ? selection : { ...selection, variantId: listing.selectionHintVariant };
|
|
3115
|
-
|
|
3977
|
+
let normalizedSelection = normalizeProductSelectionFromMatrix(
|
|
3116
3978
|
matrix,
|
|
3117
3979
|
effectiveSelection,
|
|
3118
3980
|
options
|
|
3119
3981
|
);
|
|
3982
|
+
if (options?.fillDefaults) {
|
|
3983
|
+
normalizedSelection = buildFilledNormalizedSelection(
|
|
3984
|
+
matrix,
|
|
3985
|
+
normalizedSelection,
|
|
3986
|
+
listing
|
|
3987
|
+
);
|
|
3988
|
+
}
|
|
3120
3989
|
const matchingVariantEntries = getMatchingVariantEntries(
|
|
3121
3990
|
matrix,
|
|
3122
3991
|
normalizedSelection
|
|
@@ -3145,24 +4014,22 @@ function resolveProductSelectionFromMatrix(matrix, selection = {}, options, cont
|
|
|
3145
4014
|
);
|
|
3146
4015
|
return [
|
|
3147
4016
|
option.id,
|
|
3148
|
-
option.values.map(
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
4017
|
+
option.values.map(
|
|
4018
|
+
(value) => buildProductSelectionAvailableValue(
|
|
4019
|
+
value,
|
|
4020
|
+
images,
|
|
4021
|
+
normalizedSelection.byOptionId[option.id] === value.id,
|
|
4022
|
+
availableValueIds.has(value.id),
|
|
4023
|
+
buildAvailableValueStock(
|
|
4024
|
+
getCandidateVariantsForValue(
|
|
4025
|
+
matrix,
|
|
4026
|
+
option.id,
|
|
4027
|
+
value.id,
|
|
4028
|
+
normalizedSelection.valueIds
|
|
4029
|
+
)
|
|
3160
4030
|
)
|
|
3161
|
-
)
|
|
3162
|
-
|
|
3163
|
-
thumbnail: value.thumbnail ?? null,
|
|
3164
|
-
images: value.images ?? null
|
|
3165
|
-
}))
|
|
4031
|
+
)
|
|
4032
|
+
)
|
|
3166
4033
|
];
|
|
3167
4034
|
})
|
|
3168
4035
|
);
|
|
@@ -3190,7 +4057,8 @@ function resolveProductSelectionFromMatrix(matrix, selection = {}, options, cont
|
|
|
3190
4057
|
images,
|
|
3191
4058
|
listing: {
|
|
3192
4059
|
primaryImage: listing.primaryImage ?? null
|
|
3193
|
-
}
|
|
4060
|
+
},
|
|
4061
|
+
primaryMediaItemId
|
|
3194
4062
|
},
|
|
3195
4063
|
selectedVariant,
|
|
3196
4064
|
matchingVariants,
|
|
@@ -3205,6 +4073,78 @@ function resolveProductSelection(detail, selection = {}, options) {
|
|
|
3205
4073
|
detail
|
|
3206
4074
|
});
|
|
3207
4075
|
}
|
|
4076
|
+
function selectNext(detail, current = {}, optionSlug, valueSlug, options) {
|
|
4077
|
+
const matrix = buildProductOptionMatrixFromDetail(detail);
|
|
4078
|
+
const listing = detail.listing ?? {};
|
|
4079
|
+
const normalizedCurrent = normalizeProductSelectionFromMatrix(
|
|
4080
|
+
matrix,
|
|
4081
|
+
current,
|
|
4082
|
+
options
|
|
4083
|
+
);
|
|
4084
|
+
const option = matrix.optionBySlug.get(optionSlug);
|
|
4085
|
+
if (!option) return normalizedCurrent;
|
|
4086
|
+
const valueMatches = option.values.filter(
|
|
4087
|
+
(candidate) => candidate.slug === valueSlug
|
|
4088
|
+
);
|
|
4089
|
+
if (valueMatches.length !== 1) return normalizedCurrent;
|
|
4090
|
+
const clickedValueId = valueMatches[0].id;
|
|
4091
|
+
const keepClickedSelection = () => {
|
|
4092
|
+
const selectedByOptionId = /* @__PURE__ */ new Map();
|
|
4093
|
+
selectedByOptionId.set(option.id, clickedValueId);
|
|
4094
|
+
for (const otherOptionId of matrix.optionIds) {
|
|
4095
|
+
if (otherOptionId === option.id) continue;
|
|
4096
|
+
const otherValueId = normalizedCurrent.byOptionId[otherOptionId];
|
|
4097
|
+
if (!otherValueId) continue;
|
|
4098
|
+
const constraintIds = normalizeSelectedValueIds(
|
|
4099
|
+
matrix,
|
|
4100
|
+
Array.from(selectedByOptionId.values())
|
|
4101
|
+
);
|
|
4102
|
+
const available = getAvailableOptionValues(
|
|
4103
|
+
matrix,
|
|
4104
|
+
otherOptionId,
|
|
4105
|
+
constraintIds
|
|
4106
|
+
);
|
|
4107
|
+
if (available.some((candidate) => candidate.id === otherValueId)) {
|
|
4108
|
+
selectedByOptionId.set(otherOptionId, otherValueId);
|
|
4109
|
+
}
|
|
4110
|
+
}
|
|
4111
|
+
return buildFilledNormalizedSelection(
|
|
4112
|
+
matrix,
|
|
4113
|
+
normalizedSelectionFromByOptionId(matrix, selectedByOptionId, null),
|
|
4114
|
+
listing
|
|
4115
|
+
);
|
|
4116
|
+
};
|
|
4117
|
+
const keepPriorSelection = () => {
|
|
4118
|
+
const selectedByOptionId = new Map(
|
|
4119
|
+
Object.entries(normalizedCurrent.byOptionId)
|
|
4120
|
+
);
|
|
4121
|
+
selectedByOptionId.delete(option.id);
|
|
4122
|
+
return buildFilledNormalizedSelection(
|
|
4123
|
+
matrix,
|
|
4124
|
+
normalizedSelectionFromByOptionId(matrix, selectedByOptionId, null),
|
|
4125
|
+
listing
|
|
4126
|
+
);
|
|
4127
|
+
};
|
|
4128
|
+
const clickedResult = keepClickedSelection();
|
|
4129
|
+
const clickedVariantId = resolveVariantIdForCompleteSelection(
|
|
4130
|
+
matrix,
|
|
4131
|
+
new Map(Object.entries(clickedResult.byOptionId))
|
|
4132
|
+
);
|
|
4133
|
+
const priorValueIds = Object.entries(normalizedCurrent.byOptionId).filter(([otherOptionId]) => otherOptionId !== option.id).map(([, valueId]) => valueId);
|
|
4134
|
+
const clickedAvailableWithPrior = priorValueIds.length === 0 || getAvailableOptionValues(matrix, option.id, priorValueIds).some(
|
|
4135
|
+
(candidate) => candidate.id === clickedValueId
|
|
4136
|
+
);
|
|
4137
|
+
if (clickedVariantId != null) {
|
|
4138
|
+
const priorClickedValue = normalizedCurrent.byOptionId[option.id];
|
|
4139
|
+
if (priorClickedValue != null && priorClickedValue !== clickedValueId) {
|
|
4140
|
+
return clickedResult;
|
|
4141
|
+
}
|
|
4142
|
+
if (clickedAvailableWithPrior) {
|
|
4143
|
+
return clickedResult;
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
return keepPriorSelection();
|
|
4147
|
+
}
|
|
3208
4148
|
function isProductDetailImageMedia(value) {
|
|
3209
4149
|
return typeof value === "object" && value !== null;
|
|
3210
4150
|
}
|
|
@@ -3245,18 +4185,47 @@ function joinProductPath(basePath, slug, trailingSlash) {
|
|
|
3245
4185
|
function getProductHrefGroupSelection(group, matrix) {
|
|
3246
4186
|
if (!group) return null;
|
|
3247
4187
|
if (group.variantId != null) return { variantId: group.variantId };
|
|
3248
|
-
const listingVariantId = group.listing?.selectionHintVariant;
|
|
3249
4188
|
const optionId = group.optionId != null ? String(group.optionId) : group.optionSlug ? matrix?.optionBySlug.get(group.optionSlug)?.id : void 0;
|
|
3250
|
-
if (!optionId)
|
|
3251
|
-
return listingVariantId != null ? { variantId: listingVariantId } : null;
|
|
3252
|
-
}
|
|
4189
|
+
if (!optionId) return null;
|
|
3253
4190
|
const option = matrix?.optionById.get(optionId);
|
|
3254
4191
|
const optionValueId = group.optionValueId != null ? String(group.optionValueId) : group.optionValueSlug && option ? option.values.find((value) => value.slug === group.optionValueSlug)?.id : void 0;
|
|
3255
|
-
if (!optionValueId)
|
|
3256
|
-
return listingVariantId != null ? { variantId: listingVariantId } : null;
|
|
3257
|
-
}
|
|
4192
|
+
if (!optionValueId) return null;
|
|
3258
4193
|
return { byOptionId: { [optionId]: optionValueId } };
|
|
3259
4194
|
}
|
|
4195
|
+
function getProductHrefCodecOptions(options) {
|
|
4196
|
+
return options.emit != null ? { emit: options.emit } : void 0;
|
|
4197
|
+
}
|
|
4198
|
+
function appendGroupByOptionIdHrefParams(params, group, groupSelection, options) {
|
|
4199
|
+
const emit = resolveProductSelectionUrlEmit(options.emit);
|
|
4200
|
+
const byOptionId = groupSelection.byOptionId ?? {};
|
|
4201
|
+
const entries = Object.entries(byOptionId);
|
|
4202
|
+
if (entries.length === 0) return false;
|
|
4203
|
+
for (const [optionId, valueId] of entries) {
|
|
4204
|
+
const optionSlug = group?.optionSlug ?? options.matrix?.optionById.get(optionId)?.slug ?? null;
|
|
4205
|
+
const valueSlug = group?.optionValueSlug ?? options.matrix?.valueById.get(String(valueId))?.slug ?? null;
|
|
4206
|
+
if (emit === "slug-compat" && optionSlug && valueSlug && entries.length === 1) {
|
|
4207
|
+
params.set(`opt.${optionSlug}`, valueSlug);
|
|
4208
|
+
return true;
|
|
4209
|
+
}
|
|
4210
|
+
if (emit === "slug-compat" && options.matrix && appendSlugCompatSelectionParam(
|
|
4211
|
+
params,
|
|
4212
|
+
options.matrix,
|
|
4213
|
+
optionId,
|
|
4214
|
+
String(valueId)
|
|
4215
|
+
)) {
|
|
4216
|
+
continue;
|
|
4217
|
+
}
|
|
4218
|
+
appendCanonicalSelectionParam(params, optionId, String(valueId));
|
|
4219
|
+
}
|
|
4220
|
+
return params.size > 0;
|
|
4221
|
+
}
|
|
4222
|
+
function getPreferCompleteVariantFromHintSelection(group, options) {
|
|
4223
|
+
if (!options.preferCompleteVariantFromHint) return null;
|
|
4224
|
+
if (group?.optionValueId != null || group?.optionValueSlug) return null;
|
|
4225
|
+
const hintVariantId = group?.listing?.selectionHintVariant;
|
|
4226
|
+
if (hintVariantId == null) return null;
|
|
4227
|
+
return { variantId: hintVariantId };
|
|
4228
|
+
}
|
|
3260
4229
|
function buildProductHref(product, group, options = {}) {
|
|
3261
4230
|
const path = joinProductPath(
|
|
3262
4231
|
options.basePath ?? "/products",
|
|
@@ -3265,23 +4234,46 @@ function buildProductHref(product, group, options = {}) {
|
|
|
3265
4234
|
);
|
|
3266
4235
|
const params = new URLSearchParams();
|
|
3267
4236
|
if (options.detail && options.selection) {
|
|
3268
|
-
const selection = stringifyProductSelection(
|
|
4237
|
+
const selection = stringifyProductSelection(
|
|
4238
|
+
options.detail,
|
|
4239
|
+
options.selection,
|
|
4240
|
+
getProductHrefCodecOptions(options)
|
|
4241
|
+
);
|
|
3269
4242
|
return selection ? `${path}?${selection}` : path;
|
|
3270
4243
|
}
|
|
4244
|
+
const preferVariantSelection = getPreferCompleteVariantFromHintSelection(
|
|
4245
|
+
group,
|
|
4246
|
+
options
|
|
4247
|
+
);
|
|
4248
|
+
if (preferVariantSelection) {
|
|
4249
|
+
if (options.detail) {
|
|
4250
|
+
const selection = stringifyProductSelection(
|
|
4251
|
+
options.detail,
|
|
4252
|
+
preferVariantSelection,
|
|
4253
|
+
getProductHrefCodecOptions(options)
|
|
4254
|
+
);
|
|
4255
|
+
return selection ? `${path}?${selection}` : path;
|
|
4256
|
+
}
|
|
4257
|
+
if (preferVariantSelection.variantId != null) {
|
|
4258
|
+
params.set("variant", String(preferVariantSelection.variantId));
|
|
4259
|
+
return `${path}?${params.toString()}`;
|
|
4260
|
+
}
|
|
4261
|
+
}
|
|
3271
4262
|
const groupSelection = getProductHrefGroupSelection(group, options.matrix);
|
|
3272
4263
|
if (groupSelection) {
|
|
3273
4264
|
if (options.detail) {
|
|
3274
|
-
const selection = stringifyProductSelection(
|
|
4265
|
+
const selection = stringifyProductSelection(
|
|
4266
|
+
options.detail,
|
|
4267
|
+
groupSelection,
|
|
4268
|
+
getProductHrefCodecOptions(options)
|
|
4269
|
+
);
|
|
3275
4270
|
return selection ? `${path}?${selection}` : path;
|
|
3276
4271
|
}
|
|
3277
4272
|
if (groupSelection.variantId != null) {
|
|
3278
4273
|
params.set("variant", String(groupSelection.variantId));
|
|
3279
4274
|
return `${path}?${params.toString()}`;
|
|
3280
4275
|
}
|
|
3281
|
-
|
|
3282
|
-
if (selectionEntry) {
|
|
3283
|
-
const [optionId, valueId] = selectionEntry;
|
|
3284
|
-
params.set(`opt.${optionId}`, String(valueId));
|
|
4276
|
+
if (appendGroupByOptionIdHrefParams(params, group, groupSelection, options)) {
|
|
3285
4277
|
return `${path}?${params.toString()}`;
|
|
3286
4278
|
}
|
|
3287
4279
|
}
|
|
@@ -3308,6 +4300,26 @@ function isVariantAvailableForSale(variant) {
|
|
|
3308
4300
|
if (variant.isUnlimited) return true;
|
|
3309
4301
|
return (variant.stock ?? 0) - (variant.reservedStock ?? 0) > 0;
|
|
3310
4302
|
}
|
|
4303
|
+
function sortVariantsForMediaSelection(variants) {
|
|
4304
|
+
const orderedVariants = [...variants].sort(compareVariantOrder);
|
|
4305
|
+
const activeVariants = orderedVariants.filter(
|
|
4306
|
+
(variant) => variant.isActive !== false
|
|
4307
|
+
);
|
|
4308
|
+
const availableVariants = activeVariants.filter(isVariantAvailableForSale);
|
|
4309
|
+
const unavailableActiveVariants = activeVariants.filter(
|
|
4310
|
+
(variant) => !isVariantAvailableForSale(variant)
|
|
4311
|
+
);
|
|
4312
|
+
return [...availableVariants, ...unavailableActiveVariants];
|
|
4313
|
+
}
|
|
4314
|
+
function variantHasPoolMedia(variant, productMediaPool) {
|
|
4315
|
+
if (!variant?.images?.length) return false;
|
|
4316
|
+
return variant.images.some((image) => {
|
|
4317
|
+
const imageId = getRelationID(image);
|
|
4318
|
+
return Boolean(
|
|
4319
|
+
imageId && productMediaPool.some((poolItem) => getRelationID(poolItem) === imageId)
|
|
4320
|
+
);
|
|
4321
|
+
});
|
|
4322
|
+
}
|
|
3311
4323
|
function getMinMax(values) {
|
|
3312
4324
|
const numbers = values.filter(
|
|
3313
4325
|
(value) => typeof value === "number"
|
|
@@ -3333,11 +4345,28 @@ function buildProductListingProjection(product, variants) {
|
|
|
3333
4345
|
const { min: minCompareAtPrice, max: maxCompareAtPrice } = getMinMax(
|
|
3334
4346
|
activeVariants.map((variant) => variant.compareAtPrice)
|
|
3335
4347
|
);
|
|
3336
|
-
const
|
|
3337
|
-
const
|
|
4348
|
+
const productMediaPool = product?.images ?? [];
|
|
4349
|
+
const selectionHintHasPoolMedia = variantHasPoolMedia(
|
|
4350
|
+
selectionHintVariant,
|
|
4351
|
+
productMediaPool
|
|
4352
|
+
);
|
|
4353
|
+
const mediaSelectionVariants = sortVariantsForMediaSelection(variants);
|
|
4354
|
+
const resolvedProductMedia = resolveProductSelectionMedia({
|
|
4355
|
+
productMediaPool,
|
|
4356
|
+
productPrimaryMediaItemId: getRelationID(product?.primaryMediaItemId),
|
|
4357
|
+
selectedVariant: selectionHintVariant && selectionHintHasPoolMedia ? {
|
|
4358
|
+
id: selectionHintVariant.id,
|
|
4359
|
+
images: selectionHintVariant.images
|
|
4360
|
+
} : null,
|
|
4361
|
+
matchingVariants: selectionHintHasPoolMedia ? [] : mediaSelectionVariants
|
|
4362
|
+
});
|
|
3338
4363
|
return {
|
|
3339
4364
|
selectionHintVariant: getRelationID(selectionHintVariant?.id) ?? null,
|
|
3340
|
-
primaryImage:
|
|
4365
|
+
primaryImage: resolveGenericListingPrimaryImage(
|
|
4366
|
+
product,
|
|
4367
|
+
resolvedProductMedia.primaryImage,
|
|
4368
|
+
resolvedProductMedia.source
|
|
4369
|
+
),
|
|
3341
4370
|
minPrice,
|
|
3342
4371
|
maxPrice,
|
|
3343
4372
|
minCompareAtPrice,
|
|
@@ -3356,7 +4385,33 @@ function buildProductListingCard(item, options = {}) {
|
|
|
3356
4385
|
variants,
|
|
3357
4386
|
selectionHintVariant
|
|
3358
4387
|
);
|
|
3359
|
-
const
|
|
4388
|
+
const productMediaPool = mediaArray2(product.images);
|
|
4389
|
+
const representativeHasPoolMedia = Boolean(
|
|
4390
|
+
representativeVariant?.images?.some(
|
|
4391
|
+
(image) => productMediaPool.some(
|
|
4392
|
+
(poolItem) => getRelationID(poolItem) === getRelationID(image)
|
|
4393
|
+
)
|
|
4394
|
+
)
|
|
4395
|
+
);
|
|
4396
|
+
const resolvedPrimaryMedia = resolveProductSelectionMedia(
|
|
4397
|
+
{
|
|
4398
|
+
productMediaPool,
|
|
4399
|
+
productPrimaryMediaItemId: getRelationID(product.primaryMediaItemId),
|
|
4400
|
+
selectedVariant: representativeHasPoolMedia ? representativeVariant : null,
|
|
4401
|
+
matchingVariants: representativeHasPoolMedia ? [] : variants
|
|
4402
|
+
}
|
|
4403
|
+
);
|
|
4404
|
+
const listingPrimaryPointer = resolveListingPrimaryImagePointer({
|
|
4405
|
+
productMediaPool,
|
|
4406
|
+
productPrimaryMediaItemId: getRelationID(product.primaryMediaItemId),
|
|
4407
|
+
productThumbnail: product.thumbnail ?? null,
|
|
4408
|
+
listingPrimaryImage: product.listing?.primaryImage ?? null,
|
|
4409
|
+
resolvedPrimary: resolvedPrimaryMedia.primaryImage,
|
|
4410
|
+
resolvedSource: resolvedPrimaryMedia.source
|
|
4411
|
+
});
|
|
4412
|
+
const listingPrimaryMedia = listingPrimaryPointer ? productMediaPool.find(
|
|
4413
|
+
(item2) => getRelationID(item2) === listingPrimaryPointer
|
|
4414
|
+
) ?? resolvedPrimaryMedia.primaryImage ?? null : null;
|
|
3360
4415
|
const priceRange = aggregateListingPriceRange(groups);
|
|
3361
4416
|
const availableForSale = groups.some(
|
|
3362
4417
|
(group) => group.listing.availableForSale
|
|
@@ -3371,7 +4426,7 @@ function buildProductListingCard(item, options = {}) {
|
|
|
3371
4426
|
),
|
|
3372
4427
|
title: product.title,
|
|
3373
4428
|
representativeVariant,
|
|
3374
|
-
primaryImage,
|
|
4429
|
+
primaryImage: listingPrimaryMedia,
|
|
3375
4430
|
priceRange,
|
|
3376
4431
|
availableForSale,
|
|
3377
4432
|
swatches
|
|
@@ -3419,17 +4474,16 @@ function aggregateListingPriceRange(groups) {
|
|
|
3419
4474
|
};
|
|
3420
4475
|
}
|
|
3421
4476
|
function buildListingSwatch(product, group, options) {
|
|
3422
|
-
const thumbnail = firstMedia(group.optionValueThumbnail) ?? firstMedia(group.optionValueImages) ?? null;
|
|
3423
4477
|
return {
|
|
3424
4478
|
optionId: group.optionId,
|
|
3425
4479
|
optionValueId: group.optionValueId,
|
|
3426
4480
|
label: group.optionValueLabel,
|
|
3427
|
-
|
|
3428
|
-
thumbnail,
|
|
4481
|
+
swatch: group.optionValueSwatch ?? null,
|
|
3429
4482
|
href: buildProductHref(
|
|
3430
4483
|
{ slug: product.slug },
|
|
3431
4484
|
{
|
|
3432
4485
|
optionId: group.optionId,
|
|
4486
|
+
optionSlug: group.optionSlug,
|
|
3433
4487
|
optionValueId: group.optionValueId,
|
|
3434
4488
|
optionValueSlug: group.optionValueSlug,
|
|
3435
4489
|
listing: group.listing
|
|
@@ -3464,19 +4518,34 @@ function buildProductListingGroupsByOption(args) {
|
|
|
3464
4518
|
return [];
|
|
3465
4519
|
}
|
|
3466
4520
|
const listingBase = buildProductListingProjection(void 0, variants);
|
|
3467
|
-
const
|
|
3468
|
-
const
|
|
3469
|
-
|
|
4521
|
+
const orderedVariants = sortVariantsForMediaSelection(variants);
|
|
4522
|
+
const productMediaPool = (args.product?.images ?? []).filter(
|
|
4523
|
+
(image) => image != null && typeof image === "object"
|
|
4524
|
+
);
|
|
4525
|
+
const resolvedMedia = resolveProductSelectionMedia({
|
|
4526
|
+
productMediaPool,
|
|
4527
|
+
productPrimaryMediaItemId: extractEntityId(
|
|
4528
|
+
args.product?.primaryMediaItemId ?? null
|
|
4529
|
+
),
|
|
4530
|
+
selectedVariant: null,
|
|
4531
|
+
matchingVariants: orderedVariants,
|
|
4532
|
+
selectedOptionValues: [
|
|
4533
|
+
{
|
|
4534
|
+
id: value.id,
|
|
4535
|
+
swatch: normalizeMatrixSwatch(value.swatch)
|
|
4536
|
+
}
|
|
4537
|
+
]
|
|
4538
|
+
});
|
|
4539
|
+
const groupPrimaryImage = extractEntityId(resolvedMedia.primaryImage) ?? getFirstAvailableVariantPrimaryImage(variants) ?? extractEntityId(args.product?.thumbnail) ?? getFirstMediaId(args.product?.images);
|
|
3470
4540
|
return [
|
|
3471
4541
|
{
|
|
3472
4542
|
optionId: primaryOption.id,
|
|
3473
4543
|
optionTitle: primaryOption.title,
|
|
4544
|
+
optionSlug: primaryOption.slug,
|
|
3474
4545
|
optionValueId: value.id,
|
|
3475
4546
|
optionValueLabel: value.label,
|
|
3476
4547
|
optionValueSlug: value.slug,
|
|
3477
|
-
|
|
3478
|
-
optionValueThumbnail: value.thumbnail ?? null,
|
|
3479
|
-
optionValueImages: value.images ?? null,
|
|
4548
|
+
optionValueSwatch: value.swatch ?? null,
|
|
3480
4549
|
variantIds: variants.map((variant) => String(variant.id)),
|
|
3481
4550
|
variantCount: variants.length,
|
|
3482
4551
|
variants,
|
|
@@ -3489,6 +4558,162 @@ function buildProductListingGroupsByOption(args) {
|
|
|
3489
4558
|
});
|
|
3490
4559
|
}
|
|
3491
4560
|
|
|
4561
|
+
// src/utils/product-media.ts
|
|
4562
|
+
function mediaPointerOptionValues(values) {
|
|
4563
|
+
return (values ?? []).filter((value) => value != null && value !== "").map((value) => ({
|
|
4564
|
+
swatch: {
|
|
4565
|
+
type: "media",
|
|
4566
|
+
mediaItemId: value
|
|
4567
|
+
}
|
|
4568
|
+
}));
|
|
4569
|
+
}
|
|
4570
|
+
function resolveProductMedia(input) {
|
|
4571
|
+
const resolved = resolveProductSelectionMedia({
|
|
4572
|
+
...input,
|
|
4573
|
+
selectedVariant: input.selectedVariant ?? (input.variantFeaturedMediaItemId ? { images: [input.variantFeaturedMediaItemId] } : null),
|
|
4574
|
+
selectedOptionValues: input.selectedOptionValues ?? mediaPointerOptionValues(input.selectedOptionValueMediaItemIds)
|
|
4575
|
+
});
|
|
4576
|
+
if (resolved.source !== "none") {
|
|
4577
|
+
return {
|
|
4578
|
+
...resolved,
|
|
4579
|
+
source: resolved.source === "variant_media_selected" ? "variant_featured" : resolved.source
|
|
4580
|
+
};
|
|
4581
|
+
}
|
|
4582
|
+
const display = resolveProductDisplayMedia({
|
|
4583
|
+
productMediaPool: input.productMediaPool,
|
|
4584
|
+
productPrimaryMediaItemId: input.productPrimaryMediaItemId
|
|
4585
|
+
});
|
|
4586
|
+
return {
|
|
4587
|
+
primaryImage: display.primaryImage,
|
|
4588
|
+
images: display.images,
|
|
4589
|
+
source: display.source
|
|
4590
|
+
};
|
|
4591
|
+
}
|
|
4592
|
+
|
|
4593
|
+
// src/utils/product-gallery.ts
|
|
4594
|
+
function mediaId(value) {
|
|
4595
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
4596
|
+
return String(value);
|
|
4597
|
+
}
|
|
4598
|
+
if (typeof value === "object" && value !== null && "id" in value) {
|
|
4599
|
+
const id = value.id;
|
|
4600
|
+
if (typeof id === "string" || typeof id === "number") return String(id);
|
|
4601
|
+
}
|
|
4602
|
+
return null;
|
|
4603
|
+
}
|
|
4604
|
+
function relationshipIds(values) {
|
|
4605
|
+
if (!Array.isArray(values)) return [];
|
|
4606
|
+
return values.map((value) => mediaId(value)).filter((value) => Boolean(value));
|
|
4607
|
+
}
|
|
4608
|
+
function buildPoolById2(pool) {
|
|
4609
|
+
const poolById = /* @__PURE__ */ new Map();
|
|
4610
|
+
for (const item of pool) {
|
|
4611
|
+
const id = mediaId(item);
|
|
4612
|
+
if (id) poolById.set(id, item);
|
|
4613
|
+
}
|
|
4614
|
+
return poolById;
|
|
4615
|
+
}
|
|
4616
|
+
function mediaSetItemsInPool(mediaSet, poolById) {
|
|
4617
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4618
|
+
const items = [];
|
|
4619
|
+
const primaryId = mediaId(mediaSet.primaryMediaItemId);
|
|
4620
|
+
if (primaryId) {
|
|
4621
|
+
const primary = poolById.get(primaryId);
|
|
4622
|
+
if (primary) {
|
|
4623
|
+
seen.add(primaryId);
|
|
4624
|
+
items.push(primary);
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
for (const itemId of relationshipIds(mediaSet.items)) {
|
|
4628
|
+
if (seen.has(itemId)) continue;
|
|
4629
|
+
const item = poolById.get(itemId);
|
|
4630
|
+
if (!item) continue;
|
|
4631
|
+
seen.add(itemId);
|
|
4632
|
+
items.push(item);
|
|
4633
|
+
}
|
|
4634
|
+
return items;
|
|
4635
|
+
}
|
|
4636
|
+
function resolveLegacyMediaSet(input) {
|
|
4637
|
+
if (!Array.isArray(input.mediaSets)) return null;
|
|
4638
|
+
const pool = input.productMediaPool ?? input.pool ?? [];
|
|
4639
|
+
const poolById = buildPoolById2(pool);
|
|
4640
|
+
const selectedVariantId = mediaId(input.selectedVariantId);
|
|
4641
|
+
if (selectedVariantId) {
|
|
4642
|
+
const exactSet = input.mediaSets.find(
|
|
4643
|
+
(set) => set.matchType === "exact-variant" && relationshipIds(set.variantIds).includes(selectedVariantId)
|
|
4644
|
+
);
|
|
4645
|
+
if (exactSet) {
|
|
4646
|
+
const images = mediaSetItemsInPool(exactSet, poolById);
|
|
4647
|
+
if (images.length > 0) {
|
|
4648
|
+
return {
|
|
4649
|
+
primaryImage: images[0] ?? null,
|
|
4650
|
+
images,
|
|
4651
|
+
source: "exact_variant_set"
|
|
4652
|
+
};
|
|
4653
|
+
}
|
|
4654
|
+
}
|
|
4655
|
+
}
|
|
4656
|
+
const selectedOptionValueIds = new Set(
|
|
4657
|
+
relationshipIds(input.selectedOptionValueIds)
|
|
4658
|
+
);
|
|
4659
|
+
const optionSetMatches = input.mediaSets.filter((set) => set.matchType === "option-values").map((set) => {
|
|
4660
|
+
const optionValueIds = relationshipIds(set.optionValueIds);
|
|
4661
|
+
if (optionValueIds.length === 0) return null;
|
|
4662
|
+
if (!optionValueIds.every((id) => selectedOptionValueIds.has(id))) {
|
|
4663
|
+
return null;
|
|
4664
|
+
}
|
|
4665
|
+
const images = mediaSetItemsInPool(set, poolById);
|
|
4666
|
+
if (images.length === 0) return null;
|
|
4667
|
+
return { optionValueCount: optionValueIds.length, images };
|
|
4668
|
+
}).filter(
|
|
4669
|
+
(match) => Boolean(match)
|
|
4670
|
+
).sort((a, b) => b.optionValueCount - a.optionValueCount);
|
|
4671
|
+
if (optionSetMatches.length > 0) {
|
|
4672
|
+
const images = optionSetMatches[0].images;
|
|
4673
|
+
return {
|
|
4674
|
+
primaryImage: images[0] ?? null,
|
|
4675
|
+
images,
|
|
4676
|
+
source: "option_value_set"
|
|
4677
|
+
};
|
|
4678
|
+
}
|
|
4679
|
+
const defaultSet = input.mediaSets.find((set) => set.matchType === "default");
|
|
4680
|
+
if (defaultSet) {
|
|
4681
|
+
const images = mediaSetItemsInPool(defaultSet, poolById);
|
|
4682
|
+
if (images.length > 0) {
|
|
4683
|
+
return {
|
|
4684
|
+
primaryImage: images[0] ?? null,
|
|
4685
|
+
images,
|
|
4686
|
+
source: "default_set"
|
|
4687
|
+
};
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
return {
|
|
4691
|
+
primaryImage: null,
|
|
4692
|
+
images: [],
|
|
4693
|
+
source: "none"
|
|
4694
|
+
};
|
|
4695
|
+
}
|
|
4696
|
+
function resolveProductGallery(input) {
|
|
4697
|
+
const legacyResolved = resolveLegacyMediaSet(input);
|
|
4698
|
+
if (legacyResolved && legacyResolved.source !== "none") return legacyResolved;
|
|
4699
|
+
const selectedVariantId = mediaId(input.selectedVariantId);
|
|
4700
|
+
const selectedOptionValueIds = relationshipIds(input.selectedOptionValueIds);
|
|
4701
|
+
const selection = resolveProductSelectionMedia({
|
|
4702
|
+
...input,
|
|
4703
|
+
productMediaPool: input.productMediaPool ?? input.pool ?? null,
|
|
4704
|
+
selectedVariant: input.selectedVariant ?? (selectedVariantId ? { id: selectedVariantId } : null),
|
|
4705
|
+
selectedOptionValues: input.selectedOptionValues ?? selectedOptionValueIds.map((id) => ({ id }))
|
|
4706
|
+
});
|
|
4707
|
+
if (selection.source !== "none") {
|
|
4708
|
+
return selection;
|
|
4709
|
+
}
|
|
4710
|
+
return resolveProductDisplayMedia({
|
|
4711
|
+
productMediaPool: input.productMediaPool ?? input.pool ?? null,
|
|
4712
|
+
productPrimaryMediaItemId: input.productPrimaryMediaItemId,
|
|
4713
|
+
listingPrimaryImage: input.listingPrimaryImage
|
|
4714
|
+
});
|
|
4715
|
+
}
|
|
4716
|
+
|
|
3492
4717
|
// src/utils/image.ts
|
|
3493
4718
|
var IMAGE_SIZES = [384, 768, 1536];
|
|
3494
4719
|
function getImageUrl(image, displayWidth, dpr = 1) {
|