@01.software/sdk 0.32.0 → 0.33.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 (46) hide show
  1. package/README.md +43 -20
  2. package/dist/client.cjs +31 -2
  3. package/dist/client.cjs.map +1 -1
  4. package/dist/client.d.cts +6 -6
  5. package/dist/client.d.ts +6 -6
  6. package/dist/client.js +31 -2
  7. package/dist/client.js.map +1 -1
  8. package/dist/{collection-client-DPGXnhoF.d.ts → collection-client-B6SlhzIP.d.ts} +3 -3
  9. package/dist/{collection-client-CORhppPb.d.cts → collection-client-De6eKW1J.d.cts} +3 -3
  10. package/dist/{const-Brk2Ff0q.d.cts → const-DwmSDeWq.d.ts} +2 -2
  11. package/dist/{const-DcY2_z9O.d.ts → const-sPR2IkCe.d.cts} +2 -2
  12. package/dist/index.cjs +256 -90
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +7 -7
  15. package/dist/index.d.ts +7 -7
  16. package/dist/index.js +256 -90
  17. package/dist/index.js.map +1 -1
  18. package/dist/{payload-types-DVK1QCeU.d.cts → payload-types-dkeQyrDC.d.cts} +1562 -1436
  19. package/dist/{payload-types-DVK1QCeU.d.ts → payload-types-dkeQyrDC.d.ts} +1562 -1436
  20. package/dist/query.cjs.map +1 -1
  21. package/dist/query.d.cts +9 -9
  22. package/dist/query.d.ts +9 -9
  23. package/dist/query.js.map +1 -1
  24. package/dist/realtime.d.cts +2 -2
  25. package/dist/realtime.d.ts +2 -2
  26. package/dist/server.cjs +37 -6
  27. package/dist/server.cjs.map +1 -1
  28. package/dist/server.d.cts +7 -7
  29. package/dist/server.d.ts +7 -7
  30. package/dist/server.js +37 -6
  31. package/dist/server.js.map +1 -1
  32. package/dist/{types-ByMrR_Z_.d.cts → types-B3YT092I.d.cts} +1 -1
  33. package/dist/{types-CYMSBkJC.d.ts → types-BHh0YLmq.d.ts} +27 -10
  34. package/dist/{types-CAkWqIr6.d.cts → types-BZKxss8Y.d.cts} +27 -10
  35. package/dist/{types-DUPC7Xn6.d.ts → types-Cel_4L9t.d.ts} +1 -1
  36. package/dist/ui/form.d.cts +1 -1
  37. package/dist/ui/form.d.ts +1 -1
  38. package/dist/ui/video.d.cts +1 -1
  39. package/dist/ui/video.d.ts +1 -1
  40. package/dist/webhook.cjs +94 -0
  41. package/dist/webhook.cjs.map +1 -1
  42. package/dist/webhook.d.cts +82 -7
  43. package/dist/webhook.d.ts +82 -7
  44. package/dist/webhook.js +94 -0
  45. package/dist/webhook.js.map +1 -1
  46. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
- import { D as DebugConfig, R as RetryConfig, A as ApiQueryOptions, P as PayloadFindResponse, g as PayloadMutationResponse } from './types-CYMSBkJC.js';
1
+ import { D as DebugConfig, R as RetryConfig, A as ApiQueryOptions, P as PayloadFindResponse, g as PayloadMutationResponse } from './types-BHh0YLmq.js';
2
2
  import { GenerateMetadataOptions, Metadata } from './metadata.js';
3
- import { c as ServerCollection, P as PublicCollection } from './const-DcY2_z9O.js';
4
- import { C as CollectionType } from './types-DUPC7Xn6.js';
3
+ import { c as ServerCollection, P as PublicCollection } from './const-DwmSDeWq.js';
4
+ import { C as CollectionType } from './types-Cel_4L9t.js';
5
5
 
