@01.software/sdk 0.48.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 +157 -1
  2. package/MIGRATION.md +56 -0
  3. package/README.md +276 -49
  4. package/dist/client.cjs +375 -161
  5. package/dist/client.cjs.map +1 -1
  6. package/dist/client.d.cts +7 -6
  7. package/dist/client.d.ts +7 -6
  8. package/dist/client.js +375 -161
  9. package/dist/client.js.map +1 -1
  10. package/dist/{collection-client-CBup9yOx.d.cts → collection-client-CWAeuzV4.d.cts} +6 -4
  11. package/dist/{collection-client-D3ExJU-7.d.ts → collection-client-hYvVfHIm.d.ts} +6 -4
  12. package/dist/{const-k9gHylYa.d.ts → const-D8LixhAJ.d.cts} +5 -5
  13. package/dist/{const-BXEi1Kix.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 +64 -15
  27. package/dist/errors.cjs.map +1 -1
  28. package/dist/errors.d.cts +13 -4
  29. package/dist/errors.d.ts +13 -4
  30. package/dist/errors.js +64 -15
  31. package/dist/errors.js.map +1 -1
  32. package/dist/{index-BCM9CTL7.d.cts → index-B0Hjh3Ey.d.ts} +72 -10
  33. package/dist/{index-CHGGkcLj.d.ts → index-Bu0kCc6o.d.cts} +72 -10
  34. package/dist/index.cjs +470 -429
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +9 -67
  37. package/dist/index.d.ts +9 -67
  38. package/dist/index.js +470 -429
  39. package/dist/index.js.map +1 -1
  40. package/dist/{payload-types-B6AZQcB7.d.cts → payload-types-BOsckg8B.d.cts} +396 -57
  41. package/dist/{payload-types-B6AZQcB7.d.ts → payload-types-BOsckg8B.d.ts} +396 -57
  42. package/dist/query.cjs +115 -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 +115 -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 +591 -186
  51. package/dist/server.cjs.map +1 -1
  52. package/dist/server.d.cts +8 -7
  53. package/dist/server.d.ts +8 -7
  54. package/dist/server.js +591 -186
  55. package/dist/server.js.map +1 -1
  56. package/dist/storefront-cache.cjs +22 -0
  57. package/dist/storefront-cache.cjs.map +1 -1
  58. package/dist/storefront-cache.js +22 -0
  59. package/dist/storefront-cache.js.map +1 -1
  60. package/dist/{types-ByD2zii1.d.ts → types-5ZlcAFuU.d.ts} +2 -2
  61. package/dist/{types-8us-_C-Q.d.cts → types-B14sEt1z.d.cts} +2 -2
  62. package/dist/{types-CM2je9Kw.d.cts → types-Bj8j7VHU.d.ts} +107 -26
  63. package/dist/{types-DbA5V3mt.d.ts → types-CM5qiR2k.d.cts} +107 -26
  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 +27 -5
package/dist/index.cjs CHANGED
@@ -89,6 +89,7 @@ __export(src_exports, {
89
89
  getImageSrcSet: () => getImageSrcSet,
90
90
  getImageUrl: () => getImageUrl,
91
91
  getProductSelectionImages: () => getProductSelectionImages,
92
+ getSDKErrorReason: () => getSDKErrorReason,
92
93
  getSelectedValueByOptionId: () => getSelectedValueByOptionId,
93
94
  getVariantAvailableForSale: () => getVariantAvailableForSale,
94
95
  getVariantAvailableStock: () => getVariantAvailableStock,
@@ -129,8 +130,6 @@ __export(src_exports, {
129
130
  projectProductToListingShape: () => projectProductToListingShape,
130
131
  resolveFeaturedImagePointer: () => resolveFeaturedImagePointer,
131
132
  resolveProductDisplayMedia: () => resolveProductDisplayMedia,
132
- resolveProductGallery: () => resolveProductGallery,
133
- resolveProductMedia: () => resolveProductMedia,
134
133
  resolveProductSelection: () => resolveProductSelection,
135
134
  resolveProductSelectionFromMatrix: () => resolveProductSelectionFromMatrix,
136
135
  resolveProductSelectionMedia: () => resolveProductSelectionMedia,
@@ -147,6 +146,24 @@ module.exports = __toCommonJS(src_exports);
147
146
  var import_qs_esm = require("qs-esm");
148
147
 
149
148
  // src/core/errors.ts
149
+ var SDK_ERROR_BRAND = /* @__PURE__ */ Symbol.for("@01.software/sdk/SDKError");
150
+ var SDK_ERROR_TYPE_BRAND = /* @__PURE__ */ Symbol.for("@01.software/sdk/SDKError.type");
151
+ function defineSDKErrorBrand(error) {
152
+ Object.defineProperty(error, SDK_ERROR_BRAND, {
153
+ value: true,
154
+ enumerable: false,
155
+ configurable: false,
156
+ writable: false
157
+ });
158
+ }
159
+ function defineSDKErrorType(error, type) {
160
+ Object.defineProperty(error, SDK_ERROR_TYPE_BRAND, {
161
+ value: type,
162
+ enumerable: false,
163
+ configurable: false,
164
+ writable: false
165
+ });
166
+ }
150
167
  var SDKError = class extends Error {
151
168
  constructor(code, message, status, details, userMessage, suggestion, requestId) {
152
169
  super(message);
@@ -157,6 +174,7 @@ var SDKError = class extends Error {
157
174
  this.userMessage = userMessage;
158
175
  this.suggestion = suggestion;
159
176
  this.requestId = requestId;
177
+ defineSDKErrorBrand(this);
160
178
  if (Error.captureStackTrace) {
161
179
  Error.captureStackTrace(this, new.target);
162
180
  }
@@ -177,6 +195,7 @@ var SDKError = class extends Error {
177
195
  ...this.kind !== void 0 && { kind: this.kind },
178
196
  ...this.reason !== void 0 && { reason: this.reason },
179
197
  ...this.rawReason !== void 0 && { rawReason: this.rawReason },
198
+ ...this.apiReason !== void 0 && { apiReason: this.apiReason },
180
199
  ...this.retryable !== void 0 && { retryable: this.retryable },
181
200
  ...this.retryAfter !== void 0 && { retryAfter: this.retryAfter }
182
201
  };
@@ -222,6 +241,7 @@ var COMMERCE_ERROR_CODES = [
222
241
  "payment_session_not_cancelable",
223
242
  "payment_session_conflict",
224
243
  "provider_identity_mismatch",
244
+ "managed_refund_attestation_forbidden",
225
245
  "payment_method_unavailable",
226
246
  "provider_unavailable",
227
247
  "lock_timeout",
@@ -350,8 +370,16 @@ function enhanceCommerceError(error, body, headerRequestId) {
350
370
  });
351
371
  return error;
352
372
  }
373
+ function enhanceNonCommerceError(error, reason) {
374
+ if (typeof reason === "string") Object.assign(error, { apiReason: reason });
375
+ return error;
376
+ }
377
+ function getSDKErrorReason(error) {
378
+ if (error.kind !== "commerce") return error.apiReason;
379
+ return error.reason === "unknown_commerce_error" ? error.rawReason : error.reason;
380
+ }
353
381
  function isCommerceSDKError(error) {
354
- if (!(error instanceof SDKError) || error.kind !== "commerce") return false;
382
+ if (!isSDKError(error) || error.kind !== "commerce") return false;
355
383
  if (typeof error.requestId !== "string" || typeof error.retryable !== "boolean" || error.retryAfter !== void 0 && (!Number.isSafeInteger(error.retryAfter) || error.retryAfter < 0) || typeof error.reason !== "string") {
356
384
  return false;
357
385
  }
@@ -361,12 +389,14 @@ var NetworkError = class extends SDKError {
361
389
  constructor(message, status, details, userMessage, suggestion) {
362
390
  super("NETWORK_ERROR", message, status, details, userMessage, suggestion);
363
391
  this.name = "NetworkError";
392
+ defineSDKErrorType(this, "NetworkError");
364
393
  }
365
394
  };
366
395
  var ValidationError = class extends SDKError {
367
396
  constructor(message, details, userMessage, suggestion, status = 400) {
368
397
  super("VALIDATION_ERROR", message, status, details, userMessage, suggestion);
369
398
  this.name = "ValidationError";
399
+ defineSDKErrorType(this, "ValidationError");
370
400
  }
371
401
  };
372
402
  var ApiError = class extends SDKError {
@@ -381,24 +411,28 @@ var ApiError = class extends SDKError {
381
411
  requestId
382
412
  );
383
413
  this.name = "ApiError";
414
+ defineSDKErrorType(this, "ApiError");
384
415
  }
385
416
  };
386
417
  var ConfigError = class extends SDKError {
387
418
  constructor(message, details, userMessage, suggestion) {
388
419
  super("CONFIG_ERROR", message, void 0, details, userMessage, suggestion);
389
420
  this.name = "ConfigError";
421
+ defineSDKErrorType(this, "ConfigError");
390
422
  }
391
423
  };
392
424
  var TimeoutError = class extends SDKError {
393
425
  constructor(message = "Request timed out.", details, userMessage, suggestion) {
394
426
  super("TIMEOUT_ERROR", message, 408, details, userMessage, suggestion);
395
427
  this.name = "TimeoutError";
428
+ defineSDKErrorType(this, "TimeoutError");
396
429
  }
397
430
  };
398
431
  var GoneError = class extends SDKError {
399
432
  constructor(message = "The requested resource is no longer available.", details, userMessage, suggestion) {
400
433
  super("GONE_ERROR", message, 410, details, userMessage, suggestion);
401
434
  this.name = "GoneError";
435
+ defineSDKErrorType(this, "GoneError");
402
436
  }
403
437
  };
404
438
  var ServiceUnavailableError = class extends SDKError {
@@ -413,6 +447,7 @@ var ServiceUnavailableError = class extends SDKError {
413
447
  );
414
448
  this.name = "ServiceUnavailableError";
415
449
  this.retryAfter = retryAfter;
450
+ defineSDKErrorType(this, "ServiceUnavailableError");
416
451
  }
417
452
  };
418
453
  var UsageLimitError = class extends SDKError {
@@ -420,6 +455,7 @@ var UsageLimitError = class extends SDKError {
420
455
  super("USAGE_LIMIT_ERROR", message, 429, details, userMessage, suggestion);
421
456
  this.name = "UsageLimitError";
422
457
  this.usage = usage;
458
+ defineSDKErrorType(this, "UsageLimitError");
423
459
  }
424
460
  toJSON() {
425
461
  return {
@@ -440,6 +476,7 @@ var AuthError = class extends SDKError {
440
476
  requestId
441
477
  );
442
478
  this.name = "AuthError";
479
+ defineSDKErrorType(this, "AuthError");
443
480
  }
444
481
  };
445
482
  var PermissionError = class extends SDKError {
@@ -454,6 +491,7 @@ var PermissionError = class extends SDKError {
454
491
  requestId
455
492
  );
456
493
  this.name = "PermissionError";
494
+ defineSDKErrorType(this, "PermissionError");
457
495
  }
458
496
  };
459
497
  var NotFoundError = class extends SDKError {
@@ -468,12 +506,14 @@ var NotFoundError = class extends SDKError {
468
506
  requestId
469
507
  );
470
508
  this.name = "NotFoundError";
509
+ defineSDKErrorType(this, "NotFoundError");
471
510
  }
472
511
  };
473
512
  var ConflictError = class extends SDKError {
474
513
  constructor(message, details, userMessage, suggestion, requestId) {
475
514
  super("conflict", message, 409, details, userMessage, suggestion, requestId);
476
515
  this.name = "ConflictError";
516
+ defineSDKErrorType(this, "ConflictError");
477
517
  }
478
518
  };
479
519
  var RateLimitError = class extends SDKError {
@@ -489,52 +529,63 @@ var RateLimitError = class extends SDKError {
489
529
  );
490
530
  this.name = "RateLimitError";
491
531
  this.retryAfter = retryAfter;
532
+ defineSDKErrorType(this, "RateLimitError");
492
533
  }
493
534
  };
535
+ function hasBrandedSDKErrorShape(error) {
536
+ if (error === null || typeof error !== "object") return false;
537
+ const candidate = error;
538
+ return candidate[SDK_ERROR_BRAND] === true && typeof candidate.name === "string" && typeof candidate.code === "string" && typeof candidate.message === "string" && (candidate.status === void 0 || typeof candidate.status === "number") && (candidate.userMessage === void 0 || typeof candidate.userMessage === "string") && (candidate.suggestion === void 0 || typeof candidate.suggestion === "string") && (candidate.requestId === void 0 || typeof candidate.requestId === "string") && (candidate.kind === void 0 || candidate.kind === "commerce") && (candidate.reason === void 0 || typeof candidate.reason === "string") && (candidate.rawReason === void 0 || typeof candidate.rawReason === "string") && (candidate.apiReason === void 0 || typeof candidate.apiReason === "string") && (candidate.retryable === void 0 || typeof candidate.retryable === "boolean") && (candidate.retryAfter === void 0 || typeof candidate.retryAfter === "number") && typeof candidate.getUserMessage === "function" && typeof candidate.toJSON === "function";
539
+ }
540
+ function hasSDKErrorType(error, type) {
541
+ return hasBrandedSDKErrorShape(error) && error[SDK_ERROR_TYPE_BRAND] === type;
542
+ }
494
543
  function isSDKError(error) {
495
- return error instanceof SDKError;
544
+ return error instanceof SDKError || hasBrandedSDKErrorShape(error);
496
545
  }
497
546
  function isNetworkError(error) {
498
- return error instanceof NetworkError;
547
+ return error instanceof NetworkError || hasSDKErrorType(error, "NetworkError");
499
548
  }
500
549
  function isValidationError(error) {
501
- if (error instanceof ValidationError) return true;
550
+ if (error instanceof ValidationError || hasSDKErrorType(error, "ValidationError")) {
551
+ return true;
552
+ }
502
553
  if (error == null || typeof error !== "object") return false;
503
554
  const candidate = error;
504
555
  return candidate.name === "ValidationError" && candidate.code === "VALIDATION_ERROR" && typeof candidate.message === "string" && typeof candidate.getUserMessage === "function" && typeof candidate.toJSON === "function";
505
556
  }
506
557
  function isApiError(error) {
507
- return error instanceof ApiError;
558
+ return error instanceof ApiError || hasSDKErrorType(error, "ApiError");
508
559
  }
509
560
  function isConfigError(error) {
510
- return error instanceof ConfigError;
561
+ return error instanceof ConfigError || hasSDKErrorType(error, "ConfigError");
511
562
  }
512
563
  function isTimeoutError(error) {
513
- return error instanceof TimeoutError;
564
+ return error instanceof TimeoutError || hasSDKErrorType(error, "TimeoutError");
514
565
  }
515
566
  function isGoneError(error) {
516
- return error instanceof GoneError;
567
+ return error instanceof GoneError || hasSDKErrorType(error, "GoneError");
517
568
  }
518
569
  function isServiceUnavailableError(error) {
519
- return error instanceof ServiceUnavailableError;
570
+ return error instanceof ServiceUnavailableError || hasSDKErrorType(error, "ServiceUnavailableError");
520
571
  }
521
572
  function isUsageLimitError(error) {
522
- return error instanceof UsageLimitError;
573
+ return error instanceof UsageLimitError || hasSDKErrorType(error, "UsageLimitError");
523
574
  }
524
575
  function isAuthError(error) {
525
- return error instanceof AuthError;
576
+ return error instanceof AuthError || hasSDKErrorType(error, "AuthError");
526
577
  }
527
578
  function isPermissionError(error) {
528
- return error instanceof PermissionError;
579
+ return error instanceof PermissionError || hasSDKErrorType(error, "PermissionError");
529
580
  }
530
581
  function isNotFoundError(error) {
531
- return error instanceof NotFoundError;
582
+ return error instanceof NotFoundError || hasSDKErrorType(error, "NotFoundError");
532
583
  }
533
584
  function isConflictError(error) {
534
- return error instanceof ConflictError;
585
+ return error instanceof ConflictError || hasSDKErrorType(error, "ConflictError");
535
586
  }
536
587
  function isRateLimitError(error) {
537
- return error instanceof RateLimitError;
588
+ return error instanceof RateLimitError || hasSDKErrorType(error, "RateLimitError");
538
589
  }
539
590
  var createNetworkError = (message, status, details, userMessage, suggestion) => new NetworkError(message, status, details, userMessage, suggestion);
540
591
  var createValidationError = (message, details, userMessage, suggestion, status) => new ValidationError(message, details, userMessage, suggestion, status);
@@ -733,11 +784,11 @@ function parseRetryAfter(response) {
733
784
  permitsAutomaticRetry: seconds <= MAX_AUTOMATIC_RETRY_AFTER_SECONDS
734
785
  };
735
786
  }
736
- function mapResponseToError(status, parsed, details, requestId, retryAfter, errorFamily) {
787
+ function mapResponseToError(status, parsed, details, requestId, retryAfter, canonicalCommerceError) {
737
788
  const errorDetails = {
738
789
  ...details,
739
790
  ...parsed.errors && { errors: parsed.errors },
740
- ...errorFamily !== "commerce" && parsed.body && { body: parsed.body }
791
+ ...!canonicalCommerceError && parsed.body && { body: parsed.body }
741
792
  };
742
793
  const suggestion = getParsedErrorSuggestion(status, parsed);
743
794
  const finalize = (error) => {
@@ -745,7 +796,7 @@ function mapResponseToError(status, parsed, details, requestId, retryAfter, erro
745
796
  if (retryAfter !== void 0) {
746
797
  Object.assign(withRequestId, { retryAfter });
747
798
  }
748
- return errorFamily === "commerce" ? enhanceCommerceError(withRequestId, parsed.body, requestId) : withRequestId;
799
+ return canonicalCommerceError ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(withRequestId, parsed.reason);
749
800
  };
750
801
  if (status === 400 || status === 422) {
751
802
  return finalize(
@@ -851,6 +902,7 @@ async function httpFetch(url, options) {
851
902
  retry,
852
903
  onUnauthorized,
853
904
  errorFamily,
905
+ typedCommerceErrorReasons,
854
906
  ...requestInit
855
907
  } = options || {};
856
908
  const baseUrl = resolveApiUrl(apiUrl);
@@ -904,7 +956,8 @@ async function httpFetch(url, options) {
904
956
  });
905
957
  if (!response.ok) {
906
958
  const parsed = await parseErrorBody(response);
907
- const commerceEnvelope = errorFamily === "commerce" ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
959
+ const canonicalCommerceError = errorFamily === "commerce" || typeof parsed.reason === "string" && typedCommerceErrorReasons?.includes(parsed.reason) === true;
960
+ const commerceEnvelope = canonicalCommerceError ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
908
961
  if (isUsageLimitExceededResponse(response)) {
909
962
  const limit = parseInt(
910
963
  response.headers.get("X-Usage-Limit") || "0",
@@ -932,7 +985,7 @@ async function httpFetch(url, options) {
932
985
  ),
933
986
  requestId
934
987
  );
935
- throw errorFamily === "commerce" ? enhanceCommerceError(usageError, parsed.body, requestId) : usageError;
988
+ throw canonicalCommerceError ? enhanceCommerceError(usageError, parsed.body, requestId) : enhanceNonCommerceError(usageError, parsed.reason);
936
989
  }
937
990
  if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && (commerceEnvelope?.reason ?? parsed.reason) === "token_expired") {
938
991
  hasRetried401 = true;
@@ -957,7 +1010,7 @@ async function httpFetch(url, options) {
957
1010
  details,
958
1011
  requestId,
959
1012
  retryAfter.seconds,
960
- errorFamily
1013
+ canonicalCommerceError
961
1014
  );
962
1015
  const method2 = (requestInit.method || "GET").toUpperCase();
963
1016
  const isTerminal = error instanceof RateLimitError || error instanceof UsageLimitError;
@@ -1135,15 +1188,15 @@ var HttpClient = class {
1135
1188
  throw err;
1136
1189
  }
1137
1190
  }
1138
- buildUrl(endpoint2, options) {
1139
- if (!options) return endpoint2;
1191
+ buildUrl(endpoint, options) {
1192
+ if (!options) return endpoint;
1140
1193
  const { fallbackLocale, ...rest } = options;
1141
1194
  const queryOptions = fallbackLocale === void 0 ? rest : {
1142
1195
  ...rest,
1143
1196
  "fallback-locale": fallbackLocale === false ? "none" : fallbackLocale
1144
1197
  };
1145
1198
  const queryString = (0, import_qs_esm.stringify)(queryOptions, { addQueryPrefix: true });
1146
- return queryString ? `${endpoint2}${queryString}` : endpoint2;
1199
+ return queryString ? `${endpoint}${queryString}` : endpoint;
1147
1200
  }
1148
1201
  assertJsonResponse(response) {
1149
1202
  const contentType = response.headers.get("content-type");
@@ -1292,39 +1345,39 @@ var ReadOnlyCollectionClient = class extends HttpClient {
1292
1345
  from(collection) {
1293
1346
  return new ReadOnlyCollectionQueryBuilder(this, collection);
1294
1347
  }
1295
- async requestFind(endpoint2, options) {
1296
- const url = this.buildUrl(endpoint2, options);
1348
+ async requestFind(endpoint, options) {
1349
+ const url = this.buildUrl(endpoint, options);
1297
1350
  const response = await this.fetchWithTracking(url, {
1298
1351
  ...this.defaultOptions,
1299
1352
  method: "GET"
1300
1353
  });
1301
1354
  return this.parseFindResponse(response);
1302
1355
  }
1303
- async requestFindEndpoint(endpoint2, data) {
1304
- const response = await this.fetchWithTracking(endpoint2, {
1356
+ async requestFindEndpoint(endpoint, data) {
1357
+ const response = await this.fetchWithTracking(endpoint, {
1305
1358
  ...this.defaultOptions,
1306
1359
  method: "POST",
1307
1360
  body: data ? JSON.stringify(data) : void 0
1308
1361
  });
1309
1362
  return this.parseFindResponse(response);
1310
1363
  }
1311
- async requestFindEndpointGet(endpoint2) {
1312
- const response = await this.fetchWithTracking(endpoint2, {
1364
+ async requestFindEndpointGet(endpoint) {
1365
+ const response = await this.fetchWithTracking(endpoint, {
1313
1366
  ...this.defaultOptions,
1314
1367
  method: "GET"
1315
1368
  });
1316
1369
  return this.parseFindResponse(response);
1317
1370
  }
1318
- async requestFindById(endpoint2, options) {
1319
- const url = this.buildUrl(endpoint2, options);
1371
+ async requestFindById(endpoint, options) {
1372
+ const url = this.buildUrl(endpoint, options);
1320
1373
  const response = await this.fetchWithTracking(url, {
1321
1374
  ...this.defaultOptions,
1322
1375
  method: "GET"
1323
1376
  });
1324
1377
  return this.parseDocumentResponse(response);
1325
1378
  }
1326
- async requestCount(endpoint2, options) {
1327
- const url = this.buildUrl(endpoint2, options);
1379
+ async requestCount(endpoint, options) {
1380
+ const url = this.buildUrl(endpoint, options);
1328
1381
  const response = await this.fetchWithTracking(url, {
1329
1382
  ...this.defaultOptions,
1330
1383
  method: "GET"
@@ -1334,7 +1387,7 @@ var ReadOnlyCollectionClient = class extends HttpClient {
1334
1387
  };
1335
1388
 
1336
1389
  // src/core/api/parse-response.ts
1337
- async function parseApiResponse(response, endpoint2, options = {}) {
1390
+ async function parseApiResponse(response, endpoint, options = {}) {
1338
1391
  if (response.status === 204 || response.headers.get("content-length") === "0") {
1339
1392
  return void 0;
1340
1393
  }
@@ -1343,7 +1396,7 @@ async function parseApiResponse(response, endpoint2, options = {}) {
1343
1396
  parsed = await response.json();
1344
1397
  } catch {
1345
1398
  throw createApiError(
1346
- `Invalid JSON response from ${endpoint2}`,
1399
+ `Invalid JSON response from ${endpoint}`,
1347
1400
  response.status,
1348
1401
  void 0,
1349
1402
  "Server returned an invalid response.",
@@ -1386,13 +1439,14 @@ async function parseApiResponse(response, endpoint2, options = {}) {
1386
1439
  }
1387
1440
  const withRequestId = attachRequestId(error, requestId);
1388
1441
  if (retryAfter !== void 0) Object.assign(withRequestId, { retryAfter });
1389
- throw options.errorFamily === "commerce" ? enhanceCommerceError(withRequestId, data, requestId) : withRequestId;
1442
+ throw options.errorFamily === "commerce" ? enhanceCommerceError(withRequestId, data, requestId) : enhanceNonCommerceError(withRequestId, reason);
1390
1443
  }
1391
1444
  return data;
1392
1445
  }
1393
1446
 
1394
1447
  // ../../internal/http-contracts/src/index.ts
1395
1448
  var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
1449
+ var PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE = "application/vnd.01software.portone-action-capabilities.v1+json";
1396
1450
  var operation = (collection, method, path, errorFamily) => Object.freeze({
1397
1451
  [operationBrand]: true,
1398
1452
  collection,
@@ -1401,6 +1455,10 @@ var operation = (collection, method, path, errorFamily) => Object.freeze({
1401
1455
  ...errorFamily && { errorFamily }
1402
1456
  });
1403
1457
  var strictCommerceOperation = (collection, method, path) => operation(collection, method, path, "commerce");
1458
+ var selectiveCommerceOperation = (collection, method, path, typedCommerceErrorReasons) => Object.freeze({
1459
+ ...operation(collection, method, path),
1460
+ typedCommerceErrorReasons: Object.freeze([...typedCommerceErrorReasons])
1461
+ });
1404
1462
  var COMMERCE_ENDPOINT_OPERATIONS = {
1405
1463
  products: {
1406
1464
  detail: operation("products", "get", "/detail"),
@@ -1432,7 +1490,12 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1432
1490
  confirmPayment: operation("orders", "post", "/confirm-payment"),
1433
1491
  byPayment: operation("orders", "get", "/by-payment"),
1434
1492
  cancel: operation("orders", "post", "/cancel"),
1435
- resolveCancelRefund: operation("orders", "post", "/resolve-cancel-refund"),
1493
+ resolveCancelRefund: selectiveCommerceOperation(
1494
+ "orders",
1495
+ "post",
1496
+ "/resolve-cancel-refund",
1497
+ ["managed_refund_attestation_forbidden"]
1498
+ ),
1436
1499
  checkout: strictCommerceOperation("orders", "post", "/checkout"),
1437
1500
  createFulfillment: operation("orders", "post", "/create-fulfillment"),
1438
1501
  updateFulfillment: operation("orders", "post", "/update-fulfillment")
@@ -1503,6 +1566,16 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1503
1566
  "payment-sessions",
1504
1567
  "post",
1505
1568
  "/server/confirm"
1569
+ ),
1570
+ findPortOne: strictCommerceOperation(
1571
+ "payment-sessions",
1572
+ "post",
1573
+ "/server/portone/find"
1574
+ ),
1575
+ reconcilePortOne: strictCommerceOperation(
1576
+ "payment-sessions",
1577
+ "post",
1578
+ "/server/portone/reconcile"
1506
1579
  )
1507
1580
  },
1508
1581
  custom: {
@@ -1522,12 +1595,26 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
1522
1595
  validate: operation("discounts", "post", "/validate")
1523
1596
  }
1524
1597
  };
1598
+ var portOneStandardActionCapabilityOperations = /* @__PURE__ */ new Set([
1599
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.create,
1600
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.retrieve,
1601
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.create,
1602
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.retrieve
1603
+ ]);
1525
1604
  var MEMBERSHIP_ENDPOINT_OPERATIONS = {
1526
1605
  subscribe: operation(null, "post", "/memberships/subscribe"),
1527
1606
  cancel: operation(null, "post", "/memberships/:id/cancel"),
1528
1607
  me: operation(null, "get", "/memberships/me")
1529
1608
  };
1609
+ var EMBEDDED_ADMIN_ENDPOINT_OPERATIONS = {
1610
+ show: operation("tenants", "get", "/embedded-admin-app"),
1611
+ configure: operation("tenants", "patch", "/embedded-admin-app"),
1612
+ disable: operation("tenants", "delete", "/embedded-admin-app")
1613
+ };
1530
1614
  var EVENTS_ENDPOINT_OPERATIONS = {
1615
+ events: {
1616
+ convertSchedule: operation("events", "post", "/:id/schedule")
1617
+ },
1531
1618
  occurrences: {
1532
1619
  range: operation("event-occurrences", "get", "/range"),
1533
1620
  admissionAvailability: operation(
@@ -1568,46 +1655,51 @@ function resolveOperationMethod(descriptor) {
1568
1655
  }
1569
1656
 
1570
1657
  // src/core/api/endpoints.ts
1571
- var endpoint = (method, path) => ({ method, path });
1572
1658
  var sharedEndpoint = (descriptor) => descriptor;
1573
- function resolveOperationMethod2(descriptor) {
1574
- return "collection" in descriptor ? resolveOperationMethod(descriptor) : descriptor.method;
1575
- }
1576
1659
  function resolveOperationErrorFamily(descriptor) {
1577
- return "collection" in descriptor ? descriptor.errorFamily : void 0;
1578
- }
1579
- function resolveOperationPath2(descriptor, options) {
1580
- if ("collection" in descriptor) {
1581
- return resolveOperationPath(descriptor, options);
1582
- }
1583
- const query = options?.query?.toString().replace(/^\?/, "");
1584
- return query ? `${descriptor.path}?${query}` : descriptor.path;
1660
+ return descriptor.errorFamily;
1585
1661
  }
1586
1662
  var COMMERCE_ENDPOINTS = {
1587
1663
  products: {
1588
- detail: endpoint("GET", "/api/products/detail"),
1589
- detailCatalog: endpoint("GET", "/api/products/detail/catalog"),
1590
- listingGroups: endpoint("GET", "/api/products/listing-groups"),
1591
- listingGroupsCatalog: endpoint(
1592
- "GET",
1593
- "/api/products/listing-groups/catalog"
1664
+ detail: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.detail),
1665
+ detailCatalog: sharedEndpoint(
1666
+ COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog
1667
+ ),
1668
+ listingGroups: sharedEndpoint(
1669
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroups
1670
+ ),
1671
+ listingGroupsCatalog: sharedEndpoint(
1672
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog
1673
+ ),
1674
+ // The manifest keeps the GET read and the POST body-query apart; this
1675
+ // semantic name has always resolved to the GET one.
1676
+ listingGroupsQuery: sharedEndpoint(
1677
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryGet
1678
+ ),
1679
+ listingGroupsQueryCatalog: sharedEndpoint(
1680
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryCatalog
1681
+ ),
1682
+ stockCheck: sharedEndpoint(
1683
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockCheck
1594
1684
  ),
1595
- listingGroupsQuery: endpoint("GET", "/api/products/listing-groups/query"),
1596
- listingGroupsQueryCatalog: endpoint(
1597
- "GET",
1598
- "/api/products/listing-groups/query/catalog"
1685
+ stockSnapshot: sharedEndpoint(
1686
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockSnapshot
1599
1687
  ),
1600
- stockCheck: endpoint("POST", "/api/products/stock-check"),
1601
- stockSnapshot: endpoint("GET", "/api/products/stock"),
1602
- upsert: endpoint("POST", "/api/products/upsert")
1688
+ upsert: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.upsert)
1603
1689
  },
1604
1690
  orders: {
1605
- update: endpoint("POST", "/api/orders/update"),
1606
- byPayment: endpoint("GET", "/api/orders/by-payment"),
1607
- cancel: endpoint("POST", "/api/orders/cancel"),
1608
- resolveCancelRefund: endpoint("POST", "/api/orders/resolve-cancel-refund"),
1609
- createFulfillment: endpoint("POST", "/api/orders/create-fulfillment"),
1610
- updateFulfillment: endpoint("POST", "/api/orders/update-fulfillment")
1691
+ update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.update),
1692
+ byPayment: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.byPayment),
1693
+ cancel: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.cancel),
1694
+ resolveCancelRefund: sharedEndpoint(
1695
+ COMMERCE_ENDPOINT_OPERATIONS.orders.resolveCancelRefund
1696
+ ),
1697
+ createFulfillment: sharedEndpoint(
1698
+ COMMERCE_ENDPOINT_OPERATIONS.orders.createFulfillment
1699
+ ),
1700
+ updateFulfillment: sharedEndpoint(
1701
+ COMMERCE_ENDPOINT_OPERATIONS.orders.updateFulfillment
1702
+ )
1611
1703
  },
1612
1704
  checkouts: {
1613
1705
  create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.checkout),
@@ -1619,18 +1711,21 @@ var COMMERCE_ENDPOINTS = {
1619
1711
  }
1620
1712
  },
1621
1713
  returns: {
1622
- create: endpoint("POST", "/api/returns/create"),
1623
- update: endpoint("POST", "/api/returns/update"),
1624
- returnRefund: endpoint("POST", "/api/returns/return-refund")
1714
+ create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.create),
1715
+ update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.update),
1716
+ returnRefund: sharedEndpoint(
1717
+ COMMERCE_ENDPOINT_OPERATIONS.returns.returnRefund
1718
+ )
1625
1719
  },
1626
1720
  fulfillmentOrders: {
1627
- prepare: endpoint(
1628
- "POST",
1629
- "/api/fulfillment-orders/prepare-fulfillment-order"
1721
+ prepare: sharedEndpoint(
1722
+ COMMERCE_ENDPOINT_OPERATIONS.fulfillmentOrders.prepare
1630
1723
  )
1631
1724
  },
1632
1725
  fulfillments: {
1633
- bulkImport: endpoint("POST", "/api/fulfillments/bulk-import")
1726
+ bulkImport: sharedEndpoint(
1727
+ COMMERCE_ENDPOINT_OPERATIONS.fulfillments.bulkImport
1728
+ )
1634
1729
  },
1635
1730
  carts: {
1636
1731
  create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.create),
@@ -1695,42 +1790,21 @@ var COMMERCE_ENDPOINTS = {
1695
1790
  ),
1696
1791
  confirm: sharedEndpoint(
1697
1792
  COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.confirm
1793
+ ),
1794
+ findPortOne: sharedEndpoint(
1795
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.findPortOne
1796
+ ),
1797
+ reconcilePortOne: sharedEndpoint(
1798
+ COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.reconcilePortOne
1698
1799
  )
1699
1800
  }
1700
1801
  },
1701
1802
  shippingPolicies: {
1702
- calculate: endpoint("POST", "/api/shipping-policies/calculate")
1803
+ calculate: sharedEndpoint(
1804
+ COMMERCE_ENDPOINT_OPERATIONS.shippingPolicies.calculate
1805
+ )
1703
1806
  }
1704
1807
  };
1705
- function isCommerceEndpointDescriptor(value) {
1706
- if (!value || typeof value !== "object") return false;
1707
- const candidate = value;
1708
- return typeof candidate.method === "string" && typeof candidate.path === "string";
1709
- }
1710
- function flattenEndpointPaths(value) {
1711
- if (isCommerceEndpointDescriptor(value)) return [resolveOperationPath2(value)];
1712
- if (!value || typeof value !== "object") return [];
1713
- return Object.values(value).flatMap((entry) => flattenEndpointPaths(entry));
1714
- }
1715
- function flattenEndpointDescriptors(value) {
1716
- if (isCommerceEndpointDescriptor(value)) return [value];
1717
- if (!value || typeof value !== "object") return [];
1718
- return Object.values(value).flatMap(
1719
- (entry) => flattenEndpointDescriptors(entry)
1720
- );
1721
- }
1722
- var COMMERCE_ENDPOINT_PATHS = flattenEndpointPaths(COMMERCE_ENDPOINTS);
1723
- var COMMERCE_ENDPOINT_DESCRIPTORS = flattenEndpointDescriptors(COMMERCE_ENDPOINTS);
1724
- var MEMBERSHIP_ENDPOINTS = {
1725
- subscribe: "/api/memberships/subscribe",
1726
- cancel: (id) => `/api/memberships/${id}/cancel`,
1727
- me: "/api/memberships/me"
1728
- };
1729
- var MEMBERSHIP_ENDPOINT_PATHS = [
1730
- MEMBERSHIP_ENDPOINTS.subscribe,
1731
- MEMBERSHIP_ENDPOINTS.cancel(":id"),
1732
- MEMBERSHIP_ENDPOINTS.me
1733
- ];
1734
1808
 
1735
1809
  // src/core/api/customer-scoped-api.ts
1736
1810
  var CustomerScopedTransport = class {
@@ -1751,10 +1825,10 @@ var CustomerScopedTransport = class {
1751
1825
  this.onUnauthorized = options.onUnauthorized;
1752
1826
  this.onRequestId = options.onRequestId;
1753
1827
  }
1754
- async request(endpoint2, options) {
1828
+ async request(endpoint, options) {
1755
1829
  const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
1756
1830
  try {
1757
- const response = await httpFetch(endpoint2, {
1831
+ const response = await httpFetch(endpoint, {
1758
1832
  method: options.method,
1759
1833
  apiUrl: this.apiUrl,
1760
1834
  publishableKey: this.publishableKey,
@@ -1768,7 +1842,7 @@ var CustomerScopedTransport = class {
1768
1842
  ...options.errorFamily && { errorFamily: options.errorFamily }
1769
1843
  });
1770
1844
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
1771
- return parseApiResponse(response, endpoint2, {
1845
+ return parseApiResponse(response, endpoint, {
1772
1846
  errorFamily: options.errorFamily
1773
1847
  });
1774
1848
  } catch (err) {
@@ -1782,12 +1856,12 @@ var CustomerScopedApi = class {
1782
1856
  constructor(apiName, options) {
1783
1857
  this.transport = new CustomerScopedTransport(apiName, options);
1784
1858
  }
1785
- requestEndpoint(endpoint2, body, options) {
1786
- return this.transport.request(resolveOperationPath2(endpoint2, options), {
1787
- method: resolveOperationMethod2(endpoint2),
1859
+ requestEndpoint(endpoint, body, options) {
1860
+ return this.transport.request(resolveOperationPath(endpoint, options), {
1861
+ method: resolveOperationMethod(endpoint),
1788
1862
  body,
1789
1863
  headers: options?.headers,
1790
- errorFamily: resolveOperationErrorFamily(endpoint2)
1864
+ errorFamily: resolveOperationErrorFamily(endpoint)
1791
1865
  });
1792
1866
  }
1793
1867
  };
@@ -1795,8 +1869,8 @@ var RawCustomerScopedApi = class {
1795
1869
  constructor(apiName, options) {
1796
1870
  this.transport = new CustomerScopedTransport(apiName, options);
1797
1871
  }
1798
- request(endpoint2, options) {
1799
- return this.transport.request(endpoint2, options);
1872
+ request(endpoint, options) {
1873
+ return this.transport.request(endpoint, options);
1800
1874
  }
1801
1875
  };
1802
1876
 
@@ -1810,13 +1884,7 @@ function unwrapPayloadDoc(value) {
1810
1884
  return value;
1811
1885
  }
1812
1886
  function hasCanonicalNotFoundReason(error) {
1813
- const details = error.details;
1814
- if (typeof details !== "object" || details === null) return false;
1815
- if ("reason" in details && details.reason === "not_found") return true;
1816
- if (!("body" in details) || typeof details.body !== "object" || details.body === null) {
1817
- return false;
1818
- }
1819
- return "reason" in details.body && details.body.reason === "not_found";
1887
+ return getSDKErrorReason(error) === "not_found";
1820
1888
  }
1821
1889
  var CommunityClient = class extends RawCustomerScopedApi {
1822
1890
  constructor(options) {
@@ -1877,11 +1945,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
1877
1945
  if (params.page !== void 0) urlParams.set("page", String(params.page));
1878
1946
  return `/api/comments/public?${urlParams.toString()}`;
1879
1947
  }
1880
- async execute(endpoint2, method, body) {
1881
- return this.request(endpoint2, { method, body });
1948
+ async execute(endpoint, method, body) {
1949
+ return this.request(endpoint, { method, body });
1882
1950
  }
1883
- async executeDoc(endpoint2, method, body) {
1884
- const response = await this.execute(endpoint2, method, body);
1951
+ async executeDoc(endpoint, method, body) {
1952
+ const response = await this.execute(endpoint, method, body);
1885
1953
  return unwrapPayloadDoc(response);
1886
1954
  }
1887
1955
  createPost(params) {
@@ -2147,8 +2215,8 @@ var CommunityClient = class extends RawCustomerScopedApi {
2147
2215
 
2148
2216
  // src/core/content/content-client.ts
2149
2217
  var PublicContentApi = class extends RawCustomerScopedApi {
2150
- get(endpoint2) {
2151
- return this.request(endpoint2, { method: "GET" });
2218
+ get(endpoint) {
2219
+ return this.request(endpoint, { method: "GET" });
2152
2220
  }
2153
2221
  };
2154
2222
  function appendCommonParams(search, options, defaultSort) {
@@ -2329,6 +2397,9 @@ function nullableString(value, resource, path) {
2329
2397
  fail(resource, path, "string or null");
2330
2398
  }
2331
2399
  }
2400
+ function nullableNonEmptyString(value, resource, path) {
2401
+ if (value !== null) string(value, resource, path);
2402
+ }
2332
2403
  function cartLineQuantity(value, resource, path) {
2333
2404
  const quantity = positiveInteger(value, resource, path);
2334
2405
  if (quantity > MAX_CART_LINE_QUANTITY) {
@@ -2838,8 +2909,8 @@ function validatePublicOrderItem(value, resource, path) {
2838
2909
  validateReference(item.variant, resource, `${path}.variant`);
2839
2910
  }
2840
2911
  string(item.productTitle, resource, `${path}.productTitle`);
2841
- nullableString(item.variantTitle, resource, `${path}.variantTitle`);
2842
- nullableString(item.sku, resource, `${path}.sku`);
2912
+ nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
2913
+ nullableNonEmptyString(item.sku, resource, `${path}.sku`);
2843
2914
  validateAdmissions(item.admissions, resource, `${path}.admissions`);
2844
2915
  const quantity = positiveInteger(item.quantity, resource, `${path}.quantity`);
2845
2916
  const unitPrice = safeMinor(
@@ -3090,8 +3161,8 @@ function validateCheckoutItem(value, resource, path) {
3090
3161
  validateReference(item.product, resource, `${path}.product`);
3091
3162
  validateReference(item.variant, resource, `${path}.variant`);
3092
3163
  string(item.productTitle, resource, `${path}.productTitle`);
3093
- nullableString(item.variantTitle, resource, `${path}.variantTitle`);
3094
- nullableString(item.sku, resource, `${path}.sku`);
3164
+ nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
3165
+ nullableNonEmptyString(item.sku, resource, `${path}.sku`);
3095
3166
  validateAdmissions(item.admissions, resource, `${path}.admissions`);
3096
3167
  cartLineQuantity(item.quantity, resource, `${path}.quantity`);
3097
3168
  const unitPrice = safeMinor(
@@ -3422,9 +3493,96 @@ function validateRequiredReconciliation(value, allowed, resource, path) {
3422
3493
  function validateNextAction(value, provider, resource, path) {
3423
3494
  const action = record(value, resource, path);
3424
3495
  if (provider === "portone") {
3496
+ if (action.type === "portone_sdk") {
3497
+ const hasCancelable = "cancelable" in action;
3498
+ const hasRetryPolicy = "retryPolicy" in action;
3499
+ if (hasCancelable !== hasRetryPolicy) {
3500
+ fail(
3501
+ resource,
3502
+ path,
3503
+ "exact released action or exact negotiated capability action"
3504
+ );
3505
+ }
3506
+ exact(
3507
+ action,
3508
+ [
3509
+ "type",
3510
+ "version",
3511
+ ...hasCancelable ? ["cancelable", "retryPolicy"] : [],
3512
+ "storeId",
3513
+ "channelKey",
3514
+ "paymentId",
3515
+ "orderName",
3516
+ "totalAmount",
3517
+ "currency",
3518
+ "payMethod",
3519
+ "redirectUrl"
3520
+ ],
3521
+ [],
3522
+ resource,
3523
+ path
3524
+ );
3525
+ if (action.version !== "v2") fail(resource, `${path}.version`, "v2");
3526
+ if (hasCancelable && action.cancelable !== false)
3527
+ fail(resource, `${path}.cancelable`, "false");
3528
+ if (hasRetryPolicy && action.retryPolicy !== "same_action_only") {
3529
+ fail(resource, `${path}.retryPolicy`, "same_action_only");
3530
+ }
3531
+ for (const key of ["storeId", "channelKey"]) {
3532
+ boundedString(action[key], 255, resource, `${path}.${key}`);
3533
+ }
3534
+ const paymentId = boundedString(
3535
+ action.paymentId,
3536
+ 40,
3537
+ resource,
3538
+ `${path}.paymentId`
3539
+ );
3540
+ if (!/^[A-Za-z0-9]{6,40}$/.test(paymentId)) {
3541
+ fail(
3542
+ resource,
3543
+ `${path}.paymentId`,
3544
+ "6-40 ASCII alphanumeric characters"
3545
+ );
3546
+ }
3547
+ boundedString(
3548
+ action.orderName,
3549
+ MAX_COMMERCE_SHORT_TEXT_LENGTH,
3550
+ resource,
3551
+ `${path}.orderName`
3552
+ );
3553
+ positiveInteger(action.totalAmount, resource, `${path}.totalAmount`);
3554
+ if (action.currency !== "CURRENCY_KRW") {
3555
+ fail(resource, `${path}.currency`, "CURRENCY_KRW");
3556
+ }
3557
+ if (action.payMethod !== "CARD")
3558
+ fail(resource, `${path}.payMethod`, "CARD");
3559
+ const redirectUrl = boundedString(
3560
+ action.redirectUrl,
3561
+ 2048,
3562
+ resource,
3563
+ `${path}.redirectUrl`
3564
+ );
3565
+ try {
3566
+ const parsed = new URL(redirectUrl);
3567
+ const loopback = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
3568
+ if (!loopback && parsed.protocol !== "https:" || parsed.username || parsed.password)
3569
+ throw new Error("unsafe redirect URL");
3570
+ } catch {
3571
+ fail(
3572
+ resource,
3573
+ `${path}.redirectUrl`,
3574
+ "HTTPS or loopback URL without embedded credentials"
3575
+ );
3576
+ }
3577
+ if (!hasCancelable) {
3578
+ action.cancelable = false;
3579
+ action.retryPolicy = "same_action_only";
3580
+ }
3581
+ return;
3582
+ }
3425
3583
  exact(action, ["type", "checkoutUrl"], [], resource, path);
3426
3584
  if (action.type !== "portone_checkout") {
3427
- fail(resource, `${path}.type`, "portone_checkout");
3585
+ fail(resource, `${path}.type`, "portone_checkout | portone_sdk");
3428
3586
  }
3429
3587
  const checkoutUrl = boundedString(
3430
3588
  action.checkoutUrl,
@@ -4154,8 +4312,8 @@ var CartApi = class extends CustomerScopedApi {
4154
4312
  endpoint(key) {
4155
4313
  return this.serverTransport ? COMMERCE_ENDPOINTS.carts.server[key] : COMMERCE_ENDPOINTS.carts[key];
4156
4314
  }
4157
- execute(endpoint2, body, idempotencyKey) {
4158
- return this.requestEndpoint(endpoint2, body, {
4315
+ execute(endpoint, body, idempotencyKey) {
4316
+ return this.requestEndpoint(endpoint, body, {
4159
4317
  ...idempotencyKey && {
4160
4318
  headers: { "X-Idempotency-Key": idempotencyKey }
4161
4319
  }
@@ -4172,26 +4330,26 @@ var CartApi = class extends CustomerScopedApi {
4172
4330
  );
4173
4331
  }
4174
4332
  mine(params = {}) {
4175
- const endpoint2 = this.endpoint("mine");
4176
- return this.execute(endpoint2, params).then(
4333
+ const endpoint = this.endpoint("mine");
4334
+ return this.execute(endpoint, params).then(
4177
4335
  (value) => validateCartMineResult(value)
4178
4336
  );
4179
4337
  }
4180
4338
  merge(params) {
4181
4339
  const { idempotencyKey, ...body } = params;
4182
4340
  assertCommerceIdempotencyKey(idempotencyKey);
4183
- const endpoint2 = this.endpoint("merge");
4184
- return this.execute(endpoint2, body, idempotencyKey).then(
4341
+ const endpoint = this.endpoint("merge");
4342
+ return this.execute(endpoint, body, idempotencyKey).then(
4185
4343
  (value) => validateCartMergeResult(value)
4186
4344
  );
4187
4345
  }
4188
4346
  addItem(params) {
4189
4347
  return this.mutate(this.endpoint("addItem"), params);
4190
4348
  }
4191
- mutate(endpoint2, params) {
4349
+ mutate(endpoint, params) {
4192
4350
  const { idempotencyKey, ...body } = params;
4193
4351
  assertCommerceIdempotencyKey(idempotencyKey);
4194
- return this.execute(endpoint2, body, idempotencyKey).then(
4352
+ return this.execute(endpoint, body, idempotencyKey).then(
4195
4353
  (value) => validateCartMutationResult(value)
4196
4354
  );
4197
4355
  }
@@ -4217,8 +4375,8 @@ var CheckoutApi = class extends CustomerScopedApi {
4217
4375
  constructor(options) {
4218
4376
  super("CheckoutApi", { ...options, requiresCredential: false });
4219
4377
  }
4220
- post(endpoint2, body, idempotencyKey) {
4221
- return this.requestEndpoint(endpoint2, body, {
4378
+ post(endpoint, body, idempotencyKey) {
4379
+ return this.requestEndpoint(endpoint, body, {
4222
4380
  ...idempotencyKey && {
4223
4381
  headers: { "X-Idempotency-Key": idempotencyKey }
4224
4382
  }
@@ -4285,11 +4443,15 @@ var PaymentSessionApi = class extends CustomerScopedApi {
4285
4443
  super("PaymentSessionApi", { ...options, requiresCredential: false });
4286
4444
  this.serverTransport = Boolean(options.secretKey);
4287
4445
  }
4288
- post(endpoint2, body, idempotencyKey) {
4289
- return this.requestEndpoint(endpoint2, body, {
4290
- ...idempotencyKey && {
4291
- headers: { "X-Idempotency-Key": idempotencyKey }
4446
+ post(endpoint, body, idempotencyKey, negotiateStandardActionCapabilities = false) {
4447
+ const headers = {
4448
+ ...idempotencyKey && { "X-Idempotency-Key": idempotencyKey },
4449
+ ...negotiateStandardActionCapabilities && {
4450
+ Accept: PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE
4292
4451
  }
4452
+ };
4453
+ return this.requestEndpoint(endpoint, body, {
4454
+ ...Object.keys(headers).length > 0 && { headers }
4293
4455
  });
4294
4456
  }
4295
4457
  async paymentSession(result, expectedProvider) {
@@ -4314,40 +4476,41 @@ var PaymentSessionApi = class extends CustomerScopedApi {
4314
4476
  this.post(
4315
4477
  this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.create : COMMERCE_ENDPOINTS.paymentSessions.create,
4316
4478
  body,
4317
- idempotencyKey
4479
+ idempotencyKey,
4480
+ body.providerOptions.profile === "standard_v2"
4318
4481
  ),
4319
4482
  "portone"
4320
4483
  );
4321
4484
  }
4322
4485
  retrieve(params) {
4323
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4486
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4324
4487
  return this.paymentSession(
4325
- this.post(endpoint2, params),
4488
+ this.post(endpoint, params),
4326
4489
  "toss"
4327
4490
  );
4328
4491
  }
4329
4492
  retrievePortOne(params) {
4330
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4493
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
4331
4494
  return this.paymentSession(
4332
- this.post(endpoint2, params),
4495
+ this.post(endpoint, params, void 0, true),
4333
4496
  "portone"
4334
4497
  );
4335
4498
  }
4336
4499
  cancel(params) {
4337
4500
  const { idempotencyKey, ...body } = params;
4338
4501
  assertCommerceIdempotencyKey(idempotencyKey);
4339
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4502
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4340
4503
  return this.paymentSession(
4341
- this.post(endpoint2, body, idempotencyKey),
4504
+ this.post(endpoint, body, idempotencyKey),
4342
4505
  "toss"
4343
4506
  );
4344
4507
  }
4345
4508
  cancelPortOne(params) {
4346
4509
  const { idempotencyKey, ...body } = params;
4347
4510
  assertCommerceIdempotencyKey(idempotencyKey);
4348
- const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4511
+ const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
4349
4512
  return this.paymentSession(
4350
- this.post(endpoint2, body, idempotencyKey),
4513
+ this.post(endpoint, body, idempotencyKey),
4351
4514
  "portone"
4352
4515
  );
4353
4516
  }
@@ -4426,9 +4589,9 @@ function resolveVariantImageItems(variant, poolById) {
4426
4589
  if (pooled) resolved.push(pooled);
4427
4590
  continue;
4428
4591
  }
4429
- const mediaId2 = getMediaId(entry);
4430
- if (mediaId2) {
4431
- const pooled = poolById.get(mediaId2);
4592
+ const mediaId = getMediaId(entry);
4593
+ if (mediaId) {
4594
+ const pooled = poolById.get(mediaId);
4432
4595
  if (pooled) {
4433
4596
  resolved.push(pooled);
4434
4597
  }
@@ -4619,11 +4782,11 @@ function getFirstMediaId(values) {
4619
4782
  }
4620
4783
  return null;
4621
4784
  }
4622
- function inProductMediaPool(product, mediaId2) {
4623
- if (mediaId2 == null) return null;
4785
+ function inProductMediaPool(product, mediaId) {
4786
+ if (mediaId == null) return null;
4624
4787
  const images = Array.isArray(product?.images) ? product.images : [];
4625
4788
  for (const image of images) {
4626
- if (extractEntityId(image) === mediaId2) return mediaId2;
4789
+ if (extractEntityId(image) === mediaId) return mediaId;
4627
4790
  }
4628
4791
  return null;
4629
4792
  }
@@ -6099,21 +6262,11 @@ var PRODUCT_DETAIL_UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
6099
6262
  "not_published",
6100
6263
  "feature_disabled"
6101
6264
  ]);
6102
- function isRecord(value) {
6103
- return typeof value === "object" && value !== null;
6104
- }
6105
- function readProductDetailUnavailableReason(value) {
6106
- if (!isRecord(value)) return void 0;
6107
- const directReason = value.reason ?? value.code;
6108
- if (typeof directReason === "string" && PRODUCT_DETAIL_UNAVAILABLE_REASONS.has(directReason)) {
6109
- return directReason;
6110
- }
6111
- return readProductDetailUnavailableReason(value.body);
6112
- }
6113
6265
  function productDetailResultFromError(error) {
6114
6266
  if (!(error instanceof SDKError) || error.status !== 404) return void 0;
6115
- const reason = readProductDetailUnavailableReason(error.details);
6116
- if (!reason) return void 0;
6267
+ const reason = getSDKErrorReason(error);
6268
+ if (!reason || !PRODUCT_DETAIL_UNAVAILABLE_REASONS.has(reason))
6269
+ return void 0;
6117
6270
  return { found: false, reason };
6118
6271
  }
6119
6272
  var MARKET_PRICE_QUERY_UNSUPPORTED_MESSAGE = "Market listing pages do not support base price filters or price sorts.";
@@ -6214,8 +6367,8 @@ function isProductUpsertFieldValidationErrorBody(value) {
6214
6367
 
6215
6368
  // src/core/commerce/commerce-client.ts
6216
6369
  var BrowserCommerceApi = class extends CustomerScopedApi {
6217
- requestEndpoint(endpoint2, body, options) {
6218
- return super.requestEndpoint(endpoint2, body, options);
6370
+ requestEndpoint(endpoint, body, options) {
6371
+ return super.requestEndpoint(endpoint, body, options);
6219
6372
  }
6220
6373
  };
6221
6374
  var CommerceClient = class {
@@ -6415,11 +6568,11 @@ var EventsClient = class {
6415
6568
  { useCustomerAuth: false }
6416
6569
  );
6417
6570
  }
6418
- async execute(endpoint2, method, body, options = {}) {
6571
+ async execute(endpoint, method, body, options = {}) {
6419
6572
  const useCustomerAuth = options.useCustomerAuth === true;
6420
6573
  const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
6421
6574
  try {
6422
- const response = await httpFetch(endpoint2, {
6575
+ const response = await httpFetch(endpoint, {
6423
6576
  method,
6424
6577
  apiUrl: this.apiUrl,
6425
6578
  publishableKey: this.publishableKey,
@@ -6428,7 +6581,7 @@ var EventsClient = class {
6428
6581
  ...body !== void 0 && { body: JSON.stringify(body) }
6429
6582
  });
6430
6583
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
6431
- return parseApiResponse(response, endpoint2);
6584
+ return parseApiResponse(response, endpoint);
6432
6585
  } catch (err) {
6433
6586
  const id = err instanceof SDKError ? err.requestId ?? null : null;
6434
6587
  this.onRequestId?.(id);
@@ -6686,13 +6839,106 @@ function mergeProductDetailWithStock(catalog, snapshot) {
6686
6839
  };
6687
6840
  }
6688
6841
 
6842
+ // src/core/webhook/validation.ts
6843
+ function isValidWebhookEventData(data) {
6844
+ if (typeof data !== "object" || data === null) return false;
6845
+ const event = data;
6846
+ return typeof event.collection === "string" && typeof event.operation === "string" && event.operation.length > 0 && typeof event.data === "object" && event.data !== null;
6847
+ }
6848
+
6849
+ // src/core/webhook/receiver.ts
6850
+ async function verifySignature(rawBody, secret, signature, timestamp2, deliveryId) {
6851
+ const encoder = new TextEncoder();
6852
+ const signedPrefix = encoder.encode(`${timestamp2}.${deliveryId}.`);
6853
+ const signedPayload = new Uint8Array(signedPrefix.length + rawBody.length);
6854
+ signedPayload.set(signedPrefix);
6855
+ signedPayload.set(rawBody, signedPrefix.length);
6856
+ const key = await crypto.subtle.importKey(
6857
+ "raw",
6858
+ encoder.encode(secret),
6859
+ { name: "HMAC", hash: "SHA-256" },
6860
+ false,
6861
+ ["verify"]
6862
+ );
6863
+ if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
6864
+ return false;
6865
+ }
6866
+ const sigBytes = new Uint8Array(
6867
+ (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
6868
+ );
6869
+ return crypto.subtle.verify("HMAC", key, sigBytes, signedPayload);
6870
+ }
6871
+ function timestampIsFresh(timestamp2, toleranceSeconds) {
6872
+ if (!/^\d+$/.test(timestamp2)) return false;
6873
+ const timestampMs = Number(timestamp2);
6874
+ if (!Number.isFinite(timestampMs)) return false;
6875
+ const skewMs = Math.abs(Date.now() - timestampMs);
6876
+ return skewMs <= toleranceSeconds * 1e3;
6877
+ }
6878
+ var MAX_TOLERANCE_SECONDS = 86400;
6879
+ function toleranceIsValid(toleranceSeconds) {
6880
+ return typeof toleranceSeconds === "number" && Number.isFinite(toleranceSeconds) && toleranceSeconds >= 0 && toleranceSeconds <= MAX_TOLERANCE_SECONDS;
6881
+ }
6882
+ async function processWebhookRequest(request, handler, verify) {
6883
+ try {
6884
+ const rawBody = new Uint8Array(await request.arrayBuffer());
6885
+ const verificationFailure = await verify?.(rawBody);
6886
+ if (verificationFailure) return verificationFailure;
6887
+ const body = JSON.parse(new TextDecoder().decode(rawBody));
6888
+ if (!isValidWebhookEventData(body)) {
6889
+ return new Response(
6890
+ JSON.stringify({ error: "Invalid webhook event format" }),
6891
+ { status: 400, headers: { "Content-Type": "application/json" } }
6892
+ );
6893
+ }
6894
+ await handler(body);
6895
+ return new Response(
6896
+ JSON.stringify({ success: true, message: "Webhook processed" }),
6897
+ { status: 200, headers: { "Content-Type": "application/json" } }
6898
+ );
6899
+ } catch (error) {
6900
+ console.error("Webhook processing error:", error);
6901
+ return new Response(JSON.stringify({ error: "Internal server error" }), {
6902
+ status: 500,
6903
+ headers: { "Content-Type": "application/json" }
6904
+ });
6905
+ }
6906
+ }
6907
+ async function handleSignedWebhook(request, handler, options) {
6908
+ const secret = options?.secret;
6909
+ const configuredTolerance = options?.toleranceSeconds;
6910
+ const toleranceSeconds = configuredTolerance ?? 300;
6911
+ if (typeof secret !== "string" || secret.trim().length === 0) {
6912
+ return new Response(
6913
+ JSON.stringify({ error: "Webhook signing secret is not configured" }),
6914
+ { status: 500, headers: { "Content-Type": "application/json" } }
6915
+ );
6916
+ }
6917
+ if (!toleranceIsValid(toleranceSeconds)) {
6918
+ return new Response(
6919
+ JSON.stringify({ error: "Webhook signature tolerance is not valid" }),
6920
+ { status: 500, headers: { "Content-Type": "application/json" } }
6921
+ );
6922
+ }
6923
+ return processWebhookRequest(request, handler, async (rawBody) => {
6924
+ const signature = request.headers.get("x-webhook-signature") || "";
6925
+ const timestamp2 = request.headers.get("x-webhook-timestamp") || "";
6926
+ const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
6927
+ const valid = Boolean(timestamp2 && deliveryId) && timestampIsFresh(timestamp2, toleranceSeconds) && await verifySignature(rawBody, secret, signature, timestamp2, deliveryId);
6928
+ if (!valid) {
6929
+ return new Response(
6930
+ JSON.stringify({ error: "Invalid webhook signature" }),
6931
+ { status: 401, headers: { "Content-Type": "application/json" } }
6932
+ );
6933
+ }
6934
+ });
6935
+ }
6936
+
6689
6937
  // src/core/webhook/index.ts
6690
6938
  var ORDER_CHANGED_EVENT_TYPE = "collection.orderChanged";
6691
6939
  var COMMERCE_NOTIFICATION_EVENT_TYPE = "commerce.notification";
6692
6940
  function isValidWebhookEvent(data) {
6693
- if (typeof data !== "object" || data === null) return false;
6694
- const obj = data;
6695
- return typeof obj.collection === "string" && typeof obj.operation === "string" && obj.operation.length > 0 && typeof obj.data === "object" && obj.data !== null;
6941
+ return isValidWebhookEventData(data);
6696
6942
  }
6697
6943
  var COMMERCE_NOTIFICATION_OPERATION = "notification";
6698
6944
  var COMMERCE_NOTIFICATION_EVENTS = [
@@ -6704,13 +6950,15 @@ var COMMERCE_NOTIFICATION_EVENTS = [
6704
6950
  "returnApproved",
6705
6951
  "returnRejected",
6706
6952
  "returnCanceled",
6707
- "returnCompleted"
6953
+ "returnCompleted",
6954
+ "paymentReconciliationRequired",
6955
+ "paymentRefundRequiresAttention"
6708
6956
  ];
6709
6957
  function isStringOrNumber(value) {
6710
6958
  return typeof value === "string" || typeof value === "number";
6711
6959
  }
6712
6960
  function isWebhookOrderScope(value) {
6713
- if (!isRecord2(value)) return false;
6961
+ if (!isRecord(value)) return false;
6714
6962
  if (value.kind === "collection") {
6715
6963
  return typeof value.collection === "string";
6716
6964
  }
@@ -6720,35 +6968,42 @@ function isWebhookOrderScope(value) {
6720
6968
  return false;
6721
6969
  }
6722
6970
  function isWebhookOrderMoved(value) {
6723
- if (!isRecord2(value)) return false;
6971
+ if (!isRecord(value)) return false;
6724
6972
  return typeof value.collection === "string" && isStringOrNumber(value.id) && (value.relatedCollection === void 0 || typeof value.relatedCollection === "string") && (value.relatedId === void 0 || isStringOrNumber(value.relatedId));
6725
6973
  }
6726
6974
  function hasOptionalOrderValue(value, key) {
6727
6975
  return value[key] === void 0 || value[key] === null || typeof value[key] === "string";
6728
6976
  }
6729
6977
  function isWebhookOrderChange(value) {
6730
- if (!isRecord2(value)) return false;
6978
+ if (!isRecord(value)) return false;
6731
6979
  return value.type === "order" && value.source === "payload-orderable" && (value.orderableFieldName === void 0 || typeof value.orderableFieldName === "string") && hasOptionalOrderValue(value, "previousOrder") && hasOptionalOrderValue(value, "nextOrder") && isWebhookOrderScope(value.scope) && isWebhookOrderMoved(value.moved);
6732
6980
  }
6733
6981
  function isCommerceNotificationEventName(value) {
6734
6982
  return typeof value === "string" && COMMERCE_NOTIFICATION_EVENTS.includes(value);
6735
6983
  }
6736
6984
  function isCommerceNotificationSourceCollection(value) {
6737
- return value === "orders" || value === "fulfillments" || value === "returns";
6985
+ return value === "orders" || value === "fulfillments" || value === "returns" || value === "payment-sessions" || value === "payment-refund-attempts";
6738
6986
  }
6739
6987
  function isCommerceNotificationData(value) {
6740
- if (!isRecord2(value)) return false;
6741
- if (value.source !== void 0 && (!isRecord2(value.source) || !isCommerceNotificationSourceCollection(value.source.collection) || !isStringOrNumber(value.source.id))) {
6988
+ if (!isRecord(value)) return false;
6989
+ if (value.source !== void 0 && (!isRecord(value.source) || !isCommerceNotificationSourceCollection(value.source.collection) || !isStringOrNumber(value.source.id))) {
6742
6990
  return false;
6743
6991
  }
6744
- return (value.orderId === void 0 || isStringOrNumber(value.orderId)) && (value.orderNumber === void 0 || typeof value.orderNumber === "string") && (value.status === void 0 || typeof value.status === "string") && (value.totalAmount === void 0 || typeof value.totalAmount === "number") && (value.currency === void 0 || typeof value.currency === "string") && (value.fulfillmentId === void 0 || isStringOrNumber(value.fulfillmentId)) && (value.fulfillmentStatus === void 0 || typeof value.fulfillmentStatus === "string") && (value.shippedAt === void 0 || typeof value.shippedAt === "string") && (value.returnId === void 0 || isStringOrNumber(value.returnId)) && (value.returnStatus === void 0 || typeof value.returnStatus === "string") && (value.refundAmount === void 0 || typeof value.refundAmount === "number") && (value.completedAt === void 0 || typeof value.completedAt === "string");
6992
+ return (value.orderId === void 0 || isStringOrNumber(value.orderId)) && (value.orderNumber === void 0 || typeof value.orderNumber === "string") && (value.status === void 0 || typeof value.status === "string") && (value.totalAmount === void 0 || typeof value.totalAmount === "number") && (value.currency === void 0 || typeof value.currency === "string") && (value.fulfillmentId === void 0 || isStringOrNumber(value.fulfillmentId)) && (value.fulfillmentStatus === void 0 || typeof value.fulfillmentStatus === "string") && (value.shippedAt === void 0 || typeof value.shippedAt === "string") && (value.returnId === void 0 || isStringOrNumber(value.returnId)) && (value.returnStatus === void 0 || typeof value.returnStatus === "string") && (value.refundAmount === void 0 || typeof value.refundAmount === "number") && (value.completedAt === void 0 || typeof value.completedAt === "string") && (value.paymentSessionId === void 0 || typeof value.paymentSessionId === "string") && (value.checkoutId === void 0 || typeof value.checkoutId === "string") && (value.refundAttemptId === void 0 || typeof value.refundAttemptId === "string") && (value.reason === void 0 || typeof value.reason === "string") && (value.observedAt === void 0 || typeof value.observedAt === "string") && (value.providerObject === void 0 || isRecord(value.providerObject) && typeof value.providerObject.provider === "string" && (value.providerObject.kind === "payment" || value.providerObject.kind === "refund") && typeof value.providerObject.id === "string") && (value.money === void 0 || isRecord(value.money) && Number.isSafeInteger(value.money.amountMinor) && Number(value.money.amountMinor) > 0 && typeof value.money.currency === "string");
6745
6993
  }
6746
6994
  function isCommerceNotification(value) {
6747
- if (!isRecord2(value)) return false;
6748
- 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");
6995
+ if (!isRecord(value)) return false;
6996
+ return isCommerceNotificationEventName(value.event) && typeof value.intentId === "string" && value.intentId.length > 0 && typeof value.dedupeKey === "string" && value.dedupeKey.length > 0 && (value.orderId === void 0 || typeof value.orderId === "string") && (value.fulfillmentId === void 0 || typeof value.fulfillmentId === "string") && (value.returnId === void 0 || typeof value.returnId === "string") && (value.paymentSessionId === void 0 || typeof value.paymentSessionId === "string") && (value.refundAttemptId === void 0 || typeof value.refundAttemptId === "string");
6997
+ }
6998
+ function isPaymentIncidentNotificationData(value, event) {
6999
+ const reconciliation = event === "paymentReconciliationRequired";
7000
+ const expectedCollection = reconciliation ? "payment-sessions" : "payment-refund-attempts";
7001
+ const expectedStatus = reconciliation ? "reconciliation_required" : "requires_attention";
7002
+ const expectedReason = reconciliation ? "orderless_capture" : "local_commit_ambiguous";
7003
+ return value.source?.collection === expectedCollection && typeof value.source.id === "string" && value.source.id.length > 0 && typeof value.paymentSessionId === "string" && value.paymentSessionId.length > 0 && isRecord(value.providerObject) && typeof value.providerObject.provider === "string" && value.providerObject.provider.length > 0 && (value.providerObject.kind === "payment" || value.providerObject.kind === "refund") && typeof value.providerObject.id === "string" && value.providerObject.id.length > 0 && isRecord(value.money) && Number.isSafeInteger(value.money.amountMinor) && Number(value.money.amountMinor) > 0 && typeof value.money.currency === "string" && value.money.currency.length > 0 && value.status === expectedStatus && value.reason === expectedReason && typeof value.observedAt === "string" && value.observedAt.length > 0 && !Number.isNaN(Date.parse(value.observedAt)) && (value.checkoutId === void 0 || typeof value.checkoutId === "string" && value.checkoutId.length > 0) && (value.orderId === void 0 || typeof value.orderId === "string" && value.orderId.length > 0) && (reconciliation ? value.source.id === value.paymentSessionId && value.providerObject.kind === "payment" && value.refundAttemptId === void 0 : typeof value.refundAttemptId === "string" && value.refundAttemptId.length > 0 && value.source.id === value.refundAttemptId);
6749
7004
  }
6750
7005
  function isWebhookCommerceNotificationChange(value) {
6751
- if (!isRecord2(value)) return false;
7006
+ if (!isRecord(value)) return false;
6752
7007
  return value.type === "notification" && value.source === "commerce-notifications" && isCommerceNotificationEventName(value.event) && isCommerceNotificationSourceCollection(value.sourceCollection) && isStringOrNumber(value.sourceId);
6753
7008
  }
6754
7009
  function matchesOptionalId(actual, expected) {
@@ -6786,6 +7041,15 @@ function isCommerceNotificationWebhookEvent(event) {
6786
7041
  if (!matchesOptionalId(change.sourceId, sourceId)) return false;
6787
7042
  }
6788
7043
  const changeSourceId = isWebhookCommerceNotificationChange(change) ? change.sourceId : void 0;
7044
+ if (notification.event === "paymentReconciliationRequired" || notification.event === "paymentRefundRequiresAttention") {
7045
+ if (!isPaymentIncidentNotificationData(data, notification.event)) {
7046
+ return false;
7047
+ }
7048
+ const incidentData = data;
7049
+ const expectedCollection = notification.event === "paymentReconciliationRequired" ? "payment-sessions" : "payment-refund-attempts";
7050
+ const notificationSourceId = notification.event === "paymentReconciliationRequired" ? notification.paymentSessionId : notification.refundAttemptId;
7051
+ return sourceCollection === expectedCollection && typeof notification.paymentSessionId === "string" && notification.paymentSessionId === incidentData.paymentSessionId && typeof notificationSourceId === "string" && notificationSourceId === incidentData.source.id && matchesOptionalId(changeSourceId, incidentData.source.id);
7052
+ }
6789
7053
  if (notification.event === "orderPaid" || notification.event === "orderCanceled" || notification.event === "orderDelivered") {
6790
7054
  return sourceCollection === "orders" && typeof notification.orderId === "string" && notification.orderId.length > 0 && matchesOptionalId(data.orderId, sourceId) && matchesOptionalId(notification.orderId, sourceId) && matchesOptionalId(data.orderId, notification.orderId) && matchesOptionalId(changeSourceId, data.orderId ?? notification.orderId);
6791
7055
  }
@@ -6830,7 +7094,7 @@ function isWebhookOperation(event, operation2) {
6830
7094
  return isValidWebhookEvent(event) && event.operation === operation2;
6831
7095
  }
6832
7096
  var CUSTOMER_PASSWORD_RESET_OPERATION = "password-reset";
6833
- function isRecord2(value) {
7097
+ function isRecord(value) {
6834
7098
  return typeof value === "object" && value !== null;
6835
7099
  }
6836
7100
  function hasString(value, key) {
@@ -6840,7 +7104,7 @@ function hasStringOrNumber(value, key) {
6840
7104
  return typeof value[key] === "string" || typeof value[key] === "number";
6841
7105
  }
6842
7106
  function isCustomerPasswordResetWebhookEvent(event) {
6843
- if (event.collection !== "customers" || event.operation !== CUSTOMER_PASSWORD_RESET_OPERATION || !isRecord2(event.data)) {
7107
+ if (event.collection !== "customers" || event.operation !== CUSTOMER_PASSWORD_RESET_OPERATION || !isRecord(event.data)) {
6844
7108
  return false;
6845
7109
  }
6846
7110
  return hasStringOrNumber(event.data, "customerId") && hasString(event.data, "email") && hasString(event.data, "name") && hasString(event.data, "resetPasswordToken") && hasString(event.data, "resetPasswordExpiresAt");
@@ -6854,80 +7118,8 @@ function createCustomerAuthWebhookHandler(handlers) {
6854
7118
  await handlers.unhandled?.(event);
6855
7119
  };
6856
7120
  }
6857
- async function verifySignature(payload, secret, signature, timestamp2, deliveryId) {
6858
- const encoder = new TextEncoder();
6859
- const key = await crypto.subtle.importKey(
6860
- "raw",
6861
- encoder.encode(secret),
6862
- { name: "HMAC", hash: "SHA-256" },
6863
- false,
6864
- ["verify"]
6865
- );
6866
- if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
6867
- return false;
6868
- }
6869
- const sigBytes = new Uint8Array(
6870
- (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
6871
- );
6872
- return crypto.subtle.verify(
6873
- "HMAC",
6874
- key,
6875
- sigBytes,
6876
- encoder.encode(`${timestamp2}.${deliveryId}.${payload}`)
6877
- );
6878
- }
6879
- function timestampIsFresh(timestamp2, toleranceSeconds) {
6880
- if (!/^\d+$/.test(timestamp2)) return false;
6881
- const timestampMs = Number(timestamp2);
6882
- if (!Number.isFinite(timestampMs)) return false;
6883
- const skewMs = Math.abs(Date.now() - timestampMs);
6884
- return skewMs <= toleranceSeconds * 1e3;
6885
- }
6886
7121
  async function handleWebhook(request, handler, options) {
6887
- try {
6888
- const rawBody = await request.text();
6889
- if (options?.secret) {
6890
- const signature = request.headers.get("x-webhook-signature") || "";
6891
- const timestamp2 = request.headers.get("x-webhook-timestamp") || "";
6892
- const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
6893
- const toleranceSeconds = options.toleranceSeconds ?? 300;
6894
- const valid = Boolean(timestamp2 && deliveryId) && timestampIsFresh(timestamp2, toleranceSeconds) && await verifySignature(
6895
- rawBody,
6896
- options.secret,
6897
- signature,
6898
- timestamp2,
6899
- deliveryId
6900
- );
6901
- if (!valid) {
6902
- return new Response(
6903
- JSON.stringify({ error: "Invalid webhook signature" }),
6904
- { status: 401, headers: { "Content-Type": "application/json" } }
6905
- );
6906
- }
6907
- } else {
6908
- console.warn(
6909
- "[@01.software/sdk] Webhook signature verification is disabled. Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification."
6910
- );
6911
- }
6912
- const body = JSON.parse(rawBody);
6913
- if (!isValidWebhookEvent(body)) {
6914
- return new Response(
6915
- JSON.stringify({ error: "Invalid webhook event format" }),
6916
- { status: 400, headers: { "Content-Type": "application/json" } }
6917
- );
6918
- }
6919
- await handler(body);
6920
- return new Response(
6921
- JSON.stringify({ success: true, message: "Webhook processed" }),
6922
- { status: 200, headers: { "Content-Type": "application/json" } }
6923
- );
6924
- } catch (error) {
6925
- console.error("Webhook processing error:", error);
6926
- return new Response(JSON.stringify({ error: "Internal server error" }), {
6927
- status: 500,
6928
- headers: { "Content-Type": "application/json" }
6929
- });
6930
- }
7122
+ return handleSignedWebhook(request, handler, options);
6931
7123
  }
6932
7124
  function createTypedWebhookHandler(collection, handler) {
6933
7125
  return async (event) => {
@@ -6967,6 +7159,7 @@ var INTERNAL_COLLECTIONS = [
6967
7159
  "payment-event-inbox",
6968
7160
  "payment-refund-attempts",
6969
7161
  "portone-payment-interactions",
7162
+ "commerce-payment-webhook-routes",
6970
7163
  "commerce-notification-intents",
6971
7164
  "commerce-idempotency-records",
6972
7165
  "product-collection-items",
@@ -7007,7 +7200,6 @@ var COLLECTIONS = [
7007
7200
  "brands",
7008
7201
  "customer-profiles",
7009
7202
  "customer-profile-stats",
7010
- "discounts",
7011
7203
  "shipping-policies",
7012
7204
  "shipping-zones",
7013
7205
  "documents",
@@ -7083,6 +7275,9 @@ var SERVER_ONLY_COLLECTIONS = [
7083
7275
  "cart-items",
7084
7276
  "checkouts",
7085
7277
  "checkout-items",
7278
+ // Raw discount definitions require a server credential. Browser discount
7279
+ // validation is exposed through the shaped POST /api/discounts/validate path.
7280
+ "discounts",
7086
7281
  "draft-orders",
7087
7282
  "draft-order-items",
7088
7283
  "posts",
@@ -7248,160 +7443,6 @@ var RealtimeConnection = class {
7248
7443
  }
7249
7444
  };
7250
7445
 
7251
- // src/utils/product-media.ts
7252
- function mediaPointerOptionValues(values) {
7253
- return (values ?? []).filter((value) => value != null && value !== "").map((value) => ({
7254
- swatch: {
7255
- type: "media",
7256
- mediaItemId: value
7257
- }
7258
- }));
7259
- }
7260
- function resolveProductMedia(input) {
7261
- const resolved = resolveProductSelectionMedia({
7262
- ...input,
7263
- selectedVariant: input.selectedVariant ?? (input.variantFeaturedMediaItemId ? { images: [input.variantFeaturedMediaItemId] } : null),
7264
- selectedOptionValues: input.selectedOptionValues ?? mediaPointerOptionValues(input.selectedOptionValueMediaItemIds)
7265
- });
7266
- if (resolved.source !== "none") {
7267
- return {
7268
- ...resolved,
7269
- source: resolved.source === "variant_media_selected" ? "variant_featured" : resolved.source
7270
- };
7271
- }
7272
- const display = resolveProductDisplayMedia({
7273
- productMediaPool: input.productMediaPool
7274
- });
7275
- return {
7276
- primaryImage: display.primaryImage,
7277
- images: display.images,
7278
- source: display.source
7279
- };
7280
- }
7281
-
7282
- // src/utils/product-gallery.ts
7283
- function mediaId(value) {
7284
- if (typeof value === "string" || typeof value === "number") {
7285
- return String(value);
7286
- }
7287
- if (typeof value === "object" && value !== null && "id" in value) {
7288
- const id = value.id;
7289
- if (typeof id === "string" || typeof id === "number") return String(id);
7290
- }
7291
- return null;
7292
- }
7293
- function relationshipIds(values) {
7294
- if (!Array.isArray(values)) return [];
7295
- return values.map((value) => mediaId(value)).filter((value) => Boolean(value));
7296
- }
7297
- function buildPoolById2(pool) {
7298
- const poolById = /* @__PURE__ */ new Map();
7299
- for (const item of pool) {
7300
- const id = mediaId(item);
7301
- if (id) poolById.set(id, item);
7302
- }
7303
- return poolById;
7304
- }
7305
- function mediaSetItemsInPool(mediaSet, poolById) {
7306
- const seen = /* @__PURE__ */ new Set();
7307
- const items = [];
7308
- const primaryId = mediaId(mediaSet.primaryMediaItemId);
7309
- if (primaryId) {
7310
- const primary = poolById.get(primaryId);
7311
- if (primary) {
7312
- seen.add(primaryId);
7313
- items.push(primary);
7314
- }
7315
- }
7316
- for (const itemId of relationshipIds(mediaSet.items)) {
7317
- if (seen.has(itemId)) continue;
7318
- const item = poolById.get(itemId);
7319
- if (!item) continue;
7320
- seen.add(itemId);
7321
- items.push(item);
7322
- }
7323
- return items;
7324
- }
7325
- function resolveLegacyMediaSet(input) {
7326
- if (!Array.isArray(input.mediaSets)) return null;
7327
- const pool = input.productMediaPool ?? input.pool ?? [];
7328
- const poolById = buildPoolById2(pool);
7329
- const selectedVariantId = mediaId(input.selectedVariantId);
7330
- if (selectedVariantId) {
7331
- const exactSet = input.mediaSets.find(
7332
- (set) => set.matchType === "exact-variant" && relationshipIds(set.variantIds).includes(selectedVariantId)
7333
- );
7334
- if (exactSet) {
7335
- const images = mediaSetItemsInPool(exactSet, poolById);
7336
- if (images.length > 0) {
7337
- return {
7338
- primaryImage: images[0] ?? null,
7339
- images,
7340
- source: "exact_variant_set"
7341
- };
7342
- }
7343
- }
7344
- }
7345
- const selectedOptionValueIds = new Set(
7346
- relationshipIds(input.selectedOptionValueIds)
7347
- );
7348
- const optionSetMatches = input.mediaSets.filter((set) => set.matchType === "option-values").map((set) => {
7349
- const optionValueIds = relationshipIds(set.optionValueIds);
7350
- if (optionValueIds.length === 0) return null;
7351
- if (!optionValueIds.every((id) => selectedOptionValueIds.has(id))) {
7352
- return null;
7353
- }
7354
- const images = mediaSetItemsInPool(set, poolById);
7355
- if (images.length === 0) return null;
7356
- return { optionValueCount: optionValueIds.length, images };
7357
- }).filter(
7358
- (match) => Boolean(match)
7359
- ).sort((a, b) => b.optionValueCount - a.optionValueCount);
7360
- if (optionSetMatches.length > 0) {
7361
- const images = optionSetMatches[0].images;
7362
- return {
7363
- primaryImage: images[0] ?? null,
7364
- images,
7365
- source: "option_value_set"
7366
- };
7367
- }
7368
- const defaultSet = input.mediaSets.find((set) => set.matchType === "default");
7369
- if (defaultSet) {
7370
- const images = mediaSetItemsInPool(defaultSet, poolById);
7371
- if (images.length > 0) {
7372
- return {
7373
- primaryImage: images[0] ?? null,
7374
- images,
7375
- source: "default_set"
7376
- };
7377
- }
7378
- }
7379
- return {
7380
- primaryImage: null,
7381
- images: [],
7382
- source: "none"
7383
- };
7384
- }
7385
- function resolveProductGallery(input) {
7386
- const selectedVariantId = mediaId(input.selectedVariantId);
7387
- const selectedOptionValueIds = relationshipIds(input.selectedOptionValueIds);
7388
- const selection = resolveProductSelectionMedia({
7389
- ...input,
7390
- productMediaPool: input.productMediaPool ?? input.pool ?? null,
7391
- selectedVariant: input.selectedVariant ?? (selectedVariantId ? { id: selectedVariantId } : null),
7392
- selectedOptionValues: input.selectedOptionValues ?? selectedOptionValueIds.map((id) => ({ id }))
7393
- });
7394
- if (selection.source !== "none") {
7395
- return selection;
7396
- }
7397
- const legacyResolved = resolveLegacyMediaSet(input);
7398
- if (legacyResolved && legacyResolved.source !== "none") return legacyResolved;
7399
- return resolveProductDisplayMedia({
7400
- productMediaPool: input.productMediaPool ?? input.pool ?? null,
7401
- featuredImage: input.featuredImage
7402
- });
7403
- }
7404
-
7405
7446
  // src/utils/image.ts
7406
7447
  var IMAGE_SIZES = [200, 400, 800, 1200, 1600];
7407
7448
  function imageSizeCandidates(sizes) {
@@ -7533,7 +7574,7 @@ function createAnalytics(config) {
7533
7574
  }, destroy() {
7534
7575
  } };
7535
7576
  }
7536
- const endpoint2 = config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`;
7577
+ const endpoint = config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`;
7537
7578
  const respectDnt = config.respectDnt !== false;
7538
7579
  function isDntActive() {
7539
7580
  if (!respectDnt) return false;
@@ -7574,10 +7615,10 @@ function createAnalytics(config) {
7574
7615
  try {
7575
7616
  if (typeof navigator.sendBeacon === "function") {
7576
7617
  const blob = new Blob([body], { type: "text/plain" });
7577
- const sent = navigator.sendBeacon(endpoint2, blob);
7618
+ const sent = navigator.sendBeacon(endpoint, blob);
7578
7619
  if (sent) return;
7579
7620
  }
7580
- fetch(endpoint2, {
7621
+ fetch(endpoint, {
7581
7622
  method: "POST",
7582
7623
  keepalive: true,
7583
7624
  headers: { "Content-Type": "application/json" },