@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/client.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) {
@@ -2123,11 +2294,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
2123
2294
  * - `rootComment`: comments belonging to a thread rooted at that comment.
2124
2295
  */
2125
2296
  listComments(params) {
2126
- const { postId, page, limit, rootComment, topLevelOnly, sort } = params;
2297
+ const { postId, page: page2, limit, rootComment, topLevelOnly, sort } = params;
2127
2298
  return this.execute(
2128
2299
  this.buildCommentsListQuery({
2129
2300
  postId,
2130
- page,
2301
+ page: page2,
2131
2302
  limit,
2132
2303
  rootComment,
2133
2304
  topLevelOnly,
@@ -2138,11 +2309,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
2138
2309
  }
2139
2310
  /** Direct replies to a comment (`where[parent][equals]`). */
2140
2311
  listReplies(params) {
2141
- const { commentId, page, limit, sort } = params;
2312
+ const { commentId, page: page2, limit, sort } = params;
2142
2313
  return this.execute(
2143
2314
  this.buildCommentsListQuery({
2144
2315
  parentId: commentId,
2145
- page,
2316
+ page: page2,
2146
2317
  limit,
2147
2318
  sort
2148
2319
  }),
@@ -2399,7 +2570,18 @@ var ABANDONED_REASONS = ["expired", "customer", "operator"];
2399
2570
  function managedPaymentProviders(providers) {
2400
2571
  return providers;
2401
2572
  }
2402
- var PAYMENT_PROVIDERS = managedPaymentProviders(["toss", "portone"]);
2573
+ var PAYMENT_PROVIDERS = managedPaymentProviders([
2574
+ "toss",
2575
+ "portone",
2576
+ "stripe"
2577
+ ]);
2578
+ var CANCEL_RECOVERY_METHODS = {
2579
+ toss: "cancel()",
2580
+ portone: "cancelPortOne()",
2581
+ stripe: null
2582
+ };
2583
+ var STRIPE_RETURN_URL_RAW_CHARACTERS = /^[^\s\u0000-\u001F\u007F\\]+$/;
2584
+ var STRIPE_RETURN_URL_AUTHORITY = /^[A-Za-z][A-Za-z0-9+.-]*:\/\/[^/?#@]+(?:[/?#]|$)/;
2403
2585
  var PAYMENT_PROVIDER_STATUSES = [
2404
2586
  "requires_payment_method",
2405
2587
  "requires_action",
@@ -2448,11 +2630,8 @@ function fail(resource, path, expected) {
2448
2630
  invalidCanonicalResponse(resource, { path, expected });
2449
2631
  }
2450
2632
  function providerMismatch(resource, expected, actual, operation2) {
2451
- if (operation2 === "cancel") {
2452
- const method = {
2453
- toss: "cancel()",
2454
- portone: "cancelPortOne()"
2455
- }[actual];
2633
+ const method = CANCEL_RECOVERY_METHODS[actual];
2634
+ if (operation2 === "cancel" && method !== null) {
2456
2635
  throw createApiError(
2457
2636
  `Canonical ${resource} response provider mismatch: expected ${expected}, received ${actual}.`,
2458
2637
  502,
@@ -2481,6 +2660,17 @@ function exact(value, required, optional, resource, path) {
2481
2660
  const unexpected = Object.keys(value).find((key) => !allowed.has(key));
2482
2661
  if (unexpected) fail(resource, `${path}.${unexpected}`, "no unknown fields");
2483
2662
  }
2663
+ function responseExtensionKeys(value, keys, resource, path) {
2664
+ if (!keys.some((key) => Object.prototype.hasOwnProperty.call(value, key)))
2665
+ return [];
2666
+ enumValue(
2667
+ value.deliveryMethod,
2668
+ ["shipping", "pickup"],
2669
+ resource,
2670
+ `${path}.deliveryMethod`
2671
+ );
2672
+ return [...keys];
2673
+ }
2484
2674
  function string(value, resource, path) {
2485
2675
  if (typeof value !== "string" || value.length === 0) {
2486
2676
  fail(resource, path, "non-empty string");
@@ -2820,6 +3010,12 @@ function validatePublicCart(value, resource = "Cart") {
2820
3010
  exact(
2821
3011
  cart,
2822
3012
  [
3013
+ ...responseExtensionKeys(
3014
+ cart,
3015
+ ["deliveryMethod", "shippingMinor", "totalMinor"],
3016
+ resource,
3017
+ "$"
3018
+ ),
2823
3019
  "id",
2824
3020
  "status",
2825
3021
  "revision",
@@ -2890,6 +3086,13 @@ function validatePublicCart(value, resource = "Cart") {
2890
3086
  if (expectedSubtotal - BigInt(discount) < 0n || BigInt(estimatedTotal) !== expectedSubtotal - BigInt(discount)) {
2891
3087
  fail(resource, "$.estimatedTotalMinor", "subtotalMinor - discountMinor");
2892
3088
  }
3089
+ if ("deliveryMethod" in cart) {
3090
+ const shipping = safeMinor(cart.shippingMinor, resource, "$.shippingMinor");
3091
+ const total = safeMinor(cart.totalMinor, resource, "$.totalMinor");
3092
+ if (BigInt(total) !== BigInt(estimatedTotal) + BigInt(shipping)) {
3093
+ fail(resource, "$.totalMinor", "estimatedTotalMinor + shippingMinor");
3094
+ }
3095
+ }
2893
3096
  timestamp(cart.expiresAt, resource, "$.expiresAt");
2894
3097
  timestamp(cart.createdAt, resource, "$.createdAt");
2895
3098
  timestamp(cart.updatedAt, resource, "$.updatedAt");
@@ -3048,6 +3251,12 @@ function validatePublicOrderAt(value, resource, path) {
3048
3251
  exact(
3049
3252
  order,
3050
3253
  [
3254
+ ...responseExtensionKeys(
3255
+ order,
3256
+ ["deliveryMethod", "pickup", "source"],
3257
+ resource,
3258
+ path
3259
+ ),
3051
3260
  "id",
3052
3261
  "orderNumber",
3053
3262
  "amounts",
@@ -3069,6 +3278,37 @@ function validatePublicOrderAt(value, resource, path) {
3069
3278
  resource,
3070
3279
  path
3071
3280
  );
3281
+ if ("deliveryMethod" in order) {
3282
+ enumValue(
3283
+ order.source,
3284
+ ["web", "app", "manual", "api", "import", "in_person"],
3285
+ resource,
3286
+ `${path}.source`
3287
+ );
3288
+ if (order.deliveryMethod === "shipping") {
3289
+ if (order.pickup !== null)
3290
+ fail(resource, `${path}.pickup`, "null for shipping");
3291
+ } else {
3292
+ const pickup = record(order.pickup, resource, `${path}.pickup`);
3293
+ exact(
3294
+ pickup,
3295
+ ["status", "readyAt", "pickedUpAt"],
3296
+ [],
3297
+ resource,
3298
+ `${path}.pickup`
3299
+ );
3300
+ enumValue(
3301
+ pickup.status,
3302
+ ["pending", "ready_for_pickup", "picked_up", "canceled"],
3303
+ resource,
3304
+ `${path}.pickup.status`
3305
+ );
3306
+ for (const key of ["readyAt", "pickedUpAt"]) {
3307
+ if (pickup[key] !== null)
3308
+ timestamp(pickup[key], resource, `${path}.pickup.${key}`);
3309
+ }
3310
+ }
3311
+ }
3072
3312
  string(order.id, resource, `${path}.id`);
3073
3313
  string(order.orderNumber, resource, `${path}.orderNumber`);
3074
3314
  const amounts = record(order.amounts, resource, `${path}.amounts`);
@@ -3389,6 +3629,17 @@ function validateCheckoutCore(value, resource, list, server) {
3389
3629
  "$.status"
3390
3630
  );
3391
3631
  const keys = checkoutVariantKeys(status, checkout.placedVia);
3632
+ keys.required.push(
3633
+ ...responseExtensionKeys(
3634
+ checkout,
3635
+ ["deliveryMethod", "source"],
3636
+ resource,
3637
+ "$"
3638
+ )
3639
+ );
3640
+ if ("deliveryMethod" in checkout)
3641
+ enumValue(checkout.source, ["web", "in_person"], resource, "$.source");
3642
+ keys.optional.push("funding");
3392
3643
  if (list) {
3393
3644
  keys.required = keys.required.filter(
3394
3645
  (key) => !["items", "shippingAddress", "attributes"].includes(key)
@@ -3400,6 +3651,33 @@ function validateCheckoutCore(value, resource, list, server) {
3400
3651
  exact(checkout, keys.required, keys.optional, resource, "$");
3401
3652
  string(checkout.id, resource, "$.id");
3402
3653
  validateCheckoutAmounts(checkout.amounts, resource, "$.amounts");
3654
+ if (Object.prototype.hasOwnProperty.call(checkout, "funding")) {
3655
+ const funding = record(checkout.funding, resource, "$.funding");
3656
+ exact(
3657
+ funding,
3658
+ ["creditAmount", "providerPayableAmount"],
3659
+ [],
3660
+ resource,
3661
+ "$.funding"
3662
+ );
3663
+ const credit = safeMinor(
3664
+ funding.creditAmount,
3665
+ resource,
3666
+ "$.funding.creditAmount"
3667
+ );
3668
+ const provider = safeMinor(
3669
+ funding.providerPayableAmount,
3670
+ resource,
3671
+ "$.funding.providerPayableAmount"
3672
+ );
3673
+ const amounts = checkout.amounts;
3674
+ if (BigInt(credit) + BigInt(provider) !== BigInt(amounts.totalMinor) || credit > 0 && amounts.currency !== "KRW")
3675
+ fail(
3676
+ resource,
3677
+ "$.funding",
3678
+ "exact purchase total split; positive credits require KRW"
3679
+ );
3680
+ }
3403
3681
  if (!list) {
3404
3682
  const items = array(checkout.items, resource, "$.items");
3405
3683
  if (items.length === 0) fail(resource, "$.items", "non-empty array");
@@ -3558,10 +3836,10 @@ function validateCheckoutQueryResult(value) {
3558
3836
  return value;
3559
3837
  }
3560
3838
  function validateMoney(value, resource, path) {
3561
- const money = record(value, resource, path);
3562
- exact(money, ["amountMinor", "currency"], [], resource, path);
3563
- safeMinor(money.amountMinor, resource, `${path}.amountMinor`);
3564
- currency(money.currency, resource, `${path}.currency`);
3839
+ const money2 = record(value, resource, path);
3840
+ exact(money2, ["amountMinor", "currency"], [], resource, path);
3841
+ safeMinor(money2.amountMinor, resource, `${path}.amountMinor`);
3842
+ currency(money2.currency, resource, `${path}.currency`);
3565
3843
  }
3566
3844
  function validateCaptureEvidence(value, resource, path) {
3567
3845
  const evidence = record(value, resource, path);
@@ -3597,6 +3875,65 @@ function validateRequiredReconciliation(value, allowed, resource, path) {
3597
3875
  }
3598
3876
  function validateNextAction(value, provider, resource, path) {
3599
3877
  const action = record(value, resource, path);
3878
+ if (provider === "stripe") {
3879
+ exact(
3880
+ action,
3881
+ ["type", "clientSecret", "publishableKey", "returnUrl"],
3882
+ [],
3883
+ resource,
3884
+ path
3885
+ );
3886
+ if (action.type !== "stripe_payment_element")
3887
+ fail(resource, `${path}.type`, "stripe_payment_element");
3888
+ const clientSecret = boundedString(
3889
+ action.clientSecret,
3890
+ 255,
3891
+ resource,
3892
+ `${path}.clientSecret`
3893
+ );
3894
+ if (!/^pi_[A-Za-z0-9]+_secret_[A-Za-z0-9]+$/.test(clientSecret)) {
3895
+ fail(
3896
+ resource,
3897
+ `${path}.clientSecret`,
3898
+ "Stripe PaymentIntent client secret"
3899
+ );
3900
+ }
3901
+ const publishableKey = boundedString(
3902
+ action.publishableKey,
3903
+ 255,
3904
+ resource,
3905
+ `${path}.publishableKey`
3906
+ );
3907
+ if (!/^pk_(?:test|live)_[A-Za-z0-9]+$/.test(publishableKey)) {
3908
+ fail(resource, `${path}.publishableKey`, "Stripe publishable key");
3909
+ }
3910
+ const returnUrl = boundedString(
3911
+ action.returnUrl,
3912
+ 2048,
3913
+ resource,
3914
+ `${path}.returnUrl`
3915
+ );
3916
+ if (!STRIPE_RETURN_URL_RAW_CHARACTERS.test(returnUrl) || !STRIPE_RETURN_URL_AUTHORITY.test(returnUrl)) {
3917
+ fail(
3918
+ resource,
3919
+ `${path}.returnUrl`,
3920
+ "HTTPS or loopback URL without embedded credentials"
3921
+ );
3922
+ }
3923
+ try {
3924
+ const parsed = new URL(returnUrl);
3925
+ const loopback = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
3926
+ if (!loopback && parsed.protocol !== "https:" || parsed.username || parsed.password)
3927
+ throw new Error("unsafe return URL");
3928
+ } catch {
3929
+ fail(
3930
+ resource,
3931
+ `${path}.returnUrl`,
3932
+ "HTTPS or loopback URL without embedded credentials"
3933
+ );
3934
+ }
3935
+ return;
3936
+ }
3600
3937
  if (provider === "portone") {
3601
3938
  if (action.type === "portone_sdk") {
3602
3939
  const hasCancelable = "cancelable" in action;
@@ -3972,7 +4309,7 @@ function validatePublicPaymentSession(value, expectedProvider, operation2) {
3972
4309
  );
3973
4310
  }
3974
4311
  if (expectedProvider !== void 0 && provider !== expectedProvider) {
3975
- if (operation2 === "cancel" && status !== "canceling" && status !== "canceled") {
4312
+ if (operation2 === "cancel" && CANCEL_RECOVERY_METHODS[provider] !== null && status !== "canceling" && status !== "canceled") {
3976
4313
  fail(
3977
4314
  resource,
3978
4315
  "$.providerStatus",
@@ -4864,8 +5201,9 @@ var CheckoutApi = class extends CustomerScopedApi {
4864
5201
  }
4865
5202
  post(endpoint, body, idempotencyKey) {
4866
5203
  return this.requestEndpoint(endpoint, body, {
4867
- ...idempotencyKey && {
4868
- headers: { "X-Idempotency-Key": idempotencyKey }
5204
+ headers: {
5205
+ Accept: CUSTOMER_CREDIT_FUNDING_MEDIA_TYPE,
5206
+ ...idempotencyKey && { "X-Idempotency-Key": idempotencyKey }
4869
5207
  }
4870
5208
  });
4871
5209
  }
@@ -4875,34 +5213,58 @@ var CheckoutApi = class extends CustomerScopedApi {
4875
5213
  async serverCheckout(result) {
4876
5214
  return validateServerCheckout(await result);
4877
5215
  }
4878
- async createResult(result) {
4879
- return validateCreateCheckoutResult(
5216
+ async createResult(result, creditAmount) {
5217
+ const parsed = validateCreateCheckoutResult(
4880
5218
  await result,
4881
5219
  false
4882
5220
  );
5221
+ this.assertRequestedCredit(parsed.checkout, creditAmount);
5222
+ return parsed;
4883
5223
  }
4884
- async createServerResult(result) {
4885
- return validateCreateCheckoutResult(
5224
+ async createServerResult(result, creditAmount) {
5225
+ const parsed = validateCreateCheckoutResult(
4886
5226
  await result,
4887
5227
  true
4888
5228
  );
5229
+ this.assertRequestedCredit(parsed.checkout, creditAmount);
5230
+ return parsed;
5231
+ }
5232
+ assertCreditInput(amount) {
5233
+ if (amount !== void 0 && (!Number.isSafeInteger(amount) || amount <= 0))
5234
+ throw createValidationError(
5235
+ "creditAmount must be a positive safe integer."
5236
+ );
5237
+ }
5238
+ assertRequestedCredit(checkout, requested) {
5239
+ if (requested !== void 0 && checkout.funding?.creditAmount !== requested)
5240
+ throw createApiError(
5241
+ "Credit funding was not confirmed by the server.",
5242
+ 502,
5243
+ { resource: "Checkout", path: "$.funding" },
5244
+ "The response does not confirm the requested credit funding.",
5245
+ "Retry the same create with the original idempotency key and credit amount, or retrieve the Checkout; never retry without credit."
5246
+ );
4889
5247
  }
4890
5248
  create(params) {
4891
5249
  const { idempotencyKey, ...body } = params;
4892
5250
  assertCommerceIdempotencyKey(idempotencyKey);
5251
+ this.assertCreditInput(body.creditAmount);
4893
5252
  return this.createResult(
4894
- this.post(COMMERCE_ENDPOINTS.checkouts.create, body, idempotencyKey)
5253
+ this.post(COMMERCE_ENDPOINTS.checkouts.create, body, idempotencyKey),
5254
+ body.creditAmount
4895
5255
  );
4896
5256
  }
4897
5257
  createServer(params) {
4898
5258
  const { idempotencyKey, ...body } = params;
4899
5259
  assertCommerceIdempotencyKey(idempotencyKey);
5260
+ this.assertCreditInput(body.creditAmount);
4900
5261
  return this.createServerResult(
4901
5262
  this.post(
4902
5263
  COMMERCE_ENDPOINTS.checkouts.server.create,
4903
5264
  body,
4904
5265
  idempotencyKey
4905
- )
5266
+ ),
5267
+ body.creditAmount
4906
5268
  );
4907
5269
  }
4908
5270
  retrieve(params) {
@@ -6564,6 +6926,13 @@ var Client = class _Client {
6564
6926
  this.markets = new MarketDiscovery(
6565
6927
  (options2) => this.collections.from("markets").find(options2)
6566
6928
  );
6929
+ this.credits = new CustomerCreditsApi("CustomerCreditsApi", {
6930
+ publishableKey: this.config.publishableKey,
6931
+ apiUrl: this.config.apiUrl,
6932
+ customerToken: () => this.customer.auth.getToken(),
6933
+ onUnauthorized,
6934
+ onRequestId
6935
+ });
6567
6936
  this.benefitVouchers = new CustomerBenefitVouchersApi(
6568
6937
  "CustomerBenefitVouchersApi",
6569
6938
  {
@@ -6594,7 +6963,8 @@ var Client = class _Client {
6594
6963
  ...this.config,
6595
6964
  customer: this.config.customer?.persist === false ? {
6596
6965
  ...this.config.customer,
6597
- token: this.customer.auth.getToken() ?? void 0
6966
+ token: this.customer.auth.getToken() ?? void 0,
6967
+ refreshToken: this.customer.auth.getRefreshToken() ?? void 0
6598
6968
  } : this.config.customer,
6599
6969
  market
6600
6970
  });