@jsenv/navi 0.30.25 → 0.30.26

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.
@@ -3752,6 +3752,7 @@ ${lines.join("\n")}`);
3752
3752
 
3753
3753
  const actionToRunPrivateProperties =
3754
3754
  getActionPrivateProperties(actionToPrerunOrRun);
3755
+ actionToRunPrivateProperties.answeredAsync = false;
3755
3756
  let performRunResult;
3756
3757
  try {
3757
3758
  performRunResult = actionToRunPrivateProperties.performRun({
@@ -3776,6 +3777,7 @@ ${lines.join("\n")}`);
3776
3777
  activationWeakSet.add(actionToPrerunOrRun);
3777
3778
 
3778
3779
  if (performRunResult && typeof performRunResult.then === "function") {
3780
+ actionToRunPrivateProperties.answeredAsync = true;
3779
3781
  actionPromiseMap.set(actionToPrerunOrRun, performRunResult);
3780
3782
  allThenableArray.push(performRunResult);
3781
3783
  hasAsync = true;
@@ -3805,7 +3807,9 @@ ${lines.join("\n")}`);
3805
3807
 
3806
3808
  // Execute promotions (prerun -> run requested)
3807
3809
  for (const actionToPromote of willPromoteSet) {
3808
- actionToPromote.isPrerunSignal.value = false;
3810
+ writeActionState(() => {
3811
+ actionToPromote.isPrerunSignal.value = false;
3812
+ });
3809
3813
  }
3810
3814
  }
3811
3815
 
@@ -3814,13 +3818,21 @@ ${lines.join("\n")}`);
3814
3818
  // that IS carrying it. `await action.run()` then means the same thing to
3815
3819
  // every caller: the second one waits for the first one's request and reads
3816
3820
  // the same data, instead of being handed `undefined` before the network has
