@01.software/sdk 0.49.0 → 0.51.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 (74) hide show
  1. package/CHANGELOG.md +130 -1
  2. package/MIGRATION.md +56 -0
  3. package/README.md +215 -45
  4. package/dist/client.cjs +188 -137
  5. package/dist/client.cjs.map +1 -1
  6. package/dist/client.d.cts +6 -6
  7. package/dist/client.d.ts +6 -6
  8. package/dist/client.js +188 -137
  9. package/dist/client.js.map +1 -1
  10. package/dist/{collection-client-XfGLPuTf.d.cts → collection-client-CWAeuzV4.d.cts} +6 -4
  11. package/dist/{collection-client-DnDt6EQz.d.ts → collection-client-hYvVfHIm.d.ts} +6 -4
  12. package/dist/{const-DCNV5Kq7.d.ts → const-D8LixhAJ.d.cts} +5 -5
  13. package/dist/{const-CBba4lDo.d.cts → const-JD8obaKg.d.ts} +5 -5
  14. package/dist/embedded-admin/server.cjs +306 -0
  15. package/dist/embedded-admin/server.cjs.map +1 -0
  16. package/dist/embedded-admin/server.d.cts +33 -0
  17. package/dist/embedded-admin/server.d.ts +33 -0
  18. package/dist/embedded-admin/server.js +288 -0
  19. package/dist/embedded-admin/server.js.map +1 -0
  20. package/dist/embedded-admin.cjs +400 -0
  21. package/dist/embedded-admin.cjs.map +1 -0
  22. package/dist/embedded-admin.d.cts +61 -0
  23. package/dist/embedded-admin.d.ts +61 -0
  24. package/dist/embedded-admin.js +377 -0
  25. package/dist/embedded-admin.js.map +1 -0
  26. package/dist/errors.cjs +1 -0
  27. package/dist/errors.cjs.map +1 -1
  28. package/dist/errors.d.cts +3 -3
  29. package/dist/errors.d.ts +3 -3
  30. package/dist/errors.js +1 -0
  31. package/dist/errors.js.map +1 -1
  32. package/dist/{index-CbKyoEzy.d.cts → index-B0Hjh3Ey.d.ts} +72 -10
  33. package/dist/{index-DUuIqUS8.d.ts → index-Bu0kCc6o.d.cts} +72 -10
  34. package/dist/index.cjs +320 -383
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +8 -66
  37. package/dist/index.d.ts +8 -66
  38. package/dist/index.js +320 -383
  39. package/dist/index.js.map +1 -1
  40. package/dist/{payload-types-MKbx5MuJ.d.cts → payload-types-BOsckg8B.d.cts} +263 -54
  41. package/dist/{payload-types-MKbx5MuJ.d.ts → payload-types-BOsckg8B.d.ts} +263 -54
  42. package/dist/query.cjs +94 -70
  43. package/dist/query.cjs.map +1 -1
  44. package/dist/query.d.cts +5 -5
  45. package/dist/query.d.ts +5 -5
  46. package/dist/query.js +94 -70
  47. package/dist/query.js.map +1 -1
  48. package/dist/realtime.d.cts +2 -2
  49. package/dist/realtime.d.ts +2 -2
  50. package/dist/server.cjs +404 -162
  51. package/dist/server.cjs.map +1 -1
  52. package/dist/server.d.cts +7 -7
  53. package/dist/server.d.ts +7 -7
  54. package/dist/server.js +404 -162
  55. package/dist/server.js.map +1 -1
  56. package/dist/storefront-cache.cjs +1 -0
  57. package/dist/storefront-cache.cjs.map +1 -1
  58. package/dist/storefront-cache.js +1 -0
  59. package/dist/storefront-cache.js.map +1 -1
  60. package/dist/{types-L_nh-ED7.d.ts → types-5ZlcAFuU.d.ts} +2 -2
  61. package/dist/{types-BKr_2avj.d.cts → types-B14sEt1z.d.cts} +2 -2
  62. package/dist/{types-1UeOk1Uy.d.cts → types-Bj8j7VHU.d.ts} +79 -23
  63. package/dist/{types-Du4s5anw.d.ts → types-CM5qiR2k.d.cts} +79 -23
  64. package/dist/ui/form.d.cts +1 -1
  65. package/dist/ui/form.d.ts +1 -1
  66. package/dist/ui/video.d.cts +1 -1
  67. package/dist/ui/video.d.ts +1 -1
  68. package/dist/webhook.cjs +124 -80
  69. package/dist/webhook.cjs.map +1 -1
  70. package/dist/webhook.d.cts +21 -5
  71. package/dist/webhook.d.ts +21 -5
  72. package/dist/webhook.js +124 -80
  73. package/dist/webhook.js.map +1 -1
  74. package/package.json +23 -2
