@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/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(
|
|
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([
|
|
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
|
-
|
|
2452
|
-
|
|
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
|
|
3562
|
-
exact(
|
|
3563
|
-
safeMinor(
|
|
3564
|
-
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
|
-
|
|
4868
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|