@jsenv/navi 0.30.10 → 0.30.12

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.
@@ -3729,6 +3729,7 @@ const actionWeakMap = new WeakMap();
3729
3729
  * long is this still true?" belongs to the question: a court list is good for
3730
3730
  * the session, a count of people watching grows on its own and is worth a few
3731
3731
  * minutes, a payment status is worth nothing at all.
3732
+ * A resource declares it for its reads: `resource()`'s `keep`.
3732
3733
  * @param {Array<Object | { resource: Object, on: string[] }> | (() => Array<Object | { resource: Object, on: string[] }>)} [rootOptions.dependencies] -
3733
3734
  * the resources whose writes make the answer out of date — a count, a
3734
3735
  * summary, anything read that is no row of a resource. After a listed write
@@ -4302,9 +4303,10 @@ const createAction = (callback, rootOptions = {}) => {
4302
4303
  }
4303
4304
  }
4304
4305
  runningStateSignal.value = RUNNING;
4305
- if (!isPrerun) {
4306
- isPrerunSignal.value = false;
4307
- }
4306
+ // What fills the instance says what it holds: an answer only a
4307
+ // prerun asked for is one nothing on screen has read yet, and the
4308
+ // run that asks for it next is promoted onto it (see updateActions).
4309
+ isPrerunSignal.value = isPrerun;
4308
4310
  });
4309
4311
 
4310
4312
  const args = [];
@@ -5106,10 +5108,16 @@ const actionRunEffect = (
5106
5108
  runUnwatched(() =>
5107
5109
  actionTarget.run({ reason: "params restored from falsy state" }),
5108
5110
  );
5109
- } else if (getActionPrivateProperties(actionTarget).keepsAnswers) {
5111
+ } else if (
5112
+ getActionPrivateProperties(actionTarget).keepsAnswers ||
5113
+ actionTarget.isPrerunSignal.peek()
5114
+ ) {
5110
5115
  // The lookup that moved the binding here already reset an answer
5111
5116
  // older than its `keep`: what the instance holds is still good, and
5112
- // a prerun still out is joined rather than asked again.
5117
+ // a prerun still out is joined rather than asked again. So is an
5118
+ // answer only a prerun asked for, kept or not: asked ahead for this
5119
+ // very arrival (a <RouteTravel prefetch> neighbour), nothing has read
5120
+ // it yet, and the run promotes it.
5113
5121
  runUnwatched(() => actionTarget.run({ reason: "params modified" }));
5114
5122
  } else {
5115
5123
  runUnwatched(() => actionTarget.rerun({ reason: "params modified" }));
@@ -28108,6 +28116,16 @@ const createResourceLifecycleManager = () => {
28108
28116
  }
28109
28117
  }
28110
28118
 
