@01.software/sdk 0.49.0 → 0.56.1

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 +257 -1
  2. package/MIGRATION.md +56 -0
  3. package/README.md +269 -56
  4. package/dist/client.cjs +608 -190
  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 +608 -190
  9. package/dist/client.js.map +1 -1
  10. package/dist/{collection-client-DnDt6EQz.d.ts → collection-client-Bmr53saa.d.ts} +6 -4
  11. package/dist/{collection-client-XfGLPuTf.d.cts → collection-client-DxuBDso_.d.cts} +6 -4
  12. package/dist/{const-CBba4lDo.d.cts → const-BKUqg96Q.d.ts} +5 -5
  13. package/dist/{const-DCNV5Kq7.d.ts → const-Cv1DCsp6.d.cts} +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-DUuIqUS8.d.ts → index-CGsT4AQ8.d.cts} +89 -10
  33. package/dist/{index-CbKyoEzy.d.cts → index-DFHLLqYu.d.ts} +89 -10
  34. package/dist/index.cjs +752 -436
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +12 -69
  37. package/dist/index.d.ts +12 -69
  38. package/dist/index.js +752 -436
  39. package/dist/index.js.map +1 -1
  40. package/dist/{payload-types-MKbx5MuJ.d.cts → payload-types-Bk-duc5k.d.cts} +545 -141
  41. package/dist/{payload-types-MKbx5MuJ.d.ts → payload-types-Bk-duc5k.d.ts} +545 -141
  42. package/dist/query.cjs +108 -71
  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 +108 -71
  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 +502 -175
  51. package/dist/server.cjs.map +1 -1
  52. package/dist/server.d.cts +9 -8
  53. package/dist/server.d.ts +9 -8
  54. package/dist/server.js +502 -175
  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-1UeOk1Uy.d.cts → types-CEK8uTvU.d.ts} +287 -30
  61. package/dist/{types-BKr_2avj.d.cts → types-CNdpj2fI.d.cts} +2 -2
  62. package/dist/{types-L_nh-ED7.d.ts → types-D4mjGFj4.d.ts} +2 -2
  63. package/dist/{types-Du4s5anw.d.ts → types-Dhk5NX7Z.d.cts} +287 -30
  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 +135 -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 +135 -80
  73. package/dist/webhook.js.map +1 -1
  74. package/package.json +28 -6
