@01.software/sdk 0.33.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.
Files changed (70) hide show
  1. package/README.md +214 -22
  2. package/dist/analytics/react.cjs.map +1 -1
  3. package/dist/analytics/react.js.map +1 -1
  4. package/dist/analytics.cjs.map +1 -1
  5. package/dist/analytics.js.map +1 -1
  6. package/dist/client.cjs +341 -26
  7. package/dist/client.cjs.map +1 -1
  8. package/dist/client.d.cts +7 -6
  9. package/dist/client.d.ts +7 -6
  10. package/dist/client.js +341 -26
  11. package/dist/client.js.map +1 -1
  12. package/dist/{collection-client-De6eKW1J.d.cts → collection-client-CR2B8c1v.d.cts} +7 -3
  13. package/dist/{collection-client-B6SlhzIP.d.ts → collection-client-DkREjhQ9.d.ts} +7 -3
  14. package/dist/{const-sPR2IkCe.d.cts → const-BTvdrXtY.d.cts} +4 -4
  15. package/dist/{const-DwmSDeWq.d.ts → const-CdqCauHQ.d.ts} +4 -4
  16. package/dist/index-CjA3U6X3.d.cts +186 -0
  17. package/dist/index-DK8_NXkh.d.ts +186 -0
  18. package/dist/index.cjs +1401 -176
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +74 -9
  21. package/dist/index.d.ts +74 -9
  22. package/dist/index.js +1401 -176
  23. package/dist/index.js.map +1 -1
  24. package/dist/{payload-types-dkeQyrDC.d.cts → payload-types-C7tb7Xbs.d.cts} +208 -52
  25. package/dist/{payload-types-dkeQyrDC.d.ts → payload-types-C7tb7Xbs.d.ts} +208 -52
  26. package/dist/query.cjs +194 -35
  27. package/dist/query.cjs.map +1 -1
  28. package/dist/query.d.cts +44 -17
  29. package/dist/query.d.ts +44 -17
  30. package/dist/query.js +194 -35
  31. package/dist/query.js.map +1 -1
  32. package/dist/realtime.cjs.map +1 -1
  33. package/dist/realtime.d.cts +2 -2
  34. package/dist/realtime.d.ts +2 -2
  35. package/dist/realtime.js.map +1 -1
  36. package/dist/{server-CrsPyqEc.d.cts → server-nXOezi4b.d.cts} +22 -6
  37. package/dist/{server-CrsPyqEc.d.ts → server-nXOezi4b.d.ts} +22 -6
  38. package/dist/server.cjs +439 -32
  39. package/dist/server.cjs.map +1 -1
  40. package/dist/server.d.cts +11 -179
  41. package/dist/server.d.ts +11 -179
  42. package/dist/server.js +439 -32
  43. package/dist/server.js.map +1 -1
  44. package/dist/{types-Cel_4L9t.d.ts → types-1ylMrCuW.d.ts} +1 -1
  45. package/dist/{types-B3YT092I.d.cts → types-Bx558PU6.d.cts} +1 -1
  46. package/dist/{types-BHh0YLmq.d.ts → types-Byo_Rty4.d.ts} +705 -69
  47. package/dist/{types-BZKxss8Y.d.cts → types-DDhtZI6E.d.cts} +705 -69
  48. package/dist/ui/canvas/server.cjs +231 -38
  49. package/dist/ui/canvas/server.cjs.map +1 -1
  50. package/dist/ui/canvas/server.d.cts +1 -1
  51. package/dist/ui/canvas/server.d.ts +1 -1
  52. package/dist/ui/canvas/server.js +221 -38
  53. package/dist/ui/canvas/server.js.map +1 -1
  54. package/dist/ui/canvas.cjs +320 -257
  55. package/dist/ui/canvas.cjs.map +1 -1
  56. package/dist/ui/canvas.d.cts +5 -19
  57. package/dist/ui/canvas.d.ts +5 -19
  58. package/dist/ui/canvas.js +323 -260
  59. package/dist/ui/canvas.js.map +1 -1
  60. package/dist/ui/form.d.cts +1 -1
  61. package/dist/ui/form.d.ts +1 -1
  62. package/dist/ui/video.d.cts +1 -1
  63. package/dist/ui/video.d.ts +1 -1
  64. package/dist/webhook.cjs +2 -1
  65. package/dist/webhook.cjs.map +1 -1
  66. package/dist/webhook.d.cts +20 -179
  67. package/dist/webhook.d.ts +20 -179
  68. package/dist/webhook.js +2 -1
  69. package/dist/webhook.js.map +1 -1
  70. package/package.json +4 -5