package/dist/index.cjs CHANGED
@@ -130,8 +130,6 @@ __export(src_exports, {
130
130
  projectProductToListingShape: () => projectProductToListingShape,
131
131
  resolveFeaturedImagePointer: () => resolveFeaturedImagePointer,
132
132
  resolveProductDisplayMedia: () => resolveProductDisplayMedia,
133
- resolveProductGallery: () => resolveProductGallery,
134
- resolveProductMedia: () => resolveProductMedia,
135
133
  resolveProductSelection: () => resolveProductSelection,
136
134
  resolveProductSelectionFromMatrix: () => resolveProductSelectionFromMatrix,
137
135
  resolveProductSelectionMedia: () => resolveProductSelectionMedia,
@@ -243,6 +241,7 @@ var COMMERCE_ERROR_CODES = [
243
241
  "payment_session_not_cancelable",
244
242
  "payment_session_conflict",
245
243
  "provider_identity_mismatch",
244
+ "managed_refund_attestation_forbidden",
246
245
  "payment_method_unavailable",
247
246
  "provider_unavailable",
248
247
  "lock_timeout",
@@ -785,11 +784,11 @@ function parseRetryAfter(response) {
785
784
  permitsAutomaticRetry: seconds <= MAX_AUTOMATIC_RETRY_AFTER_SECONDS
786
785
  };
787
786
  }
788
- function mapResponseToError(status, parsed, details, requestId, retryAfter, errorFamily) {
787
+ function mapResponseToError(status, parsed, details, requestId, retryAfter, canonicalCommerceError) {
789
788
  const errorDetails = {
790
789
  ...details,
791
790
  ...parsed.errors && { errors: parsed.errors },
792
- ...errorFamily !== "commerce" && parsed.body && { body: parsed.body }
791
+ ...!canonicalCommerceError && parsed.body && { body: parsed.body }
793
792
  };
794
793
  const suggestion = getParsedErrorSuggestion(status, parsed);
795
794
  const finalize = (error) => {
@@ -797,7 +796,7 @@ function mapResponseToError(status, parsed, details, requestId, retryAfter, erro
797
796
  if (retryAfter !== void 0) {
798
797
  Object.assign(withRequestId, { retryAfter });
799
798
  }
800
- return errorFamily === "commerce" ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(withRequestId, parsed.reason);
799
+ return canonicalCommerceError ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(withRequestId, parsed.reason);
801
800
  };
802
801
  if (status === 400 || status === 422) {
803
802
  return finalize(
@@ -903,6 +902,7 @@ async function httpFetch(url, options) {
903
902
  retry,
904
903
  onUnauthorized,
905
904
  errorFamily,
905
+ typedCommerceErrorReasons,
906
906
  ...requestInit
907
907
  } = options || {};
908
908
  const baseUrl = resolveApiUrl(apiUrl);
@@ -956,7 +956,8 @@ async function httpFetch(url, options) {
956
956
  });
957
957
  if (!response.ok) {
958
958
  const parsed = await parseErrorBody(response);
959
- const commerceEnvelope = errorFamily === "commerce" ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
959
+ const canonicalCommerceError = errorFamily === "commerce" || typeof parsed.reason === "string" && typedCommerceErrorReasons?.includes(parsed.reason) === true;
960
+ const commerceEnvelope = canonicalCommerceError ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
960
961
  if (isUsageLimitExceededResponse(response)) {
961
962
  const limit = parseInt(
962
963
  response.headers.get("X-Usage-Limit") || "0",
@@ -984,7 +985,7 @@ async function httpFetch(url, options) {
984
985
  ),
985
986
  requestId
986
987
  );
987
- throw errorFamily === "commerce" ? enhanceCommerceError(usageError, parsed.body, requestId) : enhanceNonCommerceError(usageError, parsed.reason);
988
+ throw canonicalCommerceError ? enhanceCommerceError(usageError, parsed.body, requestId) : enhanceNonCommerceError(usageError, parsed.reason);
988
989
  }
989
990
  if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && (commerceEnvelope?.reason ?? parsed.reason) === "token_expired") {
990
991
  hasRetried401 = true;
@@ -1009,7 +1010,7 @@ async function httpFetch(url, options) {
1009
1010
  details,
1010
1011
  requestId,
1011
1012
  retryAfter.seconds,
1012
- errorFamily
1013
+ canonicalCommerceError
1013
1014
  );
1014
1015
  const method2 = (requestInit.method || "GET").toUpperCase();
1015
1016
  const isTerminal = error instanceof RateLimitError || error instanceof UsageLimitError;
@@ -1187,15 +1188,15 @@ var HttpClient = class {
1187
1188
  throw err;
1188
1189
  }
1189
1190
  }
1190
- buildUrl(endpoint2, options) {
1191
- if (!options) return endpoint2;
1191
+ buildUrl(endpoint, options) {
1192
+ if (!options) return endpoint;
1192
1193
  const { fallbackLocale, ...rest } = options;
1193
1194
  const queryOptions = fallbackLocale === void 0 ? rest : {
1194
1195
  ...rest,
1195
1196
  "fallback-locale": fallbackLocale === false ? "none" : fallbackLocale
1196
1197
  };
1197
1198
  const queryString = (0, import_qs_esm.stringify)(queryOptions, { addQueryPrefix: true });
1198
- return queryString ? `${endpoint2}${queryString}` : endpoint2;
1199
+ return queryString ? `${endpoint}${queryString}` : endpoint;
1199
1200
  }
1200
1201
  assertJsonResponse(response) {
1201
1202
  const contentType = response.headers.get("content-type");
@@ -1344,39 +1345,39 @@ var ReadOnlyCollectionClient = class extends HttpClient {
1344
1345
  from(collection) {
1345
1346
  return new ReadOnlyCollectionQueryBuilder(this, collection);
1346
1347
  }
1347
- async requestFind(endpoint2, options) {
1348
- const url = this.buildUrl(endpoint2, options);
1348
+ async requestFind(endpoint, options) {
1349
+ const url = this.buildUrl(endpoint, options);
1349
1350
  const response = await this.fetchWithTracking(url, {
1350
1351
  ...this.defaultOptions,
1351
1352
  method: "GET"
1352
1353
  });
1353
1354
  return this.parseFindResponse(response);
1354
1355
  }
1355
- async requestFindEndpoint(endpoint2, data) {
1356
- const response = await this.fetchWithTracking(endpoint2, {
1356
+ async requestFindEndpoint(endpoint, data) {
1357
+ const response = await this.fetchWithTracking(endpoint, {
1357
1358
  ...this.defaultOptions,
1358
1359
  method: "POST",
1359
1360
  body: data ? JSON.stringify(data) : void 0
1360
1361
  });
1361
1362
  return this.parseFindResponse(response);
1362
1363
  }
1363
- async requestFindEndpointGet(endpoint2) {
1364
- const response = await this.fetchWithTracking(endpoint2, {
1364
+ async requestFindEndpointGet(endpoint) {
1365
+ const response = await this.fetchWithTracking(endpoint, {
1365
1366
  ...this.defaultOptions,
1366
1367
  method: "GET"
1367
1368
  });
1368
1369
  return this.parseFindResponse(response);
1369
1370
  }
1370
- async requestFindById(endpoint2, options) {
1371
- const url = this.buildUrl(endpoint2, options);
1371
+ async requestFindById(endpoint, options) {
1372
+ const url = this.buildUrl(endpoint, options);
1372
1373
  const response = await this.fetchWithTracking(url, {
1373
1374
  ...this.defaultOptions,
1374
1375
  method: "GET"
1375
1376
  });
1376
1377
  return this.parseDocumentResponse(response);
1377
1378
  }
1378
- async requestCount(endpoint2, options) {
1379
- const url = this.buildUrl(endpoint2, options);
1379
+ async requestCount(endpoint, options) {
1380
+ const url = this.buildUrl(endpoint, options);
1380
1381
  const response = await this.fetchWithTracking(url, {
1381
1382
  ...this.defaultOptions,
1382
1383
  method: "GET"
@@ -1386,7 +1387,7 @@ var ReadOnlyCollectionClient = class extends HttpClient {
1386
1387
  };
1387
1388
 
1388
1389
  // src/core/api/parse-response.ts
1389
- async function parseApiResponse(response, endpoint2, options = {}) {
1390
+ async function parseApiResponse(response, endpoint, options = {}) {
1390
1391
  if (response.status === 204 || response.headers.get("content-length") === "0") {
1391
1392
  return void 0;
1392
1393
  }
@@ -1395,7 +1396,7 @@ async function parseApiResponse(response, endpoint2, options = {}) {
1395
1396
  parsed = await response.json();
1396
1397
  } catch {
1397
1398
  throw createApiError(
1398
- `Invalid JSON response from ${endpoint2}`,
1399
+ `Invalid JSON response from ${endpoint}`,
1399
1400
  response.status,
1400
1401
  void 0,
1401
1402
  "Server returned an invalid response.",
@@ -1445,6 +1446,7 @@ async function parseApiResponse(response, endpoint2, options = {}) {
1445
1446
 
1446
1447
  // ../../internal/http-contracts/src/index.ts
1447
1448
  var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
1449
+ var PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE = "application/vnd.01software.portone-action-capabilities.v1+json";
1448
1450
  var operation = (collection, method, path, errorFamily) => Object.freeze({
1449
1451
  [operationBrand]: true,
1450
1452
  collection,
@@ -1453,6 +1455,10 @@ var operation = (collection, method, path, errorFamily) => Object.freeze({
1453
1455
  ...errorFamily && { errorFamily }
1454
1456
  });
1455
1457
  var strictCommerceOperation = (collection, method, path) => operation(collection, method, path, "commerce");
1458
+ var selectiveCommerceOperation = (collection, method, path, typedCommerceErrorReasons) => Object.freeze({
1459
+ ...operation(collection, method, path),
1460
+ typedCommerceErrorReasons: Object.freeze([...typedCommerceErrorReasons])
1461
+ });
1456
1462
  var COMMERCE_ENDPOINT_OPERATIONS = {
1457
1463
  products: {
1458
1464
  detail: operation("products", "get", "/detail"),
@@ -1484,7 +1490,12 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1484
1490
  confirmPayment: operation("orders", "post", "/confirm-payment"),
1485
1491
  byPayment: operation("orders", "get", "/by-payment"),
1486
1492
  cancel: operation("orders", "post", "/cancel"),
1487
- resolveCancelRefund: operation("orders", "post", "/resolve-cancel-refund"),
1493
+ resolveCancelRefund: selectiveCommerceOperation(
1494
+ "orders",
1495
+ "post",
1496
+ "/resolve-cancel-refund",
1497
+ ["managed_refund_attestation_forbidden"]
1498
+ ),
1488
1499
  checkout: strictCommerceOperation("orders", "post", "/checkout"),
1489
1500
  createFulfillment: operation("orders", "post", "/create-fulfillment"),
1490
1501
  updateFulfillment: operation("orders", "post", "/update-fulfillment")
@@ -1555,6 +1566,16 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1555
1566
  "payment-sessions",
1556
1567
  "post",
1557
1568
  "/server/confirm"
1569
+ ),
1570
+ findPortOne: strictCommerceOperation(
1571
+ "payment-sessions",
1572
+ "post",
1573
+ "/server/portone/find"
1574
+ ),
1575
+ reconcilePortOne: strictCommerceOperation(
1576
+ "payment-sessions",
1577
+ "post",
1578
+ "/server/portone/reconcile"
1558
1579
  )
1559
1580
  },
1560
1581
  custom: {
@@ -1574,12 +1595,26 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1574
1595
  validate: operation("discounts", "post", "/validate")
1575
1596
  }
1576
1597
  };
1598
+ var portOneStandardActionCapabilityOperations = /* @__PURE__ */ new Set([
1599
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.create,
1600
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.retrieve,
1601
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.create,
1602
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.retrieve
1603
+ ]);
1577
1604
  var MEMBERSHIP_ENDPOINT_OPERATIONS = {
1578
1605
  subscribe: operation(null, "post", "/memberships/subscribe"),
1579
1606
  cancel: operation(null, "post", "/memberships/:id/cancel"),
1580
1607
  me: operation(null, "get", "/memberships/me")
1581
1608
  };
1609
+ var EMBEDDED_ADMIN_ENDPOINT_OPERATIONS = {
1610
+ show: operation("tenants", "get", "/embedded-admin-app"),
1611
+ configure: operation("tenants", "patch", "/embedded-admin-app"),
1612
+ disable: operation("tenants", "delete", "/embedded-admin-app")
1613
+ };
1582
1614
  var EVENTS_ENDPOINT_OPERATIONS = {
1615
+ events: {
1616
+ convertSchedule: operation("events", "post", "/:id/schedule")
1617
+ },
1583
1618
  occurrences: {
1584
1619
  range: operation("event-occurrences", "get", "/range"),
1585
1620
  admissionAvailability: operation(
@@ -1620,46 +1655,51 @@ function resolveOperationMethod(descriptor) {
1620
1655
  }
1621
1656
 
1622
1657
  // src/core/api/endpoints.ts
1623
- var endpoint = (method, path) => ({ method, path });
1624
1658
  var sharedEndpoint = (descriptor) => descriptor;
1625
- function resolveOperationMethod2(descriptor) {
1626
- return "collection" in descriptor ? resolveOperationMethod(descriptor) : descriptor.method;
1627
- }
1628
1659
  function resolveOperationErrorFamily(descriptor) {
1629
- return "collection" in descriptor ? descriptor.errorFamily : void 0;
1630
- }
1631
- function resolveOperationPath2(descriptor, options) {
1632
- if ("collection" in descriptor) {
1633
- return resolveOperationPath(descriptor, options);
1634
- }
1635
- const query = options?.query?.toString().replace(/^\?/, "");
1636
- return query ? `${descriptor.path}?${query}` : descriptor.path;
1660
+ return descriptor.errorFamily;
1637
1661
  }
1638
1662
  var COMMERCE_ENDPOINTS = {
1639
1663
  products: {
1640
- detail: endpoint("GET", "/api/products/detail"),
1641
- detailCatalog: endpoint("GET", "/api/products/detail/catalog"),
1642
- listingGroups: endpoint("GET", "/api/products/listing-groups"),
1643
- listingGroupsCatalog: endpoint(
1644
- "GET",
1645
- "/api/products/listing-groups/catalog"
1664
+ detail: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.detail),
1665
+ detailCatalog: sharedEndpoint(
1666
+ COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog
1667
+ ),
1668
+ listingGroups: sharedEndpoint(
1669
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroups
1670
+ ),
1671
+ listingGroupsCatalog: sharedEndpoint(
1672
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog
1673
+ ),
1674
+ // The manifest keeps the GET read and the POST body-query apart; this
1675
+ // semantic name has always resolved to the GET one.
1676
+ listingGroupsQuery: sharedEndpoint(
1677
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryGet
1678
+ ),
1679
+ listingGroupsQueryCatalog: sharedEndpoint(
1680
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryCatalog
1681
+ ),
1682
+ stockCheck: sharedEndpoint(
1683
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockCheck
1646
1684
  ),
1647
- listingGroupsQuery: endpoint("GET", "/api/products/listing-groups/query"),
1648
- listingGroupsQueryCatalog: endpoint(
1649
- "GET",
1650
- "/api/products/listing-groups/query/catalog"
1685
+ stockSnapshot: sharedEndpoint(
1686
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockSnapshot
1651
1687
  ),
1652
- stockCheck: endpoint("POST", "/api/products/stock-check"),
1653
- stockSnapshot: endpoint("GET", "/api/products/stock"),
1654
- upsert: endpoint("POST", "/api/products/upsert")
1688
+ upsert: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.upsert)
1655
1689
  },
1656
1690
  orders: {
1657
- update: endpoint("POST", "/api/orders/update"),
1658
- byPayment: endpoint("GET", "/api/orders/by-payment"),
1659
- cancel: endpoint("POST", "/api/orders/cancel"),
1660
- resolveCancelRefund: endpoint("POST", "/api/orders/resolve-cancel-refund"),
1661
- createFulfillment: endpoint("POST", "/api/orders/create-fulfillment"),
1662
- updateFulfillment: endpoint("POST", "/api/orders/update-fulfillment")
1691
+ update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.update),
1692
+ byPayment: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.byPayment),
1693
+ cancel: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.cancel),
1694
+ resolveCancelRefund: sharedEndpoint(
1695
+ COMMERCE_ENDPOINT_OPERATIONS.orders.resolveCancelRefund
1696
+ ),
1697
+ createFulfillment: sharedEndpoint(
1698
+ COMMERCE_ENDPOINT_OPERATIONS.orders.createFulfillment
1699
+ ),
1700
+ updateFulfillment: sharedEndpoint(
1701
+ COMMERCE_ENDPOINT_OPERATIONS.orders.updateFulfillment
1702
+ )
1663
1703
  },
1664
1704
  checkouts: {
1665
1705
  create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.checkout),
@@ -1671,18 +1711,21 @@ var COMMERCE_ENDPOINTS = {
1671
1711
  }
1672
1712
  },
1673
1713
  returns: {
1674
- create: endpoint("POST", "/api/returns/create"),
1675
- update: endpoint("POST", "/api/returns/update"),
1676
- returnRefund: endpoint("POST", "/api/returns/return-refund")
1714
+ create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.create),
1715
+ update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.update),
1716
+ returnRefund: sharedEndpoint(
1717
+ COMMERCE_ENDPOINT_OPERATIONS.returns.returnRefund
1718
+ )
1677
1719
  },
1678
1720
  fulfillmentOrders: {
1679
- prepare: endpoint(
1680
- "POST",
1681
- "/api/fulfillment-orders/prepare-fulfillment-order"
1721
+ prepare: sharedEndpoint(
1722
+ COMMERCE_ENDPOINT_OPERATIONS.fulfillmentOrders.prepare
1682
1723
  )
1683
1724
  },
1684
1725
  fulfillments: {
1685
- bulkImport: endpoint("POST", "/api/fulfillments/bulk-import")
1726
+ bulkImport: sharedEndpoint(
1727
+ COMMERCE_ENDPOINT_OPERATIONS.fulfillments.bulkImport
1728
+ )
1686
1729
  },
1687
1730
  carts: {
1688
1731
  create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.create),
@@ -1747,42 +1790,21 @@ var COMMERCE_ENDPOINTS = {
1747
1790
  ),
1748
1791
  confirm: sharedEndpoint(
1749
1792
  COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.confirm
1793
+ ),
1794
+ findPortOne: sharedEndpoint(
1795
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.findPortOne
1796
+ ),
1797
+ reconcilePortOne: sharedEndpoint(
1798
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.reconcilePortOne
1750
1799
  )
1751
1800
  }
1752
1801
  },
1753
1802
  shippingPolicies: {
1754
- calculate: endpoint("POST", "/api/shipping-policies/calculate")
1803
+ calculate: sharedEndpoint(
1804
+ COMMERCE_ENDPOINT_OPERATIONS.shippingPolicies.calculate
1805
+ )
1755
1806
  }
1756
1807
  };
1757
- function isCommerceEndpointDescriptor(value) {
1758
- if (!value || typeof value !== "object") return false;
1759
- const candidate = value;
1760
- return typeof candidate.method === "string" && typeof candidate.path === "string";
1761
- }
1762
- function flattenEndpointPaths(value) {
1763
- if (isCommerceEndpointDescriptor(value)) return [resolveOperationPath2(value)];
1764
- if (!value || typeof value !== "object") return [];
1765
- return Object.values(value).flatMap((entry) => flattenEndpointPaths(entry));
1766
- }
1767
- function flattenEndpointDescriptors(value) {
1768
- if (isCommerceEndpointDescriptor(value)) return [value];
1769
- if (!value || typeof value !== "object") return [];
1770
- return Object.values(value).flatMap(
1771
- (entry) => flattenEndpointDescriptors(entry)
1772
- );
1773
- }
1774
- var COMMERCE_ENDPOINT_PATHS = flattenEndpointPaths(COMMERCE_ENDPOINTS);
1775
- var COMMERCE_ENDPOINT_DESCRIPTORS = flattenEndpointDescriptors(COMMERCE_ENDPOINTS);
1776
- var MEMBERSHIP_ENDPOINTS = {
1777
- subscribe: "/api/memberships/subscribe",
1778
- cancel: (id) => `/api/memberships/${id}/cancel`,
1779
- me: "/api/memberships/me"
1780
- };
1781
- var MEMBERSHIP_ENDPOINT_PATHS = [
1782
- MEMBERSHIP_ENDPOINTS.subscribe,
1783
- MEMBERSHIP_ENDPOINTS.cancel(":id"),
1784
- MEMBERSHIP_ENDPOINTS.me
1785
- ];
1786
1808
 
1787
1809
  // src/core/api/customer-scoped-api.ts
1788
1810
  var CustomerScopedTransport = class {
@@ -1803,10 +1825,10 @@ var CustomerScopedTransport = class {
1803
1825
  this.onUnauthorized = options.onUnauthorized;
1804
1826
  this.onRequestId = options.onRequestId;
1805
1827
  }
1806
- async request(endpoint2, options) {
1828
+ async request(endpoint, options) {
1807
1829
  const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
1808
1830
  try {
1809
- const response = await httpFetch(endpoint2, {
1831
+ const response = await httpFetch(endpoint, {
1810
1832
  method: options.method,
1811
1833
  apiUrl: this.apiUrl,
1812
1834
  publishableKey: this.publishableKey,
@@ -1820,7 +1842,7 @@ var CustomerScopedTransport = class {
1820
1842
  ...options.errorFamily && { errorFamily: options.errorFamily }
1821
1843
  });
1822
1844
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
1823
- return parseApiResponse(response, endpoint2, {
1845
+ return parseApiResponse(response, endpoint, {
1824
1846
  errorFamily: options.errorFamily
1825
1847
  });
1826
1848
  } catch (err) {
@@ -1834,12 +1856,12 @@ var CustomerScopedApi = class {
1834
1856
  constructor(apiName, options) {
1835
1857
  this.transport = new CustomerScopedTransport(apiName, options);
1836
1858
  }
1837
- requestEndpoint(endpoint2, body, options) {
1838
- return this.transport.request(resolveOperationPath2(endpoint2, options), {
1839
- method: resolveOperationMethod2(endpoint2),
1859
+ requestEndpoint(endpoint, body, options) {
1860
+ return this.transport.request(resolveOperationPath(endpoint, options), {
1861
+ method: resolveOperationMethod(endpoint),
1840
1862
  body,
1841
1863
  headers: options?.headers,
1842
- errorFamily: resolveOperationErrorFamily(endpoint2)
1864
+ errorFamily: resolveOperationErrorFamily(endpoint)
1843
1865
  });
1844
1866
  }
1845
1867
  };
@@ -1847,8 +1869,8 @@ var RawCustomerScopedApi = class {
1847
1869
  constructor(apiName, options) {
1848
1870
  this.transport = new CustomerScopedTransport(apiName, options);
1849
1871
  }
1850
- request(endpoint2, options) {
1851
- return this.transport.request(endpoint2, options);
1872
+ request(endpoint, options) {
1873
+ return this.transport.request(endpoint, options);
1852
1874
  }
1853
1875
  };
1854
1876
 
@@ -1923,11 +1945,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
1923
1945
  if (params.page !== void 0) urlParams.set("page", String(params.page));
1924
1946
  return `/api/comments/public?${urlParams.toString()}`;
1925
1947
  }
1926
- async execute(endpoint2, method, body) {
1927
- return this.request(endpoint2, { method, body });
1948
+ async execute(endpoint, method, body) {
1949
+ return this.request(endpoint, { method, body });
1928
1950
  }
1929
- async executeDoc(endpoint2, method, body) {
1930
- const response = await this.execute(endpoint2, method, body);
1951
+ async executeDoc(endpoint, method, body) {
1952
+ const response = await this.execute(endpoint, method, body);
1931
1953
  return unwrapPayloadDoc(response);
1932
1954
  }
1933
1955
  createPost(params) {
@@ -2193,8 +2215,8 @@ var CommunityClient = class extends RawCustomerScopedApi {
2193
2215
 
2194
2216
  // src/core/content/content-client.ts
2195
2217
  var PublicContentApi = class extends RawCustomerScopedApi {
2196
- get(endpoint2) {
2197
- return this.request(endpoint2, { method: "GET" });
2218
+ get(endpoint) {
2219
+ return this.request(endpoint, { method: "GET" });
2198
2220
  }
2199
2221
  };
2200
2222
  function appendCommonParams(search, options, defaultSort) {
@@ -2375,6 +2397,9 @@ function nullableString(value, resource, path) {
2375
2397
  fail(resource, path, "string or null");
2376
2398
  }
2377
2399
  }
2400
+ function nullableNonEmptyString(value, resource, path) {
2401
+ if (value !== null) string(value, resource, path);
2402
+ }
2378
2403
  function cartLineQuantity(value, resource, path) {
2379
2404
  const quantity = positiveInteger(value, resource, path);
2380
2405
  if (quantity > MAX_CART_LINE_QUANTITY) {
@@ -2884,8 +2909,8 @@ function validatePublicOrderItem(value, resource, path) {
2884
2909
  validateReference(item.variant, resource, `${path}.variant`);
2885
2910
  }
2886
2911
  string(item.productTitle, resource, `${path}.productTitle`);
2887
- nullableString(item.variantTitle, resource, `${path}.variantTitle`);
2888
- nullableString(item.sku, resource, `${path}.sku`);
2912
+ nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
2913
+ nullableNonEmptyString(item.sku, resource, `${path}.sku`);
2889
2914
  validateAdmissions(item.admissions, resource, `${path}.admissions`);
2890
2915
  const quantity = positiveInteger(item.quantity, resource, `${path}.quantity`);
2891
2916
  const unitPrice = safeMinor(
@@ -3136,8 +3161,8 @@ function validateCheckoutItem(value, resource, path) {
3136
3161
  validateReference(item.product, resource, `${path}.product`);
3137
3162
  validateReference(item.variant, resource, `${path}.variant`);
3138
3163
  string(item.productTitle, resource, `${path}.productTitle`);
3139
- nullableString(item.variantTitle, resource, `${path}.variantTitle`);
3140
- nullableString(item.sku, resource, `${path}.sku`);
3164
+ nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
3165
+ nullableNonEmptyString(item.sku, resource, `${path}.sku`);
3141
3166
  validateAdmissions(item.admissions, resource, `${path}.admissions`);
3142
3167
  cartLineQuantity(item.quantity, resource, `${path}.quantity`);
3143
3168
  const unitPrice = safeMinor(
@@ -3469,11 +3494,21 @@ function validateNextAction(value, provider, resource, path) {
3469
3494
  const action = record(value, resource, path);
3470
3495
  if (provider === "portone") {
3471
3496
  if (action.type === "portone_sdk") {
3497
+ const hasCancelable = "cancelable" in action;
3498
+ const hasRetryPolicy = "retryPolicy" in action;
3499
+ if (hasCancelable !== hasRetryPolicy) {
3500
+ fail(
3501
+ resource,
3502
+ path,
3503
+ "exact released action or exact negotiated capability action"
3504
+ );
3505
+ }
3472
3506
  exact(
3473
3507
  action,
3474
3508
  [
3475
3509
  "type",
3476
3510
  "version",
3511
+ ...hasCancelable ? ["cancelable", "retryPolicy"] : [],
3477
3512
  "storeId",
3478
3513
  "channelKey",
3479
3514
  "paymentId",
@@ -3488,6 +3523,11 @@ function validateNextAction(value, provider, resource, path) {
3488
3523
  path
3489
3524
  );
3490
3525
  if (action.version !== "v2") fail(resource, `${path}.version`, "v2");
3526
+ if (hasCancelable && action.cancelable !== false)
3527
+ fail(resource, `${path}.cancelable`, "false");
3528
+ if (hasRetryPolicy && action.retryPolicy !== "same_action_only") {
3529
+ fail(resource, `${path}.retryPolicy`, "same_action_only");
3530
+ }
3491
3531
  for (const key of ["storeId", "channelKey"]) {
3492
3532
  boundedString(action[key], 255, resource, `${path}.${key}`);
3493
3533
  }
@@ -3534,6 +3574,10 @@ function validateNextAction(value, provider, resource, path) {
3534
3574
  "HTTPS or loopback URL without embedded credentials"
3535
3575
  );
3536
3576
  }
3577
+ if (!hasCancelable) {
3578
+ action.cancelable = false;
3579
+ action.retryPolicy = "same_action_only";
3580
+ }
3537
3581
  return;
3538
3582
  }
3539
3583
  exact(action, ["type", "checkoutUrl"], [], resource, path);
@@ -4268,8 +4312,8 @@ var CartApi = class extends CustomerScopedApi {
4268
4312
  endpoint(key) {
4269
4313
  return this.serverTransport ? COMMERCE_ENDPOINTS.carts.server[key] : COMMERCE_ENDPOINTS.carts[key];
4270
4314
  }
4271
- execute(endpoint2, body, idempotencyKey) {
4272
- return this.requestEndpoint(endpoint2, body, {
4315
+ execute(endpoint, body, idempotencyKey) {
4316
+ return this.requestEndpoint(endpoint, body, {
4273
4317
  ...idempotencyKey && {
4274
4318
  headers: { "X-Idempotency-Key": idempotencyKey }
4275
4319
  }
@@ -4286,26 +4330,26 @@ var CartApi = class extends CustomerScopedApi {
4286
4330
  );
4287
4331
  }
4288
4332
  mine(params = {}) {
4289
- const endpoint2 = this.endpoint("mine");
4290
- return this.execute(endpoint2, params).then(
4333
+ const endpoint = this.endpoint("mine");
4334
+ return this.execute(endpoint, params).then(
4291
4335
  (value) => validateCartMineResult(value)
4292
4336
  );
4293
4337
  }
4294
4338
  merge(params) {
4295
4339
  const { idempotencyKey, ...body } = params;
4296
4340
  assertCommerceIdempotencyKey(idempotencyKey);
4297
- const endpoint2 = this.endpoint("merge");
4298
- return this.execute(endpoint2, body, idempotencyKey).then(
4341
+ const endpoint = this.endpoint("merge");
4342
+ return this.execute(endpoint, body, idempotencyKey).then(
4299
4343
  (value) => validateCartMergeResult(value)
4300
4344
  );
4301
4345
  }
4302
4346
  addItem(params) {
4303
4347
  return this.mutate(this.endpoint("addItem"), params);
4304
4348
  }
4305
- mutate(endpoint2, params) {
4349
+ mutate(endpoint, params) {
4306
4350
  const { idempotencyKey, ...body } = params;
4307
4351
  assertCommerceIdempotencyKey(idempotencyKey);
4308
- return this.execute(endpoint2, body, idempotencyKey).then(
4352
+ return this.execute(endpoint, body, idempotencyKey).then(
4309
4353
  (value) => validateCartMutationResult(value)
4310
4354
  );
4311
4355
  }
@@ -4331,8 +4375,8 @@ var CheckoutApi = class extends CustomerScopedApi {
4331
4375
  constructor(options) {
4332
4376
  super("CheckoutApi", { ...options, requiresCredential: false });
4333
4377
  }
4334
- post(endpoint2, body, idempotencyKey) {
4335
- return this.requestEndpoint(endpoint2, body, {
4378
+ post(endpoint, body, idempotencyKey) {
4379
+ return this.requestEndpoint(endpoint, body, {
4336
4380
  ...idempotencyKey && {
4337
4381
  headers: { "X-Idempotency-Key": idempotencyKey }
4338
4382
  }
@@ -4399,11 +4443,15 @@ var PaymentSessionApi = class extends CustomerScopedApi {
4399
4443
  super("PaymentSessionApi", { ...options, requiresCredential: false });
4400
4444
  this.serverTransport = Boolean(options.secretKey);
4401
4445
  }
4402
- post(endpoint2, body, idempotencyKey) {
4403
- return this.requestEndpoint(endpoint2, body, {
4404
- ...idempotencyKey && {
4405
- headers: { "X-Idempotency-Key": idempotencyKey }
4446
+ post(endpoint, body, idempotencyKey, negotiateStandardActionCapabilities = false) {
4447
+ const headers = {
4448
+ ...idempotencyKey && { "X-Idempotency-Key": idempotencyKey },
4449
+ ...negotiateStandardActionCapabilities && {
4450
+ Accept: PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE
4406
4451
  }
4452
+ };
4453
+ return this.requestEndpoint(endpoint, body, {
4454
+ ...Object.keys(headers).length > 0 && { headers }
4407
4455
  });
4408
4456
  }
4409
4457
  async paymentSession(result, expectedProvider) {
@@ -4428,40 +4476,41 @@ var PaymentSessionApi = class extends CustomerScopedApi {
4428
4476
  this.post(
4429
4477
  this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.create : COMMERCE_ENDPOINTS.paymentSessions.create,
4430
4478
  body,
4431
- idempotencyKey
4479
+ idempotencyKey,
4480
+ body.providerOptions.profile === "standard_v2"
4432
4481
  ),
4433
4482
  "portone"
4434
4483
  );
4435
4484
  }
4436
4485
  retrieve(params) {
4437
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4486
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4438
4487
  return this.paymentSession(
4439
- this.post(endpoint2, params),
4488
+ this.post(endpoint, params),
4440
4489
  "toss"
4441
4490
  );
4442
4491
  }
4443
4492
  retrievePortOne(params) {
4444
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4493
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4445
4494
  return this.paymentSession(
4446
- this.post(endpoint2, params),
4495
+ this.post(endpoint, params, void 0, true),
4447
4496
  "portone"
4448
4497
  );
4449
4498
  }
4450
4499
  cancel(params) {
4451
4500
  const { idempotencyKey, ...body } = params;
4452
4501
  assertCommerceIdempotencyKey(idempotencyKey);
4453
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4502
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4454
4503
  return this.paymentSession(
4455
- this.post(endpoint2, body, idempotencyKey),
4504
+ this.post(endpoint, body, idempotencyKey),
4456
4505
  "toss"
4457
4506
  );
4458
4507
  }
4459
4508
  cancelPortOne(params) {
4460
4509
  const { idempotencyKey, ...body } = params;
4461
4510
  assertCommerceIdempotencyKey(idempotencyKey);
4462
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4511
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4463
4512
  return this.paymentSession(
4464
- this.post(endpoint2, body, idempotencyKey),
4513
+ this.post(endpoint, body, idempotencyKey),
4465
4514
  "portone"
4466
4515
  );
4467
4516
  }
@@ -4540,9 +4589,9 @@ function resolveVariantImageItems(variant, poolById) {
4540
4589
  if (pooled) resolved.push(pooled);
4541
4590
  continue;
4542
4591
  }
4543
- const mediaId2 = getMediaId(entry);
4544
- if (mediaId2) {
4545
- const pooled = poolById.get(mediaId2);
4592
+ const mediaId = getMediaId(entry);
4593
+ if (mediaId) {
4594
+ const pooled = poolById.get(mediaId);
4546
4595
  if (pooled) {
4547
4596
  resolved.push(pooled);
4548
4597
  }
@@ -4733,11 +4782,11 @@ function getFirstMediaId(values) {
4733
4782
  }
4734
4783
  return null;
4735
4784
  }
4736
- function inProductMediaPool(product, mediaId2) {
4737
- if (mediaId2 == null) return null;
4785
+ function inProductMediaPool(product, mediaId) {
4786
+ if (mediaId == null) return null;
4738
4787
  const images = Array.isArray(product?.images) ? product.images : [];
4739
4788
  for (const image of images) {
4740
- if (extractEntityId(image) === mediaId2) return mediaId2;
4789
+ if (extractEntityId(image) === mediaId) return mediaId;
4741
4790
  }
4742
4791
  return null;
4743
4792
  }
@@ -6318,8 +6367,8 @@ function isProductUpsertFieldValidationErrorBody(value) {
6318
6367
 
6319
6368
  // src/core/commerce/commerce-client.ts
6320
6369
  var BrowserCommerceApi = class extends CustomerScopedApi {
6321
- requestEndpoint(endpoint2, body, options) {
6322
- return super.requestEndpoint(endpoint2, body, options);
6370
+ requestEndpoint(endpoint, body, options) {
6371
+ return super.requestEndpoint(endpoint, body, options);
6323
6372
  }
6324
6373
  };
6325
6374
  var CommerceClient = class {
@@ -6519,11 +6568,11 @@ var EventsClient = class {
6519
6568
  { useCustomerAuth: false }
6520
6569
  );
6521
6570
  }
6522
- async execute(endpoint2, method, body, options = {}) {
6571
+ async execute(endpoint, method, body, options = {}) {
6523
6572
  const useCustomerAuth = options.useCustomerAuth === true;
6524
6573
  const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
6525
6574
  try {
6526
- const response = await httpFetch(endpoint2, {
6575
+ const response = await httpFetch(endpoint, {
6527
6576
  method,
6528
6577
  apiUrl: this.apiUrl,
6529
6578
  publishableKey: this.publishableKey,
@@ -6532,7 +6581,7 @@ var EventsClient = class {
6532
6581
  ...body !== void 0 && { body: JSON.stringify(body) }
6533
6582
  });
6534
6583
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
6535
- return parseApiResponse(response, endpoint2);
6584
+ return parseApiResponse(response, endpoint);
6536
6585
  } catch (err) {
6537
6586
  const id = err instanceof SDKError ? err.requestId ?? null : null;
6538
6587
  this.onRequestId?.(id);
@@ -6790,13 +6839,106 @@ function mergeProductDetailWithStock(catalog, snapshot) {
6790
6839
  };
6791
6840
  }
6792
6841
 
6842
+ // src/core/webhook/validation.ts
6843
+ function isValidWebhookEventData(data) {
6844
+ if (typeof data !== "object" || data === null) return false;
6845
+ const event = data;
6846
+ return typeof event.collection === "string" && typeof event.operation === "string" && event.operation.length > 0 && typeof event.data === "object" && event.data !== null;
6847
+ }
6848
+
6849
+ // src/core/webhook/receiver.ts
6850
+ async function verifySignature(rawBody, secret, signature, timestamp2, deliveryId) {
6851
+ const encoder = new TextEncoder();
6852
+ const signedPrefix = encoder.encode(`${timestamp2}.${deliveryId}.`);
6853
+ const signedPayload = new Uint8Array(signedPrefix.length + rawBody.length);
6854
+ signedPayload.set(signedPrefix);
6855
+ signedPayload.set(rawBody, signedPrefix.length);
6856
+ const key = await crypto.subtle.importKey(
6857
+ "raw",
6858
+ encoder.encode(secret),
6859
+ { name: "HMAC", hash: "SHA-256" },
6860
+ false,
6861
+ ["verify"]
6862
+ );
6863
+ if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
6864
+ return false;
6865
+ }
6866
+ const sigBytes = new Uint8Array(
6867
+ (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
6868
+ );
6869
+ return crypto.subtle.verify("HMAC", key, sigBytes, signedPayload);
6870
+ }
6871
+ function timestampIsFresh(timestamp2, toleranceSeconds) {
6872
+ if (!/^\d+$/.test(timestamp2)) return false;
6873
+ const timestampMs = Number(timestamp2);
6874
+ if (!Number.isFinite(timestampMs)) return false;
6875
+ const skewMs = Math.abs(Date.now() - timestampMs);
6876
+ return skewMs <= toleranceSeconds * 1e3;
6877
+ }
6878
+ var MAX_TOLERANCE_SECONDS = 86400;
6879
+ function toleranceIsValid(toleranceSeconds) {
6880
+ return typeof toleranceSeconds === "number" && Number.isFinite(toleranceSeconds) && toleranceSeconds >= 0 && toleranceSeconds <= MAX_TOLERANCE_SECONDS;
6881
+ }
6882
+ async function processWebhookRequest(request, handler, verify) {
6883
+ try {
6884
+ const rawBody = new Uint8Array(await request.arrayBuffer());
6885
+ const verificationFailure = await verify?.(rawBody);
6886
+ if (verificationFailure) return verificationFailure;
6887
+ const body = JSON.parse(new TextDecoder().decode(rawBody));
6888
+ if (!isValidWebhookEventData(body)) {
6889
+ return new Response(
6890
+ JSON.stringify({ error: "Invalid webhook event format" }),
6891
+ { status: 400, headers: { "Content-Type": "application/json" } }
6892
+ );
6893
+ }
6894
+ await handler(body);
6895
+ return new Response(
6896
+ JSON.stringify({ success: true, message: "Webhook processed" }),
6897
+ { status: 200, headers: { "Content-Type": "application/json" } }
6898
+ );
6899
+ } catch (error) {
6900
+ console.error("Webhook processing error:", error);
6901
+ return new Response(JSON.stringify({ error: "Internal server error" }), {
6902
+ status: 500,
6903
+ headers: { "Content-Type": "application/json" }
6904
+ });
6905
+ }
6906
+ }
6907
+ async function handleSignedWebhook(request, handler, options) {
6908
+ const secret = options?.secret;
6909
+ const configuredTolerance = options?.toleranceSeconds;
6910
+ const toleranceSeconds = configuredTolerance ?? 300;
6911
+ if (typeof secret !== "string" || secret.trim().length === 0) {
6912
+ return new Response(
6913
+ JSON.stringify({ error: "Webhook signing secret is not configured" }),
6914
+ { status: 500, headers: { "Content-Type": "application/json" } }
6915
+ );
6916
+ }
6917
+ if (!toleranceIsValid(toleranceSeconds)) {
6918
+ return new Response(
6919
+ JSON.stringify({ error: "Webhook signature tolerance is not valid" }),
6920
+ { status: 500, headers: { "Content-Type": "application/json" } }
6921
+ );
6922
+ }
6923
+ return processWebhookRequest(request, handler, async (rawBody) => {
6924
+ const signature = request.headers.get("x-webhook-signature") || "";
6925
+ const timestamp2 = request.headers.get("x-webhook-timestamp") || "";
6926
+ const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
6927
+ const valid = Boolean(timestamp2 && deliveryId) && timestampIsFresh(timestamp2, toleranceSeconds) && await verifySignature(rawBody, secret, signature, timestamp2, deliveryId);
6928
+ if (!valid) {
6929
+ return new Response(
6930
+ JSON.stringify({ error: "Invalid webhook signature" }),
6931
+ { status: 401, headers: { "Content-Type": "application/json" } }
6932
+ );
6933
+ }
6934
+ });
6935
+ }
6936
+
6793
6937
  // src/core/webhook/index.ts
6794
6938
  var ORDER_CHANGED_EVENT_TYPE = "collection.orderChanged";
6795
6939
  var COMMERCE_NOTIFICATION_EVENT_TYPE = "commerce.notification";
6796
6940
  function isValidWebhookEvent(data) {
6797
- if (typeof data !== "object" || data === null) return false;
6798
- const obj = data;
6799
- return typeof obj.collection === "string" && typeof obj.operation === "string" && obj.operation.length > 0 && typeof obj.data === "object" && obj.data !== null;
6941
+ return isValidWebhookEventData(data);
6800
6942
  }
6801
6943
  var COMMERCE_NOTIFICATION_OPERATION = "notification";
6802
6944
  var COMMERCE_NOTIFICATION_EVENTS = [
@@ -6808,7 +6950,9 @@ var COMMERCE_NOTIFICATION_EVENTS = [
6808
6950
  "returnApproved",
6809
6951
  "returnRejected",
6810
6952
  "returnCanceled",
6811
- "returnCompleted"
6953
+ "returnCompleted",
6954
+ "paymentReconciliationRequired",
6955
+ "paymentRefundRequiresAttention"
6812
6956
  ];
6813
6957
  function isStringOrNumber(value) {
6814
6958
  return typeof value === "string" || typeof value === "number";
@@ -6838,18 +6982,25 @@ function isCommerceNotificationEventName(value) {
6838
6982
  return typeof value === "string" && COMMERCE_NOTIFICATION_EVENTS.includes(value);
6839
6983
  }
6840
6984
  function isCommerceNotificationSourceCollection(value) {
6841
- return value === "orders" || value === "fulfillments" || value === "returns";
6985
+ return value === "orders" || value === "fulfillments" || value === "returns" || value === "payment-sessions" || value === "payment-refund-attempts";
6842
6986
  }
6843
6987
  function isCommerceNotificationData(value) {
6844
6988
  if (!isRecord(value)) return false;
6845
6989
  if (value.source !== void 0 && (!isRecord(value.source) || !isCommerceNotificationSourceCollection(value.source.collection) || !isStringOrNumber(value.source.id))) {
6846
6990
  return false;
6847
6991
  }
6848
- 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");
6992
+ 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") && (value.paymentSessionId === void 0 || typeof value.paymentSessionId === "string") && (value.checkoutId === void 0 || typeof value.checkoutId === "string") && (value.refundAttemptId === void 0 || typeof value.refundAttemptId === "string") && (value.reason === void 0 || typeof value.reason === "string") && (value.observedAt === void 0 || typeof value.observedAt === "string") && (value.providerObject === void 0 || isRecord(value.providerObject) && typeof value.providerObject.provider === "string" && (value.providerObject.kind === "payment" || value.providerObject.kind === "refund") && typeof value.providerObject.id === "string") && (value.money === void 0 || isRecord(value.money) && Number.isSafeInteger(value.money.amountMinor) && Number(value.money.amountMinor) > 0 && typeof value.money.currency === "string");
6849
6993
  }
6850
6994
  function isCommerceNotification(value) {
6851
6995
  if (!isRecord(value)) return false;
6852
- 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");
6996
+ 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") && (value.paymentSessionId === void 0 || typeof value.paymentSessionId === "string") && (value.refundAttemptId === void 0 || typeof value.refundAttemptId === "string");
6997
+ }
6998
+ function isPaymentIncidentNotificationData(value, event) {
6999
+ const reconciliation = event === "paymentReconciliationRequired";
7000
+ const expectedCollection = reconciliation ? "payment-sessions" : "payment-refund-attempts";
7001
+ const expectedStatus = reconciliation ? "reconciliation_required" : "requires_attention";
7002
+ const expectedReason = reconciliation ? "orderless_capture" : "local_commit_ambiguous";
7003
+ return value.source?.collection === expectedCollection && typeof value.source.id === "string" && value.source.id.length > 0 && typeof value.paymentSessionId === "string" && value.paymentSessionId.length > 0 && isRecord(value.providerObject) && typeof value.providerObject.provider === "string" && value.providerObject.provider.length > 0 && (value.providerObject.kind === "payment" || value.providerObject.kind === "refund") && typeof value.providerObject.id === "string" && value.providerObject.id.length > 0 && isRecord(value.money) && Number.isSafeInteger(value.money.amountMinor) && Number(value.money.amountMinor) > 0 && typeof value.money.currency === "string" && value.money.currency.length > 0 && value.status === expectedStatus && value.reason === expectedReason && typeof value.observedAt === "string" && value.observedAt.length > 0 && !Number.isNaN(Date.parse(value.observedAt)) && (value.checkoutId === void 0 || typeof value.checkoutId === "string" && value.checkoutId.length > 0) && (value.orderId === void 0 || typeof value.orderId === "string" && value.orderId.length > 0) && (reconciliation ? value.source.id === value.paymentSessionId && value.providerObject.kind === "payment" && value.refundAttemptId === void 0 : typeof value.refundAttemptId === "string" && value.refundAttemptId.length > 0 && value.source.id === value.refundAttemptId);
6853
7004
  }
6854
7005
  function isWebhookCommerceNotificationChange(value) {
6855
7006
  if (!isRecord(value)) return false;
@@ -6890,6 +7041,15 @@ function isCommerceNotificationWebhookEvent(event) {
6890
7041
  if (!matchesOptionalId(change.sourceId, sourceId)) return false;
6891
7042
  }
6892
7043
  const changeSourceId = isWebhookCommerceNotificationChange(change) ? change.sourceId : void 0;
7044
+ if (notification.event === "paymentReconciliationRequired" || notification.event === "paymentRefundRequiresAttention") {
7045
+ if (!isPaymentIncidentNotificationData(data, notification.event)) {
7046
+ return false;
7047
+ }
7048
+ const incidentData = data;
7049
+ const expectedCollection = notification.event === "paymentReconciliationRequired" ? "payment-sessions" : "payment-refund-attempts";
7050
+ const notificationSourceId = notification.event === "paymentReconciliationRequired" ? notification.paymentSessionId : notification.refundAttemptId;
7051
+ return sourceCollection === expectedCollection && typeof notification.paymentSessionId === "string" && notification.paymentSessionId === incidentData.paymentSessionId && typeof notificationSourceId === "string" && notificationSourceId === incidentData.source.id && matchesOptionalId(changeSourceId, incidentData.source.id);
7052
+ }
6893
7053
  if (notification.event === "orderPaid" || notification.event === "orderCanceled" || notification.event === "orderDelivered") {
6894
7054
  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);
6895
7055
  }
@@ -6958,80 +7118,8 @@ function createCustomerAuthWebhookHandler(handlers) {
6958
7118
  await handlers.unhandled?.(event);
6959
7119
  };
6960
7120
  }
6961
- async function verifySignature(payload, secret, signature, timestamp2, deliveryId) {
6962
- const encoder = new TextEncoder();
6963
- const key = await crypto.subtle.importKey(
6964
- "raw",
6965
- encoder.encode(secret),
6966
- { name: "HMAC", hash: "SHA-256" },
6967
- false,
6968
- ["verify"]
6969
- );
6970
- if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
6971
- return false;
6972
- }
6973
- const sigBytes = new Uint8Array(
6974
- (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
6975
- );
6976
- return crypto.subtle.verify(
6977
- "HMAC",
6978
- key,
6979
- sigBytes,
6980
- encoder.encode(`${timestamp2}.${deliveryId}.${payload}`)
6981
- );
6982
- }
6983
- function timestampIsFresh(timestamp2, toleranceSeconds) {
6984
- if (!/^\d+$/.test(timestamp2)) return false;
6985
- const timestampMs = Number(timestamp2);
6986
- if (!Number.isFinite(timestampMs)) return false;
6987
- const skewMs = Math.abs(Date.now() - timestampMs);
6988
- return skewMs <= toleranceSeconds * 1e3;
6989
- }
6990
7121
  async function handleWebhook(request, handler, options) {
6991
- try {
6992
- const rawBody = await request.text();
6993
- if (options?.secret) {
6994
- const signature = request.headers.get("x-webhook-signature") || "";
6995
- const timestamp2 = request.headers.get("x-webhook-timestamp") || "";
6996
- const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
6997
- const toleranceSeconds = options.toleranceSeconds ?? 300;
6998
- const valid = Boolean(timestamp2 && deliveryId) && timestampIsFresh(timestamp2, toleranceSeconds) && await verifySignature(
6999
- rawBody,
7000
- options.secret,
7001
- signature,
7002
- timestamp2,
7003
- deliveryId
7004
- );
7005
- if (!valid) {
7006
- return new Response(
7007
- JSON.stringify({ error: "Invalid webhook signature" }),
7008
- { status: 401, headers: { "Content-Type": "application/json" } }
7009
- );
7010
- }
7011
- } else {
7012
- console.warn(
7013
- "[@01.software/sdk] Webhook signature verification is disabled. Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification."
7014
- );
7015
- }
7016
- const body = JSON.parse(rawBody);
7017
- if (!isValidWebhookEvent(body)) {
7018
- return new Response(
7019
- JSON.stringify({ error: "Invalid webhook event format" }),
7020
- { status: 400, headers: { "Content-Type": "application/json" } }
7021
- );
7022
- }
7023
- await handler(body);
7024
- return new Response(
7025
- JSON.stringify({ success: true, message: "Webhook processed" }),
7026
- { status: 200, headers: { "Content-Type": "application/json" } }
7027
- );
7028
- } catch (error) {
7029
- console.error("Webhook processing error:", error);
7030
- return new Response(JSON.stringify({ error: "Internal server error" }), {
7031
- status: 500,
7032
- headers: { "Content-Type": "application/json" }
7033
- });
7034
- }
7122
+ return handleSignedWebhook(request, handler, options);
7035
7123
  }
7036
7124
  function createTypedWebhookHandler(collection, handler) {
7037
7125
  return async (event) => {
@@ -7071,6 +7159,7 @@ var INTERNAL_COLLECTIONS = [
7071
7159
  "payment-event-inbox",
7072
7160
  "payment-refund-attempts",
7073
7161
  "portone-payment-interactions",
7162
+ "commerce-payment-webhook-routes",
7074
7163
  "commerce-notification-intents",
7075
7164
  "commerce-idempotency-records",
7076
7165
  "product-collection-items",
@@ -7111,7 +7200,6 @@ var COLLECTIONS = [
7111
7200
  "brands",
7112
7201
  "customer-profiles",
7113
7202
  "customer-profile-stats",
7114
- "discounts",
7115
7203
  "shipping-policies",
7116
7204
  "shipping-zones",
7117
7205
  "documents",
@@ -7187,6 +7275,9 @@ var SERVER_ONLY_COLLECTIONS = [
7187
7275
  "cart-items",
7188
7276
  "checkouts",
7189
7277
  "checkout-items",
7278
+ // Raw discount definitions require a server credential. Browser discount
7279
+ // validation is exposed through the shaped POST /api/discounts/validate path.
7280
+ "discounts",
7190
7281
  "draft-orders",
7191
7282
  "draft-order-items",
7192
7283
  "posts",
@@ -7352,160 +7443,6 @@ var RealtimeConnection = class {
7352
7443
  }
7353
7444
  };
7354
7445
 
7355
- // src/utils/product-media.ts
7356
- function mediaPointerOptionValues(values) {
7357
- return (values ?? []).filter((value) => value != null && value !== "").map((value) => ({
7358
- swatch: {
7359
- type: "media",
7360
- mediaItemId: value
7361
- }
7362
- }));
7363
- }
7364
- function resolveProductMedia(input) {
7365
- const resolved = resolveProductSelectionMedia({
7366
- ...input,
7367
- selectedVariant: input.selectedVariant ?? (input.variantFeaturedMediaItemId ? { images: [input.variantFeaturedMediaItemId] } : null),
7368
- selectedOptionValues: input.selectedOptionValues ?? mediaPointerOptionValues(input.selectedOptionValueMediaItemIds)
7369
- });
7370
- if (resolved.source !== "none") {
7371
- return {
7372
- ...resolved,
7373
- source: resolved.source === "variant_media_selected" ? "variant_featured" : resolved.source
7374
- };
7375
- }
7376
- const display = resolveProductDisplayMedia({
7377
- productMediaPool: input.productMediaPool
7378
- });
7379
- return {
7380
- primaryImage: display.primaryImage,
7381
- images: display.images,
7382
- source: display.source
7383
- };
7384
- }
7385
-
7386
- // src/utils/product-gallery.ts
7387
- function mediaId(value) {
7388
- if (typeof value === "string" || typeof value === "number") {
7389
- return String(value);
7390
- }
7391
- if (typeof value === "object" && value !== null && "id" in value) {
7392
- const id = value.id;
7393
- if (typeof id === "string" || typeof id === "number") return String(id);
7394
- }
7395
- return null;
7396
- }
7397
- function relationshipIds(values) {
7398
- if (!Array.isArray(values)) return [];
7399
- return values.map((value) => mediaId(value)).filter((value) => Boolean(value));
7400
- }
7401
- function buildPoolById2(pool) {
7402
- const poolById = /* @__PURE__ */ new Map();
7403
- for (const item of pool) {
7404
- const id = mediaId(item);
7405
- if (id) poolById.set(id, item);
7406
- }
7407
- return poolById;
7408
- }
7409
- function mediaSetItemsInPool(mediaSet, poolById) {
7410
- const seen = /* @__PURE__ */ new Set();
7411
- const items = [];
7412
- const primaryId = mediaId(mediaSet.primaryMediaItemId);
7413
- if (primaryId) {
7414
- const primary = poolById.get(primaryId);
7415
- if (primary) {
7416
- seen.add(primaryId);
7417
- items.push(primary);
7418
- }
7419
- }
7420
- for (const itemId of relationshipIds(mediaSet.items)) {
7421
- if (seen.has(itemId)) continue;
7422
- const item = poolById.get(itemId);
7423
- if (!item) continue;
7424
- seen.add(itemId);
7425
- items.push(item);
7426
- }
7427
- return items;
7428
- }
7429
- function resolveLegacyMediaSet(input) {
7430
- if (!Array.isArray(input.mediaSets)) return null;
7431
- const pool = input.productMediaPool ?? input.pool ?? [];
7432
- const poolById = buildPoolById2(pool);
7433
- const selectedVariantId = mediaId(input.selectedVariantId);
7434
- if (selectedVariantId) {
7435
- const exactSet = input.mediaSets.find(
7436
- (set) => set.matchType === "exact-variant" && relationshipIds(set.variantIds).includes(selectedVariantId)
7437
- );
7438
- if (exactSet) {
7439
- const images = mediaSetItemsInPool(exactSet, poolById);
7440
- if (images.length > 0) {
7441
- return {
7442
- primaryImage: images[0] ?? null,
7443
- images,
7444
- source: "exact_variant_set"
7445
- };
7446
- }
7447
- }
7448
- }
7449
- const selectedOptionValueIds = new Set(
7450
- relationshipIds(input.selectedOptionValueIds)
7451
- );
7452
- const optionSetMatches = input.mediaSets.filter((set) => set.matchType === "option-values").map((set) => {
7453
- const optionValueIds = relationshipIds(set.optionValueIds);
7454
- if (optionValueIds.length === 0) return null;
7455
- if (!optionValueIds.every((id) => selectedOptionValueIds.has(id))) {
7456
- return null;
7457
- }
7458
- const images = mediaSetItemsInPool(set, poolById);
7459
- if (images.length === 0) return null;
7460
- return { optionValueCount: optionValueIds.length, images };
7461
- }).filter(
7462
- (match) => Boolean(match)
7463
- ).sort((a, b) => b.optionValueCount - a.optionValueCount);
7464
- if (optionSetMatches.length > 0) {
7465
- const images = optionSetMatches[0].images;
7466
- return {
7467
- primaryImage: images[0] ?? null,
7468
- images,
7469
- source: "option_value_set"
7470
- };
7471
- }
7472
- const defaultSet = input.mediaSets.find((set) => set.matchType === "default");
7473
- if (defaultSet) {
7474
- const images = mediaSetItemsInPool(defaultSet, poolById);
7475
- if (images.length > 0) {
7476
- return {
7477
- primaryImage: images[0] ?? null,
7478
- images,
7479
- source: "default_set"
7480
- };
7481
- }
7482
- }
7483
- return {
7484
- primaryImage: null,
7485
- images: [],
7486
- source: "none"
7487
- };
7488
- }
7489
- function resolveProductGallery(input) {
7490
- const selectedVariantId = mediaId(input.selectedVariantId);
7491
- const selectedOptionValueIds = relationshipIds(input.selectedOptionValueIds);
7492
- const selection = resolveProductSelectionMedia({
7493
- ...input,
7494
- productMediaPool: input.productMediaPool ?? input.pool ?? null,
7495
- selectedVariant: input.selectedVariant ?? (selectedVariantId ? { id: selectedVariantId } : null),
7496
- selectedOptionValues: input.selectedOptionValues ?? selectedOptionValueIds.map((id) => ({ id }))
7497
- });
7498
- if (selection.source !== "none") {
7499
- return selection;
7500
- }
7501
- const legacyResolved = resolveLegacyMediaSet(input);
7502
- if (legacyResolved && legacyResolved.source !== "none") return legacyResolved;
7503
- return resolveProductDisplayMedia({
7504
- productMediaPool: input.productMediaPool ?? input.pool ?? null,
7505
- featuredImage: input.featuredImage
7506
- });
7507
- }
7508
-
7509
7446
  // src/utils/image.ts
7510
7447
  var IMAGE_SIZES = [200, 400, 800, 1200, 1600];
7511
7448
  function imageSizeCandidates(sizes) {
@@ -7637,7 +7574,7 @@ function createAnalytics(config) {
7637
7574
  }, destroy() {
7638
7575
  } };
7639
7576
  }
7640
- const endpoint2 = config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`;
7577
+ const endpoint = config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`;
7641
7578
  const respectDnt = config.respectDnt !== false;
7642
7579
  function isDntActive() {
7643
7580
  if (!respectDnt) return false;
@@ -7678,10 +7615,10 @@ function createAnalytics(config) {
7678
7615
  try {
7679
7616
  if (typeof navigator.sendBeacon === "function") {
7680
7617
  const blob = new Blob([body], { type: "text/plain" });
7681
- const sent = navigator.sendBeacon(endpoint2, blob);
7618
+ const sent = navigator.sendBeacon(endpoint, blob);
7682
7619
  if (sent) return;
7683
7620
  }
7684
- fetch(endpoint2, {
7621
+ fetch(endpoint, {
7685
7622
  method: "POST",
7686
7623
  keepalive: true,
7687
7624
  headers: { "Content-Type": "application/json" },