28119
+ // A head start the write made stale is dropped, not asked again: nothing
28120
+ // on screen reads it, and its owner, finding it idle, asks on arriving
28121
+ // instead of promoting what left before the write.
28122
+ for (const action of actionsToRerun) {
28123
+ if (action.isPrerunSignal.peek()) {
28124
+ actionsToRerun.delete(action);
28125
+ actionsToReset.add(action);
28126
+ }
28127
+ }
28128
+
28111
28129
  return {
28112
28130
  actionsToRerun,
28113
28131
  actionsToReset,
@@ -28195,9 +28213,8 @@ const createResourceLifecycleManager = () => {
28195
28213
  // A read to ask again after a write: answered before it landed, or still out —
28196
28214
  // an answer that left before the write is as stale as a completed one, and
28197
28215
  // would replace what the write put in the store (a rerun aborts it and asks
28198
- // again). A head start is its owner's to ask.
28216
+ // again). A head start is its owner's to ask (findEffectOnActions resets it).
28199
28217
  const isAnsweredOrAsking = (action, triggeringAction) =>
28200
- !action.isPrerun &&
28201
28218
  (action.completed || action.runningState === RUNNING) &&
28202
28219
  action !== triggeringAction;
28203
28220
  // A write named in `writes` says for itself which reads of its own resource it
@@ -28955,7 +28972,7 @@ const debug$2 = (...args) => {
28955
28972
  * "What a read shows while its params move").
28956
28973
  *
28957
28974
  * @param {string} name - resource name, used in action names and error messages
28958
- * @param {Object} restCallbacks - `{ idKey, uniqueKeys, rerunOn, dependencies, persist, writes, GET, GET_MANY, GET_RANGE, POST, POST_MANY, PUT, PUT_MANY, PATCH, PATCH_MANY, DELETE, DELETE_MANY }`
28975
+ * @param {Object} restCallbacks - `{ idKey, uniqueKeys, rerunOn, keep, dependencies, persist, writes, GET, GET_MANY, GET_RANGE, POST, POST_MANY, PUT, PUT_MANY, PATCH, PATCH_MANY, DELETE, DELETE_MANY }`
28959
28976
  * @param {string} [restCallbacks.idKey] - primary key property, defaults to `"id"`
28960
28977
  * @param {string[]} [restCallbacks.uniqueKeys] - alternate keys the store can find an item by (e.g. `"username"`)
28961
28978
  * @param {Array<Object | { resource: Object, on?: string[], reads?: Array<"GET" | "GET_MANY" | "GET_RANGE"> }> | (() => Array<Object | { resource: Object, on?: string[], reads?: Array<"GET" | "GET_MANY" | "GET_RANGE"> }>)} [restCallbacks.dependencies] -
@@ -28979,6 +28996,22 @@ const debug$2 = (...args) => {
28979
28996
  * follows `rerunOn` for its verb. A name a verb takes, or one the resource
28980
28997
  * already exposes (`withParams`, `store`…), throws. A `.scopedOne()` or
28981
28998
  * `.scopedMany()` takes `writes` too, `.scopedMany()` with the plural verbs.
28999
+ * @param {{ GET?: { ms?: number, max?: number }, GET_MANY?: { ms?: number, max?: number } }} [restCallbacks.keep] -
29000
+ * how long an answer of a read is trusted, coming back to the same params
29001
+ * within `ms` asking nothing. Left out, coming back asks again: the right
29002
+ * default for anything that moves on its own (a count of registrations), and
29003
+ * worth declaring for what barely does (a description, a finished
29004
+ * tournament). The store keeps the rows either way, and a `GET` draws the row
29005
+ * it holds while its request is out, so a kept answer and a fresh one look
29006
+ * alike: what `keep` saves is the request. Keyed by read, so a list can be
29007
+ * trusted for less time than an item. The rules are createAction's `keep`:
29008
+ * `ms` counts from the moment the answer landed, `max` caps the answers held
29009
+ * at once (the least recently looked-at going first), and past either the
29010
+ * read is asked again. A write that reruns the read (`rerunOn`,
29011
+ * `dependencies`) reruns a kept answer too, and the new one counts its `ms`
29012
+ * again. A `withParams()` scope keeps as its resource does, `max` counted per
29013
+ * scope; the reads of a relation are questions of their own and keep
29014
+ * nothing. `GET_RANGE` throws: a range reader holds no answer to keep.
28982
29015
  * @param {{ signal: import("@preact/signals").Signal, when?: () => boolean }} [restCallbacks.persist] -
28983
29016
  * mirrors the rows `GET` lands with into `signal` — a `stateSignal` with
28984
29017
  * `persists: true` and `type: "object"` keeps them across a reload, whose
@@ -29019,6 +29052,7 @@ const resource = (name, restCallbacks = {}) => {
29019
29052
  idKey = "id",
29020
29053
  uniqueKeys = [],
29021
29054
  rerunOn,
29055
+ keep,
29022
29056
  dependencies,
29023
29057
  persist,
29024
29058
  writes,
@@ -29035,6 +29069,9 @@ const resource = (name, restCallbacks = {}) => {
29035
29069
  DELETE,
29036
29070
  DELETE_MANY,
29037
29071
  } = restCallbacks;
29072
+ if (keep) {
29073
+ assertKeepNamesReads(name, keep);
29074
+ }
29038
29075
  const declarationSite = getDeclarationSite();
29039
29076
  const setupCallbackSet = new Set();
29040
29077
  const addItemSetup = (callback) => {
@@ -29159,6 +29196,7 @@ const resource = (name, restCallbacks = {}) => {
29159
29196
  findItemForGet,
29160
29197
  persistence,
29161
29198
  declarationSite,
29199
+ keep,
29162
29200
  });
29163
29201
  return createResource(name, {
29164
29202
  idKey,
@@ -30486,6 +30524,7 @@ const createRestActionFactoryForRoot = (
30486
30524
  findItemForGet,
30487
30525
  persistence,
30488
30526
  declarationSite,
30527
+ keep = {},
30489
30528
  },
30490
30529
  ) => {
30491
30530
  const createActionForRoot = (
@@ -30587,6 +30626,7 @@ const createRestActionFactoryForRoot = (
30587
30626
  : undefined,
30588
30627
  // Another params' answer is another row.
30589
30628
  inheritData: verb !== "GET",
30629
+ keep: verb === "GET" ? keep.GET : undefined,
30590
30630
  completeSideEffect: onActionComplete,
30591
30631
  });
30592
30632
  if (verb === "GET") {
@@ -30618,6 +30658,7 @@ const createRestActionFactoryForRoot = (
30618
30658
  // A binding moving to new params hands over the previous answer: a list
30619
30659
  // standing in for the next one beats a skeleton.
30620
30660
  inheritData: true,
30661
+ keep: verb === "GET" ? keep.GET_MANY : undefined,
30621
30662
  // The rows the page kept from the previous document (kept_reads.js),
30622
30663
  // drawn while the request is out when nothing was handed over.
30623
30664
  provisionalValue:
@@ -30700,6 +30741,24 @@ const applyNetworkPolicy = (
30700
30741
  };
30701
30742
  };
30702
30743
 
30744
+ // What can never be kept throws, as a rerunOn that never fires does: a range
30745
+ // reader holds no answer, its lists ask again for the window they draw.
30746
+ const KEEP_READS = ["GET", "GET_MANY"];
30747
+ const assertKeepNamesReads = (name, keep) => {
30748
+ for (const read of Object.keys(keep)) {
30749
+ if (read === "GET_RANGE") {
30750
+ throw new Error(
30751
+ `resource(${name}): keep.GET_RANGE keeps nothing — a range reader holds no answer, its lists ask again for the window they draw`,
30752
+ );
30753
+ }
30754
+ if (!KEEP_READS.includes(read)) {
30755
+ throw new Error(
30756
+ `resource(${name}): keep.${read} is not a read that keeps an answer — keep takes GET and GET_MANY`,
30757
+ );
30758
+ }
30759
+ }
30760
+ };
30761
+
30703
30762
  // A `dependencies` given as a function is read before the first request
30704
30763
  // leaves (see item_lifecycle_manager.js).
30705
30764
  const readLazyDependenciesFirst = (restCallback) => {
@@ -84078,6 +84137,7 @@ const css$w = /* css */`@property --list-group-label-height {
84078
84137
 
84079
84138
  &[data-continued] {
84080
84139
  margin-top: calc(-1 * var(--x-list-gap, 0px));
84140
+ grid-template-columns: minmax(0, 1fr);
84081
84141
  display: grid;
84082
84142
 
84083
84143
  & > .navi_list_item_group_label, & > .navi_list_item_group_list {