3817
- // said anything. See the run() JSDoc.
3821
+ // said anything. It answers in the tense of that run: the answer of a run
3822
+ // that answered with a promise comes back as one, so `run().catch()` holds
3823
+ // whatever state the instance is in. See the run() JSDoc.
3818
3824
  {
3819
3825
  for (const actionToJoin of willJoinSet) {
3820
3826
  const runningPromise = actionPromiseMap.get(actionToJoin);
3821
3827
  if (runningPromise) {
3822
3828
  hasAsync = true;
3823
3829
  resultArray.push({ type: "async", promise: runningPromise });
3830
+ } else if (getActionPrivateProperties(actionToJoin).answeredAsync) {
3831
+ hasAsync = true;
3832
+ resultArray.push({
3833
+ type: "async",
3834
+ promise: Promise.resolve(actionToJoin.dataSignal.peek()),
3835
+ });
3824
3836
  } else {
3825
3837
  resultArray.push({
3826
3838
  type: "sync",
@@ -4065,6 +4077,10 @@ const createAction = (callback, rootOptions = {}) => {
4065
4077
  * the one that asked first or the one that arrived while the request was
4066
4078
  * out. Use `rerun()` to force a fresh run ("refresh", "check now", any
4067
4079
  * explicit user intent to go back to the network).
4080
+ *
4081
+ * An asynchronous callback answers with a promise, joined or not:
4082
+ * `ACTION.run().catch(…)` holds in every state. A synchronous one answers
4083
+ * synchronously, and throws its failure.
4068
4084
  */
4069
4085
  const run = (options) => {
4070
4086
  action.debug(`${action}.run(${stringifyForDisplay(options)})`);
@@ -4524,7 +4540,9 @@ const createAction = (callback, rootOptions = {}) => {
4524
4540
  // another run's, or idle.
4525
4541
  return;
4526
4542
  }
4527
- runningStateSignal.value = ABORTED;
4543
+ writeActionState(() => {
4544
+ runningStateSignal.value = ABORTED;
4545
+ });
4528
4546
  internalAbortController.abort(abortReason);
4529
4547
  actionAbortMap.delete(action);
4530
4548
  if (isPrerun && (globalAbortSignal.aborted || abortSignal.aborted)) {
@@ -4551,7 +4569,7 @@ const createAction = (callback, rootOptions = {}) => {
4551
4569
 
4552
4570
  actionAbortMap.set(action, abort);
4553
4571
 
4554
- batch(() => {
4572
+ writeActionState(() => {
4555
4573
  if (valueSignal.peek() === undefined) {
4556
4574
  // An action saying nothing of its own may still have a value the
4557
4575
  // page kept from the previous document (see kept_values.js).
@@ -4630,7 +4648,7 @@ const createAction = (callback, rootOptions = {}) => {
4630
4648
  * before the UI attempts to render the now-missing resource.
4631
4649
  */
4632
4650
 
4633
- batch(() => {
4651
+ writeActionState(() => {
4634
4652
  const value = resultToValue
4635
4653
  ? resultToValue(runResult, action)
4636
4654
  : runResult;
@@ -4662,7 +4680,9 @@ const createAction = (callback, rootOptions = {}) => {
4662
4680
  error === internalAbortSignal.reason) ||
4663
4681
  error.name === "AbortError";
4664
4682
  if (isAbort) {
4665
- runningStateSignal.value = ABORTED;
4683
+ writeActionState(() => {
4684
+ runningStateSignal.value = ABORTED;
4685
+ });
4666
4686
  if (isPrerun && abortSignal.aborted) {
4667
4687
  prerunProtectionRegistry.unprotect(action);
4668
4688
  }
@@ -4676,7 +4696,7 @@ const createAction = (callback, rootOptions = {}) => {
4676
4696
  if (isPrerun) {
4677
4697
  markErrorAsPrerunFailure(error);
4678
4698
  }
4679
- batch(() => {
4699
+ writeActionState(() => {
4680
4700
  errorSignal.value = error;
4681
4701
  runningStateSignal.value = FAILED;
4682
4702
  onError?.(error, { event, action, args });
@@ -4771,7 +4791,7 @@ const createAction = (callback, rootOptions = {}) => {
4771
4791
  }
4772
4792
 
4773
4793
  actionPromiseMap.delete(action);
4774
- batch(() => {
4794
+ writeActionState(() => {
4775
4795
  if (!willRunOrPrerun) {
4776
4796
  errorSignal.value = undefined;
4777
4797
  valueSignal.value = valueInitial;
@@ -4789,6 +4809,9 @@ const createAction = (callback, rootOptions = {}) => {
4789
4809
  provisionalValue,
4790
4810
  inheritData,
4791
4811
  keepsAnswers: keptAnswerRegistry !== null,
4812
+ // Whether the last run answered with a promise, written by
4813
+ // updateActions: the tense a run joining this instance answers in.
4814
+ answeredAsync: false,
4792
4815
 
4793
4816
  performRun,
4794
4817
  performReset,
@@ -5272,6 +5295,35 @@ const isPlainObject$2 = (obj) => {
5272
5295
  );
5273
5296
  };
5274
5297
 
5298
+ // Every state write of a run (start, end, failure, abort, reset), batched. At
5299
+ // the end of the batch preact runs the effects those writes woke up, anywhere
5300
+ // in the app, and rethrows the first one that threw: from there it would fail
5301
+ // this run, or leave it RUNNING, or stop the update half way. That throw is
5302
+ // the effect's, so it is reported on its own, as action_error_report.js
5303
+ // reports an error (thrown from a timer), and the action carries on. What
5304
+ // `write` throws (resultToValue, onComplete…) is the run's, and goes on.
5305
+ const writeActionState = (write) => {
5306
+ let writeThrew = false;
5307
+ let writeError;
5308
+ try {
5309
+ batch(() => {
5310
+ try {
5311
+ write();
5312
+ } catch (e) {
5313
+ writeThrew = true;
5314
+ writeError = e;
5315
+ }
5316
+ });
5317
+ } catch (effectError) {
5318
+ setTimeout(() => {
5319
+ throw effectError;
5320
+ });
5321
+ }
5322
+ if (writeThrew) {
5323
+ throw writeError;
5324
+ }
5325
+ };
5326
+
5275
5327
  /**
5276
5328
  * Reactively runs an action whenever the params derived from signals change.
5277
5329
  *