@01.software/sdk 0.70.1 → 0.72.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 (70) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/MIGRATION.md +28 -0
  3. package/README.md +253 -11
  4. package/dist/client.cjs +396 -26
  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 +396 -26
  9. package/dist/client.js.map +1 -1
  10. package/dist/{collection-client-BHLStm1K.d.cts → collection-client-B3CnqMDQ.d.cts} +14 -18
  11. package/dist/{collection-client-B1FSJ24_.d.ts → collection-client-uOgS_1bC.d.ts} +14 -18
  12. package/dist/{const-ty8u0TDI.d.ts → const-BJBK7jBl.d.ts} +1 -1
  13. package/dist/{const-BfQfV-rr.d.cts → const-_ZfJjRQG.d.cts} +1 -1
  14. package/dist/embedded-admin/server.cjs +117 -2
  15. package/dist/embedded-admin/server.cjs.map +1 -1
  16. package/dist/embedded-admin/server.d.cts +30 -2
  17. package/dist/embedded-admin/server.d.ts +30 -2
  18. package/dist/embedded-admin/server.js +117 -2
  19. package/dist/embedded-admin/server.js.map +1 -1
  20. package/dist/embedded-admin.cjs +135 -7
  21. package/dist/embedded-admin.cjs.map +1 -1
  22. package/dist/embedded-admin.d.cts +35 -2
  23. package/dist/embedded-admin.d.ts +35 -2
  24. package/dist/embedded-admin.js +135 -7
  25. package/dist/embedded-admin.js.map +1 -1
  26. package/dist/errors.cjs +2 -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 +2 -0
  31. package/dist/errors.js.map +1 -1
  32. package/dist/{index-DnKgjPGM.d.ts → index-CBaP4q8r.d.ts} +3 -3
  33. package/dist/{index-CX6si6YC.d.cts → index-CI_LFWiG.d.cts} +3 -3
  34. package/dist/index.cjs +396 -26
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +24 -9
  37. package/dist/index.d.ts +24 -9
  38. package/dist/index.js +396 -26
  39. package/dist/index.js.map +1 -1
  40. package/dist/{payload-types-DTAaWKrp.d.cts → payload-types-BRg8Yary.d.cts} +262 -177
  41. package/dist/{payload-types-DTAaWKrp.d.ts → payload-types-BRg8Yary.d.ts} +262 -177
  42. package/dist/query.cjs +20 -0
  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 +20 -0
  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 +459 -46
  51. package/dist/server.cjs.map +1 -1
  52. package/dist/server.d.cts +10 -8
  53. package/dist/server.d.ts +10 -8
  54. package/dist/server.js +459 -46
  55. package/dist/server.js.map +1 -1
  56. package/dist/storefront-cache.cjs +2 -0
  57. package/dist/storefront-cache.cjs.map +1 -1
  58. package/dist/storefront-cache.js +2 -0
  59. package/dist/storefront-cache.js.map +1 -1
  60. package/dist/{types-DdlhpNVv.d.ts → types-Cmnxxvuv.d.ts} +238 -21
  61. package/dist/{types-Bzgf4mTo.d.cts → types-CnkJQUez.d.cts} +238 -21
  62. package/dist/{types-DX8Z44yQ.d.ts → types-DLjSqL0P.d.ts} +2 -2
  63. package/dist/{types-CpSiyJud.d.cts → types-FyklqLAk.d.cts} +2 -2
  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.d.cts +5 -5
  69. package/dist/webhook.d.ts +5 -5
  70. package/package.json +2 -4