6
6
  interface FetchOptions extends RequestInit {
7
7
  apiUrl?: string;
@@ -1,7 +1,7 @@
1
- import { D as DebugConfig, R as RetryConfig, A as ApiQueryOptions, P as PayloadFindResponse, g as PayloadMutationResponse } from './types-CAkWqIr6.cjs';
1
+ import { D as DebugConfig, R as RetryConfig, A as ApiQueryOptions, P as PayloadFindResponse, g as PayloadMutationResponse } from './types-BZKxss8Y.cjs';
2
2
  import { GenerateMetadataOptions, Metadata } from './metadata.cjs';
3
- import { c as ServerCollection, P as PublicCollection } from './const-Brk2Ff0q.cjs';
4
- import { C as CollectionType } from './types-ByMrR_Z_.cjs';
3
+ import { c as ServerCollection, P as PublicCollection } from './const-sPR2IkCe.cjs';
4
+ import { C as CollectionType } from './types-B3YT092I.cjs';
5
5
 
6
6
  interface FetchOptions extends RequestInit {
7
7
  apiUrl?: string;
@@ -1,4 +1,4 @@
1
- import { e as Config } from './payload-types-DVK1QCeU.cjs';
1
+ import { e as Config } from './payload-types-dkeQyrDC.js';
2
2
 
3
3
  /**
4
4
  * Collection type derived from Payload Config.
@@ -9,7 +9,7 @@ type Collection = keyof Config['collections'];
9
9
  * Internal collections that should not be exposed via SDK.
10
10
  * Includes Payload system collections and admin-only collections.
11
11
  */
12
- declare const INTERNAL_COLLECTIONS: readonly ["users", "payload-kv", "payload-locked-documents", "payload-preferences", "payload-migrations", "payload-folders", "field-configs", "system-media", "track-assets", "audiences", "email-logs", "api-usage", "tenant-analytics-daily", "tenant-web-analytics-config", "analytics-event-schemas", "subscriptions", "billing-history", "inventory-reservations", "product-collection-items", "order-status-logs", "api-keys", "personal-access-tokens", "tenant-entitlements", "tenant-purge-jobs", "direct-upload-sessions", "webhook-events", "webhook-deliveries", "audit-logs", "plans", "webhooks", "event-registrations"];
12
+ declare const INTERNAL_COLLECTIONS: readonly ["users", "payload-kv", "payload-locked-documents", "payload-preferences", "payload-migrations", "payload-folders", "field-configs", "system-media", "track-assets", "audiences", "email-logs", "api-usage", "tenant-analytics-daily", "tenant-web-analytics-config", "analytics-event-schemas", "subscriptions", "billing-history", "inventory-reservations", "commerce-notification-intents", "product-collection-items", "order-status-logs", "api-keys", "personal-access-tokens", "tenant-entitlements", "tenant-purge-jobs", "direct-upload-sessions", "webhook-events", "webhook-deliveries", "audit-logs", "plans", "webhooks", "event-registrations"];
13
13
  /**
14
14
  * Array of all public collection names for runtime use (e.g., Zod enum validation).
15
15
  * This is the single source of truth for which collections are publicly accessible via SDK.
@@ -1,4 +1,4 @@
1
- import { e as Config } from './payload-types-DVK1QCeU.js';
1
+ import { e as Config } from './payload-types-dkeQyrDC.cjs';
2
2
 
3
3
  /**
4
4
  * Collection type derived from Payload Config.
@@ -9,7 +9,7 @@ type Collection = keyof Config['collections'];
9
9
  * Internal collections that should not be exposed via SDK.
10
10
  * Includes Payload system collections and admin-only collections.
11
11
  */
12
- declare const INTERNAL_COLLECTIONS: readonly ["users", "payload-kv", "payload-locked-documents", "payload-preferences", "payload-migrations", "payload-folders", "field-configs", "system-media", "track-assets", "audiences", "email-logs", "api-usage", "tenant-analytics-daily", "tenant-web-analytics-config", "analytics-event-schemas", "subscriptions", "billing-history", "inventory-reservations", "product-collection-items", "order-status-logs", "api-keys", "personal-access-tokens", "tenant-entitlements", "tenant-purge-jobs", "direct-upload-sessions", "webhook-events", "webhook-deliveries", "audit-logs", "plans", "webhooks", "event-registrations"];
12
+ declare const INTERNAL_COLLECTIONS: readonly ["users", "payload-kv", "payload-locked-documents", "payload-preferences", "payload-migrations", "payload-folders", "field-configs", "system-media", "track-assets", "audiences", "email-logs", "api-usage", "tenant-analytics-daily", "tenant-web-analytics-config", "analytics-event-schemas", "subscriptions", "billing-history", "inventory-reservations", "commerce-notification-intents", "product-collection-items", "order-status-logs", "api-keys", "personal-access-tokens", "tenant-entitlements", "tenant-purge-jobs", "direct-upload-sessions", "webhook-events", "webhook-deliveries", "audit-logs", "plans", "webhooks", "event-registrations"];
13
13
  /**
14
14
  * Array of all public collection names for runtime use (e.g., Zod enum validation).
15
15
  * This is the single source of truth for which collections are publicly accessible via SDK.
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,
@@ -62,6 +65,7 @@ __export(src_exports, {
62
65
  createAnalytics: () => createAnalytics,
63
66
  createAuthError: () => createAuthError,
64
67
  createClient: () => createClient2,
68
+ createCommerceEmailWebhookHandler: () => createCommerceEmailWebhookHandler,
65
69
  createConflictError: () => createConflictError,
66
70
  createCustomerAuthWebhookHandler: () => createCustomerAuthWebhookHandler,
67
71
  createNotFoundError: () => createNotFoundError,
@@ -69,9 +73,11 @@ __export(src_exports, {
69
73
  createProductSelectionCodec: () => createProductSelectionCodec,
70
74
  createRateLimitError: () => createRateLimitError,
71
75
  createTypedWebhookHandler: () => createTypedWebhookHandler,
76
+ defineCommerceEmailConfig: () => defineCommerceEmailConfig,
72
77
  formatOrderName: () => formatOrderName,
73
78
  generateOrderNumber: () => generateOrderNumber,
74
79
  getAvailableOptionValues: () => getAvailableOptionValues,
80
+ getCommerceNotificationIdempotencyKey: () => getCommerceNotificationIdempotencyKey,
75
81
  getImageLqip: () => getImageLqip,
76
82
  getImagePalette: () => getImagePalette,
77
83
  getImagePlaceholderStyle: () => getImagePlaceholderStyle,
@@ -87,6 +93,7 @@ __export(src_exports, {
87
93
  handleWebhook: () => handleWebhook,
88
94
  isApiError: () => isApiError,
89
95
  isAuthError: () => isAuthError,
96
+ isCommerceNotificationWebhookEvent: () => isCommerceNotificationWebhookEvent,
90
97
  isConfigError: () => isConfigError,
91
98
  isConflictError: () => isConflictError,
92
99
  isCustomerPasswordResetWebhookEvent: () => isCustomerPasswordResetWebhookEvent,
@@ -1528,6 +1535,117 @@ var CartApi = class {
1528
1535
  }
1529
1536
  };
1530
1537
 
1538
+ // src/core/api/base-api.ts
1539
+ var BaseApi = class {
1540
+ constructor(apiName, options) {
1541
+ if (!options.secretKey) {
1542
+ throw createConfigError(`secretKey is required for ${apiName}.`);
1543
+ }
1544
+ this.publishableKey = requirePublishableKeyForSecret(
1545
+ apiName,
1546
+ options.publishableKey,
1547
+ options.secretKey
1548
+ );
1549
+ this.secretKey = options.secretKey;
1550
+ this.apiUrl = options.apiUrl;
1551
+ this.onRequestId = options.onRequestId;
1552
+ }
1553
+ async request(endpoint, body, options) {
1554
+ const method = options?.method ?? "POST";
1555
+ try {
1556
+ const response = await httpFetch(endpoint, {
1557
+ method,
1558
+ apiUrl: this.apiUrl,
1559
+ publishableKey: this.publishableKey,
1560
+ secretKey: this.secretKey,
1561
+ ...body !== void 0 && { body: JSON.stringify(body) },
1562
+ ...options?.headers && { headers: options.headers }
1563
+ });
1564
+ this.onRequestId?.(response.headers.get("x-request-id") ?? null);
1565
+ return parseApiResponse(response, endpoint);
1566
+ } catch (err) {
1567
+ const id = err instanceof SDKError ? err.requestId ?? null : null;
1568
+ this.onRequestId?.(id);
1569
+ throw err;
1570
+ }
1571
+ }
1572
+ };
1573
+
1574
+ // src/core/api/product-api.ts
1575
+ var PRODUCT_DETAIL_UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
1576
+ "not_found",
1577
+ "not_published",
1578
+ "feature_disabled"
1579
+ ]);
1580
+ function isRecord(value) {
1581
+ return typeof value === "object" && value !== null;
1582
+ }
1583
+ function readProductDetailUnavailableReason(value) {
1584
+ if (!isRecord(value)) return void 0;
1585
+ const directReason = value.reason ?? value.code;
1586
+ if (typeof directReason === "string" && PRODUCT_DETAIL_UNAVAILABLE_REASONS.has(directReason)) {
1587
+ return directReason;
1588
+ }
1589
+ return readProductDetailUnavailableReason(value.body);
1590
+ }
1591
+ function productDetailResultFromError(error) {
1592
+ if (!(error instanceof SDKError) || error.status !== 404) return void 0;
1593
+ const reason = readProductDetailUnavailableReason(error.details);
1594
+ if (!reason) return void 0;
1595
+ return { found: false, reason };
1596
+ }
1597
+ var ProductApi = class extends BaseApi {
1598
+ constructor(options) {
1599
+ super("ProductApi", options);
1600
+ }
1601
+ /**
1602
+ * Check point-in-time stock availability for one or more product variants.
1603
+ * Results reflect available stock at the moment of the call and are not guaranteed
1604
+ * to remain available by the time an order is placed.
1605
+ */
1606
+ stockCheck(params) {
1607
+ return this.request("/api/products/stock-check", params);
1608
+ }
1609
+ listingGroups(params) {
1610
+ return this.request(
1611
+ "/api/products/listing-groups",
1612
+ params
1613
+ );
1614
+ }
1615
+ /**
1616
+ * Fetch full product detail by slug or id.
1617
+ * Returns a discriminated result so storefronts can distinguish missing,
1618
+ * unpublished, and feature-disabled products.
1619
+ *
1620
+ * Only product-detail 404 responses carrying one of those allowlisted reasons
1621
+ * are mapped to `{ found: false, reason }`. Unknown or uncoded 404s, plus
1622
+ * permission/auth errors such as tenant mismatch, continue to throw typed SDK
1623
+ * errors instead of being collapsed into a storefront absence result.
1624
+ */
1625
+ async detail(params) {
1626
+ try {
1627
+ const product = await this.request(
1628
+ "/api/products/detail",
1629
+ params
1630
+ );
1631
+ return { found: true, product };
1632
+ } catch (err) {
1633
+ const notFoundResult = productDetailResultFromError(err);
1634
+ if (notFoundResult) return notFoundResult;
1635
+ throw err;
1636
+ }
1637
+ }
1638
+ /**
1639
+ * Atomically create or update a product together with its options,
1640
+ * option-values, and variants in a single transaction. Mirrors Shopify's
1641
+ * `productSet` shape and is the canonical write path for the MCP
1642
+ * `product-upsert` tool.
1643
+ */
1644
+ upsert(params) {
1645
+ return this.request("/api/products/upsert", params);
1646
+ }
1647
+ };
1648
+
1531
1649
  // src/core/commerce/commerce-client.ts
1532
1650
  var CommerceClient = class {
1533
1651
  constructor(options) {
@@ -1562,9 +1680,14 @@ var CommerceClient = class {
1562
1680
  listingGroups: (params) => execute("/api/products/listing-groups", params),
1563
1681
  detail: async (params) => {
1564
1682
  try {
1565
- return await execute("/api/products/detail", params);
1683
+ const product = await execute(
1684
+ "/api/products/detail",
1685
+ params
1686
+ );
1687
+ return { found: true, product };
1566
1688
  } catch (err) {
1567
- if (err instanceof NotFoundError) return null;
1689
+ const notFoundResult = productDetailResultFromError(err);
1690
+ if (notFoundResult) return notFoundResult;
1568
1691
  throw err;
1569
1692
  }
1570
1693
  }
@@ -1656,42 +1779,6 @@ function createClient(options) {
1656
1779
  return new Client(options);
1657
1780
  }
1658
1781
 
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
1782
  // src/core/api/order-api.ts
1696
1783
  var OrderApi = class extends BaseApi {
1697
1784
  constructor(options) {
@@ -1724,7 +1811,7 @@ var OrderApi = class extends BaseApi {
1724
1811
  }
1725
1812
  bulkImportFulfillments(params) {
1726
1813
  return this.request(
1727
- "/api/orders/bulk-import-fulfillments",
1814
+ "/api/fulfillments/bulk-import",
1728
1815
  params
1729
1816
  );
1730
1817
  }
@@ -1762,62 +1849,27 @@ var ShippingApi = class extends BaseApi {
1762
1849
  }
1763
1850
  };
1764
1851
 
1765
- // src/core/api/product-api.ts
1766
- var ProductApi = class extends BaseApi {
1767
- constructor(options) {
1768
- super("ProductApi", options);
1769
- }
1770
- /**
1771
- * Check point-in-time stock availability for one or more product variants.
1772
- * Results reflect available stock at the moment of the call and are not guaranteed
1773
- * to remain available by the time an order is placed.
1774
- */
1775
- stockCheck(params) {
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;
1796
- }
1797
- }
1798
- /**
1799
- * Atomically create or update a product together with its options,
1800
- * option-values, and variants in a single transaction. Mirrors Shopify's
1801
- * `productSet` shape and is the canonical write path for the MCP
1802
- * `product-upsert` tool.
1803
- */
1804
- upsert(params) {
1805
- return this.request("/api/products/upsert", params);
1806
- }
1807
- };
1808
-
1809
1852
  // src/core/webhook/index.ts
1810
1853
  var ORDER_CHANGED_EVENT_TYPE = "collection.orderChanged";
1854
+ var COMMERCE_NOTIFICATION_EVENT_TYPE = "commerce.notification";
1811
1855
  function isValidWebhookEvent(data) {
1812
1856
  if (typeof data !== "object" || data === null) return false;
1813
1857
  const obj = data;
1814
1858
  return typeof obj.collection === "string" && typeof obj.operation === "string" && obj.operation.length > 0 && typeof obj.data === "object" && obj.data !== null;
1815
1859
  }
1860
+ var COMMERCE_NOTIFICATION_OPERATION = "notification";
1861
+ var COMMERCE_NOTIFICATION_EVENTS = [
1862
+ "orderPaid",
1863
+ "fulfillmentShipped",
1864
+ "orderDelivered",
1865
+ "returnRequested",
1866
+ "returnCompleted"
1867
+ ];
1816
1868
  function isStringOrNumber(value) {
1817
1869
  return typeof value === "string" || typeof value === "number";
1818
1870
  }
1819
1871
  function isWebhookOrderScope(value) {
1820
- if (!isRecord(value)) return false;
1872
+ if (!isRecord2(value)) return false;
1821
1873
  if (value.kind === "collection") {
1822
1874
  return typeof value.collection === "string";
1823
1875
  }
@@ -1827,16 +1879,40 @@ function isWebhookOrderScope(value) {
1827
1879
  return false;
1828
1880
  }
1829
1881
  function isWebhookOrderMoved(value) {
1830
- if (!isRecord(value)) return false;
1882
+ if (!isRecord2(value)) return false;
1831
1883
  return typeof value.collection === "string" && isStringOrNumber(value.id) && (value.relatedCollection === void 0 || typeof value.relatedCollection === "string") && (value.relatedId === void 0 || isStringOrNumber(value.relatedId));
1832
1884
  }
1833
1885
  function hasOptionalOrderValue(value, key) {
1834
1886
  return value[key] === void 0 || value[key] === null || typeof value[key] === "string";
1835
1887
  }
1836
1888
  function isWebhookOrderChange(value) {
1837
- if (!isRecord(value)) return false;
1889
+ if (!isRecord2(value)) return false;
1838
1890
  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
1891
  }
1892
+ function isCommerceNotificationEventName(value) {
1893
+ return typeof value === "string" && COMMERCE_NOTIFICATION_EVENTS.includes(value);
1894
+ }
1895
+ function isCommerceNotificationSourceCollection(value) {
1896
+ return value === "orders" || value === "fulfillments" || value === "returns";
1897
+ }
1898
+ function isCommerceNotificationData(value) {
1899
+ if (!isRecord2(value)) return false;
1900
+ if (value.source !== void 0 && (!isRecord2(value.source) || !isCommerceNotificationSourceCollection(value.source.collection) || !isStringOrNumber(value.source.id))) {
1901
+ return false;
1902
+ }
1903
+ 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");
1904
+ }
1905
+ function isCommerceNotification(value) {
1906
+ if (!isRecord2(value)) return false;
1907
+ 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");
1908
+ }
1909
+ function isWebhookCommerceNotificationChange(value) {
1910
+ if (!isRecord2(value)) return false;
1911
+ return value.type === "notification" && value.source === "commerce-notifications" && isCommerceNotificationEventName(value.event) && isCommerceNotificationSourceCollection(value.sourceCollection) && isStringOrNumber(value.sourceId);
1912
+ }
1913
+ function matchesOptionalId(actual, expected) {
1914
+ return actual === void 0 || expected === void 0 || actual === expected;
1915
+ }
1840
1916
  function isOrderChangedWebhookEvent(event) {
1841
1917
  if (!isValidWebhookEvent(event) || event.operation !== "update" || event.eventType !== ORDER_CHANGED_EVENT_TYPE || !isWebhookOrderChange(event.change)) {
1842
1918
  return false;
@@ -1849,6 +1925,60 @@ function isOrderChangedWebhookEvent(event) {
1849
1925
  }
1850
1926
  return true;
1851
1927
  }
1928
+ function isCommerceNotificationWebhookEvent(event) {
1929
+ if (!isValidWebhookEvent(event) || event.operation !== COMMERCE_NOTIFICATION_OPERATION || event.eventType !== COMMERCE_NOTIFICATION_EVENT_TYPE || !isCommerceNotificationData(event.data) || !isCommerceNotification(event.notification)) {
1930
+ return false;
1931
+ }
1932
+ const notification = event.notification;
1933
+ const data = event.data;
1934
+ const change = event.change;
1935
+ const sourceCollection = data.source?.collection ?? event.collection;
1936
+ const sourceId = data.source?.id;
1937
+ if (!isCommerceNotificationSourceCollection(sourceCollection)) return false;
1938
+ if (data.source !== void 0 && event.collection !== data.source.collection) {
1939
+ return false;
1940
+ }
1941
+ if (change !== void 0) {
1942
+ if (!isWebhookCommerceNotificationChange(change)) return false;
1943
+ if (change.sourceCollection !== sourceCollection) return false;
1944
+ if (change.event !== notification.event) return false;
1945
+ if (!matchesOptionalId(change.sourceId, sourceId)) return false;
1946
+ }
1947
+ const changeSourceId = isWebhookCommerceNotificationChange(change) ? change.sourceId : void 0;
1948
+ if (notification.event === "orderPaid" || notification.event === "orderDelivered") {
1949
+ return sourceCollection === "orders" && typeof notification.orderId === "string" && notification.orderId.length > 0 && matchesOptionalId(data.orderId, sourceId) && matchesOptionalId(notification.orderId, sourceId) && matchesOptionalId(data.orderId, notification.orderId) && matchesOptionalId(changeSourceId, data.orderId ?? notification.orderId);
1950
+ }
1951
+ if (notification.event === "fulfillmentShipped") {
1952
+ 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);
1953
+ }
1954
+ if (notification.event === "returnRequested" || notification.event === "returnCompleted") {
1955
+ 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);
1956
+ }
1957
+ return false;
1958
+ }
1959
+ function getCommerceNotificationIdempotencyKey(event) {
1960
+ return `${event.notification.intentId}:${event.notification.dedupeKey}`;
1961
+ }
1962
+ function defineCommerceEmailConfig(config) {
1963
+ return config;
1964
+ }
1965
+ function createCommerceEmailWebhookHandler(handlers) {
1966
+ return async (event) => {
1967
+ if (!isCommerceNotificationWebhookEvent(event)) {
1968
+ await handlers.unhandled?.(event);
1969
+ return;
1970
+ }
1971
+ const handler = handlers[event.notification.event];
1972
+ if (!handler) {
1973
+ await handlers.unhandled?.(event);
1974
+ return;
1975
+ }
1976
+ await handler({
1977
+ event,
1978
+ idempotencyKey: getCommerceNotificationIdempotencyKey(event)
1979
+ });
1980
+ };
1981
+ }
1852
1982
  function isWebhookCollection(event, collection) {
1853
1983
  return isValidWebhookEvent(event) && event.collection === collection;
1854
1984
  }
@@ -1856,7 +1986,7 @@ function isWebhookOperation(event, operation) {
1856
1986
  return isValidWebhookEvent(event) && event.operation === operation;
1857
1987
  }
1858
1988
  var CUSTOMER_PASSWORD_RESET_OPERATION = "password-reset";
1859
- function isRecord(value) {
1989
+ function isRecord2(value) {
1860
1990
  return typeof value === "object" && value !== null;
1861
1991
  }
1862
1992
  function hasString(value, key) {
@@ -1866,7 +1996,7 @@ function hasStringOrNumber(value, key) {
1866
1996
  return typeof value[key] === "string" || typeof value[key] === "number";
1867
1997
  }
1868
1998
  function isCustomerPasswordResetWebhookEvent(event) {
1869
- if (event.collection !== "customers" || event.operation !== CUSTOMER_PASSWORD_RESET_OPERATION || !isRecord(event.data)) {
1999
+ if (event.collection !== "customers" || event.operation !== CUSTOMER_PASSWORD_RESET_OPERATION || !isRecord2(event.data)) {
1870
2000
  return false;
1871
2001
  }
1872
2002
  return hasStringOrNumber(event.data, "customerId") && hasString(event.data, "email") && hasString(event.data, "name") && hasString(event.data, "resetPasswordToken") && hasString(event.data, "resetPasswordExpiresAt");
@@ -1986,6 +2116,7 @@ var INTERNAL_COLLECTIONS = [
1986
2116
  "subscriptions",
1987
2117
  "billing-history",
1988
2118
  "inventory-reservations",
2119
+ "commerce-notification-intents",
1989
2120
  "product-collection-items",
1990
2121
  "order-status-logs",
1991
2122
  "api-keys",
@@ -3218,7 +3349,14 @@ function buildProductListingProjection(product, variants) {
3218
3349
  function buildProductListingCard(item, options = {}) {
3219
3350
  const product = item.product;
3220
3351
  const groups = item.groups;
3221
- const primaryImage = firstMedia(product.thumbnail) ?? firstMedia(product.images ?? null) ?? null;
3352
+ const variants = getProductListingCardVariants(item);
3353
+ const projectedListing = buildProductListingProjection(product, variants);
3354
+ const selectionHintVariant = getRelationID(product.listing?.selectionHintVariant) ?? projectedListing.selectionHintVariant;
3355
+ const representativeVariant = findListingCardRepresentativeVariant(
3356
+ variants,
3357
+ selectionHintVariant
3358
+ );
3359
+ const primaryImage = firstMedia(product.thumbnail) ?? firstMedia(product.images ?? null) ?? firstMedia(representativeVariant?.thumbnail) ?? firstMedia(representativeVariant?.images) ?? firstMedia(product.listing?.primaryImage) ?? firstMedia(projectedListing.primaryImage) ?? null;
3222
3360
  const priceRange = aggregateListingPriceRange(groups);
3223
3361
  const availableForSale = groups.some(
3224
3362
  (group) => group.listing.availableForSale
@@ -3226,14 +3364,42 @@ function buildProductListingCard(item, options = {}) {
3226
3364
  const swatches = groups.length > 1 ? groups.map((group) => buildListingSwatch(product, group, options)) : [];
3227
3365
  return {
3228
3366
  id: String(product.id),
3229
- href: buildProductHref({ slug: product.slug }, void 0, options),
3367
+ href: buildProductHref(
3368
+ { slug: product.slug },
3369
+ { listing: { selectionHintVariant } },
3370
+ options
3371
+ ),
3230
3372
  title: product.title,
3373
+ representativeVariant,
3231
3374
  primaryImage,
3232
3375
  priceRange,
3233
3376
  availableForSale,
3234
3377
  swatches
3235
3378
  };
3236
3379
  }
3380
+ function getProductListingCardVariants(item) {
3381
+ const productVariants = item.product.variants?.docs;
3382
+ if (Array.isArray(productVariants) && productVariants.length > 0) {
3383
+ return productVariants;
3384
+ }
3385
+ const variants = [];
3386
+ const seen = /* @__PURE__ */ new Set();
3387
+ for (const group of item.groups) {
3388
+ for (const variant of group.variants) {
3389
+ const id = getRelationID(variant.id);
3390
+ if (id && seen.has(id)) continue;
3391
+ if (id) seen.add(id);
3392
+ variants.push(variant);
3393
+ }
3394
+ }
3395
+ return variants;
3396
+ }
3397
+ function findListingCardRepresentativeVariant(variants, representativeVariantId) {
3398
+ if (representativeVariantId == null) return null;
3399
+ return variants.find(
3400
+ (variant) => getRelationID(variant.id) === representativeVariantId
3401
+ ) ?? null;
3402
+ }
3237
3403
  function aggregateListingPriceRange(groups) {
3238
3404
  const minPrice = minOfNullable(groups.map((g) => g.listing.minPrice));
3239
3405
  const maxPrice = maxOfNullable(groups.map((g) => g.listing.maxPrice));