@doenet/v06-to-v07 0.7.24-dev.496 → 0.7.24-dev.498

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.
@@ -45857,7 +45857,7 @@ async function cidFromArrayBuffer(data) {
45857
45857
  await crypto.subtle.digest("SHA-256", new Uint8Array());
45858
45858
  digest = (data2) => crypto.subtle.digest("SHA-256", data2);
45859
45859
  } catch (e22) {
45860
- const sha256 = (await import("./sha256-DT5xJ2Hv-CN9l-ne8-DSzmsKLe.js").then((n2) => n2.s)).default;
45860
+ const sha256 = (await import("./sha256-DT5xJ2Hv-DQlQsFFB-CzLWg3kc.js").then((n2) => n2.s)).default;
45861
45861
  digest = (data2) => sha256(data2, {
45862
45862
  asBytes: true
45863
45863
  });
@@ -70713,6 +70713,9 @@ class StatePersistence {
70713
70713
  this.saveDocStateTimeoutID = null;
70714
70714
  this.docStateToBeSavedToDatabase = null;
70715
70715
  this.changesToBeSaved = false;
70716
+ this.scoreToBeSavedToDatabase = 0;
70717
+ this._saveSequence = 0;
70718
+ this._storedSequence = 0;
70716
70719
  }
70717
70720
  /**
70718
70721
  * Cancel any pending saves and clear the buffered payload. Called from
@@ -70729,7 +70732,9 @@ class StatePersistence {
70729
70732
  this.saveDocStateTimeoutID = null;
70730
70733
  }
70731
70734
  this.docStateToBeSavedToDatabase = null;
70735
+ this.scoreToBeSavedToDatabase = 0;
70732
70736
  this.changesToBeSaved = false;
70737
+ this._storedSequence = ++this._saveSequence;
70733
70738
  }
70734
70739
  /**
70735
70740
  * Schedule a debounced `saveState` after `delayMs` milliseconds, replacing
@@ -70794,7 +70799,18 @@ class StatePersistence {
70794
70799
  if (!core2.flags.allowSaveState && !core2.flags.allowLocalState) {
70795
70800
  return;
70796
70801
  }
70802
+ const sequence = ++this._saveSequence;
70797
70803
  const { payload, coreStateString, rendererStateString } = this.buildDocStatePayload(onSubmission);
70804
+ const score = core2.flags.allowSaveState ? await core2.document.stateValues.creditAchieved : 0;
70805
+ if (!this._claimSave(sequence)) {
70806
+ await this._standDownSupersededSave(overrideThrottle, onSubmission);
70807
+ return;
70808
+ }
70809
+ if (core2.flags.allowSaveState) {
70810
+ this.docStateToBeSavedToDatabase = payload;
70811
+ this.scoreToBeSavedToDatabase = score;
70812
+ this.changesToBeSaved = true;
70813
+ }
70798
70814
  if (core2.flags.allowLocalState) {
70799
70815
  await set(
70800
70816
  `${core2.activityId}|${core2.docId}|${core2.attemptNumber}|${core2.cid}`,
@@ -70805,11 +70821,54 @@ class StatePersistence {
70805
70821
  coreInfo: core2.coreInfoString
70806
70822
  }
70807
70823
  );
70824
+ if (!this._claimSave(sequence)) {
70825
+ await this._standDownSupersededSave(
70826
+ overrideThrottle,
70827
+ onSubmission
70828
+ );
70829
+ return;
70830
+ }
70808
70831
  }
70809
70832
  if (!core2.flags.allowSaveState) {
70810
70833
  return;
70811
70834
  }
70812
- this.docStateToBeSavedToDatabase = payload;
70835
+ await this.saveChangesToDatabase(overrideThrottle);
70836
+ }
70837
+ /**
70838
+ * Whether this save is still the newest to have got this far, taking the
70839
+ * claim if so. A claim is only good until the next await, so a save that
70840
+ * yields after taking one has to take it again on the far side.
70841
+ */
70842
+ _claimSave(sequence) {
70843
+ if (sequence < this._storedSequence) {
70844
+ return false;
70845
+ }
70846
+ this._storedSequence = sequence;
70847
+ return true;
70848
+ }
70849
+ /**
70850
+ * Give up on a save that a later one overtook — while it resolved its
70851
+ * score, or while it wrote local state — without giving up what only
70852
+ * *this* save knew.
70853
+ *
70854
+ * The work itself is not lost: the save that overtook it was built later,
70855
+ * so the pair now stored holds at least as much. What does not survive the
70856
+ * hand-off is why this save was made. A submission's save says a
70857
+ * submission happened and overrides the 60-second throttle so the host
70858
+ * hears about it now; an ordinary save that overtook it does neither, and
70859
+ * simply returning here would leave a graded answer sitting behind the
70860
+ * throttle as an unreported mirror.
70861
+ */
70862
+ async _standDownSupersededSave(overrideThrottle, onSubmission) {
70863
+ if (!this.docStateToBeSavedToDatabase) {
70864
+ return;
70865
+ }
70866
+ if (onSubmission) {
70867
+ this.docStateToBeSavedToDatabase.onSubmission = true;
70868
+ }
70869
+ if (!overrideThrottle && !onSubmission) {
70870
+ return;
70871
+ }
70813
70872
  this.changesToBeSaved = true;
70814
70873
  await this.saveChangesToDatabase(overrideThrottle);
70815
70874
  }
@@ -70833,6 +70892,41 @@ class StatePersistence {
70833
70892
  await this.saveImmediately();
70834
70893
  return true;
70835
70894
  }
70895
+ /**
70896
+ * Hand the currently buffered database payload to the main realm through
70897
+ * `reportScoreAndStateCallback`.
70898
+ *
70899
+ * With `pending: true` this is a *mirror* of the payload the 60-second
70900
+ * throttle is holding back, not a report for the host to save
70901
+ * (Doenet/DoenetML#1726). A page can go away without the viewer
70902
+ * unmounting — the tab is closed, a new URL is typed, a backgrounded
70903
+ * mobile tab is discarded — and `pagehide` offers no budget for a Comlink
70904
+ * round-trip into this worker, so the payload has to already be over
70905
+ * there. `DocViewer` buffers a `pending` report rather than handing it to
70906
+ * the host, and delivers it as an ordinary report when the page hides.
70907
+ *
70908
+ * A mirror goes out on every throttled save, so it is never further behind
70909
+ * the screen than the one-second save debounce. Any real report that
70910
+ * follows (throttle expiry, submission, `SPLICE.flushState`, the
70911
+ * `saveImmediately` in `terminate`) carries the same or newer state and
70912
+ * supersedes it.
70913
+ *
70914
+ * The pair it sends was captured together by the `saveState` that built
70915
+ * it, so this needs no `await` and cannot interleave with anything: the
70916
+ * score always belongs to the payload beside it, and a page hide is never
70917
+ * handed a reader's state under a credit from the wrong side of it.
70918
+ */
70919
+ _reportStateToMainRealm(pending) {
70920
+ const payload = this.docStateToBeSavedToDatabase;
70921
+ if (!payload) {
70922
+ return;
70923
+ }
70924
+ this.core.reportScoreAndStateCallback({
70925
+ state: { ...payload },
70926
+ score: this.scoreToBeSavedToDatabase,
70927
+ pending
70928
+ });
70929
+ }
70836
70930
  async saveChangesToDatabase(overrideThrottle = false) {
70837
70931
  if (!this.changesToBeSaved) {
70838
70932
  return;
@@ -70841,6 +70935,7 @@ class StatePersistence {
70841
70935
  if (overrideThrottle) {
70842
70936
  clearTimeout(this.saveStateToDBTimerId);
70843
70937
  } else {
70938
+ this._reportStateToMainRealm(true);
70844
70939
  return;
70845
70940
  }
70846
70941
  }
@@ -70851,11 +70946,7 @@ class StatePersistence {
70851
70946
  reportTimerError(TimerLabels.throttledSaveChanges)
70852
70947
  );
70853
70948
  }, 6e4);
70854
- this.core.reportScoreAndStateCallback({
70855
- state: { ...this.docStateToBeSavedToDatabase },
70856
- score: await this.core.document.stateValues.creditAchieved
70857
- });
70858
- return;
70949
+ this._reportStateToMainRealm(false);
70859
70950
  }
70860
70951
  }
70861
70952
  class StateVariableEvaluator {
@@ -237361,4 +237452,4 @@ export {
237361
237452
  getDefaultExportFromCjs$1 as g,
237362
237453
  updateSyntaxFromV06toV07 as u
237363
237454
  };
237364
- //# sourceMappingURL=index-Co6vf-pO.js.map
237455
+ //# sourceMappingURL=index-CMbGEQt0.js.map