@blotoutio/providers-blotout-wallet-sdk 0.61.0 → 0.62.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.
Files changed (4) hide show
  1. package/index.cjs.js +133 -105
  2. package/index.js +133 -105
  3. package/index.mjs +133 -105
  4. package/package.json +1 -1
package/index.cjs.js 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 customAttributes = {
38
40
  '--bw-primary': { type: 'color', defaultValue: '#000000' },
39
41
  '--bw-title-color': { type: 'color', defaultValue: '#000000' },
@@ -362,31 +364,43 @@ const cssVars = i$4 `
362
364
  }
363
365
  `;
364
366
 
367
+ const isGecko = () => /\bGecko\/\d+/.test(navigator.userAgent);
368
+
365
369
  const fadeInDialog = (element) => {
366
- const dialogAnimation = element.animate([
367
- { transform: 'translateY(-20px)', opacity: 0 },
368
- { transform: 'translateY(0)', opacity: 1 },
369
- ], { duration: 600, easing: spring, composite: 'add' });
370
- const backdropAnimation = element.animate([{ opacity: 0 }, { opacity: 1 }], {
371
- duration: 300,
372
- easing: 'ease-out',
373
- pseudoElement: '::backdrop',
374
- fill: 'forwards',
375
- });
376
- return Promise.all([dialogAnimation.finished, backdropAnimation.finished]);
370
+ const animations = [
371
+ element.animate([
372
+ { transform: 'translateY(-20px)', opacity: 0 },
373
+ { transform: 'translateY(0)', opacity: 1 },
374
+ ], { duration: 600, easing: spring, composite: 'add' }),
375
+ ];
376
+ // Gecko does not support animating ::backdrop pseudo elements
377
+ if (!isGecko()) {
378
+ animations.push(element.animate([{ opacity: 0 }, { opacity: 1 }], {
379
+ duration: 300,
380
+ easing: 'ease-out',
381
+ pseudoElement: '::backdrop',
382
+ fill: 'forwards',
383
+ }));
384
+ }
385
+ return Promise.all(animations.map((anim) => anim.finished));
377
386
  };
378
387
  const fadeOutToBottom = (element) => {
379
- const dialogAnimation = element.animate([
380
- { transform: 'translateY(0)', opacity: 1 },
381
- { transform: 'translateY(20px)', opacity: 0 },
382
- ], { duration: 600, easing: spring });
383
- const backdropAnimation = element.animate([{ opacity: 1 }, { opacity: 0 }], {
384
- duration: 300,
385
- easing: 'ease-out',
386
- pseudoElement: '::backdrop',
387
- fill: 'forwards',
388
- });
389
- return Promise.all([dialogAnimation.finished, backdropAnimation.finished]);
388
+ const animations = [
389
+ element.animate([
390
+ { transform: 'translateY(0)', opacity: 1 },
391
+ { transform: 'translateY(20px)', opacity: 0 },
392
+ ], { duration: 600, easing: spring }),
393
+ ];
394
+ // Gecko does not support animating ::backdrop pseudo elements
395
+ if (!isGecko()) {
396
+ animations.push(element.animate([{ opacity: 1 }, { opacity: 0 }], {
397
+ duration: 300,
398
+ easing: 'ease-out',
399
+ pseudoElement: '::backdrop',
400
+ fill: 'forwards',
401
+ }));
402
+ }
403
+ return Promise.all(animations.map((anim) => anim.finished));
390
404
  };
391
405
  const flipOut = (element) => {
392
406
  const animation = element.animate([
@@ -449,7 +463,6 @@ const formatString = (str) => {
449
463
  const parts = str.split(/<\s*br\s*\/?\s*>/);
450
464
  return o(parts, x `<br />`);
451
465
  };
452
- const delay = (n, resolvedValue) => new Promise((resolve) => setTimeout(() => resolve(resolvedValue), n));
453
466
  let BlotoutWallet = class BlotoutWallet extends s {
454
467
  constructor() {
455
468
  super(...arguments);
@@ -462,78 +475,76 @@ let BlotoutWallet = class BlotoutWallet extends s {
462
475
  .then(() => (this.state = newState))
463
476
  .then(() => flipIn(this.dialog));
464
477
  };
478
+ this.restoreCart = async () => {
479
+ if (!this.lastExpiredCart) {
480
+ return;
481
+ }
482
+ const email = this.email.value.trim().toLowerCase();
483
+ if (email) {
484
+ window.edgetag('user', 'email', email, {}, { destination: this.edgeURL });
485
+ const response = await fetch(this.getUrl('/user/email'), {
486
+ method: 'POST',
487
+ body: JSON.stringify({
488
+ email: email,
489
+ }),
490
+ headers: this.getHeaders(true),
491
+ });
492
+ if (!response.ok) {
493
+ throw new Error(`Could not save email ${response.status}: ${await response.text()}`);
494
+ }
495
+ this.email.value = '';
496
+ this.hasEmail = true;
497
+ this.dispatchEvent(new CustomEvent('blotout-wallet-email-saved', { bubbles: true }));
498
+ window.edgetag('tag', 'CartRecovery_KeepCartEmailSaved', {}, {}, { destination: this.edgeURL });
499
+ }
500
+ await this.storeApi.addItems(this.lastExpiredCart.items);
501
+ const expiredCartId = this.lastExpiredCart.cartId;
502
+ // this cookie will be cleared once the next event is processed
503
+ setCookie(cartTokenLinkCookie, expiredCartId, { path: '/' });
504
+ // We attempt to mark the cart as restored, but if the request fails,
505
+ // we log the error in the console and let the user continue. Since the
506
+ // problem is probably in the `/cart/restore` endpoint, further attempts
507
+ // would not resolve the problem, which would just increase the number
508
+ // of failed calls and not solve the problem.
509
+ const response = await fetch(this.getUrl(`/cart/restore/${expiredCartId}`), {
510
+ method: 'POST',
511
+ headers: this.getHeaders(),
512
+ });
513
+ if (!response.ok) {
514
+ throw new Error(`Could not update status in DB - ${response.status}: ${response.text}\n\n${await response.text()}`);
515
+ }
516
+ this.lastExpiredCart = undefined;
517
+ this.dispatchEvent(new CustomEvent('blotout-wallet-restored', {
518
+ bubbles: true,
519
+ }));
520
+ // Send the request as beacon as there could be a immediate redirect in the next step
521
+ window.edgetag('tag', 'CartRecovery_CartRestored', { isSilent: !!this.silentRestore }, {}, { method: 'beacon' });
522
+ };
465
523
  this.onSubmit = async (ev) => {
466
524
  ev.preventDefault();
467
525
  ev.stopPropagation();
468
- const email = this.email.value.trim().toLowerCase();
469
526
  try {
470
527
  await this.transitionTo('loading');
471
- if (email) {
472
- window.edgetag('user', 'email', email, {}, { destination: this.edgeURL });
473
- const response = await fetch(this.getUrl('/user/email'), {
474
- method: 'POST',
475
- body: JSON.stringify({
476
- email: email,
477
- }),
478
- headers: this.getHeaders(true),
479
- });
480
- if (!response.ok) {
481
- throw new Error(`Could not save email ${response.status}: ${await response.text()}`);
482
- }
483
- this.email.value = '';
484
- this.hasEmail = true;
485
- this.dispatchEvent(new CustomEvent('blotout-wallet-email-saved', { bubbles: true }));
486
- window.edgetag('tag', 'CartRecovery_KeepCartEmailSaved', {}, {}, { destination: this.edgeURL });
487
- }
488
- if (this.lastExpiredCart) {
489
- await this.storeApi.addItems(this.lastExpiredCart.items);
490
- this.dispatchEvent(new CustomEvent('blotout-wallet-restored', {
491
- bubbles: true,
492
- }));
493
- const expiredCartId = this.lastExpiredCart.cartId;
494
- // this cookie will be cleared once the next event is processed
495
- setCookie(cartTokenLinkCookie, expiredCartId, { path: '/' });
496
- // We attempt to mark the cart as restored, but if the request fails,
497
- // we log the error in the console and let the user continue. Since the
498
- // problem is probably in the `/cart/restore` endpoint, further attempts
499
- // would not resolve the problem, which would just increase the number
500
- // of failed calls and not solve the problem.
501
- fetch(this.getUrl(`/cart/restore/${expiredCartId}`), {
502
- method: 'POST',
503
- headers: this.getHeaders(),
504
- })
505
- .then(async (response) => {
506
- if (!response.ok) {
507
- throw new Error(`Could not update status in DB - ${response.status}: ${response.text}\n\n${await response.text()}`);
508
- }
509
- // Send the request as beacon as there could be a immediate redirect in the next step
510
- window.edgetag('tag', 'CartRecovery_CartRestored', {}, {}, { method: 'beacon' });
511
- // Redirect to custom path
512
- if (this.restoreRedirect) {
513
- try {
514
- const redirect = new URL(this.restoreRedirect, window.location.origin);
515
- window.location.href = redirect.href;
516
- }
517
- catch (e) {
518
- console.error('Invalid redirect URL', e);
519
- }
520
- }
521
- })
522
- .catch((err) => {
523
- console.error(err);
524
- });
525
- this.lastExpiredCart = undefined;
526
- }
528
+ await this.restoreCart();
527
529
  await this.transitionTo('restored');
528
- delay(2000).then(() => {
529
- if (this.state == 'restored') {
530
- this.hideModal('restore');
530
+ await delay(2000);
531
+ if (this.state == 'restored') {
532
+ this.hideModal('restore');
533
+ }
534
+ // Redirect to custom path
535
+ if (this.restoreRedirect) {
536
+ try {
537
+ const redirect = new URL(this.restoreRedirect, window.location.origin);
538
+ window.location.href = redirect.href;
531
539
  }
532
- });
540
+ catch (e) {
541
+ console.error('Invalid redirect URL', e);
542
+ }
543
+ }
533
544
  }
534
545
  catch (e) {
535
- await this.transitionTo('failed');
536
546
  logger.error(e);
547
+ await this.transitionTo('failed');
537
548
  }
538
549
  };
539
550
  this.onDialogClick = () => {
@@ -643,6 +654,7 @@ let BlotoutWallet = class BlotoutWallet extends s {
643
654
  }
644
655
  }
645
656
  async initialize() {
657
+ var _a;
646
658
  if (!this.userId) {
647
659
  logger.error('No UserId set');
648
660
  return;
@@ -651,11 +663,11 @@ let BlotoutWallet = class BlotoutWallet extends s {
651
663
  return;
652
664
  }
653
665
  await delay(POPUP_IMPRESSION_DELAY);
654
- fetch(this.getUrl('/cart/expired'), {
655
- method: 'GET',
656
- headers: this.getHeaders(),
657
- })
658
- .then(async (response) => {
666
+ try {
667
+ const response = await fetch(this.getUrl('/cart/expired'), {
668
+ method: 'GET',
669
+ headers: this.getHeaders(),
670
+ });
659
671
  if (!response.ok) {
660
672
  throw new Error(`Unable to get Expired Cart ${response.status}: ${await response.text()}`);
661
673
  }
@@ -663,16 +675,27 @@ let BlotoutWallet = class BlotoutWallet extends s {
663
675
  const result = await response.json();
664
676
  this.hasEmail = result.email;
665
677
  this.lastExpiredCart = result.carts[0];
666
- if (result.carts && result.carts.length && !this.isPopUpDismissed) {
667
- this.showModal();
668
- window.edgetag('tag', 'CartRecovery_CartExpiredOnVisit', {}, {}, { destination: this.edgeURL });
678
+ if ((_a = result.carts) === null || _a === void 0 ? void 0 : _a.length) {
679
+ if (this.silentRestore) {
680
+ this.restoreCart().catch(logger.error);
681
+ }
682
+ else if (!this.isPopUpDismissed) {
683
+ this.showModal();
684
+ }
685
+ if (result.hasJustExpired) {
686
+ window.edgetag('tag', 'CartRecovery_CartExpiredOnVisit', {}, {}, { destination: this.edgeURL });
687
+ }
669
688
  }
670
- })
671
- .catch(logger.error);
689
+ }
690
+ catch (err) {
691
+ logger.error(err);
692
+ }
672
693
  }
673
694
  showModal() {
674
695
  this.dialog.showModal();
675
- new Promise(requestAnimationFrame).then(() => fadeInDialog(this.dialog));
696
+ new Promise(requestAnimationFrame)
697
+ .catch(logger.error)
698
+ .finally(() => fadeInDialog(this.dialog));
676
699
  this.dispatchEvent(new CustomEvent('blotout-wallet-shown', { bubbles: true }));
677
700
  fetch(this.getUrl('/user/event'), {
678
701
  method: 'POST',
@@ -681,7 +704,9 @@ let BlotoutWallet = class BlotoutWallet extends s {
681
704
  }).catch(logger.error);
682
705
  }
683
706
  hideModal(action) {
684
- fadeOutToBottom(this.dialog).then(() => { var _a; return (_a = this.dialog) === null || _a === void 0 ? void 0 : _a.close(action); });
707
+ fadeOutToBottom(this.dialog)
708
+ .catch(logger.error)
709
+ .finally(() => { var _a; return (_a = this.dialog) === null || _a === void 0 ? void 0 : _a.close(action); });
685
710
  this.dispatchEvent(new CustomEvent('blotout-wallet-hidden', { bubbles: true }));
686
711
  }
687
712
  getHeaders(json = false) {
@@ -703,18 +728,20 @@ let BlotoutWallet = class BlotoutWallet extends s {
703
728
  }
704
729
  async skipCarts() {
705
730
  this.hideModal('skip');
706
- await fetch(this.getUrl('/cart/skip'), {
707
- method: 'POST',
708
- headers: this.getHeaders(),
709
- })
710
- .then(async (response) => {
731
+ try {
732
+ const response = await fetch(this.getUrl('/cart/skip'), {
733
+ method: 'POST',
734
+ headers: this.getHeaders(),
735
+ });
711
736
  if (!response.ok) {
712
737
  throw new Error(`Could not mark cart as skipped - ${response.status}: ${await response.text()}`);
713
738
  }
714
739
  window.edgetag('tag', 'CartRecovery_CartDeclined', {}, {}, { destination: this.edgeURL });
715
740
  this.lastExpiredCart = undefined;
716
- })
717
- .catch(logger.error);
741
+ }
742
+ catch (e) {
743
+ logger.error(e);
744
+ }
718
745
  }
719
746
  render() {
720
747
  if (this.isPopUpDismissed) {
@@ -893,7 +920,7 @@ BlotoutWallet = __decorate([
893
920
  ], BlotoutWallet);
894
921
 
895
922
  const init = (params) => {
896
- var _a, _b, _c, _d, _e;
923
+ var _a, _b, _c, _d, _e, _f;
897
924
  if (
898
925
  // if loaded in non-browser SDKs
899
926
  !window ||
@@ -928,6 +955,7 @@ const init = (params) => {
928
955
  element.edgeURL = params.baseUrl;
929
956
  element.userId = params.userId;
930
957
  element.restoreRedirect = (_e = params.manifest.variables) === null || _e === void 0 ? void 0 : _e['restoreRedirect'];
958
+ element.silentRestore = ((_f = params.manifest.variables) === null || _f === void 0 ? void 0 : _f['silentRestore']) === '1';
931
959
  document.body.append(element);
932
960
  }
933
961
  };
package/index.js CHANGED
@@ -35,6 +35,8 @@ var ProvidersBlotoutWalletSdk = (function () {
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 customAttributes = {
39
41
  '--bw-primary': { type: 'color', defaultValue: '#000000' },
40
42
  '--bw-title-color': { type: 'color', defaultValue: '#000000' },
@@ -363,31 +365,43 @@ var ProvidersBlotoutWalletSdk = (function () {
363
365
  }
364
366
  `;
365
367
 
368
+ const isGecko = () => /\bGecko\/\d+/.test(navigator.userAgent);
369
+
366
370
  const fadeInDialog = (element) => {
367
- const dialogAnimation = element.animate([
368
- { transform: 'translateY(-20px)', opacity: 0 },
369
- { transform: 'translateY(0)', opacity: 1 },
370
- ], { duration: 600, easing: spring, composite: 'add' });
371
- const backdropAnimation = element.animate([{ opacity: 0 }, { opacity: 1 }], {
372
- duration: 300,
373
- easing: 'ease-out',
374
- pseudoElement: '::backdrop',
375
- fill: 'forwards',
376
- });
377
- return Promise.all([dialogAnimation.finished, backdropAnimation.finished]);
371
+ const animations = [
372
+ element.animate([
373
+ { transform: 'translateY(-20px)', opacity: 0 },
374
+ { transform: 'translateY(0)', opacity: 1 },
375
+ ], { duration: 600, easing: spring, composite: 'add' }),
376
+ ];
377
+ // Gecko does not support animating ::backdrop pseudo elements
378
+ if (!isGecko()) {
379
+ animations.push(element.animate([{ opacity: 0 }, { opacity: 1 }], {
380
+ duration: 300,
381
+ easing: 'ease-out',
382
+ pseudoElement: '::backdrop',
383
+ fill: 'forwards',
384
+ }));
385
+ }
386
+ return Promise.all(animations.map((anim) => anim.finished));
378
387
  };
379
388
  const fadeOutToBottom = (element) => {
380
- const dialogAnimation = element.animate([
381
- { transform: 'translateY(0)', opacity: 1 },
382
- { transform: 'translateY(20px)', opacity: 0 },
383
- ], { duration: 600, easing: spring });
384
- const backdropAnimation = element.animate([{ opacity: 1 }, { opacity: 0 }], {
385
- duration: 300,
386
- easing: 'ease-out',
387
- pseudoElement: '::backdrop',
388
- fill: 'forwards',
389
- });
390
- return Promise.all([dialogAnimation.finished, backdropAnimation.finished]);
389
+ const animations = [
390
+ element.animate([
391
+ { transform: 'translateY(0)', opacity: 1 },
392
+ { transform: 'translateY(20px)', opacity: 0 },
393
+ ], { duration: 600, easing: spring }),
394
+ ];
395
+ // Gecko does not support animating ::backdrop pseudo elements
396
+ if (!isGecko()) {
397
+ animations.push(element.animate([{ opacity: 1 }, { opacity: 0 }], {
398
+ duration: 300,
399
+ easing: 'ease-out',
400
+ pseudoElement: '::backdrop',
401
+ fill: 'forwards',
402
+ }));
403
+ }
404
+ return Promise.all(animations.map((anim) => anim.finished));
391
405
  };
392
406
  const flipOut = (element) => {
393
407
  const animation = element.animate([
@@ -450,7 +464,6 @@ var ProvidersBlotoutWalletSdk = (function () {
450
464
  const parts = str.split(/<\s*br\s*\/?\s*>/);
451
465
  return o(parts, x `<br />`);
452
466
  };
453
- const delay = (n, resolvedValue) => new Promise((resolve) => setTimeout(() => resolve(resolvedValue), n));
454
467
  let BlotoutWallet = class BlotoutWallet extends s {
455
468
  constructor() {
456
469
  super(...arguments);
@@ -463,78 +476,76 @@ var ProvidersBlotoutWalletSdk = (function () {
463
476
  .then(() => (this.state = newState))
464
477
  .then(() => flipIn(this.dialog));
465
478
  };
479
+ this.restoreCart = async () => {
480
+ if (!this.lastExpiredCart) {
481
+ return;
482
+ }
483
+ const email = this.email.value.trim().toLowerCase();
484
+ if (email) {
485
+ window.edgetag('user', 'email', email, {}, { destination: this.edgeURL });
486
+ const response = await fetch(this.getUrl('/user/email'), {
487
+ method: 'POST',
488
+ body: JSON.stringify({
489
+ email: email,
490
+ }),
491
+ headers: this.getHeaders(true),
492
+ });
493
+ if (!response.ok) {
494
+ throw new Error(`Could not save email ${response.status}: ${await response.text()}`);
495
+ }
496
+ this.email.value = '';
497
+ this.hasEmail = true;
498
+ this.dispatchEvent(new CustomEvent('blotout-wallet-email-saved', { bubbles: true }));
499
+ window.edgetag('tag', 'CartRecovery_KeepCartEmailSaved', {}, {}, { destination: this.edgeURL });
500
+ }
501
+ await this.storeApi.addItems(this.lastExpiredCart.items);
502
+ const expiredCartId = this.lastExpiredCart.cartId;
503
+ // this cookie will be cleared once the next event is processed
504
+ setCookie(cartTokenLinkCookie, expiredCartId, { path: '/' });
505
+ // We attempt to mark the cart as restored, but if the request fails,
506
+ // we log the error in the console and let the user continue. Since the
507
+ // problem is probably in the `/cart/restore` endpoint, further attempts
508
+ // would not resolve the problem, which would just increase the number
509
+ // of failed calls and not solve the problem.
510
+ const response = await fetch(this.getUrl(`/cart/restore/${expiredCartId}`), {
511
+ method: 'POST',
512
+ headers: this.getHeaders(),
513
+ });
514
+ if (!response.ok) {
515
+ throw new Error(`Could not update status in DB - ${response.status}: ${response.text}\n\n${await response.text()}`);
516
+ }
517
+ this.lastExpiredCart = undefined;
518
+ this.dispatchEvent(new CustomEvent('blotout-wallet-restored', {
519
+ bubbles: true,
520
+ }));
521
+ // Send the request as beacon as there could be a immediate redirect in the next step
522
+ window.edgetag('tag', 'CartRecovery_CartRestored', { isSilent: !!this.silentRestore }, {}, { method: 'beacon' });
523
+ };
466
524
  this.onSubmit = async (ev) => {
467
525
  ev.preventDefault();
468
526
  ev.stopPropagation();
469
- const email = this.email.value.trim().toLowerCase();
470
527
  try {
471
528
  await this.transitionTo('loading');
472
- if (email) {
473
- window.edgetag('user', 'email', email, {}, { destination: this.edgeURL });
474
- const response = await fetch(this.getUrl('/user/email'), {
475
- method: 'POST',
476
- body: JSON.stringify({
477
- email: email,
478
- }),
479
- headers: this.getHeaders(true),
480
- });
481
- if (!response.ok) {
482
- throw new Error(`Could not save email ${response.status}: ${await response.text()}`);
483
- }
484
- this.email.value = '';
485
- this.hasEmail = true;
486
- this.dispatchEvent(new CustomEvent('blotout-wallet-email-saved', { bubbles: true }));
487
- window.edgetag('tag', 'CartRecovery_KeepCartEmailSaved', {}, {}, { destination: this.edgeURL });
488
- }
489
- if (this.lastExpiredCart) {
490
- await this.storeApi.addItems(this.lastExpiredCart.items);
491
- this.dispatchEvent(new CustomEvent('blotout-wallet-restored', {
492
- bubbles: true,
493
- }));
494
- const expiredCartId = this.lastExpiredCart.cartId;
495
- // this cookie will be cleared once the next event is processed
496
- setCookie(cartTokenLinkCookie, expiredCartId, { path: '/' });
497
- // We attempt to mark the cart as restored, but if the request fails,
498
- // we log the error in the console and let the user continue. Since the
499
- // problem is probably in the `/cart/restore` endpoint, further attempts
500
- // would not resolve the problem, which would just increase the number
501
- // of failed calls and not solve the problem.
502
- fetch(this.getUrl(`/cart/restore/${expiredCartId}`), {
503
- method: 'POST',
504
- headers: this.getHeaders(),
505
- })
506
- .then(async (response) => {
507
- if (!response.ok) {
508
- throw new Error(`Could not update status in DB - ${response.status}: ${response.text}\n\n${await response.text()}`);
509
- }
510
- // Send the request as beacon as there could be a immediate redirect in the next step
511
- window.edgetag('tag', 'CartRecovery_CartRestored', {}, {}, { method: 'beacon' });
512
- // Redirect to custom path
513
- if (this.restoreRedirect) {
514
- try {
515
- const redirect = new URL(this.restoreRedirect, window.location.origin);
516
- window.location.href = redirect.href;
517
- }
518
- catch (e) {
519
- console.error('Invalid redirect URL', e);
520
- }
521
- }
522
- })
523
- .catch((err) => {
524
- console.error(err);
525
- });
526
- this.lastExpiredCart = undefined;
527
- }
529
+ await this.restoreCart();
528
530
  await this.transitionTo('restored');
529
- delay(2000).then(() => {
530
- if (this.state == 'restored') {
531
- this.hideModal('restore');
531
+ await delay(2000);
532
+ if (this.state == 'restored') {
533
+ this.hideModal('restore');
534
+ }
535
+ // Redirect to custom path
536
+ if (this.restoreRedirect) {
537
+ try {
538
+ const redirect = new URL(this.restoreRedirect, window.location.origin);
539
+ window.location.href = redirect.href;
532
540
  }
533
- });
541
+ catch (e) {
542
+ console.error('Invalid redirect URL', e);
543
+ }
544
+ }
534
545
  }
535
546
  catch (e) {
536
- await this.transitionTo('failed');
537
547
  logger.error(e);
548
+ await this.transitionTo('failed');
538
549
  }
539
550
  };
540
551
  this.onDialogClick = () => {
@@ -644,6 +655,7 @@ var ProvidersBlotoutWalletSdk = (function () {
644
655
  }
645
656
  }
646
657
  async initialize() {
658
+ var _a;
647
659
  if (!this.userId) {
648
660
  logger.error('No UserId set');
649
661
  return;
@@ -652,11 +664,11 @@ var ProvidersBlotoutWalletSdk = (function () {
652
664
  return;
653
665
  }
654
666
  await delay(POPUP_IMPRESSION_DELAY);
655
- fetch(this.getUrl('/cart/expired'), {
656
- method: 'GET',
657
- headers: this.getHeaders(),
658
- })
659
- .then(async (response) => {
667
+ try {
668
+ const response = await fetch(this.getUrl('/cart/expired'), {
669
+ method: 'GET',
670
+ headers: this.getHeaders(),
671
+ });
660
672
  if (!response.ok) {
661
673
  throw new Error(`Unable to get Expired Cart ${response.status}: ${await response.text()}`);
662
674
  }
@@ -664,16 +676,27 @@ var ProvidersBlotoutWalletSdk = (function () {
664
676
  const result = await response.json();
665
677
  this.hasEmail = result.email;
666
678
  this.lastExpiredCart = result.carts[0];
667
- if (result.carts && result.carts.length && !this.isPopUpDismissed) {
668
- this.showModal();
669
- window.edgetag('tag', 'CartRecovery_CartExpiredOnVisit', {}, {}, { destination: this.edgeURL });
679
+ if ((_a = result.carts) === null || _a === void 0 ? void 0 : _a.length) {
680
+ if (this.silentRestore) {
681
+ this.restoreCart().catch(logger.error);
682
+ }
683
+ else if (!this.isPopUpDismissed) {
684
+ this.showModal();
685
+ }
686
+ if (result.hasJustExpired) {
687
+ window.edgetag('tag', 'CartRecovery_CartExpiredOnVisit', {}, {}, { destination: this.edgeURL });
688
+ }
670
689
  }
671
- })
672
- .catch(logger.error);
690
+ }
691
+ catch (err) {
692
+ logger.error(err);
693
+ }
673
694
  }
674
695
  showModal() {
675
696
  this.dialog.showModal();
676
- new Promise(requestAnimationFrame).then(() => fadeInDialog(this.dialog));
697
+ new Promise(requestAnimationFrame)
698
+ .catch(logger.error)
699
+ .finally(() => fadeInDialog(this.dialog));
677
700
  this.dispatchEvent(new CustomEvent('blotout-wallet-shown', { bubbles: true }));
678
701
  fetch(this.getUrl('/user/event'), {
679
702
  method: 'POST',
@@ -682,7 +705,9 @@ var ProvidersBlotoutWalletSdk = (function () {
682
705
  }).catch(logger.error);
683
706
  }
684
707
  hideModal(action) {
685
- fadeOutToBottom(this.dialog).then(() => { var _a; return (_a = this.dialog) === null || _a === void 0 ? void 0 : _a.close(action); });
708
+ fadeOutToBottom(this.dialog)
709
+ .catch(logger.error)
710
+ .finally(() => { var _a; return (_a = this.dialog) === null || _a === void 0 ? void 0 : _a.close(action); });
686
711
  this.dispatchEvent(new CustomEvent('blotout-wallet-hidden', { bubbles: true }));
687
712
  }
688
713
  getHeaders(json = false) {
@@ -704,18 +729,20 @@ var ProvidersBlotoutWalletSdk = (function () {
704
729
  }
705
730
  async skipCarts() {
706
731
  this.hideModal('skip');
707
- await fetch(this.getUrl('/cart/skip'), {
708
- method: 'POST',
709
- headers: this.getHeaders(),
710
- })
711
- .then(async (response) => {
732
+ try {
733
+ const response = await fetch(this.getUrl('/cart/skip'), {
734
+ method: 'POST',
735
+ headers: this.getHeaders(),
736
+ });
712
737
  if (!response.ok) {
713
738
  throw new Error(`Could not mark cart as skipped - ${response.status}: ${await response.text()}`);
714
739
  }
715
740
  window.edgetag('tag', 'CartRecovery_CartDeclined', {}, {}, { destination: this.edgeURL });
716
741
  this.lastExpiredCart = undefined;
717
- })
718
- .catch(logger.error);
742
+ }
743
+ catch (e) {
744
+ logger.error(e);
745
+ }
719
746
  }
720
747
  render() {
721
748
  if (this.isPopUpDismissed) {
@@ -894,7 +921,7 @@ var ProvidersBlotoutWalletSdk = (function () {
894
921
  ], BlotoutWallet);
895
922
 
896
923
  const init = (params) => {
897
- var _a, _b, _c, _d, _e;
924
+ var _a, _b, _c, _d, _e, _f;
898
925
  if (
899
926
  // if loaded in non-browser SDKs
900
927
  !window ||
@@ -929,6 +956,7 @@ var ProvidersBlotoutWalletSdk = (function () {
929
956
  element.edgeURL = params.baseUrl;
930
957
  element.userId = params.userId;
931
958
  element.restoreRedirect = (_e = params.manifest.variables) === null || _e === void 0 ? void 0 : _e['restoreRedirect'];
959
+ element.silentRestore = ((_f = params.manifest.variables) === null || _f === void 0 ? void 0 : _f['silentRestore']) === '1';
932
960
  document.body.append(element);
933
961
  }
934
962
  };
package/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 customAttributes = {
36
38
  '--bw-primary': { type: 'color', defaultValue: '#000000' },
37
39
  '--bw-title-color': { type: 'color', defaultValue: '#000000' },
@@ -360,31 +362,43 @@ const cssVars = i$4 `
360
362
  }
361
363
  `;
362
364
 
365
+ const isGecko = () => /\bGecko\/\d+/.test(navigator.userAgent);
366
+
363
367
  const fadeInDialog = (element) => {
364
- const dialogAnimation = element.animate([
365
- { transform: 'translateY(-20px)', opacity: 0 },
366
- { transform: 'translateY(0)', opacity: 1 },
367
- ], { duration: 600, easing: spring, composite: 'add' });
368
- const backdropAnimation = element.animate([{ opacity: 0 }, { opacity: 1 }], {
369
- duration: 300,
370
- easing: 'ease-out',
371
- pseudoElement: '::backdrop',
372
- fill: 'forwards',
373
- });
374
- return Promise.all([dialogAnimation.finished, backdropAnimation.finished]);
368
+ const animations = [
369
+ element.animate([
370
+ { transform: 'translateY(-20px)', opacity: 0 },
371
+ { transform: 'translateY(0)', opacity: 1 },
372
+ ], { duration: 600, easing: spring, composite: 'add' }),
373
+ ];
374
+ // Gecko does not support animating ::backdrop pseudo elements
375
+ if (!isGecko()) {
376
+ animations.push(element.animate([{ opacity: 0 }, { opacity: 1 }], {
377
+ duration: 300,
378
+ easing: 'ease-out',
379
+ pseudoElement: '::backdrop',
380
+ fill: 'forwards',
381
+ }));
382
+ }
383
+ return Promise.all(animations.map((anim) => anim.finished));
375
384
  };
376
385
  const fadeOutToBottom = (element) => {
377
- const dialogAnimation = element.animate([
378
- { transform: 'translateY(0)', opacity: 1 },
379
- { transform: 'translateY(20px)', opacity: 0 },
380
- ], { duration: 600, easing: spring });
381
- const backdropAnimation = element.animate([{ opacity: 1 }, { opacity: 0 }], {
382
- duration: 300,
383
- easing: 'ease-out',
384
- pseudoElement: '::backdrop',
385
- fill: 'forwards',
386
- });
387
- return Promise.all([dialogAnimation.finished, backdropAnimation.finished]);
386
+ const animations = [
387
+ element.animate([
388
+ { transform: 'translateY(0)', opacity: 1 },
389
+ { transform: 'translateY(20px)', opacity: 0 },
390
+ ], { duration: 600, easing: spring }),
391
+ ];
392
+ // Gecko does not support animating ::backdrop pseudo elements
393
+ if (!isGecko()) {
394
+ animations.push(element.animate([{ opacity: 1 }, { opacity: 0 }], {
395
+ duration: 300,
396
+ easing: 'ease-out',
397
+ pseudoElement: '::backdrop',
398
+ fill: 'forwards',
399
+ }));
400
+ }
401
+ return Promise.all(animations.map((anim) => anim.finished));
388
402
  };
389
403
  const flipOut = (element) => {
390
404
  const animation = element.animate([
@@ -447,7 +461,6 @@ const formatString = (str) => {
447
461
  const parts = str.split(/<\s*br\s*\/?\s*>/);
448
462
  return o(parts, x `<br />`);
449
463
  };
450
- const delay = (n, resolvedValue) => new Promise((resolve) => setTimeout(() => resolve(resolvedValue), n));
451
464
  let BlotoutWallet = class BlotoutWallet extends s {
452
465
  constructor() {
453
466
  super(...arguments);
@@ -460,78 +473,76 @@ let BlotoutWallet = class BlotoutWallet extends s {
460
473
  .then(() => (this.state = newState))
461
474
  .then(() => flipIn(this.dialog));
462
475
  };
476
+ this.restoreCart = async () => {
477
+ if (!this.lastExpiredCart) {
478
+ return;
479
+ }
480
+ const email = this.email.value.trim().toLowerCase();
481
+ if (email) {
482
+ window.edgetag('user', 'email', email, {}, { destination: this.edgeURL });
483
+ const response = await fetch(this.getUrl('/user/email'), {
484
+ method: 'POST',
485
+ body: JSON.stringify({
486
+ email: email,
487
+ }),
488
+ headers: this.getHeaders(true),
489
+ });
490
+ if (!response.ok) {
491
+ throw new Error(`Could not save email ${response.status}: ${await response.text()}`);
492
+ }
493
+ this.email.value = '';
494
+ this.hasEmail = true;
495
+ this.dispatchEvent(new CustomEvent('blotout-wallet-email-saved', { bubbles: true }));
496
+ window.edgetag('tag', 'CartRecovery_KeepCartEmailSaved', {}, {}, { destination: this.edgeURL });
497
+ }
498
+ await this.storeApi.addItems(this.lastExpiredCart.items);
499
+ const expiredCartId = this.lastExpiredCart.cartId;
500
+ // this cookie will be cleared once the next event is processed
501
+ setCookie(cartTokenLinkCookie, expiredCartId, { path: '/' });
502
+ // We attempt to mark the cart as restored, but if the request fails,
503
+ // we log the error in the console and let the user continue. Since the
504
+ // problem is probably in the `/cart/restore` endpoint, further attempts
505
+ // would not resolve the problem, which would just increase the number
506
+ // of failed calls and not solve the problem.
507
+ const response = await fetch(this.getUrl(`/cart/restore/${expiredCartId}`), {
508
+ method: 'POST',
509
+ headers: this.getHeaders(),
510
+ });
511
+ if (!response.ok) {
512
+ throw new Error(`Could not update status in DB - ${response.status}: ${response.text}\n\n${await response.text()}`);
513
+ }
514
+ this.lastExpiredCart = undefined;
515
+ this.dispatchEvent(new CustomEvent('blotout-wallet-restored', {
516
+ bubbles: true,
517
+ }));
518
+ // Send the request as beacon as there could be a immediate redirect in the next step
519
+ window.edgetag('tag', 'CartRecovery_CartRestored', { isSilent: !!this.silentRestore }, {}, { method: 'beacon' });
520
+ };
463
521
  this.onSubmit = async (ev) => {
464
522
  ev.preventDefault();
465
523
  ev.stopPropagation();
466
- const email = this.email.value.trim().toLowerCase();
467
524
  try {
468
525
  await this.transitionTo('loading');
469
- if (email) {
470
- window.edgetag('user', 'email', email, {}, { destination: this.edgeURL });
471
- const response = await fetch(this.getUrl('/user/email'), {
472
- method: 'POST',
473
- body: JSON.stringify({
474
- email: email,
475
- }),
476
- headers: this.getHeaders(true),
477
- });
478
- if (!response.ok) {
479
- throw new Error(`Could not save email ${response.status}: ${await response.text()}`);
480
- }
481
- this.email.value = '';
482
- this.hasEmail = true;
483
- this.dispatchEvent(new CustomEvent('blotout-wallet-email-saved', { bubbles: true }));
484
- window.edgetag('tag', 'CartRecovery_KeepCartEmailSaved', {}, {}, { destination: this.edgeURL });
485
- }
486
- if (this.lastExpiredCart) {
487
- await this.storeApi.addItems(this.lastExpiredCart.items);
488
- this.dispatchEvent(new CustomEvent('blotout-wallet-restored', {
489
- bubbles: true,
490
- }));
491
- const expiredCartId = this.lastExpiredCart.cartId;
492
- // this cookie will be cleared once the next event is processed
493
- setCookie(cartTokenLinkCookie, expiredCartId, { path: '/' });
494
- // We attempt to mark the cart as restored, but if the request fails,
495
- // we log the error in the console and let the user continue. Since the
496
- // problem is probably in the `/cart/restore` endpoint, further attempts
497
- // would not resolve the problem, which would just increase the number
498
- // of failed calls and not solve the problem.
499
- fetch(this.getUrl(`/cart/restore/${expiredCartId}`), {
500
- method: 'POST',
501
- headers: this.getHeaders(),
502
- })
503
- .then(async (response) => {
504
- if (!response.ok) {
505
- throw new Error(`Could not update status in DB - ${response.status}: ${response.text}\n\n${await response.text()}`);
506
- }
507
- // Send the request as beacon as there could be a immediate redirect in the next step
508
- window.edgetag('tag', 'CartRecovery_CartRestored', {}, {}, { method: 'beacon' });
509
- // Redirect to custom path
510
- if (this.restoreRedirect) {
511
- try {
512
- const redirect = new URL(this.restoreRedirect, window.location.origin);
513
- window.location.href = redirect.href;
514
- }
515
- catch (e) {
516
- console.error('Invalid redirect URL', e);
517
- }
518
- }
519
- })
520
- .catch((err) => {
521
- console.error(err);
522
- });
523
- this.lastExpiredCart = undefined;
524
- }
526
+ await this.restoreCart();
525
527
  await this.transitionTo('restored');
526
- delay(2000).then(() => {
527
- if (this.state == 'restored') {
528
- this.hideModal('restore');
528
+ await delay(2000);
529
+ if (this.state == 'restored') {
530
+ this.hideModal('restore');
531
+ }
532
+ // Redirect to custom path
533
+ if (this.restoreRedirect) {
534
+ try {
535
+ const redirect = new URL(this.restoreRedirect, window.location.origin);
536
+ window.location.href = redirect.href;
529
537
  }
530
- });
538
+ catch (e) {
539
+ console.error('Invalid redirect URL', e);
540
+ }
541
+ }
531
542
  }
532
543
  catch (e) {
533
- await this.transitionTo('failed');
534
544
  logger.error(e);
545
+ await this.transitionTo('failed');
535
546
  }
536
547
  };
537
548
  this.onDialogClick = () => {
@@ -641,6 +652,7 @@ let BlotoutWallet = class BlotoutWallet extends s {
641
652
  }
642
653
  }
643
654
  async initialize() {
655
+ var _a;
644
656
  if (!this.userId) {
645
657
  logger.error('No UserId set');
646
658
  return;
@@ -649,11 +661,11 @@ let BlotoutWallet = class BlotoutWallet extends s {
649
661
  return;
650
662
  }
651
663
  await delay(POPUP_IMPRESSION_DELAY);
652
- fetch(this.getUrl('/cart/expired'), {
653
- method: 'GET',
654
- headers: this.getHeaders(),
655
- })
656
- .then(async (response) => {
664
+ try {
665
+ const response = await fetch(this.getUrl('/cart/expired'), {
666
+ method: 'GET',
667
+ headers: this.getHeaders(),
668
+ });
657
669
  if (!response.ok) {
658
670
  throw new Error(`Unable to get Expired Cart ${response.status}: ${await response.text()}`);
659
671
  }
@@ -661,16 +673,27 @@ let BlotoutWallet = class BlotoutWallet extends s {
661
673
  const result = await response.json();
662
674
  this.hasEmail = result.email;
663
675
  this.lastExpiredCart = result.carts[0];
664
- if (result.carts && result.carts.length && !this.isPopUpDismissed) {
665
- this.showModal();
666
- window.edgetag('tag', 'CartRecovery_CartExpiredOnVisit', {}, {}, { destination: this.edgeURL });
676
+ if ((_a = result.carts) === null || _a === void 0 ? void 0 : _a.length) {
677
+ if (this.silentRestore) {
678
+ this.restoreCart().catch(logger.error);
679
+ }
680
+ else if (!this.isPopUpDismissed) {
681
+ this.showModal();
682
+ }
683
+ if (result.hasJustExpired) {
684
+ window.edgetag('tag', 'CartRecovery_CartExpiredOnVisit', {}, {}, { destination: this.edgeURL });
685
+ }
667
686
  }
668
- })
669
- .catch(logger.error);
687
+ }
688
+ catch (err) {
689
+ logger.error(err);
690
+ }
670
691
  }
671
692
  showModal() {
672
693
  this.dialog.showModal();
673
- new Promise(requestAnimationFrame).then(() => fadeInDialog(this.dialog));
694
+ new Promise(requestAnimationFrame)
695
+ .catch(logger.error)
696
+ .finally(() => fadeInDialog(this.dialog));
674
697
  this.dispatchEvent(new CustomEvent('blotout-wallet-shown', { bubbles: true }));
675
698
  fetch(this.getUrl('/user/event'), {
676
699
  method: 'POST',
@@ -679,7 +702,9 @@ let BlotoutWallet = class BlotoutWallet extends s {
679
702
  }).catch(logger.error);
680
703
  }
681
704
  hideModal(action) {
682
- fadeOutToBottom(this.dialog).then(() => { var _a; return (_a = this.dialog) === null || _a === void 0 ? void 0 : _a.close(action); });
705
+ fadeOutToBottom(this.dialog)
706
+ .catch(logger.error)
707
+ .finally(() => { var _a; return (_a = this.dialog) === null || _a === void 0 ? void 0 : _a.close(action); });
683
708
  this.dispatchEvent(new CustomEvent('blotout-wallet-hidden', { bubbles: true }));
684
709
  }
685
710
  getHeaders(json = false) {
@@ -701,18 +726,20 @@ let BlotoutWallet = class BlotoutWallet extends s {
701
726
  }
702
727
  async skipCarts() {
703
728
  this.hideModal('skip');
704
- await fetch(this.getUrl('/cart/skip'), {
705
- method: 'POST',
706
- headers: this.getHeaders(),
707
- })
708
- .then(async (response) => {
729
+ try {
730
+ const response = await fetch(this.getUrl('/cart/skip'), {
731
+ method: 'POST',
732
+ headers: this.getHeaders(),
733
+ });
709
734
  if (!response.ok) {
710
735
  throw new Error(`Could not mark cart as skipped - ${response.status}: ${await response.text()}`);
711
736
  }
712
737
  window.edgetag('tag', 'CartRecovery_CartDeclined', {}, {}, { destination: this.edgeURL });
713
738
  this.lastExpiredCart = undefined;
714
- })
715
- .catch(logger.error);
739
+ }
740
+ catch (e) {
741
+ logger.error(e);
742
+ }
716
743
  }
717
744
  render() {
718
745
  if (this.isPopUpDismissed) {
@@ -891,7 +918,7 @@ BlotoutWallet = __decorate([
891
918
  ], BlotoutWallet);
892
919
 
893
920
  const init = (params) => {
894
- var _a, _b, _c, _d, _e;
921
+ var _a, _b, _c, _d, _e, _f;
895
922
  if (
896
923
  // if loaded in non-browser SDKs
897
924
  !window ||
@@ -926,6 +953,7 @@ const init = (params) => {
926
953
  element.edgeURL = params.baseUrl;
927
954
  element.userId = params.userId;
928
955
  element.restoreRedirect = (_e = params.manifest.variables) === null || _e === void 0 ? void 0 : _e['restoreRedirect'];
956
+ element.silentRestore = ((_f = params.manifest.variables) === null || _f === void 0 ? void 0 : _f['silentRestore']) === '1';
929
957
  document.body.append(element);
930
958
  }
931
959
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotoutio/providers-blotout-wallet-sdk",
3
- "version": "0.61.0",
3
+ "version": "0.62.0",
4
4
  "description": "Blotout Wallet SDK for EdgeTag",
5
5
  "author": "Blotout",
6
6
  "license": "MIT",