@internetarchive/ia-book-actions 1.4.4-alpha7 → 1.4.4-alpha8

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/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "author": "Internet Archive",
9
9
  "license": "AGPL-3.0-only",
10
- "version": "1.4.4-alpha7",
10
+ "version": "1.4.4-alpha8",
11
11
  "main": "index.js",
12
12
  "module": "index.js",
13
13
  "publishConfig": {
@@ -172,7 +172,7 @@ export default class ActionsHandler extends LitElement {
172
172
  action,
173
173
  identifier: this.identifier,
174
174
  success: async data => {
175
- log('RENEW_LOAN --- ', data, action, data.loan, this.identifier);
175
+ log('RENEW_LOAN --- ', data, this.identifier);
176
176
  const activeLoan = data.loan ? data.loan : undefined;
177
177
  const isRenewal = activeLoan.renewal;
178
178
 
@@ -60,6 +60,7 @@ export default class IABookActions extends LitElement {
60
60
  disableActionGroup: { type: Boolean },
61
61
  modal: { Object },
62
62
  tokenDelay: { type: Number },
63
+ tokenPollerRenewalDelay: { type: Number },
63
64
  timerExecutionSeconds: { type: Number },
64
65
  localCache: { type: Object },
65
66
  loanRenewTimeConfig: { type: Object },
@@ -105,6 +106,16 @@ export default class IABookActions extends LitElement {
105
106
  */
106
107
  this.recoveringFromLoanExpiry = false;
107
108
 
109
+ /**
110
+ * Buffer (ms) before the first create_token call that follows a
111
+ * confirmed recovery renewal — Lending::do_renew() (backend) deletes
112
+ * the old loan and writes a brand-new one to the datanode storage, so
113
+ * create_token's lookup can otherwise race that write's propagation.
114
+ * Exposed as a property (rather than a hardcoded constant) so it's
115
+ * configurable per-deployment and overridable to 0 in tests.
116
+ */
117
+ this.tokenPollerRenewalDelay = 2000;
118
+
108
119
  this.warningModalOpen = false;
109
120
 
110
121
  /**
@@ -311,8 +322,23 @@ export default class IABookActions extends LitElement {
311
322
  !hasExpired &&
312
323
  !this.loanRenewInProgress &&
313
324
  !window.IALendingIntervals.tokenPoller
314
- )
315
- this.startLoanTokenPoller();
325
+ ) {
326
+ // Lending::do_renew() (backend) doesn't extend the existing loan —
327
+ // it DELETES it and writes a brand-new loan record to the datanode
328
+ // storage. create_token's lookup for that record can race the
329
+ // write's propagation and come back empty ("you do not currently
330
+ // have this book borrowed"), even though the renewal that was just
331
+ // confirmed genuinely succeeded moments earlier. Give the write a
332
+ // moment to settle before the first create_token call that follows
333
+ // a real recovery — same underlying datanode-propagation concern
334
+ // the existing 50-second buffer in loanRenewAttempt() guards
335
+ // against for the routine renewal path.
336
+ const tokenPollerDelay = this.recoveringFromLoanExpiry
337
+ ? this.tokenPollerRenewalDelay
338
+ : 0;
339
+ this.recoveringFromLoanExpiry = false;
340
+ setTimeout(() => this.startLoanTokenPoller(), tokenPollerDelay);
341
+ }
316
342
  }, 100);
317
343
 
318
344
  this.requestUpdate();
@@ -717,8 +743,10 @@ export default class IABookActions extends LitElement {
717
743
  // the still-expired record). loanRenewInProgress already kept the
718
744
  // token poller from restarting early, so it'll pick up fresh here
719
745
  // once lendingStatus below re-triggers setupLendingToolbarActions().
746
+ // NOTE: recoveringFromLoanExpiry itself is consumed/reset there,
747
+ // not here — it decides whether that restart needs a datanode
748
+ // propagation buffer (see setupLendingToolbarActions).
720
749
  this.postInitComplete = false;
721
- this.recoveringFromLoanExpiry = false;
722
750
  }
723
751
 
724
752
  const currStatus = {
@@ -660,6 +660,9 @@ describe('autoRenewExpiredLoan', () => {
660
660
  })
661
661
  );
662
662
  await el.updateComplete;
663
+ // Not testing the post-confirmation token-poller delay here — avoid
664
+ // leaving a real multi-second timer dangling past this test.
665
+ el.tokenPollerRenewalDelay = 0;
663
666
 
664
667
  await el.localCache.set({
665
668
  key: 'foobar-loanTime',
@@ -709,6 +712,9 @@ describe('autoRenewExpiredLoan', () => {
709
712
  await el.updateComplete;
710
713
  el.postInitComplete = true;
711
714
  el.lendingBarPostInit = Sinon.spy();
715
+ // Use a small but non-zero delay to keep this test fast while still
716
+ // exercising the same "wait, then restart the poller" code path.
717
+ el.tokenPollerRenewalDelay = 50;
712
718
 
713
719
  await el.localCache.set({
714
720
  key: 'foobar-loanTime',
@@ -734,7 +740,10 @@ describe('autoRenewExpiredLoan', () => {
734
740
  })
735
741
  );
736
742
 
737
- await aTimeout(100);
743
+ // The post-confirmation token-poller restart is deliberately delayed
744
+ // (datanode write-propagation buffer — see setupLendingToolbarActions)
745
+ // before the recovery case's first create_token call.
746
+ await aTimeout(250);
738
747
  await el.updateComplete;
739
748
 
740
749
  // The confirmed renewal must have forced a fresh create_token cycle
@@ -772,6 +781,10 @@ describe('autoRenewExpiredLoan', () => {
772
781
  ttl: 3600,
773
782
  });
774
783
 
784
+ // Use a small but non-zero delay to keep this test fast while still
785
+ // exercising the same "wait, then restart the poller" code path.
786
+ el.tokenPollerRenewalDelay = 50;
787
+
775
788
  const startTokenPollerSpy = Sinon.spy(el, 'startLoanTokenPoller');
776
789
 
777
790
  el.autoRenewExpiredLoan();
@@ -790,7 +803,9 @@ describe('autoRenewExpiredLoan', () => {
790
803
  })
791
804
  );
792
805
 
793
- await aTimeout(200);
806
+ // The post-confirmation restart is deliberately delayed (datanode
807
+ // write-propagation buffer — see setupLendingToolbarActions).
808
+ await aTimeout(250);
794
809
  await el.updateComplete;
795
810
 
796
811
  expect(startTokenPollerSpy.calledOnce).to.be.true;