@blotoutio/providers-blotout-wallet-sdk 0.63.1 → 0.65.0
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/index.cjs.js +43 -18
- package/index.js +43 -18
- package/index.mjs +43 -18
- package/package.json +1 -1
- package/stores/shopify/index.cjs.js +72 -15
- package/stores/shopify/index.js +72 -15
- package/stores/shopify/index.mjs +72 -15
package/index.cjs.js
CHANGED
@@ -546,26 +546,29 @@ let BlotoutWallet = class BlotoutWallet extends s {
|
|
546
546
|
this.dispatchEvent(new CustomEvent('blotout-wallet-email-saved', { bubbles: true }));
|
547
547
|
window.edgetag('tag', 'CartRecovery_KeepCartEmailSaved', {}, {}, { destination: this.edgeURL });
|
548
548
|
}
|
549
|
-
await this.storeApi.addItems(this.lastExpiredCart.items);
|
549
|
+
this.restoreResponse = await this.storeApi.addItems(this.lastExpiredCart.items);
|
550
550
|
const expiredCartId = this.lastExpiredCart.cartId;
|
551
551
|
// We attempt to mark the cart as restored, but if the request fails,
|
552
552
|
// we log the error in the console and let the user continue. Since the
|
553
553
|
// problem is probably in the `/cart/restore` endpoint, further attempts
|
554
554
|
// would not resolve the problem, which would just increase the number
|
555
555
|
// of failed calls and not solve the problem.
|
556
|
-
|
556
|
+
await fetch(this.getUrl(`/cart/restore/${expiredCartId}`), {
|
557
557
|
method: 'POST',
|
558
558
|
headers: this.getHeaders(),
|
559
|
-
})
|
560
|
-
|
561
|
-
|
562
|
-
|
559
|
+
})
|
560
|
+
.then(async (response) => {
|
561
|
+
if (!response.ok) {
|
562
|
+
throw new Error(`Could not update status in DB - ${response.status}: ${response.text}\n\n${await response.text()}`);
|
563
|
+
}
|
564
|
+
})
|
565
|
+
.catch(logger.error);
|
563
566
|
this.lastExpiredCart = undefined;
|
564
|
-
this.dispatchEvent(new CustomEvent('blotout-wallet-restored', {
|
567
|
+
this.dispatchEvent(new CustomEvent('blotout-wallet-cart-restored', {
|
565
568
|
bubbles: true,
|
566
569
|
}));
|
567
570
|
// Send the request as beacon as there could be a immediate redirect in the next step
|
568
|
-
window.edgetag('tag', 'CartRecovery_CartRestored', { isSilent: !!this.silentRestore }, {}, { method: 'beacon' });
|
571
|
+
window.edgetag('tag', 'CartRecovery_CartRestored', { isSilent: !!this.silentRestore }, {}, { method: 'beacon', destination: this.edgeURL });
|
569
572
|
};
|
570
573
|
this.onSubmit = async (ev) => {
|
571
574
|
ev.preventDefault();
|
@@ -578,14 +581,28 @@ let BlotoutWallet = class BlotoutWallet extends s {
|
|
578
581
|
if (this.state == 'restored') {
|
579
582
|
this.hideModal('restore');
|
580
583
|
}
|
581
|
-
//
|
582
|
-
if (this.
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
584
|
+
// handle afterRestore action
|
585
|
+
if (this.afterRestore) {
|
586
|
+
switch (this.afterRestore.action) {
|
587
|
+
case 'refresh': {
|
588
|
+
window.location.reload();
|
589
|
+
break;
|
590
|
+
}
|
591
|
+
case 'redirect': {
|
592
|
+
try {
|
593
|
+
window.location.href = new URL(this.afterRestore.url, window.location.href).toString();
|
594
|
+
}
|
595
|
+
catch (e) {
|
596
|
+
console.error('Invalid redirect URL', e);
|
597
|
+
}
|
598
|
+
break;
|
599
|
+
}
|
600
|
+
case 'checkout': {
|
601
|
+
const url = this.storeApi.getCheckoutURL();
|
602
|
+
if (url) {
|
603
|
+
window.location.href = url.toString();
|
604
|
+
}
|
605
|
+
}
|
589
606
|
}
|
590
607
|
}
|
591
608
|
}
|
@@ -654,6 +671,9 @@ let BlotoutWallet = class BlotoutWallet extends s {
|
|
654
671
|
return x `
|
655
672
|
${cartTick({ class: 'icon' })}
|
656
673
|
<div>Cart restored successfully!</div>
|
674
|
+
${this.restoreResponse
|
675
|
+
? x `<p>Some items could not be added: ${this.restoreResponse}</p>`
|
676
|
+
: T}
|
657
677
|
`;
|
658
678
|
};
|
659
679
|
this.failedContent = () => {
|
@@ -767,6 +787,7 @@ let BlotoutWallet = class BlotoutWallet extends s {
|
|
767
787
|
.catch(logger.error)
|
768
788
|
.finally(() => { var _a; return (_a = this.dialog) === null || _a === void 0 ? void 0 : _a.close(action); });
|
769
789
|
this.dispatchEvent(new CustomEvent('blotout-wallet-hidden', { bubbles: true }));
|
790
|
+
this.restoreResponse = undefined;
|
770
791
|
}
|
771
792
|
getHeaders(json = false) {
|
772
793
|
const headers = new Headers({
|
@@ -980,6 +1001,10 @@ __decorate([
|
|
980
1001
|
r(),
|
981
1002
|
__metadata("design:type", String)
|
982
1003
|
], BlotoutWallet.prototype, "state", void 0);
|
1004
|
+
__decorate([
|
1005
|
+
r(),
|
1006
|
+
__metadata("design:type", Object)
|
1007
|
+
], BlotoutWallet.prototype, "restoreResponse", void 0);
|
983
1008
|
BlotoutWallet = __decorate([
|
984
1009
|
t$1('blotout-wallet')
|
985
1010
|
], BlotoutWallet);
|
@@ -1044,8 +1069,8 @@ const init = (params) => {
|
|
1044
1069
|
element.theme = theme;
|
1045
1070
|
element.edgeURL = params.baseUrl;
|
1046
1071
|
element.userId = params.userId;
|
1047
|
-
element.
|
1048
|
-
element.silentRestore = (
|
1072
|
+
element.afterRestore = (_e = params.manifest.variables) === null || _e === void 0 ? void 0 : _e.afterRestore;
|
1073
|
+
element.silentRestore = (_f = params.manifest.variables) === null || _f === void 0 ? void 0 : _f.silentRestore;
|
1049
1074
|
document.body.append(element);
|
1050
1075
|
}
|
1051
1076
|
};
|
package/index.js
CHANGED
@@ -547,26 +547,29 @@ var ProvidersBlotoutWalletSdk = (function () {
|
|
547
547
|
this.dispatchEvent(new CustomEvent('blotout-wallet-email-saved', { bubbles: true }));
|
548
548
|
window.edgetag('tag', 'CartRecovery_KeepCartEmailSaved', {}, {}, { destination: this.edgeURL });
|
549
549
|
}
|
550
|
-
await this.storeApi.addItems(this.lastExpiredCart.items);
|
550
|
+
this.restoreResponse = await this.storeApi.addItems(this.lastExpiredCart.items);
|
551
551
|
const expiredCartId = this.lastExpiredCart.cartId;
|
552
552
|
// We attempt to mark the cart as restored, but if the request fails,
|
553
553
|
// we log the error in the console and let the user continue. Since the
|
554
554
|
// problem is probably in the `/cart/restore` endpoint, further attempts
|
555
555
|
// would not resolve the problem, which would just increase the number
|
556
556
|
// of failed calls and not solve the problem.
|
557
|
-
|
557
|
+
await fetch(this.getUrl(`/cart/restore/${expiredCartId}`), {
|
558
558
|
method: 'POST',
|
559
559
|
headers: this.getHeaders(),
|
560
|
-
})
|
561
|
-
|
562
|
-
|
563
|
-
|
560
|
+
})
|
561
|
+
.then(async (response) => {
|
562
|
+
if (!response.ok) {
|
563
|
+
throw new Error(`Could not update status in DB - ${response.status}: ${response.text}\n\n${await response.text()}`);
|
564
|
+
}
|
565
|
+
})
|
566
|
+
.catch(logger.error);
|
564
567
|
this.lastExpiredCart = undefined;
|
565
|
-
this.dispatchEvent(new CustomEvent('blotout-wallet-restored', {
|
568
|
+
this.dispatchEvent(new CustomEvent('blotout-wallet-cart-restored', {
|
566
569
|
bubbles: true,
|
567
570
|
}));
|
568
571
|
// Send the request as beacon as there could be a immediate redirect in the next step
|
569
|
-
window.edgetag('tag', 'CartRecovery_CartRestored', { isSilent: !!this.silentRestore }, {}, { method: 'beacon' });
|
572
|
+
window.edgetag('tag', 'CartRecovery_CartRestored', { isSilent: !!this.silentRestore }, {}, { method: 'beacon', destination: this.edgeURL });
|
570
573
|
};
|
571
574
|
this.onSubmit = async (ev) => {
|
572
575
|
ev.preventDefault();
|
@@ -579,14 +582,28 @@ var ProvidersBlotoutWalletSdk = (function () {
|
|
579
582
|
if (this.state == 'restored') {
|
580
583
|
this.hideModal('restore');
|
581
584
|
}
|
582
|
-
//
|
583
|
-
if (this.
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
585
|
+
// handle afterRestore action
|
586
|
+
if (this.afterRestore) {
|
587
|
+
switch (this.afterRestore.action) {
|
588
|
+
case 'refresh': {
|
589
|
+
window.location.reload();
|
590
|
+
break;
|
591
|
+
}
|
592
|
+
case 'redirect': {
|
593
|
+
try {
|
594
|
+
window.location.href = new URL(this.afterRestore.url, window.location.href).toString();
|
595
|
+
}
|
596
|
+
catch (e) {
|
597
|
+
console.error('Invalid redirect URL', e);
|
598
|
+
}
|
599
|
+
break;
|
600
|
+
}
|
601
|
+
case 'checkout': {
|
602
|
+
const url = this.storeApi.getCheckoutURL();
|
603
|
+
if (url) {
|
604
|
+
window.location.href = url.toString();
|
605
|
+
}
|
606
|
+
}
|
590
607
|
}
|
591
608
|
}
|
592
609
|
}
|
@@ -655,6 +672,9 @@ var ProvidersBlotoutWalletSdk = (function () {
|
|
655
672
|
return x `
|
656
673
|
${cartTick({ class: 'icon' })}
|
657
674
|
<div>Cart restored successfully!</div>
|
675
|
+
${this.restoreResponse
|
676
|
+
? x `<p>Some items could not be added: ${this.restoreResponse}</p>`
|
677
|
+
: T}
|
658
678
|
`;
|
659
679
|
};
|
660
680
|
this.failedContent = () => {
|
@@ -768,6 +788,7 @@ var ProvidersBlotoutWalletSdk = (function () {
|
|
768
788
|
.catch(logger.error)
|
769
789
|
.finally(() => { var _a; return (_a = this.dialog) === null || _a === void 0 ? void 0 : _a.close(action); });
|
770
790
|
this.dispatchEvent(new CustomEvent('blotout-wallet-hidden', { bubbles: true }));
|
791
|
+
this.restoreResponse = undefined;
|
771
792
|
}
|
772
793
|
getHeaders(json = false) {
|
773
794
|
const headers = new Headers({
|
@@ -981,6 +1002,10 @@ var ProvidersBlotoutWalletSdk = (function () {
|
|
981
1002
|
r(),
|
982
1003
|
__metadata("design:type", String)
|
983
1004
|
], BlotoutWallet.prototype, "state", void 0);
|
1005
|
+
__decorate([
|
1006
|
+
r(),
|
1007
|
+
__metadata("design:type", Object)
|
1008
|
+
], BlotoutWallet.prototype, "restoreResponse", void 0);
|
984
1009
|
BlotoutWallet = __decorate([
|
985
1010
|
t$1('blotout-wallet')
|
986
1011
|
], BlotoutWallet);
|
@@ -1045,8 +1070,8 @@ var ProvidersBlotoutWalletSdk = (function () {
|
|
1045
1070
|
element.theme = theme;
|
1046
1071
|
element.edgeURL = params.baseUrl;
|
1047
1072
|
element.userId = params.userId;
|
1048
|
-
element.
|
1049
|
-
element.silentRestore = (
|
1073
|
+
element.afterRestore = (_e = params.manifest.variables) === null || _e === void 0 ? void 0 : _e.afterRestore;
|
1074
|
+
element.silentRestore = (_f = params.manifest.variables) === null || _f === void 0 ? void 0 : _f.silentRestore;
|
1050
1075
|
document.body.append(element);
|
1051
1076
|
}
|
1052
1077
|
};
|
package/index.mjs
CHANGED
@@ -544,26 +544,29 @@ let BlotoutWallet = class BlotoutWallet extends s {
|
|
544
544
|
this.dispatchEvent(new CustomEvent('blotout-wallet-email-saved', { bubbles: true }));
|
545
545
|
window.edgetag('tag', 'CartRecovery_KeepCartEmailSaved', {}, {}, { destination: this.edgeURL });
|
546
546
|
}
|
547
|
-
await this.storeApi.addItems(this.lastExpiredCart.items);
|
547
|
+
this.restoreResponse = await this.storeApi.addItems(this.lastExpiredCart.items);
|
548
548
|
const expiredCartId = this.lastExpiredCart.cartId;
|
549
549
|
// We attempt to mark the cart as restored, but if the request fails,
|
550
550
|
// we log the error in the console and let the user continue. Since the
|
551
551
|
// problem is probably in the `/cart/restore` endpoint, further attempts
|
552
552
|
// would not resolve the problem, which would just increase the number
|
553
553
|
// of failed calls and not solve the problem.
|
554
|
-
|
554
|
+
await fetch(this.getUrl(`/cart/restore/${expiredCartId}`), {
|
555
555
|
method: 'POST',
|
556
556
|
headers: this.getHeaders(),
|
557
|
-
})
|
558
|
-
|
559
|
-
|
560
|
-
|
557
|
+
})
|
558
|
+
.then(async (response) => {
|
559
|
+
if (!response.ok) {
|
560
|
+
throw new Error(`Could not update status in DB - ${response.status}: ${response.text}\n\n${await response.text()}`);
|
561
|
+
}
|
562
|
+
})
|
563
|
+
.catch(logger.error);
|
561
564
|
this.lastExpiredCart = undefined;
|
562
|
-
this.dispatchEvent(new CustomEvent('blotout-wallet-restored', {
|
565
|
+
this.dispatchEvent(new CustomEvent('blotout-wallet-cart-restored', {
|
563
566
|
bubbles: true,
|
564
567
|
}));
|
565
568
|
// Send the request as beacon as there could be a immediate redirect in the next step
|
566
|
-
window.edgetag('tag', 'CartRecovery_CartRestored', { isSilent: !!this.silentRestore }, {}, { method: 'beacon' });
|
569
|
+
window.edgetag('tag', 'CartRecovery_CartRestored', { isSilent: !!this.silentRestore }, {}, { method: 'beacon', destination: this.edgeURL });
|
567
570
|
};
|
568
571
|
this.onSubmit = async (ev) => {
|
569
572
|
ev.preventDefault();
|
@@ -576,14 +579,28 @@ let BlotoutWallet = class BlotoutWallet extends s {
|
|
576
579
|
if (this.state == 'restored') {
|
577
580
|
this.hideModal('restore');
|
578
581
|
}
|
579
|
-
//
|
580
|
-
if (this.
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
582
|
+
// handle afterRestore action
|
583
|
+
if (this.afterRestore) {
|
584
|
+
switch (this.afterRestore.action) {
|
585
|
+
case 'refresh': {
|
586
|
+
window.location.reload();
|
587
|
+
break;
|
588
|
+
}
|
589
|
+
case 'redirect': {
|
590
|
+
try {
|
591
|
+
window.location.href = new URL(this.afterRestore.url, window.location.href).toString();
|
592
|
+
}
|
593
|
+
catch (e) {
|
594
|
+
console.error('Invalid redirect URL', e);
|
595
|
+
}
|
596
|
+
break;
|
597
|
+
}
|
598
|
+
case 'checkout': {
|
599
|
+
const url = this.storeApi.getCheckoutURL();
|
600
|
+
if (url) {
|
601
|
+
window.location.href = url.toString();
|
602
|
+
}
|
603
|
+
}
|
587
604
|
}
|
588
605
|
}
|
589
606
|
}
|
@@ -652,6 +669,9 @@ let BlotoutWallet = class BlotoutWallet extends s {
|
|
652
669
|
return x `
|
653
670
|
${cartTick({ class: 'icon' })}
|
654
671
|
<div>Cart restored successfully!</div>
|
672
|
+
${this.restoreResponse
|
673
|
+
? x `<p>Some items could not be added: ${this.restoreResponse}</p>`
|
674
|
+
: T}
|
655
675
|
`;
|
656
676
|
};
|
657
677
|
this.failedContent = () => {
|
@@ -765,6 +785,7 @@ let BlotoutWallet = class BlotoutWallet extends s {
|
|
765
785
|
.catch(logger.error)
|
766
786
|
.finally(() => { var _a; return (_a = this.dialog) === null || _a === void 0 ? void 0 : _a.close(action); });
|
767
787
|
this.dispatchEvent(new CustomEvent('blotout-wallet-hidden', { bubbles: true }));
|
788
|
+
this.restoreResponse = undefined;
|
768
789
|
}
|
769
790
|
getHeaders(json = false) {
|
770
791
|
const headers = new Headers({
|
@@ -978,6 +999,10 @@ __decorate([
|
|
978
999
|
r(),
|
979
1000
|
__metadata("design:type", String)
|
980
1001
|
], BlotoutWallet.prototype, "state", void 0);
|
1002
|
+
__decorate([
|
1003
|
+
r(),
|
1004
|
+
__metadata("design:type", Object)
|
1005
|
+
], BlotoutWallet.prototype, "restoreResponse", void 0);
|
981
1006
|
BlotoutWallet = __decorate([
|
982
1007
|
t$1('blotout-wallet')
|
983
1008
|
], BlotoutWallet);
|
@@ -1042,8 +1067,8 @@ const init = (params) => {
|
|
1042
1067
|
element.theme = theme;
|
1043
1068
|
element.edgeURL = params.baseUrl;
|
1044
1069
|
element.userId = params.userId;
|
1045
|
-
element.
|
1046
|
-
element.silentRestore = (
|
1070
|
+
element.afterRestore = (_e = params.manifest.variables) === null || _e === void 0 ? void 0 : _e.afterRestore;
|
1071
|
+
element.silentRestore = (_f = params.manifest.variables) === null || _f === void 0 ? void 0 : _f.silentRestore;
|
1047
1072
|
document.body.append(element);
|
1048
1073
|
}
|
1049
1074
|
};
|
package/package.json
CHANGED
@@ -34,6 +34,8 @@ new Set([
|
|
34
34
|
...expand('911,921,922,923,924,926,927,932,933,935,942,944,946,950,953,955,957-958,960-969,974,975,976,977,981-982,987,988,990-999'),
|
35
35
|
]);
|
36
36
|
|
37
|
+
const delay = (n, resolvedValue) => new Promise((resolve) => setTimeout(() => resolve(resolvedValue), n));
|
38
|
+
|
37
39
|
const cartTokenCookie = 'cart';
|
38
40
|
const cartTokenTwoCookie = 'cart2';
|
39
41
|
|
@@ -78,22 +80,72 @@ const parseCookies = (cookie) => {
|
|
78
80
|
};
|
79
81
|
|
80
82
|
// eslint-disable-next-line @nx/enforce-module-boundaries
|
83
|
+
const MAX_RETRY_COUNT = 3;
|
84
|
+
const RETRY_DELAY = 500;
|
85
|
+
const ERROR_PATTERNS = {
|
86
|
+
cannotAddMore: /^You can't add more (.*?) to the cart\.$/,
|
87
|
+
soldOut: /^The product '?(.*?)'? is already sold out\.$/,
|
88
|
+
};
|
89
|
+
const getItemNameFromDescription = (description) => {
|
90
|
+
let matches = description.match(ERROR_PATTERNS.cannotAddMore);
|
91
|
+
if (matches === null || matches === void 0 ? void 0 : matches.length)
|
92
|
+
return matches[1];
|
93
|
+
matches = description.match(ERROR_PATTERNS.soldOut);
|
94
|
+
if (matches === null || matches === void 0 ? void 0 : matches.length)
|
95
|
+
return matches[1];
|
96
|
+
return null;
|
97
|
+
};
|
98
|
+
const addItemsToCart = (fetchOverride, itemsToAdd) => fetchOverride(`${window.Shopify.routes.root}cart/add.js`, {
|
99
|
+
method: 'POST',
|
100
|
+
body: JSON.stringify({
|
101
|
+
items: itemsToAdd.map((item) => ({
|
102
|
+
id: item.variantId || item.productId,
|
103
|
+
quantity: item.quantity,
|
104
|
+
})),
|
105
|
+
}),
|
106
|
+
headers: { 'Content-type': 'application/json' },
|
107
|
+
});
|
81
108
|
const createShopApi = (fetchOverride = window.fetch) => ({
|
82
|
-
addItems(items) {
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
}),
|
91
|
-
headers: { 'Content-type': 'application/json' },
|
92
|
-
}).then(async (response) => {
|
93
|
-
if (!response.ok) {
|
94
|
-
throw new Error('Could not add items', { cause: await response.text() });
|
109
|
+
async addItems(items) {
|
110
|
+
var _a;
|
111
|
+
let filteredItems = items;
|
112
|
+
const unavailableItems = [];
|
113
|
+
for (let retries = 0; retries < MAX_RETRY_COUNT; retries++) {
|
114
|
+
const response = await addItemsToCart(fetchOverride, filteredItems);
|
115
|
+
if (response.ok) {
|
116
|
+
break;
|
95
117
|
}
|
96
|
-
|
118
|
+
if (response.status == 422) {
|
119
|
+
const data = (await response.json());
|
120
|
+
const rejectedItemName = (_a = getItemNameFromDescription(data.description)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
121
|
+
if (!rejectedItemName) {
|
122
|
+
throw new Error(`Could not add items`, { cause: data });
|
123
|
+
}
|
124
|
+
else {
|
125
|
+
const oldLength = filteredItems.length;
|
126
|
+
filteredItems = filteredItems.filter((item) => {
|
127
|
+
if (item.name.toLowerCase().includes(rejectedItemName)) {
|
128
|
+
unavailableItems.push(item.name);
|
129
|
+
return false;
|
130
|
+
}
|
131
|
+
return true;
|
132
|
+
});
|
133
|
+
if (filteredItems.length == 0) {
|
134
|
+
break;
|
135
|
+
}
|
136
|
+
else if (oldLength == filteredItems.length) {
|
137
|
+
throw new Error(`Could not add items`, { cause: data });
|
138
|
+
}
|
139
|
+
}
|
140
|
+
await delay(RETRY_DELAY);
|
141
|
+
}
|
142
|
+
else if (!response.ok) {
|
143
|
+
throw new Error(`Could not add items`, { cause: await response.text() });
|
144
|
+
}
|
145
|
+
}
|
146
|
+
return unavailableItems.length > 0
|
147
|
+
? `Some items could not be added: ${unavailableItems.join(', ')}`
|
148
|
+
: undefined;
|
97
149
|
},
|
98
150
|
getCartToken() {
|
99
151
|
let cartToken = getCookieValue(cartTokenCookie);
|
@@ -102,6 +154,11 @@ const createShopApi = (fetchOverride = window.fetch) => ({
|
|
102
154
|
}
|
103
155
|
return cartToken || null;
|
104
156
|
},
|
157
|
+
getCheckoutURL() {
|
158
|
+
const token = this.getCartToken();
|
159
|
+
return token
|
160
|
+
? new URL(`/checkouts/cn/${token}`, window.location.origin)
|
161
|
+
: null;
|
162
|
+
},
|
105
163
|
});
|
106
164
|
window[registryKey].storeAPIFactory = createShopApi;
|
107
|
-
window[registryKey].platform = 'SHOPIFY';
|
package/stores/shopify/index.js
CHANGED
@@ -35,6 +35,8 @@
|
|
35
35
|
...expand('911,921,922,923,924,926,927,932,933,935,942,944,946,950,953,955,957-958,960-969,974,975,976,977,981-982,987,988,990-999'),
|
36
36
|
]);
|
37
37
|
|
38
|
+
const delay = (n, resolvedValue) => new Promise((resolve) => setTimeout(() => resolve(resolvedValue), n));
|
39
|
+
|
38
40
|
const cartTokenCookie = 'cart';
|
39
41
|
const cartTokenTwoCookie = 'cart2';
|
40
42
|
|
@@ -79,22 +81,72 @@
|
|
79
81
|
};
|
80
82
|
|
81
83
|
// eslint-disable-next-line @nx/enforce-module-boundaries
|
84
|
+
const MAX_RETRY_COUNT = 3;
|
85
|
+
const RETRY_DELAY = 500;
|
86
|
+
const ERROR_PATTERNS = {
|
87
|
+
cannotAddMore: /^You can't add more (.*?) to the cart\.$/,
|
88
|
+
soldOut: /^The product '?(.*?)'? is already sold out\.$/,
|
89
|
+
};
|
90
|
+
const getItemNameFromDescription = (description) => {
|
91
|
+
let matches = description.match(ERROR_PATTERNS.cannotAddMore);
|
92
|
+
if (matches === null || matches === void 0 ? void 0 : matches.length)
|
93
|
+
return matches[1];
|
94
|
+
matches = description.match(ERROR_PATTERNS.soldOut);
|
95
|
+
if (matches === null || matches === void 0 ? void 0 : matches.length)
|
96
|
+
return matches[1];
|
97
|
+
return null;
|
98
|
+
};
|
99
|
+
const addItemsToCart = (fetchOverride, itemsToAdd) => fetchOverride(`${window.Shopify.routes.root}cart/add.js`, {
|
100
|
+
method: 'POST',
|
101
|
+
body: JSON.stringify({
|
102
|
+
items: itemsToAdd.map((item) => ({
|
103
|
+
id: item.variantId || item.productId,
|
104
|
+
quantity: item.quantity,
|
105
|
+
})),
|
106
|
+
}),
|
107
|
+
headers: { 'Content-type': 'application/json' },
|
108
|
+
});
|
82
109
|
const createShopApi = (fetchOverride = window.fetch) => ({
|
83
|
-
addItems(items) {
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
}),
|
92
|
-
headers: { 'Content-type': 'application/json' },
|
93
|
-
}).then(async (response) => {
|
94
|
-
if (!response.ok) {
|
95
|
-
throw new Error('Could not add items', { cause: await response.text() });
|
110
|
+
async addItems(items) {
|
111
|
+
var _a;
|
112
|
+
let filteredItems = items;
|
113
|
+
const unavailableItems = [];
|
114
|
+
for (let retries = 0; retries < MAX_RETRY_COUNT; retries++) {
|
115
|
+
const response = await addItemsToCart(fetchOverride, filteredItems);
|
116
|
+
if (response.ok) {
|
117
|
+
break;
|
96
118
|
}
|
97
|
-
|
119
|
+
if (response.status == 422) {
|
120
|
+
const data = (await response.json());
|
121
|
+
const rejectedItemName = (_a = getItemNameFromDescription(data.description)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
122
|
+
if (!rejectedItemName) {
|
123
|
+
throw new Error(`Could not add items`, { cause: data });
|
124
|
+
}
|
125
|
+
else {
|
126
|
+
const oldLength = filteredItems.length;
|
127
|
+
filteredItems = filteredItems.filter((item) => {
|
128
|
+
if (item.name.toLowerCase().includes(rejectedItemName)) {
|
129
|
+
unavailableItems.push(item.name);
|
130
|
+
return false;
|
131
|
+
}
|
132
|
+
return true;
|
133
|
+
});
|
134
|
+
if (filteredItems.length == 0) {
|
135
|
+
break;
|
136
|
+
}
|
137
|
+
else if (oldLength == filteredItems.length) {
|
138
|
+
throw new Error(`Could not add items`, { cause: data });
|
139
|
+
}
|
140
|
+
}
|
141
|
+
await delay(RETRY_DELAY);
|
142
|
+
}
|
143
|
+
else if (!response.ok) {
|
144
|
+
throw new Error(`Could not add items`, { cause: await response.text() });
|
145
|
+
}
|
146
|
+
}
|
147
|
+
return unavailableItems.length > 0
|
148
|
+
? `Some items could not be added: ${unavailableItems.join(', ')}`
|
149
|
+
: undefined;
|
98
150
|
},
|
99
151
|
getCartToken() {
|
100
152
|
let cartToken = getCookieValue(cartTokenCookie);
|
@@ -103,8 +155,13 @@
|
|
103
155
|
}
|
104
156
|
return cartToken || null;
|
105
157
|
},
|
158
|
+
getCheckoutURL() {
|
159
|
+
const token = this.getCartToken();
|
160
|
+
return token
|
161
|
+
? new URL(`/checkouts/cn/${token}`, window.location.origin)
|
162
|
+
: null;
|
163
|
+
},
|
106
164
|
});
|
107
165
|
window[registryKey].storeAPIFactory = createShopApi;
|
108
|
-
window[registryKey].platform = 'SHOPIFY';
|
109
166
|
|
110
167
|
})();
|
package/stores/shopify/index.mjs
CHANGED
@@ -32,6 +32,8 @@ new Set([
|
|
32
32
|
...expand('911,921,922,923,924,926,927,932,933,935,942,944,946,950,953,955,957-958,960-969,974,975,976,977,981-982,987,988,990-999'),
|
33
33
|
]);
|
34
34
|
|
35
|
+
const delay = (n, resolvedValue) => new Promise((resolve) => setTimeout(() => resolve(resolvedValue), n));
|
36
|
+
|
35
37
|
const cartTokenCookie = 'cart';
|
36
38
|
const cartTokenTwoCookie = 'cart2';
|
37
39
|
|
@@ -76,22 +78,72 @@ const parseCookies = (cookie) => {
|
|
76
78
|
};
|
77
79
|
|
78
80
|
// eslint-disable-next-line @nx/enforce-module-boundaries
|
81
|
+
const MAX_RETRY_COUNT = 3;
|
82
|
+
const RETRY_DELAY = 500;
|
83
|
+
const ERROR_PATTERNS = {
|
84
|
+
cannotAddMore: /^You can't add more (.*?) to the cart\.$/,
|
85
|
+
soldOut: /^The product '?(.*?)'? is already sold out\.$/,
|
86
|
+
};
|
87
|
+
const getItemNameFromDescription = (description) => {
|
88
|
+
let matches = description.match(ERROR_PATTERNS.cannotAddMore);
|
89
|
+
if (matches === null || matches === void 0 ? void 0 : matches.length)
|
90
|
+
return matches[1];
|
91
|
+
matches = description.match(ERROR_PATTERNS.soldOut);
|
92
|
+
if (matches === null || matches === void 0 ? void 0 : matches.length)
|
93
|
+
return matches[1];
|
94
|
+
return null;
|
95
|
+
};
|
96
|
+
const addItemsToCart = (fetchOverride, itemsToAdd) => fetchOverride(`${window.Shopify.routes.root}cart/add.js`, {
|
97
|
+
method: 'POST',
|
98
|
+
body: JSON.stringify({
|
99
|
+
items: itemsToAdd.map((item) => ({
|
100
|
+
id: item.variantId || item.productId,
|
101
|
+
quantity: item.quantity,
|
102
|
+
})),
|
103
|
+
}),
|
104
|
+
headers: { 'Content-type': 'application/json' },
|
105
|
+
});
|
79
106
|
const createShopApi = (fetchOverride = window.fetch) => ({
|
80
|
-
addItems(items) {
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
}),
|
89
|
-
headers: { 'Content-type': 'application/json' },
|
90
|
-
}).then(async (response) => {
|
91
|
-
if (!response.ok) {
|
92
|
-
throw new Error('Could not add items', { cause: await response.text() });
|
107
|
+
async addItems(items) {
|
108
|
+
var _a;
|
109
|
+
let filteredItems = items;
|
110
|
+
const unavailableItems = [];
|
111
|
+
for (let retries = 0; retries < MAX_RETRY_COUNT; retries++) {
|
112
|
+
const response = await addItemsToCart(fetchOverride, filteredItems);
|
113
|
+
if (response.ok) {
|
114
|
+
break;
|
93
115
|
}
|
94
|
-
|
116
|
+
if (response.status == 422) {
|
117
|
+
const data = (await response.json());
|
118
|
+
const rejectedItemName = (_a = getItemNameFromDescription(data.description)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
119
|
+
if (!rejectedItemName) {
|
120
|
+
throw new Error(`Could not add items`, { cause: data });
|
121
|
+
}
|
122
|
+
else {
|
123
|
+
const oldLength = filteredItems.length;
|
124
|
+
filteredItems = filteredItems.filter((item) => {
|
125
|
+
if (item.name.toLowerCase().includes(rejectedItemName)) {
|
126
|
+
unavailableItems.push(item.name);
|
127
|
+
return false;
|
128
|
+
}
|
129
|
+
return true;
|
130
|
+
});
|
131
|
+
if (filteredItems.length == 0) {
|
132
|
+
break;
|
133
|
+
}
|
134
|
+
else if (oldLength == filteredItems.length) {
|
135
|
+
throw new Error(`Could not add items`, { cause: data });
|
136
|
+
}
|
137
|
+
}
|
138
|
+
await delay(RETRY_DELAY);
|
139
|
+
}
|
140
|
+
else if (!response.ok) {
|
141
|
+
throw new Error(`Could not add items`, { cause: await response.text() });
|
142
|
+
}
|
143
|
+
}
|
144
|
+
return unavailableItems.length > 0
|
145
|
+
? `Some items could not be added: ${unavailableItems.join(', ')}`
|
146
|
+
: undefined;
|
95
147
|
},
|
96
148
|
getCartToken() {
|
97
149
|
let cartToken = getCookieValue(cartTokenCookie);
|
@@ -100,6 +152,11 @@ const createShopApi = (fetchOverride = window.fetch) => ({
|
|
100
152
|
}
|
101
153
|
return cartToken || null;
|
102
154
|
},
|
155
|
+
getCheckoutURL() {
|
156
|
+
const token = this.getCartToken();
|
157
|
+
return token
|
158
|
+
? new URL(`/checkouts/cn/${token}`, window.location.origin)
|
159
|
+
: null;
|
160
|
+
},
|
103
161
|
});
|
104
162
|
window[registryKey].storeAPIFactory = createShopApi;
|
105
|
-
window[registryKey].platform = 'SHOPIFY';
|