@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.js CHANGED
@@ -97,6 +97,7 @@ var COMMERCE_ERROR_CODES = [
97
97
  "payment_session_not_cancelable",
98
98
  "payment_session_conflict",
99
99
  "provider_identity_mismatch",
100
+ "managed_refund_attestation_forbidden",
100
101
  "payment_method_unavailable",
101
102
  "provider_unavailable",
102
103
  "lock_timeout",
@@ -639,11 +640,11 @@ function parseRetryAfter(response) {
639
640
  permitsAutomaticRetry: seconds <= MAX_AUTOMATIC_RETRY_AFTER_SECONDS
640
641
  };
641
642
  }
642
- function mapResponseToError(status, parsed, details, requestId, retryAfter, errorFamily) {
643
+ function mapResponseToError(status, parsed, details, requestId, retryAfter, canonicalCommerceError) {
643
644
  const errorDetails = {
644
645
  ...details,
645
646
  ...parsed.errors && { errors: parsed.errors },
646
- ...errorFamily !== "commerce" && parsed.body && { body: parsed.body }
647
+ ...!canonicalCommerceError && parsed.body && { body: parsed.body }
647
648
  };
648
649
  const suggestion = getParsedErrorSuggestion(status, parsed);
649
650
  const finalize = (error) => {
@@ -651,7 +652,7 @@ function mapResponseToError(status, parsed, details, requestId, retryAfter, erro
651
652
  if (retryAfter !== void 0) {
652
653
  Object.assign(withRequestId, { retryAfter });
653
654
  }
654
- return errorFamily === "commerce" ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(withRequestId, parsed.reason);
655
+ return canonicalCommerceError ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(withRequestId, parsed.reason);
655
656
  };
656
657
  if (status === 400 || status === 422) {
657
658
  return finalize(
@@ -757,6 +758,7 @@ async function httpFetch(url, options) {
757
758
  retry,
758
759
  onUnauthorized,
759
760
  errorFamily,
761
+ typedCommerceErrorReasons,
760
762
  ...requestInit
761
763
  } = options || {};
762
764
  const baseUrl = resolveApiUrl(apiUrl);
@@ -810,7 +812,8 @@ async function httpFetch(url, options) {
810
812
  });
811
813
  if (!response.ok) {
812
814
  const parsed = await parseErrorBody(response);
813
- const commerceEnvelope = errorFamily === "commerce" ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
815
+ const canonicalCommerceError = errorFamily === "commerce" || typeof parsed.reason === "string" && typedCommerceErrorReasons?.includes(parsed.reason) === true;
816
+ const commerceEnvelope = canonicalCommerceError ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
814
817
  if (isUsageLimitExceededResponse(response)) {
815
818
  const limit = parseInt(
816
819
  response.headers.get("X-Usage-Limit") || "0",
@@ -838,7 +841,7 @@ async function httpFetch(url, options) {
838
841
  ),
839
842
  requestId
840
843
  );
841
- throw errorFamily === "commerce" ? enhanceCommerceError(usageError, parsed.body, requestId) : enhanceNonCommerceError(usageError, parsed.reason);
844
+ throw canonicalCommerceError ? enhanceCommerceError(usageError, parsed.body, requestId) : enhanceNonCommerceError(usageError, parsed.reason);
842
845
  }
843
846
  if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && (commerceEnvelope?.reason ?? parsed.reason) === "token_expired") {
844
847
  hasRetried401 = true;
@@ -863,7 +866,7 @@ async function httpFetch(url, options) {
863
866
  details,
864
867
  requestId,
865
868
  retryAfter.seconds,
866
- errorFamily
869
+ canonicalCommerceError
867
870
  );
868
871
  const method2 = (requestInit.method || "GET").toUpperCase();
869
872
  const isTerminal = error instanceof RateLimitError || error instanceof UsageLimitError;
@@ -1041,15 +1044,15 @@ var HttpClient = class {
1041
1044
  throw err;
1042
1045
  }
1043
1046
  }
1044
- buildUrl(endpoint2, options) {
1045
- if (!options) return endpoint2;
1047
+ buildUrl(endpoint, options) {
1048
+ if (!options) return endpoint;
1046
1049
  const { fallbackLocale, ...rest } = options;
1047
1050
  const queryOptions = fallbackLocale === void 0 ? rest : {
1048
1051
  ...rest,
1049
1052
  "fallback-locale": fallbackLocale === false ? "none" : fallbackLocale
1050
1053
  };
1051
1054
  const queryString = stringify(queryOptions, { addQueryPrefix: true });
1052
- return queryString ? `${endpoint2}${queryString}` : endpoint2;
1055
+ return queryString ? `${endpoint}${queryString}` : endpoint;
1053
1056
  }
1054
1057
  assertJsonResponse(response) {
1055
1058
  const contentType = response.headers.get("content-type");
@@ -1198,39 +1201,39 @@ var ReadOnlyCollectionClient = class extends HttpClient {
1198
1201
  from(collection) {
1199
1202
  return new ReadOnlyCollectionQueryBuilder(this, collection);
1200
1203
  }
1201
- async requestFind(endpoint2, options) {
1202
- const url = this.buildUrl(endpoint2, options);
1204
+ async requestFind(endpoint, options) {
1205
+ const url = this.buildUrl(endpoint, options);
1203
1206
  const response = await this.fetchWithTracking(url, {
1204
1207
  ...this.defaultOptions,
1205
1208
  method: "GET"
1206
1209
  });
1207
1210
  return this.parseFindResponse(response);
1208
1211
  }
1209
- async requestFindEndpoint(endpoint2, data) {
1210
- const response = await this.fetchWithTracking(endpoint2, {
1212
+ async requestFindEndpoint(endpoint, data) {
1213
+ const response = await this.fetchWithTracking(endpoint, {
1211
1214
  ...this.defaultOptions,
1212
1215
  method: "POST",
1213
1216
  body: data ? JSON.stringify(data) : void 0
1214
1217
  });
1215
1218
  return this.parseFindResponse(response);
1216
1219
  }
1217
- async requestFindEndpointGet(endpoint2) {
1218
- const response = await this.fetchWithTracking(endpoint2, {
1220
+ async requestFindEndpointGet(endpoint) {
1221
+ const response = await this.fetchWithTracking(endpoint, {
1219
1222
  ...this.defaultOptions,
1220
1223
  method: "GET"
1221
1224
  });
1222
1225
  return this.parseFindResponse(response);
1223
1226
  }
1224
- async requestFindById(endpoint2, options) {
1225
- const url = this.buildUrl(endpoint2, options);
1227
+ async requestFindById(endpoint, options) {
1228
+ const url = this.buildUrl(endpoint, options);
1226
1229
  const response = await this.fetchWithTracking(url, {
1227
1230
  ...this.defaultOptions,
1228
1231
  method: "GET"
1229
1232
  });
1230
1233
  return this.parseDocumentResponse(response);
1231
1234
  }
1232
- async requestCount(endpoint2, options) {
1233
- const url = this.buildUrl(endpoint2, options);
1235
+ async requestCount(endpoint, options) {
1236
+ const url = this.buildUrl(endpoint, options);
1234
1237
  const response = await this.fetchWithTracking(url, {
1235
1238
  ...this.defaultOptions,
1236
1239
  method: "GET"
@@ -1240,7 +1243,7 @@ var ReadOnlyCollectionClient = class extends HttpClient {
1240
1243
  };
1241
1244
 
1242
1245
  // src/core/api/parse-response.ts
1243
- async function parseApiResponse(response, endpoint2, options = {}) {
1246
+ async function parseApiResponse(response, endpoint, options = {}) {
1244
1247
  if (response.status === 204 || response.headers.get("content-length") === "0") {
1245
1248
  return void 0;
1246
1249
  }
@@ -1249,7 +1252,7 @@ async function parseApiResponse(response, endpoint2, options = {}) {
1249
1252
  parsed = await response.json();
1250
1253
  } catch {
1251
1254
  throw createApiError(
1252
- `Invalid JSON response from ${endpoint2}`,
1255
+ `Invalid JSON response from ${endpoint}`,
1253
1256
  response.status,
1254
1257
  void 0,
1255
1258
  "Server returned an invalid response.",
@@ -1299,6 +1302,7 @@ async function parseApiResponse(response, endpoint2, options = {}) {
1299
1302
 
1300
1303
  // ../../internal/http-contracts/src/index.ts
1301
1304
  var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
1305
+ var PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE = "application/vnd.01software.portone-action-capabilities.v1+json";
1302
1306
  var operation = (collection, method, path, errorFamily) => Object.freeze({
1303
1307
  [operationBrand]: true,
1304
1308
  collection,
@@ -1307,6 +1311,10 @@ var operation = (collection, method, path, errorFamily) => Object.freeze({
1307
1311
  ...errorFamily && { errorFamily }
1308
1312
  });
1309
1313
  var strictCommerceOperation = (collection, method, path) => operation(collection, method, path, "commerce");
1314
+ var selectiveCommerceOperation = (collection, method, path, typedCommerceErrorReasons) => Object.freeze({
1315
+ ...operation(collection, method, path),
1316
+ typedCommerceErrorReasons: Object.freeze([...typedCommerceErrorReasons])
1317
+ });
1310
1318
  var COMMERCE_ENDPOINT_OPERATIONS = {
1311
1319
  products: {
1312
1320
  detail: operation("products", "get", "/detail"),
@@ -1338,7 +1346,12 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1338
1346
  confirmPayment: operation("orders", "post", "/confirm-payment"),
1339
1347
  byPayment: operation("orders", "get", "/by-payment"),
1340
1348
  cancel: operation("orders", "post", "/cancel"),
1341
- resolveCancelRefund: operation("orders", "post", "/resolve-cancel-refund"),
1349
+ resolveCancelRefund: selectiveCommerceOperation(
1350
+ "orders",
1351
+ "post",
1352
+ "/resolve-cancel-refund",
1353
+ ["managed_refund_attestation_forbidden"]
1354
+ ),
1342
1355
  checkout: strictCommerceOperation("orders", "post", "/checkout"),
1343
1356
  createFulfillment: operation("orders", "post", "/create-fulfillment"),
1344
1357
  updateFulfillment: operation("orders", "post", "/update-fulfillment")
@@ -1409,6 +1422,16 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1409
1422
  "payment-sessions",
1410
1423
  "post",
1411
1424
  "/server/confirm"
1425
+ ),
1426
+ findPortOne: strictCommerceOperation(
1427
+ "payment-sessions",
1428
+ "post",
1429
+ "/server/portone/find"
1430
+ ),
1431
+ reconcilePortOne: strictCommerceOperation(
1432
+ "payment-sessions",
1433
+ "post",
1434
+ "/server/portone/reconcile"
1412
1435
  )
1413
1436
  },
1414
1437
  custom: {
@@ -1428,12 +1451,26 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1428
1451
  validate: operation("discounts", "post", "/validate")
1429
1452
  }
1430
1453
  };
1454
+ var portOneStandardActionCapabilityOperations = /* @__PURE__ */ new Set([
1455
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.create,
1456
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.retrieve,
1457
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.create,
1458
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.retrieve
1459
+ ]);
1431
1460
  var MEMBERSHIP_ENDPOINT_OPERATIONS = {
1432
1461
  subscribe: operation(null, "post", "/memberships/subscribe"),
1433
1462
  cancel: operation(null, "post", "/memberships/:id/cancel"),
1434
1463
  me: operation(null, "get", "/memberships/me")
1435
1464
  };
1465
+ var EMBEDDED_ADMIN_ENDPOINT_OPERATIONS = {
1466
+ show: operation("tenants", "get", "/embedded-admin-app"),
1467
+ configure: operation("tenants", "patch", "/embedded-admin-app"),
1468
+ disable: operation("tenants", "delete", "/embedded-admin-app")
1469
+ };
1436
1470
  var EVENTS_ENDPOINT_OPERATIONS = {
1471
+ events: {
1472
+ convertSchedule: operation("events", "post", "/:id/schedule")
1473
+ },
1437
1474
  occurrences: {
1438
1475
  range: operation("event-occurrences", "get", "/range"),
1439
1476
  admissionAvailability: operation(
@@ -1474,46 +1511,51 @@ function resolveOperationMethod(descriptor) {
1474
1511
  }
1475
1512
 
1476
1513
  // src/core/api/endpoints.ts
1477
- var endpoint = (method, path) => ({ method, path });
1478
1514
  var sharedEndpoint = (descriptor) => descriptor;
1479
- function resolveOperationMethod2(descriptor) {
1480
- return "collection" in descriptor ? resolveOperationMethod(descriptor) : descriptor.method;
1481
- }
1482
1515
  function resolveOperationErrorFamily(descriptor) {
1483
- return "collection" in descriptor ? descriptor.errorFamily : void 0;
1484
- }
1485
- function resolveOperationPath2(descriptor, options) {
1486
- if ("collection" in descriptor) {
1487
- return resolveOperationPath(descriptor, options);
1488
- }
1489
- const query = options?.query?.toString().replace(/^\?/, "");
1490
- return query ? `${descriptor.path}?${query}` : descriptor.path;
1516
+ return descriptor.errorFamily;
1491
1517
  }
1492
1518
  var COMMERCE_ENDPOINTS = {
1493
1519
  products: {
1494
- detail: endpoint("GET", "/api/products/detail"),
1495
- detailCatalog: endpoint("GET", "/api/products/detail/catalog"),
1496
- listingGroups: endpoint("GET", "/api/products/listing-groups"),
1497
- listingGroupsCatalog: endpoint(
1498
- "GET",
1499
- "/api/products/listing-groups/catalog"
1520
+ detail: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.detail),
1521
+ detailCatalog: sharedEndpoint(
1522
+ COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog
1523
+ ),
1524
+ listingGroups: sharedEndpoint(
1525
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroups
1526
+ ),
1527
+ listingGroupsCatalog: sharedEndpoint(
1528
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog
1529
+ ),
1530
+ // The manifest keeps the GET read and the POST body-query apart; this
1531
+ // semantic name has always resolved to the GET one.
1532
+ listingGroupsQuery: sharedEndpoint(
1533
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryGet
1534
+ ),
1535
+ listingGroupsQueryCatalog: sharedEndpoint(
1536
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryCatalog
1537
+ ),
1538
+ stockCheck: sharedEndpoint(
1539
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockCheck
1500
1540
  ),
1501
- listingGroupsQuery: endpoint("GET", "/api/products/listing-groups/query"),
1502
- listingGroupsQueryCatalog: endpoint(
1503
- "GET",
1504
- "/api/products/listing-groups/query/catalog"
1541
+ stockSnapshot: sharedEndpoint(
1542
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockSnapshot
1505
1543
  ),
1506
- stockCheck: endpoint("POST", "/api/products/stock-check"),
1507
- stockSnapshot: endpoint("GET", "/api/products/stock"),
1508
- upsert: endpoint("POST", "/api/products/upsert")
1544
+ upsert: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.upsert)
1509
1545
  },
1510
1546
  orders: {
1511
- update: endpoint("POST", "/api/orders/update"),
1512
- byPayment: endpoint("GET", "/api/orders/by-payment"),
1513
- cancel: endpoint("POST", "/api/orders/cancel"),
1514
- resolveCancelRefund: endpoint("POST", "/api/orders/resolve-cancel-refund"),
1515
- createFulfillment: endpoint("POST", "/api/orders/create-fulfillment"),
1516
- updateFulfillment: endpoint("POST", "/api/orders/update-fulfillment")
1547
+ update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.update),
1548
+ byPayment: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.byPayment),
1549
+ cancel: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.cancel),
1550
+ resolveCancelRefund: sharedEndpoint(
1551
+ COMMERCE_ENDPOINT_OPERATIONS.orders.resolveCancelRefund
1552
+ ),
1553
+ createFulfillment: sharedEndpoint(
1554
+ COMMERCE_ENDPOINT_OPERATIONS.orders.createFulfillment
1555
+ ),
1556
+ updateFulfillment: sharedEndpoint(
1557
+ COMMERCE_ENDPOINT_OPERATIONS.orders.updateFulfillment
1558
+ )
1517
1559
  },
1518
1560
  checkouts: {
1519
1561
  create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.checkout),
@@ -1525,18 +1567,21 @@ var COMMERCE_ENDPOINTS = {
1525
1567
  }
1526
1568
  },
1527
1569
  returns: {
1528
- create: endpoint("POST", "/api/returns/create"),
1529
- update: endpoint("POST", "/api/returns/update"),
1530
- returnRefund: endpoint("POST", "/api/returns/return-refund")
1570
+ create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.create),
1571
+ update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.update),
1572
+ returnRefund: sharedEndpoint(
1573
+ COMMERCE_ENDPOINT_OPERATIONS.returns.returnRefund
1574
+ )
1531
1575
  },
1532
1576
  fulfillmentOrders: {
1533
- prepare: endpoint(
1534
- "POST",
1535
- "/api/fulfillment-orders/prepare-fulfillment-order"
1577
+ prepare: sharedEndpoint(
1578
+ COMMERCE_ENDPOINT_OPERATIONS.fulfillmentOrders.prepare
1536
1579
  )
1537
1580
  },
1538
1581
  fulfillments: {
1539
- bulkImport: endpoint("POST", "/api/fulfillments/bulk-import")
1582
+ bulkImport: sharedEndpoint(
1583
+ COMMERCE_ENDPOINT_OPERATIONS.fulfillments.bulkImport
1584
+ )
1540
1585
  },
1541
1586
  carts: {
1542
1587
  create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.create),
@@ -1601,42 +1646,21 @@ var COMMERCE_ENDPOINTS = {
1601
1646
  ),
1602
1647
  confirm: sharedEndpoint(
1603
1648
  COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.confirm
1649
+ ),
1650
+ findPortOne: sharedEndpoint(
1651
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.findPortOne
1652
+ ),
1653
+ reconcilePortOne: sharedEndpoint(
1654
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.reconcilePortOne
1604
1655
  )
1605
1656
  }
1606
1657
  },
1607
1658
  shippingPolicies: {
1608
- calculate: endpoint("POST", "/api/shipping-policies/calculate")
1659
+ calculate: sharedEndpoint(
1660
+ COMMERCE_ENDPOINT_OPERATIONS.shippingPolicies.calculate
1661
+ )
1609
1662
  }
1610
1663
  };
1611
- function isCommerceEndpointDescriptor(value) {
1612
- if (!value || typeof value !== "object") return false;
1613
- const candidate = value;
1614
- return typeof candidate.method === "string" && typeof candidate.path === "string";
1615
- }
1616
- function flattenEndpointPaths(value) {
1617
- if (isCommerceEndpointDescriptor(value)) return [resolveOperationPath2(value)];
1618
- if (!value || typeof value !== "object") return [];
1619
- return Object.values(value).flatMap((entry) => flattenEndpointPaths(entry));
1620
- }
1621
- function flattenEndpointDescriptors(value) {
1622
- if (isCommerceEndpointDescriptor(value)) return [value];
1623
- if (!value || typeof value !== "object") return [];
1624
- return Object.values(value).flatMap(
1625
- (entry) => flattenEndpointDescriptors(entry)
1626
- );
1627
- }
1628
- var COMMERCE_ENDPOINT_PATHS = flattenEndpointPaths(COMMERCE_ENDPOINTS);
1629
- var COMMERCE_ENDPOINT_DESCRIPTORS = flattenEndpointDescriptors(COMMERCE_ENDPOINTS);
1630
- var MEMBERSHIP_ENDPOINTS = {
1631
- subscribe: "/api/memberships/subscribe",
1632
- cancel: (id) => `/api/memberships/${id}/cancel`,
1633
- me: "/api/memberships/me"
1634
- };
1635
- var MEMBERSHIP_ENDPOINT_PATHS = [
1636
- MEMBERSHIP_ENDPOINTS.subscribe,
1637
- MEMBERSHIP_ENDPOINTS.cancel(":id"),
1638
- MEMBERSHIP_ENDPOINTS.me
1639
- ];
1640
1664
 
1641
1665
  // src/core/api/customer-scoped-api.ts
1642
1666
  var CustomerScopedTransport = class {
@@ -1657,10 +1681,10 @@ var CustomerScopedTransport = class {
1657
1681
  this.onUnauthorized = options.onUnauthorized;
1658
1682
  this.onRequestId = options.onRequestId;
1659
1683
  }
1660
- async request(endpoint2, options) {
1684
+ async request(endpoint, options) {
1661
1685
  const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
1662
1686
  try {
1663
- const response = await httpFetch(endpoint2, {
1687
+ const response = await httpFetch(endpoint, {
1664
1688
  method: options.method,
1665
1689
  apiUrl: this.apiUrl,
1666
1690
  publishableKey: this.publishableKey,
@@ -1674,7 +1698,7 @@ var CustomerScopedTransport = class {
1674
1698
  ...options.errorFamily && { errorFamily: options.errorFamily }
1675
1699
  });
1676
1700
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
1677
- return parseApiResponse(response, endpoint2, {
1701
+ return parseApiResponse(response, endpoint, {
1678
1702
  errorFamily: options.errorFamily
1679
1703
  });
1680
1704
  } catch (err) {
@@ -1688,12 +1712,12 @@ var CustomerScopedApi = class {
1688
1712
  constructor(apiName, options) {
1689
1713
  this.transport = new CustomerScopedTransport(apiName, options);
1690
1714
  }
1691
- requestEndpoint(endpoint2, body, options) {
1692
- return this.transport.request(resolveOperationPath2(endpoint2, options), {
1693
- method: resolveOperationMethod2(endpoint2),
1715
+ requestEndpoint(endpoint, body, options) {
1716
+ return this.transport.request(resolveOperationPath(endpoint, options), {
1717
+ method: resolveOperationMethod(endpoint),
1694
1718
  body,
1695
1719
  headers: options?.headers,
1696
- errorFamily: resolveOperationErrorFamily(endpoint2)
1720
+ errorFamily: resolveOperationErrorFamily(endpoint)
1697
1721
  });
1698
1722
  }
1699
1723
  };
@@ -1701,8 +1725,8 @@ var RawCustomerScopedApi = class {
1701
1725
  constructor(apiName, options) {
1702
1726
  this.transport = new CustomerScopedTransport(apiName, options);
1703
1727
  }
1704
- request(endpoint2, options) {
1705
- return this.transport.request(endpoint2, options);
1728
+ request(endpoint, options) {
1729
+ return this.transport.request(endpoint, options);
1706
1730
  }
1707
1731
  };
1708
1732
 
@@ -1777,11 +1801,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
1777
1801
  if (params.page !== void 0) urlParams.set("page", String(params.page));
1778
1802
  return `/api/comments/public?${urlParams.toString()}`;
1779
1803
  }
1780
- async execute(endpoint2, method, body) {
1781
- return this.request(endpoint2, { method, body });
1804
+ async execute(endpoint, method, body) {
1805
+ return this.request(endpoint, { method, body });
1782
1806
  }
1783
- async executeDoc(endpoint2, method, body) {
1784
- const response = await this.execute(endpoint2, method, body);
1807
+ async executeDoc(endpoint, method, body) {
1808
+ const response = await this.execute(endpoint, method, body);
1785
1809
  return unwrapPayloadDoc(response);
1786
1810
  }
1787
1811
  createPost(params) {
@@ -2047,8 +2071,8 @@ var CommunityClient = class extends RawCustomerScopedApi {
2047
2071
 
2048
2072
  // src/core/content/content-client.ts
2049
2073
  var PublicContentApi = class extends RawCustomerScopedApi {
2050
- get(endpoint2) {
2051
- return this.request(endpoint2, { method: "GET" });
2074
+ get(endpoint) {
2075
+ return this.request(endpoint, { method: "GET" });
2052
2076
  }
2053
2077
  };
2054
2078
  function appendCommonParams(search, options, defaultSort) {
@@ -2229,6 +2253,9 @@ function nullableString(value, resource, path) {
2229
2253
  fail(resource, path, "string or null");
2230
2254
  }
2231
2255
  }
2256
+ function nullableNonEmptyString(value, resource, path) {
2257
+ if (value !== null) string(value, resource, path);
2258
+ }
2232
2259
  function cartLineQuantity(value, resource, path) {
2233
2260
  const quantity = positiveInteger(value, resource, path);
2234
2261
  if (quantity > MAX_CART_LINE_QUANTITY) {
@@ -2738,8 +2765,8 @@ function validatePublicOrderItem(value, resource, path) {
2738
2765
  validateReference(item.variant, resource, `${path}.variant`);
2739
2766
  }
2740
2767
  string(item.productTitle, resource, `${path}.productTitle`);
2741
- nullableString(item.variantTitle, resource, `${path}.variantTitle`);
2742
- nullableString(item.sku, resource, `${path}.sku`);
2768
+ nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
2769
+ nullableNonEmptyString(item.sku, resource, `${path}.sku`);
2743
2770
  validateAdmissions(item.admissions, resource, `${path}.admissions`);
2744
2771
  const quantity = positiveInteger(item.quantity, resource, `${path}.quantity`);
2745
2772
  const unitPrice = safeMinor(
@@ -2990,8 +3017,8 @@ function validateCheckoutItem(value, resource, path) {
2990
3017
  validateReference(item.product, resource, `${path}.product`);
2991
3018
  validateReference(item.variant, resource, `${path}.variant`);
2992
3019
  string(item.productTitle, resource, `${path}.productTitle`);
2993
- nullableString(item.variantTitle, resource, `${path}.variantTitle`);
2994
- nullableString(item.sku, resource, `${path}.sku`);
3020
+ nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
3021
+ nullableNonEmptyString(item.sku, resource, `${path}.sku`);
2995
3022
  validateAdmissions(item.admissions, resource, `${path}.admissions`);
2996
3023
  cartLineQuantity(item.quantity, resource, `${path}.quantity`);
2997
3024
  const unitPrice = safeMinor(
@@ -3323,11 +3350,21 @@ function validateNextAction(value, provider, resource, path) {
3323
3350
  const action = record(value, resource, path);
3324
3351
  if (provider === "portone") {
3325
3352
  if (action.type === "portone_sdk") {
3353
+ const hasCancelable = "cancelable" in action;
3354
+ const hasRetryPolicy = "retryPolicy" in action;
3355
+ if (hasCancelable !== hasRetryPolicy) {
3356
+ fail(
3357
+ resource,
3358
+ path,
3359
+ "exact released action or exact negotiated capability action"
3360
+ );
3361
+ }
3326
3362
  exact(
3327
3363
  action,
3328
3364
  [
3329
3365
  "type",
3330
3366
  "version",
3367
+ ...hasCancelable ? ["cancelable", "retryPolicy"] : [],
3331
3368
  "storeId",
3332
3369
  "channelKey",
3333
3370
  "paymentId",
@@ -3342,6 +3379,11 @@ function validateNextAction(value, provider, resource, path) {
3342
3379
  path
3343
3380
  );
3344
3381
  if (action.version !== "v2") fail(resource, `${path}.version`, "v2");
3382
+ if (hasCancelable && action.cancelable !== false)
3383
+ fail(resource, `${path}.cancelable`, "false");
3384
+ if (hasRetryPolicy && action.retryPolicy !== "same_action_only") {
3385
+ fail(resource, `${path}.retryPolicy`, "same_action_only");
3386
+ }
3345
3387
  for (const key of ["storeId", "channelKey"]) {
3346
3388
  boundedString(action[key], 255, resource, `${path}.${key}`);
3347
3389
  }
@@ -3388,6 +3430,10 @@ function validateNextAction(value, provider, resource, path) {
3388
3430
  "HTTPS or loopback URL without embedded credentials"
3389
3431
  );
3390
3432
  }
3433
+ if (!hasCancelable) {
3434
+ action.cancelable = false;
3435
+ action.retryPolicy = "same_action_only";
3436
+ }
3391
3437
  return;
3392
3438
  }
3393
3439
  exact(action, ["type", "checkoutUrl"], [], resource, path);
@@ -4122,8 +4168,8 @@ var CartApi = class extends CustomerScopedApi {
4122
4168
  endpoint(key) {
4123
4169
  return this.serverTransport ? COMMERCE_ENDPOINTS.carts.server[key] : COMMERCE_ENDPOINTS.carts[key];
4124
4170
  }
4125
- execute(endpoint2, body, idempotencyKey) {
4126
- return this.requestEndpoint(endpoint2, body, {
4171
+ execute(endpoint, body, idempotencyKey) {
4172
+ return this.requestEndpoint(endpoint, body, {
4127
4173
  ...idempotencyKey && {
4128
4174
  headers: { "X-Idempotency-Key": idempotencyKey }
4129
4175
  }
@@ -4140,26 +4186,26 @@ var CartApi = class extends CustomerScopedApi {
4140
4186
  );
4141
4187
  }
4142
4188
  mine(params = {}) {
4143
- const endpoint2 = this.endpoint("mine");
4144
- return this.execute(endpoint2, params).then(
4189
+ const endpoint = this.endpoint("mine");
4190
+ return this.execute(endpoint, params).then(
4145
4191
  (value) => validateCartMineResult(value)
4146
4192
  );
4147
4193
  }
4148
4194
  merge(params) {
4149
4195
  const { idempotencyKey, ...body } = params;
4150
4196
  assertCommerceIdempotencyKey(idempotencyKey);
4151
- const endpoint2 = this.endpoint("merge");
4152
- return this.execute(endpoint2, body, idempotencyKey).then(
4197
+ const endpoint = this.endpoint("merge");
4198
+ return this.execute(endpoint, body, idempotencyKey).then(
4153
4199
  (value) => validateCartMergeResult(value)
4154
4200
  );
4155
4201
  }
4156
4202
  addItem(params) {
4157
4203
  return this.mutate(this.endpoint("addItem"), params);
4158
4204
  }
4159
- mutate(endpoint2, params) {
4205
+ mutate(endpoint, params) {
4160
4206
  const { idempotencyKey, ...body } = params;
4161
4207
  assertCommerceIdempotencyKey(idempotencyKey);
4162
- return this.execute(endpoint2, body, idempotencyKey).then(
4208
+ return this.execute(endpoint, body, idempotencyKey).then(
4163
4209
  (value) => validateCartMutationResult(value)
4164
4210
  );
4165
4211
  }
@@ -4185,8 +4231,8 @@ var CheckoutApi = class extends CustomerScopedApi {
4185
4231
  constructor(options) {
4186
4232
  super("CheckoutApi", { ...options, requiresCredential: false });
4187
4233
  }
4188
- post(endpoint2, body, idempotencyKey) {
4189
- return this.requestEndpoint(endpoint2, body, {
4234
+ post(endpoint, body, idempotencyKey) {
4235
+ return this.requestEndpoint(endpoint, body, {
4190
4236
  ...idempotencyKey && {
4191
4237
  headers: { "X-Idempotency-Key": idempotencyKey }
4192
4238
  }
@@ -4253,11 +4299,15 @@ var PaymentSessionApi = class extends CustomerScopedApi {
4253
4299
  super("PaymentSessionApi", { ...options, requiresCredential: false });
4254
4300
  this.serverTransport = Boolean(options.secretKey);
4255
4301
  }
4256
- post(endpoint2, body, idempotencyKey) {
4257
- return this.requestEndpoint(endpoint2, body, {
4258
- ...idempotencyKey && {
4259
- headers: { "X-Idempotency-Key": idempotencyKey }
4302
+ post(endpoint, body, idempotencyKey, negotiateStandardActionCapabilities = false) {
4303
+ const headers = {
4304
+ ...idempotencyKey && { "X-Idempotency-Key": idempotencyKey },
4305
+ ...negotiateStandardActionCapabilities && {
4306
+ Accept: PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE
4260
4307
  }
4308
+ };
4309
+ return this.requestEndpoint(endpoint, body, {
4310
+ ...Object.keys(headers).length > 0 && { headers }
4261
4311
  });
4262
4312
  }
4263
4313
  async paymentSession(result, expectedProvider) {
@@ -4282,40 +4332,41 @@ var PaymentSessionApi = class extends CustomerScopedApi {
4282
4332
  this.post(
4283
4333
  this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.create : COMMERCE_ENDPOINTS.paymentSessions.create,
4284
4334
  body,
4285
- idempotencyKey
4335
+ idempotencyKey,
4336
+ body.providerOptions.profile === "standard_v2"
4286
4337
  ),
4287
4338
  "portone"
4288
4339
  );
4289
4340
  }
4290
4341
  retrieve(params) {
4291
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4342
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4292
4343
  return this.paymentSession(
4293
- this.post(endpoint2, params),
4344
+ this.post(endpoint, params),
4294
4345
  "toss"
4295
4346
  );
4296
4347
  }
4297
4348
  retrievePortOne(params) {
4298
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4349
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4299
4350
  return this.paymentSession(
4300
- this.post(endpoint2, params),
4351
+ this.post(endpoint, params, void 0, true),
4301
4352
  "portone"
4302
4353
  );
4303
4354
  }
4304
4355
  cancel(params) {
4305
4356
  const { idempotencyKey, ...body } = params;
4306
4357
  assertCommerceIdempotencyKey(idempotencyKey);
4307
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4358
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4308
4359
  return this.paymentSession(
4309
- this.post(endpoint2, body, idempotencyKey),
4360
+ this.post(endpoint, body, idempotencyKey),
4310
4361
  "toss"
4311
4362
  );
4312
4363
  }
4313
4364
  cancelPortOne(params) {
4314
4365
  const { idempotencyKey, ...body } = params;
4315
4366
  assertCommerceIdempotencyKey(idempotencyKey);
4316
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4367
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4317
4368
  return this.paymentSession(
4318
- this.post(endpoint2, body, idempotencyKey),
4369
+ this.post(endpoint, body, idempotencyKey),
4319
4370
  "portone"
4320
4371
  );
4321
4372
  }
@@ -4394,9 +4445,9 @@ function resolveVariantImageItems(variant, poolById) {
4394
4445
  if (pooled) resolved.push(pooled);
4395
4446
  continue;
4396
4447
  }
4397
- const mediaId2 = getMediaId(entry);
4398
- if (mediaId2) {
4399
- const pooled = poolById.get(mediaId2);
4448
+ const mediaId = getMediaId(entry);
4449
+ if (mediaId) {
4450
+ const pooled = poolById.get(mediaId);
4400
4451
  if (pooled) {
4401
4452
  resolved.push(pooled);
4402
4453
  }
@@ -4587,11 +4638,11 @@ function getFirstMediaId(values) {
4587
4638
  }
4588
4639
  return null;
4589
4640
  }
4590
- function inProductMediaPool(product, mediaId2) {
4591
- if (mediaId2 == null) return null;
4641
+ function inProductMediaPool(product, mediaId) {
4642
+ if (mediaId == null) return null;
4592
4643
  const images = Array.isArray(product?.images) ? product.images : [];
4593
4644
  for (const image of images) {
4594
- if (extractEntityId(image) === mediaId2) return mediaId2;
4645
+ if (extractEntityId(image) === mediaId) return mediaId;
4595
4646
  }
4596
4647
  return null;
4597
4648
  }
@@ -6172,8 +6223,8 @@ function isProductUpsertFieldValidationErrorBody(value) {
6172
6223
 
6173
6224
  // src/core/commerce/commerce-client.ts
6174
6225
  var BrowserCommerceApi = class extends CustomerScopedApi {
6175
- requestEndpoint(endpoint2, body, options) {
6176
- return super.requestEndpoint(endpoint2, body, options);
6226
+ requestEndpoint(endpoint, body, options) {
6227
+ return super.requestEndpoint(endpoint, body, options);
6177
6228
  }
6178
6229
  };
6179
6230
  var CommerceClient = class {
@@ -6373,11 +6424,11 @@ var EventsClient = class {
6373
6424
  { useCustomerAuth: false }
6374
6425
  );
6375
6426
  }
6376
- async execute(endpoint2, method, body, options = {}) {
6427
+ async execute(endpoint, method, body, options = {}) {
6377
6428
  const useCustomerAuth = options.useCustomerAuth === true;
6378
6429
  const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
6379
6430
  try {
6380
- const response = await httpFetch(endpoint2, {
6431
+ const response = await httpFetch(endpoint, {
6381
6432
  method,
6382
6433
  apiUrl: this.apiUrl,
6383
6434
  publishableKey: this.publishableKey,
@@ -6386,7 +6437,7 @@ var EventsClient = class {
6386
6437
  ...body !== void 0 && { body: JSON.stringify(body) }
6387
6438
  });
6388
6439
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
6389
- return parseApiResponse(response, endpoint2);
6440
+ return parseApiResponse(response, endpoint);
6390
6441
  } catch (err) {
6391
6442
  const id = err instanceof SDKError ? err.requestId ?? null : null;
6392
6443
  this.onRequestId?.(id);
@@ -6644,13 +6695,106 @@ function mergeProductDetailWithStock(catalog, snapshot) {
6644
6695
  };
6645
6696
  }
6646
6697
 
6698
+ // src/core/webhook/validation.ts
6699
+ function isValidWebhookEventData(data) {
6700
+ if (typeof data !== "object" || data === null) return false;
6701
+ const event = data;
6702
+ return typeof event.collection === "string" && typeof event.operation === "string" && event.operation.length > 0 && typeof event.data === "object" && event.data !== null;
6703
+ }
6704
+
6705
+ // src/core/webhook/receiver.ts
6706
+ async function verifySignature(rawBody, secret, signature, timestamp2, deliveryId) {
6707
+ const encoder = new TextEncoder();
6708
+ const signedPrefix = encoder.encode(`${timestamp2}.${deliveryId}.`);
6709
+ const signedPayload = new Uint8Array(signedPrefix.length + rawBody.length);
6710
+ signedPayload.set(signedPrefix);
6711
+ signedPayload.set(rawBody, signedPrefix.length);
6712
+ const key = await crypto.subtle.importKey(
6713
+ "raw",
6714
+ encoder.encode(secret),
6715
+ { name: "HMAC", hash: "SHA-256" },
6716
+ false,
6717
+ ["verify"]
6718
+ );
6719
+ if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
6720
+ return false;
6721
+ }
6722
+ const sigBytes = new Uint8Array(
6723
+ (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
6724
+ );
6725
+ return crypto.subtle.verify("HMAC", key, sigBytes, signedPayload);
6726
+ }
6727
+ function timestampIsFresh(timestamp2, toleranceSeconds) {
6728
+ if (!/^\d+$/.test(timestamp2)) return false;
6729
+ const timestampMs = Number(timestamp2);
6730
+ if (!Number.isFinite(timestampMs)) return false;
6731
+ const skewMs = Math.abs(Date.now() - timestampMs);
6732
+ return skewMs <= toleranceSeconds * 1e3;
6733
+ }
6734
+ var MAX_TOLERANCE_SECONDS = 86400;
6735
+ function toleranceIsValid(toleranceSeconds) {
6736
+ return typeof toleranceSeconds === "number" && Number.isFinite(toleranceSeconds) && toleranceSeconds >= 0 && toleranceSeconds <= MAX_TOLERANCE_SECONDS;
6737
+ }
6738
+ async function processWebhookRequest(request, handler, verify) {
6739
+ try {
6740
+ const rawBody = new Uint8Array(await request.arrayBuffer());
6741
+ const verificationFailure = await verify?.(rawBody);
6742
+ if (verificationFailure) return verificationFailure;
6743
+ const body = JSON.parse(new TextDecoder().decode(rawBody));
6744
+ if (!isValidWebhookEventData(body)) {
6745
+ return new Response(
6746
+ JSON.stringify({ error: "Invalid webhook event format" }),
6747
+ { status: 400, headers: { "Content-Type": "application/json" } }
6748
+ );
6749
+ }
6750
+ await handler(body);
6751
+ return new Response(
6752
+ JSON.stringify({ success: true, message: "Webhook processed" }),
6753
+ { status: 200, headers: { "Content-Type": "application/json" } }
6754
+ );
6755
+ } catch (error) {
6756
+ console.error("Webhook processing error:", error);
6757
+ return new Response(JSON.stringify({ error: "Internal server error" }), {
6758
+ status: 500,
6759
+ headers: { "Content-Type": "application/json" }
6760
+ });
6761
+ }
6762
+ }
6763
+ async function handleSignedWebhook(request, handler, options) {
6764
+ const secret = options?.secret;
6765
+ const configuredTolerance = options?.toleranceSeconds;
6766
+ const toleranceSeconds = configuredTolerance ?? 300;
6767
+ if (typeof secret !== "string" || secret.trim().length === 0) {
6768
+ return new Response(
6769
+ JSON.stringify({ error: "Webhook signing secret is not configured" }),
6770
+ { status: 500, headers: { "Content-Type": "application/json" } }
6771
+ );
6772
+ }
6773
+ if (!toleranceIsValid(toleranceSeconds)) {
6774
+ return new Response(
6775
+ JSON.stringify({ error: "Webhook signature tolerance is not valid" }),
6776
+ { status: 500, headers: { "Content-Type": "application/json" } }
6777
+ );
6778
+ }
6779
+ return processWebhookRequest(request, handler, async (rawBody) => {
6780
+ const signature = request.headers.get("x-webhook-signature") || "";
6781
+ const timestamp2 = request.headers.get("x-webhook-timestamp") || "";
6782
+ const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
6783
+ const valid = Boolean(timestamp2 && deliveryId) && timestampIsFresh(timestamp2, toleranceSeconds) && await verifySignature(rawBody, secret, signature, timestamp2, deliveryId);
6784
+ if (!valid) {
6785
+ return new Response(
6786
+ JSON.stringify({ error: "Invalid webhook signature" }),
6787
+ { status: 401, headers: { "Content-Type": "application/json" } }
6788
+ );
6789
+ }
6790
+ });
6791
+ }
6792
+
6647
6793
  // src/core/webhook/index.ts
6648
6794
  var ORDER_CHANGED_EVENT_TYPE = "collection.orderChanged";
6649
6795
  var COMMERCE_NOTIFICATION_EVENT_TYPE = "commerce.notification";
6650
6796
  function isValidWebhookEvent(data) {
6651
- if (typeof data !== "object" || data === null) return false;
6652
- const obj = data;
6653
- return typeof obj.collection === "string" && typeof obj.operation === "string" && obj.operation.length > 0 && typeof obj.data === "object" && obj.data !== null;
6797
+ return isValidWebhookEventData(data);
6654
6798
  }
6655
6799
  var COMMERCE_NOTIFICATION_OPERATION = "notification";
6656
6800
  var COMMERCE_NOTIFICATION_EVENTS = [
@@ -6662,7 +6806,9 @@ var COMMERCE_NOTIFICATION_EVENTS = [
6662
6806
  "returnApproved",
6663
6807
  "returnRejected",
6664
6808
  "returnCanceled",
6665
- "returnCompleted"
6809
+ "returnCompleted",
6810
+ "paymentReconciliationRequired",
6811
+ "paymentRefundRequiresAttention"
6666
6812
  ];
6667
6813
  function isStringOrNumber(value) {
6668
6814
  return typeof value === "string" || typeof value === "number";
@@ -6692,18 +6838,25 @@ function isCommerceNotificationEventName(value) {
6692
6838
  return typeof value === "string" && COMMERCE_NOTIFICATION_EVENTS.includes(value);
6693
6839
  }
6694
6840
  function isCommerceNotificationSourceCollection(value) {
6695
- return value === "orders" || value === "fulfillments" || value === "returns";
6841
+ return value === "orders" || value === "fulfillments" || value === "returns" || value === "payment-sessions" || value === "payment-refund-attempts";
6696
6842
  }
6697
6843
  function isCommerceNotificationData(value) {
6698
6844
  if (!isRecord(value)) return false;
6699
6845
  if (value.source !== void 0 && (!isRecord(value.source) || !isCommerceNotificationSourceCollection(value.source.collection) || !isStringOrNumber(value.source.id))) {
6700
6846
  return false;
6701
6847
  }
6702
- 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");
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") && (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");
6703
6849
  }
6704
6850
  function isCommerceNotification(value) {
6705
6851
  if (!isRecord(value)) return false;
6706
- 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");
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") && (value.paymentSessionId === void 0 || typeof value.paymentSessionId === "string") && (value.refundAttemptId === void 0 || typeof value.refundAttemptId === "string");
6853
+ }
6854
+ function isPaymentIncidentNotificationData(value, event) {
6855
+ const reconciliation = event === "paymentReconciliationRequired";
6856
+ const expectedCollection = reconciliation ? "payment-sessions" : "payment-refund-attempts";
6857
+ const expectedStatus = reconciliation ? "reconciliation_required" : "requires_attention";
6858
+ const expectedReason = reconciliation ? "orderless_capture" : "local_commit_ambiguous";
6859
+ 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);
6707
6860
  }
6708
6861
  function isWebhookCommerceNotificationChange(value) {
6709
6862
  if (!isRecord(value)) return false;
@@ -6744,6 +6897,15 @@ function isCommerceNotificationWebhookEvent(event) {
6744
6897
  if (!matchesOptionalId(change.sourceId, sourceId)) return false;
6745
6898
  }
6746
6899
  const changeSourceId = isWebhookCommerceNotificationChange(change) ? change.sourceId : void 0;
6900
+ if (notification.event === "paymentReconciliationRequired" || notification.event === "paymentRefundRequiresAttention") {
6901
+ if (!isPaymentIncidentNotificationData(data, notification.event)) {
6902
+ return false;
6903
+ }
6904
+ const incidentData = data;
6905
+ const expectedCollection = notification.event === "paymentReconciliationRequired" ? "payment-sessions" : "payment-refund-attempts";
6906
+ const notificationSourceId = notification.event === "paymentReconciliationRequired" ? notification.paymentSessionId : notification.refundAttemptId;
6907
+ return sourceCollection === expectedCollection && typeof notification.paymentSessionId === "string" && notification.paymentSessionId === incidentData.paymentSessionId && typeof notificationSourceId === "string" && notificationSourceId === incidentData.source.id && matchesOptionalId(changeSourceId, incidentData.source.id);
6908
+ }
6747
6909
  if (notification.event === "orderPaid" || notification.event === "orderCanceled" || notification.event === "orderDelivered") {
6748
6910
  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);
6749
6911
  }
@@ -6812,80 +6974,8 @@ function createCustomerAuthWebhookHandler(handlers) {
6812
6974
  await handlers.unhandled?.(event);
6813
6975
  };
6814
6976
  }
6815
- async function verifySignature(payload, secret, signature, timestamp2, deliveryId) {
6816
- const encoder = new TextEncoder();
6817
- const key = await crypto.subtle.importKey(
6818
- "raw",
6819
- encoder.encode(secret),
6820
- { name: "HMAC", hash: "SHA-256" },
6821
- false,
6822
- ["verify"]
6823
- );
6824
- if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
6825
- return false;
6826
- }
6827
- const sigBytes = new Uint8Array(
6828
- (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
6829
- );
6830
- return crypto.subtle.verify(
6831
- "HMAC",
6832
- key,
6833
- sigBytes,
6834
- encoder.encode(`${timestamp2}.${deliveryId}.${payload}`)
6835
- );
6836
- }
6837
- function timestampIsFresh(timestamp2, toleranceSeconds) {
6838
- if (!/^\d+$/.test(timestamp2)) return false;
6839
- const timestampMs = Number(timestamp2);
6840
- if (!Number.isFinite(timestampMs)) return false;
6841
- const skewMs = Math.abs(Date.now() - timestampMs);
6842
- return skewMs <= toleranceSeconds * 1e3;
6843
- }
6844
6977
  async function handleWebhook(request, handler, options) {
6845
- try {
6846
- const rawBody = await request.text();
6847
- if (options?.secret) {
6848
- const signature = request.headers.get("x-webhook-signature") || "";
6849
- const timestamp2 = request.headers.get("x-webhook-timestamp") || "";
6850
- const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
6851
- const toleranceSeconds = options.toleranceSeconds ?? 300;
6852
- const valid = Boolean(timestamp2 && deliveryId) && timestampIsFresh(timestamp2, toleranceSeconds) && await verifySignature(
6853
- rawBody,
6854
- options.secret,
6855
- signature,
6856
- timestamp2,
6857
- deliveryId
6858
- );
6859
- if (!valid) {
6860
- return new Response(
6861
- JSON.stringify({ error: "Invalid webhook signature" }),
6862
- { status: 401, headers: { "Content-Type": "application/json" } }
6863
- );
6864
- }
6865
- } else {
6866
- console.warn(
6867
- "[@01.software/sdk] Webhook signature verification is disabled. Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification."
6868
- );
6869
- }
6870
- const body = JSON.parse(rawBody);
6871
- if (!isValidWebhookEvent(body)) {
6872
- return new Response(
6873
- JSON.stringify({ error: "Invalid webhook event format" }),
6874
- { status: 400, headers: { "Content-Type": "application/json" } }
6875
- );
6876
- }
6877
- await handler(body);
6878
- return new Response(
6879
- JSON.stringify({ success: true, message: "Webhook processed" }),
6880
- { status: 200, headers: { "Content-Type": "application/json" } }
6881
- );
6882
- } catch (error) {
6883
- console.error("Webhook processing error:", error);
6884
- return new Response(JSON.stringify({ error: "Internal server error" }), {
6885
- status: 500,
6886
- headers: { "Content-Type": "application/json" }
6887
- });
6888
- }
6978
+ return handleSignedWebhook(request, handler, options);
6889
6979
  }
6890
6980
  function createTypedWebhookHandler(collection, handler) {
6891
6981
  return async (event) => {
@@ -6925,6 +7015,7 @@ var INTERNAL_COLLECTIONS = [
6925
7015
  "payment-event-inbox",
6926
7016
  "payment-refund-attempts",
6927
7017
  "portone-payment-interactions",
7018
+ "commerce-payment-webhook-routes",
6928
7019
  "commerce-notification-intents",
6929
7020
  "commerce-idempotency-records",
6930
7021
  "product-collection-items",
@@ -6965,7 +7056,6 @@ var COLLECTIONS = [
6965
7056
  "brands",
6966
7057
  "customer-profiles",
6967
7058
  "customer-profile-stats",
6968
- "discounts",
6969
7059
  "shipping-policies",
6970
7060
  "shipping-zones",
6971
7061
  "documents",
@@ -7041,6 +7131,9 @@ var SERVER_ONLY_COLLECTIONS = [
7041
7131
  "cart-items",
7042
7132
  "checkouts",
7043
7133
  "checkout-items",
7134
+ // Raw discount definitions require a server credential. Browser discount
7135
+ // validation is exposed through the shaped POST /api/discounts/validate path.
7136
+ "discounts",
7044
7137
  "draft-orders",
7045
7138
  "draft-order-items",
7046
7139
  "posts",
@@ -7206,160 +7299,6 @@ var RealtimeConnection = class {
7206
7299
  }
7207
7300
  };
7208
7301
 
7209
- // src/utils/product-media.ts
7210
- function mediaPointerOptionValues(values) {
7211
- return (values ?? []).filter((value) => value != null && value !== "").map((value) => ({
7212
- swatch: {
7213
- type: "media",
7214
- mediaItemId: value
7215
- }
7216
- }));
7217
- }
7218
- function resolveProductMedia(input) {
7219
- const resolved = resolveProductSelectionMedia({
7220
- ...input,
7221
- selectedVariant: input.selectedVariant ?? (input.variantFeaturedMediaItemId ? { images: [input.variantFeaturedMediaItemId] } : null),
7222
- selectedOptionValues: input.selectedOptionValues ?? mediaPointerOptionValues(input.selectedOptionValueMediaItemIds)
7223
- });
7224
- if (resolved.source !== "none") {
7225
- return {
7226
- ...resolved,
7227
- source: resolved.source === "variant_media_selected" ? "variant_featured" : resolved.source
7228
- };
7229
- }
7230
- const display = resolveProductDisplayMedia({
7231
- productMediaPool: input.productMediaPool
7232
- });
7233
- return {
7234
- primaryImage: display.primaryImage,
7235
- images: display.images,
7236
- source: display.source
7237
- };
7238
- }
7239
-
7240
- // src/utils/product-gallery.ts
7241
- function mediaId(value) {
7242
- if (typeof value === "string" || typeof value === "number") {
7243
- return String(value);
7244
- }
7245
- if (typeof value === "object" && value !== null && "id" in value) {
7246
- const id = value.id;
7247
- if (typeof id === "string" || typeof id === "number") return String(id);
7248
- }
7249
- return null;
7250
- }
7251
- function relationshipIds(values) {
7252
- if (!Array.isArray(values)) return [];
7253
- return values.map((value) => mediaId(value)).filter((value) => Boolean(value));
7254
- }
7255
- function buildPoolById2(pool) {
7256
- const poolById = /* @__PURE__ */ new Map();
7257
- for (const item of pool) {
7258
- const id = mediaId(item);
7259
- if (id) poolById.set(id, item);
7260
- }
7261
- return poolById;
7262
- }
7263
- function mediaSetItemsInPool(mediaSet, poolById) {
7264
- const seen = /* @__PURE__ */ new Set();
7265
- const items = [];
7266
- const primaryId = mediaId(mediaSet.primaryMediaItemId);
7267
- if (primaryId) {
7268
- const primary = poolById.get(primaryId);
7269
- if (primary) {
7270
- seen.add(primaryId);
7271
- items.push(primary);
7272
- }
7273
- }
7274
- for (const itemId of relationshipIds(mediaSet.items)) {
7275
- if (seen.has(itemId)) continue;
7276
- const item = poolById.get(itemId);
7277
- if (!item) continue;
7278
- seen.add(itemId);
7279
- items.push(item);
7280
- }
7281
- return items;
7282
- }
7283
- function resolveLegacyMediaSet(input) {
7284
- if (!Array.isArray(input.mediaSets)) return null;
7285
- const pool = input.productMediaPool ?? input.pool ?? [];
7286
- const poolById = buildPoolById2(pool);
7287
- const selectedVariantId = mediaId(input.selectedVariantId);
7288
- if (selectedVariantId) {
7289
- const exactSet = input.mediaSets.find(
7290
- (set) => set.matchType === "exact-variant" && relationshipIds(set.variantIds).includes(selectedVariantId)
7291
- );
7292
- if (exactSet) {
7293
- const images = mediaSetItemsInPool(exactSet, poolById);
7294
- if (images.length > 0) {
7295
- return {
7296
- primaryImage: images[0] ?? null,
7297
- images,
7298
- source: "exact_variant_set"
7299
- };
7300
- }
7301
- }
7302
- }
7303
- const selectedOptionValueIds = new Set(
7304
- relationshipIds(input.selectedOptionValueIds)
7305
- );
7306
- const optionSetMatches = input.mediaSets.filter((set) => set.matchType === "option-values").map((set) => {
7307
- const optionValueIds = relationshipIds(set.optionValueIds);
7308
- if (optionValueIds.length === 0) return null;
7309
- if (!optionValueIds.every((id) => selectedOptionValueIds.has(id))) {
7310
- return null;
7311
- }
7312
- const images = mediaSetItemsInPool(set, poolById);
7313
- if (images.length === 0) return null;
7314
- return { optionValueCount: optionValueIds.length, images };
7315
- }).filter(
7316
- (match) => Boolean(match)
7317
- ).sort((a, b) => b.optionValueCount - a.optionValueCount);
7318
- if (optionSetMatches.length > 0) {
7319
- const images = optionSetMatches[0].images;
7320
- return {
7321
- primaryImage: images[0] ?? null,
7322
- images,
7323
- source: "option_value_set"
7324
- };
7325
- }
7326
- const defaultSet = input.mediaSets.find((set) => set.matchType === "default");
7327
- if (defaultSet) {
7328
- const images = mediaSetItemsInPool(defaultSet, poolById);
7329
- if (images.length > 0) {
7330
- return {
7331
- primaryImage: images[0] ?? null,
7332
- images,
7333
- source: "default_set"
7334
- };
7335
- }
7336
- }
7337
- return {
7338
- primaryImage: null,
7339
- images: [],
7340
- source: "none"
7341
- };
7342
- }
7343
- function resolveProductGallery(input) {
7344
- const selectedVariantId = mediaId(input.selectedVariantId);
7345
- const selectedOptionValueIds = relationshipIds(input.selectedOptionValueIds);
7346
- const selection = resolveProductSelectionMedia({
7347
- ...input,
7348
- productMediaPool: input.productMediaPool ?? input.pool ?? null,
7349
- selectedVariant: input.selectedVariant ?? (selectedVariantId ? { id: selectedVariantId } : null),
7350
- selectedOptionValues: input.selectedOptionValues ?? selectedOptionValueIds.map((id) => ({ id }))
7351
- });
7352
- if (selection.source !== "none") {
7353
- return selection;
7354
- }
7355
- const legacyResolved = resolveLegacyMediaSet(input);
7356
- if (legacyResolved && legacyResolved.source !== "none") return legacyResolved;
7357
- return resolveProductDisplayMedia({
7358
- productMediaPool: input.productMediaPool ?? input.pool ?? null,
7359
- featuredImage: input.featuredImage
7360
- });
7361
- }
7362
-
7363
7302
  // src/utils/image.ts
7364
7303
  var IMAGE_SIZES = [200, 400, 800, 1200, 1600];
7365
7304
  function imageSizeCandidates(sizes) {
@@ -7491,7 +7430,7 @@ function createAnalytics(config) {
7491
7430
  }, destroy() {
7492
7431
  } };
7493
7432
  }
7494
- const endpoint2 = config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`;
7433
+ const endpoint = config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`;
7495
7434
  const respectDnt = config.respectDnt !== false;
7496
7435
  function isDntActive() {
7497
7436
  if (!respectDnt) return false;
@@ -7532,10 +7471,10 @@ function createAnalytics(config) {
7532
7471
  try {
7533
7472
  if (typeof navigator.sendBeacon === "function") {
7534
7473
  const blob = new Blob([body], { type: "text/plain" });
7535
- const sent = navigator.sendBeacon(endpoint2, blob);
7474
+ const sent = navigator.sendBeacon(endpoint, blob);
7536
7475
  if (sent) return;
7537
7476
  }
7538
- fetch(endpoint2, {
7477
+ fetch(endpoint, {
7539
7478
  method: "POST",
7540
7479
  keepalive: true,
7541
7480
  headers: { "Content-Type": "application/json" },
@@ -7792,8 +7731,6 @@ export {
7792
7731
  projectProductToListingShape,
7793
7732
  resolveFeaturedImagePointer,
7794
7733
  resolveProductDisplayMedia,
7795
- resolveProductGallery,
7796
- resolveProductMedia,
7797
7734
  resolveProductSelection,
7798
7735
  resolveProductSelectionFromMatrix,
7799
7736
  resolveProductSelectionMedia,