@01.software/sdk 0.32.0 → 0.34.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 +253 -38
- 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 +368 -24
- 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 +368 -24
- package/dist/client.js.map +1 -1
- package/dist/{collection-client-CORhppPb.d.cts → collection-client-CR2B8c1v.d.cts} +7 -3
- package/dist/{collection-client-DPGXnhoF.d.ts → collection-client-DkREjhQ9.d.ts} +7 -3
- package/dist/{const-DcY2_z9O.d.ts → const-BTvdrXtY.d.cts} +5 -5
- package/dist/{const-Brk2Ff0q.d.cts → const-CdqCauHQ.d.ts} +5 -5
- package/dist/index-CjA3U6X3.d.cts +186 -0
- package/dist/index-DK8_NXkh.d.ts +186 -0
- package/dist/index.cjs +1651 -260
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -9
- package/dist/index.d.ts +74 -9
- package/dist/index.js +1651 -260
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-DVK1QCeU.d.cts → payload-types-C7tb7Xbs.d.cts} +2115 -1833
- package/dist/{payload-types-DVK1QCeU.d.ts → payload-types-C7tb7Xbs.d.ts} +2115 -1833
- package/dist/query.cjs +194 -35
- 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 +194 -35
- 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 +474 -36
- 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 +474 -36
- package/dist/server.js.map +1 -1
- package/dist/{types-DUPC7Xn6.d.ts → types-1ylMrCuW.d.ts} +1 -1
- package/dist/{types-ByMrR_Z_.d.cts → types-Bx558PU6.d.cts} +1 -1
- package/dist/{types-CYMSBkJC.d.ts → types-Byo_Rty4.d.ts} +728 -75
- package/dist/{types-CAkWqIr6.d.cts → types-DDhtZI6E.d.cts} +728 -75
- 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 +95 -0
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.d.cts +20 -104
- package/dist/webhook.d.ts +20 -104
- package/dist/webhook.js +95 -0
- package/dist/webhook.js.map +1 -1
- package/package.json +4 -5
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,9 @@ __export(src_exports, {
|
|
|
24
24
|
AuthError: () => AuthError,
|
|
25
25
|
BaseApi: () => BaseApi,
|
|
26
26
|
COLLECTIONS: () => COLLECTIONS,
|
|
27
|
+
COMMERCE_NOTIFICATION_EVENTS: () => COMMERCE_NOTIFICATION_EVENTS,
|
|
28
|
+
COMMERCE_NOTIFICATION_EVENT_TYPE: () => COMMERCE_NOTIFICATION_EVENT_TYPE,
|
|
29
|
+
COMMERCE_NOTIFICATION_OPERATION: () => COMMERCE_NOTIFICATION_OPERATION,
|
|
27
30
|
CUSTOMER_PASSWORD_RESET_OPERATION: () => CUSTOMER_PASSWORD_RESET_OPERATION,
|
|
28
31
|
CartApi: () => CartApi,
|
|
29
32
|
CommerceClient: () => CommerceClient,
|
|
@@ -33,6 +36,7 @@ __export(src_exports, {
|
|
|
33
36
|
CustomerAuth: () => CustomerAuth,
|
|
34
37
|
CustomerNamespace: () => CustomerNamespace,
|
|
35
38
|
DiscountApi: () => DiscountApi,
|
|
39
|
+
EventsClient: () => EventsClient,
|
|
36
40
|
GoneError: () => GoneError,
|
|
37
41
|
IMAGE_SIZES: () => IMAGE_SIZES,
|
|
38
42
|
INTERNAL_COLLECTIONS: () => INTERNAL_COLLECTIONS,
|
|
@@ -40,6 +44,8 @@ __export(src_exports, {
|
|
|
40
44
|
NotFoundError: () => NotFoundError,
|
|
41
45
|
ORDER_CHANGED_EVENT_TYPE: () => ORDER_CHANGED_EVENT_TYPE,
|
|
42
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,
|
|
43
49
|
PermissionError: () => PermissionError,
|
|
44
50
|
ProductApi: () => ProductApi,
|
|
45
51
|
ProductSelectionCodecError: () => ProductSelectionCodecError,
|
|
@@ -62,6 +68,7 @@ __export(src_exports, {
|
|
|
62
68
|
createAnalytics: () => createAnalytics,
|
|
63
69
|
createAuthError: () => createAuthError,
|
|
64
70
|
createClient: () => createClient2,
|
|
71
|
+
createCommerceEmailWebhookHandler: () => createCommerceEmailWebhookHandler,
|
|
65
72
|
createConflictError: () => createConflictError,
|
|
66
73
|
createCustomerAuthWebhookHandler: () => createCustomerAuthWebhookHandler,
|
|
67
74
|
createNotFoundError: () => createNotFoundError,
|
|
@@ -69,9 +76,11 @@ __export(src_exports, {
|
|
|
69
76
|
createProductSelectionCodec: () => createProductSelectionCodec,
|
|
70
77
|
createRateLimitError: () => createRateLimitError,
|
|
71
78
|
createTypedWebhookHandler: () => createTypedWebhookHandler,
|
|
79
|
+
defineCommerceEmailConfig: () => defineCommerceEmailConfig,
|
|
72
80
|
formatOrderName: () => formatOrderName,
|
|
73
81
|
generateOrderNumber: () => generateOrderNumber,
|
|
74
82
|
getAvailableOptionValues: () => getAvailableOptionValues,
|
|
83
|
+
getCommerceNotificationIdempotencyKey: () => getCommerceNotificationIdempotencyKey,
|
|
75
84
|
getImageLqip: () => getImageLqip,
|
|
76
85
|
getImagePalette: () => getImagePalette,
|
|
77
86
|
getImagePlaceholderStyle: () => getImagePlaceholderStyle,
|
|
@@ -87,6 +96,7 @@ __export(src_exports, {
|
|
|
87
96
|
handleWebhook: () => handleWebhook,
|
|
88
97
|
isApiError: () => isApiError,
|
|
89
98
|
isAuthError: () => isAuthError,
|
|
99
|
+
isCommerceNotificationWebhookEvent: () => isCommerceNotificationWebhookEvent,
|
|
90
100
|
isConfigError: () => isConfigError,
|
|
91
101
|
isConflictError: () => isConflictError,
|
|
92
102
|
isCustomerPasswordResetWebhookEvent: () => isCustomerPasswordResetWebhookEvent,
|
|
@@ -95,6 +105,7 @@ __export(src_exports, {
|
|
|
95
105
|
isNotFoundError: () => isNotFoundError,
|
|
96
106
|
isOrderChangedWebhookEvent: () => isOrderChangedWebhookEvent,
|
|
97
107
|
isPermissionError: () => isPermissionError,
|
|
108
|
+
isProductUpsertFieldValidationErrorBody: () => isProductUpsertFieldValidationErrorBody,
|
|
98
109
|
isRateLimitError: () => isRateLimitError,
|
|
99
110
|
isSDKError: () => isSDKError,
|
|
100
111
|
isServiceUnavailableError: () => isServiceUnavailableError,
|
|
@@ -104,14 +115,22 @@ __export(src_exports, {
|
|
|
104
115
|
isValidationError: () => isValidationError,
|
|
105
116
|
isWebhookCollection: () => isWebhookCollection,
|
|
106
117
|
isWebhookOperation: () => isWebhookOperation,
|
|
118
|
+
mergeProductDetailWithStock: () => mergeProductDetailWithStock,
|
|
107
119
|
normalizeProductSelection: () => normalizeProductSelection,
|
|
108
120
|
normalizeProductSelectionFromMatrix: () => normalizeProductSelectionFromMatrix,
|
|
109
121
|
normalizeSelectedValueIds: () => normalizeSelectedValueIds,
|
|
110
122
|
parseProductSelection: () => parseProductSelection,
|
|
123
|
+
resolveListingPrimaryImagePointer: () => resolveListingPrimaryImagePointer,
|
|
124
|
+
resolveProductDisplayMedia: () => resolveProductDisplayMedia,
|
|
125
|
+
resolveProductGallery: () => resolveProductGallery,
|
|
126
|
+
resolveProductMedia: () => resolveProductMedia,
|
|
111
127
|
resolveProductSelection: () => resolveProductSelection,
|
|
112
128
|
resolveProductSelectionFromMatrix: () => resolveProductSelectionFromMatrix,
|
|
129
|
+
resolveProductSelectionMedia: () => resolveProductSelectionMedia,
|
|
113
130
|
resolveRelation: () => resolveRelation,
|
|
114
131
|
resolveVariantForSelection: () => resolveVariantForSelection,
|
|
132
|
+
selectNext: () => selectNext,
|
|
133
|
+
selectedSwatchMediaItemId: () => selectedSwatchMediaItemId,
|
|
115
134
|
stringifyProductSelection: () => stringifyProductSelection
|
|
116
135
|
});
|
|
117
136
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -371,9 +390,12 @@ function resolveApiUrl(apiUrl) {
|
|
|
371
390
|
|
|
372
391
|
// src/core/internal/utils/http.ts
|
|
373
392
|
var DEFAULT_TIMEOUT = 3e4;
|
|
393
|
+
var STOREFRONT_BROWSER_TIMEOUT = 15e3;
|
|
374
394
|
var DEFAULT_RETRYABLE_STATUSES = [408, 429, 500, 502, 503, 504];
|
|
375
395
|
var NON_RETRYABLE_STATUSES = [400, 401, 403, 404, 409, 422];
|
|
376
396
|
var SAFE_METHODS = ["GET", "HEAD", "OPTIONS"];
|
|
397
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
398
|
+
var STOREFRONT_BROWSER_MAX_RETRIES = 1;
|
|
377
399
|
function debugLog(debug, type, message, data) {
|
|
378
400
|
if (!debug) return;
|
|
379
401
|
const shouldLog = debug === true || type === "request" && debug.logRequests || type === "response" && debug.logResponses || type === "error" && debug.logErrors;
|
|
@@ -566,15 +588,18 @@ async function httpFetch(url, options) {
|
|
|
566
588
|
publishableKey,
|
|
567
589
|
secretKey,
|
|
568
590
|
customerToken,
|
|
569
|
-
timeout = DEFAULT_TIMEOUT,
|
|
591
|
+
timeout: timeoutOption = DEFAULT_TIMEOUT,
|
|
570
592
|
debug,
|
|
571
593
|
retry,
|
|
572
594
|
onUnauthorized,
|
|
573
595
|
...requestInit
|
|
574
596
|
} = options || {};
|
|
575
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;
|
|
576
601
|
const retryConfig = {
|
|
577
|
-
maxRetries: retry?.maxRetries ??
|
|
602
|
+
maxRetries: retry?.maxRetries ?? (isPublishableKeyBrowserGet ? STOREFRONT_BROWSER_MAX_RETRIES : DEFAULT_MAX_RETRIES),
|
|
578
603
|
retryableStatuses: retry?.retryableStatuses ?? DEFAULT_RETRYABLE_STATUSES,
|
|
579
604
|
retryDelay: retry?.retryDelay ?? ((attempt) => Math.min(1e3 * 2 ** attempt, 1e4))
|
|
580
605
|
};
|
|
@@ -682,8 +707,8 @@ async function httpFetch(url, options) {
|
|
|
682
707
|
),
|
|
683
708
|
requestId
|
|
684
709
|
);
|
|
685
|
-
const
|
|
686
|
-
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)) {
|
|
687
712
|
lastError = error;
|
|
688
713
|
const retryDelay = retryConfig.retryDelay(attempt);
|
|
689
714
|
debugLog(debug, "error", `Retrying in ${retryDelay}ms...`, error);
|
|
@@ -695,8 +720,8 @@ async function httpFetch(url, options) {
|
|
|
695
720
|
return response;
|
|
696
721
|
} catch (error) {
|
|
697
722
|
debugLog(debug, "error", url, error);
|
|
698
|
-
const
|
|
699
|
-
const isSafe = SAFE_METHODS.includes(
|
|
723
|
+
const method2 = (requestInit.method || "GET").toUpperCase();
|
|
724
|
+
const isSafe = SAFE_METHODS.includes(method2);
|
|
700
725
|
if (error instanceof Error && error.name === "AbortError") {
|
|
701
726
|
const timeoutError = createTimeoutError(
|
|
702
727
|
`Request timed out after ${timeout}ms.`,
|
|
@@ -755,6 +780,35 @@ async function httpFetch(url, options) {
|
|
|
755
780
|
throw lastError ?? new NetworkError("Request failed after retries");
|
|
756
781
|
}
|
|
757
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
|
+
|
|
758
812
|
// src/core/collection/http-client.ts
|
|
759
813
|
var HttpClient = class {
|
|
760
814
|
constructor(publishableKey, secretKey, getCustomerToken, onUnauthorized, onRequestId, apiUrl) {
|
|
@@ -1073,6 +1127,8 @@ async function parseApiResponse(response, endpoint) {
|
|
|
1073
1127
|
}
|
|
1074
1128
|
|
|
1075
1129
|
// src/core/community/community-client.ts
|
|
1130
|
+
var DEFAULT_POST_LIST_SORT = "-lastActivityAt";
|
|
1131
|
+
var DEFAULT_COMMENT_LIST_SORT = "-createdAt";
|
|
1076
1132
|
var CommunityClient = class {
|
|
1077
1133
|
constructor(options) {
|
|
1078
1134
|
this.publishableKey = requirePublishableKeyForSecret(
|
|
@@ -1091,6 +1147,40 @@ var CommunityClient = class {
|
|
|
1091
1147
|
const entries = Object.entries(params).filter((e) => e[1] !== void 0).map(([k, v]) => [k, String(v)]);
|
|
1092
1148
|
return entries.length ? `?${new URLSearchParams(entries).toString()}` : "";
|
|
1093
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
|
+
}
|
|
1094
1184
|
async execute(endpoint, method, body) {
|
|
1095
1185
|
const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
|
|
1096
1186
|
try {
|
|
@@ -1114,6 +1204,28 @@ var CommunityClient = class {
|
|
|
1114
1204
|
createPost(params) {
|
|
1115
1205
|
return this.execute("/api/posts", "POST", params);
|
|
1116
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
|
+
}
|
|
1117
1229
|
getMyPosts(params) {
|
|
1118
1230
|
return this.execute(
|
|
1119
1231
|
`/api/posts/my${this.buildQuery(params)}`,
|
|
@@ -1149,16 +1261,37 @@ var CommunityClient = class {
|
|
|
1149
1261
|
}
|
|
1150
1262
|
return this.execute("/api/comments", "POST", body);
|
|
1151
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
|
+
*/
|
|
1152
1271
|
listComments(params) {
|
|
1153
|
-
const { postId, page, limit, rootComment } = params;
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
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;
|
|
1160
1288
|
return this.execute(
|
|
1161
|
-
|
|
1289
|
+
this.buildCommentsListQuery({
|
|
1290
|
+
parentId: commentId,
|
|
1291
|
+
page,
|
|
1292
|
+
limit,
|
|
1293
|
+
sort
|
|
1294
|
+
}),
|
|
1162
1295
|
"GET"
|
|
1163
1296
|
);
|
|
1164
1297
|
}
|
|
@@ -1186,10 +1319,18 @@ var CommunityClient = class {
|
|
|
1186
1319
|
}
|
|
1187
1320
|
// Reactions
|
|
1188
1321
|
addReaction(params) {
|
|
1189
|
-
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
|
+
}
|
|
1190
1331
|
return this.execute("/api/reactions", "POST", {
|
|
1191
1332
|
post: postId,
|
|
1192
|
-
type
|
|
1333
|
+
type: reactionType
|
|
1193
1334
|
});
|
|
1194
1335
|
}
|
|
1195
1336
|
removeReaction(params) {
|
|
@@ -1200,10 +1341,18 @@ var CommunityClient = class {
|
|
|
1200
1341
|
);
|
|
1201
1342
|
}
|
|
1202
1343
|
addCommentReaction(params) {
|
|
1203
|
-
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
|
+
}
|
|
1204
1353
|
return this.execute("/api/reactions", "POST", {
|
|
1205
1354
|
comment: commentId,
|
|
1206
|
-
type
|
|
1355
|
+
type: reactionType
|
|
1207
1356
|
});
|
|
1208
1357
|
}
|
|
1209
1358
|
removeCommentReaction(params) {
|
|
@@ -1219,6 +1368,12 @@ var CommunityClient = class {
|
|
|
1219
1368
|
"GET"
|
|
1220
1369
|
);
|
|
1221
1370
|
}
|
|
1371
|
+
getCommentReactionSummary(params) {
|
|
1372
|
+
return this.execute(
|
|
1373
|
+
`/api/comments/${params.commentId}/reactions`,
|
|
1374
|
+
"GET"
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1222
1377
|
getReactionTypes() {
|
|
1223
1378
|
return this.execute(
|
|
1224
1379
|
"/api/reaction-types?limit=100",
|
|
@@ -1243,6 +1398,25 @@ var CommunityClient = class {
|
|
|
1243
1398
|
"GET"
|
|
1244
1399
|
);
|
|
1245
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
|
+
}
|
|
1246
1420
|
};
|
|
1247
1421
|
|
|
1248
1422
|
// src/core/customer/customer-auth.ts
|
|
@@ -1528,6 +1702,283 @@ var CartApi = class {
|
|
|
1528
1702
|
}
|
|
1529
1703
|
};
|
|
1530
1704
|
|
|
1705
|
+
// src/core/api/base-api.ts
|
|
1706
|
+
var BaseApi = class {
|
|
1707
|
+
constructor(apiName, options) {
|
|
1708
|
+
if (!options.secretKey) {
|
|
1709
|
+
throw createConfigError(`secretKey is required for ${apiName}.`);
|
|
1710
|
+
}
|
|
1711
|
+
this.publishableKey = requirePublishableKeyForSecret(
|
|
1712
|
+
apiName,
|
|
1713
|
+
options.publishableKey,
|
|
1714
|
+
options.secretKey
|
|
1715
|
+
);
|
|
1716
|
+
this.secretKey = options.secretKey;
|
|
1717
|
+
this.apiUrl = options.apiUrl;
|
|
1718
|
+
this.onRequestId = options.onRequestId;
|
|
1719
|
+
}
|
|
1720
|
+
async request(endpoint, body, options) {
|
|
1721
|
+
const method = options?.method ?? "POST";
|
|
1722
|
+
try {
|
|
1723
|
+
const response = await httpFetch(endpoint, {
|
|
1724
|
+
method,
|
|
1725
|
+
apiUrl: this.apiUrl,
|
|
1726
|
+
publishableKey: this.publishableKey,
|
|
1727
|
+
secretKey: this.secretKey,
|
|
1728
|
+
...body !== void 0 && { body: JSON.stringify(body) },
|
|
1729
|
+
...options?.headers && { headers: options.headers }
|
|
1730
|
+
});
|
|
1731
|
+
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
1732
|
+
return parseApiResponse(response, endpoint);
|
|
1733
|
+
} catch (err) {
|
|
1734
|
+
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
1735
|
+
this.onRequestId?.(id);
|
|
1736
|
+
throw err;
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
};
|
|
1740
|
+
|
|
1741
|
+
// src/core/api/product-api.ts
|
|
1742
|
+
var PRODUCT_DETAIL_UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
|
|
1743
|
+
"not_found",
|
|
1744
|
+
"not_published",
|
|
1745
|
+
"feature_disabled"
|
|
1746
|
+
]);
|
|
1747
|
+
function isRecord(value) {
|
|
1748
|
+
return typeof value === "object" && value !== null;
|
|
1749
|
+
}
|
|
1750
|
+
function readProductDetailUnavailableReason(value) {
|
|
1751
|
+
if (!isRecord(value)) return void 0;
|
|
1752
|
+
const directReason = value.reason ?? value.code;
|
|
1753
|
+
if (typeof directReason === "string" && PRODUCT_DETAIL_UNAVAILABLE_REASONS.has(directReason)) {
|
|
1754
|
+
return directReason;
|
|
1755
|
+
}
|
|
1756
|
+
return readProductDetailUnavailableReason(value.body);
|
|
1757
|
+
}
|
|
1758
|
+
function productDetailResultFromError(error) {
|
|
1759
|
+
if (!(error instanceof SDKError) || error.status !== 404) return void 0;
|
|
1760
|
+
const reason = readProductDetailUnavailableReason(error.details);
|
|
1761
|
+
if (!reason) return void 0;
|
|
1762
|
+
return { found: false, reason };
|
|
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
|
+
}
|
|
1803
|
+
var ProductApi = class extends BaseApi {
|
|
1804
|
+
constructor(options) {
|
|
1805
|
+
super("ProductApi", options);
|
|
1806
|
+
}
|
|
1807
|
+
/**
|
|
1808
|
+
* Check point-in-time stock availability for one or more product variants.
|
|
1809
|
+
* Results reflect available stock at the moment of the call and are not guaranteed
|
|
1810
|
+
* to remain available by the time an order is placed.
|
|
1811
|
+
*/
|
|
1812
|
+
stockCheck(params) {
|
|
1813
|
+
return this.request("/api/products/stock-check", params);
|
|
1814
|
+
}
|
|
1815
|
+
stockSnapshot(params) {
|
|
1816
|
+
return this.request(
|
|
1817
|
+
stockSnapshotQuery(params),
|
|
1818
|
+
void 0,
|
|
1819
|
+
{ method: "GET" }
|
|
1820
|
+
);
|
|
1821
|
+
}
|
|
1822
|
+
listingGroups(params) {
|
|
1823
|
+
return this.request(
|
|
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" }
|
|
1834
|
+
);
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Fetch full product detail by slug or id.
|
|
1838
|
+
* Returns a discriminated result so storefronts can distinguish missing,
|
|
1839
|
+
* unpublished, and feature-disabled products.
|
|
1840
|
+
*
|
|
1841
|
+
* Only product-detail 404 responses carrying one of those allowlisted reasons
|
|
1842
|
+
* are mapped to `{ found: false, reason }`. Unknown or uncoded 404s, plus
|
|
1843
|
+
* permission/auth errors such as tenant mismatch, continue to throw typed SDK
|
|
1844
|
+
* errors instead of being collapsed into a storefront absence result.
|
|
1845
|
+
*/
|
|
1846
|
+
async detail(params) {
|
|
1847
|
+
try {
|
|
1848
|
+
const product = await this.request(
|
|
1849
|
+
productDetailQuery(params),
|
|
1850
|
+
void 0,
|
|
1851
|
+
{ method: "GET" }
|
|
1852
|
+
);
|
|
1853
|
+
return { found: true, product };
|
|
1854
|
+
} catch (err) {
|
|
1855
|
+
const notFoundResult = productDetailResultFromError(err);
|
|
1856
|
+
if (notFoundResult) return notFoundResult;
|
|
1857
|
+
throw err;
|
|
1858
|
+
}
|
|
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
|
+
}
|
|
1874
|
+
/**
|
|
1875
|
+
* Atomically create or update a product together with its options,
|
|
1876
|
+
* option-values, and variants in a single transaction. Mirrors Shopify's
|
|
1877
|
+
* `productSet` shape and is the canonical write path for the MCP
|
|
1878
|
+
* `product-upsert` tool.
|
|
1879
|
+
*/
|
|
1880
|
+
upsert(params) {
|
|
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);
|
|
1979
|
+
}
|
|
1980
|
+
};
|
|
1981
|
+
|
|
1531
1982
|
// src/core/commerce/commerce-client.ts
|
|
1532
1983
|
var CommerceClient = class {
|
|
1533
1984
|
constructor(options) {
|
|
@@ -1538,7 +1989,7 @@ var CommerceClient = class {
|
|
|
1538
1989
|
onUnauthorized: options.onUnauthorized,
|
|
1539
1990
|
onRequestId: options.onRequestId
|
|
1540
1991
|
});
|
|
1541
|
-
const execute = async (endpoint, body) => {
|
|
1992
|
+
const execute = async (endpoint, body, requestOptions) => {
|
|
1542
1993
|
const token = options.customerToken();
|
|
1543
1994
|
try {
|
|
1544
1995
|
const response = await httpFetch(endpoint, {
|
|
@@ -1547,7 +1998,26 @@ var CommerceClient = class {
|
|
|
1547
1998
|
publishableKey: options.publishableKey,
|
|
1548
1999
|
customerToken: token ?? void 0,
|
|
1549
2000
|
...token && options.onUnauthorized && { onUnauthorized: options.onUnauthorized },
|
|
1550
|
-
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 }
|
|
1551
2021
|
});
|
|
1552
2022
|
options.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
1553
2023
|
return parseApiResponse(response, endpoint);
|
|
@@ -1559,12 +2029,28 @@ var CommerceClient = class {
|
|
|
1559
2029
|
};
|
|
1560
2030
|
this.product = {
|
|
1561
2031
|
stockCheck: (params) => execute("/api/products/stock-check", params),
|
|
1562
|
-
|
|
2032
|
+
stockSnapshot: (params) => executeGet(stockSnapshotQuery(params)),
|
|
2033
|
+
listingGroups: (params) => executeGet(listingGroupsQuery(params)),
|
|
2034
|
+
listingGroupsCatalog: (params) => executeGet(listingGroupsCatalogQuery(params)),
|
|
1563
2035
|
detail: async (params) => {
|
|
1564
2036
|
try {
|
|
1565
|
-
|
|
2037
|
+
const product = await executeGet(productDetailQuery(params));
|
|
2038
|
+
return { found: true, product };
|
|
2039
|
+
} catch (err) {
|
|
2040
|
+
const notFoundResult = productDetailResultFromError(err);
|
|
2041
|
+
if (notFoundResult) return notFoundResult;
|
|
2042
|
+
throw err;
|
|
2043
|
+
}
|
|
2044
|
+
},
|
|
2045
|
+
detailCatalog: async (params) => {
|
|
2046
|
+
try {
|
|
2047
|
+
const product = await executeGet(
|
|
2048
|
+
productDetailCatalogQuery(params)
|
|
2049
|
+
);
|
|
2050
|
+
return { found: true, product };
|
|
1566
2051
|
} catch (err) {
|
|
1567
|
-
|
|
2052
|
+
const notFoundResult = productDetailResultFromError(err);
|
|
2053
|
+
if (notFoundResult?.found === false) return notFoundResult;
|
|
1568
2054
|
throw err;
|
|
1569
2055
|
}
|
|
1570
2056
|
}
|
|
@@ -1579,7 +2065,14 @@ var CommerceClient = class {
|
|
|
1579
2065
|
clear: cartApi.clearCart.bind(cartApi)
|
|
1580
2066
|
};
|
|
1581
2067
|
this.orders = {
|
|
1582
|
-
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
|
+
},
|
|
1583
2076
|
listMine: (params) => options.customerAuth.getMyOrders(params)
|
|
1584
2077
|
};
|
|
1585
2078
|
this.discounts = {
|
|
@@ -1591,15 +2084,122 @@ var CommerceClient = class {
|
|
|
1591
2084
|
}
|
|
1592
2085
|
};
|
|
1593
2086
|
|
|
1594
|
-
// src/core/
|
|
1595
|
-
var
|
|
2087
|
+
// src/core/events/events-client.ts
|
|
2088
|
+
var EventsClient = class {
|
|
1596
2089
|
constructor(options) {
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
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
|
+
|
|
2194
|
+
// src/core/client/client.ts
|
|
2195
|
+
var Client = class {
|
|
2196
|
+
constructor(options) {
|
|
2197
|
+
this.lastRequestId = null;
|
|
2198
|
+
const publishableKey = options.publishableKey;
|
|
2199
|
+
if (!publishableKey) {
|
|
2200
|
+
throw createConfigError("publishableKey is required.");
|
|
2201
|
+
}
|
|
2202
|
+
this.config = { ...options, publishableKey };
|
|
1603
2203
|
const metadata = {
|
|
1604
2204
|
timestamp: Date.now(),
|
|
1605
2205
|
userAgent: typeof window !== "undefined" ? window.navigator?.userAgent : "Node.js"
|
|
@@ -1636,6 +2236,13 @@ var Client = class {
|
|
|
1636
2236
|
onUnauthorized,
|
|
1637
2237
|
onRequestId
|
|
1638
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
|
+
});
|
|
1639
2246
|
this.collections = new ReadOnlyCollectionClient(
|
|
1640
2247
|
this.config.publishableKey,
|
|
1641
2248
|
void 0,
|
|
@@ -1656,92 +2263,6 @@ function createClient(options) {
|
|
|
1656
2263
|
return new Client(options);
|
|
1657
2264
|
}
|
|
1658
2265
|
|
|
1659
|
-
// src/core/api/base-api.ts
|
|
1660
|
-
var BaseApi = class {
|
|
1661
|
-
constructor(apiName, options) {
|
|
1662
|
-
if (!options.secretKey) {
|
|
1663
|
-
throw createConfigError(`secretKey is required for ${apiName}.`);
|
|
1664
|
-
}
|
|
1665
|
-
this.publishableKey = requirePublishableKeyForSecret(
|
|
1666
|
-
apiName,
|
|
1667
|
-
options.publishableKey,
|
|
1668
|
-
options.secretKey
|
|
1669
|
-
);
|
|
1670
|
-
this.secretKey = options.secretKey;
|
|
1671
|
-
this.apiUrl = options.apiUrl;
|
|
1672
|
-
this.onRequestId = options.onRequestId;
|
|
1673
|
-
}
|
|
1674
|
-
async request(endpoint, body, options) {
|
|
1675
|
-
const method = options?.method ?? "POST";
|
|
1676
|
-
try {
|
|
1677
|
-
const response = await httpFetch(endpoint, {
|
|
1678
|
-
method,
|
|
1679
|
-
apiUrl: this.apiUrl,
|
|
1680
|
-
publishableKey: this.publishableKey,
|
|
1681
|
-
secretKey: this.secretKey,
|
|
1682
|
-
...body !== void 0 && { body: JSON.stringify(body) },
|
|
1683
|
-
...options?.headers && { headers: options.headers }
|
|
1684
|
-
});
|
|
1685
|
-
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
1686
|
-
return parseApiResponse(response, endpoint);
|
|
1687
|
-
} catch (err) {
|
|
1688
|
-
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
1689
|
-
this.onRequestId?.(id);
|
|
1690
|
-
throw err;
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1693
|
-
};
|
|
1694
|
-
|
|
1695
|
-
// src/core/api/order-api.ts
|
|
1696
|
-
var OrderApi = class extends BaseApi {
|
|
1697
|
-
constructor(options) {
|
|
1698
|
-
super("OrderApi", options);
|
|
1699
|
-
}
|
|
1700
|
-
createOrder(params) {
|
|
1701
|
-
return this.request("/api/orders/create", params);
|
|
1702
|
-
}
|
|
1703
|
-
updateOrder(params) {
|
|
1704
|
-
return this.request("/api/orders/update", params);
|
|
1705
|
-
}
|
|
1706
|
-
updateTransaction(params) {
|
|
1707
|
-
return this.request("/api/transactions/update", params);
|
|
1708
|
-
}
|
|
1709
|
-
confirmPayment(params) {
|
|
1710
|
-
return this.request(
|
|
1711
|
-
"/api/orders/confirm-payment",
|
|
1712
|
-
params,
|
|
1713
|
-
params.providerEventId ? { headers: { "X-Idempotency-Key": params.providerEventId } } : void 0
|
|
1714
|
-
);
|
|
1715
|
-
}
|
|
1716
|
-
checkout(params) {
|
|
1717
|
-
return this.request("/api/orders/checkout", params);
|
|
1718
|
-
}
|
|
1719
|
-
createFulfillment(params) {
|
|
1720
|
-
return this.request("/api/orders/create-fulfillment", params);
|
|
1721
|
-
}
|
|
1722
|
-
updateFulfillment(params) {
|
|
1723
|
-
return this.request("/api/orders/update-fulfillment", params);
|
|
1724
|
-
}
|
|
1725
|
-
bulkImportFulfillments(params) {
|
|
1726
|
-
return this.request(
|
|
1727
|
-
"/api/orders/bulk-import-fulfillments",
|
|
1728
|
-
params
|
|
1729
|
-
);
|
|
1730
|
-
}
|
|
1731
|
-
returnWithRefund(params) {
|
|
1732
|
-
return this.request(
|
|
1733
|
-
"/api/returns/return-refund",
|
|
1734
|
-
params
|
|
1735
|
-
);
|
|
1736
|
-
}
|
|
1737
|
-
createReturn(params) {
|
|
1738
|
-
return this.request("/api/returns/create", params);
|
|
1739
|
-
}
|
|
1740
|
-
updateReturn(params) {
|
|
1741
|
-
return this.request("/api/returns/update", params);
|
|
1742
|
-
}
|
|
1743
|
-
};
|
|
1744
|
-
|
|
1745
2266
|
// src/core/api/discount-api.ts
|
|
1746
2267
|
var DiscountApi = class extends BaseApi {
|
|
1747
2268
|
constructor(options) {
|
|
@@ -1762,62 +2283,66 @@ var ShippingApi = class extends BaseApi {
|
|
|
1762
2283
|
}
|
|
1763
2284
|
};
|
|
1764
2285
|
|
|
1765
|
-
// src/core/
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
return this.request("/api/products/stock-check", params);
|
|
1777
|
-
}
|
|
1778
|
-
listingGroups(params) {
|
|
1779
|
-
return this.request(
|
|
1780
|
-
"/api/products/listing-groups",
|
|
1781
|
-
params
|
|
1782
|
-
);
|
|
1783
|
-
}
|
|
1784
|
-
/**
|
|
1785
|
-
* Fetch full product detail by slug or id.
|
|
1786
|
-
* Returns `null` on 404 regardless of reason (`not_found` / `not_published` /
|
|
1787
|
-
* `feature_disabled`). For the reason behind a null,
|
|
1788
|
-
* inspect `client.lastRequestId` against backend logs.
|
|
1789
|
-
*/
|
|
1790
|
-
async detail(params) {
|
|
1791
|
-
try {
|
|
1792
|
-
return await this.request("/api/products/detail", params);
|
|
1793
|
-
} catch (err) {
|
|
1794
|
-
if (err instanceof NotFoundError) return null;
|
|
1795
|
-
throw err;
|
|
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 };
|
|
1796
2297
|
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
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
|
+
}
|
|
1808
2323
|
|
|
1809
2324
|
// src/core/webhook/index.ts
|
|
1810
2325
|
var ORDER_CHANGED_EVENT_TYPE = "collection.orderChanged";
|
|
2326
|
+
var COMMERCE_NOTIFICATION_EVENT_TYPE = "commerce.notification";
|
|
1811
2327
|
function isValidWebhookEvent(data) {
|
|
1812
2328
|
if (typeof data !== "object" || data === null) return false;
|
|
1813
2329
|
const obj = data;
|
|
1814
2330
|
return typeof obj.collection === "string" && typeof obj.operation === "string" && obj.operation.length > 0 && typeof obj.data === "object" && obj.data !== null;
|
|
1815
2331
|
}
|
|
2332
|
+
var COMMERCE_NOTIFICATION_OPERATION = "notification";
|
|
2333
|
+
var COMMERCE_NOTIFICATION_EVENTS = [
|
|
2334
|
+
"orderPaid",
|
|
2335
|
+
"orderCanceled",
|
|
2336
|
+
"fulfillmentShipped",
|
|
2337
|
+
"orderDelivered",
|
|
2338
|
+
"returnRequested",
|
|
2339
|
+
"returnCompleted"
|
|
2340
|
+
];
|
|
1816
2341
|
function isStringOrNumber(value) {
|
|
1817
2342
|
return typeof value === "string" || typeof value === "number";
|
|
1818
2343
|
}
|
|
1819
2344
|
function isWebhookOrderScope(value) {
|
|
1820
|
-
if (!
|
|
2345
|
+
if (!isRecord2(value)) return false;
|
|
1821
2346
|
if (value.kind === "collection") {
|
|
1822
2347
|
return typeof value.collection === "string";
|
|
1823
2348
|
}
|
|
@@ -1827,16 +2352,40 @@ function isWebhookOrderScope(value) {
|
|
|
1827
2352
|
return false;
|
|
1828
2353
|
}
|
|
1829
2354
|
function isWebhookOrderMoved(value) {
|
|
1830
|
-
if (!
|
|
2355
|
+
if (!isRecord2(value)) return false;
|
|
1831
2356
|
return typeof value.collection === "string" && isStringOrNumber(value.id) && (value.relatedCollection === void 0 || typeof value.relatedCollection === "string") && (value.relatedId === void 0 || isStringOrNumber(value.relatedId));
|
|
1832
2357
|
}
|
|
1833
2358
|
function hasOptionalOrderValue(value, key) {
|
|
1834
2359
|
return value[key] === void 0 || value[key] === null || typeof value[key] === "string";
|
|
1835
2360
|
}
|
|
1836
2361
|
function isWebhookOrderChange(value) {
|
|
1837
|
-
if (!
|
|
2362
|
+
if (!isRecord2(value)) return false;
|
|
1838
2363
|
return value.type === "order" && value.source === "payload-orderable" && (value.orderableFieldName === void 0 || typeof value.orderableFieldName === "string") && hasOptionalOrderValue(value, "previousOrder") && hasOptionalOrderValue(value, "nextOrder") && isWebhookOrderScope(value.scope) && isWebhookOrderMoved(value.moved);
|
|
1839
2364
|
}
|
|
2365
|
+
function isCommerceNotificationEventName(value) {
|
|
2366
|
+
return typeof value === "string" && COMMERCE_NOTIFICATION_EVENTS.includes(value);
|
|
2367
|
+
}
|
|
2368
|
+
function isCommerceNotificationSourceCollection(value) {
|
|
2369
|
+
return value === "orders" || value === "fulfillments" || value === "returns";
|
|
2370
|
+
}
|
|
2371
|
+
function isCommerceNotificationData(value) {
|
|
2372
|
+
if (!isRecord2(value)) return false;
|
|
2373
|
+
if (value.source !== void 0 && (!isRecord2(value.source) || !isCommerceNotificationSourceCollection(value.source.collection) || !isStringOrNumber(value.source.id))) {
|
|
2374
|
+
return false;
|
|
2375
|
+
}
|
|
2376
|
+
return (value.orderId === void 0 || isStringOrNumber(value.orderId)) && (value.orderNumber === void 0 || typeof value.orderNumber === "string") && (value.status === void 0 || typeof value.status === "string") && (value.totalAmount === void 0 || typeof value.totalAmount === "number") && (value.currency === void 0 || typeof value.currency === "string") && (value.fulfillmentId === void 0 || isStringOrNumber(value.fulfillmentId)) && (value.fulfillmentStatus === void 0 || typeof value.fulfillmentStatus === "string") && (value.shippedAt === void 0 || typeof value.shippedAt === "string") && (value.returnId === void 0 || isStringOrNumber(value.returnId)) && (value.returnStatus === void 0 || typeof value.returnStatus === "string") && (value.refundAmount === void 0 || typeof value.refundAmount === "number") && (value.completedAt === void 0 || typeof value.completedAt === "string");
|
|
2377
|
+
}
|
|
2378
|
+
function isCommerceNotification(value) {
|
|
2379
|
+
if (!isRecord2(value)) return false;
|
|
2380
|
+
return isCommerceNotificationEventName(value.event) && typeof value.intentId === "string" && value.intentId.length > 0 && typeof value.dedupeKey === "string" && value.dedupeKey.length > 0 && (value.orderId === void 0 || typeof value.orderId === "string") && (value.fulfillmentId === void 0 || typeof value.fulfillmentId === "string") && (value.returnId === void 0 || typeof value.returnId === "string");
|
|
2381
|
+
}
|
|
2382
|
+
function isWebhookCommerceNotificationChange(value) {
|
|
2383
|
+
if (!isRecord2(value)) return false;
|
|
2384
|
+
return value.type === "notification" && value.source === "commerce-notifications" && isCommerceNotificationEventName(value.event) && isCommerceNotificationSourceCollection(value.sourceCollection) && isStringOrNumber(value.sourceId);
|
|
2385
|
+
}
|
|
2386
|
+
function matchesOptionalId(actual, expected) {
|
|
2387
|
+
return actual === void 0 || expected === void 0 || actual === expected;
|
|
2388
|
+
}
|
|
1840
2389
|
function isOrderChangedWebhookEvent(event) {
|
|
1841
2390
|
if (!isValidWebhookEvent(event) || event.operation !== "update" || event.eventType !== ORDER_CHANGED_EVENT_TYPE || !isWebhookOrderChange(event.change)) {
|
|
1842
2391
|
return false;
|
|
@@ -1849,6 +2398,60 @@ function isOrderChangedWebhookEvent(event) {
|
|
|
1849
2398
|
}
|
|
1850
2399
|
return true;
|
|
1851
2400
|
}
|
|
2401
|
+
function isCommerceNotificationWebhookEvent(event) {
|
|
2402
|
+
if (!isValidWebhookEvent(event) || event.operation !== COMMERCE_NOTIFICATION_OPERATION || event.eventType !== COMMERCE_NOTIFICATION_EVENT_TYPE || !isCommerceNotificationData(event.data) || !isCommerceNotification(event.notification)) {
|
|
2403
|
+
return false;
|
|
2404
|
+
}
|
|
2405
|
+
const notification = event.notification;
|
|
2406
|
+
const data = event.data;
|
|
2407
|
+
const change = event.change;
|
|
2408
|
+
const sourceCollection = data.source?.collection ?? event.collection;
|
|
2409
|
+
const sourceId = data.source?.id;
|
|
2410
|
+
if (!isCommerceNotificationSourceCollection(sourceCollection)) return false;
|
|
2411
|
+
if (data.source !== void 0 && event.collection !== data.source.collection) {
|
|
2412
|
+
return false;
|
|
2413
|
+
}
|
|
2414
|
+
if (change !== void 0) {
|
|
2415
|
+
if (!isWebhookCommerceNotificationChange(change)) return false;
|
|
2416
|
+
if (change.sourceCollection !== sourceCollection) return false;
|
|
2417
|
+
if (change.event !== notification.event) return false;
|
|
2418
|
+
if (!matchesOptionalId(change.sourceId, sourceId)) return false;
|
|
2419
|
+
}
|
|
2420
|
+
const changeSourceId = isWebhookCommerceNotificationChange(change) ? change.sourceId : void 0;
|
|
2421
|
+
if (notification.event === "orderPaid" || notification.event === "orderCanceled" || notification.event === "orderDelivered") {
|
|
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);
|
|
2423
|
+
}
|
|
2424
|
+
if (notification.event === "fulfillmentShipped") {
|
|
2425
|
+
return sourceCollection === "fulfillments" && matchesOptionalId(data.fulfillmentId, sourceId) && typeof notification.fulfillmentId === "string" && notification.fulfillmentId.length > 0 && matchesOptionalId(notification.fulfillmentId, sourceId) && matchesOptionalId(data.fulfillmentId, notification.fulfillmentId) && matchesOptionalId(changeSourceId, notification.fulfillmentId);
|
|
2426
|
+
}
|
|
2427
|
+
if (notification.event === "returnRequested" || notification.event === "returnCompleted") {
|
|
2428
|
+
return sourceCollection === "returns" && matchesOptionalId(data.returnId, sourceId) && typeof notification.returnId === "string" && notification.returnId.length > 0 && matchesOptionalId(notification.returnId, sourceId) && matchesOptionalId(data.returnId, notification.returnId) && matchesOptionalId(changeSourceId, notification.returnId);
|
|
2429
|
+
}
|
|
2430
|
+
return false;
|
|
2431
|
+
}
|
|
2432
|
+
function getCommerceNotificationIdempotencyKey(event) {
|
|
2433
|
+
return `${event.notification.intentId}:${event.notification.dedupeKey}`;
|
|
2434
|
+
}
|
|
2435
|
+
function defineCommerceEmailConfig(config) {
|
|
2436
|
+
return config;
|
|
2437
|
+
}
|
|
2438
|
+
function createCommerceEmailWebhookHandler(handlers) {
|
|
2439
|
+
return async (event) => {
|
|
2440
|
+
if (!isCommerceNotificationWebhookEvent(event)) {
|
|
2441
|
+
await handlers.unhandled?.(event);
|
|
2442
|
+
return;
|
|
2443
|
+
}
|
|
2444
|
+
const handler = handlers[event.notification.event];
|
|
2445
|
+
if (!handler) {
|
|
2446
|
+
await handlers.unhandled?.(event);
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2449
|
+
await handler({
|
|
2450
|
+
event,
|
|
2451
|
+
idempotencyKey: getCommerceNotificationIdempotencyKey(event)
|
|
2452
|
+
});
|
|
2453
|
+
};
|
|
2454
|
+
}
|
|
1852
2455
|
function isWebhookCollection(event, collection) {
|
|
1853
2456
|
return isValidWebhookEvent(event) && event.collection === collection;
|
|
1854
2457
|
}
|
|
@@ -1856,7 +2459,7 @@ function isWebhookOperation(event, operation) {
|
|
|
1856
2459
|
return isValidWebhookEvent(event) && event.operation === operation;
|
|
1857
2460
|
}
|
|
1858
2461
|
var CUSTOMER_PASSWORD_RESET_OPERATION = "password-reset";
|
|
1859
|
-
function
|
|
2462
|
+
function isRecord2(value) {
|
|
1860
2463
|
return typeof value === "object" && value !== null;
|
|
1861
2464
|
}
|
|
1862
2465
|
function hasString(value, key) {
|
|
@@ -1866,7 +2469,7 @@ function hasStringOrNumber(value, key) {
|
|
|
1866
2469
|
return typeof value[key] === "string" || typeof value[key] === "number";
|
|
1867
2470
|
}
|
|
1868
2471
|
function isCustomerPasswordResetWebhookEvent(event) {
|
|
1869
|
-
if (event.collection !== "customers" || event.operation !== CUSTOMER_PASSWORD_RESET_OPERATION || !
|
|
2472
|
+
if (event.collection !== "customers" || event.operation !== CUSTOMER_PASSWORD_RESET_OPERATION || !isRecord2(event.data)) {
|
|
1870
2473
|
return false;
|
|
1871
2474
|
}
|
|
1872
2475
|
return hasStringOrNumber(event.data, "customerId") && hasString(event.data, "email") && hasString(event.data, "name") && hasString(event.data, "resetPasswordToken") && hasString(event.data, "resetPasswordExpiresAt");
|
|
@@ -1986,6 +2589,7 @@ var INTERNAL_COLLECTIONS = [
|
|
|
1986
2589
|
"subscriptions",
|
|
1987
2590
|
"billing-history",
|
|
1988
2591
|
"inventory-reservations",
|
|
2592
|
+
"commerce-notification-intents",
|
|
1989
2593
|
"product-collection-items",
|
|
1990
2594
|
"order-status-logs",
|
|
1991
2595
|
"api-keys",
|
|
@@ -2069,6 +2673,7 @@ var COLLECTIONS = [
|
|
|
2069
2673
|
"reaction-types",
|
|
2070
2674
|
"bookmarks",
|
|
2071
2675
|
"post-categories",
|
|
2676
|
+
"post-tags",
|
|
2072
2677
|
"customer-profile-lists",
|
|
2073
2678
|
// Events
|
|
2074
2679
|
"event-calendars",
|
|
@@ -2217,22 +2822,252 @@ var RealtimeConnection = class {
|
|
|
2217
2822
|
}
|
|
2218
2823
|
}
|
|
2219
2824
|
}
|
|
2220
|
-
scheduleReconnect() {
|
|
2221
|
-
if (this.reconnectTimer) return;
|
|
2222
|
-
const delay2 = Math.min(
|
|
2223
|
-
INITIAL_RECONNECT_DELAY * Math.pow(RECONNECT_BACKOFF_FACTOR, this.reconnectAttempt),
|
|
2224
|
-
MAX_RECONNECT_DELAY
|
|
2225
|
-
);
|
|
2226
|
-
this.reconnectAttempt++;
|
|
2227
|
-
this.reconnectTimer = setTimeout(() => {
|
|
2228
|
-
this.reconnectTimer = null;
|
|
2229
|
-
this.abortController = new AbortController();
|
|
2230
|
-
this.startStream(this.abortController.signal);
|
|
2231
|
-
}, 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
|
+
};
|
|
2969
|
+
}
|
|
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
|
+
}
|
|
2232
3000
|
}
|
|
2233
|
-
|
|
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
|
+
}
|
|
2234
3040
|
|
|
2235
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
|
+
}
|
|
2236
3071
|
var ProductSelectionCodecError = class extends Error {
|
|
2237
3072
|
constructor(message) {
|
|
2238
3073
|
super(message);
|
|
@@ -2277,6 +3112,18 @@ function getVariantPrimaryImage(variant) {
|
|
|
2277
3112
|
if (!variant) return null;
|
|
2278
3113
|
return extractEntityId(variant.thumbnail) ?? getFirstMediaId(variant.images);
|
|
2279
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
|
+
}
|
|
2280
3127
|
function getFirstAvailableVariantPrimaryImage(variants) {
|
|
2281
3128
|
const orderedVariants = [...variants].sort(compareVariantOrder);
|
|
2282
3129
|
for (const variant of orderedVariants) {
|
|
@@ -2286,6 +3133,27 @@ function getFirstAvailableVariantPrimaryImage(variants) {
|
|
|
2286
3133
|
}
|
|
2287
3134
|
return null;
|
|
2288
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
|
+
}
|
|
2289
3157
|
function normalizeOptionValue(value, fallbackOptionId, fallbackOptionSlug) {
|
|
2290
3158
|
return {
|
|
2291
3159
|
id: String(value.id),
|
|
@@ -2293,9 +3161,7 @@ function normalizeOptionValue(value, fallbackOptionId, fallbackOptionSlug) {
|
|
|
2293
3161
|
optionSlug: fallbackOptionSlug,
|
|
2294
3162
|
label: value.value || value.slug || String(value.id),
|
|
2295
3163
|
slug: value.slug ?? null,
|
|
2296
|
-
|
|
2297
|
-
thumbnail: value.thumbnail ?? null,
|
|
2298
|
-
images: value.images ?? null,
|
|
3164
|
+
swatch: normalizeProductOptionValueSwatch(value.swatch),
|
|
2299
3165
|
order: value._order ?? value["_product-option-values_values_order"] ?? ""
|
|
2300
3166
|
};
|
|
2301
3167
|
}
|
|
@@ -2401,9 +3267,7 @@ function buildProductOptionMatrixFromDetail(detail) {
|
|
|
2401
3267
|
optionSlug: option.slug,
|
|
2402
3268
|
label: value.value || value.slug || String(value.id),
|
|
2403
3269
|
slug: value.slug,
|
|
2404
|
-
|
|
2405
|
-
thumbnail: value.thumbnail ?? null,
|
|
2406
|
-
images: value.images ?? null,
|
|
3270
|
+
swatch: normalizeProductOptionValueSwatch(value.swatch),
|
|
2407
3271
|
order: matrixOrder(valueIndex)
|
|
2408
3272
|
}))
|
|
2409
3273
|
}));
|
|
@@ -2839,13 +3703,19 @@ function stringifyProductSelection(detail, selection = {}, options) {
|
|
|
2839
3703
|
return params.toString();
|
|
2840
3704
|
}
|
|
2841
3705
|
}
|
|
3706
|
+
const emit = resolveProductSelectionUrlEmit(options?.emit);
|
|
2842
3707
|
for (const optionId of matrix.optionIds) {
|
|
2843
3708
|
const valueId = normalized.byOptionId[optionId];
|
|
2844
3709
|
if (!valueId) continue;
|
|
2845
3710
|
if (!matrix.optionById.has(optionId) || !matrix.valueById.has(valueId)) {
|
|
2846
3711
|
continue;
|
|
2847
3712
|
}
|
|
2848
|
-
|
|
3713
|
+
if (emit === "slug-compat") {
|
|
3714
|
+
if (appendSlugCompatSelectionParam(params, matrix, optionId, valueId)) {
|
|
3715
|
+
continue;
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
appendCanonicalSelectionParam(params, optionId, valueId);
|
|
2849
3719
|
}
|
|
2850
3720
|
return params.toString();
|
|
2851
3721
|
}
|
|
@@ -2884,6 +3754,100 @@ function getExactSelectedVariantEntry(matrix, selection, matchingVariants) {
|
|
|
2884
3754
|
)
|
|
2885
3755
|
) ?? null;
|
|
2886
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
|
+
}
|
|
2887
3851
|
function buildSelectionPrice(variants) {
|
|
2888
3852
|
const { min, max } = getMinMax(variants.map((variant) => variant.price));
|
|
2889
3853
|
const { min: compareAtMin, max: compareAtMax } = getMinMax(
|
|
@@ -2897,38 +3861,51 @@ function buildSelectionPrice(variants) {
|
|
|
2897
3861
|
isRange: min !== null && max !== null ? min !== max : false
|
|
2898
3862
|
};
|
|
2899
3863
|
}
|
|
2900
|
-
function firstMedia(value) {
|
|
2901
|
-
if (value == null) return null;
|
|
2902
|
-
if (Array.isArray(value)) return firstMedia(value[0]);
|
|
2903
|
-
return value;
|
|
2904
|
-
}
|
|
2905
3864
|
function isPresentMedia(value) {
|
|
2906
3865
|
return value != null;
|
|
2907
3866
|
}
|
|
2908
|
-
function
|
|
3867
|
+
function mediaArray2(values) {
|
|
2909
3868
|
if (!Array.isArray(values)) return [];
|
|
2910
3869
|
return values.filter(isPresentMedia);
|
|
2911
3870
|
}
|
|
2912
3871
|
function buildSelectionMedia(detail, selectedVariant, matchingVariants, selectedValues) {
|
|
2913
|
-
const
|
|
2914
|
-
const
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
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" };
|
|
2932
3909
|
}
|
|
2933
3910
|
function buildSelectionStock(selectedVariant, matchingVariants) {
|
|
2934
3911
|
if (selectedVariant) {
|
|
@@ -2951,7 +3928,9 @@ function buildSelectionStock(selectedVariant, matchingVariants) {
|
|
|
2951
3928
|
};
|
|
2952
3929
|
}
|
|
2953
3930
|
function buildAvailableValueStock(variants) {
|
|
2954
|
-
const activeVariants = variants.filter(
|
|
3931
|
+
const activeVariants = variants.filter(
|
|
3932
|
+
(variant) => variant.isActive !== false
|
|
3933
|
+
);
|
|
2955
3934
|
const isUnlimited = activeVariants.some((variant) => variant.isUnlimited);
|
|
2956
3935
|
const availableStock = isUnlimited ? null : activeVariants.reduce(
|
|
2957
3936
|
(sum, variant) => sum + Math.max(0, variant.stock - variant.reservedStock),
|
|
@@ -2963,6 +3942,19 @@ function buildAvailableValueStock(variants) {
|
|
|
2963
3942
|
availableStock
|
|
2964
3943
|
};
|
|
2965
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
|
+
}
|
|
2966
3958
|
function getCandidateVariantsForValue(matrix, optionId, valueId, selectedValueIds) {
|
|
2967
3959
|
const selectedByOption = getSelectedValueByOptionId(matrix, selectedValueIds);
|
|
2968
3960
|
selectedByOption.set(optionId, valueId);
|
|
@@ -2975,17 +3967,25 @@ function getCandidateVariantsForValue(matrix, optionId, valueId, selectedValueId
|
|
|
2975
3967
|
function getResolutionContext(context) {
|
|
2976
3968
|
return {
|
|
2977
3969
|
images: context?.images ?? context?.detail?.images ?? [],
|
|
2978
|
-
listing: context?.listing ?? context?.detail?.listing ?? {}
|
|
3970
|
+
listing: context?.listing ?? context?.detail?.listing ?? {},
|
|
3971
|
+
primaryMediaItemId: context?.primaryMediaItemId ?? context?.detail?.primaryMediaItemId ?? null
|
|
2979
3972
|
};
|
|
2980
3973
|
}
|
|
2981
3974
|
function resolveProductSelectionFromMatrix(matrix, selection = {}, options, context) {
|
|
2982
|
-
const { images, listing } = getResolutionContext(context);
|
|
3975
|
+
const { images, listing, primaryMediaItemId } = getResolutionContext(context);
|
|
2983
3976
|
const effectiveSelection = hasExplicitSelection(selection) || listing.selectionHintVariant == null ? selection : { ...selection, variantId: listing.selectionHintVariant };
|
|
2984
|
-
|
|
3977
|
+
let normalizedSelection = normalizeProductSelectionFromMatrix(
|
|
2985
3978
|
matrix,
|
|
2986
3979
|
effectiveSelection,
|
|
2987
3980
|
options
|
|
2988
3981
|
);
|
|
3982
|
+
if (options?.fillDefaults) {
|
|
3983
|
+
normalizedSelection = buildFilledNormalizedSelection(
|
|
3984
|
+
matrix,
|
|
3985
|
+
normalizedSelection,
|
|
3986
|
+
listing
|
|
3987
|
+
);
|
|
3988
|
+
}
|
|
2989
3989
|
const matchingVariantEntries = getMatchingVariantEntries(
|
|
2990
3990
|
matrix,
|
|
2991
3991
|
normalizedSelection
|
|
@@ -3014,24 +4014,22 @@ function resolveProductSelectionFromMatrix(matrix, selection = {}, options, cont
|
|
|
3014
4014
|
);
|
|
3015
4015
|
return [
|
|
3016
4016
|
option.id,
|
|
3017
|
-
option.values.map(
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
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
|
+
)
|
|
3029
4030
|
)
|
|
3030
|
-
)
|
|
3031
|
-
|
|
3032
|
-
thumbnail: value.thumbnail ?? null,
|
|
3033
|
-
images: value.images ?? null
|
|
3034
|
-
}))
|
|
4031
|
+
)
|
|
4032
|
+
)
|
|
3035
4033
|
];
|
|
3036
4034
|
})
|
|
3037
4035
|
);
|
|
@@ -3059,7 +4057,8 @@ function resolveProductSelectionFromMatrix(matrix, selection = {}, options, cont
|
|
|
3059
4057
|
images,
|
|
3060
4058
|
listing: {
|
|
3061
4059
|
primaryImage: listing.primaryImage ?? null
|
|
3062
|
-
}
|
|
4060
|
+
},
|
|
4061
|
+
primaryMediaItemId
|
|
3063
4062
|
},
|
|
3064
4063
|
selectedVariant,
|
|
3065
4064
|
matchingVariants,
|
|
@@ -3074,6 +4073,78 @@ function resolveProductSelection(detail, selection = {}, options) {
|
|
|
3074
4073
|
detail
|
|
3075
4074
|
});
|
|
3076
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
|
+
}
|
|
3077
4148
|
function isProductDetailImageMedia(value) {
|
|
3078
4149
|
return typeof value === "object" && value !== null;
|
|
3079
4150
|
}
|
|
@@ -3114,18 +4185,47 @@ function joinProductPath(basePath, slug, trailingSlash) {
|
|
|
3114
4185
|
function getProductHrefGroupSelection(group, matrix) {
|
|
3115
4186
|
if (!group) return null;
|
|
3116
4187
|
if (group.variantId != null) return { variantId: group.variantId };
|
|
3117
|
-
const listingVariantId = group.listing?.selectionHintVariant;
|
|
3118
4188
|
const optionId = group.optionId != null ? String(group.optionId) : group.optionSlug ? matrix?.optionBySlug.get(group.optionSlug)?.id : void 0;
|
|
3119
|
-
if (!optionId)
|
|
3120
|
-
return listingVariantId != null ? { variantId: listingVariantId } : null;
|
|
3121
|
-
}
|
|
4189
|
+
if (!optionId) return null;
|
|
3122
4190
|
const option = matrix?.optionById.get(optionId);
|
|
3123
4191
|
const optionValueId = group.optionValueId != null ? String(group.optionValueId) : group.optionValueSlug && option ? option.values.find((value) => value.slug === group.optionValueSlug)?.id : void 0;
|
|
3124
|
-
if (!optionValueId)
|
|
3125
|
-
return listingVariantId != null ? { variantId: listingVariantId } : null;
|
|
3126
|
-
}
|
|
4192
|
+
if (!optionValueId) return null;
|
|
3127
4193
|
return { byOptionId: { [optionId]: optionValueId } };
|
|
3128
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
|
+
}
|
|
3129
4229
|
function buildProductHref(product, group, options = {}) {
|
|
3130
4230
|
const path = joinProductPath(
|
|
3131
4231
|
options.basePath ?? "/products",
|
|
@@ -3134,23 +4234,46 @@ function buildProductHref(product, group, options = {}) {
|
|
|
3134
4234
|
);
|
|
3135
4235
|
const params = new URLSearchParams();
|
|
3136
4236
|
if (options.detail && options.selection) {
|
|
3137
|
-
const selection = stringifyProductSelection(
|
|
4237
|
+
const selection = stringifyProductSelection(
|
|
4238
|
+
options.detail,
|
|
4239
|
+
options.selection,
|
|
4240
|
+
getProductHrefCodecOptions(options)
|
|
4241
|
+
);
|
|
3138
4242
|
return selection ? `${path}?${selection}` : path;
|
|
3139
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
|
+
}
|
|
3140
4262
|
const groupSelection = getProductHrefGroupSelection(group, options.matrix);
|
|
3141
4263
|
if (groupSelection) {
|
|
3142
4264
|
if (options.detail) {
|
|
3143
|
-
const selection = stringifyProductSelection(
|
|
4265
|
+
const selection = stringifyProductSelection(
|
|
4266
|
+
options.detail,
|
|
4267
|
+
groupSelection,
|
|
4268
|
+
getProductHrefCodecOptions(options)
|
|
4269
|
+
);
|
|
3144
4270
|
return selection ? `${path}?${selection}` : path;
|
|
3145
4271
|
}
|
|
3146
4272
|
if (groupSelection.variantId != null) {
|
|
3147
4273
|
params.set("variant", String(groupSelection.variantId));
|
|
3148
4274
|
return `${path}?${params.toString()}`;
|
|
3149
4275
|
}
|
|
3150
|
-
|
|
3151
|
-
if (selectionEntry) {
|
|
3152
|
-
const [optionId, valueId] = selectionEntry;
|
|
3153
|
-
params.set(`opt.${optionId}`, String(valueId));
|
|
4276
|
+
if (appendGroupByOptionIdHrefParams(params, group, groupSelection, options)) {
|
|
3154
4277
|
return `${path}?${params.toString()}`;
|
|
3155
4278
|
}
|
|
3156
4279
|
}
|
|
@@ -3177,6 +4300,26 @@ function isVariantAvailableForSale(variant) {
|
|
|
3177
4300
|
if (variant.isUnlimited) return true;
|
|
3178
4301
|
return (variant.stock ?? 0) - (variant.reservedStock ?? 0) > 0;
|
|
3179
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
|
+
}
|
|
3180
4323
|
function getMinMax(values) {
|
|
3181
4324
|
const numbers = values.filter(
|
|
3182
4325
|
(value) => typeof value === "number"
|
|
@@ -3202,11 +4345,28 @@ function buildProductListingProjection(product, variants) {
|
|
|
3202
4345
|
const { min: minCompareAtPrice, max: maxCompareAtPrice } = getMinMax(
|
|
3203
4346
|
activeVariants.map((variant) => variant.compareAtPrice)
|
|
3204
4347
|
);
|
|
3205
|
-
const
|
|
3206
|
-
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
|
+
});
|
|
3207
4363
|
return {
|
|
3208
4364
|
selectionHintVariant: getRelationID(selectionHintVariant?.id) ?? null,
|
|
3209
|
-
primaryImage:
|
|
4365
|
+
primaryImage: resolveGenericListingPrimaryImage(
|
|
4366
|
+
product,
|
|
4367
|
+
resolvedProductMedia.primaryImage,
|
|
4368
|
+
resolvedProductMedia.source
|
|
4369
|
+
),
|
|
3210
4370
|
minPrice,
|
|
3211
4371
|
maxPrice,
|
|
3212
4372
|
minCompareAtPrice,
|
|
@@ -3218,7 +4378,40 @@ function buildProductListingProjection(product, variants) {
|
|
|
3218
4378
|
function buildProductListingCard(item, options = {}) {
|
|
3219
4379
|
const product = item.product;
|
|
3220
4380
|
const groups = item.groups;
|
|
3221
|
-
const
|
|
4381
|
+
const variants = getProductListingCardVariants(item);
|
|
4382
|
+
const projectedListing = buildProductListingProjection(product, variants);
|
|
4383
|
+
const selectionHintVariant = getRelationID(product.listing?.selectionHintVariant) ?? projectedListing.selectionHintVariant;
|
|
4384
|
+
const representativeVariant = findListingCardRepresentativeVariant(
|
|
4385
|
+
variants,
|
|
4386
|
+
selectionHintVariant
|
|
4387
|
+
);
|
|
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;
|
|
3222
4415
|
const priceRange = aggregateListingPriceRange(groups);
|
|
3223
4416
|
const availableForSale = groups.some(
|
|
3224
4417
|
(group) => group.listing.availableForSale
|
|
@@ -3226,14 +4419,42 @@ function buildProductListingCard(item, options = {}) {
|
|
|
3226
4419
|
const swatches = groups.length > 1 ? groups.map((group) => buildListingSwatch(product, group, options)) : [];
|
|
3227
4420
|
return {
|
|
3228
4421
|
id: String(product.id),
|
|
3229
|
-
href: buildProductHref(
|
|
4422
|
+
href: buildProductHref(
|
|
4423
|
+
{ slug: product.slug },
|
|
4424
|
+
{ listing: { selectionHintVariant } },
|
|
4425
|
+
options
|
|
4426
|
+
),
|
|
3230
4427
|
title: product.title,
|
|
3231
|
-
|
|
4428
|
+
representativeVariant,
|
|
4429
|
+
primaryImage: listingPrimaryMedia,
|
|
3232
4430
|
priceRange,
|
|
3233
4431
|
availableForSale,
|
|
3234
4432
|
swatches
|
|
3235
4433
|
};
|
|
3236
4434
|
}
|
|
4435
|
+
function getProductListingCardVariants(item) {
|
|
4436
|
+
const productVariants = item.product.variants?.docs;
|
|
4437
|
+
if (Array.isArray(productVariants) && productVariants.length > 0) {
|
|
4438
|
+
return productVariants;
|
|
4439
|
+
}
|
|
4440
|
+
const variants = [];
|
|
4441
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4442
|
+
for (const group of item.groups) {
|
|
4443
|
+
for (const variant of group.variants) {
|
|
4444
|
+
const id = getRelationID(variant.id);
|
|
4445
|
+
if (id && seen.has(id)) continue;
|
|
4446
|
+
if (id) seen.add(id);
|
|
4447
|
+
variants.push(variant);
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
return variants;
|
|
4451
|
+
}
|
|
4452
|
+
function findListingCardRepresentativeVariant(variants, representativeVariantId) {
|
|
4453
|
+
if (representativeVariantId == null) return null;
|
|
4454
|
+
return variants.find(
|
|
4455
|
+
(variant) => getRelationID(variant.id) === representativeVariantId
|
|
4456
|
+
) ?? null;
|
|
4457
|
+
}
|
|
3237
4458
|
function aggregateListingPriceRange(groups) {
|
|
3238
4459
|
const minPrice = minOfNullable(groups.map((g) => g.listing.minPrice));
|
|
3239
4460
|
const maxPrice = maxOfNullable(groups.map((g) => g.listing.maxPrice));
|
|
@@ -3253,17 +4474,16 @@ function aggregateListingPriceRange(groups) {
|
|
|
3253
4474
|
};
|
|
3254
4475
|
}
|
|
3255
4476
|
function buildListingSwatch(product, group, options) {
|
|
3256
|
-
const thumbnail = firstMedia(group.optionValueThumbnail) ?? firstMedia(group.optionValueImages) ?? null;
|
|
3257
4477
|
return {
|
|
3258
4478
|
optionId: group.optionId,
|
|
3259
4479
|
optionValueId: group.optionValueId,
|
|
3260
4480
|
label: group.optionValueLabel,
|
|
3261
|
-
|
|
3262
|
-
thumbnail,
|
|
4481
|
+
swatch: group.optionValueSwatch ?? null,
|
|
3263
4482
|
href: buildProductHref(
|
|
3264
4483
|
{ slug: product.slug },
|
|
3265
4484
|
{
|
|
3266
4485
|
optionId: group.optionId,
|
|
4486
|
+
optionSlug: group.optionSlug,
|
|
3267
4487
|
optionValueId: group.optionValueId,
|
|
3268
4488
|
optionValueSlug: group.optionValueSlug,
|
|
3269
4489
|
listing: group.listing
|
|
@@ -3298,19 +4518,34 @@ function buildProductListingGroupsByOption(args) {
|
|
|
3298
4518
|
return [];
|
|
3299
4519
|
}
|
|
3300
4520
|
const listingBase = buildProductListingProjection(void 0, variants);
|
|
3301
|
-
const
|
|
3302
|
-
const
|
|
3303
|
-
|
|
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);
|
|
3304
4540
|
return [
|
|
3305
4541
|
{
|
|
3306
4542
|
optionId: primaryOption.id,
|
|
3307
4543
|
optionTitle: primaryOption.title,
|
|
4544
|
+
optionSlug: primaryOption.slug,
|
|
3308
4545
|
optionValueId: value.id,
|
|
3309
4546
|
optionValueLabel: value.label,
|
|
3310
4547
|
optionValueSlug: value.slug,
|
|
3311
|
-
|
|
3312
|
-
optionValueThumbnail: value.thumbnail ?? null,
|
|
3313
|
-
optionValueImages: value.images ?? null,
|
|
4548
|
+
optionValueSwatch: value.swatch ?? null,
|
|
3314
4549
|
variantIds: variants.map((variant) => String(variant.id)),
|
|
3315
4550
|
variantCount: variants.length,
|
|
3316
4551
|
variants,
|
|
@@ -3323,6 +4558,162 @@ function buildProductListingGroupsByOption(args) {
|
|
|
3323
4558
|
});
|
|
3324
4559
|
}
|
|
3325
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
|
+
|
|
3326
4717
|
// src/utils/image.ts
|
|
3327
4718
|
var IMAGE_SIZES = [384, 768, 1536];
|
|
3328
4719
|
function getImageUrl(image, displayWidth, dpr = 1) {
|