@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.cjs
CHANGED
|
@@ -128,6 +128,7 @@ var COMMERCE_ERROR_CODES = [
|
|
|
128
128
|
"cart_not_active",
|
|
129
129
|
"cart_locked",
|
|
130
130
|
"cart_empty",
|
|
131
|
+
"shipping_address_required",
|
|
131
132
|
"cart_market_unavailable",
|
|
132
133
|
"cart_market_mismatch",
|
|
133
134
|
"checkout_not_open",
|
|
@@ -144,6 +145,7 @@ var COMMERCE_ERROR_CODES = [
|
|
|
144
145
|
"price_changed",
|
|
145
146
|
"pricing_fact_in_use",
|
|
146
147
|
"insufficient_stock",
|
|
148
|
+
"credit_insufficient",
|
|
147
149
|
"reservation_conflict",
|
|
148
150
|
"stock_lock_unavailable",
|
|
149
151
|
"variant_not_found",
|
|
@@ -607,6 +609,8 @@ async function parseErrorBody(response) {
|
|
|
607
609
|
try {
|
|
608
610
|
const body = await response.json();
|
|
609
611
|
const reason = typeof body.reason === "string" ? body.reason : typeof body.code === "string" ? body.code : void 0;
|
|
612
|
+
const payloadErrorReason = Array.isArray(body.errors) ? readPayloadErrorReason(body.errors) : void 0;
|
|
613
|
+
const payloadReasonField = payloadErrorReason !== void 0 ? { payloadErrorReason } : {};
|
|
610
614
|
if (body.errors && Array.isArray(body.errors)) {
|
|
611
615
|
const fieldErrors = [];
|
|
612
616
|
for (const e of body.errors) {
|
|
@@ -629,6 +633,7 @@ async function parseErrorBody(response) {
|
|
|
629
633
|
errorMessage: `HTTP ${response.status}: ${details}`,
|
|
630
634
|
userMessage: details,
|
|
631
635
|
reason,
|
|
636
|
+
...payloadReasonField,
|
|
632
637
|
body,
|
|
633
638
|
errors: fieldErrors.length > 0 ? fieldErrors : body.errors
|
|
634
639
|
};
|
|
@@ -639,6 +644,7 @@ async function parseErrorBody(response) {
|
|
|
639
644
|
errorMessage: `HTTP ${response.status}: ${body.error}`,
|
|
640
645
|
userMessage: body.error,
|
|
641
646
|
reason,
|
|
647
|
+
...payloadReasonField,
|
|
642
648
|
body
|
|
643
649
|
};
|
|
644
650
|
}
|
|
@@ -647,14 +653,23 @@ async function parseErrorBody(response) {
|
|
|
647
653
|
errorMessage: `HTTP ${response.status}: ${body.message}`,
|
|
648
654
|
userMessage: body.message,
|
|
649
655
|
reason,
|
|
656
|
+
...payloadReasonField,
|
|
650
657
|
body
|
|
651
658
|
};
|
|
652
659
|
}
|
|
653
|
-
return { ...fallback, reason, body };
|
|
660
|
+
return { ...fallback, reason, ...payloadReasonField, body };
|
|
654
661
|
} catch {
|
|
655
662
|
return fallback;
|
|
656
663
|
}
|
|
657
664
|
}
|
|
665
|
+
function readPayloadErrorReason(errors) {
|
|
666
|
+
const data = errors[0]?.data;
|
|
667
|
+
if (!data || typeof data !== "object") return void 0;
|
|
668
|
+
const { reason, code } = data;
|
|
669
|
+
if (typeof reason === "string") return reason;
|
|
670
|
+
if (typeof code === "string") return code;
|
|
671
|
+
return void 0;
|
|
672
|
+
}
|
|
658
673
|
function getParsedErrorSuggestion(status, parsed) {
|
|
659
674
|
if (status === 403 && parsed.reason === "origin_not_allowed") {
|
|
660
675
|
return "Add the request origin to the tenant Browser API origins, then retry the browser request.";
|
|
@@ -700,7 +715,10 @@ function mapResponseToError(status, parsed, details, requestId, retryAfter, cano
|
|
|
700
715
|
if (retryAfter !== void 0) {
|
|
701
716
|
Object.assign(withRequestId, { retryAfter });
|
|
702
717
|
}
|
|
703
|
-
return canonicalCommerceError ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(
|
|
718
|
+
return canonicalCommerceError ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(
|
|
719
|
+
withRequestId,
|
|
720
|
+
parsed.reason ?? parsed.payloadErrorReason
|
|
721
|
+
);
|
|
704
722
|
};
|
|
705
723
|
if (status === 400 || status === 422) {
|
|
706
724
|
return finalize(
|
|
@@ -1119,6 +1137,7 @@ async function parseApiResponse(response, endpoint, options = {}) {
|
|
|
1119
1137
|
// ../../internal/http-contracts/src/index.ts
|
|
1120
1138
|
var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
|
|
1121
1139
|
var PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE = "application/vnd.01software.portone-action-capabilities.v1+json";
|
|
1140
|
+
var CUSTOMER_CREDIT_FUNDING_MEDIA_TYPE = "application/vnd.01software.credit-funding.v1+json";
|
|
1122
1141
|
var operation = (collection, method, path, errorFamily) => Object.freeze({
|
|
1123
1142
|
[operationBrand]: true,
|
|
1124
1143
|
collection,
|
|
@@ -1282,6 +1301,11 @@ var portOneStandardActionCapabilityOperations = /* @__PURE__ */ new Set([
|
|
|
1282
1301
|
]);
|
|
1283
1302
|
var MEMBERSHIP_ENDPOINT_OPERATIONS = {
|
|
1284
1303
|
subscribe: operation(null, "post", "/memberships/subscribe"),
|
|
1304
|
+
endSubscribeIntent: operation(
|
|
1305
|
+
null,
|
|
1306
|
+
"post",
|
|
1307
|
+
"/memberships/subscribe-intent/end"
|
|
1308
|
+
),
|
|
1285
1309
|
billingCustody: operation(null, "post", "/memberships/billing-custody"),
|
|
1286
1310
|
cancel: operation(null, "post", "/memberships/:id/cancel"),
|
|
1287
1311
|
me: operation(null, "get", "/memberships/me"),
|
|
@@ -1327,6 +1351,19 @@ var BENEFIT_VOUCHER_ENDPOINT_OPERATIONS = {
|
|
|
1327
1351
|
void: operation("customers", "post", "/benefit-vouchers/void"),
|
|
1328
1352
|
listMine: operation("customers", "get", "/me/benefit-vouchers")
|
|
1329
1353
|
};
|
|
1354
|
+
var CUSTOMER_CREDIT_ENDPOINT_OPERATIONS = {
|
|
1355
|
+
grant: strictCommerceOperation("customers", "post", "/credits/grant"),
|
|
1356
|
+
getGrant: strictCommerceOperation("customers", "post", "/credits/get-grant"),
|
|
1357
|
+
getAccount: strictCommerceOperation("customers", "post", "/credits/account"),
|
|
1358
|
+
revoke: strictCommerceOperation("customers", "post", "/credits/revoke"),
|
|
1359
|
+
mine: strictCommerceOperation("customers", "get", "/me/credits"),
|
|
1360
|
+
history: strictCommerceOperation("customers", "get", "/me/credits/history"),
|
|
1361
|
+
configure: strictCommerceOperation(
|
|
1362
|
+
"customers",
|
|
1363
|
+
"post",
|
|
1364
|
+
"/credits/configuration"
|
|
1365
|
+
)
|
|
1366
|
+
};
|
|
1330
1367
|
var CUSTOMER_GROUP_ENDPOINT_OPERATIONS = {
|
|
1331
1368
|
members: operation("customer-groups", "get", "/:id/members"),
|
|
1332
1369
|
grant: operation("customer-groups", "post", "/:id/members/grant"),
|
|
@@ -1716,6 +1753,140 @@ var CustomerBenefitVouchersApi = class extends CustomerScopedApi {
|
|
|
1716
1753
|
}
|
|
1717
1754
|
};
|
|
1718
1755
|
|
|
1756
|
+
// src/core/api/customer-credit-types.ts
|
|
1757
|
+
function invalid() {
|
|
1758
|
+
throw createApiError("Invalid customer credit response", 502);
|
|
1759
|
+
}
|
|
1760
|
+
function object2(value, keys) {
|
|
1761
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(value, key)))
|
|
1762
|
+
invalid();
|
|
1763
|
+
return value;
|
|
1764
|
+
}
|
|
1765
|
+
function money(value) {
|
|
1766
|
+
return typeof value === "string" && /^(0|[1-9][0-9]*)$/.test(value);
|
|
1767
|
+
}
|
|
1768
|
+
function uuid2(value) {
|
|
1769
|
+
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(
|
|
1770
|
+
value
|
|
1771
|
+
);
|
|
1772
|
+
}
|
|
1773
|
+
function time2(value) {
|
|
1774
|
+
if (typeof value !== "string") return false;
|
|
1775
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?Z$/.exec(value);
|
|
1776
|
+
if (!match) return false;
|
|
1777
|
+
const [, year, month, day, hour, minute, second = "0"] = match;
|
|
1778
|
+
const y = Number(year), m = Number(month), d = Number(day);
|
|
1779
|
+
const days = [
|
|
1780
|
+
31,
|
|
1781
|
+
y % 4 === 0 && (y % 100 !== 0 || y % 400 === 0) ? 29 : 28,
|
|
1782
|
+
31,
|
|
1783
|
+
30,
|
|
1784
|
+
31,
|
|
1785
|
+
30,
|
|
1786
|
+
31,
|
|
1787
|
+
31,
|
|
1788
|
+
30,
|
|
1789
|
+
31,
|
|
1790
|
+
30,
|
|
1791
|
+
31
|
|
1792
|
+
];
|
|
1793
|
+
return m >= 1 && m <= 12 && d >= 1 && d <= days[m - 1] && Number(hour) < 24 && Number(minute) < 60 && Number(second) < 60;
|
|
1794
|
+
}
|
|
1795
|
+
var states = ["available", "held", "spent", "expired", "revoked"];
|
|
1796
|
+
function balances(value) {
|
|
1797
|
+
const data = object2(value, states);
|
|
1798
|
+
if (states.some((key) => !money(data[key]))) invalid();
|
|
1799
|
+
}
|
|
1800
|
+
function page(value) {
|
|
1801
|
+
if (value.currency !== "KRW" || !time2(value.evaluatedAt) || !Number.isSafeInteger(value.page) || value.page < 1 || typeof value.hasNextPage !== "boolean")
|
|
1802
|
+
invalid();
|
|
1803
|
+
}
|
|
1804
|
+
function parseMyCustomerCredits(value) {
|
|
1805
|
+
const data = object2(value, [
|
|
1806
|
+
"currency",
|
|
1807
|
+
"evaluatedAt",
|
|
1808
|
+
"granted",
|
|
1809
|
+
"balances",
|
|
1810
|
+
"buckets",
|
|
1811
|
+
"page",
|
|
1812
|
+
"hasNextPage"
|
|
1813
|
+
]);
|
|
1814
|
+
page(data);
|
|
1815
|
+
balances(data.balances);
|
|
1816
|
+
if (!money(data.granted) || !Array.isArray(data.buckets) || data.buckets.length > 50)
|
|
1817
|
+
invalid();
|
|
1818
|
+
for (const value2 of data.buckets) {
|
|
1819
|
+
const bucket = object2(value2, [
|
|
1820
|
+
"id",
|
|
1821
|
+
"grantId",
|
|
1822
|
+
"kind",
|
|
1823
|
+
"grantedAt",
|
|
1824
|
+
"expiresAt",
|
|
1825
|
+
"isRevoked",
|
|
1826
|
+
"balances"
|
|
1827
|
+
]);
|
|
1828
|
+
if (!uuid2(bucket.id) || !uuid2(bucket.grantId) || !["original", "grace"].includes(bucket.kind) || !time2(bucket.grantedAt) || !time2(bucket.expiresAt) || typeof bucket.isRevoked !== "boolean")
|
|
1829
|
+
invalid();
|
|
1830
|
+
balances(bucket.balances);
|
|
1831
|
+
}
|
|
1832
|
+
return value;
|
|
1833
|
+
}
|
|
1834
|
+
function parseMyCustomerCreditHistory(value) {
|
|
1835
|
+
const data = object2(value, [
|
|
1836
|
+
"currency",
|
|
1837
|
+
"evaluatedAt",
|
|
1838
|
+
"entries",
|
|
1839
|
+
"page",
|
|
1840
|
+
"hasNextPage"
|
|
1841
|
+
]);
|
|
1842
|
+
page(data);
|
|
1843
|
+
if (!Array.isArray(data.entries) || data.entries.length > 50) invalid();
|
|
1844
|
+
for (const value2 of data.entries) {
|
|
1845
|
+
const entry = object2(value2, [
|
|
1846
|
+
"id",
|
|
1847
|
+
"grantId",
|
|
1848
|
+
"kind",
|
|
1849
|
+
"amount",
|
|
1850
|
+
"fromState",
|
|
1851
|
+
"toState",
|
|
1852
|
+
"createdAt"
|
|
1853
|
+
]);
|
|
1854
|
+
if (!uuid2(entry.id) || !uuid2(entry.grantId) || !money(entry.amount) || !time2(entry.createdAt) || ![
|
|
1855
|
+
"grant",
|
|
1856
|
+
"reserve",
|
|
1857
|
+
"consume",
|
|
1858
|
+
"release",
|
|
1859
|
+
"restore",
|
|
1860
|
+
"expire",
|
|
1861
|
+
"revoke"
|
|
1862
|
+
].includes(entry.kind) || entry.fromState !== null && !states.includes(entry.fromState) || entry.toState !== null && !states.includes(entry.toState))
|
|
1863
|
+
invalid();
|
|
1864
|
+
}
|
|
1865
|
+
return value;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
// src/core/api/customer-credits-api.ts
|
|
1869
|
+
var CustomerCreditsApi = class extends CustomerScopedApi {
|
|
1870
|
+
async mine(params = {}) {
|
|
1871
|
+
const query = new URLSearchParams();
|
|
1872
|
+
if (params.page !== void 0) query.set("page", String(params.page));
|
|
1873
|
+
return parseMyCustomerCredits(
|
|
1874
|
+
await this.requestEndpoint(CUSTOMER_CREDIT_ENDPOINT_OPERATIONS.mine, void 0, {
|
|
1875
|
+
query
|
|
1876
|
+
})
|
|
1877
|
+
);
|
|
1878
|
+
}
|
|
1879
|
+
async history(params = {}) {
|
|
1880
|
+
const query = new URLSearchParams();
|
|
1881
|
+
if (params.page !== void 0) query.set("page", String(params.page));
|
|
1882
|
+
return parseMyCustomerCreditHistory(
|
|
1883
|
+
await this.requestEndpoint(CUSTOMER_CREDIT_ENDPOINT_OPERATIONS.history, void 0, {
|
|
1884
|
+
query
|
|
1885
|
+
})
|
|
1886
|
+
);
|
|
1887
|
+
}
|
|
1888
|
+
};
|
|
1889
|
+
|
|
1719
1890
|
// src/core/collection/http-client.ts
|
|
1720
1891
|
var import_qs_esm = require("qs-esm");
|
|
1721
1892
|
function validateWhere(where) {
|
|
@@ -2166,11 +2337,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
|
|
|
2166
2337
|
* - `rootComment`: comments belonging to a thread rooted at that comment.
|
|
2167
2338
|
*/
|
|
2168
2339
|
listComments(params) {
|
|
2169
|
-
const { postId, page, limit, rootComment, topLevelOnly, sort } = params;
|
|
2340
|
+
const { postId, page: page2, limit, rootComment, topLevelOnly, sort } = params;
|
|
2170
2341
|
return this.execute(
|
|
2171
2342
|
this.buildCommentsListQuery({
|
|
2172
2343
|
postId,
|
|
2173
|
-
page,
|
|
2344
|
+
page: page2,
|
|
2174
2345
|
limit,
|
|
2175
2346
|
rootComment,
|
|
2176
2347
|
topLevelOnly,
|
|
@@ -2181,11 +2352,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
|
|
|
2181
2352
|
}
|
|
2182
2353
|
/** Direct replies to a comment (`where[parent][equals]`). */
|
|
2183
2354
|
listReplies(params) {
|
|
2184
|
-
const { commentId, page, limit, sort } = params;
|
|
2355
|
+
const { commentId, page: page2, limit, sort } = params;
|
|
2185
2356
|
return this.execute(
|
|
2186
2357
|
this.buildCommentsListQuery({
|
|
2187
2358
|
parentId: commentId,
|
|
2188
|
-
page,
|
|
2359
|
+
page: page2,
|
|
2189
2360
|
limit,
|
|
2190
2361
|
sort
|
|
2191
2362
|
}),
|
|
@@ -2442,7 +2613,18 @@ var ABANDONED_REASONS = ["expired", "customer", "operator"];
|
|
|
2442
2613
|
function managedPaymentProviders(providers) {
|
|
2443
2614
|
return providers;
|
|
2444
2615
|
}
|
|
2445
|
-
var PAYMENT_PROVIDERS = managedPaymentProviders([
|
|
2616
|
+
var PAYMENT_PROVIDERS = managedPaymentProviders([
|
|
2617
|
+
"toss",
|
|
2618
|
+
"portone",
|
|
2619
|
+
"stripe"
|
|
2620
|
+
]);
|
|
2621
|
+
var CANCEL_RECOVERY_METHODS = {
|
|
2622
|
+
toss: "cancel()",
|
|
2623
|
+
portone: "cancelPortOne()",
|
|
2624
|
+
stripe: null
|
|
2625
|
+
};
|
|
2626
|
+
var STRIPE_RETURN_URL_RAW_CHARACTERS = /^[^\s\u0000-\u001F\u007F\\]+$/;
|
|
2627
|
+
var STRIPE_RETURN_URL_AUTHORITY = /^[A-Za-z][A-Za-z0-9+.-]*:\/\/[^/?#@]+(?:[/?#]|$)/;
|
|
2446
2628
|
var PAYMENT_PROVIDER_STATUSES = [
|
|
2447
2629
|
"requires_payment_method",
|
|
2448
2630
|
"requires_action",
|
|
@@ -2491,11 +2673,8 @@ function fail(resource, path, expected) {
|
|
|
2491
2673
|
invalidCanonicalResponse(resource, { path, expected });
|
|
2492
2674
|
}
|
|
2493
2675
|
function providerMismatch(resource, expected, actual, operation2) {
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
toss: "cancel()",
|
|
2497
|
-
portone: "cancelPortOne()"
|
|
2498
|
-
}[actual];
|
|
2676
|
+
const method = CANCEL_RECOVERY_METHODS[actual];
|
|
2677
|
+
if (operation2 === "cancel" && method !== null) {
|
|
2499
2678
|
throw createApiError(
|
|
2500
2679
|
`Canonical ${resource} response provider mismatch: expected ${expected}, received ${actual}.`,
|
|
2501
2680
|
502,
|
|
@@ -2524,6 +2703,17 @@ function exact(value, required, optional, resource, path) {
|
|
|
2524
2703
|
const unexpected = Object.keys(value).find((key) => !allowed.has(key));
|
|
2525
2704
|
if (unexpected) fail(resource, `${path}.${unexpected}`, "no unknown fields");
|
|
2526
2705
|
}
|
|
2706
|
+
function responseExtensionKeys(value, keys, resource, path) {
|
|
2707
|
+
if (!keys.some((key) => Object.prototype.hasOwnProperty.call(value, key)))
|
|
2708
|
+
return [];
|
|
2709
|
+
enumValue(
|
|
2710
|
+
value.deliveryMethod,
|
|
2711
|
+
["shipping", "pickup"],
|
|
2712
|
+
resource,
|
|
2713
|
+
`${path}.deliveryMethod`
|
|
2714
|
+
);
|
|
2715
|
+
return [...keys];
|
|
2716
|
+
}
|
|
2527
2717
|
function string(value, resource, path) {
|
|
2528
2718
|
if (typeof value !== "string" || value.length === 0) {
|
|
2529
2719
|
fail(resource, path, "non-empty string");
|
|
@@ -2863,6 +3053,12 @@ function validatePublicCart(value, resource = "Cart") {
|
|
|
2863
3053
|
exact(
|
|
2864
3054
|
cart,
|
|
2865
3055
|
[
|
|
3056
|
+
...responseExtensionKeys(
|
|
3057
|
+
cart,
|
|
3058
|
+
["deliveryMethod", "shippingMinor", "totalMinor"],
|
|
3059
|
+
resource,
|
|
3060
|
+
"$"
|
|
3061
|
+
),
|
|
2866
3062
|
"id",
|
|
2867
3063
|
"status",
|
|
2868
3064
|
"revision",
|
|
@@ -2933,6 +3129,13 @@ function validatePublicCart(value, resource = "Cart") {
|
|
|
2933
3129
|
if (expectedSubtotal - BigInt(discount) < 0n || BigInt(estimatedTotal) !== expectedSubtotal - BigInt(discount)) {
|
|
2934
3130
|
fail(resource, "$.estimatedTotalMinor", "subtotalMinor - discountMinor");
|
|
2935
3131
|
}
|
|
3132
|
+
if ("deliveryMethod" in cart) {
|
|
3133
|
+
const shipping = safeMinor(cart.shippingMinor, resource, "$.shippingMinor");
|
|
3134
|
+
const total = safeMinor(cart.totalMinor, resource, "$.totalMinor");
|
|
3135
|
+
if (BigInt(total) !== BigInt(estimatedTotal) + BigInt(shipping)) {
|
|
3136
|
+
fail(resource, "$.totalMinor", "estimatedTotalMinor + shippingMinor");
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
2936
3139
|
timestamp(cart.expiresAt, resource, "$.expiresAt");
|
|
2937
3140
|
timestamp(cart.createdAt, resource, "$.createdAt");
|
|
2938
3141
|
timestamp(cart.updatedAt, resource, "$.updatedAt");
|
|
@@ -3091,6 +3294,12 @@ function validatePublicOrderAt(value, resource, path) {
|
|
|
3091
3294
|
exact(
|
|
3092
3295
|
order,
|
|
3093
3296
|
[
|
|
3297
|
+
...responseExtensionKeys(
|
|
3298
|
+
order,
|
|
3299
|
+
["deliveryMethod", "pickup", "source"],
|
|
3300
|
+
resource,
|
|
3301
|
+
path
|
|
3302
|
+
),
|
|
3094
3303
|
"id",
|
|
3095
3304
|
"orderNumber",
|
|
3096
3305
|
"amounts",
|
|
@@ -3112,6 +3321,37 @@ function validatePublicOrderAt(value, resource, path) {
|
|
|
3112
3321
|
resource,
|
|
3113
3322
|
path
|
|
3114
3323
|
);
|
|
3324
|
+
if ("deliveryMethod" in order) {
|
|
3325
|
+
enumValue(
|
|
3326
|
+
order.source,
|
|
3327
|
+
["web", "app", "manual", "api", "import", "in_person"],
|
|
3328
|
+
resource,
|
|
3329
|
+
`${path}.source`
|
|
3330
|
+
);
|
|
3331
|
+
if (order.deliveryMethod === "shipping") {
|
|
3332
|
+
if (order.pickup !== null)
|
|
3333
|
+
fail(resource, `${path}.pickup`, "null for shipping");
|
|
3334
|
+
} else {
|
|
3335
|
+
const pickup = record(order.pickup, resource, `${path}.pickup`);
|
|
3336
|
+
exact(
|
|
3337
|
+
pickup,
|
|
3338
|
+
["status", "readyAt", "pickedUpAt"],
|
|
3339
|
+
[],
|
|
3340
|
+
resource,
|
|
3341
|
+
`${path}.pickup`
|
|
3342
|
+
);
|
|
3343
|
+
enumValue(
|
|
3344
|
+
pickup.status,
|
|
3345
|
+
["pending", "ready_for_pickup", "picked_up", "canceled"],
|
|
3346
|
+
resource,
|
|
3347
|
+
`${path}.pickup.status`
|
|
3348
|
+
);
|
|
3349
|
+
for (const key of ["readyAt", "pickedUpAt"]) {
|
|
3350
|
+
if (pickup[key] !== null)
|
|
3351
|
+
timestamp(pickup[key], resource, `${path}.pickup.${key}`);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3115
3355
|
string(order.id, resource, `${path}.id`);
|
|
3116
3356
|
string(order.orderNumber, resource, `${path}.orderNumber`);
|
|
3117
3357
|
const amounts = record(order.amounts, resource, `${path}.amounts`);
|
|
@@ -3432,6 +3672,17 @@ function validateCheckoutCore(value, resource, list, server) {
|
|
|
3432
3672
|
"$.status"
|
|
3433
3673
|
);
|
|
3434
3674
|
const keys = checkoutVariantKeys(status, checkout.placedVia);
|
|
3675
|
+
keys.required.push(
|
|
3676
|
+
...responseExtensionKeys(
|
|
3677
|
+
checkout,
|
|
3678
|
+
["deliveryMethod", "source"],
|
|
3679
|
+
resource,
|
|
3680
|
+
"$"
|
|
3681
|
+
)
|
|
3682
|
+
);
|
|
3683
|
+
if ("deliveryMethod" in checkout)
|
|
3684
|
+
enumValue(checkout.source, ["web", "in_person"], resource, "$.source");
|
|
3685
|
+
keys.optional.push("funding");
|
|
3435
3686
|
if (list) {
|
|
3436
3687
|
keys.required = keys.required.filter(
|
|
3437
3688
|
(key) => !["items", "shippingAddress", "attributes"].includes(key)
|
|
@@ -3443,6 +3694,33 @@ function validateCheckoutCore(value, resource, list, server) {
|
|
|
3443
3694
|
exact(checkout, keys.required, keys.optional, resource, "$");
|
|
3444
3695
|
string(checkout.id, resource, "$.id");
|
|
3445
3696
|
validateCheckoutAmounts(checkout.amounts, resource, "$.amounts");
|
|
3697
|
+
if (Object.prototype.hasOwnProperty.call(checkout, "funding")) {
|
|
3698
|
+
const funding = record(checkout.funding, resource, "$.funding");
|
|
3699
|
+
exact(
|
|
3700
|
+
funding,
|
|
3701
|
+
["creditAmount", "providerPayableAmount"],
|
|
3702
|
+
[],
|
|
3703
|
+
resource,
|
|
3704
|
+
"$.funding"
|
|
3705
|
+
);
|
|
3706
|
+
const credit = safeMinor(
|
|
3707
|
+
funding.creditAmount,
|
|
3708
|
+
resource,
|
|
3709
|
+
"$.funding.creditAmount"
|
|
3710
|
+
);
|
|
3711
|
+
const provider = safeMinor(
|
|
3712
|
+
funding.providerPayableAmount,
|
|
3713
|
+
resource,
|
|
3714
|
+
"$.funding.providerPayableAmount"
|
|
3715
|
+
);
|
|
3716
|
+
const amounts = checkout.amounts;
|
|
3717
|
+
if (BigInt(credit) + BigInt(provider) !== BigInt(amounts.totalMinor) || credit > 0 && amounts.currency !== "KRW")
|
|
3718
|
+
fail(
|
|
3719
|
+
resource,
|
|
3720
|
+
"$.funding",
|
|
3721
|
+
"exact purchase total split; positive credits require KRW"
|
|
3722
|
+
);
|
|
3723
|
+
}
|
|
3446
3724
|
if (!list) {
|
|
3447
3725
|
const items = array(checkout.items, resource, "$.items");
|
|
3448
3726
|
if (items.length === 0) fail(resource, "$.items", "non-empty array");
|
|
@@ -3601,10 +3879,10 @@ function validateCheckoutQueryResult(value) {
|
|
|
3601
3879
|
return value;
|
|
3602
3880
|
}
|
|
3603
3881
|
function validateMoney(value, resource, path) {
|
|
3604
|
-
const
|
|
3605
|
-
exact(
|
|
3606
|
-
safeMinor(
|
|
3607
|
-
currency(
|
|
3882
|
+
const money2 = record(value, resource, path);
|
|
3883
|
+
exact(money2, ["amountMinor", "currency"], [], resource, path);
|
|
3884
|
+
safeMinor(money2.amountMinor, resource, `${path}.amountMinor`);
|
|
3885
|
+
currency(money2.currency, resource, `${path}.currency`);
|
|
3608
3886
|
}
|
|
3609
3887
|
function validateCaptureEvidence(value, resource, path) {
|
|
3610
3888
|
const evidence = record(value, resource, path);
|
|
@@ -3640,6 +3918,65 @@ function validateRequiredReconciliation(value, allowed, resource, path) {
|
|
|
3640
3918
|
}
|
|
3641
3919
|
function validateNextAction(value, provider, resource, path) {
|
|
3642
3920
|
const action = record(value, resource, path);
|
|
3921
|
+
if (provider === "stripe") {
|
|
3922
|
+
exact(
|
|
3923
|
+
action,
|
|
3924
|
+
["type", "clientSecret", "publishableKey", "returnUrl"],
|
|
3925
|
+
[],
|
|
3926
|
+
resource,
|
|
3927
|
+
path
|
|
3928
|
+
);
|
|
3929
|
+
if (action.type !== "stripe_payment_element")
|
|
3930
|
+
fail(resource, `${path}.type`, "stripe_payment_element");
|
|
3931
|
+
const clientSecret = boundedString(
|
|
3932
|
+
action.clientSecret,
|
|
3933
|
+
255,
|
|
3934
|
+
resource,
|
|
3935
|
+
`${path}.clientSecret`
|
|
3936
|
+
);
|
|
3937
|
+
if (!/^pi_[A-Za-z0-9]+_secret_[A-Za-z0-9]+$/.test(clientSecret)) {
|
|
3938
|
+
fail(
|
|
3939
|
+
resource,
|
|
3940
|
+
`${path}.clientSecret`,
|
|
3941
|
+
"Stripe PaymentIntent client secret"
|
|
3942
|
+
);
|
|
3943
|
+
}
|
|
3944
|
+
const publishableKey = boundedString(
|
|
3945
|
+
action.publishableKey,
|
|
3946
|
+
255,
|
|
3947
|
+
resource,
|
|
3948
|
+
`${path}.publishableKey`
|
|
3949
|
+
);
|
|
3950
|
+
if (!/^pk_(?:test|live)_[A-Za-z0-9]+$/.test(publishableKey)) {
|
|
3951
|
+
fail(resource, `${path}.publishableKey`, "Stripe publishable key");
|
|
3952
|
+
}
|
|
3953
|
+
const returnUrl = boundedString(
|
|
3954
|
+
action.returnUrl,
|
|
3955
|
+
2048,
|
|
3956
|
+
resource,
|
|
3957
|
+
`${path}.returnUrl`
|
|
3958
|
+
);
|
|
3959
|
+
if (!STRIPE_RETURN_URL_RAW_CHARACTERS.test(returnUrl) || !STRIPE_RETURN_URL_AUTHORITY.test(returnUrl)) {
|
|
3960
|
+
fail(
|
|
3961
|
+
resource,
|
|
3962
|
+
`${path}.returnUrl`,
|
|
3963
|
+
"HTTPS or loopback URL without embedded credentials"
|
|
3964
|
+
);
|
|
3965
|
+
}
|
|
3966
|
+
try {
|
|
3967
|
+
const parsed = new URL(returnUrl);
|
|
3968
|
+
const loopback = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
|
|
3969
|
+
if (!loopback && parsed.protocol !== "https:" || parsed.username || parsed.password)
|
|
3970
|
+
throw new Error("unsafe return URL");
|
|
3971
|
+
} catch {
|
|
3972
|
+
fail(
|
|
3973
|
+
resource,
|
|
3974
|
+
`${path}.returnUrl`,
|
|
3975
|
+
"HTTPS or loopback URL without embedded credentials"
|
|
3976
|
+
);
|
|
3977
|
+
}
|
|
3978
|
+
return;
|
|
3979
|
+
}
|
|
3643
3980
|
if (provider === "portone") {
|
|
3644
3981
|
if (action.type === "portone_sdk") {
|
|
3645
3982
|
const hasCancelable = "cancelable" in action;
|
|
@@ -4015,7 +4352,7 @@ function validatePublicPaymentSession(value, expectedProvider, operation2) {
|
|
|
4015
4352
|
);
|
|
4016
4353
|
}
|
|
4017
4354
|
if (expectedProvider !== void 0 && provider !== expectedProvider) {
|
|
4018
|
-
if (operation2 === "cancel" && status !== "canceling" && status !== "canceled") {
|
|
4355
|
+
if (operation2 === "cancel" && CANCEL_RECOVERY_METHODS[provider] !== null && status !== "canceling" && status !== "canceled") {
|
|
4019
4356
|
fail(
|
|
4020
4357
|
resource,
|
|
4021
4358
|
"$.providerStatus",
|
|
@@ -4907,8 +5244,9 @@ var CheckoutApi = class extends CustomerScopedApi {
|
|
|
4907
5244
|
}
|
|
4908
5245
|
post(endpoint, body, idempotencyKey) {
|
|
4909
5246
|
return this.requestEndpoint(endpoint, body, {
|
|
4910
|
-
|
|
4911
|
-
|
|
5247
|
+
headers: {
|
|
5248
|
+
Accept: CUSTOMER_CREDIT_FUNDING_MEDIA_TYPE,
|
|
5249
|
+
...idempotencyKey && { "X-Idempotency-Key": idempotencyKey }
|
|
4912
5250
|
}
|
|
4913
5251
|
});
|
|
4914
5252
|
}
|
|
@@ -4918,34 +5256,58 @@ var CheckoutApi = class extends CustomerScopedApi {
|
|
|
4918
5256
|
async serverCheckout(result) {
|
|
4919
5257
|
return validateServerCheckout(await result);
|
|
4920
5258
|
}
|
|
4921
|
-
async createResult(result) {
|
|
4922
|
-
|
|
5259
|
+
async createResult(result, creditAmount) {
|
|
5260
|
+
const parsed = validateCreateCheckoutResult(
|
|
4923
5261
|
await result,
|
|
4924
5262
|
false
|
|
4925
5263
|
);
|
|
5264
|
+
this.assertRequestedCredit(parsed.checkout, creditAmount);
|
|
5265
|
+
return parsed;
|
|
4926
5266
|
}
|
|
4927
|
-
async createServerResult(result) {
|
|
4928
|
-
|
|
5267
|
+
async createServerResult(result, creditAmount) {
|
|
5268
|
+
const parsed = validateCreateCheckoutResult(
|
|
4929
5269
|
await result,
|
|
4930
5270
|
true
|
|
4931
5271
|
);
|
|
5272
|
+
this.assertRequestedCredit(parsed.checkout, creditAmount);
|
|
5273
|
+
return parsed;
|
|
5274
|
+
}
|
|
5275
|
+
assertCreditInput(amount) {
|
|
5276
|
+
if (amount !== void 0 && (!Number.isSafeInteger(amount) || amount <= 0))
|
|
5277
|
+
throw createValidationError(
|
|
5278
|
+
"creditAmount must be a positive safe integer."
|
|
5279
|
+
);
|
|
5280
|
+
}
|
|
5281
|
+
assertRequestedCredit(checkout, requested) {
|
|
5282
|
+
if (requested !== void 0 && checkout.funding?.creditAmount !== requested)
|
|
5283
|
+
throw createApiError(
|
|
5284
|
+
"Credit funding was not confirmed by the server.",
|
|
5285
|
+
502,
|
|
5286
|
+
{ resource: "Checkout", path: "$.funding" },
|
|
5287
|
+
"The response does not confirm the requested credit funding.",
|
|
5288
|
+
"Retry the same create with the original idempotency key and credit amount, or retrieve the Checkout; never retry without credit."
|
|
5289
|
+
);
|
|
4932
5290
|
}
|
|
4933
5291
|
create(params) {
|
|
4934
5292
|
const { idempotencyKey, ...body } = params;
|
|
4935
5293
|
assertCommerceIdempotencyKey(idempotencyKey);
|
|
5294
|
+
this.assertCreditInput(body.creditAmount);
|
|
4936
5295
|
return this.createResult(
|
|
4937
|
-
this.post(COMMERCE_ENDPOINTS.checkouts.create, body, idempotencyKey)
|
|
5296
|
+
this.post(COMMERCE_ENDPOINTS.checkouts.create, body, idempotencyKey),
|
|
5297
|
+
body.creditAmount
|
|
4938
5298
|
);
|
|
4939
5299
|
}
|
|
4940
5300
|
createServer(params) {
|
|
4941
5301
|
const { idempotencyKey, ...body } = params;
|
|
4942
5302
|
assertCommerceIdempotencyKey(idempotencyKey);
|
|
5303
|
+
this.assertCreditInput(body.creditAmount);
|
|
4943
5304
|
return this.createServerResult(
|
|
4944
5305
|
this.post(
|
|
4945
5306
|
COMMERCE_ENDPOINTS.checkouts.server.create,
|
|
4946
5307
|
body,
|
|
4947
5308
|
idempotencyKey
|
|
4948
|
-
)
|
|
5309
|
+
),
|
|
5310
|
+
body.creditAmount
|
|
4949
5311
|
);
|
|
4950
5312
|
}
|
|
4951
5313
|
retrieve(params) {
|
|
@@ -6607,6 +6969,13 @@ var Client = class _Client {
|
|
|
6607
6969
|
this.markets = new MarketDiscovery(
|
|
6608
6970
|
(options2) => this.collections.from("markets").find(options2)
|
|
6609
6971
|
);
|
|
6972
|
+
this.credits = new CustomerCreditsApi("CustomerCreditsApi", {
|
|
6973
|
+
publishableKey: this.config.publishableKey,
|
|
6974
|
+
apiUrl: this.config.apiUrl,
|
|
6975
|
+
customerToken: () => this.customer.auth.getToken(),
|
|
6976
|
+
onUnauthorized,
|
|
6977
|
+
onRequestId
|
|
6978
|
+
});
|
|
6610
6979
|
this.benefitVouchers = new CustomerBenefitVouchersApi(
|
|
6611
6980
|
"CustomerBenefitVouchersApi",
|
|
6612
6981
|
{
|
|
@@ -6637,7 +7006,8 @@ var Client = class _Client {
|
|
|
6637
7006
|
...this.config,
|
|
6638
7007
|
customer: this.config.customer?.persist === false ? {
|
|
6639
7008
|
...this.config.customer,
|
|
6640
|
-
token: this.customer.auth.getToken() ?? void 0
|
|
7009
|
+
token: this.customer.auth.getToken() ?? void 0,
|
|
7010
|
+
refreshToken: this.customer.auth.getRefreshToken() ?? void 0
|
|
6641
7011
|
} : this.config.customer,
|
|
6642
7012
|
market
|
|
6643
7013
|
});
|