package/dist/client.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");
@@ -1191,39 +1194,39 @@ var ReadOnlyCollectionClient = class extends HttpClient {
1191
1194
  from(collection) {
1192
1195
  return new ReadOnlyCollectionQueryBuilder(this, collection);
1193
1196
  }
1194
- async requestFind(endpoint2, options) {
1195
- const url = this.buildUrl(endpoint2, options);
1197
+ async requestFind(endpoint, options) {
1198
+ const url = this.buildUrl(endpoint, options);
1196
1199
  const response = await this.fetchWithTracking(url, {
1197
1200
  ...this.defaultOptions,
1198
1201
  method: "GET"
1199
1202
  });
1200
1203
  return this.parseFindResponse(response);
1201
1204
  }
1202
- async requestFindEndpoint(endpoint2, data) {
1203
- const response = await this.fetchWithTracking(endpoint2, {
1205
+ async requestFindEndpoint(endpoint, data) {
1206
+ const response = await this.fetchWithTracking(endpoint, {
1204
1207
  ...this.defaultOptions,
1205
1208
  method: "POST",
1206
1209
  body: data ? JSON.stringify(data) : void 0
1207
1210
  });
1208
1211
  return this.parseFindResponse(response);
1209
1212
  }
1210
- async requestFindEndpointGet(endpoint2) {
1211
- const response = await this.fetchWithTracking(endpoint2, {
1213
+ async requestFindEndpointGet(endpoint) {
1214
+ const response = await this.fetchWithTracking(endpoint, {
1212
1215
  ...this.defaultOptions,
1213
1216
  method: "GET"
1214
1217
  });
1215
1218
  return this.parseFindResponse(response);
1216
1219
  }
1217
- async requestFindById(endpoint2, options) {
1218
- const url = this.buildUrl(endpoint2, options);
1220
+ async requestFindById(endpoint, options) {
1221
+ const url = this.buildUrl(endpoint, options);
1219
1222
  const response = await this.fetchWithTracking(url, {
1220
1223
  ...this.defaultOptions,
1221
1224
  method: "GET"
1222
1225
  });
1223
1226
  return this.parseDocumentResponse(response);
1224
1227
  }
1225
- async requestCount(endpoint2, options) {
1226
- const url = this.buildUrl(endpoint2, options);
1228
+ async requestCount(endpoint, options) {
1229
+ const url = this.buildUrl(endpoint, options);
1227
1230
  const response = await this.fetchWithTracking(url, {
1228
1231
  ...this.defaultOptions,
1229
1232
  method: "GET"
@@ -1233,7 +1236,7 @@ var ReadOnlyCollectionClient = class extends HttpClient {
1233
1236
  };
1234
1237
 
1235
1238
  // src/core/api/parse-response.ts
1236
- async function parseApiResponse(response, endpoint2, options = {}) {
1239
+ async function parseApiResponse(response, endpoint, options = {}) {
1237
1240
  if (response.status === 204 || response.headers.get("content-length") === "0") {
1238
1241
  return void 0;
1239
1242
  }
@@ -1242,7 +1245,7 @@ async function parseApiResponse(response, endpoint2, options = {}) {
1242
1245
  parsed = await response.json();
1243
1246
  } catch {
1244
1247
  throw createApiError(
1245
- `Invalid JSON response from ${endpoint2}`,
1248
+ `Invalid JSON response from ${endpoint}`,
1246
1249
  response.status,
1247
1250
  void 0,
1248
1251
  "Server returned an invalid response.",
@@ -1292,6 +1295,7 @@ async function parseApiResponse(response, endpoint2, options = {}) {
1292
1295
 
1293
1296
  // ../../internal/http-contracts/src/index.ts
1294
1297
  var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
1298
+ var PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE = "application/vnd.01software.portone-action-capabilities.v1+json";
1295
1299
  var operation = (collection, method, path, errorFamily) => Object.freeze({
1296
1300
  [operationBrand]: true,
1297
1301
  collection,
@@ -1300,6 +1304,10 @@ var operation = (collection, method, path, errorFamily) => Object.freeze({
1300
1304
  ...errorFamily && { errorFamily }
1301
1305
  });
1302
1306
  var strictCommerceOperation = (collection, method, path) => operation(collection, method, path, "commerce");
1307
+ var selectiveCommerceOperation = (collection, method, path, typedCommerceErrorReasons) => Object.freeze({
1308
+ ...operation(collection, method, path),
1309
+ typedCommerceErrorReasons: Object.freeze([...typedCommerceErrorReasons])
1310
+ });
1303
1311
  var COMMERCE_ENDPOINT_OPERATIONS = {
1304
1312
  products: {
1305
1313
  detail: operation("products", "get", "/detail"),
@@ -1331,7 +1339,12 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1331
1339
  confirmPayment: operation("orders", "post", "/confirm-payment"),
1332
1340
  byPayment: operation("orders", "get", "/by-payment"),
1333
1341
  cancel: operation("orders", "post", "/cancel"),
1334
- resolveCancelRefund: operation("orders", "post", "/resolve-cancel-refund"),
1342
+ resolveCancelRefund: selectiveCommerceOperation(
1343
+ "orders",
1344
+ "post",
1345
+ "/resolve-cancel-refund",
1346
+ ["managed_refund_attestation_forbidden"]
1347
+ ),
1335
1348
  checkout: strictCommerceOperation("orders", "post", "/checkout"),
1336
1349
  createFulfillment: operation("orders", "post", "/create-fulfillment"),
1337
1350
  updateFulfillment: operation("orders", "post", "/update-fulfillment")
@@ -1340,6 +1353,11 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1340
1353
  detail: strictCommerceOperation("checkouts", "post", "/detail"),
1341
1354
  query: strictCommerceOperation("checkouts", "post", "/query")
1342
1355
  },
1356
+ draftOrders: {
1357
+ calculate: operation("draft-orders", "post", "/:id/calculate"),
1358
+ complete: operation("draft-orders", "post", "/:id/complete"),
1359
+ finalize: operation("draft-orders", "post", "/:id/finalize")
1360
+ },
1343
1361
  transactions: {
1344
1362
  update: operation("transactions", "post", "/update")
1345
1363
  },
@@ -1402,6 +1420,16 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1402
1420
  "payment-sessions",
1403
1421
  "post",
1404
1422
  "/server/confirm"
1423
+ ),
1424
+ findPortOne: strictCommerceOperation(
1425
+ "payment-sessions",
1426
+ "post",
1427
+ "/server/portone/find"
1428
+ ),
1429
+ reconcilePortOne: strictCommerceOperation(
1430
+ "payment-sessions",
1431
+ "post",
1432
+ "/server/portone/reconcile"
1405
1433
  )
1406
1434
  },
1407
1435
  custom: {
@@ -1421,12 +1449,34 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1421
1449
  validate: operation("discounts", "post", "/validate")
1422
1450
  }
1423
1451
  };
1452
+ var portOneStandardActionCapabilityOperations = /* @__PURE__ */ new Set([
1453
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.create,
1454
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.retrieve,
1455
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.create,
1456
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.retrieve
1457
+ ]);
1424
1458
  var MEMBERSHIP_ENDPOINT_OPERATIONS = {
1425
1459
  subscribe: operation(null, "post", "/memberships/subscribe"),
1426
1460
  cancel: operation(null, "post", "/memberships/:id/cancel"),
1427
- me: operation(null, "get", "/memberships/me")
1461
+ me: operation(null, "get", "/memberships/me"),
1462
+ chargeResult: operation(null, "post", "/memberships/:id/charge-result"),
1463
+ refundResult: operation(null, "post", "/memberships/:id/refund-result"),
1464
+ revoke: operation(null, "post", "/memberships/:id/revoke")
1465
+ };
1466
+ var CUSTOMER_GROUP_ENDPOINT_OPERATIONS = {
1467
+ members: operation("customer-groups", "get", "/:id/members"),
1468
+ grant: operation("customer-groups", "post", "/:id/members/grant"),
1469
+ revoke: operation("customer-groups", "post", "/:id/members/revoke")
1470
+ };
1471
+ var EMBEDDED_ADMIN_ENDPOINT_OPERATIONS = {
1472
+ show: operation("tenants", "get", "/embedded-admin-app"),
1473
+ configure: operation("tenants", "patch", "/embedded-admin-app"),
1474
+ disable: operation("tenants", "delete", "/embedded-admin-app")
1428
1475
  };
1429
1476
  var EVENTS_ENDPOINT_OPERATIONS = {
1477
+ events: {
1478
+ convertSchedule: operation("events", "post", "/:id/schedule")
1479
+ },
1430
1480
  occurrences: {
1431
1481
  range: operation("event-occurrences", "get", "/range"),
1432
1482
  admissionAvailability: operation(
@@ -1467,46 +1517,51 @@ function resolveOperationMethod(descriptor) {
1467
1517
  }
1468
1518
 
1469
1519
  // src/core/api/endpoints.ts
1470
- var endpoint = (method, path) => ({ method, path });
1471
1520
  var sharedEndpoint = (descriptor) => descriptor;
1472
- function resolveOperationMethod2(descriptor) {
1473
- return "collection" in descriptor ? resolveOperationMethod(descriptor) : descriptor.method;
1474
- }
1475
1521
  function resolveOperationErrorFamily(descriptor) {
1476
- return "collection" in descriptor ? descriptor.errorFamily : void 0;
1477
- }
1478
- function resolveOperationPath2(descriptor, options) {
1479
- if ("collection" in descriptor) {
1480
- return resolveOperationPath(descriptor, options);
1481
- }
1482
- const query = options?.query?.toString().replace(/^\?/, "");
1483
- return query ? `${descriptor.path}?${query}` : descriptor.path;
1522
+ return descriptor.errorFamily;
1484
1523
  }
1485
1524
  var COMMERCE_ENDPOINTS = {
1486
1525
  products: {
1487
- detail: endpoint("GET", "/api/products/detail"),
1488
- detailCatalog: endpoint("GET", "/api/products/detail/catalog"),
1489
- listingGroups: endpoint("GET", "/api/products/listing-groups"),
1490
- listingGroupsCatalog: endpoint(
1491
- "GET",
1492
- "/api/products/listing-groups/catalog"
1526
+ detail: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.detail),
1527
+ detailCatalog: sharedEndpoint(
1528
+ COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog
1529
+ ),
1530
+ listingGroups: sharedEndpoint(
1531
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroups
1532
+ ),
1533
+ listingGroupsCatalog: sharedEndpoint(
1534
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog
1535
+ ),
1536
+ // The manifest keeps the GET read and the POST body-query apart; this
1537
+ // semantic name has always resolved to the GET one.
1538
+ listingGroupsQuery: sharedEndpoint(
1539
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryGet
1540
+ ),
1541
+ listingGroupsQueryCatalog: sharedEndpoint(
1542
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryCatalog
1493
1543
  ),
1494
- listingGroupsQuery: endpoint("GET", "/api/products/listing-groups/query"),
1495
- listingGroupsQueryCatalog: endpoint(
1496
- "GET",
1497
- "/api/products/listing-groups/query/catalog"
1544
+ stockCheck: sharedEndpoint(
1545
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockCheck
1498
1546
  ),
1499
- stockCheck: endpoint("POST", "/api/products/stock-check"),
1500
- stockSnapshot: endpoint("GET", "/api/products/stock"),
1501
- upsert: endpoint("POST", "/api/products/upsert")
1547
+ stockSnapshot: sharedEndpoint(
1548
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockSnapshot
1549
+ ),
1550
+ upsert: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.upsert)
1502
1551
  },
1503
1552
  orders: {
1504
- update: endpoint("POST", "/api/orders/update"),
1505
- byPayment: endpoint("GET", "/api/orders/by-payment"),
1506
- cancel: endpoint("POST", "/api/orders/cancel"),
1507
- resolveCancelRefund: endpoint("POST", "/api/orders/resolve-cancel-refund"),
1508
- createFulfillment: endpoint("POST", "/api/orders/create-fulfillment"),
1509
- updateFulfillment: endpoint("POST", "/api/orders/update-fulfillment")
1553
+ update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.update),
1554
+ byPayment: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.byPayment),
1555
+ cancel: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.cancel),
1556
+ resolveCancelRefund: sharedEndpoint(
1557
+ COMMERCE_ENDPOINT_OPERATIONS.orders.resolveCancelRefund
1558
+ ),
1559
+ createFulfillment: sharedEndpoint(
1560
+ COMMERCE_ENDPOINT_OPERATIONS.orders.createFulfillment
1561
+ ),
1562
+ updateFulfillment: sharedEndpoint(
1563
+ COMMERCE_ENDPOINT_OPERATIONS.orders.updateFulfillment
1564
+ )
1510
1565
  },
1511
1566
  checkouts: {
1512
1567
  create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.checkout),
@@ -1518,18 +1573,21 @@ var COMMERCE_ENDPOINTS = {
1518
1573
  }
1519
1574
  },
1520
1575
  returns: {
1521
- create: endpoint("POST", "/api/returns/create"),
1522
- update: endpoint("POST", "/api/returns/update"),
1523
- returnRefund: endpoint("POST", "/api/returns/return-refund")
1576
+ create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.create),
1577
+ update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.update),
1578
+ returnRefund: sharedEndpoint(
1579
+ COMMERCE_ENDPOINT_OPERATIONS.returns.returnRefund
1580
+ )
1524
1581
  },
1525
1582
  fulfillmentOrders: {
1526
- prepare: endpoint(
1527
- "POST",
1528
- "/api/fulfillment-orders/prepare-fulfillment-order"
1583
+ prepare: sharedEndpoint(
1584
+ COMMERCE_ENDPOINT_OPERATIONS.fulfillmentOrders.prepare
1529
1585
  )
1530
1586
  },
1531
1587
  fulfillments: {
1532
- bulkImport: endpoint("POST", "/api/fulfillments/bulk-import")
1588
+ bulkImport: sharedEndpoint(
1589
+ COMMERCE_ENDPOINT_OPERATIONS.fulfillments.bulkImport
1590
+ )
1533
1591
  },
1534
1592
  carts: {
1535
1593
  create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.create),
@@ -1594,42 +1652,21 @@ var COMMERCE_ENDPOINTS = {
1594
1652
  ),
1595
1653
  confirm: sharedEndpoint(
1596
1654
  COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.confirm
1655
+ ),
1656
+ findPortOne: sharedEndpoint(
1657
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.findPortOne
1658
+ ),
1659
+ reconcilePortOne: sharedEndpoint(
1660
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.reconcilePortOne
1597
1661
  )
1598
1662
  }
1599
1663
  },
1600
1664
  shippingPolicies: {
1601
- calculate: endpoint("POST", "/api/shipping-policies/calculate")
1665
+ calculate: sharedEndpoint(
1666
+ COMMERCE_ENDPOINT_OPERATIONS.shippingPolicies.calculate
1667
+ )
1602
1668
  }
1603
1669
  };
1604
- function isCommerceEndpointDescriptor(value) {
1605
- if (!value || typeof value !== "object") return false;
1606
- const candidate = value;
1607
- return typeof candidate.method === "string" && typeof candidate.path === "string";
1608
- }
1609
- function flattenEndpointPaths(value) {
1610
- if (isCommerceEndpointDescriptor(value)) return [resolveOperationPath2(value)];
1611
- if (!value || typeof value !== "object") return [];
1612
- return Object.values(value).flatMap((entry) => flattenEndpointPaths(entry));
1613
- }
1614
- function flattenEndpointDescriptors(value) {
1615
- if (isCommerceEndpointDescriptor(value)) return [value];
1616
- if (!value || typeof value !== "object") return [];
1617
- return Object.values(value).flatMap(
1618
- (entry) => flattenEndpointDescriptors(entry)
1619
- );
1620
- }
1621
- var COMMERCE_ENDPOINT_PATHS = flattenEndpointPaths(COMMERCE_ENDPOINTS);
1622
- var COMMERCE_ENDPOINT_DESCRIPTORS = flattenEndpointDescriptors(COMMERCE_ENDPOINTS);
1623
- var MEMBERSHIP_ENDPOINTS = {
1624
- subscribe: "/api/memberships/subscribe",
1625
- cancel: (id) => `/api/memberships/${id}/cancel`,
1626
- me: "/api/memberships/me"
1627
- };
1628
- var MEMBERSHIP_ENDPOINT_PATHS = [
1629
- MEMBERSHIP_ENDPOINTS.subscribe,
1630
- MEMBERSHIP_ENDPOINTS.cancel(":id"),
1631
- MEMBERSHIP_ENDPOINTS.me
1632
- ];
1633
1670
 
1634
1671
  // src/core/api/customer-scoped-api.ts
1635
1672
  var CustomerScopedTransport = class {
@@ -1650,10 +1687,10 @@ var CustomerScopedTransport = class {
1650
1687
  this.onUnauthorized = options.onUnauthorized;
1651
1688
  this.onRequestId = options.onRequestId;
1652
1689
  }
1653
- async request(endpoint2, options) {
1690
+ async request(endpoint, options) {
1654
1691
  const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
1655
1692
  try {
1656
- const response = await httpFetch(endpoint2, {
1693
+ const response = await httpFetch(endpoint, {
1657
1694
  method: options.method,
1658
1695
  apiUrl: this.apiUrl,
1659
1696
  publishableKey: this.publishableKey,
@@ -1667,7 +1704,7 @@ var CustomerScopedTransport = class {
1667
1704
  ...options.errorFamily && { errorFamily: options.errorFamily }
1668
1705
  });
1669
1706
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
1670
- return parseApiResponse(response, endpoint2, {
1707
+ return parseApiResponse(response, endpoint, {
1671
1708
  errorFamily: options.errorFamily
1672
1709
  });
1673
1710
  } catch (err) {
@@ -1681,12 +1718,12 @@ var CustomerScopedApi = class {
1681
1718
  constructor(apiName, options) {
1682
1719
  this.transport = new CustomerScopedTransport(apiName, options);
1683
1720
  }
1684
- requestEndpoint(endpoint2, body, options) {
1685
- return this.transport.request(resolveOperationPath2(endpoint2, options), {
1686
- method: resolveOperationMethod2(endpoint2),
1721
+ requestEndpoint(endpoint, body, options) {
1722
+ return this.transport.request(resolveOperationPath(endpoint, options), {
1723
+ method: resolveOperationMethod(endpoint),
1687
1724
  body,
1688
1725
  headers: options?.headers,
1689
- errorFamily: resolveOperationErrorFamily(endpoint2)
1726
+ errorFamily: resolveOperationErrorFamily(endpoint)
1690
1727
  });
1691
1728
  }
1692
1729
  };
@@ -1694,8 +1731,8 @@ var RawCustomerScopedApi = class {
1694
1731
  constructor(apiName, options) {
1695
1732
  this.transport = new CustomerScopedTransport(apiName, options);
1696
1733
  }
1697
- request(endpoint2, options) {
1698
- return this.transport.request(endpoint2, options);
1734
+ request(endpoint, options) {
1735
+ return this.transport.request(endpoint, options);
1699
1736
  }
1700
1737
  };
1701
1738
 
@@ -1770,11 +1807,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
1770
1807
  if (params.page !== void 0) urlParams.set("page", String(params.page));
1771
1808
  return `/api/comments/public?${urlParams.toString()}`;
1772
1809
  }
1773
- async execute(endpoint2, method, body) {
1774
- return this.request(endpoint2, { method, body });
1810
+ async execute(endpoint, method, body) {
1811
+ return this.request(endpoint, { method, body });
1775
1812
  }
1776
- async executeDoc(endpoint2, method, body) {
1777
- const response = await this.execute(endpoint2, method, body);
1813
+ async executeDoc(endpoint, method, body) {
1814
+ const response = await this.execute(endpoint, method, body);
1778
1815
  return unwrapPayloadDoc(response);
1779
1816
  }
1780
1817
  createPost(params) {
@@ -2040,8 +2077,8 @@ var CommunityClient = class extends RawCustomerScopedApi {
2040
2077
 
2041
2078
  // src/core/content/content-client.ts
2042
2079
  var PublicContentApi = class extends RawCustomerScopedApi {
2043
- get(endpoint2) {
2044
- return this.request(endpoint2, { method: "GET" });
2080
+ get(endpoint) {
2081
+ return this.request(endpoint, { method: "GET" });
2045
2082
  }
2046
2083
  };
2047
2084
  function appendCommonParams(search, options, defaultSort) {
@@ -2139,7 +2176,10 @@ var ORDER_PRIMARY_DISPLAY_STATUSES = [
2139
2176
  ];
2140
2177
  var CHECKOUT_STATUSES = ["open", "placed", "abandoned"];
2141
2178
  var ABANDONED_REASONS = ["expired", "customer", "operator"];
2142
- var PAYMENT_PROVIDERS = ["toss", "portone"];
2179
+ function managedPaymentProviders(providers) {
2180
+ return providers;
2181
+ }
2182
+ var PAYMENT_PROVIDERS = managedPaymentProviders(["toss", "portone"]);
2143
2183
  var PAYMENT_PROVIDER_STATUSES = [
2144
2184
  "requires_payment_method",
2145
2185
  "requires_action",
@@ -2187,6 +2227,26 @@ function invalidCanonicalResponse(resource, details) {
2187
2227
  function fail(resource, path, expected) {
2188
2228
  invalidCanonicalResponse(resource, { path, expected });
2189
2229
  }
2230
+ function providerMismatch(resource, expected, actual, operation2) {
2231
+ if (operation2 === "cancel") {
2232
+ const method = {
2233
+ toss: "cancel()",
2234
+ portone: "cancelPortOne()"
2235
+ }[actual];
2236
+ throw createApiError(
2237
+ `Canonical ${resource} response provider mismatch: expected ${expected}, received ${actual}.`,
2238
+ 502,
2239
+ { resource, path: "$.provider", expected, actual },
2240
+ `The server applied the cancellation to a ${actual} PaymentSession, but this SDK method expects ${expected}.`,
2241
+ `Re-invoke ${method} with the same idempotencyKey; do not create a new key.`
2242
+ );
2243
+ }
2244
+ invalidCanonicalResponse(resource, {
2245
+ path: "$.provider",
2246
+ expected,
2247
+ actual
2248
+ });
2249
+ }
2190
2250
  function record(value, resource, path) {
2191
2251
  if (!value || typeof value !== "object" || Array.isArray(value)) {
2192
2252
  fail(resource, path, "object");
@@ -2222,6 +2282,9 @@ function nullableString(value, resource, path) {
2222
2282
  fail(resource, path, "string or null");
2223
2283
  }
2224
2284
  }
2285
+ function nullableNonEmptyString(value, resource, path) {
2286
+ if (value !== null) string(value, resource, path);
2287
+ }
2225
2288
  function cartLineQuantity(value, resource, path) {
2226
2289
  const quantity = positiveInteger(value, resource, path);
2227
2290
  if (quantity > MAX_CART_LINE_QUANTITY) {
@@ -2731,8 +2794,8 @@ function validatePublicOrderItem(value, resource, path) {
2731
2794
  validateReference(item.variant, resource, `${path}.variant`);
2732
2795
  }
2733
2796
  string(item.productTitle, resource, `${path}.productTitle`);
2734
- nullableString(item.variantTitle, resource, `${path}.variantTitle`);
2735
- nullableString(item.sku, resource, `${path}.sku`);
2797
+ nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
2798
+ nullableNonEmptyString(item.sku, resource, `${path}.sku`);
2736
2799
  validateAdmissions(item.admissions, resource, `${path}.admissions`);
2737
2800
  const quantity = positiveInteger(item.quantity, resource, `${path}.quantity`);
2738
2801
  const unitPrice = safeMinor(
@@ -2983,8 +3046,8 @@ function validateCheckoutItem(value, resource, path) {
2983
3046
  validateReference(item.product, resource, `${path}.product`);
2984
3047
  validateReference(item.variant, resource, `${path}.variant`);
2985
3048
  string(item.productTitle, resource, `${path}.productTitle`);
2986
- nullableString(item.variantTitle, resource, `${path}.variantTitle`);
2987
- nullableString(item.sku, resource, `${path}.sku`);
3049
+ nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
3050
+ nullableNonEmptyString(item.sku, resource, `${path}.sku`);
2988
3051
  validateAdmissions(item.admissions, resource, `${path}.admissions`);
2989
3052
  cartLineQuantity(item.quantity, resource, `${path}.quantity`);
2990
3053
  const unitPrice = safeMinor(
@@ -3316,11 +3379,21 @@ function validateNextAction(value, provider, resource, path) {
3316
3379
  const action = record(value, resource, path);
3317
3380
  if (provider === "portone") {
3318
3381
  if (action.type === "portone_sdk") {
3382
+ const hasCancelable = "cancelable" in action;
3383
+ const hasRetryPolicy = "retryPolicy" in action;
3384
+ if (hasCancelable !== hasRetryPolicy) {
3385
+ fail(
3386
+ resource,
3387
+ path,
3388
+ "exact released action or exact negotiated capability action"
3389
+ );
3390
+ }
3319
3391
  exact(
3320
3392
  action,
3321
3393
  [
3322
3394
  "type",
3323
3395
  "version",
3396
+ ...hasCancelable ? ["cancelable", "retryPolicy"] : [],
3324
3397
  "storeId",
3325
3398
  "channelKey",
3326
3399
  "paymentId",
@@ -3335,6 +3408,11 @@ function validateNextAction(value, provider, resource, path) {
3335
3408
  path
3336
3409
  );
3337
3410
  if (action.version !== "v2") fail(resource, `${path}.version`, "v2");
3411
+ if (hasCancelable && action.cancelable !== false)
3412
+ fail(resource, `${path}.cancelable`, "false");
3413
+ if (hasRetryPolicy && action.retryPolicy !== "same_action_only") {
3414
+ fail(resource, `${path}.retryPolicy`, "same_action_only");
3415
+ }
3338
3416
  for (const key of ["storeId", "channelKey"]) {
3339
3417
  boundedString(action[key], 255, resource, `${path}.${key}`);
3340
3418
  }
@@ -3381,6 +3459,10 @@ function validateNextAction(value, provider, resource, path) {
3381
3459
  "HTTPS or loopback URL without embedded credentials"
3382
3460
  );
3383
3461
  }
3462
+ if (!hasCancelable) {
3463
+ action.cancelable = false;
3464
+ action.retryPolicy = "same_action_only";
3465
+ }
3384
3466
  return;
3385
3467
  }
3386
3468
  exact(action, ["type", "checkoutUrl"], [], resource, path);
@@ -3457,7 +3539,7 @@ function validateNextAction(value, provider, resource, path) {
3457
3539
  if (action.customerEmail !== void 0)
3458
3540
  validateCustomer({ email: action.customerEmail }, resource, path);
3459
3541
  }
3460
- function validatePublicPaymentSession(value, expectedProvider) {
3542
+ function validatePublicPaymentSession(value, expectedProvider, operation2) {
3461
3543
  const resource = "PaymentSession";
3462
3544
  const session = record(value, resource, "$");
3463
3545
  const provider = enumValue(
@@ -3466,9 +3548,6 @@ function validatePublicPaymentSession(value, expectedProvider) {
3466
3548
  resource,
3467
3549
  "$.provider"
3468
3550
  );
3469
- if (expectedProvider !== void 0 && provider !== expectedProvider) {
3470
- fail(resource, "$.provider", expectedProvider);
3471
- }
3472
3551
  const status = enumValue(
3473
3552
  session.providerStatus,
3474
3553
  PAYMENT_PROVIDER_STATUSES,
@@ -3672,44 +3751,128 @@ function validatePublicPaymentSession(value, expectedProvider) {
3672
3751
  "$.cancellationReason"
3673
3752
  );
3674
3753
  }
3754
+ if (expectedProvider !== void 0 && provider !== expectedProvider) {
3755
+ if (operation2 === "cancel" && status !== "canceling" && status !== "canceled") {
3756
+ fail(
3757
+ resource,
3758
+ "$.providerStatus",
3759
+ "canceling or canceled after a successful cancellation"
3760
+ );
3761
+ }
3762
+ providerMismatch(resource, expectedProvider, provider, operation2);
3763
+ }
3675
3764
  return value;
3676
3765
  }
3677
3766
 
3678
3767
  // src/core/customer/customer-auth.ts
3679
3768
  var DEFAULT_TIMEOUT2 = 15e3;
3680
- function safeGetItem(key) {
3769
+ var REFRESH_LOCK_TIMEOUT = DEFAULT_TIMEOUT2 * 3;
3770
+ var SESSION_RECORD_VERSION = 1;
3771
+ var STORAGE_UNUSABLE = /* @__PURE__ */ Symbol("storage-unusable");
3772
+ function canonicalApiIdentity(apiUrl) {
3681
3773
  try {
3682
- return localStorage.getItem(key);
3774
+ const url = new URL(apiUrl);
3775
+ return `${url.protocol.toLowerCase()}//${url.host.toLowerCase()}${url.pathname.replace(/\/+$/, "")}`;
3776
+ } catch {
3777
+ return apiUrl.trim().toLowerCase().replace(/\/+$/, "");
3778
+ }
3779
+ }
3780
+ function buildRefreshLockName(apiUrl, publishableKey, storageKey) {
3781
+ return `01software:customer-auth-refresh:${canonicalApiIdentity(apiUrl)}:${publishableKey}:${storageKey}`;
3782
+ }
3783
+ function getRefreshLockRequester() {
3784
+ try {
3785
+ if (typeof navigator === "undefined") return null;
3786
+ const locks = navigator.locks;
3787
+ if (!locks || typeof locks.request !== "function") return null;
3788
+ return (name, options, callback) => locks.request(
3789
+ name,
3790
+ options,
3791
+ () => callback()
3792
+ );
3683
3793
  } catch {
3684
3794
  return null;
3685
3795
  }
3686
3796
  }
3797
+ function parseSessionRecord(raw) {
3798
+ try {
3799
+ const parsed = JSON.parse(raw);
3800
+ if (!parsed || typeof parsed !== "object") return null;
3801
+ const candidate = parsed;
3802
+ if (candidate.v !== SESSION_RECORD_VERSION) return null;
3803
+ if (typeof candidate.rev !== "number" || !Number.isFinite(candidate.rev)) {
3804
+ return null;
3805
+ }
3806
+ const token = candidate.token;
3807
+ const refreshToken = candidate.refreshToken;
3808
+ if (token !== null && typeof token !== "string") return null;
3809
+ if (refreshToken !== null && typeof refreshToken !== "string") return null;
3810
+ return {
3811
+ v: SESSION_RECORD_VERSION,
3812
+ rev: candidate.rev,
3813
+ token,
3814
+ refreshToken
3815
+ };
3816
+ } catch {
3817
+ return null;
3818
+ }
3819
+ }
3820
+ function readSessionRecord(recordKey, mirrorKey, mirrorRefreshKey) {
3821
+ let raw;
3822
+ try {
3823
+ raw = localStorage.getItem(recordKey);
3824
+ } catch {
3825
+ return STORAGE_UNUSABLE;
3826
+ }
3827
+ if (raw !== null) {
3828
+ const parsed = parseSessionRecord(raw);
3829
+ return parsed ? { record: parsed, stored: true } : STORAGE_UNUSABLE;
3830
+ }
3831
+ try {
3832
+ return {
3833
+ record: {
3834
+ v: SESSION_RECORD_VERSION,
3835
+ rev: 0,
3836
+ token: localStorage.getItem(mirrorKey),
3837
+ refreshToken: localStorage.getItem(mirrorRefreshKey)
3838
+ },
3839
+ stored: false
3840
+ };
3841
+ } catch {
3842
+ return STORAGE_UNUSABLE;
3843
+ }
3844
+ }
3687
3845
  var CustomerAuth = class {
3688
3846
  constructor(publishableKey, options, apiUrl) {
3689
3847
  this.refreshPromise = null;
3848
+ /** Canonical record key; null unless persistence is active in a browser. */
3849
+ this.persistRecordKey = null;
3850
+ /** Advisory single-value access mirror, plus the retired refresh mirror. */
3851
+ this.persistMirrorKey = null;
3852
+ this.persistMirrorRefreshKey = null;
3853
+ /** Cross-context refresh lock name; null when there is no shared storage. */
3854
+ this.refreshLockName = null;
3855
+ /** Revision of the canonical record this instance last observed. */
3856
+ this.sessionRev = 0;
3690
3857
  this.publishableKey = publishableKey;
3691
3858
  this.baseUrl = resolveApiUrl(apiUrl);
3692
3859
  const persist = options?.persist ?? true;
3693
3860
  if (persist) {
3694
3861
  const key = typeof persist === "string" ? persist : "customer-token";
3695
- const refreshKey = `${key}:refresh`;
3696
3862
  const isBrowser = typeof window !== "undefined";
3697
- this.token = isBrowser ? safeGetItem(key) : null;
3698
- this.refreshTokenValue = isBrowser ? safeGetItem(refreshKey) : null;
3699
- this.onTokenChange = isBrowser ? (token) => {
3700
- try {
3701
- if (token) localStorage.setItem(key, token);
3702
- else localStorage.removeItem(key);
3703
- } catch {
3704
- }
3705
- } : void 0;
3706
- this.onRefreshTokenChange = isBrowser ? (refreshToken) => {
3707
- try {
3708
- if (refreshToken) localStorage.setItem(refreshKey, refreshToken);
3709
- else localStorage.removeItem(refreshKey);
3710
- } catch {
3711
- }
3712
- } : void 0;
3863
+ this.token = null;
3864
+ this.refreshTokenValue = null;
3865
+ if (isBrowser) {
3866
+ this.persistRecordKey = `${key}:session`;
3867
+ this.persistMirrorKey = key;
3868
+ this.persistMirrorRefreshKey = `${key}:refresh`;
3869
+ this.refreshLockName = buildRefreshLockName(
3870
+ this.baseUrl,
3871
+ publishableKey,
3872
+ key
3873
+ );
3874
+ this.syncFromPersistedStorage();
3875
+ }
3713
3876
  } else {
3714
3877
  this.token = options?.token ?? null;
3715
3878
  this.refreshTokenValue = options?.refreshToken ?? null;
@@ -3737,66 +3900,299 @@ var CustomerAuth = class {
3737
3900
  body: JSON.stringify(data)
3738
3901
  }
3739
3902
  );
3740
- this.setToken(result.token);
3741
- if (result.refreshToken) this.setRefreshToken(result.refreshToken);
3903
+ if (result.refreshToken) this.setSession(result.token, result.refreshToken);
3904
+ else this.setToken(result.token);
3742
3905
  return result;
3743
3906
  }
3744
3907
  /**
3745
3908
  * Refresh the current token. Uses a refresh token when available, otherwise
3746
3909
  * falls back to the legacy bearer-token compatibility path.
3910
+ *
3911
+ * Refresh tokens are single-use, so a persisted session shared by several
3912
+ * tabs or SDK instances must rotate at most once: concurrent rotations of the
3913
+ * same token are replay from the server's point of view and revoke the whole
3914
+ * family. Persisted browser sessions therefore serialize rotation across
3915
+ * contexts and re-read the canonical persisted credentials inside the lock.
3747
3916
  */
3748
3917
  async refreshToken() {
3918
+ this.syncFromPersistedStorage();
3749
3919
  if (!this.refreshTokenValue && !this.token) {
3750
3920
  throw new ApiError("Not authenticated", 401);
3751
3921
  }
3752
3922
  if (this.refreshPromise) return this.refreshPromise;
3753
- this.refreshPromise = this._doRefreshToken();
3923
+ const intended = this.currentFence();
3924
+ this.refreshPromise = this.rotateAcrossContexts(intended);
3754
3925
  try {
3755
3926
  return await this.refreshPromise;
3756
3927
  } finally {
3757
3928
  this.refreshPromise = null;
3758
3929
  }
3759
3930
  }
3760
- async _doRefreshToken() {
3761
- const init = this.refreshTokenValue ? {
3931
+ /**
3932
+ * Re-read the canonical persisted session. In persisted mode the shared
3933
+ * record — not this instance's memory — is the source of truth, so another
3934
+ * context's rotation, login, or logout is observed before the next credential
3935
+ * use. Change callbacks are deliberately not invoked: this is a read.
3936
+ */
3937
+ syncFromPersistedStorage() {
3938
+ const canonical = this.readCanonicalSession();
3939
+ if (canonical === STORAGE_UNUSABLE) {
3940
+ this.disablePersistence();
3941
+ return;
3942
+ }
3943
+ if (!canonical) return;
3944
+ this.sessionRev = canonical.record.rev;
3945
+ this.token = canonical.record.token;
3946
+ this.refreshTokenValue = canonical.record.refreshToken;
3947
+ }
3948
+ /** `null` when this instance does not persist. */
3949
+ readCanonicalSession() {
3950
+ if (!this.persistRecordKey || !this.persistMirrorKey || !this.persistMirrorRefreshKey) {
3951
+ return null;
3952
+ }
3953
+ return readSessionRecord(
3954
+ this.persistRecordKey,
3955
+ this.persistMirrorKey,
3956
+ this.persistMirrorRefreshKey
3957
+ );
3958
+ }
3959
+ /**
3960
+ * Publish a change to canonical storage.
3961
+ *
3962
+ * The canonical pair is re-read immediately before the single record write so
3963
+ * that a field this call does not change is taken from that read rather than
3964
+ * from this instance's possibly stale copy. That merge is BEST-EFFORT: it
3965
+ * removes the stale counterpart an instance would otherwise carry, but it is
3966
+ * not a compare-and-swap. Web Storage offers none, and the synchronous public
3967
+ * mutators cannot await the refresh lease, so a commit that lands between
3968
+ * this read and the store operation is lost by ordering — including the
3969
+ * counterpart just read, which is then republished stale. The window is one
3970
+ * store operation wide and the server remains authoritative; see
3971
+ * `CUST-AUTH-033` for the stated limit.
3972
+ *
3973
+ * Returns `false` only when `requireLiveSession` refused a write because the
3974
+ * canonical session had already been cleared.
3975
+ */
3976
+ commitPersistedSession(change, options) {
3977
+ const recordKey = this.persistRecordKey;
3978
+ const mirrorKey = this.persistMirrorKey;
3979
+ const mirrorRefreshKey = this.persistMirrorRefreshKey;
3980
+ const canonical = this.readCanonicalSession();
3981
+ if (canonical === null || !recordKey || !mirrorKey || !mirrorRefreshKey) {
3982
+ return true;
3983
+ }
3984
+ if (canonical === STORAGE_UNUSABLE) {
3985
+ this.disablePersistence();
3986
+ return true;
3987
+ }
3988
+ const current = canonical.record;
3989
+ if (options?.requireLiveSession && !current.token && !current.refreshToken) {
3990
+ return false;
3991
+ }
3992
+ const next = {
3993
+ v: SESSION_RECORD_VERSION,
3994
+ rev: current.rev + 1,
3995
+ token: "token" in change ? change.token ?? null : current.token,
3996
+ refreshToken: "refreshToken" in change ? change.refreshToken ?? null : current.refreshToken
3997
+ };
3998
+ if (
3999
+ // Only a state that is genuinely persisted can already say what this
4000
+ // write would say. An absent record reads as an empty pair, and treating
4001
+ // that as a no-op would drop the very tombstone that stops a later
4002
+ // migration from resurrecting the session out of the earlier layout.
4003
+ canonical.stored && next.token === current.token && next.refreshToken === current.refreshToken
4004
+ ) {
4005
+ this.sessionRev = current.rev;
4006
+ this.token = current.token;
4007
+ this.refreshTokenValue = current.refreshToken;
4008
+ return true;
4009
+ }
4010
+ try {
4011
+ localStorage.setItem(recordKey, JSON.stringify(next));
4012
+ } catch {
4013
+ this.disablePersistence();
4014
+ return true;
4015
+ }
4016
+ this.sessionRev = next.rev;
4017
+ this.token = next.token;
4018
+ this.refreshTokenValue = next.refreshToken;
4019
+ try {
4020
+ localStorage.removeItem(mirrorRefreshKey);
4021
+ } catch {
4022
+ return true;
4023
+ }
4024
+ try {
4025
+ if (next.token) localStorage.setItem(mirrorKey, next.token);
4026
+ else localStorage.removeItem(mirrorKey);
4027
+ } catch {
4028
+ }
4029
+ return true;
4030
+ }
4031
+ /**
4032
+ * Storage rejected a write or a read, so it is not a canonical store for this
4033
+ * instance. Fall back to the memory-only session and take no lease: there is
4034
+ * no shared state left to coordinate. Nothing is purged — the record commit
4035
+ * is atomic, so no inconsistent state was published, and another context's
4036
+ * valid session must not be destroyed by this instance's local failure.
4037
+ */
4038
+ disablePersistence() {
4039
+ this.persistRecordKey = null;
4040
+ this.persistMirrorKey = null;
4041
+ this.persistMirrorRefreshKey = null;
4042
+ this.refreshLockName = null;
4043
+ }
4044
+ /**
4045
+ * Compare the canonical record with the fence this call captured before it
4046
+ * left. Every persisted decision — rotate, converge, or fail closed — goes
4047
+ * through this one comparison. The revision catches a logout, a fresh login,
4048
+ * or a manual setter even when token values coincide; the value comparison
4049
+ * additionally catches a mirror-only writer that cannot bump a revision.
4050
+ */
4051
+ classifyCanonicalState(intended) {
4052
+ if (!this.persistRecordKey) return "current";
4053
+ this.syncFromPersistedStorage();
4054
+ if (!this.persistRecordKey) return "current";
4055
+ if (!this.token && !this.refreshTokenValue) return "cleared";
4056
+ if (intended.refreshToken !== null) {
4057
+ return this.refreshTokenValue === intended.refreshToken ? "current" : "superseded";
4058
+ }
4059
+ return this.token === intended.token && !this.refreshTokenValue ? "current" : "superseded";
4060
+ }
4061
+ /** The canonical persisted pair, as a refresh result. */
4062
+ canonicalPair(token) {
4063
+ return {
4064
+ token,
4065
+ ...this.refreshTokenValue ? { refreshToken: this.refreshTokenValue } : {}
4066
+ };
4067
+ }
4068
+ /** Current credentials plus the revision they were observed at. */
4069
+ currentFence() {
4070
+ return { token: this.token, refreshToken: this.refreshTokenValue };
4071
+ }
4072
+ /**
4073
+ * Clear an access credential a 401 just proved unusable — but only while it
4074
+ * is still the canonical one. A rotation committed by another context while
4075
+ * the request was in flight is newer than this 401, so it must survive; the
4076
+ * instance adopts it instead. The refresh entry is never touched here: a
4077
+ * rejected access token says nothing about the refresh family.
4078
+ */
4079
+ invalidateAccessToken(spentToken) {
4080
+ this.syncFromPersistedStorage();
4081
+ if (this.token !== spentToken) return;
4082
+ this.setToken(null);
4083
+ }
4084
+ /** Commit both credentials in one canonical write. */
4085
+ setSession(token, refreshToken, options) {
4086
+ this.token = token;
4087
+ this.refreshTokenValue = refreshToken;
4088
+ const committed = this.commitPersistedSession(
4089
+ { token, refreshToken },
4090
+ options
4091
+ );
4092
+ if (!committed) return false;
4093
+ this.onTokenChange?.(this.token);
4094
+ this.onRefreshTokenChange?.(this.refreshTokenValue);
4095
+ return true;
4096
+ }
4097
+ /**
4098
+ * Serialize rotation against every other context sharing the same storage
4099
+ * key and API/tenant identity. Coordination is best-effort: when it is
4100
+ * unavailable or times out the rotation still happens, so server-side reuse
4101
+ * detection is never bypassed by a client that failed to coordinate.
4102
+ */
4103
+ async rotateAcrossContexts(intended) {
4104
+ const lockName = this.refreshLockName;
4105
+ const requestLock = lockName ? getRefreshLockRequester() : null;
4106
+ if (!lockName || !requestLock) {
4107
+ return this.rotateWithCanonicalState(intended);
4108
+ }
4109
+ const controller = new AbortController();
4110
+ const timer = setTimeout(() => controller.abort(), REFRESH_LOCK_TIMEOUT);
4111
+ let entered = false;
4112
+ try {
4113
+ return await requestLock(
4114
+ lockName,
4115
+ { signal: controller.signal },
4116
+ async () => {
4117
+ entered = true;
4118
+ return this.rotateWithCanonicalState(intended);
4119
+ }
4120
+ );
4121
+ } catch (error) {
4122
+ if (entered) throw error;
4123
+ return this.rotateWithCanonicalState(intended);
4124
+ } finally {
4125
+ clearTimeout(timer);
4126
+ }
4127
+ }
4128
+ /**
4129
+ * Decide, against freshly re-read canonical state, whether this context still
4130
+ * owns the rotation.
4131
+ */
4132
+ async rotateWithCanonicalState(intended) {
4133
+ let fence = intended;
4134
+ for (let attempt = 0; attempt < 2; attempt += 1) {
4135
+ const state = this.classifyCanonicalState(fence);
4136
+ if (state === "cleared") throw new ApiError("Not authenticated", 401);
4137
+ if (state === "current") return this._doRefreshToken(fence);
4138
+ if (this.token) return this.canonicalPair(this.token);
4139
+ fence = this.currentFence();
4140
+ }
4141
+ throw new ApiError("Not authenticated", 401);
4142
+ }
4143
+ async _doRefreshToken(intended) {
4144
+ const init = intended.refreshToken ? {
3762
4145
  method: "POST",
3763
- body: JSON.stringify({ refreshToken: this.refreshTokenValue })
4146
+ body: JSON.stringify({ refreshToken: intended.refreshToken })
3764
4147
  } : {
3765
4148
  method: "POST",
3766
- headers: { Authorization: `Bearer ${this.token}` }
4149
+ headers: { Authorization: `Bearer ${intended.token}` }
3767
4150
  };
3768
4151
  const result = await this.requestJson(
3769
4152
  "/api/customers/refresh",
3770
4153
  init
3771
4154
  );
3772
- this.setToken(result.token);
3773
- if (result.refreshToken) this.setRefreshToken(result.refreshToken);
3774
- return result;
4155
+ const state = this.classifyCanonicalState(intended);
4156
+ if (state === "cleared") throw new ApiError("Not authenticated", 401);
4157
+ if (state === "superseded") {
4158
+ if (this.token) return this.canonicalPair(this.token);
4159
+ throw new ApiError("Not authenticated", 401);
4160
+ }
4161
+ const replacedAccessToken = this.token !== null && this.token !== intended.token ? this.token : null;
4162
+ const nextToken = replacedAccessToken ?? result.token;
4163
+ const nextRefresh = result.refreshToken ?? null;
4164
+ if (!this.setSession(nextToken, nextRefresh, { requireLiveSession: true })) {
4165
+ throw new ApiError("Not authenticated", 401);
4166
+ }
4167
+ return {
4168
+ token: nextToken,
4169
+ ...nextRefresh ? { refreshToken: nextRefresh } : {}
4170
+ };
3775
4171
  }
3776
4172
  /**
3777
4173
  * Clear the stored token
3778
4174
  */
3779
4175
  logout() {
3780
- this.setToken(null);
3781
- this.setRefreshToken(null);
4176
+ this.setSession(null, null);
3782
4177
  }
3783
4178
  /**
3784
4179
  * Get the current authenticated customer's profile
3785
4180
  */
3786
4181
  async me() {
3787
- if (!this.token) return null;
4182
+ const token = this.getToken();
4183
+ if (!token) return null;
3788
4184
  try {
3789
4185
  const data = await this.requestJson(
3790
4186
  "/api/customers/me",
3791
4187
  {
3792
4188
  method: "GET",
3793
- headers: { Authorization: `Bearer ${this.token}` }
4189
+ headers: { Authorization: `Bearer ${token}` }
3794
4190
  }
3795
4191
  );
3796
4192
  return data.customer ?? null;
3797
4193
  } catch (error) {
3798
4194
  if (error instanceof SDKError && error.status === 401) {
3799
- this.setToken(null);
4195
+ this.invalidateAccessToken(token);
3800
4196
  return null;
3801
4197
  }
3802
4198
  throw error;
@@ -3824,12 +4220,13 @@ var CustomerAuth = class {
3824
4220
  * Update the authenticated customer's profile (name, phone, marketingConsent)
3825
4221
  */
3826
4222
  async updateProfile(data) {
3827
- if (!this.token) throw new ApiError("Not authenticated", 401);
4223
+ const token = this.getToken();
4224
+ if (!token) throw new ApiError("Not authenticated", 401);
3828
4225
  const result = await this.requestJson(
3829
4226
  "/api/customers/me",
3830
4227
  {
3831
4228
  method: "PATCH",
3832
- headers: { Authorization: `Bearer ${this.token}` },
4229
+ headers: { Authorization: `Bearer ${token}` },
3833
4230
  body: JSON.stringify(data)
3834
4231
  }
3835
4232
  );
@@ -3839,10 +4236,11 @@ var CustomerAuth = class {
3839
4236
  * Change the password of the currently authenticated customer
3840
4237
  */
3841
4238
  async changePassword(currentPassword, newPassword) {
3842
- if (!this.token) throw new ApiError("Not authenticated", 401);
4239
+ const token = this.getToken();
4240
+ if (!token) throw new ApiError("Not authenticated", 401);
3843
4241
  await this.requestJson("/api/customers/change-password", {
3844
4242
  method: "POST",
3845
- headers: { Authorization: `Bearer ${this.token}` },
4243
+ headers: { Authorization: `Bearer ${token}` },
3846
4244
  body: JSON.stringify({ currentPassword, newPassword })
3847
4245
  });
3848
4246
  }
@@ -3850,7 +4248,8 @@ var CustomerAuth = class {
3850
4248
  * Get the authenticated customer's orders with pagination and optional status filter
3851
4249
  */
3852
4250
  async getMyOrders(options) {
3853
- if (!this.token) throw new ApiError("Not authenticated", 401);
4251
+ const token = this.getToken();
4252
+ if (!token) throw new ApiError("Not authenticated", 401);
3854
4253
  const params = new URLSearchParams();
3855
4254
  if (options?.page) params.set("page", String(options.page));
3856
4255
  if (options?.limit) params.set("limit", String(options.limit));
@@ -3872,21 +4271,27 @@ var CustomerAuth = class {
3872
4271
  `/api/customers/me/orders${qs ? `?${qs}` : ""}`,
3873
4272
  {
3874
4273
  method: "GET",
3875
- headers: { Authorization: `Bearer ${this.token}` }
4274
+ headers: { Authorization: `Bearer ${token}` }
3876
4275
  }
3877
4276
  );
3878
4277
  return validatePublicOrderList(result);
3879
4278
  }
3880
4279
  /**
3881
- * Get the current token (or null if not authenticated)
4280
+ * Get the current token (or null if not authenticated).
4281
+ *
4282
+ * In persisted mode this re-reads shared storage first, so a rotation or
4283
+ * logout performed by another tab is observed before the token is used.
3882
4284
  */
3883
4285
  getToken() {
4286
+ this.syncFromPersistedStorage();
3884
4287
  return this.token;
3885
4288
  }
3886
4289
  /**
3887
- * Get the current refresh token (or null if unavailable)
4290
+ * Get the current refresh token (or null if unavailable). Persisted mode
4291
+ * re-reads shared storage first, like {@link CustomerAuth.getToken}.
3888
4292
  */
3889
4293
  getRefreshToken() {
4294
+ this.syncFromPersistedStorage();
3890
4295
  return this.refreshTokenValue;
3891
4296
  }
3892
4297
  /**
@@ -3894,6 +4299,7 @@ var CustomerAuth = class {
3894
4299
  */
3895
4300
  setToken(token) {
3896
4301
  this.token = token;
4302
+ this.commitPersistedSession({ token });
3897
4303
  this.onTokenChange?.(token);
3898
4304
  }
3899
4305
  /**
@@ -3901,13 +4307,14 @@ var CustomerAuth = class {
3901
4307
  */
3902
4308
  setRefreshToken(refreshToken) {
3903
4309
  this.refreshTokenValue = refreshToken;
4310
+ this.commitPersistedSession({ refreshToken });
3904
4311
  this.onRefreshTokenChange?.(refreshToken);
3905
4312
  }
3906
4313
  /**
3907
4314
  * Check if the customer is currently authenticated
3908
4315
  */
3909
4316
  isAuthenticated() {
3910
- return this.token !== null;
4317
+ return this.getToken() !== null;
3911
4318
  }
3912
4319
  /**
3913
4320
  * Internal: make a request with timeout and error handling.
@@ -4111,8 +4518,8 @@ var CartApi = class extends CustomerScopedApi {
4111
4518
  endpoint(key) {
4112
4519
  return this.serverTransport ? COMMERCE_ENDPOINTS.carts.server[key] : COMMERCE_ENDPOINTS.carts[key];
4113
4520
  }
4114
- execute(endpoint2, body, idempotencyKey) {
4115
- return this.requestEndpoint(endpoint2, body, {
4521
+ execute(endpoint, body, idempotencyKey) {
4522
+ return this.requestEndpoint(endpoint, body, {
4116
4523
  ...idempotencyKey && {
4117
4524
  headers: { "X-Idempotency-Key": idempotencyKey }
4118
4525
  }
@@ -4129,26 +4536,26 @@ var CartApi = class extends CustomerScopedApi {
4129
4536
  );
4130
4537
  }
4131
4538
  mine(params = {}) {
4132
- const endpoint2 = this.endpoint("mine");
4133
- return this.execute(endpoint2, params).then(
4539
+ const endpoint = this.endpoint("mine");
4540
+ return this.execute(endpoint, params).then(
4134
4541
  (value) => validateCartMineResult(value)
4135
4542
  );
4136
4543
  }
4137
4544
  merge(params) {
4138
4545
  const { idempotencyKey, ...body } = params;
4139
4546
  assertCommerceIdempotencyKey(idempotencyKey);
4140
- const endpoint2 = this.endpoint("merge");
4141
- return this.execute(endpoint2, body, idempotencyKey).then(
4547
+ const endpoint = this.endpoint("merge");
4548
+ return this.execute(endpoint, body, idempotencyKey).then(
4142
4549
  (value) => validateCartMergeResult(value)
4143
4550
  );
4144
4551
  }
4145
4552
  addItem(params) {
4146
4553
  return this.mutate(this.endpoint("addItem"), params);
4147
4554
  }
4148
- mutate(endpoint2, params) {
4555
+ mutate(endpoint, params) {
4149
4556
  const { idempotencyKey, ...body } = params;
4150
4557
  assertCommerceIdempotencyKey(idempotencyKey);
4151
- return this.execute(endpoint2, body, idempotencyKey).then(
4558
+ return this.execute(endpoint, body, idempotencyKey).then(
4152
4559
  (value) => validateCartMutationResult(value)
4153
4560
  );
4154
4561
  }
@@ -4174,8 +4581,8 @@ var CheckoutApi = class extends CustomerScopedApi {
4174
4581
  constructor(options) {
4175
4582
  super("CheckoutApi", { ...options, requiresCredential: false });
4176
4583
  }
4177
- post(endpoint2, body, idempotencyKey) {
4178
- return this.requestEndpoint(endpoint2, body, {
4584
+ post(endpoint, body, idempotencyKey) {
4585
+ return this.requestEndpoint(endpoint, body, {
4179
4586
  ...idempotencyKey && {
4180
4587
  headers: { "X-Idempotency-Key": idempotencyKey }
4181
4588
  }
@@ -4242,15 +4649,23 @@ var PaymentSessionApi = class extends CustomerScopedApi {
4242
4649
  super("PaymentSessionApi", { ...options, requiresCredential: false });
4243
4650
  this.serverTransport = Boolean(options.secretKey);
4244
4651
  }
4245
- post(endpoint2, body, idempotencyKey) {
4246
- return this.requestEndpoint(endpoint2, body, {
4247
- ...idempotencyKey && {
4248
- headers: { "X-Idempotency-Key": idempotencyKey }
4652
+ post(endpoint, body, idempotencyKey, negotiateStandardActionCapabilities = false) {
4653
+ const headers = {
4654
+ ...idempotencyKey && { "X-Idempotency-Key": idempotencyKey },
4655
+ ...negotiateStandardActionCapabilities && {
4656
+ Accept: PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE
4249
4657
  }
4658
+ };
4659
+ return this.requestEndpoint(endpoint, body, {
4660
+ ...Object.keys(headers).length > 0 && { headers }
4250
4661
  });
4251
4662
  }
4252
- async paymentSession(result, expectedProvider) {
4253
- return validatePublicPaymentSession(await result, expectedProvider);
4663
+ async paymentSession(result, expectedProvider, operation2) {
4664
+ return validatePublicPaymentSession(
4665
+ await result,
4666
+ expectedProvider,
4667
+ operation2
4668
+ );
4254
4669
  }
4255
4670
  create(params) {
4256
4671
  const { idempotencyKey, ...body } = params;
@@ -4271,41 +4686,44 @@ var PaymentSessionApi = class extends CustomerScopedApi {
4271
4686
  this.post(
4272
4687
  this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.create : COMMERCE_ENDPOINTS.paymentSessions.create,
4273
4688
  body,
4274
- idempotencyKey
4689
+ idempotencyKey,
4690
+ body.providerOptions.profile === "standard_v2"
4275
4691
  ),
4276
4692
  "portone"
4277
4693
  );
4278
4694
  }
4279
4695
  retrieve(params) {
4280
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4696
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4281
4697
  return this.paymentSession(
4282
- this.post(endpoint2, params),
4698
+ this.post(endpoint, params),
4283
4699
  "toss"
4284
4700
  );
4285
4701
  }
4286
4702
  retrievePortOne(params) {
4287
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4703
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4288
4704
  return this.paymentSession(
4289
- this.post(endpoint2, params),
4705
+ this.post(endpoint, params, void 0, true),
4290
4706
  "portone"
4291
4707
  );
4292
4708
  }
4293
4709
  cancel(params) {
4294
4710
  const { idempotencyKey, ...body } = params;
4295
4711
  assertCommerceIdempotencyKey(idempotencyKey);
4296
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4712
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4297
4713
  return this.paymentSession(
4298
- this.post(endpoint2, body, idempotencyKey),
4299
- "toss"
4714
+ this.post(endpoint, body, idempotencyKey),
4715
+ "toss",
4716
+ "cancel"
4300
4717
  );
4301
4718
  }
4302
4719
  cancelPortOne(params) {
4303
4720
  const { idempotencyKey, ...body } = params;
4304
4721
  assertCommerceIdempotencyKey(idempotencyKey);
4305
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4722
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4306
4723
  return this.paymentSession(
4307
- this.post(endpoint2, body, idempotencyKey),
4308
- "portone"
4724
+ this.post(endpoint, body, idempotencyKey),
4725
+ "portone",
4726
+ "cancel"
4309
4727
  );
4310
4728
  }
4311
4729
  confirm(params) {
@@ -5445,8 +5863,8 @@ function withProductListingCards(response, options) {
5445
5863
 
5446
5864
  // src/core/commerce/commerce-client.ts
5447
5865
  var BrowserCommerceApi = class extends CustomerScopedApi {
5448
- requestEndpoint(endpoint2, body, options) {
5449
- return super.requestEndpoint(endpoint2, body, options);
5866
+ requestEndpoint(endpoint, body, options) {
5867
+ return super.requestEndpoint(endpoint, body, options);
5450
5868
  }
5451
5869
  };
5452
5870
  var CommerceClient = class {
@@ -5646,11 +6064,11 @@ var EventsClient = class {
5646
6064
  { useCustomerAuth: false }
5647
6065
  );
5648
6066
  }
5649
- async execute(endpoint2, method, body, options = {}) {
6067
+ async execute(endpoint, method, body, options = {}) {
5650
6068
  const useCustomerAuth = options.useCustomerAuth === true;
5651
6069
  const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
5652
6070
  try {
5653
- const response = await httpFetch(endpoint2, {
6071
+ const response = await httpFetch(endpoint, {
5654
6072
  method,
5655
6073
  apiUrl: this.apiUrl,
5656
6074
  publishableKey: this.publishableKey,
@@ -5659,7 +6077,7 @@ var EventsClient = class {
5659
6077
  ...body !== void 0 && { body: JSON.stringify(body) }
5660
6078
  });
5661
6079
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
5662
- return parseApiResponse(response, endpoint2);
6080
+ return parseApiResponse(response, endpoint);
5663
6081
  } catch (err) {
5664
6082
  const id = err instanceof SDKError ? err.requestId ?? null : null;
5665
6083
  this.onRequestId?.(id);