package/dist/index.js CHANGED
@@ -253,9 +253,12 @@ function resolveApiUrl(apiUrl) {
253
253
 
254
254
  // src/core/internal/utils/http.ts
255
255
  var DEFAULT_TIMEOUT = 3e4;
256
+ var STOREFRONT_BROWSER_TIMEOUT = 15e3;
256
257
  var DEFAULT_RETRYABLE_STATUSES = [408, 429, 500, 502, 503, 504];
257
258
  var NON_RETRYABLE_STATUSES = [400, 401, 403, 404, 409, 422];
258
259
  var SAFE_METHODS = ["GET", "HEAD", "OPTIONS"];
260
+ var DEFAULT_MAX_RETRIES = 3;
261
+ var STOREFRONT_BROWSER_MAX_RETRIES = 1;
259
262
  function debugLog(debug, type, message, data) {
260
263
  if (!debug) return;
261
264
  const shouldLog = debug === true || type === "request" && debug.logRequests || type === "response" && debug.logResponses || type === "error" && debug.logErrors;
@@ -448,15 +451,18 @@ async function httpFetch(url, options) {
448
451
  publishableKey,
449
452
  secretKey,
450
453
  customerToken,
451
- timeout = DEFAULT_TIMEOUT,
454
+ timeout: timeoutOption = DEFAULT_TIMEOUT,
452
455
  debug,
453
456
  retry,
454
457
  onUnauthorized,
455
458
  ...requestInit
456
459
  } = options || {};
457
460
  const baseUrl = resolveApiUrl(apiUrl);
461
+ const method = (requestInit.method || "GET").toUpperCase();
462
+ const isPublishableKeyBrowserGet = typeof window !== "undefined" && !secretKey && !customerToken && Boolean(publishableKey) && SAFE_METHODS.includes(method);
463
+ const timeout = timeoutOption === DEFAULT_TIMEOUT && isPublishableKeyBrowserGet ? STOREFRONT_BROWSER_TIMEOUT : timeoutOption;
458
464
  const retryConfig = {
459
- maxRetries: retry?.maxRetries ?? 3,
465
+ maxRetries: retry?.maxRetries ?? (isPublishableKeyBrowserGet ? STOREFRONT_BROWSER_MAX_RETRIES : DEFAULT_MAX_RETRIES),
460
466
  retryableStatuses: retry?.retryableStatuses ?? DEFAULT_RETRYABLE_STATUSES,
461
467
  retryDelay: retry?.retryDelay ?? ((attempt) => Math.min(1e3 * 2 ** attempt, 1e4))
462
468
  };
@@ -564,8 +570,8 @@ async function httpFetch(url, options) {
564
570
  ),
565
571
  requestId
566
572
  );
567
- const method = (requestInit.method || "GET").toUpperCase();
568
- if (attempt < retryConfig.maxRetries && SAFE_METHODS.includes(method) && retryConfig.retryableStatuses.includes(response.status)) {
573
+ const method2 = (requestInit.method || "GET").toUpperCase();
574
+ if (attempt < retryConfig.maxRetries && SAFE_METHODS.includes(method2) && retryConfig.retryableStatuses.includes(response.status)) {
569
575
  lastError = error;
570
576
  const retryDelay = retryConfig.retryDelay(attempt);
571
577
  debugLog(debug, "error", `Retrying in ${retryDelay}ms...`, error);
@@ -577,8 +583,8 @@ async function httpFetch(url, options) {
577
583
  return response;
578
584
  } catch (error) {
579
585
  debugLog(debug, "error", url, error);
580
- const method = (requestInit.method || "GET").toUpperCase();
581
- const isSafe = SAFE_METHODS.includes(method);
586
+ const method2 = (requestInit.method || "GET").toUpperCase();
587
+ const isSafe = SAFE_METHODS.includes(method2);
582
588
  if (error instanceof Error && error.name === "AbortError") {
583
589
  const timeoutError = createTimeoutError(
584
590
  `Request timed out after ${timeout}ms.`,
@@ -637,6 +643,35 @@ async function httpFetch(url, options) {
637
643
  throw lastError ?? new NetworkError("Request failed after retries");
638
644
  }
639
645
 
646
+ // src/core/internal/utils/query-string.ts
647
+ function productDetailQuery(params) {
648
+ const search = new URLSearchParams();
649
+ if ("slug" in params) {
650
+ search.set("slug", params.slug);
651
+ } else {
652
+ search.set("id", params.id);
653
+ }
654
+ return `/api/products/detail?${search}`;
655
+ }
656
+ function productDetailCatalogQuery(params) {
657
+ const search = new URLSearchParams();
658
+ if ("slug" in params) {
659
+ search.set("slug", params.slug);
660
+ } else {
661
+ search.set("id", params.id);
662
+ }
663
+ return `/api/products/detail/catalog?${search}`;
664
+ }
665
+ function listingGroupsQuery(params) {
666
+ return `/api/products/listing-groups?ids=${params.productIds.map(encodeURIComponent).join(",")}`;
667
+ }
668
+ function listingGroupsCatalogQuery(params) {
669
+ return `/api/products/listing-groups/catalog?ids=${params.productIds.map(encodeURIComponent).join(",")}`;
670
+ }
671
+ function stockSnapshotQuery(params) {
672
+ return `/api/products/stock?variantIds=${params.variantIds.map(encodeURIComponent).join(",")}`;
673
+ }
674
+
640
675
  // src/core/collection/http-client.ts
641
676
  var HttpClient = class {
642
677
  constructor(publishableKey, secretKey, getCustomerToken, onUnauthorized, onRequestId, apiUrl) {
@@ -955,6 +990,8 @@ async function parseApiResponse(response, endpoint) {
955
990
  }
956
991
 
957
992
  // src/core/community/community-client.ts
993
+ var DEFAULT_POST_LIST_SORT = "-lastActivityAt";
994
+ var DEFAULT_COMMENT_LIST_SORT = "-createdAt";
958
995
  var CommunityClient = class {
959
996
  constructor(options) {
960
997
  this.publishableKey = requirePublishableKeyForSecret(
@@ -973,6 +1010,40 @@ var CommunityClient = class {
973
1010
  const entries = Object.entries(params).filter((e) => e[1] !== void 0).map(([k, v]) => [k, String(v)]);
974
1011
  return entries.length ? `?${new URLSearchParams(entries).toString()}` : "";
975
1012
  }
1013
+ buildPostsListQuery(params) {
1014
+ const urlParams = new URLSearchParams();
1015
+ const sort = params?.sort ?? DEFAULT_POST_LIST_SORT;
1016
+ urlParams.set("sort", sort);
1017
+ if (params?.limit !== void 0) urlParams.set("limit", String(params.limit));
1018
+ if (params?.page !== void 0) urlParams.set("page", String(params.page));
1019
+ if (params?.categoryId !== void 0) {
1020
+ urlParams.set("where[categories][in]", params.categoryId);
1021
+ }
1022
+ if (params?.tagId !== void 0) {
1023
+ urlParams.set("where[tags][in]", params.tagId);
1024
+ }
1025
+ return `/api/posts?${urlParams.toString()}`;
1026
+ }
1027
+ buildCommentsListQuery(params) {
1028
+ const urlParams = new URLSearchParams();
1029
+ const sort = params.sort ?? DEFAULT_COMMENT_LIST_SORT;
1030
+ urlParams.set("sort", sort);
1031
+ if (params.postId !== void 0) {
1032
+ urlParams.set("where[post][equals]", params.postId);
1033
+ }
1034
+ if (params.parentId !== void 0) {
1035
+ urlParams.set("where[parent][equals]", params.parentId);
1036
+ }
1037
+ if (params.rootComment !== void 0) {
1038
+ urlParams.set("where[rootComment][equals]", params.rootComment);
1039
+ }
1040
+ if (params.topLevelOnly) {
1041
+ urlParams.set("where[parent][exists]", "false");
1042
+ }
1043
+ if (params.limit !== void 0) urlParams.set("limit", String(params.limit));
1044
+ if (params.page !== void 0) urlParams.set("page", String(params.page));
1045
+ return `/api/comments?${urlParams.toString()}`;
1046
+ }
976
1047
  async execute(endpoint, method, body) {
977
1048
  const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
978
1049
  try {
@@ -996,6 +1067,28 @@ var CommunityClient = class {
996
1067
  createPost(params) {
997
1068
  return this.execute("/api/posts", "POST", params);
998
1069
  }
1070
+ /**
1071
+ * Public post feed. Server applies the same visibility contract as
1072
+ * `communityPostRead` (published + visible + moderation-safe).
1073
+ */
1074
+ listPosts(params) {
1075
+ return this.execute(
1076
+ this.buildPostsListQuery(params),
1077
+ "GET"
1078
+ );
1079
+ }
1080
+ listPostCategories(params) {
1081
+ return this.execute(
1082
+ `/api/post-categories${this.buildQuery(params)}`,
1083
+ "GET"
1084
+ );
1085
+ }
1086
+ listPostTags(params) {
1087
+ return this.execute(
1088
+ `/api/post-tags${this.buildQuery(params)}`,
1089
+ "GET"
1090
+ );
1091
+ }
999
1092
  getMyPosts(params) {
1000
1093
  return this.execute(
1001
1094
  `/api/posts/my${this.buildQuery(params)}`,
@@ -1031,16 +1124,37 @@ var CommunityClient = class {
1031
1124
  }
1032
1125
  return this.execute("/api/comments", "POST", body);
1033
1126
  }
1127
+ /**
1128
+ * List comments for a post.
1129
+ *
1130
+ * - Default: all visible comments on the post (any depth).
1131
+ * - `topLevelOnly: true`: only root comments (`parent` unset).
1132
+ * - `rootComment`: comments belonging to a thread rooted at that comment.
1133
+ */
1034
1134
  listComments(params) {
1035
- const { postId, page, limit, rootComment } = params;
1036
- const urlParams = new URLSearchParams();
1037
- urlParams.set("where[post][equals]", postId);
1038
- urlParams.set("sort", "-createdAt");
1039
- if (limit !== void 0) urlParams.set("limit", String(limit));
1040
- if (page !== void 0) urlParams.set("page", String(page));
1041
- if (rootComment !== void 0) urlParams.set("where[rootComment][equals]", rootComment);
1135
+ const { postId, page, limit, rootComment, topLevelOnly, sort } = params;
1136
+ return this.execute(
1137
+ this.buildCommentsListQuery({
1138
+ postId,
1139
+ page,
1140
+ limit,
1141
+ rootComment,
1142
+ topLevelOnly,
1143
+ sort
1144
+ }),
1145
+ "GET"
1146
+ );
1147
+ }
1148
+ /** Direct replies to a comment (`where[parent][equals]`). */
1149
+ listReplies(params) {
1150
+ const { commentId, page, limit, sort } = params;
1042
1151
  return this.execute(
1043
- `/api/comments?${urlParams.toString()}`,
1152
+ this.buildCommentsListQuery({
1153
+ parentId: commentId,
1154
+ page,
1155
+ limit,
1156
+ sort
1157
+ }),
1044
1158
  "GET"
1045
1159
  );
1046
1160
  }
@@ -1068,10 +1182,18 @@ var CommunityClient = class {
1068
1182
  }
1069
1183
  // Reactions
1070
1184
  addReaction(params) {
1071
- const { postId, type } = params;
1185
+ const { postId, typeSlug, type } = params;
1186
+ const reactionType = typeSlug ?? type;
1187
+ if (!reactionType) {
1188
+ throw new SDKError(
1189
+ "validation_failed",
1190
+ "addReaction requires typeSlug (or deprecated type)",
1191
+ 400
1192
+ );
1193
+ }
1072
1194
  return this.execute("/api/reactions", "POST", {
1073
1195
  post: postId,
1074
- type
1196
+ type: reactionType
1075
1197
  });
1076
1198
  }
1077
1199
  removeReaction(params) {
@@ -1082,10 +1204,18 @@ var CommunityClient = class {
1082
1204
  );
1083
1205
  }
1084
1206
  addCommentReaction(params) {
1085
- const { commentId, type } = params;
1207
+ const { commentId, typeSlug, type } = params;
1208
+ const reactionType = typeSlug ?? type;
1209
+ if (!reactionType) {
1210
+ throw new SDKError(
1211
+ "validation_failed",
1212
+ "addCommentReaction requires typeSlug (or deprecated type)",
1213
+ 400
1214
+ );
1215
+ }
1086
1216
  return this.execute("/api/reactions", "POST", {
1087
1217
  comment: commentId,
1088
- type
1218
+ type: reactionType
1089
1219
  });
1090
1220
  }
1091
1221
  removeCommentReaction(params) {
@@ -1101,6 +1231,12 @@ var CommunityClient = class {
1101
1231
  "GET"
1102
1232
  );
1103
1233
  }
1234
+ getCommentReactionSummary(params) {
1235
+ return this.execute(
1236
+ `/api/comments/${params.commentId}/reactions`,
1237
+ "GET"
1238
+ );
1239
+ }
1104
1240
  getReactionTypes() {
1105
1241
  return this.execute(
1106
1242
  "/api/reaction-types?limit=100",
@@ -1125,6 +1261,25 @@ var CommunityClient = class {
1125
1261
  "GET"
1126
1262
  );
1127
1263
  }
1264
+ // Profiles
1265
+ listProfileLists(params) {
1266
+ return this.execute(
1267
+ `/api/customer-profile-lists${this.buildQuery(params)}`,
1268
+ "GET"
1269
+ );
1270
+ }
1271
+ async getProfileList(params) {
1272
+ const query = "slug" in params ? `?where[slug][equals]=${encodeURIComponent(params.slug)}&limit=1` : `?where[id][equals]=${encodeURIComponent(params.id)}&limit=1`;
1273
+ const res = await this.execute(`/api/customer-profile-lists${query}`, "GET");
1274
+ return res.docs[0] ?? null;
1275
+ }
1276
+ updatePublicProfile(body) {
1277
+ return this.execute(
1278
+ "/api/customers/me/profile",
1279
+ "PATCH",
1280
+ body
1281
+ );
1282
+ }
1128
1283
  };
1129
1284
 
1130
1285
  // src/core/customer/customer-auth.ts
@@ -1469,6 +1624,45 @@ function productDetailResultFromError(error) {
1469
1624
  if (!reason) return void 0;
1470
1625
  return { found: false, reason };
1471
1626
  }
1627
+ function rejectLegacyOptionValueSwatchColor(value) {
1628
+ if (Object.prototype.hasOwnProperty.call(
1629
+ value,
1630
+ "swatchColor"
1631
+ )) {
1632
+ throw new TypeError(
1633
+ 'Product upsert option values no longer accept legacy flat "swatchColor"; use nested "swatch" instead.'
1634
+ );
1635
+ }
1636
+ }
1637
+ function normalizeProductUpsertOptionValue(value) {
1638
+ rejectLegacyOptionValueSwatchColor(value);
1639
+ return value;
1640
+ }
1641
+ function normalizeProductUpsertParams(params) {
1642
+ const options = params.options ?? [];
1643
+ const variants = params.variants ?? [];
1644
+ if (!options.length) {
1645
+ return { ...params, options, variants };
1646
+ }
1647
+ return {
1648
+ ...params,
1649
+ options: options.map((option) => ({
1650
+ ...option,
1651
+ values: option.values.map(
1652
+ (value) => normalizeProductUpsertOptionValue(value)
1653
+ )
1654
+ })),
1655
+ variants
1656
+ };
1657
+ }
1658
+ var PRODUCT_UPSERT_UNKNOWN_FIELD_REASON = "unknown_field";
1659
+ var PRODUCT_UPSERT_READONLY_FIELD_REASON = "product_field_readonly";
1660
+ function isProductUpsertFieldValidationErrorBody(value) {
1661
+ if (typeof value !== "object" || value === null) return false;
1662
+ const body = value;
1663
+ const reason = body.reason;
1664
+ return typeof body.error === "string" && typeof body.field === "string" && (reason === PRODUCT_UPSERT_UNKNOWN_FIELD_REASON || reason === PRODUCT_UPSERT_READONLY_FIELD_REASON);
1665
+ }
1472
1666
  var ProductApi = class extends BaseApi {
1473
1667
  constructor(options) {
1474
1668
  super("ProductApi", options);
@@ -1481,10 +1675,25 @@ var ProductApi = class extends BaseApi {
1481
1675
  stockCheck(params) {
1482
1676
  return this.request("/api/products/stock-check", params);
1483
1677
  }
1678
+ stockSnapshot(params) {
1679
+ return this.request(
1680
+ stockSnapshotQuery(params),
1681
+ void 0,
1682
+ { method: "GET" }
1683
+ );
1684
+ }
1484
1685
  listingGroups(params) {
1485
1686
  return this.request(
1486
- "/api/products/listing-groups",
1487
- params
1687
+ listingGroupsQuery(params),
1688
+ void 0,
1689
+ { method: "GET" }
1690
+ );
1691
+ }
1692
+ listingGroupsCatalog(params) {
1693
+ return this.request(
1694
+ listingGroupsCatalogQuery(params),
1695
+ void 0,
1696
+ { method: "GET" }
1488
1697
  );
1489
1698
  }
1490
1699
  /**
@@ -1500,8 +1709,9 @@ var ProductApi = class extends BaseApi {
1500
1709
  async detail(params) {
1501
1710
  try {
1502
1711
  const product = await this.request(
1503
- "/api/products/detail",
1504
- params
1712
+ productDetailQuery(params),
1713
+ void 0,
1714
+ { method: "GET" }
1505
1715
  );
1506
1716
  return { found: true, product };
1507
1717
  } catch (err) {
@@ -1510,6 +1720,20 @@ var ProductApi = class extends BaseApi {
1510
1720
  throw err;
1511
1721
  }
1512
1722
  }
1723
+ async detailCatalog(params) {
1724
+ try {
1725
+ const product = await this.request(
1726
+ productDetailCatalogQuery(params),
1727
+ void 0,
1728
+ { method: "GET" }
1729
+ );
1730
+ return { found: true, product };
1731
+ } catch (err) {
1732
+ const notFoundResult = productDetailResultFromError(err);
1733
+ if (notFoundResult?.found === false) return notFoundResult;
1734
+ throw err;
1735
+ }
1736
+ }
1513
1737
  /**
1514
1738
  * Atomically create or update a product together with its options,
1515
1739
  * option-values, and variants in a single transaction. Mirrors Shopify's
@@ -1517,7 +1741,104 @@ var ProductApi = class extends BaseApi {
1517
1741
  * `product-upsert` tool.
1518
1742
  */
1519
1743
  upsert(params) {
1520
- return this.request("/api/products/upsert", params);
1744
+ return this.request(
1745
+ "/api/products/upsert",
1746
+ normalizeProductUpsertParams(params)
1747
+ );
1748
+ }
1749
+ };
1750
+
1751
+ // src/core/api/order-api.ts
1752
+ function idempotencyRequestOptions(idempotencyKey) {
1753
+ return idempotencyKey ? { headers: { "X-Idempotency-Key": idempotencyKey } } : void 0;
1754
+ }
1755
+ function splitIdempotencyKey(params) {
1756
+ const { idempotencyKey, ...body } = params;
1757
+ return { body, idempotencyKey };
1758
+ }
1759
+ var OrderApi = class extends BaseApi {
1760
+ constructor(options) {
1761
+ super("OrderApi", options);
1762
+ }
1763
+ createOrder(params) {
1764
+ const { body, idempotencyKey } = splitIdempotencyKey(params);
1765
+ return this.request(
1766
+ "/api/orders/create",
1767
+ body,
1768
+ idempotencyRequestOptions(idempotencyKey)
1769
+ );
1770
+ }
1771
+ updateOrder(params) {
1772
+ return this.request("/api/orders/update", params);
1773
+ }
1774
+ updateTransaction(params) {
1775
+ return this.request("/api/transactions/update", params);
1776
+ }
1777
+ confirmPayment(params) {
1778
+ const { body, idempotencyKey } = splitIdempotencyKey(params);
1779
+ const headerKey = idempotencyKey ?? params.providerEventId;
1780
+ return this.request(
1781
+ "/api/orders/confirm-payment",
1782
+ body,
1783
+ idempotencyRequestOptions(headerKey)
1784
+ );
1785
+ }
1786
+ cancelOrder(params) {
1787
+ const { idempotencyKey } = params;
1788
+ const body = {
1789
+ orderNumber: params.orderNumber,
1790
+ reasonCode: params.reasonCode,
1791
+ reasonDetail: params.reasonDetail
1792
+ };
1793
+ return this.request(
1794
+ "/api/orders/cancel",
1795
+ body,
1796
+ idempotencyKey ? { headers: { "X-Idempotency-Key": idempotencyKey } } : void 0
1797
+ );
1798
+ }
1799
+ checkout(params) {
1800
+ const { body, idempotencyKey } = splitIdempotencyKey(params);
1801
+ return this.request(
1802
+ "/api/orders/checkout",
1803
+ body,
1804
+ idempotencyRequestOptions(idempotencyKey)
1805
+ );
1806
+ }
1807
+ createFulfillment(params) {
1808
+ const { body, idempotencyKey } = splitIdempotencyKey(params);
1809
+ return this.request(
1810
+ "/api/orders/create-fulfillment",
1811
+ body,
1812
+ idempotencyRequestOptions(idempotencyKey)
1813
+ );
1814
+ }
1815
+ updateFulfillment(params) {
1816
+ return this.request("/api/orders/update-fulfillment", params);
1817
+ }
1818
+ bulkImportFulfillments(params) {
1819
+ return this.request(
1820
+ "/api/fulfillments/bulk-import",
1821
+ params
1822
+ );
1823
+ }
1824
+ returnWithRefund(params) {
1825
+ const { body, idempotencyKey } = splitIdempotencyKey(params);
1826
+ return this.request(
1827
+ "/api/returns/return-refund",
1828
+ body,
1829
+ idempotencyRequestOptions(idempotencyKey)
1830
+ );
1831
+ }
1832
+ createReturn(params) {
1833
+ const { body, idempotencyKey } = splitIdempotencyKey(params);
1834
+ return this.request(
1835
+ "/api/returns/create",
1836
+ body,
1837
+ idempotencyRequestOptions(idempotencyKey)
1838
+ );
1839
+ }
1840
+ updateReturn(params) {
1841
+ return this.request("/api/returns/update", params);
1521
1842
  }
1522
1843
  };
1523
1844
 
@@ -1531,7 +1852,7 @@ var CommerceClient = class {
1531
1852
  onUnauthorized: options.onUnauthorized,
1532
1853
  onRequestId: options.onRequestId
1533
1854
  });
1534
- const execute = async (endpoint, body) => {
1855
+ const execute = async (endpoint, body, requestOptions) => {
1535
1856
  const token = options.customerToken();
1536
1857
  try {
1537
1858
  const response = await httpFetch(endpoint, {
@@ -1540,7 +1861,26 @@ var CommerceClient = class {
1540
1861
  publishableKey: options.publishableKey,
1541
1862
  customerToken: token ?? void 0,
1542
1863
  ...token && options.onUnauthorized && { onUnauthorized: options.onUnauthorized },
1543
- body: JSON.stringify(body)
1864
+ body: JSON.stringify(body),
1865
+ ...requestOptions?.headers && { headers: requestOptions.headers }
1866
+ });
1867
+ options.onRequestId?.(response.headers.get("x-request-id") ?? null);
1868
+ return parseApiResponse(response, endpoint);
1869
+ } catch (err) {
1870
+ const id = err instanceof SDKError ? err.requestId ?? null : null;
1871
+ options.onRequestId?.(id);
1872
+ throw err;
1873
+ }
1874
+ };
1875
+ const executeGet = async (endpoint) => {
1876
+ const token = options.customerToken();
1877
+ try {
1878
+ const response = await httpFetch(endpoint, {
1879
+ method: "GET",
1880
+ apiUrl: options.apiUrl,
1881
+ publishableKey: options.publishableKey,
1882
+ customerToken: token ?? void 0,
1883
+ ...token && options.onUnauthorized && { onUnauthorized: options.onUnauthorized }
1544
1884
  });
1545
1885
  options.onRequestId?.(response.headers.get("x-request-id") ?? null);
1546
1886
  return parseApiResponse(response, endpoint);
@@ -1552,19 +1892,30 @@ var CommerceClient = class {
1552
1892
  };
1553
1893
  this.product = {
1554
1894
  stockCheck: (params) => execute("/api/products/stock-check", params),
1555
- listingGroups: (params) => execute("/api/products/listing-groups", params),
1895
+ stockSnapshot: (params) => executeGet(stockSnapshotQuery(params)),
1896
+ listingGroups: (params) => executeGet(listingGroupsQuery(params)),
1897
+ listingGroupsCatalog: (params) => executeGet(listingGroupsCatalogQuery(params)),
1556
1898
  detail: async (params) => {
1557
1899
  try {
1558
- const product = await execute(
1559
- "/api/products/detail",
1560
- params
1561
- );
1900
+ const product = await executeGet(productDetailQuery(params));
1562
1901
  return { found: true, product };
1563
1902
  } catch (err) {
1564
1903
  const notFoundResult = productDetailResultFromError(err);
1565
1904
  if (notFoundResult) return notFoundResult;
1566
1905
  throw err;
1567
1906
  }
1907
+ },
1908
+ detailCatalog: async (params) => {
1909
+ try {
1910
+ const product = await executeGet(
1911
+ productDetailCatalogQuery(params)
1912
+ );
1913
+ return { found: true, product };
1914
+ } catch (err) {
1915
+ const notFoundResult = productDetailResultFromError(err);
1916
+ if (notFoundResult?.found === false) return notFoundResult;
1917
+ throw err;
1918
+ }
1568
1919
  }
1569
1920
  };
1570
1921
  this.cart = {
@@ -1577,7 +1928,14 @@ var CommerceClient = class {
1577
1928
  clear: cartApi.clearCart.bind(cartApi)
1578
1929
  };
1579
1930
  this.orders = {
1580
- checkout: (params) => execute("/api/orders/checkout", params),
1931
+ checkout: (params) => {
1932
+ const { body, idempotencyKey } = splitIdempotencyKey(params);
1933
+ return execute(
1934
+ "/api/orders/checkout",
1935
+ body,
1936
+ idempotencyRequestOptions(idempotencyKey)
1937
+ );
1938
+ },
1581
1939
  listMine: (params) => options.customerAuth.getMyOrders(params)
1582
1940
  };
1583
1941
  this.discounts = {
@@ -1589,6 +1947,113 @@ var CommerceClient = class {
1589
1947
  }
1590
1948
  };
1591
1949
 
1950
+ // src/core/events/events-client.ts
1951
+ var EventsClient = class {
1952
+ constructor(options) {
1953
+ const secretKey = options.secretKey;
1954
+ this.publishableKey = requirePublishableKeyForSecret(
1955
+ "EventsClient",
1956
+ options.publishableKey,
1957
+ secretKey
1958
+ );
1959
+ this.apiUrl = options.apiUrl;
1960
+ this.customerToken = options.customerToken;
1961
+ this.onUnauthorized = options.onUnauthorized;
1962
+ this.onRequestId = options.onRequestId;
1963
+ }
1964
+ getRange(params) {
1965
+ return this.execute(
1966
+ buildRangeEndpoint(params),
1967
+ "GET",
1968
+ void 0,
1969
+ { useCustomerAuth: false }
1970
+ );
1971
+ }
1972
+ register(params) {
1973
+ return this.execute(
1974
+ "/api/event-registrations/register",
1975
+ "POST",
1976
+ buildRegistrationRequestBody(params),
1977
+ { useCustomerAuth: true }
1978
+ );
1979
+ }
1980
+ getGuestRegistration(token) {
1981
+ return this.execute(
1982
+ "/api/event-registrations/guest/lookup",
1983
+ "POST",
1984
+ { token },
1985
+ { useCustomerAuth: false }
1986
+ );
1987
+ }
1988
+ cancelGuestRegistration(token, params = {}) {
1989
+ return this.execute(
1990
+ "/api/event-registrations/guest/cancel",
1991
+ "POST",
1992
+ buildGuestCancelRequestBody(token, params),
1993
+ { useCustomerAuth: false }
1994
+ );
1995
+ }
1996
+ async execute(endpoint, method, body, options = {}) {
1997
+ const useCustomerAuth = options.useCustomerAuth === true;
1998
+ const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
1999
+ try {
2000
+ const response = await httpFetch(endpoint, {
2001
+ method,
2002
+ apiUrl: this.apiUrl,
2003
+ publishableKey: this.publishableKey,
2004
+ ...useCustomerAuth && token ? { customerToken: token } : {},
2005
+ ...useCustomerAuth && token && this.onUnauthorized && { onUnauthorized: this.onUnauthorized },
2006
+ ...body !== void 0 && { body: JSON.stringify(body) }
2007
+ });
2008
+ this.onRequestId?.(response.headers.get("x-request-id") ?? null);
2009
+ return parseApiResponse(response, endpoint);
2010
+ } catch (err) {
2011
+ const id = err instanceof SDKError ? err.requestId ?? null : null;
2012
+ this.onRequestId?.(id);
2013
+ throw err;
2014
+ }
2015
+ }
2016
+ };
2017
+ function buildRegistrationRequestBody(params) {
2018
+ return {
2019
+ event: params.event,
2020
+ occurrence: params.occurrence,
2021
+ ...params.quantity !== void 0 && { quantity: params.quantity },
2022
+ ...params.attendee !== void 0 && { attendee: params.attendee },
2023
+ ...params.answers !== void 0 && { answers: params.answers }
2024
+ };
2025
+ }
2026
+ function buildGuestCancelRequestBody(token, params) {
2027
+ return {
2028
+ token,
2029
+ ...params.reason !== void 0 && { reason: params.reason }
2030
+ };
2031
+ }
2032
+ function buildRangeEndpoint(params) {
2033
+ const urlParams = new URLSearchParams();
2034
+ urlParams.set("start", formatDateParam(params.start));
2035
+ urlParams.set("end", formatDateParam(params.end));
2036
+ if (params.limit !== void 0) urlParams.set("limit", String(params.limit));
2037
+ if (params.page !== void 0) urlParams.set("page", String(params.page));
2038
+ appendValues(urlParams, "calendar", params.calendar);
2039
+ appendValues(urlParams, "calendarSlug", params.calendarSlug);
2040
+ appendValues(urlParams, "category", params.category);
2041
+ appendValues(urlParams, "categorySlug", params.categorySlug);
2042
+ appendValues(urlParams, "tag", params.tag);
2043
+ appendValues(urlParams, "tagSlug", params.tagSlug);
2044
+ return `/api/event-occurrences/range?${urlParams.toString()}`;
2045
+ }
2046
+ function formatDateParam(value) {
2047
+ return value instanceof Date ? value.toISOString() : value;
2048
+ }
2049
+ function appendValues(params, key, value) {
2050
+ if (value === void 0) return;
2051
+ const values = Array.isArray(value) ? value : [value];
2052
+ for (const entry of values) {
2053
+ if (entry) params.append(key, entry);
2054
+ }
2055
+ }
2056
+
1592
2057
  // src/core/client/client.ts
1593
2058
  var Client = class {
1594
2059
  constructor(options) {
@@ -1634,6 +2099,13 @@ var Client = class {
1634
2099
  onUnauthorized,
1635
2100
  onRequestId
1636
2101
  });
2102
+ this.events = new EventsClient({
2103
+ publishableKey: this.config.publishableKey,
2104
+ apiUrl: this.config.apiUrl,
2105
+ customerToken: () => this.customer.auth.getToken(),
2106
+ onUnauthorized,
2107
+ onRequestId
2108
+ });
1637
2109
  this.collections = new ReadOnlyCollectionClient(
1638
2110
  this.config.publishableKey,
1639
2111
  void 0,
@@ -1654,56 +2126,6 @@ function createClient(options) {
1654
2126
  return new Client(options);
1655
2127
  }
1656
2128
 
1657
- // src/core/api/order-api.ts
1658
- var OrderApi = class extends BaseApi {
1659
- constructor(options) {
1660
- super("OrderApi", options);
1661
- }
1662
- createOrder(params) {
1663
- return this.request("/api/orders/create", params);
1664
- }
1665
- updateOrder(params) {
1666
- return this.request("/api/orders/update", params);
1667
- }
1668
- updateTransaction(params) {
1669
- return this.request("/api/transactions/update", params);
1670
- }
1671
- confirmPayment(params) {
1672
- return this.request(
1673
- "/api/orders/confirm-payment",
1674
- params,
1675
- params.providerEventId ? { headers: { "X-Idempotency-Key": params.providerEventId } } : void 0
1676
- );
1677
- }
1678
- checkout(params) {
1679
- return this.request("/api/orders/checkout", params);
1680
- }
1681
- createFulfillment(params) {
1682
- return this.request("/api/orders/create-fulfillment", params);
1683
- }
1684
- updateFulfillment(params) {
1685
- return this.request("/api/orders/update-fulfillment", params);
1686
- }
1687
- bulkImportFulfillments(params) {
1688
- return this.request(
1689
- "/api/fulfillments/bulk-import",
1690
- params
1691
- );
1692
- }
1693
- returnWithRefund(params) {
1694
- return this.request(
1695
- "/api/returns/return-refund",
1696
- params
1697
- );
1698
- }
1699
- createReturn(params) {
1700
- return this.request("/api/returns/create", params);
1701
- }
1702
- updateReturn(params) {
1703
- return this.request("/api/returns/update", params);
1704
- }
1705
- };
1706
-
1707
2129
  // src/core/api/discount-api.ts
1708
2130
  var DiscountApi = class extends BaseApi {
1709
2131
  constructor(options) {
@@ -1724,6 +2146,44 @@ var ShippingApi = class extends BaseApi {
1724
2146
  }
1725
2147
  };
1726
2148
 
2149
+ // src/core/commerce/merge-catalog-stock.ts
2150
+ function mergeProductDetailWithStock(catalog, snapshot) {
2151
+ const snapshotByVariantId = new Map(
2152
+ snapshot.snapshots.map((item) => [item.variantId, item])
2153
+ );
2154
+ let missingSnapshotCount = 0;
2155
+ const variants = catalog.variants.map((variant) => {
2156
+ const snap = snapshotByVariantId.get(String(variant.id));
2157
+ if (!snap) {
2158
+ missingSnapshotCount += 1;
2159
+ return { ...variant, stock: 0, reservedStock: 0 };
2160
+ }
2161
+ return {
2162
+ ...variant,
2163
+ stock: snap.isUnlimited ? 0 : snap.availableStock,
2164
+ reservedStock: 0
2165
+ };
2166
+ });
2167
+ const trackedVariants = variants.filter((variant) => !variant.isUnlimited);
2168
+ const totalInventory = trackedVariants.length === 0 ? null : trackedVariants.reduce(
2169
+ (sum, variant) => sum + Math.max(0, (variant.stock ?? 0) - (variant.reservedStock ?? 0)),
2170
+ 0
2171
+ );
2172
+ const { liveStockRequired: _liveStockRequired, ...listingBase } = catalog.listing;
2173
+ const availableForSale = snapshot.snapshots.some(
2174
+ (item) => item.status === "available" && item.availableForSale
2175
+ );
2176
+ return {
2177
+ stockMergeStatus: missingSnapshotCount === 0 ? "complete" : "partial",
2178
+ product: {
2179
+ ...catalog,
2180
+ product: { ...catalog.product, totalInventory },
2181
+ variants,
2182
+ listing: { ...listingBase, availableForSale }
2183
+ }
2184
+ };
2185
+ }
2186
+
1727
2187
  // src/core/webhook/index.ts
1728
2188
  var ORDER_CHANGED_EVENT_TYPE = "collection.orderChanged";
1729
2189
  var COMMERCE_NOTIFICATION_EVENT_TYPE = "commerce.notification";
@@ -1735,6 +2195,7 @@ function isValidWebhookEvent(data) {
1735
2195
  var COMMERCE_NOTIFICATION_OPERATION = "notification";
1736
2196
  var COMMERCE_NOTIFICATION_EVENTS = [
1737
2197
  "orderPaid",
2198
+ "orderCanceled",
1738
2199
  "fulfillmentShipped",
1739
2200
  "orderDelivered",
1740
2201
  "returnRequested",
@@ -1820,7 +2281,7 @@ function isCommerceNotificationWebhookEvent(event) {
1820
2281
  if (!matchesOptionalId(change.sourceId, sourceId)) return false;
1821
2282
  }
1822
2283
  const changeSourceId = isWebhookCommerceNotificationChange(change) ? change.sourceId : void 0;
1823
- if (notification.event === "orderPaid" || notification.event === "orderDelivered") {
2284
+ if (notification.event === "orderPaid" || notification.event === "orderCanceled" || notification.event === "orderDelivered") {
1824
2285
  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);
1825
2286
  }
1826
2287
  if (notification.event === "fulfillmentShipped") {
@@ -2075,6 +2536,7 @@ var COLLECTIONS = [
2075
2536
  "reaction-types",
2076
2537
  "bookmarks",
2077
2538
  "post-categories",
2539
+ "post-tags",
2078
2540
  "customer-profile-lists",
2079
2541
  // Events
2080
2542
  "event-calendars",
@@ -2223,22 +2685,252 @@ var RealtimeConnection = class {
2223
2685
  }
2224
2686
  }
2225
2687
  }
2226
- scheduleReconnect() {
2227
- if (this.reconnectTimer) return;
2228
- const delay2 = Math.min(
2229
- INITIAL_RECONNECT_DELAY * Math.pow(RECONNECT_BACKOFF_FACTOR, this.reconnectAttempt),
2230
- MAX_RECONNECT_DELAY
2231
- );
2232
- this.reconnectAttempt++;
2233
- this.reconnectTimer = setTimeout(() => {
2234
- this.reconnectTimer = null;
2235
- this.abortController = new AbortController();
2236
- this.startStream(this.abortController.signal);
2237
- }, delay2);
2688
+ scheduleReconnect() {
2689
+ if (this.reconnectTimer) return;
2690
+ const delay2 = Math.min(
2691
+ INITIAL_RECONNECT_DELAY * Math.pow(RECONNECT_BACKOFF_FACTOR, this.reconnectAttempt),
2692
+ MAX_RECONNECT_DELAY
2693
+ );
2694
+ this.reconnectAttempt++;
2695
+ this.reconnectTimer = setTimeout(() => {
2696
+ this.reconnectTimer = null;
2697
+ this.abortController = new AbortController();
2698
+ this.startStream(this.abortController.signal);
2699
+ }, delay2);
2700
+ }
2701
+ };
2702
+
2703
+ // src/utils/product-selection-media.ts
2704
+ function selectedSwatchMediaItemId(swatch) {
2705
+ if (!swatch || swatch.type !== "media") return null;
2706
+ const id = swatch.mediaItemId;
2707
+ if (id == null || id === "") return null;
2708
+ return String(id);
2709
+ }
2710
+ function getMediaId(value) {
2711
+ if (typeof value === "string" || typeof value === "number") {
2712
+ return String(value);
2713
+ }
2714
+ if (typeof value === "object" && value !== null && "id" in value) {
2715
+ const id = value.id;
2716
+ if (typeof id === "string" || typeof id === "number") return String(id);
2717
+ }
2718
+ return null;
2719
+ }
2720
+ function toPointerId(value) {
2721
+ return getMediaId(value);
2722
+ }
2723
+ function mediaArray(value) {
2724
+ if (!Array.isArray(value)) return [];
2725
+ return value.filter((entry) => entry != null);
2726
+ }
2727
+ function uniqueWithPrimaryFirst(primary, items) {
2728
+ const unique = /* @__PURE__ */ new Map();
2729
+ for (const item of items) {
2730
+ const id = getMediaId(item);
2731
+ const key = id ?? `inline:${unique.size}`;
2732
+ if (!unique.has(key)) unique.set(key, item);
2733
+ }
2734
+ if (primary) {
2735
+ const primaryId = getMediaId(primary);
2736
+ const prefixed = /* @__PURE__ */ new Map();
2737
+ const primaryKey = primaryId ?? "inline:primary";
2738
+ prefixed.set(primaryKey, primary);
2739
+ for (const [key, value] of unique.entries()) {
2740
+ if (!prefixed.has(key)) prefixed.set(key, value);
2741
+ }
2742
+ return Array.from(prefixed.values());
2743
+ }
2744
+ return Array.from(unique.values());
2745
+ }
2746
+ function buildPoolById(pool) {
2747
+ const poolById = /* @__PURE__ */ new Map();
2748
+ for (const item of pool) {
2749
+ const id = getMediaId(item);
2750
+ if (id) poolById.set(id, item);
2751
+ }
2752
+ return poolById;
2753
+ }
2754
+ function resolveVariantImageItems(variant, poolById) {
2755
+ if (!variant || !Array.isArray(variant.images)) return [];
2756
+ const resolved = [];
2757
+ for (const entry of variant.images) {
2758
+ if (entry == null) continue;
2759
+ if (typeof entry === "string" || typeof entry === "number") {
2760
+ const pooled = poolById.get(String(entry));
2761
+ if (pooled) resolved.push(pooled);
2762
+ continue;
2763
+ }
2764
+ const mediaId2 = getMediaId(entry);
2765
+ if (mediaId2) {
2766
+ const pooled = poolById.get(mediaId2);
2767
+ if (pooled) {
2768
+ resolved.push(pooled);
2769
+ }
2770
+ continue;
2771
+ }
2772
+ }
2773
+ return resolved;
2774
+ }
2775
+ function resolveOptionSwatchPrimary(selectedOptionValues, poolById) {
2776
+ if (!selectedOptionValues?.length) return null;
2777
+ for (const optionValue of selectedOptionValues) {
2778
+ const swatch = optionValue?.swatch;
2779
+ const swatchPointer = selectedSwatchMediaItemId(swatch);
2780
+ if (swatchPointer) {
2781
+ const pooled = poolById.get(swatchPointer);
2782
+ if (pooled) return pooled;
2783
+ }
2784
+ const inline = swatch?.inlineMedia;
2785
+ if (inline != null && typeof inline === "object") {
2786
+ return inline;
2787
+ }
2788
+ }
2789
+ return null;
2790
+ }
2791
+ function resolveProductSelectionMedia(input) {
2792
+ const pool = mediaArray(input.productMediaPool);
2793
+ const poolById = buildPoolById(pool);
2794
+ const selectedVariantImages = resolveVariantImageItems(
2795
+ input.selectedVariant,
2796
+ poolById
2797
+ );
2798
+ if (selectedVariantImages.length > 0) {
2799
+ const primaryImage = selectedVariantImages[0] ?? null;
2800
+ return {
2801
+ primaryImage,
2802
+ images: uniqueWithPrimaryFirst(primaryImage, selectedVariantImages),
2803
+ source: "variant_media_selected"
2804
+ };
2805
+ }
2806
+ if (input.selectedVariant == null && (input.matchingVariants?.length ?? 0) > 0) {
2807
+ const mergedMatchingImages = [];
2808
+ for (const matchingVariant of input.matchingVariants ?? []) {
2809
+ mergedMatchingImages.push(
2810
+ ...resolveVariantImageItems(matchingVariant, poolById)
2811
+ );
2812
+ }
2813
+ if (mergedMatchingImages.length > 0) {
2814
+ const primaryImage = mergedMatchingImages[0] ?? null;
2815
+ return {
2816
+ primaryImage,
2817
+ images: uniqueWithPrimaryFirst(primaryImage, mergedMatchingImages),
2818
+ source: "variant_media_matching"
2819
+ };
2820
+ }
2821
+ }
2822
+ const optionSwatchPrimary = resolveOptionSwatchPrimary(
2823
+ input.selectedOptionValues,
2824
+ poolById
2825
+ );
2826
+ if (optionSwatchPrimary) {
2827
+ return {
2828
+ primaryImage: optionSwatchPrimary,
2829
+ images: [optionSwatchPrimary],
2830
+ source: "option_swatch"
2831
+ };
2238
2832
  }
2239
- };
2833
+ return {
2834
+ primaryImage: null,
2835
+ images: [],
2836
+ source: "none"
2837
+ };
2838
+ }
2839
+ function resolveProductDisplayMedia(input) {
2840
+ const pool = mediaArray(input.productMediaPool);
2841
+ const poolById = buildPoolById(pool);
2842
+ const listingPointer = toPointerId(input.listingPrimaryImage);
2843
+ if (listingPointer) {
2844
+ const listingPrimary = poolById.get(listingPointer);
2845
+ if (listingPrimary) {
2846
+ return {
2847
+ primaryImage: listingPrimary,
2848
+ images: uniqueWithPrimaryFirst(listingPrimary, pool),
2849
+ source: "listing_primary"
2850
+ };
2851
+ }
2852
+ }
2853
+ const productPrimaryPointer = getMediaId(input.productPrimaryMediaItemId);
2854
+ if (productPrimaryPointer) {
2855
+ const productPrimary = poolById.get(productPrimaryPointer);
2856
+ if (productPrimary) {
2857
+ return {
2858
+ primaryImage: productPrimary,
2859
+ images: uniqueWithPrimaryFirst(productPrimary, pool),
2860
+ source: "product_primary"
2861
+ };
2862
+ }
2863
+ }
2864
+ if (pool.length > 0) {
2865
+ const productPoolPrimary = pool[0] ?? null;
2866
+ if (productPoolPrimary) {
2867
+ return {
2868
+ primaryImage: productPoolPrimary,
2869
+ images: uniqueWithPrimaryFirst(productPoolPrimary, pool),
2870
+ source: "product_pool"
2871
+ };
2872
+ }
2873
+ }
2874
+ return {
2875
+ primaryImage: null,
2876
+ images: [],
2877
+ source: "none"
2878
+ };
2879
+ }
2880
+ function resolveListingPrimaryImagePointer(input) {
2881
+ const pool = mediaArray(input.productMediaPool);
2882
+ const resolvedPointer = getMediaId(input.resolvedPrimary);
2883
+ if (resolvedPointer && input.resolvedSource !== "product_pool" && input.resolvedSource !== "none") {
2884
+ return resolvedPointer;
2885
+ }
2886
+ const poolById = buildPoolById(pool);
2887
+ const listingPointer = getMediaId(input.listingPrimaryImage);
2888
+ if (listingPointer && poolById.has(listingPointer)) {
2889
+ return listingPointer;
2890
+ }
2891
+ const primaryPointer = toPointerId(input.productPrimaryMediaItemId);
2892
+ if (primaryPointer && poolById.has(primaryPointer)) return primaryPointer;
2893
+ const thumbnailPointer = getMediaId(input.productThumbnail);
2894
+ if (thumbnailPointer && poolById.has(thumbnailPointer)) {
2895
+ return thumbnailPointer;
2896
+ }
2897
+ if (pool.length > 0) {
2898
+ const firstPoolId = getMediaId(pool[0]);
2899
+ if (firstPoolId) return firstPoolId;
2900
+ }
2901
+ return null;
2902
+ }
2240
2903
 
2241
2904
  // src/utils/ecommerce.ts
2905
+ function normalizeMatrixSwatch(swatch) {
2906
+ if (!swatch) return null;
2907
+ const rawMedia = swatch.mediaItemId;
2908
+ const inlineMedia = rawMedia != null && typeof rawMedia === "object" && "url" in rawMedia && typeof rawMedia.url === "string" ? rawMedia : null;
2909
+ return {
2910
+ type: swatch.type ?? null,
2911
+ color: swatch.color ?? null,
2912
+ mediaItemId: extractEntityId(rawMedia),
2913
+ inlineMedia
2914
+ };
2915
+ }
2916
+ var DEFAULT_PRODUCT_SELECTION_URL_EMIT = "slug-compat";
2917
+ function resolveProductSelectionUrlEmit(emit) {
2918
+ return emit ?? DEFAULT_PRODUCT_SELECTION_URL_EMIT;
2919
+ }
2920
+ function appendSlugCompatSelectionParam(params, matrix, optionId, valueId) {
2921
+ const option = matrix.optionById.get(optionId);
2922
+ const value = matrix.valueById.get(valueId);
2923
+ if (!option?.slug || !value?.slug) return false;
2924
+ const slugMatches = option.values.filter(
2925
+ (candidate) => candidate.slug === value.slug
2926
+ );
2927
+ if (slugMatches.length !== 1) return false;
2928
+ params.append(`opt.${option.slug}`, value.slug);
2929
+ return true;
2930
+ }
2931
+ function appendCanonicalSelectionParam(params, optionId, valueId) {
2932
+ params.append(`opt.${optionId}`, valueId);
2933
+ }
2242
2934
  var ProductSelectionCodecError = class extends Error {
2243
2935
  constructor(message) {
2244
2936
  super(message);
@@ -2283,6 +2975,18 @@ function getVariantPrimaryImage(variant) {
2283
2975
  if (!variant) return null;
2284
2976
  return extractEntityId(variant.thumbnail) ?? getFirstMediaId(variant.images);
2285
2977
  }
2978
+ function resolveGenericListingPrimaryImage(product, resolvedPrimary, resolvedSource) {
2979
+ return resolveListingPrimaryImagePointer({
2980
+ productMediaPool: product?.images ?? [],
2981
+ productPrimaryMediaItemId: getRelationID(
2982
+ product?.primaryMediaItemId ?? null
2983
+ ),
2984
+ productThumbnail: product?.thumbnail ?? null,
2985
+ listingPrimaryImage: product?.listing?.primaryImage ?? null,
2986
+ resolvedPrimary,
2987
+ resolvedSource
2988
+ });
2989
+ }
2286
2990
  function getFirstAvailableVariantPrimaryImage(variants) {
2287
2991
  const orderedVariants = [...variants].sort(compareVariantOrder);
2288
2992
  for (const variant of orderedVariants) {
@@ -2292,6 +2996,27 @@ function getFirstAvailableVariantPrimaryImage(variants) {
2292
2996
  }
2293
2997
  return null;
2294
2998
  }
2999
+ function normalizeProductOptionValueSwatch(swatch) {
3000
+ if (swatch == null) return null;
3001
+ if (typeof swatch !== "object") return null;
3002
+ const raw = swatch;
3003
+ const mediaItemId = extractEntityId(raw.mediaItemId);
3004
+ const color = typeof raw.color === "string" ? raw.color.trim() : "";
3005
+ const hasColor = color.length > 0;
3006
+ if (raw.type === "media" || mediaItemId && raw.type !== "color") {
3007
+ if (!mediaItemId || hasColor) return null;
3008
+ return {
3009
+ type: "media",
3010
+ mediaItemId,
3011
+ color: null
3012
+ };
3013
+ }
3014
+ if (raw.type === "color" || hasColor) {
3015
+ if (mediaItemId || !hasColor) return null;
3016
+ return { type: "color", color, mediaItemId: null };
3017
+ }
3018
+ return null;
3019
+ }
2295
3020
  function normalizeOptionValue(value, fallbackOptionId, fallbackOptionSlug) {
2296
3021
  return {
2297
3022
  id: String(value.id),
@@ -2299,9 +3024,7 @@ function normalizeOptionValue(value, fallbackOptionId, fallbackOptionSlug) {
2299
3024
  optionSlug: fallbackOptionSlug,
2300
3025
  label: value.value || value.slug || String(value.id),
2301
3026
  slug: value.slug ?? null,
2302
- swatchColor: value.swatchColor ?? null,
2303
- thumbnail: value.thumbnail ?? null,
2304
- images: value.images ?? null,
3027
+ swatch: normalizeProductOptionValueSwatch(value.swatch),
2305
3028
  order: value._order ?? value["_product-option-values_values_order"] ?? ""
2306
3029
  };
2307
3030
  }
@@ -2407,9 +3130,7 @@ function buildProductOptionMatrixFromDetail(detail) {
2407
3130
  optionSlug: option.slug,
2408
3131
  label: value.value || value.slug || String(value.id),
2409
3132
  slug: value.slug,
2410
- swatchColor: value.swatchColor ?? null,
2411
- thumbnail: value.thumbnail ?? null,
2412
- images: value.images ?? null,
3133
+ swatch: normalizeProductOptionValueSwatch(value.swatch),
2413
3134
  order: matrixOrder(valueIndex)
2414
3135
  }))
2415
3136
  }));
@@ -2845,13 +3566,19 @@ function stringifyProductSelection(detail, selection = {}, options) {
2845
3566
  return params.toString();
2846
3567
  }
2847
3568
  }
3569
+ const emit = resolveProductSelectionUrlEmit(options?.emit);
2848
3570
  for (const optionId of matrix.optionIds) {
2849
3571
  const valueId = normalized.byOptionId[optionId];
2850
3572
  if (!valueId) continue;
2851
3573
  if (!matrix.optionById.has(optionId) || !matrix.valueById.has(valueId)) {
2852
3574
  continue;
2853
3575
  }
2854
- params.append(`opt.${optionId}`, valueId);
3576
+ if (emit === "slug-compat") {
3577
+ if (appendSlugCompatSelectionParam(params, matrix, optionId, valueId)) {
3578
+ continue;
3579
+ }
3580
+ }
3581
+ appendCanonicalSelectionParam(params, optionId, valueId);
2855
3582
  }
2856
3583
  return params.toString();
2857
3584
  }
@@ -2890,6 +3617,100 @@ function getExactSelectedVariantEntry(matrix, selection, matchingVariants) {
2890
3617
  )
2891
3618
  ) ?? null;
2892
3619
  }
3620
+ function normalizedSelectionFromByOptionId(matrix, selectedByOptionId, variantId) {
3621
+ const byOptionId = Object.fromEntries(
3622
+ matrix.optionIds.map((optionId) => [optionId, selectedByOptionId.get(optionId)]).filter((entry) => Boolean(entry[1]))
3623
+ );
3624
+ const byOptionSlug = Object.fromEntries(
3625
+ matrix.options.map((option) => {
3626
+ const valueId = selectedByOptionId.get(option.id);
3627
+ const value = valueId ? matrix.valueById.get(valueId) : void 0;
3628
+ return [option.slug, value?.slug ?? void 0];
3629
+ }).filter((entry) => Boolean(entry[1]))
3630
+ );
3631
+ return {
3632
+ byOptionSlug,
3633
+ byOptionId,
3634
+ valueIds: matrix.optionIds.map((optionId) => byOptionId[optionId]).filter((valueId) => Boolean(valueId)),
3635
+ variantId
3636
+ };
3637
+ }
3638
+ function buildFilledNormalizedSelection(matrix, normalizedSelection, listing) {
3639
+ const selectedByOptionId = new Map(
3640
+ Object.entries(normalizedSelection.byOptionId)
3641
+ );
3642
+ if (matrix.optionIds.every((optionId) => selectedByOptionId.has(optionId))) {
3643
+ const variantId = normalizedSelection.variantId ?? resolveVariantIdForCompleteSelection(matrix, selectedByOptionId);
3644
+ if (variantId === normalizedSelection.variantId) {
3645
+ return normalizedSelection;
3646
+ }
3647
+ return normalizedSelectionFromByOptionId(
3648
+ matrix,
3649
+ selectedByOptionId,
3650
+ variantId
3651
+ );
3652
+ }
3653
+ for (const option of matrix.options) {
3654
+ if (selectedByOptionId.has(option.id)) continue;
3655
+ if (option.values.length === 1) {
3656
+ selectedByOptionId.set(option.id, option.values[0].id);
3657
+ }
3658
+ }
3659
+ if (matrix.optionIds.every((optionId) => selectedByOptionId.has(optionId))) {
3660
+ const variantId = normalizedSelection.variantId ?? resolveVariantIdForCompleteSelection(matrix, selectedByOptionId);
3661
+ return normalizedSelectionFromByOptionId(
3662
+ matrix,
3663
+ selectedByOptionId,
3664
+ variantId
3665
+ );
3666
+ }
3667
+ const partialNormalized = normalizedSelectionFromByOptionId(
3668
+ matrix,
3669
+ selectedByOptionId,
3670
+ normalizedSelection.variantId
3671
+ );
3672
+ const matchingVariantEntries = getMatchingVariantEntries(
3673
+ matrix,
3674
+ partialNormalized
3675
+ );
3676
+ const orderedMatches = [...matchingVariantEntries].sort(
3677
+ (left, right) => compareVariantOrder(left.source, right.source)
3678
+ );
3679
+ const hintVariantId = listing.selectionHintVariant != null ? String(listing.selectionHintVariant) : null;
3680
+ const hintedEntry = hintVariantId != null ? orderedMatches.find((entry) => entry.id === hintVariantId) : void 0;
3681
+ const availableEntry = orderedMatches.find(
3682
+ (entry) => isVariantAvailableForSale(entry.source)
3683
+ );
3684
+ const chosenEntry = hintedEntry ?? availableEntry ?? orderedMatches[0];
3685
+ if (!chosenEntry) {
3686
+ return normalizedSelection;
3687
+ }
3688
+ for (const optionId of matrix.optionIds) {
3689
+ if (selectedByOptionId.has(optionId)) continue;
3690
+ const valueId = chosenEntry.optionValueByOptionId.get(optionId);
3691
+ if (valueId) selectedByOptionId.set(optionId, valueId);
3692
+ }
3693
+ const filledVariantId = matrix.optionIds.every(
3694
+ (optionId) => selectedByOptionId.has(optionId)
3695
+ ) ? resolveVariantIdForCompleteSelection(matrix, selectedByOptionId) ?? chosenEntry.id : normalizedSelection.variantId;
3696
+ return normalizedSelectionFromByOptionId(
3697
+ matrix,
3698
+ selectedByOptionId,
3699
+ filledVariantId
3700
+ );
3701
+ }
3702
+ function resolveVariantIdForCompleteSelection(matrix, selectedByOptionId) {
3703
+ if (!matrix.optionIds.every((optionId) => selectedByOptionId.has(optionId))) {
3704
+ return null;
3705
+ }
3706
+ const normalized = normalizedSelectionFromByOptionId(
3707
+ matrix,
3708
+ selectedByOptionId,
3709
+ null
3710
+ );
3711
+ const matchingVariantEntries = getMatchingVariantEntries(matrix, normalized);
3712
+ return getExactSelectedVariantEntry(matrix, normalized, matchingVariantEntries)?.id ?? null;
3713
+ }
2893
3714
  function buildSelectionPrice(variants) {
2894
3715
  const { min, max } = getMinMax(variants.map((variant) => variant.price));
2895
3716
  const { min: compareAtMin, max: compareAtMax } = getMinMax(
@@ -2903,38 +3724,51 @@ function buildSelectionPrice(variants) {
2903
3724
  isRange: min !== null && max !== null ? min !== max : false
2904
3725
  };
2905
3726
  }
2906
- function firstMedia(value) {
2907
- if (value == null) return null;
2908
- if (Array.isArray(value)) return firstMedia(value[0]);
2909
- return value;
2910
- }
2911
3727
  function isPresentMedia(value) {
2912
3728
  return value != null;
2913
3729
  }
2914
- function mediaArray(values) {
3730
+ function mediaArray2(values) {
2915
3731
  if (!Array.isArray(values)) return [];
2916
3732
  return values.filter(isPresentMedia);
2917
3733
  }
2918
3734
  function buildSelectionMedia(detail, selectedVariant, matchingVariants, selectedValues) {
2919
- const selectedVariantImages = mediaArray(selectedVariant?.images);
2920
- const selectedValueImages = selectedValues.flatMap(
2921
- (value) => mediaArray(value.images)
2922
- );
2923
- const matchingVariantImages = matchingVariants.flatMap(
2924
- (variant) => mediaArray(variant.images)
2925
- );
2926
- const selectedValuePrimary = selectedValues.map((value) => firstMedia(value.thumbnail) ?? firstMedia(value.images)).find((value) => value != null) ?? null;
2927
- const selectedVariantPrimary = firstMedia(selectedVariant?.thumbnail) ?? firstMedia(selectedVariant?.images);
2928
- const matchingVariantPrimary = matchingVariants.map(
2929
- (variant) => firstMedia(variant.thumbnail) ?? firstMedia(variant.images)
2930
- ).find((value) => value != null) ?? null;
2931
- const detailImages = mediaArray(detail.images);
2932
- const primaryImage = selectedVariantPrimary ?? selectedValuePrimary ?? matchingVariantPrimary ?? firstMedia(detail.listing.primaryImage) ?? firstMedia(detailImages);
2933
- const images = selectedVariantImages.length > 0 ? selectedVariantImages : selectedValueImages.length > 0 ? selectedValueImages : matchingVariantImages.length > 0 ? matchingVariantImages : detailImages;
2934
- return {
2935
- primaryImage,
2936
- images
2937
- };
3735
+ const productPool = mediaArray2(detail.images);
3736
+ const resolvedMedia = resolveProductSelectionMedia({
3737
+ productMediaPool: productPool,
3738
+ productPrimaryMediaItemId: getRelationID(detail.primaryMediaItemId),
3739
+ selectedVariant: selectedVariant ? {
3740
+ id: selectedVariant.id,
3741
+ images: selectedVariant.images
3742
+ } : null,
3743
+ matchingVariants: matchingVariants.map((variant) => ({
3744
+ id: variant.id,
3745
+ images: variant.images
3746
+ })),
3747
+ selectedOptionValues: selectedValues.map((value) => ({
3748
+ id: value.id,
3749
+ swatch: normalizeMatrixSwatch(value.swatch)
3750
+ }))
3751
+ });
3752
+ if (resolvedMedia.source !== "none") {
3753
+ return {
3754
+ primaryImage: resolvedMedia.primaryImage,
3755
+ images: resolvedMedia.images,
3756
+ source: resolvedMedia.source
3757
+ };
3758
+ }
3759
+ const displayMedia = resolveProductDisplayMedia({
3760
+ productMediaPool: productPool,
3761
+ productPrimaryMediaItemId: getRelationID(detail.primaryMediaItemId),
3762
+ listingPrimaryImage: detail.listing.primaryImage ?? null
3763
+ });
3764
+ if (displayMedia.source !== "none") {
3765
+ return {
3766
+ primaryImage: displayMedia.primaryImage,
3767
+ images: displayMedia.images,
3768
+ source: displayMedia.source
3769
+ };
3770
+ }
3771
+ return { primaryImage: null, images: [], source: "none" };
2938
3772
  }
2939
3773
  function buildSelectionStock(selectedVariant, matchingVariants) {
2940
3774
  if (selectedVariant) {
@@ -2957,7 +3791,9 @@ function buildSelectionStock(selectedVariant, matchingVariants) {
2957
3791
  };
2958
3792
  }
2959
3793
  function buildAvailableValueStock(variants) {
2960
- const activeVariants = variants.filter((variant) => variant.isActive !== false);
3794
+ const activeVariants = variants.filter(
3795
+ (variant) => variant.isActive !== false
3796
+ );
2961
3797
  const isUnlimited = activeVariants.some((variant) => variant.isUnlimited);
2962
3798
  const availableStock = isUnlimited ? null : activeVariants.reduce(
2963
3799
  (sum, variant) => sum + Math.max(0, variant.stock - variant.reservedStock),
@@ -2969,6 +3805,19 @@ function buildAvailableValueStock(variants) {
2969
3805
  availableStock
2970
3806
  };
2971
3807
  }
3808
+ function buildProductSelectionAvailableValue(matrixValue, _productImages, selected, available, stock) {
3809
+ return {
3810
+ valueId: matrixValue.id,
3811
+ value: matrixValue.label,
3812
+ label: matrixValue.label,
3813
+ slug: matrixValue.slug ?? "",
3814
+ selected,
3815
+ available,
3816
+ exists: available,
3817
+ ...stock,
3818
+ swatch: matrixValue.swatch ?? null
3819
+ };
3820
+ }
2972
3821
  function getCandidateVariantsForValue(matrix, optionId, valueId, selectedValueIds) {
2973
3822
  const selectedByOption = getSelectedValueByOptionId(matrix, selectedValueIds);
2974
3823
  selectedByOption.set(optionId, valueId);
@@ -2981,17 +3830,25 @@ function getCandidateVariantsForValue(matrix, optionId, valueId, selectedValueId
2981
3830
  function getResolutionContext(context) {
2982
3831
  return {
2983
3832
  images: context?.images ?? context?.detail?.images ?? [],
2984
- listing: context?.listing ?? context?.detail?.listing ?? {}
3833
+ listing: context?.listing ?? context?.detail?.listing ?? {},
3834
+ primaryMediaItemId: context?.primaryMediaItemId ?? context?.detail?.primaryMediaItemId ?? null
2985
3835
  };
2986
3836
  }
2987
3837
  function resolveProductSelectionFromMatrix(matrix, selection = {}, options, context) {
2988
- const { images, listing } = getResolutionContext(context);
3838
+ const { images, listing, primaryMediaItemId } = getResolutionContext(context);
2989
3839
  const effectiveSelection = hasExplicitSelection(selection) || listing.selectionHintVariant == null ? selection : { ...selection, variantId: listing.selectionHintVariant };
2990
- const normalizedSelection = normalizeProductSelectionFromMatrix(
3840
+ let normalizedSelection = normalizeProductSelectionFromMatrix(
2991
3841
  matrix,
2992
3842
  effectiveSelection,
2993
3843
  options
2994
3844
  );
3845
+ if (options?.fillDefaults) {
3846
+ normalizedSelection = buildFilledNormalizedSelection(
3847
+ matrix,
3848
+ normalizedSelection,
3849
+ listing
3850
+ );
3851
+ }
2995
3852
  const matchingVariantEntries = getMatchingVariantEntries(
2996
3853
  matrix,
2997
3854
  normalizedSelection
@@ -3020,24 +3877,22 @@ function resolveProductSelectionFromMatrix(matrix, selection = {}, options, cont
3020
3877
  );
3021
3878
  return [
3022
3879
  option.id,
3023
- option.values.map((value) => ({
3024
- valueId: value.id,
3025
- value: value.label,
3026
- slug: value.slug ?? "",
3027
- selected: normalizedSelection.byOptionId[option.id] === value.id,
3028
- available: availableValueIds.has(value.id),
3029
- ...buildAvailableValueStock(
3030
- getCandidateVariantsForValue(
3031
- matrix,
3032
- option.id,
3033
- value.id,
3034
- normalizedSelection.valueIds
3880
+ option.values.map(
3881
+ (value) => buildProductSelectionAvailableValue(
3882
+ value,
3883
+ images,
3884
+ normalizedSelection.byOptionId[option.id] === value.id,
3885
+ availableValueIds.has(value.id),
3886
+ buildAvailableValueStock(
3887
+ getCandidateVariantsForValue(
3888
+ matrix,
3889
+ option.id,
3890
+ value.id,
3891
+ normalizedSelection.valueIds
3892
+ )
3035
3893
  )
3036
- ),
3037
- swatchColor: value.swatchColor ?? null,
3038
- thumbnail: value.thumbnail ?? null,
3039
- images: value.images ?? null
3040
- }))
3894
+ )
3895
+ )
3041
3896
  ];
3042
3897
  })
3043
3898
  );
@@ -3065,7 +3920,8 @@ function resolveProductSelectionFromMatrix(matrix, selection = {}, options, cont
3065
3920
  images,
3066
3921
  listing: {
3067
3922
  primaryImage: listing.primaryImage ?? null
3068
- }
3923
+ },
3924
+ primaryMediaItemId
3069
3925
  },
3070
3926
  selectedVariant,
3071
3927
  matchingVariants,
@@ -3080,6 +3936,78 @@ function resolveProductSelection(detail, selection = {}, options) {
3080
3936
  detail
3081
3937
  });
3082
3938
  }
3939
+ function selectNext(detail, current = {}, optionSlug, valueSlug, options) {
3940
+ const matrix = buildProductOptionMatrixFromDetail(detail);
3941
+ const listing = detail.listing ?? {};
3942
+ const normalizedCurrent = normalizeProductSelectionFromMatrix(
3943
+ matrix,
3944
+ current,
3945
+ options
3946
+ );
3947
+ const option = matrix.optionBySlug.get(optionSlug);
3948
+ if (!option) return normalizedCurrent;
3949
+ const valueMatches = option.values.filter(
3950
+ (candidate) => candidate.slug === valueSlug
3951
+ );
3952
+ if (valueMatches.length !== 1) return normalizedCurrent;
3953
+ const clickedValueId = valueMatches[0].id;
3954
+ const keepClickedSelection = () => {
3955
+ const selectedByOptionId = /* @__PURE__ */ new Map();
3956
+ selectedByOptionId.set(option.id, clickedValueId);
3957
+ for (const otherOptionId of matrix.optionIds) {
3958
+ if (otherOptionId === option.id) continue;
3959
+ const otherValueId = normalizedCurrent.byOptionId[otherOptionId];
3960
+ if (!otherValueId) continue;
3961
+ const constraintIds = normalizeSelectedValueIds(
3962
+ matrix,
3963
+ Array.from(selectedByOptionId.values())
3964
+ );
3965
+ const available = getAvailableOptionValues(
3966
+ matrix,
3967
+ otherOptionId,
3968
+ constraintIds
3969
+ );
3970
+ if (available.some((candidate) => candidate.id === otherValueId)) {
3971
+ selectedByOptionId.set(otherOptionId, otherValueId);
3972
+ }
3973
+ }
3974
+ return buildFilledNormalizedSelection(
3975
+ matrix,
3976
+ normalizedSelectionFromByOptionId(matrix, selectedByOptionId, null),
3977
+ listing
3978
+ );
3979
+ };
3980
+ const keepPriorSelection = () => {
3981
+ const selectedByOptionId = new Map(
3982
+ Object.entries(normalizedCurrent.byOptionId)
3983
+ );
3984
+ selectedByOptionId.delete(option.id);
3985
+ return buildFilledNormalizedSelection(
3986
+ matrix,
3987
+ normalizedSelectionFromByOptionId(matrix, selectedByOptionId, null),
3988
+ listing
3989
+ );
3990
+ };
3991
+ const clickedResult = keepClickedSelection();
3992
+ const clickedVariantId = resolveVariantIdForCompleteSelection(
3993
+ matrix,
3994
+ new Map(Object.entries(clickedResult.byOptionId))
3995
+ );
3996
+ const priorValueIds = Object.entries(normalizedCurrent.byOptionId).filter(([otherOptionId]) => otherOptionId !== option.id).map(([, valueId]) => valueId);
3997
+ const clickedAvailableWithPrior = priorValueIds.length === 0 || getAvailableOptionValues(matrix, option.id, priorValueIds).some(
3998
+ (candidate) => candidate.id === clickedValueId
3999
+ );
4000
+ if (clickedVariantId != null) {
4001
+ const priorClickedValue = normalizedCurrent.byOptionId[option.id];
4002
+ if (priorClickedValue != null && priorClickedValue !== clickedValueId) {
4003
+ return clickedResult;
4004
+ }
4005
+ if (clickedAvailableWithPrior) {
4006
+ return clickedResult;
4007
+ }
4008
+ }
4009
+ return keepPriorSelection();
4010
+ }
3083
4011
  function isProductDetailImageMedia(value) {
3084
4012
  return typeof value === "object" && value !== null;
3085
4013
  }
@@ -3120,18 +4048,47 @@ function joinProductPath(basePath, slug, trailingSlash) {
3120
4048
  function getProductHrefGroupSelection(group, matrix) {
3121
4049
  if (!group) return null;
3122
4050
  if (group.variantId != null) return { variantId: group.variantId };
3123
- const listingVariantId = group.listing?.selectionHintVariant;
3124
4051
  const optionId = group.optionId != null ? String(group.optionId) : group.optionSlug ? matrix?.optionBySlug.get(group.optionSlug)?.id : void 0;
3125
- if (!optionId) {
3126
- return listingVariantId != null ? { variantId: listingVariantId } : null;
3127
- }
4052
+ if (!optionId) return null;
3128
4053
  const option = matrix?.optionById.get(optionId);
3129
4054
  const optionValueId = group.optionValueId != null ? String(group.optionValueId) : group.optionValueSlug && option ? option.values.find((value) => value.slug === group.optionValueSlug)?.id : void 0;
3130
- if (!optionValueId) {
3131
- return listingVariantId != null ? { variantId: listingVariantId } : null;
3132
- }
4055
+ if (!optionValueId) return null;
3133
4056
  return { byOptionId: { [optionId]: optionValueId } };
3134
4057
  }
4058
+ function getProductHrefCodecOptions(options) {
4059
+ return options.emit != null ? { emit: options.emit } : void 0;
4060
+ }
4061
+ function appendGroupByOptionIdHrefParams(params, group, groupSelection, options) {
4062
+ const emit = resolveProductSelectionUrlEmit(options.emit);
4063
+ const byOptionId = groupSelection.byOptionId ?? {};
4064
+ const entries = Object.entries(byOptionId);
4065
+ if (entries.length === 0) return false;
4066
+ for (const [optionId, valueId] of entries) {
4067
+ const optionSlug = group?.optionSlug ?? options.matrix?.optionById.get(optionId)?.slug ?? null;
4068
+ const valueSlug = group?.optionValueSlug ?? options.matrix?.valueById.get(String(valueId))?.slug ?? null;
4069
+ if (emit === "slug-compat" && optionSlug && valueSlug && entries.length === 1) {
4070
+ params.set(`opt.${optionSlug}`, valueSlug);
4071
+ return true;
4072
+ }
4073
+ if (emit === "slug-compat" && options.matrix && appendSlugCompatSelectionParam(
4074
+ params,
4075
+ options.matrix,
4076
+ optionId,
4077
+ String(valueId)
4078
+ )) {
4079
+ continue;
4080
+ }
4081
+ appendCanonicalSelectionParam(params, optionId, String(valueId));
4082
+ }
4083
+ return params.size > 0;
4084
+ }
4085
+ function getPreferCompleteVariantFromHintSelection(group, options) {
4086
+ if (!options.preferCompleteVariantFromHint) return null;
4087
+ if (group?.optionValueId != null || group?.optionValueSlug) return null;
4088
+ const hintVariantId = group?.listing?.selectionHintVariant;
4089
+ if (hintVariantId == null) return null;
4090
+ return { variantId: hintVariantId };
4091
+ }
3135
4092
  function buildProductHref(product, group, options = {}) {
3136
4093
  const path = joinProductPath(
3137
4094
  options.basePath ?? "/products",
@@ -3140,23 +4097,46 @@ function buildProductHref(product, group, options = {}) {
3140
4097
  );
3141
4098
  const params = new URLSearchParams();
3142
4099
  if (options.detail && options.selection) {
3143
- const selection = stringifyProductSelection(options.detail, options.selection);
4100
+ const selection = stringifyProductSelection(
4101
+ options.detail,
4102
+ options.selection,
4103
+ getProductHrefCodecOptions(options)
4104
+ );
3144
4105
  return selection ? `${path}?${selection}` : path;
3145
4106
  }
4107
+ const preferVariantSelection = getPreferCompleteVariantFromHintSelection(
4108
+ group,
4109
+ options
4110
+ );
4111
+ if (preferVariantSelection) {
4112
+ if (options.detail) {
4113
+ const selection = stringifyProductSelection(
4114
+ options.detail,
4115
+ preferVariantSelection,
4116
+ getProductHrefCodecOptions(options)
4117
+ );
4118
+ return selection ? `${path}?${selection}` : path;
4119
+ }
4120
+ if (preferVariantSelection.variantId != null) {
4121
+ params.set("variant", String(preferVariantSelection.variantId));
4122
+ return `${path}?${params.toString()}`;
4123
+ }
4124
+ }
3146
4125
  const groupSelection = getProductHrefGroupSelection(group, options.matrix);
3147
4126
  if (groupSelection) {
3148
4127
  if (options.detail) {
3149
- const selection = stringifyProductSelection(options.detail, groupSelection);
4128
+ const selection = stringifyProductSelection(
4129
+ options.detail,
4130
+ groupSelection,
4131
+ getProductHrefCodecOptions(options)
4132
+ );
3150
4133
  return selection ? `${path}?${selection}` : path;
3151
4134
  }
3152
4135
  if (groupSelection.variantId != null) {
3153
4136
  params.set("variant", String(groupSelection.variantId));
3154
4137
  return `${path}?${params.toString()}`;
3155
4138
  }
3156
- const [selectionEntry] = Object.entries(groupSelection.byOptionId ?? {});
3157
- if (selectionEntry) {
3158
- const [optionId, valueId] = selectionEntry;
3159
- params.set(`opt.${optionId}`, String(valueId));
4139
+ if (appendGroupByOptionIdHrefParams(params, group, groupSelection, options)) {
3160
4140
  return `${path}?${params.toString()}`;
3161
4141
  }
3162
4142
  }
@@ -3183,6 +4163,26 @@ function isVariantAvailableForSale(variant) {
3183
4163
  if (variant.isUnlimited) return true;
3184
4164
  return (variant.stock ?? 0) - (variant.reservedStock ?? 0) > 0;
3185
4165
  }
4166
+ function sortVariantsForMediaSelection(variants) {
4167
+ const orderedVariants = [...variants].sort(compareVariantOrder);
4168
+ const activeVariants = orderedVariants.filter(
4169
+ (variant) => variant.isActive !== false
4170
+ );
4171
+ const availableVariants = activeVariants.filter(isVariantAvailableForSale);
4172
+ const unavailableActiveVariants = activeVariants.filter(
4173
+ (variant) => !isVariantAvailableForSale(variant)
4174
+ );
4175
+ return [...availableVariants, ...unavailableActiveVariants];
4176
+ }
4177
+ function variantHasPoolMedia(variant, productMediaPool) {
4178
+ if (!variant?.images?.length) return false;
4179
+ return variant.images.some((image) => {
4180
+ const imageId = getRelationID(image);
4181
+ return Boolean(
4182
+ imageId && productMediaPool.some((poolItem) => getRelationID(poolItem) === imageId)
4183
+ );
4184
+ });
4185
+ }
3186
4186
  function getMinMax(values) {
3187
4187
  const numbers = values.filter(
3188
4188
  (value) => typeof value === "number"
@@ -3208,11 +4208,28 @@ function buildProductListingProjection(product, variants) {
3208
4208
  const { min: minCompareAtPrice, max: maxCompareAtPrice } = getMinMax(
3209
4209
  activeVariants.map((variant) => variant.compareAtPrice)
3210
4210
  );
3211
- const productPrimaryImage = extractEntityId(product?.thumbnail) ?? getFirstMediaId(product?.images);
3212
- const variantPrimaryImage = getVariantPrimaryImage(selectionHintVariant) ?? getVariantPrimaryImage(activeVariants[0]) ?? getVariantPrimaryImage(orderedVariants[0]);
4211
+ const productMediaPool = product?.images ?? [];
4212
+ const selectionHintHasPoolMedia = variantHasPoolMedia(
4213
+ selectionHintVariant,
4214
+ productMediaPool
4215
+ );
4216
+ const mediaSelectionVariants = sortVariantsForMediaSelection(variants);
4217
+ const resolvedProductMedia = resolveProductSelectionMedia({
4218
+ productMediaPool,
4219
+ productPrimaryMediaItemId: getRelationID(product?.primaryMediaItemId),
4220
+ selectedVariant: selectionHintVariant && selectionHintHasPoolMedia ? {
4221
+ id: selectionHintVariant.id,
4222
+ images: selectionHintVariant.images
4223
+ } : null,
4224
+ matchingVariants: selectionHintHasPoolMedia ? [] : mediaSelectionVariants
4225
+ });
3213
4226
  return {
3214
4227
  selectionHintVariant: getRelationID(selectionHintVariant?.id) ?? null,
3215
- primaryImage: productPrimaryImage ?? variantPrimaryImage,
4228
+ primaryImage: resolveGenericListingPrimaryImage(
4229
+ product,
4230
+ resolvedProductMedia.primaryImage,
4231
+ resolvedProductMedia.source
4232
+ ),
3216
4233
  minPrice,
3217
4234
  maxPrice,
3218
4235
  minCompareAtPrice,
@@ -3231,7 +4248,33 @@ function buildProductListingCard(item, options = {}) {
3231
4248
  variants,
3232
4249
  selectionHintVariant
3233
4250
  );
3234
- const primaryImage = firstMedia(product.thumbnail) ?? firstMedia(product.images ?? null) ?? firstMedia(representativeVariant?.thumbnail) ?? firstMedia(representativeVariant?.images) ?? firstMedia(product.listing?.primaryImage) ?? firstMedia(projectedListing.primaryImage) ?? null;
4251
+ const productMediaPool = mediaArray2(product.images);
4252
+ const representativeHasPoolMedia = Boolean(
4253
+ representativeVariant?.images?.some(
4254
+ (image) => productMediaPool.some(
4255
+ (poolItem) => getRelationID(poolItem) === getRelationID(image)
4256
+ )
4257
+ )
4258
+ );
4259
+ const resolvedPrimaryMedia = resolveProductSelectionMedia(
4260
+ {
4261
+ productMediaPool,
4262
+ productPrimaryMediaItemId: getRelationID(product.primaryMediaItemId),
4263
+ selectedVariant: representativeHasPoolMedia ? representativeVariant : null,
4264
+ matchingVariants: representativeHasPoolMedia ? [] : variants
4265
+ }
4266
+ );
4267
+ const listingPrimaryPointer = resolveListingPrimaryImagePointer({
4268
+ productMediaPool,
4269
+ productPrimaryMediaItemId: getRelationID(product.primaryMediaItemId),
4270
+ productThumbnail: product.thumbnail ?? null,
4271
+ listingPrimaryImage: product.listing?.primaryImage ?? null,
4272
+ resolvedPrimary: resolvedPrimaryMedia.primaryImage,
4273
+ resolvedSource: resolvedPrimaryMedia.source
4274
+ });
4275
+ const listingPrimaryMedia = listingPrimaryPointer ? productMediaPool.find(
4276
+ (item2) => getRelationID(item2) === listingPrimaryPointer
4277
+ ) ?? resolvedPrimaryMedia.primaryImage ?? null : null;
3235
4278
  const priceRange = aggregateListingPriceRange(groups);
3236
4279
  const availableForSale = groups.some(
3237
4280
  (group) => group.listing.availableForSale
@@ -3246,7 +4289,7 @@ function buildProductListingCard(item, options = {}) {
3246
4289
  ),
3247
4290
  title: product.title,
3248
4291
  representativeVariant,
3249
- primaryImage,
4292
+ primaryImage: listingPrimaryMedia,
3250
4293
  priceRange,
3251
4294
  availableForSale,
3252
4295
  swatches
@@ -3294,17 +4337,16 @@ function aggregateListingPriceRange(groups) {
3294
4337
  };
3295
4338
  }
3296
4339
  function buildListingSwatch(product, group, options) {
3297
- const thumbnail = firstMedia(group.optionValueThumbnail) ?? firstMedia(group.optionValueImages) ?? null;
3298
4340
  return {
3299
4341
  optionId: group.optionId,
3300
4342
  optionValueId: group.optionValueId,
3301
4343
  label: group.optionValueLabel,
3302
- swatchColor: group.optionValueSwatchColor ?? null,
3303
- thumbnail,
4344
+ swatch: group.optionValueSwatch ?? null,
3304
4345
  href: buildProductHref(
3305
4346
  { slug: product.slug },
3306
4347
  {
3307
4348
  optionId: group.optionId,
4349
+ optionSlug: group.optionSlug,
3308
4350
  optionValueId: group.optionValueId,
3309
4351
  optionValueSlug: group.optionValueSlug,
3310
4352
  listing: group.listing
@@ -3339,19 +4381,34 @@ function buildProductListingGroupsByOption(args) {
3339
4381
  return [];
3340
4382
  }
3341
4383
  const listingBase = buildProductListingProjection(void 0, variants);
3342
- const optionValuePrimaryImage = extractEntityId(value.thumbnail) ?? getFirstMediaId(value.images);
3343
- const productFallbackImage = extractEntityId(args.product?.thumbnail) ?? getFirstMediaId(args.product?.images);
3344
- const groupPrimaryImage = getFirstAvailableVariantPrimaryImage(variants) ?? optionValuePrimaryImage ?? productFallbackImage;
4384
+ const orderedVariants = sortVariantsForMediaSelection(variants);
4385
+ const productMediaPool = (args.product?.images ?? []).filter(
4386
+ (image) => image != null && typeof image === "object"
4387
+ );
4388
+ const resolvedMedia = resolveProductSelectionMedia({
4389
+ productMediaPool,
4390
+ productPrimaryMediaItemId: extractEntityId(
4391
+ args.product?.primaryMediaItemId ?? null
4392
+ ),
4393
+ selectedVariant: null,
4394
+ matchingVariants: orderedVariants,
4395
+ selectedOptionValues: [
4396
+ {
4397
+ id: value.id,
4398
+ swatch: normalizeMatrixSwatch(value.swatch)
4399
+ }
4400
+ ]
4401
+ });
4402
+ const groupPrimaryImage = extractEntityId(resolvedMedia.primaryImage) ?? getFirstAvailableVariantPrimaryImage(variants) ?? extractEntityId(args.product?.thumbnail) ?? getFirstMediaId(args.product?.images);
3345
4403
  return [
3346
4404
  {
3347
4405
  optionId: primaryOption.id,
3348
4406
  optionTitle: primaryOption.title,
4407
+ optionSlug: primaryOption.slug,
3349
4408
  optionValueId: value.id,
3350
4409
  optionValueLabel: value.label,
3351
4410
  optionValueSlug: value.slug,
3352
- optionValueSwatchColor: value.swatchColor ?? null,
3353
- optionValueThumbnail: value.thumbnail ?? null,
3354
- optionValueImages: value.images ?? null,
4411
+ optionValueSwatch: value.swatch ?? null,
3355
4412
  variantIds: variants.map((variant) => String(variant.id)),
3356
4413
  variantCount: variants.length,
3357
4414
  variants,
@@ -3364,6 +4421,162 @@ function buildProductListingGroupsByOption(args) {
3364
4421
  });
3365
4422
  }
3366
4423
 
4424
+ // src/utils/product-media.ts
4425
+ function mediaPointerOptionValues(values) {
4426
+ return (values ?? []).filter((value) => value != null && value !== "").map((value) => ({
4427
+ swatch: {
4428
+ type: "media",
4429
+ mediaItemId: value
4430
+ }
4431
+ }));
4432
+ }
4433
+ function resolveProductMedia(input) {
4434
+ const resolved = resolveProductSelectionMedia({
4435
+ ...input,
4436
+ selectedVariant: input.selectedVariant ?? (input.variantFeaturedMediaItemId ? { images: [input.variantFeaturedMediaItemId] } : null),
4437
+ selectedOptionValues: input.selectedOptionValues ?? mediaPointerOptionValues(input.selectedOptionValueMediaItemIds)
4438
+ });
4439
+ if (resolved.source !== "none") {
4440
+ return {
4441
+ ...resolved,
4442
+ source: resolved.source === "variant_media_selected" ? "variant_featured" : resolved.source
4443
+ };
4444
+ }
4445
+ const display = resolveProductDisplayMedia({
4446
+ productMediaPool: input.productMediaPool,
4447
+ productPrimaryMediaItemId: input.productPrimaryMediaItemId
4448
+ });
4449
+ return {
4450
+ primaryImage: display.primaryImage,
4451
+ images: display.images,
4452
+ source: display.source
4453
+ };
4454
+ }
4455
+
4456
+ // src/utils/product-gallery.ts
4457
+ function mediaId(value) {
4458
+ if (typeof value === "string" || typeof value === "number") {
4459
+ return String(value);
4460
+ }
4461
+ if (typeof value === "object" && value !== null && "id" in value) {
4462
+ const id = value.id;
4463
+ if (typeof id === "string" || typeof id === "number") return String(id);
4464
+ }
4465
+ return null;
4466
+ }
4467
+ function relationshipIds(values) {
4468
+ if (!Array.isArray(values)) return [];
4469
+ return values.map((value) => mediaId(value)).filter((value) => Boolean(value));
4470
+ }
4471
+ function buildPoolById2(pool) {
4472
+ const poolById = /* @__PURE__ */ new Map();
4473
+ for (const item of pool) {
4474
+ const id = mediaId(item);
4475
+ if (id) poolById.set(id, item);
4476
+ }
4477
+ return poolById;
4478
+ }
4479
+ function mediaSetItemsInPool(mediaSet, poolById) {
4480
+ const seen = /* @__PURE__ */ new Set();
4481
+ const items = [];
4482
+ const primaryId = mediaId(mediaSet.primaryMediaItemId);
4483
+ if (primaryId) {
4484
+ const primary = poolById.get(primaryId);
4485
+ if (primary) {
4486
+ seen.add(primaryId);
4487
+ items.push(primary);
4488
+ }
4489
+ }
4490
+ for (const itemId of relationshipIds(mediaSet.items)) {
4491
+ if (seen.has(itemId)) continue;
4492
+ const item = poolById.get(itemId);
4493
+ if (!item) continue;
4494
+ seen.add(itemId);
4495
+ items.push(item);
4496
+ }
4497
+ return items;
4498
+ }
4499
+ function resolveLegacyMediaSet(input) {
4500
+ if (!Array.isArray(input.mediaSets)) return null;
4501
+ const pool = input.productMediaPool ?? input.pool ?? [];
4502
+ const poolById = buildPoolById2(pool);
4503
+ const selectedVariantId = mediaId(input.selectedVariantId);
4504
+ if (selectedVariantId) {
4505
+ const exactSet = input.mediaSets.find(
4506
+ (set) => set.matchType === "exact-variant" && relationshipIds(set.variantIds).includes(selectedVariantId)
4507
+ );
4508
+ if (exactSet) {
4509
+ const images = mediaSetItemsInPool(exactSet, poolById);
4510
+ if (images.length > 0) {
4511
+ return {
4512
+ primaryImage: images[0] ?? null,
4513
+ images,
4514
+ source: "exact_variant_set"
4515
+ };
4516
+ }
4517
+ }
4518
+ }
4519
+ const selectedOptionValueIds = new Set(
4520
+ relationshipIds(input.selectedOptionValueIds)
4521
+ );
4522
+ const optionSetMatches = input.mediaSets.filter((set) => set.matchType === "option-values").map((set) => {
4523
+ const optionValueIds = relationshipIds(set.optionValueIds);
4524
+ if (optionValueIds.length === 0) return null;
4525
+ if (!optionValueIds.every((id) => selectedOptionValueIds.has(id))) {
4526
+ return null;
4527
+ }
4528
+ const images = mediaSetItemsInPool(set, poolById);
4529
+ if (images.length === 0) return null;
4530
+ return { optionValueCount: optionValueIds.length, images };
4531
+ }).filter(
4532
+ (match) => Boolean(match)
4533
+ ).sort((a, b) => b.optionValueCount - a.optionValueCount);
4534
+ if (optionSetMatches.length > 0) {
4535
+ const images = optionSetMatches[0].images;
4536
+ return {
4537
+ primaryImage: images[0] ?? null,
4538
+ images,
4539
+ source: "option_value_set"
4540
+ };
4541
+ }
4542
+ const defaultSet = input.mediaSets.find((set) => set.matchType === "default");
4543
+ if (defaultSet) {
4544
+ const images = mediaSetItemsInPool(defaultSet, poolById);
4545
+ if (images.length > 0) {
4546
+ return {
4547
+ primaryImage: images[0] ?? null,
4548
+ images,
4549
+ source: "default_set"
4550
+ };
4551
+ }
4552
+ }
4553
+ return {
4554
+ primaryImage: null,
4555
+ images: [],
4556
+ source: "none"
4557
+ };
4558
+ }
4559
+ function resolveProductGallery(input) {
4560
+ const legacyResolved = resolveLegacyMediaSet(input);
4561
+ if (legacyResolved && legacyResolved.source !== "none") return legacyResolved;
4562
+ const selectedVariantId = mediaId(input.selectedVariantId);
4563
+ const selectedOptionValueIds = relationshipIds(input.selectedOptionValueIds);
4564
+ const selection = resolveProductSelectionMedia({
4565
+ ...input,
4566
+ productMediaPool: input.productMediaPool ?? input.pool ?? null,
4567
+ selectedVariant: input.selectedVariant ?? (selectedVariantId ? { id: selectedVariantId } : null),
4568
+ selectedOptionValues: input.selectedOptionValues ?? selectedOptionValueIds.map((id) => ({ id }))
4569
+ });
4570
+ if (selection.source !== "none") {
4571
+ return selection;
4572
+ }
4573
+ return resolveProductDisplayMedia({
4574
+ productMediaPool: input.productMediaPool ?? input.pool ?? null,
4575
+ productPrimaryMediaItemId: input.productPrimaryMediaItemId,
4576
+ listingPrimaryImage: input.listingPrimaryImage
4577
+ });
4578
+ }
4579
+
3367
4580
  // src/utils/image.ts
3368
4581
  var IMAGE_SIZES = [384, 768, 1536];
3369
4582
  function getImageUrl(image, displayWidth, dpr = 1) {
@@ -3670,6 +4883,7 @@ export {
3670
4883
  CustomerAuth,
3671
4884
  CustomerNamespace,
3672
4885
  DiscountApi,
4886
+ EventsClient,
3673
4887
  GoneError,
3674
4888
  IMAGE_SIZES,
3675
4889
  INTERNAL_COLLECTIONS,
@@ -3677,6 +4891,8 @@ export {
3677
4891
  NotFoundError,
3678
4892
  ORDER_CHANGED_EVENT_TYPE,
3679
4893
  OrderApi,
4894
+ PRODUCT_UPSERT_READONLY_FIELD_REASON,
4895
+ PRODUCT_UPSERT_UNKNOWN_FIELD_REASON,
3680
4896
  PermissionError,
3681
4897
  ProductApi,
3682
4898
  ProductSelectionCodecError,
@@ -3736,6 +4952,7 @@ export {
3736
4952
  isNotFoundError,
3737
4953
  isOrderChangedWebhookEvent,
3738
4954
  isPermissionError,
4955
+ isProductUpsertFieldValidationErrorBody,
3739
4956
  isRateLimitError,
3740
4957
  isSDKError,
3741
4958
  isServiceUnavailableError,
@@ -3745,14 +4962,22 @@ export {
3745
4962
  isValidationError,
3746
4963
  isWebhookCollection,
3747
4964
  isWebhookOperation,
4965
+ mergeProductDetailWithStock,
3748
4966
  normalizeProductSelection,
3749
4967
  normalizeProductSelectionFromMatrix,
3750
4968
  normalizeSelectedValueIds,
3751
4969
  parseProductSelection,
4970
+ resolveListingPrimaryImagePointer,
4971
+ resolveProductDisplayMedia,
4972
+ resolveProductGallery,
4973
+ resolveProductMedia,
3752
4974
  resolveProductSelection,
3753
4975
  resolveProductSelectionFromMatrix,
4976
+ resolveProductSelectionMedia,
3754
4977
  resolveRelation,
3755
4978
  resolveVariantForSelection,
4979
+ selectNext,
4980
+ selectedSwatchMediaItemId,
3756
4981
  stringifyProductSelection
3757
4982
  };
3758
4983
  //# sourceMappingURL=index.js.map