@01.software/sdk 0.49.0 → 0.56.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 +257 -1
- package/MIGRATION.md +56 -0
- package/README.md +269 -56
- package/dist/client.cjs +608 -190
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +6 -6
- package/dist/client.d.ts +6 -6
- package/dist/client.js +608 -190
- package/dist/client.js.map +1 -1
- package/dist/{collection-client-DnDt6EQz.d.ts → collection-client-Bmr53saa.d.ts} +6 -4
- package/dist/{collection-client-XfGLPuTf.d.cts → collection-client-DxuBDso_.d.cts} +6 -4
- package/dist/{const-CBba4lDo.d.cts → const-BKUqg96Q.d.ts} +5 -5
- package/dist/{const-DCNV5Kq7.d.ts → const-Cv1DCsp6.d.cts} +5 -5
- package/dist/embedded-admin/server.cjs +306 -0
- package/dist/embedded-admin/server.cjs.map +1 -0
- package/dist/embedded-admin/server.d.cts +33 -0
- package/dist/embedded-admin/server.d.ts +33 -0
- package/dist/embedded-admin/server.js +288 -0
- package/dist/embedded-admin/server.js.map +1 -0
- package/dist/embedded-admin.cjs +400 -0
- package/dist/embedded-admin.cjs.map +1 -0
- package/dist/embedded-admin.d.cts +61 -0
- package/dist/embedded-admin.d.ts +61 -0
- package/dist/embedded-admin.js +377 -0
- package/dist/embedded-admin.js.map +1 -0
- package/dist/errors.cjs +1 -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 +1 -0
- package/dist/errors.js.map +1 -1
- package/dist/{index-DUuIqUS8.d.ts → index-CGsT4AQ8.d.cts} +89 -10
- package/dist/{index-CbKyoEzy.d.cts → index-DFHLLqYu.d.ts} +89 -10
- package/dist/index.cjs +752 -436
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -69
- package/dist/index.d.ts +12 -69
- package/dist/index.js +752 -436
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-MKbx5MuJ.d.cts → payload-types-Bk-duc5k.d.cts} +545 -141
- package/dist/{payload-types-MKbx5MuJ.d.ts → payload-types-Bk-duc5k.d.ts} +545 -141
- package/dist/query.cjs +108 -71
- 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 +108 -71
- 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 +502 -175
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +9 -8
- package/dist/server.d.ts +9 -8
- package/dist/server.js +502 -175
- package/dist/server.js.map +1 -1
- package/dist/storefront-cache.cjs +1 -0
- package/dist/storefront-cache.cjs.map +1 -1
- package/dist/storefront-cache.js +1 -0
- package/dist/storefront-cache.js.map +1 -1
- package/dist/{types-1UeOk1Uy.d.cts → types-CEK8uTvU.d.ts} +287 -30
- package/dist/{types-BKr_2avj.d.cts → types-CNdpj2fI.d.cts} +2 -2
- package/dist/{types-L_nh-ED7.d.ts → types-D4mjGFj4.d.ts} +2 -2
- package/dist/{types-Du4s5anw.d.ts → types-Dhk5NX7Z.d.cts} +287 -30
- 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.cjs +135 -80
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.d.cts +21 -5
- package/dist/webhook.d.ts +21 -5
- package/dist/webhook.js +135 -80
- package/dist/webhook.js.map +1 -1
- package/package.json +28 -6
package/dist/client.cjs
CHANGED
|
@@ -140,6 +140,7 @@ var COMMERCE_ERROR_CODES = [
|
|
|
140
140
|
"payment_session_not_cancelable",
|
|
141
141
|
"payment_session_conflict",
|
|
142
142
|
"provider_identity_mismatch",
|
|
143
|
+
"managed_refund_attestation_forbidden",
|
|
143
144
|
"payment_method_unavailable",
|
|
144
145
|
"provider_unavailable",
|
|
145
146
|
"lock_timeout",
|
|
@@ -682,11 +683,11 @@ function parseRetryAfter(response) {
|
|
|
682
683
|
permitsAutomaticRetry: seconds <= MAX_AUTOMATIC_RETRY_AFTER_SECONDS
|
|
683
684
|
};
|
|
684
685
|
}
|
|
685
|
-
function mapResponseToError(status, parsed, details, requestId, retryAfter,
|
|
686
|
+
function mapResponseToError(status, parsed, details, requestId, retryAfter, canonicalCommerceError) {
|
|
686
687
|
const errorDetails = {
|
|
687
688
|
...details,
|
|
688
689
|
...parsed.errors && { errors: parsed.errors },
|
|
689
|
-
|
|
690
|
+
...!canonicalCommerceError && parsed.body && { body: parsed.body }
|
|
690
691
|
};
|
|
691
692
|
const suggestion = getParsedErrorSuggestion(status, parsed);
|
|
692
693
|
const finalize = (error) => {
|
|
@@ -694,7 +695,7 @@ function mapResponseToError(status, parsed, details, requestId, retryAfter, erro
|
|
|
694
695
|
if (retryAfter !== void 0) {
|
|
695
696
|
Object.assign(withRequestId, { retryAfter });
|
|
696
697
|
}
|
|
697
|
-
return
|
|
698
|
+
return canonicalCommerceError ? enhanceCommerceError(withRequestId, parsed.body, requestId) : enhanceNonCommerceError(withRequestId, parsed.reason);
|
|
698
699
|
};
|
|
699
700
|
if (status === 400 || status === 422) {
|
|
700
701
|
return finalize(
|
|
@@ -800,6 +801,7 @@ async function httpFetch(url, options) {
|
|
|
800
801
|
retry,
|
|
801
802
|
onUnauthorized,
|
|
802
803
|
errorFamily,
|
|
804
|
+
typedCommerceErrorReasons,
|
|
803
805
|
...requestInit
|
|
804
806
|
} = options || {};
|
|
805
807
|
const baseUrl = resolveApiUrl(apiUrl);
|
|
@@ -853,7 +855,8 @@ async function httpFetch(url, options) {
|
|
|
853
855
|
});
|
|
854
856
|
if (!response.ok) {
|
|
855
857
|
const parsed = await parseErrorBody(response);
|
|
856
|
-
const
|
|
858
|
+
const canonicalCommerceError = errorFamily === "commerce" || typeof parsed.reason === "string" && typedCommerceErrorReasons?.includes(parsed.reason) === true;
|
|
859
|
+
const commerceEnvelope = canonicalCommerceError ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
|
|
857
860
|
if (isUsageLimitExceededResponse(response)) {
|
|
858
861
|
const limit = parseInt(
|
|
859
862
|
response.headers.get("X-Usage-Limit") || "0",
|
|
@@ -881,7 +884,7 @@ async function httpFetch(url, options) {
|
|
|
881
884
|
),
|
|
882
885
|
requestId
|
|
883
886
|
);
|
|
884
|
-
throw
|
|
887
|
+
throw canonicalCommerceError ? enhanceCommerceError(usageError, parsed.body, requestId) : enhanceNonCommerceError(usageError, parsed.reason);
|
|
885
888
|
}
|
|
886
889
|
if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && (commerceEnvelope?.reason ?? parsed.reason) === "token_expired") {
|
|
887
890
|
hasRetried401 = true;
|
|
@@ -906,7 +909,7 @@ async function httpFetch(url, options) {
|
|
|
906
909
|
details,
|
|
907
910
|
requestId,
|
|
908
911
|
retryAfter.seconds,
|
|
909
|
-
|
|
912
|
+
canonicalCommerceError
|
|
910
913
|
);
|
|
911
914
|
const method2 = (requestInit.method || "GET").toUpperCase();
|
|
912
915
|
const isTerminal = error instanceof RateLimitError || error instanceof UsageLimitError;
|
|
@@ -1084,15 +1087,15 @@ var HttpClient = class {
|
|
|
1084
1087
|
throw err;
|
|
1085
1088
|
}
|
|
1086
1089
|
}
|
|
1087
|
-
buildUrl(
|
|
1088
|
-
if (!options) return
|
|
1090
|
+
buildUrl(endpoint, options) {
|
|
1091
|
+
if (!options) return endpoint;
|
|
1089
1092
|
const { fallbackLocale, ...rest } = options;
|
|
1090
1093
|
const queryOptions = fallbackLocale === void 0 ? rest : {
|
|
1091
1094
|
...rest,
|
|
1092
1095
|
"fallback-locale": fallbackLocale === false ? "none" : fallbackLocale
|
|
1093
1096
|
};
|
|
1094
1097
|
const queryString = (0, import_qs_esm.stringify)(queryOptions, { addQueryPrefix: true });
|
|
1095
|
-
return queryString ? `${
|
|
1098
|
+
return queryString ? `${endpoint}${queryString}` : endpoint;
|
|
1096
1099
|
}
|
|
1097
1100
|
assertJsonResponse(response) {
|
|
1098
1101
|
const contentType = response.headers.get("content-type");
|
|
@@ -1234,39 +1237,39 @@ var ReadOnlyCollectionClient = class extends HttpClient {
|
|
|
1234
1237
|
from(collection) {
|
|
1235
1238
|
return new ReadOnlyCollectionQueryBuilder(this, collection);
|
|
1236
1239
|
}
|
|
1237
|
-
async requestFind(
|
|
1238
|
-
const url = this.buildUrl(
|
|
1240
|
+
async requestFind(endpoint, options) {
|
|
1241
|
+
const url = this.buildUrl(endpoint, options);
|
|
1239
1242
|
const response = await this.fetchWithTracking(url, {
|
|
1240
1243
|
...this.defaultOptions,
|
|
1241
1244
|
method: "GET"
|
|
1242
1245
|
});
|
|
1243
1246
|
return this.parseFindResponse(response);
|
|
1244
1247
|
}
|
|
1245
|
-
async requestFindEndpoint(
|
|
1246
|
-
const response = await this.fetchWithTracking(
|
|
1248
|
+
async requestFindEndpoint(endpoint, data) {
|
|
1249
|
+
const response = await this.fetchWithTracking(endpoint, {
|
|
1247
1250
|
...this.defaultOptions,
|
|
1248
1251
|
method: "POST",
|
|
1249
1252
|
body: data ? JSON.stringify(data) : void 0
|
|
1250
1253
|
});
|
|
1251
1254
|
return this.parseFindResponse(response);
|
|
1252
1255
|
}
|
|
1253
|
-
async requestFindEndpointGet(
|
|
1254
|
-
const response = await this.fetchWithTracking(
|
|
1256
|
+
async requestFindEndpointGet(endpoint) {
|
|
1257
|
+
const response = await this.fetchWithTracking(endpoint, {
|
|
1255
1258
|
...this.defaultOptions,
|
|
1256
1259
|
method: "GET"
|
|
1257
1260
|
});
|
|
1258
1261
|
return this.parseFindResponse(response);
|
|
1259
1262
|
}
|
|
1260
|
-
async requestFindById(
|
|
1261
|
-
const url = this.buildUrl(
|
|
1263
|
+
async requestFindById(endpoint, options) {
|
|
1264
|
+
const url = this.buildUrl(endpoint, options);
|
|
1262
1265
|
const response = await this.fetchWithTracking(url, {
|
|
1263
1266
|
...this.defaultOptions,
|
|
1264
1267
|
method: "GET"
|
|
1265
1268
|
});
|
|
1266
1269
|
return this.parseDocumentResponse(response);
|
|
1267
1270
|
}
|
|
1268
|
-
async requestCount(
|
|
1269
|
-
const url = this.buildUrl(
|
|
1271
|
+
async requestCount(endpoint, options) {
|
|
1272
|
+
const url = this.buildUrl(endpoint, options);
|
|
1270
1273
|
const response = await this.fetchWithTracking(url, {
|
|
1271
1274
|
...this.defaultOptions,
|
|
1272
1275
|
method: "GET"
|
|
@@ -1276,7 +1279,7 @@ var ReadOnlyCollectionClient = class extends HttpClient {
|
|
|
1276
1279
|
};
|
|
1277
1280
|
|
|
1278
1281
|
// src/core/api/parse-response.ts
|
|
1279
|
-
async function parseApiResponse(response,
|
|
1282
|
+
async function parseApiResponse(response, endpoint, options = {}) {
|
|
1280
1283
|
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
1281
1284
|
return void 0;
|
|
1282
1285
|
}
|
|
@@ -1285,7 +1288,7 @@ async function parseApiResponse(response, endpoint2, options = {}) {
|
|
|
1285
1288
|
parsed = await response.json();
|
|
1286
1289
|
} catch {
|
|
1287
1290
|
throw createApiError(
|
|
1288
|
-
`Invalid JSON response from ${
|
|
1291
|
+
`Invalid JSON response from ${endpoint}`,
|
|
1289
1292
|
response.status,
|
|
1290
1293
|
void 0,
|
|
1291
1294
|
"Server returned an invalid response.",
|
|
@@ -1335,6 +1338,7 @@ async function parseApiResponse(response, endpoint2, options = {}) {
|
|
|
1335
1338
|
|
|
1336
1339
|
// ../../internal/http-contracts/src/index.ts
|
|
1337
1340
|
var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
|
|
1341
|
+
var PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE = "application/vnd.01software.portone-action-capabilities.v1+json";
|
|
1338
1342
|
var operation = (collection, method, path, errorFamily) => Object.freeze({
|
|
1339
1343
|
[operationBrand]: true,
|
|
1340
1344
|
collection,
|
|
@@ -1343,6 +1347,10 @@ var operation = (collection, method, path, errorFamily) => Object.freeze({
|
|
|
1343
1347
|
...errorFamily && { errorFamily }
|
|
1344
1348
|
});
|
|
1345
1349
|
var strictCommerceOperation = (collection, method, path) => operation(collection, method, path, "commerce");
|
|
1350
|
+
var selectiveCommerceOperation = (collection, method, path, typedCommerceErrorReasons) => Object.freeze({
|
|
1351
|
+
...operation(collection, method, path),
|
|
1352
|
+
typedCommerceErrorReasons: Object.freeze([...typedCommerceErrorReasons])
|
|
1353
|
+
});
|
|
1346
1354
|
var COMMERCE_ENDPOINT_OPERATIONS = {
|
|
1347
1355
|
products: {
|
|
1348
1356
|
detail: operation("products", "get", "/detail"),
|
|
@@ -1374,7 +1382,12 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
|
|
|
1374
1382
|
confirmPayment: operation("orders", "post", "/confirm-payment"),
|
|
1375
1383
|
byPayment: operation("orders", "get", "/by-payment"),
|
|
1376
1384
|
cancel: operation("orders", "post", "/cancel"),
|
|
1377
|
-
resolveCancelRefund:
|
|
1385
|
+
resolveCancelRefund: selectiveCommerceOperation(
|
|
1386
|
+
"orders",
|
|
1387
|
+
"post",
|
|
1388
|
+
"/resolve-cancel-refund",
|
|
1389
|
+
["managed_refund_attestation_forbidden"]
|
|
1390
|
+
),
|
|
1378
1391
|
checkout: strictCommerceOperation("orders", "post", "/checkout"),
|
|
1379
1392
|
createFulfillment: operation("orders", "post", "/create-fulfillment"),
|
|
1380
1393
|
updateFulfillment: operation("orders", "post", "/update-fulfillment")
|
|
@@ -1383,6 +1396,11 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
|
|
|
1383
1396
|
detail: strictCommerceOperation("checkouts", "post", "/detail"),
|
|
1384
1397
|
query: strictCommerceOperation("checkouts", "post", "/query")
|
|
1385
1398
|
},
|
|
1399
|
+
draftOrders: {
|
|
1400
|
+
calculate: operation("draft-orders", "post", "/:id/calculate"),
|
|
1401
|
+
complete: operation("draft-orders", "post", "/:id/complete"),
|
|
1402
|
+
finalize: operation("draft-orders", "post", "/:id/finalize")
|
|
1403
|
+
},
|
|
1386
1404
|
transactions: {
|
|
1387
1405
|
update: operation("transactions", "post", "/update")
|
|
1388
1406
|
},
|
|
@@ -1445,6 +1463,16 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
|
|
|
1445
1463
|
"payment-sessions",
|
|
1446
1464
|
"post",
|
|
1447
1465
|
"/server/confirm"
|
|
1466
|
+
),
|
|
1467
|
+
findPortOne: strictCommerceOperation(
|
|
1468
|
+
"payment-sessions",
|
|
1469
|
+
"post",
|
|
1470
|
+
"/server/portone/find"
|
|
1471
|
+
),
|
|
1472
|
+
reconcilePortOne: strictCommerceOperation(
|
|
1473
|
+
"payment-sessions",
|
|
1474
|
+
"post",
|
|
1475
|
+
"/server/portone/reconcile"
|
|
1448
1476
|
)
|
|
1449
1477
|
},
|
|
1450
1478
|
custom: {
|
|
@@ -1464,12 +1492,34 @@ var COMMERCE_ENDPOINT_OPERATIONS = {
|
|
|
1464
1492
|
validate: operation("discounts", "post", "/validate")
|
|
1465
1493
|
}
|
|
1466
1494
|
};
|
|
1495
|
+
var portOneStandardActionCapabilityOperations = /* @__PURE__ */ new Set([
|
|
1496
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.create,
|
|
1497
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.retrieve,
|
|
1498
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.create,
|
|
1499
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.retrieve
|
|
1500
|
+
]);
|
|
1467
1501
|
var MEMBERSHIP_ENDPOINT_OPERATIONS = {
|
|
1468
1502
|
subscribe: operation(null, "post", "/memberships/subscribe"),
|
|
1469
1503
|
cancel: operation(null, "post", "/memberships/:id/cancel"),
|
|
1470
|
-
me: operation(null, "get", "/memberships/me")
|
|
1504
|
+
me: operation(null, "get", "/memberships/me"),
|
|
1505
|
+
chargeResult: operation(null, "post", "/memberships/:id/charge-result"),
|
|
1506
|
+
refundResult: operation(null, "post", "/memberships/:id/refund-result"),
|
|
1507
|
+
revoke: operation(null, "post", "/memberships/:id/revoke")
|
|
1508
|
+
};
|
|
1509
|
+
var CUSTOMER_GROUP_ENDPOINT_OPERATIONS = {
|
|
1510
|
+
members: operation("customer-groups", "get", "/:id/members"),
|
|
1511
|
+
grant: operation("customer-groups", "post", "/:id/members/grant"),
|
|
1512
|
+
revoke: operation("customer-groups", "post", "/:id/members/revoke")
|
|
1513
|
+
};
|
|
1514
|
+
var EMBEDDED_ADMIN_ENDPOINT_OPERATIONS = {
|
|
1515
|
+
show: operation("tenants", "get", "/embedded-admin-app"),
|
|
1516
|
+
configure: operation("tenants", "patch", "/embedded-admin-app"),
|
|
1517
|
+
disable: operation("tenants", "delete", "/embedded-admin-app")
|
|
1471
1518
|
};
|
|
1472
1519
|
var EVENTS_ENDPOINT_OPERATIONS = {
|
|
1520
|
+
events: {
|
|
1521
|
+
convertSchedule: operation("events", "post", "/:id/schedule")
|
|
1522
|
+
},
|
|
1473
1523
|
occurrences: {
|
|
1474
1524
|
range: operation("event-occurrences", "get", "/range"),
|
|
1475
1525
|
admissionAvailability: operation(
|
|
@@ -1510,46 +1560,51 @@ function resolveOperationMethod(descriptor) {
|
|
|
1510
1560
|
}
|
|
1511
1561
|
|
|
1512
1562
|
// src/core/api/endpoints.ts
|
|
1513
|
-
var endpoint = (method, path) => ({ method, path });
|
|
1514
1563
|
var sharedEndpoint = (descriptor) => descriptor;
|
|
1515
|
-
function resolveOperationMethod2(descriptor) {
|
|
1516
|
-
return "collection" in descriptor ? resolveOperationMethod(descriptor) : descriptor.method;
|
|
1517
|
-
}
|
|
1518
1564
|
function resolveOperationErrorFamily(descriptor) {
|
|
1519
|
-
return
|
|
1520
|
-
}
|
|
1521
|
-
function resolveOperationPath2(descriptor, options) {
|
|
1522
|
-
if ("collection" in descriptor) {
|
|
1523
|
-
return resolveOperationPath(descriptor, options);
|
|
1524
|
-
}
|
|
1525
|
-
const query = options?.query?.toString().replace(/^\?/, "");
|
|
1526
|
-
return query ? `${descriptor.path}?${query}` : descriptor.path;
|
|
1565
|
+
return descriptor.errorFamily;
|
|
1527
1566
|
}
|
|
1528
1567
|
var COMMERCE_ENDPOINTS = {
|
|
1529
1568
|
products: {
|
|
1530
|
-
detail:
|
|
1531
|
-
detailCatalog:
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1569
|
+
detail: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.detail),
|
|
1570
|
+
detailCatalog: sharedEndpoint(
|
|
1571
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog
|
|
1572
|
+
),
|
|
1573
|
+
listingGroups: sharedEndpoint(
|
|
1574
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.listingGroups
|
|
1575
|
+
),
|
|
1576
|
+
listingGroupsCatalog: sharedEndpoint(
|
|
1577
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog
|
|
1578
|
+
),
|
|
1579
|
+
// The manifest keeps the GET read and the POST body-query apart; this
|
|
1580
|
+
// semantic name has always resolved to the GET one.
|
|
1581
|
+
listingGroupsQuery: sharedEndpoint(
|
|
1582
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryGet
|
|
1583
|
+
),
|
|
1584
|
+
listingGroupsQueryCatalog: sharedEndpoint(
|
|
1585
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryCatalog
|
|
1536
1586
|
),
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
"GET",
|
|
1540
|
-
"/api/products/listing-groups/query/catalog"
|
|
1587
|
+
stockCheck: sharedEndpoint(
|
|
1588
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.stockCheck
|
|
1541
1589
|
),
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1590
|
+
stockSnapshot: sharedEndpoint(
|
|
1591
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.stockSnapshot
|
|
1592
|
+
),
|
|
1593
|
+
upsert: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.products.upsert)
|
|
1545
1594
|
},
|
|
1546
1595
|
orders: {
|
|
1547
|
-
update:
|
|
1548
|
-
byPayment:
|
|
1549
|
-
cancel:
|
|
1550
|
-
resolveCancelRefund:
|
|
1551
|
-
|
|
1552
|
-
|
|
1596
|
+
update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.update),
|
|
1597
|
+
byPayment: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.byPayment),
|
|
1598
|
+
cancel: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.cancel),
|
|
1599
|
+
resolveCancelRefund: sharedEndpoint(
|
|
1600
|
+
COMMERCE_ENDPOINT_OPERATIONS.orders.resolveCancelRefund
|
|
1601
|
+
),
|
|
1602
|
+
createFulfillment: sharedEndpoint(
|
|
1603
|
+
COMMERCE_ENDPOINT_OPERATIONS.orders.createFulfillment
|
|
1604
|
+
),
|
|
1605
|
+
updateFulfillment: sharedEndpoint(
|
|
1606
|
+
COMMERCE_ENDPOINT_OPERATIONS.orders.updateFulfillment
|
|
1607
|
+
)
|
|
1553
1608
|
},
|
|
1554
1609
|
checkouts: {
|
|
1555
1610
|
create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.orders.checkout),
|
|
@@ -1561,18 +1616,21 @@ var COMMERCE_ENDPOINTS = {
|
|
|
1561
1616
|
}
|
|
1562
1617
|
},
|
|
1563
1618
|
returns: {
|
|
1564
|
-
create:
|
|
1565
|
-
update:
|
|
1566
|
-
returnRefund:
|
|
1619
|
+
create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.create),
|
|
1620
|
+
update: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.returns.update),
|
|
1621
|
+
returnRefund: sharedEndpoint(
|
|
1622
|
+
COMMERCE_ENDPOINT_OPERATIONS.returns.returnRefund
|
|
1623
|
+
)
|
|
1567
1624
|
},
|
|
1568
1625
|
fulfillmentOrders: {
|
|
1569
|
-
prepare:
|
|
1570
|
-
|
|
1571
|
-
"/api/fulfillment-orders/prepare-fulfillment-order"
|
|
1626
|
+
prepare: sharedEndpoint(
|
|
1627
|
+
COMMERCE_ENDPOINT_OPERATIONS.fulfillmentOrders.prepare
|
|
1572
1628
|
)
|
|
1573
1629
|
},
|
|
1574
1630
|
fulfillments: {
|
|
1575
|
-
bulkImport:
|
|
1631
|
+
bulkImport: sharedEndpoint(
|
|
1632
|
+
COMMERCE_ENDPOINT_OPERATIONS.fulfillments.bulkImport
|
|
1633
|
+
)
|
|
1576
1634
|
},
|
|
1577
1635
|
carts: {
|
|
1578
1636
|
create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.create),
|
|
@@ -1637,42 +1695,21 @@ var COMMERCE_ENDPOINTS = {
|
|
|
1637
1695
|
),
|
|
1638
1696
|
confirm: sharedEndpoint(
|
|
1639
1697
|
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.confirm
|
|
1698
|
+
),
|
|
1699
|
+
findPortOne: sharedEndpoint(
|
|
1700
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.findPortOne
|
|
1701
|
+
),
|
|
1702
|
+
reconcilePortOne: sharedEndpoint(
|
|
1703
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.reconcilePortOne
|
|
1640
1704
|
)
|
|
1641
1705
|
}
|
|
1642
1706
|
},
|
|
1643
1707
|
shippingPolicies: {
|
|
1644
|
-
calculate:
|
|
1708
|
+
calculate: sharedEndpoint(
|
|
1709
|
+
COMMERCE_ENDPOINT_OPERATIONS.shippingPolicies.calculate
|
|
1710
|
+
)
|
|
1645
1711
|
}
|
|
1646
1712
|
};
|
|
1647
|
-
function isCommerceEndpointDescriptor(value) {
|
|
1648
|
-
if (!value || typeof value !== "object") return false;
|
|
1649
|
-
const candidate = value;
|
|
1650
|
-
return typeof candidate.method === "string" && typeof candidate.path === "string";
|
|
1651
|
-
}
|
|
1652
|
-
function flattenEndpointPaths(value) {
|
|
1653
|
-
if (isCommerceEndpointDescriptor(value)) return [resolveOperationPath2(value)];
|
|
1654
|
-
if (!value || typeof value !== "object") return [];
|
|
1655
|
-
return Object.values(value).flatMap((entry) => flattenEndpointPaths(entry));
|
|
1656
|
-
}
|
|
1657
|
-
function flattenEndpointDescriptors(value) {
|
|
1658
|
-
if (isCommerceEndpointDescriptor(value)) return [value];
|
|
1659
|
-
if (!value || typeof value !== "object") return [];
|
|
1660
|
-
return Object.values(value).flatMap(
|
|
1661
|
-
(entry) => flattenEndpointDescriptors(entry)
|
|
1662
|
-
);
|
|
1663
|
-
}
|
|
1664
|
-
var COMMERCE_ENDPOINT_PATHS = flattenEndpointPaths(COMMERCE_ENDPOINTS);
|
|
1665
|
-
var COMMERCE_ENDPOINT_DESCRIPTORS = flattenEndpointDescriptors(COMMERCE_ENDPOINTS);
|
|
1666
|
-
var MEMBERSHIP_ENDPOINTS = {
|
|
1667
|
-
subscribe: "/api/memberships/subscribe",
|
|
1668
|
-
cancel: (id) => `/api/memberships/${id}/cancel`,
|
|
1669
|
-
me: "/api/memberships/me"
|
|
1670
|
-
};
|
|
1671
|
-
var MEMBERSHIP_ENDPOINT_PATHS = [
|
|
1672
|
-
MEMBERSHIP_ENDPOINTS.subscribe,
|
|
1673
|
-
MEMBERSHIP_ENDPOINTS.cancel(":id"),
|
|
1674
|
-
MEMBERSHIP_ENDPOINTS.me
|
|
1675
|
-
];
|
|
1676
1713
|
|
|
1677
1714
|
// src/core/api/customer-scoped-api.ts
|
|
1678
1715
|
var CustomerScopedTransport = class {
|
|
@@ -1693,10 +1730,10 @@ var CustomerScopedTransport = class {
|
|
|
1693
1730
|
this.onUnauthorized = options.onUnauthorized;
|
|
1694
1731
|
this.onRequestId = options.onRequestId;
|
|
1695
1732
|
}
|
|
1696
|
-
async request(
|
|
1733
|
+
async request(endpoint, options) {
|
|
1697
1734
|
const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
|
|
1698
1735
|
try {
|
|
1699
|
-
const response = await httpFetch(
|
|
1736
|
+
const response = await httpFetch(endpoint, {
|
|
1700
1737
|
method: options.method,
|
|
1701
1738
|
apiUrl: this.apiUrl,
|
|
1702
1739
|
publishableKey: this.publishableKey,
|
|
@@ -1710,7 +1747,7 @@ var CustomerScopedTransport = class {
|
|
|
1710
1747
|
...options.errorFamily && { errorFamily: options.errorFamily }
|
|
1711
1748
|
});
|
|
1712
1749
|
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
1713
|
-
return parseApiResponse(response,
|
|
1750
|
+
return parseApiResponse(response, endpoint, {
|
|
1714
1751
|
errorFamily: options.errorFamily
|
|
1715
1752
|
});
|
|
1716
1753
|
} catch (err) {
|
|
@@ -1724,12 +1761,12 @@ var CustomerScopedApi = class {
|
|
|
1724
1761
|
constructor(apiName, options) {
|
|
1725
1762
|
this.transport = new CustomerScopedTransport(apiName, options);
|
|
1726
1763
|
}
|
|
1727
|
-
requestEndpoint(
|
|
1728
|
-
return this.transport.request(
|
|
1729
|
-
method:
|
|
1764
|
+
requestEndpoint(endpoint, body, options) {
|
|
1765
|
+
return this.transport.request(resolveOperationPath(endpoint, options), {
|
|
1766
|
+
method: resolveOperationMethod(endpoint),
|
|
1730
1767
|
body,
|
|
1731
1768
|
headers: options?.headers,
|
|
1732
|
-
errorFamily: resolveOperationErrorFamily(
|
|
1769
|
+
errorFamily: resolveOperationErrorFamily(endpoint)
|
|
1733
1770
|
});
|
|
1734
1771
|
}
|
|
1735
1772
|
};
|
|
@@ -1737,8 +1774,8 @@ var RawCustomerScopedApi = class {
|
|
|
1737
1774
|
constructor(apiName, options) {
|
|
1738
1775
|
this.transport = new CustomerScopedTransport(apiName, options);
|
|
1739
1776
|
}
|
|
1740
|
-
request(
|
|
1741
|
-
return this.transport.request(
|
|
1777
|
+
request(endpoint, options) {
|
|
1778
|
+
return this.transport.request(endpoint, options);
|
|
1742
1779
|
}
|
|
1743
1780
|
};
|
|
1744
1781
|
|
|
@@ -1813,11 +1850,11 @@ var CommunityClient = class extends RawCustomerScopedApi {
|
|
|
1813
1850
|
if (params.page !== void 0) urlParams.set("page", String(params.page));
|
|
1814
1851
|
return `/api/comments/public?${urlParams.toString()}`;
|
|
1815
1852
|
}
|
|
1816
|
-
async execute(
|
|
1817
|
-
return this.request(
|
|
1853
|
+
async execute(endpoint, method, body) {
|
|
1854
|
+
return this.request(endpoint, { method, body });
|
|
1818
1855
|
}
|
|
1819
|
-
async executeDoc(
|
|
1820
|
-
const response = await this.execute(
|
|
1856
|
+
async executeDoc(endpoint, method, body) {
|
|
1857
|
+
const response = await this.execute(endpoint, method, body);
|
|
1821
1858
|
return unwrapPayloadDoc(response);
|
|
1822
1859
|
}
|
|
1823
1860
|
createPost(params) {
|
|
@@ -2083,8 +2120,8 @@ var CommunityClient = class extends RawCustomerScopedApi {
|
|
|
2083
2120
|
|
|
2084
2121
|
// src/core/content/content-client.ts
|
|
2085
2122
|
var PublicContentApi = class extends RawCustomerScopedApi {
|
|
2086
|
-
get(
|
|
2087
|
-
return this.request(
|
|
2123
|
+
get(endpoint) {
|
|
2124
|
+
return this.request(endpoint, { method: "GET" });
|
|
2088
2125
|
}
|
|
2089
2126
|
};
|
|
2090
2127
|
function appendCommonParams(search, options, defaultSort) {
|
|
@@ -2182,7 +2219,10 @@ var ORDER_PRIMARY_DISPLAY_STATUSES = [
|
|
|
2182
2219
|
];
|
|
2183
2220
|
var CHECKOUT_STATUSES = ["open", "placed", "abandoned"];
|
|
2184
2221
|
var ABANDONED_REASONS = ["expired", "customer", "operator"];
|
|
2185
|
-
|
|
2222
|
+
function managedPaymentProviders(providers) {
|
|
2223
|
+
return providers;
|
|
2224
|
+
}
|
|
2225
|
+
var PAYMENT_PROVIDERS = managedPaymentProviders(["toss", "portone"]);
|
|
2186
2226
|
var PAYMENT_PROVIDER_STATUSES = [
|
|
2187
2227
|
"requires_payment_method",
|
|
2188
2228
|
"requires_action",
|
|
@@ -2230,6 +2270,26 @@ function invalidCanonicalResponse(resource, details) {
|
|
|
2230
2270
|
function fail(resource, path, expected) {
|
|
2231
2271
|
invalidCanonicalResponse(resource, { path, expected });
|
|
2232
2272
|
}
|
|
2273
|
+
function providerMismatch(resource, expected, actual, operation2) {
|
|
2274
|
+
if (operation2 === "cancel") {
|
|
2275
|
+
const method = {
|
|
2276
|
+
toss: "cancel()",
|
|
2277
|
+
portone: "cancelPortOne()"
|
|
2278
|
+
}[actual];
|
|
2279
|
+
throw createApiError(
|
|
2280
|
+
`Canonical ${resource} response provider mismatch: expected ${expected}, received ${actual}.`,
|
|
2281
|
+
502,
|
|
2282
|
+
{ resource, path: "$.provider", expected, actual },
|
|
2283
|
+
`The server applied the cancellation to a ${actual} PaymentSession, but this SDK method expects ${expected}.`,
|
|
2284
|
+
`Re-invoke ${method} with the same idempotencyKey; do not create a new key.`
|
|
2285
|
+
);
|
|
2286
|
+
}
|
|
2287
|
+
invalidCanonicalResponse(resource, {
|
|
2288
|
+
path: "$.provider",
|
|
2289
|
+
expected,
|
|
2290
|
+
actual
|
|
2291
|
+
});
|
|
2292
|
+
}
|
|
2233
2293
|
function record(value, resource, path) {
|
|
2234
2294
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2235
2295
|
fail(resource, path, "object");
|
|
@@ -2265,6 +2325,9 @@ function nullableString(value, resource, path) {
|
|
|
2265
2325
|
fail(resource, path, "string or null");
|
|
2266
2326
|
}
|
|
2267
2327
|
}
|
|
2328
|
+
function nullableNonEmptyString(value, resource, path) {
|
|
2329
|
+
if (value !== null) string(value, resource, path);
|
|
2330
|
+
}
|
|
2268
2331
|
function cartLineQuantity(value, resource, path) {
|
|
2269
2332
|
const quantity = positiveInteger(value, resource, path);
|
|
2270
2333
|
if (quantity > MAX_CART_LINE_QUANTITY) {
|
|
@@ -2774,8 +2837,8 @@ function validatePublicOrderItem(value, resource, path) {
|
|
|
2774
2837
|
validateReference(item.variant, resource, `${path}.variant`);
|
|
2775
2838
|
}
|
|
2776
2839
|
string(item.productTitle, resource, `${path}.productTitle`);
|
|
2777
|
-
|
|
2778
|
-
|
|
2840
|
+
nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
|
|
2841
|
+
nullableNonEmptyString(item.sku, resource, `${path}.sku`);
|
|
2779
2842
|
validateAdmissions(item.admissions, resource, `${path}.admissions`);
|
|
2780
2843
|
const quantity = positiveInteger(item.quantity, resource, `${path}.quantity`);
|
|
2781
2844
|
const unitPrice = safeMinor(
|
|
@@ -3026,8 +3089,8 @@ function validateCheckoutItem(value, resource, path) {
|
|
|
3026
3089
|
validateReference(item.product, resource, `${path}.product`);
|
|
3027
3090
|
validateReference(item.variant, resource, `${path}.variant`);
|
|
3028
3091
|
string(item.productTitle, resource, `${path}.productTitle`);
|
|
3029
|
-
|
|
3030
|
-
|
|
3092
|
+
nullableNonEmptyString(item.variantTitle, resource, `${path}.variantTitle`);
|
|
3093
|
+
nullableNonEmptyString(item.sku, resource, `${path}.sku`);
|
|
3031
3094
|
validateAdmissions(item.admissions, resource, `${path}.admissions`);
|
|
3032
3095
|
cartLineQuantity(item.quantity, resource, `${path}.quantity`);
|
|
3033
3096
|
const unitPrice = safeMinor(
|
|
@@ -3359,11 +3422,21 @@ function validateNextAction(value, provider, resource, path) {
|
|
|
3359
3422
|
const action = record(value, resource, path);
|
|
3360
3423
|
if (provider === "portone") {
|
|
3361
3424
|
if (action.type === "portone_sdk") {
|
|
3425
|
+
const hasCancelable = "cancelable" in action;
|
|
3426
|
+
const hasRetryPolicy = "retryPolicy" in action;
|
|
3427
|
+
if (hasCancelable !== hasRetryPolicy) {
|
|
3428
|
+
fail(
|
|
3429
|
+
resource,
|
|
3430
|
+
path,
|
|
3431
|
+
"exact released action or exact negotiated capability action"
|
|
3432
|
+
);
|
|
3433
|
+
}
|
|
3362
3434
|
exact(
|
|
3363
3435
|
action,
|
|
3364
3436
|
[
|
|
3365
3437
|
"type",
|
|
3366
3438
|
"version",
|
|
3439
|
+
...hasCancelable ? ["cancelable", "retryPolicy"] : [],
|
|
3367
3440
|
"storeId",
|
|
3368
3441
|
"channelKey",
|
|
3369
3442
|
"paymentId",
|
|
@@ -3378,6 +3451,11 @@ function validateNextAction(value, provider, resource, path) {
|
|
|
3378
3451
|
path
|
|
3379
3452
|
);
|
|
3380
3453
|
if (action.version !== "v2") fail(resource, `${path}.version`, "v2");
|
|
3454
|
+
if (hasCancelable && action.cancelable !== false)
|
|
3455
|
+
fail(resource, `${path}.cancelable`, "false");
|
|
3456
|
+
if (hasRetryPolicy && action.retryPolicy !== "same_action_only") {
|
|
3457
|
+
fail(resource, `${path}.retryPolicy`, "same_action_only");
|
|
3458
|
+
}
|
|
3381
3459
|
for (const key of ["storeId", "channelKey"]) {
|
|
3382
3460
|
boundedString(action[key], 255, resource, `${path}.${key}`);
|
|
3383
3461
|
}
|
|
@@ -3424,6 +3502,10 @@ function validateNextAction(value, provider, resource, path) {
|
|
|
3424
3502
|
"HTTPS or loopback URL without embedded credentials"
|
|
3425
3503
|
);
|
|
3426
3504
|
}
|
|
3505
|
+
if (!hasCancelable) {
|
|
3506
|
+
action.cancelable = false;
|
|
3507
|
+
action.retryPolicy = "same_action_only";
|
|
3508
|
+
}
|
|
3427
3509
|
return;
|
|
3428
3510
|
}
|
|
3429
3511
|
exact(action, ["type", "checkoutUrl"], [], resource, path);
|
|
@@ -3500,7 +3582,7 @@ function validateNextAction(value, provider, resource, path) {
|
|
|
3500
3582
|
if (action.customerEmail !== void 0)
|
|
3501
3583
|
validateCustomer({ email: action.customerEmail }, resource, path);
|
|
3502
3584
|
}
|
|
3503
|
-
function validatePublicPaymentSession(value, expectedProvider) {
|
|
3585
|
+
function validatePublicPaymentSession(value, expectedProvider, operation2) {
|
|
3504
3586
|
const resource = "PaymentSession";
|
|
3505
3587
|
const session = record(value, resource, "$");
|
|
3506
3588
|
const provider = enumValue(
|
|
@@ -3509,9 +3591,6 @@ function validatePublicPaymentSession(value, expectedProvider) {
|
|
|
3509
3591
|
resource,
|
|
3510
3592
|
"$.provider"
|
|
3511
3593
|
);
|
|
3512
|
-
if (expectedProvider !== void 0 && provider !== expectedProvider) {
|
|
3513
|
-
fail(resource, "$.provider", expectedProvider);
|
|
3514
|
-
}
|
|
3515
3594
|
const status = enumValue(
|
|
3516
3595
|
session.providerStatus,
|
|
3517
3596
|
PAYMENT_PROVIDER_STATUSES,
|
|
@@ -3715,44 +3794,128 @@ function validatePublicPaymentSession(value, expectedProvider) {
|
|
|
3715
3794
|
"$.cancellationReason"
|
|
3716
3795
|
);
|
|
3717
3796
|
}
|
|
3797
|
+
if (expectedProvider !== void 0 && provider !== expectedProvider) {
|
|
3798
|
+
if (operation2 === "cancel" && status !== "canceling" && status !== "canceled") {
|
|
3799
|
+
fail(
|
|
3800
|
+
resource,
|
|
3801
|
+
"$.providerStatus",
|
|
3802
|
+
"canceling or canceled after a successful cancellation"
|
|
3803
|
+
);
|
|
3804
|
+
}
|
|
3805
|
+
providerMismatch(resource, expectedProvider, provider, operation2);
|
|
3806
|
+
}
|
|
3718
3807
|
return value;
|
|
3719
3808
|
}
|
|
3720
3809
|
|
|
3721
3810
|
// src/core/customer/customer-auth.ts
|
|
3722
3811
|
var DEFAULT_TIMEOUT2 = 15e3;
|
|
3723
|
-
|
|
3812
|
+
var REFRESH_LOCK_TIMEOUT = DEFAULT_TIMEOUT2 * 3;
|
|
3813
|
+
var SESSION_RECORD_VERSION = 1;
|
|
3814
|
+
var STORAGE_UNUSABLE = /* @__PURE__ */ Symbol("storage-unusable");
|
|
3815
|
+
function canonicalApiIdentity(apiUrl) {
|
|
3724
3816
|
try {
|
|
3725
|
-
|
|
3817
|
+
const url = new URL(apiUrl);
|
|
3818
|
+
return `${url.protocol.toLowerCase()}//${url.host.toLowerCase()}${url.pathname.replace(/\/+$/, "")}`;
|
|
3819
|
+
} catch {
|
|
3820
|
+
return apiUrl.trim().toLowerCase().replace(/\/+$/, "");
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
function buildRefreshLockName(apiUrl, publishableKey, storageKey) {
|
|
3824
|
+
return `01software:customer-auth-refresh:${canonicalApiIdentity(apiUrl)}:${publishableKey}:${storageKey}`;
|
|
3825
|
+
}
|
|
3826
|
+
function getRefreshLockRequester() {
|
|
3827
|
+
try {
|
|
3828
|
+
if (typeof navigator === "undefined") return null;
|
|
3829
|
+
const locks = navigator.locks;
|
|
3830
|
+
if (!locks || typeof locks.request !== "function") return null;
|
|
3831
|
+
return (name, options, callback) => locks.request(
|
|
3832
|
+
name,
|
|
3833
|
+
options,
|
|
3834
|
+
() => callback()
|
|
3835
|
+
);
|
|
3726
3836
|
} catch {
|
|
3727
3837
|
return null;
|
|
3728
3838
|
}
|
|
3729
3839
|
}
|
|
3840
|
+
function parseSessionRecord(raw) {
|
|
3841
|
+
try {
|
|
3842
|
+
const parsed = JSON.parse(raw);
|
|
3843
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
3844
|
+
const candidate = parsed;
|
|
3845
|
+
if (candidate.v !== SESSION_RECORD_VERSION) return null;
|
|
3846
|
+
if (typeof candidate.rev !== "number" || !Number.isFinite(candidate.rev)) {
|
|
3847
|
+
return null;
|
|
3848
|
+
}
|
|
3849
|
+
const token = candidate.token;
|
|
3850
|
+
const refreshToken = candidate.refreshToken;
|
|
3851
|
+
if (token !== null && typeof token !== "string") return null;
|
|
3852
|
+
if (refreshToken !== null && typeof refreshToken !== "string") return null;
|
|
3853
|
+
return {
|
|
3854
|
+
v: SESSION_RECORD_VERSION,
|
|
3855
|
+
rev: candidate.rev,
|
|
3856
|
+
token,
|
|
3857
|
+
refreshToken
|
|
3858
|
+
};
|
|
3859
|
+
} catch {
|
|
3860
|
+
return null;
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
function readSessionRecord(recordKey, mirrorKey, mirrorRefreshKey) {
|
|
3864
|
+
let raw;
|
|
3865
|
+
try {
|
|
3866
|
+
raw = localStorage.getItem(recordKey);
|
|
3867
|
+
} catch {
|
|
3868
|
+
return STORAGE_UNUSABLE;
|
|
3869
|
+
}
|
|
3870
|
+
if (raw !== null) {
|
|
3871
|
+
const parsed = parseSessionRecord(raw);
|
|
3872
|
+
return parsed ? { record: parsed, stored: true } : STORAGE_UNUSABLE;
|
|
3873
|
+
}
|
|
3874
|
+
try {
|
|
3875
|
+
return {
|
|
3876
|
+
record: {
|
|
3877
|
+
v: SESSION_RECORD_VERSION,
|
|
3878
|
+
rev: 0,
|
|
3879
|
+
token: localStorage.getItem(mirrorKey),
|
|
3880
|
+
refreshToken: localStorage.getItem(mirrorRefreshKey)
|
|
3881
|
+
},
|
|
3882
|
+
stored: false
|
|
3883
|
+
};
|
|
3884
|
+
} catch {
|
|
3885
|
+
return STORAGE_UNUSABLE;
|
|
3886
|
+
}
|
|
3887
|
+
}
|
|
3730
3888
|
var CustomerAuth = class {
|
|
3731
3889
|
constructor(publishableKey, options, apiUrl) {
|
|
3732
3890
|
this.refreshPromise = null;
|
|
3891
|
+
/** Canonical record key; null unless persistence is active in a browser. */
|
|
3892
|
+
this.persistRecordKey = null;
|
|
3893
|
+
/** Advisory single-value access mirror, plus the retired refresh mirror. */
|
|
3894
|
+
this.persistMirrorKey = null;
|
|
3895
|
+
this.persistMirrorRefreshKey = null;
|
|
3896
|
+
/** Cross-context refresh lock name; null when there is no shared storage. */
|
|
3897
|
+
this.refreshLockName = null;
|
|
3898
|
+
/** Revision of the canonical record this instance last observed. */
|
|
3899
|
+
this.sessionRev = 0;
|
|
3733
3900
|
this.publishableKey = publishableKey;
|
|
3734
3901
|
this.baseUrl = resolveApiUrl(apiUrl);
|
|
3735
3902
|
const persist = options?.persist ?? true;
|
|
3736
3903
|
if (persist) {
|
|
3737
3904
|
const key = typeof persist === "string" ? persist : "customer-token";
|
|
3738
|
-
const refreshKey = `${key}:refresh`;
|
|
3739
3905
|
const isBrowser = typeof window !== "undefined";
|
|
3740
|
-
this.token =
|
|
3741
|
-
this.refreshTokenValue =
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
} catch {
|
|
3754
|
-
}
|
|
3755
|
-
} : void 0;
|
|
3906
|
+
this.token = null;
|
|
3907
|
+
this.refreshTokenValue = null;
|
|
3908
|
+
if (isBrowser) {
|
|
3909
|
+
this.persistRecordKey = `${key}:session`;
|
|
3910
|
+
this.persistMirrorKey = key;
|
|
3911
|
+
this.persistMirrorRefreshKey = `${key}:refresh`;
|
|
3912
|
+
this.refreshLockName = buildRefreshLockName(
|
|
3913
|
+
this.baseUrl,
|
|
3914
|
+
publishableKey,
|
|
3915
|
+
key
|
|
3916
|
+
);
|
|
3917
|
+
this.syncFromPersistedStorage();
|
|
3918
|
+
}
|
|
3756
3919
|
} else {
|
|
3757
3920
|
this.token = options?.token ?? null;
|
|
3758
3921
|
this.refreshTokenValue = options?.refreshToken ?? null;
|
|
@@ -3780,66 +3943,299 @@ var CustomerAuth = class {
|
|
|
3780
3943
|
body: JSON.stringify(data)
|
|
3781
3944
|
}
|
|
3782
3945
|
);
|
|
3783
|
-
this.
|
|
3784
|
-
|
|
3946
|
+
if (result.refreshToken) this.setSession(result.token, result.refreshToken);
|
|
3947
|
+
else this.setToken(result.token);
|
|
3785
3948
|
return result;
|
|
3786
3949
|
}
|
|
3787
3950
|
/**
|
|
3788
3951
|
* Refresh the current token. Uses a refresh token when available, otherwise
|
|
3789
3952
|
* falls back to the legacy bearer-token compatibility path.
|
|
3953
|
+
*
|
|
3954
|
+
* Refresh tokens are single-use, so a persisted session shared by several
|
|
3955
|
+
* tabs or SDK instances must rotate at most once: concurrent rotations of the
|
|
3956
|
+
* same token are replay from the server's point of view and revoke the whole
|
|
3957
|
+
* family. Persisted browser sessions therefore serialize rotation across
|
|
3958
|
+
* contexts and re-read the canonical persisted credentials inside the lock.
|
|
3790
3959
|
*/
|
|
3791
3960
|
async refreshToken() {
|
|
3961
|
+
this.syncFromPersistedStorage();
|
|
3792
3962
|
if (!this.refreshTokenValue && !this.token) {
|
|
3793
3963
|
throw new ApiError("Not authenticated", 401);
|
|
3794
3964
|
}
|
|
3795
3965
|
if (this.refreshPromise) return this.refreshPromise;
|
|
3796
|
-
|
|
3966
|
+
const intended = this.currentFence();
|
|
3967
|
+
this.refreshPromise = this.rotateAcrossContexts(intended);
|
|
3797
3968
|
try {
|
|
3798
3969
|
return await this.refreshPromise;
|
|
3799
3970
|
} finally {
|
|
3800
3971
|
this.refreshPromise = null;
|
|
3801
3972
|
}
|
|
3802
3973
|
}
|
|
3803
|
-
|
|
3804
|
-
|
|
3974
|
+
/**
|
|
3975
|
+
* Re-read the canonical persisted session. In persisted mode the shared
|
|
3976
|
+
* record — not this instance's memory — is the source of truth, so another
|
|
3977
|
+
* context's rotation, login, or logout is observed before the next credential
|
|
3978
|
+
* use. Change callbacks are deliberately not invoked: this is a read.
|
|
3979
|
+
*/
|
|
3980
|
+
syncFromPersistedStorage() {
|
|
3981
|
+
const canonical = this.readCanonicalSession();
|
|
3982
|
+
if (canonical === STORAGE_UNUSABLE) {
|
|
3983
|
+
this.disablePersistence();
|
|
3984
|
+
return;
|
|
3985
|
+
}
|
|
3986
|
+
if (!canonical) return;
|
|
3987
|
+
this.sessionRev = canonical.record.rev;
|
|
3988
|
+
this.token = canonical.record.token;
|
|
3989
|
+
this.refreshTokenValue = canonical.record.refreshToken;
|
|
3990
|
+
}
|
|
3991
|
+
/** `null` when this instance does not persist. */
|
|
3992
|
+
readCanonicalSession() {
|
|
3993
|
+
if (!this.persistRecordKey || !this.persistMirrorKey || !this.persistMirrorRefreshKey) {
|
|
3994
|
+
return null;
|
|
3995
|
+
}
|
|
3996
|
+
return readSessionRecord(
|
|
3997
|
+
this.persistRecordKey,
|
|
3998
|
+
this.persistMirrorKey,
|
|
3999
|
+
this.persistMirrorRefreshKey
|
|
4000
|
+
);
|
|
4001
|
+
}
|
|
4002
|
+
/**
|
|
4003
|
+
* Publish a change to canonical storage.
|
|
4004
|
+
*
|
|
4005
|
+
* The canonical pair is re-read immediately before the single record write so
|
|
4006
|
+
* that a field this call does not change is taken from that read rather than
|
|
4007
|
+
* from this instance's possibly stale copy. That merge is BEST-EFFORT: it
|
|
4008
|
+
* removes the stale counterpart an instance would otherwise carry, but it is
|
|
4009
|
+
* not a compare-and-swap. Web Storage offers none, and the synchronous public
|
|
4010
|
+
* mutators cannot await the refresh lease, so a commit that lands between
|
|
4011
|
+
* this read and the store operation is lost by ordering — including the
|
|
4012
|
+
* counterpart just read, which is then republished stale. The window is one
|
|
4013
|
+
* store operation wide and the server remains authoritative; see
|
|
4014
|
+
* `CUST-AUTH-033` for the stated limit.
|
|
4015
|
+
*
|
|
4016
|
+
* Returns `false` only when `requireLiveSession` refused a write because the
|
|
4017
|
+
* canonical session had already been cleared.
|
|
4018
|
+
*/
|
|
4019
|
+
commitPersistedSession(change, options) {
|
|
4020
|
+
const recordKey = this.persistRecordKey;
|
|
4021
|
+
const mirrorKey = this.persistMirrorKey;
|
|
4022
|
+
const mirrorRefreshKey = this.persistMirrorRefreshKey;
|
|
4023
|
+
const canonical = this.readCanonicalSession();
|
|
4024
|
+
if (canonical === null || !recordKey || !mirrorKey || !mirrorRefreshKey) {
|
|
4025
|
+
return true;
|
|
4026
|
+
}
|
|
4027
|
+
if (canonical === STORAGE_UNUSABLE) {
|
|
4028
|
+
this.disablePersistence();
|
|
4029
|
+
return true;
|
|
4030
|
+
}
|
|
4031
|
+
const current = canonical.record;
|
|
4032
|
+
if (options?.requireLiveSession && !current.token && !current.refreshToken) {
|
|
4033
|
+
return false;
|
|
4034
|
+
}
|
|
4035
|
+
const next = {
|
|
4036
|
+
v: SESSION_RECORD_VERSION,
|
|
4037
|
+
rev: current.rev + 1,
|
|
4038
|
+
token: "token" in change ? change.token ?? null : current.token,
|
|
4039
|
+
refreshToken: "refreshToken" in change ? change.refreshToken ?? null : current.refreshToken
|
|
4040
|
+
};
|
|
4041
|
+
if (
|
|
4042
|
+
// Only a state that is genuinely persisted can already say what this
|
|
4043
|
+
// write would say. An absent record reads as an empty pair, and treating
|
|
4044
|
+
// that as a no-op would drop the very tombstone that stops a later
|
|
4045
|
+
// migration from resurrecting the session out of the earlier layout.
|
|
4046
|
+
canonical.stored && next.token === current.token && next.refreshToken === current.refreshToken
|
|
4047
|
+
) {
|
|
4048
|
+
this.sessionRev = current.rev;
|
|
4049
|
+
this.token = current.token;
|
|
4050
|
+
this.refreshTokenValue = current.refreshToken;
|
|
4051
|
+
return true;
|
|
4052
|
+
}
|
|
4053
|
+
try {
|
|
4054
|
+
localStorage.setItem(recordKey, JSON.stringify(next));
|
|
4055
|
+
} catch {
|
|
4056
|
+
this.disablePersistence();
|
|
4057
|
+
return true;
|
|
4058
|
+
}
|
|
4059
|
+
this.sessionRev = next.rev;
|
|
4060
|
+
this.token = next.token;
|
|
4061
|
+
this.refreshTokenValue = next.refreshToken;
|
|
4062
|
+
try {
|
|
4063
|
+
localStorage.removeItem(mirrorRefreshKey);
|
|
4064
|
+
} catch {
|
|
4065
|
+
return true;
|
|
4066
|
+
}
|
|
4067
|
+
try {
|
|
4068
|
+
if (next.token) localStorage.setItem(mirrorKey, next.token);
|
|
4069
|
+
else localStorage.removeItem(mirrorKey);
|
|
4070
|
+
} catch {
|
|
4071
|
+
}
|
|
4072
|
+
return true;
|
|
4073
|
+
}
|
|
4074
|
+
/**
|
|
4075
|
+
* Storage rejected a write or a read, so it is not a canonical store for this
|
|
4076
|
+
* instance. Fall back to the memory-only session and take no lease: there is
|
|
4077
|
+
* no shared state left to coordinate. Nothing is purged — the record commit
|
|
4078
|
+
* is atomic, so no inconsistent state was published, and another context's
|
|
4079
|
+
* valid session must not be destroyed by this instance's local failure.
|
|
4080
|
+
*/
|
|
4081
|
+
disablePersistence() {
|
|
4082
|
+
this.persistRecordKey = null;
|
|
4083
|
+
this.persistMirrorKey = null;
|
|
4084
|
+
this.persistMirrorRefreshKey = null;
|
|
4085
|
+
this.refreshLockName = null;
|
|
4086
|
+
}
|
|
4087
|
+
/**
|
|
4088
|
+
* Compare the canonical record with the fence this call captured before it
|
|
4089
|
+
* left. Every persisted decision — rotate, converge, or fail closed — goes
|
|
4090
|
+
* through this one comparison. The revision catches a logout, a fresh login,
|
|
4091
|
+
* or a manual setter even when token values coincide; the value comparison
|
|
4092
|
+
* additionally catches a mirror-only writer that cannot bump a revision.
|
|
4093
|
+
*/
|
|
4094
|
+
classifyCanonicalState(intended) {
|
|
4095
|
+
if (!this.persistRecordKey) return "current";
|
|
4096
|
+
this.syncFromPersistedStorage();
|
|
4097
|
+
if (!this.persistRecordKey) return "current";
|
|
4098
|
+
if (!this.token && !this.refreshTokenValue) return "cleared";
|
|
4099
|
+
if (intended.refreshToken !== null) {
|
|
4100
|
+
return this.refreshTokenValue === intended.refreshToken ? "current" : "superseded";
|
|
4101
|
+
}
|
|
4102
|
+
return this.token === intended.token && !this.refreshTokenValue ? "current" : "superseded";
|
|
4103
|
+
}
|
|
4104
|
+
/** The canonical persisted pair, as a refresh result. */
|
|
4105
|
+
canonicalPair(token) {
|
|
4106
|
+
return {
|
|
4107
|
+
token,
|
|
4108
|
+
...this.refreshTokenValue ? { refreshToken: this.refreshTokenValue } : {}
|
|
4109
|
+
};
|
|
4110
|
+
}
|
|
4111
|
+
/** Current credentials plus the revision they were observed at. */
|
|
4112
|
+
currentFence() {
|
|
4113
|
+
return { token: this.token, refreshToken: this.refreshTokenValue };
|
|
4114
|
+
}
|
|
4115
|
+
/**
|
|
4116
|
+
* Clear an access credential a 401 just proved unusable — but only while it
|
|
4117
|
+
* is still the canonical one. A rotation committed by another context while
|
|
4118
|
+
* the request was in flight is newer than this 401, so it must survive; the
|
|
4119
|
+
* instance adopts it instead. The refresh entry is never touched here: a
|
|
4120
|
+
* rejected access token says nothing about the refresh family.
|
|
4121
|
+
*/
|
|
4122
|
+
invalidateAccessToken(spentToken) {
|
|
4123
|
+
this.syncFromPersistedStorage();
|
|
4124
|
+
if (this.token !== spentToken) return;
|
|
4125
|
+
this.setToken(null);
|
|
4126
|
+
}
|
|
4127
|
+
/** Commit both credentials in one canonical write. */
|
|
4128
|
+
setSession(token, refreshToken, options) {
|
|
4129
|
+
this.token = token;
|
|
4130
|
+
this.refreshTokenValue = refreshToken;
|
|
4131
|
+
const committed = this.commitPersistedSession(
|
|
4132
|
+
{ token, refreshToken },
|
|
4133
|
+
options
|
|
4134
|
+
);
|
|
4135
|
+
if (!committed) return false;
|
|
4136
|
+
this.onTokenChange?.(this.token);
|
|
4137
|
+
this.onRefreshTokenChange?.(this.refreshTokenValue);
|
|
4138
|
+
return true;
|
|
4139
|
+
}
|
|
4140
|
+
/**
|
|
4141
|
+
* Serialize rotation against every other context sharing the same storage
|
|
4142
|
+
* key and API/tenant identity. Coordination is best-effort: when it is
|
|
4143
|
+
* unavailable or times out the rotation still happens, so server-side reuse
|
|
4144
|
+
* detection is never bypassed by a client that failed to coordinate.
|
|
4145
|
+
*/
|
|
4146
|
+
async rotateAcrossContexts(intended) {
|
|
4147
|
+
const lockName = this.refreshLockName;
|
|
4148
|
+
const requestLock = lockName ? getRefreshLockRequester() : null;
|
|
4149
|
+
if (!lockName || !requestLock) {
|
|
4150
|
+
return this.rotateWithCanonicalState(intended);
|
|
4151
|
+
}
|
|
4152
|
+
const controller = new AbortController();
|
|
4153
|
+
const timer = setTimeout(() => controller.abort(), REFRESH_LOCK_TIMEOUT);
|
|
4154
|
+
let entered = false;
|
|
4155
|
+
try {
|
|
4156
|
+
return await requestLock(
|
|
4157
|
+
lockName,
|
|
4158
|
+
{ signal: controller.signal },
|
|
4159
|
+
async () => {
|
|
4160
|
+
entered = true;
|
|
4161
|
+
return this.rotateWithCanonicalState(intended);
|
|
4162
|
+
}
|
|
4163
|
+
);
|
|
4164
|
+
} catch (error) {
|
|
4165
|
+
if (entered) throw error;
|
|
4166
|
+
return this.rotateWithCanonicalState(intended);
|
|
4167
|
+
} finally {
|
|
4168
|
+
clearTimeout(timer);
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
/**
|
|
4172
|
+
* Decide, against freshly re-read canonical state, whether this context still
|
|
4173
|
+
* owns the rotation.
|
|
4174
|
+
*/
|
|
4175
|
+
async rotateWithCanonicalState(intended) {
|
|
4176
|
+
let fence = intended;
|
|
4177
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
4178
|
+
const state = this.classifyCanonicalState(fence);
|
|
4179
|
+
if (state === "cleared") throw new ApiError("Not authenticated", 401);
|
|
4180
|
+
if (state === "current") return this._doRefreshToken(fence);
|
|
4181
|
+
if (this.token) return this.canonicalPair(this.token);
|
|
4182
|
+
fence = this.currentFence();
|
|
4183
|
+
}
|
|
4184
|
+
throw new ApiError("Not authenticated", 401);
|
|
4185
|
+
}
|
|
4186
|
+
async _doRefreshToken(intended) {
|
|
4187
|
+
const init = intended.refreshToken ? {
|
|
3805
4188
|
method: "POST",
|
|
3806
|
-
body: JSON.stringify({ refreshToken:
|
|
4189
|
+
body: JSON.stringify({ refreshToken: intended.refreshToken })
|
|
3807
4190
|
} : {
|
|
3808
4191
|
method: "POST",
|
|
3809
|
-
headers: { Authorization: `Bearer ${
|
|
4192
|
+
headers: { Authorization: `Bearer ${intended.token}` }
|
|
3810
4193
|
};
|
|
3811
4194
|
const result = await this.requestJson(
|
|
3812
4195
|
"/api/customers/refresh",
|
|
3813
4196
|
init
|
|
3814
4197
|
);
|
|
3815
|
-
this.
|
|
3816
|
-
if (
|
|
3817
|
-
|
|
4198
|
+
const state = this.classifyCanonicalState(intended);
|
|
4199
|
+
if (state === "cleared") throw new ApiError("Not authenticated", 401);
|
|
4200
|
+
if (state === "superseded") {
|
|
4201
|
+
if (this.token) return this.canonicalPair(this.token);
|
|
4202
|
+
throw new ApiError("Not authenticated", 401);
|
|
4203
|
+
}
|
|
4204
|
+
const replacedAccessToken = this.token !== null && this.token !== intended.token ? this.token : null;
|
|
4205
|
+
const nextToken = replacedAccessToken ?? result.token;
|
|
4206
|
+
const nextRefresh = result.refreshToken ?? null;
|
|
4207
|
+
if (!this.setSession(nextToken, nextRefresh, { requireLiveSession: true })) {
|
|
4208
|
+
throw new ApiError("Not authenticated", 401);
|
|
4209
|
+
}
|
|
4210
|
+
return {
|
|
4211
|
+
token: nextToken,
|
|
4212
|
+
...nextRefresh ? { refreshToken: nextRefresh } : {}
|
|
4213
|
+
};
|
|
3818
4214
|
}
|
|
3819
4215
|
/**
|
|
3820
4216
|
* Clear the stored token
|
|
3821
4217
|
*/
|
|
3822
4218
|
logout() {
|
|
3823
|
-
this.
|
|
3824
|
-
this.setRefreshToken(null);
|
|
4219
|
+
this.setSession(null, null);
|
|
3825
4220
|
}
|
|
3826
4221
|
/**
|
|
3827
4222
|
* Get the current authenticated customer's profile
|
|
3828
4223
|
*/
|
|
3829
4224
|
async me() {
|
|
3830
|
-
|
|
4225
|
+
const token = this.getToken();
|
|
4226
|
+
if (!token) return null;
|
|
3831
4227
|
try {
|
|
3832
4228
|
const data = await this.requestJson(
|
|
3833
4229
|
"/api/customers/me",
|
|
3834
4230
|
{
|
|
3835
4231
|
method: "GET",
|
|
3836
|
-
headers: { Authorization: `Bearer ${
|
|
4232
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
3837
4233
|
}
|
|
3838
4234
|
);
|
|
3839
4235
|
return data.customer ?? null;
|
|
3840
4236
|
} catch (error) {
|
|
3841
4237
|
if (error instanceof SDKError && error.status === 401) {
|
|
3842
|
-
this.
|
|
4238
|
+
this.invalidateAccessToken(token);
|
|
3843
4239
|
return null;
|
|
3844
4240
|
}
|
|
3845
4241
|
throw error;
|
|
@@ -3867,12 +4263,13 @@ var CustomerAuth = class {
|
|
|
3867
4263
|
* Update the authenticated customer's profile (name, phone, marketingConsent)
|
|
3868
4264
|
*/
|
|
3869
4265
|
async updateProfile(data) {
|
|
3870
|
-
|
|
4266
|
+
const token = this.getToken();
|
|
4267
|
+
if (!token) throw new ApiError("Not authenticated", 401);
|
|
3871
4268
|
const result = await this.requestJson(
|
|
3872
4269
|
"/api/customers/me",
|
|
3873
4270
|
{
|
|
3874
4271
|
method: "PATCH",
|
|
3875
|
-
headers: { Authorization: `Bearer ${
|
|
4272
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
3876
4273
|
body: JSON.stringify(data)
|
|
3877
4274
|
}
|
|
3878
4275
|
);
|
|
@@ -3882,10 +4279,11 @@ var CustomerAuth = class {
|
|
|
3882
4279
|
* Change the password of the currently authenticated customer
|
|
3883
4280
|
*/
|
|
3884
4281
|
async changePassword(currentPassword, newPassword) {
|
|
3885
|
-
|
|
4282
|
+
const token = this.getToken();
|
|
4283
|
+
if (!token) throw new ApiError("Not authenticated", 401);
|
|
3886
4284
|
await this.requestJson("/api/customers/change-password", {
|
|
3887
4285
|
method: "POST",
|
|
3888
|
-
headers: { Authorization: `Bearer ${
|
|
4286
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
3889
4287
|
body: JSON.stringify({ currentPassword, newPassword })
|
|
3890
4288
|
});
|
|
3891
4289
|
}
|
|
@@ -3893,7 +4291,8 @@ var CustomerAuth = class {
|
|
|
3893
4291
|
* Get the authenticated customer's orders with pagination and optional status filter
|
|
3894
4292
|
*/
|
|
3895
4293
|
async getMyOrders(options) {
|
|
3896
|
-
|
|
4294
|
+
const token = this.getToken();
|
|
4295
|
+
if (!token) throw new ApiError("Not authenticated", 401);
|
|
3897
4296
|
const params = new URLSearchParams();
|
|
3898
4297
|
if (options?.page) params.set("page", String(options.page));
|
|
3899
4298
|
if (options?.limit) params.set("limit", String(options.limit));
|
|
@@ -3915,21 +4314,27 @@ var CustomerAuth = class {
|
|
|
3915
4314
|
`/api/customers/me/orders${qs ? `?${qs}` : ""}`,
|
|
3916
4315
|
{
|
|
3917
4316
|
method: "GET",
|
|
3918
|
-
headers: { Authorization: `Bearer ${
|
|
4317
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
3919
4318
|
}
|
|
3920
4319
|
);
|
|
3921
4320
|
return validatePublicOrderList(result);
|
|
3922
4321
|
}
|
|
3923
4322
|
/**
|
|
3924
|
-
* Get the current token (or null if not authenticated)
|
|
4323
|
+
* Get the current token (or null if not authenticated).
|
|
4324
|
+
*
|
|
4325
|
+
* In persisted mode this re-reads shared storage first, so a rotation or
|
|
4326
|
+
* logout performed by another tab is observed before the token is used.
|
|
3925
4327
|
*/
|
|
3926
4328
|
getToken() {
|
|
4329
|
+
this.syncFromPersistedStorage();
|
|
3927
4330
|
return this.token;
|
|
3928
4331
|
}
|
|
3929
4332
|
/**
|
|
3930
|
-
* Get the current refresh token (or null if unavailable)
|
|
4333
|
+
* Get the current refresh token (or null if unavailable). Persisted mode
|
|
4334
|
+
* re-reads shared storage first, like {@link CustomerAuth.getToken}.
|
|
3931
4335
|
*/
|
|
3932
4336
|
getRefreshToken() {
|
|
4337
|
+
this.syncFromPersistedStorage();
|
|
3933
4338
|
return this.refreshTokenValue;
|
|
3934
4339
|
}
|
|
3935
4340
|
/**
|
|
@@ -3937,6 +4342,7 @@ var CustomerAuth = class {
|
|
|
3937
4342
|
*/
|
|
3938
4343
|
setToken(token) {
|
|
3939
4344
|
this.token = token;
|
|
4345
|
+
this.commitPersistedSession({ token });
|
|
3940
4346
|
this.onTokenChange?.(token);
|
|
3941
4347
|
}
|
|
3942
4348
|
/**
|
|
@@ -3944,13 +4350,14 @@ var CustomerAuth = class {
|
|
|
3944
4350
|
*/
|
|
3945
4351
|
setRefreshToken(refreshToken) {
|
|
3946
4352
|
this.refreshTokenValue = refreshToken;
|
|
4353
|
+
this.commitPersistedSession({ refreshToken });
|
|
3947
4354
|
this.onRefreshTokenChange?.(refreshToken);
|
|
3948
4355
|
}
|
|
3949
4356
|
/**
|
|
3950
4357
|
* Check if the customer is currently authenticated
|
|
3951
4358
|
*/
|
|
3952
4359
|
isAuthenticated() {
|
|
3953
|
-
return this.
|
|
4360
|
+
return this.getToken() !== null;
|
|
3954
4361
|
}
|
|
3955
4362
|
/**
|
|
3956
4363
|
* Internal: make a request with timeout and error handling.
|
|
@@ -4154,8 +4561,8 @@ var CartApi = class extends CustomerScopedApi {
|
|
|
4154
4561
|
endpoint(key) {
|
|
4155
4562
|
return this.serverTransport ? COMMERCE_ENDPOINTS.carts.server[key] : COMMERCE_ENDPOINTS.carts[key];
|
|
4156
4563
|
}
|
|
4157
|
-
execute(
|
|
4158
|
-
return this.requestEndpoint(
|
|
4564
|
+
execute(endpoint, body, idempotencyKey) {
|
|
4565
|
+
return this.requestEndpoint(endpoint, body, {
|
|
4159
4566
|
...idempotencyKey && {
|
|
4160
4567
|
headers: { "X-Idempotency-Key": idempotencyKey }
|
|
4161
4568
|
}
|
|
@@ -4172,26 +4579,26 @@ var CartApi = class extends CustomerScopedApi {
|
|
|
4172
4579
|
);
|
|
4173
4580
|
}
|
|
4174
4581
|
mine(params = {}) {
|
|
4175
|
-
const
|
|
4176
|
-
return this.execute(
|
|
4582
|
+
const endpoint = this.endpoint("mine");
|
|
4583
|
+
return this.execute(endpoint, params).then(
|
|
4177
4584
|
(value) => validateCartMineResult(value)
|
|
4178
4585
|
);
|
|
4179
4586
|
}
|
|
4180
4587
|
merge(params) {
|
|
4181
4588
|
const { idempotencyKey, ...body } = params;
|
|
4182
4589
|
assertCommerceIdempotencyKey(idempotencyKey);
|
|
4183
|
-
const
|
|
4184
|
-
return this.execute(
|
|
4590
|
+
const endpoint = this.endpoint("merge");
|
|
4591
|
+
return this.execute(endpoint, body, idempotencyKey).then(
|
|
4185
4592
|
(value) => validateCartMergeResult(value)
|
|
4186
4593
|
);
|
|
4187
4594
|
}
|
|
4188
4595
|
addItem(params) {
|
|
4189
4596
|
return this.mutate(this.endpoint("addItem"), params);
|
|
4190
4597
|
}
|
|
4191
|
-
mutate(
|
|
4598
|
+
mutate(endpoint, params) {
|
|
4192
4599
|
const { idempotencyKey, ...body } = params;
|
|
4193
4600
|
assertCommerceIdempotencyKey(idempotencyKey);
|
|
4194
|
-
return this.execute(
|
|
4601
|
+
return this.execute(endpoint, body, idempotencyKey).then(
|
|
4195
4602
|
(value) => validateCartMutationResult(value)
|
|
4196
4603
|
);
|
|
4197
4604
|
}
|
|
@@ -4217,8 +4624,8 @@ var CheckoutApi = class extends CustomerScopedApi {
|
|
|
4217
4624
|
constructor(options) {
|
|
4218
4625
|
super("CheckoutApi", { ...options, requiresCredential: false });
|
|
4219
4626
|
}
|
|
4220
|
-
post(
|
|
4221
|
-
return this.requestEndpoint(
|
|
4627
|
+
post(endpoint, body, idempotencyKey) {
|
|
4628
|
+
return this.requestEndpoint(endpoint, body, {
|
|
4222
4629
|
...idempotencyKey && {
|
|
4223
4630
|
headers: { "X-Idempotency-Key": idempotencyKey }
|
|
4224
4631
|
}
|
|
@@ -4285,15 +4692,23 @@ var PaymentSessionApi = class extends CustomerScopedApi {
|
|
|
4285
4692
|
super("PaymentSessionApi", { ...options, requiresCredential: false });
|
|
4286
4693
|
this.serverTransport = Boolean(options.secretKey);
|
|
4287
4694
|
}
|
|
4288
|
-
post(
|
|
4289
|
-
|
|
4290
|
-
...idempotencyKey && {
|
|
4291
|
-
|
|
4695
|
+
post(endpoint, body, idempotencyKey, negotiateStandardActionCapabilities = false) {
|
|
4696
|
+
const headers = {
|
|
4697
|
+
...idempotencyKey && { "X-Idempotency-Key": idempotencyKey },
|
|
4698
|
+
...negotiateStandardActionCapabilities && {
|
|
4699
|
+
Accept: PORTONE_STANDARD_ACTION_CAPABILITIES_MEDIA_TYPE
|
|
4292
4700
|
}
|
|
4701
|
+
};
|
|
4702
|
+
return this.requestEndpoint(endpoint, body, {
|
|
4703
|
+
...Object.keys(headers).length > 0 && { headers }
|
|
4293
4704
|
});
|
|
4294
4705
|
}
|
|
4295
|
-
async paymentSession(result, expectedProvider) {
|
|
4296
|
-
return validatePublicPaymentSession(
|
|
4706
|
+
async paymentSession(result, expectedProvider, operation2) {
|
|
4707
|
+
return validatePublicPaymentSession(
|
|
4708
|
+
await result,
|
|
4709
|
+
expectedProvider,
|
|
4710
|
+
operation2
|
|
4711
|
+
);
|
|
4297
4712
|
}
|
|
4298
4713
|
create(params) {
|
|
4299
4714
|
const { idempotencyKey, ...body } = params;
|
|
@@ -4314,41 +4729,44 @@ var PaymentSessionApi = class extends CustomerScopedApi {
|
|
|
4314
4729
|
this.post(
|
|
4315
4730
|
this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.create : COMMERCE_ENDPOINTS.paymentSessions.create,
|
|
4316
4731
|
body,
|
|
4317
|
-
idempotencyKey
|
|
4732
|
+
idempotencyKey,
|
|
4733
|
+
body.providerOptions.profile === "standard_v2"
|
|
4318
4734
|
),
|
|
4319
4735
|
"portone"
|
|
4320
4736
|
);
|
|
4321
4737
|
}
|
|
4322
4738
|
retrieve(params) {
|
|
4323
|
-
const
|
|
4739
|
+
const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
|
|
4324
4740
|
return this.paymentSession(
|
|
4325
|
-
this.post(
|
|
4741
|
+
this.post(endpoint, params),
|
|
4326
4742
|
"toss"
|
|
4327
4743
|
);
|
|
4328
4744
|
}
|
|
4329
4745
|
retrievePortOne(params) {
|
|
4330
|
-
const
|
|
4746
|
+
const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
|
|
4331
4747
|
return this.paymentSession(
|
|
4332
|
-
this.post(
|
|
4748
|
+
this.post(endpoint, params, void 0, true),
|
|
4333
4749
|
"portone"
|
|
4334
4750
|
);
|
|
4335
4751
|
}
|
|
4336
4752
|
cancel(params) {
|
|
4337
4753
|
const { idempotencyKey, ...body } = params;
|
|
4338
4754
|
assertCommerceIdempotencyKey(idempotencyKey);
|
|
4339
|
-
const
|
|
4755
|
+
const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
|
|
4340
4756
|
return this.paymentSession(
|
|
4341
|
-
this.post(
|
|
4342
|
-
"toss"
|
|
4757
|
+
this.post(endpoint, body, idempotencyKey),
|
|
4758
|
+
"toss",
|
|
4759
|
+
"cancel"
|
|
4343
4760
|
);
|
|
4344
4761
|
}
|
|
4345
4762
|
cancelPortOne(params) {
|
|
4346
4763
|
const { idempotencyKey, ...body } = params;
|
|
4347
4764
|
assertCommerceIdempotencyKey(idempotencyKey);
|
|
4348
|
-
const
|
|
4765
|
+
const endpoint = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
|
|
4349
4766
|
return this.paymentSession(
|
|
4350
|
-
this.post(
|
|
4351
|
-
"portone"
|
|
4767
|
+
this.post(endpoint, body, idempotencyKey),
|
|
4768
|
+
"portone",
|
|
4769
|
+
"cancel"
|
|
4352
4770
|
);
|
|
4353
4771
|
}
|
|
4354
4772
|
confirm(params) {
|
|
@@ -5488,8 +5906,8 @@ function withProductListingCards(response, options) {
|
|
|
5488
5906
|
|
|
5489
5907
|
// src/core/commerce/commerce-client.ts
|
|
5490
5908
|
var BrowserCommerceApi = class extends CustomerScopedApi {
|
|
5491
|
-
requestEndpoint(
|
|
5492
|
-
return super.requestEndpoint(
|
|
5909
|
+
requestEndpoint(endpoint, body, options) {
|
|
5910
|
+
return super.requestEndpoint(endpoint, body, options);
|
|
5493
5911
|
}
|
|
5494
5912
|
};
|
|
5495
5913
|
var CommerceClient = class {
|
|
@@ -5689,11 +6107,11 @@ var EventsClient = class {
|
|
|
5689
6107
|
{ useCustomerAuth: false }
|
|
5690
6108
|
);
|
|
5691
6109
|
}
|
|
5692
|
-
async execute(
|
|
6110
|
+
async execute(endpoint, method, body, options = {}) {
|
|
5693
6111
|
const useCustomerAuth = options.useCustomerAuth === true;
|
|
5694
6112
|
const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
|
|
5695
6113
|
try {
|
|
5696
|
-
const response = await httpFetch(
|
|
6114
|
+
const response = await httpFetch(endpoint, {
|
|
5697
6115
|
method,
|
|
5698
6116
|
apiUrl: this.apiUrl,
|
|
5699
6117
|
publishableKey: this.publishableKey,
|
|
@@ -5702,7 +6120,7 @@ var EventsClient = class {
|
|
|
5702
6120
|
...body !== void 0 && { body: JSON.stringify(body) }
|
|
5703
6121
|
});
|
|
5704
6122
|
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
5705
|
-
return parseApiResponse(response,
|
|
6123
|
+
return parseApiResponse(response, endpoint);
|
|
5706
6124
|
} catch (err) {
|
|
5707
6125
|
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
5708
6126
|
this.onRequestId?.(id);
|