package/dist/index.js CHANGED
@@ -85,6 +85,7 @@ var COMMERCE_ERROR_CODES = [
85
85
  "cart_not_active",
86
86
  "cart_locked",
87
87
  "cart_empty",
88
+ "shipping_address_required",
88
89
  "cart_market_unavailable",
89
90
  "cart_market_mismatch",
90
91
  "checkout_not_open",
@@ -101,6 +102,7 @@ var COMMERCE_ERROR_CODES = [
101
102
  "price_changed",
102
103
  "pricing_fact_in_use",
103
104
  "insufficient_stock",
105
+ "credit_insufficient",
104
106
  "reservation_conflict",
105
107
  "stock_lock_unavailable",
106
108
  "variant_not_found",
@@ -564,6 +566,8 @@ async function parseErrorBody(response) {
564
566
  try {
565
567
  const body = await response.json();
566
568
  const reason = typeof body.reason === "string" ? body.reason : typeof body.code === "string" ? body.code : void 0;
569
+ const payloadErrorReason = Array.isArray(body.errors) ? readPayloadErrorReason(body.errors) : void 0;
570
+ const payloadReasonField = payloadErrorReason !== void 0 ? { payloadErrorReason } : {};
567
571
  if (body.errors && Array.isArray(body.errors)) {
568
572
  const fieldErrors = [];
569
573
  for (const e of body.errors) {
@@ -586,6 +590,7 @@ async function parseErrorBody(response) {
586
590
  errorMessage: `HTTP ${response.status}: ${details}`,
587
591
  userMessage: details,
588
592
  reason,
593
+ ...payloadReasonField,
589
594
  body,
590
595
  errors: fieldErrors.length > 0 ? fieldErrors : body.errors
591
596
  };
@@ -596,6 +601,7 @@ async function parseErrorBody(response) {
596
601
  errorMessage: `HTTP ${response.status}: ${body.error}`,
597
602
  userMessage: body.error,
598
603
  reason,
604
+ ...payloadReasonField,
599
605
  body
600
606
  };
601
607
  }
@@ -604,14 +610,23 @@ async function parseErrorBody(response) {
604
610
  errorMessage: `HTTP ${response.status}: ${body.message}`,
605
611
  userMessage: body.message,
606
612
  reason,
613
+ ...payloadReasonField,
607
614
  body
608
615
  };
609
616
  }
610
- return { ...fallback, reason, body };
617
+ return { ...fallback, reason, ...payloadReasonField, body };
611
618
  } catch {
612
619
  return fallback;
613
620
  }
614
621
  }
622
+ function readPayloadErrorReason(errors) {
623
+ const data = errors[0]?.data;
624
+ if (!data || typeof data !== "object") return void 0;
625
+ const { reason, code } = data;
626
+ if (typeof reason === "string") return reason;
627
+ if (typeof code === "string") return code;
628
+ return void 0;
629
+ }
615
630
  function getParsedErrorSuggestion(status, parsed) {
616
631
  if (status === 403 && parsed.reason === "origin_not_allowed") {
617
632
  return "Add the request origin to the tenant Browser API origins, then retry the browser request.";
@@ -657,7 +672,10 @@ function mapResponseToError(status, parsed, details, requestId, retryAfter, cano
657
672
  if (retryAfter !== void 0) {
658
673
  Object.assign(withRequestId, { retryAfter });
659
674
  }
660
- return canonicalCommerceError ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(withRequestId, parsed.reason);
675
+ return canonicalCommerceError ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(
676
+ withRequestId,
677
+ parsed.reason ?? parsed.payloadErrorReason
678
+ );
661
679
  };
662
680
  if (status === 400 || status === 422) {
663
681
  return finalize(
@@ -1076,6 +1094,7 @@ async function parseApiResponse(response, endpoint, options = {}) {
1076
1094
  // ../../internal/http-contracts/src/index.ts
1077
1095
  var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
1078
1096
  var PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE = "application/vnd.01software.portone-action-capabilities.v1+json";
1097
+ var CUSTOMER_CREDIT_FUNDING_MEDIA_TYPE = "application/vnd.01software.credit-funding.v1+json";
1079
1098
  var operation = (collection, method, path, errorFamily) => Object.freeze({
1080
1099
  [operationBrand]: true,
1081
1100
  collection,
@@ -1239,6 +1258,11 @@ var portOneStandardActionCapabilityOperations = /* @__PURE__ */ new Set([
1239
1258
  ]);
1240
1259
  var MEMBERSHIP_ENDPOINT_OPERATIONS = {
1241
1260
  subscribe: operation(null, "post", "/memberships/subscribe"),
1261
+ endSubscribeIntent: operation(
1262
+ null,
1263
+ "post",
1264
+ "/memberships/subscribe-intent/end"
1265
+ ),
1242
1266
  billingCustody: operation(null, "post", "/memberships/billing-custody"),
1243
1267
  cancel: operation(null, "post", "/memberships/:id/cancel"),
1244
1268
  me: operation(null, "get", "/memberships/me"),
@@ -1284,6 +1308,19 @@ var BENEFIT_VOUCHER_ENDPOINT_OPERATIONS = {
1284
1308
  void: operation("customers", "post", "/benefit-vouchers/void"),
1285
1309
  listMine: operation("customers", "get", "/me/benefit-vouchers")
1286
1310
  };
1311
+ var CUSTOMER_CREDIT_ENDPOINT_OPERATIONS = {
1312
+ grant: strictCommerceOperation("customers", "post", "/credits/grant"),
1313
+ getGrant: strictCommerceOperation("customers", "post", "/credits/get-grant"),
1314
+ getAccount: strictCommerceOperation("customers", "post", "/credits/account"),
1315
+ revoke: strictCommerceOperation("customers", "post", "/credits/revoke"),
1316
+ mine: strictCommerceOperation("customers", "get", "/me/credits"),
1317
+ history: strictCommerceOperation("customers", "get", "/me/credits/history"),
1318
+ configure: strictCommerceOperation(
1319
+ "customers",
1320
+ "post",
1321
+ "/credits/configuration"
1322
+ )
1323
+ };
1287
1324
  var CUSTOMER_GROUP_ENDPOINT_OPERATIONS = {
1288
1325
  members: operation("customer-groups", "get", "/:id/members"),
1289
1326
  grant: operation("customer-groups", "post", "/:id/members/grant"),
@@ -1673,6 +1710,140 @@ var CustomerBenefitVouchersApi = class extends CustomerScopedApi {
1673
1710
  }
1674
1711
  };
1675
1712
 
1713
+ // src/core/api/customer-credit-types.ts
1714
+ function invalid() {
1715
+ throw createApiError("Invalid customer credit response", 502);
1716
+ }
1717
+ function object2(value, keys) {
1718
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(value, key)))
1719
+ invalid();
1720
+ return value;
1721
+ }
1722
+ function money(value) {
1723
+ return typeof value === "string" && /^(0|[1-9][0-9]*)$/.test(value);
1724
+ }
1725
+ function uuid2(value) {
1726
+ return typeof value === "string" && /^([0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i.test(
1727
+ value
1728
+ );
1729
+ }
1730
+ function time2(value) {
1731
+ if (typeof value !== "string") return false;
1732
+ const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?Z$/.exec(value);
1733
+ if (!match) return false;
1734
+ const [, year, month, day, hour, minute, second = "0"] = match;
1735
+ const y = Number(year), m = Number(month), d = Number(day);
1736
+ const days = [
1737
+ 31,
1738
+ y % 4 === 0 && (y % 100 !== 0 || y % 400 === 0) ? 29 : 28,
1739
+ 31,
1740
+ 30,
1741
+ 31,
1742
+ 30,
1743
+ 31,
1744
+ 31,
1745
+ 30,
1746
+ 31,
1747
+ 30,
1748
+ 31
1749
+ ];
1750
+ return m >= 1 && m <= 12 && d >= 1 && d <= days[m - 1] && Number(hour) < 24 && Number(minute) < 60 && Number(second) < 60;
1751
+ }
1752
+ var states = ["available", "held", "spent", "expired", "revoked"];
1753
+ function balances(value) {
1754
+ const data = object2(value, states);
1755
+ if (states.some((key) => !money(data[key]))) invalid();
1756
+ }
1757
+ function page(value) {
1758
+ if (value.currency !== "KRW" || !time2(value.evaluatedAt) || !Number.isSafeInteger(value.page) || value.page < 1 || typeof value.hasNextPage !== "boolean")
1759
+ invalid();
1760
+ }
1761
+ function parseMyCustomerCredits(value) {
1762
+ const data = object2(value, [
1763
+ "currency",
1764
+ "evaluatedAt",
1765
+ "granted",
1766
+ "balances",
1767
+ "buckets",
1768
+ "page",
1769
+ "hasNextPage"
1770
+ ]);
1771
+ page(data);
1772
+ balances(data.balances);
1773
+ if (!money(data.granted) || !Array.isArray(data.buckets) || data.buckets.length > 50)
1774
+ invalid();
1775
+ for (const value2 of data.buckets) {
1776
+ const bucket = object2(value2, [
1777
+ "id",
1778
+ "grantId",
1779
+ "kind",
1780
+ "grantedAt",
1781
+ "expiresAt",
1782
+ "isRevoked",
1783
+ "balances"
1784
+ ]);
1785
+ if (!uuid2(bucket.id) || !uuid2(bucket.grantId) || !["original", "grace"].includes(bucket.kind) || !time2(bucket.grantedAt) || !time2(bucket.expiresAt) || typeof bucket.isRevoked !== "boolean")
1786
+ invalid();
1787
+ balances(bucket.balances);
1788
+ }
1789
+ return value;
1790
+ }
1791
+ function parseMyCustomerCreditHistory(value) {
1792
+ const data = object2(value, [
1793
+ "currency",
1794
+ "evaluatedAt",
1795
+ "entries",
1796
+ "page",
1797
+ "hasNextPage"
1798
+ ]);
1799
+ page(data);
1800
+ if (!Array.isArray(data.entries) || data.entries.length > 50) invalid();
1801
+ for (const value2 of data.entries) {
1802
+ const entry = object2(value2, [
1803
+ "id",
1804
+ "grantId",
1805
+ "kind",
1806
+ "amount",
1807
+ "fromState",
1808
+ "toState",
1809
+ "createdAt"
1810
+ ]);
1811
+ if (!uuid2(entry.id) || !uuid2(entry.grantId) || !money(entry.amount) || !time2(entry.createdAt) || ![
1812
+ "grant",
1813
+ "reserve",
1814
+ "consume",
1815
+ "release",
1816
+ "restore",
1817
+ "expire",
1818
+ "revoke"
1819
+ ].includes(entry.kind) || entry.fromState !== null && !states.includes(entry.fromState) || entry.toState !== null && !states.includes(entry.toState))
1820
+ invalid();
1821
+ }
1822
+ return value;
1823
+ }
1824
+
1825
+ // src/core/api/customer-credits-api.ts
1826
+ var CustomerCreditsApi = class extends CustomerScopedApi {
1827
+ async mine(params = {}) {
1828
+ const query = new URLSearchParams();
1829
+ if (params.page !== void 0) query.set("page", String(params.page));
1830
+ return parseMyCustomerCredits(
1831
+ await this.requestEndpoint(CUSTOMER_CREDIT_ENDPOINT_OPERATIONS.mine, void 0, {
1832
+ query
1833
+ })
1834
+ );
1835
+ }
1836
+ async history(params = {}) {
1837
+ const query = new URLSearchParams();
1838
+ if (params.page !== void 0) query.set("page", String(params.page));
1839
+ return parseMyCustomerCreditHistory(
1840
+ await this.requestEndpoint(CUSTOMER_CREDIT_ENDPOINT_OPERATIONS.history, void 0, {
1841
+ query
1842
+ })
1843
+ );
1844
+ }
1845
+ };
1846
+
1676
1847
  // src/core/collection/http-client.ts
1677
1848
  import { stringify } from "qs-esm";
1678
1849
  function validateWhere(where) {
@@ -2130,11 +2301,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
2130
2301
  * - `rootComment`: comments belonging to a thread rooted at that comment.
2131
2302
  */
2132
2303
  listComments(params) {
2133
- const { postId, page, limit, rootComment, topLevelOnly, sort } = params;
2304
+ const { postId, page: page2, limit, rootComment, topLevelOnly, sort } = params;
2134
2305
  return this.execute(
2135
2306
  this.buildCommentsListQuery({
2136
2307
  postId,
2137
- page,
2308
+ page: page2,
2138
2309
  limit,
2139
2310
  rootComment,
2140
2311
  topLevelOnly,
@@ -2145,11 +2316,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
2145
2316
  }
2146
2317
  /** Direct replies to a comment (`where[parent][equals]`). */
2147
2318
  listReplies(params) {
2148
- const { commentId, page, limit, sort } = params;
2319
+ const { commentId, page: page2, limit, sort } = params;
2149
2320
  return this.execute(
2150
2321
  this.buildCommentsListQuery({
2151
2322
  parentId: commentId,
2152
- page,
2323
+ page: page2,
2153
2324
  limit,
2154
2325
  sort
2155
2326
  }),
@@ -2406,7 +2577,18 @@ var ABANDONED_REASONS = ["expired", "customer", "operator"];
2406
2577
  function managedPaymentProviders(providers) {
2407
2578
  return providers;
2408
2579
  }
2409
- var PAYMENT_PROVIDERS = managedPaymentProviders(["toss", "portone"]);
2580
+ var PAYMENT_PROVIDERS = managedPaymentProviders([
2581
+ "toss",
2582
+ "portone",
2583
+ "stripe"
2584
+ ]);
2585
+ var CANCEL_RECOVERY_METHODS = {
2586
+ toss: "cancel()",
2587
+ portone: "cancelPortOne()",
2588
+ stripe: null
2589
+ };
2590
+ var STRIPE_RETURN_URL_RAW_CHARACTERS = /^[^\s\u0000-\u001F\u007F\\]+$/;
2591
+ var STRIPE_RETURN_URL_AUTHORITY = /^[A-Za-z][A-Za-z0-9+.-]*:\/\/[^/?#@]+(?:[/?#]|$)/;
2410
2592
  var PAYMENT_PROVIDER_STATUSES = [
2411
2593
  "requires_payment_method",
2412
2594
  "requires_action",
@@ -2455,11 +2637,8 @@ function fail(resource, path, expected) {
2455
2637
  invalidCanonicalResponse(resource, { path, expected });
2456
2638
  }
2457
2639
  function providerMismatch(resource, expected, actual, operation2) {
2458
- if (operation2 === "cancel") {
2459
- const method = {
2460
- toss: "cancel()",
2461
- portone: "cancelPortOne()"
2462
- }[actual];
2640
+ const method = CANCEL_RECOVERY_METHODS[actual];
2641
+ if (operation2 === "cancel" && method !== null) {
2463
2642
  throw createApiError(
2464
2643
  `Canonical ${resource} response provider mismatch: expected ${expected}, received ${actual}.`,
2465
2644
  502,
@@ -2488,6 +2667,17 @@ function exact(value, required, optional, resource, path) {
2488
2667
  const unexpected = Object.keys(value).find((key) => !allowed.has(key));
2489
2668
  if (unexpected) fail(resource, `${path}.${unexpected}`, "no unknown fields");
2490
2669
  }
2670
+ function responseExtensionKeys(value, keys, resource, path) {
2671
+ if (!keys.some((key) => Object.prototype.hasOwnProperty.call(value, key)))
2672
+ return [];
2673
+ enumValue(
2674
+ value.deliveryMethod,
2675
+ ["shipping", "pickup"],
2676
+ resource,
2677
+ `${path}.deliveryMethod`
2678
+ );
2679
+ return [...keys];
2680
+ }
2491
2681
  function string(value, resource, path) {
2492
2682
  if (typeof value !== "string" || value.length === 0) {
2493
2683
  fail(resource, path, "non-empty string");
@@ -2827,6 +3017,12 @@ function validatePublicCart(value, resource = "Cart") {
2827
3017
  exact(
2828
3018
  cart,
2829
3019
  [
3020
+ ...responseExtensionKeys(
3021
+ cart,
3022
+ ["deliveryMethod", "shippingMinor", "totalMinor"],
3023
+ resource,
3024
+ "$"
3025
+ ),
2830
3026
  "id",
2831
3027
  "status",
2832
3028
  "revision",
@@ -2897,6 +3093,13 @@ function validatePublicCart(value, resource = "Cart") {
2897
3093
  if (expectedSubtotal - BigInt(discount) < 0n || BigInt(estimatedTotal) !== expectedSubtotal - BigInt(discount)) {
2898
3094
  fail(resource, "$.estimatedTotalMinor", "subtotalMinor - discountMinor");
2899
3095
  }
3096
+ if ("deliveryMethod" in cart) {
3097
+ const shipping = safeMinor(cart.shippingMinor, resource, "$.shippingMinor");
3098
+ const total = safeMinor(cart.totalMinor, resource, "$.totalMinor");
3099
+ if (BigInt(total) !== BigInt(estimatedTotal) + BigInt(shipping)) {
3100
+ fail(resource, "$.totalMinor", "estimatedTotalMinor + shippingMinor");
3101
+ }
3102
+ }
2900
3103
  timestamp(cart.expiresAt, resource, "$.expiresAt");
2901
3104
  timestamp(cart.createdAt, resource, "$.createdAt");
2902
3105
  timestamp(cart.updatedAt, resource, "$.updatedAt");
@@ -3055,6 +3258,12 @@ function validatePublicOrderAt(value, resource, path) {
3055
3258
  exact(
3056
3259
  order,
3057
3260
  [
3261
+ ...responseExtensionKeys(
3262
+ order,
3263
+ ["deliveryMethod", "pickup", "source"],
3264
+ resource,
3265
+ path
3266
+ ),
3058
3267
  "id",
3059
3268
  "orderNumber",
3060
3269
  "amounts",
@@ -3076,6 +3285,37 @@ function validatePublicOrderAt(value, resource, path) {
3076
3285
  resource,
3077
3286
  path
3078
3287
  );
3288
+ if ("deliveryMethod" in order) {
3289
+ enumValue(
3290
+ order.source,
3291
+ ["web", "app", "manual", "api", "import", "in_person"],
3292
+ resource,
3293
+ `${path}.source`
3294
+ );
3295
+ if (order.deliveryMethod === "shipping") {
3296
+ if (order.pickup !== null)
3297
+ fail(resource, `${path}.pickup`, "null for shipping");
3298
+ } else {
3299
+ const pickup = record(order.pickup, resource, `${path}.pickup`);
3300
+ exact(
3301
+ pickup,
3302
+ ["status", "readyAt", "pickedUpAt"],
3303
+ [],
3304
+ resource,
3305
+ `${path}.pickup`
3306
+ );
3307
+ enumValue(
3308
+ pickup.status,
3309
+ ["pending", "ready_for_pickup", "picked_up", "canceled"],
3310
+ resource,
3311
+ `${path}.pickup.status`
3312
+ );
3313
+ for (const key of ["readyAt", "pickedUpAt"]) {
3314
+ if (pickup[key] !== null)
3315
+ timestamp(pickup[key], resource, `${path}.pickup.${key}`);
3316
+ }
3317
+ }
3318
+ }
3079
3319
  string(order.id, resource, `${path}.id`);
3080
3320
  string(order.orderNumber, resource, `${path}.orderNumber`);
3081
3321
  const amounts = record(order.amounts, resource, `${path}.amounts`);
@@ -3396,6 +3636,17 @@ function validateCheckoutCore(value, resource, list, server) {
3396
3636
  "$.status"
3397
3637
  );
3398
3638
  const keys = checkoutVariantKeys(status, checkout.placedVia);
3639
+ keys.required.push(
3640
+ ...responseExtensionKeys(
3641
+ checkout,
3642
+ ["deliveryMethod", "source"],
3643
+ resource,
3644
+ "$"
3645
+ )
3646
+ );
3647
+ if ("deliveryMethod" in checkout)
3648
+ enumValue(checkout.source, ["web", "in_person"], resource, "$.source");
3649
+ keys.optional.push("funding");
3399
3650
  if (list) {
3400
3651
  keys.required = keys.required.filter(
3401
3652
  (key) => !["items", "shippingAddress", "attributes"].includes(key)
@@ -3407,6 +3658,33 @@ function validateCheckoutCore(value, resource, list, server) {
3407
3658
  exact(checkout, keys.required, keys.optional, resource, "$");
3408
3659
  string(checkout.id, resource, "$.id");
3409
3660
  validateCheckoutAmounts(checkout.amounts, resource, "$.amounts");
3661
+ if (Object.prototype.hasOwnProperty.call(checkout, "funding")) {
3662
+ const funding = record(checkout.funding, resource, "$.funding");
3663
+ exact(
3664
+ funding,
3665
+ ["creditAmount", "providerPayableAmount"],
3666
+ [],
3667
+ resource,
3668
+ "$.funding"
3669
+ );
3670
+ const credit = safeMinor(
3671
+ funding.creditAmount,
3672
+ resource,
3673
+ "$.funding.creditAmount"
3674
+ );
3675
+ const provider = safeMinor(
3676
+ funding.providerPayableAmount,
3677
+ resource,
3678
+ "$.funding.providerPayableAmount"
3679
+ );
3680
+ const amounts = checkout.amounts;
3681
+ if (BigInt(credit) + BigInt(provider) !== BigInt(amounts.totalMinor) || credit > 0 && amounts.currency !== "KRW")
3682
+ fail(
3683
+ resource,
3684
+ "$.funding",
3685
+ "exact purchase total split; positive credits require KRW"
3686
+ );
3687
+ }
3410
3688
  if (!list) {
3411
3689
  const items = array(checkout.items, resource, "$.items");
3412
3690
  if (items.length === 0) fail(resource, "$.items", "non-empty array");
@@ -3565,10 +3843,10 @@ function validateCheckoutQueryResult(value) {
3565
3843
  return value;
3566
3844
  }
3567
3845
  function validateMoney(value, resource, path) {
3568
- const money = record(value, resource, path);
3569
- exact(money, ["amountMinor", "currency"], [], resource, path);
3570
- safeMinor(money.amountMinor, resource, `${path}.amountMinor`);
3571
- currency(money.currency, resource, `${path}.currency`);
3846
+ const money2 = record(value, resource, path);
3847
+ exact(money2, ["amountMinor", "currency"], [], resource, path);
3848
+ safeMinor(money2.amountMinor, resource, `${path}.amountMinor`);
3849
+ currency(money2.currency, resource, `${path}.currency`);
3572
3850
  }
3573
3851
  function validateCaptureEvidence(value, resource, path) {
3574
3852
  const evidence = record(value, resource, path);
@@ -3604,6 +3882,65 @@ function validateRequiredReconciliation(value, allowed, resource, path) {
3604
3882
  }
3605
3883
  function validateNextAction(value, provider, resource, path) {
3606
3884
  const action = record(value, resource, path);
3885
+ if (provider === "stripe") {
3886
+ exact(
3887
+ action,
3888
+ ["type", "clientSecret", "publishableKey", "returnUrl"],
3889
+ [],
3890
+ resource,
3891
+ path
3892
+ );
3893
+ if (action.type !== "stripe_payment_element")
3894
+ fail(resource, `${path}.type`, "stripe_payment_element");
3895
+ const clientSecret = boundedString(
3896
+ action.clientSecret,
3897
+ 255,
3898
+ resource,
3899
+ `${path}.clientSecret`
3900
+ );
3901
+ if (!/^pi_[A-Za-z0-9]+_secret_[A-Za-z0-9]+$/.test(clientSecret)) {
3902
+ fail(
3903
+ resource,
3904
+ `${path}.clientSecret`,
3905
+ "Stripe PaymentIntent client secret"
3906
+ );
3907
+ }
3908
+ const publishableKey = boundedString(
3909
+ action.publishableKey,
3910
+ 255,
3911
+ resource,
3912
+ `${path}.publishableKey`
3913
+ );
3914
+ if (!/^pk_(?:test|live)_[A-Za-z0-9]+$/.test(publishableKey)) {
3915
+ fail(resource, `${path}.publishableKey`, "Stripe publishable key");
3916
+ }
3917
+ const returnUrl = boundedString(
3918
+ action.returnUrl,
3919
+ 2048,
3920
+ resource,
3921
+ `${path}.returnUrl`
3922
+ );
3923
+ if (!STRIPE_RETURN_URL_RAW_CHARACTERS.test(returnUrl) || !STRIPE_RETURN_URL_AUTHORITY.test(returnUrl)) {
3924
+ fail(
3925
+ resource,
3926
+ `${path}.returnUrl`,
3927
+ "HTTPS or loopback URL without embedded credentials"
3928
+ );
3929
+ }
3930
+ try {
3931
+ const parsed = new URL(returnUrl);
3932
+ const loopback = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
3933
+ if (!loopback && parsed.protocol !== "https:" || parsed.username || parsed.password)
3934
+ throw new Error("unsafe return URL");
3935
+ } catch {
3936
+ fail(
3937
+ resource,
3938
+ `${path}.returnUrl`,
3939
+ "HTTPS or loopback URL without embedded credentials"
3940
+ );
3941
+ }
3942
+ return;
3943
+ }
3607
3944
  if (provider === "portone") {
3608
3945
  if (action.type === "portone_sdk") {
3609
3946
  const hasCancelable = "cancelable" in action;
@@ -3979,7 +4316,7 @@ function validatePublicPaymentSession(value, expectedProvider, operation2) {
3979
4316
  );
3980
4317
  }
3981
4318
  if (expectedProvider !== void 0 && provider !== expectedProvider) {
3982
- if (operation2 === "cancel" && status !== "canceling" && status !== "canceled") {
4319
+ if (operation2 === "cancel" && CANCEL_RECOVERY_METHODS[provider] !== null && status !== "canceling" && status !== "canceled") {
3983
4320
  fail(
3984
4321
  resource,
3985
4322
  "$.providerStatus",
@@ -4875,8 +5212,9 @@ var CheckoutApi = class extends CustomerScopedApi {
4875
5212
  }
4876
5213
  post(endpoint, body, idempotencyKey) {
4877
5214
  return this.requestEndpoint(endpoint, body, {
4878
- ...idempotencyKey && {
4879
- headers: { "X-Idempotency-Key": idempotencyKey }
5215
+ headers: {
5216
+ Accept: CUSTOMER_CREDIT_FUNDING_MEDIA_TYPE,
5217
+ ...idempotencyKey && { "X-Idempotency-Key": idempotencyKey }
4880
5218
  }
4881
5219
  });
4882
5220
  }
@@ -4886,34 +5224,58 @@ var CheckoutApi = class extends CustomerScopedApi {
4886
5224
  async serverCheckout(result) {
4887
5225
  return validateServerCheckout(await result);
4888
5226
  }
4889
- async createResult(result) {
4890
- return validateCreateCheckoutResult(
5227
+ async createResult(result, creditAmount) {
5228
+ const parsed = validateCreateCheckoutResult(
4891
5229
  await result,
4892
5230
  false
4893
5231
  );
5232
+ this.assertRequestedCredit(parsed.checkout, creditAmount);
5233
+ return parsed;
4894
5234
  }
4895
- async createServerResult(result) {
4896
- return validateCreateCheckoutResult(
5235
+ async createServerResult(result, creditAmount) {
5236
+ const parsed = validateCreateCheckoutResult(
4897
5237
  await result,
4898
5238
  true
4899
5239
  );
5240
+ this.assertRequestedCredit(parsed.checkout, creditAmount);
5241
+ return parsed;
5242
+ }
5243
+ assertCreditInput(amount) {
5244
+ if (amount !== void 0 && (!Number.isSafeInteger(amount) || amount <= 0))
5245
+ throw createValidationError(
5246
+ "creditAmount must be a positive safe integer."
5247
+ );
5248
+ }
5249
+ assertRequestedCredit(checkout, requested) {
5250
+ if (requested !== void 0 && checkout.funding?.creditAmount !== requested)
5251
+ throw createApiError(
5252
+ "Credit funding was not confirmed by the server.",
5253
+ 502,
5254
+ { resource: "Checkout", path: "$.funding" },
5255
+ "The response does not confirm the requested credit funding.",
5256
+ "Retry the same create with the original idempotency key and credit amount, or retrieve the Checkout; never retry without credit."
5257
+ );
4900
5258
  }
4901
5259
  create(params) {
4902
5260
  const { idempotencyKey, ...body } = params;
4903
5261
  assertCommerceIdempotencyKey(idempotencyKey);
5262
+ this.assertCreditInput(body.creditAmount);
4904
5263
  return this.createResult(
4905
- this.post(COMMERCE_ENDPOINTS.checkouts.create, body, idempotencyKey)
5264
+ this.post(COMMERCE_ENDPOINTS.checkouts.create, body, idempotencyKey),
5265
+ body.creditAmount
4906
5266
  );
4907
5267
  }
4908
5268
  createServer(params) {
4909
5269
  const { idempotencyKey, ...body } = params;
4910
5270
  assertCommerceIdempotencyKey(idempotencyKey);
5271
+ this.assertCreditInput(body.creditAmount);
4911
5272
  return this.createServerResult(
4912
5273
  this.post(
4913
5274
  COMMERCE_ENDPOINTS.checkouts.server.create,
4914
5275
  body,
4915
5276
  idempotencyKey
4916
- )
5277
+ ),
5278
+ body.creditAmount
4917
5279
  );
4918
5280
  }
4919
5281
  retrieve(params) {
@@ -7291,6 +7653,13 @@ var Client = class _Client {
7291
7653
  this.markets = new MarketDiscovery(
7292
7654
  (options2) => this.collections.from("markets").find(options2)
7293
7655
  );
7656
+ this.credits = new CustomerCreditsApi("CustomerCreditsApi", {
7657
+ publishableKey: this.config.publishableKey,
7658
+ apiUrl: this.config.apiUrl,
7659
+ customerToken: () => this.customer.auth.getToken(),
7660
+ onUnauthorized,
7661
+ onRequestId
7662
+ });
7294
7663
  this.benefitVouchers = new CustomerBenefitVouchersApi(
7295
7664
  "CustomerBenefitVouchersApi",
7296
7665
  {
@@ -7321,7 +7690,8 @@ var Client = class _Client {
7321
7690
  ...this.config,
7322
7691
  customer: this.config.customer?.persist === false ? {
7323
7692
  ...this.config.customer,
7324
- token: this.customer.auth.getToken() ?? void 0
7693
+ token: this.customer.auth.getToken() ?? void 0,
7694
+ refreshToken: this.customer.auth.getRefreshToken() ?? void 0
7325
7695
  } : this.config.customer,
7326
7696
  market
7327
7697
  });