@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.
- package/CHANGELOG.md +143 -0
- package/MIGRATION.md +28 -0
- package/README.md +253 -11
- package/dist/client.cjs +396 -26
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +7 -6
- package/dist/client.d.ts +7 -6
- package/dist/client.js +396 -26
- package/dist/client.js.map +1 -1
- package/dist/{collection-client-BHLStm1K.d.cts → collection-client-B3CnqMDQ.d.cts} +14 -18
- package/dist/{collection-client-B1FSJ24_.d.ts → collection-client-uOgS_1bC.d.ts} +14 -18
- package/dist/{const-ty8u0TDI.d.ts → const-BJBK7jBl.d.ts} +1 -1
- package/dist/{const-BfQfV-rr.d.cts → const-_ZfJjRQG.d.cts} +1 -1
- package/dist/embedded-admin/server.cjs +117 -2
- package/dist/embedded-admin/server.cjs.map +1 -1
- package/dist/embedded-admin/server.d.cts +30 -2
- package/dist/embedded-admin/server.d.ts +30 -2
- package/dist/embedded-admin/server.js +117 -2
- package/dist/embedded-admin/server.js.map +1 -1
- package/dist/embedded-admin.cjs +135 -7
- package/dist/embedded-admin.cjs.map +1 -1
- package/dist/embedded-admin.d.cts +35 -2
- package/dist/embedded-admin.d.ts +35 -2
- package/dist/embedded-admin.js +135 -7
- package/dist/embedded-admin.js.map +1 -1
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +3 -3
- package/dist/errors.d.ts +3 -3
- package/dist/errors.js +2 -0
- package/dist/errors.js.map +1 -1
- package/dist/{index-DnKgjPGM.d.ts → index-CBaP4q8r.d.ts} +3 -3
- package/dist/{index-CX6si6YC.d.cts → index-CI_LFWiG.d.cts} +3 -3
- package/dist/index.cjs +396 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -9
- package/dist/index.d.ts +24 -9
- package/dist/index.js +396 -26
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-DTAaWKrp.d.cts → payload-types-BRg8Yary.d.cts} +262 -177
- package/dist/{payload-types-DTAaWKrp.d.ts → payload-types-BRg8Yary.d.ts} +262 -177
- package/dist/query.cjs +20 -0
- package/dist/query.cjs.map +1 -1
- package/dist/query.d.cts +5 -5
- package/dist/query.d.ts +5 -5
- package/dist/query.js +20 -0
- package/dist/query.js.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/server.cjs +459 -46
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +10 -8
- package/dist/server.d.ts +10 -8
- package/dist/server.js +459 -46
- package/dist/server.js.map +1 -1
- package/dist/storefront-cache.cjs +2 -0
- package/dist/storefront-cache.cjs.map +1 -1
- package/dist/storefront-cache.js +2 -0
- package/dist/storefront-cache.js.map +1 -1
- package/dist/{types-DdlhpNVv.d.ts → types-Cmnxxvuv.d.ts} +238 -21
- package/dist/{types-Bzgf4mTo.d.cts → types-CnkJQUez.d.cts} +238 -21
- package/dist/{types-DX8Z44yQ.d.ts → types-DLjSqL0P.d.ts} +2 -2
- package/dist/{types-CpSiyJud.d.cts → types-FyklqLAk.d.cts} +2 -2
- package/dist/ui/form.d.cts +1 -1
- package/dist/ui/form.d.ts +1 -1
- package/dist/ui/video.d.cts +1 -1
- package/dist/ui/video.d.ts +1 -1
- package/dist/webhook.d.cts +5 -5
- package/dist/webhook.d.ts +5 -5
- 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(
|
|
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([
|
|
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
|
-
|
|
2459
|
-
|
|
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
|
|
3569
|
-
exact(
|
|
3570
|
-
safeMinor(
|
|
3571
|
-
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
|
-
|
|
4879
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|